/** * Converts to CSS * * @param ILess_Environment $env * @return string */ public function toCSS(ILess_Environment $env) { $value = self::methodExists($this->key, 'toCSS') ? $this->key->toCSS($env) : $this->key; if ($this->operator) { $value .= $this->operator; $value .= self::methodExists($this->value, 'toCSS') ? $this->value->toCSS($env) : $this->value; } return '[' . $value . ']'; }
/** * Constructor * * @param string $value The comment value * @param boolean $silent */ public function __construct($value, $silent = false, $index = 0, ILess_FileInfo $currentFileInfo = null) { parent::__construct($value); $this->silent = (bool) $silent; $this->index = $index; $this->currentFileInfo = $currentFileInfo; }
/** * Constructor * * @param string $quotedString Whole string with quotes * @param string $string The string without quotes * @param boolean $escaped Is the string escaped? * @param integer $index Current index * @param ILess_FileInfo $currentFileInfo The current file info */ public function __construct($quotedString, $string, $escaped = false, $index = 0, ILess_FileInfo $currentFileInfo = null) { parent::__construct($string ? $string : ''); $this->escaped = $escaped; $this->quote = $quotedString[0]; $this->index = $index; $this->currentFileInfo = $currentFileInfo; }
/** * Constructor * * @param string $value The string */ public function __construct($value = null) { if ($value == ' ') { $value = ' '; } else { $value = trim($value); } parent::__construct($value); }
/** * @see ILess_Node */ public function generateCSS(ILess_Environment $env, ILess_Output $output) { if ($this->css) { $output->add('@import ', $this->currentFileInfo, $this->index); $this->path->generateCSS($env, $output); if ($this->features) { $output->add(' '); $this->features->generateCSS($env, $output); } $output->add(';'); } return $output; }
/** * Constructor * * @param string $name The name * @param array|string $value The value * @param integer $index The index * @param array $currentFileInfo Current file info */ public function __construct($name, $value, $index = 0, ILess_FileInfo $currentFileInfo = null) { $this->name = $name; if (is_array($value)) { $ruleset = new ILess_Node_Ruleset(array(), $value); $ruleset->allowImports = true; $this->rules = array($ruleset); } else { if ($value && !$value instanceof ILess_Node) { throw new InvalidArgumentException('Invalid value given. It should be an instance of ILess_Node'); } parent::__construct($value); } $this->index = $index; $this->currentFileInfo = $currentFileInfo; }
/** * Compiles the node * * @param ILess_Environment $env * @return boolean */ public function compile(ILess_Environment $env, $arguments = null, $important = null) { $a = $this->lvalue->compile($env); $b = $this->rvalue->compile($env); switch ($this->op) { case 'and': $result = $a && $b; break; case 'or': $result = $a || $b; break; default: if (self::methodExists($a, 'compare')) { $result = $a->compare($b); } elseif (self::methodExists($b, 'compare')) { $result = $b->compare($a); } else { throw new ILess_Exception_Compiler('Unable to perform the comparison', $this->index, $env->currentFileInfo); } // FIXME: Operators has beed modified. its seems that there is a bug in less.js // The operator "=>" is missing in case 0 and case 1 // Less.js version: /* switch (result) { case -1: return op === '<' || op === '=<' || op === '<='; case 0: return op === '=' || op === '>=' || op === '=<' || op === '<='; case 1: return op === '>' || op === '>='; } */ switch ($result) { case -1: $result = $this->op === '<' || $this->op === '=<' || $this->op === '<='; break; case 0: $result = $this->op === '=' || $this->op === '>=' || $this->op === '=>' || $this->op === '=<' || $this->op === '<='; break; case 1: $result = $this->op === '>' || $this->op === '>=' || $this->op === '=>'; break; } break; } return $this->negate ? !$result : $result; }
/** * Updates the currentFileInfo object to the $value * * @param ILess_Node $node The node to update * @param boolean $value The value */ protected function updateReferenceInCurrentFileInfo(ILess_Node $node, $value) { if (isset($node->currentFileInfo)) { $node->currentFileInfo->reference = $value; } if (ILess_Node::propertyExists($node, 'rules')) { foreach ($node->rules as $rule) { $this->updateReferenceInCurrentFileInfo($rule, $value); } } }
/** * Constructor * * @param array $value */ public function __construct(array $value) { parent::__construct($value); }
/** * Finds a selector * * @param ILess_Node $selector * @param ILess_Node_Ruleset $self * @param ILess_Environment $env * @return array */ public function find(ILess_Node $selector, ILess_Environment $env, ILess_Node_Ruleset $self = null) { $key = $selector->toCSS($env); if (!$self) { $self = $this; } if (!array_key_exists($key, $this->lookups)) { $this->lookups[$key] = array(); foreach ($this->rules as $rule) { if ($rule === $self) { continue; } if ($rule instanceof ILess_Node_Ruleset || $rule instanceof ILess_Node_MixinDefinition) { foreach ($rule->selectors as $ruleSelector) { $match = $selector->match($ruleSelector); if ($match) { if (count($selector->elements) > $match) { $this->lookups[$key] = array_merge($this->lookups[$key], $rule->find(new ILess_Node_Selector(array_slice($selector->elements, $match)), $env, $self)); } else { $this->lookups[$key][] = $rule; } break; } } } } } return $this->lookups[$key]; }
/** * Constructor * * @param ILess_Node $value */ public function __construct(ILess_Node $value) { parent::__construct($value); }
/** * Compares with another dimension * * @param ILess_Node $other * @return integer */ public function compare(ILess_Node $other) { if (!$other instanceof ILess_Node_Dimension) { return -1; } $a = $this->unify(); $b = $other->unify(); if ($b->value > $a->value) { return -1; } elseif ($b->value < $a->value) { return 1; } else { if (!$b->unit->isEmpty() && $a->unit->compare($b->unit) !== 0) { return -1; } return 0; } }
/** * Visits a ruleset node * * @param ILess_Node_Ruleset $node The node * @param ILess_Visitor_Arguments $arguments The arguments * @return array|ILess_Node_Ruleset */ public function visitRuleset(ILess_Node_Ruleset $node, ILess_Visitor_Arguments $arguments) { $arguments->visitDeeper = false; $rulesets = array(); if ($node->firstRoot) { $this->checkPropertiesInRoot($node->rules); } if (!$node->root) { $paths = array(); foreach ($node->paths as $p) { if ($p[0]->elements[0]->combinator->value === ' ') { $p[0]->elements[0]->combinator = new ILess_Node_Combinator(''); } if ($p[0]->getIsReferenced() && $p[0]->getIsOutput()) { $paths[] = $p; } } $node->paths = $paths; // Compile rules and rulesets for ($i = 0, $count = count($node->rules); $i < $count;) { $rule = $node->rules[$i]; //if ($rule instanceof ILess_Node_Rule || $rule instanceof ILess_Node_Ruleset) { //if ($rule instanceof ILess_Node_Ruleset) { if (ILess_Node::propertyExists($rule, 'rules')) { // visit because we are moving them out from being a child $rulesets[] = $this->visit($rule); array_splice($node->rules, $i, 1); $count--; continue; } $i++; } // accept the visitor to remove rules and refactor itself // then we can decide now whether we want it or not if ($count > 0) { $node->accept($this); $count = count($node->rules); if ($count > 0) { if ($count > 1) { $this->mergeRules($node->rules); $this->removeDuplicateRules($node->rules); } // now decide whether we keep the ruleset if (count($node->paths) > 0) { array_splice($rulesets, 0, 0, array($node)); } } } else { $node->rules = array(); } } else { $node->accept($this); $arguments->visitDeeper = false; if ($node->firstRoot || count($node->rules) > 0) { array_splice($rulesets, 0, 0, array($node)); } } if (count($rulesets) === 1) { return $rulesets[0]; } return $rulesets; }
/** * @see ILess_Node::compile */ public function compile(ILess_Environment $env, $arguments = null, $important = null) { $rules = array(); $match = false; $isOneFound = false; $args = array(); foreach ($this->arguments as $a) { $args[] = array('name' => $a['name'], 'value' => $a['value']->compile($env)); } foreach ($env->frames as $frame) { $mixins = $frame->find($this->selector, $env); if (!$mixins) { continue; } $isOneFound = true; for ($m = 0; $m < count($mixins); $m++) { $mixin = $mixins[$m]; $isRecursive = false; foreach ($env->frames as $recurFrame) { if (!$mixin instanceof ILess_Node_MixinDefinition) { if (isset($recurFrame->originalRulesetId) && $mixin->rulesetId === $recurFrame->originalRulesetId || $mixin === $recurFrame) { $isRecursive = true; break; } } } if ($isRecursive) { continue; } if ($mixin->matchArgs($args, $env)) { if (!ILess_Node::methodExists($mixin, 'matchCondition') || $mixin->matchCondition($args, $env)) { try { if (!$mixin instanceof ILess_Node_MixinDefinition) { $mixin = new ILess_Node_MixinDefinition('', array(), $mixin->rules, null, false); $mixin->originalRulesetId = $mixins[$m]->originalRulesetId ? $mixins[$m]->originalRulesetId : $mixin->originalRulesetId; } $rules = array_merge($rules, $mixin->compile($env, $args, $this->important)->rules); } catch (Exception $e) { throw new ILess_Exception_Compiler($e->getMessage(), $this->index, $this->currentFileInfo, $e); } } $match = true; } } if ($match) { if (!$this->currentFileInfo || !$this->currentFileInfo->reference) { foreach ($rules as $rule) { if ($rule instanceof ILess_Node_MarkableAsReferencedInterface) { $rule->markReferenced(); } } } return $rules; } } if ($isOneFound) { $message = array(); if ($args) { foreach ($args as $a) { $argValue = ''; if ($a['name']) { $argValue .= $a['name'] . ':'; } if (ILess_Node::methodExists($a['value'], 'toCSS')) { $argValue .= $a['value']->toCSS($env); } else { $argValue .= '???'; } $message[] = $argValue; } } throw new ILess_Exception_Compiler(sprintf('No matching definition was found for `%s(%s)`', trim($this->selector->toCSS($env)), join(',', $message)), $this->index, $this->currentFileInfo); } else { throw new ILess_Exception_Compiler(sprintf('%s is undefined.', trim($this->selector->toCSS($env))), $this->index, $this->currentFileInfo); } }
/** * Constructor * * @param ILess_Node $value * @param ILess_FileInfo $currentFileInfo */ public function __construct(ILess_Node $value, ILess_FileInfo $currentFileInfo = null) { parent::__construct($value); $this->currentFileInfo = $currentFileInfo; }
/** * Constructor * * @param string $key * @param string|ILess_INode $value */ public function __construct($key, $value) { parent::__construct($value); $this->key = $key; }
/** * Creates a SVG gradient * * @param ILess_Node $direction * @return ILess_Node_Url * @throws ILess_Exception_Compiler If the arguments are invalid */ public function svggradient(ILess_Node $direction) { if (func_num_args() < 3) { throw new ILess_Exception_Compiler('svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]'); } $arguments = func_get_args(); $stops = array_slice($arguments, 1); $gradientType = 'linear'; $rectangleDimension = 'x="0" y="0" width="1" height="1"'; $useBase64 = true; $renderEnv = new ILess_Environment(); $directionValue = $direction->toCSS($renderEnv); switch ($directionValue) { case 'to bottom': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="0%" y2="100%"'; break; case 'to right': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="0%"'; break; case 'to bottom right': $gradientDirectionSvg = 'x1="0%" y1="0%" x2="100%" y2="100%"'; break; case 'to top right': $gradientDirectionSvg = 'x1="0%" y1="100%" x2="100%" y2="0%"'; break; case 'ellipse': case 'ellipse at center': $gradientType = 'radial'; $gradientDirectionSvg = 'cx="50%" cy="50%" r="75%"'; $rectangleDimension = 'x="-50" y="-50" width="101" height="101"'; break; default: throw new ILess_Exception_Compiler("svg-gradient direction must be 'to bottom', 'to right', 'to bottom right', 'to top right' or 'ellipse at center'"); } $returner = '<?xml version="1.0" ?>' . '<svg xmlns="http://www.w3.org/2000/svg" version="1.1" width="100%" height="100%" viewBox="0 0 1 1" preserveAspectRatio="none">' . '<' . $gradientType . 'Gradient id="gradient" gradientUnits="userSpaceOnUse" ' . $gradientDirectionSvg . '>'; for ($i = 0; $i < count($stops); $i++) { if (ILess_Node::propertyExists($stops[$i], 'value') && $stops[$i]->value) { $color = $stops[$i]->value[0]; $position = $stops[$i]->value[1]; } else { $color = $stops[$i]; $position = null; } if (!$color instanceof ILess_Node_Color || !(($i === 0 || $i + 1 === count($stops)) && $position === null) && !$position instanceof ILess_Node_Dimension) { throw new ILess_Exception_Compiler('svg-gradient expects direction, start_color [start_position], [color position,]..., end_color [end_position]'); } if ($position) { $positionValue = $position->toCSS($renderEnv); } elseif ($i === 0) { $positionValue = '0%'; } else { $positionValue = '100%'; } $alpha = $color->getAlpha(true); $returner .= '<stop offset="' . $positionValue . '" stop-color="' . $color->getColor()->toString($this->env->compress, false) . '"' . ($alpha < 1 ? ' stop-opacity="' . $alpha . '"' : '') . '/>'; } $returner .= '</' . $gradientType . 'Gradient><rect ' . $rectangleDimension . ' fill="url(#gradient)" /></svg>'; if ($useBase64) { $returner = base64_encode($returner); } $returner = "'data:image/svg+xml" . ($useBase64 ? ";base64" : "") . "," . $returner . "'"; return new ILess_Node_Url(new ILess_Node_Anonymous($returner)); }
/** * Visits a ruleset node * * @param ILess_Node_Ruleset $node The node * @param ILess_Visitor_Arguments $arguments The arguments */ public function visitRuleset(ILess_Node_Ruleset $node, ILess_Visitor_Arguments $arguments) { if ($node->root) { return; } $allExtends = end($this->allExtendsStack); $pathsCount = count($node->paths); // look at each selector path in the ruleset, find any extend matches and then copy, find and replace for ($extendIndex = 0, $allExtendCount = count($allExtends); $extendIndex < $allExtendCount; $extendIndex++) { for ($pathIndex = 0; $pathIndex < $pathsCount; $pathIndex++) { $selectorPath = $node->paths[$pathIndex]; // extending extends happens initially, before the main pass if (ILess_Node::propertyExists($node, 'extendOnEveryPath') && $node->extendOnEveryPath) { continue; } if (end($selectorPath)->extendList) { continue; } $matches = $this->findMatch($allExtends[$extendIndex], $selectorPath); if ($matches) { foreach ($allExtends[$extendIndex]->selfSelectors as $selfSelector) { $node->paths[] = $this->extendSelector($matches, $selectorPath, $selfSelector); } } } } }