Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81143 views
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
"before-name" or
19
"name" or
20
"before-value" or
21
"value"
22
*/
23
var state = "before-selector";
24
25
var index;
26
var buffer = "";
27
28
var SIGNIFICANT_WHITESPACE = {
29
"selector": true,
30
"value": true,
31
"atRule": true,
32
"importRule-begin": true,
33
"importRule": true,
34
"atBlock": true,
35
'documentRule-begin': true
36
};
37
38
var styleSheet = new CSSOM.CSSStyleSheet;
39
40
// @type CSSStyleSheet|CSSMediaRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
41
var currentScope = styleSheet;
42
43
// @type CSSMediaRule|CSSKeyframesRule|CSSDocumentRule
44
var parentRule;
45
46
var selector, name, value, priority="", styleRule, mediaRule, importRule, fontFaceRule, keyframesRule, keyframeRule, documentRule;
47
48
var atKeyframesRegExp = /@(-(?:\w+-)+)?keyframes/g;
49
50
var parseError = function(message) {
51
var lines = token.substring(0, i).split('\n');
52
var lineCount = lines.length;
53
var charCount = lines.pop().length + 1;
54
var error = new Error(message + ' (line ' + lineCount + ', char ' + charCount + ')');
55
error.line = lineCount;
56
error.char = charCount;
57
error.styleSheet = styleSheet;
58
throw error;
59
};
60
61
for (var character; character = token.charAt(i); i++) {
62
63
switch (character) {
64
65
case " ":
66
case "\t":
67
case "\r":
68
case "\n":
69
case "\f":
70
if (SIGNIFICANT_WHITESPACE[state]) {
71
buffer += character;
72
}
73
break;
74
75
// String
76
case '"':
77
index = i + 1;
78
do {
79
index = token.indexOf('"', index) + 1;
80
if (!index) {
81
parseError('Unmatched "');
82
}
83
} while (token[index - 2] === '\\')
84
buffer += token.slice(i, index);
85
i = index - 1;
86
switch (state) {
87
case 'before-value':
88
state = 'value';
89
break;
90
case 'importRule-begin':
91
state = 'importRule';
92
break;
93
}
94
break;
95
96
case "'":
97
index = i + 1;
98
do {
99
index = token.indexOf("'", index) + 1;
100
if (!index) {
101
parseError("Unmatched '");
102
}
103
} while (token[index - 2] === '\\')
104
buffer += token.slice(i, index);
105
i = index - 1;
106
switch (state) {
107
case 'before-value':
108
state = 'value';
109
break;
110
case 'importRule-begin':
111
state = 'importRule';
112
break;
113
}
114
break;
115
116
// Comment
117
case "/":
118
if (token.charAt(i + 1) === "*") {
119
i += 2;
120
index = token.indexOf("*/", i);
121
if (index === -1) {
122
parseError("Missing */");
123
} else {
124
i = index + 1;
125
}
126
} else {
127
buffer += character;
128
}
129
if (state === "importRule-begin") {
130
buffer += " ";
131
state = "importRule";
132
}
133
break;
134
135
// At-rule
136
case "@":
137
if (token.indexOf("@-moz-document", i) === i) {
138
state = "documentRule-begin";
139
documentRule = new CSSOM.CSSDocumentRule;
140
documentRule.__starts = i;
141
i += "-moz-document".length;
142
buffer = "";
143
break;
144
} else if (token.indexOf("@media", i) === i) {
145
state = "atBlock";
146
mediaRule = new CSSOM.CSSMediaRule;
147
mediaRule.__starts = i;
148
i += "media".length;
149
buffer = "";
150
break;
151
} else if (token.indexOf("@import", i) === i) {
152
state = "importRule-begin";
153
i += "import".length;
154
buffer += "@import";
155
break;
156
} else if (token.indexOf("@font-face", i) === i) {
157
state = "fontFaceRule-begin";
158
i += "font-face".length;
159
fontFaceRule = new CSSOM.CSSFontFaceRule;
160
fontFaceRule.__starts = i;
161
buffer = "";
162
break;
163
} else {
164
atKeyframesRegExp.lastIndex = i;
165
var matchKeyframes = atKeyframesRegExp.exec(token);
166
if (matchKeyframes && matchKeyframes.index === i) {
167
state = "keyframesRule-begin";
168
keyframesRule = new CSSOM.CSSKeyframesRule;
169
keyframesRule.__starts = i;
170
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
171
i += matchKeyframes[0].length - 1;
172
buffer = "";
173
break;
174
} else if (state == "selector") {
175
state = "atRule";
176
}
177
}
178
buffer += character;
179
break;
180
181
case "{":
182
if (state === "selector" || state === "atRule") {
183
styleRule.selectorText = buffer.trim();
184
styleRule.style.__starts = i;
185
buffer = "";
186
state = "before-name";
187
} else if (state === "atBlock") {
188
mediaRule.media.mediaText = buffer.trim();
189
currentScope = parentRule = mediaRule;
190
mediaRule.parentStyleSheet = styleSheet;
191
buffer = "";
192
state = "before-selector";
193
} else if (state === "fontFaceRule-begin") {
194
if (parentRule) {
195
fontFaceRule.parentRule = parentRule;
196
}
197
fontFaceRule.parentStyleSheet = styleSheet;
198
styleRule = fontFaceRule;
199
buffer = "";
200
state = "before-name";
201
} else if (state === "keyframesRule-begin") {
202
keyframesRule.name = buffer.trim();
203
if (parentRule) {
204
keyframesRule.parentRule = parentRule;
205
}
206
keyframesRule.parentStyleSheet = styleSheet;
207
currentScope = parentRule = keyframesRule;
208
buffer = "";
209
state = "keyframeRule-begin";
210
} else if (state === "keyframeRule-begin") {
211
styleRule = new CSSOM.CSSKeyframeRule;
212
styleRule.keyText = buffer.trim();
213
styleRule.__starts = i;
214
buffer = "";
215
state = "before-name";
216
} else if (state === "documentRule-begin") {
217
// FIXME: what if this '{' is in the url text of the match function?
218
documentRule.matcher.matcherText = buffer.trim();
219
if (parentRule) {
220
documentRule.parentRule = parentRule;
221
}
222
currentScope = parentRule = documentRule;
223
documentRule.parentStyleSheet = styleSheet;
224
buffer = "";
225
state = "before-selector";
226
}
227
break;
228
229
case ":":
230
if (state === "name") {
231
name = buffer.trim();
232
buffer = "";
233
state = "before-value";
234
} else {
235
buffer += character;
236
}
237
break;
238
239
case '(':
240
if (state === 'value') {
241
// ie css expression mode
242
if (buffer.trim() == 'expression') {
243
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
244
245
if (info.error) {
246
parseError(info.error);
247
} else {
248
buffer += info.expression;
249
i = info.idx;
250
}
251
} else {
252
index = token.indexOf(')', i + 1);
253
if (index === -1) {
254
parseError('Unmatched "("');
255
}
256
buffer += token.slice(i, index + 1);
257
i = index;
258
}
259
} else {
260
buffer += character;
261
}
262
263
break;
264
265
case "!":
266
if (state === "value" && token.indexOf("!important", i) === i) {
267
priority = "important";
268
i += "important".length;
269
} else {
270
buffer += character;
271
}
272
break;
273
274
case ";":
275
switch (state) {
276
case "value":
277
styleRule.style.setProperty(name, buffer.trim(), priority);
278
priority = "";
279
buffer = "";
280
state = "before-name";
281
break;
282
case "atRule":
283
buffer = "";
284
state = "before-selector";
285
break;
286
case "importRule":
287
importRule = new CSSOM.CSSImportRule;
288
importRule.parentStyleSheet = importRule.styleSheet.parentStyleSheet = styleSheet;
289
importRule.cssText = buffer + character;
290
styleSheet.cssRules.push(importRule);
291
buffer = "";
292
state = "before-selector";
293
break;
294
default:
295
buffer += character;
296
break;
297
}
298
break;
299
300
case "}":
301
switch (state) {
302
case "value":
303
styleRule.style.setProperty(name, buffer.trim(), priority);
304
priority = "";
305
case "before-name":
306
case "name":
307
styleRule.__ends = i + 1;
308
if (parentRule) {
309
styleRule.parentRule = parentRule;
310
}
311
styleRule.parentStyleSheet = styleSheet;
312
currentScope.cssRules.push(styleRule);
313
buffer = "";
314
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
315
state = "keyframeRule-begin";
316
} else {
317
state = "before-selector";
318
}
319
break;
320
case "keyframeRule-begin":
321
case "before-selector":
322
case "selector":
323
// End of media/document rule.
324
if (!parentRule) {
325
parseError("Unexpected }");
326
}
327
currentScope.__ends = i + 1;
328
// Nesting rules aren't supported yet
329
styleSheet.cssRules.push(currentScope);
330
currentScope = styleSheet;
331
parentRule = null;
332
buffer = "";
333
state = "before-selector";
334
break;
335
}
336
break;
337
338
default:
339
switch (state) {
340
case "before-selector":
341
state = "selector";
342
styleRule = new CSSOM.CSSStyleRule;
343
styleRule.__starts = i;
344
break;
345
case "before-name":
346
state = "name";
347
break;
348
case "before-value":
349
state = "value";
350
break;
351
case "importRule-begin":
352
state = "importRule";
353
break;
354
}
355
buffer += character;
356
break;
357
}
358
}
359
360
return styleSheet;
361
};
362
363
364
//.CommonJS
365
exports.parse = CSSOM.parse;
366
// The following modules cannot be included sooner due to the mutual dependency with parse.js
367
CSSOM.CSSStyleSheet = require("./CSSStyleSheet").CSSStyleSheet;
368
CSSOM.CSSStyleRule = require("./CSSStyleRule").CSSStyleRule;
369
CSSOM.CSSImportRule = require("./CSSImportRule").CSSImportRule;
370
CSSOM.CSSMediaRule = require("./CSSMediaRule").CSSMediaRule;
371
CSSOM.CSSFontFaceRule = require("./CSSFontFaceRule").CSSFontFaceRule;
372
CSSOM.CSSStyleDeclaration = require('./CSSStyleDeclaration').CSSStyleDeclaration;
373
CSSOM.CSSKeyframeRule = require('./CSSKeyframeRule').CSSKeyframeRule;
374
CSSOM.CSSKeyframesRule = require('./CSSKeyframesRule').CSSKeyframesRule;
375
CSSOM.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
376
CSSOM.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
377
///CommonJS
378
379