[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * toCSS Visitor 5 * 6 * @package Less 7 * @subpackage visitor 8 */ 9 class Less_Visitor_toCSS extends Less_VisitorReplacing{ 10 11 private $charset; 12 13 public function __construct(){ 14 parent::__construct(); 15 } 16 17 /** 18 * @param Less_Tree_Ruleset $root 19 */ 20 public function run( $root ){ 21 return $this->visitObj($root); 22 } 23 24 public function visitRule( $ruleNode ){ 25 if( $ruleNode->variable ){ 26 return array(); 27 } 28 return $ruleNode; 29 } 30 31 public function visitMixinDefinition($mixinNode){ 32 // mixin definitions do not get eval'd - this means they keep state 33 // so we have to clear that state here so it isn't used if toCSS is called twice 34 $mixinNode->frames = array(); 35 return array(); 36 } 37 38 public function visitExtend(){ 39 return array(); 40 } 41 42 public function visitComment( $commentNode ){ 43 if( $commentNode->isSilent() ){ 44 return array(); 45 } 46 return $commentNode; 47 } 48 49 public function visitMedia( $mediaNode, &$visitDeeper ){ 50 $mediaNode->accept($this); 51 $visitDeeper = false; 52 53 if( !$mediaNode->rules ){ 54 return array(); 55 } 56 return $mediaNode; 57 } 58 59 public function visitDirective( $directiveNode ){ 60 if( isset($directiveNode->currentFileInfo['reference']) && (!property_exists($directiveNode,'isReferenced') || !$directiveNode->isReferenced) ){ 61 return array(); 62 } 63 if( $directiveNode->name === '@charset' ){ 64 // Only output the debug info together with subsequent @charset definitions 65 // a comment (or @media statement) before the actual @charset directive would 66 // be considered illegal css as it has to be on the first line 67 if( isset($this->charset) && $this->charset ){ 68 69 //if( $directiveNode->debugInfo ){ 70 // $comment = new Less_Tree_Comment('/* ' . str_replace("\n",'',$directiveNode->toCSS())." */\n"); 71 // $comment->debugInfo = $directiveNode->debugInfo; 72 // return $this->visit($comment); 73 //} 74 75 76 return array(); 77 } 78 $this->charset = true; 79 } 80 return $directiveNode; 81 } 82 83 public function checkPropertiesInRoot( $rulesetNode ){ 84 85 if( !$rulesetNode->firstRoot ){ 86 return; 87 } 88 89 foreach($rulesetNode->rules as $ruleNode){ 90 if( $ruleNode instanceof Less_Tree_Rule && !$ruleNode->variable ){ 91 $msg = "properties must be inside selector blocks, they cannot be in the root. Index ".$ruleNode->index.($ruleNode->currentFileInfo ? (' Filename: '.$ruleNode->currentFileInfo['filename']) : null); 92 throw new Less_Exception_Compiler($msg); 93 } 94 } 95 } 96 97 98 public function visitRuleset( $rulesetNode, &$visitDeeper ){ 99 100 $visitDeeper = false; 101 102 $this->checkPropertiesInRoot( $rulesetNode ); 103 104 if( $rulesetNode->root ){ 105 return $this->visitRulesetRoot( $rulesetNode ); 106 } 107 108 $rulesets = array(); 109 $rulesetNode->paths = $this->visitRulesetPaths($rulesetNode); 110 111 112 // Compile rules and rulesets 113 $nodeRuleCnt = count($rulesetNode->rules); 114 for( $i = 0; $i < $nodeRuleCnt; ){ 115 $rule = $rulesetNode->rules[$i]; 116 117 if( property_exists($rule,'rules') ){ 118 // visit because we are moving them out from being a child 119 $rulesets[] = $this->visitObj($rule); 120 array_splice($rulesetNode->rules,$i,1); 121 $nodeRuleCnt--; 122 continue; 123 } 124 $i++; 125 } 126 127 128 // accept the visitor to remove rules and refactor itself 129 // then we can decide now whether we want it or not 130 if( $nodeRuleCnt > 0 ){ 131 $rulesetNode->accept($this); 132 133 if( $rulesetNode->rules ){ 134 135 if( count($rulesetNode->rules) > 1 ){ 136 $this->_mergeRules( $rulesetNode->rules ); 137 $this->_removeDuplicateRules( $rulesetNode->rules ); 138 } 139 140 // now decide whether we keep the ruleset 141 if( $rulesetNode->paths ){ 142 //array_unshift($rulesets, $rulesetNode); 143 array_splice($rulesets,0,0,array($rulesetNode)); 144 } 145 } 146 147 } 148 149 150 if( count($rulesets) === 1 ){ 151 return $rulesets[0]; 152 } 153 return $rulesets; 154 } 155 156 157 /** 158 * Helper function for visitiRuleset 159 * 160 * return array|Less_Tree_Ruleset 161 */ 162 private function visitRulesetRoot( $rulesetNode ){ 163 $rulesetNode->accept( $this ); 164 if( $rulesetNode->firstRoot || $rulesetNode->rules ){ 165 return $rulesetNode; 166 } 167 return array(); 168 } 169 170 171 /** 172 * Helper function for visitRuleset() 173 * 174 * @return array 175 */ 176 private function visitRulesetPaths($rulesetNode){ 177 178 $paths = array(); 179 foreach($rulesetNode->paths as $p){ 180 if( $p[0]->elements[0]->combinator === ' ' ){ 181 $p[0]->elements[0]->combinator = ''; 182 } 183 184 foreach($p as $pi){ 185 if( $pi->getIsReferenced() && $pi->getIsOutput() ){ 186 $paths[] = $p; 187 break; 188 } 189 } 190 } 191 192 return $paths; 193 } 194 195 protected function _removeDuplicateRules( &$rules ){ 196 // remove duplicates 197 $ruleCache = array(); 198 for( $i = count($rules)-1; $i >= 0 ; $i-- ){ 199 $rule = $rules[$i]; 200 if( $rule instanceof Less_Tree_Rule || $rule instanceof Less_Tree_NameValue ){ 201 202 if( !isset($ruleCache[$rule->name]) ){ 203 $ruleCache[$rule->name] = $rule; 204 }else{ 205 $ruleList =& $ruleCache[$rule->name]; 206 207 if( $ruleList instanceof Less_Tree_Rule || $ruleList instanceof Less_Tree_NameValue ){ 208 $ruleList = $ruleCache[$rule->name] = array( $ruleCache[$rule->name]->toCSS() ); 209 } 210 211 $ruleCSS = $rule->toCSS(); 212 if( array_search($ruleCSS,$ruleList) !== false ){ 213 array_splice($rules,$i,1); 214 }else{ 215 $ruleList[] = $ruleCSS; 216 } 217 } 218 } 219 } 220 } 221 222 protected function _mergeRules( &$rules ){ 223 $groups = array(); 224 225 //obj($rules); 226 227 $rules_len = count($rules); 228 for( $i = 0; $i < $rules_len; $i++ ){ 229 $rule = $rules[$i]; 230 231 if( ($rule instanceof Less_Tree_Rule) && $rule->merge ){ 232 233 $key = $rule->name; 234 if( $rule->important ){ 235 $key .= ',!'; 236 } 237 238 if( !isset($groups[$key]) ){ 239 $groups[$key] = array(); 240 }else{ 241 array_splice($rules, $i--, 1); 242 $rules_len--; 243 } 244 245 $groups[$key][] = $rule; 246 } 247 } 248 249 250 foreach($groups as $parts){ 251 252 if( count($parts) > 1 ){ 253 $rule = $parts[0]; 254 $spacedGroups = array(); 255 $lastSpacedGroup = array(); 256 $parts_mapped = array(); 257 foreach($parts as $p){ 258 if( $p->merge === '+' ){ 259 if( $lastSpacedGroup ){ 260 $spacedGroups[] = self::toExpression($lastSpacedGroup); 261 } 262 $lastSpacedGroup = array(); 263 } 264 $lastSpacedGroup[] = $p; 265 } 266 267 $spacedGroups[] = self::toExpression($lastSpacedGroup); 268 $rule->value = self::toValue($spacedGroups); 269 } 270 } 271 272 } 273 274 public static function toExpression($values){ 275 $mapped = array(); 276 foreach($values as $p){ 277 $mapped[] = $p->value; 278 } 279 return new Less_Tree_Expression( $mapped ); 280 } 281 282 public static function toValue($values){ 283 //return new Less_Tree_Value($values); ?? 284 285 $mapped = array(); 286 foreach($values as $p){ 287 $mapped[] = $p; 288 } 289 return new Less_Tree_Value($mapped); 290 } 291 } 292
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |