Xataface 2.0
Xataface Application Framework
Dataface/CSSTool.php
Go to the documentation of this file.
00001 <?php
00002 class Dataface_CSSTool {
00003         private static $instance=null;
00004         private $includePath = array();
00005         private $stylesheets = array();
00006         private $included = array();
00007         private $ignoreFiles = array();
00008         
00009         
00010         public function ignore($path){
00011                 $this->ignoreFiles[$path] = 1;
00012                 if ( isset($this->stylesheets[$path]) ){
00013                         unset($this->stylesheets[$path]);
00014                 }
00015         }
00016         
00017         
00018         public function isIgnored($path){
00019                 return @$this->ignoreFiles[$path];
00020         }
00021         
00022         
00023         public static function getInstance(){
00024                 if ( !isset(self::$instance) ){
00025                         self::$instance = new Dataface_CSSTool();
00026                 }
00027                 return self::$instance;
00028         }
00029         
00030         public function getStylesheets(){
00031                 return $this->stylesheets;
00032         }
00033         
00034         public function addPath($path, $url){
00035                 $this->includePath[$path] = $url;
00036         }
00037         
00038         public function removePath($path){
00039                 unset($this->includePath[$path]);
00040         }
00041         
00042         public function getPaths(){
00043                 return $this->includePath;
00044         }
00045         
00046         public function import($path){
00047                 if ( @$this->ignoreFiles[$path] ) return;
00048                 
00049                 $this->stylesheets[$path] = 1;
00050         }
00051         
00052         
00053         public function getURL(){
00054                 $this->compile();
00055                 return DATAFACE_SITE_HREF.'?-action=css&--id='.$this->generateCacheKeyForScripts(array_keys($this->stylesheets));
00056         }
00057         
00058         public function getIncluded(){
00059                 return $this->included;
00060         }
00061         
00062         public function getContents(){
00063                 $this->compile();
00064                 return file_get_contents($this->getCSSCachePath(array_keys($this->stylesheets)));
00065         }
00066         
00067         private function generateCacheKeyForScripts($stylesheets){
00068                 //$this->sortScripts();
00069                 $base = basename($stylesheets[0]);
00070                 //$base = basename($scripts[0]);
00071                 $base = substr($base, 0, 10);
00072                 return $base.'-'.md5(implode(PATH_SEPARATOR, $stylesheets));
00073         }
00074         
00075         private function writeCSS($stylesheets, $contents){
00076                 $path = $this->getCSSCachePath($stylesheets);
00077                 return file_put_contents($path, $contents, LOCK_EX);
00078         }
00079         
00080         private function getCSSCachePath($stylesheets){
00081                 return DATAFACE_SITE_PATH.'/templates_c/'.$this->generateCacheKeyForScripts($stylesheets).'.css';
00082         }
00083         
00084         private function getManifestPath($stylesheets){
00085                 return DATAFACE_SITE_PATH.'/templates_c/'.$this->generateCacheKeyForScripts($stylesheets).'.manifest.css';
00086         }
00087         
00088         private function writeManifest($stylesheets, $included){
00089                 $path = $this->getManifestPath($stylesheets);
00090                 return file_put_contents($path, json_encode($included), LOCK_EX);
00091         }
00092         
00093         private function isCacheDirty($stylesheets){
00094                 $jspath = $this->getCSSCachePath($stylesheets);
00095                 $mfpath = $this->getManifestPath($stylesheets);
00096                 
00097                 if ( !file_exists($jspath) ) return true;
00098                 if ( !file_exists($mfpath) ) return true;
00099                 $mtime = filemtime($jspath);
00100                 
00101                 $deps = json_decode(file_get_contents($mfpath), true);
00102                 foreach ($deps as $script=>$file){
00103                         if ( filemtime($file) > $mtime ){
00104                                 return true;
00105                         }
00106                 }
00107                 return false;
00108                 
00109                 
00110         }
00111         
00112         
00113         
00114         public function compile($stylesheets=null, $clean=false){
00115                 if (!isset($stylesheets) ){
00116                         $stylesheets = array_keys($this->stylesheets);
00117                 }
00118                 
00119                 if ( $clean or $this->isCacheDirty($stylesheets) ){
00120                         $this->included = array();
00121                         $contents = $this->_compile($stylesheets);
00122                         
00123                         $contents = CssMin::minify($contents, array
00124                         (
00125                         "remove-empty-blocks"           => true,
00126                         "remove-empty-rulesets"         => true,
00127                         "remove-last-semicolons"        => true,
00128                         "convert-css3-properties"       => true,
00129                         "compress-color-values"         => true,
00130                         "compress-unit-values"          => true,
00131                         "emulate-css3-variables"        => true
00132                         )
00133                         );
00134                         
00135                         file_put_contents($this->getCSSCachePath($stylesheets), $contents, LOCK_EX);
00136                         file_put_contents($this->getManifestPath($stylesheets), json_encode($this->included), LOCK_EX);
00137                 }
00138                 
00139                 
00140         }
00141         
00156         private function _compile($stylesheets){
00157                 //$included = array();
00158                 $out=array();
00159                 if ( !is_array($stylesheets) ) $stylesheets = array($stylesheets);
00160                 $included =& $this->included;
00161                 
00162                 // Go through each script
00163                 foreach ($stylesheets as $script){
00164                         $contents = null;
00165                         if ( isset($included[$script]) ) continue;
00166                         
00167                         foreach ($this->includePath as $path=>$url){
00168                                 $filepath = $path.DIRECTORY_SEPARATOR.$script;
00169                                 $dirname = dirname($script);
00170                                 if ( $dirname ) $url .= '/'.$dirname;
00171                                 //echo "\nChecking $filepath\n";
00172                                 if ( is_readable($filepath) ){
00173                                         $contents = file_get_contents($filepath);
00174                                         $contents = preg_replace('/url\(\s*[\'"]?\/?(.+?)[\'"]?\s*\)/i', 'url('.$url.'/$1)', $contents);
00175                                         $included[$script] = $filepath;
00176                                         break;
00177                                 }
00178                         }
00179                         
00180                         if ( !isset($contents) ) throw new Exception(sprintf("Could not find script %s", $script));
00181                         
00182                         
00183                         $out[] = $contents;
00184                         
00185                         
00186                 }
00187                 return implode("\r\n", $out);
00188         }
00189         
00190         
00191         
00192         
00193         public function clearCache(){
00194                 $files = glob(DATAFACE_SITE_PATH.'/templates_c/*.css');
00195                 foreach($files as $f){
00196                         unlink($f);
00197                 }
00198                 $files = glob(DATAFACE_SITE_PATH.'/templates_c/*.manifest.css');
00199                 foreach($files as $f){
00200                         unlink($f);
00201                 }
00202         }
00203         
00204         
00205 }
00206 
00207 
00226 class CssMin
00227         {
00233         const T_DOCUMENT = 1;
00239         const T_COMMENT = 2;
00245         const T_AT_RULE = 3;
00251         const T_AT_MEDIA_START = 4;
00257         const T_AT_MEDIA = 5;
00263         const T_AT_MEDIA_END = 6;
00269         const T_AT_FONT_FACE_START = 7;
00275         const T_AT_FONT_FACE = 8;
00281         const T_FONT_FACE_DECLARATION = 9;
00287         const T_AT_FONT_FACE_END = 10;
00293         const T_AT_PAGE_START = 11;
00299         const T_AT_PAGE = 12;
00305         const T_PAGE_DECLARATION = 13;
00311         const T_AT_PAGE_END = 14;
00317         const T_RULESET_START = 15;
00323         const T_SELECTORS = 16;
00329         const T_DECLARATIONS_START = 17;
00335         const T_DECLARATIONS = 18;
00341         const T_DECLARATION = 19;
00347         const T_DECLARATIONS_END = 20;
00353         const T_RULESET_END = 21;
00359         const T_AT_VARIABLES_START = 100;
00365         const T_AT_VARIABLES = 101;
00371         const T_VARIABLE_DECLARATION = 102;
00377         const T_AT_VARIABLES_END = 103;
00383         const T_STRING = 254;
00389         const T_STRING_URL = 255;
00395         private static $transformations = array
00396                 (
00397                 "border-radius"                                 => array("-moz-border-radius", "-webkit-border-radius", "-khtml-border-radius"),
00398                 "border-top-left-radius"                => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", "-khtml-top-left-radius"),
00399                 "border-top-right-radius"               => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", "-khtml-top-right-radius"),
00400                 "border-bottom-right-radius"    => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", "-khtml-border-bottom-right-radius"),
00401                 "border-bottom-left-radius"             => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", "-khtml-border-bottom-left-radius"),
00402                 "box-shadow"                                    => array("-moz-box-shadow", "-webkit-box-shadow", "-khtml-box-shadow"),
00403                 "opacity"                                               => array(array("CssMin", "_tOpacity")),
00404                 "text-shadow"                                   => array("-moz-text-shadow", "-webkit-text-shadow", "-khtml-text-shadow"),
00405                 "white-space"                                   => array(array("CssMin", "_tWhiteSpacePreWrap"))
00406                 );
00414         public static function minify($css, $config = array())
00415                 {
00416                 $tokens = self::parse($css);
00417                 $config = array_merge(array
00418                         (
00419                         "remove-empty-blocks"                   => true,
00420                         "remove-empty-rulesets"                 => true,
00421                         "remove-last-semicolons"                => true,
00422                         "convert-css3-properties"               => false,
00423                         "convert-color-values"                  => false,
00424                         "compress-color-values"                 => false,
00425                         "compress-unit-values"                  => false,
00426                         "emulate-css3-variables"                => true,
00427                         ), $config);
00428                 // Minification options
00429                 $sRemoveEmptyBlocks                     = $config["remove-empty-blocks"]; 
00430                 $sRemoveEmptyRulesets           = $config["remove-empty-rulesets"];
00431                 $sRemoveLastSemicolon           = $config["remove-last-semicolons"];
00432                 $sConvertCss3Properties         = $config["convert-css3-properties"];
00433                 $sCompressUnitValues            = $config["compress-unit-values"];
00434                 $sConvertColorValues            = $config["convert-color-values"];
00435                 $sCompressColorValues           = $config["compress-color-values"];
00436                 $sEmulateCcss3Variables         = $config["emulate-css3-variables"];
00437                 $sRemoveTokens                          = array(self::T_COMMENT);
00438                 // Remove tokens
00439                 if (!$sEmulateCcss3Variables)
00440                         {
00441                         $sRemoveTokens = array_merge($sRemoveTokens, array(self::T_AT_VARIABLES_START, self::T_VARIABLE_DECLARATION, self::T_AT_VARIABLES_END));
00442                         }
00443                 for($i = 0, $l = count($tokens); $i < $l; $i++)
00444                         {
00445                         if (in_array($tokens[$i][0], $sRemoveTokens))
00446                                 {
00447                                 unset($tokens[$i]);
00448                                 }
00449                         }
00450                 $tokens = array_values($tokens);
00451                 // Remove empty rulesets
00452                 if ($sRemoveEmptyRulesets)
00453                         {
00454                         for($i = 0, $l = count($tokens); $i < $l; $i++)
00455                                 {
00456                                 // Remove empty rulesets
00457                                 if ($tokens[$i][0] == self::T_RULESET_START && $tokens[$i+4][0] == self::T_RULESET_END)
00458                                         {
00459                                         unset($tokens[$i]);     // T_RULESET_START
00460                                         unset($tokens[++$i]);   // T_SELECTORS
00461                                         unset($tokens[++$i]);   // T_DECLARATIONS_START
00462                                         unset($tokens[++$i]);   // T_DECLARATIONS_END
00463                                         unset($tokens[++$i]);   // T_RULESET_END
00464                                         }
00465                                 }
00466                         $tokens = array_values($tokens);
00467                         }
00468                 // Remove empty @media, @font-face or @page blocks
00469                 if ($sRemoveEmptyBlocks)
00470                         {
00471                         for($i = 0, $l = count($tokens); $i < $l; $i++)
00472                                 {
00473                                 // Remove empty @media, @font-face or @page blocks
00474                                 if (($tokens[$i][0] == self::T_AT_MEDIA_START && $tokens[$i+1][0] == self::T_AT_MEDIA_END)
00475                                         || ($tokens[$i][0] == self::T_AT_FONT_FACE_START && $tokens[$i+1][0] == self::T_AT_FONT_FACE_END)
00476                                         || ($tokens[$i][0] == self::T_AT_PAGE_START && $tokens[$i+1][0] == self::T_AT_PAGE_END))
00477                                         {
00478                                         unset($tokens[$i]);             // T_AT_MEDIA_START, T_AT_FONT_FACE_START, T_AT_PAGE_START
00479                                         unset($tokens[++$i]);   // T_AT_MEDIA_END, T_AT_FONT_FACE_END, T_AT_PAGE_END
00480                                         }
00481                                 }
00482                         $tokens = array_values($tokens);
00483                         }
00484                 // CSS Level 3 variables: parse variables
00485                 if ($sEmulateCcss3Variables)
00486                         {
00487                         // Parse variables
00488                         $variables = array();
00489                         for($i = 0, $l = count($tokens); $i < $l; $i++)
00490                                 {
00491                                 if ($tokens[$i][0] == self::T_VARIABLE_DECLARATION)
00492                                         {
00493                                         for($i2 = 0, $l2 = count($tokens[$i][3]); $i2 < $l2; $i2++)
00494                                                 {
00495                                                 if (!isset($variables[$tokens[$i][3][$i2]]))
00496                                                         {
00497                                                         $variables[$tokens[$i][3][$i2]] = array();
00498                                                         }
00499                                                 $variables[$tokens[$i][3][$i2]][$tokens[$i][1]] = $tokens[$i][2];
00500                                                 }
00501                                         }
00502                                 }
00503                         }
00504                 // Conversion and compression 
00505                 for($i = 0, $l = count($tokens); $i < $l; $i++)
00506                         {
00507                         if ($tokens[$i][0] == self::T_DECLARATION)
00508                                 {
00509                                 // CSS Level 3 variables
00510                                 if ($sEmulateCcss3Variables)
00511                                         {
00512                                         if (substr($tokens[$i][2], 0, 4) == "var(" && substr($tokens[$i][2], -1, 1) == ")")
00513                                                 {
00514                                                 $tokens[$i][3][] = "all";
00515                                                 $variable = trim(substr($tokens[$i][2], 4, -1));
00516                                                 for($i2 = 0, $l2 = count($tokens[$i][3]); $i2 < $l2; $i2++)
00517                                                         {
00518                                                         if (isset($variables[$tokens[$i][3][$i2]][$variable]))
00519                                                                 {
00520                                                                 $tokens[$i][2] = $variables[$tokens[$i][3][$i2]][$variable];
00521                                                                 break;
00522                                                                 }
00523                                                         }
00524                                                 }
00525                                         }
00526                                 // Compress unit values
00527                                 if ($sCompressUnitValues)
00528                                         {
00529                                         // Compress "0.5px" to ".5px"
00530                                         $tokens[$i][2] = preg_replace("/(^| |-)0\.([0-9]+)(%|em|ex|px|in|cm|mm|pt|pc)/iS", "\${1}.\${2}\${3}", $tokens[$i][2]);
00531                                         // Compress "0px" to "0"
00532                                         $tokens[$i][2] = preg_replace("/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS", "\${1}0", $tokens[$i][2]);
00533                                         // Compress "0 0 0 0" to "0"
00534                                         if ($tokens[$i][2] == "0 0 0 0") {$tokens[$i][2] = "0";}
00535                                         }
00536                                 // Convert RGB color values to hex ("rgb(200,60%,5)" => "#c89905")
00537                                 if ($sConvertColorValues && preg_match("/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS", $tokens[$i][2], $m))
00538                                         {
00539                                         for ($i2 = 1, $l2 = count($m); $i2 < $l2; $i2++)
00540                                                 {
00541                                                 if (strpos("%", $m[$i2]) !== false)
00542                                                         {
00543                                                         $m[$i2] = substr($m[$i2], 0, -1);
00544                                                         $m[$i2] = (int) (256 * ($m[$i2] / 100));
00545                                                         }
00546                                                 $m[$i2] = str_pad(dechex($m[$i2]),  2, "0", STR_PAD_LEFT);
00547                                                 }
00548                                         $tokens[$i][2] = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $tokens[$i][2]);
00549                                         }
00550                                 // Compress color values ("#aabbcc" to "#abc") 
00551                                 if ($sCompressColorValues && preg_match("/\#([0-9a-f]{6})/iS", $tokens[$i][2], $m))
00552                                         {
00553                                         $m[1] = strtolower($m[1]);
00554                                         if (substr($m[1], 0, 1) == substr($m[1], 1, 1) && substr($m[1], 2, 1) == substr($m[1], 3, 1) && substr($m[1], 4, 1) == substr($m[1], 5, 1))
00555                                                 {
00556                                                 $tokens[$i][2] = str_replace($m[0], "#" . substr($m[1], 0, 1) . substr($m[1], 2, 1) . substr($m[1], 4, 1), $tokens[$i][2]);
00557                                                 }
00558                                         }
00559                                 }
00560                         }
00561                 // Create minified css
00562                 $r = "";
00563                 for($i = 0, $l = count($tokens); $i < $l; $i++)
00564                         {
00565                         // T_AT_RULE
00566                         if ($tokens[$i][0] == self::T_AT_RULE)
00567                                 {
00568                                 $r .= "@" . $tokens[$i][1] . " " . $tokens[$i][2] . ";";
00569                                 }
00570                         // T_AT_MEDIA_START
00571                         elseif ($tokens[$i][0] == self::T_AT_MEDIA_START)
00572                                 {
00573                                 if (count($tokens[$i][1]) == 1 && $tokens[$i][1][0] == "all")
00574                                         {
00575                                         $r .= "@media{";
00576                                         }
00577                                 else
00578                                         {
00579                                         $r .= "@media " . implode(",", $tokens[$i][1]) . "{";
00580                                         }
00581                                 }
00582                         // T_AT_FONT_FACE_START
00583                         elseif ($tokens[$i][0] == self::T_AT_FONT_FACE_START)
00584                                 {
00585                                 $r .= "@font-face{";
00586                                 }
00587                         // T_FONT_FACE_DECLARATION
00588                         elseif ($tokens[$i][0] == self::T_FONT_FACE_DECLARATION)
00589                                 {
00590                                 $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && $tokens[$i+1][0] == self::T_AT_FONT_FACE_END ? "" : ";");
00591                                 }
00592                         // T_AT_PAGE_START
00593                         elseif ($tokens[$i][0] == self::T_AT_PAGE_START)
00594                                 {
00595                                 $r .= "@page{";
00596                                 }
00597                         // T_PAGE_DECLARATION
00598                         elseif ($tokens[$i][0] == self::T_PAGE_DECLARATION)
00599                                 {
00600                                 $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && $tokens[$i+1][0] == self::T_AT_PAGE_END ? "" : ";");
00601                                 }
00602                         // T_SELECTORS
00603                         elseif ($tokens[$i][0] == self::T_SELECTORS)
00604                                 {
00605                                 $r .= implode(",", $tokens[$i][1]);
00606                                 }
00607                         // Start of declarations
00608                         elseif ($tokens[$i][0] == self::T_DECLARATIONS_START)
00609                                 {
00610                                 $r .=  "{";
00611                                 }
00612                         // T_DECLARATION
00613                         elseif ($tokens[$i][0] == self::T_DECLARATION)
00614                                 {
00615                                 if ($sConvertCss3Properties && isset(self::$transformations[$tokens[$i][1]]))
00616                                         {
00617                                         foreach (self::$transformations[$tokens[$i][1]] as $value)
00618                                                 {
00619                                                 if (!is_array($value))
00620                                                         {
00621                                                         $r .= $value . ":" . $tokens[$i][2] . ";";
00622                                                         }
00623                                                 elseif (is_array($value) && is_callable($value))
00624                                                         {
00625                                                         $r.= call_user_func_array($value, array($tokens[$i][1], $tokens[$i][2]));
00626                                                         
00627                                                         }
00628                                                 }
00629                                         }
00630                                 $r .= $tokens[$i][1] . ":" . $tokens[$i][2] . ($sRemoveLastSemicolon && $tokens[$i+1][0] == self::T_DECLARATIONS_END ? "" : ";");
00631                                 }
00632                         // T_DECLARATIONS_END, T_AT_MEDIA_END, T_AT_FONT_FACE_END, T_AT_PAGE_END
00633                         elseif (in_array($tokens[$i][0], array(self::T_DECLARATIONS_END, self::T_AT_MEDIA_END, self::T_AT_FONT_FACE_END, self::T_AT_PAGE_END)))
00634                                 {
00635                                 $r .= "}";
00636                                 }
00637                         else
00638                                 {
00639                                 // Tokens with no output:
00640                                 // T_COMMENT
00641                                 // T_RULESET_START
00642                                 // T_RULESET_END
00643                                 // T_AT_VARIABLES_START
00644                                 // T_VARIABLE_DECLARATION
00645                                 // T_AT_VARIABLES_END
00646                                 }
00647                         }
00648                 return $r;
00649                 }
00656         public static function parse($css)
00657                 {
00658                 // Settings
00659                 $sDefaultScope          = array("all");                                         // Default scope
00660                 $sDefaultTrim           = " \t\n\r\0\x0B";                                      // Default trim charlist
00661                 $sTokenChars            = "@{}();:\n\"'/*,";                            // Tokens triggering parser processing
00662                 // Basic variables
00663                 $c                                      = null;                                                         // Current char
00664                 $p                                      = null;                                                         // Previous char
00665                 $buffer                         = "";                                                           // Buffer
00666                 $state                          = array(self::T_DOCUMENT);                      // State stack
00667                 $currentState           = self::T_DOCUMENT;                                     // Current state
00668                 $scope                          = $sDefaultScope;                                       // Current scope
00669                 $stringChar                     = null;                                                         // String delimiter char
00670                 $isFilterWs                     = true;                                                         // Filter double whitespaces?
00671                 $selectors                      = array();                                                      // Array with collected selectors
00672                 $r                                      = array();                                                      // Return value
00673                 // Prepare css
00674                 $css                            = str_replace("\r\n", "\n", $css);      // Windows to Unix line endings
00675                 $css                            = str_replace("\r", "\n", $css);        // Mac to Unix line endings
00676                 while (strpos($css, "\n\n") !== false)
00677                         {
00678                         $css                    = str_replace("\n\n", "\n", $css);      // Remove double line endings
00679                         }
00680                 $css                            = str_replace("\t", " ", $css);         // Convert tabs to spaces
00681                 // Parse css 
00682                 for ($i = 0, $l = strlen($css); $i < $l; $i++)
00683                         {
00684                         $c = substr($css, $i, 1);
00685                         // Filter out double spaces
00686                         if ($isFilterWs && $c == " " && $c == $p)
00687                                 {
00688                                 continue;
00689                                 }
00690                         $buffer .= $c;
00691                         if (strpos($sTokenChars, $c) !== false)
00692                                 {
00693                                 // 
00694                                 $currentState   = $state[count($state) - 1];
00695                                 /*
00696                                  * Start of comment
00697                                  */
00698                                 if ($p == "/" && $c == "*" && $currentState != self::T_STRING && $currentState != self::T_COMMENT)
00699                                         {
00700                                         $saveBuffer = substr($buffer, 0, -2); // save the buffer (will get restored with comment ending)
00701                                         $buffer         = $c;
00702                                         $isFilterWs     = false;
00703                                         array_push($state, self::T_COMMENT);
00704                                         }
00705                                 /*
00706                                  * End of comment
00707                                  */
00708                                 elseif ($p == "*" && $c == "/" && $currentState == self::T_COMMENT)
00709                                         {
00710                                         $r[]            = array(self::T_COMMENT, trim($buffer));
00711                                         $buffer         = $saveBuffer;
00712                                         $isFilterWs     = true;
00713                                         array_pop($state);
00714                                         }
00715                                 /*
00716                                  * Start of string
00717                                  */
00718                                 elseif (($c == "\"" || $c == "'") && $currentState != self::T_STRING && $currentState != self::T_COMMENT && $currentState != self::T_STRING_URL)
00719                                         {
00720                                         $stringChar     = $c;
00721                                         $isFilterWs     = false;
00722                                         array_push($state, self::T_STRING);
00723                                         }
00727                                 elseif ($c == "\n" && $p == "\\" && $currentState == self::T_STRING)
00728                                         {
00729                                         $buffer = substr($buffer, 0, -2);
00730                                         }
00731                                 /*
00732                                  * End of string
00733                                  */
00734                                 elseif ($c === $stringChar && $currentState == self::T_STRING)
00735                                         {
00736                                         if ($p == "\\") // Previous char is a escape char
00737                                                 {
00738                                                 $count = 1; 
00739                                                 $i2 = $i -2;
00740                                                 while (substr($css, $i2, 1) == "\\")
00741                                                         {
00742                                                         $count++;
00743                                                         $i2--;
00744                                                         }
00745                                                 // if count of escape chars is uneven => continue with string...
00746                                                 if ($count % 2)
00747                                                         {
00748                                                         continue;
00749                                                         }
00750                                                 }
00751                                         // ...else end the string
00752                                         $isFilterWs     = true;
00753                                         array_pop($state);
00754                                         $stringChar = null;
00755                                         }
00759                                 elseif ($c == "(" && ($currentState != self::T_COMMENT && $currentState != self::T_STRING) && strtolower(substr($css, $i - 3, 3) == "url") 
00760                                         && ($currentState == self::T_DECLARATION || $currentState == self::T_FONT_FACE_DECLARATION || $currentState == self::T_PAGE_DECLARATION || $currentState == self::T_VARIABLE_DECLARATION))
00761                                         {
00762                                         array_push($state, self::T_STRING_URL);
00763                                         }
00767                                 elseif (($c == ")" || $c == "\n") && ($currentState != self::T_COMMENT && $currentState != self::T_STRING) && $currentState == self::T_STRING_URL)
00768                                         {
00769                                         if ($p == "\\")
00770                                                 {
00771                                                 continue;
00772                                                 }
00773                                         array_pop($state);
00774                                         }
00775                                 /*
00776                                  * Start of at-rule @media block
00777                                  */
00778                                 elseif ($c == "@" && $currentState == self::T_DOCUMENT && strtolower(substr($css, $i, 6)) == "@media")
00779                                         {
00780                                         $i                      = $i + 6;
00781                                         $buffer         = "";
00782                                         array_push($state, self::T_AT_MEDIA_START);
00783                                         }
00784                                 /*
00785                                  * At-rule @media block media types
00786                                  */
00787                                 elseif ($c == "{" && $currentState == self::T_AT_MEDIA_START)
00788                                         {
00789                                         $buffer         = strtolower(trim($buffer, $sDefaultTrim . "{"));
00790                                         $scope          = $buffer != "" ? array_filter(array_map("trim", explode(",", $buffer))) : $sDefaultScope;
00791                                         $r[]            = array(self::T_AT_MEDIA_START, $scope);
00792                                         $i                      = $i++;
00793                                         $buffer         = "";
00794                                         array_pop($state);
00795                                         array_push($state, self::T_AT_MEDIA);
00796                                         }
00797                                 /*
00798                                  * End of at-rule @media block
00799                                  */
00800                                 elseif ($currentState == self::T_AT_MEDIA && $c == "}")
00801                                         {
00802                                         $r[]            = array(self::T_AT_MEDIA_END);
00803                                         $scope          = $sDefaultScope;
00804                                         $buffer         = "";
00805                                         array_pop($state);
00806                                         }
00807                                 /*
00808                                  * Start of at-rule @font-face block
00809                                  */
00810                                 elseif ($c == "@" && $currentState == self::T_DOCUMENT && strtolower(substr($css, $i, 10)) == "@font-face")
00811                                         {
00812                                         $r[]            = array(self::T_AT_FONT_FACE_START);
00813                                         $i                      = $i + 10;
00814                                         $buffer         = "";
00815                                         array_push($state, self::T_AT_FONT_FACE);
00816                                         }
00817                                 /*
00818                                  * @font-face declaration: Property
00819                                  */
00820                                 elseif ($c == ":" && $currentState == self::T_AT_FONT_FACE)
00821                                         {
00822                                         $property       = trim($buffer, $sDefaultTrim . ":{");
00823                                         $buffer         = "";
00824                                         array_push($state, self::T_FONT_FACE_DECLARATION);
00825                                         }
00826                                 /*
00827                                  * @font-face declaration: Value
00828                                  */
00829                                 elseif (($c == ";" || $c == "}" || $c == "\n") && $currentState == self::T_FONT_FACE_DECLARATION)
00830                                         {
00831                                         $value          = trim($buffer, $sDefaultTrim . ";}");
00832                                         $r[]            = array(self::T_FONT_FACE_DECLARATION, $property, $value, $scope);
00833                                         $buffer         = "";
00834                                         array_pop($state);
00835                                         if ($c == "}") // @font-face declaration closed with a right curly brace => closes @font-face block
00836                                                 {
00837                                                 array_pop($state);
00838                                                 $r[]    = array(self::T_AT_FONT_FACE_END);
00839                                                 }
00840                                         }
00841                                 /*
00842                                  * End of at-rule @font-face block
00843                                  */
00844                                 elseif ($c == "}" && $currentState == self::T_AT_FONT_FACE)
00845                                         {
00846                                         $r[]            = array(self::T_AT_FONT_FACE_END);
00847                                         $buffer         = "";
00848                                         array_pop($state);
00849                                         }
00850                                 /*
00851                                  * Start of at-rule @page block
00852                                  */
00853                                 elseif ($c == "@" && $currentState == self::T_DOCUMENT && strtolower(substr($css, $i, 5)) == "@page")
00854                                         {
00855                                         $r[]            = array(self::T_AT_PAGE_START);
00856                                         $i                      = $i + 5;
00857                                         $buffer         = "";
00858                                         array_push($state, self::T_AT_PAGE);
00859                                         }
00860                                 /*
00861                                  * @page declaration: Property
00862                                  */
00863                                 elseif ($c == ":" && $currentState == self::T_AT_PAGE)
00864                                         {
00865                                         $property       = trim($buffer, $sDefaultTrim . ":{");
00866                                         $buffer         = "";
00867                                         array_push($state, self::T_PAGE_DECLARATION);
00868                                         }
00869                                 /*
00870                                  * @page declaration: Value
00871                                  */
00872                                 elseif (($c == ";" || $c == "}" || $c == "\n") && $currentState == self::T_PAGE_DECLARATION)
00873                                         {
00874                                         $value          = trim($buffer, $sDefaultTrim . ";}");
00875                                         $r[]            = array(self::T_PAGE_DECLARATION, $property, $value, $scope);
00876                                         $buffer         = "";
00877                                         array_pop($state);
00878                                         if ($c == "}") // @page declaration closed with a right curly brace => closes @font-face block
00879                                                 {
00880                                                 array_pop($state);
00881                                                 $r[]    = array(self::T_AT_PAGE_END);
00882                                                 }
00883                                         }
00884                                 /*
00885                                  * End of at-rule @page block
00886                                  */
00887                                 elseif ($c == "}" && $currentState == self::T_AT_PAGE)
00888                                         {
00889                                         $r[]            = array(self::T_AT_PAGE_END);
00890                                         $buffer         = "";
00891                                         array_pop($state);
00892                                         }
00893                                 /*
00894                                  * Start of at-rule @variables block
00895                                  */
00896                                 elseif ($c == "@" && $currentState == self::T_DOCUMENT &&  strtolower(substr($css, $i, 10)) == "@variables")
00897                                         {
00898                                         $i                      = $i + 10;
00899                                         $buffer         = "";
00900                                         array_push($state, self::T_AT_VARIABLES_START);
00901                                         }
00902                                 /*
00903                                  * @variables media types
00904                                  */
00905                                 elseif ($c == "{" && $currentState == self::T_AT_VARIABLES_START)
00906                                         {
00907                                         $buffer         = strtolower(trim($buffer, $sDefaultTrim . "{"));
00908                                         $r[]            = array(self::T_AT_VARIABLES_START, $scope);
00909                                         $scope          = $buffer != "" ? array_filter(array_map("trim", explode(",", $buffer))) : $sDefaultScope;
00910                                         $i                      = $i++;
00911                                         $buffer         = "";
00912                                         array_pop($state);
00913                                         array_push($state, self::T_AT_VARIABLES);
00914                                         }
00915                                 /*
00916                                  * @variables declaration: Property
00917                                  */
00918                                 elseif ($c == ":" && $currentState == self::T_AT_VARIABLES)
00919                                         {
00920                                         $property       = trim($buffer, $sDefaultTrim . ":");
00921                                         $buffer         = "";
00922                                         array_push($state, self::T_VARIABLE_DECLARATION);
00923                                         }
00924                                 /*
00925                                  * @variables declaration: Value
00926                                  */
00927                                 elseif (($c == ";" || $c == "}" || $c == "\n") && $currentState == self::T_VARIABLE_DECLARATION)
00928                                         {
00929                                         $value          = trim($buffer, $sDefaultTrim . ";}");
00930                                         $r[]            = array(self::T_VARIABLE_DECLARATION, $property, $value, $scope);
00931                                         $buffer         = "";
00932                                         array_pop($state);
00933                                         if ($c == "}") // @variable declaration closed with a right curly brace => closes @variables block
00934                                                 {
00935                                                 array_pop($state);
00936                                                 $r[]    = array(self::T_AT_VARIABLES_END);
00937                                                 $scope  = $sDefaultScope;
00938                                                 }
00939                                         }
00940                                 /*
00941                                  * End of at-rule @variables block
00942                                  */
00943                                 elseif ($c == "}" && $currentState == self::T_AT_VARIABLES)
00944                                         {
00945                                         $r[]            = array(self::T_AT_VARIABLES_END);
00946                                         $scope          = $sDefaultScope;
00947                                         $buffer         = "";
00948                                         array_pop($state);
00949                                         }
00950                                 /*
00951                                  * Start of document level at-rule
00952                                  */
00953                                 elseif ($c == "@" && $currentState == self::T_DOCUMENT)
00954                                         {
00955                                         $buffer         = "";
00956                                         array_push($state, self::T_AT_RULE);
00957                                         }
00958                                 /*
00959                                  * End of document level at-rule
00960                                  */
00961                                 elseif ($c == ";" && $currentState == self::T_AT_RULE)
00962                                         {
00963                                         $pos            = strpos($buffer, " ");
00964                                         $rule           = substr($buffer, 0, $pos);
00965                                         $value          = trim(substr($buffer, $pos), $sDefaultTrim . ";");
00966                                         $r[]            = array(self::T_AT_RULE, $rule, $value);
00967                                         $buffer         = "";
00968                                         array_pop($state);
00969                                         }
00973                                 elseif ($c == "," && ($currentState == self::T_AT_MEDIA || $currentState ==  self::T_DOCUMENT))
00974                                         {
00975                                         $selectors[]= trim($buffer, $sDefaultTrim . ",");
00976                                         $buffer         = "";
00977                                         }
00978                                 /*
00979                                  * Start of ruleset
00980                                  */
00981                                 elseif ($c == "{" && ($currentState == self::T_AT_MEDIA || $currentState == self::T_DOCUMENT))
00982                                         {
00983                                         $selectors[]= trim($buffer, $sDefaultTrim . "{");
00984                                         $selectors      = array_filter(array_map("trim", $selectors));
00985                                         $r[]            = array(self::T_RULESET_START);
00986                                         $r[]            = array(self::T_SELECTORS, $selectors);
00987                                         $r[]            = array(self::T_DECLARATIONS_START);
00988                                         $buffer         = "";
00989                                         $selectors      = array();
00990                                         array_push($state, self::T_DECLARATIONS);
00991                                         }
00992                                 /*
00993                                  * Declaration: Property
00994                                  */
00995                                 elseif ($c == ":" && $currentState == self::T_DECLARATIONS)
00996                                         {
00997                                         $property       = trim($buffer, $sDefaultTrim . ":;");
00998                                         $buffer         = "";
00999                                         array_push($state, self::T_DECLARATION);
01000                                         }
01001                                 /*
01002                                  * Declaration: Value
01003                                  */
01004                                 elseif (($c == ";" || $c == "}" || $c == "\n") && $currentState == self::T_DECLARATION)
01005                                         {
01006                                         $value          = trim($buffer, $sDefaultTrim . ";}");
01007                                         $r[]            = array(self::T_DECLARATION, $property, $value, $scope);
01008                                         $buffer         = "";
01009                                         array_pop($state);
01010                                         if ($c == "}") // declaration closed with a right curly brace => close ruleset
01011                                                 {
01012                                                 array_pop($state);
01013                                                 $r[]    = array(self::T_DECLARATIONS_END);
01014                                                 $r[]    = array(self::T_RULESET_END);
01015                                                 }
01016                                         }
01017                                 /*
01018                                  * End of ruleset
01019                                  */
01020                                 elseif ($c == "}" && $currentState == self::T_DECLARATIONS)
01021                                         {
01022                                         $r[]            = array(self::T_DECLARATIONS_END);
01023                                         $r[]            = array(self::T_RULESET_END);
01024                                         $buffer         = "";
01025                                         array_pop($state);
01026                                         }
01027                                 
01028                                 }
01029                         
01030                         $p = $c;
01031                         }
01032                 return $r;
01033                 }
01041         private static function _tOpacity($property, $value)
01042                 {
01043                 $ieValue = (int) ((float) $value * 100);
01044                 $r  = "-moz-opacity:" . $value . ";";                                           // Firefox < 3.5
01045                 $r .= "-ms-filter: \"alpha(opacity=" . $ieValue . ")\";";       // Internet Explorer 8
01046                 $r .= "filter: alpha(opacity=" . $ieValue . ");zoom: 1;";       // Internet Explorer 4 - 7
01047                 return $r;
01048                 }
01056         private static function _tWhiteSpacePreWrap($property, $value)
01057                 {
01058                 if (strtolower($value) == "pre-wrap")
01059                         {
01060                         $r  = "white-space:-moz-pre-wrap;";             // Mozilla
01061                         $r .= "white-space:-webkit-pre-wrap;";  // Webkit
01062                         $r .= "white-space:-khtml-pre-wrap;";   // khtml
01063                         $r .= "white-space:-pre-wrap;";                 // Opera 4 - 6
01064                         $r .= "white-space:-o-pre-wrap;";               // Opera 7+
01065                         $r .= "word-wrap:break-word;";                  // Internet Explorer 5.5+
01066                         return $r;
01067                         }
01068                 else
01069                         {
01070                         return "";
01071                         }
01072                 }
01073         }
01074 ?>
All Data Structures Namespaces Files Functions Variables Enumerations