forked from moodle/moodle
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
MDL-55224 core: Import PHP-CSS-Parser into core
Part of MDL-55071
- Loading branch information
1 parent
e86eb6b
commit fbe18cc
Showing
34 changed files
with
3,307 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
namespace Sabberworm\CSS\CSSList; | ||
|
||
use Sabberworm\CSS\Property\AtRule; | ||
|
||
/** | ||
* A BlockList constructed by an unknown @-rule. @media rules are rendered into AtRuleBlockList objects. | ||
*/ | ||
class AtRuleBlockList extends CSSBlockList implements AtRule { | ||
|
||
private $sType; | ||
private $sArgs; | ||
|
||
public function __construct($sType, $sArgs = '', $iLineNo = 0) { | ||
parent::__construct($iLineNo); | ||
$this->sType = $sType; | ||
$this->sArgs = $sArgs; | ||
} | ||
|
||
public function atRuleName() { | ||
return $this->sType; | ||
} | ||
|
||
public function atRuleArgs() { | ||
return $this->sArgs; | ||
} | ||
|
||
public function __toString() { | ||
return $this->render(new \Sabberworm\CSS\OutputFormat()); | ||
} | ||
|
||
public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) { | ||
$sArgs = $this->sArgs; | ||
if($sArgs) { | ||
$sArgs = ' ' . $sArgs; | ||
} | ||
$sResult = "@{$this->sType}$sArgs{$oOutputFormat->spaceBeforeOpeningBrace()}{"; | ||
$sResult .= parent::render($oOutputFormat); | ||
$sResult .= '}'; | ||
return $sResult; | ||
} | ||
|
||
public function isRootList() { | ||
return false; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<?php | ||
|
||
namespace Sabberworm\CSS\CSSList; | ||
|
||
use Sabberworm\CSS\RuleSet\DeclarationBlock; | ||
use Sabberworm\CSS\RuleSet\RuleSet; | ||
use Sabberworm\CSS\Property\Selector; | ||
use Sabberworm\CSS\Rule\Rule; | ||
use Sabberworm\CSS\Value\ValueList; | ||
use Sabberworm\CSS\Value\CSSFunction; | ||
|
||
/** | ||
* A CSSBlockList is a CSSList whose DeclarationBlocks are guaranteed to contain valid declaration blocks or at-rules. | ||
* Most CSSLists conform to this category but some at-rules (such as @keyframes) do not. | ||
*/ | ||
abstract class CSSBlockList extends CSSList { | ||
public function __construct($iLineNo = 0) { | ||
parent::__construct($iLineNo); | ||
} | ||
|
||
protected function allDeclarationBlocks(&$aResult) { | ||
foreach ($this->aContents as $mContent) { | ||
if ($mContent instanceof DeclarationBlock) { | ||
$aResult[] = $mContent; | ||
} else if ($mContent instanceof CSSBlockList) { | ||
$mContent->allDeclarationBlocks($aResult); | ||
} | ||
} | ||
} | ||
|
||
protected function allRuleSets(&$aResult) { | ||
foreach ($this->aContents as $mContent) { | ||
if ($mContent instanceof RuleSet) { | ||
$aResult[] = $mContent; | ||
} else if ($mContent instanceof CSSBlockList) { | ||
$mContent->allRuleSets($aResult); | ||
} | ||
} | ||
} | ||
|
||
protected function allValues($oElement, &$aResult, $sSearchString = null, $bSearchInFunctionArguments = false) { | ||
if ($oElement instanceof CSSBlockList) { | ||
foreach ($oElement->getContents() as $oContent) { | ||
$this->allValues($oContent, $aResult, $sSearchString, $bSearchInFunctionArguments); | ||
} | ||
} else if ($oElement instanceof RuleSet) { | ||
foreach ($oElement->getRules($sSearchString) as $oRule) { | ||
$this->allValues($oRule, $aResult, $sSearchString, $bSearchInFunctionArguments); | ||
} | ||
} else if ($oElement instanceof Rule) { | ||
$this->allValues($oElement->getValue(), $aResult, $sSearchString, $bSearchInFunctionArguments); | ||
} else if ($oElement instanceof ValueList) { | ||
if ($bSearchInFunctionArguments || !($oElement instanceof CSSFunction)) { | ||
foreach ($oElement->getListComponents() as $mComponent) { | ||
$this->allValues($mComponent, $aResult, $sSearchString, $bSearchInFunctionArguments); | ||
} | ||
} | ||
} else { | ||
//Non-List Value or CSSString (CSS identifier) | ||
$aResult[] = $oElement; | ||
} | ||
} | ||
|
||
protected function allSelectors(&$aResult, $sSpecificitySearch = null) { | ||
$aDeclarationBlocks = array(); | ||
$this->allDeclarationBlocks($aDeclarationBlocks); | ||
foreach ($aDeclarationBlocks as $oBlock) { | ||
foreach ($oBlock->getSelectors() as $oSelector) { | ||
if ($sSpecificitySearch === null) { | ||
$aResult[] = $oSelector; | ||
} else { | ||
$sComparison = "\$bRes = {$oSelector->getSpecificity()} $sSpecificitySearch;"; | ||
eval($sComparison); | ||
if ($bRes) { | ||
$aResult[] = $oSelector; | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
<?php | ||
|
||
namespace Sabberworm\CSS\CSSList; | ||
|
||
use Sabberworm\CSS\Renderable; | ||
use Sabberworm\CSS\RuleSet\DeclarationBlock; | ||
use Sabberworm\CSS\RuleSet\RuleSet; | ||
use Sabberworm\CSS\Property\Selector; | ||
use Sabberworm\CSS\Comment\Commentable; | ||
|
||
/** | ||
* A CSSList is the most generic container available. Its contents include RuleSet as well as other CSSList objects. | ||
* Also, it may contain Import and Charset objects stemming from @-rules. | ||
*/ | ||
abstract class CSSList implements Renderable, Commentable { | ||
|
||
protected $aComments; | ||
protected $aContents; | ||
protected $iLineNo; | ||
|
||
public function __construct($iLineNo = 0) { | ||
$this->aComments = array(); | ||
$this->aContents = array(); | ||
$this->iLineNo = $iLineNo; | ||
} | ||
|
||
/** | ||
* @return int | ||
*/ | ||
public function getLineNo() { | ||
return $this->iLineNo; | ||
} | ||
|
||
public function append($oItem) { | ||
$this->aContents[] = $oItem; | ||
} | ||
|
||
/** | ||
* Removes an item from the CSS list. | ||
* @param RuleSet|Import|Charset|CSSList $oItemToRemove May be a RuleSet (most likely a DeclarationBlock), a Import, a Charset or another CSSList (most likely a MediaQuery) | ||
*/ | ||
public function remove($oItemToRemove) { | ||
$iKey = array_search($oItemToRemove, $this->aContents, true); | ||
if ($iKey !== false) { | ||
unset($this->aContents[$iKey]); | ||
return true; | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Set the contents. | ||
* @param array $aContents Objects to set as content. | ||
*/ | ||
public function setContents(array $aContents) { | ||
$this->aContents = array(); | ||
foreach ($aContents as $content) { | ||
$this->append($content); | ||
} | ||
} | ||
|
||
/** | ||
* Removes a declaration block from the CSS list if it matches all given selectors. | ||
* @param array|string $mSelector The selectors to match. | ||
* @param boolean $bRemoveAll Whether to stop at the first declaration block found or remove all blocks | ||
*/ | ||
public function removeDeclarationBlockBySelector($mSelector, $bRemoveAll = false) { | ||
if ($mSelector instanceof DeclarationBlock) { | ||
$mSelector = $mSelector->getSelectors(); | ||
} | ||
if (!is_array($mSelector)) { | ||
$mSelector = explode(',', $mSelector); | ||
} | ||
foreach ($mSelector as $iKey => &$mSel) { | ||
if (!($mSel instanceof Selector)) { | ||
$mSel = new Selector($mSel); | ||
} | ||
} | ||
foreach ($this->aContents as $iKey => $mItem) { | ||
if (!($mItem instanceof DeclarationBlock)) { | ||
continue; | ||
} | ||
if ($mItem->getSelectors() == $mSelector) { | ||
unset($this->aContents[$iKey]); | ||
if (!$bRemoveAll) { | ||
return; | ||
} | ||
} | ||
} | ||
} | ||
|
||
public function __toString() { | ||
return $this->render(new \Sabberworm\CSS\OutputFormat()); | ||
} | ||
|
||
public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) { | ||
$sResult = ''; | ||
$bIsFirst = true; | ||
$oNextLevel = $oOutputFormat; | ||
if(!$this->isRootList()) { | ||
$oNextLevel = $oOutputFormat->nextLevel(); | ||
} | ||
foreach ($this->aContents as $oContent) { | ||
$sRendered = $oOutputFormat->safely(function() use ($oNextLevel, $oContent) { | ||
return $oContent->render($oNextLevel); | ||
}); | ||
if($sRendered === null) { | ||
continue; | ||
} | ||
if($bIsFirst) { | ||
$bIsFirst = false; | ||
$sResult .= $oNextLevel->spaceBeforeBlocks(); | ||
} else { | ||
$sResult .= $oNextLevel->spaceBetweenBlocks(); | ||
} | ||
$sResult .= $sRendered; | ||
} | ||
|
||
if(!$bIsFirst) { | ||
// Had some output | ||
$sResult .= $oOutputFormat->spaceAfterBlocks(); | ||
} | ||
|
||
return $sResult; | ||
} | ||
|
||
/** | ||
* Return true if the list can not be further outdented. Only important when rendering. | ||
*/ | ||
public abstract function isRootList(); | ||
|
||
public function getContents() { | ||
return $this->aContents; | ||
} | ||
|
||
/** | ||
* @param array $aComments Array of comments. | ||
*/ | ||
public function addComments(array $aComments) { | ||
$this->aComments = array_merge($this->aComments, $aComments); | ||
} | ||
|
||
/** | ||
* @return array | ||
*/ | ||
public function getComments() { | ||
return $this->aComments; | ||
} | ||
|
||
/** | ||
* @param array $aComments Array containing Comment objects. | ||
*/ | ||
public function setComments(array $aComments) { | ||
$this->aComments = $aComments; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
<?php | ||
|
||
namespace Sabberworm\CSS\CSSList; | ||
|
||
/** | ||
* The root CSSList of a parsed file. Contains all top-level css contents, mostly declaration blocks, but also any @-rules encountered. | ||
*/ | ||
class Document extends CSSBlockList { | ||
/** | ||
* Document constructor. | ||
* @param int $iLineNo | ||
*/ | ||
public function __construct($iLineNo = 0) { | ||
parent::__construct($iLineNo); | ||
} | ||
|
||
/** | ||
* Gets all DeclarationBlock objects recursively. | ||
*/ | ||
public function getAllDeclarationBlocks() { | ||
$aResult = array(); | ||
$this->allDeclarationBlocks($aResult); | ||
return $aResult; | ||
} | ||
|
||
/** | ||
* @deprecated use getAllDeclarationBlocks() | ||
*/ | ||
public function getAllSelectors() { | ||
return $this->getAllDeclarationBlocks(); | ||
} | ||
|
||
/** | ||
* Returns all RuleSet objects found recursively in the tree. | ||
*/ | ||
public function getAllRuleSets() { | ||
$aResult = array(); | ||
$this->allRuleSets($aResult); | ||
return $aResult; | ||
} | ||
|
||
/** | ||
* Returns all Value objects found recursively in the tree. | ||
* @param (object|string) $mElement the CSSList or RuleSet to start the search from (defaults to the whole document). If a string is given, it is used as rule name filter (@see{RuleSet->getRules()}). | ||
* @param (bool) $bSearchInFunctionArguments whether to also return Value objects used as Function arguments. | ||
*/ | ||
public function getAllValues($mElement = null, $bSearchInFunctionArguments = false) { | ||
$sSearchString = null; | ||
if ($mElement === null) { | ||
$mElement = $this; | ||
} else if (is_string($mElement)) { | ||
$sSearchString = $mElement; | ||
$mElement = $this; | ||
} | ||
$aResult = array(); | ||
$this->allValues($mElement, $aResult, $sSearchString, $bSearchInFunctionArguments); | ||
return $aResult; | ||
} | ||
|
||
/** | ||
* Returns all Selector objects found recursively in the tree. | ||
* Note that this does not yield the full DeclarationBlock that the selector belongs to (and, currently, there is no way to get to that). | ||
* @param $sSpecificitySearch An optional filter by specificity. May contain a comparison operator and a number or just a number (defaults to "=="). | ||
* @example getSelectorsBySpecificity('>= 100') | ||
*/ | ||
public function getSelectorsBySpecificity($sSpecificitySearch = null) { | ||
if (is_numeric($sSpecificitySearch) || is_numeric($sSpecificitySearch[0])) { | ||
$sSpecificitySearch = "== $sSpecificitySearch"; | ||
} | ||
$aResult = array(); | ||
$this->allSelectors($aResult, $sSpecificitySearch); | ||
return $aResult; | ||
} | ||
|
||
/** | ||
* Expands all shorthand properties to their long value | ||
*/ | ||
public function expandShorthands() { | ||
foreach ($this->getAllDeclarationBlocks() as $oDeclaration) { | ||
$oDeclaration->expandShorthands(); | ||
} | ||
} | ||
|
||
/** | ||
* Create shorthands properties whenever possible | ||
*/ | ||
public function createShorthands() { | ||
foreach ($this->getAllDeclarationBlocks() as $oDeclaration) { | ||
$oDeclaration->createShorthands(); | ||
} | ||
} | ||
|
||
// Override render() to make format argument optional | ||
public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat = null) { | ||
if($oOutputFormat === null) { | ||
$oOutputFormat = new \Sabberworm\CSS\OutputFormat(); | ||
} | ||
return parent::render($oOutputFormat); | ||
} | ||
|
||
public function isRootList() { | ||
return true; | ||
} | ||
|
||
} |
Oops, something went wrong.