|
1 <?php |
|
2 /** |
|
3 * HTML API: WP_HTML_Active_Formatting_Elements class |
|
4 * |
|
5 * @package WordPress |
|
6 * @subpackage HTML-API |
|
7 * @since 6.4.0 |
|
8 */ |
|
9 |
|
10 /** |
|
11 * Core class used by the HTML processor during HTML parsing |
|
12 * for managing the stack of active formatting elements. |
|
13 * |
|
14 * This class is designed for internal use by the HTML processor. |
|
15 * |
|
16 * > Initially, the list of active formatting elements is empty. |
|
17 * > It is used to handle mis-nested formatting element tags. |
|
18 * > |
|
19 * > The list contains elements in the formatting category, and markers. |
|
20 * > The markers are inserted when entering applet, object, marquee, |
|
21 * > template, td, th, and caption elements, and are used to prevent |
|
22 * > formatting from "leaking" into applet, object, marquee, template, |
|
23 * > td, th, and caption elements. |
|
24 * > |
|
25 * > In addition, each element in the list of active formatting elements |
|
26 * > is associated with the token for which it was created, so that |
|
27 * > further elements can be created for that token if necessary. |
|
28 * |
|
29 * @since 6.4.0 |
|
30 * |
|
31 * @access private |
|
32 * |
|
33 * @see https://html.spec.whatwg.org/#list-of-active-formatting-elements |
|
34 * @see WP_HTML_Processor |
|
35 */ |
|
36 class WP_HTML_Active_Formatting_Elements { |
|
37 /** |
|
38 * Holds the stack of active formatting element references. |
|
39 * |
|
40 * @since 6.4.0 |
|
41 * |
|
42 * @var WP_HTML_Token[] |
|
43 */ |
|
44 private $stack = array(); |
|
45 |
|
46 /** |
|
47 * Reports if a specific node is in the stack of active formatting elements. |
|
48 * |
|
49 * @since 6.4.0 |
|
50 * |
|
51 * @param WP_HTML_Token $token Look for this node in the stack. |
|
52 * @return bool Whether the referenced node is in the stack of active formatting elements. |
|
53 */ |
|
54 public function contains_node( $token ) { |
|
55 foreach ( $this->walk_up() as $item ) { |
|
56 if ( $token->bookmark_name === $item->bookmark_name ) { |
|
57 return true; |
|
58 } |
|
59 } |
|
60 |
|
61 return false; |
|
62 } |
|
63 |
|
64 /** |
|
65 * Returns how many nodes are currently in the stack of active formatting elements. |
|
66 * |
|
67 * @since 6.4.0 |
|
68 * |
|
69 * @return int How many node are in the stack of active formatting elements. |
|
70 */ |
|
71 public function count() { |
|
72 return count( $this->stack ); |
|
73 } |
|
74 |
|
75 /** |
|
76 * Returns the node at the end of the stack of active formatting elements, |
|
77 * if one exists. If the stack is empty, returns null. |
|
78 * |
|
79 * @since 6.4.0 |
|
80 * |
|
81 * @return WP_HTML_Token|null Last node in the stack of active formatting elements, if one exists, otherwise null. |
|
82 */ |
|
83 public function current_node() { |
|
84 $current_node = end( $this->stack ); |
|
85 |
|
86 return $current_node ? $current_node : null; |
|
87 } |
|
88 |
|
89 /** |
|
90 * Pushes a node onto the stack of active formatting elements. |
|
91 * |
|
92 * @since 6.4.0 |
|
93 * |
|
94 * @see https://html.spec.whatwg.org/#push-onto-the-list-of-active-formatting-elements |
|
95 * |
|
96 * @param WP_HTML_Token $token Push this node onto the stack. |
|
97 */ |
|
98 public function push( $token ) { |
|
99 /* |
|
100 * > If there are already three elements in the list of active formatting elements after the last marker, |
|
101 * > if any, or anywhere in the list if there are no markers, that have the same tag name, namespace, and |
|
102 * > attributes as element, then remove the earliest such element from the list of active formatting |
|
103 * > elements. For these purposes, the attributes must be compared as they were when the elements were |
|
104 * > created by the parser; two elements have the same attributes if all their parsed attributes can be |
|
105 * > paired such that the two attributes in each pair have identical names, namespaces, and values |
|
106 * > (the order of the attributes does not matter). |
|
107 * |
|
108 * @todo Implement the "Noah's Ark clause" to only add up to three of any given kind of formatting elements to the stack. |
|
109 */ |
|
110 // > Add element to the list of active formatting elements. |
|
111 $this->stack[] = $token; |
|
112 } |
|
113 |
|
114 /** |
|
115 * Removes a node from the stack of active formatting elements. |
|
116 * |
|
117 * @since 6.4.0 |
|
118 * |
|
119 * @param WP_HTML_Token $token Remove this node from the stack, if it's there already. |
|
120 * @return bool Whether the node was found and removed from the stack of active formatting elements. |
|
121 */ |
|
122 public function remove_node( $token ) { |
|
123 foreach ( $this->walk_up() as $position_from_end => $item ) { |
|
124 if ( $token->bookmark_name !== $item->bookmark_name ) { |
|
125 continue; |
|
126 } |
|
127 |
|
128 $position_from_start = $this->count() - $position_from_end - 1; |
|
129 array_splice( $this->stack, $position_from_start, 1 ); |
|
130 return true; |
|
131 } |
|
132 |
|
133 return false; |
|
134 } |
|
135 |
|
136 /** |
|
137 * Steps through the stack of active formatting elements, starting with the |
|
138 * top element (added first) and walking downwards to the one added last. |
|
139 * |
|
140 * This generator function is designed to be used inside a "foreach" loop. |
|
141 * |
|
142 * Example: |
|
143 * |
|
144 * $html = '<em><strong><a>We are here'; |
|
145 * foreach ( $stack->walk_down() as $node ) { |
|
146 * echo "{$node->node_name} -> "; |
|
147 * } |
|
148 * > EM -> STRONG -> A -> |
|
149 * |
|
150 * To start with the most-recently added element and walk towards the top, |
|
151 * see WP_HTML_Active_Formatting_Elements::walk_up(). |
|
152 * |
|
153 * @since 6.4.0 |
|
154 */ |
|
155 public function walk_down() { |
|
156 $count = count( $this->stack ); |
|
157 |
|
158 for ( $i = 0; $i < $count; $i++ ) { |
|
159 yield $this->stack[ $i ]; |
|
160 } |
|
161 } |
|
162 |
|
163 /** |
|
164 * Steps through the stack of active formatting elements, starting with the |
|
165 * bottom element (added last) and walking upwards to the one added first. |
|
166 * |
|
167 * This generator function is designed to be used inside a "foreach" loop. |
|
168 * |
|
169 * Example: |
|
170 * |
|
171 * $html = '<em><strong><a>We are here'; |
|
172 * foreach ( $stack->walk_up() as $node ) { |
|
173 * echo "{$node->node_name} -> "; |
|
174 * } |
|
175 * > A -> STRONG -> EM -> |
|
176 * |
|
177 * To start with the first added element and walk towards the bottom, |
|
178 * see WP_HTML_Active_Formatting_Elements::walk_down(). |
|
179 * |
|
180 * @since 6.4.0 |
|
181 */ |
|
182 public function walk_up() { |
|
183 for ( $i = count( $this->stack ) - 1; $i >= 0; $i-- ) { |
|
184 yield $this->stack[ $i ]; |
|
185 } |
|
186 } |
|
187 } |