/** * Parses a css selector code and creates a new Selector object * * @param string $string The css code * @return Stylecow\Selector */ public static function createFromString($string) { $string = trim($string); if ($string[0] === '@') { $pieces = Parser::explodeTrim(' ', $string, 2); return new static($pieces[0], isset($pieces[1]) ? Parser::explodeTrim(',', $pieces[1]) : null); } return new static(null, Parser::explodeTrim(',', $string)); }
/** * Apply the plugin to Css object * * @param Stylecow\Css $css The css object */ public static function apply(Css $css) { $css->executeRecursive(function ($code) { while (strpos((string) $code->selector, ':matches(') !== false) { foreach ($code->selector->get() as $key => $selector) { if (preg_match('/:matches\\(([^\\)]*)\\)/', $selector, $match)) { $code->selector->delete($key); foreach (Parser::explodeTrim(',', $match[1]) as $matchSelector) { $code->selector->add(str_replace($match[0], $matchSelector, $selector)); } } } } }); }
/** * Search and replace the css variables with the real value * * @param string $value The property value where the variable is placed * @param array $variables The defined variables */ public static function replaceVariables($value, array $variables) { if (strpos($value, '$') !== false) { $value = preg_replace_callback('/\\$([\\w-]+)/', function ($matches) use($variables) { return isset($variables[$matches[1]]) ? $variables[$matches[1]] : $matches[0]; }, $value); } $value = Parser::executeFunctions($value, 'var', function ($params) use($variables) { if (!isset($params[0])) { return 'var()'; } if (isset($variables[$params[0]])) { return $variables[$params[0]]; } return isset($params[1]) ? $params[1] : 'var(' . $params[0] . ')'; }); return $value; }
/** * Apply the plugin to Css object * * @param Stylecow\Css $css The css object */ public static function apply(Css $css) { $css->executeRecursive(function ($code) { foreach ($code->getProperties() as $property) { $property->executeFunction('color', function ($parameters) { $rgba = Color::toRGBA(array_shift($parameters)); foreach ($parameters as $operation) { if (strpos($operation, ':') === false) { if (preg_match('/^[0-9]+$/', $operation)) { $function = 'tint'; $value = $operation; } else { continue; } } else { list($function, $value) = Parser::explodeTrim(':', $operation, 2); } switch ($function) { case 'hue': case 'saturation': case 'light': $rgba = Color::HSLA_RGBA(Color::editChannel(Color::RGBA_HSLA($rgba), $function, $value)); break; case 'red': case 'green': case 'blue': case 'alpha': $rgba = Color::editChannel($rgba, $function, $value); break; case 'tint': $rgba = Color::editTint($rgba, $value); break; } } if ($rgba[3] < 1) { return 'rgba(' . implode(', ', $rgba) . ')'; } return '#' . Color::RGBA_HEX($rgba); }); } }); }
/** * @param string $buffer * @return string */ private function optimize($buffer) { $plugins = array('Color' => true, 'Grid' => true, 'IeBackgroundAlpha' => true, 'IeClip' => true, 'IeFloat' => true, 'IeInlineBlock' => true, 'IeLinearGradient' => true, 'IeMinHeight' => true, 'IeOpacity' => true, 'Initial' => true, 'Matches' => true, 'Math' => true, 'MediaQuery' => false, 'NestedRules' => false, 'Rem' => true, 'IeTransform' => true, 'Variables' => false, 'VendorPrefixes' => true, 'BaseUrl' => \App::get('home')); $stylecow = \Stylecow\Parser::parseString($buffer); $stylecow->applyPlugins($plugins); return (string) $stylecow; }
/** * Generate the old webkit syntax for the linear-gradient * * @param Stylecow\Property $property The property object with the standard syntax */ public static function webkitLinearGradient(Property $property) { $newProperty = clone $property; $newProperty->executeFunction('linear-gradient', function ($params) { $point = 'top'; if (preg_match('/(top|bottom|left|right|deg)/', $params[0])) { $point = array_shift($params); } switch ($point) { case 'to bottom': $start = 'left top'; $end = 'left bottom'; break; case 'to top': $start = 'left bottom'; $end = 'left top'; break; case 'to right': $start = 'left top'; $end = 'right top'; break; case 'to left': $start = 'right top'; $end = 'left top'; break; default: if (preg_match('/^\\ddeg$/', $point)) { $radius = intval($point); } else { $start = 'left top'; $end = 'left bottom'; } } $color_stops = array(); $tk = count($params) - 1; foreach ($params as $k => $param) { $param = Parser::explode(' ', trim($param)); $color = $param[0]; $stop = isset($param[1]) ? $param[1] : null; if ($k === 0) { $text = 'from'; } else { if ($k === $tk) { $text = 'to'; } else { $text = 'color-stop'; } } if ($stop) { $color_stops[] = $text . '(' . $stop . ', ' . $color . ')'; } else { $color_stops[] = $text . '(' . $color . ')'; } } if (isset($radius)) { return '-webkit-gradient(linear, ' . $radius . 'deg, ' . implode(', ', $color_stops) . ')'; } else { return '-webkit-gradient(linear, ' . $start . ', ' . $end . ', ' . implode(', ', $color_stops) . ')'; } }); if ($property->value !== $newProperty->value) { $newProperty->vendor = 'webkit'; $property->parent->addProperty($newProperty, $property->getPositionInParent()); } }
/** * Converts a color declaration in rgba format. * * @param string $colors The css color declaration * * @return array The rgba color values */ public static function resolveColor($colors) { $colors = Parser::explodeTrim(' ', $colors); if (count($colors) === 1) { return Color::toRGBA($colors[0]); } $sumColors = array(0, 0, 0, 0); foreach ($colors as $k => $color) { $color = Color::toRGBA($color); $sumColors[0] += $color[0]; $sumColors[1] += $color[1]; $sumColors[2] += $color[2]; $sumColors[3] += $color[3]; } $total = count($colors); $sumColors[0] = round($sumColors[0] / $total); $sumColors[1] = round($sumColors[1] / $total); $sumColors[2] = round($sumColors[2] / $total); $sumColors[3] = round($sumColors[3] / $total); return $sumColors; }
/** * Get Stylecow\Css object from a string. * @param string $cssString * @param string $file * * @return Stylecow\Css */ protected function getCss($cssString, $file) { $css = Stylecow\Parser::parseString($cssString); $this->checkCssImport($css, $file); return $css; }
<?php include 'Stylecow/autoloader.php'; use Stylecow\Parser; $plugins = array('Color' => array('checked' => false, 'options' => array()), 'Grid' => array('checked' => false, 'options' => array()), 'IeBackgroundAlpha' => array('checked' => false, 'options' => array()), 'IeClip' => array('checked' => false, 'options' => array()), 'IeFloat' => array('checked' => false, 'options' => array()), 'IeInlineBlock' => array('checked' => false, 'options' => array()), 'IeLinearGradient' => array('checked' => false, 'options' => array()), 'IeMinHeight' => array('checked' => false, 'options' => array()), 'IeOpacity' => array('checked' => false, 'options' => array()), 'Initial' => array('checked' => false, 'options' => array()), 'Matches' => array('checked' => true, 'options' => array()), 'Math' => array('checked' => false, 'options' => array()), 'MediaQuery' => array('checked' => false, 'options' => array('width' => array('string', ''), 'type' => array('string', 'all'))), 'NestedRules' => array('checked' => true, 'options' => array()), 'Rem' => array('checked' => true, 'options' => array()), 'IeTransform' => array('checked' => false, 'options' => array()), 'Variables' => array('checked' => true, 'options' => array()), 'VendorPrefixes' => array('checked' => true, 'options' => array())); $input_code = $output_code = ''; //If the form has been send if (isset($_POST['send'])) { //Initialize stylecow $input_code = $_POST['code']; $css = Parser::parseString($input_code); //Load the plugin configuration $applyPlugins = array(); foreach ($plugins as $plugin => $settings) { if (isset($_POST['plugin'][$plugin])) { $applyPlugins[$plugin] = array(); $plugins[$plugin]['checked'] = true; foreach ($settings['options'] as $name => $value) { $valuePost = isset($_POST['pluginOptions'][$plugin][$name]) ? $_POST['pluginOptions'][$plugin][$name] : ''; if ($valuePost === '') { switch ($value[0]) { case 'bool': $plugins[$plugin]['options'][$name][1] = false; break; default: $plugins[$plugin]['options'][$name][1] = null; break; } } else { $plugins[$plugin]['options'][$name][1] = $valuePost; }
/** * Fix the different syntaxis for the linear-gradient * * @param string $value The value of the property * * @return array The linear-gradient code */ public static function webkitLinearGradient($value) { return Parser::executeFunctions($value, 'linear-gradient', function ($params) { $point = 'top'; if (preg_match('/(top|bottom|left|right|deg)/', $params[0])) { $point = array_shift($params); } switch ($point) { case 'center top': case 'top': $start = 'left top'; $end = 'left bottom'; break; case 'center bottom': case 'bottom': $start = 'left bottom'; $end = 'left top'; break; case 'left top': case 'left': $start = 'left top'; $end = 'right top'; break; case 'right top': case 'right': $start = 'right top'; $end = 'left top'; break; default: $radius = intval($point); } $color_stops = array(); $tk = count($params) - 1; foreach ($params as $k => $param) { $param = Parser::explode(' ', trim($param)); $color = $param[0]; $stop = isset($param[1]) ? $param[1] : null; if ($k === 0) { $text = 'from'; } else { if ($k === $tk) { $text = 'to'; } else { $text = 'color-stop'; } } if ($stop) { $color_stops[] = $text . '(' . $stop . ', ' . $color . ')'; } else { $color_stops[] = $text . '(' . $color . ')'; } } if (isset($radius)) { return '-webkit-gradient(linear, ' . $radius . 'deg, ' . implode(', ', $color_stops) . ')'; } else { return '-webkit-gradient(linear, ' . $start . ', ' . $end . ', ' . implode(', ', $color_stops) . ')'; } }); }
/** * Execute all css functions found in the css value * * @param callable $callback The function to execute with the css functions. If the functions returns a string, it replaces the css code. It's passed two parameters to the function with all arguments of css function and the function name. */ public function executeAllFunctions($callback) { $this->value = Parser::executeFunctions($this->value, null, $callback, $this); }
public static function parseMediaQueries(array $selectors) { $parsed = array(); foreach ($selectors as $k => $selector) { $parsed[$k] = array(); foreach (Parser::explodeTrim(' and ', strtolower($selector)) as $rule) { $expressions = Parser::explodeTrim(' ', $rule); while ($expressions) { $expression = array_shift($expressions); if ($expression[0] === '(' && substr($expression, -1) === ')') { $expression = trim(substr($expression, 1, -1)); } if ($expression === 'not') { $parsed[$k]['not'] = true; continue; } if ($expression === 'only') { $parsed[$k]['only'] = true; continue; } if ($expression === 'all') { continue; } if (in_array($expression, self::$types)) { $parsed[$k]['type'] = $expression; continue; } $expression = Parser::explodeTrim(':', $expression, 2); $name = $expression[0]; $value = isset($expression[1]) ? $expression[1] : true; if (isset(self::$expressions[$name])) { $fn = self::$expressions[$name]['value']; $parsed[$k][$name] = self::$fn($value); continue; } if ((strpos($name, 'min-') === 0 || strpos($name, 'max-') === 0) && ($subname = substr($name, 4)) && isset(self::$expressions[$subname]) && self::$expressions[$subname]['min-max'] === true) { $fn = self::$expressions[$subname]['value']; $parsed[$k][$name] = self::$fn($value); continue; } } } } return $parsed; }