Media.php 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. <?php
  2. /**
  3. * Media
  4. *
  5. * @package Less
  6. * @subpackage tree
  7. */
  8. class Less_Tree_Media extends Less_Tree {
  9. public $features;
  10. public $rules;
  11. public $index;
  12. public $currentFileInfo;
  13. public $isReferenced;
  14. public $type = 'Media';
  15. public function __construct( $value = array(), $features = array(), $index = null, $currentFileInfo = null ) {
  16. $this->index = $index;
  17. $this->currentFileInfo = $currentFileInfo;
  18. $selectors = $this->emptySelectors();
  19. $this->features = new Less_Tree_Value( $features );
  20. $this->rules = array( new Less_Tree_Ruleset( $selectors, $value ) );
  21. $this->rules[0]->allowImports = true;
  22. }
  23. public function accept( $visitor ) {
  24. $this->features = $visitor->visitObj( $this->features );
  25. $this->rules = $visitor->visitArray( $this->rules );
  26. }
  27. /**
  28. * @see Less_Tree::genCSS
  29. */
  30. public function genCSS( $output ) {
  31. $output->add( '@media ', $this->currentFileInfo, $this->index );
  32. $this->features->genCSS( $output );
  33. Less_Tree::outputRuleset( $output, $this->rules );
  34. }
  35. public function compile( $env ) {
  36. $media = new Less_Tree_Media( array(), array(), $this->index, $this->currentFileInfo );
  37. $strictMathBypass = false;
  38. if ( Less_Parser::$options['strictMath'] === false ) {
  39. $strictMathBypass = true;
  40. Less_Parser::$options['strictMath'] = true;
  41. }
  42. $media->features = $this->features->compile( $env );
  43. if ( $strictMathBypass ) {
  44. Less_Parser::$options['strictMath'] = false;
  45. }
  46. $env->mediaPath[] = $media;
  47. $env->mediaBlocks[] = $media;
  48. array_unshift( $env->frames, $this->rules[0] );
  49. $media->rules = array( $this->rules[0]->compile( $env ) );
  50. array_shift( $env->frames );
  51. array_pop( $env->mediaPath );
  52. return !$env->mediaPath ? $media->compileTop( $env ) : $media->compileNested( $env );
  53. }
  54. public function variable( $name ) {
  55. return $this->rules[0]->variable( $name );
  56. }
  57. public function find( $selector ) {
  58. return $this->rules[0]->find( $selector, $this );
  59. }
  60. public function emptySelectors() {
  61. $el = new Less_Tree_Element( '', '&', $this->index, $this->currentFileInfo );
  62. $sels = array( new Less_Tree_Selector( array( $el ), array(), null, $this->index, $this->currentFileInfo ) );
  63. $sels[0]->mediaEmpty = true;
  64. return $sels;
  65. }
  66. public function markReferenced() {
  67. $this->rules[0]->markReferenced();
  68. $this->isReferenced = true;
  69. Less_Tree::ReferencedArray( $this->rules[0]->rules );
  70. }
  71. // evaltop
  72. public function compileTop( $env ) {
  73. $result = $this;
  74. if ( count( $env->mediaBlocks ) > 1 ) {
  75. $selectors = $this->emptySelectors();
  76. $result = new Less_Tree_Ruleset( $selectors, $env->mediaBlocks );
  77. $result->multiMedia = true;
  78. }
  79. $env->mediaBlocks = array();
  80. $env->mediaPath = array();
  81. return $result;
  82. }
  83. public function compileNested( $env ) {
  84. $path = array_merge( $env->mediaPath, array( $this ) );
  85. // Extract the media-query conditions separated with `,` (OR).
  86. foreach ( $path as $key => $p ) {
  87. $value = $p->features instanceof Less_Tree_Value ? $p->features->value : $p->features;
  88. $path[$key] = is_array( $value ) ? $value : array( $value );
  89. }
  90. // Trace all permutations to generate the resulting media-query.
  91. //
  92. // (a, b and c) with nested (d, e) ->
  93. // a and d
  94. // a and e
  95. // b and c and d
  96. // b and c and e
  97. $permuted = $this->permute( $path );
  98. $expressions = array();
  99. foreach ( $permuted as $path ) {
  100. for ( $i = 0, $len = count( $path ); $i < $len; $i++ ) {
  101. $path[$i] = Less_Parser::is_method( $path[$i], 'toCSS' ) ? $path[$i] : new Less_Tree_Anonymous( $path[$i] );
  102. }
  103. for ( $i = count( $path ) - 1; $i > 0; $i-- ) {
  104. array_splice( $path, $i, 0, array( new Less_Tree_Anonymous( 'and' ) ) );
  105. }
  106. $expressions[] = new Less_Tree_Expression( $path );
  107. }
  108. $this->features = new Less_Tree_Value( $expressions );
  109. // Fake a tree-node that doesn't output anything.
  110. return new Less_Tree_Ruleset( array(), array() );
  111. }
  112. public function permute( $arr ) {
  113. if ( !$arr )
  114. return array();
  115. if ( count( $arr ) == 1 )
  116. return $arr[0];
  117. $result = array();
  118. $rest = $this->permute( array_slice( $arr, 1 ) );
  119. foreach ( $rest as $r ) {
  120. foreach ( $arr[0] as $a ) {
  121. $result[] = array_merge(
  122. is_array( $a ) ? $a : array( $a ),
  123. is_array( $r ) ? $r : array( $r )
  124. );
  125. }
  126. }
  127. return $result;
  128. }
  129. public function bubbleSelectors( $selectors ) {
  130. if ( !$selectors ) return;
  131. $this->rules = array( new Less_Tree_Ruleset( $selectors, array( $this->rules[0] ) ) );
  132. }
  133. }