PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 3.2.9
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v3.2.9
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 2 years ago class.csstidy_optimise.php 2 years ago class.csstidy_print.php 2 years ago data.inc.php 2 years ago
class.csstidy_print.php
500 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 to make a complete webpage
136 * @param string $doctype shorthand for the document type
137 * @param bool $externalcss indicates whether styles to be attached internally or as an external stylesheet
138 * @param string $title title to be added in the head of the document
139 * @param string $lang two-letter language code to be added to the output
140 * @return string
141 * @access public
142 * @version 1.4
143 */
144 public function formatted_page($doctype = 'html5', $externalcss = true, $title = '', $lang = 'en')
145 {
146 switch ($doctype) {
147 case 'html5':
148 $doctype_output = '<!DOCTYPE html>';
149 break;
150 case 'xhtml1.0strict':
151 $doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
152 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">';
153 break;
154 case 'xhtml1.1':
155 default:
156 $doctype_output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
157 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">';
158 break;
159 }
160
161 $output = $cssparsed = '';
162 $this->output_css_plain = &$output;
163
164 $output .= $doctype_output . "\n" . '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="' . $lang . '"';
165 $output .= ($doctype === 'xhtml1.1') ? '>' : ' lang="' . $lang . '">';
166 $output .= "\n<head>\n <title>$title</title>";
167
168 if ($externalcss) {
169 $output .= "\n <style type=\"text/css\">\n";
170 $cssparsed = file_get_contents('cssparsed.css');
171 $output .= $cssparsed; // Adds an invisible BOM or something, but not in css_optimised.php
172 $output .= "\n</style>";
173 } else {
174 $output .= "\n" . ' <link rel="stylesheet" type="text/css" href="cssparsed.css" />';
175 }
176 $output .= "\n</head>\n<body><code id=\"copytext\">";
177 $output .= $this->formatted();
178 $output .= '</code>' . "\n" . '</body></html>';
179 return $this->output_css_plain;
180 }
181
182 /**
183 * Returns the formatted CSS Code and saves it into $this->output_css and $this->output_css_plain
184 * @param bool $plain plain text or not
185 * @param string $default_media default @media to add to selectors without any @media
186 * @access private
187 * @version 2.0
188 */
189 public function _print($plain = false, $default_media = '')
190 {
191 if ($this->output_css && $this->output_css_plain) {
192 return;
193 }
194
195 $output = '';
196 if (!$this->parser->get_cfg('preserve_css')) {
197 $this->_convert_raw_css($default_media);
198 }
199
200 $template = &$this->template;
201
202 if ($plain) {
203 $template = array_map('strip_tags', $template);
204 }
205
206 if ($this->parser->get_cfg('timestamp')) {
207 array_unshift($this->tokens, array(csstidyConstants::COMMENT, ' CSSTidy ' . $this->parser->version . ': ' . date('r') . ' '));
208 }
209
210 if (!empty($this->charset)) {
211 $output .= $template[0] . '@charset ' . $template[5] . $this->charset . $template[6] . $template[13];
212 }
213
214 if (!empty($this->import)) {
215 for ($i = 0, $size = count($this->import); $i < $size; $i++) {
216 if (substr($this->import[$i], 0, 4) === 'url(' && substr($this->import[$i], -1, 1) === ')') {
217 $this->import[$i] = '"' . substr($this->import[$i], 4, -1) . '"';
218 $this->parser->log('Optimised @import : Removed "url("', 'Information');
219 } else if (!preg_match('/^".+"$/', $this->import[$i])) {
220 // fixes a bug for @import ".." instead of the expected @import url("..")
221 // If it comes in due to @import ".." the "" will be missing and the output will become @import .. (which is an error)
222 $this->import[$i] = '"' . $this->import[$i] . '"';
223 }
224
225 $output .= $template[0] . '@import ' . $template[5] . $this->import[$i] . $template[6] . $template[13];
226 }
227 }
228
229 if (!empty($this->namespace)) {
230 if (($p = strpos($this->namespace, "url(")) !== false && substr($this->namespace, -1, 1) === ')') {
231 $this->namespace = substr_replace($this->namespace, '"', $p, 4);
232 $this->namespace = substr($this->namespace, 0, -1) . '"';
233 $this->parser->log('Optimised @namespace : Removed "url("', 'Information');
234 }
235 $output .= $template[0] . '@namespace ' . $template[5] . $this->namespace . $template[6] . $template[13];
236 }
237
238 $in_at_out = [];
239 $out = &$output;
240 $indent_level = 0;
241
242 foreach ($this->tokens as $key => $token) {
243 switch ($token[0]) {
244 case csstidyConstants::AT_START:
245 $out .= $template[0] . $this->_htmlsp($token[1], $plain) . $template[1];
246 $indent_level++;
247 if (!isset($in_at_out[$indent_level])) {
248 $in_at_out[$indent_level] = '';
249 }
250 $out = &$in_at_out[$indent_level];
251 break;
252
253 case csstidyConstants::SEL_START:
254 if ($this->parser->get_cfg('lowercase_s'))
255 $token[1] = strtolower($token[1]);
256 $out .= ($token[1][0] !== '@') ? $template[2] . $this->_htmlsp($token[1], $plain) : $template[0] . $this->_htmlsp($token[1], $plain);
257 $out .= $template[3];
258 break;
259
260 case csstidyConstants::PROPERTY:
261 if ($this->parser->get_cfg('case_properties') === 2) {
262 $token[1] = strtoupper($token[1]);
263 } elseif ($this->parser->get_cfg('case_properties') === 1) {
264 $token[1] = strtolower($token[1]);
265 }
266 $out .= $template[4] . $this->_htmlsp($token[1], $plain) . ':' . $template[5];
267 break;
268
269 case csstidyConstants::VALUE:
270 $out .= $this->_htmlsp($token[1], $plain);
271 if ($this->_seeknocomment($key, 1) == csstidyConstants::SEL_END && $this->parser->get_cfg('remove_last_;')) {
272 $out .= str_replace(';', '', $template[6]);
273 } else {
274 $out .= $template[6];
275 }
276 break;
277
278 case csstidyConstants::SEL_END:
279 $out .= $template[7];
280 if ($this->_seeknocomment($key, 1) != csstidyConstants::AT_END)
281 $out .= $template[8];
282 break;
283
284 case csstidyConstants::AT_END:
285 if (strlen($template[10])) {
286 // indent the bloc we are closing
287 $out = str_replace("\n\n", "\r\n", $out); // don't fill empty lines
288 $out = str_replace("\n", "\n" . $template[10], $out);
289 $out = str_replace("\r\n", "\n\n", $out);
290 }
291 if ($indent_level > 1) {
292 $out = &$in_at_out[$indent_level - 1];
293 } else {
294 $out = &$output;
295 }
296 $out .= $template[10] . $in_at_out[$indent_level];
297 if ($this->_seeknocomment($key, 1) != csstidyConstants::AT_END) {
298 $out .= $template[9];
299 } else {
300 $out .= rtrim($template[9]);
301 }
302
303 unset($in_at_out[$indent_level]);
304 $indent_level--;
305 break;
306
307 case csstidyConstants::IMPORTANT_COMMENT:
308 case csstidyConstants::COMMENT:
309 $out .= $template[11] . '/*' . $this->_htmlsp($token[1], $plain) . '*/' . $template[12];
310 break;
311 }
312 }
313
314 $output = trim($output);
315
316 if (!$plain) {
317 $this->output_css = $output;
318 $this->_print(true);
319 } else {
320 // If using spaces in the template, don't want these to appear in the plain output
321 $this->output_css_plain = str_replace('&#160;', '', $output);
322 }
323 }
324
325 /**
326 * Gets the next token type which is $move away from $key, excluding comments
327 * @param integer $key current position
328 * @param integer $move move this far
329 * @return mixed a token type
330 * @access private
331 * @version 1.0
332 */
333 public function _seeknocomment($key, $move)
334 {
335 $go = ($move > 0) ? 1 : -1;
336 for ($i = $key + 1; abs($key - $i) - 1 < abs($move); $i += $go) {
337 if (!isset($this->tokens[$i])) {
338 return;
339 }
340 if ($this->tokens[$i][0] == csstidyConstants::COMMENT) {
341 $move += 1;
342 continue;
343 }
344 return $this->tokens[$i][0];
345 }
346 }
347
348 /**
349 * Converts $this->css array to a raw array ($this->tokens)
350 * @param string $default_media default @media to add to selectors without any @media
351 * @access private
352 * @version 1.0
353 */
354 public function _convert_raw_css($default_media = '')
355 {
356 $this->tokens = array();
357 $sort_selectors = $this->parser->get_cfg('sort_selectors');
358 $sort_properties = $this->parser->get_cfg('sort_properties');
359
360 // important comment section ?
361 if (isset($this->css['!'])) {
362 $this->parser->_add_token(csstidyConstants::IMPORTANT_COMMENT, rtrim($this->css['!']), true);
363 unset($this->css['!']);
364 }
365
366 foreach ($this->css as $medium => $val) {
367 if ($sort_selectors)
368 ksort($val);
369 if (intval($medium) < csstidyConstants::DEFAULT_AT) {
370 // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
371 if (strlen(trim($medium))) {
372 $parts_to_open = explode('{', $medium);
373 foreach ($parts_to_open as $part) {
374 $this->parser->_add_token(csstidyConstants::AT_START, $part, true);
375 }
376 }
377 } elseif ($default_media) {
378 $this->parser->_add_token(csstidyConstants::AT_START, $default_media, true);
379 }
380
381 foreach ($val as $selector => $vali) {
382 if ($sort_properties)
383 ksort($vali);
384 $this->parser->_add_token(csstidyConstants::SEL_START, $selector, true);
385
386 $invalid = array(
387 '*' => array(), // IE7 hacks first
388 '_' => array(), // IE6 hacks
389 '/' => array(), // IE6 hacks
390 '-' => array() // IE6 hacks
391 );
392 foreach ($vali as $property => $valj) {
393 if (strncmp($property, "//", 2) !== 0) {
394 $matches = array();
395 if ($sort_properties && preg_match('/^(\*|_|\/|-)(?!(ms|moz|o\b|xv|atsc|wap|khtml|webkit|ah|hp|ro|rim|tc)-)/', $property, $matches)) {
396 $invalid[$matches[1]][$property] = $valj;
397 } else {
398 $this->parser->_add_token(csstidyConstants::PROPERTY, $property, true);
399 $this->parser->_add_token(csstidyConstants::VALUE, $valj, true);
400 }
401 }
402 }
403 foreach ($invalid as $prefix => $props) {
404 foreach ($props as $property => $valj) {
405 $this->parser->_add_token(csstidyConstants::PROPERTY, $property, true);
406 $this->parser->_add_token(csstidyConstants::VALUE, $valj, true);
407 }
408 }
409 $this->parser->_add_token(csstidyConstants::SEL_END, $selector, true);
410 }
411
412 if (intval($medium) < csstidyConstants::DEFAULT_AT) {
413 // un medium vide (contenant @font-face ou autre @) ne produit aucun conteneur
414 if (strlen(trim($medium))) {
415 $parts_to_close = explode('{', $medium);
416 foreach (array_reverse($parts_to_close) as $part) {
417 $this->parser->_add_token(csstidyConstants::AT_END, $part, true);
418 }
419 }
420 } elseif ($default_media) {
421 $this->parser->_add_token(csstidyConstants::AT_END, $default_media, true);
422 }
423 }
424 }
425
426 /**
427 * Same as htmlspecialchars, only that chars are not replaced if $plain !== true. This makes print_code() cleaner.
428 * @param string $string
429 * @param bool $plain
430 * @return string
431 * @see csstidy_print::_print()
432 * @access private
433 * @version 1.0
434 */
435 public function _htmlsp($string, $plain)
436 {
437 if (!$plain) {
438 return htmlspecialchars($string, ENT_QUOTES, 'utf-8');
439 }
440 return $string;
441 }
442
443 /**
444 * Get compression ratio
445 * @access public
446 * @return float
447 * @version 1.2
448 */
449 public function get_ratio()
450 {
451 if (!$this->output_css_plain) {
452 $this->formatted();
453 }
454 return round((strlen($this->input_css) - strlen($this->output_css_plain)) / strlen($this->input_css), 3) * 100;
455 }
456
457 /**
458 * Get difference between the old and new code in bytes and prints the code if necessary.
459 * @access public
460 * @return string
461 * @version 1.1
462 */
463 public function get_diff()
464 {
465 if (!$this->output_css_plain) {
466 $this->formatted();
467 }
468
469 $diff = strlen($this->output_css_plain) - strlen($this->input_css);
470
471 if ($diff > 0) {
472 return '+' . $diff;
473 } elseif ($diff == 0) {
474 return '+-' . $diff;
475 }
476
477 return $diff;
478 }
479
480 /**
481 * Get the size of either input or output CSS in KB
482 * @param string $loc default is "output"
483 * @access public
484 * @return integer
485 * @version 1.0
486 */
487 public function size($loc = 'output')
488 {
489 if ($loc === 'output' && !$this->output_css) {
490 $this->formatted();
491 }
492
493 if ($loc === 'input') {
494 return (strlen($this->input_css) / 1000);
495 } else {
496 return (strlen($this->output_css_plain) / 1000);
497 }
498 }
499 }
500