@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/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
+