PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Libraries/Sabberworm/CSS/src/Property/Selector.php +51 -96 10.0.1 → 11.1.0 View file →
@@ -1,63 +1,50 @@
1 1 <?php
2 2
3 -namespace Sabberworm\CSS\Property;
3 +declare(strict_types=1);
4 4
5 +namespace AcyMailing\Libraries\Sabberworm\CSS\Property;
6 +
7 +use AcyMailing\Libraries\Sabberworm\CSS\CSSList\CSSList;
8 +use AcyMailing\Libraries\Sabberworm\CSS\OutputFormat;
9 +use AcyMailing\Libraries\Sabberworm\CSS\Property\Selector\SpecificityCalculator;
10 +use AcyMailing\Libraries\Sabberworm\CSS\Renderable;
11 +
5 12 /**
6 13 * Class representing a single CSS selector. Selectors have to be split by the comma prior to being passed into this
7 14 * class.
8 15 */
9 -class Selector
16 +class Selector implements Renderable
10 17 {
11 18 /**
12 - * regexp for specificity calculations
19 + * @var non-empty-string
13 20 *
14 - * @var string
21 + * @internal since 8.5.2
15 22 */
16 - const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
17 - (\.[\w]+) # classes
18 - |
19 - \[(\w+) # attributes
20 - |
21 - (\:( # pseudo classes
22 - link|visited|active
23 - |hover|focus
24 - |lang
25 - |target
26 - |enabled|disabled|checked|indeterminate
27 - |root
28 - |nth-child|nth-last-child|nth-of-type|nth-last-of-type
29 - |first-child|last-child|first-of-type|last-of-type
30 - |only-child|only-of-type
31 - |empty|contains
32 - ))
33 - /ix';
34 -
35 - /**
36 - * regexp for specificity calculations
37 - *
38 - * @var string
39 - */
40 - const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
41 - ((^|[\s\+\>\~]+)[\w]+ # elements
42 - |
43 - \:{1,2}( # pseudo-elements
44 - after|before|first-letter|first-line|selection
45 - ))
46 - /ix';
47 -
48 - /**
49 - * regexp for specificity calculations
50 - *
51 - * @var string
52 - */
53 - const SELECTOR_VALIDATION_RX = '/
23 + public const SELECTOR_VALIDATION_RX = '/
54 24 ^(
55 25 (?:
56 - [a-zA-Z0-9\x{00A0}-\x{FFFF}_^$|*="\'~\[\]()\-\s\.:#+>]* # any sequence of valid unescaped characters
57 - (?:\\\\.)? # a single escaped character
58 - (?:([\'"]).*?(?<!\\\\)\2)? # a quoted text like [id="example"]
59 - )*
26 + # any sequence of valid unescaped characters, except quotes
27 + [a-zA-Z0-9\\x{00A0}-\\x{FFFF}_^$|*=~\\[\\]()\\-\\s\\.:#+>,]++
28 + |
29 + # one or more escaped characters
30 + (?:\\\\.)++
31 + |
32 + # quoted text, like in `[id="example"]`
33 + (?:
34 + # opening quote
35 + ([\'"])
36 + (?:
37 + # sequence of characters except closing quote or backslash
38 + (?:(?!\\g{-1}|\\\\).)++
39 + |
40 + # one or more escaped characters
41 + (?:\\\\.)++
42 + )*+ # zero or more times
43 + # closing quote or end (unmatched quote is currently allowed)
44 + (?:\\g{-1}|$)
45 + )
46 + )*+ # zero or more times
60 47 )$
61 48 /ux';
62 49
63 50 /**
@@ -62,77 +49,45 @@
62 49
63 50 /**
64 51 * @var string
65 52 */
66 - private $sSelector;
53 + private $selector;
67 54
68 55 /**
69 - * @var int|null
56 + * @internal since V8.8.0
70 57 */
71 - private $iSpecificity;
58 + public static function isValid(string $selector): bool
59 + {
60 + // Note: We need to use `static::` here as the constant is overridden in the `KeyframeSelector` class.
61 + $numberOfMatches = CSSList::preg_match(static::SELECTOR_VALIDATION_RX, $selector);
72 62
73 - /**
74 - * @param string $sSelector
75 - *
76 - * @return bool
77 - */
78 - public static function isValid($sSelector)
79 - {
80 - return preg_match(static::SELECTOR_VALIDATION_RX, $sSelector);
63 + return $numberOfMatches === 1;
81 64 }
82 65
83 - /**
84 - * @param string $sSelector
85 - * @param bool $bCalculateSpecificity
86 - */
87 - public function __construct($sSelector, $bCalculateSpecificity = false)
66 + public function __construct(string $selector)
88 67 {
89 - $this->setSelector($sSelector);
90 - if ($bCalculateSpecificity) {
91 - $this->getSpecificity();
92 - }
68 + $this->setSelector($selector);
93 69 }
94 70
95 - /**
96 - * @return string
97 - */
98 - public function getSelector()
71 + public function getSelector(): string
99 72 {
100 - return $this->sSelector;
73 + return $this->selector;
101 74 }
102 75
103 - /**
104 - * @param string $sSelector
105 - *
106 - * @return void
107 - */
108 - public function setSelector($sSelector)
76 + public function setSelector(string $selector): void
109 77 {
110 - $this->sSelector = trim($sSelector);
111 - $this->iSpecificity = null;
78 + $this->selector = \trim($selector);
112 79 }
113 80
114 81 /**
115 - * @return string
82 + * @return int<0, max>
116 83 */
117 - public function __toString()
84 + public function getSpecificity(): int
118 85 {
119 - return $this->getSelector();
86 + return SpecificityCalculator::calculate($this->selector);
120 87 }
121 88
122 - /**
123 - * @return int
124 - */
125 - public function getSpecificity()
89 + public function render(OutputFormat $outputFormat): string
126 90 {
127 - if ($this->iSpecificity === null) {
128 - $a = 0;
129 - /// @todo should exclude \# as well as "#"
130 - $aMatches = null;
131 - $b = substr_count($this->sSelector, '#');
132 - $c = preg_match_all(self::NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX, $this->sSelector, $aMatches);
133 - $d = preg_match_all(self::ELEMENTS_AND_PSEUDO_ELEMENTS_RX, $this->sSelector, $aMatches);
134 - $this->iSpecificity = ($a * 1000) + ($b * 100) + ($c * 10) + $d;
135 - }
136 - return $this->iSpecificity;
91 + return $this->getSelector();
137 92 }
138 93 }