PluginProbe ʕ •ᴥ•ʔ
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress / trunk
Paid Membership Plugin, Ecommerce, User Registration Form, Login Form, User Profile & Restrict Content – ProfilePress vtrunk
4.17.2 4.17.1 4.17.0 4.16.19 4.16.18 4.16.17 4.16.16 trunk 1.0 1.0.1 1.0.2 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5a 1.1.6 1.1.7 1.2 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4 1.4.1 1.4.2 1.5 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.6 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.7 1.7.1 1.7.2 1.8 1.8.1 1.8.10 1.8.2 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9 1.9.1 1.9.10 1.9.11 1.9.12 1.9.13 1.9.2 1.9.3 1.9.4 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.1.9 2.2.10 2.2.11 2.2.12 2.2.13 2.2.14 2.2.15 2.2.16 2.2.2 2.2.5 2.2.6 2.2.7 2.2.8 2.2.9 3.0 3.1 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.10.0 4.10.1 4.10.2 4.10.3 4.11.0 4.12.0 4.13.0 4.13.1 4.13.2 4.13.3 4.13.4 4.14.0 4.14.1 4.14.2 4.14.3 4.14.4 4.15.0 4.15.1 4.15.10 4.15.11 4.15.12 4.15.13 4.15.14 4.15.15 4.15.16 4.15.17 4.15.18 4.15.19 4.15.2 4.15.20 4.15.20.1 4.15.21 4.15.22 4.15.23 4.15.24 4.15.25 4.15.3 4.15.4 4.15.5 4.15.6 4.15.7 4.15.8 4.15.9 4.16.0 4.16.1 4.16.10 4.16.11 4.16.12 4.16.13 4.16.14 4.16.15 4.16.2 4.16.3 4.16.4 4.16.5 4.16.6 4.16.7 4.16.8 4.16.9 4.2.0 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.7.0 4.8.0 4.9.0
wp-user-avatar / third-party / vendor / pelago / emogrifier / src / Utilities / CssConcatenator.php
wp-user-avatar / third-party / vendor / pelago / emogrifier / src / Utilities Last commit date
ArrayIntersector.php 1 day ago CssConcatenator.php 1 day ago DeclarationBlockParser.php 1 day ago
CssConcatenator.php
162 lines
1 <?php
2
3 declare (strict_types=1);
4 namespace ProfilePressVendor\Pelago\Emogrifier\Utilities;
5
6 /**
7 * Facilitates building a CSS string by appending rule blocks one at a time, checking whether the media query,
8 * selectors, or declarations block are the same as those from the preceding block and combining blocks in such cases.
9 *
10 * Example:
11 *
12 * ```php
13 * $concatenator = new CssConcatenator();
14 * $concatenator->append(['body'], 'color: blue;');
15 * $concatenator->append(['body'], 'font-size: 16px;');
16 * $concatenator->append(['p'], 'margin: 1em 0;');
17 * $concatenator->append(['ul', 'ol'], 'margin: 1em 0;');
18 * $concatenator->append(['body'], 'font-size: 14px;', '@media screen and (max-width: 400px)');
19 * $concatenator->append(['ul', 'ol'], 'margin: 0.75em 0;', '@media screen and (max-width: 400px)');
20 * $css = $concatenator->getCss();
21 * ```
22 *
23 * `$css` (if unminified) would contain the following CSS:
24 *
25 * ```css
26 * body {
27 * color: blue;
28 * font-size: 16px;
29 * }
30 * p, ul, ol {
31 * margin: 1em 0;
32 * }
33 *
34 * @media screen and (max-width: 400px) {
35 * body {
36 * font-size: 14px;
37 * }
38 * ul, ol {
39 * margin: 0.75em 0;
40 * }
41 * }
42 * ```
43 *
44 * @internal
45 */
46 final class CssConcatenator
47 {
48 /**
49 * Array of media rules in order. Each element is an object with the following properties:
50 * - `media` - The media query string, e.g. `@media screen and (max-width:639px)`, or an empty string for
51 * rules not within a media query block;
52 * - `ruleBlocks` - Array of rule blocks in order, where each element is an object with the following properties:
53 * - `selectorsAsKeys` - Array whose keys are selectors for the rule block (values are of no significance);
54 * - `declarationsBlock` - The property declarations, e.g. `margin-top: 0.5em; padding: 0`.
55 *
56 * @var list<object{
57 * media: string,
58 * ruleBlocks: list<object{
59 * selectorsAsKeys: array<non-empty-string, array-key>,
60 * declarationsBlock: string
61 * }>
62 * }>
63 */
64 private $mediaRules = [];
65 /**
66 * Appends a declaration block to the CSS.
67 *
68 * @param array<array-key, string> $selectors
69 * array of selectors for the rule, e.g. `["ul", "ol", "p:first-child"]`
70 * @param string $declarationsBlock
71 * the property declarations, e.g. `margin-top: 0.5em; padding: 0`
72 * @param string $media
73 * the media query for the rule, e.g. `@media screen and (max-width:639px)`, or an empty string if none
74 */
75 public function append(array $selectors, string $declarationsBlock, string $media = ''): void
76 {
77 $selectorsAsKeys = \array_flip($selectors);
78 $mediaRule = $this->getOrCreateMediaRuleToAppendTo($media);
79 $ruleBlocks = $mediaRule->ruleBlocks;
80 $lastRuleBlock = \end($ruleBlocks);
81 $hasSameDeclarationsAsLastRule = \is_object($lastRuleBlock) && $declarationsBlock === $lastRuleBlock->declarationsBlock;
82 if ($hasSameDeclarationsAsLastRule) {
83 $lastRuleBlock->selectorsAsKeys += $selectorsAsKeys;
84 } else {
85 $lastRuleBlockSelectors = \is_object($lastRuleBlock) ? $lastRuleBlock->selectorsAsKeys : [];
86 $hasSameSelectorsAsLastRule = \is_object($lastRuleBlock) && self::hasEquivalentSelectors($selectorsAsKeys, $lastRuleBlockSelectors);
87 if ($hasSameSelectorsAsLastRule) {
88 $lastDeclarationsBlockWithoutSemicolon = \rtrim(\rtrim($lastRuleBlock->declarationsBlock), ';');
89 $lastRuleBlock->declarationsBlock = $lastDeclarationsBlockWithoutSemicolon . ';' . $declarationsBlock;
90 } else {
91 $mediaRule->ruleBlocks[] = (object) \compact('selectorsAsKeys', 'declarationsBlock');
92 }
93 }
94 }
95 public function getCss(): string
96 {
97 return \implode('', \array_map([self::class, 'getMediaRuleCss'], $this->mediaRules));
98 }
99 /**
100 * @param string $media The media query for rules to be appended, e.g. `@media screen and (max-width:639px)`,
101 * or an empty string if none.
102 *
103 * @return object{
104 * media: string,
105 * ruleBlocks: list<object{
106 * selectorsAsKeys: array<non-empty-string, array-key>,
107 * declarationsBlock: string
108 * }>
109 * }
110 */
111 private function getOrCreateMediaRuleToAppendTo(string $media): object
112 {
113 $lastMediaRule = \end($this->mediaRules);
114 if (\is_object($lastMediaRule) && $media === $lastMediaRule->media) {
115 return $lastMediaRule;
116 }
117 $newMediaRule = (object) ['media' => $media, 'ruleBlocks' => []];
118 $this->mediaRules[] = $newMediaRule;
119 return $newMediaRule;
120 }
121 /**
122 * Tests if two sets of selectors are equivalent (i.e. the same selectors, possibly in a different order).
123 *
124 * @param array<string, array-key> $selectorsAsKeys1
125 * array in which the selectors are the keys, and the values are of no significance
126 * @param array<string, array-key> $selectorsAsKeys2 another such array
127 */
128 private static function hasEquivalentSelectors(array $selectorsAsKeys1, array $selectorsAsKeys2): bool
129 {
130 return \count($selectorsAsKeys1) === \count($selectorsAsKeys2) && \count($selectorsAsKeys1) === \count($selectorsAsKeys1 + $selectorsAsKeys2);
131 }
132 /**
133 * @param object{
134 * media: string,
135 * ruleBlocks: array<int, object{
136 * selectorsAsKeys: array<string, array-key>,
137 * declarationsBlock: string
138 * }>
139 * } $mediaRule
140 */
141 private static function getMediaRuleCss(object $mediaRule): string
142 {
143 $ruleBlocks = $mediaRule->ruleBlocks;
144 $css = \implode('', \array_map([self::class, 'getRuleBlockCss'], $ruleBlocks));
145 $media = $mediaRule->media;
146 if ($media !== '') {
147 $css = $media . '{' . $css . '}';
148 }
149 return $css;
150 }
151 /**
152 * @param object{selectorsAsKeys: array<string, array-key>, declarationsBlock: string} $ruleBlock
153 */
154 private static function getRuleBlockCss(object $ruleBlock): string
155 {
156 $selectorsAsKeys = $ruleBlock->selectorsAsKeys;
157 $selectors = \array_keys($selectorsAsKeys);
158 $declarationsBlock = $ruleBlock->declarationsBlock;
159 return \implode(',', $selectors) . '{' . $declarationsBlock . '}';
160 }
161 }
162