Source of file Functions.php
Size: 9,917 Bytes - Last Modified: 2021-12-23T10:20:55+00:00
/var/www/docs.ssmods.com/process/src/thirdparty/css-crush/lib/CssCrush/Functions.php
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 | <?php /** * * Custom CSS functions * */ namespace CssCrush; class Functions { protected static $builtins = array( // These functions must come first in this order. 'query' => 'CssCrush\fn__query', // These functions can be any order. 'math' => 'CssCrush\fn__math', 'percent' => 'CssCrush\fn__percent', 'pc' => 'CssCrush\fn__percent', 'hsla-adjust' => 'CssCrush\fn__hsla_adjust', 'hsl-adjust' => 'CssCrush\fn__hsl_adjust', 'h-adjust' => 'CssCrush\fn__h_adjust', 's-adjust' => 'CssCrush\fn__s_adjust', 'l-adjust' => 'CssCrush\fn__l_adjust', 'a-adjust' => 'CssCrush\fn__a_adjust', ); public $register = array(); protected $pattern; protected $patternOptions; public function __construct($register = array()) { $this->register = $register; } public function add($name, $callback) { $this->register[$name] = $callback; } public function remove($name) { unset($this->register[$name]); } public function setPattern($useAll = false) { if ($useAll) { $this->register = self::$builtins + $this->register + csscrush_add_function(); } $this->pattern = Functions::makePattern(array_keys($this->register)); } public function apply($str, \stdClass $context = null) { if (strpos($str, '(') === false) { return $str; } if (! $this->pattern) { $this->setPattern(); } if (! preg_match($this->pattern, $str)) { return $str; } $matches = Regex::matchAll($this->pattern, $str); while ($match = array_pop($matches)) { if (isset($match['function']) && $match['function'][1] !== -1) { list($function, $offset) = $match['function']; } else { list($function, $offset) = $match['simple_function']; } if (! preg_match(Regex::$patt->parens, $str, $parens, PREG_OFFSET_CAPTURE, $offset)) { continue; } $openingParen = $parens[0][1]; $closingParen = $openingParen + strlen($parens[0][0]); $rawArgs = trim($parens['parens_content'][0]); // Update the context function identifier. if ($context) { $context->function = $function; } $returns = ''; if (isset($this->register[$function])) { $fn = $this->register[$function]; if (is_array($fn) && !empty($fn['parse_args'])) { $returns = $fn['callback'](self::parseArgs($rawArgs), $context); } else { $returns = $fn($rawArgs, $context); } } $str = substr_replace($str, $returns, $offset, $closingParen - $offset); } return $str; } ############################# # API and helpers. public static function parseArgs($input, $allowSpaceDelim = false) { $options = array(); if ($allowSpaceDelim) { $options['regex'] = Regex::$patt->argListSplit; } return Util::splitDelimList($input, $options); } /* Quick argument list parsing for functions that take 1 or 2 arguments with the proviso the first argument is an ident. */ public static function parseArgsSimple($input) { return preg_split(Regex::$patt->argListSplit, $input, 2); } public static function makePattern($functionNames) { $idents = array(); $nonIdents = array(); foreach ($functionNames as $functionName) { if (preg_match(Regex::$patt->ident, $functionName[0])) { $idents[] = preg_quote($functionName); } else { $nonIdents[] = preg_quote($functionName); } } if ($idents) { $idents = '{{ LB }}-?(?<function>' . implode('|', $idents) . ')'; } if ($nonIdents) { $nonIdents = '(?<simple_function>' . implode('|', $nonIdents) . ')'; } if ($idents && $nonIdents) { $patt = "(?:$idents|$nonIdents)"; } elseif ($idents) { $patt = $idents; } elseif ($nonIdents) { $patt = $nonIdents; } return Regex::make("~$patt\(~iS"); } } ############################# # Stock CSS functions. function fn__math($input) { list($expression, $unit) = array_pad(Functions::parseArgs($input), 2, ''); // Swap in math constants. $expression = preg_replace( array('~\bpi\b~i'), array(M_PI), $expression); // Filter expression so it's just characters necessary for simple math. $expression = preg_replace("~[^.0-9/*()+-]~S", '', $expression); $evalExpression = "return $expression;"; $result = false; if (class_exists('\\ParseError')) { try { $result = @eval($evalExpression); } catch (\Error $e) {} } else { $result = @eval($evalExpression); } return ($result === false ? 0 : round($result, 5)) . $unit; } function fn__percent($input) { // Strip non-numeric and non delimiter characters $input = preg_replace('~[^\d\.\s,]~S', '', $input); $args = preg_split(Regex::$patt->argListSplit, $input, -1, PREG_SPLIT_NO_EMPTY); // Use precision argument if it exists, use default otherwise $precision = isset($args[2]) ? $args[2] : 5; // Output zero on failure $result = 0; // Need to check arguments or we may see divide by zero errors if (count($args) > 1 && ! empty($args[0]) && ! empty($args[1])) { // Use bcmath if it's available for higher precision // Arbitary high precision division if (function_exists('bcdiv')) { $div = bcdiv($args[0], $args[1], 25); } else { $div = $args[0] / $args[1]; } // Set precision percentage value if (function_exists('bcmul')) { $result = bcmul((string) $div, '100', $precision); } else { $result = round($div * 100, $precision); } // Trim unnecessary zeros and decimals $result = trim((string) $result, '0'); $result = rtrim($result, '.'); } return $result . '%'; } function fn__hsla_adjust($input) { list($color, $h, $s, $l, $a) = array_pad(Functions::parseArgs($input, true), 5, 0); return Color::test($color) ? Color::colorAdjust($color, array($h, $s, $l, $a)) : ''; } function fn__hsl_adjust($input) { list($color, $h, $s, $l) = array_pad(Functions::parseArgs($input, true), 4, 0); return Color::test($color) ? Color::colorAdjust($color, array($h, $s, $l, 0)) : ''; } function fn__h_adjust($input) { list($color, $h) = array_pad(Functions::parseArgs($input, true), 2, 0); return Color::test($color) ? Color::colorAdjust($color, array($h, 0, 0, 0)) : ''; } function fn__s_adjust($input) { list($color, $s) = array_pad(Functions::parseArgs($input, true), 2, 0); return Color::test($color) ? Color::colorAdjust($color, array(0, $s, 0, 0)) : ''; } function fn__l_adjust($input) { list($color, $l) = array_pad(Functions::parseArgs($input, true), 2, 0); return Color::test($color) ? Color::colorAdjust($color, array(0, 0, $l, 0)) : ''; } function fn__a_adjust($input) { list($color, $a) = array_pad(Functions::parseArgs($input, true), 2, 0); return Color::test($color) ? Color::colorAdjust($color, array(0, 0, 0, $a)) : ''; } function fn__this($input, $context) { $args = Functions::parseArgsSimple($input); $property = $args[0]; // Function relies on a context rule, bail if none. if (! isset($context->rule)) { return ''; } $rule = $context->rule; $rule->declarations->expandData('data', $property); if (isset($rule->declarations->data[$property])) { return $rule->declarations->data[$property]; } // Fallback value. elseif (isset($args[1])) { return $args[1]; } return ''; } function fn__query($input, $context) { $args = Functions::parseArgs($input); // Context property is required. if (! count($args) || ! isset($context->property)) { return ''; } list($target, $property, $fallback) = $args + array(null, $context->property, null); if (strtolower($property) === 'default') { $property = $context->property; } if (! preg_match(Regex::$patt->rooted_ident, $target)) { $target = Selector::makeReadable($target); } $targetRule = null; $references =& Crush::$process->references; switch (strtolower($target)) { case 'parent': $targetRule = $context->rule->parent; break; case 'previous': $targetRule = $context->rule->previous; break; case 'next': $targetRule = $context->rule->next; break; case 'top': $targetRule = $context->rule->parent; while ($targetRule && $targetRule->parent && $targetRule = $targetRule->parent); break; default: if (isset($references[$target])) { $targetRule = $references[$target]; } break; } $result = ''; if ($targetRule) { $targetRule->declarations->process(); $targetRule->declarations->expandData('queryData', $property); if (isset($targetRule->declarations->queryData[$property])) { $result = $targetRule->declarations->queryData[$property]; } } if ($result === '' && isset($fallback)) { $result = $fallback; } return $result; } |