@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/lib/parse.js
ADDED
|
@@ -0,0 +1,783 @@
|
|
|
1
|
+
//.CommonJS
|
|
2
|
+
var CSSOM = {};
|
|
3
|
+
///CommonJS
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} token
|
|
8
|
+
*/
|
|
9
|
+
CSSOM.parse = function parse(token) {
|
|
10
|
+
|
|
11
|
+
var i = 0;
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
"before-selector" or
|
|
15
|
+
"selector" or
|
|
16
|
+
"atRule" or
|
|
17
|
+
"atBlock" or
|
|
18
|
+
"conditionBlock" or
|
|
19
|
+
"before-name" or
|
|
20
|
+
"name" or
|
|
21
|
+
"before-value" or
|
|
22
|
+
"value"
|
|
23
|
+
*/
|
|
24
|
+
var state = "before-selector";
|
|
25
|
+
|
|
26
|
+
var index;
|
|
27
|
+
var buffer = "";
|
|
28
|
+
var valueParenthesisDepth = 0;
|
|
29
|
+
|
|
30
|
+
var SIGNIFICANT_WHITESPACE = {
|
|
31
|
+
"selector": true,
|
|
32
|
+
"value": true,
|
|
33
|
+
"value-parenthesis": true,
|
|
34
|
+
"atRule": true,
|
|
35
|
+
"importRule-begin": true,
|
|
36
|
+
"importRule": true,
|
|
37
|
+
"atBlock": true,
|
|
38
|
+
"containerBlock": true,
|
|
39
|
+
"conditionBlock": true,
|
|
40
|
+
'documentRule-begin': true,
|
|
41
|
+
"layerBlock": true
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
var styleSheet = new CSSOM.CSSStyleSheet();
|
|
45
|
+
|
|
46
|
+
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
47
|
+
var currentScope = styleSheet;
|
|
48
|
+
|
|
49
|
+
// @type CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSKeyframesRule|CSSDocumentRule
|
|
50
|
+
var parentRule;
|
|
51
|
+
|
|
52
|
+
var ancestorRules = [];
|
|
53
|
+
var hasAncestors = false;
|
|
54
|
+
var prevScope;
|
|
55
|
+
|
|
56
|
+
var name, priority="", styleRule, mediaRule, containerRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, layerBlockRule, nestedSelectorRule;
|
|
57
|
+
|
|
58
|
+
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g; // Match @keyframes and vendor-prefixed @keyframes
|
|
59
|
+
var atRulesStatemenRegExp = /(?<!{.*)[;}]\s*/; // Match a statement by verifying it finds a semicolon or closing brace not followed by another semicolon or closing brace
|
|
60
|
+
var beforeRulePortionRegExp = /{(?!.*{)|}(?!.*})|;(?!.*;)|\*\/(?!.*\*\/)/g; // Match the closest allowed character (a opening or closing brace, a semicolon or a comment ending) before the rule
|
|
61
|
+
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
|
|
62
|
+
var forwardRuleValidationRegExp = /(?:\(|\s|\/\*)/; // Match that the rule is followed by any whitespace, a opening comment or a condition opening parenthesis
|
|
63
|
+
var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Finds the first balanced block (including nested braces) in the string, starting from fromIndex.
|
|
67
|
+
* Returns an object similar to RegExp.prototype.match output.
|
|
68
|
+
* @param {string} str - The string to search.
|
|
69
|
+
* @param {number} [fromIndex=0] - The index to start searching from.
|
|
70
|
+
* @returns {object|null} - { 0: matchedString, index: startIndex, input: str } or null if not found.
|
|
71
|
+
*/
|
|
72
|
+
function matchBalancedBlock(str, fromIndex = 0) {
|
|
73
|
+
const openIndex = str.indexOf('{', fromIndex);
|
|
74
|
+
if (openIndex === -1) return null;
|
|
75
|
+
let depth = 0;
|
|
76
|
+
for (let i = openIndex; i < str.length; i++) {
|
|
77
|
+
if (str[i] === '{') {
|
|
78
|
+
depth++;
|
|
79
|
+
} else if (str[i] === '}') {
|
|
80
|
+
depth--;
|
|
81
|
+
if (depth === 0) {
|
|
82
|
+
const matchedString = str.slice(openIndex, i + 1);
|
|
83
|
+
return {
|
|
84
|
+
0: matchedString,
|
|
85
|
+
index: openIndex,
|
|
86
|
+
input: str
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var parseError = function(message) {
|
|
95
|
+
var lines = token.substring(0, i).split('\n');
|
|
96
|
+
var lineCount = lines.length;
|
|
97
|
+
var charCount = lines.pop().length + 1;
|
|
98
|
+
var error = new Error(message + ' (line ' + lineCount + ', char ' + charCount + ')');
|
|
99
|
+
error.line = lineCount;
|
|
100
|
+
/* jshint sub : true */
|
|
101
|
+
error['char'] = charCount;
|
|
102
|
+
error.styleSheet = styleSheet;
|
|
103
|
+
throw error;
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
var validateAtRule = function(atRuleKey, validCallback, cannotBeNested) {
|
|
107
|
+
var isValid = false;
|
|
108
|
+
var ruleRegExp = new RegExp(atRuleKey + forwardRuleValidationRegExp.source, forwardRuleValidationRegExp.flags);
|
|
109
|
+
var ruleSlice = token.slice(i);
|
|
110
|
+
// Not all rules can be nested, if the rule cannot be nested and is in the root scope, do not perform the check
|
|
111
|
+
var shouldPerformCheck = cannotBeNested && currentScope !== styleSheet ? false : true;
|
|
112
|
+
// First, check if there is no invalid characters just after the at-rule
|
|
113
|
+
if (shouldPerformCheck && ruleSlice.search(ruleRegExp) === 0) {
|
|
114
|
+
// Find the closest allowed character before the at-rule (a opening or closing brace, a semicolon or a comment ending)
|
|
115
|
+
var beforeSlice = token.slice(0, i);
|
|
116
|
+
var regexBefore = new RegExp(beforeRulePortionRegExp.source, beforeRulePortionRegExp.flags);
|
|
117
|
+
var matches = beforeSlice.match(regexBefore);
|
|
118
|
+
var lastI = matches ? beforeSlice.lastIndexOf(matches[matches.length - 1]) : 0;
|
|
119
|
+
var toCheckSlice = token.slice(lastI, i);
|
|
120
|
+
// Check if we don't have any invalid in the portion before the `at-rule` and the closest allowed character
|
|
121
|
+
var checkedSlice = toCheckSlice.search(beforeRuleValidationRegExp);
|
|
122
|
+
if (checkedSlice === 0) {
|
|
123
|
+
isValid = true;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
if (!isValid) {
|
|
127
|
+
// If it's invalid the browser will simply ignore the entire invalid block
|
|
128
|
+
// Use regex to find the closing brace of the invalid rule
|
|
129
|
+
|
|
130
|
+
var ruleStatementMatch = ruleSlice.match(atRulesStatemenRegExp);
|
|
131
|
+
|
|
132
|
+
// If it's a statement inside a nested rule, ignore only the statement
|
|
133
|
+
if (ruleStatementMatch && currentScope !== styleSheet) {
|
|
134
|
+
var ignoreEnd = ruleStatementMatch[0].indexOf(";");
|
|
135
|
+
i += ruleStatementMatch.index + ignoreEnd;
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Ignore the entire rule block (if it's a statement it should ignore the statement plus the next block)
|
|
140
|
+
var ruleClosingMatch = matchBalancedBlock(ruleSlice);
|
|
141
|
+
if (ruleClosingMatch) {
|
|
142
|
+
const ignoreRange = ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
143
|
+
i+= ignoreRange;
|
|
144
|
+
if (token.charAt(i) === '}') {
|
|
145
|
+
i -= 1;
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
i += ruleSlice.length;
|
|
149
|
+
}
|
|
150
|
+
state = "before-selector";
|
|
151
|
+
} else {
|
|
152
|
+
validCallback.call(this);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
for (var character; (character = token.charAt(i)); i++) {
|
|
157
|
+
|
|
158
|
+
switch (character) {
|
|
159
|
+
|
|
160
|
+
case " ":
|
|
161
|
+
case "\t":
|
|
162
|
+
case "\r":
|
|
163
|
+
case "\n":
|
|
164
|
+
case "\f":
|
|
165
|
+
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
166
|
+
buffer += character;
|
|
167
|
+
}
|
|
168
|
+
break;
|
|
169
|
+
|
|
170
|
+
// String
|
|
171
|
+
case '"':
|
|
172
|
+
index = i + 1;
|
|
173
|
+
do {
|
|
174
|
+
index = token.indexOf('"', index) + 1;
|
|
175
|
+
if (!index) {
|
|
176
|
+
parseError('Unmatched "');
|
|
177
|
+
}
|
|
178
|
+
} while (token[index - 2] === '\\');
|
|
179
|
+
buffer += token.slice(i, index);
|
|
180
|
+
i = index - 1;
|
|
181
|
+
switch (state) {
|
|
182
|
+
case 'before-value':
|
|
183
|
+
state = 'value';
|
|
184
|
+
break;
|
|
185
|
+
case 'importRule-begin':
|
|
186
|
+
state = 'importRule';
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
break;
|
|
190
|
+
|
|
191
|
+
case "'":
|
|
192
|
+
index = i + 1;
|
|
193
|
+
do {
|
|
194
|
+
index = token.indexOf("'", index) + 1;
|
|
195
|
+
if (!index) {
|
|
196
|
+
parseError("Unmatched '");
|
|
197
|
+
}
|
|
198
|
+
} while (token[index - 2] === '\\');
|
|
199
|
+
buffer += token.slice(i, index);
|
|
200
|
+
i = index - 1;
|
|
201
|
+
switch (state) {
|
|
202
|
+
case 'before-value':
|
|
203
|
+
state = 'value';
|
|
204
|
+
break;
|
|
205
|
+
case 'importRule-begin':
|
|
206
|
+
state = 'importRule';
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
break;
|
|
210
|
+
|
|
211
|
+
// Comment
|
|
212
|
+
case "/":
|
|
213
|
+
if (token.charAt(i + 1) === "*") {
|
|
214
|
+
i += 2;
|
|
215
|
+
index = token.indexOf("*/", i);
|
|
216
|
+
if (index === -1) {
|
|
217
|
+
parseError("Missing */");
|
|
218
|
+
} else {
|
|
219
|
+
i = index + 1;
|
|
220
|
+
}
|
|
221
|
+
} else {
|
|
222
|
+
buffer += character;
|
|
223
|
+
}
|
|
224
|
+
if (state === "importRule-begin") {
|
|
225
|
+
buffer += " ";
|
|
226
|
+
state = "importRule";
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
|
|
230
|
+
// At-rule
|
|
231
|
+
case "@":
|
|
232
|
+
if (token.indexOf("@-moz-document", i) === i) {
|
|
233
|
+
validateAtRule("@-moz-document", function(){
|
|
234
|
+
state = "documentRule-begin";
|
|
235
|
+
documentRule = new CSSOM.CSSDocumentRule();
|
|
236
|
+
documentRule.__starts = i;
|
|
237
|
+
i += "-moz-document".length;
|
|
238
|
+
});
|
|
239
|
+
buffer = "";
|
|
240
|
+
break;
|
|
241
|
+
} else if (token.indexOf("@media", i) === i) {
|
|
242
|
+
validateAtRule("@media", function(){
|
|
243
|
+
state = "atBlock";
|
|
244
|
+
mediaRule = new CSSOM.CSSMediaRule();
|
|
245
|
+
mediaRule.__starts = i;
|
|
246
|
+
i += "media".length;
|
|
247
|
+
});
|
|
248
|
+
buffer = "";
|
|
249
|
+
break;
|
|
250
|
+
} else if (token.indexOf("@container", i) === i) {
|
|
251
|
+
validateAtRule("@container", function(){
|
|
252
|
+
state = "containerBlock";
|
|
253
|
+
containerRule = new CSSOM.CSSContainerRule();
|
|
254
|
+
containerRule.__starts = i;
|
|
255
|
+
i += "container".length;
|
|
256
|
+
});
|
|
257
|
+
buffer = "";
|
|
258
|
+
break;
|
|
259
|
+
} else if (token.indexOf("@layer", i) === i) {
|
|
260
|
+
validateAtRule("@layer", function(){
|
|
261
|
+
state = "layerBlock"
|
|
262
|
+
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
263
|
+
layerBlockRule.__starts = i;
|
|
264
|
+
i += "layer".length;
|
|
265
|
+
});
|
|
266
|
+
buffer = "";
|
|
267
|
+
break;
|
|
268
|
+
} else if (token.indexOf("@supports", i) === i) {
|
|
269
|
+
validateAtRule("@supports", function(){
|
|
270
|
+
state = "conditionBlock";
|
|
271
|
+
supportsRule = new CSSOM.CSSSupportsRule();
|
|
272
|
+
supportsRule.__starts = i;
|
|
273
|
+
i += "supports".length;
|
|
274
|
+
});
|
|
275
|
+
buffer = "";
|
|
276
|
+
break;
|
|
277
|
+
} else if (token.indexOf("@host", i) === i) {
|
|
278
|
+
validateAtRule("@host", function(){
|
|
279
|
+
state = "hostRule-begin";
|
|
280
|
+
i += "host".length;
|
|
281
|
+
hostRule = new CSSOM.CSSHostRule();
|
|
282
|
+
hostRule.__starts = i;
|
|
283
|
+
});
|
|
284
|
+
buffer = "";
|
|
285
|
+
break;
|
|
286
|
+
} else if (token.indexOf("@starting-style", i) === i) {
|
|
287
|
+
validateAtRule("@starting-style", function(){
|
|
288
|
+
state = "startingStyleRule-begin";
|
|
289
|
+
i += "starting-style".length;
|
|
290
|
+
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
291
|
+
startingStyleRule.__starts = i;
|
|
292
|
+
});
|
|
293
|
+
buffer = "";
|
|
294
|
+
break;
|
|
295
|
+
} else if (token.indexOf("@import", i) === i) {
|
|
296
|
+
buffer = "";
|
|
297
|
+
validateAtRule("@import", function(){
|
|
298
|
+
state = "importRule-begin";
|
|
299
|
+
i += "import".length;
|
|
300
|
+
buffer += "@import";
|
|
301
|
+
}, true);
|
|
302
|
+
break;
|
|
303
|
+
} else if (token.indexOf("@font-face", i) === i) {
|
|
304
|
+
buffer = "";
|
|
305
|
+
validateAtRule("@font-face", function(){
|
|
306
|
+
state = "fontFaceRule-begin";
|
|
307
|
+
i += "font-face".length;
|
|
308
|
+
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
309
|
+
fontFaceRule.__starts = i;
|
|
310
|
+
}, parentRule && parentRule.constructor.name === "CSSStyleRule" );
|
|
311
|
+
break;
|
|
312
|
+
} else {
|
|
313
|
+
atKeyframesRegExp.lastIndex = i;
|
|
314
|
+
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
315
|
+
if (matchKeyframes && matchKeyframes.index === i) {
|
|
316
|
+
state = "keyframesRule-begin";
|
|
317
|
+
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
318
|
+
keyframesRule.__starts = i;
|
|
319
|
+
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
320
|
+
i += matchKeyframes[0].length - 1;
|
|
321
|
+
buffer = "";
|
|
322
|
+
break;
|
|
323
|
+
} else if (state === "selector") {
|
|
324
|
+
state = "atRule";
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
buffer += character;
|
|
328
|
+
break;
|
|
329
|
+
|
|
330
|
+
case "{":
|
|
331
|
+
if (currentScope === styleSheet) {
|
|
332
|
+
nestedSelectorRule = null;
|
|
333
|
+
}
|
|
334
|
+
if (state === "selector" || state === "atRule") {
|
|
335
|
+
if (!nestedSelectorRule && buffer.includes(";")) {
|
|
336
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
337
|
+
if (ruleClosingMatch) {
|
|
338
|
+
styleRule = null;
|
|
339
|
+
buffer = "";
|
|
340
|
+
state = "before-selector";
|
|
341
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
if (parentRule) {
|
|
347
|
+
styleRule.parentRule = parentRule;
|
|
348
|
+
ancestorRules.push(parentRule);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
currentScope = parentRule = styleRule;
|
|
352
|
+
styleRule.selectorText = buffer.trim();
|
|
353
|
+
styleRule.style.__starts = i;
|
|
354
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
355
|
+
buffer = "";
|
|
356
|
+
state = "before-name";
|
|
357
|
+
} else if (state === "atBlock") {
|
|
358
|
+
mediaRule.media.mediaText = buffer.trim();
|
|
359
|
+
|
|
360
|
+
if (parentRule) {
|
|
361
|
+
mediaRule.parentRule = parentRule;
|
|
362
|
+
ancestorRules.push(parentRule);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
currentScope = parentRule = mediaRule;
|
|
366
|
+
mediaRule.parentStyleSheet = styleSheet;
|
|
367
|
+
buffer = "";
|
|
368
|
+
state = "before-selector";
|
|
369
|
+
} else if (state === "containerBlock") {
|
|
370
|
+
containerRule.containerText = buffer.trim();
|
|
371
|
+
|
|
372
|
+
if (parentRule) {
|
|
373
|
+
containerRule.parentRule = parentRule;
|
|
374
|
+
ancestorRules.push(parentRule);
|
|
375
|
+
}
|
|
376
|
+
currentScope = parentRule = containerRule;
|
|
377
|
+
containerRule.parentStyleSheet = styleSheet;
|
|
378
|
+
buffer = "";
|
|
379
|
+
state = "before-selector";
|
|
380
|
+
} else if (state === "conditionBlock") {
|
|
381
|
+
supportsRule.conditionText = buffer.trim();
|
|
382
|
+
|
|
383
|
+
if (parentRule) {
|
|
384
|
+
supportsRule.parentRule = parentRule;
|
|
385
|
+
ancestorRules.push(parentRule);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
currentScope = parentRule = supportsRule;
|
|
389
|
+
supportsRule.parentStyleSheet = styleSheet;
|
|
390
|
+
buffer = "";
|
|
391
|
+
state = "before-selector";
|
|
392
|
+
} else if (state === "layerBlock") {
|
|
393
|
+
layerBlockRule.layerNameText = buffer.trim();
|
|
394
|
+
|
|
395
|
+
if (parentRule) {
|
|
396
|
+
layerBlockRule.parentRule = parentRule;
|
|
397
|
+
ancestorRules.push(parentRule);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
currentScope = parentRule = layerBlockRule;
|
|
401
|
+
layerBlockRule.parentStyleSheet = styleSheet;
|
|
402
|
+
buffer = "";
|
|
403
|
+
state = "before-selector";
|
|
404
|
+
} else if (state === "hostRule-begin") {
|
|
405
|
+
if (parentRule) {
|
|
406
|
+
ancestorRules.push(parentRule);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
currentScope = parentRule = hostRule;
|
|
410
|
+
hostRule.parentStyleSheet = styleSheet;
|
|
411
|
+
buffer = "";
|
|
412
|
+
state = "before-selector";
|
|
413
|
+
} else if (state === "startingStyleRule-begin") {
|
|
414
|
+
if (parentRule) {
|
|
415
|
+
startingStyleRule.parentRule = parentRule;
|
|
416
|
+
ancestorRules.push(parentRule);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
currentScope = parentRule = startingStyleRule;
|
|
420
|
+
startingStyleRule.parentStyleSheet = styleSheet;
|
|
421
|
+
buffer = "";
|
|
422
|
+
state = "before-selector";
|
|
423
|
+
|
|
424
|
+
} else if (state === "fontFaceRule-begin") {
|
|
425
|
+
if (parentRule) {
|
|
426
|
+
fontFaceRule.parentRule = parentRule;
|
|
427
|
+
}
|
|
428
|
+
fontFaceRule.parentStyleSheet = styleSheet;
|
|
429
|
+
styleRule = fontFaceRule;
|
|
430
|
+
buffer = "";
|
|
431
|
+
state = "before-name";
|
|
432
|
+
} else if (state === "keyframesRule-begin") {
|
|
433
|
+
keyframesRule.name = buffer.trim();
|
|
434
|
+
if (parentRule) {
|
|
435
|
+
ancestorRules.push(parentRule);
|
|
436
|
+
keyframesRule.parentRule = parentRule;
|
|
437
|
+
}
|
|
438
|
+
keyframesRule.parentStyleSheet = styleSheet;
|
|
439
|
+
currentScope = parentRule = keyframesRule;
|
|
440
|
+
buffer = "";
|
|
441
|
+
state = "keyframeRule-begin";
|
|
442
|
+
} else if (state === "keyframeRule-begin") {
|
|
443
|
+
styleRule = new CSSOM.CSSKeyframeRule();
|
|
444
|
+
styleRule.keyText = buffer.trim();
|
|
445
|
+
styleRule.__starts = i;
|
|
446
|
+
buffer = "";
|
|
447
|
+
state = "before-name";
|
|
448
|
+
} else if (state === "documentRule-begin") {
|
|
449
|
+
// FIXME: what if this '{' is in the url text of the match function?
|
|
450
|
+
documentRule.matcher.matcherText = buffer.trim();
|
|
451
|
+
if (parentRule) {
|
|
452
|
+
ancestorRules.push(parentRule);
|
|
453
|
+
documentRule.parentRule = parentRule;
|
|
454
|
+
}
|
|
455
|
+
currentScope = parentRule = documentRule;
|
|
456
|
+
documentRule.parentStyleSheet = styleSheet;
|
|
457
|
+
buffer = "";
|
|
458
|
+
state = "before-selector";
|
|
459
|
+
} else if (state === "name") {
|
|
460
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
461
|
+
if (styleRule.style.length) {
|
|
462
|
+
parentRule.cssRules.push(styleRule);
|
|
463
|
+
styleRule.parentRule = parentRule;
|
|
464
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
465
|
+
ancestorRules.push(parentRule);
|
|
466
|
+
} else {
|
|
467
|
+
// If the styleRule is empty, we can assume that it's a nested selector
|
|
468
|
+
ancestorRules.push(parentRule);
|
|
469
|
+
}
|
|
470
|
+
} else {
|
|
471
|
+
currentScope = parentRule = styleRule;
|
|
472
|
+
ancestorRules.push(parentRule);
|
|
473
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
478
|
+
styleRule.selectorText = buffer.trim();
|
|
479
|
+
styleRule.style.__starts = i - buffer.length;
|
|
480
|
+
styleRule.parentRule = parentRule;
|
|
481
|
+
nestedSelectorRule = styleRule;
|
|
482
|
+
|
|
483
|
+
buffer = "";
|
|
484
|
+
state = "before-name";
|
|
485
|
+
}
|
|
486
|
+
break;
|
|
487
|
+
|
|
488
|
+
case ":":
|
|
489
|
+
if (state === "name") {
|
|
490
|
+
// It can be a nested selector, let's check
|
|
491
|
+
var openBraceBeforeMatch = token.slice(i).match(/[{;}]/);
|
|
492
|
+
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
493
|
+
if (hasOpenBraceBefore) {
|
|
494
|
+
// Is a selector
|
|
495
|
+
buffer += character;
|
|
496
|
+
} else {
|
|
497
|
+
// Is a declaration
|
|
498
|
+
name = buffer.trim();
|
|
499
|
+
buffer = "";
|
|
500
|
+
state = "before-value";
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
buffer += character;
|
|
504
|
+
}
|
|
505
|
+
break;
|
|
506
|
+
|
|
507
|
+
case "(":
|
|
508
|
+
if (state === 'value') {
|
|
509
|
+
// ie css expression mode
|
|
510
|
+
if (buffer.trim() === 'expression') {
|
|
511
|
+
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
|
|
512
|
+
|
|
513
|
+
if (info.error) {
|
|
514
|
+
parseError(info.error);
|
|
515
|
+
} else {
|
|
516
|
+
buffer += info.expression;
|
|
517
|
+
i = info.idx;
|
|
518
|
+
}
|
|
519
|
+
} else {
|
|
520
|
+
state = 'value-parenthesis';
|
|
521
|
+
//always ensure this is reset to 1 on transition
|
|
522
|
+
//from value to value-parenthesis
|
|
523
|
+
valueParenthesisDepth = 1;
|
|
524
|
+
buffer += character;
|
|
525
|
+
}
|
|
526
|
+
} else if (state === 'value-parenthesis') {
|
|
527
|
+
valueParenthesisDepth++;
|
|
528
|
+
buffer += character;
|
|
529
|
+
} else {
|
|
530
|
+
buffer += character;
|
|
531
|
+
}
|
|
532
|
+
break;
|
|
533
|
+
|
|
534
|
+
case ")":
|
|
535
|
+
if (state === 'value-parenthesis') {
|
|
536
|
+
valueParenthesisDepth--;
|
|
537
|
+
if (valueParenthesisDepth === 0) state = 'value';
|
|
538
|
+
}
|
|
539
|
+
buffer += character;
|
|
540
|
+
break;
|
|
541
|
+
|
|
542
|
+
case "!":
|
|
543
|
+
if (state === "value" && token.indexOf("!important", i) === i) {
|
|
544
|
+
priority = "important";
|
|
545
|
+
i += "important".length;
|
|
546
|
+
} else {
|
|
547
|
+
buffer += character;
|
|
548
|
+
}
|
|
549
|
+
break;
|
|
550
|
+
|
|
551
|
+
case ";":
|
|
552
|
+
switch (state) {
|
|
553
|
+
case "value":
|
|
554
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
555
|
+
priority = "";
|
|
556
|
+
buffer = "";
|
|
557
|
+
state = "before-name";
|
|
558
|
+
break;
|
|
559
|
+
case "atRule":
|
|
560
|
+
buffer = "";
|
|
561
|
+
state = "before-selector";
|
|
562
|
+
break;
|
|
563
|
+
case "importRule":
|
|
564
|
+
importRule = new CSSOM.CSSImportRule();
|
|
565
|
+
importRule.parentStyleSheet = importRule.styleSheet.parentStyleSheet = styleSheet;
|
|
566
|
+
importRule.cssText = buffer + character;
|
|
567
|
+
styleSheet.cssRules.push(importRule);
|
|
568
|
+
buffer = "";
|
|
569
|
+
state = "before-selector";
|
|
570
|
+
break;
|
|
571
|
+
default:
|
|
572
|
+
buffer += character;
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
break;
|
|
576
|
+
|
|
577
|
+
case "}":
|
|
578
|
+
switch (state) {
|
|
579
|
+
case "value":
|
|
580
|
+
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
581
|
+
priority = "";
|
|
582
|
+
/* falls through */
|
|
583
|
+
case "before-name":
|
|
584
|
+
case "name":
|
|
585
|
+
styleRule.__ends = i + 1;
|
|
586
|
+
|
|
587
|
+
if (parentRule === styleRule) {
|
|
588
|
+
parentRule = ancestorRules.pop()
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (parentRule) {
|
|
592
|
+
styleRule.parentRule = parentRule;
|
|
593
|
+
}
|
|
594
|
+
styleRule.parentStyleSheet = styleSheet;
|
|
595
|
+
|
|
596
|
+
if (currentScope === styleRule) {
|
|
597
|
+
currentScope = parentRule || styleSheet;
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
currentScope.cssRules.push(styleRule);
|
|
601
|
+
buffer = "";
|
|
602
|
+
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
|
|
603
|
+
state = "keyframeRule-begin";
|
|
604
|
+
} else {
|
|
605
|
+
state = "before-selector";
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
609
|
+
if (currentScope !== styleSheet) {
|
|
610
|
+
nestedSelectorRule = currentScope;
|
|
611
|
+
}
|
|
612
|
+
styleRule = null;
|
|
613
|
+
} else {
|
|
614
|
+
styleRule = null;
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
case "keyframeRule-begin":
|
|
618
|
+
case "before-selector":
|
|
619
|
+
case "selector":
|
|
620
|
+
// End of media/supports/document rule.
|
|
621
|
+
if (!parentRule) {
|
|
622
|
+
break;
|
|
623
|
+
//parseError("Unexpected }");
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Handle rules nested in @media or @supports
|
|
627
|
+
hasAncestors = ancestorRules.length > 0;
|
|
628
|
+
|
|
629
|
+
while (ancestorRules.length > 0) {
|
|
630
|
+
parentRule = ancestorRules.pop();
|
|
631
|
+
|
|
632
|
+
if (
|
|
633
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
634
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
635
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
636
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
637
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
638
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
639
|
+
) {
|
|
640
|
+
if (nestedSelectorRule) {
|
|
641
|
+
if (nestedSelectorRule.parentRule) {
|
|
642
|
+
prevScope = nestedSelectorRule;
|
|
643
|
+
currentScope = nestedSelectorRule.parentRule;
|
|
644
|
+
if (currentScope.cssRules.findIndex(function (rule) {
|
|
645
|
+
return rule === prevScope
|
|
646
|
+
}) === -1) {
|
|
647
|
+
currentScope.cssRules.push(prevScope);
|
|
648
|
+
}
|
|
649
|
+
nestedSelectorRule = currentScope;
|
|
650
|
+
}
|
|
651
|
+
} else {
|
|
652
|
+
prevScope = currentScope;
|
|
653
|
+
currentScope = parentRule;
|
|
654
|
+
currentScope.cssRules.push(prevScope);
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
if (ancestorRules.length === 0) {
|
|
660
|
+
hasAncestors = false;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (currentScope.parentRule == null) {
|
|
665
|
+
currentScope.__ends = i + 1;
|
|
666
|
+
if (currentScope !== styleSheet && styleSheet.cssRules.findIndex(function (rule) {
|
|
667
|
+
return rule === currentScope
|
|
668
|
+
}) === -1) {
|
|
669
|
+
styleSheet.cssRules.push(currentScope);
|
|
670
|
+
}
|
|
671
|
+
currentScope = styleSheet;
|
|
672
|
+
if (nestedSelectorRule === parentRule) {
|
|
673
|
+
// Check if this selector is really starting inside another selector
|
|
674
|
+
var nestedSelectorTokenToCurrentSelectorToken = token.slice(nestedSelectorRule.__starts, i + 1);
|
|
675
|
+
|
|
676
|
+
if (nestedSelectorTokenToCurrentSelectorToken.match(/{/g)?.length === nestedSelectorTokenToCurrentSelectorToken.match(/}/g)?.length) {
|
|
677
|
+
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
678
|
+
nestedSelectorRule.__ends = i + 1;
|
|
679
|
+
nestedSelectorRule = null;
|
|
680
|
+
parentRule = null;
|
|
681
|
+
}
|
|
682
|
+
} else {
|
|
683
|
+
parentRule = null;
|
|
684
|
+
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
buffer = "";
|
|
689
|
+
state = "before-selector";
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
break;
|
|
693
|
+
|
|
694
|
+
default:
|
|
695
|
+
switch (state) {
|
|
696
|
+
case "before-selector":
|
|
697
|
+
state = "selector";
|
|
698
|
+
if (styleRule && parentRule) {
|
|
699
|
+
// Assuming it's a declaration inside Nested Selector OR a Nested Declaration
|
|
700
|
+
// If Declaration inside Nested Selector let's keep the same styleRule
|
|
701
|
+
if (
|
|
702
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
703
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
704
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
705
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
706
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
707
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
708
|
+
) {
|
|
709
|
+
// parentRule.parentRule = styleRule;
|
|
710
|
+
state = "before-name";
|
|
711
|
+
if (styleRule !== parentRule) {
|
|
712
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
713
|
+
styleRule.__starts = i;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
} else if (nestedSelectorRule && parentRule && (
|
|
718
|
+
parentRule.constructor.name === "CSSStyleRule"
|
|
719
|
+
|| parentRule.constructor.name === "CSSMediaRule"
|
|
720
|
+
|| parentRule.constructor.name === "CSSSupportsRule"
|
|
721
|
+
|| parentRule.constructor.name === "CSSContainerRule"
|
|
722
|
+
|| parentRule.constructor.name === "CSSLayerBlockRule"
|
|
723
|
+
|| parentRule.constructor.name === "CSSStartingStyleRule"
|
|
724
|
+
)) {
|
|
725
|
+
state = "before-name";
|
|
726
|
+
if (parentRule.cssRules.length) {
|
|
727
|
+
currentScope = nestedSelectorRule = parentRule;
|
|
728
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
729
|
+
styleRule.__starts = i;
|
|
730
|
+
} else {
|
|
731
|
+
if (parentRule.constructor.name === "CSSStyleRule") {
|
|
732
|
+
styleRule = parentRule;
|
|
733
|
+
} else {
|
|
734
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
735
|
+
styleRule.__starts = i;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
} else {
|
|
739
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
740
|
+
styleRule.__starts = i;
|
|
741
|
+
}
|
|
742
|
+
break;
|
|
743
|
+
case "before-name":
|
|
744
|
+
state = "name";
|
|
745
|
+
break;
|
|
746
|
+
case "before-value":
|
|
747
|
+
state = "value";
|
|
748
|
+
break;
|
|
749
|
+
case "importRule-begin":
|
|
750
|
+
state = "importRule";
|
|
751
|
+
break;
|
|
752
|
+
}
|
|
753
|
+
buffer += character;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
return styleSheet;
|
|
759
|
+
};
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
//.CommonJS
|
|
763
|
+
exports.parse = CSSOM.parse;
|
|
764
|
+
// The following modules cannot be included sooner due to the mutual dependency with parse.js
|
|
765
|
+
CSSOM.CSSStyleSheet = require("./CSSStyleSheet").CSSStyleSheet;
|
|
766
|
+
CSSOM.CSSStyleRule = require("./CSSStyleRule").CSSStyleRule;
|
|
767
|
+
CSSOM.CSSNestedDeclarations = require("./CSSNestedDeclarations").CSSNestedDeclarations;
|
|
768
|
+
CSSOM.CSSImportRule = require("./CSSImportRule").CSSImportRule;
|
|
769
|
+
CSSOM.CSSGroupingRule = require("./CSSGroupingRule").CSSGroupingRule;
|
|
770
|
+
CSSOM.CSSMediaRule = require("./CSSMediaRule").CSSMediaRule;
|
|
771
|
+
CSSOM.CSSContainerRule = require("./CSSContainerRule").CSSContainerRule;
|
|
772
|
+
CSSOM.CSSConditionRule = require("./CSSConditionRule").CSSConditionRule;
|
|
773
|
+
CSSOM.CSSSupportsRule = require("./CSSSupportsRule").CSSSupportsRule;
|
|
774
|
+
CSSOM.CSSFontFaceRule = require("./CSSFontFaceRule").CSSFontFaceRule;
|
|
775
|
+
CSSOM.CSSHostRule = require("./CSSHostRule").CSSHostRule;
|
|
776
|
+
CSSOM.CSSStartingStyleRule = require("./CSSStartingStyleRule").CSSStartingStyleRule;
|
|
777
|
+
CSSOM.CSSStyleDeclaration = require('./CSSStyleDeclaration').CSSStyleDeclaration;
|
|
778
|
+
CSSOM.CSSKeyframeRule = require('./CSSKeyframeRule').CSSKeyframeRule;
|
|
779
|
+
CSSOM.CSSKeyframesRule = require('./CSSKeyframesRule').CSSKeyframesRule;
|
|
780
|
+
CSSOM.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
|
|
781
|
+
CSSOM.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
|
|
782
|
+
CSSOM.CSSLayerBlockRule = require("./CSSLayerBlockRule").CSSLayerBlockRule;
|
|
783
|
+
///CommonJS
|