@acemir/cssom 0.9.24 → 0.9.26
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 +1505 -1236
- package/lib/CSSConditionRule.js +3 -1
- package/lib/CSSContainerRule.js +9 -5
- package/lib/CSSCounterStyleRule.js +36 -2
- package/lib/CSSDocumentRule.js +9 -2
- package/lib/CSSFontFaceRule.js +9 -2
- package/lib/CSSGroupingRule.js +65 -9
- package/lib/CSSHostRule.js +9 -2
- package/lib/CSSImportRule.js +49 -39
- package/lib/CSSKeyframeRule.js +9 -2
- package/lib/CSSKeyframesRule.js +8 -2
- package/lib/CSSLayerBlockRule.js +9 -5
- package/lib/CSSLayerStatementRule.js +9 -5
- package/lib/CSSMediaRule.js +9 -5
- package/lib/CSSNamespaceRule.js +27 -17
- package/lib/CSSNestedDeclarations.js +9 -5
- package/lib/CSSOM.js +16 -1
- package/lib/CSSPageRule.js +3 -152
- package/lib/CSSRule.js +10 -0
- package/lib/CSSScopeRule.js +2 -1
- package/lib/CSSStartingStyleRule.js +9 -2
- package/lib/CSSStyleRule.js +3 -154
- package/lib/CSSStyleSheet.js +50 -9
- package/lib/CSSSupportsRule.js +8 -2
- package/lib/CSSValueExpression.js +3 -1
- package/lib/MediaList.js +22 -7
- package/lib/StyleSheet.js +24 -1
- package/lib/errorUtils.js +8 -13
- package/lib/index.js +2 -0
- package/lib/parse.js +1089 -791
- package/package.json +1 -1
package/build/CSSOM.js
CHANGED
|
@@ -1,4 +1,18 @@
|
|
|
1
|
-
var
|
|
1
|
+
var __globalObject = null;
|
|
2
|
+
|
|
3
|
+
var CSSOM = {
|
|
4
|
+
setup: function(opts) {
|
|
5
|
+
if (opts.globalObject) {
|
|
6
|
+
__globalObject = opts.globalObject;
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
getGlobalObject: function() {
|
|
10
|
+
return __globalObject;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
2
16
|
|
|
3
17
|
|
|
4
18
|
// Utility functions for CSSOM error handling
|
|
@@ -13,19 +27,8 @@ var CSSOM = {};
|
|
|
13
27
|
* @return {Function} The error constructor
|
|
14
28
|
*/
|
|
15
29
|
function getErrorConstructor(context, errorType) {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
return context.parentStyleSheet.__globalObject[errorType];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// Try __parentStyleSheet (alternative naming)
|
|
22
|
-
if (context.__parentStyleSheet && context.__parentStyleSheet.__globalObject && context.__parentStyleSheet.__globalObject[errorType]) {
|
|
23
|
-
return context.__parentStyleSheet.__globalObject[errorType];
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Try __globalObject on the context itself
|
|
27
|
-
if (context.__globalObject && context.__globalObject[errorType]) {
|
|
28
|
-
return context.__globalObject[errorType];
|
|
30
|
+
if (CSSOM.getGlobalObject() && CSSOM.getGlobalObject()[errorType]) {
|
|
31
|
+
return CSSOM.getGlobalObject()[errorType];
|
|
29
32
|
}
|
|
30
33
|
|
|
31
34
|
// Fall back to native constructor
|
|
@@ -344,6 +347,16 @@ Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
|
344
347
|
enumerable: true
|
|
345
348
|
},
|
|
346
349
|
|
|
350
|
+
cssText: {
|
|
351
|
+
get: function() {
|
|
352
|
+
// Default getter: subclasses should override this
|
|
353
|
+
return "";
|
|
354
|
+
},
|
|
355
|
+
set: function(cssText) {
|
|
356
|
+
return cssText;
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
|
|
347
360
|
parentRule: {
|
|
348
361
|
get: function() {
|
|
349
362
|
return this.__parentRule
|
|
@@ -414,9 +427,15 @@ CSSOM.CSSNestedDeclarations = function CSSNestedDeclarations() {
|
|
|
414
427
|
this.__style.parentRule = this;
|
|
415
428
|
};
|
|
416
429
|
|
|
417
|
-
CSSOM.CSSNestedDeclarations.prototype =
|
|
430
|
+
CSSOM.CSSNestedDeclarations.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
418
431
|
CSSOM.CSSNestedDeclarations.prototype.constructor = CSSOM.CSSNestedDeclarations;
|
|
419
|
-
|
|
432
|
+
|
|
433
|
+
Object.setPrototypeOf(CSSOM.CSSNestedDeclarations, CSSOM.CSSRule);
|
|
434
|
+
|
|
435
|
+
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "type", {
|
|
436
|
+
value: 0,
|
|
437
|
+
writable: false
|
|
438
|
+
});
|
|
420
439
|
|
|
421
440
|
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
|
|
422
441
|
get: function() {
|
|
@@ -434,9 +453,7 @@ Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
|
|
|
434
453
|
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
|
|
435
454
|
get: function () {
|
|
436
455
|
return this.style.cssText;
|
|
437
|
-
}
|
|
438
|
-
configurable: true,
|
|
439
|
-
enumerable: true,
|
|
456
|
+
}
|
|
440
457
|
});
|
|
441
458
|
|
|
442
459
|
|
|
@@ -448,12 +465,19 @@ Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
|
|
|
448
465
|
*/
|
|
449
466
|
CSSOM.CSSGroupingRule = function CSSGroupingRule() {
|
|
450
467
|
CSSOM.CSSRule.call(this);
|
|
451
|
-
this.
|
|
468
|
+
this.__cssRules = new CSSOM.CSSRuleList();
|
|
452
469
|
};
|
|
453
470
|
|
|
454
|
-
CSSOM.CSSGroupingRule.prototype
|
|
471
|
+
CSSOM.CSSGroupingRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
455
472
|
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
456
473
|
|
|
474
|
+
Object.setPrototypeOf(CSSOM.CSSGroupingRule, CSSOM.CSSRule);
|
|
475
|
+
|
|
476
|
+
Object.defineProperty(CSSOM.CSSGroupingRule.prototype, "cssRules", {
|
|
477
|
+
get: function() {
|
|
478
|
+
return this.__cssRules;
|
|
479
|
+
}
|
|
480
|
+
});
|
|
457
481
|
|
|
458
482
|
/**
|
|
459
483
|
* Used to insert a new CSS rule to a list of CSS rules.
|
|
@@ -485,13 +509,60 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
485
509
|
if (index > this.cssRules.length) {
|
|
486
510
|
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
487
511
|
}
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
var
|
|
491
|
-
if (
|
|
492
|
-
|
|
512
|
+
var ruleToParse = processedRuleToParse = String(rule);
|
|
513
|
+
ruleToParse = ruleToParse.trim().replace(/^\/\*[\s\S]*?\*\/\s*/, "");
|
|
514
|
+
var isNestedSelector = this.constructor.name === "CSSStyleRule";
|
|
515
|
+
if (isNestedSelector === false) {
|
|
516
|
+
var currentRule = this;
|
|
517
|
+
while (currentRule.parentRule) {
|
|
518
|
+
currentRule = currentRule.parentRule;
|
|
519
|
+
if (currentRule.constructor.name === "CSSStyleRule") {
|
|
520
|
+
isNestedSelector = true;
|
|
521
|
+
break;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
if (isNestedSelector) {
|
|
526
|
+
processedRuleToParse = 's { n { } ' + ruleToParse + '}';
|
|
527
|
+
}
|
|
528
|
+
var isScopeRule = this.constructor.name === "CSSScopeRule";
|
|
529
|
+
if (isScopeRule) {
|
|
530
|
+
if (isNestedSelector) {
|
|
531
|
+
processedRuleToParse = 's { ' + '@scope {' + ruleToParse + '}}';
|
|
532
|
+
} else {
|
|
533
|
+
processedRuleToParse = '@scope {' + ruleToParse + '}';
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
var parsedRules = new CSSOM.CSSRuleList();
|
|
537
|
+
CSSOM.parse(processedRuleToParse, {
|
|
538
|
+
styleSheet: this.parentStyleSheet,
|
|
539
|
+
cssRules: parsedRules
|
|
540
|
+
});
|
|
541
|
+
if (isScopeRule) {
|
|
542
|
+
if (isNestedSelector) {
|
|
543
|
+
parsedRules = parsedRules[0].cssRules[0].cssRules;
|
|
544
|
+
} else {
|
|
545
|
+
parsedRules = parsedRules[0].cssRules
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
if (isNestedSelector) {
|
|
549
|
+
parsedRules = parsedRules[0].cssRules.slice(1);
|
|
550
|
+
}
|
|
551
|
+
if (parsedRules.length !== 1) {
|
|
552
|
+
if (isNestedSelector && parsedRules.length === 0 && ruleToParse.indexOf('@font-face') === 0) {
|
|
553
|
+
errorUtils.throwError(this, 'DOMException',
|
|
554
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
|
|
555
|
+
"Only conditional nested group rules, style rules, @scope rules, @apply rules, and nested declaration rules may be nested.",
|
|
556
|
+
'HierarchyRequestError');
|
|
557
|
+
} else {
|
|
558
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
var cssRule = parsedRules[0];
|
|
562
|
+
|
|
563
|
+
if (cssRule.constructor.name === 'CSSNestedDeclarations' && cssRule.style.length === 0) {
|
|
564
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
493
565
|
}
|
|
494
|
-
var cssRule = parsedSheet.cssRules[0];
|
|
495
566
|
|
|
496
567
|
// Check for rules that cannot be inserted inside a CSSGroupingRule
|
|
497
568
|
if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
@@ -535,7 +606,9 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
535
606
|
if (index >= this.cssRules.length) {
|
|
536
607
|
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
537
608
|
}
|
|
538
|
-
this.cssRules
|
|
609
|
+
this.cssRules[index].__parentRule = null;
|
|
610
|
+
this.cssRules[index].__parentStyleSheet = null;
|
|
611
|
+
this.cssRules.splice(index, 1);
|
|
539
612
|
};
|
|
540
613
|
|
|
541
614
|
|
|
@@ -549,11 +622,45 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
549
622
|
CSSOM.CSSCounterStyleRule = function CSSCounterStyleRule() {
|
|
550
623
|
CSSOM.CSSRule.call(this);
|
|
551
624
|
this.name = "";
|
|
625
|
+
this.__props = "";
|
|
552
626
|
};
|
|
553
627
|
|
|
554
|
-
CSSOM.CSSCounterStyleRule.prototype =
|
|
628
|
+
CSSOM.CSSCounterStyleRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
555
629
|
CSSOM.CSSCounterStyleRule.prototype.constructor = CSSOM.CSSCounterStyleRule;
|
|
556
|
-
|
|
630
|
+
|
|
631
|
+
Object.setPrototypeOf(CSSOM.CSSCounterStyleRule, CSSOM.CSSRule);
|
|
632
|
+
|
|
633
|
+
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "type", {
|
|
634
|
+
value: 11,
|
|
635
|
+
writable: false
|
|
636
|
+
});
|
|
637
|
+
|
|
638
|
+
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "cssText", {
|
|
639
|
+
get: function() {
|
|
640
|
+
// FIXME : Implement real cssText generation based on properties
|
|
641
|
+
return "@counter-style " + this.name + " { " + this.__props + " }";
|
|
642
|
+
}
|
|
643
|
+
});
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* NON-STANDARD
|
|
647
|
+
* Rule text parser.
|
|
648
|
+
* @param {string} cssText
|
|
649
|
+
*/
|
|
650
|
+
Object.defineProperty(CSSOM.CSSCounterStyleRule.prototype, "parse", {
|
|
651
|
+
value: function(cssText) {
|
|
652
|
+
// Extract the name from "@counter-style <name> { ... }"
|
|
653
|
+
var match = cssText.match(/@counter-style\s+([^\s{]+)\s*\{([^]*)\}/);
|
|
654
|
+
if (match) {
|
|
655
|
+
this.name = match[1];
|
|
656
|
+
// Get the text inside the brackets and clean it up
|
|
657
|
+
var propsText = match[2];
|
|
658
|
+
this.__props = propsText.trim().replace(/\n/g, " ").replace(/(['"])(?:\\.|[^\\])*?\1|(\s{2,})/g, function (match, quote) {
|
|
659
|
+
return quote ? match : ' ';
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
});
|
|
557
664
|
|
|
558
665
|
|
|
559
666
|
|
|
@@ -568,9 +675,11 @@ CSSOM.CSSConditionRule = function CSSConditionRule() {
|
|
|
568
675
|
this.__conditionText = '';
|
|
569
676
|
};
|
|
570
677
|
|
|
571
|
-
CSSOM.CSSConditionRule.prototype =
|
|
678
|
+
CSSOM.CSSConditionRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
572
679
|
CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
|
|
573
680
|
|
|
681
|
+
Object.setPrototypeOf(CSSOM.CSSConditionRule, CSSOM.CSSGroupingRule);
|
|
682
|
+
|
|
574
683
|
Object.defineProperty(CSSOM.CSSConditionRule.prototype, "conditionText", {
|
|
575
684
|
get: function () {
|
|
576
685
|
return this.__conditionText;
|
|
@@ -593,9 +702,11 @@ CSSOM.CSSStyleRule = function CSSStyleRule() {
|
|
|
593
702
|
this.__style.parentRule = this;
|
|
594
703
|
};
|
|
595
704
|
|
|
596
|
-
CSSOM.CSSStyleRule.prototype =
|
|
705
|
+
CSSOM.CSSStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
597
706
|
CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
|
|
598
707
|
|
|
708
|
+
Object.setPrototypeOf(CSSOM.CSSStyleRule, CSSOM.CSSGroupingRule);
|
|
709
|
+
|
|
599
710
|
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "type", {
|
|
600
711
|
value: 1,
|
|
601
712
|
writable: false
|
|
@@ -659,163 +770,10 @@ Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
|
659
770
|
text = "";
|
|
660
771
|
}
|
|
661
772
|
return text;
|
|
662
|
-
},
|
|
663
|
-
set: function(cssText) {
|
|
664
|
-
if (typeof cssText === "string") {
|
|
665
|
-
var rule = CSSOM.CSSStyleRule.parse(cssText);
|
|
666
|
-
this.__style = rule.style;
|
|
667
|
-
this.selectorText = rule.selectorText;
|
|
668
|
-
}
|
|
669
773
|
}
|
|
670
774
|
});
|
|
671
775
|
|
|
672
776
|
|
|
673
|
-
/**
|
|
674
|
-
* NON-STANDARD
|
|
675
|
-
* lightweight version of parse.js.
|
|
676
|
-
* @param {string} ruleText
|
|
677
|
-
* @return CSSStyleRule
|
|
678
|
-
*/
|
|
679
|
-
CSSOM.CSSStyleRule.parse = function(ruleText) {
|
|
680
|
-
var i = 0;
|
|
681
|
-
var state = "selector";
|
|
682
|
-
var index;
|
|
683
|
-
var j = i;
|
|
684
|
-
var buffer = "";
|
|
685
|
-
|
|
686
|
-
var SIGNIFICANT_WHITESPACE = {
|
|
687
|
-
"selector": true,
|
|
688
|
-
"value": true
|
|
689
|
-
};
|
|
690
|
-
|
|
691
|
-
var styleRule = new CSSOM.CSSStyleRule();
|
|
692
|
-
var name, priority="";
|
|
693
|
-
|
|
694
|
-
for (var character; (character = ruleText.charAt(i)); i++) {
|
|
695
|
-
|
|
696
|
-
switch (character) {
|
|
697
|
-
|
|
698
|
-
case " ":
|
|
699
|
-
case "\t":
|
|
700
|
-
case "\r":
|
|
701
|
-
case "\n":
|
|
702
|
-
case "\f":
|
|
703
|
-
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
704
|
-
// Squash 2 or more white-spaces in the row into 1
|
|
705
|
-
switch (ruleText.charAt(i - 1)) {
|
|
706
|
-
case " ":
|
|
707
|
-
case "\t":
|
|
708
|
-
case "\r":
|
|
709
|
-
case "\n":
|
|
710
|
-
case "\f":
|
|
711
|
-
break;
|
|
712
|
-
default:
|
|
713
|
-
buffer += " ";
|
|
714
|
-
break;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
break;
|
|
718
|
-
|
|
719
|
-
// String
|
|
720
|
-
case '"':
|
|
721
|
-
j = i + 1;
|
|
722
|
-
index = ruleText.indexOf('"', j) + 1;
|
|
723
|
-
if (!index) {
|
|
724
|
-
throw '" is missing';
|
|
725
|
-
}
|
|
726
|
-
buffer += ruleText.slice(i, index);
|
|
727
|
-
i = index - 1;
|
|
728
|
-
break;
|
|
729
|
-
|
|
730
|
-
case "'":
|
|
731
|
-
j = i + 1;
|
|
732
|
-
index = ruleText.indexOf("'", j) + 1;
|
|
733
|
-
if (!index) {
|
|
734
|
-
throw "' is missing";
|
|
735
|
-
}
|
|
736
|
-
buffer += ruleText.slice(i, index);
|
|
737
|
-
i = index - 1;
|
|
738
|
-
break;
|
|
739
|
-
|
|
740
|
-
// Comment
|
|
741
|
-
case "/":
|
|
742
|
-
if (ruleText.charAt(i + 1) === "*") {
|
|
743
|
-
i += 2;
|
|
744
|
-
index = ruleText.indexOf("*/", i);
|
|
745
|
-
if (index === -1) {
|
|
746
|
-
throw new SyntaxError("Missing */");
|
|
747
|
-
} else {
|
|
748
|
-
i = index + 1;
|
|
749
|
-
}
|
|
750
|
-
} else {
|
|
751
|
-
buffer += character;
|
|
752
|
-
}
|
|
753
|
-
break;
|
|
754
|
-
|
|
755
|
-
case "{":
|
|
756
|
-
if (state === "selector") {
|
|
757
|
-
styleRule.selectorText = buffer.trim();
|
|
758
|
-
buffer = "";
|
|
759
|
-
state = "name";
|
|
760
|
-
}
|
|
761
|
-
break;
|
|
762
|
-
|
|
763
|
-
case ":":
|
|
764
|
-
if (state === "name") {
|
|
765
|
-
name = buffer.trim();
|
|
766
|
-
buffer = "";
|
|
767
|
-
state = "value";
|
|
768
|
-
} else {
|
|
769
|
-
buffer += character;
|
|
770
|
-
}
|
|
771
|
-
break;
|
|
772
|
-
|
|
773
|
-
case "!":
|
|
774
|
-
if (state === "value" && ruleText.indexOf("!important", i) === i) {
|
|
775
|
-
priority = "important";
|
|
776
|
-
i += "important".length;
|
|
777
|
-
} else {
|
|
778
|
-
buffer += character;
|
|
779
|
-
}
|
|
780
|
-
break;
|
|
781
|
-
|
|
782
|
-
case ";":
|
|
783
|
-
if (state === "value") {
|
|
784
|
-
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
785
|
-
priority = "";
|
|
786
|
-
buffer = "";
|
|
787
|
-
state = "name";
|
|
788
|
-
} else {
|
|
789
|
-
buffer += character;
|
|
790
|
-
}
|
|
791
|
-
break;
|
|
792
|
-
|
|
793
|
-
case "}":
|
|
794
|
-
if (state === "value") {
|
|
795
|
-
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
796
|
-
priority = "";
|
|
797
|
-
buffer = "";
|
|
798
|
-
} else if (state === "name") {
|
|
799
|
-
break;
|
|
800
|
-
} else {
|
|
801
|
-
buffer += character;
|
|
802
|
-
}
|
|
803
|
-
state = "selector";
|
|
804
|
-
break;
|
|
805
|
-
|
|
806
|
-
default:
|
|
807
|
-
buffer += character;
|
|
808
|
-
break;
|
|
809
|
-
|
|
810
|
-
}
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
return styleRule;
|
|
814
|
-
|
|
815
|
-
};
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
777
|
|
|
820
778
|
|
|
821
779
|
|
|
@@ -842,12 +800,20 @@ CSSOM.MediaList.prototype = {
|
|
|
842
800
|
* @param {string} value
|
|
843
801
|
*/
|
|
844
802
|
set mediaText(value) {
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
803
|
+
if (typeof value === "string") {
|
|
804
|
+
var values = value.split(",").filter(function(text){
|
|
805
|
+
return !!text;
|
|
806
|
+
});
|
|
807
|
+
var length = this.length = values.length;
|
|
808
|
+
for (var i=0; i<length; i++) {
|
|
809
|
+
this[i] = values[i].trim();
|
|
810
|
+
}
|
|
811
|
+
} else if (value === null) {
|
|
812
|
+
var length = this.length;
|
|
813
|
+
for (var i = 0; i < length; i++) {
|
|
814
|
+
delete this[i];
|
|
815
|
+
}
|
|
816
|
+
this.length = 0;
|
|
851
817
|
}
|
|
852
818
|
},
|
|
853
819
|
|
|
@@ -869,8 +835,15 @@ CSSOM.MediaList.prototype = {
|
|
|
869
835
|
if (index !== -1) {
|
|
870
836
|
Array.prototype.splice.call(this, index, 1);
|
|
871
837
|
}
|
|
872
|
-
}
|
|
838
|
+
},
|
|
839
|
+
|
|
840
|
+
item: function(index) {
|
|
841
|
+
return this[index] || null;
|
|
842
|
+
},
|
|
873
843
|
|
|
844
|
+
toString: function() {
|
|
845
|
+
return this.mediaText;
|
|
846
|
+
}
|
|
874
847
|
};
|
|
875
848
|
|
|
876
849
|
|
|
@@ -888,9 +861,15 @@ CSSOM.CSSMediaRule = function CSSMediaRule() {
|
|
|
888
861
|
this.__media = new CSSOM.MediaList();
|
|
889
862
|
};
|
|
890
863
|
|
|
891
|
-
CSSOM.CSSMediaRule.prototype =
|
|
864
|
+
CSSOM.CSSMediaRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
892
865
|
CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
|
|
893
|
-
|
|
866
|
+
|
|
867
|
+
Object.setPrototypeOf(CSSOM.CSSMediaRule, CSSOM.CSSConditionRule);
|
|
868
|
+
|
|
869
|
+
Object.defineProperty(CSSOM.CSSMediaRule.prototype, "type", {
|
|
870
|
+
value: 4,
|
|
871
|
+
writable: false
|
|
872
|
+
});
|
|
894
873
|
|
|
895
874
|
// https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
|
|
896
875
|
Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
|
|
@@ -926,9 +905,7 @@ Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
|
|
|
926
905
|
}
|
|
927
906
|
values = valuesArr.join("\n ") + "\n}";
|
|
928
907
|
return "@media " + this.media.mediaText + values;
|
|
929
|
-
}
|
|
930
|
-
configurable: true,
|
|
931
|
-
enumerable: true
|
|
908
|
+
}
|
|
932
909
|
}
|
|
933
910
|
});
|
|
934
911
|
|
|
@@ -946,9 +923,15 @@ CSSOM.CSSContainerRule = function CSSContainerRule() {
|
|
|
946
923
|
CSSOM.CSSConditionRule.call(this);
|
|
947
924
|
};
|
|
948
925
|
|
|
949
|
-
CSSOM.CSSContainerRule.prototype =
|
|
926
|
+
CSSOM.CSSContainerRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
950
927
|
CSSOM.CSSContainerRule.prototype.constructor = CSSOM.CSSContainerRule;
|
|
951
|
-
|
|
928
|
+
|
|
929
|
+
Object.setPrototypeOf(CSSOM.CSSContainerRule, CSSOM.CSSConditionRule);
|
|
930
|
+
|
|
931
|
+
Object.defineProperty(CSSOM.CSSContainerRule.prototype, "type", {
|
|
932
|
+
value: 17,
|
|
933
|
+
writable: false
|
|
934
|
+
});
|
|
952
935
|
|
|
953
936
|
Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
|
|
954
937
|
"cssText": {
|
|
@@ -965,9 +948,7 @@ Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
|
|
|
965
948
|
}
|
|
966
949
|
values = valuesArr.join("\n ") + "\n}";
|
|
967
950
|
return "@container " + this.conditionText + values;
|
|
968
|
-
}
|
|
969
|
-
configurable: true,
|
|
970
|
-
enumerable: true
|
|
951
|
+
}
|
|
971
952
|
},
|
|
972
953
|
"containerName": {
|
|
973
954
|
get: function() {
|
|
@@ -1002,9 +983,15 @@ CSSOM.CSSSupportsRule = function CSSSupportsRule() {
|
|
|
1002
983
|
CSSOM.CSSConditionRule.call(this);
|
|
1003
984
|
};
|
|
1004
985
|
|
|
1005
|
-
CSSOM.CSSSupportsRule.prototype =
|
|
986
|
+
CSSOM.CSSSupportsRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
1006
987
|
CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
|
|
1007
|
-
|
|
988
|
+
|
|
989
|
+
Object.setPrototypeOf(CSSOM.CSSSupportsRule, CSSOM.CSSConditionRule);
|
|
990
|
+
|
|
991
|
+
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "type", {
|
|
992
|
+
value: 12,
|
|
993
|
+
writable: false
|
|
994
|
+
});
|
|
1008
995
|
|
|
1009
996
|
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
|
|
1010
997
|
get: function() {
|
|
@@ -1041,9 +1028,11 @@ CSSOM.CSSImportRule = function CSSImportRule() {
|
|
|
1041
1028
|
this.__styleSheet = new CSSOM.CSSStyleSheet();
|
|
1042
1029
|
};
|
|
1043
1030
|
|
|
1044
|
-
CSSOM.CSSImportRule.prototype =
|
|
1031
|
+
CSSOM.CSSImportRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1045
1032
|
CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
|
|
1046
1033
|
|
|
1034
|
+
Object.setPrototypeOf(CSSOM.CSSImportRule, CSSOM.CSSRule);
|
|
1035
|
+
|
|
1047
1036
|
Object.defineProperty(CSSOM.CSSImportRule.prototype, "type", {
|
|
1048
1037
|
value: 3,
|
|
1049
1038
|
writable: false
|
|
@@ -1053,8 +1042,53 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
1053
1042
|
get: function() {
|
|
1054
1043
|
var mediaText = this.media.mediaText;
|
|
1055
1044
|
return "@import url(\"" + this.href.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
1045
|
+
}
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "href", {
|
|
1049
|
+
get: function() {
|
|
1050
|
+
return this.__href;
|
|
1051
|
+
}
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "media", {
|
|
1055
|
+
get: function() {
|
|
1056
|
+
return this.__media;
|
|
1056
1057
|
},
|
|
1057
|
-
|
|
1058
|
+
set: function(value) {
|
|
1059
|
+
if (typeof value === "string") {
|
|
1060
|
+
this.__media.mediaText = value;
|
|
1061
|
+
} else {
|
|
1062
|
+
this.__media = value;
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
|
|
1068
|
+
get: function() {
|
|
1069
|
+
return this.__layerName;
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
|
|
1073
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
|
|
1074
|
+
get: function() {
|
|
1075
|
+
return this.__supportsText;
|
|
1076
|
+
}
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "styleSheet", {
|
|
1080
|
+
get: function() {
|
|
1081
|
+
return this.__styleSheet;
|
|
1082
|
+
}
|
|
1083
|
+
});
|
|
1084
|
+
|
|
1085
|
+
/**
|
|
1086
|
+
* NON-STANDARD
|
|
1087
|
+
* Rule text parser.
|
|
1088
|
+
* @param {string} cssText
|
|
1089
|
+
*/
|
|
1090
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "parse", {
|
|
1091
|
+
value: function(cssText) {
|
|
1058
1092
|
var i = 0;
|
|
1059
1093
|
|
|
1060
1094
|
/**
|
|
@@ -1233,43 +1267,6 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
1233
1267
|
}
|
|
1234
1268
|
});
|
|
1235
1269
|
|
|
1236
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "href", {
|
|
1237
|
-
get: function() {
|
|
1238
|
-
return this.__href;
|
|
1239
|
-
}
|
|
1240
|
-
});
|
|
1241
|
-
|
|
1242
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "media", {
|
|
1243
|
-
get: function() {
|
|
1244
|
-
return this.__media;
|
|
1245
|
-
},
|
|
1246
|
-
set: function(value) {
|
|
1247
|
-
if (typeof value === "string") {
|
|
1248
|
-
this.__media.mediaText = value;
|
|
1249
|
-
} else {
|
|
1250
|
-
this.__media = value;
|
|
1251
|
-
}
|
|
1252
|
-
}
|
|
1253
|
-
});
|
|
1254
|
-
|
|
1255
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
|
|
1256
|
-
get: function() {
|
|
1257
|
-
return this.__layerName;
|
|
1258
|
-
}
|
|
1259
|
-
});
|
|
1260
|
-
|
|
1261
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
|
|
1262
|
-
get: function() {
|
|
1263
|
-
return this.__supportsText;
|
|
1264
|
-
}
|
|
1265
|
-
});
|
|
1266
|
-
|
|
1267
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "styleSheet", {
|
|
1268
|
-
get: function() {
|
|
1269
|
-
return this.__styleSheet;
|
|
1270
|
-
}
|
|
1271
|
-
});
|
|
1272
|
-
|
|
1273
1270
|
|
|
1274
1271
|
|
|
1275
1272
|
|
|
@@ -1285,20 +1282,43 @@ CSSOM.CSSNamespaceRule = function CSSNamespaceRule() {
|
|
|
1285
1282
|
this.__namespaceURI = "";
|
|
1286
1283
|
};
|
|
1287
1284
|
|
|
1288
|
-
CSSOM.CSSNamespaceRule.prototype =
|
|
1285
|
+
CSSOM.CSSNamespaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1289
1286
|
CSSOM.CSSNamespaceRule.prototype.constructor = CSSOM.CSSNamespaceRule;
|
|
1290
1287
|
|
|
1288
|
+
Object.setPrototypeOf(CSSOM.CSSNamespaceRule, CSSOM.CSSRule);
|
|
1289
|
+
|
|
1291
1290
|
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "type", {
|
|
1292
1291
|
value: 10,
|
|
1293
|
-
|
|
1292
|
+
writable: false
|
|
1294
1293
|
});
|
|
1295
1294
|
|
|
1296
1295
|
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
|
|
1297
1296
|
get: function() {
|
|
1298
1297
|
return "@namespace" + (this.prefix && " " + this.prefix) + " url(\"" + this.namespaceURI + "\");";
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
|
|
1301
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
|
|
1302
|
+
get: function() {
|
|
1303
|
+
return this.__prefix;
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
|
|
1307
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
|
|
1308
|
+
get: function() {
|
|
1309
|
+
return this.__namespaceURI;
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* NON-STANDARD
|
|
1316
|
+
* Rule text parser.
|
|
1317
|
+
* @param {string} cssText
|
|
1318
|
+
*/
|
|
1319
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "parse", {
|
|
1320
|
+
value: function(cssText) {
|
|
1321
|
+
var newPrefix = "";
|
|
1302
1322
|
var newNamespaceURI = "";
|
|
1303
1323
|
|
|
1304
1324
|
// Remove @namespace and trim
|
|
@@ -1345,19 +1365,6 @@ Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
|
|
|
1345
1365
|
}
|
|
1346
1366
|
});
|
|
1347
1367
|
|
|
1348
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
|
|
1349
|
-
get: function() {
|
|
1350
|
-
return this.__prefix;
|
|
1351
|
-
}
|
|
1352
|
-
});
|
|
1353
|
-
|
|
1354
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
|
|
1355
|
-
get: function() {
|
|
1356
|
-
return this.__namespaceURI;
|
|
1357
|
-
}
|
|
1358
|
-
});
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
1368
|
|
|
1362
1369
|
|
|
1363
1370
|
|
|
@@ -1371,9 +1378,16 @@ CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
|
|
|
1371
1378
|
this.__style.parentRule = this;
|
|
1372
1379
|
};
|
|
1373
1380
|
|
|
1374
|
-
CSSOM.CSSFontFaceRule.prototype =
|
|
1381
|
+
CSSOM.CSSFontFaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1375
1382
|
CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
|
|
1376
|
-
|
|
1383
|
+
|
|
1384
|
+
Object.setPrototypeOf(CSSOM.CSSFontFaceRule, CSSOM.CSSRule);
|
|
1385
|
+
|
|
1386
|
+
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "type", {
|
|
1387
|
+
value: 5,
|
|
1388
|
+
writable: false
|
|
1389
|
+
});
|
|
1390
|
+
|
|
1377
1391
|
//FIXME
|
|
1378
1392
|
//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1379
1393
|
//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -1414,9 +1428,16 @@ CSSOM.CSSHostRule = function CSSHostRule() {
|
|
|
1414
1428
|
this.cssRules = new CSSOM.CSSRuleList();
|
|
1415
1429
|
};
|
|
1416
1430
|
|
|
1417
|
-
CSSOM.CSSHostRule.prototype =
|
|
1431
|
+
CSSOM.CSSHostRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1418
1432
|
CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
|
|
1419
|
-
|
|
1433
|
+
|
|
1434
|
+
Object.setPrototypeOf(CSSOM.CSSHostRule, CSSOM.CSSRule);
|
|
1435
|
+
|
|
1436
|
+
Object.defineProperty(CSSOM.CSSHostRule.prototype, "type", {
|
|
1437
|
+
value: 1001,
|
|
1438
|
+
writable: false
|
|
1439
|
+
});
|
|
1440
|
+
|
|
1420
1441
|
//FIXME
|
|
1421
1442
|
//CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1422
1443
|
//CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -1451,9 +1472,16 @@ CSSOM.CSSStartingStyleRule = function CSSStartingStyleRule() {
|
|
|
1451
1472
|
CSSOM.CSSGroupingRule.call(this);
|
|
1452
1473
|
};
|
|
1453
1474
|
|
|
1454
|
-
CSSOM.CSSStartingStyleRule.prototype =
|
|
1475
|
+
CSSOM.CSSStartingStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
1455
1476
|
CSSOM.CSSStartingStyleRule.prototype.constructor = CSSOM.CSSStartingStyleRule;
|
|
1456
|
-
|
|
1477
|
+
|
|
1478
|
+
Object.setPrototypeOf(CSSOM.CSSStartingStyleRule, CSSOM.CSSGroupingRule);
|
|
1479
|
+
|
|
1480
|
+
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "type", {
|
|
1481
|
+
value: 1002,
|
|
1482
|
+
writable: false
|
|
1483
|
+
});
|
|
1484
|
+
|
|
1457
1485
|
//FIXME
|
|
1458
1486
|
//CSSOM.CSSStartingStyleRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1459
1487
|
//CSSOM.CSSStartingStyleRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -1481,15 +1509,38 @@ Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
|
|
|
1481
1509
|
|
|
1482
1510
|
|
|
1483
1511
|
/**
|
|
1484
|
-
* @constructor
|
|
1485
1512
|
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
|
|
1486
1513
|
*/
|
|
1487
1514
|
CSSOM.StyleSheet = function StyleSheet() {
|
|
1515
|
+
this.__href = null;
|
|
1516
|
+
this.__ownerNode = null;
|
|
1517
|
+
this.__title = null;
|
|
1488
1518
|
this.__media = new CSSOM.MediaList();
|
|
1489
1519
|
this.__parentStyleSheet = null;
|
|
1520
|
+
this.disabled = false;
|
|
1490
1521
|
};
|
|
1491
1522
|
|
|
1492
1523
|
Object.defineProperties(CSSOM.StyleSheet.prototype, {
|
|
1524
|
+
type: {
|
|
1525
|
+
get: function() {
|
|
1526
|
+
return "text/css";
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1529
|
+
href: {
|
|
1530
|
+
get: function() {
|
|
1531
|
+
return this.__href;
|
|
1532
|
+
}
|
|
1533
|
+
},
|
|
1534
|
+
ownerNode: {
|
|
1535
|
+
get: function() {
|
|
1536
|
+
return this.__ownerNode;
|
|
1537
|
+
}
|
|
1538
|
+
},
|
|
1539
|
+
title: {
|
|
1540
|
+
get: function() {
|
|
1541
|
+
return this.__title;
|
|
1542
|
+
}
|
|
1543
|
+
},
|
|
1493
1544
|
media: {
|
|
1494
1545
|
get: function() {
|
|
1495
1546
|
return this.__media;
|
|
@@ -1515,21 +1566,52 @@ Object.defineProperties(CSSOM.StyleSheet.prototype, {
|
|
|
1515
1566
|
|
|
1516
1567
|
/**
|
|
1517
1568
|
* @constructor
|
|
1569
|
+
* @param {CSSStyleSheetInit} [opts] - CSSStyleSheetInit options.
|
|
1570
|
+
* @param {string} [opts.baseURL] - The base URL of the stylesheet.
|
|
1571
|
+
* @param {boolean} [opts.disabled] - The disabled attribute of the stylesheet.
|
|
1572
|
+
* @param {MediaList | string} [opts.media] - The media attribute of the stylesheet.
|
|
1518
1573
|
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
|
|
1519
1574
|
*/
|
|
1520
|
-
CSSOM.CSSStyleSheet = function CSSStyleSheet() {
|
|
1575
|
+
CSSOM.CSSStyleSheet = function CSSStyleSheet(opts) {
|
|
1521
1576
|
CSSOM.StyleSheet.call(this);
|
|
1522
1577
|
this.__constructed = true;
|
|
1523
|
-
this.
|
|
1578
|
+
this.__cssRules = new CSSOM.CSSRuleList();
|
|
1579
|
+
this.__ownerRule = null;
|
|
1580
|
+
|
|
1581
|
+
if (opts && typeof opts === "object") {
|
|
1582
|
+
if (opts.baseURL && typeof opts.baseURL === "string") {
|
|
1583
|
+
this.__baseURL = opts.baseURL;
|
|
1584
|
+
}
|
|
1585
|
+
if (opts.media && typeof opts.media === "string") {
|
|
1586
|
+
this.media.mediaText = opts.media;
|
|
1587
|
+
}
|
|
1588
|
+
if (typeof opts.disabled === "boolean") {
|
|
1589
|
+
this.disabled = opts.disabled;
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1524
1592
|
};
|
|
1525
1593
|
|
|
1526
1594
|
|
|
1527
|
-
CSSOM.CSSStyleSheet.prototype =
|
|
1595
|
+
CSSOM.CSSStyleSheet.prototype = Object.create(CSSOM.StyleSheet.prototype);
|
|
1528
1596
|
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
1529
1597
|
|
|
1598
|
+
Object.setPrototypeOf(CSSOM.CSSStyleSheet, CSSOM.StyleSheet);
|
|
1599
|
+
|
|
1600
|
+
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "cssRules", {
|
|
1601
|
+
get: function() {
|
|
1602
|
+
return this.__cssRules;
|
|
1603
|
+
}
|
|
1604
|
+
});
|
|
1605
|
+
|
|
1530
1606
|
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "rules", {
|
|
1531
1607
|
get: function() {
|
|
1532
|
-
return this.
|
|
1608
|
+
return this.__cssRules;
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "ownerRule", {
|
|
1613
|
+
get: function() {
|
|
1614
|
+
return this.__ownerRule;
|
|
1533
1615
|
}
|
|
1534
1616
|
});
|
|
1535
1617
|
|
|
@@ -1729,6 +1811,9 @@ CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
|
|
|
1729
1811
|
};
|
|
1730
1812
|
|
|
1731
1813
|
CSSOM.CSSStyleSheet.prototype.removeRule = function(index) {
|
|
1814
|
+
if (index === void 0) {
|
|
1815
|
+
index = 0;
|
|
1816
|
+
}
|
|
1732
1817
|
this.deleteRule(index);
|
|
1733
1818
|
};
|
|
1734
1819
|
|
|
@@ -1741,11 +1826,17 @@ CSSOM.CSSStyleSheet.prototype.removeRule = function(index) {
|
|
|
1741
1826
|
*/
|
|
1742
1827
|
CSSOM.CSSStyleSheet.prototype.replace = function(text) {
|
|
1743
1828
|
var _Promise;
|
|
1744
|
-
if (
|
|
1745
|
-
_Promise =
|
|
1829
|
+
if (CSSOM.getGlobalObject() && CSSOM.getGlobalObject()['Promise']) {
|
|
1830
|
+
_Promise = CSSOM.getGlobalObject()['Promise'];
|
|
1746
1831
|
} else {
|
|
1747
1832
|
_Promise = Promise;
|
|
1748
1833
|
}
|
|
1834
|
+
var _setTimeout;
|
|
1835
|
+
if (CSSOM.getGlobalObject() && CSSOM.getGlobalObject()['setTimeout']) {
|
|
1836
|
+
_setTimeout = CSSOM.getGlobalObject()['setTimeout'];
|
|
1837
|
+
} else {
|
|
1838
|
+
_setTimeout = setTimeout;
|
|
1839
|
+
}
|
|
1749
1840
|
var sheet = this;
|
|
1750
1841
|
return new _Promise(function (resolve, reject) {
|
|
1751
1842
|
// If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
|
|
@@ -1758,7 +1849,7 @@ CSSOM.CSSStyleSheet.prototype.replace = function(text) {
|
|
|
1758
1849
|
sheet.__disallowModification = true;
|
|
1759
1850
|
|
|
1760
1851
|
// In parallel, do these steps:
|
|
1761
|
-
|
|
1852
|
+
_setTimeout(function() {
|
|
1762
1853
|
// Let rules be the result of running parse a stylesheet's contents from text.
|
|
1763
1854
|
var rules = new CSSOM.CSSRuleList();
|
|
1764
1855
|
CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
|
|
@@ -1772,7 +1863,7 @@ CSSOM.CSSStyleSheet.prototype.replace = function(text) {
|
|
|
1772
1863
|
}
|
|
1773
1864
|
}
|
|
1774
1865
|
// Set sheet's CSS rules to rules.
|
|
1775
|
-
sheet.
|
|
1866
|
+
sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
|
|
1776
1867
|
// Unset sheet’s disallow modification flag.
|
|
1777
1868
|
delete sheet.__disallowModification;
|
|
1778
1869
|
// Resolve promise with sheet.
|
|
@@ -1807,7 +1898,7 @@ CSSOM.CSSStyleSheet.prototype.replaceSync = function(text) {
|
|
|
1807
1898
|
}
|
|
1808
1899
|
}
|
|
1809
1900
|
// Set sheet's CSS rules to rules.
|
|
1810
|
-
sheet.
|
|
1901
|
+
sheet.__cssRules.splice.apply(sheet.__cssRules, [0, sheet.__cssRules.length].concat(rules));
|
|
1811
1902
|
}
|
|
1812
1903
|
|
|
1813
1904
|
/**
|
|
@@ -1869,9 +1960,15 @@ CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
|
|
|
1869
1960
|
});
|
|
1870
1961
|
};
|
|
1871
1962
|
|
|
1872
|
-
CSSOM.CSSKeyframesRule.prototype =
|
|
1963
|
+
CSSOM.CSSKeyframesRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1873
1964
|
CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
|
|
1874
|
-
|
|
1965
|
+
|
|
1966
|
+
Object.setPrototypeOf(CSSOM.CSSKeyframesRule, CSSOM.CSSRule);
|
|
1967
|
+
|
|
1968
|
+
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "type", {
|
|
1969
|
+
value: 7,
|
|
1970
|
+
writable: false
|
|
1971
|
+
});
|
|
1875
1972
|
|
|
1876
1973
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
|
|
1877
1974
|
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
|
|
@@ -2071,9 +2168,16 @@ CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
|
|
|
2071
2168
|
this.__style.parentRule = this;
|
|
2072
2169
|
};
|
|
2073
2170
|
|
|
2074
|
-
CSSOM.CSSKeyframeRule.prototype =
|
|
2171
|
+
CSSOM.CSSKeyframeRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
2075
2172
|
CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
|
|
2076
|
-
|
|
2173
|
+
|
|
2174
|
+
Object.setPrototypeOf(CSSOM.CSSKeyframeRule, CSSOM.CSSRule);
|
|
2175
|
+
|
|
2176
|
+
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "type", {
|
|
2177
|
+
value: 8,
|
|
2178
|
+
writable: false
|
|
2179
|
+
});
|
|
2180
|
+
|
|
2077
2181
|
//FIXME
|
|
2078
2182
|
//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
2079
2183
|
//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -2172,9 +2276,16 @@ CSSOM.CSSDocumentRule = function CSSDocumentRule() {
|
|
|
2172
2276
|
this.cssRules = new CSSOM.CSSRuleList();
|
|
2173
2277
|
};
|
|
2174
2278
|
|
|
2175
|
-
CSSOM.CSSDocumentRule.prototype =
|
|
2279
|
+
CSSOM.CSSDocumentRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
2176
2280
|
CSSOM.CSSDocumentRule.prototype.constructor = CSSOM.CSSDocumentRule;
|
|
2177
|
-
|
|
2281
|
+
|
|
2282
|
+
Object.setPrototypeOf(CSSOM.CSSDocumentRule, CSSOM.CSSRule);
|
|
2283
|
+
|
|
2284
|
+
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "type", {
|
|
2285
|
+
value: 10,
|
|
2286
|
+
writable: false
|
|
2287
|
+
});
|
|
2288
|
+
|
|
2178
2289
|
//FIXME
|
|
2179
2290
|
//CSSOM.CSSDocumentRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
2180
2291
|
//CSSOM.CSSDocumentRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -2243,9 +2354,11 @@ CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
|
|
|
2243
2354
|
this._idx = idx;
|
|
2244
2355
|
};
|
|
2245
2356
|
|
|
2246
|
-
CSSOM.CSSValueExpression.prototype =
|
|
2357
|
+
CSSOM.CSSValueExpression.prototype = Object.create(CSSOM.CSSValue.prototype);
|
|
2247
2358
|
CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
|
|
2248
2359
|
|
|
2360
|
+
Object.setPrototypeOf(CSSOM.CSSValueExpression, CSSOM.CSSValue);
|
|
2361
|
+
|
|
2249
2362
|
/**
|
|
2250
2363
|
* parse css expression() value
|
|
2251
2364
|
*
|
|
@@ -2580,9 +2693,10 @@ CSSOM.CSSScopeRule = function CSSScopeRule() {
|
|
|
2580
2693
|
this.__end = null;
|
|
2581
2694
|
};
|
|
2582
2695
|
|
|
2583
|
-
CSSOM.CSSScopeRule.prototype =
|
|
2696
|
+
CSSOM.CSSScopeRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2584
2697
|
CSSOM.CSSScopeRule.prototype.constructor = CSSOM.CSSScopeRule;
|
|
2585
2698
|
|
|
2699
|
+
Object.setPrototypeOf(CSSOM.CSSScopeRule, CSSOM.CSSGroupingRule);
|
|
2586
2700
|
|
|
2587
2701
|
Object.defineProperties(CSSOM.CSSScopeRule.prototype, {
|
|
2588
2702
|
type: {
|
|
@@ -2631,9 +2745,15 @@ CSSOM.CSSLayerBlockRule = function CSSLayerBlockRule() {
|
|
|
2631
2745
|
this.name = "";
|
|
2632
2746
|
};
|
|
2633
2747
|
|
|
2634
|
-
CSSOM.CSSLayerBlockRule.prototype =
|
|
2748
|
+
CSSOM.CSSLayerBlockRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2635
2749
|
CSSOM.CSSLayerBlockRule.prototype.constructor = CSSOM.CSSLayerBlockRule;
|
|
2636
|
-
|
|
2750
|
+
|
|
2751
|
+
Object.setPrototypeOf(CSSOM.CSSLayerBlockRule, CSSOM.CSSRule);
|
|
2752
|
+
|
|
2753
|
+
Object.defineProperty(CSSOM.CSSLayerBlockRule.prototype, "type", {
|
|
2754
|
+
value: 18,
|
|
2755
|
+
writable: false
|
|
2756
|
+
});
|
|
2637
2757
|
|
|
2638
2758
|
Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
|
|
2639
2759
|
cssText: {
|
|
@@ -2650,9 +2770,7 @@ Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
|
|
|
2650
2770
|
}
|
|
2651
2771
|
values = valuesArr.join("\n ") + "\n}";
|
|
2652
2772
|
return "@layer" + (this.name ? " " + this.name : "") + values;
|
|
2653
|
-
}
|
|
2654
|
-
configurable: true,
|
|
2655
|
-
enumerable: true,
|
|
2773
|
+
}
|
|
2656
2774
|
},
|
|
2657
2775
|
});
|
|
2658
2776
|
|
|
@@ -2668,17 +2786,21 @@ CSSOM.CSSLayerStatementRule = function CSSLayerStatementRule() {
|
|
|
2668
2786
|
this.nameList = [];
|
|
2669
2787
|
};
|
|
2670
2788
|
|
|
2671
|
-
CSSOM.CSSLayerStatementRule.prototype =
|
|
2789
|
+
CSSOM.CSSLayerStatementRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
2672
2790
|
CSSOM.CSSLayerStatementRule.prototype.constructor = CSSOM.CSSLayerStatementRule;
|
|
2673
|
-
|
|
2791
|
+
|
|
2792
|
+
Object.setPrototypeOf(CSSOM.CSSLayerStatementRule, CSSOM.CSSRule);
|
|
2793
|
+
|
|
2794
|
+
Object.defineProperty(CSSOM.CSSLayerStatementRule.prototype, "type", {
|
|
2795
|
+
value: 0,
|
|
2796
|
+
writable: false
|
|
2797
|
+
});
|
|
2674
2798
|
|
|
2675
2799
|
Object.defineProperties(CSSOM.CSSLayerStatementRule.prototype, {
|
|
2676
2800
|
cssText: {
|
|
2677
2801
|
get: function () {
|
|
2678
2802
|
return "@layer " + this.nameList.join(", ") + ";";
|
|
2679
|
-
}
|
|
2680
|
-
configurable: true,
|
|
2681
|
-
enumerable: true,
|
|
2803
|
+
}
|
|
2682
2804
|
},
|
|
2683
2805
|
});
|
|
2684
2806
|
|
|
@@ -2696,9 +2818,11 @@ CSSOM.CSSPageRule = function CSSPageRule() {
|
|
|
2696
2818
|
this.__style.parentRule = this;
|
|
2697
2819
|
};
|
|
2698
2820
|
|
|
2699
|
-
CSSOM.CSSPageRule.prototype =
|
|
2821
|
+
CSSOM.CSSPageRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2700
2822
|
CSSOM.CSSPageRule.prototype.constructor = CSSOM.CSSPageRule;
|
|
2701
2823
|
|
|
2824
|
+
Object.setPrototypeOf(CSSOM.CSSPageRule, CSSOM.CSSGroupingRule);
|
|
2825
|
+
|
|
2702
2826
|
Object.defineProperty(CSSOM.CSSPageRule.prototype, "type", {
|
|
2703
2827
|
value: 6,
|
|
2704
2828
|
writable: false
|
|
@@ -2793,161 +2917,9 @@ Object.defineProperty(CSSOM.CSSPageRule.prototype, "cssText", {
|
|
|
2793
2917
|
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
2794
2918
|
}
|
|
2795
2919
|
return "@page" + (this.selectorText ? " " + this.selectorText : "") + values;
|
|
2796
|
-
},
|
|
2797
|
-
set: function(cssText) {
|
|
2798
|
-
if (typeof value === "string") {
|
|
2799
|
-
var rule = CSSOM.CSSPageRule.parse(cssText);
|
|
2800
|
-
this.__style = rule.style;
|
|
2801
|
-
this.selectorText = rule.selectorText;
|
|
2802
|
-
}
|
|
2803
2920
|
}
|
|
2804
2921
|
});
|
|
2805
2922
|
|
|
2806
|
-
/**
|
|
2807
|
-
* NON-STANDARD
|
|
2808
|
-
* lightweight version of parse.js.
|
|
2809
|
-
* @param {string} ruleText
|
|
2810
|
-
* @return CSSPageRule
|
|
2811
|
-
*/
|
|
2812
|
-
CSSOM.CSSPageRule.parse = function(ruleText) {
|
|
2813
|
-
var i = 0;
|
|
2814
|
-
var state = "selector";
|
|
2815
|
-
var index;
|
|
2816
|
-
var j = i;
|
|
2817
|
-
var buffer = "";
|
|
2818
|
-
|
|
2819
|
-
var SIGNIFICANT_WHITESPACE = {
|
|
2820
|
-
"selector": true,
|
|
2821
|
-
"value": true
|
|
2822
|
-
};
|
|
2823
|
-
|
|
2824
|
-
var pageRule = new CSSOM.CSSPageRule();
|
|
2825
|
-
var name, priority="";
|
|
2826
|
-
|
|
2827
|
-
for (var character; (character = ruleText.charAt(i)); i++) {
|
|
2828
|
-
|
|
2829
|
-
switch (character) {
|
|
2830
|
-
|
|
2831
|
-
case " ":
|
|
2832
|
-
case "\t":
|
|
2833
|
-
case "\r":
|
|
2834
|
-
case "\n":
|
|
2835
|
-
case "\f":
|
|
2836
|
-
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
2837
|
-
// Squash 2 or more white-spaces in the row into 1
|
|
2838
|
-
switch (ruleText.charAt(i - 1)) {
|
|
2839
|
-
case " ":
|
|
2840
|
-
case "\t":
|
|
2841
|
-
case "\r":
|
|
2842
|
-
case "\n":
|
|
2843
|
-
case "\f":
|
|
2844
|
-
break;
|
|
2845
|
-
default:
|
|
2846
|
-
buffer += " ";
|
|
2847
|
-
break;
|
|
2848
|
-
}
|
|
2849
|
-
}
|
|
2850
|
-
break;
|
|
2851
|
-
|
|
2852
|
-
// String
|
|
2853
|
-
case '"':
|
|
2854
|
-
j = i + 1;
|
|
2855
|
-
index = ruleText.indexOf('"', j) + 1;
|
|
2856
|
-
if (!index) {
|
|
2857
|
-
throw '" is missing';
|
|
2858
|
-
}
|
|
2859
|
-
buffer += ruleText.slice(i, index);
|
|
2860
|
-
i = index - 1;
|
|
2861
|
-
break;
|
|
2862
|
-
|
|
2863
|
-
case "'":
|
|
2864
|
-
j = i + 1;
|
|
2865
|
-
index = ruleText.indexOf("'", j) + 1;
|
|
2866
|
-
if (!index) {
|
|
2867
|
-
throw "' is missing";
|
|
2868
|
-
}
|
|
2869
|
-
buffer += ruleText.slice(i, index);
|
|
2870
|
-
i = index - 1;
|
|
2871
|
-
break;
|
|
2872
|
-
|
|
2873
|
-
// Comment
|
|
2874
|
-
case "/":
|
|
2875
|
-
if (ruleText.charAt(i + 1) === "*") {
|
|
2876
|
-
i += 2;
|
|
2877
|
-
index = ruleText.indexOf("*/", i);
|
|
2878
|
-
if (index === -1) {
|
|
2879
|
-
throw new SyntaxError("Missing */");
|
|
2880
|
-
} else {
|
|
2881
|
-
i = index + 1;
|
|
2882
|
-
}
|
|
2883
|
-
} else {
|
|
2884
|
-
buffer += character;
|
|
2885
|
-
}
|
|
2886
|
-
break;
|
|
2887
|
-
|
|
2888
|
-
case "{":
|
|
2889
|
-
if (state === "selector") {
|
|
2890
|
-
pageRule.selectorText = buffer.trim();
|
|
2891
|
-
buffer = "";
|
|
2892
|
-
state = "name";
|
|
2893
|
-
}
|
|
2894
|
-
break;
|
|
2895
|
-
|
|
2896
|
-
case ":":
|
|
2897
|
-
if (state === "name") {
|
|
2898
|
-
name = buffer.trim();
|
|
2899
|
-
buffer = "";
|
|
2900
|
-
state = "value";
|
|
2901
|
-
} else {
|
|
2902
|
-
buffer += character;
|
|
2903
|
-
}
|
|
2904
|
-
break;
|
|
2905
|
-
|
|
2906
|
-
case "!":
|
|
2907
|
-
if (state === "value" && ruleText.indexOf("!important", i) === i) {
|
|
2908
|
-
priority = "important";
|
|
2909
|
-
i += "important".length;
|
|
2910
|
-
} else {
|
|
2911
|
-
buffer += character;
|
|
2912
|
-
}
|
|
2913
|
-
break;
|
|
2914
|
-
|
|
2915
|
-
case ";":
|
|
2916
|
-
if (state === "value") {
|
|
2917
|
-
pageRule.style.setProperty(name, buffer.trim(), priority);
|
|
2918
|
-
priority = "";
|
|
2919
|
-
buffer = "";
|
|
2920
|
-
state = "name";
|
|
2921
|
-
} else {
|
|
2922
|
-
buffer += character;
|
|
2923
|
-
}
|
|
2924
|
-
break;
|
|
2925
|
-
|
|
2926
|
-
case "}":
|
|
2927
|
-
if (state === "value") {
|
|
2928
|
-
pageRule.style.setProperty(name, buffer.trim(), priority);
|
|
2929
|
-
priority = "";
|
|
2930
|
-
buffer = "";
|
|
2931
|
-
} else if (state === "name") {
|
|
2932
|
-
break;
|
|
2933
|
-
} else {
|
|
2934
|
-
buffer += character;
|
|
2935
|
-
}
|
|
2936
|
-
state = "selector";
|
|
2937
|
-
break;
|
|
2938
|
-
|
|
2939
|
-
default:
|
|
2940
|
-
buffer += character;
|
|
2941
|
-
break;
|
|
2942
|
-
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
|
-
return pageRule;
|
|
2947
|
-
|
|
2948
|
-
};
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
2923
|
|
|
2952
2924
|
|
|
2953
2925
|
|
|
@@ -2956,7 +2928,9 @@ CSSOM.CSSPageRule.parse = function(ruleText) {
|
|
|
2956
2928
|
*
|
|
2957
2929
|
* @param {string} token - The CSS string to parse.
|
|
2958
2930
|
* @param {object} [opts] - Optional parsing options.
|
|
2959
|
-
* @param {object} [opts.globalObject] - An optional global object to
|
|
2931
|
+
* @param {object} [opts.globalObject] - @deprecated This property will be removed in the next release. Use CSSOM.setup({ globalObject }) instead. - An optional global object to override globals and window. Useful on jsdom webplatform tests.
|
|
2932
|
+
* @param {Element | ProcessingInstruction} [opts.ownerNode] - The owner node of the stylesheet.
|
|
2933
|
+
* @param {CSSRule} [opts.ownerRule] - The owner rule of the stylesheet.
|
|
2960
2934
|
* @param {CSSOM.CSSStyleSheet} [opts.styleSheet] - Reuse a style sheet instead of creating a new one (e.g. as `parentStyleSheet`)
|
|
2961
2935
|
* @param {CSSOM.CSSRuleList} [opts.cssRules] - Prepare all rules in this list instead of mutating the style sheet continually
|
|
2962
2936
|
* @param {function|boolean} [errorHandler] - Optional error handler function or `true` to use `console.error`.
|
|
@@ -3010,6 +2984,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3010
2984
|
styleSheet = opts.styleSheet;
|
|
3011
2985
|
} else {
|
|
3012
2986
|
styleSheet = new CSSOM.CSSStyleSheet()
|
|
2987
|
+
styleSheet.__constructed = false;
|
|
3013
2988
|
}
|
|
3014
2989
|
|
|
3015
2990
|
var topScope;
|
|
@@ -3020,7 +2995,19 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3020
2995
|
}
|
|
3021
2996
|
|
|
3022
2997
|
if (opts && opts.globalObject) {
|
|
3023
|
-
|
|
2998
|
+
CSSOM.setup({ globalObject: opts.globalObject });
|
|
2999
|
+
}
|
|
3000
|
+
|
|
3001
|
+
if (opts && opts.ownerNode) {
|
|
3002
|
+
styleSheet.__ownerNode = opts.ownerNode;
|
|
3003
|
+
var ownerNodeMedia = opts.ownerNode.media || (opts.ownerNode.getAttribute && opts.ownerNode.getAttribute("media"));
|
|
3004
|
+
if (ownerNodeMedia) {
|
|
3005
|
+
styleSheet.media.mediaText = ownerNodeMedia;
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
|
|
3009
|
+
if (opts && opts.ownerRule) {
|
|
3010
|
+
styleSheet.__ownerRule = opts.ownerRule;
|
|
3024
3011
|
}
|
|
3025
3012
|
|
|
3026
3013
|
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
@@ -3032,7 +3019,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3032
3019
|
var ancestorRules = [];
|
|
3033
3020
|
var prevScope;
|
|
3034
3021
|
|
|
3035
|
-
var name, priority="", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, pageRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
3022
|
+
var name, priority = "", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, pageRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
3036
3023
|
|
|
3037
3024
|
// Track defined namespace prefixes for validation
|
|
3038
3025
|
var definedNamespacePrefixes = {};
|
|
@@ -3130,14 +3117,14 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3130
3117
|
var ruleClosingMatch = matchBalancedBlock(str, fromIndex);
|
|
3131
3118
|
if (ruleClosingMatch) {
|
|
3132
3119
|
var ignoreRange = ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
3133
|
-
i+= ignoreRange;
|
|
3120
|
+
i += ignoreRange;
|
|
3134
3121
|
if (token.charAt(i) === '}') {
|
|
3135
3122
|
i -= 1;
|
|
3136
3123
|
}
|
|
3137
3124
|
} else {
|
|
3138
3125
|
i += str.length;
|
|
3139
3126
|
}
|
|
3140
|
-
return i;
|
|
3127
|
+
return i;
|
|
3141
3128
|
}
|
|
3142
3129
|
|
|
3143
3130
|
/**
|
|
@@ -3147,29 +3134,29 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3147
3134
|
*/
|
|
3148
3135
|
function parseScopePrelude(preludeContent) {
|
|
3149
3136
|
var parts = preludeContent.split(/\s*\)\s*to\s+\(/);
|
|
3150
|
-
|
|
3137
|
+
|
|
3151
3138
|
// Restore the parentheses that were consumed by the split
|
|
3152
3139
|
if (parts.length === 2) {
|
|
3153
3140
|
parts[0] = parts[0] + ')';
|
|
3154
3141
|
parts[1] = '(' + parts[1];
|
|
3155
3142
|
}
|
|
3156
|
-
|
|
3143
|
+
|
|
3157
3144
|
var hasStart = parts[0] &&
|
|
3158
3145
|
parts[0].charAt(0) === '(' &&
|
|
3159
3146
|
parts[0].charAt(parts[0].length - 1) === ')';
|
|
3160
3147
|
var hasEnd = parts[1] &&
|
|
3161
3148
|
parts[1].charAt(0) === '(' &&
|
|
3162
3149
|
parts[1].charAt(parts[1].length - 1) === ')';
|
|
3163
|
-
|
|
3150
|
+
|
|
3164
3151
|
// Handle case: @scope to (<end>)
|
|
3165
3152
|
var hasOnlyEnd = !hasStart &&
|
|
3166
3153
|
!hasEnd &&
|
|
3167
3154
|
parts[0].indexOf('to (') === 0 &&
|
|
3168
3155
|
parts[0].charAt(parts[0].length - 1) === ')';
|
|
3169
|
-
|
|
3156
|
+
|
|
3170
3157
|
var startSelector = '';
|
|
3171
3158
|
var endSelector = '';
|
|
3172
|
-
|
|
3159
|
+
|
|
3173
3160
|
if (hasStart) {
|
|
3174
3161
|
startSelector = parts[0].slice(1, -1).trim();
|
|
3175
3162
|
}
|
|
@@ -3179,7 +3166,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3179
3166
|
if (hasOnlyEnd) {
|
|
3180
3167
|
endSelector = parts[0].slice(4, -1).trim();
|
|
3181
3168
|
}
|
|
3182
|
-
|
|
3169
|
+
|
|
3183
3170
|
return {
|
|
3184
3171
|
startSelector: startSelector,
|
|
3185
3172
|
endSelector: endSelector,
|
|
@@ -3217,11 +3204,11 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3217
3204
|
var inDoubleQuote = false;
|
|
3218
3205
|
var inAttr = false;
|
|
3219
3206
|
var stack = useStack ? [] : null;
|
|
3220
|
-
|
|
3207
|
+
|
|
3221
3208
|
for (var i = 0; i < selector.length; i++) {
|
|
3222
3209
|
var char = selector[i];
|
|
3223
3210
|
var prevChar = i > 0 ? selector[i - 1] : '';
|
|
3224
|
-
|
|
3211
|
+
|
|
3225
3212
|
if (inSingleQuote) {
|
|
3226
3213
|
if (char === "'" && prevChar !== "\\") {
|
|
3227
3214
|
inSingleQuote = false;
|
|
@@ -3272,7 +3259,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3272
3259
|
}
|
|
3273
3260
|
}
|
|
3274
3261
|
}
|
|
3275
|
-
|
|
3262
|
+
|
|
3276
3263
|
// Check if everything is balanced
|
|
3277
3264
|
if (useStack) {
|
|
3278
3265
|
return stack.length === 0 && bracketDepth === 0 && !inSingleQuote && !inDoubleQuote && !inAttr;
|
|
@@ -3322,7 +3309,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3322
3309
|
/(?:^|[\s>+~,\[])cue\s*\(/i,
|
|
3323
3310
|
/(?:^|[\s>+~,\[])cue-region\s*\(/i
|
|
3324
3311
|
];
|
|
3325
|
-
|
|
3312
|
+
|
|
3326
3313
|
for (var i = 0; i < invalidPatterns.length; i++) {
|
|
3327
3314
|
if (invalidPatterns[i].test(selector)) {
|
|
3328
3315
|
return true;
|
|
@@ -3368,7 +3355,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3368
3355
|
isValid = true;
|
|
3369
3356
|
}
|
|
3370
3357
|
}
|
|
3371
|
-
|
|
3358
|
+
|
|
3372
3359
|
// Additional validation for @scope rule
|
|
3373
3360
|
if (isValid && atRuleKey === "@scope") {
|
|
3374
3361
|
var openBraceIndex = ruleSlice.indexOf('{');
|
|
@@ -3387,7 +3374,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3387
3374
|
var hasStart = parsedScopePrelude.hasStart;
|
|
3388
3375
|
var hasEnd = parsedScopePrelude.hasEnd;
|
|
3389
3376
|
var hasOnlyEnd = parsedScopePrelude.hasOnlyEnd;
|
|
3390
|
-
|
|
3377
|
+
|
|
3391
3378
|
// Validation rules for @scope:
|
|
3392
3379
|
// 1. Empty selectors in parentheses are invalid: @scope () {} or @scope (.a) to () {}
|
|
3393
3380
|
if ((hasStart && startSelector === '') || (hasEnd && endSelector === '') || (hasOnlyEnd && endSelector === '')) {
|
|
@@ -3423,13 +3410,13 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3423
3410
|
if (openBraceIndex !== -1) {
|
|
3424
3411
|
// Extract the rule prelude (everything between the at-rule and {)
|
|
3425
3412
|
var rulePrelude = ruleSlice.slice(0, openBraceIndex).trim();
|
|
3426
|
-
|
|
3413
|
+
|
|
3427
3414
|
// Skip past at-rule keyword and whitespace
|
|
3428
3415
|
var preludeContent = rulePrelude.slice("@page".length).trim();
|
|
3429
3416
|
|
|
3430
3417
|
if (preludeContent.length > 0) {
|
|
3431
3418
|
var trimmedValue = preludeContent.trim();
|
|
3432
|
-
|
|
3419
|
+
|
|
3433
3420
|
// Empty selector is valid for @page
|
|
3434
3421
|
if (trimmedValue !== '') {
|
|
3435
3422
|
// Parse @page selectorText for page name and pseudo-pages
|
|
@@ -3453,7 +3440,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3453
3440
|
|
|
3454
3441
|
// Validate pseudo-pages if present
|
|
3455
3442
|
if (pseudoPages) {
|
|
3456
|
-
var pseudos = pseudoPages.split(':').filter(function(p) { return p; });
|
|
3443
|
+
var pseudos = pseudoPages.split(':').filter(function (p) { return p; });
|
|
3457
3444
|
var validPseudos = ['left', 'right', 'first', 'blank'];
|
|
3458
3445
|
var allValid = true;
|
|
3459
3446
|
for (var j = 0; j < pseudos.length; j++) {
|
|
@@ -3462,7 +3449,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3462
3449
|
break;
|
|
3463
3450
|
}
|
|
3464
3451
|
}
|
|
3465
|
-
|
|
3452
|
+
|
|
3466
3453
|
if (!allValid) {
|
|
3467
3454
|
isValid = false;
|
|
3468
3455
|
}
|
|
@@ -3471,15 +3458,15 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3471
3458
|
isValid = false;
|
|
3472
3459
|
}
|
|
3473
3460
|
}
|
|
3474
|
-
|
|
3461
|
+
|
|
3475
3462
|
}
|
|
3476
3463
|
}
|
|
3477
3464
|
}
|
|
3478
|
-
|
|
3465
|
+
|
|
3479
3466
|
if (!isValid) {
|
|
3480
3467
|
// If it's invalid the browser will simply ignore the entire invalid block
|
|
3481
3468
|
// Use regex to find the closing brace of the invalid rule
|
|
3482
|
-
|
|
3469
|
+
|
|
3483
3470
|
// Regex used above is not ES5 compliant. Using alternative.
|
|
3484
3471
|
// var ruleStatementMatch = ruleSlice.match(atRulesStatemenRegExp); //
|
|
3485
3472
|
var ruleStatementMatch = atRulesStatemenRegExpES5Alternative(ruleSlice);
|
|
@@ -3494,7 +3481,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3494
3481
|
// Check if there's a semicolon before the invalid at-rule and the first opening brace
|
|
3495
3482
|
if (atRuleKey === "@layer") {
|
|
3496
3483
|
var ruleSemicolonAndOpeningBraceMatch = ruleSlice.match(forwardRuleSemicolonAndOpeningBraceRegExp);
|
|
3497
|
-
if (ruleSemicolonAndOpeningBraceMatch && ruleSemicolonAndOpeningBraceMatch[1] === ";"
|
|
3484
|
+
if (ruleSemicolonAndOpeningBraceMatch && ruleSemicolonAndOpeningBraceMatch[1] === ";") {
|
|
3498
3485
|
// Ignore the rule block until the semicolon
|
|
3499
3486
|
i += ruleSemicolonAndOpeningBraceMatch.index + ruleSemicolonAndOpeningBraceMatch[0].length;
|
|
3500
3487
|
state = "before-selector";
|
|
@@ -3512,7 +3499,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3512
3499
|
|
|
3513
3500
|
// Helper functions for looseSelectorValidator
|
|
3514
3501
|
// Defined outside to avoid recreation on every validation call
|
|
3515
|
-
|
|
3502
|
+
|
|
3516
3503
|
/**
|
|
3517
3504
|
* Check if character is a valid identifier start
|
|
3518
3505
|
* @param {string} c - Character to check
|
|
@@ -3584,19 +3571,19 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3584
3571
|
// Helper: Parse namespace prefix (optional)
|
|
3585
3572
|
function parseNamespace() {
|
|
3586
3573
|
var start = i;
|
|
3587
|
-
|
|
3574
|
+
|
|
3588
3575
|
// Match: *| or identifier| or |
|
|
3589
3576
|
if (i < len && selector[i] === '*') {
|
|
3590
3577
|
i++;
|
|
3591
3578
|
} else if (i < len && (isIdentStart(selector[i]) || selector[i] === '\\')) {
|
|
3592
3579
|
parseIdentifier();
|
|
3593
3580
|
}
|
|
3594
|
-
|
|
3581
|
+
|
|
3595
3582
|
if (i < len && selector[i] === '|') {
|
|
3596
3583
|
i++;
|
|
3597
3584
|
return true;
|
|
3598
3585
|
}
|
|
3599
|
-
|
|
3586
|
+
|
|
3600
3587
|
// Rollback if no pipe found
|
|
3601
3588
|
i = start;
|
|
3602
3589
|
return false;
|
|
@@ -3607,15 +3594,15 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3607
3594
|
if (i >= len || selector[i] !== '(') {
|
|
3608
3595
|
return false;
|
|
3609
3596
|
}
|
|
3610
|
-
|
|
3597
|
+
|
|
3611
3598
|
i++; // Skip opening paren
|
|
3612
3599
|
var depth = 1;
|
|
3613
3600
|
var inString = false;
|
|
3614
3601
|
var stringChar = '';
|
|
3615
|
-
|
|
3602
|
+
|
|
3616
3603
|
while (i < len && depth > 0) {
|
|
3617
3604
|
var c = selector[i];
|
|
3618
|
-
|
|
3605
|
+
|
|
3619
3606
|
if (c === '\\' && i + 1 < len) {
|
|
3620
3607
|
i += 2; // Skip escaped character
|
|
3621
3608
|
} else if (!inString && (c === '"' || c === '\'')) {
|
|
@@ -3635,7 +3622,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3635
3622
|
i++;
|
|
3636
3623
|
}
|
|
3637
3624
|
}
|
|
3638
|
-
|
|
3625
|
+
|
|
3639
3626
|
return depth === 0;
|
|
3640
3627
|
}
|
|
3641
3628
|
|
|
@@ -3737,7 +3724,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3737
3724
|
// Match type selector with optional namespace: [namespace|]identifier
|
|
3738
3725
|
else if (i < len && (isIdentStart(selector[i]) || selector[i] === '\\' || selector[i] === '*' || selector[i] === '|')) {
|
|
3739
3726
|
parseNamespace(); // Optional namespace prefix
|
|
3740
|
-
|
|
3727
|
+
|
|
3741
3728
|
if (i < len && selector[i] === '*') {
|
|
3742
3729
|
i++; // Universal selector
|
|
3743
3730
|
hasMatchedComponent = true;
|
|
@@ -3813,36 +3800,36 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3813
3800
|
// Pseudo-classes like :lang(), :dir(), :nth-*() should not accept quoted strings
|
|
3814
3801
|
// Using iterative parsing instead of regex to avoid exponential backtracking
|
|
3815
3802
|
var noQuotesPseudos = ['lang', 'dir', 'nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type'];
|
|
3816
|
-
|
|
3803
|
+
|
|
3817
3804
|
for (var idx = 0; idx < selector.length; idx++) {
|
|
3818
3805
|
// Look for pseudo-class/element start
|
|
3819
3806
|
if (selector[idx] === ':') {
|
|
3820
3807
|
var pseudoStart = idx;
|
|
3821
3808
|
idx++;
|
|
3822
|
-
|
|
3809
|
+
|
|
3823
3810
|
// Skip second colon for pseudo-elements
|
|
3824
3811
|
if (idx < selector.length && selector[idx] === ':') {
|
|
3825
3812
|
idx++;
|
|
3826
3813
|
}
|
|
3827
|
-
|
|
3814
|
+
|
|
3828
3815
|
// Extract pseudo name
|
|
3829
3816
|
var nameStart = idx;
|
|
3830
3817
|
while (idx < selector.length && /[a-zA-Z0-9\-]/.test(selector[idx])) {
|
|
3831
3818
|
idx++;
|
|
3832
3819
|
}
|
|
3833
|
-
|
|
3820
|
+
|
|
3834
3821
|
if (idx === nameStart) {
|
|
3835
3822
|
continue; // No name found
|
|
3836
3823
|
}
|
|
3837
|
-
|
|
3824
|
+
|
|
3838
3825
|
var pseudoName = selector.substring(nameStart, idx).toLowerCase();
|
|
3839
|
-
|
|
3826
|
+
|
|
3840
3827
|
// Check if this pseudo has arguments
|
|
3841
3828
|
if (idx < selector.length && selector[idx] === '(') {
|
|
3842
3829
|
idx++;
|
|
3843
3830
|
var contentStart = idx;
|
|
3844
3831
|
var depth = 1;
|
|
3845
|
-
|
|
3832
|
+
|
|
3846
3833
|
// Find matching closing paren (handle nesting)
|
|
3847
3834
|
while (idx < selector.length && depth > 0) {
|
|
3848
3835
|
if (selector[idx] === '\\') {
|
|
@@ -3857,10 +3844,10 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3857
3844
|
idx++;
|
|
3858
3845
|
}
|
|
3859
3846
|
}
|
|
3860
|
-
|
|
3847
|
+
|
|
3861
3848
|
if (depth === 0) {
|
|
3862
3849
|
var pseudoContent = selector.substring(contentStart, idx - 1);
|
|
3863
|
-
|
|
3850
|
+
|
|
3864
3851
|
// Check if this pseudo should not have quoted strings
|
|
3865
3852
|
for (var j = 0; j < noQuotesPseudos.length; j++) {
|
|
3866
3853
|
if (pseudoName === noQuotesPseudos[j] && /['"]/.test(pseudoContent)) {
|
|
@@ -3875,7 +3862,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3875
3862
|
// Use the iterative validator to avoid regex backtracking issues
|
|
3876
3863
|
return looseSelectorValidator(selector);
|
|
3877
3864
|
}
|
|
3878
|
-
|
|
3865
|
+
|
|
3879
3866
|
/**
|
|
3880
3867
|
* Regular expression to match CSS pseudo-classes with arguments.
|
|
3881
3868
|
*
|
|
@@ -3894,7 +3881,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3894
3881
|
*
|
|
3895
3882
|
* REPLACED WITH FUNCTION to avoid exponential backtracking.
|
|
3896
3883
|
*/
|
|
3897
|
-
|
|
3884
|
+
|
|
3898
3885
|
/**
|
|
3899
3886
|
* Extract pseudo-classes with arguments from a selector using iterative parsing.
|
|
3900
3887
|
* Replaces the previous globalPseudoClassRegExp to avoid exponential backtracking.
|
|
@@ -3910,30 +3897,30 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3910
3897
|
*/
|
|
3911
3898
|
function extractPseudoClasses(selector) {
|
|
3912
3899
|
var matches = [];
|
|
3913
|
-
|
|
3900
|
+
|
|
3914
3901
|
for (var i = 0; i < selector.length; i++) {
|
|
3915
3902
|
// Look for pseudo-class start (single or double colon)
|
|
3916
3903
|
if (selector[i] === ':') {
|
|
3917
3904
|
var pseudoStart = i;
|
|
3918
3905
|
i++;
|
|
3919
|
-
|
|
3906
|
+
|
|
3920
3907
|
// Skip second colon for pseudo-elements (::)
|
|
3921
3908
|
if (i < selector.length && selector[i] === ':') {
|
|
3922
3909
|
i++;
|
|
3923
3910
|
}
|
|
3924
|
-
|
|
3911
|
+
|
|
3925
3912
|
// Extract pseudo name
|
|
3926
3913
|
var nameStart = i;
|
|
3927
3914
|
while (i < selector.length && /[a-zA-Z\-]/.test(selector[i])) {
|
|
3928
3915
|
i++;
|
|
3929
3916
|
}
|
|
3930
|
-
|
|
3917
|
+
|
|
3931
3918
|
if (i === nameStart) {
|
|
3932
3919
|
continue; // No name found
|
|
3933
3920
|
}
|
|
3934
|
-
|
|
3921
|
+
|
|
3935
3922
|
var pseudoName = selector.substring(nameStart, i);
|
|
3936
|
-
|
|
3923
|
+
|
|
3937
3924
|
// Check if this pseudo has arguments
|
|
3938
3925
|
if (i < selector.length && selector[i] === '(') {
|
|
3939
3926
|
i++;
|
|
@@ -3941,11 +3928,11 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3941
3928
|
var depth = 1;
|
|
3942
3929
|
var inSingleQuote = false;
|
|
3943
3930
|
var inDoubleQuote = false;
|
|
3944
|
-
|
|
3931
|
+
|
|
3945
3932
|
// Find matching closing paren (handle nesting and strings)
|
|
3946
3933
|
while (i < selector.length && depth > 0) {
|
|
3947
3934
|
var ch = selector[i];
|
|
3948
|
-
|
|
3935
|
+
|
|
3949
3936
|
if (ch === '\\') {
|
|
3950
3937
|
i += 2; // Skip escaped character
|
|
3951
3938
|
} else if (ch === "'" && !inDoubleQuote) {
|
|
@@ -3964,21 +3951,21 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3964
3951
|
i++;
|
|
3965
3952
|
}
|
|
3966
3953
|
}
|
|
3967
|
-
|
|
3954
|
+
|
|
3968
3955
|
if (depth === 0) {
|
|
3969
3956
|
var pseudoArgs = selector.substring(argsStart, i - 1);
|
|
3970
3957
|
var fullMatch = selector.substring(pseudoStart, i);
|
|
3971
|
-
|
|
3958
|
+
|
|
3972
3959
|
// Store match in same format as regex: [fullMatch, pseudoName, pseudoArgs, startIndex]
|
|
3973
3960
|
matches.push([fullMatch, pseudoName, pseudoArgs, pseudoStart]);
|
|
3974
3961
|
}
|
|
3975
|
-
|
|
3962
|
+
|
|
3976
3963
|
// Move back one since loop will increment
|
|
3977
3964
|
i--;
|
|
3978
3965
|
}
|
|
3979
3966
|
}
|
|
3980
3967
|
}
|
|
3981
|
-
|
|
3968
|
+
|
|
3982
3969
|
return matches;
|
|
3983
3970
|
}
|
|
3984
3971
|
|
|
@@ -4082,6 +4069,23 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4082
4069
|
var pseudoClass = pseudoClassMatches[j][1];
|
|
4083
4070
|
if (selectorListPseudoClasses.hasOwnProperty(pseudoClass)) {
|
|
4084
4071
|
var nestedSelectors = parseAndSplitNestedSelectors(pseudoClassMatches[j][2]);
|
|
4072
|
+
|
|
4073
|
+
// Check if ANY selector in the list contains & (nesting selector)
|
|
4074
|
+
// If so, skip validation for the entire selector list since & will be replaced at runtime
|
|
4075
|
+
var hasAmpersand = false;
|
|
4076
|
+
for (var k = 0; k < nestedSelectors.length; k++) {
|
|
4077
|
+
if (/&/.test(nestedSelectors[k])) {
|
|
4078
|
+
hasAmpersand = true;
|
|
4079
|
+
break;
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
// If any selector has &, skip validation for this entire pseudo-class
|
|
4084
|
+
if (hasAmpersand) {
|
|
4085
|
+
continue;
|
|
4086
|
+
}
|
|
4087
|
+
|
|
4088
|
+
// Otherwise, validate each selector normally
|
|
4085
4089
|
for (var i = 0; i < nestedSelectors.length; i++) {
|
|
4086
4090
|
var nestedSelector = nestedSelectors[i];
|
|
4087
4091
|
if (!validatedSelectorsCache.hasOwnProperty(nestedSelector)) {
|
|
@@ -4118,10 +4122,10 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4118
4122
|
var inAttr = false;
|
|
4119
4123
|
var inSingleQuote = false;
|
|
4120
4124
|
var inDoubleQuote = false;
|
|
4121
|
-
|
|
4125
|
+
|
|
4122
4126
|
for (var i = 0; i < selector.length; i++) {
|
|
4123
4127
|
var char = selector[i];
|
|
4124
|
-
|
|
4128
|
+
|
|
4125
4129
|
if (inSingleQuote) {
|
|
4126
4130
|
if (char === "'" && selector[i - 1] !== "\\") {
|
|
4127
4131
|
inSingleQuote = false;
|
|
@@ -4148,18 +4152,18 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4148
4152
|
}
|
|
4149
4153
|
}
|
|
4150
4154
|
}
|
|
4151
|
-
|
|
4155
|
+
|
|
4152
4156
|
if (pipeIndex === -1) {
|
|
4153
4157
|
return true; // No namespace, always valid
|
|
4154
4158
|
}
|
|
4155
|
-
|
|
4159
|
+
|
|
4156
4160
|
var namespacePrefix = selector.substring(0, pipeIndex);
|
|
4157
|
-
|
|
4161
|
+
|
|
4158
4162
|
// Universal namespace (*|) and default namespace (|) are always valid
|
|
4159
4163
|
if (namespacePrefix === '*' || namespacePrefix === '') {
|
|
4160
4164
|
return true;
|
|
4161
4165
|
}
|
|
4162
|
-
|
|
4166
|
+
|
|
4163
4167
|
// Check if the custom namespace prefix is defined
|
|
4164
4168
|
return definedNamespacePrefixes.hasOwnProperty(namespacePrefix);
|
|
4165
4169
|
}
|
|
@@ -4168,22 +4172,92 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4168
4172
|
* Processes a CSS selector text
|
|
4169
4173
|
*
|
|
4170
4174
|
* @param {string} selectorText - The CSS selector text to process
|
|
4171
|
-
* @returns {string} The processed selector text with normalized whitespace
|
|
4175
|
+
* @returns {string} The processed selector text with normalized whitespace and invalid selectors removed
|
|
4172
4176
|
*/
|
|
4173
4177
|
function processSelectorText(selectorText) {
|
|
4174
|
-
//
|
|
4175
|
-
|
|
4176
|
-
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
4177
|
-
|
|
4178
|
-
/**
|
|
4179
|
-
* Normalizes whitespace and preserving quoted strings.
|
|
4180
|
-
* Replaces all newline characters (CRLF, CR, or LF) with spaces while keeping quoted
|
|
4181
|
-
* strings (single or double quotes) intact, including any escaped characters within them.
|
|
4182
|
-
*/
|
|
4183
|
-
return selectorText.replace(/(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g, function(match, _, newline) {
|
|
4178
|
+
// Normalize whitespace first
|
|
4179
|
+
var normalized = selectorText.replace(/(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g, function (match, _, newline) {
|
|
4184
4180
|
if (newline) return " ";
|
|
4185
4181
|
return match;
|
|
4186
4182
|
});
|
|
4183
|
+
|
|
4184
|
+
// Recursively process pseudo-classes to handle nesting
|
|
4185
|
+
return processNestedPseudoClasses(normalized);
|
|
4186
|
+
}
|
|
4187
|
+
|
|
4188
|
+
/**
|
|
4189
|
+
* Recursively processes pseudo-classes to filter invalid selectors
|
|
4190
|
+
*
|
|
4191
|
+
* @param {string} selectorText - The CSS selector text to process
|
|
4192
|
+
* @param {number} depth - Current recursion depth (to prevent infinite loops)
|
|
4193
|
+
* @returns {string} The processed selector text with invalid selectors removed
|
|
4194
|
+
*/
|
|
4195
|
+
function processNestedPseudoClasses(selectorText, depth) {
|
|
4196
|
+
// Prevent infinite recursion
|
|
4197
|
+
if (typeof depth === 'undefined') {
|
|
4198
|
+
depth = 0;
|
|
4199
|
+
}
|
|
4200
|
+
if (depth > 10) {
|
|
4201
|
+
return selectorText;
|
|
4202
|
+
}
|
|
4203
|
+
|
|
4204
|
+
var pseudoClassMatches = extractPseudoClasses(selectorText);
|
|
4205
|
+
|
|
4206
|
+
// If no pseudo-classes found, return as-is
|
|
4207
|
+
if (pseudoClassMatches.length === 0) {
|
|
4208
|
+
return selectorText;
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
// Build result by processing matches from right to left (to preserve positions)
|
|
4212
|
+
var result = selectorText;
|
|
4213
|
+
|
|
4214
|
+
for (var j = pseudoClassMatches.length - 1; j >= 0; j--) {
|
|
4215
|
+
var pseudoClass = pseudoClassMatches[j][1];
|
|
4216
|
+
if (selectorListPseudoClasses.hasOwnProperty(pseudoClass)) {
|
|
4217
|
+
var fullMatch = pseudoClassMatches[j][0];
|
|
4218
|
+
var pseudoArgs = pseudoClassMatches[j][2];
|
|
4219
|
+
var matchStart = pseudoClassMatches[j][3];
|
|
4220
|
+
|
|
4221
|
+
// Check if ANY selector contains & BEFORE processing
|
|
4222
|
+
var nestedSelectorsRaw = parseAndSplitNestedSelectors(pseudoArgs);
|
|
4223
|
+
var hasAmpersand = false;
|
|
4224
|
+
for (var k = 0; k < nestedSelectorsRaw.length; k++) {
|
|
4225
|
+
if (/&/.test(nestedSelectorsRaw[k])) {
|
|
4226
|
+
hasAmpersand = true;
|
|
4227
|
+
break;
|
|
4228
|
+
}
|
|
4229
|
+
}
|
|
4230
|
+
|
|
4231
|
+
// If & is present, skip all processing (keep everything unchanged)
|
|
4232
|
+
if (hasAmpersand) {
|
|
4233
|
+
continue;
|
|
4234
|
+
}
|
|
4235
|
+
|
|
4236
|
+
// Recursively process the arguments
|
|
4237
|
+
var processedArgs = processNestedPseudoClasses(pseudoArgs, depth + 1);
|
|
4238
|
+
var nestedSelectors = parseAndSplitNestedSelectors(processedArgs);
|
|
4239
|
+
|
|
4240
|
+
// Filter out invalid selectors
|
|
4241
|
+
var validSelectors = [];
|
|
4242
|
+
for (var i = 0; i < nestedSelectors.length; i++) {
|
|
4243
|
+
var nestedSelector = nestedSelectors[i];
|
|
4244
|
+
if (basicSelectorValidator(nestedSelector)) {
|
|
4245
|
+
validSelectors.push(nestedSelector);
|
|
4246
|
+
}
|
|
4247
|
+
}
|
|
4248
|
+
|
|
4249
|
+
// Reconstruct the pseudo-class with only valid selectors
|
|
4250
|
+
var newArgs = validSelectors.join(', ');
|
|
4251
|
+
var newPseudoClass = ':' + pseudoClass + '(' + newArgs + ')';
|
|
4252
|
+
|
|
4253
|
+
// Replace in the result string using position (processing right to left preserves positions)
|
|
4254
|
+
result = result.substring(0, matchStart) + newPseudoClass + result.substring(matchStart + fullMatch.length);
|
|
4255
|
+
}
|
|
4256
|
+
}
|
|
4257
|
+
|
|
4258
|
+
return result;
|
|
4259
|
+
|
|
4260
|
+
return normalized;
|
|
4187
4261
|
}
|
|
4188
4262
|
|
|
4189
4263
|
/**
|
|
@@ -4197,6 +4271,12 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4197
4271
|
// TODO: The same validations here needs to be reused in CSSStyleRule.selectorText setter
|
|
4198
4272
|
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
4199
4273
|
|
|
4274
|
+
// Check for empty selector lists in pseudo-classes (e.g., :is(), :not(), :where(), :has())
|
|
4275
|
+
// These are invalid after filtering out invalid selectors
|
|
4276
|
+
if (/:(?:is|not|where|has)\(\s*\)/.test(selectorText)) {
|
|
4277
|
+
return false;
|
|
4278
|
+
}
|
|
4279
|
+
|
|
4200
4280
|
// Check for newlines inside single or double quotes using regex
|
|
4201
4281
|
// This matches any quoted string (single or double) containing a newline
|
|
4202
4282
|
var quotedNewlineRegExp = /(['"])(?:\\.|[^\\])*?\1/g;
|
|
@@ -4236,12 +4316,22 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4236
4316
|
// Print the error but continue parsing the sheet
|
|
4237
4317
|
try {
|
|
4238
4318
|
throw error;
|
|
4239
|
-
} catch(e) {
|
|
4319
|
+
} catch (e) {
|
|
4240
4320
|
errorHandler && errorHandler(e);
|
|
4241
4321
|
}
|
|
4242
4322
|
};
|
|
4243
4323
|
|
|
4324
|
+
// Helper functions to check character types
|
|
4325
|
+
function isSelectorStartChar(char) {
|
|
4326
|
+
return '.:#&*['.indexOf(char) !== -1;
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
function isWhitespaceChar(char) {
|
|
4330
|
+
return ' \t\n\r'.indexOf(char) !== -1;
|
|
4331
|
+
}
|
|
4332
|
+
|
|
4244
4333
|
var endingIndex = token.length - 1;
|
|
4334
|
+
var initialEndingIndex = endingIndex;
|
|
4245
4335
|
|
|
4246
4336
|
for (var character; (character = token.charAt(i)); i++) {
|
|
4247
4337
|
if (i === endingIndex) {
|
|
@@ -4251,8 +4341,9 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4251
4341
|
case "layerBlock":
|
|
4252
4342
|
if (character !== ";") {
|
|
4253
4343
|
token += ";";
|
|
4254
|
-
|
|
4344
|
+
endingIndex += 1;
|
|
4255
4345
|
}
|
|
4346
|
+
break;
|
|
4256
4347
|
case "value":
|
|
4257
4348
|
if (character !== "}") {
|
|
4258
4349
|
if (character === ";") {
|
|
@@ -4280,7 +4371,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4280
4371
|
}
|
|
4281
4372
|
}
|
|
4282
4373
|
}
|
|
4283
|
-
|
|
4374
|
+
|
|
4284
4375
|
// Handle escape sequences before processing special characters
|
|
4285
4376
|
// If we encounter a backslash, add both the backslash and the next character to buffer
|
|
4286
4377
|
// and skip the next iteration to prevent the escaped character from being interpreted
|
|
@@ -4289,813 +4380,991 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
4289
4380
|
i++; // Skip the next character
|
|
4290
4381
|
continue;
|
|
4291
4382
|
}
|
|
4292
|
-
|
|
4293
|
-
switch (character) {
|
|
4294
4383
|
|
|
4295
|
-
|
|
4296
|
-
case "\t":
|
|
4297
|
-
case "\r":
|
|
4298
|
-
case "\n":
|
|
4299
|
-
case "\f":
|
|
4300
|
-
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
4301
|
-
buffer += character;
|
|
4302
|
-
}
|
|
4303
|
-
break;
|
|
4384
|
+
switch (character) {
|
|
4304
4385
|
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
if (
|
|
4311
|
-
|
|
4386
|
+
case " ":
|
|
4387
|
+
case "\t":
|
|
4388
|
+
case "\r":
|
|
4389
|
+
case "\n":
|
|
4390
|
+
case "\f":
|
|
4391
|
+
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
4392
|
+
buffer += character;
|
|
4312
4393
|
}
|
|
4313
|
-
} while (token[index - 2] === '\\');
|
|
4314
|
-
if (index === 0) {
|
|
4315
4394
|
break;
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
state = 'importRule';
|
|
4325
|
-
if (i === endingIndex) {
|
|
4326
|
-
token += ';'
|
|
4395
|
+
|
|
4396
|
+
// String
|
|
4397
|
+
case '"':
|
|
4398
|
+
index = i + 1;
|
|
4399
|
+
do {
|
|
4400
|
+
index = token.indexOf('"', index) + 1;
|
|
4401
|
+
if (!index) {
|
|
4402
|
+
parseError('Unmatched "');
|
|
4327
4403
|
}
|
|
4404
|
+
} while (token[index - 2] === '\\');
|
|
4405
|
+
if (index === 0) {
|
|
4328
4406
|
break;
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4407
|
+
}
|
|
4408
|
+
buffer += token.slice(i, index);
|
|
4409
|
+
i = index - 1;
|
|
4410
|
+
switch (state) {
|
|
4411
|
+
case 'before-value':
|
|
4412
|
+
state = 'value';
|
|
4413
|
+
break;
|
|
4414
|
+
case 'importRule-begin':
|
|
4415
|
+
state = 'importRule';
|
|
4416
|
+
if (i === endingIndex) {
|
|
4417
|
+
token += ';'
|
|
4418
|
+
}
|
|
4419
|
+
break;
|
|
4420
|
+
case 'namespaceRule-begin':
|
|
4421
|
+
state = 'namespaceRule';
|
|
4422
|
+
if (i === endingIndex) {
|
|
4423
|
+
token += ';'
|
|
4424
|
+
}
|
|
4425
|
+
break;
|
|
4426
|
+
}
|
|
4427
|
+
break;
|
|
4428
|
+
|
|
4429
|
+
case "'":
|
|
4430
|
+
index = i + 1;
|
|
4431
|
+
do {
|
|
4432
|
+
index = token.indexOf("'", index) + 1;
|
|
4433
|
+
if (!index) {
|
|
4434
|
+
parseError("Unmatched '");
|
|
4333
4435
|
}
|
|
4436
|
+
} while (token[index - 2] === '\\');
|
|
4437
|
+
if (index === 0) {
|
|
4334
4438
|
break;
|
|
4335
|
-
}
|
|
4336
|
-
break;
|
|
4337
|
-
|
|
4338
|
-
case "'":
|
|
4339
|
-
index = i + 1;
|
|
4340
|
-
do {
|
|
4341
|
-
index = token.indexOf("'", index) + 1;
|
|
4342
|
-
if (!index) {
|
|
4343
|
-
parseError("Unmatched '");
|
|
4344
4439
|
}
|
|
4345
|
-
|
|
4346
|
-
|
|
4440
|
+
buffer += token.slice(i, index);
|
|
4441
|
+
i = index - 1;
|
|
4442
|
+
switch (state) {
|
|
4443
|
+
case 'before-value':
|
|
4444
|
+
state = 'value';
|
|
4445
|
+
break;
|
|
4446
|
+
case 'importRule-begin':
|
|
4447
|
+
state = 'importRule';
|
|
4448
|
+
break;
|
|
4449
|
+
case 'namespaceRule-begin':
|
|
4450
|
+
state = 'namespaceRule';
|
|
4451
|
+
break;
|
|
4452
|
+
}
|
|
4347
4453
|
break;
|
|
4348
|
-
}
|
|
4349
|
-
buffer += token.slice(i, index);
|
|
4350
|
-
i = index - 1;
|
|
4351
|
-
switch (state) {
|
|
4352
|
-
case 'before-value':
|
|
4353
|
-
state = 'value';
|
|
4354
|
-
break;
|
|
4355
|
-
case 'importRule-begin':
|
|
4356
|
-
state = 'importRule';
|
|
4357
|
-
break;
|
|
4358
|
-
case 'namespaceRule-begin':
|
|
4359
|
-
state = 'namespaceRule';
|
|
4360
|
-
break;
|
|
4361
|
-
}
|
|
4362
|
-
break;
|
|
4363
4454
|
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4455
|
+
// Comment
|
|
4456
|
+
case "/":
|
|
4457
|
+
if (token.charAt(i + 1) === "*") {
|
|
4458
|
+
i += 2;
|
|
4459
|
+
index = token.indexOf("*/", i);
|
|
4460
|
+
if (index === -1) {
|
|
4461
|
+
i = token.length - 1;
|
|
4462
|
+
buffer = "";
|
|
4463
|
+
} else {
|
|
4464
|
+
i = index + 1;
|
|
4465
|
+
}
|
|
4372
4466
|
} else {
|
|
4373
|
-
|
|
4467
|
+
buffer += character;
|
|
4374
4468
|
}
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
if (state === "importRule-begin") {
|
|
4379
|
-
buffer += " ";
|
|
4380
|
-
state = "importRule";
|
|
4381
|
-
}
|
|
4382
|
-
if (state === "namespaceRule-begin") {
|
|
4383
|
-
buffer += " ";
|
|
4384
|
-
state = "namespaceRule";
|
|
4385
|
-
}
|
|
4386
|
-
break;
|
|
4387
|
-
|
|
4388
|
-
// At-rule
|
|
4389
|
-
case "@":
|
|
4390
|
-
if (nestedSelectorRule) {
|
|
4391
|
-
if (styleRule && styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4392
|
-
currentScope.cssRules.push(styleRule);
|
|
4469
|
+
if (state === "importRule-begin") {
|
|
4470
|
+
buffer += " ";
|
|
4471
|
+
state = "importRule";
|
|
4393
4472
|
}
|
|
4394
|
-
if (
|
|
4395
|
-
|
|
4473
|
+
if (state === "namespaceRule-begin") {
|
|
4474
|
+
buffer += " ";
|
|
4475
|
+
state = "namespaceRule";
|
|
4396
4476
|
}
|
|
4397
|
-
nestedSelectorRule = null;
|
|
4398
|
-
}
|
|
4399
|
-
if (token.indexOf("@-moz-document", i) === i) {
|
|
4400
|
-
validateAtRule("@-moz-document", function(){
|
|
4401
|
-
state = "documentRule-begin";
|
|
4402
|
-
documentRule = new CSSOM.CSSDocumentRule();
|
|
4403
|
-
documentRule.__starts = i;
|
|
4404
|
-
i += "-moz-document".length;
|
|
4405
|
-
});
|
|
4406
|
-
buffer = "";
|
|
4407
|
-
break;
|
|
4408
|
-
} else if (token.indexOf("@media", i) === i) {
|
|
4409
|
-
validateAtRule("@media", function(){
|
|
4410
|
-
state = "atBlock";
|
|
4411
|
-
mediaRule = new CSSOM.CSSMediaRule();
|
|
4412
|
-
mediaRule.__starts = i;
|
|
4413
|
-
i += "media".length;
|
|
4414
|
-
});
|
|
4415
|
-
buffer = "";
|
|
4416
|
-
break;
|
|
4417
|
-
} else if (token.indexOf("@container", i) === i) {
|
|
4418
|
-
validateAtRule("@container", function(){
|
|
4419
|
-
state = "containerBlock";
|
|
4420
|
-
containerRule = new CSSOM.CSSContainerRule();
|
|
4421
|
-
containerRule.__starts = i;
|
|
4422
|
-
i += "container".length;
|
|
4423
|
-
});
|
|
4424
|
-
buffer = "";
|
|
4425
|
-
break;
|
|
4426
|
-
} else if (token.indexOf("@counter-style", i) === i) {
|
|
4427
|
-
validateAtRule("@counter-style", function(){
|
|
4428
|
-
state = "counterStyleBlock"
|
|
4429
|
-
counterStyleRule = new CSSOM.CSSCounterStyleRule();
|
|
4430
|
-
counterStyleRule.__starts = i;
|
|
4431
|
-
i += "counter-style".length;
|
|
4432
|
-
}, true);
|
|
4433
|
-
buffer = "";
|
|
4434
|
-
break;
|
|
4435
|
-
} else if (token.indexOf("@scope", i) === i) {
|
|
4436
|
-
validateAtRule("@scope", function(){
|
|
4437
|
-
state = "scopeBlock";
|
|
4438
|
-
scopeRule = new CSSOM.CSSScopeRule();
|
|
4439
|
-
scopeRule.__starts = i;
|
|
4440
|
-
i += "scope".length;
|
|
4441
|
-
});
|
|
4442
|
-
buffer = "";
|
|
4443
|
-
break;
|
|
4444
|
-
} else if (token.indexOf("@layer", i) === i) {
|
|
4445
|
-
validateAtRule("@layer", function(){
|
|
4446
|
-
state = "layerBlock"
|
|
4447
|
-
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
4448
|
-
layerBlockRule.__starts = i;
|
|
4449
|
-
i += "layer".length;
|
|
4450
|
-
});
|
|
4451
|
-
buffer = "";
|
|
4452
|
-
break;
|
|
4453
|
-
} else if (token.indexOf("@page", i) === i) {
|
|
4454
|
-
validateAtRule("@page", function(){
|
|
4455
|
-
state = "pageBlock"
|
|
4456
|
-
pageRule = new CSSOM.CSSPageRule();
|
|
4457
|
-
pageRule.__starts = i;
|
|
4458
|
-
i += "page".length;
|
|
4459
|
-
});
|
|
4460
|
-
buffer = "";
|
|
4461
|
-
break;
|
|
4462
|
-
} else if (token.indexOf("@supports", i) === i) {
|
|
4463
|
-
validateAtRule("@supports", function(){
|
|
4464
|
-
state = "conditionBlock";
|
|
4465
|
-
supportsRule = new CSSOM.CSSSupportsRule();
|
|
4466
|
-
supportsRule.__starts = i;
|
|
4467
|
-
i += "supports".length;
|
|
4468
|
-
});
|
|
4469
|
-
buffer = "";
|
|
4470
|
-
break;
|
|
4471
|
-
} else if (token.indexOf("@host", i) === i) {
|
|
4472
|
-
validateAtRule("@host", function(){
|
|
4473
|
-
state = "hostRule-begin";
|
|
4474
|
-
i += "host".length;
|
|
4475
|
-
hostRule = new CSSOM.CSSHostRule();
|
|
4476
|
-
hostRule.__starts = i;
|
|
4477
|
-
});
|
|
4478
|
-
buffer = "";
|
|
4479
|
-
break;
|
|
4480
|
-
} else if (token.indexOf("@starting-style", i) === i) {
|
|
4481
|
-
validateAtRule("@starting-style", function(){
|
|
4482
|
-
state = "startingStyleRule-begin";
|
|
4483
|
-
i += "starting-style".length;
|
|
4484
|
-
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
4485
|
-
startingStyleRule.__starts = i;
|
|
4486
|
-
});
|
|
4487
|
-
buffer = "";
|
|
4488
4477
|
break;
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
4493
|
-
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
|
|
4502
|
-
|
|
4503
|
-
|
|
4504
|
-
|
|
4505
|
-
|
|
4506
|
-
|
|
4507
|
-
|
|
4508
|
-
state = "fontFaceRule-begin";
|
|
4509
|
-
i += "font-face".length;
|
|
4510
|
-
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
4511
|
-
fontFaceRule.__starts = i;
|
|
4512
|
-
}, true);
|
|
4513
|
-
break;
|
|
4514
|
-
} else {
|
|
4515
|
-
atKeyframesRegExp.lastIndex = i;
|
|
4516
|
-
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
4517
|
-
if (matchKeyframes && matchKeyframes.index === i) {
|
|
4518
|
-
state = "keyframesRule-begin";
|
|
4519
|
-
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
4520
|
-
keyframesRule.__starts = i;
|
|
4521
|
-
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
4522
|
-
i += matchKeyframes[0].length - 1;
|
|
4478
|
+
|
|
4479
|
+
// At-rule
|
|
4480
|
+
case "@":
|
|
4481
|
+
if (nestedSelectorRule) {
|
|
4482
|
+
if (styleRule && styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4483
|
+
currentScope.cssRules.push(styleRule);
|
|
4484
|
+
}
|
|
4485
|
+
if (nestedSelectorRule.parentRule && nestedSelectorRule.parentRule.constructor.name === "CSSStyleRule") {
|
|
4486
|
+
styleRule = nestedSelectorRule.parentRule;
|
|
4487
|
+
}
|
|
4488
|
+
// Don't reset nestedSelectorRule here - preserve it through @-rules
|
|
4489
|
+
}
|
|
4490
|
+
if (token.indexOf("@-moz-document", i) === i) {
|
|
4491
|
+
validateAtRule("@-moz-document", function () {
|
|
4492
|
+
state = "documentRule-begin";
|
|
4493
|
+
documentRule = new CSSOM.CSSDocumentRule();
|
|
4494
|
+
documentRule.__starts = i;
|
|
4495
|
+
i += "-moz-document".length;
|
|
4496
|
+
});
|
|
4523
4497
|
buffer = "";
|
|
4524
4498
|
break;
|
|
4525
|
-
} else if (
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4499
|
+
} else if (token.indexOf("@media", i) === i) {
|
|
4500
|
+
validateAtRule("@media", function () {
|
|
4501
|
+
state = "atBlock";
|
|
4502
|
+
mediaRule = new CSSOM.CSSMediaRule();
|
|
4503
|
+
mediaRule.__starts = i;
|
|
4504
|
+
i += "media".length;
|
|
4505
|
+
});
|
|
4506
|
+
buffer = "";
|
|
4507
|
+
break;
|
|
4508
|
+
} else if (token.indexOf("@container", i) === i) {
|
|
4509
|
+
validateAtRule("@container", function () {
|
|
4510
|
+
state = "containerBlock";
|
|
4511
|
+
containerRule = new CSSOM.CSSContainerRule();
|
|
4512
|
+
containerRule.__starts = i;
|
|
4513
|
+
i += "container".length;
|
|
4514
|
+
});
|
|
4515
|
+
buffer = "";
|
|
4516
|
+
break;
|
|
4517
|
+
} else if (token.indexOf("@counter-style", i) === i) {
|
|
4518
|
+
validateAtRule("@counter-style", function () {
|
|
4519
|
+
state = "counterStyleBlock"
|
|
4520
|
+
counterStyleRule = new CSSOM.CSSCounterStyleRule();
|
|
4521
|
+
counterStyleRule.__starts = i;
|
|
4522
|
+
i += "counter-style".length;
|
|
4523
|
+
}, true);
|
|
4524
|
+
buffer = "";
|
|
4525
|
+
break;
|
|
4526
|
+
} else if (token.indexOf("@scope", i) === i) {
|
|
4527
|
+
validateAtRule("@scope", function () {
|
|
4528
|
+
state = "scopeBlock";
|
|
4529
|
+
scopeRule = new CSSOM.CSSScopeRule();
|
|
4530
|
+
scopeRule.__starts = i;
|
|
4531
|
+
i += "scope".length;
|
|
4532
|
+
});
|
|
4533
|
+
buffer = "";
|
|
4534
|
+
break;
|
|
4535
|
+
} else if (token.indexOf("@layer", i) === i) {
|
|
4536
|
+
validateAtRule("@layer", function () {
|
|
4537
|
+
state = "layerBlock"
|
|
4538
|
+
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
4539
|
+
layerBlockRule.__starts = i;
|
|
4540
|
+
i += "layer".length;
|
|
4541
|
+
});
|
|
4542
|
+
buffer = "";
|
|
4543
|
+
break;
|
|
4544
|
+
} else if (token.indexOf("@page", i) === i) {
|
|
4545
|
+
validateAtRule("@page", function () {
|
|
4546
|
+
state = "pageBlock"
|
|
4547
|
+
pageRule = new CSSOM.CSSPageRule();
|
|
4548
|
+
pageRule.__starts = i;
|
|
4549
|
+
i += "page".length;
|
|
4550
|
+
});
|
|
4551
|
+
buffer = "";
|
|
4552
|
+
break;
|
|
4553
|
+
} else if (token.indexOf("@supports", i) === i) {
|
|
4554
|
+
validateAtRule("@supports", function () {
|
|
4555
|
+
state = "conditionBlock";
|
|
4556
|
+
supportsRule = new CSSOM.CSSSupportsRule();
|
|
4557
|
+
supportsRule.__starts = i;
|
|
4558
|
+
i += "supports".length;
|
|
4559
|
+
});
|
|
4560
|
+
buffer = "";
|
|
4561
|
+
break;
|
|
4562
|
+
} else if (token.indexOf("@host", i) === i) {
|
|
4563
|
+
validateAtRule("@host", function () {
|
|
4564
|
+
state = "hostRule-begin";
|
|
4565
|
+
i += "host".length;
|
|
4566
|
+
hostRule = new CSSOM.CSSHostRule();
|
|
4567
|
+
hostRule.__starts = i;
|
|
4568
|
+
});
|
|
4569
|
+
buffer = "";
|
|
4570
|
+
break;
|
|
4571
|
+
} else if (token.indexOf("@starting-style", i) === i) {
|
|
4572
|
+
validateAtRule("@starting-style", function () {
|
|
4573
|
+
state = "startingStyleRule-begin";
|
|
4574
|
+
i += "starting-style".length;
|
|
4575
|
+
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
4576
|
+
startingStyleRule.__starts = i;
|
|
4577
|
+
});
|
|
4578
|
+
buffer = "";
|
|
4579
|
+
break;
|
|
4580
|
+
} else if (token.indexOf("@import", i) === i) {
|
|
4581
|
+
buffer = "";
|
|
4582
|
+
validateAtRule("@import", function () {
|
|
4583
|
+
state = "importRule-begin";
|
|
4584
|
+
i += "import".length;
|
|
4585
|
+
buffer += "@import";
|
|
4586
|
+
}, true);
|
|
4587
|
+
break;
|
|
4588
|
+
} else if (token.indexOf("@namespace", i) === i) {
|
|
4589
|
+
buffer = "";
|
|
4590
|
+
validateAtRule("@namespace", function () {
|
|
4591
|
+
state = "namespaceRule-begin";
|
|
4592
|
+
i += "namespace".length;
|
|
4593
|
+
buffer += "@namespace";
|
|
4594
|
+
}, true);
|
|
4595
|
+
break;
|
|
4596
|
+
} else if (token.indexOf("@font-face", i) === i) {
|
|
4597
|
+
buffer = "";
|
|
4598
|
+
// @font-face can be nested only inside CSSScopeRule or CSSConditionRule
|
|
4599
|
+
// and only if there's no CSSStyleRule in the parent chain
|
|
4600
|
+
var cannotBeNested = true;
|
|
4601
|
+
if (currentScope !== topScope) {
|
|
4602
|
+
var hasStyleRuleInChain = false;
|
|
4603
|
+
var hasValidParent = false;
|
|
4604
|
+
|
|
4605
|
+
// Check currentScope
|
|
4606
|
+
if (currentScope.constructor.name === 'CSSStyleRule') {
|
|
4607
|
+
hasStyleRuleInChain = true;
|
|
4608
|
+
} else if (currentScope instanceof CSSOM.CSSScopeRule || currentScope instanceof CSSOM.CSSConditionRule) {
|
|
4609
|
+
hasValidParent = true;
|
|
4610
|
+
}
|
|
4531
4611
|
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
|
|
4539
|
-
|
|
4540
|
-
|
|
4541
|
-
|
|
4542
|
-
|
|
4543
|
-
|
|
4544
|
-
|
|
4545
|
-
|
|
4612
|
+
// Check ancestorRules for CSSStyleRule
|
|
4613
|
+
if (!hasStyleRuleInChain) {
|
|
4614
|
+
for (var j = 0; j < ancestorRules.length; j++) {
|
|
4615
|
+
if (ancestorRules[j].constructor.name === 'CSSStyleRule') {
|
|
4616
|
+
hasStyleRuleInChain = true;
|
|
4617
|
+
break;
|
|
4618
|
+
}
|
|
4619
|
+
if (ancestorRules[j] instanceof CSSOM.CSSScopeRule || ancestorRules[j] instanceof CSSOM.CSSConditionRule) {
|
|
4620
|
+
hasValidParent = true;
|
|
4621
|
+
}
|
|
4622
|
+
}
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4625
|
+
// Allow nesting if we have a valid parent and no style rule in the chain
|
|
4626
|
+
if (hasValidParent && !hasStyleRuleInChain) {
|
|
4627
|
+
cannotBeNested = false;
|
|
4628
|
+
}
|
|
4629
|
+
}
|
|
4630
|
+
validateAtRule("@font-face", function () {
|
|
4631
|
+
state = "fontFaceRule-begin";
|
|
4632
|
+
i += "font-face".length;
|
|
4633
|
+
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
4634
|
+
fontFaceRule.__starts = i;
|
|
4635
|
+
}, cannotBeNested);
|
|
4636
|
+
break;
|
|
4637
|
+
} else {
|
|
4638
|
+
atKeyframesRegExp.lastIndex = i;
|
|
4639
|
+
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
4640
|
+
if (matchKeyframes && matchKeyframes.index === i) {
|
|
4641
|
+
state = "keyframesRule-begin";
|
|
4642
|
+
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
4643
|
+
keyframesRule.__starts = i;
|
|
4644
|
+
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
4645
|
+
i += matchKeyframes[0].length - 1;
|
|
4546
4646
|
buffer = "";
|
|
4547
|
-
state = "before-selector";
|
|
4548
|
-
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
4549
4647
|
break;
|
|
4648
|
+
} else if (state === "selector") {
|
|
4649
|
+
state = "atRule";
|
|
4550
4650
|
}
|
|
4551
4651
|
}
|
|
4652
|
+
buffer += character;
|
|
4653
|
+
break;
|
|
4552
4654
|
|
|
4553
|
-
|
|
4554
|
-
|
|
4555
|
-
|
|
4556
|
-
}
|
|
4557
|
-
|
|
4558
|
-
currentScope = parentRule = styleRule;
|
|
4559
|
-
styleRule.selectorText = processSelectorText(buffer.trim());
|
|
4560
|
-
styleRule.style.__starts = i;
|
|
4561
|
-
styleRule.__parentStyleSheet = styleSheet;
|
|
4562
|
-
buffer = "";
|
|
4563
|
-
state = "before-name";
|
|
4564
|
-
} else if (state === "atBlock") {
|
|
4565
|
-
mediaRule.media.mediaText = buffer.trim();
|
|
4566
|
-
|
|
4567
|
-
if (parentRule) {
|
|
4568
|
-
mediaRule.__parentRule = parentRule;
|
|
4569
|
-
pushToAncestorRules(parentRule);
|
|
4570
|
-
}
|
|
4571
|
-
|
|
4572
|
-
currentScope = parentRule = mediaRule;
|
|
4573
|
-
mediaRule.__parentStyleSheet = styleSheet;
|
|
4574
|
-
buffer = "";
|
|
4575
|
-
state = "before-selector";
|
|
4576
|
-
} else if (state === "containerBlock") {
|
|
4577
|
-
containerRule.__conditionText = buffer.trim();
|
|
4578
|
-
|
|
4579
|
-
if (parentRule) {
|
|
4580
|
-
containerRule.__parentRule = parentRule;
|
|
4581
|
-
pushToAncestorRules(parentRule);
|
|
4582
|
-
}
|
|
4583
|
-
currentScope = parentRule = containerRule;
|
|
4584
|
-
containerRule.__parentStyleSheet = styleSheet;
|
|
4585
|
-
buffer = "";
|
|
4586
|
-
state = "before-selector";
|
|
4587
|
-
} else if (state === "counterStyleBlock") {
|
|
4588
|
-
// TODO: Validate counter-style name. At least that it cannot be empty nor multiple
|
|
4589
|
-
counterStyleRule.name = buffer.trim().replace(/\n/g, "");
|
|
4590
|
-
currentScope = parentRule = counterStyleRule;
|
|
4591
|
-
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
4592
|
-
buffer = "";
|
|
4593
|
-
} else if (state === "conditionBlock") {
|
|
4594
|
-
supportsRule.__conditionText = buffer.trim();
|
|
4595
|
-
|
|
4596
|
-
if (parentRule) {
|
|
4597
|
-
supportsRule.__parentRule = parentRule;
|
|
4598
|
-
pushToAncestorRules(parentRule);
|
|
4599
|
-
}
|
|
4600
|
-
|
|
4601
|
-
currentScope = parentRule = supportsRule;
|
|
4602
|
-
supportsRule.__parentStyleSheet = styleSheet;
|
|
4603
|
-
buffer = "";
|
|
4604
|
-
state = "before-selector";
|
|
4605
|
-
} else if (state === "scopeBlock") {
|
|
4606
|
-
var parsedScopePrelude = parseScopePrelude(buffer.trim());
|
|
4607
|
-
|
|
4608
|
-
if (parsedScopePrelude.hasStart) {
|
|
4609
|
-
scopeRule.__start = parsedScopePrelude.startSelector;
|
|
4655
|
+
case "{":
|
|
4656
|
+
if (currentScope === topScope) {
|
|
4657
|
+
nestedSelectorRule = null;
|
|
4610
4658
|
}
|
|
4611
|
-
if (
|
|
4612
|
-
|
|
4613
|
-
|
|
4614
|
-
|
|
4615
|
-
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4659
|
+
if (state === 'before-selector') {
|
|
4660
|
+
parseError("Unexpected {");
|
|
4661
|
+
i = ignoreBalancedBlock(i, token.slice(i));
|
|
4662
|
+
break;
|
|
4616
4663
|
}
|
|
4664
|
+
if (state === "selector" || state === "atRule") {
|
|
4665
|
+
if (!nestedSelectorRule && buffer.indexOf(";") !== -1) {
|
|
4666
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
4667
|
+
if (ruleClosingMatch) {
|
|
4668
|
+
styleRule = null;
|
|
4669
|
+
buffer = "";
|
|
4670
|
+
state = "before-selector";
|
|
4671
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
4672
|
+
break;
|
|
4673
|
+
}
|
|
4674
|
+
}
|
|
4617
4675
|
|
|
4618
|
-
|
|
4619
|
-
|
|
4620
|
-
|
|
4621
|
-
|
|
4622
|
-
|
|
4623
|
-
scopeRule.__parentStyleSheet = styleSheet;
|
|
4624
|
-
buffer = "";
|
|
4625
|
-
state = "before-selector";
|
|
4626
|
-
} else if (state === "layerBlock") {
|
|
4627
|
-
layerBlockRule.name = buffer.trim();
|
|
4676
|
+
// Ensure styleRule exists before trying to set properties on it
|
|
4677
|
+
if (!styleRule) {
|
|
4678
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
4679
|
+
styleRule.__starts = i;
|
|
4680
|
+
}
|
|
4628
4681
|
|
|
4629
|
-
|
|
4682
|
+
var originalParentRule = parentRule;
|
|
4630
4683
|
|
|
4631
|
-
if (isValidName) {
|
|
4632
4684
|
if (parentRule) {
|
|
4633
|
-
|
|
4685
|
+
styleRule.__parentRule = parentRule;
|
|
4634
4686
|
pushToAncestorRules(parentRule);
|
|
4635
4687
|
}
|
|
4636
|
-
|
|
4637
|
-
currentScope = parentRule = layerBlockRule;
|
|
4638
|
-
layerBlockRule.__parentStyleSheet = styleSheet;
|
|
4639
|
-
}
|
|
4640
|
-
buffer = "";
|
|
4641
|
-
state = "before-selector";
|
|
4642
|
-
} else if (state === "pageBlock") {
|
|
4643
|
-
pageRule.selectorText = buffer.trim();
|
|
4644
|
-
|
|
4645
|
-
if (parentRule) {
|
|
4646
|
-
pageRule.__parentRule = parentRule;
|
|
4647
|
-
pushToAncestorRules(parentRule);
|
|
4648
|
-
}
|
|
4649
4688
|
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4689
|
+
currentScope = parentRule = styleRule;
|
|
4690
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
4691
|
+
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
4692
|
+
if (originalParentRule && originalParentRule.constructor.name === "CSSStyleRule") {
|
|
4693
|
+
styleRule.selectorText = parseAndSplitNestedSelectors(processedSelectorText).map(function (sel) {
|
|
4694
|
+
// Add & at the beginning if there's no & in the selector, or if it starts with a combinator
|
|
4695
|
+
return (sel.indexOf('&') === -1 || startsWithCombinatorRegExp.test(sel)) ? '& ' + sel : sel;
|
|
4696
|
+
}).join(', ');
|
|
4697
|
+
} else {
|
|
4698
|
+
styleRule.selectorText = processedSelectorText;
|
|
4699
|
+
}
|
|
4700
|
+
styleRule.style.__starts = i;
|
|
4701
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
4702
|
+
buffer = "";
|
|
4703
|
+
state = "before-name";
|
|
4704
|
+
} else if (state === "atBlock") {
|
|
4705
|
+
mediaRule.media.mediaText = buffer.trim();
|
|
4659
4706
|
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4667
|
-
|
|
4668
|
-
|
|
4707
|
+
if (parentRule) {
|
|
4708
|
+
mediaRule.__parentRule = parentRule;
|
|
4709
|
+
pushToAncestorRules(parentRule);
|
|
4710
|
+
// If entering @media from within a CSSStyleRule, set nestedSelectorRule
|
|
4711
|
+
// so that & selectors and declarations work correctly inside
|
|
4712
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4713
|
+
nestedSelectorRule = parentRule;
|
|
4714
|
+
}
|
|
4715
|
+
}
|
|
4669
4716
|
|
|
4670
|
-
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4717
|
+
currentScope = parentRule = mediaRule;
|
|
4718
|
+
pushToAncestorRules(mediaRule);
|
|
4719
|
+
mediaRule.__parentStyleSheet = styleSheet;
|
|
4720
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4721
|
+
buffer = "";
|
|
4722
|
+
state = "before-selector";
|
|
4723
|
+
} else if (state === "containerBlock") {
|
|
4724
|
+
containerRule.__conditionText = buffer.trim();
|
|
4674
4725
|
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
fontFaceRule.__parentRule = parentRule;
|
|
4678
|
-
}
|
|
4679
|
-
fontFaceRule.__parentStyleSheet = styleSheet;
|
|
4680
|
-
styleRule = fontFaceRule;
|
|
4681
|
-
buffer = "";
|
|
4682
|
-
state = "before-name";
|
|
4683
|
-
} else if (state === "keyframesRule-begin") {
|
|
4684
|
-
keyframesRule.name = buffer.trim();
|
|
4685
|
-
if (parentRule) {
|
|
4686
|
-
pushToAncestorRules(parentRule);
|
|
4687
|
-
keyframesRule.__parentRule = parentRule;
|
|
4688
|
-
}
|
|
4689
|
-
keyframesRule.__parentStyleSheet = styleSheet;
|
|
4690
|
-
currentScope = parentRule = keyframesRule;
|
|
4691
|
-
buffer = "";
|
|
4692
|
-
state = "keyframeRule-begin";
|
|
4693
|
-
} else if (state === "keyframeRule-begin") {
|
|
4694
|
-
styleRule = new CSSOM.CSSKeyframeRule();
|
|
4695
|
-
styleRule.keyText = buffer.trim();
|
|
4696
|
-
styleRule.__starts = i;
|
|
4697
|
-
buffer = "";
|
|
4698
|
-
state = "before-name";
|
|
4699
|
-
} else if (state === "documentRule-begin") {
|
|
4700
|
-
// FIXME: what if this '{' is in the url text of the match function?
|
|
4701
|
-
documentRule.matcher.matcherText = buffer.trim();
|
|
4702
|
-
if (parentRule) {
|
|
4703
|
-
pushToAncestorRules(parentRule);
|
|
4704
|
-
documentRule.__parentRule = parentRule;
|
|
4705
|
-
}
|
|
4706
|
-
currentScope = parentRule = documentRule;
|
|
4707
|
-
documentRule.__parentStyleSheet = styleSheet;
|
|
4708
|
-
buffer = "";
|
|
4709
|
-
state = "before-selector";
|
|
4710
|
-
} else if (state === "before-name" || state === "name") {
|
|
4711
|
-
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4712
|
-
if (styleRule.style.length) {
|
|
4713
|
-
parentRule.cssRules.push(styleRule);
|
|
4714
|
-
styleRule.__parentRule = parentRule;
|
|
4715
|
-
styleRule.__parentStyleSheet = styleSheet;
|
|
4716
|
-
pushToAncestorRules(parentRule);
|
|
4717
|
-
} else {
|
|
4718
|
-
// If the styleRule is empty, we can assume that it's a nested selector
|
|
4726
|
+
if (parentRule) {
|
|
4727
|
+
containerRule.__parentRule = parentRule;
|
|
4719
4728
|
pushToAncestorRules(parentRule);
|
|
4729
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4730
|
+
nestedSelectorRule = parentRule;
|
|
4731
|
+
}
|
|
4720
4732
|
}
|
|
4721
|
-
|
|
4722
|
-
|
|
4723
|
-
|
|
4724
|
-
styleRule
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
|
|
4729
|
-
|
|
4730
|
-
|
|
4731
|
-
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
}
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
nestedSelectorRule = styleRule;
|
|
4733
|
+
currentScope = parentRule = containerRule;
|
|
4734
|
+
pushToAncestorRules(containerRule);
|
|
4735
|
+
containerRule.__parentStyleSheet = styleSheet;
|
|
4736
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4737
|
+
buffer = "";
|
|
4738
|
+
state = "before-selector";
|
|
4739
|
+
} else if (state === "counterStyleBlock") {
|
|
4740
|
+
var counterStyleName = buffer.trim().replace(/\n/g, "");
|
|
4741
|
+
// Validate: name cannot be empty, contain whitespace, or contain dots
|
|
4742
|
+
var isValidCounterStyleName = counterStyleName.length > 0 && !/[\s.]/.test(counterStyleName);
|
|
4743
|
+
|
|
4744
|
+
if (isValidCounterStyleName) {
|
|
4745
|
+
counterStyleRule.name = counterStyleName;
|
|
4746
|
+
currentScope = parentRule = counterStyleRule;
|
|
4747
|
+
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
4748
|
+
}
|
|
4749
|
+
buffer = "";
|
|
4750
|
+
} else if (state === "conditionBlock") {
|
|
4751
|
+
supportsRule.__conditionText = buffer.trim();
|
|
4741
4752
|
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4753
|
+
if (parentRule) {
|
|
4754
|
+
supportsRule.__parentRule = parentRule;
|
|
4755
|
+
pushToAncestorRules(parentRule);
|
|
4756
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4757
|
+
nestedSelectorRule = parentRule;
|
|
4758
|
+
}
|
|
4759
|
+
}
|
|
4746
4760
|
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
|
|
4750
|
-
|
|
4751
|
-
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
4752
|
-
if (hasOpenBraceBefore) {
|
|
4753
|
-
// Is a selector
|
|
4754
|
-
buffer += character;
|
|
4755
|
-
} else {
|
|
4756
|
-
// Is a declaration
|
|
4757
|
-
name = buffer.trim();
|
|
4761
|
+
currentScope = parentRule = supportsRule;
|
|
4762
|
+
pushToAncestorRules(supportsRule);
|
|
4763
|
+
supportsRule.__parentStyleSheet = styleSheet;
|
|
4764
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4758
4765
|
buffer = "";
|
|
4759
|
-
state = "before-
|
|
4760
|
-
}
|
|
4761
|
-
|
|
4762
|
-
buffer += character;
|
|
4763
|
-
}
|
|
4764
|
-
break;
|
|
4766
|
+
state = "before-selector";
|
|
4767
|
+
} else if (state === "scopeBlock") {
|
|
4768
|
+
var parsedScopePrelude = parseScopePrelude(buffer.trim());
|
|
4765
4769
|
|
|
4766
|
-
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
|
|
4770
|
-
|
|
4770
|
+
if (parsedScopePrelude.hasStart) {
|
|
4771
|
+
scopeRule.__start = parsedScopePrelude.startSelector;
|
|
4772
|
+
}
|
|
4773
|
+
if (parsedScopePrelude.hasEnd) {
|
|
4774
|
+
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4775
|
+
}
|
|
4776
|
+
if (parsedScopePrelude.hasOnlyEnd) {
|
|
4777
|
+
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4778
|
+
}
|
|
4771
4779
|
|
|
4772
|
-
if (
|
|
4773
|
-
|
|
4774
|
-
|
|
4775
|
-
|
|
4776
|
-
|
|
4780
|
+
if (parentRule) {
|
|
4781
|
+
scopeRule.__parentRule = parentRule;
|
|
4782
|
+
pushToAncestorRules(parentRule);
|
|
4783
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4784
|
+
nestedSelectorRule = parentRule;
|
|
4785
|
+
}
|
|
4777
4786
|
}
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
//
|
|
4782
|
-
|
|
4783
|
-
|
|
4784
|
-
}
|
|
4785
|
-
|
|
4786
|
-
valueParenthesisDepth++;
|
|
4787
|
-
buffer += character;
|
|
4788
|
-
} else {
|
|
4789
|
-
buffer += character;
|
|
4790
|
-
}
|
|
4791
|
-
break;
|
|
4787
|
+
currentScope = parentRule = scopeRule;
|
|
4788
|
+
pushToAncestorRules(scopeRule);
|
|
4789
|
+
scopeRule.__parentStyleSheet = styleSheet;
|
|
4790
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4791
|
+
buffer = "";
|
|
4792
|
+
state = "before-selector";
|
|
4793
|
+
} else if (state === "layerBlock") {
|
|
4794
|
+
layerBlockRule.name = buffer.trim();
|
|
4792
4795
|
|
|
4793
|
-
|
|
4794
|
-
if (state === 'value-parenthesis') {
|
|
4795
|
-
valueParenthesisDepth--;
|
|
4796
|
-
if (valueParenthesisDepth === 0) state = 'value';
|
|
4797
|
-
}
|
|
4798
|
-
buffer += character;
|
|
4799
|
-
break;
|
|
4796
|
+
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(cssCustomIdentifierRegExp) !== null;
|
|
4800
4797
|
|
|
4801
|
-
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4798
|
+
if (isValidName) {
|
|
4799
|
+
if (parentRule) {
|
|
4800
|
+
layerBlockRule.__parentRule = parentRule;
|
|
4801
|
+
pushToAncestorRules(parentRule);
|
|
4802
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4803
|
+
nestedSelectorRule = parentRule;
|
|
4804
|
+
}
|
|
4805
|
+
}
|
|
4809
4806
|
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4807
|
+
currentScope = parentRule = layerBlockRule;
|
|
4808
|
+
pushToAncestorRules(layerBlockRule);
|
|
4809
|
+
layerBlockRule.__parentStyleSheet = styleSheet;
|
|
4810
|
+
}
|
|
4811
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4815
4812
|
buffer = "";
|
|
4816
|
-
state = "before-
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4813
|
+
state = "before-selector";
|
|
4814
|
+
} else if (state === "pageBlock") {
|
|
4815
|
+
pageRule.selectorText = buffer.trim();
|
|
4816
|
+
|
|
4817
|
+
if (parentRule) {
|
|
4818
|
+
pageRule.__parentRule = parentRule;
|
|
4819
|
+
pushToAncestorRules(parentRule);
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
currentScope = parentRule = pageRule;
|
|
4823
|
+
pageRule.__parentStyleSheet = styleSheet;
|
|
4824
|
+
styleRule = pageRule;
|
|
4821
4825
|
buffer = "";
|
|
4822
4826
|
state = "before-name";
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
state = "before-selector";
|
|
4827
|
-
break;
|
|
4828
|
-
case "importRule":
|
|
4829
|
-
var isValid = topScope.cssRules.length === 0 || topScope.cssRules.some(function (rule) {
|
|
4830
|
-
return ['CSSImportRule', 'CSSLayerStatementRule'].indexOf(rule.constructor.name) !== -1
|
|
4831
|
-
});
|
|
4832
|
-
if (isValid) {
|
|
4833
|
-
importRule = new CSSOM.CSSImportRule();
|
|
4834
|
-
importRule.__parentStyleSheet = importRule.styleSheet.__parentStyleSheet = styleSheet;
|
|
4835
|
-
importRule.cssText = buffer + character;
|
|
4836
|
-
topScope.cssRules.push(importRule);
|
|
4827
|
+
} else if (state === "hostRule-begin") {
|
|
4828
|
+
if (parentRule) {
|
|
4829
|
+
pushToAncestorRules(parentRule);
|
|
4837
4830
|
}
|
|
4831
|
+
|
|
4832
|
+
currentScope = parentRule = hostRule;
|
|
4833
|
+
pushToAncestorRules(hostRule);
|
|
4834
|
+
hostRule.__parentStyleSheet = styleSheet;
|
|
4838
4835
|
buffer = "";
|
|
4839
4836
|
state = "before-selector";
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
try {
|
|
4847
|
-
// Validate namespace syntax before creating the rule
|
|
4848
|
-
var testNamespaceRule = new CSSOM.CSSNamespaceRule();
|
|
4849
|
-
testNamespaceRule.cssText = buffer + character;
|
|
4850
|
-
|
|
4851
|
-
namespaceRule = testNamespaceRule;
|
|
4852
|
-
namespaceRule.__parentStyleSheet = styleSheet;
|
|
4853
|
-
topScope.cssRules.push(namespaceRule);
|
|
4854
|
-
|
|
4855
|
-
// Track the namespace prefix for validation
|
|
4856
|
-
if (namespaceRule.prefix) {
|
|
4857
|
-
definedNamespacePrefixes[namespaceRule.prefix] = namespaceRule.namespaceURI;
|
|
4858
|
-
}
|
|
4859
|
-
} catch(e) {
|
|
4860
|
-
parseError(e.message);
|
|
4837
|
+
} else if (state === "startingStyleRule-begin") {
|
|
4838
|
+
if (parentRule) {
|
|
4839
|
+
startingStyleRule.__parentRule = parentRule;
|
|
4840
|
+
pushToAncestorRules(parentRule);
|
|
4841
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4842
|
+
nestedSelectorRule = parentRule;
|
|
4861
4843
|
}
|
|
4862
4844
|
}
|
|
4845
|
+
|
|
4846
|
+
currentScope = parentRule = startingStyleRule;
|
|
4847
|
+
pushToAncestorRules(startingStyleRule);
|
|
4848
|
+
startingStyleRule.__parentStyleSheet = styleSheet;
|
|
4849
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4863
4850
|
buffer = "";
|
|
4864
4851
|
state = "before-selector";
|
|
4865
|
-
break;
|
|
4866
|
-
case "layerBlock":
|
|
4867
|
-
var nameListStr = buffer.trim().split(",").map(function (name) {
|
|
4868
|
-
return name.trim();
|
|
4869
|
-
});
|
|
4870
|
-
var isInvalid = parentRule !== undefined || nameListStr.some(function (name) {
|
|
4871
|
-
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
4872
|
-
});
|
|
4873
4852
|
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
layerStatementRule.__starts = layerBlockRule.__starts;
|
|
4878
|
-
layerStatementRule.__ends = i;
|
|
4879
|
-
layerStatementRule.nameList = nameListStr;
|
|
4880
|
-
topScope.cssRules.push(layerStatementRule);
|
|
4853
|
+
} else if (state === "fontFaceRule-begin") {
|
|
4854
|
+
if (parentRule) {
|
|
4855
|
+
fontFaceRule.__parentRule = parentRule;
|
|
4881
4856
|
}
|
|
4857
|
+
fontFaceRule.__parentStyleSheet = styleSheet;
|
|
4858
|
+
styleRule = fontFaceRule;
|
|
4882
4859
|
buffer = "";
|
|
4883
|
-
state = "before-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
break;
|
|
4890
|
-
|
|
4891
|
-
case "}":
|
|
4892
|
-
if (state === "counterStyleBlock") {
|
|
4893
|
-
// FIXME : Implement cssText get setter that parses the real implementation
|
|
4894
|
-
counterStyleRule.cssText = "@counter-style " + counterStyleRule.name + " { " + buffer.trim().replace(/\n/g, " ").replace(/(['"])(?:\\.|[^\\])*?\1|(\s{2,})/g, function(match, quote) {
|
|
4895
|
-
return quote ? match : ' ';
|
|
4896
|
-
}) + " }";
|
|
4897
|
-
buffer = "";
|
|
4898
|
-
state = "before-selector";
|
|
4899
|
-
}
|
|
4900
|
-
|
|
4901
|
-
switch (state) {
|
|
4902
|
-
case "value":
|
|
4903
|
-
styleRule.style.setProperty(name, buffer.trim(), priority, parseError);
|
|
4904
|
-
priority = "";
|
|
4905
|
-
/* falls through */
|
|
4906
|
-
case "before-value":
|
|
4907
|
-
case "before-name":
|
|
4908
|
-
case "name":
|
|
4909
|
-
styleRule.__ends = i + 1;
|
|
4910
|
-
|
|
4911
|
-
if (parentRule === styleRule) {
|
|
4912
|
-
parentRule = ancestorRules.pop()
|
|
4860
|
+
state = "before-name";
|
|
4861
|
+
} else if (state === "keyframesRule-begin") {
|
|
4862
|
+
keyframesRule.name = buffer.trim();
|
|
4863
|
+
if (parentRule) {
|
|
4864
|
+
pushToAncestorRules(parentRule);
|
|
4865
|
+
keyframesRule.__parentRule = parentRule;
|
|
4913
4866
|
}
|
|
4914
|
-
|
|
4867
|
+
keyframesRule.__parentStyleSheet = styleSheet;
|
|
4868
|
+
currentScope = parentRule = keyframesRule;
|
|
4869
|
+
buffer = "";
|
|
4870
|
+
state = "keyframeRule-begin";
|
|
4871
|
+
} else if (state === "keyframeRule-begin") {
|
|
4872
|
+
styleRule = new CSSOM.CSSKeyframeRule();
|
|
4873
|
+
styleRule.keyText = buffer.trim();
|
|
4874
|
+
styleRule.__starts = i;
|
|
4875
|
+
buffer = "";
|
|
4876
|
+
state = "before-name";
|
|
4877
|
+
} else if (state === "documentRule-begin") {
|
|
4878
|
+
// FIXME: what if this '{' is in the url text of the match function?
|
|
4879
|
+
documentRule.matcher.matcherText = buffer.trim();
|
|
4915
4880
|
if (parentRule) {
|
|
4916
|
-
|
|
4881
|
+
pushToAncestorRules(parentRule);
|
|
4882
|
+
documentRule.__parentRule = parentRule;
|
|
4917
4883
|
}
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4884
|
+
currentScope = parentRule = documentRule;
|
|
4885
|
+
pushToAncestorRules(documentRule);
|
|
4886
|
+
documentRule.__parentStyleSheet = styleSheet;
|
|
4887
|
+
buffer = "";
|
|
4888
|
+
state = "before-selector";
|
|
4889
|
+
} else if (state === "before-name" || state === "name") {
|
|
4890
|
+
// @font-face and similar rules don't support nested selectors
|
|
4891
|
+
// If we encounter a nested selector block inside them, skip it
|
|
4892
|
+
if (styleRule.constructor.name === "CSSFontFaceRule" ||
|
|
4893
|
+
styleRule.constructor.name === "CSSKeyframeRule" ||
|
|
4894
|
+
(styleRule.constructor.name === "CSSPageRule" && parentRule === styleRule)) {
|
|
4895
|
+
// Skip the nested block
|
|
4896
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
4897
|
+
if (ruleClosingMatch) {
|
|
4898
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length - 1;
|
|
4899
|
+
buffer = "";
|
|
4900
|
+
state = "before-name";
|
|
4901
|
+
break;
|
|
4902
|
+
}
|
|
4922
4903
|
}
|
|
4923
4904
|
|
|
4924
|
-
if (styleRule.constructor.name === "
|
|
4925
|
-
if (styleRule
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
if (styleRule.parentRule) {
|
|
4931
|
-
styleRule.parentRule.cssRules.push(styleRule);
|
|
4905
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4906
|
+
if (styleRule.style.length) {
|
|
4907
|
+
parentRule.cssRules.push(styleRule);
|
|
4908
|
+
styleRule.__parentRule = parentRule;
|
|
4909
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
4910
|
+
pushToAncestorRules(parentRule);
|
|
4932
4911
|
} else {
|
|
4933
|
-
|
|
4912
|
+
// If the styleRule is empty, we can assume that it's a nested selector
|
|
4913
|
+
pushToAncestorRules(parentRule);
|
|
4934
4914
|
}
|
|
4915
|
+
} else {
|
|
4916
|
+
currentScope = parentRule = styleRule;
|
|
4917
|
+
pushToAncestorRules(parentRule);
|
|
4918
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
4935
4919
|
}
|
|
4920
|
+
|
|
4921
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
4922
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
4923
|
+
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
4924
|
+
if (parentRule.constructor.name === "CSSScopeRule" || (parentRule.constructor.name !== "CSSStyleRule" && parentRule.parentRule === null)) {
|
|
4925
|
+
styleRule.selectorText = processedSelectorText;
|
|
4926
|
+
} else {
|
|
4927
|
+
styleRule.selectorText = parseAndSplitNestedSelectors(processedSelectorText).map(function (sel) {
|
|
4928
|
+
// Add & at the beginning if there's no & in the selector, or if it starts with a combinator
|
|
4929
|
+
return (sel.indexOf('&') === -1 || startsWithCombinatorRegExp.test(sel)) ? '& ' + sel : sel;
|
|
4930
|
+
}).join(', ');
|
|
4931
|
+
}
|
|
4932
|
+
styleRule.style.__starts = i - buffer.length;
|
|
4933
|
+
styleRule.__parentRule = parentRule;
|
|
4934
|
+
// Only set nestedSelectorRule if we're directly inside a CSSStyleRule or CSSScopeRule,
|
|
4935
|
+
// not inside other grouping rules like @media/@supports
|
|
4936
|
+
if (parentRule.constructor.name === "CSSStyleRule" || parentRule.constructor.name === "CSSScopeRule") {
|
|
4937
|
+
nestedSelectorRule = styleRule;
|
|
4938
|
+
}
|
|
4939
|
+
|
|
4936
4940
|
buffer = "";
|
|
4937
|
-
|
|
4938
|
-
|
|
4941
|
+
state = "before-name";
|
|
4942
|
+
}
|
|
4943
|
+
break;
|
|
4944
|
+
|
|
4945
|
+
case ":":
|
|
4946
|
+
if (state === "name") {
|
|
4947
|
+
// It can be a nested selector, let's check
|
|
4948
|
+
var openBraceBeforeMatch = token.slice(i).match(/[{;}]/);
|
|
4949
|
+
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
4950
|
+
if (hasOpenBraceBefore) {
|
|
4951
|
+
// Is a selector
|
|
4952
|
+
buffer += character;
|
|
4939
4953
|
} else {
|
|
4940
|
-
|
|
4954
|
+
// Is a declaration
|
|
4955
|
+
name = buffer.trim();
|
|
4956
|
+
buffer = "";
|
|
4957
|
+
state = "before-value";
|
|
4941
4958
|
}
|
|
4959
|
+
} else {
|
|
4960
|
+
buffer += character;
|
|
4961
|
+
}
|
|
4962
|
+
break;
|
|
4942
4963
|
|
|
4943
|
-
|
|
4944
|
-
|
|
4945
|
-
|
|
4964
|
+
case "(":
|
|
4965
|
+
if (state === 'value') {
|
|
4966
|
+
// ie css expression mode
|
|
4967
|
+
if (buffer.trim() === 'expression') {
|
|
4968
|
+
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
|
|
4969
|
+
|
|
4970
|
+
if (info.error) {
|
|
4971
|
+
parseError(info.error);
|
|
4972
|
+
} else {
|
|
4973
|
+
buffer += info.expression;
|
|
4974
|
+
i = info.idx;
|
|
4946
4975
|
}
|
|
4947
|
-
styleRule = null;
|
|
4948
4976
|
} else {
|
|
4949
|
-
|
|
4950
|
-
|
|
4977
|
+
state = 'value-parenthesis';
|
|
4978
|
+
//always ensure this is reset to 1 on transition
|
|
4979
|
+
//from value to value-parenthesis
|
|
4980
|
+
valueParenthesisDepth = 1;
|
|
4981
|
+
buffer += character;
|
|
4951
4982
|
}
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4983
|
+
} else if (state === 'value-parenthesis') {
|
|
4984
|
+
valueParenthesisDepth++;
|
|
4985
|
+
buffer += character;
|
|
4986
|
+
} else {
|
|
4987
|
+
buffer += character;
|
|
4988
|
+
}
|
|
4989
|
+
break;
|
|
4990
|
+
|
|
4991
|
+
case ")":
|
|
4992
|
+
if (state === 'value-parenthesis') {
|
|
4993
|
+
valueParenthesisDepth--;
|
|
4994
|
+
if (valueParenthesisDepth === 0) state = 'value';
|
|
4995
|
+
}
|
|
4996
|
+
buffer += character;
|
|
4997
|
+
break;
|
|
4998
|
+
|
|
4999
|
+
case "!":
|
|
5000
|
+
if (state === "value" && token.indexOf("!important", i) === i) {
|
|
5001
|
+
priority = "important";
|
|
5002
|
+
i += "important".length;
|
|
5003
|
+
} else {
|
|
5004
|
+
buffer += character;
|
|
5005
|
+
}
|
|
5006
|
+
break;
|
|
5007
|
+
|
|
5008
|
+
case ";":
|
|
5009
|
+
switch (state) {
|
|
5010
|
+
case "before-value":
|
|
5011
|
+
case "before-name":
|
|
5012
|
+
parseError("Unexpected ;");
|
|
5013
|
+
buffer = "";
|
|
5014
|
+
state = "before-name";
|
|
5015
|
+
break;
|
|
5016
|
+
case "value":
|
|
5017
|
+
styleRule.style.setProperty(name, buffer.trim(), priority, parseError);
|
|
5018
|
+
priority = "";
|
|
5019
|
+
buffer = "";
|
|
5020
|
+
state = "before-name";
|
|
5021
|
+
break;
|
|
5022
|
+
case "atRule":
|
|
5023
|
+
buffer = "";
|
|
5024
|
+
state = "before-selector";
|
|
5025
|
+
break;
|
|
5026
|
+
case "importRule":
|
|
5027
|
+
var isValid = topScope.cssRules.length === 0 || topScope.cssRules.some(function (rule) {
|
|
5028
|
+
return ['CSSImportRule', 'CSSLayerStatementRule'].indexOf(rule.constructor.name) !== -1
|
|
5029
|
+
});
|
|
5030
|
+
if (isValid) {
|
|
5031
|
+
importRule = new CSSOM.CSSImportRule();
|
|
5032
|
+
importRule.__parentStyleSheet = importRule.styleSheet.__parentStyleSheet = styleSheet;
|
|
5033
|
+
importRule.parse(buffer + character);
|
|
5034
|
+
topScope.cssRules.push(importRule);
|
|
4962
5035
|
}
|
|
4963
|
-
|
|
5036
|
+
buffer = "";
|
|
5037
|
+
state = "before-selector";
|
|
4964
5038
|
break;
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
if (
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
4988
|
-
|
|
5039
|
+
case "namespaceRule":
|
|
5040
|
+
var isValid = topScope.cssRules.length === 0 || topScope.cssRules.every(function (rule) {
|
|
5041
|
+
return ['CSSImportRule', 'CSSLayerStatementRule', 'CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
|
|
5042
|
+
});
|
|
5043
|
+
if (isValid) {
|
|
5044
|
+
try {
|
|
5045
|
+
// Validate namespace syntax before creating the rule
|
|
5046
|
+
var testNamespaceRule = new CSSOM.CSSNamespaceRule();
|
|
5047
|
+
testNamespaceRule.parse(buffer + character);
|
|
5048
|
+
|
|
5049
|
+
namespaceRule = testNamespaceRule;
|
|
5050
|
+
namespaceRule.__parentStyleSheet = styleSheet;
|
|
5051
|
+
topScope.cssRules.push(namespaceRule);
|
|
5052
|
+
|
|
5053
|
+
// Track the namespace prefix for validation
|
|
5054
|
+
if (namespaceRule.prefix) {
|
|
5055
|
+
definedNamespacePrefixes[namespaceRule.prefix] = namespaceRule.namespaceURI;
|
|
5056
|
+
}
|
|
5057
|
+
} catch (e) {
|
|
5058
|
+
parseError(e.message);
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
buffer = "";
|
|
5062
|
+
state = "before-selector";
|
|
5063
|
+
break;
|
|
5064
|
+
case "layerBlock":
|
|
5065
|
+
var nameListStr = buffer.trim().split(",").map(function (name) {
|
|
5066
|
+
return name.trim();
|
|
5067
|
+
});
|
|
5068
|
+
var isInvalid = nameListStr.some(function (name) {
|
|
5069
|
+
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
5070
|
+
});
|
|
5071
|
+
|
|
5072
|
+
// Check if there's a CSSStyleRule in the parent chain
|
|
5073
|
+
var hasStyleRuleParent = false;
|
|
5074
|
+
if (parentRule) {
|
|
5075
|
+
var checkParent = parentRule;
|
|
5076
|
+
while (checkParent) {
|
|
5077
|
+
if (checkParent.constructor.name === "CSSStyleRule") {
|
|
5078
|
+
hasStyleRuleParent = true;
|
|
5079
|
+
break;
|
|
4989
5080
|
}
|
|
5081
|
+
checkParent = checkParent.__parentRule;
|
|
5082
|
+
}
|
|
5083
|
+
}
|
|
5084
|
+
|
|
5085
|
+
if (!isInvalid && !hasStyleRuleParent) {
|
|
5086
|
+
layerStatementRule = new CSSOM.CSSLayerStatementRule();
|
|
5087
|
+
layerStatementRule.__parentStyleSheet = styleSheet;
|
|
5088
|
+
layerStatementRule.__starts = layerBlockRule.__starts;
|
|
5089
|
+
layerStatementRule.__ends = i;
|
|
5090
|
+
layerStatementRule.nameList = nameListStr;
|
|
5091
|
+
|
|
5092
|
+
// Add to parent rule if nested, otherwise to top scope
|
|
5093
|
+
if (parentRule) {
|
|
5094
|
+
layerStatementRule.__parentRule = parentRule;
|
|
5095
|
+
parentRule.cssRules.push(layerStatementRule);
|
|
4990
5096
|
} else {
|
|
4991
|
-
|
|
4992
|
-
parentRule !== prevScope && parentRule.cssRules.push(prevScope);
|
|
4993
|
-
break;
|
|
5097
|
+
topScope.cssRules.push(layerStatementRule);
|
|
4994
5098
|
}
|
|
4995
5099
|
}
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5100
|
+
buffer = "";
|
|
5101
|
+
state = "before-selector";
|
|
5102
|
+
break;
|
|
5103
|
+
default:
|
|
5104
|
+
buffer += character;
|
|
5105
|
+
break;
|
|
5106
|
+
}
|
|
5107
|
+
break;
|
|
5108
|
+
|
|
5109
|
+
case "}":
|
|
5110
|
+
if (state === "counterStyleBlock") {
|
|
5111
|
+
// FIXME : Implement missing properties on CSSCounterStyleRule interface and update parse method
|
|
5112
|
+
// For now it's just assigning entire rule text
|
|
5113
|
+
counterStyleRule.parse("@counter-style " + counterStyleRule.name + " { " + buffer + " }");
|
|
5114
|
+
buffer = "";
|
|
5115
|
+
state = "before-selector";
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
switch (state) {
|
|
5119
|
+
case "value":
|
|
5120
|
+
styleRule.style.setProperty(name, buffer.trim(), priority, parseError);
|
|
5121
|
+
priority = "";
|
|
5122
|
+
/* falls through */
|
|
5123
|
+
case "before-value":
|
|
5124
|
+
case "before-name":
|
|
5125
|
+
case "name":
|
|
5126
|
+
styleRule.__ends = i + 1;
|
|
5127
|
+
|
|
5128
|
+
if (parentRule === styleRule) {
|
|
5129
|
+
parentRule = ancestorRules.pop()
|
|
5130
|
+
}
|
|
5131
|
+
|
|
5132
|
+
if (parentRule) {
|
|
5133
|
+
styleRule.__parentRule = parentRule;
|
|
5004
5134
|
}
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
5014
|
-
if (openingBraceLen === closingBraceLen) {
|
|
5015
|
-
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
5016
|
-
nestedSelectorRule.__ends = i + 1;
|
|
5135
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
5136
|
+
|
|
5137
|
+
if (currentScope === styleRule) {
|
|
5138
|
+
currentScope = parentRule || topScope;
|
|
5139
|
+
}
|
|
5140
|
+
|
|
5141
|
+
if (styleRule.constructor.name === "CSSStyleRule" && !isValidSelectorText(styleRule.selectorText)) {
|
|
5142
|
+
if (styleRule === nestedSelectorRule) {
|
|
5017
5143
|
nestedSelectorRule = null;
|
|
5018
|
-
parentRule = null;
|
|
5019
5144
|
}
|
|
5145
|
+
parseError('Invalid CSSStyleRule (selectorText = "' + styleRule.selectorText + '")', styleRule.parentRule !== null);
|
|
5146
|
+
} else {
|
|
5147
|
+
if (styleRule.parentRule) {
|
|
5148
|
+
styleRule.parentRule.cssRules.push(styleRule);
|
|
5149
|
+
} else {
|
|
5150
|
+
currentScope.cssRules.push(styleRule);
|
|
5151
|
+
}
|
|
5152
|
+
}
|
|
5153
|
+
buffer = "";
|
|
5154
|
+
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
|
|
5155
|
+
state = "keyframeRule-begin";
|
|
5020
5156
|
} else {
|
|
5021
|
-
|
|
5157
|
+
state = "before-selector";
|
|
5158
|
+
}
|
|
5022
5159
|
|
|
5160
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
5161
|
+
if (currentScope !== topScope) {
|
|
5162
|
+
// Only set nestedSelectorRule if currentScope is CSSStyleRule or CSSScopeRule
|
|
5163
|
+
// Not for other grouping rules like @media/@supports
|
|
5164
|
+
if (currentScope.constructor.name === "CSSStyleRule" || currentScope.constructor.name === "CSSScopeRule") {
|
|
5165
|
+
nestedSelectorRule = currentScope;
|
|
5166
|
+
}
|
|
5167
|
+
}
|
|
5168
|
+
styleRule = null;
|
|
5169
|
+
} else {
|
|
5170
|
+
// Update nestedSelectorRule when closing a CSSStyleRule
|
|
5171
|
+
if (styleRule === nestedSelectorRule) {
|
|
5172
|
+
var selector = styleRule.selectorText && styleRule.selectorText.trim();
|
|
5173
|
+
// Check if this is proper nesting (&.class, &:pseudo) vs prepended & (& :is, & .class with space)
|
|
5174
|
+
// Prepended & has pattern "& X" where X starts with : or .
|
|
5175
|
+
var isPrependedAmpersand = selector && selector.match(/^&\s+[:\.]/);
|
|
5176
|
+
|
|
5177
|
+
// Check if parent is a grouping rule that can contain nested selectors
|
|
5178
|
+
var isGroupingRule = currentScope && currentScope instanceof CSSOM.CSSGroupingRule;
|
|
5179
|
+
|
|
5180
|
+
if (!isPrependedAmpersand && isGroupingRule) {
|
|
5181
|
+
// Proper nesting - set nestedSelectorRule to parent for more nested selectors
|
|
5182
|
+
// But only if it's a CSSStyleRule or CSSScopeRule, not other grouping rules like @media
|
|
5183
|
+
if (currentScope.constructor.name === "CSSStyleRule" || currentScope.constructor.name === "CSSScopeRule") {
|
|
5184
|
+
nestedSelectorRule = currentScope;
|
|
5185
|
+
}
|
|
5186
|
+
// If currentScope is another type of grouping rule (like @media), keep nestedSelectorRule unchanged
|
|
5187
|
+
} else {
|
|
5188
|
+
// Prepended & or not nested in grouping rule - reset to prevent CSSNestedDeclarations
|
|
5189
|
+
nestedSelectorRule = null;
|
|
5190
|
+
}
|
|
5191
|
+
} else if (nestedSelectorRule && currentScope instanceof CSSOM.CSSGroupingRule) {
|
|
5192
|
+
// When closing a nested rule that's not the nestedSelectorRule itself,
|
|
5193
|
+
// maintain nestedSelectorRule if we're still inside a grouping rule
|
|
5194
|
+
// This ensures declarations after nested selectors inside @media/@supports etc. work correctly
|
|
5195
|
+
}
|
|
5196
|
+
styleRule = null;
|
|
5197
|
+
break;
|
|
5023
5198
|
}
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5199
|
+
case "keyframeRule-begin":
|
|
5200
|
+
case "before-selector":
|
|
5201
|
+
case "selector":
|
|
5202
|
+
// End of media/supports/document rule.
|
|
5203
|
+
if (!parentRule) {
|
|
5204
|
+
parseError("Unexpected }");
|
|
5205
|
+
|
|
5206
|
+
var hasPreviousStyleRule = currentScope.cssRules.length && currentScope.cssRules[currentScope.cssRules.length - 1].constructor.name === "CSSStyleRule";
|
|
5207
|
+
if (hasPreviousStyleRule) {
|
|
5208
|
+
i = ignoreBalancedBlock(i, token.slice(i), 1);
|
|
5209
|
+
}
|
|
5027
5210
|
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
break;
|
|
5031
|
-
}
|
|
5032
|
-
break;
|
|
5211
|
+
break;
|
|
5212
|
+
}
|
|
5033
5213
|
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5214
|
+
while (ancestorRules.length > 0) {
|
|
5215
|
+
parentRule = ancestorRules.pop();
|
|
5216
|
+
|
|
5217
|
+
if (parentRule instanceof CSSOM.CSSGroupingRule && (parentRule.constructor.name !== 'CSSStyleRule' || parentRule.__parentRule)) {
|
|
5218
|
+
if (nestedSelectorRule) {
|
|
5219
|
+
if (nestedSelectorRule.parentRule) {
|
|
5220
|
+
prevScope = nestedSelectorRule;
|
|
5221
|
+
currentScope = nestedSelectorRule.parentRule;
|
|
5222
|
+
if (currentScope.cssRules.findIndex(function (rule) {
|
|
5223
|
+
return rule === prevScope
|
|
5224
|
+
}) === -1) {
|
|
5225
|
+
currentScope.cssRules.push(prevScope);
|
|
5226
|
+
}
|
|
5227
|
+
nestedSelectorRule = currentScope;
|
|
5228
|
+
} else {
|
|
5229
|
+
// If nestedSelectorRule doesn't have a parentRule, we're closing a grouping rule
|
|
5230
|
+
// inside a top-level CSSStyleRule. We need to push currentScope to the parentRule.
|
|
5231
|
+
prevScope = currentScope;
|
|
5232
|
+
// Push to actual parent from ancestorRules if available
|
|
5233
|
+
var actualParent = ancestorRules.length > 0 ? ancestorRules[ancestorRules.length - 1] : nestedSelectorRule;
|
|
5234
|
+
actualParent !== prevScope && actualParent.cssRules.push(prevScope);
|
|
5235
|
+
// Update currentScope to the nestedSelectorRule before breaking
|
|
5236
|
+
currentScope = actualParent;
|
|
5237
|
+
parentRule = actualParent;
|
|
5238
|
+
break;
|
|
5239
|
+
}
|
|
5240
|
+
} else {
|
|
5241
|
+
prevScope = currentScope;
|
|
5242
|
+
parentRule !== prevScope && parentRule.cssRules.push(prevScope);
|
|
5243
|
+
break;
|
|
5244
|
+
}
|
|
5055
5245
|
}
|
|
5056
5246
|
}
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
if
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5247
|
+
|
|
5248
|
+
// If currentScope has a __parentRule and wasn't added yet, add it
|
|
5249
|
+
if (ancestorRules.length === 0 && currentScope.__parentRule && currentScope.__parentRule.cssRules) {
|
|
5250
|
+
if (currentScope.__parentRule.cssRules.findIndex(function (rule) {
|
|
5251
|
+
return rule === currentScope
|
|
5252
|
+
}) === -1) {
|
|
5253
|
+
currentScope.__parentRule.cssRules.push(currentScope);
|
|
5254
|
+
}
|
|
5255
|
+
}
|
|
5256
|
+
|
|
5257
|
+
// Only handle top-level rule closing if we processed all ancestors
|
|
5258
|
+
if (ancestorRules.length === 0 && currentScope.parentRule == null) {
|
|
5259
|
+
currentScope.__ends = i + 1;
|
|
5260
|
+
if (currentScope !== topScope && topScope.cssRules.findIndex(function (rule) {
|
|
5261
|
+
return rule === currentScope
|
|
5262
|
+
}) === -1) {
|
|
5263
|
+
topScope.cssRules.push(currentScope);
|
|
5264
|
+
}
|
|
5265
|
+
currentScope = topScope;
|
|
5266
|
+
if (nestedSelectorRule === parentRule) {
|
|
5267
|
+
// Check if this selector is really starting inside another selector
|
|
5268
|
+
var nestedSelectorTokenToCurrentSelectorToken = token.slice(nestedSelectorRule.__starts, i + 1);
|
|
5269
|
+
var openingBraceMatch = nestedSelectorTokenToCurrentSelectorToken.match(/{/g);
|
|
5270
|
+
var closingBraceMatch = nestedSelectorTokenToCurrentSelectorToken.match(/}/g);
|
|
5271
|
+
var openingBraceLen = openingBraceMatch && openingBraceMatch.length;
|
|
5272
|
+
var closingBraceLen = closingBraceMatch && closingBraceMatch.length;
|
|
5273
|
+
|
|
5274
|
+
if (openingBraceLen === closingBraceLen) {
|
|
5275
|
+
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
5276
|
+
nestedSelectorRule.__ends = i + 1;
|
|
5277
|
+
nestedSelectorRule = null;
|
|
5278
|
+
parentRule = null;
|
|
5279
|
+
}
|
|
5074
5280
|
} else {
|
|
5281
|
+
parentRule = null;
|
|
5282
|
+
}
|
|
5283
|
+
} else {
|
|
5284
|
+
currentScope = parentRule;
|
|
5285
|
+
}
|
|
5286
|
+
|
|
5287
|
+
buffer = "";
|
|
5288
|
+
state = "before-selector";
|
|
5289
|
+
break;
|
|
5290
|
+
}
|
|
5291
|
+
break;
|
|
5292
|
+
|
|
5293
|
+
default:
|
|
5294
|
+
switch (state) {
|
|
5295
|
+
case "before-selector":
|
|
5296
|
+
state = "selector";
|
|
5297
|
+
if ((styleRule || scopeRule) && parentRule) {
|
|
5298
|
+
// Assuming it's a declaration inside Nested Selector OR a Nested Declaration
|
|
5299
|
+
// If Declaration inside Nested Selector let's keep the same styleRule
|
|
5300
|
+
if (!isSelectorStartChar(character) && !isWhitespaceChar(character) && parentRule instanceof CSSOM.CSSGroupingRule) {
|
|
5301
|
+
// parentRule.__parentRule = styleRule;
|
|
5302
|
+
state = "before-name";
|
|
5303
|
+
if (styleRule !== parentRule) {
|
|
5304
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
5305
|
+
styleRule.__starts = i;
|
|
5306
|
+
}
|
|
5307
|
+
}
|
|
5308
|
+
|
|
5309
|
+
} else if (nestedSelectorRule && parentRule && parentRule instanceof CSSOM.CSSGroupingRule) {
|
|
5310
|
+
if (isSelectorStartChar(character)) {
|
|
5311
|
+
// If starting with a selector character, create CSSStyleRule instead of CSSNestedDeclarations
|
|
5075
5312
|
styleRule = new CSSOM.CSSStyleRule();
|
|
5076
|
-
styleRule.__starts = i;
|
|
5313
|
+
styleRule.__starts = i;
|
|
5314
|
+
} else if (!isWhitespaceChar(character)) {
|
|
5315
|
+
// Starting a declaration (not whitespace, not a selector)
|
|
5316
|
+
state = "before-name";
|
|
5317
|
+
// Check if we should create CSSNestedDeclarations
|
|
5318
|
+
// This happens if: parent has cssRules OR nestedSelectorRule exists (indicating CSSStyleRule in hierarchy)
|
|
5319
|
+
if (parentRule.cssRules.length || nestedSelectorRule) {
|
|
5320
|
+
currentScope = parentRule;
|
|
5321
|
+
// Only set nestedSelectorRule if parentRule is CSSStyleRule or CSSScopeRule
|
|
5322
|
+
if (parentRule.constructor.name === "CSSStyleRule" || parentRule.constructor.name === "CSSScopeRule") {
|
|
5323
|
+
nestedSelectorRule = parentRule;
|
|
5324
|
+
}
|
|
5325
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
5326
|
+
styleRule.__starts = i;
|
|
5327
|
+
} else {
|
|
5328
|
+
if (parentRule.constructor.name === "CSSStyleRule") {
|
|
5329
|
+
styleRule = parentRule;
|
|
5330
|
+
} else {
|
|
5331
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
5332
|
+
styleRule.__starts = i;
|
|
5333
|
+
}
|
|
5334
|
+
}
|
|
5077
5335
|
}
|
|
5078
5336
|
}
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5337
|
+
break;
|
|
5338
|
+
case "before-name":
|
|
5339
|
+
state = "name";
|
|
5340
|
+
break;
|
|
5341
|
+
case "before-value":
|
|
5342
|
+
state = "value";
|
|
5343
|
+
break;
|
|
5344
|
+
case "importRule-begin":
|
|
5345
|
+
state = "importRule";
|
|
5346
|
+
break;
|
|
5347
|
+
case "namespaceRule-begin":
|
|
5348
|
+
state = "namespaceRule";
|
|
5349
|
+
break;
|
|
5350
|
+
}
|
|
5351
|
+
buffer += character;
|
|
5352
|
+
break;
|
|
5353
|
+
}
|
|
5354
|
+
|
|
5355
|
+
// Auto-close all unclosed nested structures
|
|
5356
|
+
// Check AFTER processing the character, at the ORIGINAL ending index
|
|
5357
|
+
// Only add closing braces if CSS is incomplete (not at top scope)
|
|
5358
|
+
if (i === initialEndingIndex && (currentScope !== topScope || ancestorRules.length > 0)) {
|
|
5359
|
+
var needsClosing = ancestorRules.length;
|
|
5360
|
+
if (currentScope !== topScope && ancestorRules.indexOf(currentScope) === -1) {
|
|
5361
|
+
needsClosing += 1;
|
|
5362
|
+
}
|
|
5363
|
+
// Add closing braces for all unclosed structures
|
|
5364
|
+
for (var closeIdx = 0; closeIdx < needsClosing; closeIdx++) {
|
|
5365
|
+
token += "}";
|
|
5366
|
+
endingIndex += 1;
|
|
5096
5367
|
}
|
|
5097
|
-
buffer += character;
|
|
5098
|
-
break;
|
|
5099
5368
|
}
|
|
5100
5369
|
}
|
|
5101
5370
|
|