Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

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