Merge branch 'MDL-81073' of https://github.com/paulholden/moodle
[moodle.git] / lib / php-css-parser / Property / Selector.php
blob70c9b2fd5c22d950b5bc55961d4ae7e38470f7ba
1 <?php
3 namespace Sabberworm\CSS\Property;
5 /**
6 * Class representing a single CSS selector. Selectors have to be split by the comma prior to being passed into this
7 * class.
8 */
9 class Selector
11 /**
12 * regexp for specificity calculations
14 * @var string
16 const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
17 (\.[\w]+) # classes
19 \[(\w+) # attributes
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
33 /ix';
35 /**
36 * regexp for specificity calculations
38 * @var string
40 const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
41 ((^|[\s\+\>\~]+)[\w]+ # elements
43 \:{1,2}( # pseudo-elements
44 after|before|first-letter|first-line|selection
46 /ix';
48 /**
49 * regexp for specificity calculations
51 * @var string
53 const SELECTOR_VALIDATION_RX = '/
55 (?:
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"]
61 /ux';
63 /**
64 * @var string
66 private $sSelector;
68 /**
69 * @var int|null
71 private $iSpecificity;
73 /**
74 * @param string $sSelector
76 * @return bool
78 public static function isValid($sSelector)
80 return preg_match(static::SELECTOR_VALIDATION_RX, $sSelector);
83 /**
84 * @param string $sSelector
85 * @param bool $bCalculateSpecificity
87 public function __construct($sSelector, $bCalculateSpecificity = false)
89 $this->setSelector($sSelector);
90 if ($bCalculateSpecificity) {
91 $this->getSpecificity();
95 /**
96 * @return string
98 public function getSelector()
100 return $this->sSelector;
104 * @param string $sSelector
106 * @return void
108 public function setSelector($sSelector)
110 $this->sSelector = trim($sSelector);
111 $this->iSpecificity = null;
115 * @return string
117 public function __toString()
119 return $this->getSelector();
123 * @return int
125 public function getSpecificity()
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;
136 return $this->iSpecificity;