Skip to content

Commit c53c8b9

Browse files
committed
Added the CSSValueList class and made CSSSlashedValue and CSSFunction subtypes thereof.
Additionally, CSSColor is now a CSSFunction. Also fixed the problem of CSSDocument->getAllValues() not returning values inside slashed value blocks. CSSSize values inside color function arguments now return false when asked CSSSize->isSize(). These changes may pave the way for a complete overhaul of how the generated structure will look like. Instead of using nested arrays to represent a list of values, each CSSRule could have one value object which is either a CSSPrimitiveValue or a (nested) set of CSSValueList objects. This change would not be backwards-compatible but would result in a much cleaner parsed code structure.
1 parent bfb9ea6 commit c53c8b9

File tree

5 files changed

+124
-101
lines changed

5 files changed

+124
-101
lines changed

CSSParser.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
require_once('lib/CSSRuleSet.php');
55
require_once('lib/CSSRule.php');
66
require_once('lib/CSSValue.php');
7+
require_once('lib/CSSValueList.php');
78

89
/**
910
* @package html
@@ -261,7 +262,7 @@ private function parseSingleValue() {
261262
return $oValue;
262263
}
263264

264-
private function parseNumericValue() {
265+
private function parseNumericValue($bForColor = false) {
265266
$sSize = '';
266267
if($this->comes('-')) {
267268
$sSize .= $this->consume('-');
@@ -300,7 +301,7 @@ private function parseNumericValue() {
300301
} else if($this->comes('mm')) {
301302
$sUnit = $this->consume('mm');
302303
}
303-
return new CSSSize($fSize, $sUnit);
304+
return new CSSSize($fSize, $sUnit, $bForColor);
304305
}
305306

306307
private function parseColorValue() {
@@ -311,15 +312,15 @@ private function parseColorValue() {
311312
if(mb_strlen($sValue, $this->sCharset) === 3) {
312313
$sValue = $sValue[0].$sValue[0].$sValue[1].$sValue[1].$sValue[2].$sValue[2];
313314
}
314-
$aColor = array('r' => new CSSSize(intval($sValue[0].$sValue[1], 16)), 'g' => new CSSSize(intval($sValue[2].$sValue[3], 16)), 'b' => new CSSSize(intval($sValue[4].$sValue[5], 16)));
315+
$aColor = array('r' => new CSSSize(intval($sValue[0].$sValue[1], 16), null, true), 'g' => new CSSSize(intval($sValue[2].$sValue[3], 16), null, true), 'b' => new CSSSize(intval($sValue[4].$sValue[5], 16), null, true));
315316
} else {
316317
$sColorMode = $this->parseIdentifier(false);
317318
$this->consumeWhiteSpace();
318319
$this->consume('(');
319320
$iLength = mb_strlen($sColorMode, $this->sCharset);
320321
for($i=0;$i<$iLength;$i++) {
321322
$this->consumeWhiteSpace();
322-
$aColor[$sColorMode[$i]] = $this->parseNumericValue();
323+
$aColor[$sColorMode[$i]] = $this->parseNumericValue(true);
323324
$this->consumeWhiteSpace();
324325
if($i < ($iLength-1)) {
325326
$this->consume(',');

lib/CSSList.php

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,14 +59,18 @@ protected function allValues($oElement, &$aResult, $sSearchString = null, $bSear
5959
} else if($oElement instanceof CSSRule) {
6060
foreach($oElement->getValues() as $aValues) {
6161
foreach($aValues as $mValue) {
62-
$aResult[] = $mValue;
63-
if($bSearchInFunctionArguments && $mValue instanceof CSSFunction) {
64-
foreach($mValue->getArguments() as $mArgument) {
65-
$aResult[] = $mArgument;
66-
}
67-
}
62+
$this->allValues($mValue, $aResult, $sSearchString, $bSearchInFunctionArguments);
63+
}
64+
}
65+
} else if($oElement instanceof CSSValueList) {
66+
if($bSearchInFunctionArguments || !($oElement instanceof CSSFunction)) {
67+
foreach($oElement->getListComponents() as $mComponent) {
68+
$this->allValues($mComponent, $aResult, $sSearchString, $bSearchInFunctionArguments);
6869
}
6970
}
71+
} else {
72+
//Non-List CSSValue or String (CSS identifier)
73+
$aResult[] = $oElement;
7074
}
7175
}
7276

lib/CSSValue.php

Lines changed: 23 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -4,33 +4,47 @@ abstract class CSSValue {
44
public abstract function __toString();
55
}
66

7-
class CSSSize extends CSSValue {
7+
abstract class CSSPrimitiveValue extends CSSValue {
8+
9+
}
10+
11+
class CSSSize extends CSSPrimitiveValue {
812
private $fSize;
913
private $sUnit;
14+
private $bIsColorComponent;
1015

11-
public function __construct($fSize, $sUnit = null) {
16+
public function __construct($fSize, $sUnit = null, $bIsColorComponent = false) {
1217
$this->fSize = floatval($fSize);
1318
$this->sUnit = $sUnit;
19+
$this->bIsColorComponent = $bIsColorComponent;
1420
}
1521

1622
public function setUnit($sUnit) {
17-
$this->sUnit = $sUnit;
23+
$this->sUnit = $sUnit;
1824
}
1925

2026
public function getUnit() {
21-
return $this->sUnit;
27+
return $this->sUnit;
2228
}
2329

2430
public function setSize($fSize) {
25-
$this->fSize = floatval($fSize);
31+
$this->fSize = floatval($fSize);
2632
}
2733

2834
public function getSize() {
29-
return $this->fSize;
35+
return $this->fSize;
3036
}
3137

38+
public function isColorComponent() {
39+
return $this->bIsColorComponent;
40+
}
41+
42+
/**
43+
* Returns whether the number stored in this CSSSize really represents a size (as in a length of something on screen).
44+
* @return false if the unit is degrees, seconds or if the number is a component in a CSSColor object.
45+
*/
3246
public function isSize() {
33-
return $this->sUnit !== 'deg' && $this->sUnit !== 's';
47+
return $this->sUnit !== 'deg' && $this->sUnit !== 's' && !$this->isColorComponent();
3448
}
3549

3650
public function isRelative() {
@@ -48,31 +62,7 @@ public function __toString() {
4862
}
4963
}
5064

51-
class CSSColor extends CSSValue {
52-
private $aColor;
53-
54-
public function __construct($aColor) {
55-
$this->aColor = $aColor;
56-
}
57-
58-
public function setColor($aColor) {
59-
$this->aColor = $aColor;
60-
}
61-
62-
public function getColor() {
63-
return $this->aColor;
64-
}
65-
66-
public function getColorDescription() {
67-
return implode('', array_keys($this->aColor));
68-
}
69-
70-
public function __toString() {
71-
return $this->getColorDescription().'('.implode(', ', $this->aColor).')';
72-
}
73-
}
74-
75-
class CSSString extends CSSValue {
65+
class CSSString extends CSSPrimitiveValue {
7666
private $sString;
7767

7868
public function __construct($sString) {
@@ -94,7 +84,7 @@ public function __toString() {
9484
}
9585
}
9686

97-
class CSSURL extends CSSValue {
87+
class CSSURL extends CSSPrimitiveValue {
9888
private $oURL;
9989

10090
public function __construct(CSSString $oURL) {
@@ -114,55 +104,3 @@ public function __toString() {
114104
}
115105
}
116106

117-
class CSSSlashedValue extends CSSValue {
118-
private $oValue1;
119-
private $oValue2;
120-
121-
public function __construct($oValue1, $oValue2) {
122-
$this->oValue1 = $oValue1;
123-
$this->oValue2 = $oValue2;
124-
}
125-
126-
public function getValue1() {
127-
return $this->oValue1;
128-
}
129-
130-
public function getValue2() {
131-
return $this->oValue2;
132-
}
133-
134-
public function __toString() {
135-
$oValue1 = $this->oValue1;
136-
$oValue2 = $this->oValue2;
137-
if($oValue1 instanceof CSSValue) {
138-
$oValue1 = $oValue1->__toString();
139-
}
140-
if($oValue2 instanceof CSSValue) {
141-
$oValue2 = $oValue2->__toString();
142-
}
143-
return "$oValue1/$oValue2";
144-
}
145-
}
146-
147-
class CSSFunction extends CSSValue {
148-
private $sName;
149-
private $aArguments;
150-
151-
public function __construct($sName, $aArguments) {
152-
$this->sName = $sName;
153-
$this->aArguments = $aArguments;
154-
}
155-
156-
public function getName() {
157-
return $this->sName;
158-
}
159-
160-
public function getArguments() {
161-
return $this->aArguments;
162-
}
163-
164-
public function __toString() {
165-
$aArguments = implode(',', $this->aArguments);
166-
return "{$this->sName}({$aArguments})";
167-
}
168-
}

lib/CSSValueList.php

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
<?php
2+
3+
abstract class CSSValueList extends CSSValue {
4+
protected $aComponents;
5+
protected $sSeparator;
6+
7+
public function __construct($aComponents = array(), $sSeparator = ',') {
8+
$this->aComponents = $aComponents;
9+
$this->sSeparator = $sSeparator;
10+
}
11+
12+
public function getListComponents() {
13+
return $this->aComponents;
14+
}
15+
16+
public function getListSeparator() {
17+
return $this->sSeparator;
18+
}
19+
20+
function __toString() {
21+
return implode($this->sSeparator, $this->aComponents);
22+
}
23+
}
24+
25+
class CSSSlashedValue extends CSSValueList {
26+
public function __construct($oValue1, $oValue2) {
27+
parent::__construct(array($oValue1, $oValue2), '/');
28+
}
29+
30+
public function getValue1() {
31+
return $this->aComponents[0];
32+
}
33+
34+
public function getValue2() {
35+
return $this->aComponents[1];
36+
}
37+
}
38+
39+
class CSSFunction extends CSSValueList {
40+
private $sName;
41+
public function __construct($sName, $aArguments) {
42+
$this->sName = $sName;
43+
parent::__construct($aArguments);
44+
}
45+
46+
public function getName() {
47+
return $this->sName;
48+
}
49+
50+
public function getArguments() {
51+
return $this->aComponents;
52+
}
53+
54+
public function __toString() {
55+
$aArguments = parent::__toString();
56+
return "{$this->sName}({$aArguments})";
57+
}
58+
}
59+
60+
class CSSColor extends CSSFunction {
61+
public function __construct($aColor) {
62+
parent::__construct(implode('', array_keys($aColor)), $aColor);
63+
}
64+
65+
public function getColor() {
66+
return $this->aComponents;
67+
}
68+
69+
public function getColorDescription() {
70+
return $this->getName();
71+
}
72+
}
73+
74+

tests/CSSParserTests.php

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,18 +49,18 @@ function testColorParsing() {
4949
$this->assertSame('red', $aValues[0][0]);
5050
$aColorRule = $oRuleSet->getRules('background-');
5151
$aValues = $aColorRule['background-color']->getValues();
52-
$this->assertEquals(array('r' => new CSSSize(35.0), 'g' => new CSSSize(35.0), 'b' => new CSSSize(35.0)), $aValues[0][0]->getColor());
52+
$this->assertEquals(array('r' => new CSSSize(35.0, null, true), 'g' => new CSSSize(35.0, null, true), 'b' => new CSSSize(35.0, null, true)), $aValues[0][0]->getColor());
5353
$aColorRule = $oRuleSet->getRules('border-color');
5454
$aValues = $aColorRule['border-color']->getValues();
55-
$this->assertEquals(array('r' => new CSSSize(10.0), 'g' => new CSSSize(100.0), 'b' => new CSSSize(230.0), 'a' => new CSSSize(0.3)), $aValues[0][0]->getColor());
55+
$this->assertEquals(array('r' => new CSSSize(10.0, null, true), 'g' => new CSSSize(100.0, null, true), 'b' => new CSSSize(230.0, null, true), 'a' => new CSSSize(0.3, null, true)), $aValues[0][0]->getColor());
5656
$aColorRule = $oRuleSet->getRules('outline-color');
5757
$aValues = $aColorRule['outline-color']->getValues();
58-
$this->assertEquals(array('r' => new CSSSize(34.0), 'g' => new CSSSize(34.0), 'b' => new CSSSize(34.0)), $aValues[0][0]->getColor());
58+
$this->assertEquals(array('r' => new CSSSize(34.0, null, true), 'g' => new CSSSize(34.0, null, true), 'b' => new CSSSize(34.0, null, true)), $aValues[0][0]->getColor());
5959
}
6060
}
6161
foreach($oDoc->getAllValues('background-') as $oColor) {
6262
if($oColor->getColorDescription() === 'hsl') {
63-
$this->assertEquals(array('h' => new CSSSize(220.0), 's' => new CSSSize(10.0), 'l' => new CSSSize(220.0)), $oColor->getColor());
63+
$this->assertEquals(array('h' => new CSSSize(220.0, null, true), 's' => new CSSSize(10.0, null, true), 'l' => new CSSSize(220.0, null, true)), $oColor->getColor());
6464
}
6565
}
6666
foreach($oDoc->getAllValues('color') as $sColor) {
@@ -166,11 +166,17 @@ function testManipulation() {
166166
function testSlashedValues() {
167167
$oDoc = $this->parsedStructureForFile('slashed');
168168
$this->assertSame('.test {font: 12px/1.5;border-radius: 5px 10px 5px 10px/10px 5px 10px 5px;}', $oDoc->__toString());
169+
foreach($oDoc->getAllValues(null) as $mValue) {
170+
if($mValue instanceof CSSSize && $mValue->isSize() && !$mValue->isRelative()) {
171+
$mValue->setSize($mValue->getSize()*3);
172+
}
173+
}
174+
$this->assertSame('.test {font: 36px/1.5;border-radius: 15px 30px 15px 30px/30px 15px 30px 15px;}', $oDoc->__toString());
169175
}
170176

171177
function testFunctionSyntax() {
172178
$oDoc = $this->parsedStructureForFile('functions');
173-
$sExpected = 'div.main {background-image: linear-gradient(rgb(0, 0, 0),rgb(255, 255, 255));}.collapser::before, .collapser::-moz-before, .collapser::-webkit-before {content: "»";font-size: 1.2em;margin-right: 0.2em;-moz-transition-property: -moz-transform;-moz-transition-duration: 0.2s;-moz-transform-origin: center 60%;}.collapser.expanded::before, .collapser.expanded::-moz-before, .collapser.expanded::-webkit-before {-moz-transform: rotate(90deg);}.collapser + * {height: 0;overflow: hidden;-moz-transition-property: height;-moz-transition-duration: 0.3s;}.collapser.expanded + * {height: auto;}';
179+
$sExpected = 'div.main {background-image: linear-gradient(rgb(0,0,0),rgb(255,255,255));}.collapser::before, .collapser::-moz-before, .collapser::-webkit-before {content: "»";font-size: 1.2em;margin-right: 0.2em;-moz-transition-property: -moz-transform;-moz-transition-duration: 0.2s;-moz-transform-origin: center 60%;}.collapser.expanded::before, .collapser.expanded::-moz-before, .collapser.expanded::-webkit-before {-moz-transform: rotate(90deg);}.collapser + * {height: 0;overflow: hidden;-moz-transition-property: height;-moz-transition-duration: 0.3s;}.collapser.expanded + * {height: auto;}';
174180
$this->assertSame($sExpected, $oDoc->__toString());
175181

176182
foreach($oDoc->getAllValues(null, true) as $mValue) {
@@ -182,7 +188,7 @@ function testFunctionSyntax() {
182188
$this->assertSame($sExpected, $oDoc->__toString());
183189

184190
foreach($oDoc->getAllValues(null, true) as $mValue) {
185-
if($mValue instanceof CSSSize && !$mValue->isRelative()) {
191+
if($mValue instanceof CSSSize && !$mValue->isRelative() && !$mValue->isColorComponent()) {
186192
$mValue->setSize($mValue->getSize()*2);
187193
}
188194
}

0 commit comments

Comments
 (0)