PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.34.2
MailPoet – Newsletters, Email Marketing, and Automation v5.34.2
5.35.0 5.34.3 5.34.2 5.34.1 5.34.0 5.33.1 5.33.0 5.32.0 5.31.0 5.30.0 5.29.0 5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / sabberworm / php-css-parser / src / RuleSet / DeclarationBlock.php
mailpoet / vendor-prefixed / sabberworm / php-css-parser / src / RuleSet Last commit date
AtRuleSet.php 2 years ago DeclarationBlock.php 2 years ago RuleSet.php 8 months ago index.php 3 years ago
DeclarationBlock.php
565 lines
1 <?php
2 namespace MailPoetVendor\Sabberworm\CSS\RuleSet;
3 if (!defined('ABSPATH')) exit;
4 use MailPoetVendor\Sabberworm\CSS\CSSList\CSSList;
5 use MailPoetVendor\Sabberworm\CSS\CSSList\KeyFrame;
6 use MailPoetVendor\Sabberworm\CSS\OutputFormat;
7 use MailPoetVendor\Sabberworm\CSS\Parsing\OutputException;
8 use MailPoetVendor\Sabberworm\CSS\Parsing\ParserState;
9 use MailPoetVendor\Sabberworm\CSS\Parsing\UnexpectedEOFException;
10 use MailPoetVendor\Sabberworm\CSS\Parsing\UnexpectedTokenException;
11 use MailPoetVendor\Sabberworm\CSS\Property\KeyframeSelector;
12 use MailPoetVendor\Sabberworm\CSS\Property\Selector;
13 use MailPoetVendor\Sabberworm\CSS\Rule\Rule;
14 use MailPoetVendor\Sabberworm\CSS\Value\Color;
15 use MailPoetVendor\Sabberworm\CSS\Value\RuleValueList;
16 use MailPoetVendor\Sabberworm\CSS\Value\Size;
17 use MailPoetVendor\Sabberworm\CSS\Value\URL;
18 use MailPoetVendor\Sabberworm\CSS\Value\Value;
19 class DeclarationBlock extends RuleSet
20 {
21 private $aSelectors;
22 public function __construct($iLineNo = 0)
23 {
24 parent::__construct($iLineNo);
25 $this->aSelectors = [];
26 }
27 public static function parse(ParserState $oParserState, $oList = null)
28 {
29 $aComments = [];
30 $oResult = new DeclarationBlock($oParserState->currentLine());
31 try {
32 $aSelectorParts = [];
33 $sStringWrapperChar = \false;
34 do {
35 $aSelectorParts[] = $oParserState->consume(1) . $oParserState->consumeUntil(['{', '}', '\'', '"'], \false, \false, $aComments);
36 if (\in_array($oParserState->peek(), ['\'', '"']) && \substr(\end($aSelectorParts), -1) != "\\") {
37 if ($sStringWrapperChar === \false) {
38 $sStringWrapperChar = $oParserState->peek();
39 } elseif ($sStringWrapperChar == $oParserState->peek()) {
40 $sStringWrapperChar = \false;
41 }
42 }
43 } while (!\in_array($oParserState->peek(), ['{', '}']) || $sStringWrapperChar !== \false);
44 $oResult->setSelectors(\implode('', $aSelectorParts), $oList);
45 if ($oParserState->comes('{')) {
46 $oParserState->consume(1);
47 }
48 } catch (UnexpectedTokenException $e) {
49 if ($oParserState->getSettings()->bLenientParsing) {
50 if (!$oParserState->comes('}')) {
51 $oParserState->consumeUntil('}', \false, \true);
52 }
53 return \false;
54 } else {
55 throw $e;
56 }
57 }
58 $oResult->setComments($aComments);
59 RuleSet::parseRuleSet($oParserState, $oResult);
60 return $oResult;
61 }
62 public function setSelectors($mSelector, $oList = null)
63 {
64 if (\is_array($mSelector)) {
65 $this->aSelectors = $mSelector;
66 } else {
67 $this->aSelectors = \explode(',', $mSelector);
68 }
69 foreach ($this->aSelectors as $iKey => $mSelector) {
70 if (!$mSelector instanceof Selector) {
71 if ($oList === null || !$oList instanceof KeyFrame) {
72 if (!Selector::isValid($mSelector)) {
73 throw new UnexpectedTokenException("Selector did not match '" . Selector::SELECTOR_VALIDATION_RX . "'.", $mSelector, "custom");
74 }
75 $this->aSelectors[$iKey] = new Selector($mSelector);
76 } else {
77 if (!KeyframeSelector::isValid($mSelector)) {
78 throw new UnexpectedTokenException("Selector did not match '" . KeyframeSelector::SELECTOR_VALIDATION_RX . "'.", $mSelector, "custom");
79 }
80 $this->aSelectors[$iKey] = new KeyframeSelector($mSelector);
81 }
82 }
83 }
84 }
85 public function removeSelector($mSelector)
86 {
87 if ($mSelector instanceof Selector) {
88 $mSelector = $mSelector->getSelector();
89 }
90 foreach ($this->aSelectors as $iKey => $oSelector) {
91 if ($oSelector->getSelector() === $mSelector) {
92 unset($this->aSelectors[$iKey]);
93 return \true;
94 }
95 }
96 return \false;
97 }
98 public function getSelector()
99 {
100 return $this->getSelectors();
101 }
102 public function setSelector($mSelector, $oList = null)
103 {
104 $this->setSelectors($mSelector, $oList);
105 }
106 public function getSelectors()
107 {
108 return $this->aSelectors;
109 }
110 public function expandShorthands()
111 {
112 // border must be expanded before dimensions
113 $this->expandBorderShorthand();
114 $this->expandDimensionsShorthand();
115 $this->expandFontShorthand();
116 $this->expandBackgroundShorthand();
117 $this->expandListStyleShorthand();
118 }
119 public function createShorthands()
120 {
121 $this->createBackgroundShorthand();
122 $this->createDimensionsShorthand();
123 // border must be shortened after dimensions
124 $this->createBorderShorthand();
125 $this->createFontShorthand();
126 $this->createListStyleShorthand();
127 }
128 public function expandBorderShorthand()
129 {
130 $aBorderRules = ['border', 'border-left', 'border-right', 'border-top', 'border-bottom'];
131 $aBorderSizes = ['thin', 'medium', 'thick'];
132 $aRules = $this->getRulesAssoc();
133 foreach ($aBorderRules as $sBorderRule) {
134 if (!isset($aRules[$sBorderRule])) {
135 continue;
136 }
137 $oRule = $aRules[$sBorderRule];
138 $mRuleValue = $oRule->getValue();
139 $aValues = [];
140 if (!$mRuleValue instanceof RuleValueList) {
141 $aValues[] = $mRuleValue;
142 } else {
143 $aValues = $mRuleValue->getListComponents();
144 }
145 foreach ($aValues as $mValue) {
146 if ($mValue instanceof Value) {
147 $mNewValue = clone $mValue;
148 } else {
149 $mNewValue = $mValue;
150 }
151 if ($mValue instanceof Size) {
152 $sNewRuleName = $sBorderRule . "-width";
153 } elseif ($mValue instanceof Color) {
154 $sNewRuleName = $sBorderRule . "-color";
155 } else {
156 if (\in_array($mValue, $aBorderSizes)) {
157 $sNewRuleName = $sBorderRule . "-width";
158 } else {
159 $sNewRuleName = $sBorderRule . "-style";
160 }
161 }
162 $oNewRule = new Rule($sNewRuleName, $oRule->getLineNo(), $oRule->getColNo());
163 $oNewRule->setIsImportant($oRule->getIsImportant());
164 $oNewRule->addValue([$mNewValue]);
165 $this->addRule($oNewRule);
166 }
167 $this->removeRule($sBorderRule);
168 }
169 }
170 public function expandDimensionsShorthand()
171 {
172 $aExpansions = ['margin' => 'margin-%s', 'padding' => 'padding-%s', 'border-color' => 'border-%s-color', 'border-style' => 'border-%s-style', 'border-width' => 'border-%s-width'];
173 $aRules = $this->getRulesAssoc();
174 foreach ($aExpansions as $sProperty => $sExpanded) {
175 if (!isset($aRules[$sProperty])) {
176 continue;
177 }
178 $oRule = $aRules[$sProperty];
179 $mRuleValue = $oRule->getValue();
180 $aValues = [];
181 if (!$mRuleValue instanceof RuleValueList) {
182 $aValues[] = $mRuleValue;
183 } else {
184 $aValues = $mRuleValue->getListComponents();
185 }
186 $top = $right = $bottom = $left = null;
187 switch (\count($aValues)) {
188 case 1:
189 $top = $right = $bottom = $left = $aValues[0];
190 break;
191 case 2:
192 $top = $bottom = $aValues[0];
193 $left = $right = $aValues[1];
194 break;
195 case 3:
196 $top = $aValues[0];
197 $left = $right = $aValues[1];
198 $bottom = $aValues[2];
199 break;
200 case 4:
201 $top = $aValues[0];
202 $right = $aValues[1];
203 $bottom = $aValues[2];
204 $left = $aValues[3];
205 break;
206 }
207 foreach (['top', 'right', 'bottom', 'left'] as $sPosition) {
208 $oNewRule = new Rule(\sprintf($sExpanded, $sPosition), $oRule->getLineNo(), $oRule->getColNo());
209 $oNewRule->setIsImportant($oRule->getIsImportant());
210 $oNewRule->addValue(${$sPosition});
211 $this->addRule($oNewRule);
212 }
213 $this->removeRule($sProperty);
214 }
215 }
216 public function expandFontShorthand()
217 {
218 $aRules = $this->getRulesAssoc();
219 if (!isset($aRules['font'])) {
220 return;
221 }
222 $oRule = $aRules['font'];
223 // reset properties to 'normal' per http://www.w3.org/TR/21/fonts.html#font-shorthand
224 $aFontProperties = ['font-style' => 'normal', 'font-variant' => 'normal', 'font-weight' => 'normal', 'font-size' => 'normal', 'line-height' => 'normal'];
225 $mRuleValue = $oRule->getValue();
226 $aValues = [];
227 if (!$mRuleValue instanceof RuleValueList) {
228 $aValues[] = $mRuleValue;
229 } else {
230 $aValues = $mRuleValue->getListComponents();
231 }
232 foreach ($aValues as $mValue) {
233 if (!$mValue instanceof Value) {
234 $mValue = \mb_strtolower($mValue);
235 }
236 if (\in_array($mValue, ['normal', 'inherit'])) {
237 foreach (['font-style', 'font-weight', 'font-variant'] as $sProperty) {
238 if (!isset($aFontProperties[$sProperty])) {
239 $aFontProperties[$sProperty] = $mValue;
240 }
241 }
242 } elseif (\in_array($mValue, ['italic', 'oblique'])) {
243 $aFontProperties['font-style'] = $mValue;
244 } elseif ($mValue == 'small-caps') {
245 $aFontProperties['font-variant'] = $mValue;
246 } elseif (\in_array($mValue, ['bold', 'bolder', 'lighter']) || $mValue instanceof Size && \in_array($mValue->getSize(), \range(100, 900, 100))) {
247 $aFontProperties['font-weight'] = $mValue;
248 } elseif ($mValue instanceof RuleValueList && $mValue->getListSeparator() == '/') {
249 list($oSize, $oHeight) = $mValue->getListComponents();
250 $aFontProperties['font-size'] = $oSize;
251 $aFontProperties['line-height'] = $oHeight;
252 } elseif ($mValue instanceof Size && $mValue->getUnit() !== null) {
253 $aFontProperties['font-size'] = $mValue;
254 } else {
255 $aFontProperties['font-family'] = $mValue;
256 }
257 }
258 foreach ($aFontProperties as $sProperty => $mValue) {
259 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
260 $oNewRule->addValue($mValue);
261 $oNewRule->setIsImportant($oRule->getIsImportant());
262 $this->addRule($oNewRule);
263 }
264 $this->removeRule('font');
265 }
266 public function expandBackgroundShorthand()
267 {
268 $aRules = $this->getRulesAssoc();
269 if (!isset($aRules['background'])) {
270 return;
271 }
272 $oRule = $aRules['background'];
273 $aBgProperties = ['background-color' => ['transparent'], 'background-image' => ['none'], 'background-repeat' => ['repeat'], 'background-attachment' => ['scroll'], 'background-position' => [new Size(0, '%', null, \false, $this->iLineNo), new Size(0, '%', null, \false, $this->iLineNo)]];
274 $mRuleValue = $oRule->getValue();
275 $aValues = [];
276 if (!$mRuleValue instanceof RuleValueList) {
277 $aValues[] = $mRuleValue;
278 } else {
279 $aValues = $mRuleValue->getListComponents();
280 }
281 if (\count($aValues) == 1 && $aValues[0] == 'inherit') {
282 foreach ($aBgProperties as $sProperty => $mValue) {
283 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
284 $oNewRule->addValue('inherit');
285 $oNewRule->setIsImportant($oRule->getIsImportant());
286 $this->addRule($oNewRule);
287 }
288 $this->removeRule('background');
289 return;
290 }
291 $iNumBgPos = 0;
292 foreach ($aValues as $mValue) {
293 if (!$mValue instanceof Value) {
294 $mValue = \mb_strtolower($mValue);
295 }
296 if ($mValue instanceof URL) {
297 $aBgProperties['background-image'] = $mValue;
298 } elseif ($mValue instanceof Color) {
299 $aBgProperties['background-color'] = $mValue;
300 } elseif (\in_array($mValue, ['scroll', 'fixed'])) {
301 $aBgProperties['background-attachment'] = $mValue;
302 } elseif (\in_array($mValue, ['repeat', 'no-repeat', 'repeat-x', 'repeat-y'])) {
303 $aBgProperties['background-repeat'] = $mValue;
304 } elseif (\in_array($mValue, ['left', 'center', 'right', 'top', 'bottom']) || $mValue instanceof Size) {
305 if ($iNumBgPos == 0) {
306 $aBgProperties['background-position'][0] = $mValue;
307 $aBgProperties['background-position'][1] = 'center';
308 } else {
309 $aBgProperties['background-position'][$iNumBgPos] = $mValue;
310 }
311 $iNumBgPos++;
312 }
313 }
314 foreach ($aBgProperties as $sProperty => $mValue) {
315 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
316 $oNewRule->setIsImportant($oRule->getIsImportant());
317 $oNewRule->addValue($mValue);
318 $this->addRule($oNewRule);
319 }
320 $this->removeRule('background');
321 }
322 public function expandListStyleShorthand()
323 {
324 $aListProperties = ['list-style-type' => 'disc', 'list-style-position' => 'outside', 'list-style-image' => 'none'];
325 $aListStyleTypes = ['none', 'disc', 'circle', 'square', 'decimal-leading-zero', 'decimal', 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', 'upper-alpha', 'upper-latin', 'hebrew', 'armenian', 'georgian', 'cjk-ideographic', 'hiragana', 'hira-gana-iroha', 'katakana-iroha', 'katakana'];
326 $aListStylePositions = ['inside', 'outside'];
327 $aRules = $this->getRulesAssoc();
328 if (!isset($aRules['list-style'])) {
329 return;
330 }
331 $oRule = $aRules['list-style'];
332 $mRuleValue = $oRule->getValue();
333 $aValues = [];
334 if (!$mRuleValue instanceof RuleValueList) {
335 $aValues[] = $mRuleValue;
336 } else {
337 $aValues = $mRuleValue->getListComponents();
338 }
339 if (\count($aValues) == 1 && $aValues[0] == 'inherit') {
340 foreach ($aListProperties as $sProperty => $mValue) {
341 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
342 $oNewRule->addValue('inherit');
343 $oNewRule->setIsImportant($oRule->getIsImportant());
344 $this->addRule($oNewRule);
345 }
346 $this->removeRule('list-style');
347 return;
348 }
349 foreach ($aValues as $mValue) {
350 if (!$mValue instanceof Value) {
351 $mValue = \mb_strtolower($mValue);
352 }
353 if ($mValue instanceof Url) {
354 $aListProperties['list-style-image'] = $mValue;
355 } elseif (\in_array($mValue, $aListStyleTypes)) {
356 $aListProperties['list-style-types'] = $mValue;
357 } elseif (\in_array($mValue, $aListStylePositions)) {
358 $aListProperties['list-style-position'] = $mValue;
359 }
360 }
361 foreach ($aListProperties as $sProperty => $mValue) {
362 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
363 $oNewRule->setIsImportant($oRule->getIsImportant());
364 $oNewRule->addValue($mValue);
365 $this->addRule($oNewRule);
366 }
367 $this->removeRule('list-style');
368 }
369 public function createShorthandProperties(array $aProperties, $sShorthand)
370 {
371 $aRules = $this->getRulesAssoc();
372 $oRule = null;
373 $aNewValues = [];
374 foreach ($aProperties as $sProperty) {
375 if (!isset($aRules[$sProperty])) {
376 continue;
377 }
378 $oRule = $aRules[$sProperty];
379 if (!$oRule->getIsImportant()) {
380 $mRuleValue = $oRule->getValue();
381 $aValues = [];
382 if (!$mRuleValue instanceof RuleValueList) {
383 $aValues[] = $mRuleValue;
384 } else {
385 $aValues = $mRuleValue->getListComponents();
386 }
387 foreach ($aValues as $mValue) {
388 $aNewValues[] = $mValue;
389 }
390 $this->removeRule($sProperty);
391 }
392 }
393 if ($aNewValues !== [] && $oRule instanceof Rule) {
394 $oNewRule = new Rule($sShorthand, $oRule->getLineNo(), $oRule->getColNo());
395 foreach ($aNewValues as $mValue) {
396 $oNewRule->addValue($mValue);
397 }
398 $this->addRule($oNewRule);
399 }
400 }
401 public function createBackgroundShorthand()
402 {
403 $aProperties = ['background-color', 'background-image', 'background-repeat', 'background-position', 'background-attachment'];
404 $this->createShorthandProperties($aProperties, 'background');
405 }
406 public function createListStyleShorthand()
407 {
408 $aProperties = ['list-style-type', 'list-style-position', 'list-style-image'];
409 $this->createShorthandProperties($aProperties, 'list-style');
410 }
411 public function createBorderShorthand()
412 {
413 $aProperties = ['border-width', 'border-style', 'border-color'];
414 $this->createShorthandProperties($aProperties, 'border');
415 }
416 public function createDimensionsShorthand()
417 {
418 $aPositions = ['top', 'right', 'bottom', 'left'];
419 $aExpansions = ['margin' => 'margin-%s', 'padding' => 'padding-%s', 'border-color' => 'border-%s-color', 'border-style' => 'border-%s-style', 'border-width' => 'border-%s-width'];
420 $aRules = $this->getRulesAssoc();
421 foreach ($aExpansions as $sProperty => $sExpanded) {
422 $aFoldable = [];
423 foreach ($aRules as $sRuleName => $oRule) {
424 foreach ($aPositions as $sPosition) {
425 if ($sRuleName == \sprintf($sExpanded, $sPosition)) {
426 $aFoldable[$sRuleName] = $oRule;
427 }
428 }
429 }
430 // All four dimensions must be present
431 if (\count($aFoldable) == 4) {
432 $aValues = [];
433 foreach ($aPositions as $sPosition) {
434 $oRule = $aRules[\sprintf($sExpanded, $sPosition)];
435 $mRuleValue = $oRule->getValue();
436 $aRuleValues = [];
437 if (!$mRuleValue instanceof RuleValueList) {
438 $aRuleValues[] = $mRuleValue;
439 } else {
440 $aRuleValues = $mRuleValue->getListComponents();
441 }
442 $aValues[$sPosition] = $aRuleValues;
443 }
444 $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
445 if ((string) $aValues['left'][0] == (string) $aValues['right'][0]) {
446 if ((string) $aValues['top'][0] == (string) $aValues['bottom'][0]) {
447 if ((string) $aValues['top'][0] == (string) $aValues['left'][0]) {
448 // All 4 sides are equal
449 $oNewRule->addValue($aValues['top']);
450 } else {
451 // Top and bottom are equal, left and right are equal
452 $oNewRule->addValue($aValues['top']);
453 $oNewRule->addValue($aValues['left']);
454 }
455 } else {
456 // Only left and right are equal
457 $oNewRule->addValue($aValues['top']);
458 $oNewRule->addValue($aValues['left']);
459 $oNewRule->addValue($aValues['bottom']);
460 }
461 } else {
462 // No sides are equal
463 $oNewRule->addValue($aValues['top']);
464 $oNewRule->addValue($aValues['left']);
465 $oNewRule->addValue($aValues['bottom']);
466 $oNewRule->addValue($aValues['right']);
467 }
468 $this->addRule($oNewRule);
469 foreach ($aPositions as $sPosition) {
470 $this->removeRule(\sprintf($sExpanded, $sPosition));
471 }
472 }
473 }
474 }
475 public function createFontShorthand()
476 {
477 $aFontProperties = ['font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family'];
478 $aRules = $this->getRulesAssoc();
479 if (!isset($aRules['font-size']) || !isset($aRules['font-family'])) {
480 return;
481 }
482 $oOldRule = isset($aRules['font-size']) ? $aRules['font-size'] : $aRules['font-family'];
483 $oNewRule = new Rule('font', $oOldRule->getLineNo(), $oOldRule->getColNo());
484 unset($oOldRule);
485 foreach (['font-style', 'font-variant', 'font-weight'] as $sProperty) {
486 if (isset($aRules[$sProperty])) {
487 $oRule = $aRules[$sProperty];
488 $mRuleValue = $oRule->getValue();
489 $aValues = [];
490 if (!$mRuleValue instanceof RuleValueList) {
491 $aValues[] = $mRuleValue;
492 } else {
493 $aValues = $mRuleValue->getListComponents();
494 }
495 if ($aValues[0] !== 'normal') {
496 $oNewRule->addValue($aValues[0]);
497 }
498 }
499 }
500 // Get the font-size value
501 $oRule = $aRules['font-size'];
502 $mRuleValue = $oRule->getValue();
503 $aFSValues = [];
504 if (!$mRuleValue instanceof RuleValueList) {
505 $aFSValues[] = $mRuleValue;
506 } else {
507 $aFSValues = $mRuleValue->getListComponents();
508 }
509 // But wait to know if we have line-height to add it
510 if (isset($aRules['line-height'])) {
511 $oRule = $aRules['line-height'];
512 $mRuleValue = $oRule->getValue();
513 $aLHValues = [];
514 if (!$mRuleValue instanceof RuleValueList) {
515 $aLHValues[] = $mRuleValue;
516 } else {
517 $aLHValues = $mRuleValue->getListComponents();
518 }
519 if ($aLHValues[0] !== 'normal') {
520 $val = new RuleValueList('/', $this->iLineNo);
521 $val->addListComponent($aFSValues[0]);
522 $val->addListComponent($aLHValues[0]);
523 $oNewRule->addValue($val);
524 }
525 } else {
526 $oNewRule->addValue($aFSValues[0]);
527 }
528 $oRule = $aRules['font-family'];
529 $mRuleValue = $oRule->getValue();
530 $aFFValues = [];
531 if (!$mRuleValue instanceof RuleValueList) {
532 $aFFValues[] = $mRuleValue;
533 } else {
534 $aFFValues = $mRuleValue->getListComponents();
535 }
536 $oFFValue = new RuleValueList(',', $this->iLineNo);
537 $oFFValue->setListComponents($aFFValues);
538 $oNewRule->addValue($oFFValue);
539 $this->addRule($oNewRule);
540 foreach ($aFontProperties as $sProperty) {
541 $this->removeRule($sProperty);
542 }
543 }
544 public function __toString()
545 {
546 return $this->render(new OutputFormat());
547 }
548 public function render(OutputFormat $oOutputFormat)
549 {
550 $sResult = $oOutputFormat->comments($this);
551 if (\count($this->aSelectors) === 0) {
552 // If all the selectors have been removed, this declaration block becomes invalid
553 throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo);
554 }
555 $sResult .= $oOutputFormat->sBeforeDeclarationBlock;
556 $sResult .= $oOutputFormat->implode($oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors);
557 $sResult .= $oOutputFormat->sAfterDeclarationBlockSelectors;
558 $sResult .= $oOutputFormat->spaceBeforeOpeningBrace() . '{';
559 $sResult .= $this->renderRules($oOutputFormat);
560 $sResult .= '}';
561 $sResult .= $oOutputFormat->sAfterDeclarationBlock;
562 return $sResult;
563 }
564 }
565