Merge branch 'MDL-40255_M25' of git://github.com/lazydaisy/moodle into MOODLE_25_STABLE
[moodle.git] / lib / tests / csslib_test.php
blob59134f1aa37e67d5ff44b830cb2528831e34dbd6
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.
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/>.
17 /**
18 * This file contains the unittests for the css optimiser in csslib.php
20 * @package core_css
21 * @category phpunit
22 * @copyright 2012 Sam Hemelryk
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die();
28 global $CFG;
29 require_once($CFG->libdir . '/csslib.php');
32 /**
33 * CSS optimiser test class
35 * @package core_css
36 * @category css
37 * @copyright 2012 Sam Hemelryk
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
40 class css_optimiser_testcase extends advanced_testcase {
42 protected $optimiser;
44 public function get_optimiser() {
45 if (!$this->optimiser instanceof css_optimiser) {
46 $this->optimiser = new css_optimiser;
48 return $this->optimiser;
51 /**
52 * Sets up the test class
54 protected function setUp() {
55 global $CFG;
56 parent::setUp();
57 // We need to disable these if they are enabled to that we can predict
58 // the output.
59 $CFG->cssoptimiserstats = false;
60 $CFG->cssoptimiserpretty = false;
62 $this->resetAfterTest(true);
65 /**
66 * Test the process method
68 public function test_process() {
69 $optimiser = new css_optimiser;
71 $this->try_broken_css_found_in_moodle();
72 $this->try_invalid_css_handling();
73 $this->try_bulk_processing();
74 $this->try_break_things();
75 $this->try_media_rules();
76 $this->try_keyframe_css_animation();
79 /**
80 * Background colour tests
82 * When testing background styles it is important to understand how the background shorthand works.
83 * background shorthand allows the following styles to be specified in a single "background" declaration:
84 * - background-color
85 * - background-image
86 * - background-repeat
87 * - background-attachment
88 * - background-position
90 * If the background shorthand is used it can contain one or more of those (preferabbly in that order).
91 * Important it does not need to contain all of them.
92 * However even if it doesn't contain values for all styles all of the styles will be affected.
93 * If a style is missed from the shorthand background style but has an existing value in the rule then the existing value
94 * is cleared.
96 * For example:
97 * .test {background: url(\'test.png\');background: bottom right;background:#123456;}
98 * will result in:
99 * .test {background:#123456;}
101 * And:
102 * .test {background-image: url(\'test.png\');background:#123456;}
103 * will result in:
104 * .test {background:#123456;}
106 * @param css_optimiser $optimiser
108 public function test_background() {
109 $optimiser = $this->get_optimiser();
111 $cssin = '.test {background-color: #123456;}';
112 $cssout = '.test{background-color:#123456;}';
113 $this->assertEquals($cssout, $optimiser->process($cssin));
115 $cssin = '.test {background: #123456;}';
116 $cssout = '.test{background:#123456;}';
117 $this->assertEquals($cssout, $optimiser->process($cssin));
119 $cssin = '.test {background-image: url(\'test.png\');}';
120 $cssout = '.test{background-image:url(\'test.png\');}';
121 $this->assertEquals($cssout, $optimiser->process($cssin));
123 $cssin = '.test {background: #123456 url(\'test.png\') no-repeat top left;}';
124 $cssout = '.test{background:#123456 url(\'test.png\') no-repeat top left;}';
125 $this->assertEquals($cssout, $optimiser->process($cssin));
127 // Check out this for madness, background position and background-repeat have been reversed
128 $cssin = '.test {background: #123456 url(\'test.png\') center no-repeat;}';
129 $cssout = '.test{background:#123456 url(\'test.png\') no-repeat center;}';
130 $this->assertEquals($cssout, $optimiser->process($cssin));
132 $cssin = '.test {background: url(\'test.png\') no-repeat top left;}.test{background-position: bottom right}.test {background-color:#123456;}';
133 $cssout = '.test{background:#123456 url(\'test.png\') no-repeat bottom right;}';
134 $this->assertEquals($cssout, $optimiser->process($cssin));
136 $cssin = '.test {background: url( \'test.png\' )}.test{background: bottom right}.test {background:#123456;}';
137 $cssout = '.test{background:#123456;}';
138 $this->assertEquals($cssout, $optimiser->process($cssin));
140 $cssin = '.test {background-image: url(\'test.png\');background:#123456;}';
141 $cssout = '.test{background:#123456;}';
142 $this->assertEquals($cssout, $optimiser->process($cssin));
144 $cssin = '.test {background-color: #123456;background-repeat: repeat-x; background-position: 100% 0%;}';
145 $cssout = '.test{background-color:#123456;background-repeat:repeat-x;background-position:100% 0%;}';
146 $this->assertEquals($cssout, $optimiser->process($cssin));
148 $cssin = '.tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
149 .tree_item.branch.navigation_node {background-image:none;padding-left:0;}';
150 $cssout = '.tree_item.branch{background-image:url([[pix:t/expanded]]);background-position:0 10%;background-repeat:no-repeat;} .tree_item.branch.navigation_node{background-image:none;padding-left:0;}';
151 $this->assertEquals($cssout, $optimiser->process($cssin));
153 $cssin = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
154 $cssout = '#nextLink{background:url(data:image/gif;base64,AAAA);}';
155 $this->assertEquals($cssout, $optimiser->process($cssin));
157 $cssin = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
158 $cssout = '#nextLink{background-image:url(data:image/gif;base64,AAAA);}';
159 $this->assertEquals($cssout, $optimiser->process($cssin));
161 $cssin = '.test {background: #123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
162 $cssout = '.test{background:#123456 url(data:image/gif;base64,AAAA) no-repeat top left;}';
163 $this->assertEquals($cssout, $optimiser->process($cssin));
165 $cssin = '#test {background-image:none;background-position:right center;background-repeat:no-repeat;}';
166 $cssout = '#test{background-image:none;background-position:right center;background-repeat:no-repeat;}';
167 $this->assertEquals($cssout, $optimiser->process($cssin));
169 $cssin = '.test {background: url([[pix:theme|photos]]) no-repeat 50% 50%;background-size: 40px 40px;-webkit-background-size: 40px 40px;}';
170 $cssout = '.test{background:url([[pix:theme|photos]]) no-repeat 50% 50%;background-size:40px 40px;-webkit-background-size:40px 40px;}';
171 $this->assertEquals($cssout, $optimiser->process($cssin));
173 $cssin = '.test{background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
174 $cssout = '.test{background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
175 $this->assertEquals($cssout, $optimiser->process($cssin));
177 $cssin = '.test{background-image: -moz-linear-gradient(#3c3c3c, #111);background-image: -webkit-linear-gradient(#3c3c3c, #111);background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);background-image: url(/test.png);}';
178 $cssout = '.test{background-image:-moz-linear-gradient(#3c3c3c, #111);background-image:-webkit-linear-gradient(#3c3c3c, #111);background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);background-image:url(/test.png);}';
179 $cssout = '.test{background-image:url(/test.png);background-image:-moz-linear-gradient(#3c3c3c, #111);background-image:-webkit-linear-gradient(#3c3c3c, #111);background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
180 $this->assertEquals($cssout, $optimiser->process($cssin));
182 $cssin = '.test{background:#CCC; background-image: url(test.png);}';
183 $cssout = '.test{background:#CCC url(test.png);}';
184 $this->assertEquals($cssout, $optimiser->process($cssin));
186 $cssin = '.test{background:#CCC; background-image: linear-gradient(#3c3c3c, #111);}';
187 $cssout = '.test{background:#CCC;background-image:linear-gradient(#3c3c3c, #111);}';
188 $this->assertEquals($cssout, $optimiser->process($cssin));
190 $cssin = '.test{background:#CCC; background-image: -o-linear-gradient(#3c3c3c, #111);background-image: linear-gradient(#3c3c3c, #111);}';
191 $cssout = '.test{background:#CCC;background-image:-o-linear-gradient(#3c3c3c, #111);background-image:linear-gradient(#3c3c3c, #111);}';
192 $this->assertEquals($cssout, $optimiser->process($cssin));
194 $cssin = '#newmessageoverlay{font-weight: normal; border: 1px solid #222; background: #444; color: #ddd; text-shadow: 0 -1px 0px #000; background-image: -moz-linear-gradient(top, #333 0%, #333 5%, #444 15%, #444 60%, #222 100%); background-image: -webkit-gradient(linear, center top, center bottom, color-stop(0, #333), color-stop(5%, #333), color-stop(15%, #444), color-stop(60%, #444), color-stop(1, #222)); -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorStr=\'#333333\', EndColorStr=\'#222222\')"; padding:20px; padding-left: 0px; padding-right: 10px; position: inherit; z-index: 9999; width: 90%; margin-left: auto; margin-right: auto; height: 100%;}';
195 $cssout = '#newmessageoverlay{font-weight:normal;border:1px solid #222;background:#444;color:#DDD;text-shadow:0 -1px 0px #000;-ms-filter:"progid:DXImageTransform.Microsoft.gradient(startColorStr=\'#333333\', EndColorStr=\'#222222\')";padding:20px 10px 20px 0;position:inherit;z-index:9999;width:90%;margin-left:auto;margin-right:auto;height:100%;background-image:-moz-linear-gradient(top, #333 0%, #333 5%, #444 15%, #444 60%, #222 100%);background-image:-webkit-gradient(linear, center top, center bottom, color-stop(0, #333), color-stop(5%, #333), color-stop(15%, #444), color-stop(60%, #444), color-stop(1, #222));}';
196 $this->assertEquals($cssout, $optimiser->process($cssin));
198 $cssin = '.userenrolment {background-color:inherit !important;background: inherit !important;}';
199 $cssout = '.userenrolment{background:inherit !important;}';
200 $this->assertEquals($cssout, $optimiser->process($cssin));
202 $cssin = '.userenrolment {background-image:url(test.png) !important;background: inherit !important;}';
203 $cssout = '.userenrolment{background:inherit !important;}';
204 $this->assertEquals($cssout, $optimiser->process($cssin));
206 $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png) !important;}';
207 $cssout = '.userenrolment{background:inherit url(test.png) !important;}';
208 $this->assertEquals($cssout, $optimiser->process($cssin));
210 $cssin = '.userenrolment {background: inherit !important;background-image:url(test.png);}';
211 $cssout = '.userenrolment{background:inherit !important;}';
212 $this->assertEquals($cssout, $optimiser->process($cssin));
214 $css = '#filesskin .yui3-widget-hd{background:#CCC;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC));background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC);}';
215 $this->assertEquals($css, $optimiser->process($css));
217 $css = '.userenrolment{background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}';
218 $this->assertEquals($css, $optimiser->process($css));
220 $css = '.userenrolment{background:#CCC !important;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC)) !important;background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}';
221 $this->assertEquals($css, $optimiser->process($css));
223 $cssin = '.userenrolment{background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;}.userenrolment {background: #CCCCCC!important;background: -webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC))!important;}';
224 $cssout = '.userenrolment{background:#CCC !important;background:-moz-linear-gradient(top, #FFFFFF, #CCCCCC) !important;background:-webkit-gradient(linear, left top, left bottom, from(#FFFFFF), to(#CCCCCC)) !important;}';
225 $this->assertEquals($cssout, $optimiser->process($cssin));
229 * Border tests
230 * @param css_optimiser $optimiser
232 public function test_borders() {
233 $optimiser = $this->get_optimiser();
235 $cssin = '.test {border: 1px solid #654321} .test {border-bottom-color: #123456}';
236 $cssout = '.test{border:1px solid;border-color:#654321 #654321 #123456;}';
237 $this->assertEquals($cssout, $optimiser->process($cssin));
239 $cssin = '.one {border:1px solid red;}';
240 $cssout = '.one{border:1px solid #F00;}';
241 $this->assertEquals($cssout, $optimiser->process($cssin));
243 $cssin = '.one {border:1px solid;} .one {border:2px dotted #DDD;}';
244 $cssout = '.one{border:2px dotted #DDD;}';
245 $this->assertEquals($cssout, $optimiser->process($cssin));
247 $cssin = '.one {border:2px dotted #DDD;}.one {border:1px solid;} ';
248 $cssout = '.one{border:1px solid #DDD;}';
249 $this->assertEquals($cssout, $optimiser->process($cssin));
251 $cssin = '.one, .two {border:1px solid red;}';
252 $cssout = ".one, .two{border:1px solid #F00;}";
253 $this->assertEquals($cssout, $optimiser->process($cssin));
255 $cssin = '.one, .two {border:0px;}';
256 $cssout = ".one, .two{border-width:0;}";
257 $this->assertEquals($cssout, $optimiser->process($cssin));
259 $cssin = '.one, .two {border: thin;}';
260 $cssout = ".one, .two{border-width:thin;}";
261 $this->assertEquals($cssout, $optimiser->process($cssin));
263 $cssin = '.one, .two {border: thin solid black;}';
264 $cssout = ".one, .two{border:thin solid #000;}";
265 $this->assertEquals($cssout, $optimiser->process($cssin));
267 $cssin = '.one, .two {border-top: 5px solid white;}';
268 $cssout = ".one, .two{border-top:5px solid #FFF;}";
269 $this->assertEquals($cssout, $optimiser->process($cssin));
271 $cssin = '.one {border:1px solid red;} .two {border:1px solid red;}';
272 $cssout = ".one, .two{border:1px solid #F00;}";
273 $this->assertEquals($cssout, $optimiser->process($cssin));
275 $cssin = '.one {border:1px solid red;width:20px;} .two {border:1px solid red;height:20px;}';
276 $cssout = ".one{border:1px solid #F00;width:20px;} .two{border:1px solid #F00;height:20px;}";
277 $this->assertEquals($cssout, $optimiser->process($cssin));
279 $cssin = '.test {border: 1px solid #123456;} .test {border-color: #654321}';
280 $cssout = '.test{border:1px solid #654321;}';
281 $this->assertEquals($cssout, $optimiser->process($cssin));
283 $cssin = '.test {border-width: 1px; border-style: solid; border-color: #123456;}';
284 $cssout = '.test{border:1px solid #123456;}';
285 $this->assertEquals($cssout, $optimiser->process($cssin));
287 $cssin = '.test {border:1px solid #123456;border-top:2px dotted #654321;}';
288 $cssout = '.test{border:1px solid #123456;border-top:2px dotted #654321;}';
289 $this->assertEquals($cssout, $optimiser->process($cssin));
291 $cssin = '.test {border:1px solid #123456;border-left:2px dotted #654321;}';
292 $cssout = '.test{border:1px solid #123456;border-left:2px dotted #654321;}';
293 $this->assertEquals($cssout, $optimiser->process($cssin));
295 $cssin = '.test {border-left:2px dotted #654321;border:1px solid #123456;}';
296 $cssout = '.test{border:1px solid #123456;}';
297 $this->assertEquals($cssout, $optimiser->process($cssin));
299 $cssin = '.test {border:1px solid;border-top-color:#123456;}';
300 $cssout = '.test{border:1px solid;border-top-color:#123456;}';
301 $this->assertEquals($cssout, $optimiser->process($cssin));
303 $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;}';
304 $cssout = '.test{border:1px solid;border-top-color:#111;border-bottom-color:#222;border-left-color:#333;}';
305 $this->assertEquals($cssout, $optimiser->process($cssin));
307 $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;border-right-color:#444;}';
308 $cssout = '.test{border:1px solid;border-color:#111 #444 #222 #333;}';
309 $this->assertEquals($cssout, $optimiser->process($cssin));
311 $cssin = '.generaltable .cell {border-color:#EEE;} .generaltable .cell {border-width: 1px;border-style: solid;}';
312 $cssout = '.generaltable .cell{border:1px solid #EEE;}';
313 $this->assertEquals($cssout, $optimiser->process($cssin));
315 $cssin = '#page-admin-roles-override .rolecap {border:none;border-bottom:1px solid #CECECE;}';
316 $cssout = '#page-admin-roles-override .rolecap{border-top:0;border-right:0;border-bottom:1px solid #CECECE;border-left:0;}';
317 $this->assertEquals($cssout, $optimiser->process($cssin));
321 * Test colour styles
322 * @param css_optimiser $optimiser
324 public function test_colors() {
325 $optimiser = $this->get_optimiser();
327 $css = '.css{}';
328 $this->assertEquals($css, $optimiser->process($css));
330 $css = '.css{color:#123456;}';
331 $this->assertEquals($css, $optimiser->process($css));
333 $css = '#some{color:#123456;}';
334 $this->assertEquals($css, $optimiser->process($css));
336 $css = 'div{color:#123456;}';
337 $this->assertEquals($css, $optimiser->process($css));
339 $css = 'div.css{color:#123456;}';
340 $this->assertEquals($css, $optimiser->process($css));
342 $css = 'div#some{color:#123456;}';
343 $this->assertEquals($css, $optimiser->process($css));
345 $css = 'div[type=blah]{color:#123456;}';
346 $this->assertEquals($css, $optimiser->process($css));
348 $css = 'div.css[type=blah]{color:#123456;}';
349 $this->assertEquals($css, $optimiser->process($css));
351 $css = 'div#some[type=blah]{color:#123456;}';
352 $this->assertEquals($css, $optimiser->process($css));
354 $css = '#some.css[type=blah]{color:#123456;}';
355 $this->assertEquals($css, $optimiser->process($css));
357 $css = '#some .css[type=blah]{color:#123456;}';
358 $this->assertEquals($css, $optimiser->process($css));
360 $cssin = '.one {color:red;} .two {color:#F00;}';
361 $cssout = ".one, .two{color:#F00;}";
362 $this->assertEquals($cssout, $optimiser->process($cssin));
364 $cssin = '.one {color:#123;color:#321;}';
365 $cssout = '.one{color:#321;}';
366 $this->assertEquals($cssout, $optimiser->process($cssin));
368 $cssin = '.one {color:#123; color : #321 ;}';
369 $cssout = '.one{color:#321;}';
370 $this->assertEquals($cssout, $optimiser->process($cssin));
372 $cssin = '.one {color:#123;} .one {color:#321;}';
373 $cssout = '.one{color:#321;}';
374 $this->assertEquals($cssout, $optimiser->process($cssin));
376 $cssin = '.one {color:#123 !important;color:#321;}';
377 $cssout = '.one{color:#123 !important;}';
378 $this->assertEquals($cssout, $optimiser->process($cssin));
380 $cssin = '.one {color:#123 !important;} .one {color:#321;}';
381 $cssout = '.one{color:#123 !important;}';
382 $this->assertEquals($cssout, $optimiser->process($cssin));
384 $cssin = '.one {color:#123!important;} .one {color:#321;}';
385 $cssout = '.one{color:#123 !important;}';
386 $this->assertEquals($cssout, $optimiser->process($cssin));
388 $cssin = '.one {color:rgb(255, 128, 1)}';
389 $cssout = '.one{color:rgb(255, 128, 1);}';
390 $this->assertEquals($cssout, $optimiser->process($cssin));
392 $cssin = '.one {color:rgba(255, 128, 1, 0.5)}';
393 $cssout = '.one{color:rgba(255, 128, 1, 0.5);}';
394 $this->assertEquals($cssout, $optimiser->process($cssin));
396 $cssin = '.one {color:hsl(120, 65%, 75%)}';
397 $cssout = '.one{color:hsl(120, 65%, 75%);}';
398 $this->assertEquals($cssout, $optimiser->process($cssin));
400 $cssin = '.one {color:hsla(120,65%,75%,0.5)}';
401 $cssout = '.one{color:hsla(120,65%,75%,0.5);}';
402 $this->assertEquals($cssout, $optimiser->process($cssin));
404 // Try some invalid colours to make sure we don't mangle them.
405 $css = 'div#some{color:#1;}';
406 $this->assertEquals($css, $optimiser->process($css));
408 $css = 'div#some{color:#12;}';
409 $this->assertEquals($css, $optimiser->process($css));
411 $css = 'div#some{color:#1234;}';
412 $this->assertEquals($css, $optimiser->process($css));
414 $css = 'div#some{color:#12345;}';
415 $this->assertEquals($css, $optimiser->process($css));
418 public function test_widths() {
419 $optimiser = $this->get_optimiser();
421 $cssin = '.css {width:0}';
422 $cssout = '.css{width:0;}';
423 $this->assertEquals($cssout, $optimiser->process($cssin));
425 $cssin = '.css {width:0px}';
426 $cssout = '.css{width:0;}';
427 $this->assertEquals($cssout, $optimiser->process($cssin));
429 $cssin = '.css {width:0em}';
430 $cssout = '.css{width:0;}';
431 $this->assertEquals($cssout, $optimiser->process($cssin));
433 $cssin = '.css {width:0pt}';
434 $cssout = '.css{width:0;}';
435 $this->assertEquals($cssout, $optimiser->process($cssin));
437 $cssin = '.css {width:0mm}';
438 $cssout = '.css{width:0;}';
439 $this->assertEquals($cssout, $optimiser->process($cssin));
441 $cssin = '.css {width:100px}';
442 $cssout = '.css{width:100px;}';
443 $this->assertEquals($cssout, $optimiser->process($cssin));
447 * Test margin styles
448 * @param css_optimiser $optimiser
450 public function test_margins() {
451 $optimiser = $this->get_optimiser();
453 $cssin = '.one {margin: 1px 2px 3px 4px}';
454 $cssout = '.one{margin:1px 2px 3px 4px;}';
455 $this->assertEquals($cssout, $optimiser->process($cssin));
457 $cssin = '.one {margin-top:1px; margin-left:4px; margin-right:2px; margin-bottom: 3px;}';
458 $cssout = '.one{margin:1px 2px 3px 4px;}';
459 $this->assertEquals($cssout, $optimiser->process($cssin));
461 $cssin = '.one {margin-top:1px; margin-left:4px;}';
462 $cssout = '.one{margin-top:1px;margin-left:4px;}';
463 $this->assertEquals($cssout, $optimiser->process($cssin));
465 $cssin = '.one {margin:1px; margin-left:4px;}';
466 $cssout = '.one{margin:1px 1px 1px 4px;}';
467 $this->assertEquals($cssout, $optimiser->process($cssin));
469 $cssin = '.one {margin:1px; margin-bottom:4px;}';
470 $cssout = '.one{margin:1px 1px 4px;}';
471 $this->assertEquals($cssout, $optimiser->process($cssin));
473 $cssin = '.one, .two, .one.two, .one .two {margin:0;} .one.two {margin:0 7px;}';
474 $cssout = '.one, .two{margin:0;} .one.two{margin:0 7px;} .one .two{margin:0;}';
475 $this->assertEquals($cssout, $optimiser->process($cssin));
477 $cssin = '.block {margin-top: 0px !important;margin-bottom: 0px !important;}';
478 $cssout = '.block{margin-top:0 !important;margin-bottom:0 !important;}';
479 $this->assertEquals($cssout, $optimiser->process($cssin));
481 $cssin = '.block {margin: 0px !important;margin-bottom: 3px;}';
482 $cssout = '.block{margin:0 !important;}';
483 $this->assertEquals($cssout, $optimiser->process($cssin));
485 $cssin = '.block {margin: 5px;margin-right: 0 !important;}';
486 $cssout = '.block{margin:5px;margin-right:0 !important;}';
487 $this->assertEquals($cssout, $optimiser->process($cssin));
491 * Test padding styles
493 * @param css_optimiser $optimiser
495 public function test_padding() {
496 $optimiser = $this->get_optimiser();
498 $cssin = '.one {padding: 1px 2px 3px 4px}';
499 $cssout = '.one{padding:1px 2px 3px 4px;}';
500 $this->assertEquals($cssout, $optimiser->process($cssin));
502 $cssin = '.one {padding-top:1px; padding-left:4px; padding-right:2px; padding-bottom: 3px;}';
503 $cssout = '.one{padding:1px 2px 3px 4px;}';
504 $this->assertEquals($cssout, $optimiser->process($cssin));
506 $cssin = '.one {padding-top:1px; padding-left:4px;padding-bottom: 3px;}';
507 $cssout = '.one{padding-top:1px;padding-left:4px;padding-bottom:3px;}';
508 $this->assertEquals($cssout, $optimiser->process($cssin));
510 $cssin = '.one {padding-top:1px; padding-left:4px;}';
511 $cssout = '.one{padding-top:1px;padding-left:4px;}';
512 $this->assertEquals($cssout, $optimiser->process($cssin));
514 $cssin = '.one {padding:1px; padding-left:4px;}';
515 $cssout = '.one{padding:1px 1px 1px 4px;}';
516 $this->assertEquals($cssout, $optimiser->process($cssin));
518 $cssin = '.one {padding:1px; padding-bottom:4px;}';
519 $cssout = '.one{padding:1px 1px 4px;}';
520 $this->assertEquals($cssout, $optimiser->process($cssin));
522 $cssin = '.one {padding:0 !important;}';
523 $cssout = '.one{padding:0 !important;}';
524 $this->assertEquals($cssout, $optimiser->process($cssin));
526 $cssin = '.one {padding:0 !important;}';
527 $cssout = '.one{padding:0 !important;}';
528 $this->assertEquals($cssout, $optimiser->process($cssin));
530 $cssin = '.one, .two, .one.two, .one .two {padding:0;} .one.two {padding:0 7px;}';
531 $cssout = '.one, .two{padding:0;} .one.two{padding:0 7px;} .one .two{padding:0;}';
532 $this->assertEquals($cssout, $optimiser->process($cssin));
534 $cssin = '.block {padding-top: 0px !important;padding-bottom: 0px !important;}';
535 $cssout = '.block{padding-top:0 !important;padding-bottom:0 !important;}';
536 $this->assertEquals($cssout, $optimiser->process($cssin));
538 $cssin = '.block {padding: 0px !important;padding-bottom: 3px;}';
539 $cssout = '.block{padding:0 !important;}';
540 $this->assertEquals($cssout, $optimiser->process($cssin));
542 $cssin = '.block {padding: 5px;padding-right: 0 !important;}';
543 $cssout = '.block{padding:5px;padding-right:0 !important;}';
544 $this->assertEquals($cssout, $optimiser->process($cssin));
547 public function test_cursor() {
548 $optimiser = $this->get_optimiser();
550 // Valid cursor
551 $cssin = '.one {cursor: pointer;}';
552 $cssout = '.one{cursor:pointer;}';
553 $this->assertEquals($cssout, $optimiser->process($cssin));
555 // Invalid cursor but tollerated
556 $cssin = '.one {cursor: hand;}';
557 $cssout = '.one{cursor:hand;}';
558 $this->assertEquals($cssout, $optimiser->process($cssin));
560 // Valid cursor: url relative
561 $cssin = '.one {cursor: mycursor.png;}';
562 $cssout = '.one{cursor:mycursor.png;}';
563 $this->assertEquals($cssout, $optimiser->process($cssin));
565 // Valid cursor: url absolute
566 $cssin = '.one {cursor: http://local.host/mycursor.png;}';
567 $cssout = '.one{cursor:http://local.host/mycursor.png;}';
568 $this->assertEquals($cssout, $optimiser->process($cssin));
571 public function test_vertical_align() {
572 $optimiser = $this->get_optimiser();
574 // Valid vertical aligns
575 $cssin = '.one {vertical-align: baseline;}';
576 $cssout = '.one{vertical-align:baseline;}';
577 $this->assertEquals($cssout, $optimiser->process($cssin));
578 $cssin = '.one {vertical-align: middle;}';
579 $cssout = '.one{vertical-align:middle;}';
580 $this->assertEquals($cssout, $optimiser->process($cssin));
581 $cssin = '.one {vertical-align: 0.75em;}';
582 $cssout = '.one{vertical-align:0.75em;}';
583 $this->assertEquals($cssout, $optimiser->process($cssin));
584 $cssin = '.one {vertical-align: 50%;}';
585 $cssout = '.one{vertical-align:50%;}';
586 $this->assertEquals($cssout, $optimiser->process($cssin));
588 // Invalid but tollerated
589 $cssin = '.one {vertical-align: center;}';
590 $cssout = '.one{vertical-align:center;}';
591 $this->assertEquals($cssout, $optimiser->process($cssin));
594 public function test_float() {
595 $optimiser = $this->get_optimiser();
597 // Valid vertical aligns
598 $cssin = '.one {float: inherit;}';
599 $cssout = '.one{float:inherit;}';
600 $this->assertEquals($cssout, $optimiser->process($cssin));
601 $cssin = '.one {float: left;}';
602 $cssout = '.one{float:left;}';
603 $this->assertEquals($cssout, $optimiser->process($cssin));
604 $cssin = '.one {float: right;}';
605 $cssout = '.one{float:right;}';
606 $this->assertEquals($cssout, $optimiser->process($cssin));
607 $cssin = '.one {float: none;}';
608 $cssout = '.one{float:none;}';
609 $this->assertEquals($cssout, $optimiser->process($cssin));
611 // Invalid but tollerated
612 $cssin = '.one {float: center;}';
613 $cssout = '.one{float:center;}';
614 $this->assertEquals($cssout, $optimiser->process($cssin));
618 * Test some totally invalid CSS optimisation
620 * @param css_optimiser $optimiser
622 protected function try_invalid_css_handling() {
623 $optimiser = $this->get_optimiser();
625 $cssin = array(
626 '.one{}',
627 '.one {:}',
628 '.one {;}',
629 '.one {;;;;;}',
630 '.one {:;}',
631 '.one {:;:;:;:::;;;}',
632 '.one {!important}',
633 '.one {:!important}',
634 '.one {:!important;}',
635 '.one {;!important}'
637 $cssout = '.one{}';
638 foreach ($cssin as $css) {
639 $this->assertEquals($cssout, $optimiser->process($css));
642 $cssin = array(
643 '.one{background-color:red;}',
644 '.one {background-color:red;} .one {background-color:}',
645 '.one {background-color:red;} .one {background-color;}',
646 '.one {background-color:red;} .one {background-color}',
647 '.one {background-color:red;} .one {background-color:;}',
648 '.one {background-color:red;} .one {:blue;}',
649 '.one {background-color:red;} .one {:#00F}',
651 $cssout = '.one{background-color:#F00;}';
652 foreach ($cssin as $css) {
653 $this->assertEquals($cssout, $optimiser->process($css));
656 $cssin = '..one {background-color:color:red}';
657 $cssout = '..one{background-color:color:red;}';
658 $this->assertEquals($cssout, $optimiser->process($cssin));
660 $cssin = '#.one {background-color:color:red}';
661 $cssout = '#.one{background-color:color:red;}';
662 $this->assertEquals($cssout, $optimiser->process($cssin));
664 $cssin = '##one {background-color:color:red}';
665 $cssout = '##one{background-color:color:red;}';
666 $this->assertEquals($cssout, $optimiser->process($cssin));
668 $cssin = '.one {background-color:color:red}';
669 $cssout = '.one{background-color:color:red;}';
670 $this->assertEquals($cssout, $optimiser->process($cssin));
672 $cssin = '.one {background-color:red;color;border-color:blue}';
673 $cssout = '.one{background-color:#F00;border-color:#00F;}';
674 $this->assertEquals($cssout, $optimiser->process($cssin));
676 $cssin = '{background-color:#123456;color:red;}{color:green;}';
677 $cssout = "{background-color:#123456;color:#008000;}";
678 $this->assertEquals($cssout, $optimiser->process($cssin));
680 $cssin = '.one {color:red;} {color:green;} .one {background-color:blue;}';
681 $cssout = ".one{color:#F00;background-color:#00F;} {color:#008000;}";
682 $this->assertEquals($cssout, $optimiser->process($cssin));
686 * Try to break some things
687 * @param css_optimiser $optimiser
689 protected function try_break_things() {
690 $optimiser = $this->get_optimiser();
692 // Wildcard test
693 $cssin = '* {color: black;}';
694 $cssout = '*{color:#000;}';
695 $this->assertEquals($cssout, $optimiser->process($cssin));
697 // Wildcard test
698 $cssin = '.one * {color: black;}';
699 $cssout = '.one *{color:#000;}';
700 $this->assertEquals($cssout, $optimiser->process($cssin));
702 // Wildcard test
703 $cssin = '* .one * {color: black;}';
704 $cssout = '* .one *{color:#000;}';
705 $this->assertEquals($cssout, $optimiser->process($cssin));
707 // Wildcard test
708 $cssin = '*,* {color: black;}';
709 $cssout = '*{color:#000;}';
710 $this->assertEquals($cssout, $optimiser->process($cssin));
712 // Wildcard test
713 $cssin = '*, * .one {color: black;}';
714 $cssout = "*,\n* .one{color:#000;}";
715 $this->assertEquals($cssout, $optimiser->process($cssin));
717 // Wildcard test
718 $cssin = '*, *.one {color: black;}';
719 $cssout = "*,\n*.one{color:#000;}";
720 $this->assertEquals($cssout, $optimiser->process($cssin));
722 // Psedo test
723 $cssin = '.one:before {color: black;}';
724 $cssout = '.one:before{color:#000;}';
725 $this->assertEquals($cssout, $optimiser->process($cssin));
727 // Psedo test
728 $cssin = '.one:after {color: black;}';
729 $cssout = '.one:after{color:#000;}';
730 $this->assertEquals($cssout, $optimiser->process($cssin));
732 // Psedo test
733 $cssin = '.one:onclick {color: black;}';
734 $cssout = '.one:onclick{color:#000;}';
735 $this->assertEquals($cssout, $optimiser->process($cssin));
737 // Test complex CSS rules that don't really exist but mimic other CSS rules
738 $cssin = '.one {master-of-destruction: explode(\' \', "What madness");}';
739 $cssout = '.one{master-of-destruction:explode(\' \', "What madness");}';
740 $this->assertEquals($cssout, $optimiser->process($cssin));
742 // Test some complex IE css... I couldn't even think of a more complext solution
743 // than the CSS they came up with.
744 $cssin = 'a { opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50); }';
745 $cssout = 'a{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
746 $this->assertEquals($cssout, $optimiser->process($cssin));
750 * A bulk processing test
751 * @param css_optimiser $optimiser
753 protected function try_bulk_processing() {
754 global $CFG;
755 $cssin = <<<CSS
756 .test .one {
757 margin:5px;
758 border:0;
760 .test .one {
761 margin: 10px;
762 color: red;
765 .test.one {
766 margin: 15px;
769 #test .one {margin: 20px;}
770 #test #one {margin: 25px;}.test #one {margin: 30px;}
771 .test .one { background-color: #123; }
772 .test.one{border:1px solid blue}.test.one{border-color:green;}
774 @media print {
775 #test .one {margin: 35px;}
778 @media print {
779 #test .one {margin: 40px;color: #123456;}
780 #test #one {margin: 45px;}
783 @media print,screen {
784 #test .one {color: #654321;}
787 #test .one,
788 #new.style {color:#000;}
789 CSS;
791 $cssout = <<<CSS
792 .test .one{margin:10px;border-width:0;color:#F00;background-color:#123;}
793 .test.one{margin:15px;border:1px solid #008000;}
794 #test .one{margin:20px;color:#000;}
795 #test #one{margin:25px;}
796 .test #one{margin:30px;}
797 #new.style{color:#000;}
799 @media print {
800 #test .one{margin:40px;color:#123456;}
801 #test #one{margin:45px;}
803 @media print,screen {
804 #test .one{color:#654321;}
806 CSS;
807 $CFG->cssoptimiserpretty = 1;
808 $this->assertEquals($this->get_optimiser()->process($cssin), $cssout);
812 * Test CSS colour matching
814 public function test_css_is_colour() {
815 // First lets test hex colours
816 $this->assertTrue(css_is_colour('#123456'));
817 $this->assertTrue(css_is_colour('#123'));
818 $this->assertTrue(css_is_colour('#ABCDEF'));
819 $this->assertTrue(css_is_colour('#ABC'));
820 $this->assertTrue(css_is_colour('#abcdef'));
821 $this->assertTrue(css_is_colour('#abc'));
822 $this->assertTrue(css_is_colour('#aBcDeF'));
823 $this->assertTrue(css_is_colour('#aBc'));
824 $this->assertTrue(css_is_colour('#1a2Bc3'));
825 $this->assertTrue(css_is_colour('#1Ac'));
827 // Note the following two colour's arn't really colours but browsers process
828 // them still.
829 $this->assertTrue(css_is_colour('#A'));
830 $this->assertTrue(css_is_colour('#12'));
831 // Having four or five characters however are not valid colours and
832 // browsers don't parse them. They need to fail so that broken CSS
833 // stays broken after optimisation.
834 $this->assertFalse(css_is_colour('#1234'));
835 $this->assertFalse(css_is_colour('#12345'));
837 $this->assertFalse(css_is_colour('#BCDEFG'));
838 $this->assertFalse(css_is_colour('#'));
839 $this->assertFalse(css_is_colour('#0000000'));
840 $this->assertFalse(css_is_colour('#132-245'));
841 $this->assertFalse(css_is_colour('#13 23 43'));
842 $this->assertFalse(css_is_colour('123456'));
844 // Next lets test real browser mapped colours
845 $this->assertTrue(css_is_colour('black'));
846 $this->assertTrue(css_is_colour('blue'));
847 $this->assertTrue(css_is_colour('BLACK'));
848 $this->assertTrue(css_is_colour('Black'));
849 $this->assertTrue(css_is_colour('bLACK'));
850 $this->assertTrue(css_is_colour('mediumaquamarine'));
851 $this->assertTrue(css_is_colour('mediumAquamarine'));
852 $this->assertFalse(css_is_colour('monkey'));
853 $this->assertFalse(css_is_colour(''));
854 $this->assertFalse(css_is_colour('not a colour'));
856 // Next lets test rgb(a) colours
857 $this->assertTrue(css_is_colour('rgb(255,255,255)'));
858 $this->assertTrue(css_is_colour('rgb(0, 0, 0)'));
859 $this->assertTrue(css_is_colour('RGB (255, 255 , 255)'));
860 $this->assertTrue(css_is_colour('rgba(0,0,0,0)'));
861 $this->assertTrue(css_is_colour('RGBA(255,255,255,1)'));
862 $this->assertTrue(css_is_colour('rgbA(255,255,255,0.5)'));
863 $this->assertFalse(css_is_colour('rgb(-255,-255,-255)'));
864 $this->assertFalse(css_is_colour('rgb(256,-256,256)'));
866 // Now lets test HSL colours
867 $this->assertTrue(css_is_colour('hsl(0,0%,100%)'));
868 $this->assertTrue(css_is_colour('hsl(180, 0%, 10%)'));
869 $this->assertTrue(css_is_colour('hsl (360, 100% , 95%)'));
871 // Finally test the special values
872 $this->assertTrue(css_is_colour('inherit'));
876 * Test the css_is_width function
878 public function test_css_is_width() {
880 $this->assertTrue(css_is_width('0'));
881 $this->assertTrue(css_is_width('0px'));
882 $this->assertTrue(css_is_width('0em'));
883 $this->assertTrue(css_is_width('199px'));
884 $this->assertTrue(css_is_width('199em'));
885 $this->assertTrue(css_is_width('199%'));
886 $this->assertTrue(css_is_width('-1px'));
887 $this->assertTrue(css_is_width('auto'));
888 $this->assertTrue(css_is_width('inherit'));
890 // Valid widths but missing their unit specifier
891 $this->assertFalse(css_is_width('0.75'));
892 $this->assertFalse(css_is_width('3'));
893 $this->assertFalse(css_is_width('-1'));
894 // Totally invalid widths
895 $this->assertFalse(css_is_width('-'));
896 $this->assertFalse(css_is_width('bananas'));
897 $this->assertFalse(css_is_width(''));
898 $this->assertFalse(css_is_width('top'));
902 * This function tests some of the broken crazy CSS we have in Moodle.
903 * For each of these things the value needs to be corrected if we can be 100%
904 * certain what is going wrong, Or it needs to be left as is.
906 * @param css_optimiser $optimiser
908 public function try_broken_css_found_in_moodle() {
909 $optimiser = $this->get_optimiser();
911 // Notice how things are out of order here but that they get corrected
912 $cssin = '.test {background:url([[pix:theme|pageheaderbgred]]) top center no-repeat}';
913 $cssout = '.test{background:url([[pix:theme|pageheaderbgred]]) no-repeat top center;}';
914 $this->assertEquals($cssout, $optimiser->process($cssin));
916 // Cursor hand isn't valid
917 $cssin = '.test {cursor: hand;}';
918 $cssout = '.test{cursor:hand;}';
919 $this->assertEquals($cssout, $optimiser->process($cssin));
921 // Zoom property isn't valid
922 $cssin = '.test {zoom: 1;}';
923 $cssout = '.test{zoom:1;}';
924 $this->assertEquals($cssout, $optimiser->process($cssin));
926 // Left isn't a valid position property
927 $cssin = '.test {position: left;}';
928 $cssout = '.test{position:left;}';
929 $this->assertEquals($cssout, $optimiser->process($cssin));
931 // The dark red color isn't a valid HTML color but has a standardised
932 // translation of #8B0000
933 $cssin = '.test {color: darkred;}';
934 $cssout = '.test{color:#8B0000;}';
935 $this->assertEquals($cssout, $optimiser->process($cssin));
937 // You can't use argb colours as border colors
938 $cssin = '.test {border-bottom: 1px solid rgba(0,0,0,0.25);}';
939 $cssout = '.test{border-bottom:1px solid rgba(0,0,0,0.25);}';
940 $this->assertEquals($cssout, $optimiser->process($cssin));
942 // Opacity with annoying IE equivilants....
943 $cssin = '.test {opacity: 0.5; -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)"; filter: alpha(opacity=50);}';
944 $cssout = '.test{opacity:0.5;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter:alpha(opacity=50);}';
945 $this->assertEquals($cssout, $optimiser->process($cssin));
949 * Test keyframe declarations
950 * @param css_optimiser $optimiser
952 public function try_keyframe_css_animation() {
953 $optimiser = $this->get_optimiser();
955 $css = '.dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url(\'[[pix:theme|fp/dnd_arrow]]\') no-repeat center;margin-left:-28px;}';
956 $this->assertEquals($css, $optimiser->process($css));
958 $css = '@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}';
959 $this->assertEquals($css, $optimiser->process($css));
961 $css = "@keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
962 $css .= "@-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}\n";
963 $css .= "@-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}";
964 $this->assertEquals($css, $optimiser->process($css));
967 $cssin = <<<CSS
968 .test {color:#FFF;}
969 .testtwo {color:#FFF;}
970 @media print {
971 .test {background-color:#FFF;}
973 .dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;margin-left:-28px;}
974 @media print {
975 .test {background-color:#000;}
977 @keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
978 @-moz-keyframes mymove{0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
979 @-webkit-keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
980 @media print {
981 .test {background-color:#333;}
983 .test {color:#888;}
984 .testtwo {color:#888;}
985 CSS;
987 $cssout = <<<CSS
988 .test,
989 .testtwo{color:#888;}
990 .dndupload-arrow{width:56px;height:47px;position:absolute;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;margin-left:-28px;}
992 @media print {
993 .test{background-color:#333;}
995 @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
996 @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
997 @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
998 CSS;
999 $this->assertEquals($cssout, $optimiser->process($cssin));
1003 $cssin = <<<CSS
1004 .dndupload-target {display:none;}
1005 .dndsupported .dndupload-ready .dndupload-target {display:block;}
1006 .dndupload-uploadinprogress {display:none;text-align:center;}
1007 .dndupload-uploading .dndupload-uploadinprogress {display:block;}
1008 .dndupload-arrow {background:url('[[pix:theme|fp/dnd_arrow]]') center no-repeat;width:56px;height:47px;position:absolute;margin-left: -28px;/*right:46%;left:46%;*/animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;}
1009 @keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}@-moz-keyframes mymove{0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}@-webkit-keyframes mymove {0%{top:10px;} 12%{top:40px;} 30%{top:20px} 65%{top:35px;} 100%{top:9px;}}
1012 * Select Dialogue (File Manager only)
1014 .filemanager.fp-select .fp-select-loading {display:none;}
1015 .filemanager.fp-select.loading .fp-select-loading {display:block;}
1016 .filemanager.fp-select.loading form {display:none;}
1017 CSS;
1019 $cssout = <<<CSS
1020 .dndupload-target{display:none;}
1021 .dndsupported .dndupload-ready .dndupload-target{display:block;}
1022 .dndupload-uploadinprogress{display:none;text-align:center;}
1023 .dndupload-uploading .dndupload-uploadinprogress{display:block;}
1024 .dndupload-arrow{background:url('[[pix:theme|fp/dnd_arrow]]') no-repeat center;width:56px;height:47px;position:absolute;margin-left:-28px;animation:mymove 5s infinite;-moz-animation:mymove 5s infinite;-webkit-animation:mymove 5s infinite;}
1025 .filemanager.fp-select .fp-select-loading{display:none;}
1026 .filemanager.fp-select.loading .fp-select-loading{display:block;}
1027 .filemanager.fp-select.loading form{display:none;}
1029 @keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1030 @-moz-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1031 @-webkit-keyframes mymove {0%{top:10px;}12%{top:40px;}30%{top:20px;}65%{top:35px;}100%{top:9px;}}
1032 CSS;
1033 $this->assertEquals($cssout, $optimiser->process($cssin));
1037 * Test media declarations
1038 * @param css_optimiser $optimiser
1040 public function try_media_rules() {
1041 $optimiser = $this->get_optimiser();
1043 $cssin = "@media print {\n .test{background-color:#333;}\n}";
1044 $cssout = "@media print {\n .test{background-color:#333;}\n}";
1045 $this->assertEquals($cssout, $optimiser->process($cssin));
1047 $cssin = "@media screen and (min-width:30px) {\n #region-main-box{left: 30px;float: left;}\n}";
1048 $cssout = "@media screen and (min-width:30px) {\n #region-main-box{left:30px;float:left;}\n}";
1049 $this->assertEquals($cssout, $optimiser->process($cssin));
1051 $cssin = "@media all and (min-width:500px) {\n #region-main-box{left:30px;float:left;}\n}";
1052 $cssout = "@media all and (min-width:500px) {\n #region-main-box{left:30px;float:left;}\n}";
1053 $this->assertEquals($cssout, $optimiser->process($cssin));
1055 $cssin = "@media (min-width:500px) {\n #region-main-box{left:30px;float:left;}\n}";
1056 $cssout = "@media (min-width:500px) {\n #region-main-box{left:30px;float:left;}\n}";
1057 $this->assertEquals($cssout, $optimiser->process($cssin));
1059 $cssin = "@media screen and (color), projection and (color) {\n #region-main-box{left:30px;float:left;}\n}";
1060 $cssout = "@media screen and (color),projection and (color) {\n #region-main-box{left:30px;float:left;}\n}";
1061 $this->assertEquals($cssout, $optimiser->process($cssin));
1063 $cssin = "@media print {\n .test{background-color:#000;}\n}@media print {\n .test{background-color:#FFF;}\n}";
1064 $cssout = "@media print {\n .test{background-color:#FFF;}\n}";
1065 $this->assertEquals($cssout, $optimiser->process($cssin));
1067 $cssin = "@media screen and (min-width:30px) {\n #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:30px) {\n #region-main-box{background-color:#FFF;}\n}";
1068 $cssout = "@media screen and (min-width:30px) {\n #region-main-box{background-color:#FFF;}\n}";
1069 $this->assertEquals($cssout, $optimiser->process($cssin));
1071 $cssin = "@media screen and (min-width:30px) {\n #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:31px) {\n #region-main-box{background-color:#FFF;}\n}";
1072 $cssout = "@media screen and (min-width:30px) {\n #region-main-box{background-color:#000;}\n}\n@media screen and (min-width:31px) {\n #region-main-box{background-color:#FFF;}\n}";
1073 $this->assertEquals($cssout, $optimiser->process($cssin));
1077 public function test_css_optimisation_ordering() {
1078 $optimiser = $this->get_optimiser();
1080 $css = '.test{display:none;} .dialogue{display:block;} .dialogue-hidden{display:none;}';
1081 $this->assertEquals($css, $optimiser->process($css));
1083 $cssin = '.test{display:none;} .dialogue-hidden{display:none;} .dialogue{display:block;}';
1084 $cssout = '.test, .dialogue-hidden{display:none;} .dialogue{display:block;}';
1085 $this->assertEquals($cssout, $optimiser->process($cssin));
1088 public function test_css_chunking() {
1089 // Test with an even number of styles.
1090 $css = 'a{}b{}c{}d{}e{}f{}';
1091 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1092 $this->assertInternalType('array', $chunks);
1093 $this->assertCount(3, $chunks);
1094 $this->assertArrayHasKey(0, $chunks);
1095 $this->assertArrayHasKey(1, $chunks);
1096 $this->assertArrayHasKey(2, $chunks);
1097 $this->assertEquals('a{}b{}', $chunks[0]);
1098 $this->assertEquals('c{}d{}', $chunks[1]);
1099 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne{}f{}", $chunks[2]);
1101 // Test with an odd number of styles.
1102 $css = 'a{}b{}c{}d{}e{}';
1103 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1104 $this->assertInternalType('array', $chunks);
1105 $this->assertCount(3, $chunks);
1106 $this->assertArrayHasKey(0, $chunks);
1107 $this->assertArrayHasKey(1, $chunks);
1108 $this->assertArrayHasKey(2, $chunks);
1109 $this->assertEquals('a{}b{}', $chunks[0]);
1110 $this->assertEquals('c{}d{}', $chunks[1]);
1111 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne{}", $chunks[2]);
1113 // Test buffering. Set a buffer that will reduce the effective sheet size back to two.
1114 $css = 'a{}b{}c{}d{}e{}f{}';
1115 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 6, 4);
1116 $this->assertInternalType('array', $chunks);
1117 $this->assertCount(3, $chunks);
1118 $this->assertArrayHasKey(0, $chunks);
1119 $this->assertArrayHasKey(1, $chunks);
1120 $this->assertArrayHasKey(2, $chunks);
1121 $this->assertEquals('a{}b{}', $chunks[0]);
1122 $this->assertEquals('c{}d{}', $chunks[1]);
1123 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne{}f{}", $chunks[2]);
1125 // Test well placed commas.
1126 $css = 'a,b{}c,d{}e,f{}';
1127 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1128 $this->assertInternalType('array', $chunks);
1129 $this->assertCount(3, $chunks);
1130 $this->assertArrayHasKey(0, $chunks);
1131 $this->assertArrayHasKey(1, $chunks);
1132 $this->assertArrayHasKey(2, $chunks);
1133 $this->assertEquals('a,b{}', $chunks[0]);
1134 $this->assertEquals('c,d{}', $chunks[1]);
1135 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne,f{}", $chunks[2]);
1137 // Test unfortunately placed commas.
1138 $css = 'a{}b,c{color:red;}d{}e{}f{}';
1139 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1140 $this->assertInternalType('array', $chunks);
1141 $this->assertCount(3, $chunks);
1142 $this->assertArrayHasKey(0, $chunks);
1143 $this->assertArrayHasKey(1, $chunks);
1144 $this->assertArrayHasKey(2, $chunks);
1145 $this->assertEquals('a{}b{color:red;}', $chunks[0]);
1146 $this->assertEquals('c{color:red;}d{}', $chunks[1]);
1147 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne{}f{}", $chunks[2]);
1149 // Test unfortunate CSS.
1150 $css = 'a,b,c,d,e,f{color:red;}';
1151 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1152 $this->assertInternalType('array', $chunks);
1153 $this->assertCount(3, $chunks);
1154 $this->assertArrayHasKey(0, $chunks);
1155 $this->assertArrayHasKey(1, $chunks);
1156 $this->assertArrayHasKey(2, $chunks);
1157 $this->assertEquals('a,b{color:red;}', $chunks[0]);
1158 $this->assertEquals('c,d{color:red;}', $chunks[1]);
1159 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne,f{color:red;}", $chunks[2]);
1161 // Test to make sure invalid CSS isn't totally ruined.
1162 $css = 'a{},,,e{},';
1163 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1164 // Believe it or not we want to care what comes out here as this will be parsed correctly
1165 // by a browser.
1166 $this->assertInternalType('array', $chunks);
1167 $this->assertCount(2, $chunks);
1168 $this->assertArrayHasKey(0, $chunks);
1169 $this->assertArrayHasKey(1, $chunks);
1170 $this->assertEquals('a{},{}', $chunks[0]);
1171 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n,e{}/** Error chunking CSS **/", $chunks[1]);
1173 // Test utter crap CSS to make sure we don't loop to our deaths.
1174 $css = 'a,b,c,d,e,f';
1175 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1176 $this->assertInternalType('array', $chunks);
1177 $this->assertCount(3, $chunks);
1178 $this->assertArrayHasKey(0, $chunks);
1179 $this->assertArrayHasKey(1, $chunks);
1180 $this->assertArrayHasKey(2, $chunks);
1181 $this->assertEquals('a,b/** Error chunking CSS **/', $chunks[0]);
1182 $this->assertEquals('c,d/** Error chunking CSS **/', $chunks[1]);
1183 $this->assertEquals("@import url(styles.php?type=test&chunk=0);\n@import url(styles.php?type=test&chunk=1);\ne,f", $chunks[2]);
1184 // Test another death situation to make sure we're invincible.
1185 $css = 'a,,,,,e';
1186 $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
1187 $this->assertInternalType('array', $chunks);
1188 // I don't care what the outcome is, I just want to make sure it doesn't die.