- <?php
- /**
- * CSSPP - CSS Parser and Optimiser
- *
- * CSS Parser class ( CSS PreProcessor or CSS PostProcessor, depends on the point of view )
- * This class represents a CSS parser which reads CSS code and saves it in an array.
- * In opposite to most other CSS parsers, it does not use regular expressions and
- * thus has full CSS2 support and a higher reliability. The downside of not using regular expressions
- * is a lower speed though.
- * Additional to that it applies some optimisations and fixes to the CSS code.
- * An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
- * @package csspp
- * @author Florian Schmitz (floele at gmail dot com) 2005
- */
-
- /**
- * Various CSS data needed for correct optimisations etc.
- *
- * @version 1.0
- */
- require("data.inc.php");
-
- /**
- * All fcuntions which are not directly related to the parser class
- *
- * @version 1.0
- */
- require("functions.inc.php");
-
- /**
- * CSS Parser class ( CSS PreProcessor or CSS PostProcessor, depends on the point of view )
- *
- * This class represents a CSS parser which reads CSS code and saves it in an array.
- * In opposite to most other CSS parsers, it does not use regular expressions and
- * thus has full CSS2 support and a higher reliability. The downside of not using regular expressions
- * is a lower speed though.
- * Additional to that it applies some optimisations and fixes to the CSS code.
- * An online version should be available here: http://cdburnerxp.se/cssparse/css_optimiser.php
- * @package csspp
- * @author Florian Schmitz (floele at gmail dot com) 2005
- * @version 0.98
- */
- class csspp {
-
- /**
- * Saves the parsed CSS
- * @var array
- * @access public
- */
- var $css = array();
-
- /**
- * Saves the charset (@charset)
- * @var string
- * @access private
- */
- var $charset = '';
-
- /**
- * Saves all @import URLs
- * @var array
- * @access private
- */
- var $import = array();
-
- /**
- * Saves the input CSS string
- * @var string
- * @access private
- */
- var $input_css = '';
-
- /**
- * Saves the formatted CSS string
- * @var string
- * @access public
- */
- var $output_css = '';
-
- /**
- * Saves the templates
- * @var array
- * @access private
- * @see http://cdburnerxp.se/cssparse/template.htm
- */
- var $template = array();
-
- /**
- * A list of certain chars, needed for removing unnecessary backslashes
- * @var array
- * @access private
- */
- var $hex = array('a','b','c','d','e','f','\\',':','=');
-
- /**
- * Contains the version of CSSPP
- * @var string
- * @access private
- */
- var $version = '0.98dev';
-
- /**
- * Stores the settings
- * @var array
- * @access private
- */
- var $settings = array();
-
- /**
- * Saves the parser-status:
- * wfs = wait for selector
- * is = in selector
- * wfp = wait for property
- * ip = in property
- * iv = in value
- * instr = in string (-> ",' ( => ignore } and ; etc.) )
- * ic = in comment (ignore everything)
- * at = in @-block
- *
- * @var string
- * @access private
- */
- var $status = 'wfs';
-
-
- /**
- * Saves the current at rule (@media)
- * @var string
- * @access private
- */
- var $cur_at = '';
-
- /**
- * Saves the current selector
- * @var string
- * @access private
- */
- var $cur_selector = '';
-
- /**
- * Saves the current property
- * @var string
- * @access private
- */
- var $cur_property = '';
-
- /**
- * Saves the current value
- * @var string
- * @access private
- */
- var $cur_value = '';
-
- /**
- * Saves the current sub-value
- *
- * Example for a subvalue:
- * background:url(foo.png) red no-repeat;
- * "url(foo.png)", "red", and "no-repeat" are subvalues,
- * seperated by whitespace
- * @var string
- * @access private
- */
- var $cur_sub_value = '';
-
- /**
- * Array which saves all subvalues for a property.
- * @var string
- * @see cur_sub_value
- * @access private
- */
- var $cur_sub_value_arr = array();
-
- /**
- * Saves the char which opened the last string
- * @var string
- * @access private
- */
- var $str_char = '';
-
- /**
- * Status where the string has been started (is or iv)
- * @var string
- * @access private
- */
- var $str_from = '';
-
- /**
- * Variable needed to manage string-in-strings, for example url("foo.png")
- * @var string
- * @access private
- */
- var $str_in_str = FALSE;
-
- /**
- * Status where the comment has been started
- * @var string
- * @access private
- */
- var $comment_from = '';
-
-
- /**
- * Loads standard template and sets default settings
- * @access private
- * @version 1.0
- */
- function csspp()
- {
- $this->settings["remove_bslash"] = true;
- $this->settings["compress_colors"] = true;
- $this->settings["lowercase_s"] = false;
- $this->settings["save_ie_hacks"] = false;
- $this->settings["optimise_shorthands"] = true;
- $this->settings["remove_last_;"] = false;
- $this->settings["uppercase_properties"] = false;
- $this->settings["sort_properties"] = false;
- $this->settings["sort_selectors"] = false;
- $this->settings["merge_selectors"] = true;
-
- $this->template[0] = '<span class="at">'; //string before @rule
- $this->template[1] = '</span> <span class="format">{</span>'."\n"; //bracket after @-rule
- $this->template[2] = '<span class="selector">'; //string before selector
- $this->template[3] = '</span> <span class="format">{</span>'."\n"; //bracket after selector
- $this->template[4] = '<span class="property">'; //string before property
- $this->template[5] = '</span><span class="value">'; //string after property+before value
- $this->template[6] = '</span><span class="format">;</span>'."\n"; //string after value
- $this->template[7] = '<span class="format">}</span>'; //closing bracket - selector
- $this->template[8] = "\n\n"; //after closing bracket (conditional)
- $this->template[9] = "\n".'<span class="format">}</span>'."\n\n"; //closing bracket @-rule
- $this->template[10] = ''; //indent in @-rule
- $this->template[11] = '</span> <span class="format">{</span>'."\n"; //indent in @-rule before selector bracket
- $this->template[12] = ''; // after @-rule
- }
-
- /**
- * Get the value of a setting.
- * @param string $setting
- * @access public
- * @return bool
- * @version 1.0
- */
- function get_cfg($setting)
- {
- if(isset($this->settings[$setting]))
- {
- return $this->settings[$setting];
- }
- else
- {
- return false;
- }
- }
-
- /**
- * Set the value of a setting.
- * @param string $setting
- * @param bool $value
- * @access public
- * @return bool
- * @version 1.0
- */
- function set_cfg($setting,$value)
- {
- if(isset($this->settings[$setting]) && ($value === TRUE || $value === FALSE))
- {
- $this->settings[$setting] = $value;
- return true;
- }
- return false;
- }
-
- /**
- * Extract URL from @import value (if $opt == TRUE) and/or add missing http:// to URL
- * @param string $string
- * @param bool $opt
- * @access public
- * @return bool
- * @version 1.0
- */
- function parseurl($string,$opt = TRUE)
- {
- if(substr($string,0,4) == 'url(' && $opt)
- {
- $string = substr($string,4);
-
- $string = substr($string,0,(strlen($string)-1)-strpos(strrev($string),')'));
- }
- if(($string{0} == '"' || $string{0} == '\'') && $opt)
- {
- $string = substr($string,0,(strlen($string)-1)-strpos(strrev($string),$string{0}));
- $string = substr($string,1);
- }
- if(substr($string,0,7) != 'http://')
- {
- $string = 'http://'.$string;
- }
- return $string;
- }
-
- /**
- * Compresses shorthand values. Example: margin:1px 1px 1px 1px -> margin:1px
- * @param string $value
- * @access private
- * @return string
- * @version 1.0
- */
- function shorthand($value)
- {
- $important = '';
- if(csspp::is_important($value))
- {
- $values = csspp::gvw_important($value);
- $important = ' !important';
- }
- else $values = $value;
-
- $values = explode(' ',$values);
- switch(count($values))
- {
- case 4:
- if($values[0] == $values[1] && $values[0] == $values[2] && $values[0] == $values[3])
- {
- return $values[0].$important;
- }
- elseif($values[1] == $values[3] && $values[0] == $values[2])
- {
- return $values[0].' '.$values[1].$important;
- }
- elseif($values[1] == $values[3])
- {
- return $values[0].' '.$values[1].' '.$values[2].$important;
- }
- else return $value;
- break;
-
- case 3:
- if($values[0] == $values[1] && $values[0] == $values[2])
- {
- return $values[0].$important;
- }
- elseif($values[0] == $values[2])
- {
- return $values[0].' '.$values[1].$important;
- }
- else return $value;
- break;
-
- case 2:
- if($values[0] == $values[1])
- {
- return $values[0].$important;
- }
- else return $value;
- break;
-
- default:
- return $value;
- }
- }
-
- /**
- * Get compression ratio and prints the code if necessary.
- * @access public
- * @return float
- * @version 1.0
- */
- function get_ratio()
- {
- if(empty($this->output_css))
- {
- $this->print_code($this->css);
- }
- return $ratio = round(((strlen($this->input_css))-(strlen(strip_tags(html_entity_decode($this->output_css)))))/(strlen($this->input_css)),3)*100;
- }
-
- /**
- * Get difference between the old and new code in bytes and prints the code if necessary.
- * @access public
- * @return string
- * @version 1.0
- */
- function get_diff()
- {
- if(empty($this->output_css))
- {
- $this->print_code($this->css);
- }
- $diff = (strlen(html_entity_decode(strip_tags($this->output_css))))-(strlen($this->input_css));
-
- if($diff > 0)
- {
- return '+'.$diff;
- }
- elseif($diff == 0)
- {
- return '+-'.$diff;
- }
- else
- {
- return $diff;
- }
- }
-
- /**
- * Get the size of either input or output CSS in KB
- * @param string $loc default is "output"
- * @access public
- * @return integer
- * @version 1.0
- */
- function size($loc = 'output')
- {
- if($loc == 'output' && empty($this->output_css))
- {
- $this->print_code($this->css);
- }
-
- if($loc == 'input')
- {
- return (strlen($this->input_css)/1000);
- }
- else
- {
- return (strlen(html_entity_decode(strip_tags($this->output_css)))/1000);
- }
- }
-
- /**
- * Loads a new template
- * @param string $content either filename (if $from_file == true) or content of a template file
- * @param bool $from_file uses $content as filename if true
- * @access public
- * @version 1.0
- * @see http://cdburnerxp.se/cssparse/template.htm
- */
- function load_template($content,$from_file=TRUE)
- {
- if($from_file)
- {
- $content = strip_tags(file_get_contents($content),'<span>');
- }
- $content = str_replace("\r\n","\n",$content); // Unify newlines (because the output also only uses \n)
- $template = explode('|',$content);
-
- for ($i = 0, $size = count($this->template); $i < $size; $i++ )
- {
- $this->template[$i] = @$template[$i];
- }
- }
-
- /**
- * Starts parsing from URL
- * @param string $url
- * @access public
- * @version 1.0
- */
- function parse_from_url($url)
- {
- $content = @file_get_contents($url);
- $this->parse($content);
- }
-
- /**
- * Parses CSS in $string. The code is saved as array in $this->css
- * @param string $string the CSS code
- * @access public
- * @return bool
- * @version 0.98
- */
- function parse($string) {
-
- global $shorthands;
- $string = str_replace("\r\n","\n",$string);
- $this->input_css = $string;
-
- for ($i = 0, $size = strlen($string); $i < $size; $i++ ) {
- switch($this->status)
- {
- case 'wfs':
- if($string{$i} == '/' && @$string{$i+1} == '*')
- {
- $this->status = 'ic';
- $this->comment_from = 'wfs';
- }
- elseif($string{$i} == '@')
- {
- if(strtolower(substr($string,$i+1,4)) == 'page' || strtolower(substr($string,$i+1,9)) == 'font-face')
- {
- $this->cur_selector = '@';
- $this->status = 'is';
- }
- elseif(strtolower(substr($string,$i+1,7)) == 'charset')
- {
- $this->cur_selector = '@charset';
- $i += 7;
- $this->status = 'iv';
- }
- elseif(strtolower(substr($string,$i+1,6)) == 'import')
- {
- $this->cur_selector = '@import';
- $i += 6;
- $this->status = 'iv';
- }
- else
- {
- $this->cur_at = '@';
- $this->status = 'at';
- }
- }
- elseif($string{$i} == '}')
- {
- $this->cur_at = '';
- }
- elseif(!ctype_space($string{$i}))
- {
- $this->status = 'is';
- $this->cur_selector = $string{$i};
- }
- break;
-
- case 'at';
- if($string{$i} == '/' && @$string{$i+1} == '*')
- {
- $this->status = 'ic';
- $this->comment_from = 'at';
- }
- elseif($string{$i} != '{')
- {
- if($string{$i-1} == ',' && !ctype_space($string{$i}) || $string{$i-1} != ',')
- {
- if( ( !ctype_space($string{$i-1}) && ctype_space($string{$i}) ) || !ctype_space($string{$i}))
- {
- $this->cur_at .= $string{$i};
- }
- }
- }
- elseif($string{$i} == '{')
- {
- $this->status = 'wfs';
- }
- break;
-
- case 'is';
- if($string{$i} == '/' && @$string{$i+1} == '*')
- {
- $this->status = 'ic';
- $this->comment_from = 'is';
- }
- elseif(($string{$i} == '"' || $string{$i} == "'") && !csspp::escaped($string,$i))
- {
- $this->cur_selector .= $string{$i};
- $this->status = 'instr';
- $this->str_char = $string{$i};
- $this->str_from = 'is';
- }
- elseif($string{$i} != '{')
- {
- if($string{$i-1} == ',' && !ctype_space($string{$i}) || $string{$i-1} != ',')
- {
- if( ( !ctype_space($string{$i-1}) && ctype_space($string{$i}) ) || !ctype_space($string{$i}))
- {
- $this->cur_selector .= $string{$i};
- }
- }
- }
- elseif($string{$i} == '{' && !csspp::escaped($string,$i))
- {
- $this->status = 'wfp';
- }
- elseif($string{$i} == '{' && csspp::escaped($string,$i))
- {
- $this->cur_selector .= $string{$i};
- }
- break;
-
- case 'wfp':
- if($string{$i} == '/' && @$string{$i+1} == '*')
- {
- $this->status = 'ic';
- $this->comment_from = 'wfp';
- }
- elseif($string{$i} == '}')
- {
- $this->status = 'wfs';
- $this->cur_selector = '';
- }
- elseif(!ctype_space($string{$i}))
- {
- $this->cur_property .= $string{$i};
- $this->status = 'ip';
- }
- break;
-
- case 'ip':
- if(!ctype_space($string{$i}) && $string{$i} != ':' && $string{$i} != '=')
- {
- if($string{$i} != '\\' || !$this->get_cfg('remove_bslash'))
- {
- $this->cur_property .= $string{$i};
- }
- elseif($this->get_cfg('remove_bslash'))
- {
- if(($string{$i} == '\\' && in_array(@$string{$i+1},$this->hex)) || csspp::escaped($string,$i))
- {
- $this->cur_property .= $string{$i};
- }
- }
- }
- if($string{$i} == ':' || $string{$i} == '=')
- {
- $this->status = 'iv';
- }
- break;
-
- case 'iv':
- if($string{$i} == '/' && @$string{$i+1} == '*')
- {
- $this->status = 'ic';
- $this->comment_from = 'iv';
- }
- elseif(($string{$i} == '"' || $string{$i} == "'" || $string{$i} == '(') && !csspp::escaped($string,$i))
- {
- if($this->cur_selector != '@charset')
- {
- $this->cur_sub_value .= $string{$i};
- }
- if($string{$i} == '(') $this->str_char = ')'; else $this->str_char = $string{$i};
- $this->status = 'instr';
- $this->str_from = 'iv';
- }
- elseif($string{$i} != ';' && $string{$i} != '}' && !( ($string[$i] == "\n" || $string[$i] == "\r") && csspp::property_is_next($string,$i+1)))
- {
- if($this->cur_selector == '@charset')
- {
- break;
- }
- $c = FALSE;
- if((($string{$i-1} != ' ') && $string{$i} == ' ') || $string{$i} != ' ')
- {
- $c = TRUE;
- $this->cur_sub_value .= $string{$i};
- }
- if(ctype_space($string{$i}) && $c)
- {
- if(trim($this->cur_sub_value) != '')
- {
- if($this->get_cfg('compress_colors'))
- {
- $this->cur_sub_value = cut_color($this->cur_sub_value);
- }
- compress_numbers($this->cur_sub_value);
- $this->cur_sub_value_arr[] = trim($this->cur_sub_value);
- }
- $this->cur_sub_value = '';
- }
- }
- elseif($string{$i} == ';' || ( ($string[$i] == "\n" || $string[$i] == "\r") && csspp::property_is_next($string,$i+1)))
- {
- if($this->cur_selector == '@charset')
- {
- $this->status = 'wfs';
- $this->charset = $this->cur_sub_value;
- $this->cur_sub_value = '';
- $this->cur_selector = '';
- }
- elseif($this->cur_selector == '@import')
- {
- $this->cur_sub_value_arr[] = trim($this->cur_sub_value);
- $this->status = 'wfs';
- $this->import[] = implode(' ',$this->cur_sub_value_arr);
- $this->cur_sub_value_arr = array();
- $this->cur_sub_value = '';
- $this->cur_selector = '';
- }
- else
- {
- $this->status = 'wfp';
- }
- }
- if(($string{$i} == '}' || $string{$i} == ';' || ( ($string[$i] == "\n" || $string[$i] == "\r") && csspp::property_is_next($string,$i+1))) && !empty($this->cur_selector))
- {
- if($this->cur_at == '')
- {
- $this->cur_at = 'standard';
- }
- // case settings
- if($this->get_cfg('lowercase_s'))
- {
- $this->cur_selector = strtolower($this->cur_selector);
- }
- $this->cur_property = strtolower($this->cur_property);
-
- if(trim($this->cur_sub_value) != '')
- {
- if($this->get_cfg('compress_colors'))
- {
- $this->cur_sub_value = cut_color($this->cur_sub_value);
- }
- compress_numbers($this->cur_sub_value);
- $this->cur_sub_value_arr[] = $this->cur_sub_value;
- $this->cur_sub_value = '';
- }
-
- $this->cur_value = implode(' ',$this->cur_sub_value_arr);
-
- $this->cur_selector = trim($this->cur_selector);
-
- // optimise shorthand properties
- if(isset($shorthands[$this->cur_property]))
- {
- $this->cur_value = csspp::shorthand($this->cur_value);
- }
-
- // Remove whitespace at ! important
- csspp::c_important($this->cur_value);
-
-
- if(isset($this->css[$this->cur_at][$this->cur_selector]) && ($this->get_cfg('save_ie_hacks') || csspp::has_subkey($this->cur_property,$this->css[$this->cur_at][$this->cur_selector])))
- {
- $this->css_add_property($this->css[$this->cur_at][$this->cur_selector],$this->cur_property,$this->cur_value);
- }
- else
- {
- $this->css[$this->cur_at][$this->cur_selector][][$this->cur_property] = trim($this->cur_value);
- }
-
- // Further Optimisation
- if($this->cur_property === 'background' && $this->get_cfg('optimise_shorthands'))
- {
- $temp = dissolve_short_bg($this->cur_value);
- csspp::rm_subkey('background',$this->css[$this->cur_at][$this->cur_selector]);
- csspp::merge_css_blocks($this->css[$this->cur_at][$this->cur_selector],$temp);
- }
- if(isset($shorthands[$this->cur_property]) && $this->get_cfg('optimise_shorthands'))
- {
- $temp = dissolve_4value_shorthands($this->cur_property,$this->cur_value);
- csspp::merge_css_blocks($this->css[$this->cur_at][$this->cur_selector],$temp);
- if(is_array($shorthands[$this->cur_property]))
- {
- csspp::rm_subkey($this->cur_property,$this->css[$this->cur_at][$this->cur_selector]);
- }
- }
-
- $this->cur_property = '';
- $this->cur_sub_value_arr = array();
- $this->cur_value = '';
- }
- if($string{$i} == '}')
- {
- $this->status = 'wfs';
- $this->cur_selector = '';
- }
- break;
-
- case 'instr':
- if($this->str_char == ')' && $string{$i} == '"' && $this->str_in_str === FALSE && !csspp::escaped($string,$i))
- {
- $this->str_in_str = TRUE;
- }
- elseif($this->str_char == ')' && $string{$i} == '"' && $this->str_in_str === TRUE && !csspp::escaped($string,$i))
- {
- $this->str_in_str = FALSE;
- }
- if($string{$i} == $this->str_char && !csspp::escaped($string,$i) && $this->str_in_str === FALSE)
- {
- if($this->str_from == 'iv')
- {
- $this->status = 'iv';
- }
- elseif($this->str_from == 'is')
- {
- $this->status = 'is';
- }
- if($this->cur_selector == '@charset')
- {
- break;
- }
- }
- $temp_add = $string{$i};
-
- if( ($string{$i} == "\n" || $string{$i} == "\r") && !($string{$i-1 } == '\\' && !csspp::escaped($string,$i-1)) )
- {
- $temp_add = "\\A";
- }
- if($this->str_from == 'iv')
- {
- $this->cur_sub_value .= $temp_add;
- }
- elseif($this->str_from == 'is')
- {
- $this->cur_selector .= $temp_add;
- }
- break;
-
- case 'ic':
- if($string{$i} == '/' && $string{$i-1} == '*' && !csspp::escaped($string,$i))
- {
- $this->status = $this->comment_from;
- }
- break;
- }
- }
-
- if($this->get_cfg('merge_selectors'))
- {
- foreach($this->css as $medium => $value)
- {
- for ($i = 0; $i < count($this->css); $i++)
- {
- $this->css[$medium] = csspp::merge_selectors($this->css[$medium]);
- }
- }
- }
-
- if($this->get_cfg('optimise_shorthands'))
- {
- foreach($this->css as $medium => $value)
- {
- foreach($value as $selector => $value1)
- {
- $this->css[$medium][$selector] = merge_4value_shorthands($this->css[$medium][$selector]);
- $this->css[$medium][$selector] = merge_bg($this->css[$medium][$selector]);
- if(empty($this->css[$medium][$selector]))
- {
- unset($this->css[$medium][$selector]);
- }
- }
- }
- }
-
- return (empty($this->css)) ? FALSE : TRUE;
- }
-
- /**
- * Checks if a character is escaped (and returns TRUE if it is)
- * @param string $string
- * @param integer $pos
- * @access public
- * @return bool
- * @version 1.0
- */
- function escaped(&$string,$pos)
- {
- if(@($string{$pos-1} != '\\'))
- {
- return FALSE;
- }
- elseif(csspp::escaped($string,$pos-1))
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
- }
-
- /**
- * Checks if $array has the key $find (array[x][$find]). If gv=1, the value of the key is returned.
- * @param string $find
- * @param array $array
- * @param integer $gv default is 0
- * @access public
- * @return mixed depends on $gv, either bool or string
- * @version 1.0
- */
- function has_subkey($find,$array,$gv=0) {
- foreach($array as $key => $value)
- {
- if(isset($array[$key][$find]))
- {
- return ($gv == 0) ? TRUE : $array[$key][$find];
- }
- }
- return FALSE;
- }
-
- /**
- * Removes all keys $find in $array (array[x][$find]).
- * @param string $find
- * @param array $array
- * @param string $del_val if this is !== NULL, it only removes if the value of they key $find === $del_val
- * @access public
- * @version 1.0
- */
- function rm_subkey($find,&$array,$del_val = NULL)
- {
- foreach($array as $key => $value)
- {
- if(isset($array[$key][$find]) && ($del_val === NULL || $array[$key][$find] === $del_val))
- {
- unset($array[$key]);
- }
- }
- }
-
- /**
- * Adds a property with value to an existing CSS block
- * @param array $css
- * @param string $property
- * @param string $new_val
- * @param bool $ie if $ie == FALSE IE Hacks are not saved even if it is enabled in settings
- * @access public
- * @version 1.0
- */
- function css_add_property(&$css,$property,$new_val,$ie=TRUE)
- {
- $temp = $css;
- if($this->get_cfg('save_ie_hacks') && $ie)
- {
- $overwrite = FALSE;
- foreach($css as $key => $value)
- {
- if(isset($css[$key][$property]) && (!csspp::is_important($css[$key][$property]) && !($property == 'voice-family' && $css[$key][$property] == '"\"}\""') ) )
- {
- $overwrite = TRUE;
- $temp[$key][$property] = trim($new_val);
- }
- }
- if(!$overwrite) $temp[][$property] = trim($new_val);
- }
- else
- {
- foreach($css as $key => $value)
- {
- if(isset($css[$key][$property]))
- {
- if((csspp::is_important($css[$key][$property]) && csspp::is_important($new_val)) || !csspp::is_important($css[$key][$property]))
- {
- unset($temp[$key]);
- $temp[][$property] = trim($new_val);
- }
- }
- }
- }
- $css = $temp;
- }
-
- /**
- * Merges two CSS blocks
- * @param array $existing_css
- * @param array $css_add
- * @access public
- * @version 1.0
- */
- function merge_css_blocks(&$existing_css,$css_add)
- {
- foreach($css_add as $key => $value)
- {
- if(!csspp::has_subkey($key,$existing_css))
- {
- $existing_css[][$key] = $value;
- }
- else
- {
- $this->css_add_property($existing_css,$key,$value,false);
- }
- }
- }
-
- /**
- * This function checks if the properties $needle also exist in other selectors $haystack and returs them as $keys
- * @param array $needle
- * @param array $haystack
- * @access public
- * @version 1.0
- */
- function in_array_prop($needle, $haystack)
- {
- $keys = array();
- foreach($haystack as $key => $value)
- {
- $i = 0;
- foreach($needle as $key1 => $value1)
- {
- if(in_array($needle[$key1],$haystack[$key]))
- $i++;
- }
- if($i == count($needle) && $i == count($haystack[$key])) $keys[] = $key;
- }
- if(empty($keys)) return FALSE; else return $keys;
- }
-
- /**
- * Merges selectors with same properties. Example: a{color:red} b{color:red} -> a,b{color:red}
- * Very basic and has at least one bug. Hopefully there is a replacement soon.
- * @param array $array
- * @return array
- * @access public
- * @version 1.0
- */
- function merge_selectors($array)
- {
- foreach($array as $key => $value)
- {
- if(isset($array[$key]))
- {
- $newsel = '';
- $temp = $array;
- unset($temp[$key]);
-
- $result = csspp::in_array_prop($array[$key],$temp);
- if($result !== FALSE)
- {
- $newsel = $key;
- unset($array[$key]);
- foreach($result as $key1 => $value1)
- {
- unset($array[$value1]);
- $newsel .= ','.$value1;
- }
- $array[$newsel] = $value;
- }
- }
- }
- return $array;
- }
-
-
- /**
- * Checks if $value is !important.
- * @param string $value
- * @return bool
- * @access public
- * @version 1.0
- */
- function is_important(&$value)
- {
- global $whitespace;
- if(strtolower(substr(str_replace($whitespace,'',$value),-10,10)) === '!important')
- {
- return TRUE;
- }
- return FALSE;
- }
-
- /**
- * Returns a value without !important
- * @param string $value
- * @return string
- * @access public
- * @version 1.0
- */
- function gvw_important($value)
- {
- if(csspp::is_important($value))
- {
- $value = trim($value);
- $value = substr($value,0,-9);
- $value = trim($value);
- $value = substr($value,0,-1);
- $value = trim($value);
- return $value;
- }
- else
- {
- return $value;
- }
- }
-
- /**
- * Removes unnecessary whitespace in ! important
- * @param string $string
- * @access public
- * @version 1.0
- */
- function c_important(&$string)
- {
- if(csspp::is_important($string))
- {
- $string = csspp::gvw_important($string) . ' !important';
- }
- }
-
- /**
- * Sort function for sorting the properties
- * @param string $val1
- * @param string $val2
- * @return integer
- * @access public
- * @version 1.0
- */
- function usort_properties($val1,$val2)
- {
- if(key($val1) > key($val2))
- {
- return 1;
- }
- elseif(key($val1) < key($val2))
- {
- return -1;
- }
- else
- {
- return 0;
- }
- }
-
- /**
- * Returns the formatted CSS Code and saves it into $this->output_css
- * @param array $css
- * @return string
- * @access public
- * @version 1.1
- */
- function print_code($css = NULL)
- {
- $output = '';
- if($css === NULL)
- {
- $css = $this->css;
- }
-
- if(!empty ($this->charset))
- {
- $output .= $this->template[0].'@charset '.$this->template[5].'"'.$this->charset.'"'.$this->template[6].$this->template[12];
- }
-
- if(!empty ($this->import))
- {
- for ($i = 0, $size = count($this->import); $i < $size; $i ++) {
- $output .= $this->template[0].'@import '.$this->template[5].$this->import[$i].$this->template[6].$this->template[12];
- }
- }
-
- ksort($css);
-
- foreach($css as $medium => $val)
- {
- if ($medium !== 'standard')
- {
- $output .= $this->template[0].htmlspecialchars($medium).$this->template[1];
- }
-
- if ($this->get_cfg('sort_selectors')) ksort($val);
-
- foreach($val as $selector => $vali)
- {
- if ($this->get_cfg('sort_properties')) usort($vali,array('csspp','usort_properties'));
-
- if ($medium !== 'standard') $output .= $this->template[10];
-
- $output .= ($selector{0} !== '@') ? $this->template[2].htmlspecialchars($selector) : $this->template[0].htmlspecialchars($selector);
- $output .= ($medium !== 'standard') ? $this->template[11] : $this->template[3];
-
- foreach($vali as $num_prop => $valj)
- {
- foreach($valj as $property => $value)
- {
- if ($medium !== 'standard') $output .= $this->template[10];
-
- $output .= $this->template[4];
- $output .= ($this->get_cfg('uppercase_properties')) ? htmlspecialchars(strtoupper($property)) : htmlspecialchars($property);
- $output .= ':'.$this->template[5].htmlspecialchars($value);
- $output .= ($this->get_cfg('remove_last_;') && end($vali) === $valj) ? str_replace(';','',$this->template[6]) : $this->template[6];
- }
- }
-
- if ($medium !== 'standard') $output .= $this->template[10];
- $output .= $this->template[7];
- if (( end($val) !== $vali && $medium !== 'standard') || $medium === 'standard') $output .= $this->template[8];
- }
- if ($medium != 'standard') $output .= $this->template[9];
- }
-
- $output = trim($output);
- $this->output_css = $output;
- return $output;
- }
-
- /**
- * Checks if the next word in a string from pos is a CSS property
- * @param string $istring
- * @param integer $pos
- * @return bool
- * @access public
- * @version 1.1
- */
- function property_is_next($istring, $pos)
- {
- global $all_properties;
- $istring = strtolower(ltrim(substr($istring,$pos,strlen($istring)-$pos)));
- for($i = 0; $i < count($all_properties); $i++)
- {
- if(substr($istring,0,strlen($all_properties[$i])) == $all_properties[$i])
- {
- return true;
- }
- }
- return false;
- }
-
- }
-
- ?>