source: trunk/library/csstidy/class.csstidy.php @ 7673

Revision 7673, 27.8 KB checked in by douglasz, 11 years ago (diff)

Ticket #3236 - Correcoes para Performance: Function Within Loop Declaration.

  • Property svn:executable set to *
Line 
1<?php
2/**
3 * CSSTidy - CSS Parser and Optimiser
4 *
5 * CSS Parser class
6 *
7 * This file is part of CSSTidy.
8 *
9 * CSSTidy is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * CSSTidy is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with CSSTidy; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @license http://opensource.org/licenses/gpl-license.php GNU Public License
24 * @package csstidy
25 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
26 */
27
28/**
29 * Various CSS data needed for correct optimisations etc.
30 *
31 * @version 1.3
32 */
33require('data.inc.php');
34
35/**
36 * Contains a class for printing CSS code
37 *
38 * @version 1.0
39 */
40require('class.csstidy_print.php');
41
42/**
43 * Contains a class for optimising CSS code
44 *
45 * @version 1.0
46 */
47require('class.csstidy_optimise.php');
48
49/**
50 * CSS Parser class
51 *
52 * This class represents a CSS parser which reads CSS code and saves it in an array.
53 * In opposite to most other CSS parsers, it does not use regular expressions and
54 * thus has full CSS2 support and a higher reliability.
55 * Additional to that it applies some optimisations and fixes to the CSS code.
56 * An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
57 * @package csstidy
58 * @author Florian Schmitz (floele at gmail dot com) 2005-2006
59 * @version 1.3
60 */
61class csstidy {
62
63/**
64 * Saves the parsed CSS
65 * @var array
66 * @access public
67 */
68var $css = array();
69
70/**
71 * Saves the parsed CSS (raw)
72 * @var array
73 * @access private
74 */
75var $tokens = array();
76
77/**
78 * Printer class
79 * @see csstidy_print
80 * @var object
81 * @access public
82 */
83var $print;
84
85/**
86 * Optimiser class
87 * @see csstidy_optimise
88 * @var object
89 * @access private
90 */
91var $optimise;
92
93/**
94 * Saves the CSS charset (@charset)
95 * @var string
96 * @access private
97 */
98var $charset = '';
99
100/**
101 * Saves all @import URLs
102 * @var array
103 * @access private
104 */
105var $import = array();
106
107/**
108 * Saves the namespace
109 * @var string
110 * @access private
111 */
112var $namespace = '';
113
114/**
115 * Contains the version of csstidy
116 * @var string
117 * @access private
118 */
119var $version = '1.3';
120
121/**
122 * Stores the settings
123 * @var array
124 * @access private
125 */
126var $settings = array();
127
128/**
129 * Saves the parser-status.
130 *
131 * Possible values:
132 * - is = in selector
133 * - ip = in property
134 * - iv = in value
135 * - instr = in string (started at " or ' or ( )
136 * - ic = in comment (ignore everything)
137 * - at = in @-block
138 *
139 * @var string
140 * @access private
141 */
142var $status = 'is';
143
144
145/**
146 * Saves the current at rule (@media)
147 * @var string
148 * @access private
149 */
150var $at = '';
151
152/**
153 * Saves the current selector
154 * @var string
155 * @access private
156 */
157var $selector = '';
158
159/**
160 * Saves the current property
161 * @var string
162 * @access private
163 */
164var $property = '';
165
166/**
167 * Saves the position of , in selectors
168 * @var array
169 * @access private
170 */
171var $sel_separate = array();
172
173/**
174 * Saves the current value
175 * @var string
176 * @access private
177 */
178var $value = '';
179
180/**
181 * Saves the current sub-value
182 *
183 * Example for a subvalue:
184 * background:url(foo.png) red no-repeat;
185 * "url(foo.png)", "red", and  "no-repeat" are subvalues,
186 * seperated by whitespace
187 * @var string
188 * @access private
189 */
190var $sub_value = '';
191
192/**
193 * Array which saves all subvalues for a property.
194 * @var array
195 * @see sub_value
196 * @access private
197 */
198var $sub_value_arr = array();
199
200/**
201 * Saves the char which opened the last string
202 * @var string
203 * @access private
204 */
205var $str_char = '';
206var $cur_string = '';
207
208/**
209 * Status from which the parser switched to ic or instr
210 * @var string
211 * @access private
212 */
213var $from = '';
214
215/**
216 * Variable needed to manage string-in-strings, for example url("foo.png")
217 * @var string
218 * @access private
219 */
220var $str_in_str = false;
221
222/**
223 * =true if in invalid at-rule
224 * @var bool
225 * @access private
226 */
227var $invalid_at = false;
228
229/**
230 * =true if something has been added to the current selector
231 * @var bool
232 * @access private
233 */
234var $added = false;
235
236/**
237 * Array which saves the message log
238 * @var array
239 * @access private
240 */
241var $log = array();
242
243/**
244 * Saves the line number
245 * @var integer
246 * @access private
247 */
248var $line = 1;
249
250/**
251 * Loads standard template and sets default settings
252 * @access private
253 * @version 1.3
254 */
255function csstidy()
256{
257        $this->settings['remove_bslash'] = true;
258        $this->settings['compress_colors'] = true;
259        $this->settings['compress_font-weight'] = true;
260        $this->settings['lowercase_s'] = false;
261        $this->settings['optimise_shorthands'] = 1;
262        $this->settings['remove_last_;'] = false;
263        $this->settings['case_properties'] = 1;
264        $this->settings['sort_properties'] = false;
265        $this->settings['sort_selectors'] = false;
266        $this->settings['merge_selectors'] = 2;
267        $this->settings['discard_invalid_properties'] = false;
268        $this->settings['css_level'] = 'CSS2.1';
269    $this->settings['preserve_css'] = false;
270    $this->settings['timestamp'] = false;
271
272        $this->load_template('default');
273    $this->print = new csstidy_print($this);
274    $this->optimise = new csstidy_optimise($this);
275}
276
277/**
278 * Get the value of a setting.
279 * @param string $setting
280 * @access public
281 * @return mixed
282 * @version 1.0
283 */
284function get_cfg($setting)
285{
286        if(isset($this->settings[$setting]))
287        {
288                return $this->settings[$setting];
289        }
290        return false;
291}
292
293/**
294 * Set the value of a setting.
295 * @param string $setting
296 * @param mixed $value
297 * @access public
298 * @return bool
299 * @version 1.0
300 */
301function set_cfg($setting,$value)
302{
303        if(isset($this->settings[$setting]) && $value !== '')
304        {
305                $this->settings[$setting] = $value;
306                return true;
307        }
308        return false;
309}
310
311/**
312 * Adds a token to $this->tokens
313 * @param mixed $type
314 * @param string $data
315 * @param bool $do add a token even if preserve_css is off
316 * @access private
317 * @version 1.0
318 */
319function _add_token($type, $data, $do = false) {
320    if($this->get_cfg('preserve_css') || $do) {
321        $this->tokens[] = array($type, ($type == COMMENT) ? $data : trim($data));
322    }
323}
324
325/**
326 * Add a message to the message log
327 * @param string $message
328 * @param string $type
329 * @param integer $line
330 * @access private
331 * @version 1.0
332 */
333function log($message,$type,$line = -1)
334{
335        if($line === -1)
336        {
337                $line = $this->line;
338        }
339        $line = intval($line);
340        $add = array('m' => $message, 't' => $type);
341        if(!isset($this->log[$line]) || !in_array($add,$this->log[$line]))
342        {
343                $this->log[$line][] = $add;
344        }
345}
346
347/**
348 * Parse unicode notations and find a replacement character
349 * @param string $string
350 * @param integer $i
351 * @access private
352 * @return string
353 * @version 1.2
354 */
355function _unicode(&$string, &$i)
356{
357        ++$i;
358        $add = '';
359        $tokens =& $GLOBALS['csstidy']['tokens'];
360        $replaced = false;
361
362        while($i < strlen($string) && (ctype_xdigit($string{$i}) || ctype_space($string{$i})) && strlen($add) < 6)
363        {
364                $add .= $string{$i};
365
366                if(ctype_space($string{$i})) {
367                        break;
368                }
369                ++$i;
370        }
371
372        if(hexdec($add) > 47 && hexdec($add) < 58 || hexdec($add) > 64 && hexdec($add) < 91 || hexdec($add) > 96 && hexdec($add) < 123)
373        {
374                $this->log('Replaced unicode notation: Changed \\'. $add .' to ' . chr(hexdec($add)),'Information');
375                $add = chr(hexdec($add));
376                $replaced = true;
377        }
378        else {
379                $add = trim('\\'.$add);
380        }
381
382        if(@ctype_xdigit($string{$i+1}) && ctype_space($string{$i})
383       && !$replaced || !ctype_space($string{$i})) {
384                $i--;
385        }
386
387        if($add != '\\' || !$this->get_cfg('remove_bslash') || strpos($tokens, $string{$i+1}) !== false) {
388                return $add;
389        }
390
391        if($add == '\\') {
392                $this->log('Removed unnecessary backslash','Information');
393        }
394        return '';
395}
396
397/**
398 * Loads a new template
399 * @param string $content either filename (if $from_file == true), content of a template file, "high_compression", "highest_compression", "low_compression", or "default"
400 * @param bool $from_file uses $content as filename if true
401 * @access public
402 * @version 1.1
403 * @see http://csstidy.sourceforge.net/templates.php
404 */
405function load_template($content, $from_file=true)
406{
407        $predefined_templates =& $GLOBALS['csstidy']['predefined_templates'];
408        if($content == 'high_compression' || $content == 'default' || $content == 'highest_compression' || $content == 'low_compression')
409        {
410                $this->template = $predefined_templates[$content];
411                return;
412        }
413
414        if($from_file)
415        {
416                $content = strip_tags(file_get_contents($content),'<span>');
417        }
418        $content = str_replace("\r\n","\n",$content); // Unify newlines (because the output also only uses \n)
419        $template = explode('|',$content);
420
421    $template_count = count($template);
422        for ($i = 0; $i < $template_count; ++$i )
423        {
424                $this->template[$i] = $template[$i];
425        }
426}
427
428/**
429 * Starts parsing from URL
430 * @param string $url
431 * @access public
432 * @version 1.0
433 */
434function parse_from_url($url)
435{
436        return $this->parse(@file_get_contents($url));
437}
438
439/**
440 * Checks if there is a token at the current position
441 * @param string $string
442 * @param integer $i
443 * @access public
444 * @version 1.11
445 */
446function is_token(&$string, $i)
447{
448        $tokens =& $GLOBALS['csstidy']['tokens'];
449        return (strpos($tokens, $string{$i}) !== false && !csstidy::escaped($string,$i));
450}
451
452
453/**
454 * Parses CSS in $string. The code is saved as array in $this->css
455 * @param string $string the CSS code
456 * @access public
457 * @return bool
458 * @version 1.1
459 */
460function parse($string) {
461    // PHP bug? Settings need to be refreshed in PHP4
462    $this->print = new csstidy_print($this);
463    $this->optimise = new csstidy_optimise($this);
464
465    $all_properties =& $GLOBALS['csstidy']['all_properties'];
466    $at_rules =& $GLOBALS['csstidy']['at_rules'];
467
468    $this->css = array();
469    $this->print->input_css = $string;
470    $string = str_replace("\r\n","\n",$string) . ' ';
471    $cur_comment = '';
472
473    for ($i = 0, $size = strlen($string); $i < $size; ++$i )
474    {
475        if($string{$i} == "\n" || $string{$i} == "\r")
476        {
477            ++$this->line;
478        }
479
480        switch($this->status)
481        {
482            /* Case in at-block */
483            case 'at':
484            if(csstidy::is_token($string,$i))
485            {
486                if($string{$i} == '/' && @$string{$i+1} == '*')
487                {
488                    $this->status = 'ic'; ++$i;
489                    $this->from = 'at';
490                }
491                elseif($string{$i} == '{')
492                {
493                    $this->status = 'is';
494                    $this->_add_token(AT_START, $this->at);
495                }
496                elseif($string{$i} == ',')
497                {
498                    $this->at = trim($this->at).',';
499                }
500                elseif($string{$i} == '\\')
501                {
502                    $this->at .= $this->_unicode($string,$i);
503                }
504            }
505            else
506            {
507                $lastpos = strlen($this->at)-1;
508                if(!( (ctype_space($this->at{$lastpos}) || csstidy::is_token($this->at,$lastpos) && $this->at{$lastpos} == ',') && ctype_space($string{$i})))
509                {
510                    $this->at .= $string{$i};
511                }
512            }
513            break;
514
515            /* Case in-selector */
516            case 'is':
517            if(csstidy::is_token($string,$i))
518            {
519                if($string{$i} == '/' && @$string{$i+1} == '*' && trim($this->selector) == '')
520                {
521                    $this->status = 'ic'; ++$i;
522                    $this->from = 'is';
523                }
524                elseif($string{$i} == '@' && trim($this->selector) == '')
525                {
526                    // Check for at-rule
527                    $this->invalid_at = true;
528                    foreach($at_rules as $name => $type)
529                    {
530                        if(!strcasecmp(substr($string,$i+1,strlen($name)),$name))
531                        {
532                            ($type == 'at') ? $this->at = '@'.$name : $this->selector = '@'.$name;
533                            $this->status = $type;
534                            $i += strlen($name);
535                            $this->invalid_at = false;
536                        }
537                    }
538
539                    if($this->invalid_at)
540                    {
541                        $this->selector = '@';
542                        $invalid_at_name = '';
543                        for($j = $i+1; $j < $size; ++$j)
544                        {
545                            if(!ctype_alpha($string{$j}))
546                            {
547                                break;
548                            }
549                            $invalid_at_name .= $string{$j};
550                        }
551                        $this->log('Invalid @-rule: '.$invalid_at_name.' (removed)','Warning');
552                    }
553                }
554                elseif(($string{$i} == '"' || $string{$i} == "'"))
555                {
556                    $this->cur_string = $string{$i};
557                    $this->status = 'instr';
558                    $this->str_char = $string{$i};
559                    $this->from = 'is';
560                }
561                elseif($this->invalid_at && $string{$i} == ';')
562                {
563                    $this->invalid_at = false;
564                    $this->status = 'is';
565                }
566                elseif($string{$i} == '{')
567                {
568                    $this->status = 'ip';
569                    $this->_add_token(SEL_START, $this->selector);
570                    $this->added = false;
571                }
572                elseif($string{$i} == '}')
573                {
574                    $this->_add_token(AT_END, $this->at);
575                    $this->at = '';
576                    $this->selector = '';
577                    $this->sel_separate = array();
578                }
579                elseif($string{$i} == ',')
580                {
581                    $this->selector = trim($this->selector).',';
582                    $this->sel_separate[] = strlen($this->selector);
583                }
584                elseif($string{$i} == '\\')
585                {
586                    $this->selector .= $this->_unicode($string,$i);
587                }
588                // remove unnecessary universal selector,  FS#147
589                else if(!($string{$i} == '*' && @in_array($string{$i+1}, array('.', '#', '[', ':')))) {
590                    $this->selector .= $string{$i};
591                }
592            }
593            else
594            {
595                $lastpos = strlen($this->selector)-1;
596                if($lastpos == -1 || !( (ctype_space($this->selector{$lastpos}) || csstidy::is_token($this->selector,$lastpos) && $this->selector{$lastpos} == ',') && ctype_space($string{$i})))
597                {
598                    $this->selector .= $string{$i};
599                }
600            }
601            break;
602
603            /* Case in-property */
604            case 'ip':
605            if(csstidy::is_token($string,$i))
606            {
607                if(($string{$i} == ':' || $string{$i} == '=') && $this->property != '')
608                {
609                    $this->status = 'iv';
610                    if(!$this->get_cfg('discard_invalid_properties') || csstidy::property_is_valid($this->property)) {
611                        $this->_add_token(PROPERTY, $this->property);
612                    }
613                }
614                elseif($string{$i} == '/' && @$string{$i+1} == '*' && $this->property == '')
615                {
616                    $this->status = 'ic'; ++$i;
617                    $this->from = 'ip';
618                }
619                elseif($string{$i} == '}')
620                {
621                    $this->explode_selectors();
622                    $this->status = 'is';
623                    $this->invalid_at = false;
624                    $this->_add_token(SEL_END, $this->selector);
625                    $this->selector = '';
626                    $this->property = '';
627                }
628                elseif($string{$i} == ';')
629                {
630                    $this->property = '';
631                }
632                elseif($string{$i} == '\\')
633                {
634                    $this->property .= $this->_unicode($string,$i);
635                }
636            }
637            elseif(!ctype_space($string{$i}))
638            {
639                $this->property .= $string{$i};
640            }
641            break;
642
643            /* Case in-value */
644            case 'iv':
645            $pn = (($string{$i} == "\n" || $string{$i} == "\r") && $this->property_is_next($string,$i+1) || $i == strlen($string)-1);
646            if(csstidy::is_token($string,$i) || $pn)
647            {
648                if($string{$i} == '/' && @$string{$i+1} == '*')
649                {
650                    $this->status = 'ic'; ++$i;
651                    $this->from = 'iv';
652                }
653                elseif(($string{$i} == '"' || $string{$i} == "'" || $string{$i} == '('))
654                {
655                    $this->cur_string = $string{$i};
656                    $this->str_char = ($string{$i} == '(') ? ')' : $string{$i};
657                    $this->status = 'instr';
658                    $this->from = 'iv';
659                }
660                elseif($string{$i} == ',')
661                {
662                    $this->sub_value = trim($this->sub_value).',';
663                }
664                elseif($string{$i} == '\\')
665                {
666                    $this->sub_value .= $this->_unicode($string,$i);
667                }
668                elseif($string{$i} == ';' || $pn)
669                {
670                    if(( isset($this->selector{0}) && $this->selector{0} == '@') && isset($at_rules[substr($this->selector,1)]) && $at_rules[substr($this->selector,1)] == 'iv')
671                    {
672                        $this->sub_value_arr[] = trim($this->sub_value);
673
674                        $this->status = 'is';
675
676                        switch($this->selector)
677                        {
678                            case '@charset': $this->charset = $this->sub_value_arr[0]; break;
679                            case '@namespace': $this->namespace = implode(' ',$this->sub_value_arr); break;
680                            case '@import': $this->import[] = implode(' ',$this->sub_value_arr); break;
681                        }
682
683                        $this->sub_value_arr = array();
684                        $this->sub_value = '';
685                        $this->selector = '';
686                        $this->sel_separate = array();
687                    }
688                    else
689                    {
690                        $this->status = 'ip';
691                    }
692                }
693                elseif($string{$i} != '}')
694                {
695                    $this->sub_value .= $string{$i};
696                }
697                if(($string{$i} == '}' || $string{$i} == ';' || $pn) && !empty($this->selector))
698                {
699                    if($this->at == '')
700                    {
701                        $this->at = DEFAULT_AT;
702                    }
703
704                    // case settings
705                    if($this->get_cfg('lowercase_s'))
706                    {
707                        $this->selector = strtolower($this->selector);
708                    }
709                    $this->property = strtolower($this->property);
710
711                    $this->optimise->subvalue();
712                    if($this->sub_value != '') {
713                        $this->sub_value_arr[] = $this->sub_value;
714                        $this->sub_value = '';
715                    }
716
717                    $this->value = implode(' ',$this->sub_value_arr);
718
719                    $this->selector = trim($this->selector);
720
721                    $this->optimise->value();
722
723                    $valid = csstidy::property_is_valid($this->property);
724                    if((!$this->invalid_at || $this->get_cfg('preserve_css')) && (!$this->get_cfg('discard_invalid_properties') || $valid))
725                    {
726                        $this->css_add_property($this->at,$this->selector,$this->property,$this->value);
727                        $this->_add_token(VALUE, $this->value);
728                        $this->optimise->shorthands();
729                    }
730                    if(!$valid)
731                    {
732                        if($this->get_cfg('discard_invalid_properties'))
733                        {
734                            $this->log('Removed invalid property: '.$this->property,'Warning');
735                        }
736                        else
737                        {
738                            $this->log('Invalid property in '.strtoupper($this->get_cfg('css_level')).': '.$this->property,'Warning');
739                        }
740                    }
741
742                    $this->property = '';
743                    $this->sub_value_arr = array();
744                    $this->value = '';
745                }
746                if($string{$i} == '}')
747                {
748                    $this->explode_selectors();
749                    $this->_add_token(SEL_END, $this->selector);
750                    $this->status = 'is';
751                    $this->invalid_at = false;
752                    $this->selector = '';
753                }
754            }
755            elseif(!$pn)
756            {
757                $this->sub_value .= $string{$i};
758
759                if(ctype_space($string{$i}))
760                {
761                    $this->optimise->subvalue();
762                    if($this->sub_value != '') {
763                        $this->sub_value_arr[] = $this->sub_value;
764                        $this->sub_value = '';
765                    }
766                }
767            }
768            break;
769
770            /* Case in string */
771            case 'instr':
772            if($this->str_char == ')' && ($string{$i} == '"' || $string{$i} == '\'') && !$this->str_in_str && !csstidy::escaped($string,$i))
773            {
774                $this->str_in_str = true;
775            }
776            elseif($this->str_char == ')' && ($string{$i} == '"' || $string{$i} == '\'') && $this->str_in_str && !csstidy::escaped($string,$i))
777            {
778                $this->str_in_str = false;
779            }
780            $temp_add = $string{$i};           // ...and no not-escaped backslash at the previous position
781            if( ($string{$i} == "\n" || $string{$i} == "\r") && !($string{$i-1} == '\\' && !csstidy::escaped($string,$i-1)) )
782            {
783                $temp_add = "\\A ";
784                $this->log('Fixed incorrect newline in string','Warning');
785            }
786            if (!($this->str_char == ')' && in_array($string{$i}, $GLOBALS['csstidy']['whitespace']) && !$this->str_in_str)) {
787                $this->cur_string .= $temp_add;
788            }
789            if($string{$i} == $this->str_char && !csstidy::escaped($string,$i) && !$this->str_in_str)
790            {
791                $this->status = $this->from;
792                if (!preg_match('|[' . implode('', $GLOBALS['csstidy']['whitespace']) . ']|uis', $this->cur_string) && $this->property != 'content') {
793                    if ($this->str_char == '"' || $this->str_char == '\'') {
794                                                $this->cur_string = substr($this->cur_string, 1, -1);
795                                        } else if (strlen($this->cur_string) > 3 && ($this->cur_string[1] == '"' || $this->cur_string[1] == '\'')) /* () */ {
796                                                $this->cur_string = $this->cur_string[0] . substr($this->cur_string, 2, -2) . substr($this->cur_string, -1);
797                                        }
798                }
799                if($this->from == 'iv')
800                {
801                    $this->sub_value .= $this->cur_string;
802                }
803                elseif($this->from == 'is')
804                {
805                    $this->selector .= $this->cur_string;
806                }
807            }
808            break;
809
810            /* Case in-comment */
811            case 'ic':
812            if($string{$i} == '*' && $string{$i+1} == '/')
813            {
814                $this->status = $this->from;
815                ++$i;
816                $this->_add_token(COMMENT, $cur_comment);
817                $cur_comment = '';
818            }
819            else
820            {
821                $cur_comment .= $string{$i};
822            }
823            break;
824        }
825    }
826
827    $this->optimise->postparse();
828
829    $this->print->_reset();
830
831    return !(empty($this->css) && empty($this->import) && empty($this->charset) && empty($this->tokens) && empty($this->namespace));
832}
833
834/**
835 * Explodes selectors
836 * @access private
837 * @version 1.0
838 */
839function explode_selectors()
840{
841    // Explode multiple selectors
842    if($this->get_cfg('merge_selectors') == 1)
843    {
844        $new_sels = array();
845        $lastpos = 0;
846        $this->sel_separate[] = strlen($this->selector);
847        foreach($this->sel_separate as $num => $pos)
848        {
849            if($num == count($this->sel_separate)-1) {
850                $pos += 1;
851            }
852
853            $new_sels[] = substr($this->selector,$lastpos,$pos-$lastpos-1);
854            $lastpos = $pos;
855        }
856
857        if(count($new_sels) > 1)
858        {
859            foreach($new_sels as $selector)
860            {
861                $this->merge_css_blocks($this->at,$selector,$this->css[$this->at][$this->selector]);
862            }
863            unset($this->css[$this->at][$this->selector]);
864        }
865    }
866    $this->sel_separate = array();
867}
868
869/**
870 * Checks if a character is escaped (and returns true if it is)
871 * @param string $string
872 * @param integer $pos
873 * @access public
874 * @return bool
875 * @version 1.02
876 */
877function escaped(&$string,$pos)
878{
879        return !(@($string{$pos-1} != '\\') || csstidy::escaped($string,$pos-1));
880}
881
882/**
883 * Adds a property with value to the existing CSS code
884 * @param string $media
885 * @param string $selector
886 * @param string $property
887 * @param string $new_val
888 * @access private
889 * @version 1.2
890 */
891function css_add_property($media,$selector,$property,$new_val)
892{
893    if($this->get_cfg('preserve_css') || trim($new_val) == '') {
894        return;
895    }
896
897    $this->added = true;
898    if(isset($this->css[$media][$selector][$property]))
899    {
900        if((csstidy::is_important($this->css[$media][$selector][$property]) && csstidy::is_important($new_val)) || !csstidy::is_important($this->css[$media][$selector][$property]))
901        {
902            unset($this->css[$media][$selector][$property]);
903            $this->css[$media][$selector][$property] = trim($new_val);
904        }
905    }
906    else
907    {
908        $this->css[$media][$selector][$property] = trim($new_val);
909    }
910}
911
912/**
913 * Adds CSS to an existing media/selector
914 * @param string $media
915 * @param string $selector
916 * @param array $css_add
917 * @access private
918 * @version 1.1
919 */
920function merge_css_blocks($media,$selector,$css_add)
921{
922        foreach($css_add as $property => $value)
923        {
924                $this->css_add_property($media,$selector,$property,$value,false);
925        }
926}
927
928/**
929 * Checks if $value is !important.
930 * @param string $value
931 * @return bool
932 * @access public
933 * @version 1.0
934 */
935static function is_important(&$value)
936{
937        return (!strcasecmp(substr(str_replace($GLOBALS['csstidy']['whitespace'],'',$value),-10,10),'!important'));
938}
939
940/**
941 * Returns a value without !important
942 * @param string $value
943 * @return string
944 * @access public
945 * @version 1.0
946 */
947static function gvw_important($value)
948{
949        if(csstidy::is_important($value))
950        {
951                $value = trim($value);
952                $value = substr($value,0,-9);
953                $value = trim($value);
954                $value = substr($value,0,-1);
955                $value = trim($value);
956                return $value;
957        }
958        return $value;
959}
960
961/**
962 * Checks if the next word in a string from pos is a CSS property
963 * @param string $istring
964 * @param integer $pos
965 * @return bool
966 * @access private
967 * @version 1.2
968 */
969function property_is_next($istring, $pos)
970{
971        $all_properties =& $GLOBALS['csstidy']['all_properties'];
972        $istring = substr($istring,$pos,strlen($istring)-$pos);
973        $pos = strpos($istring,':');
974        if($pos === false)
975        {
976                return false;
977        }
978        $istring = strtolower(trim(substr($istring,0,$pos)));
979        if(isset($all_properties[$istring]))
980        {
981                $this->log('Added semicolon to the end of declaration','Warning');
982                return true;
983        }
984        return false;
985}
986
987/**
988 * Checks if a property is valid
989 * @param string $property
990 * @return bool;
991 * @access public
992 * @version 1.0
993 */
994function property_is_valid($property) {
995    $all_properties =& $GLOBALS['csstidy']['all_properties'];
996    return (isset($all_properties[$property]) && strpos($all_properties[$property],strtoupper($this->get_cfg('css_level'))) !== false );
997}
998
999}
1000?>
Note: See TracBrowser for help on using the repository browser.