/** * 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 * @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; }
/** * 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); } } }
/** * 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); } } } } }