diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..485dee6
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.idea
diff --git a/composer.json b/composer.json
index c8bc43a..7942f5c 100644
--- a/composer.json
+++ b/composer.json
@@ -6,23 +6,25 @@
"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/PHPWee"
+ }
+ },
"require": {
"php": ">=5.3.0"
}
-}
\ No newline at end of file
+}
diff --git a/examples/example.php b/examples/example.php
index 1ed5fd7..a35a3a5 100644
--- a/examples/example.php
+++ b/examples/example.php
@@ -1,9 +1,15 @@
-
-require_once ("../phpwee.php");
+
$subject |
---|
Gzipped Bytes Before PHPWee | Gzipped 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));
+ ?>
+
+
+ = $subject; ?> |
+
+
+ Gzipped Bytes Before PHPWee |
+ Gzipped Bytes After PHPWee |
+ % Performance Boost |
+
+
+ = $before; ?> before |
+ = $after; ?> after |
+ = $improvement; ?> % faster |
+
+
+
+
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * 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
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * 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
- */
-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
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * 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
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * 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
- */
-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
diff --git a/src/HtmlMin/HtmlMin.php b/src/HtmlMin/HtmlMin.php
deleted file mode 100644
index e25f753..0000000
--- a/src/HtmlMin/HtmlMin.php
+++ /dev/null
@@ -1,122 +0,0 @@
-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
diff --git a/src/PHPWee/CssMin/CssAtBlockEndToken.php b/src/PHPWee/CssMin/CssAtBlockEndToken.php
new file mode 100644
index 0000000..278e251
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtBlockEndToken.php
@@ -0,0 +1,25 @@
+
+ * @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/PHPWee/CssMin/CssAtBlockStartToken.php b/src/PHPWee/CssMin/CssAtBlockStartToken.php
new file mode 100644
index 0000000..6c0b085
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtBlockStartToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtCharsetParserPlugin.php b/src/PHPWee/CssMin/CssAtCharsetParserPlugin.php
new file mode 100644
index 0000000..b409d59
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtCharsetParserPlugin.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 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
+ * @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"
+ ) {
+ $this->parser->pushState("T_AT_CHARSET");
+ $this->parser->clearBuffer();
+ return $index + 8;
+ }
+
+ if (($char === ";" || $char === "\n") && $state === "T_AT_CHARSET") {
+ $charset = $this->parser->getAndClearBuffer(";");
+ $this->parser->popState();
+ $this->parser->appendToken(new CssAtCharsetToken($charset));
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/src/PHPWee/CssMin/CssAtCharsetToken.php b/src/PHPWee/CssMin/CssAtCharsetToken.php
new file mode 100644
index 0000000..f0aff65
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtCharsetToken.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 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
+ */
+ public function __construct($charset)
+ {
+ $this->Charset = $charset;
+ }
+
+ /**
+ * Implements {@link CssToken::__toString()}.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return "@charset ".$this->Charset.";";
+ }
+}
diff --git a/src/PHPWee/CssMin/CssAtFontFaceDeclarationToken.php b/src/PHPWee/CssMin/CssAtFontFaceDeclarationToken.php
new file mode 100644
index 0000000..a3ee4d6
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtFontFaceDeclarationToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtFontFaceEndToken.php b/src/PHPWee/CssMin/CssAtFontFaceEndToken.php
new file mode 100644
index 0000000..356748b
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtFontFaceEndToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtFontFaceParserPlugin.php b/src/PHPWee/CssMin/CssAtFontFaceParserPlugin.php
new file mode 100644
index 0000000..302b3ed
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtFontFaceParserPlugin.php
@@ -0,0 +1,110 @@
+
+ * @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
+ * @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"
+ ) {
+ $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()."_"
+ )
+ );
+ } 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));
+ $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();
+ }
+ } 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/PHPWee/CssMin/CssAtFontFaceStartToken.php b/src/PHPWee/CssMin/CssAtFontFaceStartToken.php
new file mode 100644
index 0000000..cdecef6
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssAtImportParserPlugin.php b/src/PHPWee/CssMin/CssAtImportParserPlugin.php
new file mode 100644
index 0000000..d2ba4be
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssAtImportToken.php b/src/PHPWee/CssMin/CssAtImportToken.php
new file mode 100644
index 0000000..da20a72
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtImportToken.php
@@ -0,0 +1,52 @@
+
+ * @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
+ */
+ 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/PHPWee/CssMin/CssAtKeyframesEndToken.php b/src/PHPWee/CssMin/CssAtKeyframesEndToken.php
new file mode 100644
index 0000000..3123ca2
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtKeyframesEndToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtKeyframesParserPlugin.php b/src/PHPWee/CssMin/CssAtKeyframesParserPlugin.php
new file mode 100644
index 0000000..5e78292
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtKeyframesParserPlugin.php
@@ -0,0 +1,164 @@
+
+ * @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
+ * @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"
+ ) {
+ $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/PHPWee/CssMin/CssAtKeyframesRulesetDeclarationToken.php b/src/PHPWee/CssMin/CssAtKeyframesRulesetDeclarationToken.php
new file mode 100644
index 0000000..8c8e921
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtKeyframesRulesetDeclarationToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtKeyframesRulesetEndToken.php b/src/PHPWee/CssMin/CssAtKeyframesRulesetEndToken.php
new file mode 100644
index 0000000..04805ba
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtKeyframesRulesetEndToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtKeyframesRulesetStartToken.php b/src/PHPWee/CssMin/CssAtKeyframesRulesetStartToken.php
new file mode 100644
index 0000000..6c401d2
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtKeyframesRulesetStartToken.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 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
+ */
+ 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/PHPWee/CssMin/CssAtKeyframesStartToken.php b/src/PHPWee/CssMin/CssAtKeyframesStartToken.php
new file mode 100644
index 0000000..8911451
--- /dev/null
+++ b/src/PHPWee/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 $name
+ * @param null $atRuleName
+ */
+ 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/PHPWee/CssMin/CssAtMediaEndToken.php b/src/PHPWee/CssMin/CssAtMediaEndToken.php
new file mode 100644
index 0000000..82bf077
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtMediaEndToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtMediaParserPlugin.php b/src/PHPWee/CssMin/CssAtMediaParserPlugin.php
new file mode 100644
index 0000000..e0b7b82
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtMediaParserPlugin.php
@@ -0,0 +1,76 @@
+
+ * @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
+ * @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"
+ ) {
+ $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/PHPWee/CssMin/CssAtMediaStartToken.php b/src/PHPWee/CssMin/CssAtMediaStartToken.php
new file mode 100644
index 0000000..60bd8f8
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtMediaStartToken.php
@@ -0,0 +1,35 @@
+
+ * @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
+ */
+ 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/PHPWee/CssMin/CssAtPageDeclarationToken.php b/src/PHPWee/CssMin/CssAtPageDeclarationToken.php
new file mode 100644
index 0000000..e31d639
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtPageDeclarationToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtPageEndToken.php b/src/PHPWee/CssMin/CssAtPageEndToken.php
new file mode 100644
index 0000000..5ba0ca2
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtPageEndToken.php
@@ -0,0 +1,16 @@
+
+ * @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/PHPWee/CssMin/CssAtPageParserPlugin.php b/src/PHPWee/CssMin/CssAtPageParserPlugin.php
new file mode 100644
index 0000000..21c5235
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtPageParserPlugin.php
@@ -0,0 +1,112 @@
+
+ * @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
+ * @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"
+ ) {
+ $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/PHPWee/CssMin/CssAtPageStartToken.php b/src/PHPWee/CssMin/CssAtPageStartToken.php
new file mode 100644
index 0000000..3101394
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtPageStartToken.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 CssAtPageStartToken extends CssAtBlockStartToken
+{
+ /**
+ * Selector.
+ *
+ * @var string
+ */
+ public $Selector = "";
+
+ /**
+ * Sets the properties of the @page at-rule.
+ *
+ * @param string $selector Selector
+ */
+ 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/PHPWee/CssMin/CssAtVariablesDeclarationToken.php b/src/PHPWee/CssMin/CssAtVariablesDeclarationToken.php
new file mode 100644
index 0000000..a900877
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssAtVariablesEndToken.php b/src/PHPWee/CssMin/CssAtVariablesEndToken.php
new file mode 100644
index 0000000..cde3f13
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssAtVariablesParserPlugin.php b/src/PHPWee/CssMin/CssAtVariablesParserPlugin.php
new file mode 100644
index 0000000..b9d20a3
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtVariablesParserPlugin.php
@@ -0,0 +1,107 @@
+
+ * @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
+ * @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"
+ ) {
+ $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/PHPWee/CssMin/CssAtVariablesStartToken.php b/src/PHPWee/CssMin/CssAtVariablesStartToken.php
new file mode 100644
index 0000000..d682f3f
--- /dev/null
+++ b/src/PHPWee/CssMin/CssAtVariablesStartToken.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 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
+ */
+ 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/PHPWee/CssMin/CssCommentParserPlugin.php b/src/PHPWee/CssMin/CssCommentParserPlugin.php
new file mode 100644
index 0000000..3456d57
--- /dev/null
+++ b/src/PHPWee/CssMin/CssCommentParserPlugin.php
@@ -0,0 +1,73 @@
+
+ * @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
+ * @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 === "*" && $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/PHPWee/CssMin/CssCommentToken.php b/src/PHPWee/CssMin/CssCommentToken.php
new file mode 100644
index 0000000..7628337
--- /dev/null
+++ b/src/PHPWee/CssMin/CssCommentToken.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 CssCommentToken extends CssToken
+{
+ /**
+ * Comment as Text.
+ *
+ * @var string
+ */
+ public $Comment = "";
+
+ /**
+ * Set the properties of a comment token.
+ *
+ * @param string $comment Comment including comment delimiters
+ */
+ public function __construct($comment)
+ {
+ $this->Comment = $comment;
+ }
+
+ /**
+ * Implements {@link CssToken::__toString()}.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->Comment;
+ }
+}
diff --git a/src/PHPWee/CssMin/CssCompressColorValuesMinifierPlugin.php b/src/PHPWee/CssMin/CssCompressColorValuesMinifierPlugin.php
new file mode 100644
index 0000000..20ca878
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssCompressExpressionValuesMinifierPlugin.php b/src/PHPWee/CssMin/CssCompressExpressionValuesMinifierPlugin.php
new file mode 100644
index 0000000..66e52c5
--- /dev/null
+++ b/src/PHPWee/CssMin/CssCompressExpressionValuesMinifierPlugin.php
@@ -0,0 +1,51 @@
+
+ * @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 = 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/PHPWee/CssMin/CssCompressUnitValuesMinifierPlugin.php b/src/PHPWee/CssMin/CssCompressUnitValuesMinifierPlugin.php
new file mode 100644
index 0000000..86c775a
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssConvertFontWeightMinifierPlugin.php b/src/PHPWee/CssMin/CssConvertFontWeightMinifierPlugin.php
new file mode 100644
index 0000000..9e4a041
--- /dev/null
+++ b/src/PHPWee/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.
+ */
+ 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/PHPWee/CssMin/CssConvertHslColorsMinifierPlugin.php b/src/PHPWee/CssMin/CssConvertHslColorsMinifierPlugin.php
new file mode 100644
index 0000000..f648a72
--- /dev/null
+++ b/src/PHPWee/CssMin/CssConvertHslColorsMinifierPlugin.php
@@ -0,0 +1,126 @@
+
+ * 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/PHPWee/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php b/src/PHPWee/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.php
new file mode 100644
index 0000000..5acdd35
--- /dev/null
+++ b/src/PHPWee/CssMin/CssConvertLevel3AtKeyframesMinifierFilter.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 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/PHPWee/CssMin/CssConvertLevel3PropertiesMinifierFilter.php b/src/PHPWee/CssMin/CssConvertLevel3PropertiesMinifierFilter.php
new file mode 100644
index 0000000..d98ff80
--- /dev/null
+++ b/src/PHPWee/CssMin/CssConvertLevel3PropertiesMinifierFilter.php
@@ -0,0 +1,365 @@
+
+ * @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),
+ "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"),
+ "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(CssToken $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;
+ }
+
+ return array();
+ }
+}
diff --git a/src/PHPWee/CssMin/CssConvertNamedColorsMinifierPlugin.php b/src/PHPWee/CssMin/CssConvertNamedColorsMinifierPlugin.php
new file mode 100644
index 0000000..6e718b5
--- /dev/null
+++ b/src/PHPWee/CssMin/CssConvertNamedColorsMinifierPlugin.php
@@ -0,0 +1,238 @@
+
+ * 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]
+ */
+ 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/PHPWee/CssMin/CssConvertRgbColorsMinifierPlugin.php b/src/PHPWee/CssMin/CssConvertRgbColorsMinifierPlugin.php
new file mode 100644
index 0000000..555c908
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssDeclarationToken.php b/src/PHPWee/CssMin/CssDeclarationToken.php
new file mode 100644
index 0000000..b59321c
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssError.php b/src/PHPWee/CssMin/CssError.php
new file mode 100644
index 0000000..c1fd066
--- /dev/null
+++ b/src/PHPWee/CssMin/CssError.php
@@ -0,0 +1,71 @@
+
+ * @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 $file
+ * @param $line
+ * @param string $message Error message
+ * @param string $source Corresponding line [optional]
+ */
+ 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/PHPWee/CssMin/CssExpressionParserPlugin.php b/src/PHPWee/CssMin/CssExpressionParserPlugin.php
new file mode 100644
index 0000000..56b4662
--- /dev/null
+++ b/src/PHPWee/CssMin/CssExpressionParserPlugin.php
@@ -0,0 +1,92 @@
+
+ * @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
+ * @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"
+ ) {
+ $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/PHPWee/CssMin/CssFormatter.php b/src/PHPWee/CssMin/CssFormatter.php
new file mode 100644
index 0000000..8cd8cf7
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssImportImportsMinifierFilter.php b/src/PHPWee/CssMin/CssImportImportsMinifierFilter.php
new file mode 100644
index 0000000..ad9a63a
--- /dev/null
+++ b/src/PHPWee/CssMin/CssImportImportsMinifierFilter.php
@@ -0,0 +1,218 @@
+
+ * @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 no media types are 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);
+ }
+ }
+ }
+
+ return count($tokens);
+ }
+}
diff --git a/src/PHPWee/CssMin/CssMin.php b/src/PHPWee/CssMin/CssMin.php
new file mode 100644
index 0000000..1ad9b74
--- /dev/null
+++ b/src/PHPWee/CssMin/CssMin.php
@@ -0,0 +1,158 @@
+
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * 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
+ */
+
+/**
+ * CssMin - A (simple) css minifier with benefits
+ *
+ * --
+ * Copyright (c) 2011 Joe Scylla
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * 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
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * 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
+{
+ /**
+ * 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/PHPWee/CssMin/CssMinifier.php b/src/PHPWee/CssMin/CssMinifier.php
new file mode 100644
index 0000000..f584899
--- /dev/null
+++ b/src/PHPWee/CssMin/CssMinifier.php
@@ -0,0 +1,206 @@
+
+ * @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]
+ */
+ 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 = '\\'.__NAMESPACE__."\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 = '\\'.__NAMESPACE__."\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 $class 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/PHPWee/CssMin/CssMinifierFilter.php b/src/PHPWee/CssMin/CssMinifierFilter.php
new file mode 100644
index 0000000..0b6597a
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssMinifierPlugin.php b/src/PHPWee/CssMin/CssMinifierPlugin.php
new file mode 100644
index 0000000..d99f25b
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssNullToken.php b/src/PHPWee/CssMin/CssNullToken.php
new file mode 100644
index 0000000..66945bc
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssOtbsFormatter.php b/src/PHPWee/CssMin/CssOtbsFormatter.php
new file mode 100644
index 0000000..ec049b7
--- /dev/null
+++ b/src/PHPWee/CssMin/CssOtbsFormatter.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 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/PHPWee/CssMin/CssParser.php b/src/PHPWee/CssMin/CssParser.php
new file mode 100644
index 0000000..b3859d2
--- /dev/null
+++ b/src/PHPWee/CssMin/CssParser.php
@@ -0,0 +1,433 @@
+
+ * @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]
+ */
+ 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 = '\\'.__NAMESPACE__."\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 $class 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
+ // 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/PHPWee/CssMin/CssParserPlugin.php b/src/PHPWee/CssMin/CssParserPlugin.php
new file mode 100644
index 0000000..b2a6452
--- /dev/null
+++ b/src/PHPWee/CssMin/CssParserPlugin.php
@@ -0,0 +1,76 @@
+
+ * @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
+ * @param $state
+ * @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/PHPWee/CssMin/CssRemoveCommentsMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveCommentsMinifierFilter.php
new file mode 100644
index 0000000..3a91f28
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveEmptyAtBlocksMinifierFilter.php
new file mode 100644
index 0000000..53d59dd
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveEmptyRulesetsMinifierFilter.php
new file mode 100644
index 0000000..b890f5c
--- /dev/null
+++ b/src/PHPWee/CssMin/CssRemoveEmptyRulesetsMinifierFilter.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 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/PHPWee/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php b/src/PHPWee/CssMin/CssRemoveLastDelarationSemiColonMinifierFilter.php
new file mode 100644
index 0000000..4e36acd
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssRulesetDeclarationToken.php b/src/PHPWee/CssMin/CssRulesetDeclarationToken.php
new file mode 100644
index 0000000..6d00fc0
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssRulesetEndToken.php b/src/PHPWee/CssMin/CssRulesetEndToken.php
new file mode 100644
index 0000000..5357087
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssRulesetParserPlugin.php b/src/PHPWee/CssMin/CssRulesetParserPlugin.php
new file mode 100644
index 0000000..a639c51
--- /dev/null
+++ b/src/PHPWee/CssMin/CssRulesetParserPlugin.php
@@ -0,0 +1,135 @@
+
+ * @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
+ * @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 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/PHPWee/CssMin/CssRulesetStartToken.php b/src/PHPWee/CssMin/CssRulesetStartToken.php
new file mode 100644
index 0000000..5bea261
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssSortRulesetPropertiesMinifierFilter.php b/src/PHPWee/CssMin/CssSortRulesetPropertiesMinifierFilter.php
new file mode 100644
index 0000000..ad6a6dd
--- /dev/null
+++ b/src/PHPWee/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/PHPWee/CssMin/CssStringParserPlugin.php b/src/PHPWee/CssMin/CssStringParserPlugin.php
new file mode 100644
index 0000000..cc6fe3d
--- /dev/null
+++ b/src/PHPWee/CssMin/CssStringParserPlugin.php
@@ -0,0 +1,107 @@
+
+ * @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
+ * @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 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/PHPWee/CssMin/CssToken.php b/src/PHPWee/CssMin/CssToken.php
new file mode 100644
index 0000000..c7fd900
--- /dev/null
+++ b/src/PHPWee/CssMin/CssToken.php
@@ -0,0 +1,39 @@
+
+ * @copyright 2008 - 2011 Joe Scylla
+ * @license http://opensource.org/licenses/mit-license.php MIT License
+ * @version 3.0.1
+ */
+abstract class CssToken
+{
+ /**
+ * @var array
+ */
+ public $MediaTypes = array();
+
+ /**
+ * @var string
+ */
+ public $Property = "";
+
+ /**
+ * @var string
+ */
+ public $Value = "";
+
+ /**
+ * Returns the token as string.
+ *
+ * @return string
+ */
+ abstract public function __toString();
+}
diff --git a/src/PHPWee/CssMin/CssUrlParserPlugin.php b/src/PHPWee/CssMin/CssUrlParserPlugin.php
new file mode 100644
index 0000000..03e8f39
--- /dev/null
+++ b/src/PHPWee/CssMin/CssUrlParserPlugin.php
@@ -0,0 +1,86 @@
+
+ * @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
+ * @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 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/PHPWee/CssMin/CssVariablesMinifierFilter.php b/src/PHPWee/CssMin/CssVariablesMinifierFilter.php
new file mode 100644
index 0000000..9844de2
--- /dev/null
+++ b/src/PHPWee/CssMin/CssVariablesMinifierFilter.php
@@ -0,0 +1,88 @@
+
+ * @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");
+ $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 < $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/PHPWee/CssMin/CssVariablesMinifierPlugin.php b/src/PHPWee/CssMin/CssVariablesMinifierPlugin.php
new file mode 100644
index 0000000..aaa1caa
--- /dev/null
+++ b/src/PHPWee/CssMin/CssVariablesMinifierPlugin.php
@@ -0,0 +1,119 @@
+
+ * @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/PHPWee/CssMin/CssWhitesmithsFormatter.php b/src/PHPWee/CssMin/CssWhitesmithsFormatter.php
new file mode 100644
index 0000000..9fcf9b2
--- /dev/null
+++ b/src/PHPWee/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/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/PHPWee/HtmlMin/HtmlMin.php b/src/PHPWee/HtmlMin/HtmlMin.php
new file mode 100644
index 0000000..63c252c
--- /dev/null
+++ b/src/PHPWee/HtmlMin/HtmlMin.php
@@ -0,0 +1,149 @@
+preserveWhiteSpace = false;
+ $doc->encoding = $encoding;
+ @$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"];
+
+ /** @var \DOMNode $t */
+ 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');
+
+ /** @var \DOMNode $d */
+ foreach ($scriptnodes as $d) {
+ $attributes = [];
+ foreach ($d->attributes as $attr) {
+ $attributes[$attr->nodeName] = $attr->nodeValue;
+ }
+
+ if (isset($attributes['type']) && (strtolower($attributes['type']) !== 'text/javascript')) {
+ continue;
+ }
+
+ if (isset($attributes['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) {
+ $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 = CssMin::minify($d->nodeValue);
+ }
+ }
+ return ($doc->saveHTML());
+ }
+}
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 87%
rename from src/JsMin/JsMin.php
rename to src/PHPWee/JsMin/JsMin.php
index 8649358..6973f44 100644
--- a/src/JsMin/JsMin.php
+++ b/src/PHPWee/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/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/PHPWee/JsMin/UnterminatedCommentException.php b/src/PHPWee/JsMin/UnterminatedCommentException.php
new file mode 100644
index 0000000..7e5325b
--- /dev/null
+++ b/src/PHPWee/JsMin/UnterminatedCommentException.php
@@ -0,0 +1,10 @@
+