Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
<?php

namespace Sabberworm\CSS\RuleSet;

< use Sabberworm\CSS\Parsing\ParserState;
> use Sabberworm\CSS\CSSList\CSSList; > use Sabberworm\CSS\CSSList\KeyFrame; > use Sabberworm\CSS\OutputFormat;
use Sabberworm\CSS\Parsing\OutputException;
> use Sabberworm\CSS\Parsing\ParserState; use Sabberworm\CSS\Property\Selector; > use Sabberworm\CSS\Parsing\UnexpectedEOFException; use Sabberworm\CSS\Rule\Rule; > use Sabberworm\CSS\Parsing\UnexpectedTokenException; use Sabberworm\CSS\Value\RuleValueList; > use Sabberworm\CSS\Property\KeyframeSelector;
use Sabberworm\CSS\Value\Value;
> use Sabberworm\CSS\Value\Color;
< use Sabberworm\CSS\Value\Value;
< use Sabberworm\CSS\Value\Color;
use Sabberworm\CSS\Value\URL;
> use Sabberworm\CSS\Value\Value;
/**
< * Declaration blocks are the parts of a css file which denote the rules belonging to a selector. < * Declaration blocks usually appear directly inside a Document or another CSSList (mostly a MediaQuery).
> * Declaration blocks are the parts of a CSS file which denote the rules belonging to a selector. > * > * Declaration blocks usually appear directly inside a `Document` or another `CSSList` (mostly a `MediaQuery`). > */ > class DeclarationBlock extends RuleSet > { > /** > * @var array<int, Selector|string>
*/
< class DeclarationBlock extends RuleSet { <
private $aSelectors;
< public function __construct($iLineNo = 0) {
> /** > * @param int $iLineNo > */ > public function __construct($iLineNo = 0) > {
parent::__construct($iLineNo);
< $this->aSelectors = array();
> $this->aSelectors = [];
}
< public static function parse(ParserState $oParserState) { < $aComments = array();
> /** > * @param CSSList|null $oList > * > * @return DeclarationBlock|false > * > * @throws UnexpectedTokenException > * @throws UnexpectedEOFException > */ > public static function parse(ParserState $oParserState, $oList = null) > { > $aComments = [];
$oResult = new DeclarationBlock($oParserState->currentLine());
< $oResult->setSelector($oParserState->consumeUntil('{', false, true, $aComments));
> try { > $aSelectorParts = []; > $sStringWrapperChar = false; > do { > $aSelectorParts[] = $oParserState->consume(1) > . $oParserState->consumeUntil(['{', '}', '\'', '"'], false, false, $aComments); > if (in_array($oParserState->peek(), ['\'', '"']) && substr(end($aSelectorParts), -1) != "\\") { > if ($sStringWrapperChar === false) { > $sStringWrapperChar = $oParserState->peek(); > } elseif ($sStringWrapperChar == $oParserState->peek()) { > $sStringWrapperChar = false; > } > } > } while (!in_array($oParserState->peek(), ['{', '}']) || $sStringWrapperChar !== false); > $oResult->setSelectors(implode('', $aSelectorParts), $oList); > if ($oParserState->comes('{')) { > $oParserState->consume(1); > } > } catch (UnexpectedTokenException $e) { > if ($oParserState->getSettings()->bLenientParsing) { > if (!$oParserState->comes('}')) { > $oParserState->consumeUntil('}', false, true); > } > return false; > } else { > throw $e; > } > }
$oResult->setComments($aComments); RuleSet::parseRuleSet($oParserState, $oResult); return $oResult; }
< < public function setSelectors($mSelector) {
> /** > * @param array<int, Selector|string>|string $mSelector > * @param CSSList|null $oList > * > * @throws UnexpectedTokenException > */ > public function setSelectors($mSelector, $oList = null) > {
if (is_array($mSelector)) { $this->aSelectors = $mSelector; } else { $this->aSelectors = explode(',', $mSelector); } foreach ($this->aSelectors as $iKey => $mSelector) { if (!($mSelector instanceof Selector)) {
> if ($oList === null || !($oList instanceof KeyFrame)) { $this->aSelectors[$iKey] = new Selector($mSelector); > if (!Selector::isValid($mSelector)) { } > throw new UnexpectedTokenException( } > "Selector did not match '" . Selector::SELECTOR_VALIDATION_RX . "'.", } > $mSelector, > "custom" // remove one of the selector of the block > ); public function removeSelector($mSelector) { > }
if($mSelector instanceof Selector) {
> } else { $mSelector = $mSelector->getSelector(); > if (!KeyframeSelector::isValid($mSelector)) { } > throw new UnexpectedTokenException( foreach($this->aSelectors as $iKey => $oSelector) { > "Selector did not match '" . KeyframeSelector::SELECTOR_VALIDATION_RX . "'.", if($oSelector->getSelector() === $mSelector) { > $mSelector, unset($this->aSelectors[$iKey]); > "custom" return true; > ); } > } } > $this->aSelectors[$iKey] = new KeyframeSelector($mSelector); return false; > }
< // remove one of the selector of the block < public function removeSelector($mSelector) {
> /** > * Remove one of the selectors of the block. > * > * @param Selector|string $mSelector > * > * @return bool > */ > public function removeSelector($mSelector) > {
/**
< * @deprecated use getSelectors()
> * @return array<int, Selector|string> > * > * @deprecated will be removed in version 9.0; use `getSelectors()` instead
*/
< public function getSelector() {
> public function getSelector() > {
return $this->getSelectors(); } /**
< * @deprecated use setSelectors()
> * @param Selector|string $mSelector > * @param CSSList|null $oList > * > * @return void > * > * @deprecated will be removed in version 9.0; use `setSelectors()` instead
*/
< public function setSelector($mSelector) { < $this->setSelectors($mSelector);
> public function setSelector($mSelector, $oList = null) > { > $this->setSelectors($mSelector, $oList);
} /**
< * Get selectors. < * < * @return Selector[] Selectors.
> * @return array<int, Selector|string>
*/
< public function getSelectors() {
> public function getSelectors() > {
return $this->aSelectors; } /**
< * Split shorthand declarations (e.g. +margin+ or +font+) into their constituent parts. < * */ < public function expandShorthands() {
> * Splits shorthand declarations (e.g. `margin` or `font`) into their constituent parts. > * > * @return void > */ > public function expandShorthands() > {
// border must be expanded before dimensions $this->expandBorderShorthand(); $this->expandDimensionsShorthand(); $this->expandFontShorthand(); $this->expandBackgroundShorthand(); $this->expandListStyleShorthand(); } /**
< * Create shorthand declarations (e.g. +margin+ or +font+) whenever possible. < * */ < public function createShorthands() {
> * Creates shorthand declarations (e.g. `margin` or `font`) whenever possible. > * > * @return void > */ > public function createShorthands() > {
$this->createBackgroundShorthand(); $this->createDimensionsShorthand(); // border must be shortened after dimensions $this->createBorderShorthand(); $this->createFontShorthand(); $this->createListStyleShorthand(); } /**
< * Split shorthand border declarations (e.g. <tt>border: 1px red;</tt>) < * Additional splitting happens in expandDimensionsShorthand < * Multiple borders are not yet supported as of 3 < * */ < public function expandBorderShorthand() { < $aBorderRules = array( < 'border', 'border-left', 'border-right', 'border-top', 'border-bottom' < ); < $aBorderSizes = array( < 'thin', 'medium', 'thick' < );
> * Splits shorthand border declarations (e.g. `border: 1px red;`). > * > * Additional splitting happens in expandDimensionsShorthand. > * > * Multiple borders are not yet supported as of 3. > * > * @return void > */ > public function expandBorderShorthand() > { > $aBorderRules = [ > 'border', > 'border-left', > 'border-right', > 'border-top', > 'border-bottom', > ]; > $aBorderSizes = [ > 'thin', > 'medium', > 'thick', > ];
$aRules = $this->getRulesAssoc(); foreach ($aBorderRules as $sBorderRule) {
< if (!isset($aRules[$sBorderRule]))
> if (!isset($aRules[$sBorderRule])) {
continue;
> }
$oRule = $aRules[$sBorderRule]; $mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } foreach ($aValues as $mValue) { if ($mValue instanceof Value) { $mNewValue = clone $mValue; } else { $mNewValue = $mValue; } if ($mValue instanceof Size) { $sNewRuleName = $sBorderRule . "-width"; } else if ($mValue instanceof Color) { $sNewRuleName = $sBorderRule . "-color"; } else { if (in_array($mValue, $aBorderSizes)) { $sNewRuleName = $sBorderRule . "-width";
< } else/* if(in_array($mValue, $aBorderStyles)) */ {
> } else {
$sNewRuleName = $sBorderRule . "-style"; } }
< $oNewRule = new Rule($sNewRuleName, $this->iLineNo);
> $oNewRule = new Rule($sNewRuleName, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->setIsImportant($oRule->getIsImportant());
< $oNewRule->addValue(array($mNewValue));
> $oNewRule->addValue([$mNewValue]);
$this->addRule($oNewRule); } $this->removeRule($sBorderRule); } } /**
< * Split shorthand dimensional declarations (e.g. <tt>margin: 0px auto;</tt>)
> * Splits shorthand dimensional declarations (e.g. `margin: 0px auto;`)
* into their constituent parts.
< * Handles margin, padding, border-color, border-style and border-width. < * */ < public function expandDimensionsShorthand() { < $aExpansions = array(
> * > * Handles `margin`, `padding`, `border-color`, `border-style` and `border-width`. > * > * @return void > */ > public function expandDimensionsShorthand() > { > $aExpansions = [
'margin' => 'margin-%s', 'padding' => 'padding-%s', 'border-color' => 'border-%s-color', 'border-style' => 'border-%s-style',
< 'border-width' => 'border-%s-width' < );
> 'border-width' => 'border-%s-width', > ];
$aRules = $this->getRulesAssoc(); foreach ($aExpansions as $sProperty => $sExpanded) {
< if (!isset($aRules[$sProperty]))
> if (!isset($aRules[$sProperty])) {
continue;
> }
$oRule = $aRules[$sProperty]; $mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } $top = $right = $bottom = $left = null; switch (count($aValues)) { case 1: $top = $right = $bottom = $left = $aValues[0]; break; case 2: $top = $bottom = $aValues[0]; $left = $right = $aValues[1]; break; case 3: $top = $aValues[0]; $left = $right = $aValues[1]; $bottom = $aValues[2]; break; case 4: $top = $aValues[0]; $right = $aValues[1]; $bottom = $aValues[2]; $left = $aValues[3]; break; }
< foreach (array('top', 'right', 'bottom', 'left') as $sPosition) { < $oNewRule = new Rule(sprintf($sExpanded, $sPosition), $this->iLineNo);
> foreach (['top', 'right', 'bottom', 'left'] as $sPosition) { > $oNewRule = new Rule(sprintf($sExpanded, $sPosition), $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->setIsImportant($oRule->getIsImportant()); $oNewRule->addValue(${$sPosition}); $this->addRule($oNewRule); } $this->removeRule($sProperty); } } /**
< * Convert shorthand font declarations < * (e.g. <tt>font: 300 italic 11px/14px verdana, helvetica, sans-serif;</tt>)
> * Converts shorthand font declarations > * (e.g. `font: 300 italic 11px/14px verdana, helvetica, sans-serif;`)
* into their constituent parts.
< * */ < public function expandFontShorthand() {
> * > * @return void > */ > public function expandFontShorthand() > {
$aRules = $this->getRulesAssoc();
< if (!isset($aRules['font']))
> if (!isset($aRules['font'])) {
return;
> }
$oRule = $aRules['font']; // reset properties to 'normal' per http://www.w3.org/TR/21/fonts.html#font-shorthand
< $aFontProperties = array(
> $aFontProperties = [
'font-style' => 'normal', 'font-variant' => 'normal', 'font-weight' => 'normal', 'font-size' => 'normal',
< 'line-height' => 'normal' < );
> 'line-height' => 'normal', > ];
$mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } foreach ($aValues as $mValue) { if (!$mValue instanceof Value) { $mValue = mb_strtolower($mValue); }
< if (in_array($mValue, array('normal', 'inherit'))) { < foreach (array('font-style', 'font-weight', 'font-variant') as $sProperty) {
> if (in_array($mValue, ['normal', 'inherit'])) { > foreach (['font-style', 'font-weight', 'font-variant'] as $sProperty) {
if (!isset($aFontProperties[$sProperty])) { $aFontProperties[$sProperty] = $mValue; } }
< } else if (in_array($mValue, array('italic', 'oblique'))) {
> } elseif (in_array($mValue, ['italic', 'oblique'])) {
$aFontProperties['font-style'] = $mValue; } else if ($mValue == 'small-caps') { $aFontProperties['font-variant'] = $mValue; } else if (
< in_array($mValue, array('bold', 'bolder', 'lighter'))
> in_array($mValue, ['bold', 'bolder', 'lighter'])
|| ($mValue instanceof Size && in_array($mValue->getSize(), range(100, 900, 100))) ) { $aFontProperties['font-weight'] = $mValue; } else if ($mValue instanceof RuleValueList && $mValue->getListSeparator() == '/') { list($oSize, $oHeight) = $mValue->getListComponents(); $aFontProperties['font-size'] = $oSize; $aFontProperties['line-height'] = $oHeight; } else if ($mValue instanceof Size && $mValue->getUnit() !== null) { $aFontProperties['font-size'] = $mValue; } else { $aFontProperties['font-family'] = $mValue; } } foreach ($aFontProperties as $sProperty => $mValue) {
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->addValue($mValue); $oNewRule->setIsImportant($oRule->getIsImportant()); $this->addRule($oNewRule); } $this->removeRule('font'); }
< /* < * Convert shorthand background declarations < * (e.g. <tt>background: url("chess.png") gray 50% repeat fixed;</tt>)
> /** > * Converts shorthand background declarations > * (e.g. `background: url("chess.png") gray 50% repeat fixed;`)
* into their constituent parts.
> *
* @see http://www.w3.org/TR/21/colors.html#propdef-background
< * */ < < public function expandBackgroundShorthand() {
> * > * @return void > */ > public function expandBackgroundShorthand() > {
$aRules = $this->getRulesAssoc();
< if (!isset($aRules['background']))
> if (!isset($aRules['background'])) {
return;
> }
$oRule = $aRules['background'];
< $aBgProperties = array( < 'background-color' => array('transparent'), 'background-image' => array('none'), < 'background-repeat' => array('repeat'), 'background-attachment' => array('scroll'), < 'background-position' => array(new Size(0, '%', null, false, $this->iLineNo), new Size(0, '%', null, false, $this->iLineNo)) < );
> $aBgProperties = [ > 'background-color' => ['transparent'], > 'background-image' => ['none'], > 'background-repeat' => ['repeat'], > 'background-attachment' => ['scroll'], > 'background-position' => [ > new Size(0, '%', null, false, $this->iLineNo), > new Size(0, '%', null, false, $this->iLineNo), > ], > ];
$mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } if (count($aValues) == 1 && $aValues[0] == 'inherit') { foreach ($aBgProperties as $sProperty => $mValue) {
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->addValue('inherit'); $oNewRule->setIsImportant($oRule->getIsImportant()); $this->addRule($oNewRule); } $this->removeRule('background'); return; } $iNumBgPos = 0; foreach ($aValues as $mValue) { if (!$mValue instanceof Value) { $mValue = mb_strtolower($mValue); } if ($mValue instanceof URL) { $aBgProperties['background-image'] = $mValue; } else if ($mValue instanceof Color) { $aBgProperties['background-color'] = $mValue;
< } else if (in_array($mValue, array('scroll', 'fixed'))) {
> } elseif (in_array($mValue, ['scroll', 'fixed'])) {
$aBgProperties['background-attachment'] = $mValue;
< } else if (in_array($mValue, array('repeat', 'no-repeat', 'repeat-x', 'repeat-y'))) {
> } elseif (in_array($mValue, ['repeat', 'no-repeat', 'repeat-x', 'repeat-y'])) {
$aBgProperties['background-repeat'] = $mValue;
< } else if (in_array($mValue, array('left', 'center', 'right', 'top', 'bottom'))
> } elseif ( > in_array($mValue, ['left', 'center', 'right', 'top', 'bottom'])
|| $mValue instanceof Size ) { if ($iNumBgPos == 0) { $aBgProperties['background-position'][0] = $mValue; $aBgProperties['background-position'][1] = 'center'; } else { $aBgProperties['background-position'][$iNumBgPos] = $mValue; } $iNumBgPos++; } } foreach ($aBgProperties as $sProperty => $mValue) {
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->setIsImportant($oRule->getIsImportant()); $oNewRule->addValue($mValue); $this->addRule($oNewRule); } $this->removeRule('background'); }
< public function expandListStyleShorthand() { < $aListProperties = array(
> /** > * @return void > */ > public function expandListStyleShorthand() > { > $aListProperties = [
'list-style-type' => 'disc', 'list-style-position' => 'outside',
< 'list-style-image' => 'none' < ); < $aListStyleTypes = array( < 'none', 'disc', 'circle', 'square', 'decimal-leading-zero', 'decimal', < 'lower-roman', 'upper-roman', 'lower-greek', 'lower-alpha', 'lower-latin', < 'upper-alpha', 'upper-latin', 'hebrew', 'armenian', 'georgian', 'cjk-ideographic', < 'hiragana', 'hira-gana-iroha', 'katakana-iroha', 'katakana' < ); < $aListStylePositions = array( < 'inside', 'outside' < );
> 'list-style-image' => 'none', > ]; > $aListStyleTypes = [ > 'none', > 'disc', > 'circle', > 'square', > 'decimal-leading-zero', > 'decimal', > 'lower-roman', > 'upper-roman', > 'lower-greek', > 'lower-alpha', > 'lower-latin', > 'upper-alpha', > 'upper-latin', > 'hebrew', > 'armenian', > 'georgian', > 'cjk-ideographic', > 'hiragana', > 'hira-gana-iroha', > 'katakana-iroha', > 'katakana', > ]; > $aListStylePositions = [ > 'inside', > 'outside', > ];
$aRules = $this->getRulesAssoc();
< if (!isset($aRules['list-style']))
> if (!isset($aRules['list-style'])) {
return;
> }
$oRule = $aRules['list-style']; $mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } if (count($aValues) == 1 && $aValues[0] == 'inherit') { foreach ($aListProperties as $sProperty => $mValue) {
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->addValue('inherit'); $oNewRule->setIsImportant($oRule->getIsImportant()); $this->addRule($oNewRule); } $this->removeRule('list-style'); return; } foreach ($aValues as $mValue) { if (!$mValue instanceof Value) { $mValue = mb_strtolower($mValue); } if ($mValue instanceof Url) { $aListProperties['list-style-image'] = $mValue; } else if (in_array($mValue, $aListStyleTypes)) { $aListProperties['list-style-types'] = $mValue; } else if (in_array($mValue, $aListStylePositions)) { $aListProperties['list-style-position'] = $mValue; } } foreach ($aListProperties as $sProperty => $mValue) {
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
$oNewRule->setIsImportant($oRule->getIsImportant()); $oNewRule->addValue($mValue); $this->addRule($oNewRule); } $this->removeRule('list-style'); }
< public function createShorthandProperties(array $aProperties, $sShorthand) {
> /** > * @param array<array-key, string> $aProperties > * @param string $sShorthand > * > * @return void > */ > public function createShorthandProperties(array $aProperties, $sShorthand) > {
$aRules = $this->getRulesAssoc();
< $aNewValues = array();
> $aNewValues = [];
foreach ($aProperties as $sProperty) {
< if (!isset($aRules[$sProperty]))
> if (!isset($aRules[$sProperty])) {
continue;
> }
$oRule = $aRules[$sProperty]; if (!$oRule->getIsImportant()) { $mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } foreach ($aValues as $mValue) { $aNewValues[] = $mValue; } $this->removeRule($sProperty); } } if (count($aNewValues)) {
< $oNewRule = new Rule($sShorthand, $this->iLineNo);
> $oNewRule = new Rule($sShorthand, $oRule->getLineNo(), $oRule->getColNo());
foreach ($aNewValues as $mValue) { $oNewRule->addValue($mValue); } $this->addRule($oNewRule); } }
< public function createBackgroundShorthand() { < $aProperties = array( < 'background-color', 'background-image', 'background-repeat', < 'background-position', 'background-attachment' < );
> /** > * @return void > */ > public function createBackgroundShorthand() > { > $aProperties = [ > 'background-color', > 'background-image', > 'background-repeat', > 'background-position', > 'background-attachment', > ];
$this->createShorthandProperties($aProperties, 'background'); }
< public function createListStyleShorthand() { < $aProperties = array( < 'list-style-type', 'list-style-position', 'list-style-image' < );
> /** > * @return void > */ > public function createListStyleShorthand() > { > $aProperties = [ > 'list-style-type', > 'list-style-position', > 'list-style-image', > ];
$this->createShorthandProperties($aProperties, 'list-style'); } /**
< * Combine border-color, border-style and border-width into border < * Should be run after create_dimensions_shorthand! < * */ < public function createBorderShorthand() { < $aProperties = array( < 'border-width', 'border-style', 'border-color' < );
> * Combines `border-color`, `border-style` and `border-width` into `border`. > * > * Should be run after `create_dimensions_shorthand`! > * > * @return void > */ > public function createBorderShorthand() > { > $aProperties = [ > 'border-width', > 'border-style', > 'border-color', > ];
$this->createShorthandProperties($aProperties, 'border'); }
< /*
> /**
* Looks for long format CSS dimensional properties * (margin, padding, border-color, border-style and border-width) * and converts them into shorthand CSS properties.
< * */ < < public function createDimensionsShorthand() { < $aPositions = array('top', 'right', 'bottom', 'left'); < $aExpansions = array(
> * > * @return void > */ > public function createDimensionsShorthand() > { > $aPositions = ['top', 'right', 'bottom', 'left']; > $aExpansions = [
'margin' => 'margin-%s', 'padding' => 'padding-%s', 'border-color' => 'border-%s-color', 'border-style' => 'border-%s-style',
< 'border-width' => 'border-%s-width' < );
> 'border-width' => 'border-%s-width', > ];
$aRules = $this->getRulesAssoc(); foreach ($aExpansions as $sProperty => $sExpanded) {
< $aFoldable = array();
> $aFoldable = [];
foreach ($aRules as $sRuleName => $oRule) { foreach ($aPositions as $sPosition) { if ($sRuleName == sprintf($sExpanded, $sPosition)) { $aFoldable[$sRuleName] = $oRule; } } } // All four dimensions must be present if (count($aFoldable) == 4) {
< $aValues = array();
> $aValues = [];
foreach ($aPositions as $sPosition) { $oRule = $aRules[sprintf($sExpanded, $sPosition)]; $mRuleValue = $oRule->getValue();
< $aRuleValues = array();
> $aRuleValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aRuleValues[] = $mRuleValue; } else { $aRuleValues = $mRuleValue->getListComponents(); } $aValues[$sPosition] = $aRuleValues; }
< $oNewRule = new Rule($sProperty, $this->iLineNo);
> $oNewRule = new Rule($sProperty, $oRule->getLineNo(), $oRule->getColNo());
if ((string) $aValues['left'][0] == (string) $aValues['right'][0]) { if ((string) $aValues['top'][0] == (string) $aValues['bottom'][0]) { if ((string) $aValues['top'][0] == (string) $aValues['left'][0]) { // All 4 sides are equal $oNewRule->addValue($aValues['top']); } else { // Top and bottom are equal, left and right are equal $oNewRule->addValue($aValues['top']); $oNewRule->addValue($aValues['left']); } } else { // Only left and right are equal $oNewRule->addValue($aValues['top']); $oNewRule->addValue($aValues['left']); $oNewRule->addValue($aValues['bottom']); } } else { // No sides are equal $oNewRule->addValue($aValues['top']); $oNewRule->addValue($aValues['left']); $oNewRule->addValue($aValues['bottom']); $oNewRule->addValue($aValues['right']); } $this->addRule($oNewRule); foreach ($aPositions as $sPosition) { $this->removeRule(sprintf($sExpanded, $sPosition)); } } } } /**
< * Looks for long format CSS font properties (e.g. <tt>font-weight</tt>) and < * tries to convert them into a shorthand CSS <tt>font</tt> property. < * At least font-size AND font-family must be present in order to create a shorthand declaration. < * */ < public function createFontShorthand() { < $aFontProperties = array( < 'font-style', 'font-variant', 'font-weight', 'font-size', 'line-height', 'font-family' < );
> * Looks for long format CSS font properties (e.g. `font-weight`) and > * tries to convert them into a shorthand CSS `font` property. > * > * At least `font-size` AND `font-family` must be present in order to create a shorthand declaration. > * > * @return void > */ > public function createFontShorthand() > { > $aFontProperties = [ > 'font-style', > 'font-variant', > 'font-weight', > 'font-size', > 'line-height', > 'font-family', > ];
$aRules = $this->getRulesAssoc(); if (!isset($aRules['font-size']) || !isset($aRules['font-family'])) { return; }
< $oNewRule = new Rule('font', $this->iLineNo); < foreach (array('font-style', 'font-variant', 'font-weight') as $sProperty) {
> $oOldRule = isset($aRules['font-size']) ? $aRules['font-size'] : $aRules['font-family']; > $oNewRule = new Rule('font', $oOldRule->getLineNo(), $oOldRule->getColNo()); > unset($oOldRule); > foreach (['font-style', 'font-variant', 'font-weight'] as $sProperty) {
if (isset($aRules[$sProperty])) { $oRule = $aRules[$sProperty]; $mRuleValue = $oRule->getValue();
< $aValues = array();
> $aValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aValues[] = $mRuleValue; } else { $aValues = $mRuleValue->getListComponents(); } if ($aValues[0] !== 'normal') { $oNewRule->addValue($aValues[0]); } } } // Get the font-size value $oRule = $aRules['font-size']; $mRuleValue = $oRule->getValue();
< $aFSValues = array();
> $aFSValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aFSValues[] = $mRuleValue; } else { $aFSValues = $mRuleValue->getListComponents(); } // But wait to know if we have line-height to add it if (isset($aRules['line-height'])) { $oRule = $aRules['line-height']; $mRuleValue = $oRule->getValue();
< $aLHValues = array();
> $aLHValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aLHValues[] = $mRuleValue; } else { $aLHValues = $mRuleValue->getListComponents(); } if ($aLHValues[0] !== 'normal') { $val = new RuleValueList('/', $this->iLineNo); $val->addListComponent($aFSValues[0]); $val->addListComponent($aLHValues[0]); $oNewRule->addValue($val); } } else { $oNewRule->addValue($aFSValues[0]); } $oRule = $aRules['font-family']; $mRuleValue = $oRule->getValue();
< $aFFValues = array();
> $aFFValues = [];
if (!$mRuleValue instanceof RuleValueList) { $aFFValues[] = $mRuleValue; } else { $aFFValues = $mRuleValue->getListComponents(); } $oFFValue = new RuleValueList(',', $this->iLineNo); $oFFValue->setListComponents($aFFValues); $oNewRule->addValue($oFFValue); $this->addRule($oNewRule); foreach ($aFontProperties as $sProperty) { $this->removeRule($sProperty); } }
< public function __toString() { < return $this->render(new \Sabberworm\CSS\OutputFormat());
> /** > * @return string > * > * @throws OutputException > */ > public function __toString() > { > return $this->render(new OutputFormat());
}
< public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
> /** > * @return string > * > * @throws OutputException > */ > public function render(OutputFormat $oOutputFormat) > {
if(count($this->aSelectors) === 0) { // If all the selectors have been removed, this declaration block becomes invalid throw new OutputException("Attempt to print declaration block with missing selector", $this->iLineNo); } $sResult = $oOutputFormat->sBeforeDeclarationBlock;
< $sResult .= $oOutputFormat->implode($oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), $this->aSelectors);
> $sResult .= $oOutputFormat->implode( > $oOutputFormat->spaceBeforeSelectorSeparator() . ',' . $oOutputFormat->spaceAfterSelectorSeparator(), > $this->aSelectors > );
$sResult .= $oOutputFormat->sAfterDeclarationBlockSelectors; $sResult .= $oOutputFormat->spaceBeforeOpeningBrace() . '{'; $sResult .= parent::render($oOutputFormat); $sResult .= '}'; $sResult .= $oOutputFormat->sAfterDeclarationBlock; return $sResult; }
<
}