forked from WordPress/wordpress-develop
-
Notifications
You must be signed in to change notification settings - Fork 0
Html api/add html processor #6
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
Draft
dmsnell
wants to merge
55
commits into
trunk
Choose a base branch
from
html-api/add-html-processor
base: trunk
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 1 commit
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 84e35ef
WIP: HTML API: Expose self-closing flag in Tag Processor
dmsnell 84e25cf
Expand documentation
dmsnell c18a81a
Appease the linting gods
dmsnell af8d49d
Add extra tests for syntax peculiarities.
dmsnell 72e5de0
Appease the linting gods
dmsnell 095a110
Appease the linting gods
dmsnell 9b3f90d
Appease the linting gods
dmsnell 09e16b2
Merge branch 'html-api/tag-processor-self-closing-flag' into html-api…
dmsnell 396285b
Add `ensure_support()` and tests
dmsnell b2e6856
WIP: Work on next_sibling
dmsnell 65c9f5b
Add the rest of it
dmsnell f5e4d5e
Merge branch 'trunk' into html-api/add-html-processor
dmsnell 247966b
Rename "next_child" to "first_child" to better match its purpose
dmsnell f1ccd9b
Ensure no children are found for void elements.
dmsnell fb31ea1
rename next_child to first_child in test names
dmsnell 2af46d0
Merge branch 'trunk' into html-api/add-html-processor
dmsnell e945f16
Add Trac ticket reference to tests
dmsnell 96053c9
fixup! Add Trac ticket reference to tests
dmsnell da7880a
Merge branch 'trunk' into html-api/add-html-processor
dmsnell 264ae35
Merge branch 'html-api/tag-processor-self-closing-flag' into html-api…
dmsnell 04a37b5
Linting issues
dmsnell 0975e34
Wrap bookmarking to create special internal bookmarks used in HTML tr…
dmsnell d30f766
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell cafee03
Remove `ensure_support`
dmsnell 67bef48
Introduce step function and insertion mode
dmsnell be6e901
Create some IS_SPECIAL flags
dmsnell 9980a36
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell 2e874e4
Some bookmarking stuff
dmsnell d0e3f4a
Merge branch 'trunk' into html-api/add-html-processor
dmsnell ece3a68
I think we need a separate actual stack for open elements
dmsnell a5284d6
Merge branch 'trunk' into html-api/add-html-processor
dmsnell 74c9e6b
Merge branch 'trunk' into html-api/add-html-processor
dmsnell a4569cd
Merge branch 'trunk' into html-api/add-html-processor
dmsnell 98180bc
Add WIP stack class, trap exceptions in `step()` to allow nested call…
dmsnell 0e3ada5
Play with an alternate matching syntax
dmsnell 739b4aa
Add reset_insertion_mode_appropriately
dmsnell 2b263b5
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell e1ec10c
Merge branch 'trunk' into html-api/add-html-processor
dmsnell bc61ea8
Add custom "Unsupported Exception" class to differentiate from other …
dmsnell 6f58b70
Set template insertion mode stack to empty array, not null
dmsnell d82b146
Expand SPEC data for IS_SPECIAL and IS_OBSOLETE
dmsnell a6e5323
Docs for SPEC and some minor refactoring
dmsnell 8a2215e
Add algorithms for handling list of active formatting elements.
dmsnell d96c05a
Add docs for HEAD and FORM pointers.
dmsnell c93d420
Generate implied end tags, poorly and naively.
dmsnell 2e0e4f9
More docs, remove something not necessary.
dmsnell f5c7651
Introduce static factory methods
dmsnell 3956ad9
Access private methods and properties of friend class
dmsnell 37ce95e
Merge branch 'trunk' into html-api/add-html-processor
dmsnell 613ae1a
Replace goto:ignored with recursion
dmsnell 46e3777
Continue adding IN BODY handling.
dmsnell a1a095c
Merge branch 'trunk' into html-api/add-html-processor
dmsnell c2dcc37
Merge remote-tracking branch 'upstream/trunk' into html-api/add-html-…
dmsnell c29570e
More support
dmsnell File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
src/wp-includes/html-api/class-wp-html-element-stack-item.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | ||
} | ||
} |
266 changes: 266 additions & 0 deletions
266
src/wp-includes/html-api/class-wp-html-element-stack.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
<?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(); | ||
|
||
public function __construct( $bookmark_name, $element, $flags ) { | ||
$this->bookmark_name = $bookmark_name; | ||
$this->element = $element; | ||
$this->flags = $flags; | ||
} | ||
|
||
/** | ||
* 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, | ||
) ); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,12 +24,20 @@ class WP_HTML_Processor extends WP_HTML_Tag_Processor { | |
* @return boolean Whether an element was found. | ||
*/ | ||
public function step( $insertion_mode = null ) { | ||
switch ( $insertion_mode ?: $this->insertion_mode ) { | ||
case 'in-body': | ||
return $this->step_in_body(); | ||
try { | ||
switch ( $insertion_mode ?: $this->insertion_mode ) { | ||
case 'in-body': | ||
return $this->step_in_body(); | ||
|
||
default: | ||
return self::NOT_IMPLEMENTED_YET; | ||
default: | ||
return self::NOT_IMPLEMENTED_YET; | ||
} | ||
} catch ( Exception $e ) { | ||
/* | ||
* Exceptions are used in this class to escape deep call stacks that | ||
* otherwise might involve messier calling and return conventions. | ||
*/ | ||
return false; | ||
} | ||
} | ||
|
||
|
@@ -215,7 +223,7 @@ private function close_p_element() { | |
* @return void | ||
*/ | ||
private function generate_implied_end_tags( $except_for_this_element = null ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! I can't remember why I used an array here, but it doesn't seem like one is needed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you support "comprehensive" implied tags in the same function |
||
|
||
} | ||
|
||
/** | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Catching all exceptions might hide legitimate errors, it would be safer to have a HTML_Exception class or so
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. at some point I wanted to go back and special-case known exceptions so we don't hide others, but I didn't do that yet because I wasn't entirely sure how I felt about the escaping mechanism as throwing Exceptions.