@acemir/cssom 0.9.0
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/LICENSE.txt +20 -0
- package/README.mdown +64 -0
- package/build/CSSOM.js +2283 -0
- package/lib/CSSConditionRule.js +25 -0
- package/lib/CSSContainerRule.js +50 -0
- package/lib/CSSDocumentRule.js +39 -0
- package/lib/CSSFontFaceRule.js +36 -0
- package/lib/CSSGroupingRule.js +69 -0
- package/lib/CSSHostRule.js +37 -0
- package/lib/CSSImportRule.js +132 -0
- package/lib/CSSKeyframeRule.js +37 -0
- package/lib/CSSKeyframesRule.js +39 -0
- package/lib/CSSLayerBlockRule.js +48 -0
- package/lib/CSSMediaRule.js +53 -0
- package/lib/CSSNestedDeclarations.js +31 -0
- package/lib/CSSOM.js +3 -0
- package/lib/CSSRule.js +42 -0
- package/lib/CSSStartingStyleRule.js +37 -0
- package/lib/CSSStyleDeclaration.js +148 -0
- package/lib/CSSStyleRule.js +200 -0
- package/lib/CSSStyleSheet.js +88 -0
- package/lib/CSSSupportsRule.js +36 -0
- package/lib/CSSValue.js +43 -0
- package/lib/CSSValueExpression.js +344 -0
- package/lib/MatcherList.js +62 -0
- package/lib/MediaList.js +61 -0
- package/lib/StyleSheet.js +17 -0
- package/lib/clone.js +81 -0
- package/lib/index.js +27 -0
- package/lib/parse.js +783 -0
- package/package.json +30 -0
package/build/CSSOM.js
ADDED
|
@@ -0,0 +1,2283 @@
|
|
|
1
|
+
var CSSOM = {};
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @constructor
|
|
6
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration
|
|
7
|
+
*/
|
|
8
|
+
CSSOM.CSSStyleDeclaration = function CSSStyleDeclaration(){
|
|
9
|
+
this.length = 0;
|
|
10
|
+
this.parentRule = null;
|
|
11
|
+
|
|
12
|
+
// NON-STANDARD
|
|
13
|
+
this._importants = {};
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
CSSOM.CSSStyleDeclaration.prototype = {
|
|
18
|
+
|
|
19
|
+
constructor: CSSOM.CSSStyleDeclaration,
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
* @param {string} name
|
|
24
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-getPropertyValue
|
|
25
|
+
* @return {string} the value of the property if it has been explicitly set for this declaration block.
|
|
26
|
+
* Returns the empty string if the property has not been set.
|
|
27
|
+
*/
|
|
28
|
+
getPropertyValue: function(name) {
|
|
29
|
+
return this[name] || "";
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {string} name
|
|
35
|
+
* @param {string} value
|
|
36
|
+
* @param {string} [priority=null] "important" or null
|
|
37
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
|
|
38
|
+
*/
|
|
39
|
+
setProperty: function(name, value, priority) {
|
|
40
|
+
if (this[name]) {
|
|
41
|
+
// Property already exist. Overwrite it.
|
|
42
|
+
var index = Array.prototype.indexOf.call(this, name);
|
|
43
|
+
if (index < 0) {
|
|
44
|
+
this[this.length] = name;
|
|
45
|
+
this.length++;
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
// New property.
|
|
49
|
+
this[this.length] = name;
|
|
50
|
+
this.length++;
|
|
51
|
+
}
|
|
52
|
+
this[name] = value + "";
|
|
53
|
+
this._importants[name] = priority;
|
|
54
|
+
},
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
*
|
|
58
|
+
* @param {string} name
|
|
59
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-removeProperty
|
|
60
|
+
* @return {string} the value of the property if it has been explicitly set for this declaration block.
|
|
61
|
+
* Returns the empty string if the property has not been set or the property name does not correspond to a known CSS property.
|
|
62
|
+
*/
|
|
63
|
+
removeProperty: function(name) {
|
|
64
|
+
if (!(name in this)) {
|
|
65
|
+
return "";
|
|
66
|
+
}
|
|
67
|
+
var index = Array.prototype.indexOf.call(this, name);
|
|
68
|
+
if (index < 0) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
var prevValue = this[name];
|
|
72
|
+
this[name] = "";
|
|
73
|
+
|
|
74
|
+
// That's what WebKit and Opera do
|
|
75
|
+
Array.prototype.splice.call(this, index, 1);
|
|
76
|
+
|
|
77
|
+
// That's what Firefox does
|
|
78
|
+
//this[index] = ""
|
|
79
|
+
|
|
80
|
+
return prevValue;
|
|
81
|
+
},
|
|
82
|
+
|
|
83
|
+
getPropertyCSSValue: function() {
|
|
84
|
+
//FIXME
|
|
85
|
+
},
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
*
|
|
89
|
+
* @param {String} name
|
|
90
|
+
*/
|
|
91
|
+
getPropertyPriority: function(name) {
|
|
92
|
+
return this._importants[name] || "";
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* element.style.overflow = "auto"
|
|
98
|
+
* element.style.getPropertyShorthand("overflow-x")
|
|
99
|
+
* -> "overflow"
|
|
100
|
+
*/
|
|
101
|
+
getPropertyShorthand: function() {
|
|
102
|
+
//FIXME
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
isPropertyImplicit: function() {
|
|
106
|
+
//FIXME
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
// Doesn't work in IE < 9
|
|
110
|
+
get cssText(){
|
|
111
|
+
var properties = [];
|
|
112
|
+
for (var i=0, length=this.length; i < length; ++i) {
|
|
113
|
+
var name = this[i];
|
|
114
|
+
var value = this.getPropertyValue(name);
|
|
115
|
+
var priority = this.getPropertyPriority(name);
|
|
116
|
+
if (priority) {
|
|
117
|
+
priority = " !" + priority;
|
|
118
|
+
}
|
|
119
|
+
properties[i] = name + ": " + value + priority + ";";
|
|
120
|
+
}
|
|
121
|
+
return properties.join(" ");
|
|
122
|
+
},
|
|
123
|
+
|
|
124
|
+
set cssText(text){
|
|
125
|
+
var i, name;
|
|
126
|
+
for (i = this.length; i--;) {
|
|
127
|
+
name = this[i];
|
|
128
|
+
this[name] = "";
|
|
129
|
+
}
|
|
130
|
+
Array.prototype.splice.call(this, 0, this.length);
|
|
131
|
+
this._importants = {};
|
|
132
|
+
|
|
133
|
+
var dummyRule = CSSOM.parse('#bogus{' + text + '}').cssRules[0].style;
|
|
134
|
+
var length = dummyRule.length;
|
|
135
|
+
for (i = 0; i < length; ++i) {
|
|
136
|
+
name = dummyRule[i];
|
|
137
|
+
this.setProperty(dummyRule[i], dummyRule.getPropertyValue(name), dummyRule.getPropertyPriority(name));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* @constructor
|
|
146
|
+
* @see http://dev.w3.org/csswg/cssom/#the-cssrule-interface
|
|
147
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSRule
|
|
148
|
+
*/
|
|
149
|
+
CSSOM.CSSRule = function CSSRule() {
|
|
150
|
+
this.parentRule = null;
|
|
151
|
+
this.parentStyleSheet = null;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
|
|
155
|
+
CSSOM.CSSRule.STYLE_RULE = 1;
|
|
156
|
+
CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
|
|
157
|
+
CSSOM.CSSRule.IMPORT_RULE = 3;
|
|
158
|
+
CSSOM.CSSRule.MEDIA_RULE = 4;
|
|
159
|
+
CSSOM.CSSRule.FONT_FACE_RULE = 5;
|
|
160
|
+
CSSOM.CSSRule.PAGE_RULE = 6;
|
|
161
|
+
CSSOM.CSSRule.KEYFRAMES_RULE = 7;
|
|
162
|
+
CSSOM.CSSRule.KEYFRAME_RULE = 8;
|
|
163
|
+
CSSOM.CSSRule.MARGIN_RULE = 9;
|
|
164
|
+
CSSOM.CSSRule.NAMESPACE_RULE = 10;
|
|
165
|
+
CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
|
|
166
|
+
CSSOM.CSSRule.SUPPORTS_RULE = 12;
|
|
167
|
+
CSSOM.CSSRule.DOCUMENT_RULE = 13;
|
|
168
|
+
CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
|
|
169
|
+
CSSOM.CSSRule.VIEWPORT_RULE = 15;
|
|
170
|
+
CSSOM.CSSRule.REGION_STYLE_RULE = 16;
|
|
171
|
+
CSSOM.CSSRule.CONTAINER_RULE = 17;
|
|
172
|
+
CSSOM.CSSRule.LAYER_BLOCK_RULE = 18;
|
|
173
|
+
CSSOM.CSSRule.STARTING_STYLE_RULE = 1002;
|
|
174
|
+
|
|
175
|
+
CSSOM.CSSRule.prototype = {
|
|
176
|
+
constructor: CSSOM.CSSRule,
|
|
177
|
+
//FIXME
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
exports.CSSRule = CSSOM.CSSRule;
|
|
181
|
+
///CommonJS
|
|
182
|
+
/**
|
|
183
|
+
* @constructor
|
|
184
|
+
* @see https://drafts.csswg.org/css-nesting-1/
|
|
185
|
+
*/
|
|
186
|
+
CSSOM.CSSNestedDeclarations = function CSSNestedDeclarations() {
|
|
187
|
+
CSSOM.CSSRule.call(this);
|
|
188
|
+
this.style = new CSSOM.CSSStyleDeclaration();
|
|
189
|
+
this.style.parentRule = this;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
CSSOM.CSSNestedDeclarations.prototype = new CSSOM.CSSRule();
|
|
193
|
+
CSSOM.CSSNestedDeclarations.prototype.constructor = CSSOM.CSSNestedDeclarations;
|
|
194
|
+
CSSOM.CSSNestedDeclarations.prototype.type = 0;
|
|
195
|
+
|
|
196
|
+
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
|
|
197
|
+
get: function () {
|
|
198
|
+
return this.style.cssText;
|
|
199
|
+
},
|
|
200
|
+
configurable: true,
|
|
201
|
+
enumerable: true,
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @constructor
|
|
206
|
+
* @see https://drafts.csswg.org/cssom/#the-cssgroupingrule-interface
|
|
207
|
+
*/
|
|
208
|
+
CSSOM.CSSGroupingRule = function CSSGroupingRule() {
|
|
209
|
+
CSSOM.CSSRule.call(this);
|
|
210
|
+
this.cssRules = [];
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
CSSOM.CSSGroupingRule.prototype = new CSSOM.CSSRule();
|
|
214
|
+
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Used to insert a new CSS rule to a list of CSS rules.
|
|
219
|
+
*
|
|
220
|
+
* @example
|
|
221
|
+
* cssGroupingRule.cssText
|
|
222
|
+
* -> "body{margin:0;}"
|
|
223
|
+
* cssGroupingRule.insertRule("img{border:none;}", 1)
|
|
224
|
+
* -> 1
|
|
225
|
+
* cssGroupingRule.cssText
|
|
226
|
+
* -> "body{margin:0;}img{border:none;}"
|
|
227
|
+
*
|
|
228
|
+
* @param {string} rule
|
|
229
|
+
* @param {number} [index]
|
|
230
|
+
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-insertrule
|
|
231
|
+
* @return {number} The index within the grouping rule's collection of the newly inserted rule.
|
|
232
|
+
*/
|
|
233
|
+
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
|
|
234
|
+
if (index < 0 || index > this.cssRules.length) {
|
|
235
|
+
throw new RangeError("INDEX_SIZE_ERR");
|
|
236
|
+
}
|
|
237
|
+
var cssRule = CSSOM.parse(rule).cssRules[0];
|
|
238
|
+
cssRule.parentRule = this;
|
|
239
|
+
this.cssRules.splice(index, 0, cssRule);
|
|
240
|
+
return index;
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Used to delete a rule from the grouping rule.
|
|
245
|
+
*
|
|
246
|
+
* cssGroupingRule.cssText
|
|
247
|
+
* -> "img{border:none;}body{margin:0;}"
|
|
248
|
+
* cssGroupingRule.deleteRule(0)
|
|
249
|
+
* cssGroupingRule.cssText
|
|
250
|
+
* -> "body{margin:0;}"
|
|
251
|
+
*
|
|
252
|
+
* @param {number} index within the grouping rule's rule list of the rule to remove.
|
|
253
|
+
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
|
|
254
|
+
*/
|
|
255
|
+
CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
|
|
256
|
+
if (index < 0 || index >= this.cssRules.length) {
|
|
257
|
+
throw new RangeError("INDEX_SIZE_ERR");
|
|
258
|
+
}
|
|
259
|
+
this.cssRules.splice(index, 1)[0].parentRule = null;
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* @constructor
|
|
265
|
+
* @see https://www.w3.org/TR/css-conditional-3/#the-cssconditionrule-interface
|
|
266
|
+
*/
|
|
267
|
+
CSSOM.CSSConditionRule = function CSSConditionRule() {
|
|
268
|
+
CSSOM.CSSGroupingRule.call(this);
|
|
269
|
+
this.cssRules = [];
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
CSSOM.CSSConditionRule.prototype = new CSSOM.CSSGroupingRule();
|
|
273
|
+
CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
|
|
274
|
+
CSSOM.CSSConditionRule.prototype.conditionText = ''
|
|
275
|
+
CSSOM.CSSConditionRule.prototype.cssText = ''
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* @constructor
|
|
280
|
+
* @see http://dev.w3.org/csswg/cssom/#cssstylerule
|
|
281
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleRule
|
|
282
|
+
*/
|
|
283
|
+
CSSOM.CSSStyleRule = function CSSStyleRule() {
|
|
284
|
+
CSSOM.CSSGroupingRule.call(this);
|
|
285
|
+
this.selectorText = "";
|
|
286
|
+
this.style = new CSSOM.CSSStyleDeclaration();
|
|
287
|
+
this.style.parentRule = this;
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
CSSOM.CSSStyleRule.prototype = new CSSOM.CSSGroupingRule();
|
|
291
|
+
CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
|
|
292
|
+
CSSOM.CSSStyleRule.prototype.type = 1;
|
|
293
|
+
|
|
294
|
+
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
295
|
+
get: function() {
|
|
296
|
+
var text;
|
|
297
|
+
if (this.selectorText) {
|
|
298
|
+
var values = ""
|
|
299
|
+
if (this.cssRules.length) {
|
|
300
|
+
var valuesArr = [" {"];
|
|
301
|
+
this.style.cssText && valuesArr.push(this.style.cssText);
|
|
302
|
+
valuesArr.push(this.cssRules.map(function(rule){ return rule.cssText }).join("\n "));
|
|
303
|
+
values = valuesArr.join("\n ") + "\n}"
|
|
304
|
+
} else {
|
|
305
|
+
values = " {" + this.style.cssText + "}";
|
|
306
|
+
}
|
|
307
|
+
text = this.selectorText + values;
|
|
308
|
+
} else {
|
|
309
|
+
text = "";
|
|
310
|
+
}
|
|
311
|
+
return text;
|
|
312
|
+
},
|
|
313
|
+
set: function(cssText) {
|
|
314
|
+
var rule = CSSOM.CSSStyleRule.parse(cssText);
|
|
315
|
+
this.style = rule.style;
|
|
316
|
+
this.selectorText = rule.selectorText;
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* NON-STANDARD
|
|
323
|
+
* lightweight version of parse.js.
|
|
324
|
+
* @param {string} ruleText
|
|
325
|
+
* @return CSSStyleRule
|
|
326
|
+
*/
|
|
327
|
+
CSSOM.CSSStyleRule.parse = function(ruleText) {
|
|
328
|
+
var i = 0;
|
|
329
|
+
var state = "selector";
|
|
330
|
+
var index;
|
|
331
|
+
var j = i;
|
|
332
|
+
var buffer = "";
|
|
333
|
+
|
|
334
|
+
var SIGNIFICANT_WHITESPACE = {
|
|
335
|
+
"selector": true,
|
|
336
|
+
"value": true
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
var styleRule = new CSSOM.CSSStyleRule();
|
|
340
|
+
var name, priority="";
|
|
341
|
+
|
|
342
|
+
for (var character; (character = ruleText.charAt(i)); i++) {
|
|
343
|
+
|
|
344
|
+
switch (character) {
|
|
345
|
+
|
|
346
|
+
case " ":
|
|
347
|
+
case "\t":
|
|
348
|
+
case "\r":
|
|
349
|
+
case "\n":
|
|
350
|
+
case "\f":
|
|
351
|
+
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
352
|
+
// Squash 2 or more white-spaces in the row into 1
|
|
353
|
+
switch (ruleText.charAt(i - 1)) {
|
|
354
|
+
case " ":
|
|
355
|
+
case "\t":
|
|
356
|
+
case "\r":
|
|
357
|
+
case "\n":
|
|
358
|
+
case "\f":
|
|
359
|
+
break;
|
|
360
|
+
default:
|
|
361
|
+
buffer += " ";
|
|
362
|
+
break;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
break;
|
|
366
|
+
|
|
367
|
+
// String
|
|
368
|
+
case '"':
|
|
369
|
+
j = i + 1;
|
|
370
|
+
index = ruleText.indexOf('"', j) + 1;
|
|
371
|
+
if (!index) {
|
|
372
|
+
throw '" is missing';
|
|
373
|
+
}
|
|
374
|
+
buffer += ruleText.slice(i, index);
|
|
375
|
+
i = index - 1;
|
|
376
|
+
break;
|
|
377
|
+
|
|
378
|
+
case "'":
|
|
379
|
+
j = i + 1;
|
|
380
|
+
index = ruleText.indexOf("'", j) + 1;
|
|
381
|
+
if (!index) {
|
|
382
|
+
throw "' is missing";
|
|
383
|
+
}
|
|
384
|
+
buffer += ruleText.slice(i, index);
|
|
385
|
+
i = index - 1;
|
|
386
|
+
break;
|
|
387
|
+
|
|
388
|
+
// Comment
|
|
389
|
+
case "/":
|
|
390
|
+
if (ruleText.charAt(i + 1) === "*") {
|
|
391
|
+
i += 2;
|
|
392
|
+
index = ruleText.indexOf("*/", i);
|
|
393
|
+
if (index === -1) {
|
|
394
|
+
throw new SyntaxError("Missing */");
|
|
395
|
+
} else {
|
|
396
|
+
i = index + 1;
|
|
397
|
+
}
|
|
398
|
+
} else {
|
|
399
|
+
buffer += character;
|
|
400
|
+
}
|
|
401
|
+
break;
|
|
402
|
+
|
|
403
|
+
case "{":
|
|
404
|
+
if (state === "selector") {
|
|
405
|
+
styleRule.selectorText = buffer.trim();
|
|
406
|
+
buffer = "";
|
|
407
|
+
state = "name";
|
|
408
|
+
}
|
|
409
|
+
break;
|
|
410
|
+
|
|
411
|
+
case ":":
|
|
412
|
+
if (state === "name") {
|
|
413
|
+
name = buffer.trim();
|
|
414
|
+
buffer = "";
|
|
415
|
+
state = "value";
|
|
416
|
+
} else {
|
|
417
|
+
buffer += character;
|
|
418
|
+
}
|
|
419
|
+
break;
|
|
420
|
+
|
|
421
|
+
case "!":
|
|
422
|
+
if (state === "value" && ruleText.indexOf("!important", i) === i) {
|
|
423
|
+
priority = "important";
|
|
424
|
+
i += "important".length;
|
|
425
|
+
} else {
|
|
426
|
+
buffer += character;
|
|
427
|
+
}
|
|
428
|
+
break;
|
|
429
|
+
|
|
430
|
+
case ";":
|
|
431
|
+
if (state === "value") {
|
|
432
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
433
|
+
priority = "";
|
|
434
|
+
buffer = "";
|
|
435
|
+
state = "name";
|
|
436
|
+
} else {
|
|
437
|
+
buffer += character;
|
|
438
|
+
}
|
|
439
|
+
break;
|
|
440
|
+
|
|
441
|
+
case "}":
|
|
442
|
+
if (state === "value") {
|
|
443
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
444
|
+
priority = "";
|
|
445
|
+
buffer = "";
|
|
446
|
+
} else if (state === "name") {
|
|
447
|
+
break;
|
|
448
|
+
} else {
|
|
449
|
+
buffer += character;
|
|
450
|
+
}
|
|
451
|
+
state = "selector";
|
|
452
|
+
break;
|
|
453
|
+
|
|
454
|
+
default:
|
|
455
|
+
buffer += character;
|
|
456
|
+
break;
|
|
457
|
+
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
return styleRule;
|
|
462
|
+
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
/**
|
|
468
|
+
* @constructor
|
|
469
|
+
* @see http://dev.w3.org/csswg/cssom/#the-medialist-interface
|
|
470
|
+
*/
|
|
471
|
+
CSSOM.MediaList = function MediaList(){
|
|
472
|
+
this.length = 0;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
CSSOM.MediaList.prototype = {
|
|
476
|
+
|
|
477
|
+
constructor: CSSOM.MediaList,
|
|
478
|
+
|
|
479
|
+
/**
|
|
480
|
+
* @return {string}
|
|
481
|
+
*/
|
|
482
|
+
get mediaText() {
|
|
483
|
+
return Array.prototype.join.call(this, ", ");
|
|
484
|
+
},
|
|
485
|
+
|
|
486
|
+
/**
|
|
487
|
+
* @param {string} value
|
|
488
|
+
*/
|
|
489
|
+
set mediaText(value) {
|
|
490
|
+
var values = value.split(",");
|
|
491
|
+
var length = this.length = values.length;
|
|
492
|
+
for (var i=0; i<length; i++) {
|
|
493
|
+
this[i] = values[i].trim();
|
|
494
|
+
}
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* @param {string} medium
|
|
499
|
+
*/
|
|
500
|
+
appendMedium: function(medium) {
|
|
501
|
+
if (Array.prototype.indexOf.call(this, medium) === -1) {
|
|
502
|
+
this[this.length] = medium;
|
|
503
|
+
this.length++;
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
|
|
507
|
+
/**
|
|
508
|
+
* @param {string} medium
|
|
509
|
+
*/
|
|
510
|
+
deleteMedium: function(medium) {
|
|
511
|
+
var index = Array.prototype.indexOf.call(this, medium);
|
|
512
|
+
if (index !== -1) {
|
|
513
|
+
Array.prototype.splice.call(this, index, 1);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
/**
|
|
522
|
+
* @constructor
|
|
523
|
+
* @see http://dev.w3.org/csswg/cssom/#cssmediarule
|
|
524
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSMediaRule
|
|
525
|
+
*/
|
|
526
|
+
CSSOM.CSSMediaRule = function CSSMediaRule() {
|
|
527
|
+
CSSOM.CSSConditionRule.call(this);
|
|
528
|
+
this.media = new CSSOM.MediaList();
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
CSSOM.CSSMediaRule.prototype = new CSSOM.CSSConditionRule();
|
|
532
|
+
CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
|
|
533
|
+
CSSOM.CSSMediaRule.prototype.type = 4;
|
|
534
|
+
|
|
535
|
+
// https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
|
|
536
|
+
Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
|
|
537
|
+
"conditionText": {
|
|
538
|
+
get: function() {
|
|
539
|
+
return this.media.mediaText;
|
|
540
|
+
},
|
|
541
|
+
set: function(value) {
|
|
542
|
+
this.media.mediaText = value;
|
|
543
|
+
},
|
|
544
|
+
configurable: true,
|
|
545
|
+
enumerable: true
|
|
546
|
+
},
|
|
547
|
+
"cssText": {
|
|
548
|
+
get: function() {
|
|
549
|
+
var cssTexts = [];
|
|
550
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
551
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
552
|
+
}
|
|
553
|
+
return "@media " + this.media.mediaText + " {" + cssTexts.join("") + "}";
|
|
554
|
+
},
|
|
555
|
+
configurable: true,
|
|
556
|
+
enumerable: true
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
/**
|
|
563
|
+
* @constructor
|
|
564
|
+
* @see https://drafts.csswg.org/css-contain-3/
|
|
565
|
+
* @see https://www.w3.org/TR/css-contain-3/
|
|
566
|
+
*/
|
|
567
|
+
CSSOM.CSSContainerRule = function CSSContainerRule() {
|
|
568
|
+
CSSOM.CSSConditionRule.call(this);
|
|
569
|
+
};
|
|
570
|
+
|
|
571
|
+
CSSOM.CSSContainerRule.prototype = new CSSOM.CSSConditionRule();
|
|
572
|
+
CSSOM.CSSContainerRule.prototype.constructor = CSSOM.CSSContainerRule;
|
|
573
|
+
CSSOM.CSSContainerRule.prototype.type = 17;
|
|
574
|
+
|
|
575
|
+
Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
|
|
576
|
+
"conditionText": {
|
|
577
|
+
get: function() {
|
|
578
|
+
return this.containerText;
|
|
579
|
+
},
|
|
580
|
+
set: function(value) {
|
|
581
|
+
this.containerText = value;
|
|
582
|
+
},
|
|
583
|
+
configurable: true,
|
|
584
|
+
enumerable: true
|
|
585
|
+
},
|
|
586
|
+
"cssText": {
|
|
587
|
+
get: function() {
|
|
588
|
+
var cssTexts = [];
|
|
589
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
590
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
591
|
+
}
|
|
592
|
+
return "@container " + this.containerText + " {" + cssTexts.join("") + "}";
|
|
593
|
+
},
|
|
594
|
+
configurable: true,
|
|
595
|
+
enumerable: true
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
|
|
599
|
+
|
|
600
|
+
|
|
601
|
+
/**
|
|
602
|
+
* @constructor
|
|
603
|
+
* @see https://drafts.csswg.org/css-conditional-3/#the-csssupportsrule-interface
|
|
604
|
+
*/
|
|
605
|
+
CSSOM.CSSSupportsRule = function CSSSupportsRule() {
|
|
606
|
+
CSSOM.CSSConditionRule.call(this);
|
|
607
|
+
};
|
|
608
|
+
|
|
609
|
+
CSSOM.CSSSupportsRule.prototype = new CSSOM.CSSConditionRule();
|
|
610
|
+
CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
|
|
611
|
+
CSSOM.CSSSupportsRule.prototype.type = 12;
|
|
612
|
+
|
|
613
|
+
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
|
|
614
|
+
get: function() {
|
|
615
|
+
var cssTexts = [];
|
|
616
|
+
|
|
617
|
+
for (var i = 0, length = this.cssRules.length; i < length; i++) {
|
|
618
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return "@supports " + this.conditionText + " {" + cssTexts.join("") + "}";
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
|
|
625
|
+
|
|
626
|
+
/**
|
|
627
|
+
* @constructor
|
|
628
|
+
* @see http://dev.w3.org/csswg/cssom/#cssimportrule
|
|
629
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSImportRule
|
|
630
|
+
*/
|
|
631
|
+
CSSOM.CSSImportRule = function CSSImportRule() {
|
|
632
|
+
CSSOM.CSSRule.call(this);
|
|
633
|
+
this.href = "";
|
|
634
|
+
this.media = new CSSOM.MediaList();
|
|
635
|
+
this.styleSheet = new CSSOM.CSSStyleSheet();
|
|
636
|
+
};
|
|
637
|
+
|
|
638
|
+
CSSOM.CSSImportRule.prototype = new CSSOM.CSSRule();
|
|
639
|
+
CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
|
|
640
|
+
CSSOM.CSSImportRule.prototype.type = 3;
|
|
641
|
+
|
|
642
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
643
|
+
get: function() {
|
|
644
|
+
var mediaText = this.media.mediaText;
|
|
645
|
+
return "@import url(" + this.href + ")" + (mediaText ? " " + mediaText : "") + ";";
|
|
646
|
+
},
|
|
647
|
+
set: function(cssText) {
|
|
648
|
+
var i = 0;
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* @import url(partial.css) screen, handheld;
|
|
652
|
+
* || |
|
|
653
|
+
* after-import media
|
|
654
|
+
* |
|
|
655
|
+
* url
|
|
656
|
+
*/
|
|
657
|
+
var state = '';
|
|
658
|
+
|
|
659
|
+
var buffer = '';
|
|
660
|
+
var index;
|
|
661
|
+
for (var character; (character = cssText.charAt(i)); i++) {
|
|
662
|
+
|
|
663
|
+
switch (character) {
|
|
664
|
+
case ' ':
|
|
665
|
+
case '\t':
|
|
666
|
+
case '\r':
|
|
667
|
+
case '\n':
|
|
668
|
+
case '\f':
|
|
669
|
+
if (state === 'after-import') {
|
|
670
|
+
state = 'url';
|
|
671
|
+
} else {
|
|
672
|
+
buffer += character;
|
|
673
|
+
}
|
|
674
|
+
break;
|
|
675
|
+
|
|
676
|
+
case '@':
|
|
677
|
+
if (!state && cssText.indexOf('@import', i) === i) {
|
|
678
|
+
state = 'after-import';
|
|
679
|
+
i += 'import'.length;
|
|
680
|
+
buffer = '';
|
|
681
|
+
}
|
|
682
|
+
break;
|
|
683
|
+
|
|
684
|
+
case 'u':
|
|
685
|
+
if (state === 'url' && cssText.indexOf('url(', i) === i) {
|
|
686
|
+
index = cssText.indexOf(')', i + 1);
|
|
687
|
+
if (index === -1) {
|
|
688
|
+
throw i + ': ")" not found';
|
|
689
|
+
}
|
|
690
|
+
i += 'url('.length;
|
|
691
|
+
var url = cssText.slice(i, index);
|
|
692
|
+
if (url[0] === url[url.length - 1]) {
|
|
693
|
+
if (url[0] === '"' || url[0] === "'") {
|
|
694
|
+
url = url.slice(1, -1);
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
this.href = url;
|
|
698
|
+
i = index;
|
|
699
|
+
state = 'media';
|
|
700
|
+
}
|
|
701
|
+
break;
|
|
702
|
+
|
|
703
|
+
case '"':
|
|
704
|
+
if (state === 'url') {
|
|
705
|
+
index = cssText.indexOf('"', i + 1);
|
|
706
|
+
if (!index) {
|
|
707
|
+
throw i + ": '\"' not found";
|
|
708
|
+
}
|
|
709
|
+
this.href = cssText.slice(i + 1, index);
|
|
710
|
+
i = index;
|
|
711
|
+
state = 'media';
|
|
712
|
+
}
|
|
713
|
+
break;
|
|
714
|
+
|
|
715
|
+
case "'":
|
|
716
|
+
if (state === 'url') {
|
|
717
|
+
index = cssText.indexOf("'", i + 1);
|
|
718
|
+
if (!index) {
|
|
719
|
+
throw i + ': "\'" not found';
|
|
720
|
+
}
|
|
721
|
+
this.href = cssText.slice(i + 1, index);
|
|
722
|
+
i = index;
|
|
723
|
+
state = 'media';
|
|
724
|
+
}
|
|
725
|
+
break;
|
|
726
|
+
|
|
727
|
+
case ';':
|
|
728
|
+
if (state === 'media') {
|
|
729
|
+
if (buffer) {
|
|
730
|
+
this.media.mediaText = buffer.trim();
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
break;
|
|
734
|
+
|
|
735
|
+
default:
|
|
736
|
+
if (state === 'media') {
|
|
737
|
+
buffer += character;
|
|
738
|
+
}
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
});
|
|
744
|
+
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
/**
|
|
748
|
+
* @constructor
|
|
749
|
+
* @see http://dev.w3.org/csswg/cssom/#css-font-face-rule
|
|
750
|
+
*/
|
|
751
|
+
CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
|
|
752
|
+
CSSOM.CSSRule.call(this);
|
|
753
|
+
this.style = new CSSOM.CSSStyleDeclaration();
|
|
754
|
+
this.style.parentRule = this;
|
|
755
|
+
};
|
|
756
|
+
|
|
757
|
+
CSSOM.CSSFontFaceRule.prototype = new CSSOM.CSSRule();
|
|
758
|
+
CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
|
|
759
|
+
CSSOM.CSSFontFaceRule.prototype.type = 5;
|
|
760
|
+
//FIXME
|
|
761
|
+
//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
762
|
+
//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
763
|
+
|
|
764
|
+
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
|
|
765
|
+
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
|
|
766
|
+
get: function() {
|
|
767
|
+
return "@font-face {" + this.style.cssText + "}";
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
|
|
771
|
+
|
|
772
|
+
|
|
773
|
+
/**
|
|
774
|
+
* @constructor
|
|
775
|
+
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
|
|
776
|
+
*/
|
|
777
|
+
CSSOM.CSSHostRule = function CSSHostRule() {
|
|
778
|
+
CSSOM.CSSRule.call(this);
|
|
779
|
+
this.cssRules = [];
|
|
780
|
+
};
|
|
781
|
+
|
|
782
|
+
CSSOM.CSSHostRule.prototype = new CSSOM.CSSRule();
|
|
783
|
+
CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
|
|
784
|
+
CSSOM.CSSHostRule.prototype.type = 1001;
|
|
785
|
+
//FIXME
|
|
786
|
+
//CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
787
|
+
//CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
788
|
+
|
|
789
|
+
Object.defineProperty(CSSOM.CSSHostRule.prototype, "cssText", {
|
|
790
|
+
get: function() {
|
|
791
|
+
var cssTexts = [];
|
|
792
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
793
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
794
|
+
}
|
|
795
|
+
return "@host {" + cssTexts.join("") + "}";
|
|
796
|
+
}
|
|
797
|
+
});
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
|
|
801
|
+
/**
|
|
802
|
+
* @constructor
|
|
803
|
+
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
|
|
804
|
+
*/
|
|
805
|
+
CSSOM.CSSStartingStyleRule = function CSSStartingStyleRule() {
|
|
806
|
+
CSSOM.CSSRule.call(this);
|
|
807
|
+
this.cssRules = [];
|
|
808
|
+
};
|
|
809
|
+
|
|
810
|
+
CSSOM.CSSStartingStyleRule.prototype = new CSSOM.CSSRule();
|
|
811
|
+
CSSOM.CSSStartingStyleRule.prototype.constructor = CSSOM.CSSStartingStyleRule;
|
|
812
|
+
CSSOM.CSSStartingStyleRule.prototype.type = 1002;
|
|
813
|
+
//FIXME
|
|
814
|
+
//CSSOM.CSSStartingStyleRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
815
|
+
//CSSOM.CSSStartingStyleRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
816
|
+
|
|
817
|
+
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
|
|
818
|
+
get: function() {
|
|
819
|
+
var cssTexts = [];
|
|
820
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
821
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
822
|
+
}
|
|
823
|
+
return "@starting-style {" + cssTexts.join("") + "}";
|
|
824
|
+
}
|
|
825
|
+
});
|
|
826
|
+
|
|
827
|
+
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* @constructor
|
|
831
|
+
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
|
|
832
|
+
*/
|
|
833
|
+
CSSOM.StyleSheet = function StyleSheet() {
|
|
834
|
+
this.parentStyleSheet = null;
|
|
835
|
+
};
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
|
|
839
|
+
/**
|
|
840
|
+
* @constructor
|
|
841
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
|
|
842
|
+
*/
|
|
843
|
+
CSSOM.CSSStyleSheet = function CSSStyleSheet() {
|
|
844
|
+
CSSOM.StyleSheet.call(this);
|
|
845
|
+
this.cssRules = [];
|
|
846
|
+
};
|
|
847
|
+
|
|
848
|
+
|
|
849
|
+
CSSOM.CSSStyleSheet.prototype = new CSSOM.StyleSheet();
|
|
850
|
+
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
/**
|
|
854
|
+
* Used to insert a new rule into the style sheet. The new rule now becomes part of the cascade.
|
|
855
|
+
*
|
|
856
|
+
* sheet = new Sheet("body {margin: 0}")
|
|
857
|
+
* sheet.toString()
|
|
858
|
+
* -> "body{margin:0;}"
|
|
859
|
+
* sheet.insertRule("img {border: none}", 0)
|
|
860
|
+
* -> 0
|
|
861
|
+
* sheet.toString()
|
|
862
|
+
* -> "img{border:none;}body{margin:0;}"
|
|
863
|
+
*
|
|
864
|
+
* @param {string} rule
|
|
865
|
+
* @param {number} index
|
|
866
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-insertRule
|
|
867
|
+
* @return {number} The index within the style sheet's rule collection of the newly inserted rule.
|
|
868
|
+
*/
|
|
869
|
+
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
870
|
+
if (index < 0 || index > this.cssRules.length) {
|
|
871
|
+
throw new RangeError("INDEX_SIZE_ERR");
|
|
872
|
+
}
|
|
873
|
+
var cssRule = CSSOM.parse(rule).cssRules[0];
|
|
874
|
+
cssRule.parentStyleSheet = this;
|
|
875
|
+
this.cssRules.splice(index, 0, cssRule);
|
|
876
|
+
return index;
|
|
877
|
+
};
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
/**
|
|
881
|
+
* Used to delete a rule from the style sheet.
|
|
882
|
+
*
|
|
883
|
+
* sheet = new Sheet("img{border:none} body{margin:0}")
|
|
884
|
+
* sheet.toString()
|
|
885
|
+
* -> "img{border:none;}body{margin:0;}"
|
|
886
|
+
* sheet.deleteRule(0)
|
|
887
|
+
* sheet.toString()
|
|
888
|
+
* -> "body{margin:0;}"
|
|
889
|
+
*
|
|
890
|
+
* @param {number} index within the style sheet's rule list of the rule to remove.
|
|
891
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet-deleteRule
|
|
892
|
+
*/
|
|
893
|
+
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
|
|
894
|
+
if (index < 0 || index >= this.cssRules.length) {
|
|
895
|
+
throw new RangeError("INDEX_SIZE_ERR");
|
|
896
|
+
}
|
|
897
|
+
this.cssRules.splice(index, 1);
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
/**
|
|
902
|
+
* NON-STANDARD
|
|
903
|
+
* @return {string} serialize stylesheet
|
|
904
|
+
*/
|
|
905
|
+
CSSOM.CSSStyleSheet.prototype.toString = function() {
|
|
906
|
+
var result = "";
|
|
907
|
+
var rules = this.cssRules;
|
|
908
|
+
for (var i=0; i<rules.length; i++) {
|
|
909
|
+
result += rules[i].cssText + "\n";
|
|
910
|
+
}
|
|
911
|
+
return result;
|
|
912
|
+
};
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
/**
|
|
917
|
+
* @constructor
|
|
918
|
+
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframesRule
|
|
919
|
+
*/
|
|
920
|
+
CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
|
|
921
|
+
CSSOM.CSSRule.call(this);
|
|
922
|
+
this.name = '';
|
|
923
|
+
this.cssRules = [];
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
CSSOM.CSSKeyframesRule.prototype = new CSSOM.CSSRule();
|
|
927
|
+
CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
|
|
928
|
+
CSSOM.CSSKeyframesRule.prototype.type = 7;
|
|
929
|
+
//FIXME
|
|
930
|
+
//CSSOM.CSSKeyframesRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
931
|
+
//CSSOM.CSSKeyframesRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
932
|
+
|
|
933
|
+
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
|
|
934
|
+
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
|
|
935
|
+
get: function() {
|
|
936
|
+
var cssTexts = [];
|
|
937
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
938
|
+
cssTexts.push(" " + this.cssRules[i].cssText);
|
|
939
|
+
}
|
|
940
|
+
return "@" + (this._vendorPrefix || '') + "keyframes " + this.name + " { \n" + cssTexts.join("\n") + "\n}";
|
|
941
|
+
}
|
|
942
|
+
});
|
|
943
|
+
|
|
944
|
+
|
|
945
|
+
|
|
946
|
+
/**
|
|
947
|
+
* @constructor
|
|
948
|
+
* @see http://www.w3.org/TR/css3-animations/#DOM-CSSKeyframeRule
|
|
949
|
+
*/
|
|
950
|
+
CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
|
|
951
|
+
CSSOM.CSSRule.call(this);
|
|
952
|
+
this.keyText = '';
|
|
953
|
+
this.style = new CSSOM.CSSStyleDeclaration();
|
|
954
|
+
this.style.parentRule = this;
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
CSSOM.CSSKeyframeRule.prototype = new CSSOM.CSSRule();
|
|
958
|
+
CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
|
|
959
|
+
CSSOM.CSSKeyframeRule.prototype.type = 8;
|
|
960
|
+
//FIXME
|
|
961
|
+
//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
962
|
+
//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
963
|
+
|
|
964
|
+
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
|
|
965
|
+
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
|
|
966
|
+
get: function() {
|
|
967
|
+
return this.keyText + " {" + this.style.cssText + "} ";
|
|
968
|
+
}
|
|
969
|
+
});
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
/**
|
|
974
|
+
* @constructor
|
|
975
|
+
* @see https://developer.mozilla.org/en/CSS/@-moz-document
|
|
976
|
+
*/
|
|
977
|
+
CSSOM.MatcherList = function MatcherList(){
|
|
978
|
+
this.length = 0;
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
CSSOM.MatcherList.prototype = {
|
|
982
|
+
|
|
983
|
+
constructor: CSSOM.MatcherList,
|
|
984
|
+
|
|
985
|
+
/**
|
|
986
|
+
* @return {string}
|
|
987
|
+
*/
|
|
988
|
+
get matcherText() {
|
|
989
|
+
return Array.prototype.join.call(this, ", ");
|
|
990
|
+
},
|
|
991
|
+
|
|
992
|
+
/**
|
|
993
|
+
* @param {string} value
|
|
994
|
+
*/
|
|
995
|
+
set matcherText(value) {
|
|
996
|
+
// just a temporary solution, actually it may be wrong by just split the value with ',', because a url can include ','.
|
|
997
|
+
var values = value.split(",");
|
|
998
|
+
var length = this.length = values.length;
|
|
999
|
+
for (var i=0; i<length; i++) {
|
|
1000
|
+
this[i] = values[i].trim();
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
/**
|
|
1005
|
+
* @param {string} matcher
|
|
1006
|
+
*/
|
|
1007
|
+
appendMatcher: function(matcher) {
|
|
1008
|
+
if (Array.prototype.indexOf.call(this, matcher) === -1) {
|
|
1009
|
+
this[this.length] = matcher;
|
|
1010
|
+
this.length++;
|
|
1011
|
+
}
|
|
1012
|
+
},
|
|
1013
|
+
|
|
1014
|
+
/**
|
|
1015
|
+
* @param {string} matcher
|
|
1016
|
+
*/
|
|
1017
|
+
deleteMatcher: function(matcher) {
|
|
1018
|
+
var index = Array.prototype.indexOf.call(this, matcher);
|
|
1019
|
+
if (index !== -1) {
|
|
1020
|
+
Array.prototype.splice.call(this, index, 1);
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
};
|
|
1025
|
+
|
|
1026
|
+
|
|
1027
|
+
|
|
1028
|
+
/**
|
|
1029
|
+
* @constructor
|
|
1030
|
+
* @see https://developer.mozilla.org/en/CSS/@-moz-document
|
|
1031
|
+
*/
|
|
1032
|
+
CSSOM.CSSDocumentRule = function CSSDocumentRule() {
|
|
1033
|
+
CSSOM.CSSRule.call(this);
|
|
1034
|
+
this.matcher = new CSSOM.MatcherList();
|
|
1035
|
+
this.cssRules = [];
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
CSSOM.CSSDocumentRule.prototype = new CSSOM.CSSRule();
|
|
1039
|
+
CSSOM.CSSDocumentRule.prototype.constructor = CSSOM.CSSDocumentRule;
|
|
1040
|
+
CSSOM.CSSDocumentRule.prototype.type = 10;
|
|
1041
|
+
//FIXME
|
|
1042
|
+
//CSSOM.CSSDocumentRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1043
|
+
//CSSOM.CSSDocumentRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
1044
|
+
|
|
1045
|
+
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "cssText", {
|
|
1046
|
+
get: function() {
|
|
1047
|
+
var cssTexts = [];
|
|
1048
|
+
for (var i=0, length=this.cssRules.length; i < length; i++) {
|
|
1049
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
1050
|
+
}
|
|
1051
|
+
return "@-moz-document " + this.matcher.matcherText + " {" + cssTexts.join("") + "}";
|
|
1052
|
+
}
|
|
1053
|
+
});
|
|
1054
|
+
|
|
1055
|
+
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* @constructor
|
|
1059
|
+
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
|
|
1060
|
+
*
|
|
1061
|
+
* TODO: add if needed
|
|
1062
|
+
*/
|
|
1063
|
+
CSSOM.CSSValue = function CSSValue() {
|
|
1064
|
+
};
|
|
1065
|
+
|
|
1066
|
+
CSSOM.CSSValue.prototype = {
|
|
1067
|
+
constructor: CSSOM.CSSValue,
|
|
1068
|
+
|
|
1069
|
+
// @see: http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSValue
|
|
1070
|
+
set cssText(text) {
|
|
1071
|
+
var name = this._getConstructorName();
|
|
1072
|
+
|
|
1073
|
+
throw new Error('DOMException: property "cssText" of "' + name + '" is readonly and can not be replaced with "' + text + '"!');
|
|
1074
|
+
},
|
|
1075
|
+
|
|
1076
|
+
get cssText() {
|
|
1077
|
+
var name = this._getConstructorName();
|
|
1078
|
+
|
|
1079
|
+
throw new Error('getter "cssText" of "' + name + '" is not implemented!');
|
|
1080
|
+
},
|
|
1081
|
+
|
|
1082
|
+
_getConstructorName: function() {
|
|
1083
|
+
var s = this.constructor.toString(),
|
|
1084
|
+
c = s.match(/function\s([^\(]+)/),
|
|
1085
|
+
name = c[1];
|
|
1086
|
+
|
|
1087
|
+
return name;
|
|
1088
|
+
}
|
|
1089
|
+
};
|
|
1090
|
+
|
|
1091
|
+
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* @constructor
|
|
1095
|
+
* @see http://msdn.microsoft.com/en-us/library/ms537634(v=vs.85).aspx
|
|
1096
|
+
*
|
|
1097
|
+
*/
|
|
1098
|
+
CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
|
|
1099
|
+
this._token = token;
|
|
1100
|
+
this._idx = idx;
|
|
1101
|
+
};
|
|
1102
|
+
|
|
1103
|
+
CSSOM.CSSValueExpression.prototype = new CSSOM.CSSValue();
|
|
1104
|
+
CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
|
|
1105
|
+
|
|
1106
|
+
/**
|
|
1107
|
+
* parse css expression() value
|
|
1108
|
+
*
|
|
1109
|
+
* @return {Object}
|
|
1110
|
+
* - error:
|
|
1111
|
+
* or
|
|
1112
|
+
* - idx:
|
|
1113
|
+
* - expression:
|
|
1114
|
+
*
|
|
1115
|
+
* Example:
|
|
1116
|
+
*
|
|
1117
|
+
* .selector {
|
|
1118
|
+
* zoom: expression(documentElement.clientWidth > 1000 ? '1000px' : 'auto');
|
|
1119
|
+
* }
|
|
1120
|
+
*/
|
|
1121
|
+
CSSOM.CSSValueExpression.prototype.parse = function() {
|
|
1122
|
+
var token = this._token,
|
|
1123
|
+
idx = this._idx;
|
|
1124
|
+
|
|
1125
|
+
var character = '',
|
|
1126
|
+
expression = '',
|
|
1127
|
+
error = '',
|
|
1128
|
+
info,
|
|
1129
|
+
paren = [];
|
|
1130
|
+
|
|
1131
|
+
|
|
1132
|
+
for (; ; ++idx) {
|
|
1133
|
+
character = token.charAt(idx);
|
|
1134
|
+
|
|
1135
|
+
// end of token
|
|
1136
|
+
if (character === '') {
|
|
1137
|
+
error = 'css expression error: unfinished expression!';
|
|
1138
|
+
break;
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
switch(character) {
|
|
1142
|
+
case '(':
|
|
1143
|
+
paren.push(character);
|
|
1144
|
+
expression += character;
|
|
1145
|
+
break;
|
|
1146
|
+
|
|
1147
|
+
case ')':
|
|
1148
|
+
paren.pop(character);
|
|
1149
|
+
expression += character;
|
|
1150
|
+
break;
|
|
1151
|
+
|
|
1152
|
+
case '/':
|
|
1153
|
+
if ((info = this._parseJSComment(token, idx))) { // comment?
|
|
1154
|
+
if (info.error) {
|
|
1155
|
+
error = 'css expression error: unfinished comment in expression!';
|
|
1156
|
+
} else {
|
|
1157
|
+
idx = info.idx;
|
|
1158
|
+
// ignore the comment
|
|
1159
|
+
}
|
|
1160
|
+
} else if ((info = this._parseJSRexExp(token, idx))) { // regexp
|
|
1161
|
+
idx = info.idx;
|
|
1162
|
+
expression += info.text;
|
|
1163
|
+
} else { // other
|
|
1164
|
+
expression += character;
|
|
1165
|
+
}
|
|
1166
|
+
break;
|
|
1167
|
+
|
|
1168
|
+
case "'":
|
|
1169
|
+
case '"':
|
|
1170
|
+
info = this._parseJSString(token, idx, character);
|
|
1171
|
+
if (info) { // string
|
|
1172
|
+
idx = info.idx;
|
|
1173
|
+
expression += info.text;
|
|
1174
|
+
} else {
|
|
1175
|
+
expression += character;
|
|
1176
|
+
}
|
|
1177
|
+
break;
|
|
1178
|
+
|
|
1179
|
+
default:
|
|
1180
|
+
expression += character;
|
|
1181
|
+
break;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
if (error) {
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
// end of expression
|
|
1189
|
+
if (paren.length === 0) {
|
|
1190
|
+
break;
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
var ret;
|
|
1195
|
+
if (error) {
|
|
1196
|
+
ret = {
|
|
1197
|
+
error: error
|
|
1198
|
+
};
|
|
1199
|
+
} else {
|
|
1200
|
+
ret = {
|
|
1201
|
+
idx: idx,
|
|
1202
|
+
expression: expression
|
|
1203
|
+
};
|
|
1204
|
+
}
|
|
1205
|
+
|
|
1206
|
+
return ret;
|
|
1207
|
+
};
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
/**
|
|
1211
|
+
*
|
|
1212
|
+
* @return {Object|false}
|
|
1213
|
+
* - idx:
|
|
1214
|
+
* - text:
|
|
1215
|
+
* or
|
|
1216
|
+
* - error:
|
|
1217
|
+
* or
|
|
1218
|
+
* false
|
|
1219
|
+
*
|
|
1220
|
+
*/
|
|
1221
|
+
CSSOM.CSSValueExpression.prototype._parseJSComment = function(token, idx) {
|
|
1222
|
+
var nextChar = token.charAt(idx + 1),
|
|
1223
|
+
text;
|
|
1224
|
+
|
|
1225
|
+
if (nextChar === '/' || nextChar === '*') {
|
|
1226
|
+
var startIdx = idx,
|
|
1227
|
+
endIdx,
|
|
1228
|
+
commentEndChar;
|
|
1229
|
+
|
|
1230
|
+
if (nextChar === '/') { // line comment
|
|
1231
|
+
commentEndChar = '\n';
|
|
1232
|
+
} else if (nextChar === '*') { // block comment
|
|
1233
|
+
commentEndChar = '*/';
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
endIdx = token.indexOf(commentEndChar, startIdx + 1 + 1);
|
|
1237
|
+
if (endIdx !== -1) {
|
|
1238
|
+
endIdx = endIdx + commentEndChar.length - 1;
|
|
1239
|
+
text = token.substring(idx, endIdx + 1);
|
|
1240
|
+
return {
|
|
1241
|
+
idx: endIdx,
|
|
1242
|
+
text: text
|
|
1243
|
+
};
|
|
1244
|
+
} else {
|
|
1245
|
+
var error = 'css expression error: unfinished comment in expression!';
|
|
1246
|
+
return {
|
|
1247
|
+
error: error
|
|
1248
|
+
};
|
|
1249
|
+
}
|
|
1250
|
+
} else {
|
|
1251
|
+
return false;
|
|
1252
|
+
}
|
|
1253
|
+
};
|
|
1254
|
+
|
|
1255
|
+
|
|
1256
|
+
/**
|
|
1257
|
+
*
|
|
1258
|
+
* @return {Object|false}
|
|
1259
|
+
* - idx:
|
|
1260
|
+
* - text:
|
|
1261
|
+
* or
|
|
1262
|
+
* false
|
|
1263
|
+
*
|
|
1264
|
+
*/
|
|
1265
|
+
CSSOM.CSSValueExpression.prototype._parseJSString = function(token, idx, sep) {
|
|
1266
|
+
var endIdx = this._findMatchedIdx(token, idx, sep),
|
|
1267
|
+
text;
|
|
1268
|
+
|
|
1269
|
+
if (endIdx === -1) {
|
|
1270
|
+
return false;
|
|
1271
|
+
} else {
|
|
1272
|
+
text = token.substring(idx, endIdx + sep.length);
|
|
1273
|
+
|
|
1274
|
+
return {
|
|
1275
|
+
idx: endIdx,
|
|
1276
|
+
text: text
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* parse regexp in css expression
|
|
1284
|
+
*
|
|
1285
|
+
* @return {Object|false}
|
|
1286
|
+
* - idx:
|
|
1287
|
+
* - regExp:
|
|
1288
|
+
* or
|
|
1289
|
+
* false
|
|
1290
|
+
*/
|
|
1291
|
+
|
|
1292
|
+
/*
|
|
1293
|
+
|
|
1294
|
+
all legal RegExp
|
|
1295
|
+
|
|
1296
|
+
/a/
|
|
1297
|
+
(/a/)
|
|
1298
|
+
[/a/]
|
|
1299
|
+
[12, /a/]
|
|
1300
|
+
|
|
1301
|
+
!/a/
|
|
1302
|
+
|
|
1303
|
+
+/a/
|
|
1304
|
+
-/a/
|
|
1305
|
+
* /a/
|
|
1306
|
+
/ /a/
|
|
1307
|
+
%/a/
|
|
1308
|
+
|
|
1309
|
+
===/a/
|
|
1310
|
+
!==/a/
|
|
1311
|
+
==/a/
|
|
1312
|
+
!=/a/
|
|
1313
|
+
>/a/
|
|
1314
|
+
>=/a/
|
|
1315
|
+
</a/
|
|
1316
|
+
<=/a/
|
|
1317
|
+
|
|
1318
|
+
&/a/
|
|
1319
|
+
|/a/
|
|
1320
|
+
^/a/
|
|
1321
|
+
~/a/
|
|
1322
|
+
<</a/
|
|
1323
|
+
>>/a/
|
|
1324
|
+
>>>/a/
|
|
1325
|
+
|
|
1326
|
+
&&/a/
|
|
1327
|
+
||/a/
|
|
1328
|
+
?/a/
|
|
1329
|
+
=/a/
|
|
1330
|
+
,/a/
|
|
1331
|
+
|
|
1332
|
+
delete /a/
|
|
1333
|
+
in /a/
|
|
1334
|
+
instanceof /a/
|
|
1335
|
+
new /a/
|
|
1336
|
+
typeof /a/
|
|
1337
|
+
void /a/
|
|
1338
|
+
|
|
1339
|
+
*/
|
|
1340
|
+
CSSOM.CSSValueExpression.prototype._parseJSRexExp = function(token, idx) {
|
|
1341
|
+
var before = token.substring(0, idx).replace(/\s+$/, ""),
|
|
1342
|
+
legalRegx = [
|
|
1343
|
+
/^$/,
|
|
1344
|
+
/\($/,
|
|
1345
|
+
/\[$/,
|
|
1346
|
+
/\!$/,
|
|
1347
|
+
/\+$/,
|
|
1348
|
+
/\-$/,
|
|
1349
|
+
/\*$/,
|
|
1350
|
+
/\/\s+/,
|
|
1351
|
+
/\%$/,
|
|
1352
|
+
/\=$/,
|
|
1353
|
+
/\>$/,
|
|
1354
|
+
/<$/,
|
|
1355
|
+
/\&$/,
|
|
1356
|
+
/\|$/,
|
|
1357
|
+
/\^$/,
|
|
1358
|
+
/\~$/,
|
|
1359
|
+
/\?$/,
|
|
1360
|
+
/\,$/,
|
|
1361
|
+
/delete$/,
|
|
1362
|
+
/in$/,
|
|
1363
|
+
/instanceof$/,
|
|
1364
|
+
/new$/,
|
|
1365
|
+
/typeof$/,
|
|
1366
|
+
/void$/
|
|
1367
|
+
];
|
|
1368
|
+
|
|
1369
|
+
var isLegal = legalRegx.some(function(reg) {
|
|
1370
|
+
return reg.test(before);
|
|
1371
|
+
});
|
|
1372
|
+
|
|
1373
|
+
if (!isLegal) {
|
|
1374
|
+
return false;
|
|
1375
|
+
} else {
|
|
1376
|
+
var sep = '/';
|
|
1377
|
+
|
|
1378
|
+
// same logic as string
|
|
1379
|
+
return this._parseJSString(token, idx, sep);
|
|
1380
|
+
}
|
|
1381
|
+
};
|
|
1382
|
+
|
|
1383
|
+
|
|
1384
|
+
/**
|
|
1385
|
+
*
|
|
1386
|
+
* find next sep(same line) index in `token`
|
|
1387
|
+
*
|
|
1388
|
+
* @return {Number}
|
|
1389
|
+
*
|
|
1390
|
+
*/
|
|
1391
|
+
CSSOM.CSSValueExpression.prototype._findMatchedIdx = function(token, idx, sep) {
|
|
1392
|
+
var startIdx = idx,
|
|
1393
|
+
endIdx;
|
|
1394
|
+
|
|
1395
|
+
var NOT_FOUND = -1;
|
|
1396
|
+
|
|
1397
|
+
while(true) {
|
|
1398
|
+
endIdx = token.indexOf(sep, startIdx + 1);
|
|
1399
|
+
|
|
1400
|
+
if (endIdx === -1) { // not found
|
|
1401
|
+
endIdx = NOT_FOUND;
|
|
1402
|
+
break;
|
|
1403
|
+
} else {
|
|
1404
|
+
var text = token.substring(idx + 1, endIdx),
|
|
1405
|
+
matched = text.match(/\\+$/);
|
|
1406
|
+
if (!matched || matched[0] % 2 === 0) { // not escaped
|
|
1407
|
+
break;
|
|
1408
|
+
} else {
|
|
1409
|
+
startIdx = endIdx;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
// boundary must be in the same line(js sting or regexp)
|
|
1415
|
+
var nextNewLineIdx = token.indexOf('\n', idx + 1);
|
|
1416
|
+
if (nextNewLineIdx < endIdx) {
|
|
1417
|
+
endIdx = NOT_FOUND;
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
|
|
1421
|
+
return endIdx;
|
|
1422
|
+
};
|
|
1423
|
+
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
|
|
1427
|
+
|
|
1428
|
+
/**
|
|
1429
|
+
* @constructor
|
|
1430
|
+
* @see https://drafts.csswg.org/css-cascade-5/#csslayerblockrule
|
|
1431
|
+
*/
|
|
1432
|
+
CSSOM.CSSLayerBlockRule = function CSSLayerBlockRule() {
|
|
1433
|
+
CSSOM.CSSGroupingRule.call(this);
|
|
1434
|
+
this.layerName = "";
|
|
1435
|
+
this.cssRules = [];
|
|
1436
|
+
};
|
|
1437
|
+
|
|
1438
|
+
CSSOM.CSSLayerBlockRule.prototype = new CSSOM.CSSGroupingRule();
|
|
1439
|
+
CSSOM.CSSLayerBlockRule.prototype.constructor = CSSOM.CSSLayerBlockRule;
|
|
1440
|
+
CSSOM.CSSLayerBlockRule.prototype.type = 18;
|
|
1441
|
+
|
|
1442
|
+
Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
|
|
1443
|
+
layerNameText: {
|
|
1444
|
+
get: function () {
|
|
1445
|
+
return this.layerName;
|
|
1446
|
+
},
|
|
1447
|
+
set: function (value) {
|
|
1448
|
+
this.layerName = value;
|
|
1449
|
+
},
|
|
1450
|
+
configurable: true,
|
|
1451
|
+
enumerable: true,
|
|
1452
|
+
},
|
|
1453
|
+
cssText: {
|
|
1454
|
+
get: function () {
|
|
1455
|
+
var cssTexts = [];
|
|
1456
|
+
for (var i = 0, length = this.cssRules.length; i < length; i++) {
|
|
1457
|
+
cssTexts.push(this.cssRules[i].cssText);
|
|
1458
|
+
}
|
|
1459
|
+
return "@layer " + this.layerNameText + " {" + cssTexts.join("") + "}";
|
|
1460
|
+
},
|
|
1461
|
+
configurable: true,
|
|
1462
|
+
enumerable: true,
|
|
1463
|
+
},
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
|
|
1467
|
+
/**
|
|
1468
|
+
* @param {string} token
|
|
1469
|
+
*/
|
|
1470
|
+
CSSOM.parse = function parse(token) {
|
|
1471
|
+
|
|
1472
|
+
var i = 0;
|
|
1473
|
+
|
|
1474
|
+
/**
|
|
1475
|
+
"before-selector" or
|
|
1476
|
+
"selector" or
|
|
1477
|
+
"atRule" or
|
|
1478
|
+
"atBlock" or
|
|
1479
|
+
"conditionBlock" or
|
|
1480
|
+
"before-name" or
|
|
1481
|
+
"name" or
|
|
1482
|
+
"before-value" or
|
|
1483
|
+
"value"
|
|
1484
|
+
*/
|
|
1485
|
+
var state = "before-selector";
|
|
1486
|
+
|
|
1487
|
+
var index;
|
|
1488
|
+
var buffer = "";
|
|
1489
|
+
var valueParenthesisDepth = 0;
|
|
1490
|
+
|
|
1491
|
+
var SIGNIFICANT_WHITESPACE = {
|
|
1492
|
+
"selector": true,
|
|
1493
|
+
"value": true,
|
|
1494
|
+
"value-parenthesis": true,
|
|
1495
|
+
"atRule": true,
|
|
1496
|
+
"importRule-begin": true,
|
|
1497
|
+
"importRule": true,
|
|
1498
|
+
"atBlock": true,
|
|
1499
|
+
"containerBlock": true,
|
|
1500
|
+
"conditionBlock": true,
|
|
1501
|
+
'documentRule-begin': true,
|
|
1502
|
+
"layerBlock": true
|
|
1503
|
+
};
|
|
1504
|
+
|
|
1505
|
+
var styleSheet = new CSSOM.CSSStyleSheet();
|
|
1506
|
+
|
|
1507
|
+
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
1508
|
+
var currentScope = styleSheet;
|
|
1509
|
+
|
|
1510
|
+
// @type CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSKeyframesRule|CSSDocumentRule
|
|
1511
|
+
var parentRule;
|
|
1512
|
+
|
|
1513
|
+
var ancestorRules = [];
|
|
1514
|
+
var hasAncestors = false;
|
|
1515
|
+
var prevScope;
|
|
1516
|
+
|
|
1517
|
+
var name, priority="", styleRule, mediaRule, containerRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, layerBlockRule, nestedSelectorRule;
|
|
1518
|
+
|
|
1519
|
+
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
|
|
1520
|
+
var atRulesStatemenRegExp = /(?<!{.*)[;}]\s*/; // Match a statement by verifying it finds a semicolon or closing brace not followed by another semicolon or closing brace
|
|
1521
|
+
var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
|
|
1522
|
+
var beforeRuleValidationRegExp = /^[\s{};]*(\*\/\s*)?$/; // Match that the portion before the rule is empty or contains only whitespace, semicolons, opening/closing braces, and optionally a comment ending (*/) followed by whitespace
|
|
1523
|
+
var forwardRuleValidationRegExp = /(?:\(|\s|\/\*)/; // Match that the rule is followed by any whitespace, a opening comment or a condition opening parenthesis
|
|
1524
|
+
var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
|
|
1525
|
+
|
|
1526
|
+
/**
|
|
1527
|
+
* Finds the first balanced block (including nested braces) in the string, starting from fromIndex.
|
|
1528
|
+
* Returns an object similar to RegExp.prototype.match output.
|
|
1529
|
+
* @param {string} str - The string to search.
|
|
1530
|
+
* @param {number} [fromIndex=0] - The index to start searching from.
|
|
1531
|
+
* @returns {object|null} - { 0: matchedString, index: startIndex, input: str } or null if not found.
|
|
1532
|
+
*/
|
|
1533
|
+
function matchBalancedBlock(str, fromIndex = 0) {
|
|
1534
|
+
const openIndex = str.indexOf('{', fromIndex);
|
|
1535
|
+
if (openIndex === -1) return null;
|
|
1536
|
+
let depth = 0;
|
|
1537
|
+
for (let i = openIndex; i < str.length; i++) {
|
|
1538
|
+
if (str[i] === '{') {
|
|
1539
|
+
depth++;
|
|
1540
|
+
} else if (str[i] === '}') {
|
|
1541
|
+
depth--;
|
|
1542
|
+
if (depth === 0) {
|
|
1543
|
+
const matchedString = str.slice(openIndex, i + 1);
|
|
1544
|
+
return {
|
|
1545
|
+
0: matchedString,
|
|
1546
|
+
index: openIndex,
|
|
1547
|
+
input: str
|
|
1548
|
+
};
|
|
1549
|
+
}
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return null;
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
var parseError = function(message) {
|
|
1556
|
+
var lines = token.substring(0, i).split('\n');
|
|
1557
|
+
var lineCount = lines.length;
|
|
1558
|
+
var charCount = lines.pop().length + 1;
|
|
1559
|
+
var error = new Error(message + ' (line ' + lineCount + ', char ' + charCount + ')');
|
|
1560
|
+
error.line = lineCount;
|
|
1561
|
+
/* jshint sub : true */
|
|
1562
|
+
error['char'] = charCount;
|
|
1563
|
+
error.styleSheet = styleSheet;
|
|
1564
|
+
throw error;
|
|
1565
|
+
};
|
|
1566
|
+
|
|
1567
|
+
var validateAtRule = function(atRuleKey, validCallback, cannotBeNested) {
|
|
1568
|
+
var isValid = false;
|
|
1569
|
+
var ruleRegExp = new RegExp(atRuleKey + forwardRuleValidationRegExp.source, forwardRuleValidationRegExp.flags);
|
|
1570
|
+
var ruleSlice = token.slice(i);
|
|
1571
|
+
// Not all rules can be nested, if the rule cannot be nested and is in the root scope, do not perform the check
|
|
1572
|
+
var shouldPerformCheck = cannotBeNested && currentScope !== styleSheet ? false : true;
|
|
1573
|
+
// First, check if there is no invalid characters just after the at-rule
|
|
1574
|
+
if (shouldPerformCheck && ruleSlice.search(ruleRegExp) === 0) {
|
|
1575
|
+
// Find the closest allowed character before the at-rule (a opening or closing brace, a semicolon or a comment ending)
|
|
1576
|
+
var beforeSlice = token.slice(0, i);
|
|
1577
|
+
var regexBefore = new RegExp(beforeRulePortionRegExp.source, beforeRulePortionRegExp.flags);
|
|
1578
|
+
var matches = beforeSlice.match(regexBefore);
|
|
1579
|
+
var lastI = matches ? beforeSlice.lastIndexOf(matches[matches.length - 1]) : 0;
|
|
1580
|
+
var toCheckSlice = token.slice(lastI, i);
|
|
1581
|
+
// Check if we don't have any invalid in the portion before the `at-rule` and the closest allowed character
|
|
1582
|
+
var checkedSlice = toCheckSlice.search(beforeRuleValidationRegExp);
|
|
1583
|
+
if (checkedSlice === 0) {
|
|
1584
|
+
isValid = true;
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
if (!isValid) {
|
|
1588
|
+
// If it's invalid the browser will simply ignore the entire invalid block
|
|
1589
|
+
// Use regex to find the closing brace of the invalid rule
|
|
1590
|
+
|
|
1591
|
+
var ruleStatementMatch = ruleSlice.match(atRulesStatemenRegExp);
|
|
1592
|
+
|
|
1593
|
+
// If it's a statement inside a nested rule, ignore only the statement
|
|
1594
|
+
if (ruleStatementMatch && currentScope !== styleSheet) {
|
|
1595
|
+
var ignoreEnd = ruleStatementMatch[0].indexOf(";");
|
|
1596
|
+
i += ruleStatementMatch.index + ignoreEnd;
|
|
1597
|
+
return;
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
// Ignore the entire rule block (if it's a statement it should ignore the statement plus the next block)
|
|
1601
|
+
var ruleClosingMatch = matchBalancedBlock(ruleSlice);
|
|
1602
|
+
if (ruleClosingMatch) {
|
|
1603
|
+
const ignoreRange = ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
1604
|
+
i+= ignoreRange;
|
|
1605
|
+
if (token.charAt(i) === '}') {
|
|
1606
|
+
i -= 1;
|
|
1607
|
+
}
|
|
1608
|
+
} else {
|
|
1609
|
+
i += ruleSlice.length;
|
|
1610
|
+
}
|
|
1611
|
+
state = "before-selector";
|
|
1612
|
+
} else {
|
|
1613
|
+
validCallback.call(this);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
|
|
1617
|
+
for (var character; (character = token.charAt(i)); i++) {
|
|
1618
|
+
|
|
1619
|
+
switch (character) {
|
|
1620
|
+
|
|
1621
|
+
case " ":
|
|
1622
|
+
case "\t":
|
|
1623
|
+
case "\r":
|
|
1624
|
+
case "\n":
|
|
1625
|
+
case "\f":
|
|
1626
|
+
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
1627
|
+
buffer += character;
|
|
1628
|
+
}
|
|
1629
|
+
break;
|
|
1630
|
+
|
|
1631
|
+
// String
|
|
1632
|
+
case '"':
|
|
1633
|
+
index = i + 1;
|
|
1634
|
+
do {
|
|
1635
|
+
index = token.indexOf('"', index) + 1;
|
|
1636
|
+
if (!index) {
|
|
1637
|
+
parseError('Unmatched "');
|
|
1638
|
+
}
|
|
1639
|
+
} while (token[index - 2] === '\\');
|
|
1640
|
+
buffer += token.slice(i, index);
|
|
1641
|
+
i = index - 1;
|
|
1642
|
+
switch (state) {
|
|
1643
|
+
case 'before-value':
|
|
1644
|
+
state = 'value';
|
|
1645
|
+
break;
|
|
1646
|
+
case 'importRule-begin':
|
|
1647
|
+
state = 'importRule';
|
|
1648
|
+
break;
|
|
1649
|
+
}
|
|
1650
|
+
break;
|
|
1651
|
+
|
|
1652
|
+
case "'":
|
|
1653
|
+
index = i + 1;
|
|
1654
|
+
do {
|
|
1655
|
+
index = token.indexOf("'", index) + 1;
|
|
1656
|
+
if (!index) {
|
|
1657
|
+
parseError("Unmatched '");
|
|
1658
|
+
}
|
|
1659
|
+
} while (token[index - 2] === '\\');
|
|
1660
|
+
buffer += token.slice(i, index);
|
|
1661
|
+
i = index - 1;
|
|
1662
|
+
switch (state) {
|
|
1663
|
+
case 'before-value':
|
|
1664
|
+
state = 'value';
|
|
1665
|
+
break;
|
|
1666
|
+
case 'importRule-begin':
|
|
1667
|
+
state = 'importRule';
|
|
1668
|
+
break;
|
|
1669
|
+
}
|
|
1670
|
+
break;
|
|
1671
|
+
|
|
1672
|
+
// Comment
|
|
1673
|
+
case "/":
|
|
1674
|
+
if (token.charAt(i + 1) === "*") {
|
|
1675
|
+
i += 2;
|
|
1676
|
+
index = token.indexOf("*/", i);
|
|
1677
|
+
if (index === -1) {
|
|
1678
|
+
parseError("Missing */");
|
|
1679
|
+
} else {
|
|
1680
|
+
i = index + 1;
|
|
1681
|
+
}
|
|
1682
|
+
} else {
|
|
1683
|
+
buffer += character;
|
|
1684
|
+
}
|
|
1685
|
+
if (state === "importRule-begin") {
|
|
1686
|
+
buffer += " ";
|
|
1687
|
+
state = "importRule";
|
|
1688
|
+
}
|
|
1689
|
+
break;
|
|
1690
|
+
|
|
1691
|
+
// At-rule
|
|
1692
|
+
case "@":
|
|
1693
|
+
if (token.indexOf("@-moz-document", i) === i) {
|
|
1694
|
+
validateAtRule("@-moz-document", function(){
|
|
1695
|
+
state = "documentRule-begin";
|
|
1696
|
+
documentRule = new CSSOM.CSSDocumentRule();
|
|
1697
|
+
documentRule.__starts = i;
|
|
1698
|
+
i += "-moz-document".length;
|
|
1699
|
+
});
|
|
1700
|
+
buffer = "";
|
|
1701
|
+
break;
|
|
1702
|
+
} else if (token.indexOf("@media", i) === i) {
|
|
1703
|
+
validateAtRule("@media", function(){
|
|
1704
|
+
state = "atBlock";
|
|
1705
|
+
mediaRule = new CSSOM.CSSMediaRule();
|
|
1706
|
+
mediaRule.__starts = i;
|
|
1707
|
+
i += "media".length;
|
|
1708
|
+
});
|
|
1709
|
+
buffer = "";
|
|
1710
|
+
break;
|
|
1711
|
+
} else if (token.indexOf("@container", i) === i) {
|
|
1712
|
+
validateAtRule("@container", function(){
|
|
1713
|
+
state = "containerBlock";
|
|
1714
|
+
containerRule = new CSSOM.CSSContainerRule();
|
|
1715
|
+
containerRule.__starts = i;
|
|
1716
|
+
i += "container".length;
|
|
1717
|
+
});
|
|
1718
|
+
buffer = "";
|
|
1719
|
+
break;
|
|
1720
|
+
} else if (token.indexOf("@layer", i) === i) {
|
|
1721
|
+
validateAtRule("@layer", function(){
|
|
1722
|
+
state = "layerBlock"
|
|
1723
|
+
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
1724
|
+
layerBlockRule.__starts = i;
|
|
1725
|
+
i += "layer".length;
|
|
1726
|
+
});
|
|
1727
|
+
buffer = "";
|
|
1728
|
+
break;
|
|
1729
|
+
} else if (token.indexOf("@supports", i) === i) {
|
|
1730
|
+
validateAtRule("@supports", function(){
|
|
1731
|
+
state = "conditionBlock";
|
|
1732
|
+
supportsRule = new CSSOM.CSSSupportsRule();
|
|
1733
|
+
supportsRule.__starts = i;
|
|
1734
|
+
i += "supports".length;
|
|
1735
|
+
});
|
|
1736
|
+
buffer = "";
|
|
1737
|
+
break;
|
|
1738
|
+
} else if (token.indexOf("@host", i) === i) {
|
|
1739
|
+
validateAtRule("@host", function(){
|
|
1740
|
+
state = "hostRule-begin";
|
|
1741
|
+
i += "host".length;
|
|
1742
|
+
hostRule = new CSSOM.CSSHostRule();
|
|
1743
|
+
hostRule.__starts = i;
|
|
1744
|
+
});
|
|
1745
|
+
buffer = "";
|
|
1746
|
+
break;
|
|
1747
|
+
} else if (token.indexOf("@starting-style", i) === i) {
|
|
1748
|
+
validateAtRule("@starting-style", function(){
|
|
1749
|
+
state = "startingStyleRule-begin";
|
|
1750
|
+
i += "starting-style".length;
|
|
1751
|
+
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
1752
|
+
startingStyleRule.__starts = i;
|
|
1753
|
+
});
|
|
1754
|
+
buffer = "";
|
|
1755
|
+
break;
|
|
1756
|
+
} else if (token.indexOf("@import", i) === i) {
|
|
1757
|
+
buffer = "";
|
|
1758
|
+
validateAtRule("@import", function(){
|
|
1759
|
+
state = "importRule-begin";
|
|
1760
|
+
i += "import".length;
|
|
1761
|
+
buffer += "@import";
|
|
1762
|
+
}, true);
|
|
1763
|
+
break;
|
|
1764
|
+
} else if (token.indexOf("@font-face", i) === i) {
|
|
1765
|
+
buffer = "";
|
|
1766
|
+
validateAtRule("@font-face", function(){
|
|
1767
|
+
state = "fontFaceRule-begin";
|
|
1768
|
+
i += "font-face".length;
|
|
1769
|
+
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
1770
|
+
fontFaceRule.__starts = i;
|
|
1771
|
+
}, parentRule && parentRule.constructor.name === "CSSStyleRule" );
|
|
1772
|
+
break;
|
|
1773
|
+
} else {
|
|
1774
|
+
atKeyframesRegExp.lastIndex = i;
|
|
1775
|
+
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
1776
|
+
if (matchKeyframes && matchKeyframes.index === i) {
|
|
1777
|
+
state = "keyframesRule-begin";
|
|
1778
|
+
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
1779
|
+
keyframesRule.__starts = i;
|
|
1780
|
+
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
1781
|
+
i += matchKeyframes[0].length - 1;
|
|
1782
|
+
buffer = "";
|
|
1783
|
+
break;
|
|
1784
|
+
} else if (state === "selector") {
|
|
1785
|
+
state = "atRule";
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
buffer += character;
|
|
1789
|
+
break;
|
|
1790
|
+
|
|
1791
|
+
case "{":
|
|
1792
|
+
if (currentScope === styleSheet) {
|
|
1793
|
+
nestedSelectorRule = null;
|
|
1794
|
+
}
|
|
1795
|
+
if (state === "selector" || state === "atRule") {
|
|
1796
|
+
if (!nestedSelectorRule && buffer.includes(";")) {
|
|
1797
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
1798
|
+
if (ruleClosingMatch) {
|
|
1799
|
+
styleRule = null;
|
|
1800
|
+
buffer = "";
|
|
1801
|
+
state = "before-selector";
|
|
1802
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
1803
|
+
break;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
|
|
1807
|
+
if (parentRule) {
|
|
1808
|
+
styleRule.parentRule = parentRule;
|
|
1809
|
+
ancestorRules.push(parentRule);
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
currentScope = parentRule = styleRule;
|
|
1813
|
+
styleRule.selectorText = buffer.trim();
|
|
1814
|
+
styleRule.style.__starts = i;
|
|
1815
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
1816
|
+
buffer = "";
|
|
1817
|
+
state = "before-name";
|
|
1818
|
+
} else if (state === "atBlock") {
|
|
1819
|
+
mediaRule.media.mediaText = buffer.trim();
|
|
1820
|
+
|
|
1821
|
+
if (parentRule) {
|
|
1822
|
+
mediaRule.parentRule = parentRule;
|
|
1823
|
+
ancestorRules.push(parentRule);
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
currentScope = parentRule = mediaRule;
|
|
1827
|
+
mediaRule.parentStyleSheet = styleSheet;
|
|
1828
|
+
buffer = "";
|
|
1829
|
+
state = "before-selector";
|
|
1830
|
+
} else if (state === "containerBlock") {
|
|
1831
|
+
containerRule.containerText = buffer.trim();
|
|
1832
|
+
|
|
1833
|
+
if (parentRule) {
|
|
1834
|
+
containerRule.parentRule = parentRule;
|
|
1835
|
+
ancestorRules.push(parentRule);
|
|
1836
|
+
}
|
|
1837
|
+
currentScope = parentRule = containerRule;
|
|
1838
|
+
containerRule.parentStyleSheet = styleSheet;
|
|
1839
|
+
buffer = "";
|
|
1840
|
+
state = "before-selector";
|
|
1841
|
+
} else if (state === "conditionBlock") {
|
|
1842
|
+
supportsRule.conditionText = buffer.trim();
|
|
1843
|
+
|
|
1844
|
+
if (parentRule) {
|
|
1845
|
+
supportsRule.parentRule = parentRule;
|
|
1846
|
+
ancestorRules.push(parentRule);
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
currentScope = parentRule = supportsRule;
|
|
1850
|
+
supportsRule.parentStyleSheet = styleSheet;
|
|
1851
|
+
buffer = "";
|
|
1852
|
+
state = "before-selector";
|
|
1853
|
+
} else if (state === "layerBlock") {
|
|
1854
|
+
layerBlockRule.layerNameText = buffer.trim();
|
|
1855
|
+
|
|
1856
|
+
if (parentRule) {
|
|
1857
|
+
layerBlockRule.parentRule = parentRule;
|
|
1858
|
+
ancestorRules.push(parentRule);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
currentScope = parentRule = layerBlockRule;
|
|
1862
|
+
layerBlockRule.parentStyleSheet = styleSheet;
|
|
1863
|
+
buffer = "";
|
|
1864
|
+
state = "before-selector";
|
|
1865
|
+
} else if (state === "hostRule-begin") {
|
|
1866
|
+
if (parentRule) {
|
|
1867
|
+
ancestorRules.push(parentRule);
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
currentScope = parentRule = hostRule;
|
|
1871
|
+
hostRule.parentStyleSheet = styleSheet;
|
|
1872
|
+
buffer = "";
|
|
1873
|
+
state = "before-selector";
|
|
1874
|
+
} else if (state === "startingStyleRule-begin") {
|
|
1875
|
+
if (parentRule) {
|
|
1876
|
+
startingStyleRule.parentRule = parentRule;
|
|
1877
|
+
ancestorRules.push(parentRule);
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1880
|
+
currentScope = parentRule = startingStyleRule;
|
|
1881
|
+
startingStyleRule.parentStyleSheet = styleSheet;
|
|
1882
|
+
buffer = "";
|
|
1883
|
+
state = "before-selector";
|
|
1884
|
+
|
|
1885
|
+
} else if (state === "fontFaceRule-begin") {
|
|
1886
|
+
if (parentRule) {
|
|
1887
|
+
fontFaceRule.parentRule = parentRule;
|
|
1888
|
+
}
|
|
1889
|
+
fontFaceRule.parentStyleSheet = styleSheet;
|
|
1890
|
+
styleRule = fontFaceRule;
|
|
1891
|
+
buffer = "";
|
|
1892
|
+
state = "before-name";
|
|
1893
|
+
} else if (state === "keyframesRule-begin") {
|
|
1894
|
+
keyframesRule.name = buffer.trim();
|
|
1895
|
+
if (parentRule) {
|
|
1896
|
+
ancestorRules.push(parentRule);
|
|
1897
|
+
keyframesRule.parentRule = parentRule;
|
|
1898
|
+
}
|
|
1899
|
+
keyframesRule.parentStyleSheet = styleSheet;
|
|
1900
|
+
currentScope = parentRule = keyframesRule;
|
|
1901
|
+
buffer = "";
|
|
1902
|
+
state = "keyframeRule-begin";
|
|
1903
|
+
} else if (state === "keyframeRule-begin") {
|
|
1904
|
+
styleRule = new CSSOM.CSSKeyframeRule();
|
|
1905
|
+
styleRule.keyText = buffer.trim();
|
|
1906
|
+
styleRule.__starts = i;
|
|
1907
|
+
buffer = "";
|
|
1908
|
+
state = "before-name";
|
|
1909
|
+
} else if (state === "documentRule-begin") {
|
|
1910
|
+
// FIXME: what if this '{' is in the url text of the match function?
|
|
1911
|
+
documentRule.matcher.matcherText = buffer.trim();
|
|
1912
|
+
if (parentRule) {
|
|
1913
|
+
ancestorRules.push(parentRule);
|
|
1914
|
+
documentRule.parentRule = parentRule;
|
|
1915
|
+
}
|
|
1916
|
+
currentScope = parentRule = documentRule;
|
|
1917
|
+
documentRule.parentStyleSheet = styleSheet;
|
|
1918
|
+
buffer = "";
|
|
1919
|
+
state = "before-selector";
|
|
1920
|
+
} else if (state === "name") {
|
|
1921
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
1922
|
+
if (styleRule.style.length) {
|
|
1923
|
+
parentRule.cssRules.push(styleRule);
|
|
1924
|
+
styleRule.parentRule = parentRule;
|
|
1925
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
1926
|
+
ancestorRules.push(parentRule);
|
|
1927
|
+
} else {
|
|
1928
|
+
// If the styleRule is empty, we can assume that it's a nested selector
|
|
1929
|
+
ancestorRules.push(parentRule);
|
|
1930
|
+
}
|
|
1931
|
+
} else {
|
|
1932
|
+
currentScope = parentRule = styleRule;
|
|
1933
|
+
ancestorRules.push(parentRule);
|
|
1934
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
1935
|
+
}
|
|
1936
|
+
|
|
1937
|
+
|
|
1938
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
1939
|
+
styleRule.selectorText = buffer.trim();
|
|
1940
|
+
styleRule.style.__starts = i - buffer.length;
|
|
1941
|
+
styleRule.parentRule = parentRule;
|
|
1942
|
+
nestedSelectorRule = styleRule;
|
|
1943
|
+
|
|
1944
|
+
buffer = "";
|
|
1945
|
+
state = "before-name";
|
|
1946
|
+
}
|
|
1947
|
+
break;
|
|
1948
|
+
|
|
1949
|
+
case ":":
|
|
1950
|
+
if (state === "name") {
|
|
1951
|
+
// It can be a nested selector, let's check
|
|
1952
|
+
var openBraceBeforeMatch = token.slice(i).match(/[{;}]/);
|
|
1953
|
+
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
1954
|
+
if (hasOpenBraceBefore) {
|
|
1955
|
+
// Is a selector
|
|
1956
|
+
buffer += character;
|
|
1957
|
+
} else {
|
|
1958
|
+
// Is a declaration
|
|
1959
|
+
name = buffer.trim();
|
|
1960
|
+
buffer = "";
|
|
1961
|
+
state = "before-value";
|
|
1962
|
+
}
|
|
1963
|
+
} else {
|
|
1964
|
+
buffer += character;
|
|
1965
|
+
}
|
|
1966
|
+
break;
|
|
1967
|
+
|
|
1968
|
+
case "(":
|
|
1969
|
+
if (state === 'value') {
|
|
1970
|
+
// ie css expression mode
|
|
1971
|
+
if (buffer.trim() === 'expression') {
|
|
1972
|
+
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
|
|
1973
|
+
|
|
1974
|
+
if (info.error) {
|
|
1975
|
+
parseError(info.error);
|
|
1976
|
+
} else {
|
|
1977
|
+
buffer += info.expression;
|
|
1978
|
+
i = info.idx;
|
|
1979
|
+
}
|
|
1980
|
+
} else {
|
|
1981
|
+
state = 'value-parenthesis';
|
|
1982
|
+
//always ensure this is reset to 1 on transition
|
|
1983
|
+
//from value to value-parenthesis
|
|
1984
|
+
valueParenthesisDepth = 1;
|
|
1985
|
+
buffer += character;
|
|
1986
|
+
}
|
|
1987
|
+
} else if (state === 'value-parenthesis') {
|
|
1988
|
+
valueParenthesisDepth++;
|
|
1989
|
+
buffer += character;
|
|
1990
|
+
} else {
|
|
1991
|
+
buffer += character;
|
|
1992
|
+
}
|
|
1993
|
+
break;
|
|
1994
|
+
|
|
1995
|
+
case ")":
|
|
1996
|
+
if (state === 'value-parenthesis') {
|
|
1997
|
+
valueParenthesisDepth--;
|
|
1998
|
+
if (valueParenthesisDepth === 0) state = 'value';
|
|
1999
|
+
}
|
|
2000
|
+
buffer += character;
|
|
2001
|
+
break;
|
|
2002
|
+
|
|
2003
|
+
case "!":
|
|
2004
|
+
if (state === "value" && token.indexOf("!important", i) === i) {
|
|
2005
|
+
priority = "important";
|
|
2006
|
+
i += "important".length;
|
|
2007
|
+
} else {
|
|
2008
|
+
buffer += character;
|
|
2009
|
+
}
|
|
2010
|
+
break;
|
|
2011
|
+
|
|
2012
|
+
case ";":
|
|
2013
|
+
switch (state) {
|
|
2014
|
+
case "value":
|
|
2015
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
2016
|
+
priority = "";
|
|
2017
|
+
buffer = "";
|
|
2018
|
+
state = "before-name";
|
|
2019
|
+
break;
|
|
2020
|
+
case "atRule":
|
|
2021
|
+
buffer = "";
|
|
2022
|
+
state = "before-selector";
|
|
2023
|
+
break;
|
|
2024
|
+
case "importRule":
|
|
2025
|
+
importRule = new CSSOM.CSSImportRule();
|
|
2026
|
+
importRule.parentStyleSheet = importRule.styleSheet.parentStyleSheet = styleSheet;
|
|
2027
|
+
importRule.cssText = buffer + character;
|
|
2028
|
+
styleSheet.cssRules.push(importRule);
|
|
2029
|
+
buffer = "";
|
|
2030
|
+
state = "before-selector";
|
|
2031
|
+
break;
|
|
2032
|
+
default:
|
|
2033
|
+
buffer += character;
|
|
2034
|
+
break;
|
|
2035
|
+
}
|
|
2036
|
+
break;
|
|
2037
|
+
|
|
2038
|
+
case "}":
|
|
2039
|
+
switch (state) {
|
|
2040
|
+
case "value":
|
|
2041
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
2042
|
+
priority = "";
|
|
2043
|
+
/* falls through */
|
|
2044
|
+
case "before-name":
|
|
2045
|
+
case "name":
|
|
2046
|
+
styleRule.__ends = i + 1;
|
|
2047
|
+
|
|
2048
|
+
if (parentRule === styleRule) {
|
|
2049
|
+
parentRule = ancestorRules.pop()
|
|
2050
|
+
}
|
|
2051
|
+
|
|
2052
|
+
if (parentRule) {
|
|
2053
|
+
styleRule.parentRule = parentRule;
|
|
2054
|
+
}
|
|
2055
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
2056
|
+
|
|
2057
|
+
if (currentScope === styleRule) {
|
|
2058
|
+
currentScope = parentRule || styleSheet;
|
|
2059
|
+
}
|
|
2060
|
+
|
|
2061
|
+
currentScope.cssRules.push(styleRule);
|
|
2062
|
+
buffer = "";
|
|
2063
|
+
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
|
|
2064
|
+
state = "keyframeRule-begin";
|
|
2065
|
+
} else {
|
|
2066
|
+
state = "before-selector";
|
|
2067
|
+
}
|
|
2068
|
+
|
|
2069
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
2070
|
+
if (currentScope !== styleSheet) {
|
|
2071
|
+
nestedSelectorRule = currentScope;
|
|
2072
|
+
}
|
|
2073
|
+
styleRule = null;
|
|
2074
|
+
} else {
|
|
2075
|
+
styleRule = null;
|
|
2076
|
+
break;
|
|
2077
|
+
}
|
|
2078
|
+
case "keyframeRule-begin":
|
|
2079
|
+
case "before-selector":
|
|
2080
|
+
case "selector":
|
|
2081
|
+
// End of media/supports/document rule.
|
|
2082
|
+
if (!parentRule) {
|
|
2083
|
+
break;
|
|
2084
|
+
//parseError("Unexpected }");
|
|
2085
|
+
}
|
|
2086
|
+
|
|
2087
|
+
// Handle rules nested in @media or @supports
|
|
2088
|
+
hasAncestors = ancestorRules.length > 0;
|
|
2089
|
+
|
|
2090
|
+
while (ancestorRules.length > 0) {
|
|
2091
|
+
parentRule = ancestorRules.pop();
|
|
2092
|
+
|
|
2093
|
+
if (
|
|
2094
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
2095
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
2096
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
2097
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
2098
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
2099
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
2100
|
+
) {
|
|
2101
|
+
if (nestedSelectorRule) {
|
|
2102
|
+
if (nestedSelectorRule.parentRule) {
|
|
2103
|
+
prevScope = nestedSelectorRule;
|
|
2104
|
+
currentScope = nestedSelectorRule.parentRule;
|
|
2105
|
+
if (currentScope.cssRules.findIndex(function (rule) {
|
|
2106
|
+
return rule === prevScope
|
|
2107
|
+
}) === -1) {
|
|
2108
|
+
currentScope.cssRules.push(prevScope);
|
|
2109
|
+
}
|
|
2110
|
+
nestedSelectorRule = currentScope;
|
|
2111
|
+
}
|
|
2112
|
+
} else {
|
|
2113
|
+
prevScope = currentScope;
|
|
2114
|
+
currentScope = parentRule;
|
|
2115
|
+
currentScope.cssRules.push(prevScope);
|
|
2116
|
+
break;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
if (ancestorRules.length === 0) {
|
|
2121
|
+
hasAncestors = false;
|
|
2122
|
+
}
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
if (currentScope.parentRule == null) {
|
|
2126
|
+
currentScope.__ends = i + 1;
|
|
2127
|
+
if (currentScope !== styleSheet && styleSheet.cssRules.findIndex(function (rule) {
|
|
2128
|
+
return rule === currentScope
|
|
2129
|
+
}) === -1) {
|
|
2130
|
+
styleSheet.cssRules.push(currentScope);
|
|
2131
|
+
}
|
|
2132
|
+
currentScope = styleSheet;
|
|
2133
|
+
if (nestedSelectorRule === parentRule) {
|
|
2134
|
+
// Check if this selector is really starting inside another selector
|
|
2135
|
+
var nestedSelectorTokenToCurrentSelectorToken = token.slice(nestedSelectorRule.__starts, i + 1);
|
|
2136
|
+
|
|
2137
|
+
if (nestedSelectorTokenToCurrentSelectorToken.match(/{/g)?.length === nestedSelectorTokenToCurrentSelectorToken.match(/}/g)?.length) {
|
|
2138
|
+
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
2139
|
+
nestedSelectorRule.__ends = i + 1;
|
|
2140
|
+
nestedSelectorRule = null;
|
|
2141
|
+
parentRule = null;
|
|
2142
|
+
}
|
|
2143
|
+
} else {
|
|
2144
|
+
parentRule = null;
|
|
2145
|
+
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
|
|
2149
|
+
buffer = "";
|
|
2150
|
+
state = "before-selector";
|
|
2151
|
+
break;
|
|
2152
|
+
}
|
|
2153
|
+
break;
|
|
2154
|
+
|
|
2155
|
+
default:
|
|
2156
|
+
switch (state) {
|
|
2157
|
+
case "before-selector":
|
|
2158
|
+
state = "selector";
|
|
2159
|
+
if (styleRule && parentRule) {
|
|
2160
|
+
// Assuming it's a declaration inside Nested Selector OR a Nested Declaration
|
|
2161
|
+
// If Declaration inside Nested Selector let's keep the same styleRule
|
|
2162
|
+
if (
|
|
2163
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
2164
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
2165
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
2166
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
2167
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
2168
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
2169
|
+
) {
|
|
2170
|
+
// parentRule.parentRule = styleRule;
|
|
2171
|
+
state = "before-name";
|
|
2172
|
+
if (styleRule !== parentRule) {
|
|
2173
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
2174
|
+
styleRule.__starts = i;
|
|
2175
|
+
}
|
|
2176
|
+
}
|
|
2177
|
+
|
|
2178
|
+
} else if (nestedSelectorRule && parentRule && (
|
|
2179
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
2180
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
2181
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
2182
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
2183
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
2184
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
2185
|
+
)) {
|
|
2186
|
+
state = "before-name";
|
|
2187
|
+
if (parentRule.cssRules.length) {
|
|
2188
|
+
currentScope = nestedSelectorRule = parentRule;
|
|
2189
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
2190
|
+
styleRule.__starts = i;
|
|
2191
|
+
} else {
|
|
2192
|
+
if (parentRule.constructor.name === "CSSStyleRule") {
|
|
2193
|
+
styleRule = parentRule;
|
|
2194
|
+
} else {
|
|
2195
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
2196
|
+
styleRule.__starts = i;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
} else {
|
|
2200
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
2201
|
+
styleRule.__starts = i;
|
|
2202
|
+
}
|
|
2203
|
+
break;
|
|
2204
|
+
case "before-name":
|
|
2205
|
+
state = "name";
|
|
2206
|
+
break;
|
|
2207
|
+
case "before-value":
|
|
2208
|
+
state = "value";
|
|
2209
|
+
break;
|
|
2210
|
+
case "importRule-begin":
|
|
2211
|
+
state = "importRule";
|
|
2212
|
+
break;
|
|
2213
|
+
}
|
|
2214
|
+
buffer += character;
|
|
2215
|
+
break;
|
|
2216
|
+
}
|
|
2217
|
+
}
|
|
2218
|
+
|
|
2219
|
+
return styleSheet;
|
|
2220
|
+
};
|
|
2221
|
+
|
|
2222
|
+
|
|
2223
|
+
|
|
2224
|
+
/**
|
|
2225
|
+
* Produces a deep copy of stylesheet — the instance variables of stylesheet are copied recursively.
|
|
2226
|
+
* @param {CSSStyleSheet|CSSOM.CSSStyleSheet} stylesheet
|
|
2227
|
+
* @nosideeffects
|
|
2228
|
+
* @return {CSSOM.CSSStyleSheet}
|
|
2229
|
+
*/
|
|
2230
|
+
CSSOM.clone = function clone(stylesheet) {
|
|
2231
|
+
|
|
2232
|
+
var cloned = new CSSOM.CSSStyleSheet();
|
|
2233
|
+
|
|
2234
|
+
var rules = stylesheet.cssRules;
|
|
2235
|
+
if (!rules) {
|
|
2236
|
+
return cloned;
|
|
2237
|
+
}
|
|
2238
|
+
|
|
2239
|
+
for (var i = 0, rulesLength = rules.length; i < rulesLength; i++) {
|
|
2240
|
+
var rule = rules[i];
|
|
2241
|
+
var ruleClone = cloned.cssRules[i] = new rule.constructor();
|
|
2242
|
+
|
|
2243
|
+
var style = rule.style;
|
|
2244
|
+
if (style) {
|
|
2245
|
+
var styleClone = ruleClone.style = new CSSOM.CSSStyleDeclaration();
|
|
2246
|
+
for (var j = 0, styleLength = style.length; j < styleLength; j++) {
|
|
2247
|
+
var name = styleClone[j] = style[j];
|
|
2248
|
+
styleClone[name] = style[name];
|
|
2249
|
+
styleClone._importants[name] = style.getPropertyPriority(name);
|
|
2250
|
+
}
|
|
2251
|
+
styleClone.length = style.length;
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
if (rule.hasOwnProperty('keyText')) {
|
|
2255
|
+
ruleClone.keyText = rule.keyText;
|
|
2256
|
+
}
|
|
2257
|
+
|
|
2258
|
+
if (rule.hasOwnProperty('selectorText')) {
|
|
2259
|
+
ruleClone.selectorText = rule.selectorText;
|
|
2260
|
+
}
|
|
2261
|
+
|
|
2262
|
+
if (rule.hasOwnProperty('mediaText')) {
|
|
2263
|
+
ruleClone.mediaText = rule.mediaText;
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
if (rule.hasOwnProperty('conditionText')) {
|
|
2267
|
+
ruleClone.conditionText = rule.conditionText;
|
|
2268
|
+
}
|
|
2269
|
+
|
|
2270
|
+
if (rule.hasOwnProperty('layerName')) {
|
|
2271
|
+
ruleClone.layerName = rule.layerName;
|
|
2272
|
+
}
|
|
2273
|
+
|
|
2274
|
+
if (rule.hasOwnProperty('cssRules')) {
|
|
2275
|
+
ruleClone.cssRules = clone(rule).cssRules;
|
|
2276
|
+
}
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
return cloned;
|
|
2280
|
+
|
|
2281
|
+
};
|
|
2282
|
+
|
|
2283
|
+
|