Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.11.x will end 14 Nov 2022 (12 months plus 6 months extension).
  • Bug fixes for security issues in 3.11.x will end 13 Nov 2023 (18 months plus 12 months extension).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.

Differences Between: [Versions 311 and 401] [Versions 311 and 402] [Versions 311 and 403]

   1  <?php
   2  
   3  namespace Sabberworm\CSS\Rule;
   4  
   5  use Sabberworm\CSS\Comment\Commentable;
   6  use Sabberworm\CSS\Parsing\ParserState;
   7  use Sabberworm\CSS\Renderable;
   8  use Sabberworm\CSS\Value\RuleValueList;
   9  use Sabberworm\CSS\Value\Value;
  10  
  11  /**
  12   * RuleSets contains Rule objects which always have a key and a value.
  13   * In CSS, Rules are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
  14   */
  15  class Rule implements Renderable, Commentable {
  16  
  17  	 private $sRule;
  18  	 private $mValue;
  19  	 private $bIsImportant;
  20  	 private $aIeHack;
  21  	 protected $iLineNo;
  22  	 protected $aComments;
  23  
  24  	public function __construct($sRule, $iLineNo = 0) {
  25  	 	 $this->sRule = $sRule;
  26  	 	 $this->mValue = null;
  27  	 	 $this->bIsImportant = false;
  28  	 	 $this->aIeHack = array();
  29  	 	 $this->iLineNo = $iLineNo;
  30  	 	 $this->aComments = array();
  31  	 }
  32  
  33  	public static function parse(ParserState $oParserState) {
  34  	 	 $aComments = $oParserState->consumeWhiteSpace();
  35  	 	 $oRule = new Rule($oParserState->parseIdentifier(), $oParserState->currentLine());
  36  	 	 $oRule->setComments($aComments);
  37  	 	 $oRule->addComments($oParserState->consumeWhiteSpace());
  38  	 	 $oParserState->consume(':');
  39  	 	 $oValue = Value::parseValue($oParserState, self::listDelimiterForRule($oRule->getRule()));
  40  	 	 $oRule->setValue($oValue);
  41  	 	 if ($oParserState->getSettings()->bLenientParsing) {
  42  	 	 	 while ($oParserState->comes('\\')) {
  43  	 	 	 	 $oParserState->consume('\\');
  44  	 	 	 	 $oRule->addIeHack($oParserState->consume());
  45  	 	 	 	 $oParserState->consumeWhiteSpace();
  46  	 	 	 }
  47  	 	 }
  48  	 	 $oParserState->consumeWhiteSpace();
  49  	 	 if ($oParserState->comes('!')) {
  50  	 	 	 $oParserState->consume('!');
  51  	 	 	 $oParserState->consumeWhiteSpace();
  52  	 	 	 $oParserState->consume('important');
  53  	 	 	 $oRule->setIsImportant(true);
  54  	 	 }
  55  	 	 $oParserState->consumeWhiteSpace();
  56  	 	 while ($oParserState->comes(';')) {
  57  	 	 	 $oParserState->consume(';');
  58  	 	 }
  59  
  60  	 	 return $oRule;
  61  	 }
  62  
  63  	private static function listDelimiterForRule($sRule) {
  64  	 	 if (preg_match('/^font($|-)/', $sRule)) {
  65  	 	 	 return array(',', '/', ' ');
  66  	 	 }
  67  	 	 return array(',', ' ', '/');
  68  	 }
  69  
  70  	 /**
  71  	  * @return int
  72  	  */
  73  	public function getLineNo() {
  74  	 	 return $this->iLineNo;
  75  	 }
  76  
  77  	public function setRule($sRule) {
  78  	 	 $this->sRule = $sRule;
  79  	 }
  80  
  81  	public function getRule() {
  82  	 	 return $this->sRule;
  83  	 }
  84  
  85  	public function getValue() {
  86  	 	 return $this->mValue;
  87  	 }
  88  
  89  	public function setValue($mValue) {
  90  	 	 $this->mValue = $mValue;
  91  	 }
  92  
  93  	 /**
  94  	  *	 @deprecated Old-Style 2-dimensional array given. Retained for (some) backwards-compatibility. Use setValue() instead and wrapp the value inside a RuleValueList if necessary.
  95  	  */
  96  	public function setValues($aSpaceSeparatedValues) {
  97  	 	 $oSpaceSeparatedList = null;
  98  	 	 if (count($aSpaceSeparatedValues) > 1) {
  99  	 	 	 $oSpaceSeparatedList = new RuleValueList(' ', $this->iLineNo);
 100  	 	 }
 101  	 	 foreach ($aSpaceSeparatedValues as $aCommaSeparatedValues) {
 102  	 	 	 $oCommaSeparatedList = null;
 103  	 	 	 if (count($aCommaSeparatedValues) > 1) {
 104  	 	 	 	 $oCommaSeparatedList = new RuleValueList(',', $this->iLineNo);
 105  	 	 	 }
 106  	 	 	 foreach ($aCommaSeparatedValues as $mValue) {
 107  	 	 	 	 if (!$oSpaceSeparatedList && !$oCommaSeparatedList) {
 108  	 	 	 	 	 $this->mValue = $mValue;
 109  	 	 	 	 	 return $mValue;
 110  	 	 	 	 }
 111  	 	 	 	 if ($oCommaSeparatedList) {
 112  	 	 	 	 	 $oCommaSeparatedList->addListComponent($mValue);
 113  	 	 	 	 } else {
 114  	 	 	 	 	 $oSpaceSeparatedList->addListComponent($mValue);
 115  	 	 	 	 }
 116  	 	 	 }
 117  	 	 	 if (!$oSpaceSeparatedList) {
 118  	 	 	 	 $this->mValue = $oCommaSeparatedList;
 119  	 	 	 	 return $oCommaSeparatedList;
 120  	 	 	 } else {
 121  	 	 	 	 $oSpaceSeparatedList->addListComponent($oCommaSeparatedList);
 122  	 	 	 }
 123  	 	 }
 124  	 	 $this->mValue = $oSpaceSeparatedList;
 125  	 	 return $oSpaceSeparatedList;
 126  	 }
 127  
 128  	 /**
 129  	  *	 @deprecated Old-Style 2-dimensional array returned. Retained for (some) backwards-compatibility. Use getValue() instead and check for the existance of a (nested set of) ValueList object(s).
 130  	  */
 131  	public function getValues() {
 132  	 	 if (!$this->mValue instanceof RuleValueList) {
 133  	 	 	 return array(array($this->mValue));
 134  	 	 }
 135  	 	 if ($this->mValue->getListSeparator() === ',') {
 136  	 	 	 return array($this->mValue->getListComponents());
 137  	 	 }
 138  	 	 $aResult = array();
 139  	 	 foreach ($this->mValue->getListComponents() as $mValue) {
 140  	 	 	 if (!$mValue instanceof RuleValueList || $mValue->getListSeparator() !== ',') {
 141  	 	 	 	 $aResult[] = array($mValue);
 142  	 	 	 	 continue;
 143  	 	 	 }
 144  	 	 	 if ($this->mValue->getListSeparator() === ' ' || count($aResult) === 0) {
 145  	 	 	 	 $aResult[] = array();
 146  	 	 	 }
 147  	 	 	 foreach ($mValue->getListComponents() as $mValue) {
 148  	 	 	 	 $aResult[count($aResult) - 1][] = $mValue;
 149  	 	 	 }
 150  	 	 }
 151  	 	 return $aResult;
 152  	 }
 153  
 154  	 /**
 155  	  * Adds a value to the existing value. Value will be appended if a RuleValueList exists of the given type. Otherwise, the existing value will be wrapped by one.
 156  	  */
 157  	public function addValue($mValue, $sType = ' ') {
 158  	 	 if (!is_array($mValue)) {
 159  	 	 	 $mValue = array($mValue);
 160  	 	 }
 161  	 	 if (!$this->mValue instanceof RuleValueList || $this->mValue->getListSeparator() !== $sType) {
 162  	 	 	 $mCurrentValue = $this->mValue;
 163  	 	 	 $this->mValue = new RuleValueList($sType, $this->iLineNo);
 164  	 	 	 if ($mCurrentValue) {
 165  	 	 	 	 $this->mValue->addListComponent($mCurrentValue);
 166  	 	 	 }
 167  	 	 }
 168  	 	 foreach ($mValue as $mValueItem) {
 169  	 	 	 $this->mValue->addListComponent($mValueItem);
 170  	 	 }
 171  	 }
 172  
 173  	public function addIeHack($iModifier) {
 174  	 	 $this->aIeHack[] = $iModifier;
 175  	 }
 176  
 177  	public function setIeHack(array $aModifiers) {
 178  	 	 $this->aIeHack = $aModifiers;
 179  	 }
 180  
 181  	public function getIeHack() {
 182  	 	 return $this->aIeHack;
 183  	 }
 184  
 185  	public function setIsImportant($bIsImportant) {
 186  	 	 $this->bIsImportant = $bIsImportant;
 187  	 }
 188  
 189  	public function getIsImportant() {
 190  	 	 return $this->bIsImportant;
 191  	 }
 192  
 193  	public function __toString() {
 194  	 	 return $this->render(new \Sabberworm\CSS\OutputFormat());
 195  	 }
 196  
 197  	public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
 198  	 	 $sResult = "{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
 199  	 	 if ($this->mValue instanceof Value) { //Can also be a ValueList
 200  	 	 	 $sResult .= $this->mValue->render($oOutputFormat);
 201  	 	 } else {
 202  	 	 	 $sResult .= $this->mValue;
 203  	 	 }
 204  	 	 if (!empty($this->aIeHack)) {
 205  	 	 	 $sResult .= ' \\' . implode('\\', $this->aIeHack);
 206  	 	 }
 207  	 	 if ($this->bIsImportant) {
 208  	 	 	 $sResult .= ' !important';
 209  	 	 }
 210  	 	 $sResult .= ';';
 211  	 	 return $sResult;
 212  	 }
 213  
 214  	 /**
 215  	  * @param array $aComments Array of comments.
 216  	  */
 217  	public function addComments(array $aComments) {
 218  	 	 $this->aComments = array_merge($this->aComments, $aComments);
 219  	 }
 220  
 221  	 /**
 222  	  * @return array
 223  	  */
 224  	public function getComments() {
 225  	 	 return $this->aComments;
 226  	 }
 227  
 228  	 /**
 229  	  * @param array $aComments Array containing Comment objects.
 230  	  */
 231  	public function setComments(array $aComments) {
 232  	 	 $this->aComments = $aComments;
 233  	 }
 234  
 235  }