From 89460cee05211f8b8b408cc9b8e66bb2b1fb3826 Mon Sep 17 00:00:00 2001 From: Carsten Henkelmann Date: Tue, 15 Sep 2015 13:38:09 +0200 Subject: [PATCH 1/8] All classes moved to their own files. --- .gitignore | 0 PHPWee.php | 24 + phpwee.php | 35 - src/CssMin/CssAtBlockEndToken.php | 25 + src/CssMin/CssAtBlockStartToken.php | 17 + src/CssMin/CssAtCharsetParserPlugin.php | 61 + src/CssMin/CssAtCharsetToken.php | 43 + src/CssMin/CssAtFontFaceDeclarationToken.php | 17 + src/CssMin/CssAtFontFaceEndToken.php | 17 + src/CssMin/CssAtFontFaceParserPlugin.php | 97 + src/CssMin/CssAtFontFaceStartToken.php | 25 + src/CssMin/CssAtImportParserPlugin.php | 95 + src/CssMin/CssAtImportToken.php | 51 + src/CssMin/CssAtKeyframesEndToken.php | 17 + src/CssMin/CssAtKeyframesParserPlugin.php | 137 + .../CssAtKeyframesRulesetDeclarationToken.php | 17 + src/CssMin/CssAtKeyframesRulesetEndToken.php | 17 + .../CssAtKeyframesRulesetStartToken.php | 43 + src/CssMin/CssAtKeyframesStartToken.php | 52 + src/CssMin/CssAtMediaEndToken.php | 17 + src/CssMin/CssAtMediaParserPlugin.php | 69 + src/CssMin/CssAtMediaStartToken.php | 36 + src/CssMin/CssAtPageDeclarationToken.php | 17 + src/CssMin/CssAtPageEndToken.php | 17 + src/CssMin/CssAtPageParserPlugin.php | 98 + src/CssMin/CssAtPageStartToken.php | 43 + src/CssMin/CssAtVariablesDeclarationToken.php | 25 + src/CssMin/CssAtVariablesEndToken.php | 25 + src/CssMin/CssAtVariablesParserPlugin.php | 93 + src/CssMin/CssAtVariablesStartToken.php | 43 + src/CssMin/CssCommentParserPlugin.php | 69 + src/CssMin/CssCommentToken.php | 43 + .../CssCompressColorValuesMinifierPlugin.php | 65 + ...CompressExpressionValuesMinifierPlugin.php | 50 + .../CssCompressUnitValuesMinifierPlugin.php | 80 + .../CssConvertFontWeightMinifierPlugin.php | 105 + .../CssConvertHslColorsMinifierPlugin.php | 122 + ...ConvertLevel3AtKeyframesMinifierFilter.php | 60 + ...sConvertLevel3PropertiesMinifierFilter.php | 333 ++ .../CssConvertNamedColorsMinifierPlugin.php | 235 + .../CssConvertRgbColorsMinifierPlugin.php | 68 + src/CssMin/CssDeclarationToken.php | 66 + src/CssMin/CssError.php | 65 + src/CssMin/CssExpressionParserPlugin.php | 82 + src/CssMin/CssFormatter.php | 57 + src/CssMin/CssImportImportsMinifierFilter.php | 167 + src/CssMin/CssMin.php | 5151 +---------------- src/CssMin/CssMinifier.php | 192 + src/CssMin/CssMinifierFilter.php | 51 + src/CssMin/CssMinifierPlugin.php | 58 + src/CssMin/CssNullToken.php | 25 + src/CssMin/CssOtbsFormatter.php | 81 + src/CssMin/CssParser.php | 418 ++ src/CssMin/CssParserPlugin.php | 75 + .../CssRemoveCommentsMinifierFilter.php | 33 + .../CssRemoveEmptyAtBlocksMinifierFilter.php | 42 + .../CssRemoveEmptyRulesetsMinifierFilter.php | 40 + ...eLastDelarationSemiColonMinifierFilter.php | 38 + src/CssMin/CssRulesetDeclarationToken.php | 37 + src/CssMin/CssRulesetEndToken.php | 25 + src/CssMin/CssRulesetParserPlugin.php | 134 + src/CssMin/CssRulesetStartToken.php | 42 + ...CssSortRulesetPropertiesMinifierFilter.php | 97 + src/CssMin/CssStringParserPlugin.php | 106 + src/CssMin/CssToken.php | 24 + src/CssMin/CssUrlParserPlugin.php | 85 + src/CssMin/CssVariablesMinifierFilter.php | 89 + src/CssMin/CssVariablesMinifierPlugin.php | 112 + src/CssMin/CssWhitesmithsFormatter.php | 87 + src/HtmlMin/HtmlMin.php | 238 +- src/JsMin/JsMin.php | 80 +- src/JsMin/UnterminatedCommentException.php | 10 + src/JsMin/UnterminatedRegExpException.php | 10 + src/JsMin/UnterminatedStringException.php | 10 + 74 files changed, 5105 insertions(+), 5225 deletions(-) create mode 100644 .gitignore create mode 100644 PHPWee.php delete mode 100644 phpwee.php create mode 100644 src/CssMin/CssAtBlockEndToken.php create mode 100644 src/CssMin/CssAtBlockStartToken.php create mode 100644 src/CssMin/CssAtCharsetParserPlugin.php create mode 100644 src/CssMin/CssAtCharsetToken.php create mode 100644 src/CssMin/CssAtFontFaceDeclarationToken.php create mode 100644 src/CssMin/CssAtFontFaceEndToken.php create mode 100644 src/CssMin/CssAtFontFaceParserPlugin.php create mode 100644 src/CssMin/CssAtFontFaceStartToken.php create mode 100644 src/CssMin/CssAtImportParserPlugin.php create mode 100644 src/CssMin/CssAtImportToken.php create mode 100644 src/CssMin/CssAtKeyframesEndToken.php create mode 100644 src/CssMin/CssAtKeyframesParserPlugin.php create mode 100644 src/CssMin/CssAtKeyframesRulesetDeclarationToken.php create mode 100644 src/CssMin/CssAtKeyframesRulesetEndToken.php create mode 100644 src/CssMin/CssAtKeyframesRulesetStartToken.php create mode 100644 src/CssMin/CssAtKeyframesStartToken.php create mode 100644 src/CssMin/CssAtMediaEndToken.php create mode 100644 src/CssMin/CssAtMediaParserPlugin.php create mode 100644 src/CssMin/CssAtMediaStartToken.php create mode 100644 src/CssMin/CssAtPageDeclarationToken.php create mode 100644 src/CssMin/CssAtPageEndToken.php create mode 100644 src/CssMin/CssAtPageParserPlugin.php create mode 100644 src/CssMin/CssAtPageStartToken.php create mode 100644 src/CssMin/CssAtVariablesDeclarationToken.php create mode 100644 src/CssMin/CssAtVariablesEndToken.php create mode 100644 src/CssMin/CssAtVariablesParserPlugin.php create mode 100644 src/CssMin/CssAtVariablesStartToken.php create mode 100644 src/CssMin/CssCommentParserPlugin.php create mode 100644 src/CssMin/CssCommentToken.php create mode 100644 src/CssMin/CssCompressColorValuesMinifierPlugin.php create mode 100644 src/CssMin/CssCompressExpressionValuesMinifierPlugin.php create mode 100644 src/CssMin/CssCompressUnitValuesMinifierPlugin.php create mode 100644 src/CssMin/CssConvertFontWeightMinifierPlugin.php create mode 100644 src/CssMin/CssConvertHslColorsMinifierPlugin.php create mode 100644 src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php create mode 100644 src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php create mode 100644 src/CssMin/CssConvertNamedColorsMinifierPlugin.php create mode 100644 src/CssMin/CssConvertRgbColorsMinifierPlugin.php create mode 100644 src/CssMin/CssDeclarationToken.php create mode 100644 src/CssMin/CssError.php create mode 100644 src/CssMin/CssExpressionParserPlugin.php create mode 100644 src/CssMin/CssFormatter.php create mode 100644 src/CssMin/CssImportImportsMinifierFilter.php create mode 100644 src/CssMin/CssMinifier.php create mode 100644 src/CssMin/CssMinifierFilter.php create mode 100644 src/CssMin/CssMinifierPlugin.php create mode 100644 src/CssMin/CssNullToken.php create mode 100644 src/CssMin/CssOtbsFormatter.php create mode 100644 src/CssMin/CssParser.php create mode 100644 src/CssMin/CssParserPlugin.php create mode 100644 src/CssMin/CssRemoveCommentsMinifierFilter.php create mode 100644 src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php create mode 100644 src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php create mode 100644 src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php create mode 100644 src/CssMin/CssRulesetDeclarationToken.php create mode 100644 src/CssMin/CssRulesetEndToken.php create mode 100644 src/CssMin/CssRulesetParserPlugin.php create mode 100644 src/CssMin/CssRulesetStartToken.php create mode 100644 src/CssMin/CssSortRulesetPropertiesMinifierFilter.php create mode 100644 src/CssMin/CssStringParserPlugin.php create mode 100644 src/CssMin/CssToken.php create mode 100644 src/CssMin/CssUrlParserPlugin.php create mode 100644 src/CssMin/CssVariablesMinifierFilter.php create mode 100644 src/CssMin/CssVariablesMinifierPlugin.php create mode 100644 src/CssMin/CssWhitesmithsFormatter.php create mode 100644 src/JsMin/UnterminatedCommentException.php create mode 100644 src/JsMin/UnterminatedRegExpException.php create mode 100644 src/JsMin/UnterminatedStringException.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e69de29 diff --git a/PHPWee.php b/PHPWee.php new file mode 100644 index 0000000..cb2aa39 --- /dev/null +++ b/PHPWee.php @@ -0,0 +1,24 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssAtBlockEndToken extends CssToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} diff --git a/src/CssMin/CssAtBlockStartToken.php b/src/CssMin/CssAtBlockStartToken.php new file mode 100644 index 0000000..3cd22a3 --- /dev/null +++ b/src/CssMin/CssAtBlockStartToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssAtBlockStartToken extends CssToken +{ + +} diff --git a/src/CssMin/CssAtCharsetParserPlugin.php b/src/CssMin/CssAtCharsetParserPlugin.php new file mode 100644 index 0000000..f5cba3d --- /dev/null +++ b/src/CssMin/CssAtCharsetParserPlugin.php @@ -0,0 +1,61 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", "\n"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_CHARSET"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset") { + $this->parser->pushState("T_AT_CHARSET"); + $this->parser->clearBuffer(); + return $index + 8; + } elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") { + $charset = $this->parser->getAndClearBuffer(";"); + $this->parser->popState(); + $this->parser->appendToken(new CssAtCharsetToken($charset)); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtCharsetToken.php b/src/CssMin/CssAtCharsetToken.php new file mode 100644 index 0000000..46b0be8 --- /dev/null +++ b/src/CssMin/CssAtCharsetToken.php @@ -0,0 +1,43 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtCharsetToken extends CssToken +{ + /** + * Charset of the @charset at-rule. + * + * @var string + */ + public $Charset = ""; + + /** + * Set the properties of @charset at-rule token. + * + * @param string $charset Charset of the @charset at-rule token + * @return void + */ + public function __construct($charset) + { + $this->Charset = $charset; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@charset ".$this->Charset.";"; + } +} diff --git a/src/CssMin/CssAtFontFaceDeclarationToken.php b/src/CssMin/CssAtFontFaceDeclarationToken.php new file mode 100644 index 0000000..bc5789b --- /dev/null +++ b/src/CssMin/CssAtFontFaceDeclarationToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceDeclarationToken extends CssDeclarationToken +{ + +} diff --git a/src/CssMin/CssAtFontFaceEndToken.php b/src/CssMin/CssAtFontFaceEndToken.php new file mode 100644 index 0000000..856a8f3 --- /dev/null +++ b/src/CssMin/CssAtFontFaceEndToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceEndToken extends CssAtBlockEndToken +{ + +} diff --git a/src/CssMin/CssAtFontFaceParserPlugin.php b/src/CssMin/CssAtFontFaceParserPlugin.php new file mode 100644 index 0000000..2d0264f --- /dev/null +++ b/src/CssMin/CssAtFontFaceParserPlugin.php @@ -0,0 +1,97 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_FONT_FACE::PREPARE", "T_AT_FONT_FACE", "T_AT_FONT_FACE_DECLARATION"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @font-face at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face") { + $this->parser->pushState("T_AT_FONT_FACE::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @font-face declarations + elseif ($char === "{" && $state === "T_AT_FONT_FACE::PREPARE") { + $this->parser->setState("T_AT_FONT_FACE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtFontFaceStartToken()); + } // Start of @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE") { + $this->parser->pushState("T_AT_FONT_FACE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_FONT_FACE_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @font-face declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + } // End of @font-face declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + // -- + if ($char === "}") { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->popState(); + } + } // End of @font-face at-rule block + elseif ($char === "}" && $state === "T_AT_FONT_FACE") { + $this->parser->appendToken(new CssAtFontFaceEndToken()); + $this->parser->clearBuffer(); + $this->parser->popState(); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtFontFaceStartToken.php b/src/CssMin/CssAtFontFaceStartToken.php new file mode 100644 index 0000000..cdecef6 --- /dev/null +++ b/src/CssMin/CssAtFontFaceStartToken.php @@ -0,0 +1,25 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtFontFaceStartToken extends CssAtBlockStartToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@font-face{"; + } +} diff --git a/src/CssMin/CssAtImportParserPlugin.php b/src/CssMin/CssAtImportParserPlugin.php new file mode 100644 index 0000000..d2ba4be --- /dev/null +++ b/src/CssMin/CssAtImportParserPlugin.php @@ -0,0 +1,95 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtImportParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", ";", ",", "\n"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_IMPORT"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 7)) === "@import" + ) { + $this->parser->pushState("T_AT_IMPORT"); + $this->parser->clearBuffer(); + return $index + 7; + } elseif (($char === ";" || $char === "\n") && $state === "T_AT_IMPORT") { + $this->buffer = $this->parser->getAndClearBuffer(";"); + $pos = false; + foreach (array(")", "\"", "'") as $needle) { + if (($pos = strrpos($this->buffer, $needle)) !== false) { + break; + } + } + $import = substr($this->buffer, 0, $pos + 1); + if (stripos($import, "url(") === 0) { + $import = substr($import, 4, -1); + } + $import = trim($import, " \t\n\r\0\x0B'\""); + $mediaTypes = array_filter( + array_map( + "trim", + explode(",", trim(substr($this->buffer, $pos + 1), " \t\n\r\0\x0B{")) + ) + ); + if ($pos) { + $this->parser->appendToken(new CssAtImportToken($import, $mediaTypes)); + } else { + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Invalid @import at-rule syntax", + $this->parser->getBuffer() + ) + ); + } + $this->parser->popState(); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtImportToken.php b/src/CssMin/CssAtImportToken.php new file mode 100644 index 0000000..a39b8bf --- /dev/null +++ b/src/CssMin/CssAtImportToken.php @@ -0,0 +1,51 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1.b1 (2001-02-22) + */ +class CssAtImportToken extends CssToken +{ + /** + * Import path of the @import at-rule. + * + * @var string + */ + public $Import = ""; + /** + * Media types of the @import at-rule. + * + * @var array + */ + public $MediaTypes = array(); + + /** + * Set the properties of a @import at-rule token. + * + * @param string $import Import path + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($import, $mediaTypes) + { + $this->Import = $import; + $this->MediaTypes = $mediaTypes ? $mediaTypes : array(); + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@import \"".$this->Import."\"".(count($this->MediaTypes) > 0 ? " ".implode(",", $this->MediaTypes) : "").";"; + } +} diff --git a/src/CssMin/CssAtKeyframesEndToken.php b/src/CssMin/CssAtKeyframesEndToken.php new file mode 100644 index 0000000..a91b3d7 --- /dev/null +++ b/src/CssMin/CssAtKeyframesEndToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesEndToken extends CssAtBlockEndToken +{ + +} diff --git a/src/CssMin/CssAtKeyframesParserPlugin.php b/src/CssMin/CssAtKeyframesParserPlugin.php new file mode 100644 index 0000000..e5d4e32 --- /dev/null +++ b/src/CssMin/CssAtKeyframesParserPlugin.php @@ -0,0 +1,137 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesParserPlugin extends CssParserPlugin +{ + /** + * @var string Keyword + */ + private $atRuleName = ""; + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ",", ";"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @keyframes at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") { + $this->atRuleName = "keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @keyframes at-rule block (@-moz-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes") { + $this->atRuleName = "-moz-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 15; + } // Start of @keyframes at-rule block (@-webkit-keyframes) + elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes") { + $this->atRuleName = "-webkit-keyframes"; + $this->parser->pushState("T_AT_KEYFRAMES::NAME"); + $this->parser->clearBuffer(); + return $index + 18; + } // Start of @keyframes rulesets + elseif ($char === "{" && $state === "T_AT_KEYFRAMES::NAME") { + $name = $this->parser->getAndClearBuffer("{\"'"); + $this->parser->setState("T_AT_KEYFRAMES_RULESETS"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName)); + } + // Start of @keyframe ruleset and selectors + if ($char === "," && $state === "T_AT_KEYFRAMES_RULESETS") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } // Start of a @keyframes ruleset + elseif ($char === "{" && $state === "T_AT_KEYFRAMES_RULESETS") { + if ($this->parser->getBuffer() !== "") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + $this->parser->pushState("T_AT_KEYFRAMES_RULESET"); + $this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } // Start of @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET") { + $this->parser->pushState("T_AT_KEYFRAMES_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } // Unterminated @keyframes ruleset declaration + elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @keyframes ruleset declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + } // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant)); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") { + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } // End of @keyframes ruleset + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESET") { + $this->parser->clearBuffer(); + + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); + } // End of @keyframes rulesets + elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESETS") { + $this->parser->clearBuffer(); + $this->parser->popState(); + $this->parser->appendToken(new CssAtKeyframesEndToken()); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php b/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php new file mode 100644 index 0000000..c4018f6 --- /dev/null +++ b/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetDeclarationToken extends CssDeclarationToken +{ + +} diff --git a/src/CssMin/CssAtKeyframesRulesetEndToken.php b/src/CssMin/CssAtKeyframesRulesetEndToken.php new file mode 100644 index 0000000..9f48287 --- /dev/null +++ b/src/CssMin/CssAtKeyframesRulesetEndToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetEndToken extends CssRulesetEndToken +{ + +} diff --git a/src/CssMin/CssAtKeyframesRulesetStartToken.php b/src/CssMin/CssAtKeyframesRulesetStartToken.php new file mode 100644 index 0000000..62bd3df --- /dev/null +++ b/src/CssMin/CssAtKeyframesRulesetStartToken.php @@ -0,0 +1,43 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesRulesetStartToken extends CssRulesetStartToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + * @return void + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors)."{"; + } +} diff --git a/src/CssMin/CssAtKeyframesStartToken.php b/src/CssMin/CssAtKeyframesStartToken.php new file mode 100644 index 0000000..8f6f526 --- /dev/null +++ b/src/CssMin/CssAtKeyframesStartToken.php @@ -0,0 +1,52 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtKeyframesStartToken extends CssAtBlockStartToken +{ + /** + * Name of the at-rule. + * + * @var string + */ + public $AtRuleName = "keyframes"; + /** + * Name + * + * @var string + */ + public $Name = ""; + + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($name, $atRuleName = null) + { + $this->Name = $name; + if (!is_null($atRuleName)) { + $this->AtRuleName = $atRuleName; + } + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@".$this->AtRuleName." \"".$this->Name."\"{"; + } +} diff --git a/src/CssMin/CssAtMediaEndToken.php b/src/CssMin/CssAtMediaEndToken.php new file mode 100644 index 0000000..a6d1edd --- /dev/null +++ b/src/CssMin/CssAtMediaEndToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaEndToken extends CssAtBlockEndToken +{ + +} diff --git a/src/CssMin/CssAtMediaParserPlugin.php b/src/CssMin/CssAtMediaParserPlugin.php new file mode 100644 index 0000000..28fdaf5 --- /dev/null +++ b/src/CssMin/CssAtMediaParserPlugin.php @@ -0,0 +1,69 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA::PREPARE", "T_AT_MEDIA"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media") { + $this->parser->pushState("T_AT_MEDIA::PREPARE"); + $this->parser->clearBuffer(); + return $index + 6; + } elseif ($char === "{" && $state === "T_AT_MEDIA::PREPARE") { + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->setMediaTypes($mediaTypes); + $this->parser->setState("T_AT_MEDIA"); + $this->parser->appendToken(new CssAtMediaStartToken($mediaTypes)); + } elseif ($char === "}" && $state === "T_AT_MEDIA") { + $this->parser->appendToken(new CssAtMediaEndToken()); + $this->parser->clearBuffer(); + $this->parser->unsetMediaTypes(); + $this->parser->popState(); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtMediaStartToken.php b/src/CssMin/CssAtMediaStartToken.php new file mode 100644 index 0000000..06d5ad8 --- /dev/null +++ b/src/CssMin/CssAtMediaStartToken.php @@ -0,0 +1,36 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtMediaStartToken extends CssAtBlockStartToken +{ + /** + * Sets the properties of the @media at-rule. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct(array $mediaTypes = array()) + { + $this->MediaTypes = $mediaTypes; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@media ".implode(",", $this->MediaTypes)."{"; + } +} diff --git a/src/CssMin/CssAtPageDeclarationToken.php b/src/CssMin/CssAtPageDeclarationToken.php new file mode 100644 index 0000000..6e28a2c --- /dev/null +++ b/src/CssMin/CssAtPageDeclarationToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageDeclarationToken extends CssDeclarationToken +{ + +} diff --git a/src/CssMin/CssAtPageEndToken.php b/src/CssMin/CssAtPageEndToken.php new file mode 100644 index 0000000..7c3329f --- /dev/null +++ b/src/CssMin/CssAtPageEndToken.php @@ -0,0 +1,17 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageEndToken extends CssAtBlockEndToken +{ + +} diff --git a/src/CssMin/CssAtPageParserPlugin.php b/src/CssMin/CssAtPageParserPlugin.php new file mode 100644 index 0000000..2f400a5 --- /dev/null +++ b/src/CssMin/CssAtPageParserPlugin.php @@ -0,0 +1,98 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_PAGE::SELECTOR", "T_AT_PAGE", "T_AT_PAGE_DECLARATION"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @page at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page") { + $this->parser->pushState("T_AT_PAGE::SELECTOR"); + $this->parser->clearBuffer(); + return $index + 5; + } // Start of @page declarations + elseif ($char === "{" && $state === "T_AT_PAGE::SELECTOR") { + $selector = $this->parser->getAndClearBuffer("{"); + $this->parser->setState("T_AT_PAGE"); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageStartToken($selector)); + } // Start of @page declaration + elseif ($char === ":" && $state === "T_AT_PAGE") { + $this->parser->pushState("T_AT_PAGE_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":", true); + } // Unterminated @font-face declaration + elseif ($char === ":" && $state === "T_AT_PAGE_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @page declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + } // End of @page declaration + elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) == "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant)); + // -- + if ($char === "}") { + $this->parser->popState(); + $this->parser->appendToken(new CssAtPageEndToken()); + } + $this->buffer = ""; + } // End of @page at-rule block + elseif ($char === "}" && $state === "T_AT_PAGE") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtPageEndToken()); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtPageStartToken.php b/src/CssMin/CssAtPageStartToken.php new file mode 100644 index 0000000..37a723b --- /dev/null +++ b/src/CssMin/CssAtPageStartToken.php @@ -0,0 +1,43 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtPageStartToken extends CssAtBlockStartToken +{ + /** + * Selector. + * + * @var string + */ + public $Selector = ""; + + /** + * Sets the properties of the @page at-rule. + * + * @param string $selector Selector + * @return void + */ + public function __construct($selector = "") + { + $this->Selector = $selector; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "@page".($this->Selector ? " ".$this->Selector : "")."{"; + } +} diff --git a/src/CssMin/CssAtVariablesDeclarationToken.php b/src/CssMin/CssAtVariablesDeclarationToken.php new file mode 100644 index 0000000..a900877 --- /dev/null +++ b/src/CssMin/CssAtVariablesDeclarationToken.php @@ -0,0 +1,25 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesDeclarationToken extends CssDeclarationToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} diff --git a/src/CssMin/CssAtVariablesEndToken.php b/src/CssMin/CssAtVariablesEndToken.php new file mode 100644 index 0000000..cde3f13 --- /dev/null +++ b/src/CssMin/CssAtVariablesEndToken.php @@ -0,0 +1,25 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesEndToken extends CssAtBlockEndToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} diff --git a/src/CssMin/CssAtVariablesParserPlugin.php b/src/CssMin/CssAtVariablesParserPlugin.php new file mode 100644 index 0000000..1f1a4a6 --- /dev/null +++ b/src/CssMin/CssAtVariablesParserPlugin.php @@ -0,0 +1,93 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("@", "{", "}", ":", ";"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_VARIABLES::PREPARE", "T_AT_VARIABLES", "T_AT_VARIABLES_DECLARATION"); + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of @variables at-rule block + if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables") { + $this->parser->pushState("T_AT_VARIABLES::PREPARE"); + $this->parser->clearBuffer(); + return $index + 10; + } // Start of @variables declarations + elseif ($char === "{" && $state === "T_AT_VARIABLES::PREPARE") { + $this->parser->setState("T_AT_VARIABLES"); + $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); + $this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes)); + } + // Start of @variables declaration + if ($char === ":" && $state === "T_AT_VARIABLES") { + $this->buffer = $this->parser->getAndClearBuffer(":"); + $this->parser->pushState("T_AT_VARIABLES_DECLARATION"); + } // Unterminated @variables declaration + elseif ($char === ":" && $state === "T_AT_VARIABLES_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @variables declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + } // End of @variables declaration + elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant)); + $this->buffer = ""; + } // End of @variables at-rule block + elseif ($char === "}" && $state === "T_AT_VARIABLES") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssAtVariablesEndToken()); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssAtVariablesStartToken.php b/src/CssMin/CssAtVariablesStartToken.php new file mode 100644 index 0000000..9271a3d --- /dev/null +++ b/src/CssMin/CssAtVariablesStartToken.php @@ -0,0 +1,43 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssAtVariablesStartToken extends CssAtBlockStartToken +{ + /** + * Media types of the @variables at-rule block. + * + * @var array + */ + public $MediaTypes = array(); + + /** + * Set the properties of a @variables at-rule token. + * + * @param array $mediaTypes Media types + * @return void + */ + public function __construct($mediaTypes = null) + { + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} diff --git a/src/CssMin/CssCommentParserPlugin.php b/src/CssMin/CssCommentParserPlugin.php new file mode 100644 index 0000000..febe451 --- /dev/null +++ b/src/CssMin/CssCommentParserPlugin.php @@ -0,0 +1,69 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("*", "/"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Stored buffer for restore. + * + * @var string + */ + private $restoreBuffer = ""; + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + if ($char === "*" && $previousChar === "/" && $state !== "T_COMMENT") { + $this->parser->pushState("T_COMMENT"); + $this->parser->setExclusive(__CLASS__); + $this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2); + } elseif ($char === "/" && $previousChar === "*" && $state === "T_COMMENT") { + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->parser->appendToken(new CssCommentToken("/*".$this->parser->getAndClearBuffer())); + $this->parser->setBuffer($this->restoreBuffer); + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssCommentToken.php b/src/CssMin/CssCommentToken.php new file mode 100644 index 0000000..cf86964 --- /dev/null +++ b/src/CssMin/CssCommentToken.php @@ -0,0 +1,43 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCommentToken extends CssToken +{ + /** + * Comment as Text. + * + * @var string + */ + public $Comment = ""; + + /** + * Set the properties of a comment token. + * + * @param string $comment Comment including comment delimiters + * @return void + */ + public function __construct($comment) + { + $this->Comment = $comment; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Comment; + } +} diff --git a/src/CssMin/CssCompressColorValuesMinifierPlugin.php b/src/CssMin/CssCompressColorValuesMinifierPlugin.php new file mode 100644 index 0000000..20ca878 --- /dev/null +++ b/src/CssMin/CssCompressColorValuesMinifierPlugin.php @@ -0,0 +1,65 @@ + + * color: #aabbcc; + * + * + * Will get converted to: + * + * color:#abc; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressColorValuesMinifierPlugin extends CssMinifierPlugin +{ + /** + * Regular expression matching 6 char hexadecimal color values. + * + * @var string + */ + private $reMatch = "/\#([0-9a-f]{6})/iS"; + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (strpos($token->Value, "#") !== false && preg_match($this->reMatch, $token->Value, $m)) { + $value = strtolower($m[1]); + if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5]) { + $token->Value = str_replace($m[0], "#".$value[0].$value[2].$value[4], $token->Value); + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php b/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php new file mode 100644 index 0000000..a8c0cec --- /dev/null +++ b/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php @@ -0,0 +1,50 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressExpressionValuesMinifierPlugin extends CssMinifierPlugin +{ + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (class_exists("JSMin") && stripos($token->Value, "expression(") !== false) { + $value = $token->Value; + $value = substr($token->Value, stripos($token->Value, "expression(") + 10); + $value = trim(JSMin::minify($value)); + $token->Value = "expression(".$value.")"; + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssCompressUnitValuesMinifierPlugin.php b/src/CssMin/CssCompressUnitValuesMinifierPlugin.php new file mode 100644 index 0000000..86c775a --- /dev/null +++ b/src/CssMin/CssCompressUnitValuesMinifierPlugin.php @@ -0,0 +1,80 @@ + + * padding: 0.5em; + * border: 0px; + * margin: 0 0 0 0; + * + * + * Will get compressed to: + * + * + * padding:.5px; + * border:0; + * margin:0; + * + * + * -- + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssCompressUnitValuesMinifierPlugin extends CssMinifierPlugin +{ + /** + * Regular expression used for matching and replacing unit values. + * + * @var array + */ + private $re = array + ( + "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}.\${2}\${4}", + "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}0", + "/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" => "0" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS"; + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (preg_match($this->reMatch, $token->Value)) { + foreach ($this->re as $reMatch => $reReplace) { + $token->Value = preg_replace($reMatch, $reReplace, $token->Value); + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssConvertFontWeightMinifierPlugin.php b/src/CssMin/CssConvertFontWeightMinifierPlugin.php new file mode 100644 index 0000000..fa0a4d5 --- /dev/null +++ b/src/CssMin/CssConvertFontWeightMinifierPlugin.php @@ -0,0 +1,105 @@ + + * font-weight: normal; + * font: bold 11px monospace; + * + * + * Will get converted to: + * + * font-weight:400; + * font:700 11px monospace; + * + * + * @package CssMin/Minifier/Pluginsn + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertFontWeightMinifierPlugin extends CssMinifierPlugin +{ + /** + * Array of included declaration properties this plugin will process; others declaration properties will get + * ignored. + * + * @var array + */ + private $include = array + ( + "font", + "font-weight" + ); + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Regular expression replace the value. + * + * @var string + */ + private $reReplace = "\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\""; + /** + * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}. + * + * @var array + */ + private $transformation = array + ( + "normal" => "400", + "bold" => "700" + ); + + /** + * Overwrites {@link CssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression} + * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @return void + */ + public function __construct(CssMinifier $minifier) + { + $this->reMatch = "/(^|\s)+(".implode("|", array_keys($this->transformation)).")(\s|$)+/eiS"; + parent::__construct($minifier); + } + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m)) { + $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssConvertHslColorsMinifierPlugin.php b/src/CssMin/CssConvertHslColorsMinifierPlugin.php new file mode 100644 index 0000000..bec5b34 --- /dev/null +++ b/src/CssMin/CssConvertHslColorsMinifierPlugin.php @@ -0,0 +1,122 @@ + + * color: hsl(232,36%,48%); + * + * + * Will get converted to: + * + * color:#4e5aa7; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertHslColorsMinifierPlugin extends CssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS"; + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (stripos($token->Value, "hsl") !== false && preg_match($this->reMatch, $token->Value, $m)) { + $token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } + + /** + * Convert a HSL value to hexadecimal notation. + * + * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}. + * + * @param integer $hue Hue + * @param integer $saturation Saturation + * @param integer $lightness Lightnesss + * @return string + */ + private function hsl2hex($hue, $saturation, $lightness) + { + $hue = $hue / 360; + $saturation = $saturation / 100; + $lightness = $lightness / 100; + if ($saturation == 0) { + $red = $lightness * 255; + $green = $lightness * 255; + $blue = $lightness * 255; + } else { + if ($lightness < 0.5) { + $v2 = $lightness * (1 + $saturation); + } else { + $v2 = ($lightness + $saturation) - ($saturation * $lightness); + } + $v1 = 2 * $lightness - $v2; + $red = 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3)); + $green = 255 * self::hue2rgb($v1, $v2, $hue); + $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3)); + } + return "#".str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT).str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT).str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); + } + + /** + * Apply hue to a rgb color value. + * + * @param integer $v1 Value 1 + * @param integer $v2 Value 2 + * @param integer $hue Hue + * @return integer + */ + private function hue2rgb($v1, $v2, $hue) + { + if ($hue < 0) { + $hue += 1; + } + if ($hue > 1) { + $hue -= 1; + } + if ((6 * $hue) < 1) { + return ($v1 + ($v2 - $v1) * 6 * $hue); + } + if ((2 * $hue) < 1) { + return ($v2); + } + if ((3 * $hue) < 2) { + return ($v1 + ($v2 - $v1) * ((2 / 3) - $hue) * 6); + } + return $v1; + } +} diff --git a/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php b/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php new file mode 100644 index 0000000..5a8d833 --- /dev/null +++ b/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php @@ -0,0 +1,60 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3AtKeyframesMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = array("-moz-keyframes", "-webkit-keyframes"); + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssAtKeyframesStartToken") { + for ($ii = $i; $ii < $l; $ii++) { + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") { + break; + } + } + if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") { + $add = array(); + $source = array(); + for ($iii = $i; $iii <= $ii; $iii++) { + $source[] = clone($tokens[$iii]); + } + foreach ($transformations as $transformation) { + $t = array(); + foreach ($source as $token) { + $t[] = clone($token); + } + $t[0]->AtRuleName = $transformation; + $add = array_merge($add, $t); + } + if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true) { + array_splice($tokens, $i, $ii - $i + 1, $add); + } else { + array_splice($tokens, $ii + 1, 0, $add); + } + $l = count($tokens); + $i = $ii + count($add); + $r += count($add); + } + } + } + return $r; + } +} diff --git a/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php b/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php new file mode 100644 index 0000000..8bf659e --- /dev/null +++ b/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php @@ -0,0 +1,333 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter +{ + /** + * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific + * counterparts. + * + * @var array + */ + private $transformations = array + ( + // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored + "animation" => array(null, "-webkit-animation", null, null), + "animation-delay" => array(null, "-webkit-animation-delay", null, null), + "animation-direction" => array(null, "-webkit-animation-direction", null, null), + "animation-duration" => array(null, "-webkit-animation-duration", null, null), + "animation-fill-mode" => array(null, "-webkit-animation-fill-mode", null, null), + "animation-iteration-count" => array(null, "-webkit-animation-iteration-count", null, null), + "animation-name" => array(null, "-webkit-animation-name", null, null), + "animation-play-state" => array(null, "-webkit-animation-play-state", null, null), + "animation-timing-function" => array(null, "-webkit-animation-timing-function", null, null), + "appearance" => array("-moz-appearance", "-webkit-appearance", null, null), + "backface-visibility" => array(null, "-webkit-backface-visibility", null, null), + "background-clip" => array(null, "-webkit-background-clip", null, null), + "background-composite" => array(null, "-webkit-background-composite", null, null), + "background-inline-policy" => array("-moz-background-inline-policy", null, null, null), + "background-origin" => array(null, "-webkit-background-origin", null, null), + "background-position-x" => array(null, null, null, "-ms-background-position-x"), + "background-position-y" => array(null, null, null, "-ms-background-position-y"), + "background-size" => array(null, "-webkit-background-size", null, null), + "behavior" => array(null, null, null, "-ms-behavior"), + "binding" => array("-moz-binding", null, null, null), + "border-after" => array(null, "-webkit-border-after", null, null), + "border-after-color" => array(null, "-webkit-border-after-color", null, null), + "border-after-style" => array(null, "-webkit-border-after-style", null, null), + "border-after-width" => array(null, "-webkit-border-after-width", null, null), + "border-before" => array(null, "-webkit-border-before", null, null), + "border-before-color" => array(null, "-webkit-border-before-color", null, null), + "border-before-style" => array(null, "-webkit-border-before-style", null, null), + "border-before-width" => array(null, "-webkit-border-before-width", null, null), + "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null), + "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null), + "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null), + "border-end" => array("-moz-border-end", "-webkit-border-end", null, null), + "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null), + "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null), + "border-end-width" => array("-moz-border-end-width", "-webkit-border-end-width", null, null), + "border-fit" => array(null, "-webkit-border-fit", null, null), + "border-horizontal-spacing" => array(null, "-webkit-border-horizontal-spacing", null, null), + "border-image" => array("-moz-border-image", "-webkit-border-image", null, null), + "border-left-colors" => array("-moz-border-left-colors", null, null, null), + "border-radius" => array("-moz-border-radius", "-webkit-border-radius", null, null), + "border-border-right-colors" => array("-moz-border-right-colors", null, null, null), + "border-start" => array("-moz-border-start", "-webkit-border-start", null, null), + "border-start-color" => array("-moz-border-start-color", "-webkit-border-start-color", null, null), + "border-start-style" => array("-moz-border-start-style", "-webkit-border-start-style", null, null), + "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null), + "border-top-colors" => array("-moz-border-top-colors", null, null, null), + "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null), + "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null), + "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null), + "box-align" => array("-moz-box-align", "-webkit-box-align", null, null), + "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null), + "box-flex" => array("-moz-box-flex", "-webkit-box-flex", null, null), + "box-flex-group" => array(null, "-webkit-box-flex-group", null, null), + "box-flex-lines" => array(null, "-webkit-box-flex-lines", null, null), + "box-ordinal-group" => array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null), + "box-orient" => array("-moz-box-orient", "-webkit-box-orient", null, null), + "box-pack" => array("-moz-box-pack", "-webkit-box-pack", null, null), + "box-reflect" => array(null, "-webkit-box-reflect", null, null), + "box-shadow" => array("-moz-box-shadow", "-webkit-box-shadow", null, null), + "box-sizing" => array("-moz-box-sizing", null, null, null), + "color-correction" => array(null, "-webkit-color-correction", null, null), + "column-break-after" => array(null, "-webkit-column-break-after", null, null), + "column-break-before" => array(null, "-webkit-column-break-before", null, null), + "column-break-inside" => array(null, "-webkit-column-break-inside", null, null), + "column-count" => array("-moz-column-count", "-webkit-column-count", null, null), + "column-gap" => array("-moz-column-gap", "-webkit-column-gap", null, null), + "column-rule" => array("-moz-column-rule", "-webkit-column-rule", null, null), + "column-rule-color" => array("-moz-column-rule-color", "-webkit-column-rule-color", null, null), + "column-rule-style" => array("-moz-column-rule-style", "-webkit-column-rule-style", null, null), + "column-rule-width" => array("-moz-column-rule-width", "-webkit-column-rule-width", null, null), + "column-span" => array(null, "-webkit-column-span", null, null), + "column-width" => array("-moz-column-width", "-webkit-column-width", null, null), + "columns" => array(null, "-webkit-columns", null, null), + "filter" => array(__CLASS__, "filter"), + "float-edge" => array("-moz-float-edge", null, null, null), + "font-feature-settings" => array("-moz-font-feature-settings", null, null, null), + "font-language-override" => array("-moz-font-language-override", null, null, null), + "font-size-delta" => array(null, "-webkit-font-size-delta", null, null), + "font-smoothing" => array(null, "-webkit-font-smoothing", null, null), + "force-broken-image-icon" => array("-moz-force-broken-image-icon", null, null, null), + "highlight" => array(null, "-webkit-highlight", null, null), + "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null), + "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null), + "hyphens" => array(null, "-webkit-hyphens", null, null), + "force-broken-image-icon" => array("-moz-image-region", null, null, null), + "ime-mode" => array(null, null, null, "-ms-ime-mode"), + "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"), + "layout-flow" => array(null, null, null, "-ms-layout-flow"), + "layout-grid" => array(null, null, null, "-ms-layout-grid"), + "layout-grid-char" => array(null, null, null, "-ms-layout-grid-char"), + "layout-grid-line" => array(null, null, null, "-ms-layout-grid-line"), + "layout-grid-mode" => array(null, null, null, "-ms-layout-grid-mode"), + "layout-grid-type" => array(null, null, null, "-ms-layout-grid-type"), + "line-break" => array(null, "-webkit-line-break", null, "-ms-line-break"), + "line-clamp" => array(null, "-webkit-line-clamp", null, null), + "line-grid-mode" => array(null, null, null, "-ms-line-grid-mode"), + "logical-height" => array(null, "-webkit-logical-height", null, null), + "logical-width" => array(null, "-webkit-logical-width", null, null), + "margin-after" => array(null, "-webkit-margin-after", null, null), + "margin-after-collapse" => array(null, "-webkit-margin-after-collapse", null, null), + "margin-before" => array(null, "-webkit-margin-before", null, null), + "margin-before-collapse" => array(null, "-webkit-margin-before-collapse", null, null), + "margin-bottom-collapse" => array(null, "-webkit-margin-bottom-collapse", null, null), + "margin-collapse" => array(null, "-webkit-margin-collapse", null, null), + "margin-end" => array("-moz-margin-end", "-webkit-margin-end", null, null), + "margin-start" => array("-moz-margin-start", "-webkit-margin-start", null, null), + "margin-top-collapse" => array(null, "-webkit-margin-top-collapse", null, null), + "marquee " => array(null, "-webkit-marquee", null, null), + "marquee-direction" => array(null, "-webkit-marquee-direction", null, null), + "marquee-increment" => array(null, "-webkit-marquee-increment", null, null), + "marquee-repetition" => array(null, "-webkit-marquee-repetition", null, null), + "marquee-speed" => array(null, "-webkit-marquee-speed", null, null), + "marquee-style" => array(null, "-webkit-marquee-style", null, null), + "mask" => array(null, "-webkit-mask", null, null), + "mask-attachment" => array(null, "-webkit-mask-attachment", null, null), + "mask-box-image" => array(null, "-webkit-mask-box-image", null, null), + "mask-clip" => array(null, "-webkit-mask-clip", null, null), + "mask-composite" => array(null, "-webkit-mask-composite", null, null), + "mask-image" => array(null, "-webkit-mask-image", null, null), + "mask-origin" => array(null, "-webkit-mask-origin", null, null), + "mask-position" => array(null, "-webkit-mask-position", null, null), + "mask-position-x" => array(null, "-webkit-mask-position-x", null, null), + "mask-position-y" => array(null, "-webkit-mask-position-y", null, null), + "mask-repeat" => array(null, "-webkit-mask-repeat", null, null), + "mask-repeat-x" => array(null, "-webkit-mask-repeat-x", null, null), + "mask-repeat-y" => array(null, "-webkit-mask-repeat-y", null, null), + "mask-size" => array(null, "-webkit-mask-size", null, null), + "match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null), + "max-logical-height" => array(null, "-webkit-max-logical-height", null, null), + "max-logical-width" => array(null, "-webkit-max-logical-width", null, null), + "min-logical-height" => array(null, "-webkit-min-logical-height", null, null), + "min-logical-width" => array(null, "-webkit-min-logical-width", null, null), + "object-fit" => array(null, null, "-o-object-fit", null), + "object-position" => array(null, null, "-o-object-position", null), + "opacity" => array(__CLASS__, "opacity"), + "outline-radius" => array("-moz-outline-radius", null, null, null), + "outline-bottom-left-radius" => array("-moz-outline-radius-bottomleft", null, null, null), + "outline-bottom-right-radius" => array("-moz-outline-radius-bottomright", null, null, null), + "outline-top-left-radius" => array("-moz-outline-radius-topleft", null, null, null), + "outline-top-right-radius" => array("-moz-outline-radius-topright", null, null, null), + "padding-after" => array(null, "-webkit-padding-after", null, null), + "padding-before" => array(null, "-webkit-padding-before", null, null), + "padding-end" => array("-moz-padding-end", "-webkit-padding-end", null, null), + "padding-start" => array("-moz-padding-start", "-webkit-padding-start", null, null), + "perspective" => array(null, "-webkit-perspective", null, null), + "perspective-origin" => array(null, "-webkit-perspective-origin", null, null), + "perspective-origin-x" => array(null, "-webkit-perspective-origin-x", null, null), + "perspective-origin-y" => array(null, "-webkit-perspective-origin-y", null, null), + "rtl-ordering" => array(null, "-webkit-rtl-ordering", null, null), + "scrollbar-3dlight-color" => array(null, null, null, "-ms-scrollbar-3dlight-color"), + "scrollbar-arrow-color" => array(null, null, null, "-ms-scrollbar-arrow-color"), + "scrollbar-base-color" => array(null, null, null, "-ms-scrollbar-base-color"), + "scrollbar-darkshadow-color" => array(null, null, null, "-ms-scrollbar-darkshadow-color"), + "scrollbar-face-color" => array(null, null, null, "-ms-scrollbar-face-color"), + "scrollbar-highlight-color" => array(null, null, null, "-ms-scrollbar-highlight-color"), + "scrollbar-shadow-color" => array(null, null, null, "-ms-scrollbar-shadow-color"), + "scrollbar-track-color" => array(null, null, null, "-ms-scrollbar-track-color"), + "stack-sizing" => array("-moz-stack-sizing", null, null, null), + "svg-shadow" => array(null, "-webkit-svg-shadow", null, null), + "tab-size" => array("-moz-tab-size", null, "-o-tab-size", null), + "table-baseline" => array(null, null, "-o-table-baseline", null), + "text-align-last" => array(null, null, null, "-ms-text-align-last"), + "text-autospace" => array(null, null, null, "-ms-text-autospace"), + "text-combine" => array(null, "-webkit-text-combine", null, null), + "text-decorations-in-effect" => array(null, "-webkit-text-decorations-in-effect", null, null), + "text-emphasis" => array(null, "-webkit-text-emphasis", null, null), + "text-emphasis-color" => array(null, "-webkit-text-emphasis-color", null, null), + "text-emphasis-position" => array(null, "-webkit-text-emphasis-position", null, null), + "text-emphasis-style" => array(null, "-webkit-text-emphasis-style", null, null), + "text-fill-color" => array(null, "-webkit-text-fill-color", null, null), + "text-justify" => array(null, null, null, "-ms-text-justify"), + "text-kashida-space" => array(null, null, null, "-ms-text-kashida-space"), + "text-overflow" => array(null, null, "-o-text-overflow", "-ms-text-overflow"), + "text-security" => array(null, "-webkit-text-security", null, null), + "text-size-adjust" => array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"), + "text-stroke" => array(null, "-webkit-text-stroke", null, null), + "text-stroke-color" => array(null, "-webkit-text-stroke-color", null, null), + "text-stroke-width" => array(null, "-webkit-text-stroke-width", null, null), + "text-underline-position" => array(null, null, null, "-ms-text-underline-position"), + "transform" => array("-moz-transform", "-webkit-transform", "-o-transform", null), + "transform-origin" => array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null), + "transform-origin-x" => array(null, "-webkit-transform-origin-x", null, null), + "transform-origin-y" => array(null, "-webkit-transform-origin-y", null, null), + "transform-origin-z" => array(null, "-webkit-transform-origin-z", null, null), + "transform-style" => array(null, "-webkit-transform-style", null, null), + "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null), + "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null), + "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null), + "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null), + "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null), + "user-drag" => array(null, "-webkit-user-drag", null, null), + "user-focus" => array("-moz-user-focus", null, null, null), + "user-input" => array("-moz-user-input", null, null, null), + "user-modify" => array("-moz-user-modify", "-webkit-user-modify", null, null), + "user-select" => array("-moz-user-select", "-webkit-user-select", null, null), + "white-space" => array(__CLASS__, "whiteSpace"), + "window-shadow" => array("-moz-window-shadow", null, null, null), + "word-break" => array(null, null, null, "-ms-word-break"), + "word-wrap" => array(null, null, null, "-ms-word-wrap"), + "writing-mode" => array(null, "-webkit-writing-mode", null, "-ms-writing-mode"), + "zoom" => array(null, null, null, "-ms-zoom") + ); + + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + $transformations = &$this->transformations; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssRulesetDeclarationToken") { + $tProperty = $tokens[$i]->Property; + if (isset($transformations[$tProperty])) { + $result = array(); + if (is_callable($transformations[$tProperty])) { + $result = call_user_func_array($transformations[$tProperty], array($tokens[$i])); + if (!is_array($result) && is_object($result)) { + $result = array($result); + } + } else { + $tValue = $tokens[$i]->Value; + $tMediaTypes = $tokens[$i]->MediaTypes; + foreach ($transformations[$tProperty] as $property) { + if ($property !== null) { + $result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes); + } + } + } + if (count($result) > 0) { + array_splice($tokens, $i + 1, 0, $result); + $i += count($result); + $l += count($result); + } + } + } + } + return $r; + } + + /** + * Transforms the Internet Explorer specific declaration property "filter" to Internet Explorer 8+ compatible + * declaratiopn property "-ms-filter". + * + * @param CssToken $token + * @return array + */ + private static function filter($token) + { + $r = array + ( + new CssRulesetDeclarationToken("-ms-filter", "\"".$token->Value."\"", $token->MediaTypes), + ); + return $r; + } + + /** + * Transforms "opacity: {value}" into browser specific counterparts. + * + * @param CssToken $token + * @return array + */ + private static function opacity($token) + { + // Calculate the value for Internet Explorer filter statement + $ieValue = (int)((float)$token->Value * 100); + $r = array + ( + // Internet Explorer >= 8 + new CssRulesetDeclarationToken("-ms-filter", "\"alpha(opacity=".$ieValue.")\"", $token->MediaTypes), + // Internet Explorer >= 4 <= 7 + new CssRulesetDeclarationToken("filter", "alpha(opacity=".$ieValue.")", $token->MediaTypes), + new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes) + ); + return $r; + } + + /** + * Transforms "white-space: pre-wrap" into browser specific counterparts. + * + * @param CssToken $token + * @return array + */ + private static function whiteSpace($token) + { + if (strtolower($token->Value) === "pre-wrap") { + $r = array + ( + // Firefox < 3 + new CssRulesetDeclarationToken("white-space", "-moz-pre-wrap", $token->MediaTypes), + // Webkit + new CssRulesetDeclarationToken("white-space", "-webkit-pre-wrap", $token->MediaTypes), + // Opera >= 4 <= 6 + new CssRulesetDeclarationToken("white-space", "-pre-wrap", $token->MediaTypes), + // Opera >= 7 + new CssRulesetDeclarationToken("white-space", "-o-pre-wrap", $token->MediaTypes), + // Internet Explorer >= 5.5 + new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes) + ); + return $r; + } else { + return array(); + } + } +} diff --git a/src/CssMin/CssConvertNamedColorsMinifierPlugin.php b/src/CssMin/CssConvertNamedColorsMinifierPlugin.php new file mode 100644 index 0000000..67f46bd --- /dev/null +++ b/src/CssMin/CssConvertNamedColorsMinifierPlugin.php @@ -0,0 +1,235 @@ + + * color: black; + * border: 1px solid indigo; + * + * + * Will get converted to: + * + * color:#000; + * border:1px solid #4b0082; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertNamedColorsMinifierPlugin extends CssMinifierPlugin +{ + + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = null; + /** + * Regular expression replacing the value. + * + * @var string + */ + private $reReplace = "\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\""; + /** + * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}. + * + * @var array + */ + private $transformation = array + ( + "aliceblue" => "#f0f8ff", + "antiquewhite" => "#faebd7", + "aqua" => "#0ff", + "aquamarine" => "#7fffd4", + "azure" => "#f0ffff", + "beige" => "#f5f5dc", + "black" => "#000", + "blue" => "#00f", + "blueviolet" => "#8a2be2", + "brown" => "#a52a2a", + "burlywood" => "#deb887", + "cadetblue" => "#5f9ea0", + "chartreuse" => "#7fff00", + "chocolate" => "#d2691e", + "coral" => "#ff7f50", + "cornflowerblue" => "#6495ed", + "cornsilk" => "#fff8dc", + "crimson" => "#dc143c", + "darkblue" => "#00008b", + "darkcyan" => "#008b8b", + "darkgoldenrod" => "#b8860b", + "darkgray" => "#a9a9a9", + "darkgreen" => "#006400", + "darkkhaki" => "#bdb76b", + "darkmagenta" => "#8b008b", + "darkolivegreen" => "#556b2f", + "darkorange" => "#ff8c00", + "darkorchid" => "#9932cc", + "darkred" => "#8b0000", + "darksalmon" => "#e9967a", + "darkseagreen" => "#8fbc8f", + "darkslateblue" => "#483d8b", + "darkslategray" => "#2f4f4f", + "darkturquoise" => "#00ced1", + "darkviolet" => "#9400d3", + "deeppink" => "#ff1493", + "deepskyblue" => "#00bfff", + "dimgray" => "#696969", + "dodgerblue" => "#1e90ff", + "firebrick" => "#b22222", + "floralwhite" => "#fffaf0", + "forestgreen" => "#228b22", + "fuchsia" => "#f0f", + "gainsboro" => "#dcdcdc", + "ghostwhite" => "#f8f8ff", + "gold" => "#ffd700", + "goldenrod" => "#daa520", + "gray" => "#808080", + "green" => "#008000", + "greenyellow" => "#adff2f", + "honeydew" => "#f0fff0", + "hotpink" => "#ff69b4", + "indianred" => "#cd5c5c", + "indigo" => "#4b0082", + "ivory" => "#fffff0", + "khaki" => "#f0e68c", + "lavender" => "#e6e6fa", + "lavenderblush" => "#fff0f5", + "lawngreen" => "#7cfc00", + "lemonchiffon" => "#fffacd", + "lightblue" => "#add8e6", + "lightcoral" => "#f08080", + "lightcyan" => "#e0ffff", + "lightgoldenrodyellow" => "#fafad2", + "lightgreen" => "#90ee90", + "lightgrey" => "#d3d3d3", + "lightpink" => "#ffb6c1", + "lightsalmon" => "#ffa07a", + "lightseagreen" => "#20b2aa", + "lightskyblue" => "#87cefa", + "lightslategray" => "#789", + "lightsteelblue" => "#b0c4de", + "lightyellow" => "#ffffe0", + "lime" => "#0f0", + "limegreen" => "#32cd32", + "linen" => "#faf0e6", + "maroon" => "#800000", + "mediumaquamarine" => "#66cdaa", + "mediumblue" => "#0000cd", + "mediumorchid" => "#ba55d3", + "mediumpurple" => "#9370db", + "mediumseagreen" => "#3cb371", + "mediumslateblue" => "#7b68ee", + "mediumspringgreen" => "#00fa9a", + "mediumturquoise" => "#48d1cc", + "mediumvioletred" => "#c71585", + "midnightblue" => "#191970", + "mintcream" => "#f5fffa", + "mistyrose" => "#ffe4e1", + "moccasin" => "#ffe4b5", + "navajowhite" => "#ffdead", + "navy" => "#000080", + "oldlace" => "#fdf5e6", + "olive" => "#808000", + "olivedrab" => "#6b8e23", + "orange" => "#ffa500", + "orangered" => "#ff4500", + "orchid" => "#da70d6", + "palegoldenrod" => "#eee8aa", + "palegreen" => "#98fb98", + "paleturquoise" => "#afeeee", + "palevioletred" => "#db7093", + "papayawhip" => "#ffefd5", + "peachpuff" => "#ffdab9", + "peru" => "#cd853f", + "pink" => "#ffc0cb", + "plum" => "#dda0dd", + "powderblue" => "#b0e0e6", + "purple" => "#800080", + "red" => "#f00", + "rosybrown" => "#bc8f8f", + "royalblue" => "#4169e1", + "saddlebrown" => "#8b4513", + "salmon" => "#fa8072", + "sandybrown" => "#f4a460", + "seagreen" => "#2e8b57", + "seashell" => "#fff5ee", + "sienna" => "#a0522d", + "silver" => "#c0c0c0", + "skyblue" => "#87ceeb", + "slateblue" => "#6a5acd", + "slategray" => "#708090", + "snow" => "#fffafa", + "springgreen" => "#00ff7f", + "steelblue" => "#4682b4", + "tan" => "#d2b48c", + "teal" => "#008080", + "thistle" => "#d8bfd8", + "tomato" => "#ff6347", + "turquoise" => "#40e0d0", + "violet" => "#ee82ee", + "wheat" => "#f5deb3", + "white" => "#fff", + "whitesmoke" => "#f5f5f5", + "yellow" => "#ff0", + "yellowgreen" => "#9acd32" + ); + + /** + * Overwrites {@link CssMinifierPlugin::__construct()}. + * + * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression} + * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + * @return void + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->reMatch = "/(^|\s)+(".implode("|", array_keys($this->transformation)).")(\s|$)+/eiS"; + parent::__construct($minifier, $configuration); + } + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + $lcValue = strtolower($token->Value); + // Declaration value equals a value in the transformation table => simple replace + if (isset($this->transformation[$lcValue])) { + $token->Value = $this->transformation[$lcValue]; + } // Declaration value contains a value in the transformation table => regular expression replace + elseif (preg_match($this->reMatch, $token->Value)) { + $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssConvertRgbColorsMinifierPlugin.php b/src/CssMin/CssConvertRgbColorsMinifierPlugin.php new file mode 100644 index 0000000..555c908 --- /dev/null +++ b/src/CssMin/CssConvertRgbColorsMinifierPlugin.php @@ -0,0 +1,68 @@ + + * color: rgb(200,60%,5); + * + * + * Will get converted to: + * + * color:#c89905; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssConvertRgbColorsMinifierPlugin extends CssMinifierPlugin +{ + /** + * Regular expression matching the value. + * + * @var string + */ + private $reMatch = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS"; + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (stripos($token->Value, "rgb") !== false && preg_match($this->reMatch, $token->Value, $m)) { + for ($i = 1, $l = count($m); $i < $l; $i++) { + if (strpos("%", $m[$i]) !== false) { + $m[$i] = substr($m[$i], 0, -1); + $m[$i] = (int)(256 * ($m[$i] / 100)); + } + $m[$i] = str_pad(dechex($m[$i]), 2, "0", STR_PAD_LEFT); + } + $token->Value = str_replace($m[0], "#".$m[1].$m[2].$m[3], $token->Value); + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } +} diff --git a/src/CssMin/CssDeclarationToken.php b/src/CssMin/CssDeclarationToken.php new file mode 100644 index 0000000..b59321c --- /dev/null +++ b/src/CssMin/CssDeclarationToken.php @@ -0,0 +1,66 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssDeclarationToken extends CssToken +{ + /** + * Is the declaration flagged as important? + * + * @var boolean + */ + public $IsImportant = false; + /** + * Is the declaration flagged as last one of the ruleset? + * + * @var boolean + */ + public $IsLast = false; + /** + * Property name of the declaration. + * + * @var string + */ + public $Property = ""; + /** + * Value of the declaration. + * + * @var string + */ + public $Value = ""; + + /** + * Set the properties of the @font-face declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param boolean $isImportant Is the !important flag is set? + * @param bool $isLast Is the declaration the last one of the block? + */ + public function __construct($property, $value, $isImportant = false, $isLast = false) + { + $this->Property = $property; + $this->Value = $value; + $this->IsImportant = $isImportant; + $this->IsLast = $isLast; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return $this->Property.":".$this->Value.($this->IsImportant ? " !important" : "").($this->IsLast ? "" : ";"); + } +} diff --git a/src/CssMin/CssError.php b/src/CssMin/CssError.php new file mode 100644 index 0000000..30fd39a --- /dev/null +++ b/src/CssMin/CssError.php @@ -0,0 +1,65 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssError +{ + /** + * File. + * + * @var string + */ + public $File = ""; + /** + * Line. + * + * @var integer + */ + public $Line = 0; + /** + * Error message. + * + * @var string + */ + public $Message = ""; + /** + * Source. + * + * @var string + */ + public $Source = ""; + + /** + * Constructor triggering the error. + * + * @param string $message Error message + * @param string $source Corresponding line [optional] + * @return void + */ + public function __construct($file, $line, $message, $source = "") + { + $this->File = $file; + $this->Line = $line; + $this->Message = $message; + $this->Source = $source; + } + + /** + * Returns the error as formatted string. + * + * @return string + */ + public function __toString() + { + return $this->Message.($this->Source ? ":
".$this->Source."" : "")."
in file ".$this->File." at line ".$this->Line; + } +} diff --git a/src/CssMin/CssExpressionParserPlugin.php b/src/CssMin/CssExpressionParserPlugin.php new file mode 100644 index 0000000..72443ae --- /dev/null +++ b/src/CssMin/CssExpressionParserPlugin.php @@ -0,0 +1,82 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssExpressionParserPlugin extends CssParserPlugin +{ + /** + * Count of left braces. + * + * @var integer + */ + private $leftBraces = 0; + /** + * Count of right braces. + * + * @var integer + */ + private $rightBraces = 0; + + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")", ";", "}"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of expression + if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION") { + $this->parser->pushState("T_EXPRESSION"); + $this->leftBraces++; + } // Count left braces + elseif ($char === "(" && $state === "T_EXPRESSION") { + $this->leftBraces++; + } // Count right braces + elseif ($char === ")" && $state === "T_EXPRESSION") { + $this->rightBraces++; + } // Possible end of expression; if left and right braces are equal the expressen ends + elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces) { + $this->leftBraces = $this->rightBraces = 0; + $this->parser->popState(); + return $index - 1; + } else { + return false; + } + return true; + } +} diff --git a/src/CssMin/CssFormatter.php b/src/CssMin/CssFormatter.php new file mode 100644 index 0000000..8cd8cf7 --- /dev/null +++ b/src/CssMin/CssFormatter.php @@ -0,0 +1,57 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssFormatter +{ + /** + * Indent string. + * + * @var string + */ + protected $indent = " "; + /** + * Declaration padding. + * + * @var integer + */ + protected $padding = 0; + /** + * Tokens. + * + * @var array + */ + protected $tokens = array(); + + /** + * Constructor. + * + * @param array $tokens Array of CssToken + * @param string $indent Indent string [optional] + * @param integer $padding Declaration value padding [optional] + */ + public function __construct(array $tokens, $indent = null, $padding = null) + { + $this->tokens = $tokens; + $this->indent = !is_null($indent) ? $indent : $this->indent; + $this->padding = !is_null($padding) ? $padding : $this->padding; + } + + /** + * Returns the array of CssToken as formatted string. + * + * @return string + */ + abstract public function __toString(); +} diff --git a/src/CssMin/CssImportImportsMinifierFilter.php b/src/CssMin/CssImportImportsMinifierFilter.php new file mode 100644 index 0000000..9a8fa2e --- /dev/null +++ b/src/CssMin/CssImportImportsMinifierFilter.php @@ -0,0 +1,167 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssImportImportsMinifierFilter extends CssMinifierFilter +{ + /** + * Array with already imported external stylesheets. + * + * @var array + */ + private $imported = array(); + + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"])) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Base path ".($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null")." is not a directory")); + return 0; + } + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssAtImportToken") { + $import = $this->configuration["BasePath"]."/".$tokens[$i]->Import; + // Import file was not found/is not a file + if (!is_file($import)) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Import file ".$import." was not found.", (string)$tokens[$i])); + } // Import file already imported; remove this @import at-rule to prevent recursions + elseif (in_array($import, $this->imported)) { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Import file ".$import." was already imported.", (string)$tokens[$i])); + $tokens[$i] = null; + } else { + $this->imported[] = $import; + $parser = new CssParser(file_get_contents($import)); + $import = $parser->getTokens(); + // The @import at-rule has media types defined requiring special handling + if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all")) { + $blocks = array(); + /* + * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtImportToken") { + // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule + if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all")) { + $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes; + } // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule + elseif (count($import[$ii]->MediaTypes > 0)) { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) { + unset($import[$ii]->MediaTypes[$index]); + } + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + // If there are no media types left in the @import at-rule remove the @import at-rule + if (count($import[$ii]->MediaTypes) == 0) { + $import[$ii] = null; + } + } + } + } + /* + * Remove media types of @media at-rule block not defined in the @import at-rule + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken") { + foreach ($import[$ii]->MediaTypes as $index => $mediaType) { + if (!in_array($mediaType, $tokens[$i]->MediaTypes)) { + unset($import[$ii]->MediaTypes[$index]); + } + $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); + } + } + } + /* + * If no media types left of the @media at-rule block remove the complete block + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken") { + if (count($import[$ii]->MediaTypes) === 0) { + for ($iii = $ii; $iii < $ll; $iii++) { + if (get_class($import[$iii]) === "CssAtMediaEndToken") { + break; + } + } + if (get_class($import[$iii]) === "CssAtMediaEndToken") { + array_splice($import, $ii, $iii - $ii + 1, array()); + $ll = count($import); + } + } + } + } + /* + * If the media types of the @media at-rule equals the media types defined in the @import + * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0) { + for ($iii = $ii; $iii < $ll; $iii++) { + if (get_class($import[$iii]) == "CssAtMediaEndToken") { + break; + } + } + if (get_class($import[$iii]) == "CssAtMediaEndToken") { + unset($import[$ii]); + unset($import[$iii]); + $import = array_values($import); + $ll = count($import); + } + } + } + /** + * Extract CssAtImportToken and CssAtCharsetToken tokens + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + $class = get_class($import[$ii]); + if ($class === "CssAtImportToken" || $class === "CssAtCharsetToken") { + $blocks = array_merge($blocks, array_splice($import, $ii, 1, array())); + $ll = count($import); + } + } + /* + * Extract the @font-face, @media and @page at-rule block + */ + for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { + $class = get_class($import[$ii]); + if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken") { + for ($iii = $ii; $iii < $ll; $iii++) { + $class = get_class($import[$iii]); + if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken") { + break; + } + } + $class = get_class($import[$iii]); + if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")) { + $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array())); + $ll = count($import); + } + } + } + // Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block + $import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken())); + } + // Insert the imported tokens + array_splice($tokens, $i, 1, $import); + // Modify parameters of the for-loop + $i--; + $l = count($tokens); + } + } + } + } +} diff --git a/src/CssMin/CssMin.php b/src/CssMin/CssMin.php index c91a789..6f8d1fb 100644 --- a/src/CssMin/CssMin.php +++ b/src/CssMin/CssMin.php @@ -1,8 +1,9 @@ * @@ -12,10 +13,10 @@ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -24,2113 +25,18 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * -- - * - * @package CssMin - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -/** - * Abstract definition of a CSS token class. - * - * Every token has to extend this class. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssToken - { - /** - * Returns the token as string. - * - * @return string - */ - abstract public function __toString(); - } - -/** - * Abstract definition of a for a ruleset start token. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssRulesetStartToken extends aCssToken - { - - } - -/** - * Abstract definition of a for ruleset end token. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssRulesetEndToken extends aCssToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "}"; - } - } - -/** - * Abstract definition of a parser plugin. - * - * Every parser plugin have to extend this class. A parser plugin contains the logic to parse one or aspects of a - * stylesheet. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssParserPlugin - { - /** - * Plugin configuration. - * - * @var array - */ - protected $configuration = array(); - /** - * The CssParser of the plugin. - * - * @var CssParser - */ - protected $parser = null; - /** - * Plugin buffer. - * - * @var string - */ - protected $buffer = ""; - /** - * Constructor. - * - * @param CssParser $parser The CssParser object of this plugin. - * @param array $configuration Plugin configuration [optional] - * @return void - */ - public function __construct(CssParser $parser, array $configuration = null) - { - $this->configuration = $configuration; - $this->parser = $parser; - } - /** - * Returns the array of chars triggering the parser plugin. - * - * @return array - */ - abstract public function getTriggerChars(); - /** - * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin. - * - * @return array - */ - abstract public function getTriggerStates(); - /** - * Parser routine of the plugin. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - abstract public function parse($index, $char, $previousChar, $state); - } - -/** - * Abstract definition of a minifier plugin class. - * - * Minifier plugin process the parsed tokens one by one to apply changes to the token. Every minifier plugin has to - * extend this class. - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssMinifierPlugin - { - /** - * Plugin configuration. - * - * @var array - */ - protected $configuration = array(); - /** - * The CssMinifier of the plugin. - * - * @var CssMinifier - */ - protected $minifier = null; - /** - * Constructor. - * - * @param CssMinifier $minifier The CssMinifier object of this plugin. - * @param array $configuration Plugin configuration [optional] - * @return void - */ - public function __construct(CssMinifier $minifier, array $configuration = array()) - { - $this->configuration = $configuration; - $this->minifier = $minifier; - } - /** - * Apply the plugin to the token. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - abstract public function apply(aCssToken &$token); - /** - * -- - * - * @return array - */ - abstract public function getTriggerTokens(); - } - -/** - * Abstract definition of a minifier filter class. - * - * Minifier filters allows a pre-processing of the parsed token to add, edit or delete tokens. Every minifier filter - * has to extend this class. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssMinifierFilter - { - /** - * Filter configuration. - * - * @var array - */ - protected $configuration = array(); - /** - * The CssMinifier of the filter. - * - * @var CssMinifier - */ - protected $minifier = null; - /** - * Constructor. - * - * @param CssMinifier $minifier The CssMinifier object of this plugin. - * @param array $configuration Filter configuration [optional] - * @return void - */ - public function __construct(CssMinifier $minifier, array $configuration = array()) - { - $this->configuration = $configuration; - $this->minifier = $minifier; - } - /** - * Filter the tokens. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - abstract public function apply(array &$tokens); - } - -/** - * Abstract formatter definition. - * - * Every formatter have to extend this class. - * - * @package CssMin/Formatter - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssFormatter - { - /** - * Indent string. - * - * @var string - */ - protected $indent = " "; - /** - * Declaration padding. - * - * @var integer - */ - protected $padding = 0; - /** - * Tokens. - * - * @var array - */ - protected $tokens = array(); - /** - * Constructor. - * - * @param array $tokens Array of CssToken - * @param string $indent Indent string [optional] - * @param integer $padding Declaration value padding [optional] - */ - public function __construct(array $tokens, $indent = null, $padding = null) - { - $this->tokens = $tokens; - $this->indent = !is_null($indent) ? $indent : $this->indent; - $this->padding = !is_null($padding) ? $padding : $this->padding; - } - /** - * Returns the array of aCssToken as formatted string. - * - * @return string - */ - abstract public function __toString(); - } - -/** - * Abstract definition of a ruleset declaration token. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssDeclarationToken extends aCssToken - { - /** - * Is the declaration flagged as important? - * - * @var boolean - */ - public $IsImportant = false; - /** - * Is the declaration flagged as last one of the ruleset? - * - * @var boolean - */ - public $IsLast = false; - /** - * Property name of the declaration. - * - * @var string - */ - public $Property = ""; - /** - * Value of the declaration. - * - * @var string - */ - public $Value = ""; - /** - * Set the properties of the @font-face declaration. - * - * @param string $property Property of the declaration - * @param string $value Value of the declaration - * @param boolean $isImportant Is the !important flag is set? - * @param boolean $IsLast Is the declaration the last one of the block? - * @return void - */ - public function __construct($property, $value, $isImportant = false, $isLast = false) - { - $this->Property = $property; - $this->Value = $value; - $this->IsImportant = $isImportant; - $this->IsLast = $isLast; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return $this->Property . ":" . $this->Value . ($this->IsImportant ? " !important" : "") . ($this->IsLast ? "" : ";"); - } - } - -/** - * Abstract definition of a for at-rule block start token. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssAtBlockStartToken extends aCssToken - { - - } - -/** - * Abstract definition of a for at-rule block end token. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -abstract class aCssAtBlockEndToken extends aCssToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "}"; - } - } - -/** - * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/etzLs Whitesmiths indent style}. - * - * @package CssMin/Formatter - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssWhitesmithsFormatter extends aCssFormatter - { - /** - * Implements {@link aCssFormatter::__toString()}. - * - * @return string - */ - public function __toString() - { - $r = array(); - $level = 0; - for ($i = 0, $l = count($this->tokens); $i < $l; $i++) - { - $token = $this->tokens[$i]; - $class = get_class($token); - $indent = str_repeat($this->indent, $level); - if ($class === "CssCommentToken") - { - $lines = array_map("trim", explode("\n", $token->Comment)); - for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) - { - $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; - } - } - elseif ($class === "CssAtCharsetToken") - { - $r[] = $indent . "@charset " . $token->Charset . ";"; - } - elseif ($class === "CssAtFontFaceStartToken") - { - $r[] = $indent . "@font-face"; - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class === "CssAtImportToken") - { - $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; - } - elseif ($class === "CssAtKeyframesStartToken") - { - $r[] = $indent . "@keyframes \"" . $token->Name . "\""; - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class === "CssAtMediaStartToken") - { - $r[] = $indent . "@media " . implode(", ", $token->MediaTypes); - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class === "CssAtPageStartToken") - { - $r[] = $indent . "@page"; - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class === "CssAtVariablesStartToken") - { - $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes); - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") - { - $r[] = $indent . implode(", ", $token->Selectors); - $r[] = $this->indent . $indent . "{"; - $level++; - } - elseif ($class == "CssAtFontFaceDeclarationToken" - || $class === "CssAtKeyframesRulesetDeclarationToken" - || $class === "CssAtPageDeclarationToken" - || $class == "CssAtVariablesDeclarationToken" - || $class === "CssRulesetDeclarationToken" - ) - { - $declaration = $indent . $token->Property . ": "; - if ($this->padding) - { - $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); - } - $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; - } - elseif ($class === "CssAtFontFaceEndToken" - || $class === "CssAtMediaEndToken" - || $class === "CssAtKeyframesEndToken" - || $class === "CssAtKeyframesRulesetEndToken" - || $class === "CssAtPageEndToken" - || $class === "CssAtVariablesEndToken" - || $class === "CssRulesetEndToken" - ) - { - $r[] = $indent . "}"; - $level--; - } - } - return implode("\n", $r); - } - } - -/** - * This {@link aCssMinifierPlugin} will process var-statement and sets the declaration value to the variable value. - * - * This plugin only apply the variable values. The variable values itself will get parsed by the - * {@link CssVariablesMinifierFilter}. - * - * Example: - * - * @variables - * { - * defaultColor: black; - * } - * color: var(defaultColor); - * - * - * Will get converted to: - * - * color:black; - * - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssVariablesMinifierPlugin extends aCssMinifierPlugin - { - /** - * Regular expression matching a value. - * - * @var string - */ - private $reMatch = "/var\((.+)\)/iSU"; - /** - * Parsed variables. - * - * @var array - */ - private $variables = null; - /** - * Returns the variables. - * - * @return array - */ - public function getVariables() - { - return $this->variables; - } - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m)) - { - $mediaTypes = $token->MediaTypes; - if (!in_array("all", $mediaTypes)) - { - $mediaTypes[] = "all"; - } - for ($i = 0, $l = count($m[0]); $i < $l; $i++) - { - $variable = trim($m[1][$i]); - foreach ($mediaTypes as $mediaType) - { - if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable])) - { - // Variable value found => set the declaration value to the variable value and return - $token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value); - continue 2; - } - } - // If no value was found trigger an error and replace the token with a CssNullToken - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": No value found for variable " . $variable . " in media types " . implode(", ", $mediaTypes) . "", (string) $token)); - $token = new CssNullToken(); - return true; - } - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - /** - * Sets the variables. - * - * @param array $variables Variables to set - * @return void - */ - public function setVariables(array $variables) - { - $this->variables = $variables; - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} will parse the variable declarations out of @variables at-rule - * blocks. The variables will get store in the {@link CssVariablesMinifierPlugin} that will apply the variables to - * declaration. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssVariablesMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $variables = array(); - $defaultMediaTypes = array("all"); - $mediaTypes = array(); - $remove = array(); - for($i = 0, $l = count($tokens); $i < $l; $i++) - { - // @variables at-rule block found - if (get_class($tokens[$i]) === "CssAtVariablesStartToken") - { - $remove[] = $i; - $mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes); - foreach ($mediaTypes as $mediaType) - { - if (!isset($variables[$mediaType])) - { - $variables[$mediaType] = array(); - } - } - // Read the variable declaration tokens - for($i = $i; $i < $l; $i++) - { - // Found a variable declaration => read the variable values - if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken") - { - foreach ($mediaTypes as $mediaType) - { - $variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value; - } - $remove[] = $i; - } - // Found the variables end token => break; - elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken") - { - $remove[] = $i; - break; - } - } - } - } - // Variables in @variables at-rule blocks - foreach($variables as $mediaType => $null) - { - foreach($variables[$mediaType] as $variable => $value) - { - // If a var() statement in a variable value found... - if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m)) - { - // ... then replace the var() statement with the variable values. - for ($i = 0, $l = count($m[0]); $i < $l; $i++) - { - $variables[$mediaType][$variable] = str_replace($m[0][$i], (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), $variables[$mediaType][$variable]); - } - } - } - } - // Remove the complete @variables at-rule block - foreach ($remove as $i) - { - $tokens[$i] = null; - } - if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin"))) - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin CssVariablesMinifierPlugin was not found but is required for " . __CLASS__ . "")); - } - else - { - $plugin->setVariables($variables); - } - return count($remove); - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for preserve parsing url() values. - * - * This plugin return no {@link aCssToken CssToken} but ensures that url() values will get parsed properly. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssUrlParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("(", ")"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return false; - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of string - if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" && $state !== "T_URL") - { - $this->parser->pushState("T_URL"); - $this->parser->setExclusive(__CLASS__); - } - // Escaped LF in url => remove escape backslash and LF - elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL") - { - $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); - } - // Parse error: Unescaped LF in string literal - elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL") - { - $line = $this->parser->getBuffer(); - $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . ")"); // Replace the LF with the url string delimiter - $this->parser->popState(); - $this->parser->unsetExclusive(); - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); - } - // End of string - elseif ($char === ")" && $state === "T_URL") - { - $this->parser->popState(); - $this->parser->unsetExclusive(); - } - else - { - return false; - } - return true; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for preserve parsing string values. - * - * This plugin return no {@link aCssToken CssToken} but ensures that string values will get parsed properly. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssStringParserPlugin extends aCssParserPlugin - { - /** - * Current string delimiter char. - * - * @var string - */ - private $delimiterChar = null; - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("\"", "'", "\n"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return false; - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of string - if (($char === "\"" || $char === "'") && $state !== "T_STRING") - { - $this->delimiterChar = $char; - $this->parser->pushState("T_STRING"); - $this->parser->setExclusive(__CLASS__); - } - // Escaped LF in string => remove escape backslash and LF - elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING") - { - $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); - } - // Parse error: Unescaped LF in string literal - elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING") - { - $line = $this->parser->getBuffer(); - $this->parser->popState(); - $this->parser->unsetExclusive(); - $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1) . $this->delimiterChar); // Replace the LF with the current string char - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated string literal", $line . "_")); - $this->delimiterChar = null; - } - // End of string - elseif ($char === $this->delimiterChar && $state === "T_STRING") - { - // If the Previous char is a escape char count the amount of the previous escape chars. If the amount of - // escape chars is uneven do not end the string - if ($previousChar == "\\") - { - $source = $this->parser->getSource(); - $c = 1; - $i = $index - 2; - while (substr($source, $i, 1) === "\\") - { - $c++; $i--; - } - if ($c % 2) - { - return false; - } - } - $this->parser->popState(); - $this->parser->unsetExclusive(); - $this->delimiterChar = null; - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} sorts the ruleset declarations of a ruleset by name. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Rowan Beentje - * @copyright Rowan Beentje - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssSortRulesetPropertiesMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - // Only look for ruleset start rules - if (get_class($tokens[$i]) !== "CssRulesetStartToken") { continue; } - // Look for the corresponding ruleset end - $endIndex = false; - for ($ii = $i + 1; $ii < $l; $ii++) - { - if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { continue; } - $endIndex = $ii; - break; - } - if (!$endIndex) { break; } - $startIndex = $i; - $i = $endIndex; - // Skip if there's only one token in this ruleset - if ($endIndex - $startIndex <= 2) { continue; } - // Ensure that everything between the start and end is a declaration token, for safety - for ($ii = $startIndex + 1; $ii < $endIndex; $ii++) - { - if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { continue(2); } - } - $declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1); - // Check whether a sort is required - $sortRequired = $lastPropertyName = false; - foreach ($declarations as $declaration) - { - if ($lastPropertyName) - { - if (strcmp($lastPropertyName, $declaration->Property) > 0) - { - $sortRequired = true; - break; - } - } - $lastPropertyName = $declaration->Property; - } - if (!$sortRequired) { continue; } - // Arrange the declarations alphabetically by name - usort($declarations, array(__CLASS__, "userDefinedSort1")); - // Update "IsLast" property - for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++) - { - if ($ii == $ll) - { - $declarations[$ii]->IsLast = true; - } - else - { - $declarations[$ii]->IsLast = false; - } - } - // Splice back into the array. - array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations); - $r += $endIndex - $startIndex - 1; - } - return $r; - } - /** - * User defined sort function. - * - * @return integer - */ - public static function userDefinedSort1($a, $b) - { - return strcmp($a->Property, $b->Property); - } - } - -/** - * This {@link aCssToken CSS token} represents the start of a ruleset. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRulesetStartToken extends aCssRulesetStartToken - { - /** - * Array of selectors. - * - * @var array - */ - public $Selectors = array(); - /** - * Set the properties of a ruleset token. - * - * @param array $selectors Selectors of the ruleset - * @return void - */ - public function __construct(array $selectors = array()) - { - $this->Selectors = $selectors; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return implode(",", $this->Selectors) . "{"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing ruleset block with including declarations. - * - * Found rulesets will add a {@link CssRulesetStartToken} and {@link CssRulesetEndToken} to the - * parser; including declarations as {@link CssRulesetDeclarationToken}. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRulesetParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array(",", "{", "}", ":", ";"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION"); - } - /** - * Selectors. - * - * @var array - */ - private $selectors = array(); - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of Ruleset and selectors - if ($char === "," && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) - { - if ($state !== "T_RULESET::SELECTORS") - { - $this->parser->pushState("T_RULESET::SELECTORS"); - } - $this->selectors[] = $this->parser->getAndClearBuffer(",{"); - } - // End of selectors and start of declarations - elseif ($char === "{" && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS")) - { - if ($this->parser->getBuffer() !== "") - { - $this->selectors[] = $this->parser->getAndClearBuffer(",{"); - if ($state == "T_RULESET::SELECTORS") - { - $this->parser->popState(); - } - $this->parser->pushState("T_RULESET"); - $this->parser->appendToken(new CssRulesetStartToken($this->selectors)); - $this->selectors = array(); - } - } - // Start of declaration - elseif ($char === ":" && $state === "T_RULESET") - { - $this->parser->pushState("T_RULESET_DECLARATION"); - $this->buffer = $this->parser->getAndClearBuffer(":;", true); - } - // Unterminated ruleset declaration - elseif ($char === ":" && $state === "T_RULESET_DECLARATION") - { - // Ignore Internet Explorer filter declarations - if ($this->buffer === "filter") - { - return false; - } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); - } - // End of declaration - elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION") - { - $value = $this->parser->getAndClearBuffer(";}"); - if (strtolower(substr($value, -10, 10)) === "!important") - { - $value = trim(substr($value, 0, -10)); - $isImportant = true; - } - else - { - $isImportant = false; - } - $this->parser->popState(); - $this->parser->appendToken(new CssRulesetDeclarationToken($this->buffer, $value, $this->parser->getMediaTypes(), $isImportant)); - // Declaration ends with a right curly brace; so we have to end the ruleset - if ($char === "}") - { - $this->parser->appendToken(new CssRulesetEndToken()); - $this->parser->popState(); - } - $this->buffer = ""; - } - // End of ruleset - elseif ($char === "}" && $state === "T_RULESET") - { - $this->parser->popState(); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssRulesetEndToken()); - $this->buffer = ""; - $this->selectors = array(); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a ruleset. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRulesetEndToken extends aCssRulesetEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a ruleset declaration. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRulesetDeclarationToken extends aCssDeclarationToken - { - /** - * Media types of the declaration. - * - * @var array - */ - public $MediaTypes = array("all"); - /** - * Set the properties of a ddocument- or at-rule @media level declaration. - * - * @param string $property Property of the declaration - * @param string $value Value of the declaration - * @param mixed $mediaTypes Media types of the declaration - * @param boolean $isImportant Is the !important flag is set - * @param boolean $isLast Is the declaration the last one of the ruleset - * @return void - */ - public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false) - { - parent::__construct($property, $value, $isImportant, $isLast); - $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} sets the IsLast property of any last declaration in a ruleset, - * @font-face at-rule or @page at-rule block. If the property IsLast is TRUE the decrations will get stringified - * without tailing semicolon. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRemoveLastDelarationSemiColonMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - $current = get_class($tokens[$i]); - $next = isset($tokens[$i+1]) ? get_class($tokens[$i+1]) : false; - if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") || - ($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") || - ($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken")) - { - $tokens[$i]->IsLast = true; - } - } - return 0; - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} will remove any empty rulesets (including @keyframes at-rule block - * rulesets). - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRemoveEmptyRulesetsMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - $current = get_class($tokens[$i]); - $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; - if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") || - ($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) - ) - { - $tokens[$i] = null; - $tokens[$i + 1] = null; - $i++; - $r = $r + 2; - } - } - return $r; - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} will remove any empty @font-face, @keyframes, @media and @page - * at-rule blocks. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRemoveEmptyAtBlocksMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - $current = get_class($tokens[$i]); - $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; - if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") || - ($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") || - ($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") || - ($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken")) - { - $tokens[$i] = null; - $tokens[$i + 1] = null; - $i++; - $r = $r + 2; - } - } - return $r; - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} will remove any comments from the array of parsed tokens. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssRemoveCommentsMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - if (get_class($tokens[$i]) === "CssCommentToken") - { - $tokens[$i] = null; - $r++; - } - } - return $r; - } - } - -/** - * CSS Parser. - * - * @package CssMin/Parser - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssParser - { - /** - * Parse buffer. - * - * @var string - */ - private $buffer = ""; - /** - * {@link aCssParserPlugin Plugins}. - * - * @var array - */ - private $plugins = array(); - /** - * Source to parse. - * - * @var string - */ - private $source = ""; - /** - * Current state. - * - * @var integer - */ - private $state = "T_DOCUMENT"; - /** - * Exclusive state. - * - * @var string - */ - private $stateExclusive = false; - /** - * Media types state. - * - * @var mixed - */ - private $stateMediaTypes = false; - /** - * State stack. - * - * @var array - */ - private $states = array("T_DOCUMENT"); - /** - * Parsed tokens. - * - * @var array - */ - private $tokens = array(); - /** - * Constructer. - * - * Create instances of the used {@link aCssParserPlugin plugins}. - * - * @param string $source CSS source [optional] - * @param array $plugins Plugin configuration [optional] - * @return void - */ - public function __construct($source = null, array $plugins = null) - { - $plugins = array_merge(array - ( - "Comment" => true, - "String" => true, - "Url" => true, - "Expression" => true, - "Ruleset" => true, - "AtCharset" => true, - "AtFontFace" => true, - "AtImport" => true, - "AtKeyframes" => true, - "AtMedia" => true, - "AtPage" => true, - "AtVariables" => true - ), is_array($plugins) ? $plugins : array()); - // Create plugin instances - foreach ($plugins as $name => $config) - { - if ($config !== false) - { - $class = "Css" . $name . "ParserPlugin"; - $config = is_array($config) ? $config : array(); - if (class_exists($class)) - { - $this->plugins[] = new $class($this, $config); - } - else - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); - } - } - } - if (!is_null($source)) - { - $this->parse($source); - } - } - /** - * Append a token to the array of tokens. - * - * @param aCssToken $token Token to append - * @return void - */ - public function appendToken(aCssToken $token) - { - $this->tokens[] = $token; - } - /** - * Clears the current buffer. - * - * @return void - */ - public function clearBuffer() - { - $this->buffer = ""; - } - /** - * Returns and clear the current buffer. - * - * @param string $trim Chars to use to trim the returned buffer - * @param boolean $tolower if TRUE the returned buffer will get converted to lower case - * @return string - */ - public function getAndClearBuffer($trim = "", $tolower = false) - { - $r = $this->getBuffer($trim, $tolower); - $this->buffer = ""; - return $r; - } - /** - * Returns the current buffer. - * - * @param string $trim Chars to use to trim the returned buffer - * @param boolean $tolower if TRUE the returned buffer will get converted to lower case - * @return string - */ - public function getBuffer($trim = "", $tolower = false) - { - $r = $this->buffer; - if ($trim) - { - $r = trim($r, " \t\n\r\0\x0B" . $trim); - } - if ($tolower) - { - $r = strtolower($r); - } - return $r; - } - /** - * Returns the current media types state. - * - * @return array - */ - public function getMediaTypes() - { - return $this->stateMediaTypes; - } - /** - * Returns the CSS source. - * - * @return string - */ - public function getSource() - { - return $this->source; - } - /** - * Returns the current state. - * - * @return integer The current state - */ - public function getState() - { - return $this->state; - } - /** - * Returns a plugin by class name. - * - * @param string $name Class name of the plugin - * @return aCssParserPlugin - */ - public function getPlugin($class) - { - static $index = null; - if (is_null($index)) - { - $index = array(); - for ($i = 0, $l = count($this->plugins); $i < $l; $i++) - { - $index[get_class($this->plugins[$i])] = $i; - } - } - return isset($index[$class]) ? $this->plugins[$index[$class]] : false; - } - /** - * Returns the parsed tokens. - * - * @return array - */ - public function getTokens() - { - return $this->tokens; - } - /** - * Returns if the current state equals the passed state. - * - * @param integer $state State to compare with the current state - * @return boolean TRUE is the state equals to the passed state; FALSE if not - */ - public function isState($state) - { - return ($this->state == $state); - } - /** - * Parse the CSS source and return a array with parsed tokens. - * - * @param string $source CSS source - * @return array Array with tokens - */ - public function parse($source) - { - // Reset - $this->source = ""; - $this->tokens = array(); - // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create - // several helper variables for plugin handling - $globalTriggerChars = ""; - $plugins = $this->plugins; - $pluginCount = count($plugins); - $pluginIndex = array(); - $pluginTriggerStates = array(); - $pluginTriggerChars = array(); - for ($i = 0, $l = count($plugins); $i < $l; $i++) - { - $tPluginClassName = get_class($plugins[$i]); - $pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars()); - $tPluginTriggerStates = $plugins[$i]->getTriggerStates(); - $pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|" . implode("|", $tPluginTriggerStates) . "|"; - $pluginIndex[$tPluginClassName] = $i; - for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++) - { - $c = substr($pluginTriggerChars[$i], $ii, 1); - if (strpos($globalTriggerChars, $c) === false) - { - $globalTriggerChars .= $c; - } - } - } - // Normalise line endings - $source = str_replace("\r\n", "\n", $source); // Windows to Unix line endings - $source = str_replace("\r", "\n", $source); // Mac to Unix line endings - $this->source = $source; - // Variables - $buffer = &$this->buffer; - $exclusive = &$this->stateExclusive; - $state = &$this->state; - $c = $p = null; - // -- - for ($i = 0, $l = strlen($source); $i < $l; $i++) - { - // Set the current Char - $c = $source[$i]; // Is faster than: $c = substr($source, $i, 1); - // Normalize and filter double whitespace characters - if ($exclusive === false) - { - if ($c === "\n" || $c === "\t") - { - $c = " "; - } - if ($c === " " && $p === " ") - { - continue; - } - } - $buffer .= $c; - // Extended processing only if the current char is a global trigger char - if (strpos($globalTriggerChars, $c) !== false) - { - // Exclusive state is set; process with the exclusive plugin - if ($exclusive) - { - $tPluginIndex = $pluginIndex[$exclusive]; - if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false)) - { - $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state); - // Return value is TRUE => continue with next char - if ($r === true) - { - continue; - } - // Return value is numeric => set new index and continue with next char - elseif ($r !== false && $r != $i) - { - $i = $r; - continue; - } - } - } - // Else iterate through the plugins - else - { - $triggerState = "|" . $state . "|"; - for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++) - { - // Only process if the current char is one of the plugin trigger chars - if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false)) - { - // Process with the plugin - $r = $plugins[$ii]->parse($i, $c, $p, $state); - // Return value is TRUE => break the plugin loop and and continue with next char - if ($r === true) - { - break; - } - // Return value is numeric => set new index, break the plugin loop and and continue with next char - elseif ($r !== false && $r != $i) - { - $i = $r; - break; - } - } - } - } - } - $p = $c; // Set the parent char - } - return $this->tokens; - } - /** - * Remove the last state of the state stack and return the removed stack value. - * - * @return integer Removed state value - */ - public function popState() - { - $r = array_pop($this->states); - $this->state = $this->states[count($this->states) - 1]; - return $r; - } - /** - * Adds a new state onto the state stack. - * - * @param integer $state State to add onto the state stack. - * @return integer The index of the added state in the state stacks - */ - public function pushState($state) - { - $r = array_push($this->states, $state); - $this->state = $this->states[count($this->states) - 1]; - return $r; - } - /** - * Sets/restores the buffer. - * - * @param string $buffer Buffer to set - * @return void - */ - public function setBuffer($buffer) - { - $this->buffer = $buffer; - } - /** - * Set the exclusive state. - * - * @param string $exclusive Exclusive state - * @return void - */ - public function setExclusive($exclusive) - { - $this->stateExclusive = $exclusive; - } - /** - * Set the media types state. - * - * @param array $mediaTypes Media types state - * @return void - */ - public function setMediaTypes(array $mediaTypes) - { - $this->stateMediaTypes = $mediaTypes; - } - /** - * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}. - * - * @param integer $state State to set - * @return integer - */ - public function setState($state) - { - $r = array_pop($this->states); - array_push($this->states, $state); - $this->state = $this->states[count($this->states) - 1]; - return $r; - } - /** - * Removes the exclusive state. - * - * @return void - */ - public function unsetExclusive() - { - $this->stateExclusive = false; - } - /** - * Removes the media types state. - * - * @return void - */ - public function unsetMediaTypes() - { - $this->stateMediaTypes = false; - } - } - -/** - * {@link aCssFromatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style). - * - * @package CssMin/Formatter - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssOtbsFormatter extends aCssFormatter - { - /** - * Implements {@link aCssFormatter::__toString()}. - * - * @return string - */ - public function __toString() - { - $r = array(); - $level = 0; - for ($i = 0, $l = count($this->tokens); $i < $l; $i++) - { - $token = $this->tokens[$i]; - $class = get_class($token); - $indent = str_repeat($this->indent, $level); - if ($class === "CssCommentToken") - { - $lines = array_map("trim", explode("\n", $token->Comment)); - for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) - { - $r[] = $indent . (substr($lines[$ii], 0, 1) == "*" ? " " : "") . $lines[$ii]; - } - } - elseif ($class === "CssAtCharsetToken") - { - $r[] = $indent . "@charset " . $token->Charset . ";"; - } - elseif ($class === "CssAtFontFaceStartToken") - { - $r[] = $indent . "@font-face {"; - $level++; - } - elseif ($class === "CssAtImportToken") - { - $r[] = $indent . "@import " . $token->Import . " " . implode(", ", $token->MediaTypes) . ";"; - } - elseif ($class === "CssAtKeyframesStartToken") - { - $r[] = $indent . "@keyframes \"" . $token->Name . "\" {"; - $level++; - } - elseif ($class === "CssAtMediaStartToken") - { - $r[] = $indent . "@media " . implode(", ", $token->MediaTypes) . " {"; - $level++; - } - elseif ($class === "CssAtPageStartToken") - { - $r[] = $indent . "@page {"; - $level++; - } - elseif ($class === "CssAtVariablesStartToken") - { - $r[] = $indent . "@variables " . implode(", ", $token->MediaTypes) . " {"; - $level++; - } - elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") - { - $r[] = $indent . implode(", ", $token->Selectors) . " {"; - $level++; - } - elseif ($class == "CssAtFontFaceDeclarationToken" - || $class === "CssAtKeyframesRulesetDeclarationToken" - || $class === "CssAtPageDeclarationToken" - || $class == "CssAtVariablesDeclarationToken" - || $class === "CssRulesetDeclarationToken" - ) - { - $declaration = $indent . $token->Property . ": "; - if ($this->padding) - { - $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); - } - $r[] = $declaration . $token->Value . ($token->IsImportant ? " !important" : "") . ";"; - } - elseif ($class === "CssAtFontFaceEndToken" - || $class === "CssAtMediaEndToken" - || $class === "CssAtKeyframesEndToken" - || $class === "CssAtKeyframesRulesetEndToken" - || $class === "CssAtPageEndToken" - || $class === "CssAtVariablesEndToken" - || $class === "CssRulesetEndToken" - ) - { - $level--; - $r[] = str_repeat($indent, $level) . "}"; - } - } - return implode("\n", $r); - } - } - -/** - * This {@link aCssToken CSS token} is a utility token that extends {@link aNullToken} and returns only a empty string. * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 */ -class CssNullToken extends aCssToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return ""; - } - } - -/** - * CSS Minifier. - * - * @package CssMin/Minifier - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssMinifier - { - /** - * {@link aCssMinifierFilter Filters}. - * - * @var array - */ - private $filters = array(); - /** - * {@link aCssMinifierPlugin Plugins}. - * - * @var array - */ - private $plugins = array(); - /** - * Minified source. - * - * @var string - */ - private $minified = ""; - /** - * Constructer. - * - * Creates instances of {@link aCssMinifierFilter filters} and {@link aCssMinifierPlugin plugins}. - * - * @param string $source CSS source [optional] - * @param array $filters Filter configuration [optional] - * @param array $plugins Plugin configuration [optional] - * @return void - */ - public function __construct($source = null, array $filters = null, array $plugins = null) - { - $filters = array_merge(array - ( - "ImportImports" => false, - "RemoveComments" => true, - "RemoveEmptyRulesets" => true, - "RemoveEmptyAtBlocks" => true, - "ConvertLevel3Properties" => false, - "ConvertLevel3AtKeyframes" => false, - "Variables" => true, - "RemoveLastDelarationSemiColon" => true - ), is_array($filters) ? $filters : array()); - $plugins = array_merge(array - ( - "Variables" => true, - "ConvertFontWeight" => false, - "ConvertHslColors" => false, - "ConvertRgbColors" => false, - "ConvertNamedColors" => false, - "CompressColorValues" => false, - "CompressUnitValues" => false, - "CompressExpressionValues" => false - ), is_array($plugins) ? $plugins : array()); - // Filters - foreach ($filters as $name => $config) - { - if ($config !== false) - { - $class = "Css" . $name . "MinifierFilter"; - $config = is_array($config) ? $config : array(); - if (class_exists($class)) - { - $this->filters[] = new $class($this, $config); - } - else - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The filter " . $name . " with the class name " . $class . " was not found")); - } - } - } - // Plugins - foreach ($plugins as $name => $config) - { - if ($config !== false) - { - $class = "Css" . $name . "MinifierPlugin"; - $config = is_array($config) ? $config : array(); - if (class_exists($class)) - { - $this->plugins[] = new $class($this, $config); - } - else - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": The plugin " . $name . " with the class name " . $class . " was not found")); - } - } - } - // -- - if (!is_null($source)) - { - $this->minify($source); - } - } - /** - * Returns the minified Source. - * - * @return string - */ - public function getMinified() - { - return $this->minified; - } - /** - * Returns a plugin by class name. - * - * @param string $name Class name of the plugin - * @return aCssMinifierPlugin - */ - public function getPlugin($class) - { - static $index = null; - if (is_null($index)) - { - $index = array(); - for ($i = 0, $l = count($this->plugins); $i < $l; $i++) - { - $index[get_class($this->plugins[$i])] = $i; - } - } - return isset($index[$class]) ? $this->plugins[$index[$class]] : false; - } - /** - * Minifies the CSS source. - * - * @param string $source CSS source - * @return string - */ - public function minify($source) - { - // Variables - $r = ""; - $parser = new CssParser($source); - $tokens = $parser->getTokens(); - $filters = $this->filters; - $filterCount = count($this->filters); - $plugins = $this->plugins; - $pluginCount = count($plugins); - $pluginIndex = array(); - $pluginTriggerTokens = array(); - $globalTriggerTokens = array(); - for ($i = 0, $l = count($plugins); $i < $l; $i++) - { - $tPluginClassName = get_class($plugins[$i]); - $pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens(); - foreach ($pluginTriggerTokens[$i] as $v) - { - if (!in_array($v, $globalTriggerTokens)) - { - $globalTriggerTokens[] = $v; - } - } - $pluginTriggerTokens[$i] = "|" . implode("|", $pluginTriggerTokens[$i]) . "|"; - $pluginIndex[$tPluginClassName] = $i; - } - $globalTriggerTokens = "|" . implode("|", $globalTriggerTokens) . "|"; - /* - * Apply filters - */ - for($i = 0; $i < $filterCount; $i++) - { - // Apply the filter; if the return value is larger than 0... - if ($filters[$i]->apply($tokens) > 0) - { - // ...then filter null values and rebuild the token array - $tokens = array_values(array_filter($tokens)); - } - } - $tokenCount = count($tokens); - /* - * Apply plugins - */ - for($i = 0; $i < $tokenCount; $i++) - { - $triggerToken = "|" . get_class($tokens[$i]) . "|"; - if (strpos($globalTriggerTokens, $triggerToken) !== false) - { - for($ii = 0; $ii < $pluginCount; $ii++) - { - if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false) - { - // Apply the plugin; if the return value is TRUE continue to the next token - if ($plugins[$ii]->apply($tokens[$i]) === true) - { - continue 2; - } - } - } - } - } - // Stringify the tokens - for($i = 0; $i < $tokenCount; $i++) - { - $r .= (string) $tokens[$i]; - } - $this->minified = $r; - return $r; - } - } /** * CssMin - A (simple) css minifier with benefits - * + * * -- * Copyright (c) 2011 Joe Scylla * @@ -2140,10 +46,10 @@ public function minify($source) * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: - * + * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE @@ -2152,2932 +58,107 @@ public function minify($source) * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * -- - * - * @package CssMin - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssMin - { - /** - * Index of classes - * - * @var array - */ - private static $classIndex = array(); - /** - * Parse/minify errors - * - * @var array - */ - private static $errors = array(); - /** - * Verbose output. - * - * @var boolean - */ - private static $isVerbose = false; - /** - * {@link http://goo.gl/JrW54 Autoload} function of CssMin. - * - * @param string $class Name of the class - * @return void - */ - public static function autoload($class) - { - if (isset(self::$classIndex[$class])) - { - require(self::$classIndex[$class]); - } - } - /** - * Return errors - * - * @return array of {CssError}. - */ - public static function getErrors() - { - return self::$errors; - } - /** - * Returns if there were errors. - * - * @return boolean - */ - public static function hasErrors() - { - return count(self::$errors) > 0; - } - /** - * Initialises CssMin. - * - * @return void - */ - public static function initialise() - { - // Create the class index for autoloading or including - $paths = array(dirname(__FILE__)); - while (list($i, $path) = each($paths)) - { - $subDirectorys = glob($path . "*", GLOB_MARK | GLOB_ONLYDIR | GLOB_NOSORT); - if (is_array($subDirectorys)) - { - foreach ($subDirectorys as $subDirectory) - { - $paths[] = $subDirectory; - } - } - $files = glob($path . "*.php", 0); - if (is_array($files)) - { - foreach ($files as $file) - { - $class = substr(basename($file), 0, -4); - self::$classIndex[$class] = $file; - } - } - } - krsort(self::$classIndex); - // Only use autoloading if spl_autoload_register() is available and no __autoload() is defined (because - // __autoload() breaks if spl_autoload_register() is used. - if (function_exists("spl_autoload_register") && !is_callable("__autoload")) - { - spl_autoload_register(array(__CLASS__, "autoload")); - } - // Otherwise include all class files - else - { - foreach (self::$classIndex as $class => $file) - { - if (!class_exists($class)) - { - require_once($file); - } - } - } - } - /** - * Minifies CSS source. - * - * @param string $source CSS source - * @param array $filters Filter configuration [optional] - * @param array $plugins Plugin configuration [optional] - * @return string Minified CSS - */ - public static function minify($source, array $filters = null, array $plugins = null) - { - self::$errors = array(); - $minifier = new CssMinifier($source, $filters, $plugins); - return $minifier->getMinified(); - } - /** - * Parse the CSS source. - * - * @param string $source CSS source - * @param array $plugins Plugin configuration [optional] - * @return array Array of aCssToken - */ - public static function parse($source, array $plugins = null) - { - self::$errors = array(); - $parser = new CssParser($source, $plugins); - return $parser->getTokens(); - } - /** - * -- - * - * @param boolean $to - * @return boolean - */ - public static function setVerbose($to) - { - self::$isVerbose = (boolean) $to; - return self::$isVerbose; - } - /** - * -- - * - * @param CssError $error - * @return void - */ - public static function triggerError(CssError $error) - { - self::$errors[] = $error; - if (self::$isVerbose) - { - trigger_error((string) $error, E_USER_WARNING); - } - } - } -// Initialises CssMin -CssMin::initialise(); - -/** - * This {@link aCssMinifierFilter minifier filter} import external css files defined with the @import at-rule into the - * current stylesheet. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssImportImportsMinifierFilter extends aCssMinifierFilter - { - /** - * Array with already imported external stylesheets. - * - * @var array - */ - private $imported = array(); - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"])) - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Base path " . ($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null"). " is not a directory")); - return 0; - } - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - if (get_class($tokens[$i]) === "CssAtImportToken") - { - $import = $this->configuration["BasePath"] . "/" . $tokens[$i]->Import; - // Import file was not found/is not a file - if (!is_file($import)) - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import. " was not found.", (string) $tokens[$i])); - } - // Import file already imported; remove this @import at-rule to prevent recursions - elseif (in_array($import, $this->imported)) - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Import file " . $import. " was already imported.", (string) $tokens[$i])); - $tokens[$i] = null; - } - else - { - $this->imported[] = $import; - $parser = new CssParser(file_get_contents($import)); - $import = $parser->getTokens(); - // The @import at-rule has media types defined requiring special handling - if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all")) - { - $blocks = array(); - /* - * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - if (get_class($import[$ii]) === "CssAtImportToken") - { - // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule - if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all")) - { - $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes; - } - // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule - elseif (count($import[$ii]->MediaTypes > 0)) - { - foreach ($import[$ii]->MediaTypes as $index => $mediaType) - { - if (!in_array($mediaType, $tokens[$i]->MediaTypes)) - { - unset($import[$ii]->MediaTypes[$index]); - } - } - $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); - // If there are no media types left in the @import at-rule remove the @import at-rule - if (count($import[$ii]->MediaTypes) == 0) - { - $import[$ii] = null; - } - } - } - } - /* - * Remove media types of @media at-rule block not defined in the @import at-rule - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - if (get_class($import[$ii]) === "CssAtMediaStartToken") - { - foreach ($import[$ii]->MediaTypes as $index => $mediaType) - { - if (!in_array($mediaType, $tokens[$i]->MediaTypes)) - { - unset($import[$ii]->MediaTypes[$index]); - } - $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); - } - } - } - /* - * If no media types left of the @media at-rule block remove the complete block - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - if (get_class($import[$ii]) === "CssAtMediaStartToken") - { - if (count($import[$ii]->MediaTypes) === 0) - { - for ($iii = $ii; $iii < $ll; $iii++) - { - if (get_class($import[$iii]) === "CssAtMediaEndToken") - { - break; - } - } - if (get_class($import[$iii]) === "CssAtMediaEndToken") - { - array_splice($import, $ii, $iii - $ii + 1, array()); - $ll = count($import); - } - } - } - } - /* - * If the media types of the @media at-rule equals the media types defined in the @import - * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0) - { - for ($iii = $ii; $iii < $ll; $iii++) - { - if (get_class($import[$iii]) == "CssAtMediaEndToken") - { - break; - } - } - if (get_class($import[$iii]) == "CssAtMediaEndToken") - { - unset($import[$ii]); - unset($import[$iii]); - $import = array_values($import); - $ll = count($import); - } - } - } - /** - * Extract CssAtImportToken and CssAtCharsetToken tokens - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - $class = get_class($import[$ii]); - if ($class === "CssAtImportToken" || $class === "CssAtCharsetToken") - { - $blocks = array_merge($blocks, array_splice($import, $ii, 1, array())); - $ll = count($import); - } - } - /* - * Extract the @font-face, @media and @page at-rule block - */ - for($ii = 0, $ll = count($import); $ii < $ll; $ii++) - { - $class = get_class($import[$ii]); - if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken") - { - for ($iii = $ii; $iii < $ll; $iii++) - { - $class = get_class($import[$iii]); - if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken") - { - break; - } - } - $class = get_class($import[$iii]); - if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")) - { - $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array())); - $ll = count($import); - } - } - } - // Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block - $import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken())); - } - // Insert the imported tokens - array_splice($tokens, $i, 1, $import); - // Modify parameters of the for-loop - $i--; - $l = count($tokens); - } - } - } - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for preserve parsing expression() declaration values. - * - * This plugin return no {@link aCssToken CssToken} but ensures that expression() declaration values will get parsed - * properly. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssExpressionParserPlugin extends aCssParserPlugin - { - /** - * Count of left braces. - * - * @var integer - */ - private $leftBraces = 0; - /** - * Count of right braces. - * - * @var integer - */ - private $rightBraces = 0; - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("(", ")", ";", "}"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return false; - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of expression - if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION") - { - $this->parser->pushState("T_EXPRESSION"); - $this->leftBraces++; - } - // Count left braces - elseif ($char === "(" && $state === "T_EXPRESSION") - { - $this->leftBraces++; - } - // Count right braces - elseif ($char === ")" && $state === "T_EXPRESSION") - { - $this->rightBraces++; - } - // Possible end of expression; if left and right braces are equal the expressen ends - elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces) - { - $this->leftBraces = $this->rightBraces = 0; - $this->parser->popState(); - return $index - 1; - } - else - { - return false; - } - return true; - } - } - -/** - * CSS Error. - * - * @package CssMin - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssError - { - /** - * File. - * - * @var string - */ - public $File = ""; - /** - * Line. - * - * @var integer - */ - public $Line = 0; - /** - * Error message. - * - * @var string - */ - public $Message = ""; - /** - * Source. - * - * @var string - */ - public $Source = ""; - /** - * Constructor triggering the error. - * - * @param string $message Error message - * @param string $source Corresponding line [optional] - * @return void - */ - public function __construct($file, $line, $message, $source = "") - { - $this->File = $file; - $this->Line = $line; - $this->Message = $message; - $this->Source = $source; - } - /** - * Returns the error as formatted string. - * - * @return string - */ - public function __toString() - { - return $this->Message . ($this->Source ? ":
" . $this->Source . "": "") . "
in file " . $this->File . " at line " . $this->Line; - } - } - -/** - * This {@link aCssMinifierPlugin} will convert a color value in rgb notation to hexadecimal notation. - * - * Example: - * - * color: rgb(200,60%,5); - * - * - * Will get converted to: - * - * color:#c89905; - * * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 + * @package CssMin + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 */ -class CssConvertRgbColorsMinifierPlugin extends aCssMinifierPlugin - { - /** - * Regular expression matching the value. - * - * @var string - */ - private $reMatch = "/rgb\s*\(\s*([0-9%]+)\s*,\s*([0-9%]+)\s*,\s*([0-9%]+)\s*\)/iS"; - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (stripos($token->Value, "rgb") !== false && preg_match($this->reMatch, $token->Value, $m)) - { - for ($i = 1, $l = count($m); $i < $l; $i++) - { - if (strpos("%", $m[$i]) !== false) - { - $m[$i] = substr($m[$i], 0, -1); - $m[$i] = (int) (256 * ($m[$i] / 100)); - } - $m[$i] = str_pad(dechex($m[$i]), 2, "0", STR_PAD_LEFT); - } - $token->Value = str_replace($m[0], "#" . $m[1] . $m[2] . $m[3], $token->Value); - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssMinifierPlugin} will convert named color values to hexadecimal notation. - * - * Example: - * - * color: black; - * border: 1px solid indigo; - * - * - * Will get converted to: - * - * color:#000; - * border:1px solid #4b0082; - * - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssConvertNamedColorsMinifierPlugin extends aCssMinifierPlugin - { - - /** - * Regular expression matching the value. - * - * @var string - */ - private $reMatch = null; - /** - * Regular expression replacing the value. - * - * @var string - */ - private $reReplace = "\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\""; - /** - * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}. - * - * @var array - */ - private $transformation = array - ( - "aliceblue" => "#f0f8ff", - "antiquewhite" => "#faebd7", - "aqua" => "#0ff", - "aquamarine" => "#7fffd4", - "azure" => "#f0ffff", - "beige" => "#f5f5dc", - "black" => "#000", - "blue" => "#00f", - "blueviolet" => "#8a2be2", - "brown" => "#a52a2a", - "burlywood" => "#deb887", - "cadetblue" => "#5f9ea0", - "chartreuse" => "#7fff00", - "chocolate" => "#d2691e", - "coral" => "#ff7f50", - "cornflowerblue" => "#6495ed", - "cornsilk" => "#fff8dc", - "crimson" => "#dc143c", - "darkblue" => "#00008b", - "darkcyan" => "#008b8b", - "darkgoldenrod" => "#b8860b", - "darkgray" => "#a9a9a9", - "darkgreen" => "#006400", - "darkkhaki" => "#bdb76b", - "darkmagenta" => "#8b008b", - "darkolivegreen" => "#556b2f", - "darkorange" => "#ff8c00", - "darkorchid" => "#9932cc", - "darkred" => "#8b0000", - "darksalmon" => "#e9967a", - "darkseagreen" => "#8fbc8f", - "darkslateblue" => "#483d8b", - "darkslategray" => "#2f4f4f", - "darkturquoise" => "#00ced1", - "darkviolet" => "#9400d3", - "deeppink" => "#ff1493", - "deepskyblue" => "#00bfff", - "dimgray" => "#696969", - "dodgerblue" => "#1e90ff", - "firebrick" => "#b22222", - "floralwhite" => "#fffaf0", - "forestgreen" => "#228b22", - "fuchsia" => "#f0f", - "gainsboro" => "#dcdcdc", - "ghostwhite" => "#f8f8ff", - "gold" => "#ffd700", - "goldenrod" => "#daa520", - "gray" => "#808080", - "green" => "#008000", - "greenyellow" => "#adff2f", - "honeydew" => "#f0fff0", - "hotpink" => "#ff69b4", - "indianred" => "#cd5c5c", - "indigo" => "#4b0082", - "ivory" => "#fffff0", - "khaki" => "#f0e68c", - "lavender" => "#e6e6fa", - "lavenderblush" => "#fff0f5", - "lawngreen" => "#7cfc00", - "lemonchiffon" => "#fffacd", - "lightblue" => "#add8e6", - "lightcoral" => "#f08080", - "lightcyan" => "#e0ffff", - "lightgoldenrodyellow" => "#fafad2", - "lightgreen" => "#90ee90", - "lightgrey" => "#d3d3d3", - "lightpink" => "#ffb6c1", - "lightsalmon" => "#ffa07a", - "lightseagreen" => "#20b2aa", - "lightskyblue" => "#87cefa", - "lightslategray" => "#789", - "lightsteelblue" => "#b0c4de", - "lightyellow" => "#ffffe0", - "lime" => "#0f0", - "limegreen" => "#32cd32", - "linen" => "#faf0e6", - "maroon" => "#800000", - "mediumaquamarine" => "#66cdaa", - "mediumblue" => "#0000cd", - "mediumorchid" => "#ba55d3", - "mediumpurple" => "#9370db", - "mediumseagreen" => "#3cb371", - "mediumslateblue" => "#7b68ee", - "mediumspringgreen" => "#00fa9a", - "mediumturquoise" => "#48d1cc", - "mediumvioletred" => "#c71585", - "midnightblue" => "#191970", - "mintcream" => "#f5fffa", - "mistyrose" => "#ffe4e1", - "moccasin" => "#ffe4b5", - "navajowhite" => "#ffdead", - "navy" => "#000080", - "oldlace" => "#fdf5e6", - "olive" => "#808000", - "olivedrab" => "#6b8e23", - "orange" => "#ffa500", - "orangered" => "#ff4500", - "orchid" => "#da70d6", - "palegoldenrod" => "#eee8aa", - "palegreen" => "#98fb98", - "paleturquoise" => "#afeeee", - "palevioletred" => "#db7093", - "papayawhip" => "#ffefd5", - "peachpuff" => "#ffdab9", - "peru" => "#cd853f", - "pink" => "#ffc0cb", - "plum" => "#dda0dd", - "powderblue" => "#b0e0e6", - "purple" => "#800080", - "red" => "#f00", - "rosybrown" => "#bc8f8f", - "royalblue" => "#4169e1", - "saddlebrown" => "#8b4513", - "salmon" => "#fa8072", - "sandybrown" => "#f4a460", - "seagreen" => "#2e8b57", - "seashell" => "#fff5ee", - "sienna" => "#a0522d", - "silver" => "#c0c0c0", - "skyblue" => "#87ceeb", - "slateblue" => "#6a5acd", - "slategray" => "#708090", - "snow" => "#fffafa", - "springgreen" => "#00ff7f", - "steelblue" => "#4682b4", - "tan" => "#d2b48c", - "teal" => "#008080", - "thistle" => "#d8bfd8", - "tomato" => "#ff6347", - "turquoise" => "#40e0d0", - "violet" => "#ee82ee", - "wheat" => "#f5deb3", - "white" => "#fff", - "whitesmoke" => "#f5f5f5", - "yellow" => "#ff0", - "yellowgreen" => "#9acd32" - ); - /** - * Overwrites {@link aCssMinifierPlugin::__construct()}. - * - * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression} - * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}. - * - * @param CssMinifier $minifier The CssMinifier object of this plugin. - * @param array $configuration Plugin configuration [optional] - * @return void - */ - public function __construct(CssMinifier $minifier, array $configuration = array()) - { - $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)) . ")(\s|$)+/eiS"; - parent::__construct($minifier, $configuration); - } - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - $lcValue = strtolower($token->Value); - // Declaration value equals a value in the transformation table => simple replace - if (isset($this->transformation[$lcValue])) - { - $token->Value = $this->transformation[$lcValue]; - } - // Declaration value contains a value in the transformation table => regular expression replace - elseif (preg_match($this->reMatch, $token->Value)) - { - $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} triggers on CSS Level 3 properties and will add declaration tokens - * with browser-specific properties. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssConvertLevel3PropertiesMinifierFilter extends aCssMinifierFilter - { - /** - * Css property transformations table. Used to convert CSS3 and proprietary properties to the browser-specific - * counterparts. - * - * @var array - */ - private $transformations = array - ( - // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored - "animation" => array(null, "-webkit-animation", null, null), - "animation-delay" => array(null, "-webkit-animation-delay", null, null), - "animation-direction" => array(null, "-webkit-animation-direction", null, null), - "animation-duration" => array(null, "-webkit-animation-duration", null, null), - "animation-fill-mode" => array(null, "-webkit-animation-fill-mode", null, null), - "animation-iteration-count" => array(null, "-webkit-animation-iteration-count", null, null), - "animation-name" => array(null, "-webkit-animation-name", null, null), - "animation-play-state" => array(null, "-webkit-animation-play-state", null, null), - "animation-timing-function" => array(null, "-webkit-animation-timing-function", null, null), - "appearance" => array("-moz-appearance", "-webkit-appearance", null, null), - "backface-visibility" => array(null, "-webkit-backface-visibility", null, null), - "background-clip" => array(null, "-webkit-background-clip", null, null), - "background-composite" => array(null, "-webkit-background-composite", null, null), - "background-inline-policy" => array("-moz-background-inline-policy", null, null, null), - "background-origin" => array(null, "-webkit-background-origin", null, null), - "background-position-x" => array(null, null, null, "-ms-background-position-x"), - "background-position-y" => array(null, null, null, "-ms-background-position-y"), - "background-size" => array(null, "-webkit-background-size", null, null), - "behavior" => array(null, null, null, "-ms-behavior"), - "binding" => array("-moz-binding", null, null, null), - "border-after" => array(null, "-webkit-border-after", null, null), - "border-after-color" => array(null, "-webkit-border-after-color", null, null), - "border-after-style" => array(null, "-webkit-border-after-style", null, null), - "border-after-width" => array(null, "-webkit-border-after-width", null, null), - "border-before" => array(null, "-webkit-border-before", null, null), - "border-before-color" => array(null, "-webkit-border-before-color", null, null), - "border-before-style" => array(null, "-webkit-border-before-style", null, null), - "border-before-width" => array(null, "-webkit-border-before-width", null, null), - "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null), - "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null), - "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null), - "border-end" => array("-moz-border-end", "-webkit-border-end", null, null), - "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null), - "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null), - "border-end-width" => array("-moz-border-end-width", "-webkit-border-end-width", null, null), - "border-fit" => array(null, "-webkit-border-fit", null, null), - "border-horizontal-spacing" => array(null, "-webkit-border-horizontal-spacing", null, null), - "border-image" => array("-moz-border-image", "-webkit-border-image", null, null), - "border-left-colors" => array("-moz-border-left-colors", null, null, null), - "border-radius" => array("-moz-border-radius", "-webkit-border-radius", null, null), - "border-border-right-colors" => array("-moz-border-right-colors", null, null, null), - "border-start" => array("-moz-border-start", "-webkit-border-start", null, null), - "border-start-color" => array("-moz-border-start-color", "-webkit-border-start-color", null, null), - "border-start-style" => array("-moz-border-start-style", "-webkit-border-start-style", null, null), - "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null), - "border-top-colors" => array("-moz-border-top-colors", null, null, null), - "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null), - "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null), - "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null), - "box-align" => array("-moz-box-align", "-webkit-box-align", null, null), - "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null), - "box-flex" => array("-moz-box-flex", "-webkit-box-flex", null, null), - "box-flex-group" => array(null, "-webkit-box-flex-group", null, null), - "box-flex-lines" => array(null, "-webkit-box-flex-lines", null, null), - "box-ordinal-group" => array("-moz-box-ordinal-group", "-webkit-box-ordinal-group", null, null), - "box-orient" => array("-moz-box-orient", "-webkit-box-orient", null, null), - "box-pack" => array("-moz-box-pack", "-webkit-box-pack", null, null), - "box-reflect" => array(null, "-webkit-box-reflect", null, null), - "box-shadow" => array("-moz-box-shadow", "-webkit-box-shadow", null, null), - "box-sizing" => array("-moz-box-sizing", null, null, null), - "color-correction" => array(null, "-webkit-color-correction", null, null), - "column-break-after" => array(null, "-webkit-column-break-after", null, null), - "column-break-before" => array(null, "-webkit-column-break-before", null, null), - "column-break-inside" => array(null, "-webkit-column-break-inside", null, null), - "column-count" => array("-moz-column-count", "-webkit-column-count", null, null), - "column-gap" => array("-moz-column-gap", "-webkit-column-gap", null, null), - "column-rule" => array("-moz-column-rule", "-webkit-column-rule", null, null), - "column-rule-color" => array("-moz-column-rule-color", "-webkit-column-rule-color", null, null), - "column-rule-style" => array("-moz-column-rule-style", "-webkit-column-rule-style", null, null), - "column-rule-width" => array("-moz-column-rule-width", "-webkit-column-rule-width", null, null), - "column-span" => array(null, "-webkit-column-span", null, null), - "column-width" => array("-moz-column-width", "-webkit-column-width", null, null), - "columns" => array(null, "-webkit-columns", null, null), - "filter" => array(__CLASS__, "filter"), - "float-edge" => array("-moz-float-edge", null, null, null), - "font-feature-settings" => array("-moz-font-feature-settings", null, null, null), - "font-language-override" => array("-moz-font-language-override", null, null, null), - "font-size-delta" => array(null, "-webkit-font-size-delta", null, null), - "font-smoothing" => array(null, "-webkit-font-smoothing", null, null), - "force-broken-image-icon" => array("-moz-force-broken-image-icon", null, null, null), - "highlight" => array(null, "-webkit-highlight", null, null), - "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null), - "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null), - "hyphens" => array(null, "-webkit-hyphens", null, null), - "force-broken-image-icon" => array("-moz-image-region", null, null, null), - "ime-mode" => array(null, null, null, "-ms-ime-mode"), - "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"), - "layout-flow" => array(null, null, null, "-ms-layout-flow"), - "layout-grid" => array(null, null, null, "-ms-layout-grid"), - "layout-grid-char" => array(null, null, null, "-ms-layout-grid-char"), - "layout-grid-line" => array(null, null, null, "-ms-layout-grid-line"), - "layout-grid-mode" => array(null, null, null, "-ms-layout-grid-mode"), - "layout-grid-type" => array(null, null, null, "-ms-layout-grid-type"), - "line-break" => array(null, "-webkit-line-break", null, "-ms-line-break"), - "line-clamp" => array(null, "-webkit-line-clamp", null, null), - "line-grid-mode" => array(null, null, null, "-ms-line-grid-mode"), - "logical-height" => array(null, "-webkit-logical-height", null, null), - "logical-width" => array(null, "-webkit-logical-width", null, null), - "margin-after" => array(null, "-webkit-margin-after", null, null), - "margin-after-collapse" => array(null, "-webkit-margin-after-collapse", null, null), - "margin-before" => array(null, "-webkit-margin-before", null, null), - "margin-before-collapse" => array(null, "-webkit-margin-before-collapse", null, null), - "margin-bottom-collapse" => array(null, "-webkit-margin-bottom-collapse", null, null), - "margin-collapse" => array(null, "-webkit-margin-collapse", null, null), - "margin-end" => array("-moz-margin-end", "-webkit-margin-end", null, null), - "margin-start" => array("-moz-margin-start", "-webkit-margin-start", null, null), - "margin-top-collapse" => array(null, "-webkit-margin-top-collapse", null, null), - "marquee " => array(null, "-webkit-marquee", null, null), - "marquee-direction" => array(null, "-webkit-marquee-direction", null, null), - "marquee-increment" => array(null, "-webkit-marquee-increment", null, null), - "marquee-repetition" => array(null, "-webkit-marquee-repetition", null, null), - "marquee-speed" => array(null, "-webkit-marquee-speed", null, null), - "marquee-style" => array(null, "-webkit-marquee-style", null, null), - "mask" => array(null, "-webkit-mask", null, null), - "mask-attachment" => array(null, "-webkit-mask-attachment", null, null), - "mask-box-image" => array(null, "-webkit-mask-box-image", null, null), - "mask-clip" => array(null, "-webkit-mask-clip", null, null), - "mask-composite" => array(null, "-webkit-mask-composite", null, null), - "mask-image" => array(null, "-webkit-mask-image", null, null), - "mask-origin" => array(null, "-webkit-mask-origin", null, null), - "mask-position" => array(null, "-webkit-mask-position", null, null), - "mask-position-x" => array(null, "-webkit-mask-position-x", null, null), - "mask-position-y" => array(null, "-webkit-mask-position-y", null, null), - "mask-repeat" => array(null, "-webkit-mask-repeat", null, null), - "mask-repeat-x" => array(null, "-webkit-mask-repeat-x", null, null), - "mask-repeat-y" => array(null, "-webkit-mask-repeat-y", null, null), - "mask-size" => array(null, "-webkit-mask-size", null, null), - "match-nearest-mail-blockquote-color" => array(null, "-webkit-match-nearest-mail-blockquote-color", null, null), - "max-logical-height" => array(null, "-webkit-max-logical-height", null, null), - "max-logical-width" => array(null, "-webkit-max-logical-width", null, null), - "min-logical-height" => array(null, "-webkit-min-logical-height", null, null), - "min-logical-width" => array(null, "-webkit-min-logical-width", null, null), - "object-fit" => array(null, null, "-o-object-fit", null), - "object-position" => array(null, null, "-o-object-position", null), - "opacity" => array(__CLASS__, "opacity"), - "outline-radius" => array("-moz-outline-radius", null, null, null), - "outline-bottom-left-radius" => array("-moz-outline-radius-bottomleft", null, null, null), - "outline-bottom-right-radius" => array("-moz-outline-radius-bottomright", null, null, null), - "outline-top-left-radius" => array("-moz-outline-radius-topleft", null, null, null), - "outline-top-right-radius" => array("-moz-outline-radius-topright", null, null, null), - "padding-after" => array(null, "-webkit-padding-after", null, null), - "padding-before" => array(null, "-webkit-padding-before", null, null), - "padding-end" => array("-moz-padding-end", "-webkit-padding-end", null, null), - "padding-start" => array("-moz-padding-start", "-webkit-padding-start", null, null), - "perspective" => array(null, "-webkit-perspective", null, null), - "perspective-origin" => array(null, "-webkit-perspective-origin", null, null), - "perspective-origin-x" => array(null, "-webkit-perspective-origin-x", null, null), - "perspective-origin-y" => array(null, "-webkit-perspective-origin-y", null, null), - "rtl-ordering" => array(null, "-webkit-rtl-ordering", null, null), - "scrollbar-3dlight-color" => array(null, null, null, "-ms-scrollbar-3dlight-color"), - "scrollbar-arrow-color" => array(null, null, null, "-ms-scrollbar-arrow-color"), - "scrollbar-base-color" => array(null, null, null, "-ms-scrollbar-base-color"), - "scrollbar-darkshadow-color" => array(null, null, null, "-ms-scrollbar-darkshadow-color"), - "scrollbar-face-color" => array(null, null, null, "-ms-scrollbar-face-color"), - "scrollbar-highlight-color" => array(null, null, null, "-ms-scrollbar-highlight-color"), - "scrollbar-shadow-color" => array(null, null, null, "-ms-scrollbar-shadow-color"), - "scrollbar-track-color" => array(null, null, null, "-ms-scrollbar-track-color"), - "stack-sizing" => array("-moz-stack-sizing", null, null, null), - "svg-shadow" => array(null, "-webkit-svg-shadow", null, null), - "tab-size" => array("-moz-tab-size", null, "-o-tab-size", null), - "table-baseline" => array(null, null, "-o-table-baseline", null), - "text-align-last" => array(null, null, null, "-ms-text-align-last"), - "text-autospace" => array(null, null, null, "-ms-text-autospace"), - "text-combine" => array(null, "-webkit-text-combine", null, null), - "text-decorations-in-effect" => array(null, "-webkit-text-decorations-in-effect", null, null), - "text-emphasis" => array(null, "-webkit-text-emphasis", null, null), - "text-emphasis-color" => array(null, "-webkit-text-emphasis-color", null, null), - "text-emphasis-position" => array(null, "-webkit-text-emphasis-position", null, null), - "text-emphasis-style" => array(null, "-webkit-text-emphasis-style", null, null), - "text-fill-color" => array(null, "-webkit-text-fill-color", null, null), - "text-justify" => array(null, null, null, "-ms-text-justify"), - "text-kashida-space" => array(null, null, null, "-ms-text-kashida-space"), - "text-overflow" => array(null, null, "-o-text-overflow", "-ms-text-overflow"), - "text-security" => array(null, "-webkit-text-security", null, null), - "text-size-adjust" => array(null, "-webkit-text-size-adjust", null, "-ms-text-size-adjust"), - "text-stroke" => array(null, "-webkit-text-stroke", null, null), - "text-stroke-color" => array(null, "-webkit-text-stroke-color", null, null), - "text-stroke-width" => array(null, "-webkit-text-stroke-width", null, null), - "text-underline-position" => array(null, null, null, "-ms-text-underline-position"), - "transform" => array("-moz-transform", "-webkit-transform", "-o-transform", null), - "transform-origin" => array("-moz-transform-origin", "-webkit-transform-origin", "-o-transform-origin", null), - "transform-origin-x" => array(null, "-webkit-transform-origin-x", null, null), - "transform-origin-y" => array(null, "-webkit-transform-origin-y", null, null), - "transform-origin-z" => array(null, "-webkit-transform-origin-z", null, null), - "transform-style" => array(null, "-webkit-transform-style", null, null), - "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null), - "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null), - "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null), - "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null), - "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null), - "user-drag" => array(null, "-webkit-user-drag", null, null), - "user-focus" => array("-moz-user-focus", null, null, null), - "user-input" => array("-moz-user-input", null, null, null), - "user-modify" => array("-moz-user-modify", "-webkit-user-modify", null, null), - "user-select" => array("-moz-user-select", "-webkit-user-select", null, null), - "white-space" => array(__CLASS__, "whiteSpace"), - "window-shadow" => array("-moz-window-shadow", null, null, null), - "word-break" => array(null, null, null, "-ms-word-break"), - "word-wrap" => array(null, null, null, "-ms-word-wrap"), - "writing-mode" => array(null, "-webkit-writing-mode", null, "-ms-writing-mode"), - "zoom" => array(null, null, null, "-ms-zoom") - ); - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - $transformations = &$this->transformations; - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - if (get_class($tokens[$i]) === "CssRulesetDeclarationToken") - { - $tProperty = $tokens[$i]->Property; - if (isset($transformations[$tProperty])) - { - $result = array(); - if (is_callable($transformations[$tProperty])) - { - $result = call_user_func_array($transformations[$tProperty], array($tokens[$i])); - if (!is_array($result) && is_object($result)) - { - $result = array($result); - } - } - else - { - $tValue = $tokens[$i]->Value; - $tMediaTypes = $tokens[$i]->MediaTypes; - foreach ($transformations[$tProperty] as $property) - { - if ($property !== null) - { - $result[] = new CssRulesetDeclarationToken($property, $tValue, $tMediaTypes); - } - } - } - if (count($result) > 0) - { - array_splice($tokens, $i + 1, 0, $result); - $i += count($result); - $l += count($result); - } - } - } - } - return $r; - } - /** - * Transforms the Internet Explorer specific declaration property "filter" to Internet Explorer 8+ compatible - * declaratiopn property "-ms-filter". - * - * @param aCssToken $token - * @return array - */ - private static function filter($token) - { - $r = array - ( - new CssRulesetDeclarationToken("-ms-filter", "\"" . $token->Value . "\"", $token->MediaTypes), - ); - return $r; - } - /** - * Transforms "opacity: {value}" into browser specific counterparts. - * - * @param aCssToken $token - * @return array - */ - private static function opacity($token) - { - // Calculate the value for Internet Explorer filter statement - $ieValue = (int) ((float) $token->Value * 100); - $r = array - ( - // Internet Explorer >= 8 - new CssRulesetDeclarationToken("-ms-filter", "\"alpha(opacity=" . $ieValue . ")\"", $token->MediaTypes), - // Internet Explorer >= 4 <= 7 - new CssRulesetDeclarationToken("filter", "alpha(opacity=" . $ieValue . ")", $token->MediaTypes), - new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes) - ); - return $r; - } - /** - * Transforms "white-space: pre-wrap" into browser specific counterparts. - * - * @param aCssToken $token - * @return array - */ - private static function whiteSpace($token) - { - if (strtolower($token->Value) === "pre-wrap") - { - $r = array - ( - // Firefox < 3 - new CssRulesetDeclarationToken("white-space", "-moz-pre-wrap", $token->MediaTypes), - // Webkit - new CssRulesetDeclarationToken("white-space", "-webkit-pre-wrap", $token->MediaTypes), - // Opera >= 4 <= 6 - new CssRulesetDeclarationToken("white-space", "-pre-wrap", $token->MediaTypes), - // Opera >= 7 - new CssRulesetDeclarationToken("white-space", "-o-pre-wrap", $token->MediaTypes), - // Internet Explorer >= 5.5 - new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes) - ); - return $r; - } - else - { - return array(); - } - } - } - -/** - * This {@link aCssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts. - * - * @package CssMin/Minifier/Filters - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssConvertLevel3AtKeyframesMinifierFilter extends aCssMinifierFilter - { - /** - * Implements {@link aCssMinifierFilter::filter()}. - * - * @param array $tokens Array of objects of type aCssToken - * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array - */ - public function apply(array &$tokens) - { - $r = 0; - $transformations = array("-moz-keyframes", "-webkit-keyframes"); - for ($i = 0, $l = count($tokens); $i < $l; $i++) - { - if (get_class($tokens[$i]) === "CssAtKeyframesStartToken") - { - for ($ii = $i; $ii < $l; $ii++) - { - if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") - { - break; - } - } - if (get_class($tokens[$ii]) === "CssAtKeyframesEndToken") - { - $add = array(); - $source = array(); - for ($iii = $i; $iii <= $ii; $iii++) - { - $source[] = clone($tokens[$iii]); - } - foreach ($transformations as $transformation) - { - $t = array(); - foreach ($source as $token) - { - $t[] = clone($token); - } - $t[0]->AtRuleName = $transformation; - $add = array_merge($add, $t); - } - if (isset($this->configuration["RemoveSource"]) && $this->configuration["RemoveSource"] === true) - { - array_splice($tokens, $i, $ii - $i + 1, $add); - } - else - { - array_splice($tokens, $ii + 1, 0, $add); - } - $l = count($tokens); - $i = $ii + count($add); - $r += count($add); - } - } - } - return $r; - } - } - -/** - * This {@link aCssMinifierPlugin} will convert a color value in hsl notation to hexadecimal notation. - * - * Example: - * - * color: hsl(232,36%,48%); - * - * - * Will get converted to: - * - * color:#4e5aa7; - * - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssConvertHslColorsMinifierPlugin extends aCssMinifierPlugin - { - /** - * Regular expression matching the value. - * - * @var string - */ - private $reMatch = "/^hsl\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*%\s*,\s*([0-9]+)\s*%\s*\)/iS"; - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (stripos($token->Value, "hsl") !== false && preg_match($this->reMatch, $token->Value, $m)) - { - $token->Value = str_replace($m[0], $this->hsl2hex($m[1], $m[2], $m[3]), $token->Value); - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - /** - * Convert a HSL value to hexadecimal notation. - * - * Based on: {@link http://www.easyrgb.com/index.php?X=MATH&H=19#text19}. - * - * @param integer $hue Hue - * @param integer $saturation Saturation - * @param integer $lightness Lightnesss - * @return string - */ - private function hsl2hex($hue, $saturation, $lightness) - { - $hue = $hue / 360; - $saturation = $saturation / 100; - $lightness = $lightness / 100; - if ($saturation == 0) - { - $red = $lightness * 255; - $green = $lightness * 255; - $blue = $lightness * 255; - } - else - { - if ($lightness < 0.5 ) - { - $v2 = $lightness * (1 + $saturation); - } - else - { - $v2 = ($lightness + $saturation) - ($saturation * $lightness); - } - $v1 = 2 * $lightness - $v2; - $red = 255 * self::hue2rgb($v1, $v2, $hue + (1 / 3)); - $green = 255 * self::hue2rgb($v1, $v2, $hue); - $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3)); - } - return "#" . str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); - } - /** - * Apply hue to a rgb color value. - * - * @param integer $v1 Value 1 - * @param integer $v2 Value 2 - * @param integer $hue Hue - * @return integer - */ - private function hue2rgb($v1, $v2, $hue) - { - if ($hue < 0) - { - $hue += 1; - } - if ($hue > 1) - { - $hue -= 1; - } - if ((6 * $hue) < 1) - { - return ($v1 + ($v2 - $v1) * 6 * $hue); - } - if ((2 * $hue) < 1) - { - return ($v2); - } - if ((3 * $hue) < 2) - { - return ($v1 + ($v2 - $v1) * (( 2 / 3) - $hue) * 6); - } - return $v1; - } - } - -/** - * This {@link aCssMinifierPlugin} will convert the font-weight values normal and bold to their numeric notation. - * - * Example: - * - * font-weight: normal; - * font: bold 11px monospace; - * - * - * Will get converted to: - * - * font-weight:400; - * font:700 11px monospace; - * - * - * @package CssMin/Minifier/Pluginsn - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssConvertFontWeightMinifierPlugin extends aCssMinifierPlugin - { - /** - * Array of included declaration properties this plugin will process; others declaration properties will get - * ignored. - * - * @var array - */ - private $include = array - ( - "font", - "font-weight" - ); - /** - * Regular expression matching the value. - * - * @var string - */ - private $reMatch = null; - /** - * Regular expression replace the value. - * - * @var string - */ - private $reReplace = "\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\""; - /** - * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}. - * - * @var array - */ - private $transformation = array - ( - "normal" => "400", - "bold" => "700" - ); - /** - * Overwrites {@link aCssMinifierPlugin::__construct()}. - * - * The constructor will create the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression} - * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}. - * - * @param CssMinifier $minifier The CssMinifier object of this plugin. - * @return void - */ - public function __construct(CssMinifier $minifier) - { - $this->reMatch = "/(^|\s)+(" . implode("|", array_keys($this->transformation)). ")(\s|$)+/eiS"; - parent::__construct($minifier); - } - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (in_array($token->Property, $this->include) && preg_match($this->reMatch, $token->Value, $m)) - { - $token->Value = preg_replace($this->reMatch, $this->reReplace, $token->Value); - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssMinifierPlugin} will compress several unit values to their short notations. Examples: - * - * - * padding: 0.5em; - * border: 0px; - * margin: 0 0 0 0; - * - * - * Will get compressed to: - * - * - * padding:.5px; - * border:0; - * margin:0; - * - * - * -- - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssCompressUnitValuesMinifierPlugin extends aCssMinifierPlugin - { - /** - * Regular expression used for matching and replacing unit values. - * - * @var array - */ - private $re = array - ( - "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}.\${2}\${4}", - "/(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)/iS" => "\${1}0", - "/(^0\s0\s0\s0)|(^0\s0\s0$)|(^0\s0$)/iS" => "0" - ); - /** - * Regular expression matching the value. - * - * @var string - */ - private $reMatch = "/(^| |-)0\.([0-9]+?)(0+)?(%|em|ex|px|in|cm|mm|pt|pc)|(^| )-?(\.?)0(%|em|ex|px|in|cm|mm|pt|pc)|(^0\s0\s0\s0$)|(^0\s0\s0$)|(^0\s0$)/iS"; - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (preg_match($this->reMatch, $token->Value)) - { - foreach ($this->re as $reMatch => $reReplace) - { - $token->Value = preg_replace($reMatch, $reReplace, $token->Value); - } - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssMinifierPlugin} compress the content of expresssion() declaration values. - * - * For compression of expressions {@link https://github.com/rgrove/jsmin-php/ JSMin} will get used. JSMin have to be - * already included or loadable via {@link http://goo.gl/JrW54 PHP autoloading}. - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssCompressExpressionValuesMinifierPlugin extends aCssMinifierPlugin - { - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (class_exists("JSMin") && stripos($token->Value, "expression(") !== false) - { - $value = $token->Value; - $value = substr($token->Value, stripos($token->Value, "expression(") + 10); - $value = trim(JSMin::minify($value)); - $token->Value = "expression(" . $value . ")"; - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssMinifierPlugin} will convert hexadecimal color value with 6 chars to their 3 char hexadecimal - * notation (if possible). - * - * Example: - * - * color: #aabbcc; - * - * - * Will get converted to: - * - * color:#abc; - * - * - * @package CssMin/Minifier/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssCompressColorValuesMinifierPlugin extends aCssMinifierPlugin - { - /** - * Regular expression matching 6 char hexadecimal color values. - * - * @var string - */ - private $reMatch = "/\#([0-9a-f]{6})/iS"; - /** - * Implements {@link aCssMinifierPlugin::minify()}. - * - * @param aCssToken $token Token to process - * @return boolean Return TRUE to break the processing of this token; FALSE to continue - */ - public function apply(aCssToken &$token) - { - if (strpos($token->Value, "#") !== false && preg_match($this->reMatch, $token->Value, $m)) - { - $value = strtolower($m[1]); - if ($value[0] == $value[1] && $value[2] == $value[3] && $value[4] == $value[5]) - { - $token->Value = str_replace($m[0], "#" . $value[0] . $value[2] . $value[4], $token->Value); - } - } - return false; - } - /** - * Implements {@link aMinifierPlugin::getTriggerTokens()} - * - * @return array - */ - public function getTriggerTokens() - { - return array - ( - "CssAtFontFaceDeclarationToken", - "CssAtPageDeclarationToken", - "CssRulesetDeclarationToken" - ); - } - } - -/** - * This {@link aCssToken CSS token} represents a CSS comment. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssCommentToken extends aCssToken - { - /** - * Comment as Text. - * - * @var string - */ - public $Comment = ""; - /** - * Set the properties of a comment token. - * - * @param string $comment Comment including comment delimiters - * @return void - */ - public function __construct($comment) - { - $this->Comment = $comment; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return $this->Comment; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing comments. - * - * Adds a {@link CssCommentToken} to the parser if a comment was found. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssCommentParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("*", "/"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return false; - } - /** - * Stored buffer for restore. - * - * @var string - */ - private $restoreBuffer = ""; - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - if ($char === "*" && $previousChar === "/" && $state !== "T_COMMENT") - { - $this->parser->pushState("T_COMMENT"); - $this->parser->setExclusive(__CLASS__); - $this->restoreBuffer = substr($this->parser->getAndClearBuffer(), 0, -2); - } - elseif ($char === "/" && $previousChar === "*" && $state === "T_COMMENT") - { - $this->parser->popState(); - $this->parser->unsetExclusive(); - $this->parser->appendToken(new CssCommentToken("/*" . $this->parser->getAndClearBuffer())); - $this->parser->setBuffer($this->restoreBuffer); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the start of a @variables at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtVariablesStartToken extends aCssAtBlockStartToken - { - /** - * Media types of the @variables at-rule block. - * - * @var array - */ - public $MediaTypes = array(); - /** - * Set the properties of a @variables at-rule token. - * - * @param array $mediaTypes Media types - * @return void - */ - public function __construct($mediaTypes = null) - { - $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return ""; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @variables at-rule block with including declarations. - * - * Found @variables at-rule blocks will add a {@link CssAtVariablesStartToken} and {@link CssAtVariablesEndToken} to the - * parser; including declarations as {@link CssAtVariablesDeclarationToken}. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtVariablesParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", "{", "}", ":", ";"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_VARIABLES::PREPARE", "T_AT_VARIABLES", "T_AT_VARIABLES_DECLARATION"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of @variables at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables") - { - $this->parser->pushState("T_AT_VARIABLES::PREPARE"); - $this->parser->clearBuffer(); - return $index + 10; - } - // Start of @variables declarations - elseif ($char === "{" && $state === "T_AT_VARIABLES::PREPARE") - { - $this->parser->setState("T_AT_VARIABLES"); - $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); - $this->parser->appendToken(new CssAtVariablesStartToken($mediaTypes)); - } - // Start of @variables declaration - if ($char === ":" && $state === "T_AT_VARIABLES") - { - $this->buffer = $this->parser->getAndClearBuffer(":"); - $this->parser->pushState("T_AT_VARIABLES_DECLARATION"); - } - // Unterminated @variables declaration - elseif ($char === ":" && $state === "T_AT_VARIABLES_DECLARATION") - { - // Ignore Internet Explorer filter declarations - if ($this->buffer === "filter") - { - return false; - } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @variables declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); - } - // End of @variables declaration - elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION") - { - $value = $this->parser->getAndClearBuffer(";}"); - if (strtolower(substr($value, -10, 10)) === "!important") - { - $value = trim(substr($value, 0, -10)); - $isImportant = true; - } - else - { - $isImportant = false; - } - $this->parser->popState(); - $this->parser->appendToken(new CssAtVariablesDeclarationToken($this->buffer, $value, $isImportant)); - $this->buffer = ""; - } - // End of @variables at-rule block - elseif ($char === "}" && $state === "T_AT_VARIABLES") - { - $this->parser->popState(); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssAtVariablesEndToken()); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a @variables at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtVariablesEndToken extends aCssAtBlockEndToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return ""; - } - } - -/** - * This {@link aCssToken CSS token} represents a declaration of a @variables at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtVariablesDeclarationToken extends aCssDeclarationToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return ""; - } - } - -/** -* This {@link aCssToken CSS token} represents the start of a @page at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtPageStartToken extends aCssAtBlockStartToken - { - /** - * Selector. - * - * @var string - */ - public $Selector = ""; - /** - * Sets the properties of the @page at-rule. - * - * @param string $selector Selector - * @return void - */ - public function __construct($selector = "") - { - $this->Selector = $selector; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@page" . ($this->Selector ? " " . $this->Selector : "") . "{"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @page at-rule block with including declarations. - * - * Found @page at-rule blocks will add a {@link CssAtPageStartToken} and {@link CssAtPageEndToken} to the - * parser; including declarations as {@link CssAtPageDeclarationToken}. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtPageParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", "{", "}", ":", ";"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_PAGE::SELECTOR", "T_AT_PAGE", "T_AT_PAGE_DECLARATION"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of @page at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page") - { - $this->parser->pushState("T_AT_PAGE::SELECTOR"); - $this->parser->clearBuffer(); - return $index + 5; - } - // Start of @page declarations - elseif ($char === "{" && $state === "T_AT_PAGE::SELECTOR") - { - $selector = $this->parser->getAndClearBuffer("{"); - $this->parser->setState("T_AT_PAGE"); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssAtPageStartToken($selector)); - } - // Start of @page declaration - elseif ($char === ":" && $state === "T_AT_PAGE") - { - $this->parser->pushState("T_AT_PAGE_DECLARATION"); - $this->buffer = $this->parser->getAndClearBuffer(":", true); - } - // Unterminated @font-face declaration - elseif ($char === ":" && $state === "T_AT_PAGE_DECLARATION") - { - // Ignore Internet Explorer filter declarations - if ($this->buffer === "filter") - { - return false; - } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @page declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); - } - // End of @page declaration - elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION") - { - $value = $this->parser->getAndClearBuffer(";}"); - if (strtolower(substr($value, -10, 10)) == "!important") - { - $value = trim(substr($value, 0, -10)); - $isImportant = true; - } - else - { - $isImportant = false; - } - $this->parser->popState(); - $this->parser->appendToken(new CssAtPageDeclarationToken($this->buffer, $value, $isImportant)); - // -- - if ($char === "}") - { - $this->parser->popState(); - $this->parser->appendToken(new CssAtPageEndToken()); - } - $this->buffer = ""; - } - // End of @page at-rule block - elseif ($char === "}" && $state === "T_AT_PAGE") - { - $this->parser->popState(); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssAtPageEndToken()); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a @page at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtPageEndToken extends aCssAtBlockEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a declaration of a @page at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtPageDeclarationToken extends aCssDeclarationToken - { - - } - -/** - * This {@link aCssToken CSS token} represents the start of a @media at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtMediaStartToken extends aCssAtBlockStartToken - { - /** - * Sets the properties of the @media at-rule. - * - * @param array $mediaTypes Media types - * @return void - */ - public function __construct(array $mediaTypes = array()) - { - $this->MediaTypes = $mediaTypes; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@media " . implode(",", $this->MediaTypes) . "{"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @media at-rule block. - * - * Found @media at-rule blocks will add a {@link CssAtMediaStartToken} and {@link CssAtMediaEndToken} to the parser. - * This plugin will also set the the current media types using {@link CssParser::setMediaTypes()} and - * {@link CssParser::unsetMediaTypes()}. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtMediaParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", "{", "}"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_MEDIA::PREPARE", "T_AT_MEDIA"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media") - { - $this->parser->pushState("T_AT_MEDIA::PREPARE"); - $this->parser->clearBuffer(); - return $index + 6; - } - elseif ($char === "{" && $state === "T_AT_MEDIA::PREPARE") - { - $mediaTypes = array_filter(array_map("trim", explode(",", $this->parser->getAndClearBuffer("{")))); - $this->parser->setMediaTypes($mediaTypes); - $this->parser->setState("T_AT_MEDIA"); - $this->parser->appendToken(new CssAtMediaStartToken($mediaTypes)); - } - elseif ($char === "}" && $state === "T_AT_MEDIA") - { - $this->parser->appendToken(new CssAtMediaEndToken()); - $this->parser->clearBuffer(); - $this->parser->unsetMediaTypes(); - $this->parser->popState(); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a @media at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtMediaEndToken extends aCssAtBlockEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents the start of a @keyframes at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesStartToken extends aCssAtBlockStartToken - { - /** - * Name of the at-rule. - * - * @var string - */ - public $AtRuleName = "keyframes"; - /** - * Name - * - * @var string - */ - public $Name = ""; - /** - * Sets the properties of the @page at-rule. - * - * @param string $selector Selector - * @return void - */ - public function __construct($name, $atRuleName = null) - { - $this->Name = $name; - if (!is_null($atRuleName)) - { - $this->AtRuleName = $atRuleName; - } - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@" . $this->AtRuleName . " \"" . $this->Name . "\"{"; - } - } - -/** - * This {@link aCssToken CSS token} represents the start of a ruleset of a @keyframes at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesRulesetStartToken extends aCssRulesetStartToken - { - /** - * Array of selectors. - * - * @var array - */ - public $Selectors = array(); - /** - * Set the properties of a ruleset token. - * - * @param array $selectors Selectors of the ruleset - * @return void - */ - public function __construct(array $selectors = array()) - { - $this->Selectors = $selectors; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return implode(",", $this->Selectors) . "{"; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a ruleset of a @keyframes at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesRulesetEndToken extends aCssRulesetEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a ruleset declaration of a @keyframes at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesRulesetDeclarationToken extends aCssDeclarationToken - { - - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @keyframes at-rule blocks, rulesets and declarations. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesParserPlugin extends aCssParserPlugin - { - /** - * @var string Keyword - */ - private $atRuleName = ""; - /** - * Selectors. - * - * @var array - */ - private $selectors = array(); - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", "{", "}", ":", ",", ";"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of @keyframes at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") - { - $this->atRuleName = "keyframes"; - $this->parser->pushState("T_AT_KEYFRAMES::NAME"); - $this->parser->clearBuffer(); - return $index + 10; - } - // Start of @keyframes at-rule block (@-moz-keyframes) - elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes") - { - $this->atRuleName = "-moz-keyframes"; - $this->parser->pushState("T_AT_KEYFRAMES::NAME"); - $this->parser->clearBuffer(); - return $index + 15; - } - // Start of @keyframes at-rule block (@-webkit-keyframes) - elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes") - { - $this->atRuleName = "-webkit-keyframes"; - $this->parser->pushState("T_AT_KEYFRAMES::NAME"); - $this->parser->clearBuffer(); - return $index + 18; - } - // Start of @keyframes rulesets - elseif ($char === "{" && $state === "T_AT_KEYFRAMES::NAME") - { - $name = $this->parser->getAndClearBuffer("{\"'"); - $this->parser->setState("T_AT_KEYFRAMES_RULESETS"); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssAtKeyframesStartToken($name, $this->atRuleName)); - } - // Start of @keyframe ruleset and selectors - if ($char === "," && $state === "T_AT_KEYFRAMES_RULESETS") - { - $this->selectors[] = $this->parser->getAndClearBuffer(",{"); - } - // Start of a @keyframes ruleset - elseif ($char === "{" && $state === "T_AT_KEYFRAMES_RULESETS") - { - if ($this->parser->getBuffer() !== "") - { - $this->selectors[] = $this->parser->getAndClearBuffer(",{"); - $this->parser->pushState("T_AT_KEYFRAMES_RULESET"); - $this->parser->appendToken(new CssAtKeyframesRulesetStartToken($this->selectors)); - $this->selectors = array(); - } - } - // Start of @keyframes ruleset declaration - elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET") - { - $this->parser->pushState("T_AT_KEYFRAMES_RULESET_DECLARATION"); - $this->buffer = $this->parser->getAndClearBuffer(":;", true); - } - // Unterminated @keyframes ruleset declaration - elseif ($char === ":" && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") - { - // Ignore Internet Explorer filter declarations - if ($this->buffer === "filter") - { - return false; - } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @keyframes ruleset declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); - } - // End of declaration - elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") - { - $value = $this->parser->getAndClearBuffer(";}"); - if (strtolower(substr($value, -10, 10)) === "!important") - { - $value = trim(substr($value, 0, -10)); - $isImportant = true; - } - else - { - $isImportant = false; - } - $this->parser->popState(); - $this->parser->appendToken(new CssAtKeyframesRulesetDeclarationToken($this->buffer, $value, $isImportant)); - // Declaration ends with a right curly brace; so we have to end the ruleset - if ($char === "}") - { - $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); - $this->parser->popState(); - } - $this->buffer = ""; - } - // End of @keyframes ruleset - elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESET") - { - $this->parser->clearBuffer(); - - $this->parser->popState(); - $this->parser->appendToken(new CssAtKeyframesRulesetEndToken()); - } - // End of @keyframes rulesets - elseif ($char === "}" && $state === "T_AT_KEYFRAMES_RULESETS") - { - $this->parser->clearBuffer(); - $this->parser->popState(); - $this->parser->appendToken(new CssAtKeyframesEndToken()); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a @keyframes at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtKeyframesEndToken extends aCssAtBlockEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a @import at-rule. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1.b1 (2001-02-22) - */ -class CssAtImportToken extends aCssToken - { - /** - * Import path of the @import at-rule. - * - * @var string - */ - public $Import = ""; - /** - * Media types of the @import at-rule. - * - * @var array - */ - public $MediaTypes = array(); - /** - * Set the properties of a @import at-rule token. - * - * @param string $import Import path - * @param array $mediaTypes Media types - * @return void - */ - public function __construct($import, $mediaTypes) - { - $this->Import = $import; - $this->MediaTypes = $mediaTypes ? $mediaTypes : array(); - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@import \"" . $this->Import . "\"" . (count($this->MediaTypes) > 0 ? " " . implode(",", $this->MediaTypes) : ""). ";"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @import at-rule. - * - * If a @import at-rule was found this plugin will add a {@link CssAtImportToken} to the parser. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtImportParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", ";", ",", "\n"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_IMPORT"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 7)) === "@import") - { - $this->parser->pushState("T_AT_IMPORT"); - $this->parser->clearBuffer(); - return $index + 7; - } - elseif (($char === ";" || $char === "\n") && $state === "T_AT_IMPORT") - { - $this->buffer = $this->parser->getAndClearBuffer(";"); - $pos = false; - foreach (array(")", "\"", "'") as $needle) - { - if (($pos = strrpos($this->buffer, $needle)) !== false) - { - break; - } - } - $import = substr($this->buffer, 0, $pos + 1); - if (stripos($import, "url(") === 0) - { - $import = substr($import, 4, -1); - } - $import = trim($import, " \t\n\r\0\x0B'\""); - $mediaTypes = array_filter(array_map("trim", explode(",", trim(substr($this->buffer, $pos + 1), " \t\n\r\0\x0B{")))); - if ($pos) - { - $this->parser->appendToken(new CssAtImportToken($import, $mediaTypes)); - } - else - { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Invalid @import at-rule syntax", $this->parser->buffer)); - } - $this->parser->popState(); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the start of a @font-face at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtFontFaceStartToken extends aCssAtBlockStartToken - { - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@font-face{"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @font-face at-rule block with including declarations. - * - * Found @font-face at-rule blocks will add a {@link CssAtFontFaceStartToken} and {@link CssAtFontFaceEndToken} to the - * parser; including declarations as {@link CssAtFontFaceDeclarationToken}. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtFontFaceParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", "{", "}", ":", ";"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_FONT_FACE::PREPARE", "T_AT_FONT_FACE", "T_AT_FONT_FACE_DECLARATION"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - // Start of @font-face at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face") - { - $this->parser->pushState("T_AT_FONT_FACE::PREPARE"); - $this->parser->clearBuffer(); - return $index + 10; - } - // Start of @font-face declarations - elseif ($char === "{" && $state === "T_AT_FONT_FACE::PREPARE") - { - $this->parser->setState("T_AT_FONT_FACE"); - $this->parser->clearBuffer(); - $this->parser->appendToken(new CssAtFontFaceStartToken()); - } - // Start of @font-face declaration - elseif ($char === ":" && $state === "T_AT_FONT_FACE") - { - $this->parser->pushState("T_AT_FONT_FACE_DECLARATION"); - $this->buffer = $this->parser->getAndClearBuffer(":", true); - } - // Unterminated @font-face declaration - elseif ($char === ":" && $state === "T_AT_FONT_FACE_DECLARATION") - { - // Ignore Internet Explorer filter declarations - if ($this->buffer === "filter") - { - return false; - } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__ . ": Unterminated @font-face declaration", $this->buffer . ":" . $this->parser->getBuffer() . "_")); - } - // End of @font-face declaration - elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") - { - $value = $this->parser->getAndClearBuffer(";}"); - if (strtolower(substr($value, -10, 10)) === "!important") - { - $value = trim(substr($value, 0, -10)); - $isImportant = true; - } - else - { - $isImportant = false; - } - $this->parser->popState(); - $this->parser->appendToken(new CssAtFontFaceDeclarationToken($this->buffer, $value, $isImportant)); - $this->buffer = ""; - // -- - if ($char === "}") - { - $this->parser->appendToken(new CssAtFontFaceEndToken()); - $this->parser->popState(); - } - } - // End of @font-face at-rule block - elseif ($char === "}" && $state === "T_AT_FONT_FACE") - { - $this->parser->appendToken(new CssAtFontFaceEndToken()); - $this->parser->clearBuffer(); - $this->parser->popState(); - } - else - { - return false; - } - return true; - } - } - -/** - * This {@link aCssToken CSS token} represents the end of a @font-face at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtFontFaceEndToken extends aCssAtBlockEndToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a declaration of a @font-face at-rule block. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtFontFaceDeclarationToken extends aCssDeclarationToken - { - - } - -/** - * This {@link aCssToken CSS token} represents a @charset at-rule. - * - * @package CssMin/Tokens - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtCharsetToken extends aCssToken - { - /** - * Charset of the @charset at-rule. - * - * @var string - */ - public $Charset = ""; - /** - * Set the properties of @charset at-rule token. - * - * @param string $charset Charset of the @charset at-rule token - * @return void - */ - public function __construct($charset) - { - $this->Charset = $charset; - } - /** - * Implements {@link aCssToken::__toString()}. - * - * @return string - */ - public function __toString() - { - return "@charset " . $this->Charset . ";"; - } - } - -/** - * {@link aCssParserPlugin Parser plugin} for parsing @charset at-rule. - * - * If a @charset at-rule was found this plugin will add a {@link CssAtCharsetToken} to the parser. - * - * @package CssMin/Parser/Plugins - * @link http://code.google.com/p/cssmin/ - * @author Joe Scylla - * @copyright 2008 - 2011 Joe Scylla - * @license http://opensource.org/licenses/mit-license.php MIT License - * @version 3.0.1 - */ -class CssAtCharsetParserPlugin extends aCssParserPlugin - { - /** - * Implements {@link aCssParserPlugin::getTriggerChars()}. - * - * @return array - */ - public function getTriggerChars() - { - return array("@", ";", "\n"); - } - /** - * Implements {@link aCssParserPlugin::getTriggerStates()}. - * - * @return array - */ - public function getTriggerStates() - { - return array("T_DOCUMENT", "T_AT_CHARSET"); - } - /** - * Implements {@link aCssParserPlugin::parse()}. - * - * @param integer $index Current index - * @param string $char Current char - * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing - */ - public function parse($index, $char, $previousChar, $state) - { - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset") - { - $this->parser->pushState("T_AT_CHARSET"); - $this->parser->clearBuffer(); - return $index + 8; - } - elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") - { - $charset = $this->parser->getAndClearBuffer(";"); - $this->parser->popState(); - $this->parser->appendToken(new CssAtCharsetToken($charset)); - } - else - { - return false; - } - return true; - } - } - -?> \ No newline at end of file +class CssMin +{ + /** + * Index of classes + * + * @var array + */ + private static $classIndex = array(); + /** + * Parse/minify errors + * + * @var array + */ + private static $errors = array(); + /** + * Verbose output. + * + * @var boolean + */ + private static $isVerbose = false; + + /** + * Return errors + * + * @return array of {CssError}. + */ + public static function getErrors() + { + return self::$errors; + } + + /** + * Returns if there were errors. + * + * @return boolean + */ + public static function hasErrors() + { + return count(self::$errors) > 0; + } + + /** + * Minifies CSS source. + * + * @param string $source CSS source + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return string Minified CSS + */ + public static function minify($source, array $filters = null, array $plugins = null) + { + self::$errors = array(); + $minifier = new CssMinifier($source, $filters, $plugins); + return $minifier->getMinified(); + } + + /** + * Parse the CSS source. + * + * @param string $source CSS source + * @param array $plugins Plugin configuration [optional] + * @return array Array of CssToken + */ + public static function parse($source, array $plugins = null) + { + self::$errors = array(); + $parser = new CssParser($source, $plugins); + return $parser->getTokens(); + } + + /** + * -- + * + * @param boolean $to + * @return boolean + */ + public static function setVerbose($to) + { + self::$isVerbose = (boolean)$to; + return self::$isVerbose; + } + + /** + * -- + * + * @param CssError $error + * @return void + */ + public static function triggerError(CssError $error) + { + self::$errors[] = $error; + if (self::$isVerbose) { + trigger_error((string)$error, E_USER_WARNING); + } + } +} diff --git a/src/CssMin/CssMinifier.php b/src/CssMin/CssMinifier.php new file mode 100644 index 0000000..7a6868b --- /dev/null +++ b/src/CssMin/CssMinifier.php @@ -0,0 +1,192 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssMinifier +{ + /** + * {@link CssMinifierFilter Filters}. + * + * @var array + */ + private $filters = array(); + /** + * {@link CssMinifierPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Minified source. + * + * @var string + */ + private $minified = ""; + + /** + * Constructer. + * + * Creates instances of {@link CssMinifierFilter filters} and {@link CssMinifierPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $filters Filter configuration [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $filters = null, array $plugins = null) + { + $filters = array_merge(array + ( + "ImportImports" => false, + "RemoveComments" => true, + "RemoveEmptyRulesets" => true, + "RemoveEmptyAtBlocks" => true, + "ConvertLevel3Properties" => false, + "ConvertLevel3AtKeyframes" => false, + "Variables" => true, + "RemoveLastDelarationSemiColon" => true + ), is_array($filters) ? $filters : array()); + $plugins = array_merge(array + ( + "Variables" => true, + "ConvertFontWeight" => false, + "ConvertHslColors" => false, + "ConvertRgbColors" => false, + "ConvertNamedColors" => false, + "CompressColorValues" => false, + "CompressUnitValues" => false, + "CompressExpressionValues" => false + ), is_array($plugins) ? $plugins : array()); + // Filters + foreach ($filters as $name => $config) { + if ($config !== false) { + $class = "Css".$name."MinifierFilter"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->filters[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The filter ".$name." with the class name ".$class." was not found")); + } + } + } + // Plugins + foreach ($plugins as $name => $config) { + if ($config !== false) { + $class = "Css".$name."MinifierPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->plugins[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The plugin ".$name." with the class name ".$class." was not found")); + } + } + } + // -- + if (!is_null($source)) { + $this->minify($source); + } + } + + /** + * Returns the minified Source. + * + * @return string + */ + public function getMinified() + { + return $this->minified; + } + + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return CssMinifierPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } + + /** + * Minifies the CSS source. + * + * @param string $source CSS source + * @return string + */ + public function minify($source) + { + // Variables + $r = ""; + $parser = new CssParser($source); + $tokens = $parser->getTokens(); + $filters = $this->filters; + $filterCount = count($this->filters); + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerTokens = array(); + $globalTriggerTokens = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerTokens[$i] = $plugins[$i]->getTriggerTokens(); + foreach ($pluginTriggerTokens[$i] as $v) { + if (!in_array($v, $globalTriggerTokens)) { + $globalTriggerTokens[] = $v; + } + } + $pluginTriggerTokens[$i] = "|".implode("|", $pluginTriggerTokens[$i])."|"; + $pluginIndex[$tPluginClassName] = $i; + } + $globalTriggerTokens = "|".implode("|", $globalTriggerTokens)."|"; + /* + * Apply filters + */ + for ($i = 0; $i < $filterCount; $i++) { + // Apply the filter; if the return value is larger than 0... + if ($filters[$i]->apply($tokens) > 0) { + // ...then filter null values and rebuild the token array + $tokens = array_values(array_filter($tokens)); + } + } + $tokenCount = count($tokens); + /* + * Apply plugins + */ + for ($i = 0; $i < $tokenCount; $i++) { + $triggerToken = "|".get_class($tokens[$i])."|"; + if (strpos($globalTriggerTokens, $triggerToken) !== false) { + for ($ii = 0; $ii < $pluginCount; $ii++) { + if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false) { + // Apply the plugin; if the return value is TRUE continue to the next token + if ($plugins[$ii]->apply($tokens[$i]) === true) { + continue 2; + } + } + } + } + } + // Stringify the tokens + for ($i = 0; $i < $tokenCount; $i++) { + $r .= (string)$tokens[$i]; + } + $this->minified = $r; + return $r; + } +} diff --git a/src/CssMin/CssMinifierFilter.php b/src/CssMin/CssMinifierFilter.php new file mode 100644 index 0000000..0b6597a --- /dev/null +++ b/src/CssMin/CssMinifierFilter.php @@ -0,0 +1,51 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssMinifierFilter +{ + /** + * Filter configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the filter. + * + * @var CssMinifier + */ + protected $minifier = null; + + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Filter configuration [optional] + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + + /** + * Filter the tokens. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + abstract public function apply(array &$tokens); +} diff --git a/src/CssMin/CssMinifierPlugin.php b/src/CssMin/CssMinifierPlugin.php new file mode 100644 index 0000000..d99f25b --- /dev/null +++ b/src/CssMin/CssMinifierPlugin.php @@ -0,0 +1,58 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssMinifierPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssMinifier of the plugin. + * + * @var CssMinifier + */ + protected $minifier = null; + + /** + * Constructor. + * + * @param CssMinifier $minifier The CssMinifier object of this plugin. + * @param array $configuration Plugin configuration [optional] + */ + public function __construct(CssMinifier $minifier, array $configuration = array()) + { + $this->configuration = $configuration; + $this->minifier = $minifier; + } + + /** + * Apply the plugin to the token. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + abstract public function apply(CssToken &$token); + + /** + * -- + * + * @return array + */ + abstract public function getTriggerTokens(); +} diff --git a/src/CssMin/CssNullToken.php b/src/CssMin/CssNullToken.php new file mode 100644 index 0000000..66945bc --- /dev/null +++ b/src/CssMin/CssNullToken.php @@ -0,0 +1,25 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssNullToken extends CssToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return ""; + } +} diff --git a/src/CssMin/CssOtbsFormatter.php b/src/CssMin/CssOtbsFormatter.php new file mode 100644 index 0000000..e0e0bcb --- /dev/null +++ b/src/CssMin/CssOtbsFormatter.php @@ -0,0 +1,81 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssOtbsFormatter extends CssFormatter +{ + /** + * Implements {@link CssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) { + $r[] = $indent.(substr($lines[$ii], 0, 1) == "*" ? " " : "").$lines[$ii]; + } + } elseif ($class === "CssAtCharsetToken") { + $r[] = $indent."@charset ".$token->Charset.";"; + } elseif ($class === "CssAtFontFaceStartToken") { + $r[] = $indent."@font-face {"; + $level++; + } elseif ($class === "CssAtImportToken") { + $r[] = $indent."@import ".$token->Import." ".implode(", ", $token->MediaTypes).";"; + } elseif ($class === "CssAtKeyframesStartToken") { + $r[] = $indent."@keyframes \"".$token->Name."\" {"; + $level++; + } elseif ($class === "CssAtMediaStartToken") { + $r[] = $indent."@media ".implode(", ", $token->MediaTypes)." {"; + $level++; + } elseif ($class === "CssAtPageStartToken") { + $r[] = $indent."@page {"; + $level++; + } elseif ($class === "CssAtVariablesStartToken") { + $r[] = $indent."@variables ".implode(", ", $token->MediaTypes)." {"; + $level++; + } elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") { + $r[] = $indent.implode(", ", $token->Selectors)." {"; + $level++; + } elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) { + $declaration = $indent.$token->Property.": "; + if ($this->padding) { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration.$token->Value.($token->IsImportant ? " !important" : "").";"; + } elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) { + $level--; + $r[] = str_repeat($indent, $level)."}"; + } + } + return implode("\n", $r); + } +} diff --git a/src/CssMin/CssParser.php b/src/CssMin/CssParser.php new file mode 100644 index 0000000..d571820 --- /dev/null +++ b/src/CssMin/CssParser.php @@ -0,0 +1,418 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssParser +{ + /** + * Parse buffer. + * + * @var string + */ + private $buffer = ""; + /** + * {@link CssParserPlugin Plugins}. + * + * @var array + */ + private $plugins = array(); + /** + * Source to parse. + * + * @var string + */ + private $source = ""; + /** + * Current state. + * + * @var integer + */ + private $state = "T_DOCUMENT"; + /** + * Exclusive state. + * + * @var string + */ + private $stateExclusive = false; + /** + * Media types state. + * + * @var mixed + */ + private $stateMediaTypes = false; + /** + * State stack. + * + * @var array + */ + private $states = array("T_DOCUMENT"); + /** + * Parsed tokens. + * + * @var array + */ + private $tokens = array(); + + /** + * Constructer. + * + * Create instances of the used {@link CssParserPlugin plugins}. + * + * @param string $source CSS source [optional] + * @param array $plugins Plugin configuration [optional] + * @return void + */ + public function __construct($source = null, array $plugins = null) + { + $plugins = array_merge(array + ( + "Comment" => true, + "String" => true, + "Url" => true, + "Expression" => true, + "Ruleset" => true, + "AtCharset" => true, + "AtFontFace" => true, + "AtImport" => true, + "AtKeyframes" => true, + "AtMedia" => true, + "AtPage" => true, + "AtVariables" => true + ), is_array($plugins) ? $plugins : array()); + // Create plugin instances + foreach ($plugins as $name => $config) { + if ($config !== false) { + $class = "Css".$name."ParserPlugin"; + $config = is_array($config) ? $config : array(); + if (class_exists($class)) { + $this->plugins[] = new $class($this, $config); + } else { + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The plugin ".$name." with the class name ".$class." was not found")); + } + } + } + if (!is_null($source)) { + $this->parse($source); + } + } + + /** + * Append a token to the array of tokens. + * + * @param CssToken $token Token to append + * @return void + */ + public function appendToken(CssToken $token) + { + $this->tokens[] = $token; + } + + /** + * Clears the current buffer. + * + * @return void + */ + public function clearBuffer() + { + $this->buffer = ""; + } + + /** + * Returns and clear the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getAndClearBuffer($trim = "", $tolower = false) + { + $r = $this->getBuffer($trim, $tolower); + $this->buffer = ""; + return $r; + } + + /** + * Returns the current buffer. + * + * @param string $trim Chars to use to trim the returned buffer + * @param boolean $tolower if TRUE the returned buffer will get converted to lower case + * @return string + */ + public function getBuffer($trim = "", $tolower = false) + { + $r = $this->buffer; + if ($trim) { + $r = trim($r, " \t\n\r\0\x0B".$trim); + } + if ($tolower) { + $r = strtolower($r); + } + return $r; + } + + /** + * Returns the current media types state. + * + * @return array + */ + public function getMediaTypes() + { + return $this->stateMediaTypes; + } + + /** + * Returns the CSS source. + * + * @return string + */ + public function getSource() + { + return $this->source; + } + + /** + * Returns the current state. + * + * @return integer The current state + */ + public function getState() + { + return $this->state; + } + + /** + * Returns a plugin by class name. + * + * @param string $name Class name of the plugin + * @return CssParserPlugin + */ + public function getPlugin($class) + { + static $index = null; + if (is_null($index)) { + $index = array(); + for ($i = 0, $l = count($this->plugins); $i < $l; $i++) { + $index[get_class($this->plugins[$i])] = $i; + } + } + return isset($index[$class]) ? $this->plugins[$index[$class]] : false; + } + + /** + * Returns the parsed tokens. + * + * @return array + */ + public function getTokens() + { + return $this->tokens; + } + + /** + * Returns if the current state equals the passed state. + * + * @param integer $state State to compare with the current state + * @return boolean TRUE is the state equals to the passed state; FALSE if not + */ + public function isState($state) + { + return ($this->state == $state); + } + + /** + * Parse the CSS source and return a array with parsed tokens. + * + * @param string $source CSS source + * @return array Array with tokens + */ + public function parse($source) + { + // Reset + $this->source = ""; + $this->tokens = array(); + // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create + // several helper variables for plugin handling + $globalTriggerChars = ""; + $plugins = $this->plugins; + $pluginCount = count($plugins); + $pluginIndex = array(); + $pluginTriggerStates = array(); + $pluginTriggerChars = array(); + for ($i = 0, $l = count($plugins); $i < $l; $i++) { + $tPluginClassName = get_class($plugins[$i]); + $pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars()); + $tPluginTriggerStates = $plugins[$i]->getTriggerStates(); + $pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|".implode("|", $tPluginTriggerStates)."|"; + $pluginIndex[$tPluginClassName] = $i; + for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++) { + $c = substr($pluginTriggerChars[$i], $ii, 1); + if (strpos($globalTriggerChars, $c) === false) { + $globalTriggerChars .= $c; + } + } + } + // Normalise line endings + $source = str_replace("\r\n", "\n", $source); // Windows to Unix line endings + $source = str_replace("\r", "\n", $source); // Mac to Unix line endings + $this->source = $source; + // Variables + $buffer = &$this->buffer; + $exclusive = &$this->stateExclusive; + $state = &$this->state; + $c = $p = null; + // -- + for ($i = 0, $l = strlen($source); $i < $l; $i++) { + // Set the current Char + $c = $source[$i]; // Is faster than: $c = substr($source, $i, 1); + // Normalize and filter double whitespace characters + if ($exclusive === false) { + if ($c === "\n" || $c === "\t") { + $c = " "; + } + if ($c === " " && $p === " ") { + continue; + } + } + $buffer .= $c; + // Extended processing only if the current char is a global trigger char + if (strpos($globalTriggerChars, $c) !== false) { + // Exclusive state is set; process with the exclusive plugin + if ($exclusive) { + $tPluginIndex = $pluginIndex[$exclusive]; + if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false)) { + $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state); + // Return value is TRUE => continue with next char + if ($r === true) { + continue; + } // Return value is numeric => set new index and continue with next char + elseif ($r !== false && $r != $i) { + $i = $r; + continue; + } + } + } // Else iterate through the plugins + else { + $triggerState = "|".$state."|"; + for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++) { + // Only process if the current char is one of the plugin trigger chars + if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false)) { + // Process with the plugin + $r = $plugins[$ii]->parse($i, $c, $p, $state); + // Return value is TRUE => break the plugin loop and and continue with next char + if ($r === true) { + break; + } // Return value is numeric => set new index, break the plugin loop and and continue with next char + elseif ($r !== false && $r != $i) { + $i = $r; + break; + } + } + } + } + } + $p = $c; // Set the parent char + } + return $this->tokens; + } + + /** + * Remove the last state of the state stack and return the removed stack value. + * + * @return integer Removed state value + */ + public function popState() + { + $r = array_pop($this->states); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Adds a new state onto the state stack. + * + * @param integer $state State to add onto the state stack. + * @return integer The index of the added state in the state stacks + */ + public function pushState($state) + { + $r = array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Sets/restores the buffer. + * + * @param string $buffer Buffer to set + * @return void + */ + public function setBuffer($buffer) + { + $this->buffer = $buffer; + } + + /** + * Set the exclusive state. + * + * @param string $exclusive Exclusive state + * @return void + */ + public function setExclusive($exclusive) + { + $this->stateExclusive = $exclusive; + } + + /** + * Set the media types state. + * + * @param array $mediaTypes Media types state + * @return void + */ + public function setMediaTypes(array $mediaTypes) + { + $this->stateMediaTypes = $mediaTypes; + } + + /** + * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}. + * + * @param integer $state State to set + * @return integer + */ + public function setState($state) + { + $r = array_pop($this->states); + array_push($this->states, $state); + $this->state = $this->states[count($this->states) - 1]; + return $r; + } + + /** + * Removes the exclusive state. + * + * @return void + */ + public function unsetExclusive() + { + $this->stateExclusive = false; + } + + /** + * Removes the media types state. + * + * @return void + */ + public function unsetMediaTypes() + { + $this->stateMediaTypes = false; + } +} diff --git a/src/CssMin/CssParserPlugin.php b/src/CssMin/CssParserPlugin.php new file mode 100644 index 0000000..5b9adc9 --- /dev/null +++ b/src/CssMin/CssParserPlugin.php @@ -0,0 +1,75 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssParserPlugin +{ + /** + * Plugin configuration. + * + * @var array + */ + protected $configuration = array(); + /** + * The CssParser of the plugin. + * + * @var CssParser + */ + protected $parser = null; + /** + * Plugin buffer. + * + * @var string + */ + protected $buffer = ""; + + /** + * Constructor. + * + * @param CssParser $parser The CssParser object of this plugin. + * @param array $configuration Plugin configuration [optional] + */ + public function __construct(CssParser $parser, array $configuration = null) + { + $this->configuration = $configuration; + $this->parser = $parser; + } + + /** + * Returns the array of chars triggering the parser plugin. + * + * @return array + */ + abstract public function getTriggerChars(); + + /** + * Returns the array of states triggering the parser plugin or FALSE if every state will trigger the parser plugin. + * + * @return array + */ + abstract public function getTriggerStates(); + + /** + * Parser routine of the plugin. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing + */ + abstract public function parse($index, $char, $previousChar, $state); +} diff --git a/src/CssMin/CssRemoveCommentsMinifierFilter.php b/src/CssMin/CssRemoveCommentsMinifierFilter.php new file mode 100644 index 0000000..3a91f28 --- /dev/null +++ b/src/CssMin/CssRemoveCommentsMinifierFilter.php @@ -0,0 +1,33 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveCommentsMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + if (get_class($tokens[$i]) === "CssCommentToken") { + $tokens[$i] = null; + $r++; + } + } + return $r; + } +} diff --git a/src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php b/src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php new file mode 100644 index 0000000..53d59dd --- /dev/null +++ b/src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php @@ -0,0 +1,42 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyAtBlocksMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssAtFontFaceStartToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtKeyframesStartToken" && $next === "CssAtKeyframesEndToken") || + ($current === "CssAtPageStartToken" && $next === "CssAtPageEndToken") || + ($current === "CssAtMediaStartToken" && $next === "CssAtMediaEndToken") + ) { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} diff --git a/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php b/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php new file mode 100644 index 0000000..6104ed3 --- /dev/null +++ b/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php @@ -0,0 +1,40 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveEmptyRulesetsMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) + ) { + $tokens[$i] = null; + $tokens[$i + 1] = null; + $i++; + $r = $r + 2; + } + } + return $r; + } +} diff --git a/src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php b/src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php new file mode 100644 index 0000000..4e36acd --- /dev/null +++ b/src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php @@ -0,0 +1,38 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRemoveLastDelarationSemiColonMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + $current = get_class($tokens[$i]); + $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; + if (($current === "CssRulesetDeclarationToken" && $next === "CssRulesetEndToken") || + ($current === "CssAtFontFaceDeclarationToken" && $next === "CssAtFontFaceEndToken") || + ($current === "CssAtPageDeclarationToken" && $next === "CssAtPageEndToken") + ) { + $tokens[$i]->IsLast = true; + } + } + return 0; + } +} diff --git a/src/CssMin/CssRulesetDeclarationToken.php b/src/CssMin/CssRulesetDeclarationToken.php new file mode 100644 index 0000000..6d00fc0 --- /dev/null +++ b/src/CssMin/CssRulesetDeclarationToken.php @@ -0,0 +1,37 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetDeclarationToken extends CssDeclarationToken +{ + /** + * Media types of the declaration. + * + * @var array + */ + public $MediaTypes = array("all"); + + /** + * Set the properties of a ddocument- or at-rule @media level declaration. + * + * @param string $property Property of the declaration + * @param string $value Value of the declaration + * @param mixed $mediaTypes Media types of the declaration + * @param boolean $isImportant Is the !important flag is set + * @param boolean $isLast Is the declaration the last one of the ruleset + */ + public function __construct($property, $value, $mediaTypes = null, $isImportant = false, $isLast = false) + { + parent::__construct($property, $value, $isImportant, $isLast); + $this->MediaTypes = $mediaTypes ? $mediaTypes : array("all"); + } +} diff --git a/src/CssMin/CssRulesetEndToken.php b/src/CssMin/CssRulesetEndToken.php new file mode 100644 index 0000000..5357087 --- /dev/null +++ b/src/CssMin/CssRulesetEndToken.php @@ -0,0 +1,25 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetEndToken extends CssToken +{ + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return "}"; + } +} diff --git a/src/CssMin/CssRulesetParserPlugin.php b/src/CssMin/CssRulesetParserPlugin.php new file mode 100644 index 0000000..9e53a6b --- /dev/null +++ b/src/CssMin/CssRulesetParserPlugin.php @@ -0,0 +1,134 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array(",", "{", "}", ":", ";"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return array("T_DOCUMENT", "T_AT_MEDIA", "T_RULESET::SELECTORS", "T_RULESET", "T_RULESET_DECLARATION"); + } + + /** + * Selectors. + * + * @var array + */ + private $selectors = array(); + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of Ruleset and selectors + if ($char === "," + && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS") + ) { + if ($state !== "T_RULESET::SELECTORS") { + $this->parser->pushState("T_RULESET::SELECTORS"); + } + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + } // End of selectors and start of declarations + elseif ($char === "{" + && ($state === "T_DOCUMENT" || $state === "T_AT_MEDIA" || $state === "T_RULESET::SELECTORS") + ) { + if ($this->parser->getBuffer() !== "") { + $this->selectors[] = $this->parser->getAndClearBuffer(",{"); + if ($state == "T_RULESET::SELECTORS") { + $this->parser->popState(); + } + $this->parser->pushState("T_RULESET"); + $this->parser->appendToken(new CssRulesetStartToken($this->selectors)); + $this->selectors = array(); + } + } // Start of declaration + elseif ($char === ":" && $state === "T_RULESET") { + $this->parser->pushState("T_RULESET_DECLARATION"); + $this->buffer = $this->parser->getAndClearBuffer(":;", true); + } // Unterminated ruleset declaration + elseif ($char === ":" && $state === "T_RULESET_DECLARATION") { + // Ignore Internet Explorer filter declarations + if ($this->buffer === "filter") { + return false; + } + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated declaration", + $this->buffer.":".$this->parser->getBuffer()."_" + ) + ); + } // End of declaration + elseif (($char === ";" || $char === "}") && $state === "T_RULESET_DECLARATION") { + $value = $this->parser->getAndClearBuffer(";}"); + if (strtolower(substr($value, -10, 10)) === "!important") { + $value = trim(substr($value, 0, -10)); + $isImportant = true; + } else { + $isImportant = false; + } + $this->parser->popState(); + $this->parser->appendToken( + new CssRulesetDeclarationToken( + $this->buffer, + $value, + $this->parser->getMediaTypes(), + $isImportant + ) + ); + // Declaration ends with a right curly brace; so we have to end the ruleset + if ($char === "}") { + $this->parser->appendToken(new CssRulesetEndToken()); + $this->parser->popState(); + } + $this->buffer = ""; + } // End of ruleset + elseif ($char === "}" && $state === "T_RULESET") { + $this->parser->popState(); + $this->parser->clearBuffer(); + $this->parser->appendToken(new CssRulesetEndToken()); + $this->buffer = ""; + $this->selectors = array(); + } else { + return false; + } + + return true; + } +} diff --git a/src/CssMin/CssRulesetStartToken.php b/src/CssMin/CssRulesetStartToken.php new file mode 100644 index 0000000..5bea261 --- /dev/null +++ b/src/CssMin/CssRulesetStartToken.php @@ -0,0 +1,42 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssRulesetStartToken extends CssToken +{ + /** + * Array of selectors. + * + * @var array + */ + public $Selectors = array(); + + /** + * Set the properties of a ruleset token. + * + * @param array $selectors Selectors of the ruleset + */ + public function __construct(array $selectors = array()) + { + $this->Selectors = $selectors; + } + + /** + * Implements {@link CssToken::__toString()}. + * + * @return string + */ + public function __toString() + { + return implode(",", $this->Selectors)."{"; + } +} diff --git a/src/CssMin/CssSortRulesetPropertiesMinifierFilter.php b/src/CssMin/CssSortRulesetPropertiesMinifierFilter.php new file mode 100644 index 0000000..ad6a6dd --- /dev/null +++ b/src/CssMin/CssSortRulesetPropertiesMinifierFilter.php @@ -0,0 +1,97 @@ + + * @copyright Rowan Beentje + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssSortRulesetPropertiesMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value larger than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $r = 0; + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + // Only look for ruleset start rules + if (get_class($tokens[$i]) !== "CssRulesetStartToken") { + continue; + } + // Look for the corresponding ruleset end + $endIndex = false; + for ($ii = $i + 1; $ii < $l; $ii++) { + if (get_class($tokens[$ii]) !== "CssRulesetEndToken") { + continue; + } + $endIndex = $ii; + break; + } + if (!$endIndex) { + break; + } + $startIndex = $i; + $i = $endIndex; + // Skip if there's only one token in this ruleset + if ($endIndex - $startIndex <= 2) { + continue; + } + // Ensure that everything between the start and end is a declaration token, for safety + for ($ii = $startIndex + 1; $ii < $endIndex; $ii++) { + if (get_class($tokens[$ii]) !== "CssRulesetDeclarationToken") { + continue(2); + } + } + $declarations = array_slice($tokens, $startIndex + 1, $endIndex - $startIndex - 1); + // Check whether a sort is required + $sortRequired = $lastPropertyName = false; + foreach ($declarations as $declaration) { + if ($lastPropertyName) { + if (strcmp($lastPropertyName, $declaration->Property) > 0) { + $sortRequired = true; + break; + } + } + $lastPropertyName = $declaration->Property; + } + if (!$sortRequired) { + continue; + } + // Arrange the declarations alphabetically by name + usort($declarations, array(__CLASS__, "userDefinedSort1")); + // Update "IsLast" property + for ($ii = 0, $ll = count($declarations) - 1; $ii <= $ll; $ii++) { + if ($ii == $ll) { + $declarations[$ii]->IsLast = true; + } else { + $declarations[$ii]->IsLast = false; + } + } + // Splice back into the array. + array_splice($tokens, $startIndex + 1, $endIndex - $startIndex - 1, $declarations); + $r += $endIndex - $startIndex - 1; + } + return $r; + } + + /** + * User defined sort function. + * + * @param $a + * @param $b + * @return int + */ + public static function userDefinedSort1($a, $b) + { + return strcmp($a->Property, $b->Property); + } +} diff --git a/src/CssMin/CssStringParserPlugin.php b/src/CssMin/CssStringParserPlugin.php new file mode 100644 index 0000000..8c59a15 --- /dev/null +++ b/src/CssMin/CssStringParserPlugin.php @@ -0,0 +1,106 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssStringParserPlugin extends CssParserPlugin +{ + /** + * Current string delimiter char. + * + * @var string + */ + private $delimiterChar = null; + + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("\"", "'", "\n"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if (($char === "\"" || $char === "'") && $state !== "T_STRING") { + $this->delimiterChar = $char; + $this->parser->pushState("T_STRING"); + $this->parser->setExclusive(__CLASS__); + } // Escaped LF in string => remove escape backslash and LF + elseif ($char === "\n" && $previousChar === "\\" && $state === "T_STRING") { + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } // Parse error: Unescaped LF in string literal + elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_STRING") { + $line = $this->parser->getBuffer(); + $this->parser->popState(); + $this->parser->unsetExclusive(); + // Replace the LF with the current string char + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1).$this->delimiterChar); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated string literal", + $line."_" + ) + ); + $this->delimiterChar = null; + } // End of string + elseif ($char === $this->delimiterChar && $state === "T_STRING") { + // If the Previous char is a escape char count the amount of the previous escape chars. If the amount of + // escape chars is uneven do not end the string + if ($previousChar == "\\") { + $source = $this->parser->getSource(); + $c = 1; + $i = $index - 2; + while (substr($source, $i, 1) === "\\") { + $c++; + $i--; + } + if ($c % 2) { + return false; + } + } + $this->parser->popState(); + $this->parser->unsetExclusive(); + $this->delimiterChar = null; + } else { + return false; + } + + return true; + } +} diff --git a/src/CssMin/CssToken.php b/src/CssMin/CssToken.php new file mode 100644 index 0000000..2bceb6b --- /dev/null +++ b/src/CssMin/CssToken.php @@ -0,0 +1,24 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +abstract class CssToken +{ + /** + * Returns the token as string. + * + * @return string + */ + abstract public function __toString(); +} diff --git a/src/CssMin/CssUrlParserPlugin.php b/src/CssMin/CssUrlParserPlugin.php new file mode 100644 index 0000000..ee7c5ca --- /dev/null +++ b/src/CssMin/CssUrlParserPlugin.php @@ -0,0 +1,85 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssUrlParserPlugin extends CssParserPlugin +{ + /** + * Implements {@link CssParserPlugin::getTriggerChars()}. + * + * @return array + */ + public function getTriggerChars() + { + return array("(", ")"); + } + + /** + * Implements {@link CssParserPlugin::getTriggerStates()}. + * + * @return array + */ + public function getTriggerStates() + { + return false; + } + + /** + * Implements {@link CssParserPlugin::parse()}. + * + * @param integer $index Current index + * @param string $char Current char + * @param string $previousChar Previous char + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing + */ + public function parse($index, $char, $previousChar, $state) + { + // Start of string + if ($char === "(" + && strtolower(substr($this->parser->getSource(), $index - 3, 4)) === "url(" + && $state !== "T_URL" + ) { + $this->parser->pushState("T_URL"); + $this->parser->setExclusive(__CLASS__); + } elseif ($char === "\n" && $previousChar === "\\" && $state === "T_URL") { + // Escaped LF in url => remove escape backslash and LF + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -2)); + } elseif ($char === "\n" && $previousChar !== "\\" && $state === "T_URL") { + // Parse error: Unescaped LF in string literal + $line = $this->parser->getBuffer(); + // Replace the LF with the url string delimiter + $this->parser->setBuffer(substr($this->parser->getBuffer(), 0, -1).")"); + $this->parser->popState(); + $this->parser->unsetExclusive(); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated string literal", + $line."_" + ) + ); + } elseif ($char === ")" && $state === "T_URL") { + // End of string + $this->parser->popState(); + $this->parser->unsetExclusive(); + } else { + return false; + } + + return true; + } +} diff --git a/src/CssMin/CssVariablesMinifierFilter.php b/src/CssMin/CssVariablesMinifierFilter.php new file mode 100644 index 0000000..1ce1d0e --- /dev/null +++ b/src/CssMin/CssVariablesMinifierFilter.php @@ -0,0 +1,89 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierFilter extends CssMinifierFilter +{ + /** + * Implements {@link CssMinifierFilter::filter()}. + * + * @param array $tokens Array of objects of type CssToken + * @return integer Count of added, changed or removed tokens; a return value large than 0 will rebuild the array + */ + public function apply(array &$tokens) + { + $variables = array(); + $defaultMediaTypes = array("all"); + $mediaTypes = array(); + $remove = array(); + for ($i = 0, $l = count($tokens); $i < $l; $i++) { + // @variables at-rule block found + if (get_class($tokens[$i]) === "CssAtVariablesStartToken") { + $remove[] = $i; + $mediaTypes = (count($tokens[$i]->MediaTypes) == 0 ? $defaultMediaTypes : $tokens[$i]->MediaTypes); + foreach ($mediaTypes as $mediaType) { + if (!isset($variables[$mediaType])) { + $variables[$mediaType] = array(); + } + } + // Read the variable declaration tokens + for ($i = $i; $i < $l; $i++) { + // Found a variable declaration => read the variable values + if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken") { + foreach ($mediaTypes as $mediaType) { + $variables[$mediaType][$tokens[$i]->Property] = $tokens[$i]->Value; + } + $remove[] = $i; + } // Found the variables end token => break; + elseif (get_class($tokens[$i]) === "CssAtVariablesEndToken") { + $remove[] = $i; + break; + } + } + } + } + // Variables in @variables at-rule blocks + foreach ($variables as $mediaType => $null) { + foreach ($variables[$mediaType] as $variable => $value) { + // If a var() statement in a variable value found... + if (stripos($value, "var") !== false && preg_match_all("/var\((.+)\)/iSU", $value, $m)) { + // ... then replace the var() statement with the variable values. + for ($i = 0, $l = count($m[0]); $i < $l; $i++) { + $variables[$mediaType][$variable] = str_replace( + $m[0][$i], + (isset($variables[$mediaType][$m[1][$i]]) ? $variables[$mediaType][$m[1][$i]] : ""), + $variables[$mediaType][$variable] + ); + } + } + } + } + // Remove the complete @variables at-rule block + foreach ($remove as $i) { + $tokens[$i] = null; + } + if (!($plugin = $this->minifier->getPlugin("CssVariablesMinifierPlugin"))) { + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": The plugin CssVariablesMinifierPlugin was not found but is required for ".__CLASS__."" + ) + ); + } else { + $plugin->setVariables($variables); + } + return count($remove); + } +} diff --git a/src/CssMin/CssVariablesMinifierPlugin.php b/src/CssMin/CssVariablesMinifierPlugin.php new file mode 100644 index 0000000..29bbc46 --- /dev/null +++ b/src/CssMin/CssVariablesMinifierPlugin.php @@ -0,0 +1,112 @@ + + * @variables + * { + * defaultColor: black; + * } + * color: var(defaultColor); + * + * + * Will get converted to: + * + * color:black; + * + * + * @package CssMin/Minifier/Plugins + * @link http://code.google.com/p/cssmin/ + * @author Joe Scylla + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssVariablesMinifierPlugin extends CssMinifierPlugin +{ + /** + * Regular expression matching a value. + * + * @var string + */ + private $reMatch = "/var\((.+)\)/iSU"; + /** + * Parsed variables. + * + * @var array + */ + private $variables = null; + + /** + * Returns the variables. + * + * @return array + */ + public function getVariables() + { + return $this->variables; + } + + /** + * Implements {@link CssMinifierPlugin::minify()}. + * + * @param CssToken $token Token to process + * @return boolean Return TRUE to break the processing of this token; FALSE to continue + */ + public function apply(CssToken &$token) + { + if (stripos($token->Value, "var") !== false && preg_match_all($this->reMatch, $token->Value, $m)) { + $mediaTypes = $token->MediaTypes; + if (!in_array("all", $mediaTypes)) { + $mediaTypes[] = "all"; + } + for ($i = 0, $l = count($m[0]); $i < $l; $i++) { + $variable = trim($m[1][$i]); + foreach ($mediaTypes as $mediaType) { + if (isset($this->variables[$mediaType], $this->variables[$mediaType][$variable])) { + // Variable value found => set the declaration value to the variable value and return + $token->Value = str_replace($m[0][$i], $this->variables[$mediaType][$variable], $token->Value); + continue 2; + } + } + // If no value was found trigger an error and replace the token with a CssNullToken + CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": No value found for variable ".$variable." in media types ".implode(", ", $mediaTypes)."", (string)$token)); + $token = new CssNullToken(); + return true; + } + } + return false; + } + + /** + * Implements {@link aMinifierPlugin::getTriggerTokens()} + * + * @return array + */ + public function getTriggerTokens() + { + return array + ( + "CssAtFontFaceDeclarationToken", + "CssAtPageDeclarationToken", + "CssRulesetDeclarationToken" + ); + } + + /** + * Sets the variables. + * + * @param array $variables Variables to set + * @return void + */ + public function setVariables(array $variables) + { + $this->variables = $variables; + } +} diff --git a/src/CssMin/CssWhitesmithsFormatter.php b/src/CssMin/CssWhitesmithsFormatter.php new file mode 100644 index 0000000..9fcf9b2 --- /dev/null +++ b/src/CssMin/CssWhitesmithsFormatter.php @@ -0,0 +1,87 @@ + + * @copyright 2008 - 2011 Joe Scylla + * @license http://opensource.org/licenses/mit-license.php MIT License + * @version 3.0.1 + */ +class CssWhitesmithsFormatter extends CssFormatter +{ + /** + * Implements {@link CssFormatter::__toString()}. + * + * @return string + */ + public function __toString() + { + $r = array(); + $level = 0; + for ($i = 0, $l = count($this->tokens); $i < $l; $i++) { + $token = $this->tokens[$i]; + $class = get_class($token); + $indent = str_repeat($this->indent, $level); + if ($class === "CssCommentToken") { + $lines = array_map("trim", explode("\n", $token->Comment)); + for ($ii = 0, $ll = count($lines); $ii < $ll; $ii++) { + $r[] = $indent.(substr($lines[$ii], 0, 1) == "*" ? " " : "").$lines[$ii]; + } + } elseif ($class === "CssAtCharsetToken") { + $r[] = $indent."@charset ".$token->Charset.";"; + } elseif ($class === "CssAtFontFaceStartToken") { + $r[] = $indent."@font-face"; + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class === "CssAtImportToken") { + $r[] = $indent."@import ".$token->Import." ".implode(", ", $token->MediaTypes).";"; + } elseif ($class === "CssAtKeyframesStartToken") { + $r[] = $indent."@keyframes \"".$token->Name."\""; + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class === "CssAtMediaStartToken") { + $r[] = $indent."@media ".implode(", ", $token->MediaTypes); + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class === "CssAtPageStartToken") { + $r[] = $indent."@page"; + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class === "CssAtVariablesStartToken") { + $r[] = $indent."@variables ".implode(", ", $token->MediaTypes); + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class === "CssRulesetStartToken" || $class === "CssAtKeyframesRulesetStartToken") { + $r[] = $indent.implode(", ", $token->Selectors); + $r[] = $this->indent.$indent."{"; + $level++; + } elseif ($class == "CssAtFontFaceDeclarationToken" + || $class === "CssAtKeyframesRulesetDeclarationToken" + || $class === "CssAtPageDeclarationToken" + || $class == "CssAtVariablesDeclarationToken" + || $class === "CssRulesetDeclarationToken" + ) { + $declaration = $indent.$token->Property.": "; + if ($this->padding) { + $declaration = str_pad($declaration, $this->padding, " ", STR_PAD_RIGHT); + } + $r[] = $declaration.$token->Value.($token->IsImportant ? " !important" : "").";"; + } elseif ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtKeyframesEndToken" + || $class === "CssAtKeyframesRulesetEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + || $class === "CssRulesetEndToken" + ) { + $r[] = $indent."}"; + $level--; + } + } + return implode("\n", $r); + } +} diff --git a/src/HtmlMin/HtmlMin.php b/src/HtmlMin/HtmlMin.php index e25f753..8337d87 100644 --- a/src/HtmlMin/HtmlMin.php +++ b/src/HtmlMin/HtmlMin.php @@ -1,122 +1,128 @@ preserveWhiteSpace = false; + @$doc->loadHTML($html); + $xpath = new \DOMXPath($doc); + foreach ($xpath->query('//comment()') as $comment) { + $val= $comment->nodeValue; + if (strpos($val, '[') !== 0) { + $comment->parentNode->removeChild($comment); + } + } + $doc->normalizeDocument(); + $textnodes = $xpath->query('//text()'); + $skip = ["style","pre","code","script","textarea"]; + foreach ($textnodes as $t) { + $xp = $t->getNodePath(); + $doskip = false; + foreach ($skip as $pattern) { + if (strpos($xp, "/$pattern") !== false) { + $doskip = true; + break; + } + } + if ($doskip) { + continue; + } + $t->nodeValue = preg_replace("/\s{2,}/", " ", $t->nodeValue); + } + $doc->normalizeDocument(); + $divnodes = $xpath->query('//div|//p|//nav|//footer|//article|//script|//hr|//br'); + foreach ($divnodes as $d) { + $candidates = []; + if (count($d->childNodes)) { + $candidates[] = $d->firstChild; + $candidates[] = $d->lastChild; + $candidates[] = $d->previousSibling; + $candidates[] = $d->nextSibling; + } + foreach ($candidates as $c) { + if ($c === null) { + continue; + } + if ($c->nodeType == 3) { + $c->nodeValue = trim($c->nodeValue); + } + } + } -PHPWee PHP Minifier Package - http://searchturbine.com/php/phpwee + $doc->normalizeDocument(); -Copyright (c) 2015, SearchTurbine - Enterprise Search for Everyone -http://searchturbine.com/ + if ($js) { + $scriptnodes = $xpath->query('//script'); + foreach ($scriptnodes as $d) { + if ($d->hasAttribute("type") && strtolower($d->getAttribute("type"))!=='text/javascript' ) { + continue; + } + if ($d->hasAttribute("data-no-min")) { + continue; + } + if (trim($d->nodeValue)=="") { + continue; + } + $d->nodeValue = \PHPWee\JSMin::minify($d->nodeValue); + } + } -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - -*/ - // -- Class Name : HtmlMin - // -- Purpose : PHP class to minify html code. - // -- Usage: echo PHPWee\Minify::html($myhtml); - // -- notes: aply data-no-min to a style or script node to exempt it - // -- HTML 4, XHTML, and HTML 5 compliant - - class HtmlMin{ - // -- Function Name : minify - Params : $html, $js = true, $css = true - public static function minify($html, $js = true, $css = true){ - $doc = new \DOMDocument(); - $doc->preserveWhiteSpace = false; - @$doc->loadHTML($html); - $xpath = new \DOMXPath($doc); - foreach ($xpath->query('//comment()') as $comment) { - $val= $comment->nodeValue; - if( strpos($val,'[')!==0){ - $comment->parentNode->removeChild($comment); - } - } - $doc->normalizeDocument(); - $textnodes = $xpath->query('//text()'); - $skip = ["style","pre","code","script","textarea"]; - foreach($textnodes as $t){ - $xp = $t->getNodePath(); - $doskip = false; - foreach($skip as $pattern){ - if(strpos($xp,"/$pattern")!==false){ - $doskip = true; - break; - } - } - if($doskip){ - continue; - } - $t->nodeValue = preg_replace("/\s{2,}/", " ", $t->nodeValue); - } - $doc->normalizeDocument(); - $divnodes = $xpath->query('//div|//p|//nav|//footer|//article|//script|//hr|//br'); - foreach($divnodes as $d){ - $candidates = []; - if(count($d->childNodes)){ - $candidates[] = $d->firstChild; - $candidates[] = $d->lastChild; - $candidates[] = $d->previousSibling; - $candidates[] = $d->nextSibling; - } - foreach($candidates as $c){ - if($c==null){ - continue; - } - if($c->nodeType==3){ - $c->nodeValue = trim($c->nodeValue); - } - } - } - $doc->normalizeDocument(); - if($js){ - $scriptnodes = $xpath->query('//script'); - foreach($scriptnodes as $d){ - if($d->hasAttribute("type") && strtolower($d->getAttribute("type"))!=='text/javascript' ){ - continue; - } - if($d->hasAttribute("data-no-min")){ - continue; - } - if(trim($d->nodeValue)==""){ - continue; - } - $d->nodeValue = JSMin::minify( $d->nodeValue); - } - } - if($css){ - $cssnodes = $xpath->query('//style'); - foreach($cssnodes as $d){ - if($d->hasAttribute("data-no-min")){ - continue; - } - if(trim($d->nodeValue)==""){ - continue; - } - $d->nodeValue = CssMin::minify( $d->nodeValue); - } - } - return ($doc->saveHTML()); - } - } \ No newline at end of file + if ($css) { + $cssnodes = $xpath->query('//style'); + foreach ($cssnodes as $d) { + if ($d->hasAttribute("data-no-min")) { + continue; + } + if (trim($d->nodeValue) == "") { + continue; + } + $d->nodeValue = \PHPWee\CssMin::minify($d->nodeValue); + } + } + return ($doc->saveHTML()); + } +} \ No newline at end of file diff --git a/src/JsMin/JsMin.php b/src/JsMin/JsMin.php index 8649358..e687066 100644 --- a/src/JsMin/JsMin.php +++ b/src/JsMin/JsMin.php @@ -1,5 +1,6 @@ min(); } @@ -161,7 +162,7 @@ public function min() * ACTION_DELETE_A_B = Get the next B. * * @param int $command - * @throws JSMin_UnterminatedRegExpException|JSMin_UnterminatedStringException + * @throws UnterminatedRegExpException|UnterminatedStringException */ protected function action($command) { @@ -178,7 +179,7 @@ protected function action($command) } switch ($command) { - case self::ACTION_KEEP_A: // 1 + case self::ACTION_KEEP_A: $this->output .= $this->a; if ($this->keptComment) { @@ -190,11 +191,12 @@ protected function action($command) $this->lastByteOut = $this->a; // fallthrough intentional - case self::ACTION_DELETE_A: // 2 + case self::ACTION_DELETE_A: $this->a = $this->b; + if ($this->a === "'" || $this->a === '"') { // string literal $str = $this->a; // in case needed for exception - for(;;) { + for (;;) { $this->output .= $this->a; $this->lastByteOut = $this->a; @@ -204,8 +206,9 @@ protected function action($command) } if ($this->isEOF($this->a)) { $byte = $this->inputIndex - 1; - throw new JSMin_UnterminatedStringException( - "JSMin: Unterminated String at byte {$byte}: {$str}"); + throw new UnterminatedStringException( + "JSMin: Unterminated String at byte {$byte}: {$str}" + ); } $str .= $this->a; if ($this->a === '\\') { @@ -219,16 +222,17 @@ protected function action($command) } // fallthrough intentional - case self::ACTION_DELETE_A_B: // 3 + case self::ACTION_DELETE_A_B: $this->b = $this->next(); + if ($this->b === '/' && $this->isRegexpLiteral()) { $this->output .= $this->a . $this->b; $pattern = '/'; // keep entire pattern in case we need to report it in the exception - for(;;) { + for (;;) { $this->a = $this->get(); $pattern .= $this->a; if ($this->a === '[') { - for(;;) { + for (;;) { $this->output .= $this->a; $this->a = $this->get(); $pattern .= $this->a; @@ -241,9 +245,10 @@ protected function action($command) $pattern .= $this->a; } if ($this->isEOF($this->a)) { - throw new JSMin_UnterminatedRegExpException( + throw new UnterminatedRegExpException( "JSMin: Unterminated set in RegExp at byte " - . $this->inputIndex .": {$pattern}"); + . $this->inputIndex .": {$pattern}" + ); } } } @@ -256,15 +261,15 @@ protected function action($command) $pattern .= $this->a; } elseif ($this->isEOF($this->a)) { $byte = $this->inputIndex - 1; - throw new JSMin_UnterminatedRegExpException( - "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}"); + throw new UnterminatedRegExpException( + "JSMin: Unterminated RegExp at byte {$byte}: {$pattern}" + ); } $this->output .= $this->a; $this->lastByteOut = $this->a; } $this->b = $this->next(); } - // end case ACTION_DELETE_A_B } } @@ -278,12 +283,12 @@ protected function isRegexpLiteral() return true; } - // we have to check for a preceding keyword, and we don't need to pattern - // match over the whole output. - $recentOutput = substr($this->output, -10); + // we have to check for a preceding keyword, and we don't need to pattern + // match over the whole output. + $recentOutput = substr($this->output, -10); - // check if return/typeof directly precede a pattern without a space - foreach (array('return', 'typeof') as $keyword) { + // check if return/typeof directly precede a pattern without a space + foreach (array('return', 'typeof') as $keyword) { if ($this->a !== substr($keyword, -1)) { // certainly wasn't keyword continue; @@ -295,13 +300,13 @@ protected function isRegexpLiteral() } } - // check all keywords - if ($this->a === ' ' || $this->a === "\n") { - if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) { - if ($m[1] === '' || !$this->isAlphaNum($m[1])) { - return true; - } - } + // check all keywords + if ($this->a === ' ' || $this->a === "\n") { + if (preg_match('~(^|[\\s\\S])(?:case|else|in|return|typeof)$~', $recentOutput, $m)) { + if ($m[1] === '' || !$this->isAlphaNum($m[1])) { + return true; + } + } } return false; @@ -391,13 +396,13 @@ protected function consumeSingleLineComment() /** * Consume a multiple line comment from input (possibly retaining it) * - * @throws JSMin_UnterminatedCommentException + * @throws UnterminatedCommentException */ protected function consumeMultipleLineComment() { $this->get(); $comment = ''; - for(;;) { + for (;;) { $get = $this->get(); if ($get === '*') { if ($this->peek() === '/') { // end of comment reached @@ -409,15 +414,16 @@ protected function consumeMultipleLineComment() $this->keptComment = "\n"; } $this->keptComment .= "/*!" . substr($comment, 1) . "*/\n"; - } else if (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { + } elseif (preg_match('/^@(?:cc_on|if|elif|else|end)\\b/', $comment)) { // IE conditional $this->keptComment .= "/*{$comment}*/"; } return; } } elseif ($get === null) { - throw new JSMin_UnterminatedCommentException( - "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}"); + throw new UnterminatedCommentException( + "JSMin: Unterminated comment at byte {$this->inputIndex}: /*{$comment}" + ); } $comment .= $get; } @@ -446,7 +452,3 @@ protected function next() return $get; } } - -class JSMin_UnterminatedStringException extends \Exception {} -class JSMin_UnterminatedCommentException extends \Exception {} -class JSMin_UnterminatedRegExpException extends \Exception {} \ No newline at end of file diff --git a/src/JsMin/UnterminatedCommentException.php b/src/JsMin/UnterminatedCommentException.php new file mode 100644 index 0000000..7e5325b --- /dev/null +++ b/src/JsMin/UnterminatedCommentException.php @@ -0,0 +1,10 @@ + Date: Tue, 15 Sep 2015 13:41:50 +0200 Subject: [PATCH 2/8] Table structure fixed. --- examples/example.php | 44 +++++++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 11 deletions(-) diff --git a/examples/example.php b/examples/example.php index 1ed5fd7..c7dce53 100644 --- a/examples/example.php +++ b/examples/example.php @@ -1,9 +1,9 @@ -$subjectGzipped Bytes Before PHPWeeGzipped Bytes After PHPWee% Performance Boost$before before$after after $improvement % faster

"; -} \ No newline at end of file + +/** + * @param $subject + * @param $minified + * @param $html + */ +function print_performance_graph($subject, $minified, $html) +{ + $before = strlen(gzcompress($html)); + $after = strlen(gzcompress($minified)); + $improvement = 100 * (1-($after/$before)); + ?> + + + + + + + + + + + + + + +
Gzipped Bytes Before PHPWeeGzipped Bytes After PHPWee% Performance Boost
before after % faster
+

+ Date: Tue, 15 Sep 2015 13:42:39 +0200 Subject: [PATCH 3/8] .idea added to .gitignore. --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e69de29..485dee6 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1 @@ +.idea From 5f79aa7c5e7c44becae5ada927b62d4a575f96fd Mon Sep 17 00:00:00 2001 From: Carsten Henkelmann Date: Thu, 17 Sep 2015 11:53:31 +0200 Subject: [PATCH 4/8] Namespace fixes and code cleanup. --- composer.json | 32 +++---- src/CssMin/CssAtBlockStartToken.php | 1 - src/CssMin/CssAtCharsetParserPlugin.php | 20 +++-- src/CssMin/CssAtCharsetToken.php | 1 - src/CssMin/CssAtFontFaceDeclarationToken.php | 1 - src/CssMin/CssAtFontFaceEndToken.php | 1 - src/CssMin/CssAtFontFaceParserPlugin.php | 27 ++++-- src/CssMin/CssAtImportToken.php | 5 +- src/CssMin/CssAtKeyframesEndToken.php | 1 - src/CssMin/CssAtKeyframesParserPlugin.php | 39 +++++++-- .../CssAtKeyframesRulesetDeclarationToken.php | 1 - src/CssMin/CssAtKeyframesRulesetEndToken.php | 1 - .../CssAtKeyframesRulesetStartToken.php | 1 - src/CssMin/CssAtKeyframesStartToken.php | 4 +- src/CssMin/CssAtMediaEndToken.php | 1 - src/CssMin/CssAtMediaParserPlugin.php | 11 ++- src/CssMin/CssAtMediaStartToken.php | 1 - src/CssMin/CssAtPageDeclarationToken.php | 1 - src/CssMin/CssAtPageEndToken.php | 1 - src/CssMin/CssAtPageParserPlugin.php | 20 ++++- src/CssMin/CssAtPageStartToken.php | 1 - src/CssMin/CssAtVariablesParserPlugin.php | 20 ++++- src/CssMin/CssAtVariablesStartToken.php | 1 - src/CssMin/CssCommentParserPlugin.php | 6 +- src/CssMin/CssCommentToken.php | 1 - ...CompressExpressionValuesMinifierPlugin.php | 5 +- .../CssConvertFontWeightMinifierPlugin.php | 4 +- .../CssConvertHslColorsMinifierPlugin.php | 6 +- ...ConvertLevel3AtKeyframesMinifierFilter.php | 3 +- ...sConvertLevel3PropertiesMinifierFilter.php | 54 +++++++++--- .../CssConvertNamedColorsMinifierPlugin.php | 9 +- src/CssMin/CssError.php | 10 ++- src/CssMin/CssExpressionParserPlugin.php | 16 +++- src/CssMin/CssImportImportsMinifierFilter.php | 83 +++++++++++++++---- src/CssMin/CssMin.php | 6 -- src/CssMin/CssMinifier.php | 24 ++++-- src/CssMin/CssOtbsFormatter.php | 3 +- src/CssMin/CssParser.php | 35 +++++--- src/CssMin/CssParserPlugin.php | 1 + .../CssRemoveEmptyRulesetsMinifierFilter.php | 4 +- src/CssMin/CssRulesetParserPlugin.php | 1 + src/CssMin/CssStringParserPlugin.php | 1 + src/CssMin/CssToken.php | 15 ++++ src/CssMin/CssUrlParserPlugin.php | 1 + src/CssMin/CssVariablesMinifierFilter.php | 3 +- src/CssMin/CssVariablesMinifierPlugin.php | 9 +- src/HtmlMin/HtmlMin.php | 32 +++++-- src/JsMin/JsMin.php | 2 +- 48 files changed, 390 insertions(+), 136 deletions(-) diff --git a/composer.json b/composer.json index c8bc43a..9e99c7b 100644 --- a/composer.json +++ b/composer.json @@ -6,22 +6,24 @@ "license": "BSD", "homepage": "http://searchturbine.com/php/phpwee", "authors": [ - { - "name": "Search Turbine - Open Source PHP Dev Team", - "email": "community@searchturbine.com", - "homepage": "http://searchturbine.com", - "role": "Developer" - } - ], + { + "name": "Search Turbine - Open Source PHP Dev Team", + "email": "community@searchturbine.com", + "homepage": "http://searchturbine.com", + "role": "Developer" + } + ], "repositories": [ - { - "type": "vcs", - "url": "https://github.com/searchturbine/phpwee-php-minifier" - } - ], - "autoload": { - "files": ["phpwee.php"] - }, + { + "type": "vcs", + "url": "https://github.com/searchturbine/phpwee-php-minifier" + } + ], + "autoload": { + "psr-4": { + "PHPWee\\": "src/" + } + }, "require": { "php": ">=5.3.0" } diff --git a/src/CssMin/CssAtBlockStartToken.php b/src/CssMin/CssAtBlockStartToken.php index 3cd22a3..6c0b085 100644 --- a/src/CssMin/CssAtBlockStartToken.php +++ b/src/CssMin/CssAtBlockStartToken.php @@ -13,5 +13,4 @@ */ abstract class CssAtBlockStartToken extends CssToken { - } diff --git a/src/CssMin/CssAtCharsetParserPlugin.php b/src/CssMin/CssAtCharsetParserPlugin.php index f5cba3d..b409d59 100644 --- a/src/CssMin/CssAtCharsetParserPlugin.php +++ b/src/CssMin/CssAtCharsetParserPlugin.php @@ -41,21 +41,29 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 8)) === "@charset" + ) { $this->parser->pushState("T_AT_CHARSET"); $this->parser->clearBuffer(); return $index + 8; - } elseif (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") { + } + + if (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") { $charset = $this->parser->getAndClearBuffer(";"); $this->parser->popState(); $this->parser->appendToken(new CssAtCharsetToken($charset)); - } else { - return false; + return true; } - return true; + + return false; } } diff --git a/src/CssMin/CssAtCharsetToken.php b/src/CssMin/CssAtCharsetToken.php index 46b0be8..f0aff65 100644 --- a/src/CssMin/CssAtCharsetToken.php +++ b/src/CssMin/CssAtCharsetToken.php @@ -24,7 +24,6 @@ class CssAtCharsetToken extends CssToken * Set the properties of @charset at-rule token. * * @param string $charset Charset of the @charset at-rule token - * @return void */ public function __construct($charset) { diff --git a/src/CssMin/CssAtFontFaceDeclarationToken.php b/src/CssMin/CssAtFontFaceDeclarationToken.php index bc5789b..a3ee4d6 100644 --- a/src/CssMin/CssAtFontFaceDeclarationToken.php +++ b/src/CssMin/CssAtFontFaceDeclarationToken.php @@ -13,5 +13,4 @@ */ class CssAtFontFaceDeclarationToken extends CssDeclarationToken { - } diff --git a/src/CssMin/CssAtFontFaceEndToken.php b/src/CssMin/CssAtFontFaceEndToken.php index 856a8f3..356748b 100644 --- a/src/CssMin/CssAtFontFaceEndToken.php +++ b/src/CssMin/CssAtFontFaceEndToken.php @@ -13,5 +13,4 @@ */ class CssAtFontFaceEndToken extends CssAtBlockEndToken { - } diff --git a/src/CssMin/CssAtFontFaceParserPlugin.php b/src/CssMin/CssAtFontFaceParserPlugin.php index 2d0264f..302b3ed 100644 --- a/src/CssMin/CssAtFontFaceParserPlugin.php +++ b/src/CssMin/CssAtFontFaceParserPlugin.php @@ -42,12 +42,18 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { // Start of @font-face at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 10)) === "@font-face" + ) { $this->parser->pushState("T_AT_FONT_FACE::PREPARE"); $this->parser->clearBuffer(); return $index + 10; @@ -66,9 +72,16 @@ public function parse($index, $char, $previousChar, $state) if ($this->buffer === "filter") { return false; } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @font-face declaration", $this->buffer.":".$this->parser->getBuffer()."_")); - } // End of @font-face declaration - elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") { + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated @font-face declaration", + $this->buffer.":".$this->parser->getBuffer()."_" + ) + ); + } elseif (($char === ";" || $char === "}") && $state === "T_AT_FONT_FACE_DECLARATION") { + // End of @font-face declaration $value = $this->parser->getAndClearBuffer(";}"); if (strtolower(substr($value, -10, 10)) === "!important") { $value = trim(substr($value, 0, -10)); @@ -84,14 +97,14 @@ public function parse($index, $char, $previousChar, $state) $this->parser->appendToken(new CssAtFontFaceEndToken()); $this->parser->popState(); } - } // End of @font-face at-rule block - elseif ($char === "}" && $state === "T_AT_FONT_FACE") { + } elseif ($char === "}" && $state === "T_AT_FONT_FACE") { // End of @font-face at-rule block $this->parser->appendToken(new CssAtFontFaceEndToken()); $this->parser->clearBuffer(); $this->parser->popState(); } else { return false; } + return true; } } diff --git a/src/CssMin/CssAtImportToken.php b/src/CssMin/CssAtImportToken.php index a39b8bf..da20a72 100644 --- a/src/CssMin/CssAtImportToken.php +++ b/src/CssMin/CssAtImportToken.php @@ -31,7 +31,6 @@ class CssAtImportToken extends CssToken * * @param string $import Import path * @param array $mediaTypes Media types - * @return void */ public function __construct($import, $mediaTypes) { @@ -46,6 +45,8 @@ public function __construct($import, $mediaTypes) */ public function __toString() { - return "@import \"".$this->Import."\"".(count($this->MediaTypes) > 0 ? " ".implode(",", $this->MediaTypes) : "").";"; + return "@import \"".$this->Import."\"" + . (count($this->MediaTypes) > 0 ? " ".implode(",", $this->MediaTypes) : "") + . ";"; } } diff --git a/src/CssMin/CssAtKeyframesEndToken.php b/src/CssMin/CssAtKeyframesEndToken.php index a91b3d7..3123ca2 100644 --- a/src/CssMin/CssAtKeyframesEndToken.php +++ b/src/CssMin/CssAtKeyframesEndToken.php @@ -13,5 +13,4 @@ */ class CssAtKeyframesEndToken extends CssAtBlockEndToken { - } diff --git a/src/CssMin/CssAtKeyframesParserPlugin.php b/src/CssMin/CssAtKeyframesParserPlugin.php index e5d4e32..5e78292 100644 --- a/src/CssMin/CssAtKeyframesParserPlugin.php +++ b/src/CssMin/CssAtKeyframesParserPlugin.php @@ -41,7 +41,14 @@ public function getTriggerChars() */ public function getTriggerStates() { - return array("T_DOCUMENT", "T_AT_KEYFRAMES::NAME", "T_AT_KEYFRAMES", "T_AT_KEYFRAMES_RULESETS", "T_AT_KEYFRAMES_RULESET", "T_AT_KEYFRAMES_RULESET_DECLARATION"); + return array( + "T_DOCUMENT", + "T_AT_KEYFRAMES::NAME", + "T_AT_KEYFRAMES", + "T_AT_KEYFRAMES_RULESETS", + "T_AT_KEYFRAMES_RULESET", + "T_AT_KEYFRAMES_RULESET_DECLARATION" + ); } /** @@ -50,24 +57,36 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { // Start of @keyframes at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 10)) === "@keyframes" + ) { $this->atRuleName = "keyframes"; $this->parser->pushState("T_AT_KEYFRAMES::NAME"); $this->parser->clearBuffer(); return $index + 10; } // Start of @keyframes at-rule block (@-moz-keyframes) - elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes") { + elseif ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 15)) === "@-moz-keyframes" + ) { $this->atRuleName = "-moz-keyframes"; $this->parser->pushState("T_AT_KEYFRAMES::NAME"); $this->parser->clearBuffer(); return $index + 15; } // Start of @keyframes at-rule block (@-webkit-keyframes) - elseif ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes") { + elseif ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 18)) === "@-webkit-keyframes" + ) { $this->atRuleName = "-webkit-keyframes"; $this->parser->pushState("T_AT_KEYFRAMES::NAME"); $this->parser->clearBuffer(); @@ -100,7 +119,14 @@ public function parse($index, $char, $previousChar, $state) if ($this->buffer === "filter") { return false; } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @keyframes ruleset declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated @keyframes ruleset declaration", + $this->buffer.":".$this->parser->getBuffer()."_" + ) + ); } // End of declaration elseif (($char === ";" || $char === "}") && $state === "T_AT_KEYFRAMES_RULESET_DECLARATION") { $value = $this->parser->getAndClearBuffer(";}"); @@ -132,6 +158,7 @@ public function parse($index, $char, $previousChar, $state) } else { return false; } + return true; } } diff --git a/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php b/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php index c4018f6..8c8e921 100644 --- a/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php +++ b/src/CssMin/CssAtKeyframesRulesetDeclarationToken.php @@ -13,5 +13,4 @@ */ class CssAtKeyframesRulesetDeclarationToken extends CssDeclarationToken { - } diff --git a/src/CssMin/CssAtKeyframesRulesetEndToken.php b/src/CssMin/CssAtKeyframesRulesetEndToken.php index 9f48287..04805ba 100644 --- a/src/CssMin/CssAtKeyframesRulesetEndToken.php +++ b/src/CssMin/CssAtKeyframesRulesetEndToken.php @@ -13,5 +13,4 @@ */ class CssAtKeyframesRulesetEndToken extends CssRulesetEndToken { - } diff --git a/src/CssMin/CssAtKeyframesRulesetStartToken.php b/src/CssMin/CssAtKeyframesRulesetStartToken.php index 62bd3df..6c401d2 100644 --- a/src/CssMin/CssAtKeyframesRulesetStartToken.php +++ b/src/CssMin/CssAtKeyframesRulesetStartToken.php @@ -24,7 +24,6 @@ class CssAtKeyframesRulesetStartToken extends CssRulesetStartToken * Set the properties of a ruleset token. * * @param array $selectors Selectors of the ruleset - * @return void */ public function __construct(array $selectors = array()) { diff --git a/src/CssMin/CssAtKeyframesStartToken.php b/src/CssMin/CssAtKeyframesStartToken.php index 8f6f526..8911451 100644 --- a/src/CssMin/CssAtKeyframesStartToken.php +++ b/src/CssMin/CssAtKeyframesStartToken.php @@ -29,8 +29,8 @@ class CssAtKeyframesStartToken extends CssAtBlockStartToken /** * Sets the properties of the @page at-rule. * - * @param string $selector Selector - * @return void + * @param $name + * @param null $atRuleName */ public function __construct($name, $atRuleName = null) { diff --git a/src/CssMin/CssAtMediaEndToken.php b/src/CssMin/CssAtMediaEndToken.php index a6d1edd..82bf077 100644 --- a/src/CssMin/CssAtMediaEndToken.php +++ b/src/CssMin/CssAtMediaEndToken.php @@ -13,5 +13,4 @@ */ class CssAtMediaEndToken extends CssAtBlockEndToken { - } diff --git a/src/CssMin/CssAtMediaParserPlugin.php b/src/CssMin/CssAtMediaParserPlugin.php index 28fdaf5..e0b7b82 100644 --- a/src/CssMin/CssAtMediaParserPlugin.php +++ b/src/CssMin/CssAtMediaParserPlugin.php @@ -43,11 +43,17 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 6)) === "@media" + ) { $this->parser->pushState("T_AT_MEDIA::PREPARE"); $this->parser->clearBuffer(); return $index + 6; @@ -64,6 +70,7 @@ public function parse($index, $char, $previousChar, $state) } else { return false; } + return true; } } diff --git a/src/CssMin/CssAtMediaStartToken.php b/src/CssMin/CssAtMediaStartToken.php index 06d5ad8..60bd8f8 100644 --- a/src/CssMin/CssAtMediaStartToken.php +++ b/src/CssMin/CssAtMediaStartToken.php @@ -17,7 +17,6 @@ class CssAtMediaStartToken extends CssAtBlockStartToken * Sets the properties of the @media at-rule. * * @param array $mediaTypes Media types - * @return void */ public function __construct(array $mediaTypes = array()) { diff --git a/src/CssMin/CssAtPageDeclarationToken.php b/src/CssMin/CssAtPageDeclarationToken.php index 6e28a2c..e31d639 100644 --- a/src/CssMin/CssAtPageDeclarationToken.php +++ b/src/CssMin/CssAtPageDeclarationToken.php @@ -13,5 +13,4 @@ */ class CssAtPageDeclarationToken extends CssDeclarationToken { - } diff --git a/src/CssMin/CssAtPageEndToken.php b/src/CssMin/CssAtPageEndToken.php index 7c3329f..5ba0ca2 100644 --- a/src/CssMin/CssAtPageEndToken.php +++ b/src/CssMin/CssAtPageEndToken.php @@ -13,5 +13,4 @@ */ class CssAtPageEndToken extends CssAtBlockEndToken { - } diff --git a/src/CssMin/CssAtPageParserPlugin.php b/src/CssMin/CssAtPageParserPlugin.php index 2f400a5..21c5235 100644 --- a/src/CssMin/CssAtPageParserPlugin.php +++ b/src/CssMin/CssAtPageParserPlugin.php @@ -42,12 +42,18 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { // Start of @page at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 5)) === "@page" + ) { $this->parser->pushState("T_AT_PAGE::SELECTOR"); $this->parser->clearBuffer(); return $index + 5; @@ -67,7 +73,14 @@ public function parse($index, $char, $previousChar, $state) if ($this->buffer === "filter") { return false; } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @page declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated @page declaration", + $this->buffer.":".$this->parser->getBuffer()."_" + ) + ); } // End of @page declaration elseif (($char === ";" || $char === "}") && $state == "T_AT_PAGE_DECLARATION") { $value = $this->parser->getAndClearBuffer(";}"); @@ -93,6 +106,7 @@ public function parse($index, $char, $previousChar, $state) } else { return false; } + return true; } } diff --git a/src/CssMin/CssAtPageStartToken.php b/src/CssMin/CssAtPageStartToken.php index 37a723b..3101394 100644 --- a/src/CssMin/CssAtPageStartToken.php +++ b/src/CssMin/CssAtPageStartToken.php @@ -24,7 +24,6 @@ class CssAtPageStartToken extends CssAtBlockStartToken * Sets the properties of the @page at-rule. * * @param string $selector Selector - * @return void */ public function __construct($selector = "") { diff --git a/src/CssMin/CssAtVariablesParserPlugin.php b/src/CssMin/CssAtVariablesParserPlugin.php index 1f1a4a6..b9d20a3 100644 --- a/src/CssMin/CssAtVariablesParserPlugin.php +++ b/src/CssMin/CssAtVariablesParserPlugin.php @@ -42,12 +42,18 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { // Start of @variables at-rule block - if ($char === "@" && $state === "T_DOCUMENT" && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables") { + if ($char === "@" + && $state === "T_DOCUMENT" + && strtolower(substr($this->parser->getSource(), $index, 10)) === "@variables" + ) { $this->parser->pushState("T_AT_VARIABLES::PREPARE"); $this->parser->clearBuffer(); return $index + 10; @@ -67,7 +73,14 @@ public function parse($index, $char, $previousChar, $state) if ($this->buffer === "filter") { return false; } - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Unterminated @variables declaration", $this->buffer.":".$this->parser->getBuffer()."_")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Unterminated @variables declaration", + $this->buffer.":".$this->parser->getBuffer()."_" + ) + ); } // End of @variables declaration elseif (($char === ";" || $char === "}") && $state === "T_AT_VARIABLES_DECLARATION") { $value = $this->parser->getAndClearBuffer(";}"); @@ -88,6 +101,7 @@ public function parse($index, $char, $previousChar, $state) } else { return false; } + return true; } } diff --git a/src/CssMin/CssAtVariablesStartToken.php b/src/CssMin/CssAtVariablesStartToken.php index 9271a3d..d682f3f 100644 --- a/src/CssMin/CssAtVariablesStartToken.php +++ b/src/CssMin/CssAtVariablesStartToken.php @@ -24,7 +24,6 @@ class CssAtVariablesStartToken extends CssAtBlockStartToken * Set the properties of a @variables at-rule token. * * @param array $mediaTypes Media types - * @return void */ public function __construct($mediaTypes = null) { diff --git a/src/CssMin/CssCommentParserPlugin.php b/src/CssMin/CssCommentParserPlugin.php index febe451..3456d57 100644 --- a/src/CssMin/CssCommentParserPlugin.php +++ b/src/CssMin/CssCommentParserPlugin.php @@ -48,7 +48,10 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { @@ -64,6 +67,7 @@ public function parse($index, $char, $previousChar, $state) } else { return false; } + return true; } } diff --git a/src/CssMin/CssCommentToken.php b/src/CssMin/CssCommentToken.php index cf86964..7628337 100644 --- a/src/CssMin/CssCommentToken.php +++ b/src/CssMin/CssCommentToken.php @@ -24,7 +24,6 @@ class CssCommentToken extends CssToken * Set the properties of a comment token. * * @param string $comment Comment including comment delimiters - * @return void */ public function __construct($comment) { diff --git a/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php b/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php index a8c0cec..66e52c5 100644 --- a/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php +++ b/src/CssMin/CssCompressExpressionValuesMinifierPlugin.php @@ -1,6 +1,8 @@ Value, "expression(") !== false) { - $value = $token->Value; $value = substr($token->Value, stripos($token->Value, "expression(") + 10); - $value = trim(JSMin::minify($value)); + $value = trim(JsMin::minify($value)); $token->Value = "expression(".$value.")"; } return false; diff --git a/src/CssMin/CssConvertFontWeightMinifierPlugin.php b/src/CssMin/CssConvertFontWeightMinifierPlugin.php index fa0a4d5..9e4a041 100644 --- a/src/CssMin/CssConvertFontWeightMinifierPlugin.php +++ b/src/CssMin/CssConvertFontWeightMinifierPlugin.php @@ -49,7 +49,8 @@ class CssConvertFontWeightMinifierPlugin extends CssMinifierPlugin */ private $reReplace = "\"\${1}\" . \$this->transformation[\"\${2}\"] . \"\${3}\""; /** - * Transformation table used by the {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}. + * Transformation table used by the + * {@link CssConvertFontWeightMinifierPlugin::$reReplace replace regular expression}. * * @var array */ @@ -66,7 +67,6 @@ class CssConvertFontWeightMinifierPlugin extends CssMinifierPlugin * based on the {@link CssConvertFontWeightMinifierPlugin::$transformation transformation table}. * * @param CssMinifier $minifier The CssMinifier object of this plugin. - * @return void */ public function __construct(CssMinifier $minifier) { diff --git a/src/CssMin/CssConvertHslColorsMinifierPlugin.php b/src/CssMin/CssConvertHslColorsMinifierPlugin.php index bec5b34..f648a72 100644 --- a/src/CssMin/CssConvertHslColorsMinifierPlugin.php +++ b/src/CssMin/CssConvertHslColorsMinifierPlugin.php @@ -89,7 +89,11 @@ private function hsl2hex($hue, $saturation, $lightness) $green = 255 * self::hue2rgb($v1, $v2, $hue); $blue = 255 * self::hue2rgb($v1, $v2, $hue - (1 / 3)); } - return "#".str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT).str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT).str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); + + return "#" + . str_pad(dechex(round($red)), 2, "0", STR_PAD_LEFT) + . str_pad(dechex(round($green)), 2, "0", STR_PAD_LEFT) + . str_pad(dechex(round($blue)), 2, "0", STR_PAD_LEFT); } /** diff --git a/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php b/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php index 5a8d833..5acdd35 100644 --- a/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php +++ b/src/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php @@ -2,7 +2,8 @@ namespace PHPWee\CssMin; /** - * This {@link CssMinifierFilter minifier filter} will convert @keyframes at-rule block to browser specific counterparts. + * This {@link CssMinifierFilter minifier filter} will convert + * @keyframes at-rule block to browser specific counterparts. * * @package CssMin/Minifier/Filters * @link http://code.google.com/p/cssmin/ diff --git a/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php b/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php index 8bf659e..d98ff80 100644 --- a/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php +++ b/src/CssMin/CssConvertLevel3PropertiesMinifierFilter.php @@ -22,7 +22,7 @@ class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter */ private $transformations = array ( - // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored + // Property Array(Mozilla, Webkit, Opera, Internet Explorer); NULL values are placeholders and will get ignored "animation" => array(null, "-webkit-animation", null, null), "animation-delay" => array(null, "-webkit-animation-delay", null, null), "animation-direction" => array(null, "-webkit-animation-direction", null, null), @@ -52,8 +52,18 @@ class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter "border-before-style" => array(null, "-webkit-border-before-style", null, null), "border-before-width" => array(null, "-webkit-border-before-width", null, null), "border-border-bottom-colors" => array("-moz-border-bottom-colors", null, null, null), - "border-bottom-left-radius" => array("-moz-border-radius-bottomleft", "-webkit-border-bottom-left-radius", null, null), - "border-bottom-right-radius" => array("-moz-border-radius-bottomright", "-webkit-border-bottom-right-radius", null, null), + "border-bottom-left-radius" => array( + "-moz-border-radius-bottomleft", + "-webkit-border-bottom-left-radius", + null, + null + ), + "border-bottom-right-radius" => array( + "-moz-border-radius-bottomright", + "-webkit-border-bottom-right-radius", + null, + null + ), "border-end" => array("-moz-border-end", "-webkit-border-end", null, null), "border-end-color" => array("-moz-border-end-color", "-webkit-border-end-color", null, null), "border-end-style" => array("-moz-border-end-style", "-webkit-border-end-style", null, null), @@ -70,7 +80,12 @@ class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter "border-start-width" => array("-moz-border-start-width", "-webkit-border-start-width", null, null), "border-top-colors" => array("-moz-border-top-colors", null, null, null), "border-top-left-radius" => array("-moz-border-radius-topleft", "-webkit-border-top-left-radius", null, null), - "border-top-right-radius" => array("-moz-border-radius-topright", "-webkit-border-top-right-radius", null, null), + "border-top-right-radius" => array( + "-moz-border-radius-topright", + "-webkit-border-top-right-radius", + null, + null + ), "border-vertical-spacing" => array(null, "-webkit-border-vertical-spacing", null, null), "box-align" => array("-moz-box-align", "-webkit-box-align", null, null), "box-direction" => array("-moz-box-direction", "-webkit-box-direction", null, null), @@ -107,7 +122,7 @@ class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter "hyphenate-character" => array(null, "-webkit-hyphenate-character", null, null), "hyphenate-locale" => array(null, "-webkit-hyphenate-locale", null, null), "hyphens" => array(null, "-webkit-hyphens", null, null), - "force-broken-image-icon" => array("-moz-image-region", null, null, null), + "image-region" => array("-moz-image-region", null, null, null), "ime-mode" => array(null, null, null, "-ms-ime-mode"), "interpolation-mode" => array(null, null, null, "-ms-interpolation-mode"), "layout-flow" => array(null, null, null, "-ms-layout-flow"), @@ -210,9 +225,24 @@ class CssConvertLevel3PropertiesMinifierFilter extends CssMinifierFilter "transform-style" => array(null, "-webkit-transform-style", null, null), "transition" => array("-moz-transition", "-webkit-transition", "-o-transition", null), "transition-delay" => array("-moz-transition-delay", "-webkit-transition-delay", "-o-transition-delay", null), - "transition-duration" => array("-moz-transition-duration", "-webkit-transition-duration", "-o-transition-duration", null), - "transition-property" => array("-moz-transition-property", "-webkit-transition-property", "-o-transition-property", null), - "transition-timing-function" => array("-moz-transition-timing-function", "-webkit-transition-timing-function", "-o-transition-timing-function", null), + "transition-duration" => array( + "-moz-transition-duration", + "-webkit-transition-duration", + "-o-transition-duration", + null + ), + "transition-property" => array( + "-moz-transition-property", + "-webkit-transition-property", + "-o-transition-property", + null + ), + "transition-timing-function" => array( + "-moz-transition-timing-function", + "-webkit-transition-timing-function", + "-o-transition-timing-function", + null + ), "user-drag" => array(null, "-webkit-user-drag", null, null), "user-focus" => array("-moz-user-focus", null, null, null), "user-input" => array("-moz-user-input", null, null, null), @@ -273,12 +303,13 @@ public function apply(array &$tokens) * @param CssToken $token * @return array */ - private static function filter($token) + private static function filter(CssToken $token) { $r = array ( new CssRulesetDeclarationToken("-ms-filter", "\"".$token->Value."\"", $token->MediaTypes), ); + return $r; } @@ -300,6 +331,7 @@ private static function opacity($token) new CssRulesetDeclarationToken("filter", "alpha(opacity=".$ieValue.")", $token->MediaTypes), new CssRulesetDeclarationToken("zoom", "1", $token->MediaTypes) ); + return $r; } @@ -326,8 +358,8 @@ private static function whiteSpace($token) new CssRulesetDeclarationToken("word-wrap", "break-word", $token->MediaTypes) ); return $r; - } else { - return array(); } + + return array(); } } diff --git a/src/CssMin/CssConvertNamedColorsMinifierPlugin.php b/src/CssMin/CssConvertNamedColorsMinifierPlugin.php index 67f46bd..6e718b5 100644 --- a/src/CssMin/CssConvertNamedColorsMinifierPlugin.php +++ b/src/CssMin/CssConvertNamedColorsMinifierPlugin.php @@ -32,14 +32,17 @@ class CssConvertNamedColorsMinifierPlugin extends CssMinifierPlugin * @var string */ private $reMatch = null; + /** * Regular expression replacing the value. * * @var string */ private $reReplace = "\"\${1}\" . \$this->transformation[strtolower(\"\${2}\")] . \"\${3}\""; + /** - * Transformation table used by the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}. + * Transformation table used by the + * {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression}. * * @var array */ @@ -186,12 +189,12 @@ class CssConvertNamedColorsMinifierPlugin extends CssMinifierPlugin /** * Overwrites {@link CssMinifierPlugin::__construct()}. * - * The constructor will create the {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression} + * The constructor will create the + * {@link CssConvertNamedColorsMinifierPlugin::$reReplace replace regular expression} * based on the {@link CssConvertNamedColorsMinifierPlugin::$transformation transformation table}. * * @param CssMinifier $minifier The CssMinifier object of this plugin. * @param array $configuration Plugin configuration [optional] - * @return void */ public function __construct(CssMinifier $minifier, array $configuration = array()) { diff --git a/src/CssMin/CssError.php b/src/CssMin/CssError.php index 30fd39a..c1fd066 100644 --- a/src/CssMin/CssError.php +++ b/src/CssMin/CssError.php @@ -41,9 +41,10 @@ class CssError /** * Constructor triggering the error. * + * @param $file + * @param $line * @param string $message Error message * @param string $source Corresponding line [optional] - * @return void */ public function __construct($file, $line, $message, $source = "") { @@ -60,6 +61,11 @@ public function __construct($file, $line, $message, $source = "") */ public function __toString() { - return $this->Message.($this->Source ? ":
".$this->Source."" : "")."
in file ".$this->File." at line ".$this->Line; + return $this->Message + . ($this->Source ? ":
".$this->Source."" : "") + . "
in file " + . $this->File + . " at line " + . $this->Line; } } diff --git a/src/CssMin/CssExpressionParserPlugin.php b/src/CssMin/CssExpressionParserPlugin.php index 72443ae..56b4662 100644 --- a/src/CssMin/CssExpressionParserPlugin.php +++ b/src/CssMin/CssExpressionParserPlugin.php @@ -55,12 +55,18 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char - * @return mixed TRUE will break the processing; FALSE continue with the next plugin; integer set a new index and break the processing + * @param $state + * @return mixed TRUE will break the processing; + * FALSE continue with the next plugin; + * integer set a new index and break the processing */ public function parse($index, $char, $previousChar, $state) { // Start of expression - if ($char === "(" && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" && $state !== "T_EXPRESSION") { + if ($char === "(" + && strtolower(substr($this->parser->getSource(), $index - 10, 11)) === "expression(" + && $state !== "T_EXPRESSION" + ) { $this->parser->pushState("T_EXPRESSION"); $this->leftBraces++; } // Count left braces @@ -70,13 +76,17 @@ public function parse($index, $char, $previousChar, $state) elseif ($char === ")" && $state === "T_EXPRESSION") { $this->rightBraces++; } // Possible end of expression; if left and right braces are equal the expressen ends - elseif (($char === ";" || $char === "}") && $state === "T_EXPRESSION" && $this->leftBraces === $this->rightBraces) { + elseif (($char === ";" || $char === "}") + && $state === "T_EXPRESSION" + && $this->leftBraces === $this->rightBraces + ) { $this->leftBraces = $this->rightBraces = 0; $this->parser->popState(); return $index - 1; } else { return false; } + return true; } } diff --git a/src/CssMin/CssImportImportsMinifierFilter.php b/src/CssMin/CssImportImportsMinifierFilter.php index 9a8fa2e..ad9a63a 100644 --- a/src/CssMin/CssImportImportsMinifierFilter.php +++ b/src/CssMin/CssImportImportsMinifierFilter.php @@ -30,43 +30,71 @@ class CssImportImportsMinifierFilter extends CssMinifierFilter public function apply(array &$tokens) { if (!isset($this->configuration["BasePath"]) || !is_dir($this->configuration["BasePath"])) { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Base path ".($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null")." is not a directory")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Base path ".($this->configuration["BasePath"] ? $this->configuration["BasePath"] : "null")." is not a directory" + ) + ); return 0; } + for ($i = 0, $l = count($tokens); $i < $l; $i++) { if (get_class($tokens[$i]) === "CssAtImportToken") { $import = $this->configuration["BasePath"]."/".$tokens[$i]->Import; // Import file was not found/is not a file if (!is_file($import)) { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Import file ".$import." was not found.", (string)$tokens[$i])); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Import file ".$import." was not found.", + (string)$tokens[$i] + ) + ); } // Import file already imported; remove this @import at-rule to prevent recursions elseif (in_array($import, $this->imported)) { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": Import file ".$import." was already imported.", (string)$tokens[$i])); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": Import file ".$import." was already imported.", + (string)$tokens[$i] + ) + ); $tokens[$i] = null; } else { $this->imported[] = $import; $parser = new CssParser(file_get_contents($import)); $import = $parser->getTokens(); // The @import at-rule has media types defined requiring special handling - if (count($tokens[$i]->MediaTypes) > 0 && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all")) { + if (count($tokens[$i]->MediaTypes) > 0 + && !(count($tokens[$i]->MediaTypes) == 1 && $tokens[$i]->MediaTypes[0] == "all") + ) { $blocks = array(); /* - * Filter or set media types of @import at-rule or remove the @import at-rule if no media type is matching the parent @import at-rule + * Filter or set media types of @import at-rule or remove the @import at-rule + * if no media type is matching the parent @import at-rule */ for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { if (get_class($import[$ii]) === "CssAtImportToken") { - // @import at-rule defines no media type or only the "all" media type; set the media types to the one defined in the parent @import at-rule - if (count($import[$ii]->MediaTypes) == 0 || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all")) { + // @import at-rule defines no media type or only the "all" media type; + // set the media types to the one defined in the parent @import at-rule + if (count($import[$ii]->MediaTypes) == 0 + || (count($import[$ii]->MediaTypes) == 1 && $import[$ii]->MediaTypes[0] == "all") + ) { $import[$ii]->MediaTypes = $tokens[$i]->MediaTypes; - } // @import at-rule defineds one or more media types; filter out media types not matching with the parent @import at-rule - elseif (count($import[$ii]->MediaTypes > 0)) { + } // @import at-rule defineds one or more media types; + // filter out media types not matching with the parent @import at-rule + elseif (count($import[$ii]->MediaTypes) > 0) { foreach ($import[$ii]->MediaTypes as $index => $mediaType) { if (!in_array($mediaType, $tokens[$i]->MediaTypes)) { unset($import[$ii]->MediaTypes[$index]); } } $import[$ii]->MediaTypes = array_values($import[$ii]->MediaTypes); - // If there are no media types left in the @import at-rule remove the @import at-rule + // If no media types are left in the @import at-rule remove the @import at-rule if (count($import[$ii]->MediaTypes) == 0) { $import[$ii] = null; } @@ -109,7 +137,9 @@ public function apply(array &$tokens) * at-rule remove the CssAtMediaStartToken and CssAtMediaEndToken token */ for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { - if (get_class($import[$ii]) === "CssAtMediaStartToken" && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0) { + if (get_class($import[$ii]) === "CssAtMediaStartToken" + && count(array_diff($tokens[$i]->MediaTypes, $import[$ii]->MediaTypes)) === 0 + ) { for ($iii = $ii; $iii < $ll; $iii++) { if (get_class($import[$iii]) == "CssAtMediaEndToken") { break; @@ -138,22 +168,41 @@ public function apply(array &$tokens) */ for ($ii = 0, $ll = count($import); $ii < $ll; $ii++) { $class = get_class($import[$ii]); - if ($class === "CssAtFontFaceStartToken" || $class === "CssAtMediaStartToken" || $class === "CssAtPageStartToken" || $class === "CssAtVariablesStartToken") { + if ($class === "CssAtFontFaceStartToken" + || $class === "CssAtMediaStartToken" + || $class === "CssAtPageStartToken" + || $class === "CssAtVariablesStartToken" + ) { for ($iii = $ii; $iii < $ll; $iii++) { $class = get_class($import[$iii]); - if ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken") { + if ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken" + ) { break; } } $class = get_class($import[$iii]); - if (isset($import[$iii]) && ($class === "CssAtFontFaceEndToken" || $class === "CssAtMediaEndToken" || $class === "CssAtPageEndToken" || $class === "CssAtVariablesEndToken")) { + if (isset($import[$iii]) + && ($class === "CssAtFontFaceEndToken" + || $class === "CssAtMediaEndToken" + || $class === "CssAtPageEndToken" + || $class === "CssAtVariablesEndToken") + ) { $blocks = array_merge($blocks, array_splice($import, $ii, $iii - $ii + 1, array())); $ll = count($import); } } } - // Create the import array with extracted tokens and the rulesets wrapped into a @media at-rule block - $import = array_merge($blocks, array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), $import, array(new CssAtMediaEndToken())); + // Create the import array with extracted tokens and the rulesets + // wrapped into a @media at-rule block + $import = array_merge( + $blocks, + array(new CssAtMediaStartToken($tokens[$i]->MediaTypes)), + $import, + array(new CssAtMediaEndToken()) + ); } // Insert the imported tokens array_splice($tokens, $i, 1, $import); @@ -163,5 +212,7 @@ public function apply(array &$tokens) } } } + + return count($tokens); } } diff --git a/src/CssMin/CssMin.php b/src/CssMin/CssMin.php index 6f8d1fb..1ad9b74 100644 --- a/src/CssMin/CssMin.php +++ b/src/CssMin/CssMin.php @@ -68,12 +68,6 @@ */ class CssMin { - /** - * Index of classes - * - * @var array - */ - private static $classIndex = array(); /** * Parse/minify errors * diff --git a/src/CssMin/CssMinifier.php b/src/CssMin/CssMinifier.php index 7a6868b..51e9a6f 100644 --- a/src/CssMin/CssMinifier.php +++ b/src/CssMin/CssMinifier.php @@ -40,7 +40,6 @@ class CssMinifier * @param string $source CSS source [optional] * @param array $filters Filter configuration [optional] * @param array $plugins Plugin configuration [optional] - * @return void */ public function __construct($source = null, array $filters = null, array $plugins = null) { @@ -74,7 +73,13 @@ public function __construct($source = null, array $filters = null, array $plugin if (class_exists($class)) { $this->filters[] = new $class($this, $config); } else { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The filter ".$name." with the class name ".$class." was not found")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": The filter ".$name." with the class name ".$class." was not found" + ) + ); } } } @@ -86,7 +91,13 @@ public function __construct($source = null, array $filters = null, array $plugin if (class_exists($class)) { $this->plugins[] = new $class($this, $config); } else { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The plugin ".$name." with the class name ".$class." was not found")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": The plugin ".$name." with the class name ".$class." was not found" + ) + ); } } } @@ -109,7 +120,7 @@ public function getMinified() /** * Returns a plugin by class name. * - * @param string $name Class name of the plugin + * @param string $class Class name of the plugin * @return CssMinifierPlugin */ public function getPlugin($class) @@ -173,7 +184,9 @@ public function minify($source) $triggerToken = "|".get_class($tokens[$i])."|"; if (strpos($globalTriggerTokens, $triggerToken) !== false) { for ($ii = 0; $ii < $pluginCount; $ii++) { - if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false || $pluginTriggerTokens[$ii] === false) { + if (strpos($pluginTriggerTokens[$ii], $triggerToken) !== false + || $pluginTriggerTokens[$ii] === false + ) { // Apply the plugin; if the return value is TRUE continue to the next token if ($plugins[$ii]->apply($tokens[$i]) === true) { continue 2; @@ -187,6 +200,7 @@ public function minify($source) $r .= (string)$tokens[$i]; } $this->minified = $r; + return $r; } } diff --git a/src/CssMin/CssOtbsFormatter.php b/src/CssMin/CssOtbsFormatter.php index e0e0bcb..ec049b7 100644 --- a/src/CssMin/CssOtbsFormatter.php +++ b/src/CssMin/CssOtbsFormatter.php @@ -2,7 +2,8 @@ namespace PHPWee\CssMin; /** - * {@link CssFormatter Formatter} returning the CSS source in {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style). + * {@link CssFormatter Formatter} returning the CSS source in + * {@link http://goo.gl/j4XdU OTBS indent style} (The One True Brace Style). * * @package CssMin/Formatter * @link http://code.google.com/p/cssmin/ diff --git a/src/CssMin/CssParser.php b/src/CssMin/CssParser.php index d571820..e46060f 100644 --- a/src/CssMin/CssParser.php +++ b/src/CssMin/CssParser.php @@ -69,7 +69,6 @@ class CssParser * * @param string $source CSS source [optional] * @param array $plugins Plugin configuration [optional] - * @return void */ public function __construct($source = null, array $plugins = null) { @@ -96,7 +95,13 @@ public function __construct($source = null, array $plugins = null) if (class_exists($class)) { $this->plugins[] = new $class($this, $config); } else { - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": The plugin ".$name." with the class name ".$class." was not found")); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": The plugin ".$name." with the class name ".$class." was not found" + ) + ); } } } @@ -192,7 +197,7 @@ public function getState() /** * Returns a plugin by class name. * - * @param string $name Class name of the plugin + * @param string $class Class name of the plugin * @return CssParserPlugin */ public function getPlugin($class) @@ -239,7 +244,7 @@ public function parse($source) // Reset $this->source = ""; $this->tokens = array(); - // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create + // Create a global and plugin lookup table for trigger chars; set array of plugins as local variable and create // several helper variables for plugin handling $globalTriggerChars = ""; $plugins = $this->plugins; @@ -251,7 +256,9 @@ public function parse($source) $tPluginClassName = get_class($plugins[$i]); $pluginTriggerChars[$i] = implode("", $plugins[$i]->getTriggerChars()); $tPluginTriggerStates = $plugins[$i]->getTriggerStates(); - $pluginTriggerStates[$i] = $tPluginTriggerStates === false ? false : "|".implode("|", $tPluginTriggerStates)."|"; + $pluginTriggerStates[$i] = ($tPluginTriggerStates === false) + ? false + : "|".implode("|", $tPluginTriggerStates)."|"; $pluginIndex[$tPluginClassName] = $i; for ($ii = 0, $ll = strlen($pluginTriggerChars[$i]); $ii < $ll; $ii++) { $c = substr($pluginTriggerChars[$i], $ii, 1); @@ -285,10 +292,13 @@ public function parse($source) $buffer .= $c; // Extended processing only if the current char is a global trigger char if (strpos($globalTriggerChars, $c) !== false) { - // Exclusive state is set; process with the exclusive plugin + // Exclusive state is set; process with the exclusive plugin if ($exclusive) { $tPluginIndex = $pluginIndex[$exclusive]; - if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false && ($pluginTriggerStates[$tPluginIndex] === false || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false)) { + if (strpos($pluginTriggerChars[$tPluginIndex], $c) !== false + && ($pluginTriggerStates[$tPluginIndex] === false + || strpos($pluginTriggerStates[$tPluginIndex], $state) !== false) + ) { $r = $plugins[$tPluginIndex]->parse($i, $c, $p, $state); // Return value is TRUE => continue with next char if ($r === true) { @@ -304,13 +314,17 @@ public function parse($source) $triggerState = "|".$state."|"; for ($ii = 0, $ll = $pluginCount; $ii < $ll; $ii++) { // Only process if the current char is one of the plugin trigger chars - if (strpos($pluginTriggerChars[$ii], $c) !== false && ($pluginTriggerStates[$ii] === false || strpos($pluginTriggerStates[$ii], $triggerState) !== false)) { + if (strpos($pluginTriggerChars[$ii], $c) !== false + && ($pluginTriggerStates[$ii] === false + || strpos($pluginTriggerStates[$ii], $triggerState) !== false) + ) { // Process with the plugin $r = $plugins[$ii]->parse($i, $c, $p, $state); // Return value is TRUE => break the plugin loop and and continue with next char if ($r === true) { break; - } // Return value is numeric => set new index, break the plugin loop and and continue with next char + } // Return value is numeric => set new index, break the plugin loop and + // continue with next char elseif ($r !== false && $r != $i) { $i = $r; break; @@ -383,7 +397,8 @@ public function setMediaTypes(array $mediaTypes) } /** - * Sets the current state in the state stack; equals to {@link CssParser::popState()} + {@link CssParser::pushState()}. + * Sets the current state in the state stack; equals to + * {@link CssParser::popState()} + {@link CssParser::pushState()}. * * @param integer $state State to set * @return integer diff --git a/src/CssMin/CssParserPlugin.php b/src/CssMin/CssParserPlugin.php index 5b9adc9..b2a6452 100644 --- a/src/CssMin/CssParserPlugin.php +++ b/src/CssMin/CssParserPlugin.php @@ -67,6 +67,7 @@ abstract public function getTriggerStates(); * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char + * @param $state * @return mixed TRUE will break the processing; * FALSE continue with the next plugin; * integer set a new index and break the processing diff --git a/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php b/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php index 6104ed3..b890f5c 100644 --- a/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php +++ b/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php @@ -27,7 +27,9 @@ public function apply(array &$tokens) $current = get_class($tokens[$i]); $next = isset($tokens[$i + 1]) ? get_class($tokens[$i + 1]) : false; if (($current === "CssRulesetStartToken" && $next === "CssRulesetEndToken") || - ($current === "CssAtKeyframesRulesetStartToken" && $next === "CssAtKeyframesRulesetEndToken" && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) + ($current === "CssAtKeyframesRulesetStartToken" + && $next === "CssAtKeyframesRulesetEndToken" + && !array_intersect(array("from", "0%", "to", "100%"), array_map("strtolower", $tokens[$i]->Selectors))) ) { $tokens[$i] = null; $tokens[$i + 1] = null; diff --git a/src/CssMin/CssRulesetParserPlugin.php b/src/CssMin/CssRulesetParserPlugin.php index 9e53a6b..a639c51 100644 --- a/src/CssMin/CssRulesetParserPlugin.php +++ b/src/CssMin/CssRulesetParserPlugin.php @@ -49,6 +49,7 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char + * @param $state * @return mixed TRUE will break the processing; * FALSE continue with the next plugin; * integer set a new index and break the processing diff --git a/src/CssMin/CssStringParserPlugin.php b/src/CssMin/CssStringParserPlugin.php index 8c59a15..cc6fe3d 100644 --- a/src/CssMin/CssStringParserPlugin.php +++ b/src/CssMin/CssStringParserPlugin.php @@ -48,6 +48,7 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char + * @param $state * @return mixed TRUE will break the processing; * FALSE continue with the next plugin; * integer set a new index and break the processing diff --git a/src/CssMin/CssToken.php b/src/CssMin/CssToken.php index 2bceb6b..c7fd900 100644 --- a/src/CssMin/CssToken.php +++ b/src/CssMin/CssToken.php @@ -15,6 +15,21 @@ */ abstract class CssToken { + /** + * @var array + */ + public $MediaTypes = array(); + + /** + * @var string + */ + public $Property = ""; + + /** + * @var string + */ + public $Value = ""; + /** * Returns the token as string. * diff --git a/src/CssMin/CssUrlParserPlugin.php b/src/CssMin/CssUrlParserPlugin.php index ee7c5ca..03e8f39 100644 --- a/src/CssMin/CssUrlParserPlugin.php +++ b/src/CssMin/CssUrlParserPlugin.php @@ -41,6 +41,7 @@ public function getTriggerStates() * @param integer $index Current index * @param string $char Current char * @param string $previousChar Previous char + * @param $state * @return mixed TRUE will break the processing; * FALSE continue with the next plugin; * integer set a new index and break the processing diff --git a/src/CssMin/CssVariablesMinifierFilter.php b/src/CssMin/CssVariablesMinifierFilter.php index 1ce1d0e..9844de2 100644 --- a/src/CssMin/CssVariablesMinifierFilter.php +++ b/src/CssMin/CssVariablesMinifierFilter.php @@ -25,7 +25,6 @@ public function apply(array &$tokens) { $variables = array(); $defaultMediaTypes = array("all"); - $mediaTypes = array(); $remove = array(); for ($i = 0, $l = count($tokens); $i < $l; $i++) { // @variables at-rule block found @@ -38,7 +37,7 @@ public function apply(array &$tokens) } } // Read the variable declaration tokens - for ($i = $i; $i < $l; $i++) { + for (; $i < $l; $i++) { // Found a variable declaration => read the variable values if (get_class($tokens[$i]) === "CssAtVariablesDeclarationToken") { foreach ($mediaTypes as $mediaType) { diff --git a/src/CssMin/CssVariablesMinifierPlugin.php b/src/CssMin/CssVariablesMinifierPlugin.php index 29bbc46..aaa1caa 100644 --- a/src/CssMin/CssVariablesMinifierPlugin.php +++ b/src/CssMin/CssVariablesMinifierPlugin.php @@ -76,7 +76,14 @@ public function apply(CssToken &$token) } } // If no value was found trigger an error and replace the token with a CssNullToken - CssMin::triggerError(new CssError(__FILE__, __LINE__, __METHOD__.": No value found for variable ".$variable." in media types ".implode(", ", $mediaTypes)."", (string)$token)); + CssMin::triggerError( + new CssError( + __FILE__, + __LINE__, + __METHOD__.": No value found for variable ".$variable." in media types ".implode(", ", $mediaTypes)."", + (string)$token + ) + ); $token = new CssNullToken(); return true; } diff --git a/src/HtmlMin/HtmlMin.php b/src/HtmlMin/HtmlMin.php index 8337d87..6d0c42b 100644 --- a/src/HtmlMin/HtmlMin.php +++ b/src/HtmlMin/HtmlMin.php @@ -32,6 +32,9 @@ * */ +use PHPWee\CssMin\CssMin; +use PHPWee\JsMin\JsMin; + /** * Class HtmlMin * @@ -59,6 +62,8 @@ public static function minify($html, $js = true, $css = true) $doc->normalizeDocument(); $textnodes = $xpath->query('//text()'); $skip = ["style","pre","code","script","textarea"]; + + /** @var \DOMNode $t */ foreach ($textnodes as $t) { $xp = $t->getNodePath(); $doskip = false; @@ -97,32 +102,47 @@ public static function minify($html, $js = true, $css = true) if ($js) { $scriptnodes = $xpath->query('//script'); + + /** @var \DOMNode $d */ foreach ($scriptnodes as $d) { - if ($d->hasAttribute("type") && strtolower($d->getAttribute("type"))!=='text/javascript' ) { + $attributes = []; + foreach ($d->attributes as $attr) { + $attributes[$attr->nodeName] = $attr->nodeValue; + } + + if (isset($attributes['type']) && (strtolower($d['type']) !== 'text/javascript')) { continue; } - if ($d->hasAttribute("data-no-min")) { + + if (isset($attributes['data-no-min'])) { continue; } + if (trim($d->nodeValue)=="") { continue; } - $d->nodeValue = \PHPWee\JSMin::minify($d->nodeValue); + $d->nodeValue = JsMin::minify($d->nodeValue); } } if ($css) { $cssnodes = $xpath->query('//style'); foreach ($cssnodes as $d) { - if ($d->hasAttribute("data-no-min")) { + $attributes = []; + foreach ($d->attributes as $attr) { + $attributes[$attr->nodeName] = $attr->nodeValue; + } + + if (isset($attributes['data-no-min'])) { continue; } + if (trim($d->nodeValue) == "") { continue; } - $d->nodeValue = \PHPWee\CssMin::minify($d->nodeValue); + $d->nodeValue = CssMin::minify($d->nodeValue); } } return ($doc->saveHTML()); } -} \ No newline at end of file +} diff --git a/src/JsMin/JsMin.php b/src/JsMin/JsMin.php index e687066..6973f44 100644 --- a/src/JsMin/JsMin.php +++ b/src/JsMin/JsMin.php @@ -56,7 +56,7 @@ * @link http://code.google.com/p/jsmin-php/ */ -class JSMin +class JsMin { const ORD_LF = 10; const ORD_SPACE = 32; From 13240b21f0d95690df0183740518a2c28010997b Mon Sep 17 00:00:00 2001 From: Carsten Henkelmann Date: Wed, 23 Sep 2015 16:09:11 +0200 Subject: [PATCH 5/8] Moving everything to the correct namespace directory structure. --- examples/example.php | 10 ++++++++-- .../CssMin/CssAtBlockEndToken.php | 0 .../CssMin/CssAtBlockStartToken.php | 0 .../CssMin/CssAtCharsetParserPlugin.php | 0 src/{ => PHPWee}/CssMin/CssAtCharsetToken.php | 0 .../CssMin/CssAtFontFaceDeclarationToken.php | 0 .../CssMin/CssAtFontFaceEndToken.php | 0 .../CssMin/CssAtFontFaceParserPlugin.php | 0 .../CssMin/CssAtFontFaceStartToken.php | 0 .../CssMin/CssAtImportParserPlugin.php | 0 src/{ => PHPWee}/CssMin/CssAtImportToken.php | 0 .../CssMin/CssAtKeyframesEndToken.php | 0 .../CssMin/CssAtKeyframesParserPlugin.php | 0 .../CssAtKeyframesRulesetDeclarationToken.php | 0 .../CssMin/CssAtKeyframesRulesetEndToken.php | 0 .../CssAtKeyframesRulesetStartToken.php | 0 .../CssMin/CssAtKeyframesStartToken.php | 0 .../CssMin/CssAtMediaEndToken.php | 0 .../CssMin/CssAtMediaParserPlugin.php | 0 .../CssMin/CssAtMediaStartToken.php | 0 .../CssMin/CssAtPageDeclarationToken.php | 0 src/{ => PHPWee}/CssMin/CssAtPageEndToken.php | 0 .../CssMin/CssAtPageParserPlugin.php | 0 .../CssMin/CssAtPageStartToken.php | 0 .../CssMin/CssAtVariablesDeclarationToken.php | 0 .../CssMin/CssAtVariablesEndToken.php | 0 .../CssMin/CssAtVariablesParserPlugin.php | 0 .../CssMin/CssAtVariablesStartToken.php | 0 .../CssMin/CssCommentParserPlugin.php | 0 src/{ => PHPWee}/CssMin/CssCommentToken.php | 0 .../CssCompressColorValuesMinifierPlugin.php | 0 ...CompressExpressionValuesMinifierPlugin.php | 0 .../CssCompressUnitValuesMinifierPlugin.php | 0 .../CssConvertFontWeightMinifierPlugin.php | 0 .../CssConvertHslColorsMinifierPlugin.php | 0 ...ConvertLevel3AtKeyframesMinifierFilter.php | 0 ...sConvertLevel3PropertiesMinifierFilter.php | 0 .../CssConvertNamedColorsMinifierPlugin.php | 0 .../CssConvertRgbColorsMinifierPlugin.php | 0 .../CssMin/CssDeclarationToken.php | 0 src/{ => PHPWee}/CssMin/CssError.php | 0 .../CssMin/CssExpressionParserPlugin.php | 0 src/{ => PHPWee}/CssMin/CssFormatter.php | 0 .../CssMin/CssImportImportsMinifierFilter.php | 0 src/{ => PHPWee}/CssMin/CssMin.php | 0 src/{ => PHPWee}/CssMin/CssMinifier.php | 4 ++-- src/{ => PHPWee}/CssMin/CssMinifierFilter.php | 0 src/{ => PHPWee}/CssMin/CssMinifierPlugin.php | 0 src/{ => PHPWee}/CssMin/CssNullToken.php | 0 src/{ => PHPWee}/CssMin/CssOtbsFormatter.php | 0 src/{ => PHPWee}/CssMin/CssParser.php | 2 +- src/{ => PHPWee}/CssMin/CssParserPlugin.php | 0 .../CssRemoveCommentsMinifierFilter.php | 0 .../CssRemoveEmptyAtBlocksMinifierFilter.php | 0 .../CssRemoveEmptyRulesetsMinifierFilter.php | 0 ...eLastDelarationSemiColonMinifierFilter.php | 0 .../CssMin/CssRulesetDeclarationToken.php | 0 .../CssMin/CssRulesetEndToken.php | 0 .../CssMin/CssRulesetParserPlugin.php | 0 .../CssMin/CssRulesetStartToken.php | 0 ...CssSortRulesetPropertiesMinifierFilter.php | 0 .../CssMin/CssStringParserPlugin.php | 0 src/{ => PHPWee}/CssMin/CssToken.php | 0 .../CssMin/CssUrlParserPlugin.php | 0 .../CssMin/CssVariablesMinifierFilter.php | 0 .../CssMin/CssVariablesMinifierPlugin.php | 0 .../CssMin/CssWhitesmithsFormatter.php | 0 src/{ => PHPWee}/CssMin/README.md | 0 src/{ => PHPWee}/HtmlMin/HtmlMin.php | 0 src/{ => PHPWee}/HtmlMin/README.md | 0 src/{ => PHPWee}/JsMin/JsMin.php | 0 src/{ => PHPWee}/JsMin/README.md | 0 .../JsMin/UnterminatedCommentException.php | 0 .../JsMin/UnterminatedRegExpException.php | 0 .../JsMin/UnterminatedStringException.php | 0 PHPWee.php => src/PHPWee/PHPWee.php | 20 +++++++++++++++---- 76 files changed, 27 insertions(+), 9 deletions(-) rename src/{ => PHPWee}/CssMin/CssAtBlockEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtBlockStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtCharsetParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtCharsetToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtFontFaceDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtFontFaceEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtFontFaceParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtFontFaceStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtImportParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtImportToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesRulesetDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesRulesetEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesRulesetStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtKeyframesStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtMediaEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtMediaParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtMediaStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtPageDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtPageEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtPageParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtPageStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtVariablesDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtVariablesEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssAtVariablesParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssAtVariablesStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssCommentParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssCommentToken.php (100%) rename src/{ => PHPWee}/CssMin/CssCompressColorValuesMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssCompressExpressionValuesMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssCompressUnitValuesMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertFontWeightMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertHslColorsMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertLevel3PropertiesMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertNamedColorsMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssConvertRgbColorsMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssError.php (100%) rename src/{ => PHPWee}/CssMin/CssExpressionParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssFormatter.php (100%) rename src/{ => PHPWee}/CssMin/CssImportImportsMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssMin.php (100%) rename src/{ => PHPWee}/CssMin/CssMinifier.php (97%) rename src/{ => PHPWee}/CssMin/CssMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssNullToken.php (100%) rename src/{ => PHPWee}/CssMin/CssOtbsFormatter.php (100%) rename src/{ => PHPWee}/CssMin/CssParser.php (99%) rename src/{ => PHPWee}/CssMin/CssParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssRemoveCommentsMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssRulesetDeclarationToken.php (100%) rename src/{ => PHPWee}/CssMin/CssRulesetEndToken.php (100%) rename src/{ => PHPWee}/CssMin/CssRulesetParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssRulesetStartToken.php (100%) rename src/{ => PHPWee}/CssMin/CssSortRulesetPropertiesMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssStringParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssToken.php (100%) rename src/{ => PHPWee}/CssMin/CssUrlParserPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssVariablesMinifierFilter.php (100%) rename src/{ => PHPWee}/CssMin/CssVariablesMinifierPlugin.php (100%) rename src/{ => PHPWee}/CssMin/CssWhitesmithsFormatter.php (100%) rename src/{ => PHPWee}/CssMin/README.md (100%) rename src/{ => PHPWee}/HtmlMin/HtmlMin.php (100%) rename src/{ => PHPWee}/HtmlMin/README.md (100%) rename src/{ => PHPWee}/JsMin/JsMin.php (100%) rename src/{ => PHPWee}/JsMin/README.md (100%) rename src/{ => PHPWee}/JsMin/UnterminatedCommentException.php (100%) rename src/{ => PHPWee}/JsMin/UnterminatedRegExpException.php (100%) rename src/{ => PHPWee}/JsMin/UnterminatedStringException.php (100%) rename PHPWee.php => src/PHPWee/PHPWee.php (62%) diff --git a/examples/example.php b/examples/example.php index c7dce53..a35a3a5 100644 --- a/examples/example.php +++ b/examples/example.php @@ -1,8 +1,14 @@ $config) { if ($config !== false) { - $class = "Css".$name."MinifierFilter"; + $class = '\\'.__NAMESPACE__."\Css".$name."MinifierFilter"; $config = is_array($config) ? $config : array(); if (class_exists($class)) { $this->filters[] = new $class($this, $config); @@ -86,7 +86,7 @@ public function __construct($source = null, array $filters = null, array $plugin // Plugins foreach ($plugins as $name => $config) { if ($config !== false) { - $class = "Css".$name."MinifierPlugin"; + $class = '\\'.__NAMESPACE__."\Css".$name."MinifierPlugin"; $config = is_array($config) ? $config : array(); if (class_exists($class)) { $this->plugins[] = new $class($this, $config); diff --git a/src/CssMin/CssMinifierFilter.php b/src/PHPWee/CssMin/CssMinifierFilter.php similarity index 100% rename from src/CssMin/CssMinifierFilter.php rename to src/PHPWee/CssMin/CssMinifierFilter.php diff --git a/src/CssMin/CssMinifierPlugin.php b/src/PHPWee/CssMin/CssMinifierPlugin.php similarity index 100% rename from src/CssMin/CssMinifierPlugin.php rename to src/PHPWee/CssMin/CssMinifierPlugin.php diff --git a/src/CssMin/CssNullToken.php b/src/PHPWee/CssMin/CssNullToken.php similarity index 100% rename from src/CssMin/CssNullToken.php rename to src/PHPWee/CssMin/CssNullToken.php diff --git a/src/CssMin/CssOtbsFormatter.php b/src/PHPWee/CssMin/CssOtbsFormatter.php similarity index 100% rename from src/CssMin/CssOtbsFormatter.php rename to src/PHPWee/CssMin/CssOtbsFormatter.php diff --git a/src/CssMin/CssParser.php b/src/PHPWee/CssMin/CssParser.php similarity index 99% rename from src/CssMin/CssParser.php rename to src/PHPWee/CssMin/CssParser.php index e46060f..b3859d2 100644 --- a/src/CssMin/CssParser.php +++ b/src/PHPWee/CssMin/CssParser.php @@ -90,7 +90,7 @@ public function __construct($source = null, array $plugins = null) // Create plugin instances foreach ($plugins as $name => $config) { if ($config !== false) { - $class = "Css".$name."ParserPlugin"; + $class = '\\'.__NAMESPACE__."\Css".$name."ParserPlugin"; $config = is_array($config) ? $config : array(); if (class_exists($class)) { $this->plugins[] = new $class($this, $config); diff --git a/src/CssMin/CssParserPlugin.php b/src/PHPWee/CssMin/CssParserPlugin.php similarity index 100% rename from src/CssMin/CssParserPlugin.php rename to src/PHPWee/CssMin/CssParserPlugin.php diff --git a/src/CssMin/CssRemoveCommentsMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveCommentsMinifierFilter.php similarity index 100% rename from src/CssMin/CssRemoveCommentsMinifierFilter.php rename to src/PHPWee/CssMin/CssRemoveCommentsMinifierFilter.php diff --git a/src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php similarity index 100% rename from src/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php rename to src/PHPWee/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php diff --git a/src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php similarity index 100% rename from src/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php rename to src/PHPWee/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php diff --git a/src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php similarity index 100% rename from src/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php rename to src/PHPWee/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php diff --git a/src/CssMin/CssRulesetDeclarationToken.php b/src/PHPWee/CssMin/CssRulesetDeclarationToken.php similarity index 100% rename from src/CssMin/CssRulesetDeclarationToken.php rename to src/PHPWee/CssMin/CssRulesetDeclarationToken.php diff --git a/src/CssMin/CssRulesetEndToken.php b/src/PHPWee/CssMin/CssRulesetEndToken.php similarity index 100% rename from src/CssMin/CssRulesetEndToken.php rename to src/PHPWee/CssMin/CssRulesetEndToken.php diff --git a/src/CssMin/CssRulesetParserPlugin.php b/src/PHPWee/CssMin/CssRulesetParserPlugin.php similarity index 100% rename from src/CssMin/CssRulesetParserPlugin.php rename to src/PHPWee/CssMin/CssRulesetParserPlugin.php diff --git a/src/CssMin/CssRulesetStartToken.php b/src/PHPWee/CssMin/CssRulesetStartToken.php similarity index 100% rename from src/CssMin/CssRulesetStartToken.php rename to src/PHPWee/CssMin/CssRulesetStartToken.php diff --git a/src/CssMin/CssSortRulesetPropertiesMinifierFilter.php b/src/PHPWee/CssMin/CssSortRulesetPropertiesMinifierFilter.php similarity index 100% rename from src/CssMin/CssSortRulesetPropertiesMinifierFilter.php rename to src/PHPWee/CssMin/CssSortRulesetPropertiesMinifierFilter.php diff --git a/src/CssMin/CssStringParserPlugin.php b/src/PHPWee/CssMin/CssStringParserPlugin.php similarity index 100% rename from src/CssMin/CssStringParserPlugin.php rename to src/PHPWee/CssMin/CssStringParserPlugin.php diff --git a/src/CssMin/CssToken.php b/src/PHPWee/CssMin/CssToken.php similarity index 100% rename from src/CssMin/CssToken.php rename to src/PHPWee/CssMin/CssToken.php diff --git a/src/CssMin/CssUrlParserPlugin.php b/src/PHPWee/CssMin/CssUrlParserPlugin.php similarity index 100% rename from src/CssMin/CssUrlParserPlugin.php rename to src/PHPWee/CssMin/CssUrlParserPlugin.php diff --git a/src/CssMin/CssVariablesMinifierFilter.php b/src/PHPWee/CssMin/CssVariablesMinifierFilter.php similarity index 100% rename from src/CssMin/CssVariablesMinifierFilter.php rename to src/PHPWee/CssMin/CssVariablesMinifierFilter.php diff --git a/src/CssMin/CssVariablesMinifierPlugin.php b/src/PHPWee/CssMin/CssVariablesMinifierPlugin.php similarity index 100% rename from src/CssMin/CssVariablesMinifierPlugin.php rename to src/PHPWee/CssMin/CssVariablesMinifierPlugin.php diff --git a/src/CssMin/CssWhitesmithsFormatter.php b/src/PHPWee/CssMin/CssWhitesmithsFormatter.php similarity index 100% rename from src/CssMin/CssWhitesmithsFormatter.php rename to src/PHPWee/CssMin/CssWhitesmithsFormatter.php diff --git a/src/CssMin/README.md b/src/PHPWee/CssMin/README.md similarity index 100% rename from src/CssMin/README.md rename to src/PHPWee/CssMin/README.md diff --git a/src/HtmlMin/HtmlMin.php b/src/PHPWee/HtmlMin/HtmlMin.php similarity index 100% rename from src/HtmlMin/HtmlMin.php rename to src/PHPWee/HtmlMin/HtmlMin.php diff --git a/src/HtmlMin/README.md b/src/PHPWee/HtmlMin/README.md similarity index 100% rename from src/HtmlMin/README.md rename to src/PHPWee/HtmlMin/README.md diff --git a/src/JsMin/JsMin.php b/src/PHPWee/JsMin/JsMin.php similarity index 100% rename from src/JsMin/JsMin.php rename to src/PHPWee/JsMin/JsMin.php diff --git a/src/JsMin/README.md b/src/PHPWee/JsMin/README.md similarity index 100% rename from src/JsMin/README.md rename to src/PHPWee/JsMin/README.md diff --git a/src/JsMin/UnterminatedCommentException.php b/src/PHPWee/JsMin/UnterminatedCommentException.php similarity index 100% rename from src/JsMin/UnterminatedCommentException.php rename to src/PHPWee/JsMin/UnterminatedCommentException.php diff --git a/src/JsMin/UnterminatedRegExpException.php b/src/PHPWee/JsMin/UnterminatedRegExpException.php similarity index 100% rename from src/JsMin/UnterminatedRegExpException.php rename to src/PHPWee/JsMin/UnterminatedRegExpException.php diff --git a/src/JsMin/UnterminatedStringException.php b/src/PHPWee/JsMin/UnterminatedStringException.php similarity index 100% rename from src/JsMin/UnterminatedStringException.php rename to src/PHPWee/JsMin/UnterminatedStringException.php diff --git a/PHPWee.php b/src/PHPWee/PHPWee.php similarity index 62% rename from PHPWee.php rename to src/PHPWee/PHPWee.php index cb2aa39..792079d 100644 --- a/PHPWee.php +++ b/src/PHPWee/PHPWee.php @@ -2,21 +2,33 @@ namespace PHPWee; /** - * Class Minify + * Class PHPWee * @package PHPWee */ -class Minify +class PHPWee { + /** + * @param $html + * @return string + */ public static function html($html) { return HtmlMin\HtmlMin::minify($html); } - + + /** + * @param $css + * @return string + */ public static function css($css) { return CssMin\CssMin::minify($css); } - + + /** + * @param $js + * @return string + */ public static function js($js) { return JsMin\JsMin::minify($js); From 3626a7f792c04ef77368875c2853fc3da49b8925 Mon Sep 17 00:00:00 2001 From: Mariano Custiel Date: Mon, 30 May 2016 14:52:18 +0200 Subject: [PATCH 6/8] Fixed DomElement as array error --- src/PHPWee/HtmlMin/HtmlMin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PHPWee/HtmlMin/HtmlMin.php b/src/PHPWee/HtmlMin/HtmlMin.php index 6d0c42b..78ff7a7 100644 --- a/src/PHPWee/HtmlMin/HtmlMin.php +++ b/src/PHPWee/HtmlMin/HtmlMin.php @@ -110,7 +110,7 @@ public static function minify($html, $js = true, $css = true) $attributes[$attr->nodeName] = $attr->nodeValue; } - if (isset($attributes['type']) && (strtolower($d['type']) !== 'text/javascript')) { + if (isset($attributes['type']) && (strtolower($attributes['type']) !== 'text/javascript')) { continue; } From fb771cf01ec1db750c5cc3c5e926b8e7de923663 Mon Sep 17 00:00:00 2001 From: Mariano Custiel Date: Tue, 7 Jun 2016 09:16:07 +0200 Subject: [PATCH 7/8] Update composer.json --- composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 9e99c7b..7942f5c 100644 --- a/composer.json +++ b/composer.json @@ -21,10 +21,10 @@ ], "autoload": { "psr-4": { - "PHPWee\\": "src/" + "PHPWee\\": "src/PHPWee" } }, "require": { "php": ">=5.3.0" } -} \ No newline at end of file +} From a5e233e21fc9d94f68fb6af845c5f6eefb995ff3 Mon Sep 17 00:00:00 2001 From: Mariano Custiel Date: Fri, 10 Jun 2016 15:25:12 +0200 Subject: [PATCH 8/8] Added encoding option --- src/PHPWee/HtmlMin/HtmlMin.php | 5 +++-- src/PHPWee/PHPWee.php | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/PHPWee/HtmlMin/HtmlMin.php b/src/PHPWee/HtmlMin/HtmlMin.php index 78ff7a7..63c252c 100644 --- a/src/PHPWee/HtmlMin/HtmlMin.php +++ b/src/PHPWee/HtmlMin/HtmlMin.php @@ -47,10 +47,11 @@ */ class HtmlMin { - public static function minify($html, $js = true, $css = true) + public static function minify($html, $js = true, $css = true, $encoding = 'UTF-8') { - $doc = new \DOMDocument(); + $doc = new \DOMDocument('1.0', $encoding); $doc->preserveWhiteSpace = false; + $doc->encoding = $encoding; @$doc->loadHTML($html); $xpath = new \DOMXPath($doc); foreach ($xpath->query('//comment()') as $comment) { diff --git a/src/PHPWee/PHPWee.php b/src/PHPWee/PHPWee.php index 792079d..df3b1b6 100644 --- a/src/PHPWee/PHPWee.php +++ b/src/PHPWee/PHPWee.php @@ -11,9 +11,9 @@ class PHPWee * @param $html * @return string */ - public static function html($html) + public static function html($html, $css = true, $js = true, $encoding = 'UTF-8') { - return HtmlMin\HtmlMin::minify($html); + return HtmlMin\HtmlMin::minify($html, $css, $js, $encoding); } /**