Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Html api/add html processor #6

Draft
wants to merge 55 commits into
base: trunk
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 36 commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
805fb55
WIP: HTML API: Add HTML Spec class to convey information related to t…
dmsnell Feb 24, 2023
84e35ef
WIP: HTML API: Expose self-closing flag in Tag Processor
dmsnell Mar 2, 2023
84e25cf
Expand documentation
dmsnell Mar 2, 2023
c18a81a
Appease the linting gods
dmsnell Mar 2, 2023
af8d49d
Add extra tests for syntax peculiarities.
dmsnell Mar 2, 2023
72e5de0
Appease the linting gods
dmsnell Mar 2, 2023
095a110
Appease the linting gods
dmsnell Mar 2, 2023
9b3f90d
Appease the linting gods
dmsnell Mar 2, 2023
09e16b2
Merge branch 'html-api/tag-processor-self-closing-flag' into html-api…
dmsnell Mar 7, 2023
396285b
Add `ensure_support()` and tests
dmsnell Mar 7, 2023
b2e6856
WIP: Work on next_sibling
dmsnell Mar 7, 2023
65c9f5b
Add the rest of it
dmsnell Mar 10, 2023
f5e4d5e
Merge branch 'trunk' into html-api/add-html-processor
dmsnell Mar 21, 2023
247966b
Rename "next_child" to "first_child" to better match its purpose
dmsnell Mar 21, 2023
f1ccd9b
Ensure no children are found for void elements.
dmsnell Mar 22, 2023
fb31ea1
rename next_child to first_child in test names
dmsnell Mar 22, 2023
2af46d0
Merge branch 'trunk' into html-api/add-html-processor
dmsnell Mar 25, 2023
e945f16
Add Trac ticket reference to tests
dmsnell Mar 29, 2023
96053c9
fixup! Add Trac ticket reference to tests
dmsnell Mar 29, 2023
da7880a
Merge branch 'trunk' into html-api/add-html-processor
dmsnell Mar 29, 2023
264ae35
Merge branch 'html-api/tag-processor-self-closing-flag' into html-api…
dmsnell Mar 29, 2023
04a37b5
Linting issues
dmsnell Mar 29, 2023
0975e34
Wrap bookmarking to create special internal bookmarks used in HTML tr…
dmsnell Apr 20, 2023
d30f766
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell Apr 20, 2023
cafee03
Remove `ensure_support`
dmsnell Apr 20, 2023
67bef48
Introduce step function and insertion mode
dmsnell Apr 20, 2023
be6e901
Create some IS_SPECIAL flags
dmsnell May 3, 2023
9980a36
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell May 3, 2023
2e874e4
Some bookmarking stuff
dmsnell May 4, 2023
d0e3f4a
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 4, 2023
ece3a68
I think we need a separate actual stack for open elements
dmsnell May 4, 2023
a5284d6
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 8, 2023
74c9e6b
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 8, 2023
a4569cd
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 16, 2023
98180bc
Add WIP stack class, trap exceptions in `step()` to allow nested call…
dmsnell May 17, 2023
0e3ada5
Play with an alternate matching syntax
dmsnell May 17, 2023
739b4aa
Add reset_insertion_mode_appropriately
dmsnell May 17, 2023
2b263b5
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell May 17, 2023
e1ec10c
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 20, 2023
bc61ea8
Add custom "Unsupported Exception" class to differentiate from other …
dmsnell May 20, 2023
6f58b70
Set template insertion mode stack to empty array, not null
dmsnell May 20, 2023
d82b146
Expand SPEC data for IS_SPECIAL and IS_OBSOLETE
dmsnell May 21, 2023
a6e5323
Docs for SPEC and some minor refactoring
dmsnell May 21, 2023
8a2215e
Add algorithms for handling list of active formatting elements.
dmsnell May 21, 2023
d96c05a
Add docs for HEAD and FORM pointers.
dmsnell May 21, 2023
c93d420
Generate implied end tags, poorly and naively.
dmsnell May 21, 2023
2e0e4f9
More docs, remove something not necessary.
dmsnell May 21, 2023
f5c7651
Introduce static factory methods
dmsnell May 22, 2023
3956ad9
Access private methods and properties of friend class
dmsnell May 23, 2023
37ce95e
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 24, 2023
613ae1a
Replace goto:ignored with recursion
dmsnell May 24, 2023
46e3777
Continue adding IN BODY handling.
dmsnell May 25, 2023
a1a095c
Merge branch 'trunk' into html-api/add-html-processor
dmsnell May 26, 2023
c2dcc37
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell May 28, 2023
c29570e
More support
dmsnell May 29, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/wp-includes/html-api/class-wp-html-element-stack-item.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

class WP_HTML_Element_Stack_Item {
const IS_CLOSER = 1 << 0;
const HAS_SELF_CLOSING_FLAG = 1 << 1;

/**
* Stores the name of the bookmark pointing to the element at the position of the item.
*
* @var string|null
*/
public $bookmark_name = null;

/**
* Stores the element class name for the element at the position of the item.
*
* This is the name of the PHP class representing the element.
* For example, `WP_HTMLDivElement` from calling `WP_HTMLDivElement::class`.
*
* @var string|null
*/
public $element = null;

/**
* Properties about this item in the stack that are relevant for relating opening and closing tags.
*
* @var int
*/
public $flags = 0;

/**
* Pointer to related item on the stack, if one exists.
* For example, a tag opener that opens the current tag closer.
*
* @var WP_HTML_Element_Stack_Item|null
*/
public $related_item = null;

public function __construct( $bookmark_name, $element, $flags, $related_item = null ) {
$this->bookmark_name = $bookmark_name;
$this->element = $element;
$this->flags = $flags;
$this->related_item = $related_item;
}
}
260 changes: 260 additions & 0 deletions src/wp-includes/html-api/class-wp-html-element-stack.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
<?php

class WP_HTML_Element_Stack {
/**
* Stack holding HTML tokens, tag openers, tag closers, or plain bookmarks.
*
* @var WP_HTML_Element_Stack_Item[]
*/
public $stack = array();

/**
* Add an item to the top of the stack.
*
* @TODO: Do we need to insertion-sort these?
*
* @param $stack_item
* @return void
*/
public function push( $stack_item ) {
$this->stack[] = $stack_item;
}

public function count() {
return count( $this->stack );
}

/**
* Returns the bottom-most node on the stack.
*
* @return WP_HTML_Element_Stack_Item|null
*/
public function current_node() {
$count = $this->count();

return $this->count() > 0
? $this->stack[ $count - 1 ]
: null;
}

/**
* Returns whether the given element is on the stack.
*
* @param string $element the ::class name of the element to check for.
* @return boolean whether the given element is on the stack.
*/
public function has_element( $element ) {
for ( $i = count( $this->stack ) - 1; $i > 0; $i++ ) {
if ( $this->stack[ $i ]->element === $element ) {
return true;
}
}

return false;
}

/**
* Returns whether an element is in a specific scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-the-specific-scope
*
* @param string $element The target node.
* @param string[] $termination_list List of elements that terminate the search.
* @return bool
*/
public function has_element_in_specific_scope( $element, $termination_list ) {
$i = $this->count();
if ( $i === 0 ) {
return false;
}

$node = $this->stack[ --$i ];

if ( $node->element === $element ) {
return true;
}

if ( in_array( $element, $termination_list, true ) ) {
return false;
}

while ( $i > 0 && null !== ( $node = $this->stack[ --$i ] ) ) {
if ( $node->element === $element ) {
return true;
}
}

return false;
}

/**
* Returns whether a given element is in a particular scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-scope
*
* @param string $element
* @return bool
*/
public function has_element_in_particular_scope( $element ) {
return $this->has_element_in_specific_scope( $element, array(
WP_HTMLAppletElement::class,
WP_HTMLCaptionElement::class,
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTdElement::class,
WP_HTMLThElement::class,
WP_HTMLMarqueeElement::class,
WP_HTMLObjectElement::class,
WP_HTMLTemplateElement::class,
WP_MathML_Mi_Element::class,
WP_MathML_Mo_Element::class,
WP_MathML_Mn_Element::class,
WP_MathML_Ms_Element::class,
WP_MathML_Mtext_Element::class,
WP_MathML_Annotation_Xml_Element::class,
WP_SVG_ForeignObject_Element::class,
WP_SVG_Description_Element::class,
WP_SVG_Title_Element::class,
) );
}

/**
* Returns whether a given element is in list item scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-list-item-scope
*
* @param $element
* @return void
*/
public function has_element_in_list_item_scope( $element ) {
return $this->has_element_in_specific_scope( $element, array(
WP_HTMLAppletElement::class,
WP_HTMLCaptionElement::class,
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTdElement::class,
WP_HTMLThElement::class,
WP_HTMLMarqueeElement::class,
WP_HTMLObjectElement::class,
WP_HTMLTemplateElement::class,
WP_MathML_Mi_Element::class,
WP_MathML_Mo_Element::class,
WP_MathML_Mn_Element::class,
WP_MathML_Ms_Element::class,
WP_MathML_Mtext_Element::class,
WP_MathML_Annotation_Xml_Element::class,
WP_SVG_ForeignObject_Element::class,
WP_SVG_Description_Element::class,
WP_SVG_Title_Element::class,

// Additionally these elements.
WP_HTMLOlElement::class,
WP_HTMLUlElement::class,
) );
}

/**
* Returns whether a given element is in button scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-button-scope
*
* @param string $element
* @return boolean
*/
public function has_element_in_button_scope( $element ) {
return $this->has_element_in_specific_scope( $element, array(
WP_HTMLAppletElement::class,
WP_HTMLCaptionElement::class,
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTdElement::class,
WP_HTMLThElement::class,
WP_HTMLMarqueeElement::class,
WP_HTMLObjectElement::class,
WP_HTMLTemplateElement::class,
WP_MathML_Mi_Element::class,
WP_MathML_Mo_Element::class,
WP_MathML_Mn_Element::class,
WP_MathML_Ms_Element::class,
WP_MathML_Mtext_Element::class,
WP_MathML_Annotation_Xml_Element::class,
WP_SVG_ForeignObject_Element::class,
WP_SVG_Description_Element::class,
WP_SVG_Title_Element::class,

// Additionally these elements.
WP_HTMLButtonElement::class,
) );
}

/**
* Returns whether the given element is in table scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-table-scope
*
* @param string $element
* @return bool
*/
public function has_element_in_table_scope( $element ) {
return $this->has_element_in_specific_scope( $element, array(
WP_HTMLAppletElement::class,
WP_HTMLCaptionElement::class,
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTdElement::class,
WP_HTMLThElement::class,
WP_HTMLMarqueeElement::class,
WP_HTMLObjectElement::class,
WP_HTMLTemplateElement::class,
WP_MathML_Mi_Element::class,
WP_MathML_Mo_Element::class,
WP_MathML_Mn_Element::class,
WP_MathML_Ms_Element::class,
WP_MathML_Mtext_Element::class,
WP_MathML_Annotation_Xml_Element::class,
WP_SVG_ForeignObject_Element::class,
WP_SVG_Description_Element::class,
WP_SVG_Title_Element::class,

// Additionally these elements.
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTemplateElement::class,
) );
}

/**
* Returns whether a given element is in select scope.
*
* @see https://html.spec.whatwg.org/#has-an-element-in-select-scope
*
* @param string $element
* @return bool
*/
public function has_element_in_select_scope( $element ) {
return $this->has_element_in_specific_scope( $element, array(
WP_HTMLAppletElement::class,
WP_HTMLCaptionElement::class,
WP_HTMLHtmlElement::class,
WP_HTMLTableElement::class,
WP_HTMLTdElement::class,
WP_HTMLThElement::class,
WP_HTMLMarqueeElement::class,
WP_HTMLObjectElement::class,
WP_HTMLTemplateElement::class,
WP_MathML_Mi_Element::class,
WP_MathML_Mo_Element::class,
WP_MathML_Mn_Element::class,
WP_MathML_Ms_Element::class,
WP_MathML_Mtext_Element::class,
WP_MathML_Annotation_Xml_Element::class,
WP_SVG_ForeignObject_Element::class,
WP_SVG_Description_Element::class,
WP_SVG_Title_Element::class,

// Additionally these elements.
WP_HTMLOptgroupElement::class,
WP_HTMLOptionElement::class,
) );
}
}
Loading