174 lines
4.4 KiB
PHP
174 lines
4.4 KiB
PHP
|
<?php
|
||
|
|
||
|
/**
|
||
|
* Media
|
||
|
*
|
||
|
* @package Less
|
||
|
* @subpackage tree
|
||
|
*/
|
||
|
class Less_Tree_Media extends Less_Tree {
|
||
|
|
||
|
public $features;
|
||
|
public $rules;
|
||
|
public $index;
|
||
|
public $currentFileInfo;
|
||
|
public $isReferenced;
|
||
|
public $type = 'Media';
|
||
|
|
||
|
public function __construct( $value = array(), $features = array(), $index = null, $currentFileInfo = null ) {
|
||
|
$this->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] ) ) );
|
||
|
}
|
||
|
|
||
|
}
|