Вход Регистрация
Файл: min/lib/Minify/CSS/Compressor.php
Строк: 254
<?php
/**
 * Class Minify_CSS_Compressor 
 * @package Minify
 */

/**
 * Compress CSS
 *
 * This is a heavy regex-based removal of whitespace, unnecessary
 * comments and tokens, and some CSS value minimization, where practical.
 * Many steps have been taken to avoid breaking comment-based hacks, 
 * including the ie5/mac filter (and its inversion), but expect tricky
 * hacks involving comment tokens in 'content' value strings to break
 * minimization badly. A test suite is available.
 * 
 * @package Minify
 * @author Stephen Clay <steve@mrclay.org>
 * @author http://code.google.com/u/1stvamp/ (Issue 64 patch)
 */
class Minify_CSS_Compressor {

    
/**
     * Minify a CSS string
     * 
     * @param string $css
     * 
     * @param array $options (currently ignored)
     * 
     * @return string
     */
    
public static function process($css$options = array())
    {
        
$obj = new Minify_CSS_Compressor($options);
        return 
$obj->_process($css);
    }
    
    
/**
     * @var array options
     */
    
protected $_options null;
    
    
/**
     * @var bool Are we "in" a hack?
     * 
     * I.e. are some browsers targetted until the next comment?
     */
    
protected $_inHack false;
    
    
    
/**
     * Constructor
     * 
     * @param array $options (currently ignored)
     * 
     * @return null
     */
    
private function __construct($options) {
        
$this->_options $options;
    }
    
    
/**
     * Minify a CSS string
     * 
     * @param string $css
     * 
     * @return string
     */
    
protected function _process($css)
    {
        
$css str_replace("rn""n"$css);
        
        
// preserve empty comment after '>'
        // http://www.webdevout.net/css-hacks#in_css-selectors
        
$css preg_replace('@>/\*\s*\*/@''>/*keep*/'$css);
        
        
// preserve empty comment between property and value
        // http://css-discuss.incutio.com/?page=BoxModelHack
        
$css preg_replace('@/\*\s*\*/\s*:@''/*keep*/:'$css);
        
$css preg_replace('@:\s*/\*\s*\*/@'':/*keep*/'$css);
        
        
// apply callback to all valid comments (and strip out surrounding ws
        
$css preg_replace_callback('@\s*/\*([\s\S]*?)\*/\s*@'
            
,array($this'_commentCB'), $css);

        
// remove ws around { } and last semicolon in declaration block
        
$css preg_replace('/\s*{\s*/''{'$css);
        
$css preg_replace('/;?\s*}\s*/''}'$css);
        
        
// remove ws surrounding semicolons
        
$css preg_replace('/\s*;\s*/'';'$css);
        
        
// remove ws around urls
        
$css preg_replace('/
                url\(      # url(
                \s*
                ([^\)]+?)  # 1 = the URL (really just a bunch of non right parenthesis)
                \s*
                \)         # )
            /x'
'url($1)'$css);
        
        
// remove ws between rules and colons
        
$css preg_replace('/
                \s*
                ([{;])              # 1 = beginning of block or rule separator 
                \s*
                ([\*_]?[\w\-]+)  # 2 = property (and maybe IE filter)
                \s*
                :
                \s*
                (\b|[#'"])        # 3 = first character of a value
            /x', '$1$2:$3', 
$css);
        
        // remove ws in selectors
        
$css = preg_replace_callback('/
                (?:              # non-capture
                    \s*
                    [^~>+,\s]+  # selector part
                    \s*
                    [,>+~]       # combinators
                )+
                \s*
                [^~>+,\s]+      # selector part
                {                # open declaration block
            /x'
            ,array(
$this, '_selectorsCB'), $css);
        
        // minimize hex colors
        
$css = preg_replace('/([^=])#([a-f\d])\2([a-f\d])\3([a-f\d])\4([\s;\}])/i'
            , '$1#$2$3$4$5', 
$css);
        
        // remove spaces between font families
        
$css = preg_replace_callback('/font-family:([^;}]+)([;}])/'
            ,array(
$this, '_fontFamilyCB'), $css);
        
        
$css = preg_replace('/@import\s+url/', '@import url', $css);
        
        // replace any ws involving newlines with a single newline
        
$css = preg_replace('/[ \t]*\n+\s*/', "n", $css);
        
        // separate common descendent selectors w/ newlines (to limit line lengths)
        
$css = preg_replace('/([\w#\.\*]+)\s+([\w#\.\*]+){/', "$1n$2{", $css);
        
        // Use newline after 1st numeric value (to limit line lengths).
        
$css = preg_replace('/
            ((?:padding|margin|border|outline):\d+(?:px|em)?) # 1 = prop : 1st numeric value
            \s+
            /x'
            ,"
$1n", $css);
        
        // prevent triggering IE6 bug: http://www.crankygeek.com/ie6pebug/
        
$css = preg_replace('/:first-l(etter|ine)\{/', ':first-l$1 {', $css);
            
        return trim(
$css);
    }
    
    /**
     * Replace what looks like a set of selectors  
     *
     * @param array 
$m regex matches
     * 
     * @return string
     */
    protected function _selectorsCB(
$m)
    {
        // remove ws around the combinators
        return preg_replace('/\s*([,>+~])\s*/', '$1', 
$m[0]);
    }
    
    /**
     * Process a comment and return a replacement
     * 
     * @param array 
$m regex matches
     * 
     * @return string
     */
    protected function _commentCB(
$m)
    {
        
$hasSurroundingWs = (trim($m[0]) !== $m[1]);
        
$m = $m[1]
        // 
$m is the comment content w/o the surrounding tokens, 
        // but the return value will replace the entire comment.
        if (
$m === 'keep') {
            return '/**/';
        }
        if (
$m === '" "') {
            // component of http://tantek.com/CSS/Examples/midpass.html
            return '/*" "*/';
        }
        if (preg_match('@"
;\}\s*\}/\*\s+@', $m)) {
            // component of http://tantek.com/CSS/Examples/midpass.html
            return '
/*";}}/* */';
        }
        if ($this->_inHack) {
            // inversion: feeding only to one browser
            if (preg_match('
@
                    ^/               
# comment started like /*/
                    
\s*
                    (\
S[\s\S]+?)  # has at least some non-ws content
                    
\s*
                    /\*             
# ends like /*/ or /**/
                
@x', $m, $n)) {
                // end hack mode after this comment, but preserve the hack and comment content
                $this->_inHack = false;
                return "/*/{$n[1]}/**/";
            }
        }
        if (substr($m, -1) === '
\') { // comment ends like */
            // begin hack mode and preserve hack
            $this->_inHack = true;
            return '
/*\*/';
        }
        if ($m !== '' && $m[0] === '
/') { // comment looks like /*/ foo */
            // begin hack mode and preserve hack
            $this->_inHack = true;
            return '
/*/*/';
        }
        if ($this->_inHack) {
            // a regular comment ends hack mode but should be preserved
            $this->_inHack = false;
            return '
/**/';
        }
        // Issue 107: if there'
s any surrounding whitespaceit may be importantso 
        
// replace the comment with a single space
        
return $hasSurroundingWs // remove all other comments
            
' '
            
'';
    }
    
    
/**
     * Process a font-family listing and return a replacement
     * 
     * @param array $m regex matches
     * 
     * @return string   
     */
    
protected function _fontFamilyCB($m)
    {
        
$m[1] = preg_replace('/
                \s*
                (
                    "[^"]+"      # 1 = family in double qutoes
                    |'
[^']+'  # or 1 = family in single quotes
                    
|[\w\-]+   # or 1 = unquoted family
                
)
                \
s*
            /
x', '$1', $m[1]);
        return '
font-family:' . $m[1] . $m[2];
    }
}
Онлайн: 1
Реклама