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\Value;
   4  
   5  use Sabberworm\CSS\Parsing\ParserState;
   6  use Sabberworm\CSS\Parsing\UnexpectedTokenException;
   7  use Sabberworm\CSS\Renderable;
   8  
   9  abstract class Value implements Renderable {
  10  	 protected $iLineNo;
  11  
  12  	public function __construct($iLineNo = 0) {
  13  	 	 $this->iLineNo = $iLineNo;
  14  	 }
  15  
  16  	public static function parseValue(ParserState $oParserState, $aListDelimiters = array()) {
  17  	 	 $aStack = array();
  18  	 	 $oParserState->consumeWhiteSpace();
  19  	 	 //Build a list of delimiters and parsed values
  20  	 	 while (!($oParserState->comes('}') || $oParserState->comes(';') || $oParserState->comes('!') || $oParserState->comes(')') || $oParserState->comes('\\'))) {
  21  	 	 	 if (count($aStack) > 0) {
  22  	 	 	 	 $bFoundDelimiter = false;
  23  	 	 	 	 foreach ($aListDelimiters as $sDelimiter) {
  24  	 	 	 	 	 if ($oParserState->comes($sDelimiter)) {
  25  	 	 	 	 	 	 array_push($aStack, $oParserState->consume($sDelimiter));
  26  	 	 	 	 	 	 $oParserState->consumeWhiteSpace();
  27  	 	 	 	 	 	 $bFoundDelimiter = true;
  28  	 	 	 	 	 	 break;
  29  	 	 	 	 	 }
  30  	 	 	 	 }
  31  	 	 	 	 if (!$bFoundDelimiter) {
  32  	 	 	 	 	 //Whitespace was the list delimiter
  33  	 	 	 	 	 array_push($aStack, ' ');
  34  	 	 	 	 }
  35  	 	 	 }
  36  	 	 	 array_push($aStack, self::parsePrimitiveValue($oParserState));
  37  	 	 	 $oParserState->consumeWhiteSpace();
  38  	 	 }
  39  	 	 //Convert the list to list objects
  40  	 	 foreach ($aListDelimiters as $sDelimiter) {
  41  	 	 	 if (count($aStack) === 1) {
  42  	 	 	 	 return $aStack[0];
  43  	 	 	 }
  44  	 	 	 $iStartPosition = null;
  45  	 	 	 while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
  46  	 	 	 	 $iLength = 2; //Number of elements to be joined
  47  	 	 	 	 for ($i = $iStartPosition + 2; $i < count($aStack); $i+=2, ++$iLength) {
  48  	 	 	 	 	 if ($sDelimiter !== $aStack[$i]) {
  49  	 	 	 	 	 	 break;
  50  	 	 	 	 	 }
  51  	 	 	 	 }
  52  	 	 	 	 $oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
  53  	 	 	 	 for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i+=2) {
  54  	 	 	 	 	 $oList->addListComponent($aStack[$i]);
  55  	 	 	 	 }
  56  	 	 	 	 array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, array($oList));
  57  	 	 	 }
  58  	 	 }
  59  	 	 if (!isset($aStack[0])) {
  60  	 	 	 throw new UnexpectedTokenException(" {$oParserState->peek()} ", $oParserState->peek(1, -1) . $oParserState->peek(2), 'literal', $oParserState->currentLine());
  61  	 	 }
  62  	 	 return $aStack[0];
  63  	 }
  64  
  65  	public static function parseIdentifierOrFunction(ParserState $oParserState, $bIgnoreCase = false) {
  66  	 	 $sResult = $oParserState->parseIdentifier($bIgnoreCase);
  67  
  68  	 	 if ($oParserState->comes('(')) {
  69  	 	 	 $oParserState->consume('(');
  70  	 	 	 $aArguments = Value::parseValue($oParserState, array('=', ' ', ','));
  71  	 	 	 $sResult = new CSSFunction($sResult, $aArguments, ',', $oParserState->currentLine());
  72  	 	 	 $oParserState->consume(')');
  73  	 	 }
  74  
  75  	 	 return $sResult;
  76  	 }
  77  
  78  	public static function parsePrimitiveValue(ParserState $oParserState) {
  79  	 	 $oValue = null;
  80  	 	 $oParserState->consumeWhiteSpace();
  81  	 	 if (is_numeric($oParserState->peek()) || ($oParserState->comes('-.') && is_numeric($oParserState->peek(1, 2))) || (($oParserState->comes('-') || $oParserState->comes('.')) && is_numeric($oParserState->peek(1, 1)))) {
  82  	 	 	 $oValue = Size::parse($oParserState);
  83  	 	 } else if ($oParserState->comes('#') || $oParserState->comes('rgb', true) || $oParserState->comes('hsl', true)) {
  84  	 	 	 $oValue = Color::parse($oParserState);
  85  	 	 } else if ($oParserState->comes('url', true)) {
  86  	 	 	 $oValue = URL::parse($oParserState);
  87  	 	 } else if ($oParserState->comes('calc', true) || $oParserState->comes('-webkit-calc', true) || $oParserState->comes('-moz-calc', true)) {
  88  	 	 	 $oValue = CalcFunction::parse($oParserState);
  89  	 	 } else if ($oParserState->comes("'") || $oParserState->comes('"')) {
  90  	 	 	 $oValue = CSSString::parse($oParserState);
  91  	 	 } else if ($oParserState->comes("progid:") && $oParserState->getSettings()->bLenientParsing) {
  92  	 	 	 $oValue = self::parseMicrosoftFilter($oParserState);
  93  	 	 } else if ($oParserState->comes("[")) {
  94  	 	 	 $oValue = LineName::parse($oParserState);
  95  	 	 } else if ($oParserState->comes("U+")) {
  96  	 	 	 $oValue = self::parseUnicodeRangeValue($oParserState);
  97  	 	 } else {
  98  	 	 	 $oValue = self::parseIdentifierOrFunction($oParserState);
  99  	 	 }
 100  	 	 $oParserState->consumeWhiteSpace();
 101  	 	 return $oValue;
 102  	 }
 103  
 104  	private static function parseMicrosoftFilter(ParserState $oParserState) {
 105  	 	 $sFunction = $oParserState->consumeUntil('(', false, true);
 106  	 	 $aArguments = Value::parseValue($oParserState, array(',', '='));
 107  	 	 return new CSSFunction($sFunction, $aArguments, ',', $oParserState->currentLine());
 108  	 }
 109  
 110  	private static function parseUnicodeRangeValue(ParserState $oParserState) {
 111  	 	 $iCodepointMaxLenth = 6; // Code points outside BMP can use up to six digits
 112  	 	 $sRange = "";
 113  	 	 $oParserState->consume("U+");
 114  	 	 do {
 115  	 	 	 if ($oParserState->comes('-')) $iCodepointMaxLenth = 13; // Max length is 2 six digit code points + the dash(-) between them
 116  	 	 	 $sRange .= $oParserState->consume(1);
 117  	 	 } while (strlen($sRange) < $iCodepointMaxLenth && preg_match("/[A-Fa-f0-9\?-]/", $oParserState->peek()));
 118  	 	 return "U+{$sRange}";
 119  	 }
 120  	 
 121  	 /**
 122  	  * @return int
 123  	  */
 124  	public function getLineNo() {
 125  	 	 return $this->iLineNo;
 126  	 }
 127  
 128  	 //Methods are commented out because re-declaring them here is a fatal error in PHP < 5.3.9
 129  	 //public abstract function __toString();
 130  	 //public abstract function render(\Sabberworm\CSS\OutputFormat $oOutputFormat);
 131  }