PluginProbe
Elementor Website Builder – more than just a page builder / 4.2.4
Elementor Website Builder – more than just a page builder v4.2.4
4.3.0-beta2 4.3.0-beta1 4.2.4 4.2.3 4.2.2 4.2.1 4.2.0 4.1.5 4.2.0-beta2 4.2.0-dev2 4.2.0-beta1 4.1.4 4.1.3 4.1.2 4.1.1 4.1.0 4.1.0-beta3 4.1.0-dev3 4.0.9 4.1.0-beta2 4.1.0-dev2 4.0.8 4.1.0-beta1 4.1.0-dev1 4.0.7 All 451 releases
elementor / includes / stylesheet.php

stylesheet.php in Elementor Website Builder – more than just a page builder 4.2.4, at includes/stylesheet.php

415 lines 8.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace Elementor;
3
4 if ( ! defined( 'ABSPATH' ) ) {
5 exit; // Exit if accessed directly.
6 }
7
8 /**
9 * Elementor stylesheet.
10 *
11 * Elementor stylesheet handler class responsible for setting up CSS rules and
12 * properties, and all the CSS `@media` rule with supported viewport width.
13 *
14 * @since 1.0.0
15 */
16 class Stylesheet {
17
18 /**
19 * CSS Rules.
20 *
21 * Holds the list of CSS rules.
22 *
23 * @since 1.0.0
24 * @access private
25 *
26 * @var array A list of CSS rules.
27 */
28 private $rules = [];
29
30 /**
31 * Devices.
32 *
33 * Holds the list of devices.
34 *
35 * @since 1.0.0
36 * @access private
37 *
38 * @var array A list of devices.
39 */
40 private $devices = [];
41
42 /**
43 * Raw CSS.
44 *
45 * Holds the raw CSS.
46 *
47 * @since 1.0.0
48 * @access private
49 *
50 * @var array The raw CSS.
51 */
52 private $raw = [];
53
54 /**
55 * Parse CSS rules.
56 *
57 * Goes over the list of CSS rules and generates the final CSS.
58 *
59 * @since 1.0.0
60 * @access public
61 * @static
62 *
63 * @param array $rules CSS rules.
64 *
65 * @return string Parsed rules.
66 */
67 public static function parse_rules( array $rules ) {
68 $parsed_rules = '';
69
70 foreach ( $rules as $selector => $properties ) {
71 $selector_content = self::parse_properties( $properties );
72
73 if ( $selector_content ) {
74 $parsed_rules .= $selector . '{' . $selector_content . '}';
75 }
76 }
77
78 return $parsed_rules;
79 }
80
81 /**
82 * Parse CSS properties.
83 *
84 * Goes over the selector properties and generates the CSS of the selector.
85 *
86 * @since 1.0.0
87 * @access public
88 * @static
89 *
90 * @param array $properties CSS properties.
91 *
92 * @return string Parsed properties.
93 */
94 public static function parse_properties( array $properties ) {
95 $parsed_properties = '';
96
97 foreach ( $properties as $property_key => $property_value ) {
98 if ( '' !== $property_value ) {
99 $parsed_properties .= $property_key . ':' . $property_value . ';';
100 }
101 }
102
103 return $parsed_properties;
104 }
105
106 /**
107 * Add device.
108 *
109 * Add a new device to the devices list.
110 *
111 * @since 1.0.0
112 * @access public
113 *
114 * @param string $device_name Device name.
115 * @param string $device_max_point Device maximum point.
116 *
117 * @return Stylesheet The current stylesheet class instance.
118 */
119 public function add_device( $device_name, $device_max_point ) {
120 $this->devices[ $device_name ] = $device_max_point;
121
122 asort( $this->devices );
123
124 return $this;
125 }
126
127 /**
128 * Add rules.
129 *
130 * Add a new CSS rule to the rules list.
131 *
132 * @since 1.0.0
133 * @access public
134 *
135 * @param string $selector CSS selector.
136 * @param array|string $style_rules Optional. Style rules. Default is `null`.
137 * @param array $query Optional. Media query. Default is `null`.
138 *
139 * @return Stylesheet The current stylesheet class instance.
140 */
141 public function add_rules( $selector, $style_rules = null, ?array $query = null ) {
142 $query_hash = 'all';
143
144 if ( $query ) {
145 $query_hash = $this->query_to_hash( $query );
146 }
147
148 if ( ! isset( $this->rules[ $query_hash ] ) ) {
149 $this->add_query_hash( $query_hash );
150 }
151
152 if ( null === $style_rules ) {
153 preg_match_all( '/([^\s].+?(?=\{))\{((?s:.)+?(?=}))}/', $selector, $parsed_rules );
154
155 foreach ( $parsed_rules[1] as $index => $selector ) {
156 $this->add_rules( $selector, $parsed_rules[2][ $index ], $query );
157 }
158
159 return $this;
160 }
161
162 if ( ! isset( $this->rules[ $query_hash ][ $selector ] ) ) {
163 $this->rules[ $query_hash ][ $selector ] = [];
164 }
165
166 if ( is_string( $style_rules ) ) {
167 $style_rules = array_filter( explode( ';', trim( $style_rules ) ) );
168
169 $ordered_rules = [];
170
171 foreach ( $style_rules as $rule ) {
172 $property = explode( ':', $rule, 2 );
173
174 if ( count( $property ) < 2 ) {
175 return $this;
176 }
177
178 $ordered_rules[ trim( $property[0] ) ] = trim( $property[1], ' ;' );
179 }
180
181 $style_rules = $ordered_rules;
182 }
183
184 $this->rules[ $query_hash ][ $selector ] = array_merge( $this->rules[ $query_hash ][ $selector ], $style_rules );
185
186 return $this;
187 }
188
189 /**
190 * Add raw CSS.
191 *
192 * Add a raw CSS rule.
193 *
194 * @since 1.0.8
195 * @access public
196 *
197 * @param string $css The raw CSS.
198 * @param string $device Optional. The device. Default is empty.
199 *
200 * @return Stylesheet The current stylesheet class instance.
201 */
202 public function add_raw_css( $css, $device = '' ) {
203 if ( ! isset( $this->raw[ $device ] ) ) {
204 $this->raw[ $device ] = [];
205 }
206
207 $this->raw[ $device ][] = trim( $css );
208
209 return $this;
210 }
211
212 /**
213 * Get CSS rules.
214 *
215 * Retrieve the CSS rules.
216 *
217 * @since 1.0.5
218 * @access public
219 *
220 * @param string $device Optional. The device. Default is empty.
221 * @param string $selector Optional. CSS selector. Default is empty.
222 * @param string $property Optional. CSS property. Default is empty.
223 *
224 * @return null|array CSS rules, or `null` if not rules found.
225 */
226 public function get_rules( $device = null, $selector = null, $property = null ) {
227 if ( ! $device ) {
228 return $this->rules;
229 }
230
231 if ( $property ) {
232 return isset( $this->rules[ $device ][ $selector ][ $property ] ) ? $this->rules[ $device ][ $selector ][ $property ] : null;
233 }
234
235 if ( $selector ) {
236 return isset( $this->rules[ $device ][ $selector ] ) ? $this->rules[ $device ][ $selector ] : null;
237 }
238
239 return isset( $this->rules[ $device ] ) ? $this->rules[ $device ] : null;
240 }
241
242 /**
243 * To string.
244 *
245 * This magic method responsible for parsing the rules into one CSS string.
246 *
247 * @since 1.0.0
248 * @access public
249 *
250 * @return string CSS style.
251 */
252 public function __toString() {
253 $style_text = '';
254
255 foreach ( $this->rules as $query_hash => $rule ) {
256 $device_text = self::parse_rules( $rule );
257
258 if ( 'all' !== $query_hash ) {
259 $device_text = $this->get_query_hash_style_format( $query_hash ) . '{' . $device_text . '}';
260 }
261
262 $style_text .= $device_text;
263 }
264
265 foreach ( $this->raw as $device_name => $raw ) {
266 $raw = implode( "\n", $raw );
267
268 if ( $raw && isset( $this->devices[ $device_name ] ) ) {
269 $raw = '@media(max-width: ' . $this->devices[ $device_name ] . 'px){' . $raw . '}';
270 }
271
272 $style_text .= $raw;
273 }
274
275 return $style_text;
276 }
277
278 /**
279 * Query to hash.
280 *
281 * Turns the media query into a hashed string that represents the query
282 * endpoint in the rules list.
283 *
284 * @since 1.2.0
285 * @access private
286 *
287 * @param array $query CSS media query.
288 *
289 * @return string Hashed string of the query.
290 */
291 private function query_to_hash( array $query ) {
292 $hash = [];
293
294 foreach ( $query as $endpoint => $value ) {
295 $hash[] = $endpoint . '_' . $value;
296 }
297
298 return implode( '-', $hash );
299 }
300
301 /**
302 * Hash to query.
303 *
304 * Turns the hashed string to an array that contains the data of the query
305 * endpoint.
306 *
307 * @since 1.2.0
308 * @access private
309 *
310 * @param string $hash Hashed string of the query.
311 *
312 * @return array Media query data.
313 */
314 private function hash_to_query( $hash ) {
315 $query = [];
316
317 $hash = array_filter( explode( '-', $hash ) );
318
319 foreach ( $hash as $single_query ) {
320 preg_match( '/(min|max)_(.*)/', $single_query, $query_parts );
321
322 $end_point = $query_parts[1];
323
324 $device_name = $query_parts[2];
325
326 $query[ $end_point ] = 'max' === $end_point ? $this->devices[ $device_name ] : Plugin::$instance->breakpoints->get_device_min_breakpoint( $device_name );
327 }
328
329 return $query;
330 }
331
332 /**
333 * Add query hash.
334 *
335 * Register new endpoint query and sort the rules the way they should be
336 * displayed in the final stylesheet based on the device and the viewport
337 * width.
338 *
339 * @since 1.2.0
340 * @access private
341 *
342 * @param string $query_hash Hashed string of the query.
343 */
344 private function add_query_hash( $query_hash ) {
345 $this->rules[ $query_hash ] = [];
346
347 uksort(
348 $this->rules, function( $a, $b ) {
349 if ( 'all' === $a ) {
350 return -1;
351 }
352
353 if ( 'all' === $b ) {
354 return 1;
355 }
356
357 $a_query = $this->hash_to_query( $a );
358
359 $b_query = $this->hash_to_query( $b );
360
361 if ( isset( $a_query['min'] ) xor isset( $b_query['min'] ) ) {
362 return 1;
363 }
364
365 if ( isset( $a_query['min'] ) ) {
366 $range = $a_query['min'] - $b_query['min'];
367
368 if ( $range ) {
369 return $range;
370 }
371
372 $a_has_max = isset( $a_query['max'] );
373
374 if ( $a_has_max xor isset( $b_query['max'] ) ) {
375 return $a_has_max ? 1 : -1;
376 }
377
378 if ( ! $a_has_max ) {
379 return 0;
380 }
381 }
382
383 return $b_query['max'] - $a_query['max'];
384 }
385 );
386 }
387
388 /**
389 * Get query hash style format.
390 *
391 * Retrieve formatted media query rule with the endpoint width settings.
392 *
393 * The method returns the CSS `@media` rule and supported viewport width in
394 * pixels. It can also handle multiple width endpoints.
395 *
396 * @since 1.2.0
397 * @access private
398 *
399 * @param string $query_hash The hash of the query.
400 *
401 * @return string CSS media query.
402 */
403 private function get_query_hash_style_format( $query_hash ) {
404 $query = $this->hash_to_query( $query_hash );
405
406 $style_format = [];
407
408 foreach ( $query as $end_point => $value ) {
409 $style_format[] = '(' . $end_point . '-width:' . $value . 'px)';
410 }
411
412 return '@media' . implode( ' and ', $style_format );
413 }
414 }
415