Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1441 ariadna 1
<?php
2
 
3
namespace Sabberworm\CSS\Rule;
4
 
5
use Sabberworm\CSS\Comment\Comment;
6
use Sabberworm\CSS\Comment\Commentable;
7
use Sabberworm\CSS\OutputFormat;
8
use Sabberworm\CSS\Parsing\ParserState;
9
use Sabberworm\CSS\Parsing\UnexpectedEOFException;
10
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
11
use Sabberworm\CSS\Renderable;
12
use Sabberworm\CSS\Value\RuleValueList;
13
use Sabberworm\CSS\Value\Value;
14
 
15
/**
16
 * `Rule`s just have a string key (the rule) and a 'Value'.
17
 *
18
 * In CSS, `Rule`s are expressed as follows: “key: value[0][0] value[0][1], value[1][0] value[1][1];”
19
 */
20
class Rule implements Renderable, Commentable
21
{
22
    /**
23
     * @var string
24
     */
25
    private $sRule;
26
 
27
    /**
28
     * @var RuleValueList|string|null
29
     */
30
    private $mValue;
31
 
32
    /**
33
     * @var bool
34
     */
35
    private $bIsImportant;
36
 
37
    /**
38
     * @var array<int, int>
39
     */
40
    private $aIeHack;
41
 
42
    /**
43
     * @var int
44
     */
45
    protected $iLineNo;
46
 
47
    /**
48
     * @var int
49
     */
50
    protected $iColNo;
51
 
52
    /**
53
     * @var array<array-key, Comment>
54
     */
55
    protected $aComments;
56
 
57
    /**
58
     * @param string $sRule
59
     * @param int $iLineNo
60
     * @param int $iColNo
61
     */
62
    public function __construct($sRule, $iLineNo = 0, $iColNo = 0)
63
    {
64
        $this->sRule = $sRule;
65
        $this->mValue = null;
66
        $this->bIsImportant = false;
67
        $this->aIeHack = [];
68
        $this->iLineNo = $iLineNo;
69
        $this->iColNo = $iColNo;
70
        $this->aComments = [];
71
    }
72
 
73
    /**
74
     * @return Rule
75
     *
76
     * @throws UnexpectedEOFException
77
     * @throws UnexpectedTokenException
78
     */
79
    public static function parse(ParserState $oParserState)
80
    {
81
        $aComments = $oParserState->consumeWhiteSpace();
82
        $oRule = new Rule(
83
            $oParserState->parseIdentifier(!$oParserState->comes("--")),
84
            $oParserState->currentLine(),
85
            $oParserState->currentColumn()
86
        );
87
        $oRule->setComments($aComments);
88
        $oRule->addComments($oParserState->consumeWhiteSpace());
89
        $oParserState->consume(':');
90
        $oValue = Value::parseValue($oParserState, self::listDelimiterForRule($oRule->getRule()));
91
        $oRule->setValue($oValue);
92
        if ($oParserState->getSettings()->bLenientParsing) {
93
            while ($oParserState->comes('\\')) {
94
                $oParserState->consume('\\');
95
                $oRule->addIeHack($oParserState->consume());
96
                $oParserState->consumeWhiteSpace();
97
            }
98
        }
99
        $oParserState->consumeWhiteSpace();
100
        if ($oParserState->comes('!')) {
101
            $oParserState->consume('!');
102
            $oParserState->consumeWhiteSpace();
103
            $oParserState->consume('important');
104
            $oRule->setIsImportant(true);
105
        }
106
        $oParserState->consumeWhiteSpace();
107
        while ($oParserState->comes(';')) {
108
            $oParserState->consume(';');
109
        }
110
 
111
        // Begin Moodle Hack.
112
        // $oParserState->consumeWhiteSpace();
113
        // End Moodle Hack.
114
 
115
        return $oRule;
116
    }
117
 
118
    /**
119
     * @param string $sRule
120
     *
121
     * @return array<int, string>
122
     */
123
    private static function listDelimiterForRule($sRule)
124
    {
125
        if (preg_match('/^font($|-)/', $sRule)) {
126
            return [',', '/', ' '];
127
        }
128
        return [',', ' ', '/'];
129
    }
130
 
131
    /**
132
     * @return int
133
     */
134
    public function getLineNo()
135
    {
136
        return $this->iLineNo;
137
    }
138
 
139
    /**
140
     * @return int
141
     */
142
    public function getColNo()
143
    {
144
        return $this->iColNo;
145
    }
146
 
147
    /**
148
     * @param int $iLine
149
     * @param int $iColumn
150
     *
151
     * @return void
152
     */
153
    public function setPosition($iLine, $iColumn)
154
    {
155
        $this->iColNo = $iColumn;
156
        $this->iLineNo = $iLine;
157
    }
158
 
159
    /**
160
     * @param string $sRule
161
     *
162
     * @return void
163
     */
164
    public function setRule($sRule)
165
    {
166
        $this->sRule = $sRule;
167
    }
168
 
169
    /**
170
     * @return string
171
     */
172
    public function getRule()
173
    {
174
        return $this->sRule;
175
    }
176
 
177
    /**
178
     * @return RuleValueList|string|null
179
     */
180
    public function getValue()
181
    {
182
        return $this->mValue;
183
    }
184
 
185
    /**
186
     * @param RuleValueList|string|null $mValue
187
     *
188
     * @return void
189
     */
190
    public function setValue($mValue)
191
    {
192
        $this->mValue = $mValue;
193
    }
194
 
195
    /**
196
     * @param array<array-key, array<array-key, RuleValueList>> $aSpaceSeparatedValues
197
     *
198
     * @return RuleValueList
199
     *
200
     * @deprecated will be removed in version 9.0
201
     *             Old-Style 2-dimensional array given. Retained for (some) backwards-compatibility.
202
     *             Use `setValue()` instead and wrap the value inside a RuleValueList if necessary.
203
     */
204
    public function setValues(array $aSpaceSeparatedValues)
205
    {
206
        $oSpaceSeparatedList = null;
207
        if (count($aSpaceSeparatedValues) > 1) {
208
            $oSpaceSeparatedList = new RuleValueList(' ', $this->iLineNo);
209
        }
210
        foreach ($aSpaceSeparatedValues as $aCommaSeparatedValues) {
211
            $oCommaSeparatedList = null;
212
            if (count($aCommaSeparatedValues) > 1) {
213
                $oCommaSeparatedList = new RuleValueList(',', $this->iLineNo);
214
            }
215
            foreach ($aCommaSeparatedValues as $mValue) {
216
                if (!$oSpaceSeparatedList && !$oCommaSeparatedList) {
217
                    $this->mValue = $mValue;
218
                    return $mValue;
219
                }
220
                if ($oCommaSeparatedList) {
221
                    $oCommaSeparatedList->addListComponent($mValue);
222
                } else {
223
                    $oSpaceSeparatedList->addListComponent($mValue);
224
                }
225
            }
226
            if (!$oSpaceSeparatedList) {
227
                $this->mValue = $oCommaSeparatedList;
228
                return $oCommaSeparatedList;
229
            } else {
230
                $oSpaceSeparatedList->addListComponent($oCommaSeparatedList);
231
            }
232
        }
233
        $this->mValue = $oSpaceSeparatedList;
234
        return $oSpaceSeparatedList;
235
    }
236
 
237
    /**
238
     * @return array<int, array<int, RuleValueList>>
239
     *
240
     * @deprecated will be removed in version 9.0
241
     *             Old-Style 2-dimensional array returned. Retained for (some) backwards-compatibility.
242
     *             Use `getValue()` instead and check for the existence of a (nested set of) ValueList object(s).
243
     */
244
    public function getValues()
245
    {
246
        if (!$this->mValue instanceof RuleValueList) {
247
            return [[$this->mValue]];
248
        }
249
        if ($this->mValue->getListSeparator() === ',') {
250
            return [$this->mValue->getListComponents()];
251
        }
252
        $aResult = [];
253
        foreach ($this->mValue->getListComponents() as $mValue) {
254
            if (!$mValue instanceof RuleValueList || $mValue->getListSeparator() !== ',') {
255
                $aResult[] = [$mValue];
256
                continue;
257
            }
258
            if ($this->mValue->getListSeparator() === ' ' || count($aResult) === 0) {
259
                $aResult[] = [];
260
            }
261
            foreach ($mValue->getListComponents() as $mValue) {
262
                $aResult[count($aResult) - 1][] = $mValue;
263
            }
264
        }
265
        return $aResult;
266
    }
267
 
268
    /**
269
     * Adds a value to the existing value. Value will be appended if a `RuleValueList` exists of the given type.
270
     * Otherwise, the existing value will be wrapped by one.
271
     *
272
     * @param RuleValueList|array<int, RuleValueList> $mValue
273
     * @param string $sType
274
     *
275
     * @return void
276
     */
277
    public function addValue($mValue, $sType = ' ')
278
    {
279
        if (!is_array($mValue)) {
280
            $mValue = [$mValue];
281
        }
282
        if (!$this->mValue instanceof RuleValueList || $this->mValue->getListSeparator() !== $sType) {
283
            $mCurrentValue = $this->mValue;
284
            $this->mValue = new RuleValueList($sType, $this->iLineNo);
285
            if ($mCurrentValue) {
286
                $this->mValue->addListComponent($mCurrentValue);
287
            }
288
        }
289
        foreach ($mValue as $mValueItem) {
290
            $this->mValue->addListComponent($mValueItem);
291
        }
292
    }
293
 
294
    /**
295
     * @param int $iModifier
296
     *
297
     * @return void
298
     */
299
    public function addIeHack($iModifier)
300
    {
301
        $this->aIeHack[] = $iModifier;
302
    }
303
 
304
    /**
305
     * @param array<int, int> $aModifiers
306
     *
307
     * @return void
308
     */
309
    public function setIeHack(array $aModifiers)
310
    {
311
        $this->aIeHack = $aModifiers;
312
    }
313
 
314
    /**
315
     * @return array<int, int>
316
     */
317
    public function getIeHack()
318
    {
319
        return $this->aIeHack;
320
    }
321
 
322
    /**
323
     * @param bool $bIsImportant
324
     *
325
     * @return void
326
     */
327
    public function setIsImportant($bIsImportant)
328
    {
329
        $this->bIsImportant = $bIsImportant;
330
    }
331
 
332
    /**
333
     * @return bool
334
     */
335
    public function getIsImportant()
336
    {
337
        return $this->bIsImportant;
338
    }
339
 
340
    /**
341
     * @return string
342
     */
343
    public function __toString()
344
    {
345
        return $this->render(new OutputFormat());
346
    }
347
 
348
    /**
349
     * @param OutputFormat|null $oOutputFormat
350
     *
351
     * @return string
352
     */
353
    public function render($oOutputFormat)
354
    {
355
        $sResult = "{$oOutputFormat->comments($this)}{$this->sRule}:{$oOutputFormat->spaceAfterRuleName()}";
356
        if ($this->mValue instanceof Value) { // Can also be a ValueList
357
            $sResult .= $this->mValue->render($oOutputFormat);
358
        } else {
359
            $sResult .= $this->mValue;
360
        }
361
        if (!empty($this->aIeHack)) {
362
            $sResult .= ' \\' . implode('\\', $this->aIeHack);
363
        }
364
        if ($this->bIsImportant) {
365
            $sResult .= ' !important';
366
        }
367
        $sResult .= ';';
368
        return $sResult;
369
    }
370
 
371
    /**
372
     * @param array<array-key, Comment> $aComments
373
     *
374
     * @return void
375
     */
376
    public function addComments(array $aComments)
377
    {
378
        $this->aComments = array_merge($this->aComments, $aComments);
379
    }
380
 
381
    /**
382
     * @return array<array-key, Comment>
383
     */
384
    public function getComments()
385
    {
386
        return $this->aComments;
387
    }
388
 
389
    /**
390
     * @param array<array-key, Comment> $aComments
391
     *
392
     * @return void
393
     */
394
    public function setComments(array $aComments)
395
    {
396
        $this->aComments = $aComments;
397
    }
398
}