MDL-29941 csslib: Improved PHPdocs
[moodle.git] / lib / csslib.php
CommitLineData
0e641c74
SH
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * This file contains CSS related methods and a CSS optimiser
19 *
20 * @package moodlecore
21 * @copyright 2011 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25/**
26 * Stores CSS in a file at the given path.
27 *
28 * @param theme_config $theme
29 * @param string $csspath
30 * @param array $cssfiles
31 */
32function css_store_css(theme_config $theme, $csspath, array $cssfiles) {
1d1d807e
SH
33 global $CFG;
34
35 if (!empty($CFG->cssoptimise)) {
36 // This is an experimental feature introduced in Moodle 2.2
37 // The CSS optimiser organises the CSS in order to reduce the overall number
38 // of rules and styles being sent to the client. It does this by collating
39 // the CSS before it is cached removing excess styles and rules and stripping
40 // out any extraneous content such as comments and empty rules.
41 $optimiser = new css_optimiser;
42 $css = '';
43 foreach ($cssfiles as $file) {
44 $css .= file_get_contents($file)."\n";
45 }
46 $css = $theme->post_process($css);
47 $css = $optimiser->process($css);
0e641c74 48
1d1d807e
SH
49 // If cssoptimisestats is set then stats from the optimisation are collected
50 // and output at the beginning of the CSS
51 if (!empty($CFG->cssoptimisestats)) {
52 $css = $optimiser->output_stats_css().$css;
53 }
54 } else {
55 // This is the default behaviour.
56 // The cssoptimise setting was introduced in Moodle 2.2 and will hopefully
57 // in the future be changed from an experimental setting to the default.
58 // The css_minify_css will method will use the Minify library remove
59 // comments, additional whitespace and other minor measures to reduce the
60 // the overall CSS being sent.
61 // However it has the distinct disadvantage of having to minify the CSS
62 // before running the post process functions. Potentially things may break
63 // here if theme designers try to push things with CSS post processing.
64 $css = $theme->post_process(css_minify_css($cssfiles));
65 }
0e641c74
SH
66
67 check_dir_exists(dirname($csspath));
68 $fp = fopen($csspath, 'w');
69 fwrite($fp, $css);
70 fclose($fp);
71 return true;
72}
73
74/**
75 * Sends IE specific CSS
76 *
77 * @param string $themename
78 * @param string $rev
79 */
80function css_send_ie_css($themename, $rev) {
81 $lifetime = 60*60*24*30; // 30 days
82
83 $css = "/** Unfortunately IE6/7 does not support more than 4096 selectors in one CSS file, which means we have to use some ugly hacks :-( **/";
84 $css = "@import url(styles.php?theme=$themename&rev=$rev&type=plugins);";
85 $css = "@import url(styles.php?theme=$themename&rev=$rev&type=parents);";
86 $css = "@import url(styles.php?theme=$themename&rev=$rev&type=theme);";
87
88 header('Etag: '.md5($rev));
89 header('Content-Disposition: inline; filename="styles.php"');
90 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
91 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
92 header('Pragma: ');
93 header('Cache-Control: max-age='.$lifetime);
94 header('Accept-Ranges: none');
95 header('Content-Type: text/css; charset=utf-8');
96 header('Content-Length: '.strlen($css));
97
98 echo $css;
99 die;
100}
101
102/**
103 * Sends a cached CSS file
104 *
105 * @param string $csspath
106 * @param string $rev
107 */
108function css_send_cached_css($csspath, $rev) {
109 $lifetime = 60*60*24*30; // 30 days
110
111 header('Content-Disposition: inline; filename="styles.php"');
112 header('Last-Modified: '. gmdate('D, d M Y H:i:s', filemtime($csspath)) .' GMT');
113 header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT');
114 header('Pragma: ');
115 header('Cache-Control: max-age='.$lifetime);
116 header('Accept-Ranges: none');
117 header('Content-Type: text/css; charset=utf-8');
118 if (!min_enable_zlib_compression()) {
119 header('Content-Length: '.filesize($csspath));
120 }
121
122 readfile($csspath);
123 die;
124}
125
126/**
127 * Sends CSS directly without caching it.
128 *
129 * @param string CSS
130 */
131function css_send_uncached_css($css) {
1d1d807e 132 global $CFG;
0e641c74
SH
133
134 header('Content-Disposition: inline; filename="styles_debug.php"');
135 header('Last-Modified: '. gmdate('D, d M Y H:i:s', time()) .' GMT');
136 header('Expires: '. gmdate('D, d M Y H:i:s', time() + THEME_DESIGNER_CACHE_LIFETIME) .' GMT');
137 header('Pragma: ');
138 header('Accept-Ranges: none');
139 header('Content-Type: text/css; charset=utf-8');
140
141 if (is_array($css)) {
142 $css = implode("\n\n", $css);
143 }
1d1d807e
SH
144
145 if (!empty($CFG->cssoptimise) && !empty($CFG->cssoptimisedebug)) {
146 $css = str_replace("\n", "\r\n", $css);
147
148 $optimiser = new css_optimiser;
149 $css = $optimiser->process($css);
150 if (!empty($CFG->cssoptimisestats)) {
151 $css = $optimiser->output_stats_css().$css;
152 }
153 }
154
155 echo $css;
0e641c74
SH
156
157 die;
158}
159
160/**
161 * Sends a 404 message about CSS not being found.
162 */
163function css_send_css_not_found() {
164 header('HTTP/1.0 404 not found');
165 die('CSS was not found, sorry.');
166}
167
0abd4846
SH
168/**
169 * Uses the minify library to compress CSS.
170 *
171 * This is used if $CFG->cssoptimise has been turned off. This was
172 * the original CSS optimisation library.
173 *
174 * @param array $files An array of files to minify
175 * @return string The minified CSS
176 */
1d1d807e
SH
177function css_minify_css($files) {
178 global $CFG;
179
180 set_include_path($CFG->libdir . '/minify/lib' . PATH_SEPARATOR . get_include_path());
181 require_once('Minify.php');
182
183 if (0 === stripos(PHP_OS, 'win')) {
184 Minify::setDocRoot(); // IIS may need help
185 }
186 // disable all caching, we do it in moodle
187 Minify::setCache(null, false);
188
189 $options = array(
190 'bubbleCssImports' => false,
191 // Don't gzip content we just want text for storage
192 'encodeOutput' => false,
193 // Maximum age to cache, not used but required
194 'maxAge' => (60*60*24*20),
195 // The files to minify
196 'files' => $files,
197 // Turn orr URI rewriting
198 'rewriteCssUris' => false,
199 // This returns the CSS rather than echoing it for display
200 'quiet' => true
201 );
202 $result = Minify::serve('Files', $options);
203 return $result['content'];
204}
205
206/**
207 * Given a value determines if it is a valid CSS colour
208 *
209 * @param string $value
210 * @return bool
211 */
212function css_is_colour($value) {
213 $value = trim($value);
214 if (preg_match('/^#([a-fA-F0-9]{1,6})$/', $value)) {
215 return true;
216 } else if (in_array(strtolower($value), array_keys(css_optimiser::$htmlcolours))) {
217 return true;
218 } else if (preg_match('#^(rgb|hsl)\s*\(\s*\d{1,3}\%?\s*,\s*\d{1,3}\%?\s*,\s*\d{1,3}\%?\s*\)$#', $value)) {
219 return true;
220 } else if (preg_match('#^(rgb|hsl)a\s*\(\s*\d{1,3}\%?\s*,\s*\d{1,3}\%?\s*,\s*\d{1,3}\%?\s*,\s*\d(\.\d+)?\s*\)$#', $value)) {
221 return true;
222 }
223 return false;
224}
225
0abd4846
SH
226/**
227 * A simple sorting function to sort two array values on the number of items they contain
228 *
229 * @param array $a
230 * @param array $b
231 * @return int
232 */
233function css_sort_by_count(array $a, array $b) {
234 $a = count($a);
235 $b = count($b);
236 if ($a == $b) {
237 return 0;
238 }
239 return ($a > $b) ? -1 : 1;
240}
241
0e641c74
SH
242/**
243 * A basic CSS optimiser that strips out unwanted things and then processing the
244 * CSS organising styles and moving duplicates and useless CSS.
245 *
246 * @package moodlecore
247 * @copyright 2011 Sam Hemelryk
248 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
249 */
250class css_optimiser {
251
252 /**#@+
253 * Processing states. Used internally.
254 */
255 const PROCESSING_START = 0;
256 const PROCESSING_SELECTORS = 0;
257 const PROCESSING_STYLES = 1;
258 const PROCESSING_COMMENT = 2;
259 const PROCESSING_ATRULE = 3;
260 /**#@-*/
261
262 /**#@+
263 * Stats variables set during and after processing
264 * @var int
265 */
266 protected $rawstrlen = 0;
267 protected $commentsincss = 0;
268 protected $rawrules = 0;
269 protected $rawselectors = 0;
270 protected $optimisedstrlen = 0;
271 protected $optimisedrules = 0;
272 protected $optimisedselectors = 0;
273 protected $timestart = 0;
274 protected $timecomplete = 0;
275 /**#@-*/
276
277 /**
278 * Processes incoming CSS optimising it and then returning it.
279 *
280 * @param string $css The raw CSS to optimise
281 * @return string The optimised CSS
282 */
283 public function process($css) {
284 global $CFG;
285
286 $this->reset_stats();
287 $this->timestart = microtime(true);
288 $this->rawstrlen = strlen($css);
289
290 // First up we need to remove all line breaks - this allows us to instantly
291 // reduce our processing requirements and as we will process everything
292 // into a new structure there's really nothing lost.
293 $css = preg_replace('#\r?\n#', ' ', $css);
294
295 // Next remove the comments... no need to them in an optimised world and
296 // knowing they're all gone allows us to REALLY make our processing simpler
297 $css = preg_replace('#/\*(.*?)\*/#m', '', $css, -1, $this->commentsincss);
298
299 $medias = array(
300 'all' => new css_media()
301 );
302 $imports = array();
303 $charset = false;
1d1d807e 304
0e641c74 305 $currentprocess = self::PROCESSING_START;
1d1d807e 306 $currentrule = css_rule::init();
0e641c74
SH
307 $currentselector = css_selector::init();
308 $inquotes = false; // ' or "
309 $inbraces = false; // {
310 $inbrackets = false; // [
311 $inparenthesis = false; // (
312 $currentmedia = $medias['all'];
313 $currentatrule = null;
314 $suspectatrule = false;
315
316 $buffer = '';
317 $char = null;
318
319 // Next we are going to iterate over every single character in $css.
320 // This is why re removed line breaks and comments!
321 for ($i = 0; $i < $this->rawstrlen; $i++) {
322 $lastchar = $char;
323 $char = substr($css, $i, 1);
324 if ($char == '@' && $buffer == '') {
325 $suspectatrule = true;
326 }
327 switch ($currentprocess) {
328 // Start processing an at rule e.g. @media, @page
329 case self::PROCESSING_ATRULE:
330 switch ($char) {
331 case ';':
332 if (!$inbraces) {
333 $buffer .= $char;
334 if ($currentatrule == 'import') {
335 $imports[] = $buffer;
336 $currentprocess = self::PROCESSING_SELECTORS;
337 } else if ($currentatrule == 'charset') {
338 $charset = $buffer;
339 $currentprocess = self::PROCESSING_SELECTORS;
340 }
341 }
342 $buffer = '';
343 $currentatrule = false;
344 continue 3;
345 case '{':
346 if ($currentatrule == 'media' && preg_match('#\s*@media\s*([a-zA-Z0-9]+(\s*,\s*[a-zA-Z0-9]+)*)#', $buffer, $matches)) {
347 $mediatypes = str_replace(' ', '', $matches[1]);
348 if (!array_key_exists($mediatypes, $medias)) {
349 $medias[$mediatypes] = new css_media($mediatypes);
350 }
351 $currentmedia = $medias[$mediatypes];
352 $currentprocess = self::PROCESSING_SELECTORS;
353 $buffer = '';
354 }
355 continue 3;
356 }
357 break;
358 // Start processing selectors
359 case self::PROCESSING_START:
360 case self::PROCESSING_SELECTORS:
361 switch ($char) {
362 case '[':
363 $inbrackets ++;
364 $buffer .= $char;
365 continue 3;
366 case ']':
367 $inbrackets --;
368 $buffer .= $char;
369 continue 3;
370 case ' ':
371 if ($inbrackets) {
372 continue 3;
373 }
374 if (!empty($buffer)) {
375 if ($suspectatrule && preg_match('#@(media|import|charset)\s*#', $buffer, $matches)) {
376 $currentatrule = $matches[1];
377 $currentprocess = self::PROCESSING_ATRULE;
378 $buffer .= $char;
379 } else {
380 $currentselector->add($buffer);
381 $buffer = '';
382 }
383 }
384 $suspectatrule = false;
385 continue 3;
386 case '{':
387 if ($inbrackets) {
388 continue 3;
389 }
1d1d807e 390
0e641c74 391 $currentselector->add($buffer);
1d1d807e 392 $currentrule->add_selector($currentselector);
0e641c74
SH
393 $currentselector = css_selector::init();
394 $currentprocess = self::PROCESSING_STYLES;
395
396 $buffer = '';
397 continue 3;
398 case '}':
399 if ($inbrackets) {
400 continue 3;
401 }
402 if ($currentatrule == 'media') {
403 $currentmedia = $medias['all'];
404 $currentatrule = false;
405 $buffer = '';
406 }
407 continue 3;
408 case ',':
409 if ($inbrackets) {
410 continue 3;
411 }
412 $currentselector->add($buffer);
1d1d807e 413 $currentrule->add_selector($currentselector);
0e641c74
SH
414 $currentselector = css_selector::init();
415 $buffer = '';
416 continue 3;
417 }
418 break;
419 // Start processing styles
420 case self::PROCESSING_STYLES:
421 if ($char == '"' || $char == "'") {
422 if ($inquotes === false) {
423 $inquotes = $char;
424 }
425 if ($inquotes === $char && $lastchar !== '\\') {
426 $inquotes = false;
427 }
428 }
429 if ($inquotes) {
430 $buffer .= $char;
431 continue 2;
432 }
433 switch ($char) {
434 case ';':
1d1d807e 435 $currentrule->add_style($buffer);
0e641c74
SH
436 $buffer = '';
437 $inquotes = false;
438 continue 3;
439 case '}':
1d1d807e
SH
440 $currentrule->add_style($buffer);
441 $this->rawselectors += $currentrule->get_selector_count();
0e641c74 442
1d1d807e 443 $currentmedia->add_rule($currentrule);
0e641c74 444
1d1d807e 445 $currentrule = css_rule::init();
0e641c74
SH
446 $currentprocess = self::PROCESSING_SELECTORS;
447 $this->rawrules++;
448 $buffer = '';
449 $inquotes = false;
450 continue 3;
451 }
452 break;
453 }
454 $buffer .= $char;
455 }
456
457 $css = '';
458 if (!empty($charset)) {
459 $imports[] = $charset;
460 }
461 if (!empty($imports)) {
462 $css .= implode("\n", $imports);
463 $css .= "\n\n";
464 }
465 foreach ($medias as $media) {
466 $media->organise_rules_by_selectors();
467 $this->optimisedrules += $media->count_rules();
468 $this->optimisedselectors += $media->count_selectors();
469 $css .= $media->out();
470 }
471 $this->optimisedstrlen = strlen($css);
472
473 $this->timecomplete = microtime(true);
0e641c74
SH
474 return trim($css);
475 }
476
477 /**
8589a4a5 478 * Returns an array of stats from the last processing run
0e641c74
SH
479 * @return string
480 */
481 public function get_stats() {
8589a4a5
SH
482 $stats = array(
483 'timestart' => $this->timestart,
484 'timecomplete' => $this->timecomplete,
485 'timetaken' => round($this->timecomplete - $this->timestart, 4),
486 'commentsincss' => $this->commentsincss,
487 'rawstrlen' => $this->rawstrlen,
488 'rawselectors' => $this->rawselectors,
489 'rawrules' => $this->rawrules,
490 'optimisedstrlen' => $this->optimisedstrlen,
491 'optimisedrules' => $this->optimisedrules,
1d1d807e 492 'optimisedselectors' => $this->optimisedselectors,
8589a4a5
SH
493 'improvementstrlen' => round(100 - ($this->optimisedstrlen / $this->rawstrlen) * 100, 1).'%',
494 'improvementrules' => round(100 - ($this->optimisedrules / $this->rawrules) * 100, 1).'%',
495 'improvementselectors' => round(100 - ($this->optimisedselectors / $this->rawselectors) * 100, 1).'%',
496 );
497 return $stats;
498 }
499
500 /**
501 * Returns a string to display stats about the last generation within CSS output
502 * @return string
503 */
504 public function output_stats_css() {
505 $stats = $this->get_stats();
506
507 $strlenimprovement = round(100 - ($this->optimisedstrlen / $this->rawstrlen) * 100, 1);
508 $ruleimprovement = round(100 - ($this->optimisedrules / $this->rawrules) * 100, 1);
509 $selectorimprovement = round(100 - ($this->optimisedselectors / $this->rawselectors) * 100, 1);
0e641c74
SH
510 $timetaken = round($this->timecomplete - $this->timestart, 4);
511
512 $computedcss = "/****************************************\n";
513 $computedcss .= " *------- CSS Optimisation stats --------\n";
514 $computedcss .= " * ".date('r')."\n";
1d1d807e
SH
515 $computedcss .= " * {$stats['commentsincss']} \t comments removed\n";
516 $computedcss .= " * Optimisation took {$stats['timetaken']} seconds\n";
0e641c74 517 $computedcss .= " *--------------- before ----------------\n";
1d1d807e
SH
518 $computedcss .= " * {$stats['rawstrlen']} \t chars read in\n";
519 $computedcss .= " * {$stats['rawrules']} \t rules read in\n";
520 $computedcss .= " * {$stats['rawselectors']} \t total selectors\n";
0e641c74 521 $computedcss .= " *---------------- after ----------------\n";
1d1d807e
SH
522 $computedcss .= " * {$stats['optimisedstrlen']} \t chars once optimized\n";
523 $computedcss .= " * {$stats['optimisedrules']} \t optimized rules\n";
524 $computedcss .= " * {$stats['optimisedselectors']} \t total selectors once optimized\n";
0e641c74 525 $computedcss .= " *---------------- stats ----------------\n";
1d1d807e
SH
526 $computedcss .= " * {$stats['improvementstrlen']} \t reduction in chars\n";
527 $computedcss .= " * {$stats['improvementrules']} \t reduction in rules\n";
528 $computedcss .= " * {$stats['improvementselectors']} \t reduction in selectors\n";
0e641c74
SH
529 $computedcss .= " ****************************************/\n\n";
530
531 return $computedcss;
532 }
533
534 /**
535 * Resets the stats ready for another fresh processing
536 */
537 public function reset_stats() {
538 $this->commentsincss = 0;
539 $this->optimisedrules = 0;
540 $this->optimisedselectors = 0;
541 $this->optimisedstrlen = 0;
542 $this->rawrules = 0;
543 $this->rawselectors = 0;
544 $this->rawstrlen = 0;
545 $this->timecomplete = 0;
546 $this->timestart = 0;
547 }
548
549 /**
550 * An array of the common HTML colours that are supported by most browsers.
551 *
552 * This reference table is used to allow us to unify colours, and will aid
553 * us in identifying buggy CSS using unsupported colours.
554 *
555 * @staticvar array
556 * @var array
557 */
558 public static $htmlcolours = array(
559 'aliceblue' => '#F0F8FF',
560 'antiquewhite' => '#FAEBD7',
561 'aqua' => '#00FFFF',
562 'aquamarine' => '#7FFFD4',
563 'azure' => '#F0FFFF',
564 'beige' => '#F5F5DC',
565 'bisque' => '#FFE4C4',
566 'black' => '#000000',
567 'blanchedalmond' => '#FFEBCD',
568 'blue' => '#0000FF',
569 'blueviolet' => '#8A2BE2',
570 'brown' => '#A52A2A',
571 'burlywood' => '#DEB887',
572 'cadetblue' => '#5F9EA0',
573 'chartreuse' => '#7FFF00',
574 'chocolate' => '#D2691E',
575 'coral' => '#FF7F50',
576 'cornflowerblue' => '#6495ED',
577 'cornsilk' => '#FFF8DC',
578 'crimson' => '#DC143C',
579 'cyan' => '#00FFFF',
580 'darkblue' => '#00008B',
581 'darkcyan' => '#008B8B',
582 'darkgoldenrod' => '#B8860B',
583 'darkgray' => '#A9A9A9',
584 'darkgrey' => '#A9A9A9',
585 'darkgreen' => '#006400',
586 'darkKhaki' => '#BDB76B',
587 'darkmagenta' => '#8B008B',
588 'darkolivegreen' => '#556B2F',
589 'arkorange' => '#FF8C00',
590 'darkorchid' => '#9932CC',
591 'darkred' => '#8B0000',
592 'darksalmon' => '#E9967A',
593 'darkseagreen' => '#8FBC8F',
594 'darkslateblue' => '#483D8B',
595 'darkslategray' => '#2F4F4F',
596 'darkslategrey' => '#2F4F4F',
597 'darkturquoise' => '#00CED1',
598 'darkviolet' => '#9400D3',
599 'deeppink' => '#FF1493',
600 'deepskyblue' => '#00BFFF',
601 'dimgray' => '#696969',
602 'dimgrey' => '#696969',
603 'dodgerblue' => '#1E90FF',
604 'firebrick' => '#B22222',
605 'floralwhite' => '#FFFAF0',
606 'forestgreen' => '#228B22',
607 'fuchsia' => '#FF00FF',
608 'gainsboro' => '#DCDCDC',
609 'ghostwhite' => '#F8F8FF',
610 'gold' => '#FFD700',
611 'goldenrod' => '#DAA520',
612 'gray' => '#808080',
613 'grey' => '#808080',
614 'green' => '#008000',
615 'greenyellow' => '#ADFF2F',
616 'honeydew' => '#F0FFF0',
617 'hotpink' => '#FF69B4',
618 'indianred ' => '#CD5C5C',
619 'indigo ' => '#4B0082',
620 'ivory' => '#FFFFF0',
621 'khaki' => '#F0E68C',
622 'lavender' => '#E6E6FA',
623 'lavenderblush' => '#FFF0F5',
624 'lawngreen' => '#7CFC00',
625 'lemonchiffon' => '#FFFACD',
626 'lightblue' => '#ADD8E6',
627 'lightcoral' => '#F08080',
628 'lightcyan' => '#E0FFFF',
629 'lightgoldenrodyellow' => '#FAFAD2',
630 'lightgray' => '#D3D3D3',
631 'lightgrey' => '#D3D3D3',
632 'lightgreen' => '#90EE90',
633 'lightpink' => '#FFB6C1',
634 'lightsalmon' => '#FFA07A',
635 'lightseagreen' => '#20B2AA',
636 'lightskyblue' => '#87CEFA',
637 'lightslategray' => '#778899',
638 'lightslategrey' => '#778899',
639 'lightsteelblue' => '#B0C4DE',
640 'lightyellow' => '#FFFFE0',
641 'lime' => '#00FF00',
642 'limegreen' => '#32CD32',
643 'linen' => '#FAF0E6',
644 'magenta' => '#FF00FF',
645 'maroon' => '#800000',
646 'mediumaquamarine' => '#66CDAA',
647 'mediumblue' => '#0000CD',
648 'mediumorchid' => '#BA55D3',
649 'mediumpurple' => '#9370D8',
650 'mediumseagreen' => '#3CB371',
651 'mediumslateblue' => '#7B68EE',
652 'mediumspringgreen' => '#00FA9A',
653 'mediumturquoise' => '#48D1CC',
654 'mediumvioletred' => '#C71585',
655 'midnightblue' => '#191970',
656 'mintcream' => '#F5FFFA',
657 'mistyrose' => '#FFE4E1',
658 'moccasin' => '#FFE4B5',
659 'navajowhite' => '#FFDEAD',
660 'navy' => '#000080',
661 'oldlace' => '#FDF5E6',
662 'olive' => '#808000',
663 'olivedrab' => '#6B8E23',
664 'orange' => '#FFA500',
665 'orangered' => '#FF4500',
666 'orchid' => '#DA70D6',
667 'palegoldenrod' => '#EEE8AA',
668 'palegreen' => '#98FB98',
669 'paleturquoise' => '#AFEEEE',
670 'palevioletred' => '#D87093',
671 'papayawhip' => '#FFEFD5',
672 'peachpuff' => '#FFDAB9',
673 'peru' => '#CD853F',
674 'pink' => '#FFC0CB',
675 'plum' => '#DDA0DD',
676 'powderblue' => '#B0E0E6',
677 'purple' => '#800080',
678 'red' => '#FF0000',
679 'rosybrown' => '#BC8F8F',
680 'royalblue' => '#4169E1',
681 'saddlebrown' => '#8B4513',
682 'salmon' => '#FA8072',
683 'sandybrown' => '#F4A460',
684 'seagreen' => '#2E8B57',
685 'seashell' => '#FFF5EE',
686 'sienna' => '#A0522D',
687 'silver' => '#C0C0C0',
688 'skyblue' => '#87CEEB',
689 'slateblue' => '#6A5ACD',
690 'slategray' => '#708090',
691 'slategrey' => '#708090',
692 'snow' => '#FFFAFA',
693 'springgreen' => '#00FF7F',
694 'steelblue' => '#4682B4',
695 'tan' => '#D2B48C',
696 'teal' => '#008080',
697 'thistle' => '#D8BFD8',
698 'tomato' => '#FF6347',
699 'turquoise' => '#40E0D0',
700 'violet' => '#EE82EE',
701 'wheat' => '#F5DEB3',
702 'white' => '#FFFFFF',
703 'whitesmoke' => '#F5F5F5',
704 'yellow' => '#FFFF00',
705 'yellowgreen' => '#9ACD32'
706 );
707}
708
1d1d807e
SH
709/**
710 * Used to prepare CSS strings
711 *
712 * @package moodlecore
713 * @copyright 2011 Sam Hemelryk
714 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
715 */
716abstract class css_writer {
717 /**
718 * The current indent level
719 * @var int
720 */
721 protected static $indent = 0;
722
723 /**
724 * Returns true if the output should still maintain minimum formatting.
725 * @return bool
726 */
727 protected static function is_pretty() {
728 global $CFG;
729 return (!empty($CFG->cssoptimisepretty));
730 }
731
732 /**
733 * Returns the indenting char to use for indenting things nicely.
734 * @return string
735 */
736 protected static function get_indent() {
737 if (self::is_pretty()) {
738 return str_repeat(" ", self::$indent);
739 }
740 return '';
741 }
742
743 /**
744 * Increases the current indent
745 */
746 protected static function increase_indent() {
747 self::$indent++;
748 }
749
750 /**
751 * Descreases the current indent
752 */
753 protected static function decrease_indent() {
754 self::$indent--;
755 }
756
757 /**
758 * Returns the string to use as a separator
759 * @return string
760 */
761 protected static function get_separator() {
762 return (self::is_pretty())?"\n":' ';
763 }
764
765 /**
766 * Returns CSS for media
767 *
768 * @param string $typestring
769 * @param array $rules An array of css_rule objects
770 * @return string
771 */
772 public static function media($typestring, array &$rules) {
773 $nl = self::get_separator();
774
775 $output = '';
776 if ($typestring !== 'all') {
777 $output .= $nl.$nl."@media {$typestring} {".$nl;
778 self::increase_indent();
779 }
780 foreach ($rules as $rule) {
781 $output .= $rule->out().$nl;
782 }
783 if ($typestring !== 'all') {
784 self::decrease_indent();
785 $output .= '}';
786 }
787 return $output;
788 }
789
790 /**
791 * Returns CSS for a rule
792 *
793 * @param string $selector
794 * @param string $styles
795 * @return string
796 */
797 public static function rule($selector, $styles) {
798 $css = self::get_indent()."{$selector}{{$styles}}";
799 return $css;
800 }
801
802 /**
803 * Returns CSS for the selectors of a rule
804 *
805 * @param array $selectors Array of css_selector objects
806 * @return string
807 */
808 public static function selectors(array $selectors) {
809 $nl = self::get_separator();
810 $selectorstrings = array();
811 foreach ($selectors as $selector) {
812 $selectorstrings[] = $selector->out();
813 }
814 return join(','.$nl, $selectorstrings);
815 }
816
817 /**
818 * Returns a selector given the components that make it up.
819 *
820 * @param array $components
821 * @return string
822 */
823 public static function selector(array $components) {
824 return trim(join(' ', $components));
825 }
826
827 /**
828 *
829 * @param array $styles Array of css_style objects
830 * @return type
831 */
832 public static function styles(array $styles) {
833 $bits = array();
834 foreach ($styles as $style) {
835 $bits[] = $style->out();
836 }
837 return join('', $bits);
838 }
839
840 /**
841 * Returns a style CSS
842 *
843 * @param string $name
844 * @param string $value
845 * @param bool $important
846 * @return string
847 */
848 public static function style($name, $value, $important = false) {
849 if ($important && strpos($value, '!important') === false) {
850 $value .= ' !important';
851 }
852 return "{$name}:{$value};";
853 }
854}
855
0e641c74
SH
856/**
857 * A structure to represent a CSS selector.
858 *
859 * The selector is the classes, id, elements, and psuedo bits that make up a CSS
860 * rule.
861 *
862 * @package moodlecore
863 * @copyright 2011 Sam Hemelryk
864 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
865 */
866class css_selector {
867
868 /**
869 * An array of selector bits
870 * @var array
871 */
872 protected $selectors = array();
873
874 /**
875 * The number of selectors.
876 * @var int
877 */
878 protected $count = 0;
879
880 /**
881 * Initialises a new CSS selector
1d1d807e 882 * @return css_selector
0e641c74
SH
883 */
884 public static function init() {
885 return new css_selector();
886 }
887
888 /**
889 * CSS selectors can only be created through the init method above.
890 */
891 protected function __construct() {}
892
893 /**
894 * Adds a selector to the end of the current selector
895 * @param string $selector
896 */
897 public function add($selector) {
898 $selector = trim($selector);
899 $count = 0;
900 $count += preg_match_all('/(\.|#)/', $selector, $matchesarray);
901 if (strpos($selector, '.') !== 0 && strpos($selector, '#') !== 0) {
902 $count ++;
903 }
904 $this->count = $count;
905 $this->selectors[] = $selector;
906 }
907 /**
908 * Returns the number of individual components that make up this selector
909 * @return int
910 */
911 public function get_selector_count() {
912 return $this->count;
913 }
914
915 /**
916 * Returns the selector for use in a CSS rule
917 * @return string
918 */
919 public function out() {
1d1d807e 920 return css_writer::selector($this->selectors);
0e641c74
SH
921 }
922}
923
924/**
925 * A structure to represent a CSS rule.
926 *
927 * @package moodlecore
928 * @copyright 2011 Sam Hemelryk
929 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
930 */
931class css_rule {
932
933 /**
934 * An array of CSS selectors {@see css_selector}
935 * @var array
936 */
937 protected $selectors = array();
938
939 /**
940 * An array of CSS styles {@see css_style}
941 * @var array
942 */
943 protected $styles = array();
944
945 /**
946 * Created a new CSS rule. This is the only way to create a new CSS rule externally.
947 * @return css_rule
948 */
949 public static function init() {
950 return new css_rule();
951 }
952
953 /**
954 * Constructs a new css rule - this can only be called from within the scope of
955 * this class or its descendants.
956 *
957 * @param type $selector
958 * @param array $styles
959 */
960 protected function __construct($selector = null, array $styles = array()) {
961 if ($selector != null) {
962 if (is_array($selector)) {
963 $this->selectors = $selector;
964 } else {
965 $this->selectors = array($selector);
966 }
967 $this->add_styles($styles);
968 }
969 }
970
971 /**
972 * Adds a new CSS selector to this rule
973 *
974 * @param css_selector $selector
975 */
976 public function add_selector(css_selector $selector) {
977 $this->selectors[] = $selector;
978 }
979
980 /**
981 * Adds a new CSS style to this rule.
982 *
983 * @param css_style|string $style
984 */
985 public function add_style($style) {
986 if (is_string($style)) {
987 $style = trim($style);
988 if (empty($style)) {
989 return;
990 }
991 $bits = explode(':', $style, 2);
992 if (count($bits) == 2) {
993 list($name, $value) = array_map('trim', $bits);
994 }
995 if (isset($name) && isset($value) && $name !== '' && $value !== '') {
996 $style = css_style::init($name, $value);
997 }
1d1d807e
SH
998 } else if ($style instanceof css_style) {
999 $style = clone($style);
0e641c74
SH
1000 }
1001 if ($style instanceof css_style) {
1002 $name = $style->get_name();
1003 if (array_key_exists($name, $this->styles)) {
1004 $this->styles[$name]->set_value($style->get_value());
1005 } else {
1006 $this->styles[$name] = $style;
1007 }
1d1d807e
SH
1008 } else if (is_array($style)) {
1009 foreach ($style as $astyle) {
1010 $this->add_style($astyle);
1011 }
0e641c74
SH
1012 }
1013 }
1014
1015 /**
1016 * An easy method of adding several styles at once. Just calls add_style.
1017 *
1018 * @param array $styles
1019 */
1020 public function add_styles(array $styles) {
1021 foreach ($styles as $style) {
1022 $this->add_style($style);
1023 }
1024 }
1025
0e641c74
SH
1026 /**
1027 * Returns the array of selectors
1028 * @return array
1029 */
1030 public function get_selectors() {
1031 return $this->selectors;
1032 }
1033
1034 /**
1035 * Returns the array of styles
1036 * @return array
1037 */
1038 public function get_styles() {
1039 return $this->styles;
1040 }
1041
1042 /**
1043 * Outputs this rule as a fragment of CSS
1044 * @return string
1045 */
1046 public function out() {
1d1d807e
SH
1047 $selectors = css_writer::selectors($this->selectors);
1048 $styles = css_writer::styles($this->get_consolidated_styles());
1049 return css_writer::rule($selectors, $styles);
1050 }
1051
0abd4846
SH
1052 /**
1053 * Consolidates all styles associated with this rule
1054 *
1055 * @return array An array of consolidated styles
1056 */
1d1d807e
SH
1057 public function get_consolidated_styles() {
1058 $finalstyles = array();
1059 $consolidate = array();
1060 foreach ($this->styles as $style) {
1061 $consolidatetoclass = $style->consolidate_to();
50836f26 1062 if ($style->is_valid() && !empty($consolidatetoclass) && class_exists('css_style_'.$consolidatetoclass)) {
1d1d807e
SH
1063 $class = 'css_style_'.$consolidatetoclass;
1064 if (!array_key_exists($class, $consolidate)) {
1065 $consolidate[$class] = array();
1066 }
1067 $consolidate[$class][] = $style;
1068 } else {
1069 $finalstyles[] = $style;
1070 }
1071 }
1072
1073 foreach ($consolidate as $class => $styles) {
1074 $styles = $class::consolidate($styles);
1075 foreach ($styles as $style) {
1076 $finalstyles[] = $style;
1077 }
1078 }
1079 return $finalstyles;
0e641c74
SH
1080 }
1081
1082 /**
1083 * Splits this rules into an array of CSS rules. One for each of the selectors
1084 * that make up this rule.
1085 *
1086 * @return array(css_rule)
1087 */
1088 public function split_by_selector() {
1089 $return = array();
1090 foreach ($this->selectors as $selector) {
1091 $return[] = new css_rule($selector, $this->styles);
1092 }
1093 return $return;
1094 }
1095
1096 /**
1097 * Splits this rule into an array of rules. One for each of the styles that
1098 * make up this rule
1099 *
1100 * @return array(css_rule)
1101 */
1102 public function split_by_style() {
1103 $return = array();
1104 foreach ($this->styles as $style) {
1105 $return[] = new css_rule($this->selectors, array($style));
1106 }
1107 return $return;
1108 }
1109
1110 /**
1111 * Gets a hash for the styles of this rule
1112 * @return string
1113 */
1114 public function get_style_hash() {
1d1d807e 1115 return md5(css_writer::styles($this->styles));
0e641c74
SH
1116 }
1117
1118 /**
1119 * Gets a hash for the selectors of this rule
1120 * @return string
1121 */
1122 public function get_selector_hash() {
1d1d807e 1123 return md5(css_writer::selectors($this->selectors));
0e641c74
SH
1124 }
1125
1126 /**
1127 * Gets the number of selectors that make up this rule.
1128 * @return int
1129 */
1130 public function get_selector_count() {
1131 $count = 0;
1132 foreach ($this->selectors as $selector) {
1133 $count += $selector->get_selector_count();
1134 }
1135 return $count;
1136 }
1137}
1138
1139/**
1140 * A media class to organise rules by the media they apply to.
1141 *
1142 * @package moodlecore
1143 * @copyright 2011 Sam Hemelryk
1144 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1145 */
1146class css_media {
1147
1148 /**
1149 * An array of the different media types this instance applies to.
1150 * @var array
1151 */
1152 protected $types = array();
1153
1154 /**
1155 * An array of rules within this media instance
1156 * @var array
1157 */
1158 protected $rules = array();
1159
1160 /**
1161 * Initalises a new media instance
1162 *
1163 * @param type $for
1164 */
1165 public function __construct($for = 'all') {
1166 $types = explode(',', $for);
1167 $this->types = array_map('trim', $types);
1168 }
1169
1170 /**
1171 * Adds a new CSS rule to this media instance
1172 *
1173 * @param css_rule $newrule
1174 */
1175 public function add_rule(css_rule $newrule) {
1176 foreach ($newrule->split_by_selector() as $rule) {
1177 $hash = $rule->get_selector_hash();
1178 if (!array_key_exists($hash, $this->rules)) {
1179 $this->rules[$hash] = $rule;
1180 } else {
1181 $this->rules[$hash]->add_styles($rule->get_styles());
1182 }
1183 }
1184 }
1185
1186 /**
1187 * Returns the rules used by this
1188 *
1189 * @return array
1190 */
1191 public function get_rules() {
1192 return $this->rules;
1193 }
1194
1195 /**
1196 * Organises rules by gropuing selectors based upon the styles and consolidating
1197 * those selectors into single rules.
1198 *
1199 * @return array An array of optimised styles
1200 */
1201 public function organise_rules_by_selectors() {
1202 $optimised = array();
1203 $beforecount = count($this->rules);
1204 foreach ($this->rules as $rule) {
1205 $hash = $rule->get_style_hash();
1206 if (!array_key_exists($hash, $optimised)) {
1207 $optimised[$hash] = clone($rule);
1208 } else {
1209 foreach ($rule->get_selectors() as $selector) {
1210 $optimised[$hash]->add_selector($selector);
1211 }
1212 }
1213 }
1214 $this->rules = $optimised;
1215 $aftercount = count($this->rules);
1216 return ($beforecount < $aftercount);
1217 }
1218
1219 /**
1220 * Returns the total number of rules that exist within this media set
1221 *
1222 * @return int
1223 */
1224 public function count_rules() {
1225 return count($this->rules);
1226 }
1227
1228 /**
1229 * Returns the total number of selectors that exist within this media set
1230 *
1231 * @return int
1232 */
1233 public function count_selectors() {
1234 $count = 0;
1235 foreach ($this->rules as $rule) {
1236 $count += $rule->get_selector_count();
1237 }
1238 return $count;
1239 }
1240
1241 /**
1242 * Returns the CSS for this media and all of its rules.
1243 *
1244 * @return string
1245 */
1246 public function out() {
1d1d807e 1247 return css_writer::media(join(',', $this->types), $this->rules);
0e641c74
SH
1248 }
1249
1250 /**
1251 * Returns an array of media that this media instance applies to
1252 *
1253 * @return array
1254 */
1255 public function get_types() {
1256 return $this->types;
1257 }
1258}
1259
1260/**
1261 * An absract class to represent CSS styles
1262 *
1263 * @package moodlecore
1264 * @copyright 2011 Sam Hemelryk
1265 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1266 */
1267abstract class css_style {
1268
1269 /**
1270 * The name of the style
1271 * @var string
1272 */
1273 protected $name;
1274
1275 /**
1276 * The value for the style
1277 * @var mixed
1278 */
1279 protected $value;
1280
1281 /**
1282 * If set to true this style was defined with the !important rule.
1283 * @var bool
1284 */
1285 protected $important = false;
1286
1287 /**
1288 * Initialises a new style.
1289 *
1290 * This is the only public way to create a style to ensure they that appropriate
1291 * style class is used if it exists.
1292 *
1293 * @param type $name
1294 * @param type $value
1d1d807e 1295 * @return css_style_generic
0e641c74
SH
1296 */
1297 public static function init($name, $value) {
1298 $specificclass = 'css_style_'.preg_replace('#[^a-zA-Z0-9]+#', '', $name);
1299 if (class_exists($specificclass)) {
1300 return $specificclass::init($value);
1301 }
1302 return new css_style_generic($name, $value);
1303 }
1304
1305 /**
1306 * Creates a new style when given its name and value
1307 *
1308 * @param string $name
1309 * @param string $value
1310 */
1311 protected function __construct($name, $value) {
1312 $this->name = $name;
1313 $this->set_value($value);
1314 }
1315
1316 /**
1317 * Sets the value for the style
1318 *
1319 * @param string $value
1320 */
1321 final public function set_value($value) {
1322 $value = trim($value);
1323 $important = preg_match('#(\!important\s*;?\s*)$#', $value, $matches);
1324 if ($important) {
1325 $value = substr($value, 0, -(strlen($matches[1])));
1326 }
1327 if (!$this->important || $important) {
1328 $this->value = $this->clean_value($value);
1329 $this->important = $important;
1330 }
1331 }
1332
0abd4846
SH
1333 /**
1334 * Returns true if the value associated with this style is valid
1335 *
1336 * @return bool
1337 */
50836f26
SH
1338 public function is_valid() {
1339 return true;
1340 }
1341
0e641c74
SH
1342 /**
1343 * Returns the name for the style
1344 *
1345 * @return string
1346 */
1347 public function get_name() {
1348 return $this->name;
1349 }
1350
1351 /**
1352 * Returns the value for the style
1353 *
1354 * @return string
1355 */
1356 public function get_value() {
1357 $value = $this->value;
1358 if ($this->important) {
1359 $value .= ' !important';
1360 }
1361 return $value;
1362 }
1363
1364 /**
1365 * Returns the style ready for use in CSS
1366 *
1367 * @param string|null $value
1368 * @return string
1369 */
1370 public function out($value = null) {
1d1d807e 1371 if (is_null($value)) {
0e641c74 1372 $value = $this->get_value();
0e641c74 1373 }
1d1d807e 1374 return css_writer::style($this->name, $value, $this->important);
0e641c74
SH
1375 }
1376
1377 /**
1378 * This can be overridden by a specific style allowing it to clean its values
1379 * consistently.
1380 *
1381 * @param mixed $value
1382 * @return mixed
1383 */
1384 protected function clean_value($value) {
1385 return $value;
1386 }
1d1d807e 1387
0abd4846
SH
1388 /**
1389 * If this particular style can be consolidated into another style this function
1390 * should return the style that it can be consolidated into.
1391 *
1392 * @return string|null
1393 */
1d1d807e
SH
1394 public function consolidate_to() {
1395 return null;
1396 }
0e641c74
SH
1397}
1398
1399/**
1400 * A generic CSS style class to use when a more specific class does not exist.
1401 *
1402 * @package moodlecore
1403 * @copyright 2011 Sam Hemelryk
1404 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1405 */
1406class css_style_generic extends css_style {
1407 /**
1408 * Cleans incoming values for typical things that can be optimised.
1409 *
1410 * @param mixed $value
1411 * @return string
1412 */
1413 protected function clean_value($value) {
1414 if (trim($value) == '0px') {
1415 $value = 0;
1416 } else if (preg_match('/^#([a-fA-F0-9]{3,6})/', $value, $matches)) {
1417 $value = '#'.strtoupper($matches[1]);
1418 }
1419 return $value;
1420 }
1421}
1422
1423/**
1424 * A colour CSS style
1425 *
1426 * @package moodlecore
1427 * @copyright 2011 Sam Hemelryk
1428 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1429 */
1430class css_style_color extends css_style {
1431 /**
1432 * Creates a new colour style
1433 *
1434 * @param mixed $value
1435 * @return css_style_color
1436 */
1437 public static function init($value) {
1438 return new css_style_color('color', $value);
1439 }
1440
1441 /**
1442 * Cleans the colour unifing it to a 6 char hash colour if possible
1443 * Doing this allows us to associate identical colours being specified in
1444 * different ways. e.g. Red, red, #F00, and #F00000
1445 *
1446 * @param mixed $value
1447 * @return string
1448 */
1449 protected function clean_value($value) {
1450 $value = trim($value);
1451 if (preg_match('/#([a-fA-F0-9]{6})/', $value, $matches)) {
1452 $value = '#'.strtoupper($matches[1]);
1453 } else if (preg_match('/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/', $value, $matches)) {
1454 $value = $matches[1] . $matches[1] . $matches[2] . $matches[2] . $matches[3] . $matches[3];
1455 $value = '#'.strtoupper($value);
1456 } else if (array_key_exists(strtolower($value), css_optimiser::$htmlcolours)) {
1457 $value = css_optimiser::$htmlcolours[strtolower($value)];
1458 }
1459 return $value;
1460 }
1461
1462 /**
1463 * Returns the colour style for use within CSS.
1464 * Will return an optimised hash colour.
1465 *
1466 * e.g #123456
1467 * #123 instead of #112233
1468 * #F00 instead of red
1469 *
1470 * @param string $overridevalue
1471 * @return string
1472 */
1473 public function out($overridevalue = null) {
50836f26
SH
1474 if ($overridevalue === null) {
1475 $overridevalue = $this->value;
1476 }
1477 return parent::out(self::shrink_value($overridevalue));
1478 }
1479
0abd4846
SH
1480 /**
1481 * Shrinks the colour value is possible.
1482 *
1483 * @param string $value
1484 * @return string
1485 */
50836f26
SH
1486 public static function shrink_value($value) {
1487 if (preg_match('/#([a-fA-F0-9])\1([a-fA-F0-9])\2([a-fA-F0-9])\3/', $value, $matches)) {
1488 return '#'.$matches[1].$matches[2].$matches[3];
0e641c74 1489 }
50836f26
SH
1490 return $value;
1491 }
1492
0abd4846
SH
1493 /**
1494 * Returns true if the value is a valid colour.
1495 *
1496 * @return bool
1497 */
50836f26
SH
1498 public function is_valid() {
1499 return css_is_colour($this->value);
0e641c74
SH
1500 }
1501}
1502
0abd4846
SH
1503/**
1504 * A margin style
1505 *
1506 * @package moodlecore
1507 * @copyright 2011 Sam Hemelryk
1508 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1509 */
1d1d807e 1510class css_style_margin extends css_style {
0abd4846
SH
1511
1512 /**
1513 * Initialises a margin style.
1514 *
1515 * In this case we split the margin into several other margin styles so that
1516 * we can properly condense overrides and then reconsolidate them later into
1517 * an optimal form.
1518 *
1519 * @param string $value
1520 * @return array An array of margin values that can later be consolidated
1521 */
1d1d807e
SH
1522 public static function init($value) {
1523 $value = preg_replace('#\s+#', ' ', $value);
1524 $bits = explode(' ', $value, 4);
1525
1526 $top = $right = $bottom = $left = null;
1527 if (count($bits) > 0) {
1528 $top = $right = $bottom = $left = array_shift($bits);
1529 }
1530 if (count($bits) > 0) {
1531 $right = $left = array_shift($bits);
1532 }
1533 if (count($bits) > 0) {
1534 $bottom = array_shift($bits);
1535 }
1536 if (count($bits) > 0) {
1537 $left = array_shift($bits);
1538 }
1539 return array(
1540 new css_style_margintop('margin-top', $top),
1541 new css_style_marginright('margin-right', $right),
1542 new css_style_marginbottom('margin-bottom', $bottom),
1543 new css_style_marginleft('margin-left', $left)
1544 );
1545 }
0abd4846
SH
1546
1547 /**
1548 * Consolidates individual margin styles into a single margin style
1549 *
1550 * @param array $styles
1551 * @return array An array of consolidated styles
1552 */
1d1d807e
SH
1553 public static function consolidate(array $styles) {
1554 if (count($styles) != 4) {
1555 return $styles;
1556 }
1557 $top = $right = $bottom = $left = null;
1558 foreach ($styles as $style) {
1559 switch ($style->get_name()) {
1560 case 'margin-top' : $top = $style->get_value();break;
1561 case 'margin-right' : $right = $style->get_value();break;
1562 case 'margin-bottom' : $bottom = $style->get_value();break;
1563 case 'margin-left' : $left = $style->get_value();break;
1564 }
1565 }
1566 if ($top == $bottom && $left == $right) {
1567 if ($top == $left) {
1568 return array(new css_style_margin('margin', $top));
1569 } else {
1570 return array(new css_style_margin('margin', "{$top} {$left}"));
1571 }
1572 } else if ($left == $right) {
1573 return array(new css_style_margin('margin', "{$top} {$right} {$bottom}"));
1574 } else {
1575 return array(new css_style_margin('margin', "{$top} {$right} {$bottom} {$left}"));
1576 }
1d1d807e
SH
1577 }
1578}
1579
0abd4846
SH
1580/**
1581 * A margin top style
1582 *
1583 * @package moodlecore
1584 * @copyright 2011 Sam Hemelryk
1585 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1586 */
1d1d807e 1587class css_style_margintop extends css_style {
0abd4846
SH
1588 /**
1589 * A simple init, just a single style
1590 *
1591 * @param string $value
1592 * @return css_style_margintop
1593 */
1d1d807e
SH
1594 public static function init($value) {
1595 return new css_style_margintop('margin-top', $value);
1596 }
0abd4846
SH
1597 /**
1598 * This style can be consolidated into a single margin style
1599 *
1600 * @return string
1601 */
1d1d807e
SH
1602 public function consolidate_to() {
1603 return 'margin';
1604 }
1605}
1606
0abd4846
SH
1607/**
1608 * A margin right style
1609 *
1610 * @package moodlecore
1611 * @copyright 2011 Sam Hemelryk
1612 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1613 */
1d1d807e 1614class css_style_marginright extends css_style {
0abd4846
SH
1615 /**
1616 * A simple init, just a single style
1617 *
1618 * @param string $value
1619 * @return css_style_margintop
1620 */
1d1d807e
SH
1621 public static function init($value) {
1622 return new css_style_marginright('margin-right', $value);
1623 }
0abd4846
SH
1624 /**
1625 * This style can be consolidated into a single margin style
1626 *
1627 * @return string
1628 */
1d1d807e
SH
1629 public function consolidate_to() {
1630 return 'margin';
1631 }
1632}
1633
0abd4846
SH
1634/**
1635 * A margin bottom style
1636 *
1637 * @package moodlecore
1638 * @copyright 2011 Sam Hemelryk
1639 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1640 */
1d1d807e 1641class css_style_marginbottom extends css_style {
0abd4846
SH
1642 /**
1643 * A simple init, just a single style
1644 *
1645 * @param string $value
1646 * @return css_style_margintop
1647 */
1d1d807e
SH
1648 public static function init($value) {
1649 return new css_style_marginbottom('margin-bottom', $value);
1650 }
0abd4846
SH
1651 /**
1652 * This style can be consolidated into a single margin style
1653 *
1654 * @return string
1655 */
1d1d807e
SH
1656 public function consolidate_to() {
1657 return 'margin';
1658 }
1659}
1660
0abd4846
SH
1661/**
1662 * A margin left style
1663 *
1664 * @package moodlecore
1665 * @copyright 2011 Sam Hemelryk
1666 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1667 */
1d1d807e 1668class css_style_marginleft extends css_style {
0abd4846
SH
1669 /**
1670 * A simple init, just a single style
1671 *
1672 * @param string $value
1673 * @return css_style_margintop
1674 */
1d1d807e
SH
1675 public static function init($value) {
1676 return new css_style_marginleft('margin-left', $value);
1677 }
0abd4846
SH
1678 /**
1679 * This style can be consolidated into a single margin style
1680 *
1681 * @return string
1682 */
1d1d807e
SH
1683 public function consolidate_to() {
1684 return 'margin';
1685 }
1686}
1687
1688/**
1689 * A border style
1690 *
1691 * @package moodlecore
1692 * @copyright 2011 Sam Hemelryk
1693 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1694 */
1695class css_style_border extends css_style {
0abd4846
SH
1696 /**
1697 * Initalises the border style into an array of individual style compontents
1698 *
1699 * @param string $value
1700 * @return css_style_bordercolor
1701 */
1d1d807e
SH
1702 public static function init($value) {
1703 $value = preg_replace('#\s+#', ' ', $value);
1704 $bits = explode(' ', $value, 3);
1705
1706 $return = array();
1707 if (count($bits) > 0) {
1708 $width = array_shift($bits);
1709 $return[] = new css_style_borderwidth('border-width-top', $width);
1710 $return[] = new css_style_borderwidth('border-width-right', $width);
1711 $return[] = new css_style_borderwidth('border-width-bottom', $width);
1712 $return[] = new css_style_borderwidth('border-width-left', $width);
1713 }
1714 if (count($bits) > 0) {
1715 $style = array_shift($bits);
1716 $return[] = new css_style_borderstyle('border-style-top', $style);
1717 $return[] = new css_style_borderstyle('border-style-right', $style);
1718 $return[] = new css_style_borderstyle('border-style-bottom', $style);
1719 $return[] = new css_style_borderstyle('border-style-left', $style);
1720 }
1721 if (count($bits) > 0) {
1722 $colour = array_shift($bits);
1723 $return[] = new css_style_bordercolor('border-color-top', $colour);
1724 $return[] = new css_style_bordercolor('border-color-right', $colour);
1725 $return[] = new css_style_bordercolor('border-color-bottom', $colour);
1726 $return[] = new css_style_bordercolor('border-color-left', $colour);
1727 }
1728 return $return;
1729 }
0abd4846
SH
1730 /**
1731 * Consolidates all border styles into a single style
1732 *
1733 * @param array $styles
1734 * @return array
1735 */
1d1d807e
SH
1736 public static function consolidate(array $styles) {
1737
1738 $borderwidths = array('top' => null, 'right' => null, 'bottom' => null, 'left' => null);
1739 $borderstyles = array('top' => null, 'right' => null, 'bottom' => null, 'left' => null);
1740 $bordercolors = array('top' => null, 'right' => null, 'bottom' => null, 'left' => null);
1741
1742 foreach ($styles as $style) {
1743 switch ($style->get_name()) {
1744 case 'border-width-top': $borderwidths['top'] = $style->get_value(); break;
1745 case 'border-width-right': $borderwidths['right'] = $style->get_value(); break;
1746 case 'border-width-bottom': $borderwidths['bottom'] = $style->get_value(); break;
1747 case 'border-width-left': $borderwidths['left'] = $style->get_value(); break;
1748
1749 case 'border-style-top': $borderstyles['top'] = $style->get_value(); break;
1750 case 'border-style-right': $borderstyles['right'] = $style->get_value(); break;
1751 case 'border-style-bottom': $borderstyles['bottom'] = $style->get_value(); break;
1752 case 'border-style-left': $borderstyles['left'] = $style->get_value(); break;
1753
1754 case 'border-color-top': $bordercolors['top'] = $style->get_value(); break;
1755 case 'border-color-right': $bordercolors['right'] = $style->get_value(); break;
1756 case 'border-color-bottom': $bordercolors['bottom'] = $style->get_value(); break;
1757 case 'border-color-left': $bordercolors['left'] = $style->get_value(); break;
1758 }
1759 }
1760
1761 $uniquewidths = count(array_unique($borderwidths));
1762 $uniquestyles = count(array_unique($borderstyles));
1763 $uniquecolors = count(array_unique($bordercolors));
1764
1765 $nullwidths = in_array(null, $borderwidths);
1766 $nullstyles = in_array(null, $borderstyles);
1767 $nullcolors = in_array(null, $bordercolors);
1768
50836f26
SH
1769 $allwidthsthesame = ($uniquewidths === 1)?1:0;
1770 $allstylesthesame = ($uniquestyles === 1)?1:0;
1771 $allcolorsthesame = ($uniquecolors === 1)?1:0;
1d1d807e
SH
1772
1773 $allwidthsnull = $allwidthsthesame && $nullwidths;
1774 $allstylesnull = $allstylesthesame && $nullstyles;
1775 $allcolorsnull = $allcolorsthesame && $nullcolors;
1776
1777 $return = array();
1778 if ($allwidthsnull && $allstylesnull && $allcolorsnull) {
1779 // Everything is null still... boo
1780 return array(new css_style_border('border', ''));
1781
1782 } else if ($allwidthsnull && $allstylesnull) {
1783
1784 self::consolidate_styles_by_direction($return, 'css_style_bordercolor', 'border-color', $bordercolors);
1785 return $return;
1786
1787 } else if ($allwidthsnull && $allcolorsnull) {
1788
1789 self::consolidate_styles_by_direction($return, 'css_style_borderstyle', 'border-style', $borderstyles);
1790 return $return;
1791
1792 } else if ($allcolorsnull && $allstylesnull) {
1793
1794 self::consolidate_styles_by_direction($return, 'css_style_borderwidth', 'border-width', $borderwidths);
1795 return $return;
1796
1797 }
1798
1799 if ($allwidthsthesame + $allstylesthesame + $allcolorsthesame == 3) {
1800
1801 $return[] = new css_style_border('border', $borderwidths['top'].' '.$borderstyles['top'].' '.$bordercolors['top']);
0abd4846 1802
1d1d807e
SH
1803 } else if ($allwidthsthesame + $allstylesthesame + $allcolorsthesame == 2) {
1804
1805 if ($allwidthsthesame && $allstylesthesame && !$nullwidths && !$nullstyles) {
1806
1807 $return[] = new css_style_border('border', $borderwidths['top'].' '.$borderstyles['top']);
1808 self::consolidate_styles_by_direction($return, 'css_style_bordercolor', 'border-color', $bordercolors);
0abd4846 1809
1d1d807e
SH
1810 } else if ($allwidthsthesame && $allcolorsthesame && !$nullwidths && !$nullcolors) {
1811
1812 $return[] = new css_style_border('border', $borderwidths['top'].' solid '.$bordercolors['top']);
1813 self::consolidate_styles_by_direction($return, 'css_style_borderstyle', 'border-style', $borderstyles);
0abd4846 1814
1d1d807e
SH
1815 } else if ($allstylesthesame && $allcolorsthesame && !$nullstyles && !$nullcolors) {
1816
1817 $return[] = new css_style_border('border', '1px '.$borderstyles['top'].' '.$bordercolors['top']);
1818 self::consolidate_styles_by_direction($return, 'css_style_borderwidth', 'border-width', $borderwidths);
1819
1820 } else {
1821 self::consolidate_styles_by_direction($return, 'css_style_borderwidth', 'border-width', $borderwidths);
1822 self::consolidate_styles_by_direction($return, 'css_style_borderstyle', 'border-style', $borderstyles);
1823 self::consolidate_styles_by_direction($return, 'css_style_bordercolor', 'border-color', $bordercolors);
1824 }
1825
50836f26 1826 } else if (!$nullwidths && !$nullcolors && !$nullstyles && max(array_count_values($borderwidths)) == 3 && max(array_count_values($borderstyles)) == 3 && max(array_count_values($bordercolors)) == 3) {
1d1d807e
SH
1827 $widthkeys = array();
1828 $stylekeys = array();
1829 $colorkeys = array();
1830
1831 foreach ($borderwidths as $key => $value) {
1832 if (!array_key_exists($value, $widthkeys)) {
1833 $widthkeys[$value] = array();
1834 }
1835 $widthkeys[$value][] = $key;
1836 }
1837 usort($widthkeys, 'css_sort_by_count');
1838 $widthkeys = array_values($widthkeys);
1839
1840 foreach ($borderstyles as $key => $value) {
1841 if (!array_key_exists($value, $stylekeys)) {
1842 $stylekeys[$value] = array();
1843 }
1844 $stylekeys[$value][] = $key;
1845 }
1846 usort($stylekeys, 'css_sort_by_count');
1847 $stylekeys = array_values($stylekeys);
1848
1849 foreach ($bordercolors as $key => $value) {
1850 if (!array_key_exists($value, $colorkeys)) {
1851 $colorkeys[$value] = array();
1852 }
1853 $colorkeys[$value][] = $key;
1854 }
1855 usort($colorkeys, 'css_sort_by_count');
1856 $colorkeys = array_values($colorkeys);
1857
1858 if ($widthkeys == $stylekeys && $stylekeys == $colorkeys) {
1859 $key = $widthkeys[0][0];
50836f26 1860 self::build_style_string($return, 'css_style_border', 'border', $borderwidths[$key], $borderstyles[$key], $bordercolors[$key]);
1d1d807e 1861 $key = $widthkeys[1][0];
50836f26 1862 self::build_style_string($return, 'css_style_border'.$key, 'border-'.$key, $borderwidths[$key], $borderstyles[$key], $bordercolors[$key]);
1d1d807e
SH
1863 } else {
1864 self::build_style_string($return, 'css_style_bordertop', 'border-top', $borderwidths['top'], $borderstyles['top'], $bordercolors['top']);
1865 self::build_style_string($return, 'css_style_borderright', 'border-right', $borderwidths['right'], $borderstyles['right'], $bordercolors['right']);
1866 self::build_style_string($return, 'css_style_borderbottom', 'border-bottom', $borderwidths['bottom'], $borderstyles['bottom'], $bordercolors['bottom']);
1867 self::build_style_string($return, 'css_style_borderleft', 'border-left', $borderwidths['left'], $borderstyles['left'], $bordercolors['left']);
1868 }
1869 } else {
1870 self::build_style_string($return, 'css_style_bordertop', 'border-top', $borderwidths['top'], $borderstyles['top'], $bordercolors['top']);
1871 self::build_style_string($return, 'css_style_borderright', 'border-right', $borderwidths['right'], $borderstyles['right'], $bordercolors['right']);
1872 self::build_style_string($return, 'css_style_borderbottom', 'border-bottom', $borderwidths['bottom'], $borderstyles['bottom'], $bordercolors['bottom']);
1873 self::build_style_string($return, 'css_style_borderleft', 'border-left', $borderwidths['left'], $borderstyles['left'], $bordercolors['left']);
1874 }
1875 foreach ($return as $key => $style) {
1876 if ($style->get_value() == '') {
1877 unset($return[$key]);
1878 }
1879 }
1880 return $return;
1881 }
0abd4846
SH
1882 /**
1883 * Border styles get consolidated to a single border style.
1884 *
1885 * @return string
1886 */
1d1d807e
SH
1887 public function consolidate_to() {
1888 return 'border';
1889 }
0abd4846
SH
1890 /**
1891 *
1892 * @param array $array An array to add styles into during consolidation. Passed by reference.
1893 * @param string $class The class type to initalise
1894 * @param string $style The style to create
1895 * @param string|array $top The top value
1896 * @param string $right The right value
1897 * @param string $bottom The bottom value
1898 * @param string $left The left value
1899 * @return bool
1900 */
1d1d807e 1901 public static function consolidate_styles_by_direction(&$array, $class, $style, $top, $right = null, $bottom = null, $left = null) {
1d1d807e
SH
1902 if (is_array($top)) {
1903 $right = $top['right'];
1904 $bottom = $top['bottom'];
1905 $left = $top['left'];
1906 $top = $top['top'];
1907 }
1908
1909 if ($top == $bottom && $left == $right && $top == $left) {
1910 if ($top == null) {
1911 $array[] = new $class($style, '');
1912 } else {
1913 $array[] = new $class($style, $top);
1914 }
1915 } else if ($top == null || $right == null || $bottom == null || $left == null) {
1916 if ($top !== null) {
1917 $array[] = new $class($style.'-top', $top);
1918 }
1919 if ($right !== null) {
1920 $array[] = new $class($style.'-right', $right);
1921 }
1922 if ($bottom !== null) {
1923 $array[] = new $class($style.'-bottom', $bottom);
1924 }
1925 if ($left !== null) {
1926 $array[] = new $class($style.'-left', $left);
1927 }
1928 } else if ($top == $bottom && $left == $right) {
1929 $array[] = new $class($style, $top.' '.$right);
1930 } else if ($left == $right) {
1931 $array[] = new $class($style, $top.' '.$right.' '.$bottom);
1932 } else {
1933 $array[] = new $class($style, $top.' '.$right.' '.$bottom.' '.$left);
1934 }
1935 return true;
1936 }
0abd4846
SH
1937
1938 /**
1939 * Builds a border style for a set of width, style, and colour values
1940 *
1941 * @param array $array An array into which the generated style is added
1942 * @param string $class The class type to initialise
1943 * @param string $cssstyle The style to use
1944 * @param string $width The width of the border
1945 * @param string $style The style of the border
1946 * @param string $color The colour of the border
1947 * @return bool
1948 */
1d1d807e
SH
1949 public static function build_style_string(&$array, $class, $cssstyle, $width = null, $style = null, $color = null) {
1950 if (!is_null($width) && !is_null($style) && !is_null($color)) {
1951 $array[] = new $class($cssstyle, $width.' '.$style.' '.$color);
1952 } else if (!is_null($width) && !is_null($style) && is_null($color)) {
1953 $array[] = new $class($cssstyle, $width.' '.$style);
1954 } else if (!is_null($width) && is_null($style) && is_null($color)) {
1955 $array[] = new $class($cssstyle.'-width', $width);
1956 } else {
1957 if (!is_null($width)) $array[] = new $class($cssstyle.'-width', $width);
1958 if (!is_null($style)) $array[] = new $class($cssstyle.'-style', $style);
1959 if (!is_null($color)) $array[] = new $class($cssstyle.'-color', $color);
1960 }
1961 return true;
1962 }
1963}
1964
1d1d807e
SH
1965/**
1966 * A border colour style
1967 *
1968 * @package moodlecore
1969 * @copyright 2011 Sam Hemelryk
1970 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
1971 */
1972class css_style_bordercolor extends css_style_color {
1973 /**
1974 * Creates a new border colour style
1975 *
1976 * Based upon the colour style
1977 *
1978 * @param mixed $value
1979 * @return css_style_bordercolor
1980 */
1981 public static function init($value) {
1982 $value = preg_replace('#\s+#', ' ', $value);
1983 $bits = explode(' ', $value, 4);
1984
1985 $top = $right = $bottom = $left = null;
1986 if (count($bits) > 0) {
1987 $top = $right = $bottom = $left = array_shift($bits);
1988 }
1989 if (count($bits) > 0) {
1990 $right = $left = array_shift($bits);
1991 }
1992 if (count($bits) > 0) {
1993 $bottom = array_shift($bits);
1994 }
1995 if (count($bits) > 0) {
1996 $left = array_shift($bits);
1997 }
1998 return array(
50836f26
SH
1999 css_style_bordercolortop::init($top),
2000 css_style_bordercolorright::init($right),
2001 css_style_bordercolorbottom::init($bottom),
2002 css_style_bordercolorleft::init($left)
1d1d807e
SH
2003 );
2004 }
0abd4846
SH
2005 /**
2006 * Consolidate this to a single border style
2007 *
2008 * @return string
2009 */
1d1d807e
SH
2010 public function consolidate_to() {
2011 return 'border';
2012 }
0abd4846
SH
2013 /**
2014 * Cleans the value
2015 *
2016 * @param string $value
2017 * @return string
2018 */
1d1d807e
SH
2019 protected function clean_value($value) {
2020 $values = explode(' ', $value);
2021 $values = array_map('parent::clean_value', $values);
2022 return join (' ', $values);
2023 }
0abd4846
SH
2024 /**
2025 * Outputs this style
2026 *
2027 * @param string $overridevalue
2028 * @return string
2029 */
50836f26
SH
2030 public function out($overridevalue = null) {
2031 if ($overridevalue === null) {
2032 $overridevalue = $this->value;
2033 }
2034 $values = explode(' ', $overridevalue);
2035 $values = array_map('css_style_color::shrink_value', $values);
2036 return parent::out(join (' ', $values));
2037 }
1d1d807e
SH
2038}
2039
0abd4846
SH
2040/**
2041 * A border left style
2042 *
2043 * @package moodlecore
2044 * @copyright 2011 Sam Hemelryk
2045 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2046 */
1d1d807e 2047class css_style_borderleft extends css_style_generic {
0abd4846
SH
2048 /**
2049 * Initialises the border left style into individual components
2050 *
2051 * @param string $value
2052 * @return css_style_borderwidthleft|css_style_borderstyleleft|css_style_bordercolorleft
2053 */
1d1d807e
SH
2054 public static function init($value) {
2055 $value = preg_replace('#\s+#', ' ', $value);
2056 $bits = explode(' ', $value, 3);
2057
2058 $return = array();
2059 if (count($bits) > 0) {
50836f26 2060 $return[] = css_style_borderwidthleft::init(array_shift($bits));
1d1d807e
SH
2061 }
2062 if (count($bits) > 0) {
50836f26 2063 $return[] = css_style_borderstyleleft::init(array_shift($bits));
1d1d807e
SH
2064 }
2065 if (count($bits) > 0) {
50836f26 2066 $return[] = css_style_bordercolorleft::init(array_shift($bits));
1d1d807e
SH
2067 }
2068 return $return;
2069 }
0abd4846
SH
2070 /**
2071 * Consolidate this to a single border style
2072 *
2073 * @return string
2074 */
1d1d807e
SH
2075 public function consolidate_to() {
2076 return 'border';
2077 }
2078}
2079
0abd4846
SH
2080/**
2081 * A border right style
2082 *
2083 * @package moodlecore
2084 * @copyright 2011 Sam Hemelryk
2085 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2086 */
1d1d807e 2087class css_style_borderright extends css_style_generic {
0abd4846
SH
2088 /**
2089 * Initialises the border right style into individual components
2090 *
2091 * @param string $value
2092 * @return css_style_borderwidthright|css_style_borderstyleright|css_style_bordercolorright
2093 */
1d1d807e
SH
2094 public static function init($value) {
2095 $value = preg_replace('#\s+#', ' ', $value);
2096 $bits = explode(' ', $value, 3);
2097
2098 $return = array();
2099 if (count($bits) > 0) {
50836f26 2100 $return[] = css_style_borderwidthright::init(array_shift($bits));
1d1d807e
SH
2101 }
2102 if (count($bits) > 0) {
50836f26 2103 $return[] = css_style_borderstyleright::init(array_shift($bits));
1d1d807e
SH
2104 }
2105 if (count($bits) > 0) {
50836f26 2106 $return[] = css_style_bordercolorright::init(array_shift($bits));
1d1d807e
SH
2107 }
2108 return $return;
2109 }
0abd4846
SH
2110 /**
2111 * Consolidate this to a single border style
2112 *
2113 * @return string
2114 */
1d1d807e
SH
2115 public function consolidate_to() {
2116 return 'border';
2117 }
2118}
2119
0abd4846
SH
2120/**
2121 * A border top style
2122 *
2123 * @package moodlecore
2124 * @copyright 2011 Sam Hemelryk
2125 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2126 */
1d1d807e 2127class css_style_bordertop extends css_style_generic {
0abd4846
SH
2128 /**
2129 * Initialises the border top style into individual components
2130 *
2131 * @param string $value
2132 * @return css_style_borderwidthtop|css_style_borderstyletop|css_style_bordercolortop
2133 */
1d1d807e
SH
2134 public static function init($value) {
2135 $value = preg_replace('#\s+#', ' ', $value);
2136 $bits = explode(' ', $value, 3);
2137
2138 $return = array();
2139 if (count($bits) > 0) {
50836f26 2140 $return[] = css_style_borderwidthtop::init(array_shift($bits));
1d1d807e
SH
2141 }
2142 if (count($bits) > 0) {
50836f26 2143 $return[] = css_style_borderstyletop::init(array_shift($bits));
1d1d807e
SH
2144 }
2145 if (count($bits) > 0) {
50836f26 2146 $return[] = css_style_bordercolortop::init(array_shift($bits));
1d1d807e
SH
2147 }
2148 return $return;
2149 }
0abd4846
SH
2150 /**
2151 * Consolidate this to a single border style
2152 *
2153 * @return string
2154 */
1d1d807e
SH
2155 public function consolidate_to() {
2156 return 'border';
2157 }
2158}
2159
0abd4846
SH
2160/**
2161 * A border bottom style
2162 *
2163 * @package moodlecore
2164 * @copyright 2011 Sam Hemelryk
2165 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2166 */
1d1d807e 2167class css_style_borderbottom extends css_style_generic {
0abd4846
SH
2168 /**
2169 * Initialises the border bottom style into individual components
2170 *
2171 * @param string $value
2172 * @return css_style_borderwidthbottom|css_style_borderstylebottom|css_style_bordercolorbottom
2173 */
1d1d807e
SH
2174 public static function init($value) {
2175 $value = preg_replace('#\s+#', ' ', $value);
2176 $bits = explode(' ', $value, 3);
2177
2178 $return = array();
2179 if (count($bits) > 0) {
50836f26 2180 $return[] = css_style_borderwidthbottom::init(array_shift($bits));
1d1d807e
SH
2181 }
2182 if (count($bits) > 0) {
50836f26 2183 $return[] = css_style_borderstylebottom::init(array_shift($bits));
1d1d807e
SH
2184 }
2185 if (count($bits) > 0) {
50836f26 2186 $return[] = css_style_bordercolorbottom::init(array_shift($bits));
1d1d807e
SH
2187 }
2188 return $return;
2189 }
0abd4846
SH
2190 /**
2191 * Consolidate this to a single border style
2192 *
2193 * @return string
2194 */
1d1d807e
SH
2195 public function consolidate_to() {
2196 return 'border';
2197 }
2198}
2199
2200/**
2201 * A border width style
2202 *
2203 * @package moodlecore
2204 * @copyright 2011 Sam Hemelryk
2205 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2206 */
2207class css_style_borderwidth extends css_style_generic {
2208 /**
2209 * Creates a new border colour style
2210 *
2211 * Based upon the colour style
2212 *
2213 * @param mixed $value
2214 * @return css_style_borderwidth
2215 */
2216 public static function init($value) {
2217 $value = preg_replace('#\s+#', ' ', $value);
2218 $bits = explode(' ', $value, 4);
2219
2220 $top = $right = $bottom = $left = null;
2221 if (count($bits) > 0) {
2222 $top = $right = $bottom = $left = array_shift($bits);
2223 }
2224 if (count($bits) > 0) {
2225 $right = $left = array_shift($bits);
2226 }
2227 if (count($bits) > 0) {
2228 $bottom = array_shift($bits);
2229 }
2230 if (count($bits) > 0) {
2231 $left = array_shift($bits);
2232 }
2233 return array(
50836f26
SH
2234 css_style_borderwidthtop::init($top),
2235 css_style_borderwidthright::init($right),
2236 css_style_borderwidthbottom::init($bottom),
2237 css_style_borderwidthleft::init($left)
1d1d807e
SH
2238 );
2239 }
0abd4846
SH
2240 /**
2241 * Consolidate this to a single border style
2242 *
2243 * @return string
2244 */
1d1d807e
SH
2245 public function consolidate_to() {
2246 return 'border';
2247 }
2248}
2249
2250/**
2251 * A border style style
2252 *
2253 * @package moodlecore
2254 * @copyright 2011 Sam Hemelryk
2255 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2256 */
2257class css_style_borderstyle extends css_style_generic {
2258 /**
2259 * Creates a new border colour style
2260 *
2261 * Based upon the colour style
2262 *
2263 * @param mixed $value
2264 * @return css_style_borderstyle
2265 */
2266 public static function init($value) {
2267 $value = preg_replace('#\s+#', ' ', $value);
2268 $bits = explode(' ', $value, 4);
2269
2270 $top = $right = $bottom = $left = null;
2271 if (count($bits) > 0) {
2272 $top = $right = $bottom = $left = array_shift($bits);
2273 }
2274 if (count($bits) > 0) {
2275 $right = $left = array_shift($bits);
2276 }
2277 if (count($bits) > 0) {
2278 $bottom = array_shift($bits);
2279 }
2280 if (count($bits) > 0) {
2281 $left = array_shift($bits);
2282 }
2283 return array(
50836f26
SH
2284 css_style_borderstyletop::init($top),
2285 css_style_borderstyleright::init($right),
2286 css_style_borderstylebottom::init($bottom),
2287 css_style_borderstyleleft::init($left)
1d1d807e
SH
2288 );
2289 }
0abd4846
SH
2290 /**
2291 * Consolidate this to a single border style
2292 *
2293 * @return string
2294 */
1d1d807e
SH
2295 public function consolidate_to() {
2296 return 'border';
2297 }
2298}
2299
0abd4846
SH
2300/**
2301 * A border top colour style
2302 *
2303 * @package moodlecore
2304 * @copyright 2011 Sam Hemelryk
2305 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2306 */
50836f26 2307class css_style_bordercolortop extends css_style_color {
0abd4846
SH
2308 /**
2309 * Initialises this style object
2310 *
2311 * @param string $value
2312 * @return css_style_bordercolortop
2313 */
50836f26
SH
2314 public static function init($value) {
2315 return new css_style_bordercolortop('border-color-top', $value);
2316 }
0abd4846
SH
2317 /**
2318 * Consolidate this to a single border style
2319 *
2320 * @return string
2321 */
50836f26
SH
2322 public function consolidate_to() {
2323 return 'border';
2324 }
2325}
0abd4846
SH
2326
2327/**
2328 * A border left colour style
2329 *
2330 * @package moodlecore
2331 * @copyright 2011 Sam Hemelryk
2332 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2333 */
50836f26 2334class css_style_bordercolorleft extends css_style_color {
0abd4846
SH
2335 /**
2336 * Initialises this style object
2337 *
2338 * @param string $value
2339 * @return css_style_bordercolorleft
2340 */
50836f26
SH
2341 public static function init($value) {
2342 return new css_style_bordercolorleft('border-color-left', $value);
2343 }
0abd4846
SH
2344 /**
2345 * Consolidate this to a single border style
2346 *
2347 * @return string
2348 */
50836f26
SH
2349 public function consolidate_to() {
2350 return 'border';
2351 }
2352}
0abd4846
SH
2353
2354/**
2355 * A border right colour style
2356 *
2357 * @package moodlecore
2358 * @copyright 2011 Sam Hemelryk
2359 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2360 */
50836f26 2361class css_style_bordercolorright extends css_style_color {
0abd4846
SH
2362 /**
2363 * Initialises this style object
2364 *
2365 * @param string $value
2366 * @return css_style_bordercolorright
2367 */
50836f26
SH
2368 public static function init($value) {
2369 return new css_style_bordercolorright('border-color-right', $value);
2370 }
0abd4846
SH
2371 /**
2372 * Consolidate this to a single border style
2373 *
2374 * @return string
2375 */
50836f26
SH
2376 public function consolidate_to() {
2377 return 'border';
2378 }
2379}
0abd4846
SH
2380
2381/**
2382 * A border bottom colour style
2383 *
2384 * @package moodlecore
2385 * @copyright 2011 Sam Hemelryk
2386 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2387 */
50836f26 2388class css_style_bordercolorbottom extends css_style_color {
0abd4846
SH
2389 /**
2390 * Initialises this style object
2391 *
2392 * @param string $value
2393 * @return css_style_bordercolorbottom
2394 */
50836f26
SH
2395 public static function init($value) {
2396 return new css_style_bordercolorbottom('border-color-bottom', $value);
2397 }
0abd4846
SH
2398 /**
2399 * Consolidate this to a single border style
2400 *
2401 * @return string
2402 */
50836f26
SH
2403 public function consolidate_to() {
2404 return 'border';
2405 }
2406}
2407
0abd4846
SH
2408/**
2409 * A border width top style
2410 *
2411 * @package moodlecore
2412 * @copyright 2011 Sam Hemelryk
2413 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2414 */
50836f26 2415class css_style_borderwidthtop extends css_style_generic {
0abd4846
SH
2416 /**
2417 * Initialises this style object
2418 *
2419 * @param string $value
2420 * @return css_style_borderwidthtop
2421 */
50836f26
SH
2422 public static function init($value) {
2423 return new css_style_borderwidthtop('border-width-top', $value);
2424 }
0abd4846
SH
2425 /**
2426 * Consolidate this to a single border style
2427 *
2428 * @return string
2429 */
50836f26
SH
2430 public function consolidate_to() {
2431 return 'border';
2432 }
2433}
0abd4846
SH
2434
2435/**
2436 * A border width left style
2437 *
2438 * @package moodlecore
2439 * @copyright 2011 Sam Hemelryk
2440 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2441 */
50836f26 2442class css_style_borderwidthleft extends css_style_generic {
0abd4846
SH
2443 /**
2444 * Initialises this style object
2445 *
2446 * @param string $value
2447 * @return css_style_borderwidthleft
2448 */
50836f26
SH
2449 public static function init($value) {
2450 return new css_style_borderwidthleft('border-width-left', $value);
2451 }
0abd4846
SH
2452 /**
2453 * Consolidate this to a single border style
2454 *
2455 * @return string
2456 */
50836f26
SH
2457 public function consolidate_to() {
2458 return 'border';
2459 }
2460}
0abd4846
SH
2461
2462/**
2463 * A border width right style
2464 *
2465 * @package moodlecore
2466 * @copyright 2011 Sam Hemelryk
2467 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2468 */
50836f26 2469class css_style_borderwidthright extends css_style_generic {
0abd4846
SH
2470 /**
2471 * Initialises this style object
2472 *
2473 * @param string $value
2474 * @return css_style_borderwidthright
2475 */
50836f26
SH
2476 public static function init($value) {
2477 return new css_style_borderwidthright('border-width-right', $value);
2478 }
0abd4846
SH
2479 /**
2480 * Consolidate this to a single border style
2481 *
2482 * @return string
2483 */
50836f26
SH
2484 public function consolidate_to() {
2485 return 'border';
2486 }
2487}
0abd4846
SH
2488
2489/**
2490 * A border width bottom style
2491 *
2492 * @package moodlecore
2493 * @copyright 2011 Sam Hemelryk
2494 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2495 */
50836f26 2496class css_style_borderwidthbottom extends css_style_generic {
0abd4846
SH
2497 /**
2498 * Initialises this style object
2499 *
2500 * @param string $value
2501 * @return css_style_borderwidthbottom
2502 */
50836f26
SH
2503 public static function init($value) {
2504 return new css_style_borderwidthbottom('border-width-bottom', $value);
2505 }
0abd4846
SH
2506 /**
2507 * Consolidate this to a single border style
2508 *
2509 * @return string
2510 */
50836f26
SH
2511 public function consolidate_to() {
2512 return 'border';
2513 }
2514}
2515
0abd4846
SH
2516/**
2517 * A border top style
2518 *
2519 * @package moodlecore
2520 * @copyright 2011 Sam Hemelryk
2521 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2522 */
50836f26 2523class css_style_borderstyletop extends css_style_generic {
0abd4846
SH
2524 /**
2525 * Initialises this style object
2526 *
2527 * @param string $value
2528 * @return css_style_borderstyletop
2529 */
50836f26
SH
2530 public static function init($value) {
2531 return new css_style_borderstyletop('border-style-top', $value);
2532 }
0abd4846
SH
2533 /**
2534 * Consolidate this to a single border style
2535 *
2536 * @return string
2537 */
50836f26
SH
2538 public function consolidate_to() {
2539 return 'border';
2540 }
2541}
0abd4846
SH
2542
2543/**
2544 * A border left style
2545 *
2546 * @package moodlecore
2547 * @copyright 2011 Sam Hemelryk
2548 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2549 */
50836f26 2550class css_style_borderstyleleft extends css_style_generic {
0abd4846
SH
2551 /**
2552 * Initialises this style object
2553 *
2554 * @param string $value
2555 * @return css_style_borderstyleleft
2556 */
50836f26
SH
2557 public static function init($value) {
2558 return new css_style_borderstyleleft('border-style-left', $value);
2559 }
0abd4846
SH
2560 /**
2561 * Consolidate this to a single border style
2562 *
2563 * @return string
2564 */
50836f26
SH
2565 public function consolidate_to() {
2566 return 'border';
2567 }
2568}
0abd4846
SH
2569
2570/**
2571 * A border right style
2572 *
2573 * @package moodlecore
2574 * @copyright 2011 Sam Hemelryk
2575 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2576 */
50836f26 2577class css_style_borderstyleright extends css_style_generic {
0abd4846
SH
2578 /**
2579 * Initialises this style object
2580 *
2581 * @param string $value
2582 * @return css_style_borderstyleright
2583 */
50836f26
SH
2584 public static function init($value) {
2585 return new css_style_borderstyleright('border-style-right', $value);
2586 }
0abd4846
SH
2587 /**
2588 * Consolidate this to a single border style
2589 *
2590 * @return string
2591 */
50836f26
SH
2592 public function consolidate_to() {
2593 return 'border';
2594 }
2595}
0abd4846
SH
2596
2597/**
2598 * A border bottom style
2599 *
2600 * @package moodlecore
2601 * @copyright 2011 Sam Hemelryk
2602 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2603 */
50836f26 2604class css_style_borderstylebottom extends css_style_generic {
0abd4846
SH
2605 /**
2606 * Initialises this style object
2607 *
2608 * @return css_style_borderstylebottom
2609 */
50836f26
SH
2610 public static function init($value) {
2611 return new css_style_borderstylebottom('border-style-bottom', $value);
2612 }
0abd4846
SH
2613 /**
2614 * Consolidate this to a single border style
2615 *
2616 * @return string
2617 */
50836f26
SH
2618 public function consolidate_to() {
2619 return 'border';
2620 }
2621}
2622
0abd4846
SH
2623/**
2624 * A background style
2625 *
2626 * @package moodlecore
2627 * @copyright 2011 Sam Hemelryk
2628 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2629 */
1d1d807e
SH
2630class css_style_background extends css_style {
2631 public static function init($value) {
2632 // colour - image - repeat - attachment - position
2633
2634 $imageurl = null;
2635 if (preg_match('#url\(([^\)]+)\)#', $value, $matches)) {
2636 $imageurl = trim($matches[1]);
2637 $value = str_replace($matches[1], '', $value);
2638 }
2639
2640 $value = preg_replace('#\s+#', ' ', $value);
2641 $bits = explode(' ', $value);
2642
2643 $repeats = array('repeat', 'repeat-x', 'repeat-y', 'no-repeat', 'inherit');
2644 $attachments = array('scroll' , 'fixed', 'inherit');
2645
2646 $return = array();
2647 if (count($bits) > 0 && css_is_colour(reset($bits))) {
2648 $return[] = new css_style_backgroundcolor('background-color', array_shift($bits));
2649 }
2650 if (count($bits) > 0 && preg_match('#(none|inherit|url\(\))#', reset($bits))) {
2651 $image = array_shift($bits);
2652 if ($image == 'url()') {
2653 $image = "url({$imageurl})";
2654 }
2655 $return[] = new css_style_backgroundimage('background-image', $image);
2656 }
2657 if (count($bits) > 0 && in_array(reset($bits), $repeats)) {
2658 $return[] = new css_style_backgroundrepeat('background-repeat', array_shift($bits));
2659 }
2660 if (count($bits) > 0 && in_array(reset($bits), $attachments)) {
2661 // scroll , fixed, inherit
2662 $return[] = new css_style_backgroundattachment('background-attachment', array_shift($bits));
2663 }
2664 if (count($bits) > 0) {
2665 $return[] = new css_style_backgroundposition('background-position', join(' ',$bits));
2666 }
2667 return $return;
2668 }
0abd4846
SH
2669
2670 /**
2671 * Consolidates background styles into a single background style
2672 *
2673 * @param array $styles
2674 * @return array
2675 */
1d1d807e
SH
2676 public static function consolidate(array $styles) {
2677
2678 if (count($styles) < 1) {
2679 return $styles;
2680 }
2681
2682 $color = $image = $repeat = $attachment = $position = null;
2683 foreach ($styles as $style) {
2684 switch ($style->get_name()) {
50836f26 2685 case 'background-color' : $color = css_style_color::shrink_value($style->get_value()); break;
1d1d807e
SH
2686 case 'background-image' : $image = $style->get_value(); break;
2687 case 'background-repeat' : $repeat = $style->get_value(); break;
2688 case 'background-attachment' : $attachment = $style->get_value(); break;
2689 case 'background-position' : $position = $style->get_value(); break;
2690 }
2691 }
50836f26
SH
2692
2693 if ((is_null($image) || is_null($position) || is_null($repeat)) && ($image!= null || $position != null || $repeat != null)) {
2694 return $styles;
2695 }
2696
1d1d807e
SH
2697 $value = array();
2698 if (!is_null($color)) $value[] .= $color;
2699 if (!is_null($image)) $value[] .= $image;
2700 if (!is_null($repeat)) $value[] .= $repeat;
2701 if (!is_null($attachment)) $value[] .= $attachment;
2702 if (!is_null($position)) $value[] .= $position;
2703 return array(new css_style_background('background', join(' ', $value)));
2704 }
2705}
2706
0e641c74
SH
2707/**
2708 * A background colour style.
2709 *
2710 * Based upon the colour style.
2711 *
2712 * @package moodlecore
2713 * @copyright 2011 Sam Hemelryk
2714 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2715 */
2716class css_style_backgroundcolor extends css_style_color {
2717 /**
2718 * Creates a new background colour style
2719 *
2720 * @param mixed $value
2721 * @return css_style_backgroundcolor
2722 */
2723 public static function init($value) {
2724 return new css_style_backgroundcolor('background-color', $value);
2725 }
1d1d807e
SH
2726 public function consolidate_to() {
2727 return 'background';
2728 }
0e641c74
SH
2729}
2730
2731/**
1d1d807e 2732 * A background image style.
0e641c74
SH
2733 *
2734 * @package moodlecore
2735 * @copyright 2011 Sam Hemelryk
2736 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2737 */
1d1d807e 2738class css_style_backgroundimage extends css_style_generic {
0e641c74 2739 /**
1d1d807e 2740 * Creates a new background colour style
0e641c74 2741 *
1d1d807e
SH
2742 * @param mixed $value
2743 * @return css_style_backgroundimage
2744 */
2745 public static function init($value) {
2746 return new css_style_backgroundimage('background-image', $value);
2747 }
0abd4846
SH
2748 /**
2749 * Consolidates this style into a single background style
2750 *
2751 * @return type
2752 */
1d1d807e
SH
2753 public function consolidate_to() {
2754 return 'background';
2755 }
2756}
2757
2758/**
2759 * A background repeat style.
2760 *
2761 * @package moodlecore
2762 * @copyright 2011 Sam Hemelryk
2763 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2764 */
2765class css_style_backgroundrepeat extends css_style_generic {
2766 /**
2767 * Creates a new background colour style
0e641c74
SH
2768 *
2769 * @param mixed $value
1d1d807e 2770 * @return css_style_backgroundrepeat
0e641c74
SH
2771 */
2772 public static function init($value) {
1d1d807e
SH
2773 return new css_style_backgroundrepeat('background-repeat', $value);
2774 }
0abd4846
SH
2775 /**
2776 * Consolidates this style into a single background style
2777 *
2778 * @return type
2779 */
1d1d807e
SH
2780 public function consolidate_to() {
2781 return 'background';
0e641c74
SH
2782 }
2783}
2784
2785/**
1d1d807e 2786 * A background attachment style.
0e641c74
SH
2787 *
2788 * @package moodlecore
2789 * @copyright 2011 Sam Hemelryk
2790 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2791 */
1d1d807e
SH
2792class css_style_backgroundattachment extends css_style_generic {
2793 /**
2794 * Creates a new background colour style
2795 *
2796 * @param mixed $value
2797 * @return css_style_backgroundattachment
2798 */
2799 public static function init($value) {
2800 return new css_style_backgroundattachment('background-attachment', $value);
2801 }
0abd4846
SH
2802 /**
2803 * Consolidates this style into a single background style
2804 *
2805 * @return type
2806 */
1d1d807e
SH
2807 public function consolidate_to() {
2808 return 'background';
2809 }
2810}
2811
2812/**
2813 * A background position style.
2814 *
2815 * @package moodlecore
2816 * @copyright 2011 Sam Hemelryk
2817 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2818 */
2819class css_style_backgroundposition extends css_style_generic {
0e641c74 2820 /**
1d1d807e 2821 * Creates a new background colour style
0e641c74
SH
2822 *
2823 * @param mixed $value
1d1d807e 2824 * @return css_style_backgroundposition
0e641c74
SH
2825 */
2826 public static function init($value) {
1d1d807e
SH
2827 return new css_style_backgroundposition('background-position', $value);
2828 }
0abd4846
SH
2829 /**
2830 * Consolidates this style into a single background style
2831 *
2832 * @return type
2833 */
1d1d807e
SH
2834 public function consolidate_to() {
2835 return 'background';
2836 }
2837}
2838
0abd4846
SH
2839/**
2840 * A padding style.
2841 *
2842 * @package moodlecore
2843 * @copyright 2011 Sam Hemelryk
2844 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2845 */
1d1d807e 2846class css_style_padding extends css_style {
0abd4846
SH
2847 /**
2848 * Initialises this padding style into several individual padding styles
2849 *
2850 * @param string $value
2851 * @return array
2852 */
1d1d807e
SH
2853 public static function init($value) {
2854 $value = preg_replace('#\s+#', ' ', $value);
2855 $bits = explode(' ', $value, 4);
2856
2857 $top = $right = $bottom = $left = null;
2858 if (count($bits) > 0) {
2859 $top = $right = $bottom = $left = array_shift($bits);
2860 }
2861 if (count($bits) > 0) {
2862 $right = $left = array_shift($bits);
2863 }
2864 if (count($bits) > 0) {
2865 $bottom = array_shift($bits);
2866 }
2867 if (count($bits) > 0) {
2868 $left = array_shift($bits);
2869 }
2870 return array(
2871 new css_style_paddingtop('padding-top', $top),
2872 new css_style_paddingright('padding-right', $right),
2873 new css_style_paddingbottom('padding-bottom', $bottom),
2874 new css_style_paddingleft('padding-left', $left)
2875 );
2876 }
0abd4846
SH
2877 /**
2878 * Consolidates several padding styles into a single style.
2879 *
2880 * @param array $styles
2881 * @return array
2882 */
1d1d807e
SH
2883 public static function consolidate(array $styles) {
2884 if (count($styles) != 4) {
2885 return $styles;
2886 }
2887 $top = $right = $bottom = $left = null;
2888 foreach ($styles as $style) {
2889 switch ($style->get_name()) {
2890 case 'padding-top' : $top = $style->get_value();break;
2891 case 'padding-right' : $right = $style->get_value();break;
2892 case 'padding-bottom' : $bottom = $style->get_value();break;
2893 case 'padding-left' : $left = $style->get_value();break;
2894 }
2895 }
2896 if ($top == $bottom && $left == $right) {
2897 if ($top == $left) {
2898 return array(new css_style_padding('padding', $top));
2899 } else {
2900 return array(new css_style_padding('padding', "{$top} {$left}"));
2901 }
2902 } else if ($left == $right) {
2903 return array(new css_style_padding('padding', "{$top} {$right} {$bottom}"));
2904 } else {
2905 return array(new css_style_padding('padding', "{$top} {$right} {$bottom} {$left}"));
2906 }
2907
2908 }
2909}
2910
0abd4846
SH
2911/**
2912 * A padding top style.
2913 *
2914 * @package moodlecore
2915 * @copyright 2011 Sam Hemelryk
2916 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2917 */
1d1d807e 2918class css_style_paddingtop extends css_style {
0abd4846
SH
2919 /**
2920 * Initialises this style
2921 *
2922 * @param string $value
2923 * @return css_style_paddingtop
2924 */
1d1d807e
SH
2925 public static function init($value) {
2926 return new css_style_paddingtop('padding-top', $value);
2927 }
0abd4846
SH
2928 /**
2929 * Consolidates this style into a single padding style
2930 *
2931 * @return string
2932 */
1d1d807e
SH
2933 public function consolidate_to() {
2934 return 'padding';
2935 }
2936}
2937
0abd4846
SH
2938/**
2939 * A padding right style.
2940 *
2941 * @package moodlecore
2942 * @copyright 2011 Sam Hemelryk
2943 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2944 */
1d1d807e 2945class css_style_paddingright extends css_style {
0abd4846
SH
2946 /**
2947 * Initialises this style
2948 *
2949 * @param string $value
2950 * @return css_style_paddingright
2951 */
1d1d807e
SH
2952 public static function init($value) {
2953 return new css_style_paddingright('padding-right', $value);
2954 }
0abd4846
SH
2955 /**
2956 * Consolidates this style into a single padding style
2957 *
2958 * @return string
2959 */
1d1d807e
SH
2960 public function consolidate_to() {
2961 return 'padding';
2962 }
2963}
2964
0abd4846
SH
2965/**
2966 * A padding bottom style.
2967 *
2968 * @package moodlecore
2969 * @copyright 2011 Sam Hemelryk
2970 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2971 */
1d1d807e 2972class css_style_paddingbottom extends css_style {
0abd4846
SH
2973 /**
2974 * Initialises this style
2975 *
2976 * @param string $value
2977 * @return css_style_paddingbottom
2978 */
1d1d807e
SH
2979 public static function init($value) {
2980 return new css_style_paddingbottom('padding-bottom', $value);
2981 }
0abd4846
SH
2982 /**
2983 * Consolidates this style into a single padding style
2984 *
2985 * @return string
2986 */
1d1d807e
SH
2987 public function consolidate_to() {
2988 return 'padding';
2989 }
2990}
2991
0abd4846
SH
2992/**
2993 * A padding left style.
2994 *
2995 * @package moodlecore
2996 * @copyright 2011 Sam Hemelryk
2997 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2998 */
1d1d807e 2999class css_style_paddingleft extends css_style {
0abd4846
SH
3000 /**
3001 * Initialises this style
3002 *
3003 * @param string $value
3004 * @return css_style_paddingleft
3005 */
1d1d807e
SH
3006 public static function init($value) {
3007 return new css_style_paddingleft('padding-left', $value);
3008 }
0abd4846
SH
3009 /**
3010 * Consolidates this style into a single padding style
3011 *
3012 * @return string
3013 */
1d1d807e
SH
3014 public function consolidate_to() {
3015 return 'padding';
0e641c74
SH
3016 }
3017}