index = $index; $this->currentFileInfo = $currentFileInfo; $selectors = $this->emptySelectors(); $this->features = new Less_Tree_Value( $features ); $this->rules = array( new Less_Tree_Ruleset( $selectors, $value ) ); $this->rules[0]->allowImports = true; } public function accept( $visitor ) { $this->features = $visitor->visitObj( $this->features ); $this->rules = $visitor->visitArray( $this->rules ); } /** * @see Less_Tree::genCSS */ public function genCSS( $output ) { $output->add( '@media ', $this->currentFileInfo, $this->index ); $this->features->genCSS( $output ); Less_Tree::outputRuleset( $output, $this->rules ); } public function compile( $env ) { $media = new Less_Tree_Media( array(), array(), $this->index, $this->currentFileInfo ); $strictMathBypass = false; if ( Less_Parser::$options['strictMath'] === false ) { $strictMathBypass = true; Less_Parser::$options['strictMath'] = true; } $media->features = $this->features->compile( $env ); if ( $strictMathBypass ) { Less_Parser::$options['strictMath'] = false; } $env->mediaPath[] = $media; $env->mediaBlocks[] = $media; array_unshift( $env->frames, $this->rules[0] ); $media->rules = array( $this->rules[0]->compile( $env ) ); array_shift( $env->frames ); array_pop( $env->mediaPath ); return !$env->mediaPath ? $media->compileTop( $env ) : $media->compileNested( $env ); } public function variable( $name ) { return $this->rules[0]->variable( $name ); } public function find( $selector ) { return $this->rules[0]->find( $selector, $this ); } public function emptySelectors() { $el = new Less_Tree_Element( '', '&', $this->index, $this->currentFileInfo ); $sels = array( new Less_Tree_Selector( array( $el ), array(), null, $this->index, $this->currentFileInfo ) ); $sels[0]->mediaEmpty = true; return $sels; } public function markReferenced() { $this->rules[0]->markReferenced(); $this->isReferenced = true; Less_Tree::ReferencedArray( $this->rules[0]->rules ); } // evaltop public function compileTop( $env ) { $result = $this; if ( count( $env->mediaBlocks ) > 1 ) { $selectors = $this->emptySelectors(); $result = new Less_Tree_Ruleset( $selectors, $env->mediaBlocks ); $result->multiMedia = true; } $env->mediaBlocks = array(); $env->mediaPath = array(); return $result; } public function compileNested( $env ) { $path = array_merge( $env->mediaPath, array( $this ) ); // Extract the media-query conditions separated with `,` (OR). foreach ( $path as $key => $p ) { $value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features; $path[$key] = is_array( $value ) ? $value : array( $value ); } // Trace all permutations to generate the resulting media-query. // // (a, b and c) with nested (d, e) -> // a and d // a and e // b and c and d // b and c and e $permuted = $this->permute( $path ); $expressions = array(); foreach ( $permuted as $path ) { for ( $i = 0, $len = count( $path ); $i < $len; $i++ ) { $path[$i] = Less_Parser::is_method( $path[$i], 'toCSS' ) ? $path[$i] : new Less_Tree_Anonymous( $path[$i] ); } for ( $i = count( $path ) - 1; $i > 0; $i-- ) { array_splice( $path, $i, 0, array( new Less_Tree_Anonymous( 'and' ) ) ); } $expressions[] = new Less_Tree_Expression( $path ); } $this->features = new Less_Tree_Value( $expressions ); // Fake a tree-node that doesn't output anything. return new Less_Tree_Ruleset( array(), array() ); } public function permute( $arr ) { if ( !$arr ) return array(); if ( count( $arr ) == 1 ) return $arr[0]; $result = array(); $rest = $this->permute( array_slice( $arr, 1 ) ); foreach ( $rest as $r ) { foreach ( $arr[0] as $a ) { $result[] = array_merge( is_array( $a ) ? $a : array( $a ), is_array( $r ) ? $r : array( $r ) ); } } return $result; } public function bubbleSelectors( $selectors ) { if ( !$selectors ) return; $this->rules = array( new Less_Tree_Ruleset( $selectors, array( $this->rules[0] ) ) ); } }