PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.1
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.1
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/RuleSet/DeclarationBlock.php +0 -301 10.11.1 → 11.1.1 View file →
@@ -1,301 +1,0 @@
1 -<?php
2 -
3 -declare(strict_types=1);
4 -
5 -namespace AcyMailing\Libraries\Sabberworm\CSS\RuleSet;
6 -
7 -use AcyMailing\Libraries\Sabberworm\CSS\Comment\CommentContainer;
8 -use AcyMailing\Libraries\Sabberworm\CSS\CSSElement;
9 -use AcyMailing\Libraries\Sabberworm\CSS\CSSList\CSSList;
10 -use AcyMailing\Libraries\Sabberworm\CSS\CSSList\CSSListItem;
11 -use AcyMailing\Libraries\Sabberworm\CSS\CSSList\KeyFrame;
12 -use AcyMailing\Libraries\Sabberworm\CSS\OutputFormat;
13 -use AcyMailing\Libraries\Sabberworm\CSS\Parsing\OutputException;
14 -use AcyMailing\Libraries\Sabberworm\CSS\Parsing\ParserState;
15 -use AcyMailing\Libraries\Sabberworm\CSS\Parsing\UnexpectedEOFException;
16 -use AcyMailing\Libraries\Sabberworm\CSS\Parsing\UnexpectedTokenException;
17 -use AcyMailing\Libraries\Sabberworm\CSS\Position\Position;
18 -use AcyMailing\Libraries\Sabberworm\CSS\Position\Positionable;
19 -use AcyMailing\Libraries\Sabberworm\CSS\Property\KeyframeSelector;
20 -use AcyMailing\Libraries\Sabberworm\CSS\Property\Selector;
21 -use AcyMailing\Libraries\Sabberworm\CSS\Rule\Rule;
22 -
23 -/**
24 - * This class represents a `RuleSet` constrained by a `Selector`.
25 - *
26 - * It contains an array of selector objects (comma-separated in the CSS) as well as the rules to be applied to the
27 - * matching elements.
28 - *
29 - * Declaration blocks usually appear directly inside a `Document` or another `CSSList` (mostly a `MediaQuery`).
30 - *
31 - * Note that `CSSListItem` extends both `Commentable` and `Renderable`, so those interfaces must also be implemented.
32 - */
33 -class DeclarationBlock implements CSSElement, CSSListItem, Positionable, RuleContainer
34 -{
35 - use CommentContainer;
36 - use Position;
37 -
38 - /**
39 - * @var array<Selector|string>
40 - */
41 - private $selectors = [];
42 -
43 - /**
44 - * @var RuleSet
45 - */
46 - private $ruleSet;
47 -
48 - /**
49 - * @param int<1, max>|null $lineNumber
50 - */
51 - public function __construct(?int $lineNumber = null)
52 - {
53 - $this->ruleSet = new RuleSet($lineNumber);
54 - $this->setPosition($lineNumber);
55 - }
56 -
57 - /**
58 - * @throws UnexpectedTokenException
59 - * @throws UnexpectedEOFException
60 - *
61 - * @internal since V8.8.0
62 - */
63 - public static function parse(ParserState $parserState, ?CSSList $list = null): ?DeclarationBlock
64 - {
65 - $comments = [];
66 - $result = new DeclarationBlock($parserState->currentLine());
67 - try {
68 - $selectors = [];
69 - $selectorParts = [];
70 - $stringWrapperCharacter = null;
71 - $functionNestingLevel = 0;
72 - $consumedNextCharacter = false;
73 - static $stopCharacters = ['{', '}', '\'', '"', '(', ')', ','];
74 - do {
75 - if (!$consumedNextCharacter) {
76 - $selectorParts[] = $parserState->consume(1);
77 - }
78 - $selectorParts[] = $parserState->consumeUntil($stopCharacters, false, false, $comments);
79 - $nextCharacter = $parserState->peek();
80 - $consumedNextCharacter = false;
81 - switch ($nextCharacter) {
82 - case '\'':
83 - // The fallthrough is intentional.
84 - case '"':
85 - if (!\is_string($stringWrapperCharacter)) {
86 - $stringWrapperCharacter = $nextCharacter;
87 - } elseif ($stringWrapperCharacter === $nextCharacter) {
88 - if (\substr(\end($selectorParts), -1) !== '\\') {
89 - $stringWrapperCharacter = null;
90 - }
91 - }
92 - break;
93 - case '(':
94 - if (!\is_string($stringWrapperCharacter)) {
95 - ++$functionNestingLevel;
96 - }
97 - break;
98 - case ')':
99 - if (!\is_string($stringWrapperCharacter)) {
100 - if ($functionNestingLevel <= 0) {
101 - throw new UnexpectedTokenException('anything but', ')');
102 - }
103 - --$functionNestingLevel;
104 - }
105 - break;
106 - case ',':
107 - if (!\is_string($stringWrapperCharacter) && $functionNestingLevel === 0) {
108 - $selectors[] = \implode('', $selectorParts);
109 - $selectorParts = [];
110 - $parserState->consume(1);
111 - $consumedNextCharacter = true;
112 - }
113 - break;
114 - }
115 - } while (!\in_array($nextCharacter, ['{', '}'], true) || \is_string($stringWrapperCharacter));
116 - if ($functionNestingLevel !== 0) {
117 - throw new UnexpectedTokenException(')', $nextCharacter);
118 - }
119 - $selectors[] = \implode('', $selectorParts); // add final or only selector
120 - $result->setSelectors($selectors, $list);
121 - if ($parserState->comes('{')) {
122 - $parserState->consume(1);
123 - }
124 - } catch (UnexpectedTokenException $e) {
125 - if ($parserState->getSettings()->usesLenientParsing()) {
126 - if (!$parserState->comes('}')) {
127 - $parserState->consumeUntil('}', false, true);
128 - }
129 - return null;
130 - } else {
131 - throw $e;
132 - }
133 - }
134 - $result->setComments($comments);
135 -
136 - RuleSet::parseRuleSet($parserState, $result->getRuleSet());
137 -
138 - return $result;
139 - }
140 -
141 - /**
142 - * @param array<Selector|string>|string $selectors
143 - *
144 - * @throws UnexpectedTokenException
145 - */
146 - public function setSelectors($selectors, ?CSSList $list = null): void
147 - {
148 - if (\is_array($selectors)) {
149 - $this->selectors = $selectors;
150 - } else {
151 - $this->selectors = \explode(',', $selectors);
152 - }
153 - foreach ($this->selectors as $key => $selector) {
154 - if (!($selector instanceof Selector)) {
155 - if ($list === null || !($list instanceof KeyFrame)) {
156 - if (!Selector::isValid($selector)) {
157 - throw new UnexpectedTokenException(
158 - "Selector did not match '" . Selector::SELECTOR_VALIDATION_RX . "'.",
159 - $selector,
160 - 'custom'
161 - );
162 - }
163 - $this->selectors[$key] = new Selector($selector);
164 - } else {
165 - if (!KeyframeSelector::isValid($selector)) {
166 - throw new UnexpectedTokenException(
167 - "Selector did not match '" . KeyframeSelector::SELECTOR_VALIDATION_RX . "'.",
168 - $selector,
169 - 'custom'
170 - );
171 - }
172 - $this->selectors[$key] = new KeyframeSelector($selector);
173 - }
174 - }
175 - }
176 - }
177 -
178 - /**
179 - * Remove one of the selectors of the block.
180 - *
181 - * @param Selector|string $selectorToRemove
182 - */
183 - public function removeSelector($selectorToRemove): bool
184 - {
185 - if ($selectorToRemove instanceof Selector) {
186 - $selectorToRemove = $selectorToRemove->getSelector();
187 - }
188 - foreach ($this->selectors as $key => $selector) {
189 - if ($selector->getSelector() === $selectorToRemove) {
190 - unset($this->selectors[$key]);
191 - return true;
192 - }
193 - }
194 - return false;
195 - }
196 -
197 - /**
198 - * @return array<Selector>
199 - */
200 - public function getSelectors(): array
201 - {
202 - return $this->selectors;
203 - }
204 -
205 - public function getRuleSet(): RuleSet
206 - {
207 - return $this->ruleSet;
208 - }
209 -
210 - /**
211 - * @see RuleSet::addRule()
212 - */
213 - public function addRule(Rule $ruleToAdd, ?Rule $sibling = null): void
214 - {
215 - $this->ruleSet->addRule($ruleToAdd, $sibling);
216 - }
217 -
218 - /**
219 - * @see RuleSet::getRules()
220 - *
221 - * @return array<int<0, max>, Rule>
222 - */
223 - public function getRules(?string $searchPattern = null): array
224 - {
225 - return $this->ruleSet->getRules($searchPattern);
226 - }
227 -
228 - /**
229 - * @see RuleSet::setRules()
230 - *
231 - * @param array<Rule> $rules
232 - */
233 - public function setRules(array $rules): void
234 - {
235 - $this->ruleSet->setRules($rules);
236 - }
237 -
238 - /**
239 - * @see RuleSet::getRulesAssoc()
240 - *
241 - * @return array<string, Rule>
242 - */
243 - public function getRulesAssoc(?string $searchPattern = null): array
244 - {
245 - return $this->ruleSet->getRulesAssoc($searchPattern);
246 - }
247 -
248 - /**
249 - * @see RuleSet::removeRule()
250 - */
251 - public function removeRule(Rule $ruleToRemove): void
252 - {
253 - $this->ruleSet->removeRule($ruleToRemove);
254 - }
255 -
256 - /**
257 - * @see RuleSet::removeMatchingRules()
258 - */
259 - public function removeMatchingRules(string $searchPattern): void
260 - {
261 - $this->ruleSet->removeMatchingRules($searchPattern);
262 - }
263 -
264 - /**
265 - * @see RuleSet::removeAllRules()
266 - */
267 - public function removeAllRules(): void
268 - {
269 - $this->ruleSet->removeAllRules();
270 - }
271 -
272 - /**
273 - * @return non-empty-string
274 - *
275 - * @throws OutputException
276 - */
277 - public function render(OutputFormat $outputFormat): string
278 - {
279 - $formatter = $outputFormat->getFormatter();
280 - $result = $formatter->comments($this);
281 - if (\count($this->selectors) === 0) {
282 - // If all the selectors have been removed, this declaration block becomes invalid
283 - throw new OutputException(
284 - 'Attempt to print declaration block with missing selector',
285 - $this->getLineNumber()
286 - );
287 - }
288 - $result .= $outputFormat->getContentBeforeDeclarationBlock();
289 - $result .= $formatter->implode(
290 - $formatter->spaceBeforeSelectorSeparator() . ',' . $formatter->spaceAfterSelectorSeparator(),
291 - $this->selectors
292 - );
293 - $result .= $outputFormat->getContentAfterDeclarationBlockSelectors();
294 - $result .= $formatter->spaceBeforeOpeningBrace() . '{';
295 - $result .= $this->ruleSet->render($outputFormat);
296 - $result .= '}';
297 - $result .= $outputFormat->getContentAfterDeclarationBlock();
298 -
299 - return $result;
300 - }
301 -}