weekly release 3.8dev
[moodle.git] / lib / php-css-parser / CSSList / CSSList.php
CommitLineData
fbe18cc0
FM
1<?php
2
3namespace Sabberworm\CSS\CSSList;
4
5use Sabberworm\CSS\Renderable;
6use Sabberworm\CSS\RuleSet\DeclarationBlock;
7use Sabberworm\CSS\RuleSet\RuleSet;
8use Sabberworm\CSS\Property\Selector;
9use Sabberworm\CSS\Comment\Commentable;
10
11/**
12 * A CSSList is the most generic container available. Its contents include RuleSet as well as other CSSList objects.
13 * Also, it may contain Import and Charset objects stemming from @-rules.
14 */
15abstract class CSSList implements Renderable, Commentable {
16
17 protected $aComments;
18 protected $aContents;
19 protected $iLineNo;
20
21 public function __construct($iLineNo = 0) {
22 $this->aComments = array();
23 $this->aContents = array();
24 $this->iLineNo = $iLineNo;
25 }
26
27 /**
28 * @return int
29 */
30 public function getLineNo() {
31 return $this->iLineNo;
32 }
33
34 public function append($oItem) {
35 $this->aContents[] = $oItem;
36 }
37
515ceadd
FM
38 /**
39 * Insert an item before its sibling.
40 *
41 * @param mixed $oItem The item.
42 * @param mixed $oSibling The sibling.
43 */
44 public function insert($oItem, $oSibling) {
45 $iIndex = array_search($oSibling, $this->aContents);
46 if ($iIndex === false) {
47 return $this->append($oItem);
48 }
49 array_splice($this->aContents, $iIndex, 0, array($oItem));
50 }
51
fbe18cc0
FM
52 /**
53 * Removes an item from the CSS list.
54 * @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)
55 */
56 public function remove($oItemToRemove) {
57 $iKey = array_search($oItemToRemove, $this->aContents, true);
58 if ($iKey !== false) {
59 unset($this->aContents[$iKey]);
60 return true;
61 }
62 return false;
63 }
64
65 /**
66 * Set the contents.
67 * @param array $aContents Objects to set as content.
68 */
69 public function setContents(array $aContents) {
70 $this->aContents = array();
71 foreach ($aContents as $content) {
72 $this->append($content);
73 }
74 }
75
76 /**
77 * Removes a declaration block from the CSS list if it matches all given selectors.
78 * @param array|string $mSelector The selectors to match.
79 * @param boolean $bRemoveAll Whether to stop at the first declaration block found or remove all blocks
80 */
81 public function removeDeclarationBlockBySelector($mSelector, $bRemoveAll = false) {
82 if ($mSelector instanceof DeclarationBlock) {
83 $mSelector = $mSelector->getSelectors();
84 }
85 if (!is_array($mSelector)) {
86 $mSelector = explode(',', $mSelector);
87 }
88 foreach ($mSelector as $iKey => &$mSel) {
89 if (!($mSel instanceof Selector)) {
90 $mSel = new Selector($mSel);
91 }
92 }
93 foreach ($this->aContents as $iKey => $mItem) {
94 if (!($mItem instanceof DeclarationBlock)) {
95 continue;
96 }
97 if ($mItem->getSelectors() == $mSelector) {
98 unset($this->aContents[$iKey]);
99 if (!$bRemoveAll) {
100 return;
101 }
102 }
103 }
104 }
105
106 public function __toString() {
107 return $this->render(new \Sabberworm\CSS\OutputFormat());
108 }
109
110 public function render(\Sabberworm\CSS\OutputFormat $oOutputFormat) {
111 $sResult = '';
112 $bIsFirst = true;
113 $oNextLevel = $oOutputFormat;
114 if(!$this->isRootList()) {
115 $oNextLevel = $oOutputFormat->nextLevel();
116 }
117 foreach ($this->aContents as $oContent) {
118 $sRendered = $oOutputFormat->safely(function() use ($oNextLevel, $oContent) {
119 return $oContent->render($oNextLevel);
120 });
121 if($sRendered === null) {
122 continue;
123 }
124 if($bIsFirst) {
125 $bIsFirst = false;
126 $sResult .= $oNextLevel->spaceBeforeBlocks();
127 } else {
128 $sResult .= $oNextLevel->spaceBetweenBlocks();
129 }
130 $sResult .= $sRendered;
131 }
132
133 if(!$bIsFirst) {
134 // Had some output
135 $sResult .= $oOutputFormat->spaceAfterBlocks();
136 }
137
138 return $sResult;
139 }
140
141 /**
142 * Return true if the list can not be further outdented. Only important when rendering.
143 */
144 public abstract function isRootList();
145
146 public function getContents() {
147 return $this->aContents;
148 }
149
150 /**
151 * @param array $aComments Array of comments.
152 */
153 public function addComments(array $aComments) {
154 $this->aComments = array_merge($this->aComments, $aComments);
155 }
156
157 /**
158 * @return array
159 */
160 public function getComments() {
161 return $this->aComments;
162 }
163
164 /**
165 * @param array $aComments Array containing Comment objects.
166 */
167 public function setComments(array $aComments) {
168 $this->aComments = $aComments;
169 }
170
171}