MDL-55224 core: Import PHP-CSS-Parser into core
Part of MDL-55071
This commit is contained in:
committed by
Dan Poltawski
parent
e86eb6b80d
commit
fbe18cc022
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace Sabberworm\CSS\CSSList;
|
||||
|
||||
use Sabberworm\CSS\Property\AtRule;
|
||||
|
||||
class KeyFrame extends CSSList implements AtRule {
|
||||
|
||||
private $vendorKeyFrame;
|
||||
private $animationName;
|
||||
|
||||
public function __construct($iLineNo = 0) {
|
||||
parent::__construct($iLineNo);
|
||||
$this->vendorKeyFrame = null;
|
||||
$this->animationName = null;
|
||||
}
|
||||
|
||||
public function setVendorKeyFrame($vendorKeyFrame) {
|
||||
$this->vendorKeyFrame = $vendorKeyFrame;
|
||||
}
|
||||
|
||||
public function getVendorKeyFrame() {
|
||||
return $this->vendorKeyFrame;
|
||||
}
|
||||
|
||||
public function setAnimationName($animationName) {
|
||||
$this->animationName = $animationName;
|
||||
}
|
||||
|
||||
public function getAnimationName() {
|
||||
return $this->animationName;
|
||||
}
|
||||
|
||||
public function __toString() {
|
||||
return $this->render(new \Sabberworm\CSS\OutputFormat());
|
||||
}
|
||||
|
||||
public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
|
||||
$sResult = "@{$this->vendorKeyFrame} {$this->animationName}{$oOutputFormat->spaceBeforeOpeningBrace()}{";
|
||||
$sResult .= parent::render($oOutputFormat);
|
||||
$sResult .= '}';
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
public function isRootList() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function atRuleName() {
|
||||
return $this->vendorKeyFrame;
|
||||
}
|
||||
|
||||
public function atRuleArgs() {
|
||||
return $this->animationName;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user