Skip to content

Commit 9e752e5

Browse files
committed
Make things worse, but lead towards making them better; GOTO
1 parent 68d72e8 commit 9e752e5

File tree

4 files changed

+165
-42
lines changed

4 files changed

+165
-42
lines changed

lib/experimental/html/class-wp-html-attribute-sourcer.php

Lines changed: 125 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -128,37 +128,149 @@ public function source_attributes() {
128128
);
129129
}
130130

131+
public static function select_match( $tags, $s ) {
132+
if ( ! empty( $s['tag_name'] ) && strtoupper( $s['tag_name'] ) !== $tags->get_tag() ) {
133+
return null;
134+
}
135+
136+
if ( ! empty( $s['class_names'] ) ) {
137+
$classes = $tags->get_attribute( 'class' );
138+
if ( null === $classes ) {
139+
return null;
140+
}
141+
142+
foreach ( $s['class_names'] as $class_name ) {
143+
if ( ! preg_match( "~\b{$class_name}\b~", $classes ) ) {
144+
return null;
145+
}
146+
}
147+
}
148+
149+
if ( isset( $s['hash'] ) && $s['identifier'] !== $tags->get_attribute( 'id' ) ) {
150+
return null;
151+
}
152+
153+
if ( isset( $s['has_attribute'] ) && null === $tags->get_attribute( $s['has_attribute'] ) ) {
154+
return null;
155+
}
156+
157+
return $tags;
158+
}
159+
131160
public static function select( $selectors, $html ) {
132161
$tags = new WP_HTML_Processor( $html );
162+
if ( ! $tags->next_tag() ) {
163+
return null;
164+
}
165+
166+
$tags->set_bookmark( 'start' );
133167

134-
while ( $tags->next_tag() ) {
135-
foreach ( $selectors as $s ) {
136-
if ( ! empty( $s['tag_name'] ) && strtoupper( $s['tag_name'] ) !== $tags->get_tag() ) {
168+
foreach ( $selectors as $s ) {
169+
$tags->seek( 'start' );
170+
$max = 100;
171+
while ( --$max > 0 ) {
172+
$next = $s;
173+
174+
// This label is probably where some stack-level data should reside.
175+
next:
176+
// Find the next starting point
177+
while ( null === self::select_match( $tags, $next ) && $tags->next_tag() ) {
137178
continue;
138179
}
139180

140-
if ( ! empty( $s['class_names'] ) ) {
141-
$classes = $tags->get_attribute( 'class' );
142-
if ( null === $classes ) {
181+
// We're out of possible starting points
182+
if ( null === self::select_match( $tags, $next ) ) {
183+
continue 2;
184+
}
185+
186+
// No further selectors, then bingo!
187+
if ( ! isset( $next['then'] ) ) {
188+
return $tags;
189+
}
190+
191+
$next = $next['then'];
192+
193+
// Adjacent sibling must be the immediately-following element.
194+
if ( '+' === $next['combinator'] ) {
195+
var_dump( [
196+
'msg' => "Processing adjacent sibling",
197+
'html' => $html,
198+
'tag' => $tags->get_tag(),
199+
'selector' => $next
200+
] );
201+
$state = [];
202+
while ( $tags->next_within_balanced_tags( $state ) ) {
143203
continue;
144204
}
145205

146-
foreach ( $s['class_names'] as $class_name ) {
147-
if ( ! preg_match( "~\b{$class_name}\b~", $classes ) ) {
148-
continue 2;
149-
}
206+
$tags->next_tag();
207+
if ( null === self::select_match( $tags, $next ) ) {
208+
continue;
150209
}
210+
211+
if ( isset( $next['then'] ) ) {
212+
goto next;
213+
}
214+
215+
// @TODO: Recurse here so we can handle more than one level.
216+
return $tags;
151217
}
152218

153-
if ( isset( $s['hash'] ) && $s['identifier'] !== $tags->get_attribute( 'id' ) ) {
219+
// Child must be one level into current tag.
220+
if ( '>' === $next['combinator'] ) {
221+
var_dump( [
222+
'msg' => "Processing child",
223+
'html' => $html,
224+
'tag' => $tags->get_tag(),
225+
'selector' => $next
226+
] );
227+
$state = [];
228+
while ( $tags->next_within_balanced_tags( $state, null, 1 ) ) {
229+
if ( null === self::select_match( $tags, $next ) ) {
230+
continue;
231+
}
232+
233+
if ( isset( $next['then'] ) ) {
234+
goto next;
235+
}
236+
237+
// @TODO: Recurse here so we can handle more than one level.
238+
return $tags;
239+
}
240+
154241
continue;
155242
}
156243

157-
if ( isset( $s['has_attribute'] ) && null === $tags->get_attribute( $s['has_attribute'] ) ) {
244+
// Descendant can be anywhere inside current tag.
245+
if ( ' ' === $next['combinator'] ) {
246+
var_dump( [
247+
'msg' => "Processing descendant",
248+
'html' => $html,
249+
'tag' => $tags->get_tag(),
250+
'selector' => $next
251+
] );
252+
$state = [];
253+
while ( $tags->next_within_balanced_tags( $state ) ) {
254+
if ( null === self::select_match( $tags, $next ) ) {
255+
continue;
256+
}
257+
258+
if ( isset( $next['then'] ) ) {
259+
goto next;
260+
}
261+
262+
// @TODO: Recurse here so we can handle more than one level.
263+
return $tags;
264+
}
265+
158266
continue;
159267
}
160268

161-
return $tags;
269+
// General sibling must be anything at current level.
270+
if ( '~' === $next['combinator'] ) {
271+
// @TODO: Support this.
272+
return null;
273+
}
162274
}
163275
}
164276

lib/experimental/html/class-wp-html-processor.php

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,40 @@
1717
*/
1818

1919
class WP_HTML_Processor extends WP_HTML_Tag_Processor {
20-
public function next_within_balanced_tags( $query, $max_depth = 1000 ) {
21-
$budget = 1000;
22-
if ( self::is_html_void_element( $this->get_tag() ) ) {
23-
return false;
20+
public function next_within_balanced_tags( &$state, $query = null, $max_depth = 1000 ) {
21+
if ( empty( $state ) ) {
22+
$state['budget'] = 1000;
23+
$state['tag_name'] = $this->get_tag();
24+
$state['balanced_depth'] = 1;
25+
$state['depth'] = 1;
26+
27+
if ( self::is_html_void_element( $this->get_tag() ) ) {
28+
return false;
29+
}
2430
}
2531

26-
$tag_name = $this->get_tag();
27-
$balanced_depth = 1;
28-
$depth = 1;
29-
30-
while ( $this->next_tag( array( 'tag_closers' => 'visit' ) ) && $budget-- > 0 ) {
31-
if ( $this->get_tag() === $tag_name && $this->is_tag_closer() && $balanced_depth === 1 ) {
32+
while ( $this->next_tag( array( 'tag_closers' => 'visit' ) ) && $state['budget']-- > 0 ) {
33+
if (
34+
$this->get_tag() === $state['tag_name'] &&
35+
$this->is_tag_closer() &&
36+
$state['balanced_depth'] === 1
37+
) {
3238
return false;
3339
}
3440

35-
if ( $depth <= $max_depth ) {
41+
if ( $state['depth'] <= $max_depth ) {
3642
$this->parse_query( $query );
3743
if ( $this->matches() ) {
3844
return true;
3945
}
4046
}
4147

4248
if ( ! self::is_html_void_element( $this->get_tag() ) ) {
43-
$depth += $this->is_tag_closer() ? -1 : 1;
49+
$state['depth'] += $this->is_tag_closer() ? -1 : 1;
4450
}
4551

46-
if ( $this->get_tag() === $tag_name ) {
47-
$balanced_depth += $this->is_tag_closer() ? -1 : 1;
52+
if ( $this->get_tag() === $state['tag_name'] ) {
53+
$state['balanced_depth'] += $this->is_tag_closer() ? -1 : 1;
4854
}
4955
}
5056

phpunit/html/wp-html-attribute-sourcer-test.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,16 +26,16 @@ public function data_sourced_attributes() {
2626
array(
2727
array( 'attributes' => array( 'link' => 'docs.html' ), 'unparsed' => array() ),
2828
<<<EOF
29-
<main>
30-
<section>Just another section</section>
31-
<section><div><a href="blah">blah</a></div></section>
32-
<p>Stuff</p>
33-
<div><a href="blarg">blarg</a></div>
34-
<section>Still another section</section>
35-
<div><img><a href="image">image</a></div>
36-
<section>Still another section</section>
37-
<div><a href="docs.html">docs</a></div>
38-
</main>
29+
<main>
30+
<section>Just another section</section>
31+
<section><div><a href="blah">blah</a></div></section>
32+
<p>Stuff</p>
33+
<div><a href="blarg">blarg</a></div>
34+
<section>Still another section</section>
35+
<div><img><a href="image">image</a></div>
36+
<section>Still another section</section>
37+
<div><a href="docs.html">docs</a></div>
38+
</main>
3939
EOF,
4040
array(
4141
'link' => array(

phpunit/html/wp-html-processor-test.php

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,30 +19,35 @@ public function test_find_descendant_tag() {
1919
$tags = new WP_HTML_Processor( '<div>outside</div><section><div><img>inside</div></section>' );
2020

2121
$tags->next_tag( 'div' );
22-
$this->assertFalse( $tags->next_within_balanced_tags( 'img' ) );
22+
$state = [];
23+
$this->assertFalse( $tags->next_within_balanced_tags( $state, 'img' ) );
2324

2425
$this->assertTrue( $tags->next_tag( 'div' ) );
25-
$this->assertTrue( $tags->next_within_balanced_tags( 'img' ) );
26+
$state = [];
27+
$this->assertTrue( $tags->next_within_balanced_tags( $state, 'img' ) );
2628
}
2729

2830
public function test_find_immediate_child_tag() {
2931
$tags = new WP_HTML_Processor( '<div><div><div><img></div></div></div>' );
3032

3133
$tags->next_tag( 'div' );
32-
$this->assertFalse( $tags->next_within_balanced_tags( 'img', 1 ) );
34+
$state = [];
35+
$this->assertFalse( $tags->next_within_balanced_tags( $state, 'img', 1 ) );
3336
}
3437

3538
public function test_find_immediate_child_tag2() {
3639
$tags = new WP_HTML_Processor( '<div><div><div><img></div></div><img></div>' );
3740

3841
$tags->next_tag( 'div' );
39-
$this->assertTrue( $tags->next_within_balanced_tags( 'img', 1 ) );
42+
$state = [];
43+
$this->assertTrue( $tags->next_within_balanced_tags( $state, 'img', 1 ) );
4044
}
4145

4246
public function test_find_child_tag() {
4347
$tags = new WP_HTML_Processor( '<div><div><div><img></div></div></div>' );
4448

4549
$tags->next_tag( 'div' );
46-
$this->assertTrue( $tags->next_within_balanced_tags( 'img', 3 ) );
50+
$state = [];
51+
$this->assertTrue( $tags->next_within_balanced_tags( $state, 'img', 3 ) );
4752
}
4853
}

0 commit comments

Comments
 (0)