PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 3.6.1
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v3.6.1
4.0.7 4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / data / csstidy / class.csstidy_print.php
superb-blocks / src / data / csstidy Last commit date
class.csstidy.php 11 months ago class.csstidy_optimise.php 11 months ago class.csstidy_print.php 11 months ago data.inc.php 11 months ago
class.csstidy_print.php
452 lines
1 <?php
2
3 namespace SuperbAddons\CSSTidy;
4 // Added namespace and moved defines to class consts
5
6 /**
7 * CSSTidy - CSS Parser and Optimiser
8 *
9 * CSS Printing class
10 * This class prints CSS data generated by csstidy.
11 *
12 * Copyright 2005, 2006, 2007 Florian Schmitz
13 *
14 * This file is part of CSSTidy.
15 *
16 * CSSTidy is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU Lesser General Public License as published by
18 * the Free Software Foundation; either version 2.1 of the License, or
19 * (at your option) any later version.
20 *
21 * CSSTidy is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU Lesser General Public License for more details.
25 *
26 * You should have received a copy of the GNU Lesser General Public License
27 * along with this program. If not, see <http://www.gnu.org/licenses/>.
28 *
29 * @license http://opensource.org/licenses/lgpl-license.php GNU Lesser General Public License
30 * @package csstidy
31 * @author Florian Schmitz (floele at gmail dot com) 2005-2007
32 * @author Brett Zamir (brettz9 at yahoo dot com) 2007
33 * @author Cedric Morin (cedric at yterium dot com) 2010-2012
34 */
35
36 /**
37 * CSS Printing class
38 *
39 * This class prints CSS data generated by csstidy.
40 *
41 * @package csstidy
42 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
43 * @version 1.1.0
44 */
45 class csstidy_print
46 {
47
48 /**
49 * csstidy object
50 * @var object
51 */
52 public $parser;
53
54 /**
55 * Saves the input CSS string
56 * @var string
57 * @access private
58 */
59 public $input_css = '';
60 /**
61 * Saves the formatted CSS string
62 * @var string
63 * @access public
64 */
65 public $output_css = '';
66 /**
67 * Saves the formatted CSS string (plain text)
68 * @var string
69 * @access public
70 */
71 public $output_css_plain = '';
72
73 public $css;
74 public $template;
75 public $tokens;
76 public $charset;
77 public $import;
78 public $namespace;
79
80 /**
81 * Constructor
82 * @param array $css contains the class csstidy
83 * @access private
84 * @version 1.0
85 */
86 public function __construct($css)
87 {
88 $this->parser = $css;
89 $this->css = &$css->css;
90 $this->template = &$css->template;
91 $this->tokens = &$css->tokens;
92 $this->charset = &$css->charset;
93 $this->import = &$css->import;
94 $this->namespace = &$css->namespace;
95 }
96
97 /**
98 * Resets output_css and output_css_plain (new css code)
99 * @access private
100 * @version 1.0
101 */
102 public function _reset()
103 {
104 $this->output_css = '';
105 $this->output_css_plain = '';
106 }
107
108 /**
109 * Returns the CSS code as plain text
110 * @param string $default_media default @media to add to selectors without any @media
111 * @return string
112 * @access public
113 * @version 1.0
114 */
115 public function plain($default_media = '')
116 {
117 $this->_print(true, $default_media);
118 return $this->output_css_plain;
119 }
120
121 /**
122 * Returns the formatted CSS code
123 * @param string $default_media default @media to add to selectors without any @media
124 * @return string
125 * @access public
126 * @version 1.0
127 */
128 public function formatted($default_media = '')
129 {
130 $this->_print(false, $default_media);
131 return $this->output_css;
132 }
133
134 /**
135 * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain
136 * @param bool $plain plain text or not
137 * @param string $default_media default @media to add to selectors without any @media
138 * @access private
139 * @version 2.0
140 */
141 public function _print($plain = false, $default_media = '')
142 {
143 if ($this->output_css && $this->output_css_plain) {
144 return;
145 }
146
147 $output = '';
148 if (!$this->parser->get_cfg('preserve_css')) {
149 $this->_convert_raw_css($default_media);
150 }
151
152 $template = &$this->template;
153
154 if ($plain) {
155 $template = array_map('strip_tags', $template);
156 }
157
158 if ($this->parser->get_cfg('timestamp')) {
159 array_unshift($this->tokens, array(csstidyConstants::COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . gmdate('r') . ' '));
160 }
161
162 if (!empty($this->charset)) {
163 $output .= $template[0] . '@charset ' . $template[5] . $this->charset . $template[6] . $template[13];
164 }
165
166 if (!empty($this->import)) {
167 for ($i = 0, $size = count($this->import); $i < $size; $i++) {
168 if (substr($this->import[$i], 0, 4) === 'url(' && substr($this->import[$i], -1, 1) === ')') {
169 $this->import[$i] = '"' . substr($this->import[$i], 4, -1) . '"';
170 $this->parser->log('Optimised @import : Removed "url("', 'Information');
171 } else if (!preg_match('/^".+"$/', $this->import[$i])) {
172 // fixes a bug for @import ".." instead of the expected @import url("..")
173 // If it comes in due to @import ".." the "" will be missing and the output will become @import .. (which is an error)
174 $this->import[$i] = '"' . $this->import[$i] . '"';
175 }
176
177 $output .= $template[0] . '@import ' . $template[5] . $this->import[$i] . $template[6] . $template[13];
178 }
179 }
180
181 if (!empty($this->namespace)) {
182 if (($p = strpos($this->namespace, "url(")) !== false && substr($this->namespace, -1, 1) === ')') {
183 $this->namespace = substr_replace($this->namespace, '"', $p, 4);
184 $this->namespace = substr($this->namespace, 0, -1) . '"';
185 $this->parser->log('Optimised @namespace : Removed "url("', 'Information');
186 }
187 $output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6] . $template[13];
188 }
189
190 $in_at_out = [];
191 $out = &$output;
192 $indent_level = 0;
193
194 foreach ($this->tokens as $key => $token) {
195 switch ($token[0]) {
196 case csstidyConstants::AT_START:
197 $out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
198 $indent_level++;
199 if (!isset($in_at_out[$indent_level])) {
200 $in_at_out[$indent_level] = '';
201 }
202 $out = &$in_at_out[$indent_level];
203 break;
204
205 case csstidyConstants::SEL_START:
206 if ($this->parser->get_cfg('lowercase_s'))
207 $token[1] = strtolower($token[1]);
208 $out .= ($token[1][0] !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
209 $out .= $template[3];
210 break;
211
212 case csstidyConstants::PROPERTY:
213 if ($this->parser->get_cfg('case_properties') === 2) {
214 $token[1] = strtoupper($token[1]);
215 } elseif ($this->parser->get_cfg('case_properties') === 1) {
216 $token[1] = strtolower($token[1]);
217 }
218 $out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
219 break;
220
221 case csstidyConstants::VALUE:
222 $out .= $this->_htmlsp($token[1], $plain);
223 if ($this->_seeknocomment($key, 1) == csstidyConstants::SEL_END && $this->parser->get_cfg('remove_last_;')) {
224 $out .= str_replace(';', '', $template[6]);
225 } else {
226 $out .= $template[6];
227 }
228 break;
229
230 case csstidyConstants::SEL_END:
231 $out .= $template[7];
232 if ($this->_seeknocomment($key, 1) != csstidyConstants::AT_END)
233 $out .= $template[8];
234 break;
235
236 case csstidyConstants::AT_END:
237 if (strlen($template[10])) {
238 // indent the bloc we are closing
239 $out = str_replace("\n\n", "\r\n", $out); // don't fill empty lines
240 $out = str_replace("\n", "\n" . $template[10], $out);
241 $out = str_replace("\r\n", "\n\n", $out);
242 }
243 if ($indent_level > 1) {
244 $out = &$in_at_out[$indent_level - 1];
245 } else {
246 $out = &$output;
247 }
248 $out .= $template[10] . $in_at_out[$indent_level];
249 if ($this->_seeknocomment($key, 1) != csstidyConstants::AT_END) {
250 $out .= $template[9];
251 } else {
252 $out .= rtrim($template[9]);
253 }
254
255 unset($in_at_out[$indent_level]);
256 $indent_level--;
257 break;
258
259 case csstidyConstants::IMPORTANT_COMMENT:
260 case csstidyConstants::COMMENT:
261 $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
262 break;
263 }
264 }
265
266 $output = trim($output);
267
268 if (!$plain) {
269 $this->output_css = $output;
270 $this->_print(true);
271 } else {
272 // If using spaces in the template, don't want these to appear in the plain output
273 $this->output_css_plain = str_replace('&#160;', '', $output);
274 }
275 }
276
277 /**
278 * Gets the next token type which is $move away from $key, excluding comments
279 * @param integer $key current position
280 * @param integer $move move this far
281 * @return mixed a token type
282 * @access private
283 * @version 1.0
284 */
285 public function _seeknocomment($key, $move)
286 {
287 $go = ($move > 0) ? 1 : -1;
288 for ($i = $key + 1; abs($key - $i) - 1 < abs($move); $i += $go) {
289 if (!isset($this->tokens[$i])) {
290 return;
291 }
292 if ($this->tokens[$i][0] == csstidyConstants::COMMENT) {
293 $move += 1;
294 continue;
295 }
296 return $this->tokens[$i][0];
297 }
298 }
299
300 /**
301 * Converts $this->css array to a raw array ($this->tokens)
302 * @param string $default_media default @media to add to selectors without any @media
303 * @access private
304 * @version 1.0
305 */
306 public function _convert_raw_css($default_media = '')
307 {
308 $this->tokens = array();
309 $sort_selectors = $this->parser->get_cfg('sort_selectors');
310 $sort_properties = $this->parser->get_cfg('sort_properties');
311
312 // important comment section ?
313 if (isset($this->css['!'])) {
314 $this->parser->_add_token(csstidyConstants::IMPORTANT_COMMENT, rtrim($this->css['!']), true);
315 unset($this->css['!']);
316 }
317
318 foreach ($this->css as $medium => $val) {
319 if ($sort_selectors)
320 ksort($val);
321 if (intval($medium) < csstidyConstants::DEFAULT_AT) {
322 // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
323 if (strlen(trim($medium))) {
324 $parts_to_open = explode('{', $medium);
325 foreach ($parts_to_open as $part) {
326 $this->parser->_add_token(csstidyConstants::AT_START, $part, true);
327 }
328 }
329 } elseif ($default_media) {
330 $this->parser->_add_token(csstidyConstants::AT_START, $default_media, true);
331 }
332
333 foreach ($val as $selector => $vali) {
334 if ($sort_properties)
335 ksort($vali);
336 $this->parser->_add_token(csstidyConstants::SEL_START, $selector, true);
337
338 $invalid = array(
339 '*' => array(), // IE7 hacks first
340 '_' => array(), // IE6 hacks
341 '/' => array(), // IE6 hacks
342 '-' => array() // IE6 hacks
343 );
344 foreach ($vali as $property => $valj) {
345 if (strncmp($property, "//", 2) !== 0) {
346 $matches = array();
347 if ($sort_properties && preg_match('/^(\*|_|\/|-)(?!(ms|moz|o\b|xv|atsc|wap|khtml|webkit|ah|hp|ro|rim|tc)-)/', $property, $matches)) {
348 $invalid[$matches[1]][$property] = $valj;
349 } else {
350 $this->parser->_add_token(csstidyConstants::PROPERTY, $property, true);
351 $this->parser->_add_token(csstidyConstants::VALUE, $valj, true);
352 }
353 }
354 }
355 foreach ($invalid as $prefix => $props) {
356 foreach ($props as $property => $valj) {
357 $this->parser->_add_token(csstidyConstants::PROPERTY, $property, true);
358 $this->parser->_add_token(csstidyConstants::VALUE, $valj, true);
359 }
360 }
361 $this->parser->_add_token(csstidyConstants::SEL_END, $selector, true);
362 }
363
364 if (intval($medium) < csstidyConstants::DEFAULT_AT) {
365 // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
366 if (strlen(trim($medium))) {
367 $parts_to_close = explode('{', $medium);
368 foreach (array_reverse($parts_to_close) as $part) {
369 $this->parser->_add_token(csstidyConstants::AT_END, $part, true);
370 }
371 }
372 } elseif ($default_media) {
373 $this->parser->_add_token(csstidyConstants::AT_END, $default_media, true);
374 }
375 }
376 }
377
378 /**
379 * Same as htmlspecialchars, only that chars are not replaced if $plain !== true. This makes print_code() cleaner.
380 * @param string $string
381 * @param bool $plain
382 * @return string
383 * @see csstidy_print::_print()
384 * @access private
385 * @version 1.0
386 */
387 public function _htmlsp($string, $plain)
388 {
389 if (!$plain) {
390 return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
391 }
392 return $string;
393 }
394
395 /**
396 * Get compression ratio
397 * @access public
398 * @return float
399 * @version 1.2
400 */
401 public function get_ratio()
402 {
403 if (!$this->output_css_plain) {
404 $this->formatted();
405 }
406 return round((strlen($this->input_css) - strlen($this->output_css_plain)) / strlen($this->input_css), 3) * 100;
407 }
408
409 /**
410 * Get difference between the old and new code in bytes and prints the code if necessary.
411 * @access public
412 * @return string
413 * @version 1.1
414 */
415 public function get_diff()
416 {
417 if (!$this->output_css_plain) {
418 $this->formatted();
419 }
420
421 $diff = strlen($this->output_css_plain) - strlen($this->input_css);
422
423 if ($diff > 0) {
424 return '+' . $diff;
425 } elseif ($diff == 0) {
426 return '+-' . $diff;
427 }
428
429 return $diff;
430 }
431
432 /**
433 * Get the size of either input or output CSS in KB
434 * @param string $loc default is "output"
435 * @access public
436 * @return integer
437 * @version 1.0
438 */
439 public function size($loc = 'output')
440 {
441 if ($loc === 'output' && !$this->output_css) {
442 $this->formatted();
443 }
444
445 if ($loc === 'input') {
446 return (strlen($this->input_css) / 1000);
447 } else {
448 return (strlen($this->output_css_plain) / 1000);
449 }
450 }
451 }
452