PluginProbe
MaxButtons – Create buttons / 6.4
MaxButtons – Create buttons v6.4
6.23 6.24 6.25 6.26 6.26.1 6.27 6.28 6.3 6.4 6.5 6.6 6.7 6.8 6.9 7.0 7.1 7.1.1 7.1.2 7.1.3 7.10 7.11 7.13 7.13.1 7.13.2 7.13.3 All 100 releases
maxbuttons / classes / maxCSSParser.php

maxCSSParser.php in MaxButtons – Create buttons 6.4, at classes/maxCSSParser.php

561 lines 13.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /* Class to Parse CSS. Load as array with diffent pseudo-types,
3 ability to add nested and new root blocks
4 parses via scss
5 ability to use complicated css stuff via scss mixins parsing like gradient
6 auto-discovery for -unit field types to set units (like px, or %)
7 auto-discovery of fields via domobj.
8
9 */
10 class maxCSSParser
11 {
12 protected $struct = array();
13 protected $domObj = '';
14 protected $pseudo = array("hover","active","responsive");
15
16 protected $data;
17 protected $output_css;
18
19 protected $inline = array();
20 protected $responsive = array();
21
22 // settings
23 protected $elements_ignore_zero = array(
24 'text-shadow-left',
25 'text_shadow-top',
26 'text-shadow-width',
27 'box-shadow-offset-left',
28 'box-shadow-offset-top',
29 'box-shadow-width',
30 'box-shadow-spread',
31 ); // items to ignore if value is zero, otherwise they become unremovable ( where 0 is still something on display)
32
33 protected $important = false;
34
35 // log possible problems and incidents for debugging;
36 protected $parse_log = array();
37
38 function __construct()
39 {
40 //$root[] = array("a" => array("hover","active","responsive"));
41
42 }
43
44 function loadDom($domObj)
45 {
46 $this->domObj = $domObj;
47
48 $root = $domObj->find(0,0);
49 $struct[$root->tag] = array();
50
51 $children = $root->children();
52
53 if (count($children) > 0)
54 $struct[$root->tag] = $this->loadRecursive(array(), $children);
55
56 $this->struct = $struct;
57
58
59 }
60
61 function loadRecursive($struct, $children)
62 {
63 foreach($children as $domChild)
64 {
65
66 $class = $domChild->class;
67 $class = str_replace(" ",".", $class); // combine seperate classes
68
69 $struct[$class]["tag"] = $domChild->tag;
70
71 $child_children = $domChild->children();
72
73 if (count($child_children) > 0)
74 {
75
76 $struct[$class]["children"] = $this->loadRecursive(array(), $child_children);
77 }
78 }
79
80 return $struct;
81 }
82
83
84 function parse($data)
85 {
86 $this->clear();
87
88 $struct = $this->struct;
89
90 $this->data = $data;
91
92
93 if (isset($data["settings"])) // room for settings in parser
94 {
95 $settings = $data["settings"];
96 $this->important = (isset($settings["important"])) ? $settings["important"] : false;
97
98 unset($this->data["settings"]);
99 }
100
101
102 $elements = array_shift($struct); // first element is a 'stub' root.
103
104 foreach($elements as $el => $el_data)
105 {
106
107 $this->parse_part($el,$el_data);
108 }
109
110
111 $this->parse_responsive();
112
113 maxUtils::startTime('compile CSS');
114 $css = $this->compile($this->output_css);
115 maxUtils::endTime('compile CSS');
116
117
118 return $css;
119
120 }
121
122 // reset output values.
123 protected function clear()
124 {
125 $this->data = '';
126 $this->output_css = '';
127 $this->inline = array();
128 //$this->struct = array();
129 $this->responsive = array();
130
131 }
132
133 protected function compile($css)
134 {
135 $scss = new scssc();
136 $scss->setImportPaths(MB()->get_plugin_path() . "assets/scss");
137
138 $minify = get_option("maxbuttons_minify", 1);
139 if ($minify == 1)
140 $scss->setFormatter('scss_formatter_compressed');
141
142 $compile = " @import '_mixins.scss'; " . $css;
143 //maxUtils::addTime("CSSParser: Compile start ");
144
145 try
146 {
147 $css = $scss->compile($compile);
148 } catch (Exception $e) {
149
150 $css = $this->output_css;
151 }
152
153 //maxUtils::addTime("CSSParser: Compile end ");
154
155 return $css;
156 }
157
158 function parse_part($element, $el_data, $el_add = '')
159 {
160 maxUtils::addTime("CSSParser: Parse $element ");
161
162 $tag = $el_data["tag"];
163 $element_data = $this->findData($this->data, $element);
164
165 // not using scss selectors here since there is trouble w/ the :pseudo selector, which should be put on the maxbutton / a tag.
166 if ($element != '')
167 { $el_add .= " ." . $element;
168
169 }
170
171
172 if (isset($element_data["responsive"]))
173 {
174 $responsive = $element_data["responsive"]; // doing that at the end
175 unset($element_data["responsive"]);
176
177 $this->responsive[$el_add] = $responsive;
178 }
179
180 foreach($element_data as $pseudo => $values)
181 {
182
183 if ($pseudo != 'normal')
184 {
185 // select the maxbutton case, ending with either space or next class -dot.
186 $ps_selector = preg_replace('/.maxbutton$|.maxbutton([.| ])/i',".maxbutton:$pseudo\$1",$el_add);
187
188 $this->output_css .= " $ps_selector { ";
189 }
190 else {
191 $this->output_css .= " $el_add { ";
192 }
193
194 $values = $this->doMixins($values);
195
196 foreach($values as $cssTag => $cssVal)
197 {
198
199 $statement = $this->parse_cssline($values, $cssTag,$cssVal); ///"$cssTag $css_sep $cssVal$unit$css_end ";
200 if ($statement)
201 {
202 $this->output_css .= $statement ;
203
204 if (! isset($this->inline[$pseudo][$element])) $this->inline[$pseudo][$element] = '';
205 $this->inline[$pseudo][$element] .= $statement;
206 }
207 }
208
209 $this->output_css .= " } ";
210 }
211 if (isset($el_data["children"]))
212 {
213 foreach($el_data["children"] as $child_id => $child_data)
214 {
215
216 $this->parse_part($child_id, $child_data, $el_add);
217 }
218 }
219
220 }
221
222 function parse_cssline($values, $cssTag, $cssVal, $css_end = ';')
223 {
224
225 // unit check - two ways; either unitable items is first or unit declaration.
226 if (isset($values[$cssTag . "_unit"]))
227 {
228 $unit = $values[$cssTag . "_unit"];
229 }
230 elseif(strpos($cssTag, "_unit") !== false)
231 {
232 return false; // no print, should be found under first def.
233 }
234 else $unit = '';
235
236
237 $important = ($this->is_important()) ? " !important" : "";
238 $important = ($cssTag == '@include') ? "" : $important; // mixin's problem, no checking here.
239
240 $css_sep = ($cssTag == '@include') ? $css_sep = '' : ':';
241
242 if ($cssVal == 0 && in_array($cssTag, $this->elements_ignore_zero))
243 return false;
244
245 if($cssVal !== '' && $cssTag !== '')
246 {
247 $statement = "$cssTag $css_sep $cssVal$unit$important$css_end ";
248 return $statement;
249 }
250 return false;
251
252 }
253
254 function parse_responsive()
255 {
256
257 $responsive = $this->responsive;
258 if (! is_array($responsive) || count($responsive) == 0)
259 return;
260
261 $media_queries = maxUtils::get_media_query(2); // query names
262
263 $output = '';
264
265 $query_array = array();
266
267
268 foreach($responsive as $element => $queries)
269 {
270 foreach($queries as $query => $qdata)
271 foreach($qdata as $index => $data)
272 {{
273 $query_array[$query][$index][$element] = $data;
274
275 }}
276 }
277
278
279 foreach($query_array as $query => $vdata):
280
281 if ($query == 'custom')
282 {
283
284 // first discover the custom size properties.
285 foreach($vdata as $index => $data):
286 foreach($data as $element => $values):
287
288 if (isset($values["custom_maxwidth"]) || isset($values["custom_minwidth"]) )
289 {
290
291 $minwidth = (isset($values["custom_minwidth"])) ? intval($values["custom_minwidth"]) : -1;
292 $maxwidth = (isset($values["custom_maxwidth"])) ? intval($values["custom_maxwidth"]) : -1;
293
294
295 unset($vdata[$index][$element]["custom_minwidth"]);
296 unset($vdata[$index][$element]["custom_maxwidth"]);
297
298
299 // make it always an integer
300 if ($minwidth == '') $minwidth = 0;
301 if ($maxwidth == '') $maxwidth = 0;
302
303 // if minwidth is not set and maxwidth zero or not set - ignore since it would result in an empty media line.
304 //if ($minwidth <= 0 && $maxwidth <= 0)
305 //{
306 //continue;
307 //}
308
309 if ($minwidth > 0 && $maxwidth > 0)
310 $qdef = "only screen and (min-width: $minwidth" . "px) and (max-width: $maxwidth" . "px)";
311 if ($minwidth >= 0 && $maxwidth <= 0)
312 $qdef = "only screen and (min-width: $minwidth" . "px) ";
313 if ($minwidth <= 0 && $maxwidth > 0)
314 $qdef = "only screen and (max-width: $maxwidth" . "px) ";
315
316 //break;
317
318 }
319 endforeach; //foreach data
320
321 // The problem is that every 'custom' query needs to run with a different qdef unlike other queries.
322
323 $qdata = array($vdata[$index]);
324
325 $output = $this->parse_responsive_definition($output, $qdef, $qdata);
326 endforeach; // foreach vdata
327 }
328 else
329 {
330
331 $qdef = $media_queries[$query];
332 $output = $this->parse_responsive_definition($output, $qdef, $vdata);
333 }
334
335 endforeach;
336
337
338 $this->output_css .= $output;
339 }
340
341 protected function parse_responsive_definition($output, $qdef, $vdata)
342 {
343
344 if (! isset($qdef) || $qdef == '') {
345
346 return; // no definition.
347 }
348
349
350 $output .= "@media ". $qdef . " { ";
351
352
353 foreach($vdata as $index => $data)
354 {
355
356 foreach($data as $element => $values) {
357 //foreach($vdat as $index => $values):
358 $output .= $element . " { ";
359 $css_end = ';';
360
361 // same as parse part, maybe merge in future
362 foreach($values as $cssTag => $cssVal)
363 {
364 // unit check - two ways; either unitable items is first or unit declaration.
365 $statement = $this->parse_cssline($values, $cssTag,$cssVal);
366 if($statement)
367 $output .= $statement;
368
369 }
370
371 $output .= " } ";
372 // endforeach;
373 }
374
375
376 }
377 $output .= " } ";
378
379 //endforeach;
380
381 return $output;
382 }
383
384 private function is_important()
385 {
386
387 if ($this->important == 1)
388 return true;
389 else
390 return false;
391 }
392
393 function findData($data, $el)
394 {
395 $classes = explode(".", $el);
396
397 foreach($data as $part => $values)
398 {
399 if (in_array($part, $classes))
400 return $data[$part];
401 }
402 return array();
403 }
404
405 function doMixins($values)
406 {
407 $mixins = array("gradient", "box-shadow", "text-shadow");
408
409 foreach($mixins as $mixin)
410 {
411
412 $results = preg_grep("/^$mixin/i",array_keys($values) );
413 $mixin_array = array();
414 foreach($results as $result)
415 {
416 $mixin_array[$result] = $values[$result];
417 }
418
419 if (count($mixin_array) > 0)
420 {
421 switch($mixin)
422 {
423 case "gradient":
424 $values = $this->mixin_gradient($mixin_array, $values);
425
426 break;
427 case "box-shadow":
428 $values = $this->mixin_boxshadow($mixin_array, $values);
429 break;
430 case "text-shadow":
431 $values = $this->mixin_textshadow($mixin_array, $values);
432 break;
433 }
434 }
435
436
437 }
438 return $values;
439 }
440
441 function mixin_gradient($results, $values)
442 {
443
444 $start = isset($results["gradient-start-color"]) ? $results["gradient-start-color"] : '';
445 $end = isset( $results["gradient-end-color"] ) ? $results["gradient-end-color"] : '';
446 $start_opacity = isset( $results["gradient-start-opacity"] ) ? $results["gradient-start-opacity"] : '';
447 $end_opacity = isset( $results["gradient-end-opacity"] ) ? $results["gradient-end-opacity"] : '';
448 $stop = (isset( $results["gradient-stop"]) && $results["gradient-stop"] != '') ? $results["gradient-stop"] . "%" : '45%';
449
450 $start = maxUtils::hex2rgba($start, $start_opacity);
451 $end = maxUtils::hex2rgba($end, $end_opacity);
452
453 $important = ($this->is_important()) ? "!important" : "";
454
455 $values = $this->add_include($values, "linear-gradient($start,$end,$stop,$important)");
456 $values = array_diff_key($values, $results);
457
458 return $values;
459
460 }
461
462 function mixin_boxshadow($results, $values)
463 {
464 $width = $results["box-shadow-width"];
465 $left = $results["box-shadow-offset-left"];
466 $top = $results["box-shadow-offset-top"];
467 $spread = isset($results['box-shadow-spread']) ? $results['box-shadow-spread'] : 0;
468 $color = isset($results["box-shadow-color"]) ? $results["box-shadow-color"] : '';
469
470 $important = ($this->is_important()) ? "!important" : "";
471
472 if ($width == 0 && $left == 0 && $top == 0)
473 return $values;
474
475 $values = $this->add_include($values, "box-shadow($left, $top, $width, $color,$spread, false, $important) ");
476 $values = array_diff_key($values, $results);
477
478 return $values;
479 }
480
481 function mixin_textshadow($results, $values)
482 {
483 $width = isset($results["text-shadow-width"]) ? $results["text-shadow-width"] : 0;
484 $left = isset($results["text-shadow-left"]) ? $results["text-shadow-left"] : 0;
485 $top = isset($results["text-shadow-top"]) ? $results["text-shadow-top"] : 0;
486 $color = isset($results["text-shadow-color"]) ? $results["text-shadow-color"] : '';
487 $important = ($this->is_important()) ? "!important" : "";
488
489 if ($width == 0 && $left == 0 && $top == 0)
490 return $values;
491
492 $values = $this->add_include($values, "text-shadow ($left,$top,$width,$color $important)");
493
494 $values = array_diff_key($values, $results);
495
496 return $values;
497 }
498
499 private function add_include($values, $include)
500 {
501 if (isset($values["@include"]))
502 $values["@include"] .= "; @include " . $include;
503 else
504 $values["@include"] = $include;
505 return $values;
506 }
507
508 function outputInline($domObj, $pseudo = 'normal')
509 {
510 $domObj = $domObj->load($domObj->save());
511
512 $inline = $this->inline;
513
514 // ISSUE #43 Sometimes this breaks
515 if (! isset($inline[$pseudo]))
516 return $domObj;
517
518 $elements = array_keys($inline[$pseudo]);
519 if ($pseudo != 'normal') // gather all elements
520 $elements = array_merge($elements, array_keys($inline["normal"]));
521
522 foreach($elements as $element )
523 {
524 $styles = isset($inline[$pseudo][$element]) ? $inline[$pseudo][$element] : '';
525
526 if ($pseudo != 'normal') // parse all possible missing styles from pseudo el.
527 $normstyle = $this->compile($inline['normal'][$element]);
528
529 $normstyle = '';
530 if ($pseudo != 'normal') // parse all possible missing styles from pseudo el.
531 $normstyle = $this->compile($inline['normal'][$element]);
532
533 maxUtils::addTime("CSSParser: Parse inline done");
534
535 $styles = $normstyle . $this->compile($styles);
536
537 $element = trim(str_replace("."," ", $element)); // molten css class, seperator.
538
539 $el = $domObj->find('[class*="' . $element . '"]', 0);
540 if (is_null($el)) echo "NULL";
541 $el->style = $styles;
542
543 }
544
545 return $domObj;
546
547 }
548
549 function output()
550 {
551
552
553 }
554
555 }
556
557 class compileException extends Exception {
558 protected $code = -1;
559
560 }
561