Example #1
0
 public function setStyleDeclaration(StyleDeclaration $style_declaration)
 {
     $style_declaration->setParentRule($this);
     if ($parentStyleSheet = $this->getParentStyleSheet()) {
         $style_declaration->setParentStyleSheet($parentStyleSheet);
     }
     $this->style_declaration = $style_declaration;
 }
Example #2
0
 /**
  * Merge multiple Css RuleSets by cascading according to the Css 3 cascading rules 
  * (http://www.w3.org/TR/REC-CSS2/cascade.html#cascading-order).
  * 
  * Cascading:
  * If a Css\StyleRule object has its +specificity+ defined, that specificity is 
  * used in the cascade calculations.  
  * 
  * If no specificity is explicitly set and the Css\StyleRule has *one* selector, 
  * the specificity is calculated using that selector.
  * 
  * If no selectors or multiple selectors are present, the specificity is 
  * treated as 0.
  * 
  *
  * @param  array $rules An array of Css\StyleRule objects
  * @return ju1ius\Css\StyleRule The merged ju1ius\Css\StyleRule
  * 
  **/
 public static function merge(array $rules)
 {
     if (1 === count($rules)) {
         if (!$rules[0] instanceof StyleRule) {
             throw new \InvalidArgumentException('You must provide an array of ju1ius\\Css\\StyleRule objects');
         }
         return clone $rules[0];
     }
     // Internal storage of Css properties that we will keep
     $aProperties = array();
     foreach ($rules as $rule) {
         if (!$rule instanceof StyleRule) {
             throw new \InvalidArgumentException('You must provide an array of ju1ius\\Css\\StyleRule objects');
         }
         $styleDeclaration = $rule->getStyleDeclaration();
         $selectorList = $rule->getSelectorList();
         $specificity = 0;
         //
         $styleDeclaration->expandShorthands();
         if (1 === count($selectorList)) {
             $specificity = $selectorList[0]->getSpecificity();
         }
         //
         foreach ($styleDeclaration->getAppliedProperties() as $name => $property) {
             // Add the property to the list to be folded per
             // http://www.w3.org/TR/css3-cascade/#cascading
             $override = false;
             $isImportant = $property->getIsImportant();
             if (isset($aProperties[$name])) {
                 $oldProp = $aProperties[$name];
                 // properties have same weight so we consider specificity
                 if ($isImportant === $oldProp['property']->getIsImportant()) {
                     if ($specificity >= $oldProp['specificity']) {
                         $override = true;
                     }
                 } else {
                     if ($isImportant) {
                         $override = true;
                     }
                 }
             } else {
                 $override = true;
             }
             if ($override) {
                 $aProperties[$name] = array('property' => Object::getClone($property), 'specificity' => $specificity);
             }
         }
     }
     $merged = new StyleDeclaration();
     foreach ($aProperties as $name => $details) {
         $merged->append($details['property']);
     }
     $merged->createShorthands();
     return new StyleRule(new SelectorList(), $merged);
 }
Example #3
0
 /**
  * Not part of CSS grammar, but this pattern occurs frequently
  * in the official CSS grammar. Split out here to eliminate
  * duplicate code.
  *
  * @param boolean $check_start Indicates if the rule should check for the left brace at the beginning.
  * @param boolean $margins Indicates if the rule should check for @margin-box tokens.
  **/
 protected function _parseDeclarations($check_start, $margins)
 {
     /*{{{*/
     /**
      * Reads the pattern:
      *   S* '{' S* declaration [ ';' S* declaration ]* '}' S*
      *   or
      *   S* '{' S* [ declaration | margin ]? [ ';' S* [ declaration | margin ]? ]* '}' S*
      * Note that this is how it is described in CSS3 Paged Media, but is actually incorrect.
      * A semicolon is only necessary following a declaration is there's another declaration
      * or margin afterwards.
      **/
     $style_declaration = new StyleDeclaration();
     if ($margins) {
         $margin_rules = new RuleList();
     }
     $this->_ws();
     if ($check_start) {
         $this->match(Lexer::T_LCURLY);
     }
     $this->_ws();
     while (true) {
         try {
             $property = $this->_declaration();
         } catch (ParseException $e) {
             if ($this->strict) {
                 throw $e;
             }
             $this->skipDeclaration();
             continue;
         }
         if (null !== $property) {
             $style_declaration->append($property);
             if ($this->LT()->type === Lexer::T_SEMICOLON) {
                 $this->consume();
                 $this->_ws();
                 continue;
             } else {
                 break;
             }
         } else {
             if ($margins && in_array($this->LT()->type, array(Lexer::T_TOPLEFTCORNER_SYM, Lexer::T_TOPLEFT_SYM, Lexer::T_TOPCENTER_SYM, Lexer::T_TOPRIGHT_SYM, Lexer::T_TOPRIGHTCORNER_SYM, Lexer::T_BOTTOMLEFTCORNER_SYM, Lexer::T_BOTTOMLEFT_SYM, Lexer::T_BOTTOMCENTER_SYM, Lexer::T_BOTTOMRIGHT_SYM, Lexer::T_BOTTOMRIGHTCORNER_SYM, Lexer::T_LEFTTOP_SYM, Lexer::T_LEFTMIDDLE_SYM, Lexer::T_LEFTBOTTOM_SYM, Lexer::T_RIGHTTOP_SYM, Lexer::T_RIGHTMIDDLE_SYM, Lexer::T_RIGHTBOTTOM_SYM))) {
                 try {
                     $margin_rules->append($this->_margin());
                 } catch (ParseException $e) {
                     if ($this->strict) {
                         throw $e;
                     }
                     $this->skipRuleset(true);
                 }
             } else {
                 break;
             }
         }
     }
     if ($check_start) {
         $this->match(Lexer::T_RCURLY);
     }
     $this->_ws();
     return $margins ? array('style_declaration' => $style_declaration, 'rule_list' => $margin_rules) : $style_declaration;
 }