public function filterLoad(AssetInterface $asset) { $options = array(); if (null !== $this->debug) { $options['debug'] = (bool) $this->debug; } if (null !== $this->boilerplate) { $options['boilerplate'] = (bool) $this->boilerplate; } if (null !== $this->versioning) { $options['versioning'] = (bool) $this->versioning; } if (!empty($this->plugins)) { $options['enable'] = $this->plugins; } // remember the previous document root $snapshot = \CssCrush::$config->docRoot; // process the asset \CssCrush::$config->docRoot = $asset->getSourceRoot(); $output = (string) \CssCrush::string($asset->getContent(), $options); $asset->setContent($output); // cleanup \CssCrush::$config->docRoot = $snapshot; }
/** * * CSS Crush * Extensible CSS preprocessor * * @version 1.4.1 * @license http://www.opensource.org/licenses/mit-license.php (MIT) * @copyright Copyright 2010-2012 Pete Boere * * * <?php * * // Basic usage * require_once 'CssCrush.php'; * $global_css = CssCrush::file( '/css/global.css' ); * * ?> * * <link rel="stylesheet" href="<?php echo $global_css; ?>" /> * */ require_once 'lib/Util.php'; require_once 'lib/Core.php'; CssCrush::init(dirname(__FILE__)); require_once 'lib/Rule.php'; require_once 'lib/Function.php'; CssCrush_Function::init(); require_once 'lib/Importer.php'; require_once 'lib/Color.php'; require_once 'lib/Hook.php';
public static function hostfile($hostfile) { $config = CssCrush::$config; $regex = CssCrush::$regex; // Keep track of all import file info for later logging $mtimes = array(); $filenames = array(); // Get the hostfile contents and obfuscate commented imports $str = self::obfuscateComments(file_get_contents($hostfile->path)); // This may be set non-zero if an absoulte URL is encountered $searchOffset = 0; // Recurses until the nesting heirarchy is flattened and all files are combined while (preg_match($regex->import, $str, $match, PREG_OFFSET_CAPTURE, $searchOffset)) { $fullMatch = $match[0][0]; // Full match $matchStart = $match[0][1]; // Full match offset $matchEnd = $matchStart + strlen($fullMatch); $url = trim($match[1][0]); // The url $mediaContext = trim($match[2][0]); // The media context if specified $preStatement = substr($str, 0, $matchStart); $postStatement = substr($str, $matchEnd); // Pass over absolute urls // Move the search pointer forward if (preg_match('!^https?://!', $url)) { $searchOffset = $matchEnd; continue; } $import = new stdClass(); $import->name = $url; $import->mediaContext = $mediaContext; $import->path = "{$hostfile->dir}/{$import->name}"; $import->content = @file_get_contents($import->path); // Failed to open import, just continue with the import line removed if (!$import->content) { CssCrush::log("Import file '{$import->name}' not found"); $str = $preStatement . $postStatement; continue; } else { $import->content = self::obfuscateComments($import->content); if ($import->mediaContext) { $import->content = "@media {$import->mediaContext} {" . $import->content . '}'; } $import->dir = dirname($import->name); // Store import file info $mtimes[] = filemtime($import->path); $filenames[] = $import->name; // Store the replacements we might find $replacements = array(); // Match all @import statements in the import content // Alter all the url strings to be paths relative to the hostfile $matchCount = preg_match_all($regex->import, $import->content, $matchAll, PREG_OFFSET_CAPTURE); for ($index = 0; $index < $matchCount; $index++) { $fullMatch = $matchAll[0][$index][0]; $urlMatch = $matchAll[1][$index][0]; $search = $urlMatch; $replace = "{$import->dir}/{$urlMatch}"; // Try to resolve absolute paths // On failure strip the @import statement if (strpos($urlMatch, '/') === 0) { $replace = self::resolveAbsolutePath($urlMatch); if (!$replace) { $search = $fullMatch; $replace = ''; } } $replacements[$fullMatch] = str_replace($search, $replace, $fullMatch); } // If we've stored any altered @import strings then we need to apply them if (count($replacements)) { $import->content = str_replace(array_keys($replacements), array_values($replacements), $import->content); } // CssCrush::log( $replacements ); $str = $preStatement . $import->content . $postStatement; } } // End while self::save(array('imports' => $filenames, 'datem_sum' => array_sum($mtimes) + $hostfile->mtime, 'options' => CssCrush::$options)); return $str; }
public function __construct($selector_string = null, $declarations_string) { $regex = CssCrush::$regex; // Parse the selectors chunk if (!empty($selector_string)) { $selector_adjustments = array('!:hocus([^a-z0-9_-])!' => ':any(:hover,:focus)$1', '!:pocus([^a-z0-9_-])!' => ':any(:hover,:focus,:active)$1', '!::(after|before|first-letter|first-line)!' => ':$1'); $selector_string = preg_replace(array_keys($selector_adjustments), array_values($selector_adjustments), $selector_string); $selectors_match = CssCrush::splitDelimList($selector_string, ','); $this->parens += $selectors_match->matches; // Remove and store comments that sit above the first selector // remove all comments between the other selectors preg_match_all($regex->token->comment, $selectors_match->list[0], $m); $this->comments = $m[0]; foreach ($selectors_match->list as &$selector) { $selector = preg_replace($regex->token->comment, '', $selector); $selector = trim($selector); } $this->selectors = $selectors_match->list; } // Parse the declarations chunk $declarations_match = CssCrush::splitDelimList($declarations_string, ';'); $this->parens += $declarations_match->matches; // Parse declarations in to property/value pairs foreach ($declarations_match->list as $declaration) { // Strip comments around the property $declaration = preg_replace($regex->token->comment, '', $declaration); // Store the property $colonPos = strpos($declaration, ':'); if ($colonPos === false) { // If there is no colon it's malformed continue; } else { $prop = trim(substr($declaration, 0, $colonPos)); // Store the property name $this->addProperty($prop); } // Extract the value part of the declaration $value = substr($declaration, $colonPos + 1); $value = $value !== false ? trim($value) : $value; if ($value === false or $value === '') { // We'll ignore declarations with empty values continue; } // If are parenthesised expressions in the value // Search for any custom functions so we can apply them if (count($declarations_match->matches)) { CssCrush::$storage->tmpParens = $declarations_match->matches; $value = preg_replace_callback($regex->function->custom, array('CssCrush_Function', 'css_fn'), $value); } // Store the property family // Store the vendor id, if one is present if (preg_match($regex->vendorPrefix, $prop, $vendor)) { $family = $vendor[2]; $vendor = $vendor[1]; } else { $vendor = null; $family = $prop; } // Create an index of all functions in the current declaration if (preg_match_all($regex->function->match, $value, $functions) > 0) { $out = array(); foreach ($functions[2] as $index => $fn_name) { $out[] = $fn_name; } $functions = array_unique($out); } else { $functions = array(); } // Store the declaration $_declaration = (object) array('property' => $prop, 'family' => $family, 'vendor' => $vendor, 'functions' => $functions, 'value' => $value); $this->declarations[] = $_declaration; } }
<?php ################################################################################################ # Comment out/in as required // IE 6 shims CssCrush::addRuleMacro('csscrush_minheight'); // IE 6/7 shims CssCrush::addRuleMacro('csscrush_clip'); CssCrush::addRuleMacro('csscrush_display_inlineblock'); // IE filter CssCrush::addRuleMacro('csscrush_filter'); // RGBA fallback CssCrush::addRuleMacro('csscrush_rgba'); // HSL for all browsers CssCrush::addRuleMacro('csscrush_hsl'); ################################################################################################ /** * Simulate inline-block in IE < 8 * * Before: * display: inline-block; * * After: * display: inline-block; * *display: inline; * *zoom: 1; */ function csscrush_display_inlineblock(CssCrush_Rule $rule) { if ($rule->propertyCount('display') < 1) { return;
protected static function parseArgs($input, $argCount = null) { $args = CssCrush::splitDelimList($input, ',', true, true); return array_map('trim', $args->list); }
protected static function compile($stream) { $regex = self::$regex; // Reset properties for current process self::$tokenUID = 0; self::$storage = new stdClass(); self::$storage->tokens = (object) array('strings' => array(), 'comments' => array(), 'rules' => array(), 'parens' => array()); self::$storage->variables = array(); // Load in aliases and macros if (!self::$assetsLoaded) { self::loadAssets(); self::$assetsLoaded = true; } // Set the custom function regular expression $css_functions = CssCrush_Function::getFunctions(); $regex->function->custom = str_replace('<functions>', implode('|', $css_functions), $regex->function->custom); // Extract comments $stream = preg_replace_callback($regex->comment, array('self', 'cb_extractComments'), $stream); // Extract strings $stream = preg_replace_callback($regex->string, array('self', 'cb_extractStrings'), $stream); // Parse variables $stream = preg_replace_callback($regex->variables, array('self', 'cb_extractVariables'), $stream); // Calculate the variable stack self::calculateVariables(); self::log(self::$storage->variables); // Place the variables $stream = self::placeVariables($stream); // Normalize whitespace $stream = self::normalize($stream); // Adjust the stream so we can extract the rules cleanly $map = array('@' => "\n@", '}' => "}\n", '{' => "{\n", ';' => ";\n"); $stream = "\n" . str_replace(array_keys($map), array_values($map), $stream); // Extract rules $stream = preg_replace_callback($regex->rule, array('self', 'cb_extractRules'), $stream); // Alias at-rules (if there are any) $stream = self::aliasAtRules($stream); // print it all back $stream = self::display($stream); // self::log( self::$storage->tokens->rules ); // self::log( self::$storage->tokens ); self::log(self::$config->data); // Release memory self::$storage = null; return $stream; }