@acemir/cssom 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/CSSOM.js +485 -70
- package/lib/CSSImportRule.js +55 -4
- package/lib/CSSLayerBlockRule.js +2 -12
- package/lib/CSSLayerStatementRule.js +32 -0
- package/lib/CSSStyleDeclaration.js +41 -4
- package/lib/CSSStyleSheet.js +4 -1
- package/lib/clone.js +18 -1
- package/lib/index.js +1 -0
- package/lib/parse.js +344 -50
- package/package.json +1 -1
package/lib/CSSImportRule.js
CHANGED
|
@@ -16,6 +16,8 @@ CSSOM.CSSImportRule = function CSSImportRule() {
|
|
|
16
16
|
CSSOM.CSSRule.call(this);
|
|
17
17
|
this.href = "";
|
|
18
18
|
this.media = new CSSOM.MediaList();
|
|
19
|
+
this.layerName = null;
|
|
20
|
+
this.supportsText = null;
|
|
19
21
|
this.styleSheet = new CSSOM.CSSStyleSheet();
|
|
20
22
|
};
|
|
21
23
|
|
|
@@ -26,7 +28,7 @@ CSSOM.CSSImportRule.prototype.type = 3;
|
|
|
26
28
|
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
27
29
|
get: function() {
|
|
28
30
|
var mediaText = this.media.mediaText;
|
|
29
|
-
return "@import url(" + this.href + ")" + (mediaText ? " " + mediaText : "") + ";";
|
|
31
|
+
return "@import url(" + this.href + ")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
30
32
|
},
|
|
31
33
|
set: function(cssText) {
|
|
32
34
|
var i = 0;
|
|
@@ -42,6 +44,12 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
42
44
|
|
|
43
45
|
var buffer = '';
|
|
44
46
|
var index;
|
|
47
|
+
|
|
48
|
+
var layerRegExp = /layer\(([^)]*)\)/;
|
|
49
|
+
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)$/;
|
|
50
|
+
var supportsRegExp = /supports\(([^)]+)\)/;
|
|
51
|
+
var doubleOrMoreSpacesRegExp = /\s{2,}/g;
|
|
52
|
+
|
|
45
53
|
for (var character; (character = cssText.charAt(i)); i++) {
|
|
46
54
|
|
|
47
55
|
switch (character) {
|
|
@@ -66,6 +74,9 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
66
74
|
break;
|
|
67
75
|
|
|
68
76
|
case 'u':
|
|
77
|
+
if (state === 'media') {
|
|
78
|
+
buffer += character;
|
|
79
|
+
}
|
|
69
80
|
if (state === 'url' && cssText.indexOf('url(', i) === i) {
|
|
70
81
|
index = cssText.indexOf(')', i + 1);
|
|
71
82
|
if (index === -1) {
|
|
@@ -85,7 +96,7 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
85
96
|
break;
|
|
86
97
|
|
|
87
98
|
case '"':
|
|
88
|
-
if (state === 'url') {
|
|
99
|
+
if (state === 'after-import' || state === 'url') {
|
|
89
100
|
index = cssText.indexOf('"', i + 1);
|
|
90
101
|
if (!index) {
|
|
91
102
|
throw i + ": '\"' not found";
|
|
@@ -97,7 +108,7 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
97
108
|
break;
|
|
98
109
|
|
|
99
110
|
case "'":
|
|
100
|
-
if (state === 'url') {
|
|
111
|
+
if (state === 'after-import' || state === 'url') {
|
|
101
112
|
index = cssText.indexOf("'", i + 1);
|
|
102
113
|
if (!index) {
|
|
103
114
|
throw i + ': "\'" not found';
|
|
@@ -111,7 +122,47 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
111
122
|
case ';':
|
|
112
123
|
if (state === 'media') {
|
|
113
124
|
if (buffer) {
|
|
114
|
-
|
|
125
|
+
var bufferTrimmed = buffer.trim();
|
|
126
|
+
|
|
127
|
+
if (bufferTrimmed.indexOf('layer') === 0) {
|
|
128
|
+
var layerMatch = bufferTrimmed.match(layerRegExp);
|
|
129
|
+
|
|
130
|
+
if (layerMatch) {
|
|
131
|
+
var layerName = layerMatch[1].trim();
|
|
132
|
+
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
|
|
133
|
+
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
134
|
+
.trim();
|
|
135
|
+
|
|
136
|
+
if (layerName.match(layerRuleNameRegExp) !== null) {
|
|
137
|
+
this.layerName = layerMatch[1].trim();
|
|
138
|
+
} else {
|
|
139
|
+
// REVIEW: In the browser, an empty layer() is not processed as a unamed layer
|
|
140
|
+
// and treats the rest of the string as mediaText, ignoring the parse of supports()
|
|
141
|
+
if (bufferTrimmed) {
|
|
142
|
+
this.media.mediaText = bufferTrimmed;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
} else {
|
|
147
|
+
this.layerName = "";
|
|
148
|
+
bufferTrimmed = bufferTrimmed.substring('layer'.length).trim()
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
var supportsMatch = bufferTrimmed.match(supportsRegExp);
|
|
153
|
+
|
|
154
|
+
if (supportsMatch && supportsMatch.index === 0) {
|
|
155
|
+
// REVIEW: In the browser, an empty supports() invalidates and ignores the entire @import rule
|
|
156
|
+
this.supportsText = supportsMatch[1].trim();
|
|
157
|
+
bufferTrimmed = bufferTrimmed.replace(supportsRegExp, '')
|
|
158
|
+
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
159
|
+
.trim();
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// REVIEW: In the browser, any invalid media is replaced with 'not all'
|
|
163
|
+
if (bufferTrimmed) {
|
|
164
|
+
this.media.mediaText = bufferTrimmed;
|
|
165
|
+
}
|
|
115
166
|
}
|
|
116
167
|
}
|
|
117
168
|
break;
|
package/lib/CSSLayerBlockRule.js
CHANGED
|
@@ -11,7 +11,7 @@ var CSSOM = {
|
|
|
11
11
|
*/
|
|
12
12
|
CSSOM.CSSLayerBlockRule = function CSSLayerBlockRule() {
|
|
13
13
|
CSSOM.CSSGroupingRule.call(this);
|
|
14
|
-
this.
|
|
14
|
+
this.name = "";
|
|
15
15
|
this.cssRules = [];
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -20,23 +20,13 @@ CSSOM.CSSLayerBlockRule.prototype.constructor = CSSOM.CSSLayerBlockRule;
|
|
|
20
20
|
CSSOM.CSSLayerBlockRule.prototype.type = 18;
|
|
21
21
|
|
|
22
22
|
Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
|
|
23
|
-
layerNameText: {
|
|
24
|
-
get: function () {
|
|
25
|
-
return this.layerName;
|
|
26
|
-
},
|
|
27
|
-
set: function (value) {
|
|
28
|
-
this.layerName = value;
|
|
29
|
-
},
|
|
30
|
-
configurable: true,
|
|
31
|
-
enumerable: true,
|
|
32
|
-
},
|
|
33
23
|
cssText: {
|
|
34
24
|
get: function () {
|
|
35
25
|
var cssTexts = [];
|
|
36
26
|
for (var i = 0, length = this.cssRules.length; i < length; i++) {
|
|
37
27
|
cssTexts.push(this.cssRules[i].cssText);
|
|
38
28
|
}
|
|
39
|
-
return "@layer " + this.
|
|
29
|
+
return "@layer " + this.name + (this.name && " ") + "{" + cssTexts.join("") + "}";
|
|
40
30
|
},
|
|
41
31
|
configurable: true,
|
|
42
32
|
enumerable: true,
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
//.CommonJS
|
|
2
|
+
var CSSOM = {
|
|
3
|
+
CSSRule: require("./CSSRule").CSSRule,
|
|
4
|
+
};
|
|
5
|
+
///CommonJS
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @constructor
|
|
9
|
+
* @see https://drafts.csswg.org/css-cascade-5/#csslayerstatementrule
|
|
10
|
+
*/
|
|
11
|
+
CSSOM.CSSLayerStatementRule = function CSSLayerStatementRule() {
|
|
12
|
+
CSSOM.CSSRule.call(this);
|
|
13
|
+
this.nameList = [];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
CSSOM.CSSLayerStatementRule.prototype = new CSSOM.CSSRule();
|
|
17
|
+
CSSOM.CSSLayerStatementRule.prototype.constructor = CSSOM.CSSLayerStatementRule;
|
|
18
|
+
CSSOM.CSSLayerStatementRule.prototype.type = 0;
|
|
19
|
+
|
|
20
|
+
Object.defineProperties(CSSOM.CSSLayerStatementRule.prototype, {
|
|
21
|
+
cssText: {
|
|
22
|
+
get: function () {
|
|
23
|
+
return "@layer " + this.nameList.join(", ") + ";";
|
|
24
|
+
},
|
|
25
|
+
configurable: true,
|
|
26
|
+
enumerable: true,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
//.CommonJS
|
|
31
|
+
exports.CSSLayerStatementRule = CSSOM.CSSLayerStatementRule;
|
|
32
|
+
///CommonJS
|
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
var CSSOM = {};
|
|
3
3
|
///CommonJS
|
|
4
4
|
|
|
5
|
+
// NOTE: Check viability to add a validation for css values or use a dependency like csstree-validator
|
|
6
|
+
/**
|
|
7
|
+
* Regular expression to detect invalid characters in the value portion of a CSS style declaration.
|
|
8
|
+
*
|
|
9
|
+
* This regex matches a colon (:) that is not inside parentheses and not inside single or double quotes.
|
|
10
|
+
* It is used to ensure that the value part of a CSS property does not contain unexpected colons,
|
|
11
|
+
* which would indicate a malformed declaration (e.g., "color: foo:bar;" is invalid).
|
|
12
|
+
*
|
|
13
|
+
* The negative lookahead `(?![^(]*\))` ensures that the colon is not followed by a closing
|
|
14
|
+
* parenthesis without encountering an opening parenthesis, effectively ignoring colons inside
|
|
15
|
+
* function-like values (e.g., `url(data:image/png;base64,...)`).
|
|
16
|
+
*
|
|
17
|
+
* The lookahead `(?=(?:[^'"]|'[^']*'|"[^"]*")*$)` ensures that the colon is not inside single or double quotes,
|
|
18
|
+
* allowing colons within quoted strings (e.g., `content: ":";` or `background: url("foo:bar.png");`).
|
|
19
|
+
*
|
|
20
|
+
* Example:
|
|
21
|
+
* "color: red;" // valid, does not match
|
|
22
|
+
* "background: url(data:image/png;base64,...);" // valid, does not match
|
|
23
|
+
* "content: ':';" // valid, does not match
|
|
24
|
+
* "color: foo:bar;" // invalid, matches
|
|
25
|
+
*/
|
|
26
|
+
var basicStylePropertyValueValidationRegExp = /:(?![^(]*\))(?=(?:[^'"]|'[^']*'|"[^"]*")*$)/;
|
|
5
27
|
|
|
6
28
|
/**
|
|
7
29
|
* @constructor
|
|
@@ -38,21 +60,36 @@ CSSOM.CSSStyleDeclaration.prototype = {
|
|
|
38
60
|
* @param {string} [priority=null] "important" or null
|
|
39
61
|
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
|
|
40
62
|
*/
|
|
41
|
-
setProperty: function(name, value, priority)
|
|
42
|
-
|
|
63
|
+
setProperty: function(name, value, priority, parseErrorHandler)
|
|
64
|
+
{
|
|
65
|
+
// NOTE: Check viability to add a validation for css values or use a dependency like csstree-validator
|
|
66
|
+
if (basicStylePropertyValueValidationRegExp.test(value)) {
|
|
67
|
+
parseErrorHandler && parseErrorHandler('Invalid CSSStyleDeclaration property value');
|
|
68
|
+
} else if (this[name]) {
|
|
43
69
|
// Property already exist. Overwrite it.
|
|
44
70
|
var index = Array.prototype.indexOf.call(this, name);
|
|
45
71
|
if (index < 0) {
|
|
46
72
|
this[this.length] = name;
|
|
47
73
|
this.length++;
|
|
48
74
|
}
|
|
75
|
+
|
|
76
|
+
// If the priority value of the incoming property is "important",
|
|
77
|
+
// or the value of the existing property is not "important",
|
|
78
|
+
// then remove the existing property and rewrite it.
|
|
79
|
+
if (priority || !this._importants[name]) {
|
|
80
|
+
this.removeProperty(name);
|
|
81
|
+
this[this.length] = name;
|
|
82
|
+
this.length++;
|
|
83
|
+
this[name] = value + '';
|
|
84
|
+
this._importants[name] = priority;
|
|
85
|
+
}
|
|
49
86
|
} else {
|
|
50
87
|
// New property.
|
|
51
88
|
this[this.length] = name;
|
|
52
89
|
this.length++;
|
|
90
|
+
this[name] = value + '';
|
|
91
|
+
this._importants[name] = priority;
|
|
53
92
|
}
|
|
54
|
-
this[name] = value + "";
|
|
55
|
-
this._importants[name] = priority;
|
|
56
93
|
},
|
|
57
94
|
|
|
58
95
|
/**
|
package/lib/CSSStyleSheet.js
CHANGED
|
@@ -32,11 +32,14 @@ CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
|
32
32
|
* -> "img{border:none;}body{margin:0;}"
|
|
33
33
|
*
|
|
34
34
|
* @param {string} rule
|
|
35
|
-
* @param {number} index
|
|
35
|
+
* @param {number} [index=0]
|
|
36
36
|
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
|
|
37
37
|
* @return {number} The index within the style sheet's rule collection of the newly inserted rule.
|
|
38
38
|
*/
|
|
39
39
|
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
40
|
+
if (index === void 0) {
|
|
41
|
+
index = 0;
|
|
42
|
+
}
|
|
40
43
|
if (index < 0 || index > this.cssRules.length) {
|
|
41
44
|
throw new RangeError("INDEX_SIZE_ERR");
|
|
42
45
|
}
|
package/lib/clone.js
CHANGED
|
@@ -12,7 +12,8 @@ var CSSOM = {
|
|
|
12
12
|
CSSStyleDeclaration: require("./CSSStyleDeclaration").CSSStyleDeclaration,
|
|
13
13
|
CSSKeyframeRule: require('./CSSKeyframeRule').CSSKeyframeRule,
|
|
14
14
|
CSSKeyframesRule: require('./CSSKeyframesRule').CSSKeyframesRule,
|
|
15
|
-
CSSLayerBlockRule: require('./CSSLayerBlockRule').CSSLayerBlockRule
|
|
15
|
+
CSSLayerBlockRule: require('./CSSLayerBlockRule').CSSLayerBlockRule,
|
|
16
|
+
CSSLayerStatementRule: require('./CSSLayerStatementRule').CSSLayerStatementRule
|
|
16
17
|
};
|
|
17
18
|
///CommonJS
|
|
18
19
|
|
|
@@ -59,6 +60,10 @@ CSSOM.clone = function clone(stylesheet) {
|
|
|
59
60
|
ruleClone.mediaText = rule.mediaText;
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
if (rule.hasOwnProperty('supportsText')) {
|
|
64
|
+
ruleClone.supports = rule.supports;
|
|
65
|
+
}
|
|
66
|
+
|
|
62
67
|
if (rule.hasOwnProperty('conditionText')) {
|
|
63
68
|
ruleClone.conditionText = rule.conditionText;
|
|
64
69
|
}
|
|
@@ -67,6 +72,18 @@ CSSOM.clone = function clone(stylesheet) {
|
|
|
67
72
|
ruleClone.layerName = rule.layerName;
|
|
68
73
|
}
|
|
69
74
|
|
|
75
|
+
if (rule.hasOwnProperty('href')) {
|
|
76
|
+
ruleClone.href = rule.href;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (rule.hasOwnProperty('name')) {
|
|
80
|
+
ruleClone.name = rule.name;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (rule.hasOwnProperty('nameList')) {
|
|
84
|
+
ruleClone.nameList = rule.nameList;
|
|
85
|
+
}
|
|
86
|
+
|
|
70
87
|
if (rule.hasOwnProperty('cssRules')) {
|
|
71
88
|
ruleClone.cssRules = clone(rule).cssRules;
|
|
72
89
|
}
|
package/lib/index.js
CHANGED
|
@@ -23,5 +23,6 @@ exports.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
|
|
|
23
23
|
exports.CSSValue = require('./CSSValue').CSSValue;
|
|
24
24
|
exports.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
|
|
25
25
|
exports.CSSLayerBlockRule = require('./CSSLayerBlockRule').CSSLayerBlockRule;
|
|
26
|
+
exports.CSSLayerStatementRule = require('./CSSLayerStatementRule').CSSLayerStatementRule;
|
|
26
27
|
exports.parse = require('./parse').parse;
|
|
27
28
|
exports.clone = require('./clone').clone;
|