Skip to content

Commit d753f9f

Browse files
committed
Implement ~= attribute matching
1 parent 13be62e commit d753f9f

File tree

1 file changed

+37
-6
lines changed

1 file changed

+37
-6
lines changed

src/wp-includes/html-api/class-wp-css-selectors.php

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,10 @@ public static function parse( string $input, int &$offset );
180180

181181
abstract class WP_CSS_Selector_Parser implements IWP_CSS_Selector_Parser, IWP_CSS_Selector_Matcher {
182182
const UTF8_MAX_CODEPOINT_VALUE = 0x10FFFF;
183+
const WHITESPACE_CHARACTERS = " \t\r\n\f";
183184

184185
public static function parse_whitespace( string $input, int &$offset ): bool {
185-
$length = strspn( $input, " \t\r\n\f", $offset );
186+
$length = strspn( $input, self::WHITESPACE_CHARACTERS, $offset );
186187
$advanced = $length > 0;
187188
$offset += $length;
188189
return $advanced;
@@ -698,8 +699,16 @@ public function matches( WP_HTML_Processor $processor ): bool {
698699
: $att_value === $this->value;
699700

700701
case self::MATCH_ONE_OF_EXACT:
701-
// @todo
702-
throw new Exception( 'One of attribute matching is not supported yet.' );
702+
foreach ( $this->whitespace_delimited_list( $att_value ) as $val ) {
703+
if (
704+
$case_insensitive
705+
? 0 === strcasecmp( $val, $this->value )
706+
: $val === $this->value
707+
) {
708+
return true;
709+
}
710+
}
711+
return false;
703712

704713
case self::MATCH_EXACT_OR_EXACT_WITH_HYPHEN:
705714
// Attempt the full match first
@@ -727,13 +736,35 @@ public function matches( WP_HTML_Processor $processor ): bool {
727736

728737
case self::MATCH_CONTAINS:
729738
return false !== (
730-
$case_insensitive ?
731-
stripos( $att_value, $this->value ) :
732-
strpos( $att_value, $this->value )
739+
$case_insensitive
740+
? stripos( $att_value, $this->value )
741+
: strpos( $att_value, $this->value )
733742
);
734743
}
735744
}
736745

746+
/**
747+
* @param string $input
748+
*
749+
* @return Generator<string>
750+
*/
751+
private function whitespace_delimited_list( string $input ): Generator {
752+
$offset = strspn( $input, self::WHITESPACE_CHARACTERS );
753+
754+
while ( $offset < strlen( $input ) ) {
755+
// Find the byte length until the next boundary.
756+
$length = strcspn( $input, self::WHITESPACE_CHARACTERS, $offset );
757+
if ( 0 === $length ) {
758+
return;
759+
}
760+
761+
$value = substr( $input, $offset, $length );
762+
$offset += $length + strspn( $input, self::WHITESPACE_CHARACTERS, $offset + $length );
763+
764+
yield $value;
765+
}
766+
}
767+
737768
/**
738769
* [att=val]
739770
* Represents an element with the att attribute whose value is exactly "val".

0 commit comments

Comments
 (0)