function add_rule(&$rule, &$pipeline) { $rule_obj = new CSSRule($rule, $pipeline); $this->rules[] = $rule_obj; $tag = $this->detect_applicable_tag($rule_obj->get_selector()); if ($tag === null) { $tag = "*"; } $this->tag_filtered[$tag][] = $rule_obj; }
function parse_style_attr($root, &$state, &$pipeline) { $style = $root->get_attribute("style"); // Some "designers" (obviously lacking the brain and ability to read ) use such constructs: // // <input maxLength=256 size=45 name=searchfor value="" style="{width:350px}"> // // It is out of standard, as HTML 4.01 says: // // The syntax of the value of the style attribute is determined by the default style sheet language. // For example, for [[CSS2]] inline style, use the declaration block syntax described in section 4.1.8 // *(without curly brace delimiters)* // // but still parsed by many browsers; let's be compatible with these idiots - remove curly braces // $style = preg_replace("/^\\s*{/", "", $style); $style = preg_replace("/}\\s*\$/", "", $style); $properties = parse_css_properties($style, $pipeline); $rule = new CSSRule(array(array(SELECTOR_ANY), $properties, $pipeline->get_base_url(), $root), $pipeline); $rule->apply($root, $state, $pipeline); }
private function parseRule() { $oRule = new CSSRule($this->parseIdentifier()); $this->consumeWhiteSpace(); $this->consume(':'); $oValue = $this->parseValue(self::listDelimiterForRule($oRule->getRule())); $oRule->setValue($oValue); if ($this->comes('!')) { $this->consume('!'); $this->consumeWhiteSpace(); $sImportantMarker = $this->consume(strlen('important')); if (mb_convert_case($sImportantMarker, MB_CASE_LOWER) !== 'important') { throw new Exception("! was followed by “" . $sImportantMarker . "”. Expected “important”"); } $oRule->setIsImportant(true); } if ($this->comes(';')) { $this->consume(';'); } return $oRule; }
public function addRule(CSSRule $oRule) { $this->aRules[$oRule->getRule()] = $oRule; }
/** * Looks for long format CSS font properties (e.g. <tt>font-weight</tt>) and * tries to convert them into a shorthand CSS <tt>font</tt> property. * At least font-size AND font-family must be present in order to create a shorthand declaration. **/ public function createFontShorthand() { $aFontProperties = array('font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family'); $aRules = $this->getRules(); if (!isset($aRules['font-size']) || !isset($aRules['font-family'])) { return; } $oNewRule = new CSSRule('font'); foreach (array('font-style', 'font-variant', 'font-weight') as $sProperty) { if (isset($aRules[$sProperty])) { $oRule = $aRules[$sProperty]; $mRuleValue = $oRule->getValue(); $aValues = array(); if (!$mRuleValue instanceof CSSRuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } if ($aValues[0] !== 'normal') { $oNewRule->addValue($aValues[0]); } } } // Get the font-size value $oRule = $aRules['font-size']; $mRuleValue = $oRule->getValue(); $aFSValues = array(); if (!$mRuleValue instanceof CSSRuleValueList) { $aFSValues[] = $mRuleValue; } else { $aFSValues = $mRuleValue->getListComponents(); } // But wait to know if we have line-height to add it if (isset($aRules['line-height'])) { $oRule = $aRules['line-height']; $mRuleValue = $oRule->getValue(); $aLHValues = array(); if (!$mRuleValue instanceof CSSRuleValueList) { $aLHValues[] = $mRuleValue; } else { $aLHValues = $mRuleValue->getListComponents(); } if ($aLHValues[0] !== 'normal') { $val = new CSSRuleValueList('/'); $val->addListComponent($aFSValues[0]); $val->addListComponent($aLHValues[0]); $oNewRule->addValue($val); } } else { $oNewRule->addValue($aFSValues[0]); } $oRule = $aRules['font-family']; $mRuleValue = $oRule->getValue(); $aFFValues = array(); if (!$mRuleValue instanceof CSSRuleValueList) { $aFFValues[] = $mRuleValue; } else { $aFFValues = $mRuleValue->getListComponents(); } $oFFValue = new CSSRuleValueList(','); $oFFValue->setListComponents($aFFValues); $oNewRule->addValue($oFFValue); $this->addRule($oNewRule); foreach ($aFontProperties as $sProperty) { $this->removeRule($sProperty); } }
/** * Merge multiple CSS RuleSets by cascading according to the CSS 2.1 cascading rules * (http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order). * * @param array $aDeclarations An array of CSSDeclarationBlock objects. * * @return CSSDeclarationBlock. * * ==== Cascading * If a CSSDeclarationBlock object has its +specificity+ defined, that specificity is * used in the cascade calculations. * * If no specificity is explicitly set and the CSSDeclarationBlock has *one* selector, * the specificity is calculated using that selector. * * If no selectors or multiple selectors are present, the specificity is * treated as 0. * * ==== Example #1 * <code> * $oDecl_1 = new CSSDeclarationBlock(); * $oRule_1 = new CSSRule('color'); * $oRule_1->addValue(new CSSColor('#F00')); * $oDecl_1->addRule($oRule_1); * $oDecl_2 = new CSSDeclarationBlock(); * $oRule_2 = new CSSRule('margin'); * $oRule_2->addValue( * new CSSSize(0, 'px') * ); * $oDecl_2->addRule($oRule_2); * * $oMerged = CSSDocument::mergeDeclarations($oDecl_1, $oDecl_2); * * echo $oMerged; * //=> "{ margin: 0px; color: rgb(255,0,0); }" * </code> * ==== Example #2 * <code> * $oDecl_1 = new CSSDeclarationBlock(); * $oRule_1 = new CSSRule('background-color'); * $oRule_1->addValue(new CSSColor('black')); * $oDecl_1->addRule($oRule_1); * $oDecl_2 = new CSSDeclarationBlock(); * $oRule_2 = new CSSRule('background-image'); * $oRule_2->addValue('none'); * $oDecl_2->addRule($oRule_2); * * $oMerged = CSSDocument::mergeDeclarations($oDecl_1, $oDecl_2); * * echo $oMerged; * //=> "{ background: none rgb(0,0,0); }" * </code> **/ static function mergeDeclarations(array $aDeclarations) { // Internal storage of CSS properties that we will keep $aProperties = array(); foreach ($aDeclarations as $oDeclaration) { $oDeclaration->expandShorthands(); $aSelectors = $oDeclaration->getSelectors(); $iSpecificity = 0; if (count($aSelectors) == 1) { $iSpecificity = $aSelectors[0]->getSpecificity(); } foreach ($oDeclaration->getRules() as $sProperty => $oRule) { // Add the property to the list to be folded per // http://www.w3.org/TR/CSS21/cascade.html#cascading-order if (!isset($aProperties[$sProperty])) { $aProperties[$sProperty] = array('values' => $oRule->getValues(), 'specificity' => $iSpecificity, 'important' => $oRule->getIsImportant()); } else { $aProperty = $aProperties[$sProperty]; if ($aProperty['specificity'] <= $iSpecificity && !$aProperty['important']) { $aProperties[$sProperty] = array('values' => $oRule->getValues(), 'specificity' => $iSpecificity, 'important' => $oRule->getIsImportant()); } } if ($oRule->getIsImportant()) { $aProperties[$sProperty] = array('values' => $oRule->getValues(), 'specificity' => $iSpecificity, 'important' => $oRule->getIsImportant()); } } // end foreach rules } // end foreach rulesets $oMerged = new CSSDeclarationBlock(); foreach ($aProperties as $sProperty => $aDetails) { $oNewRule = new CSSRule($sProperty); foreach ($aDetails['values'] as $aValue) { $oNewRule->addvalue($aValue); } if ($aDetails['important']) { $oNewRule->setIsImportant(true); } $oMerged->addRule($oNewRule); } $oMerged->createShorthands(); return $oMerged; }