@acemir/cssom 0.9.23 → 0.9.25
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 +2113 -1269
- package/lib/CSSConditionRule.js +3 -1
- package/lib/CSSContainerRule.js +20 -9
- package/lib/CSSCounterStyleRule.js +36 -2
- package/lib/CSSDocumentRule.js +10 -2
- package/lib/CSSFontFaceRule.js +9 -2
- package/lib/CSSGroupingRule.js +65 -9
- package/lib/CSSHostRule.js +22 -6
- package/lib/CSSImportRule.js +49 -39
- package/lib/CSSKeyframeRule.js +9 -2
- package/lib/CSSKeyframesRule.js +20 -7
- package/lib/CSSLayerBlockRule.js +20 -9
- package/lib/CSSLayerStatementRule.js +9 -5
- package/lib/CSSMediaRule.js +20 -9
- package/lib/CSSNamespaceRule.js +27 -17
- package/lib/CSSNestedDeclarations.js +9 -5
- package/lib/CSSOM.js +16 -1
- package/lib/CSSPageRule.js +11 -155
- package/lib/CSSRule.js +10 -0
- package/lib/CSSScopeRule.js +13 -5
- package/lib/CSSStartingStyleRule.js +20 -6
- package/lib/CSSStyleRule.js +11 -157
- package/lib/CSSStyleSheet.js +115 -4
- package/lib/CSSSupportsRule.js +19 -8
- package/lib/CSSValueExpression.js +3 -1
- package/lib/MediaList.js +3 -1
- package/lib/StyleSheet.js +24 -1
- package/lib/errorUtils.js +23 -16
- package/lib/index.js +2 -0
- package/lib/parse.js +1521 -784
- 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
|
|
@@ -34,6 +37,19 @@ function getErrorConstructor(context, errorType) {
|
|
|
34
37
|
eval(errorType);
|
|
35
38
|
}
|
|
36
39
|
|
|
40
|
+
/**
|
|
41
|
+
* Creates an appropriate error with context-aware constructor.
|
|
42
|
+
*
|
|
43
|
+
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
|
|
44
|
+
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
|
|
45
|
+
* @param {string} message - The error message
|
|
46
|
+
* @param {string} [name] - Optional name for DOMException
|
|
47
|
+
*/
|
|
48
|
+
function createError(context, errorType, message, name) {
|
|
49
|
+
var ErrorConstructor = getErrorConstructor(context, errorType);
|
|
50
|
+
return new ErrorConstructor(message, name);
|
|
51
|
+
}
|
|
52
|
+
|
|
37
53
|
/**
|
|
38
54
|
* Creates and throws an appropriate error with context-aware constructor.
|
|
39
55
|
*
|
|
@@ -43,9 +59,7 @@ function getErrorConstructor(context, errorType) {
|
|
|
43
59
|
* @param {string} [name] - Optional name for DOMException
|
|
44
60
|
*/
|
|
45
61
|
function throwError(context, errorType, message, name) {
|
|
46
|
-
|
|
47
|
-
var error = new ErrorConstructor(message, name);
|
|
48
|
-
throw error;
|
|
62
|
+
throw createError(context, errorType, message, name);
|
|
49
63
|
}
|
|
50
64
|
|
|
51
65
|
/**
|
|
@@ -98,6 +112,7 @@ function throwIndexError(context, methodName, objectName, index, maxIndex, name)
|
|
|
98
112
|
}
|
|
99
113
|
|
|
100
114
|
var errorUtils = {
|
|
115
|
+
createError: createError,
|
|
101
116
|
getErrorConstructor: getErrorConstructor,
|
|
102
117
|
throwError: throwError,
|
|
103
118
|
throwMissingArguments: throwMissingArguments,
|
|
@@ -332,6 +347,16 @@ Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
|
332
347
|
enumerable: true
|
|
333
348
|
},
|
|
334
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
|
+
|
|
335
360
|
parentRule: {
|
|
336
361
|
get: function() {
|
|
337
362
|
return this.__parentRule
|
|
@@ -402,9 +427,15 @@ CSSOM.CSSNestedDeclarations = function CSSNestedDeclarations() {
|
|
|
402
427
|
this.__style.parentRule = this;
|
|
403
428
|
};
|
|
404
429
|
|
|
405
|
-
CSSOM.CSSNestedDeclarations.prototype =
|
|
430
|
+
CSSOM.CSSNestedDeclarations.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
406
431
|
CSSOM.CSSNestedDeclarations.prototype.constructor = CSSOM.CSSNestedDeclarations;
|
|
407
|
-
|
|
432
|
+
|
|
433
|
+
Object.setPrototypeOf(CSSOM.CSSNestedDeclarations, CSSOM.CSSRule);
|
|
434
|
+
|
|
435
|
+
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "type", {
|
|
436
|
+
value: 0,
|
|
437
|
+
writable: false
|
|
438
|
+
});
|
|
408
439
|
|
|
409
440
|
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
|
|
410
441
|
get: function() {
|
|
@@ -422,9 +453,7 @@ Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "style", {
|
|
|
422
453
|
Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
|
|
423
454
|
get: function () {
|
|
424
455
|
return this.style.cssText;
|
|
425
|
-
}
|
|
426
|
-
configurable: true,
|
|
427
|
-
enumerable: true,
|
|
456
|
+
}
|
|
428
457
|
});
|
|
429
458
|
|
|
430
459
|
|
|
@@ -436,12 +465,19 @@ Object.defineProperty(CSSOM.CSSNestedDeclarations.prototype, "cssText", {
|
|
|
436
465
|
*/
|
|
437
466
|
CSSOM.CSSGroupingRule = function CSSGroupingRule() {
|
|
438
467
|
CSSOM.CSSRule.call(this);
|
|
439
|
-
this.
|
|
468
|
+
this.__cssRules = new CSSOM.CSSRuleList();
|
|
440
469
|
};
|
|
441
470
|
|
|
442
|
-
CSSOM.CSSGroupingRule.prototype
|
|
471
|
+
CSSOM.CSSGroupingRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
443
472
|
CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
444
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
|
+
});
|
|
445
481
|
|
|
446
482
|
/**
|
|
447
483
|
* Used to insert a new CSS rule to a list of CSS rules.
|
|
@@ -473,13 +509,60 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
473
509
|
if (index > this.cssRules.length) {
|
|
474
510
|
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
475
511
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
var
|
|
479
|
-
if (
|
|
480
|
-
|
|
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');
|
|
481
565
|
}
|
|
482
|
-
var cssRule = parsedSheet.cssRules[0];
|
|
483
566
|
|
|
484
567
|
// Check for rules that cannot be inserted inside a CSSGroupingRule
|
|
485
568
|
if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
@@ -523,7 +606,9 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
523
606
|
if (index >= this.cssRules.length) {
|
|
524
607
|
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
525
608
|
}
|
|
526
|
-
this.cssRules
|
|
609
|
+
this.cssRules[index].__parentRule = null;
|
|
610
|
+
this.cssRules[index].__parentStyleSheet = null;
|
|
611
|
+
this.cssRules.splice(index, 1);
|
|
527
612
|
};
|
|
528
613
|
|
|
529
614
|
|
|
@@ -537,11 +622,45 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
537
622
|
CSSOM.CSSCounterStyleRule = function CSSCounterStyleRule() {
|
|
538
623
|
CSSOM.CSSRule.call(this);
|
|
539
624
|
this.name = "";
|
|
625
|
+
this.__props = "";
|
|
540
626
|
};
|
|
541
627
|
|
|
542
|
-
CSSOM.CSSCounterStyleRule.prototype =
|
|
628
|
+
CSSOM.CSSCounterStyleRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
543
629
|
CSSOM.CSSCounterStyleRule.prototype.constructor = CSSOM.CSSCounterStyleRule;
|
|
544
|
-
|
|
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
|
+
});
|
|
545
664
|
|
|
546
665
|
|
|
547
666
|
|
|
@@ -556,9 +675,11 @@ CSSOM.CSSConditionRule = function CSSConditionRule() {
|
|
|
556
675
|
this.__conditionText = '';
|
|
557
676
|
};
|
|
558
677
|
|
|
559
|
-
CSSOM.CSSConditionRule.prototype =
|
|
678
|
+
CSSOM.CSSConditionRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
560
679
|
CSSOM.CSSConditionRule.prototype.constructor = CSSOM.CSSConditionRule;
|
|
561
680
|
|
|
681
|
+
Object.setPrototypeOf(CSSOM.CSSConditionRule, CSSOM.CSSGroupingRule);
|
|
682
|
+
|
|
562
683
|
Object.defineProperty(CSSOM.CSSConditionRule.prototype, "conditionText", {
|
|
563
684
|
get: function () {
|
|
564
685
|
return this.__conditionText;
|
|
@@ -581,9 +702,11 @@ CSSOM.CSSStyleRule = function CSSStyleRule() {
|
|
|
581
702
|
this.__style.parentRule = this;
|
|
582
703
|
};
|
|
583
704
|
|
|
584
|
-
CSSOM.CSSStyleRule.prototype =
|
|
705
|
+
CSSOM.CSSStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
585
706
|
CSSOM.CSSStyleRule.prototype.constructor = CSSOM.CSSStyleRule;
|
|
586
707
|
|
|
708
|
+
Object.setPrototypeOf(CSSOM.CSSStyleRule, CSSOM.CSSGroupingRule);
|
|
709
|
+
|
|
587
710
|
Object.defineProperty(CSSOM.CSSStyleRule.prototype, "type", {
|
|
588
711
|
value: 1,
|
|
589
712
|
writable: false
|
|
@@ -628,12 +751,17 @@ Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
|
628
751
|
get: function() {
|
|
629
752
|
var text;
|
|
630
753
|
if (this.selectorText) {
|
|
631
|
-
var values = ""
|
|
754
|
+
var values = "";
|
|
632
755
|
if (this.cssRules.length) {
|
|
633
756
|
var valuesArr = [" {"];
|
|
634
757
|
this.style.cssText && valuesArr.push(this.style.cssText);
|
|
635
|
-
valuesArr.push(this.cssRules.
|
|
636
|
-
|
|
758
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
759
|
+
if (rule.cssText !== "") {
|
|
760
|
+
acc.push(rule.cssText);
|
|
761
|
+
}
|
|
762
|
+
return acc;
|
|
763
|
+
}, []).join("\n "));
|
|
764
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
637
765
|
} else {
|
|
638
766
|
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
639
767
|
}
|
|
@@ -642,163 +770,10 @@ Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
|
642
770
|
text = "";
|
|
643
771
|
}
|
|
644
772
|
return text;
|
|
645
|
-
},
|
|
646
|
-
set: function(cssText) {
|
|
647
|
-
if (typeof cssText === "string") {
|
|
648
|
-
var rule = CSSOM.CSSStyleRule.parse(cssText);
|
|
649
|
-
this.__style = rule.style;
|
|
650
|
-
this.selectorText = rule.selectorText;
|
|
651
|
-
}
|
|
652
773
|
}
|
|
653
774
|
});
|
|
654
775
|
|
|
655
776
|
|
|
656
|
-
/**
|
|
657
|
-
* NON-STANDARD
|
|
658
|
-
* lightweight version of parse.js.
|
|
659
|
-
* @param {string} ruleText
|
|
660
|
-
* @return CSSStyleRule
|
|
661
|
-
*/
|
|
662
|
-
CSSOM.CSSStyleRule.parse = function(ruleText) {
|
|
663
|
-
var i = 0;
|
|
664
|
-
var state = "selector";
|
|
665
|
-
var index;
|
|
666
|
-
var j = i;
|
|
667
|
-
var buffer = "";
|
|
668
|
-
|
|
669
|
-
var SIGNIFICANT_WHITESPACE = {
|
|
670
|
-
"selector": true,
|
|
671
|
-
"value": true
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
var styleRule = new CSSOM.CSSStyleRule();
|
|
675
|
-
var name, priority="";
|
|
676
|
-
|
|
677
|
-
for (var character; (character = ruleText.charAt(i)); i++) {
|
|
678
|
-
|
|
679
|
-
switch (character) {
|
|
680
|
-
|
|
681
|
-
case " ":
|
|
682
|
-
case "\t":
|
|
683
|
-
case "\r":
|
|
684
|
-
case "\n":
|
|
685
|
-
case "\f":
|
|
686
|
-
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
687
|
-
// Squash 2 or more white-spaces in the row into 1
|
|
688
|
-
switch (ruleText.charAt(i - 1)) {
|
|
689
|
-
case " ":
|
|
690
|
-
case "\t":
|
|
691
|
-
case "\r":
|
|
692
|
-
case "\n":
|
|
693
|
-
case "\f":
|
|
694
|
-
break;
|
|
695
|
-
default:
|
|
696
|
-
buffer += " ";
|
|
697
|
-
break;
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
break;
|
|
701
|
-
|
|
702
|
-
// String
|
|
703
|
-
case '"':
|
|
704
|
-
j = i + 1;
|
|
705
|
-
index = ruleText.indexOf('"', j) + 1;
|
|
706
|
-
if (!index) {
|
|
707
|
-
throw '" is missing';
|
|
708
|
-
}
|
|
709
|
-
buffer += ruleText.slice(i, index);
|
|
710
|
-
i = index - 1;
|
|
711
|
-
break;
|
|
712
|
-
|
|
713
|
-
case "'":
|
|
714
|
-
j = i + 1;
|
|
715
|
-
index = ruleText.indexOf("'", j) + 1;
|
|
716
|
-
if (!index) {
|
|
717
|
-
throw "' is missing";
|
|
718
|
-
}
|
|
719
|
-
buffer += ruleText.slice(i, index);
|
|
720
|
-
i = index - 1;
|
|
721
|
-
break;
|
|
722
|
-
|
|
723
|
-
// Comment
|
|
724
|
-
case "/":
|
|
725
|
-
if (ruleText.charAt(i + 1) === "*") {
|
|
726
|
-
i += 2;
|
|
727
|
-
index = ruleText.indexOf("*/", i);
|
|
728
|
-
if (index === -1) {
|
|
729
|
-
throw new SyntaxError("Missing */");
|
|
730
|
-
} else {
|
|
731
|
-
i = index + 1;
|
|
732
|
-
}
|
|
733
|
-
} else {
|
|
734
|
-
buffer += character;
|
|
735
|
-
}
|
|
736
|
-
break;
|
|
737
|
-
|
|
738
|
-
case "{":
|
|
739
|
-
if (state === "selector") {
|
|
740
|
-
styleRule.selectorText = buffer.trim();
|
|
741
|
-
buffer = "";
|
|
742
|
-
state = "name";
|
|
743
|
-
}
|
|
744
|
-
break;
|
|
745
|
-
|
|
746
|
-
case ":":
|
|
747
|
-
if (state === "name") {
|
|
748
|
-
name = buffer.trim();
|
|
749
|
-
buffer = "";
|
|
750
|
-
state = "value";
|
|
751
|
-
} else {
|
|
752
|
-
buffer += character;
|
|
753
|
-
}
|
|
754
|
-
break;
|
|
755
|
-
|
|
756
|
-
case "!":
|
|
757
|
-
if (state === "value" && ruleText.indexOf("!important", i) === i) {
|
|
758
|
-
priority = "important";
|
|
759
|
-
i += "important".length;
|
|
760
|
-
} else {
|
|
761
|
-
buffer += character;
|
|
762
|
-
}
|
|
763
|
-
break;
|
|
764
|
-
|
|
765
|
-
case ";":
|
|
766
|
-
if (state === "value") {
|
|
767
|
-
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
768
|
-
priority = "";
|
|
769
|
-
buffer = "";
|
|
770
|
-
state = "name";
|
|
771
|
-
} else {
|
|
772
|
-
buffer += character;
|
|
773
|
-
}
|
|
774
|
-
break;
|
|
775
|
-
|
|
776
|
-
case "}":
|
|
777
|
-
if (state === "value") {
|
|
778
|
-
styleRule.style.setProperty(name, buffer.trim(), priority);
|
|
779
|
-
priority = "";
|
|
780
|
-
buffer = "";
|
|
781
|
-
} else if (state === "name") {
|
|
782
|
-
break;
|
|
783
|
-
} else {
|
|
784
|
-
buffer += character;
|
|
785
|
-
}
|
|
786
|
-
state = "selector";
|
|
787
|
-
break;
|
|
788
|
-
|
|
789
|
-
default:
|
|
790
|
-
buffer += character;
|
|
791
|
-
break;
|
|
792
|
-
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
return styleRule;
|
|
797
|
-
|
|
798
|
-
};
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
777
|
|
|
803
778
|
|
|
804
779
|
|
|
@@ -825,7 +800,9 @@ CSSOM.MediaList.prototype = {
|
|
|
825
800
|
* @param {string} value
|
|
826
801
|
*/
|
|
827
802
|
set mediaText(value) {
|
|
828
|
-
var values = value.split(",")
|
|
803
|
+
var values = value.split(",").filter(function(text){
|
|
804
|
+
return !!text;
|
|
805
|
+
});
|
|
829
806
|
var length = this.length = values.length;
|
|
830
807
|
for (var i=0; i<length; i++) {
|
|
831
808
|
this[i] = values[i].trim();
|
|
@@ -869,9 +846,15 @@ CSSOM.CSSMediaRule = function CSSMediaRule() {
|
|
|
869
846
|
this.__media = new CSSOM.MediaList();
|
|
870
847
|
};
|
|
871
848
|
|
|
872
|
-
CSSOM.CSSMediaRule.prototype =
|
|
849
|
+
CSSOM.CSSMediaRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
873
850
|
CSSOM.CSSMediaRule.prototype.constructor = CSSOM.CSSMediaRule;
|
|
874
|
-
|
|
851
|
+
|
|
852
|
+
Object.setPrototypeOf(CSSOM.CSSMediaRule, CSSOM.CSSConditionRule);
|
|
853
|
+
|
|
854
|
+
Object.defineProperty(CSSOM.CSSMediaRule.prototype, "type", {
|
|
855
|
+
value: 4,
|
|
856
|
+
writable: false
|
|
857
|
+
});
|
|
875
858
|
|
|
876
859
|
// https://opensource.apple.com/source/WebCore/WebCore-7611.1.21.161.3/css/CSSMediaRule.cpp
|
|
877
860
|
Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
|
|
@@ -895,14 +878,19 @@ Object.defineProperties(CSSOM.CSSMediaRule.prototype, {
|
|
|
895
878
|
},
|
|
896
879
|
"cssText": {
|
|
897
880
|
get: function() {
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
881
|
+
var values = "";
|
|
882
|
+
var valuesArr = [" {"];
|
|
883
|
+
if (this.cssRules.length) {
|
|
884
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
885
|
+
if (rule.cssText !== "") {
|
|
886
|
+
acc.push(rule.cssText);
|
|
887
|
+
}
|
|
888
|
+
return acc;
|
|
889
|
+
}, []).join("\n "));
|
|
901
890
|
}
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
enumerable: true
|
|
891
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
892
|
+
return "@media " + this.media.mediaText + values;
|
|
893
|
+
}
|
|
906
894
|
}
|
|
907
895
|
});
|
|
908
896
|
|
|
@@ -920,21 +908,32 @@ CSSOM.CSSContainerRule = function CSSContainerRule() {
|
|
|
920
908
|
CSSOM.CSSConditionRule.call(this);
|
|
921
909
|
};
|
|
922
910
|
|
|
923
|
-
CSSOM.CSSContainerRule.prototype =
|
|
911
|
+
CSSOM.CSSContainerRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
924
912
|
CSSOM.CSSContainerRule.prototype.constructor = CSSOM.CSSContainerRule;
|
|
925
|
-
|
|
913
|
+
|
|
914
|
+
Object.setPrototypeOf(CSSOM.CSSContainerRule, CSSOM.CSSConditionRule);
|
|
915
|
+
|
|
916
|
+
Object.defineProperty(CSSOM.CSSContainerRule.prototype, "type", {
|
|
917
|
+
value: 17,
|
|
918
|
+
writable: false
|
|
919
|
+
});
|
|
926
920
|
|
|
927
921
|
Object.defineProperties(CSSOM.CSSContainerRule.prototype, {
|
|
928
922
|
"cssText": {
|
|
929
923
|
get: function() {
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
924
|
+
var values = "";
|
|
925
|
+
var valuesArr = [" {"];
|
|
926
|
+
if (this.cssRules.length) {
|
|
927
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
928
|
+
if (rule.cssText !== "") {
|
|
929
|
+
acc.push(rule.cssText);
|
|
930
|
+
}
|
|
931
|
+
return acc;
|
|
932
|
+
}, []).join("\n "));
|
|
933
933
|
}
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
enumerable: true
|
|
934
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
935
|
+
return "@container " + this.conditionText + values;
|
|
936
|
+
}
|
|
938
937
|
},
|
|
939
938
|
"containerName": {
|
|
940
939
|
get: function() {
|
|
@@ -969,19 +968,30 @@ CSSOM.CSSSupportsRule = function CSSSupportsRule() {
|
|
|
969
968
|
CSSOM.CSSConditionRule.call(this);
|
|
970
969
|
};
|
|
971
970
|
|
|
972
|
-
CSSOM.CSSSupportsRule.prototype =
|
|
971
|
+
CSSOM.CSSSupportsRule.prototype = Object.create(CSSOM.CSSConditionRule.prototype);
|
|
973
972
|
CSSOM.CSSSupportsRule.prototype.constructor = CSSOM.CSSSupportsRule;
|
|
974
|
-
|
|
973
|
+
|
|
974
|
+
Object.setPrototypeOf(CSSOM.CSSSupportsRule, CSSOM.CSSConditionRule);
|
|
975
|
+
|
|
976
|
+
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "type", {
|
|
977
|
+
value: 12,
|
|
978
|
+
writable: false
|
|
979
|
+
});
|
|
975
980
|
|
|
976
981
|
Object.defineProperty(CSSOM.CSSSupportsRule.prototype, "cssText", {
|
|
977
982
|
get: function() {
|
|
978
|
-
var
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
983
|
+
var values = "";
|
|
984
|
+
var valuesArr = [" {"];
|
|
985
|
+
if (this.cssRules.length) {
|
|
986
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
987
|
+
if (rule.cssText !== "") {
|
|
988
|
+
acc.push(rule.cssText);
|
|
989
|
+
}
|
|
990
|
+
return acc;
|
|
991
|
+
}, []).join("\n "));
|
|
982
992
|
}
|
|
983
|
-
|
|
984
|
-
return "@supports " + this.conditionText +
|
|
993
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
994
|
+
return "@supports " + this.conditionText + values;
|
|
985
995
|
}
|
|
986
996
|
});
|
|
987
997
|
|
|
@@ -1003,9 +1013,11 @@ CSSOM.CSSImportRule = function CSSImportRule() {
|
|
|
1003
1013
|
this.__styleSheet = new CSSOM.CSSStyleSheet();
|
|
1004
1014
|
};
|
|
1005
1015
|
|
|
1006
|
-
CSSOM.CSSImportRule.prototype =
|
|
1016
|
+
CSSOM.CSSImportRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1007
1017
|
CSSOM.CSSImportRule.prototype.constructor = CSSOM.CSSImportRule;
|
|
1008
1018
|
|
|
1019
|
+
Object.setPrototypeOf(CSSOM.CSSImportRule, CSSOM.CSSRule);
|
|
1020
|
+
|
|
1009
1021
|
Object.defineProperty(CSSOM.CSSImportRule.prototype, "type", {
|
|
1010
1022
|
value: 3,
|
|
1011
1023
|
writable: false
|
|
@@ -1015,8 +1027,53 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
1015
1027
|
get: function() {
|
|
1016
1028
|
var mediaText = this.media.mediaText;
|
|
1017
1029
|
return "@import url(\"" + this.href.replace(/\\/g, '\\\\').replace(/"/g, '\\"') + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
1030
|
+
}
|
|
1031
|
+
});
|
|
1032
|
+
|
|
1033
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "href", {
|
|
1034
|
+
get: function() {
|
|
1035
|
+
return this.__href;
|
|
1036
|
+
}
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "media", {
|
|
1040
|
+
get: function() {
|
|
1041
|
+
return this.__media;
|
|
1018
1042
|
},
|
|
1019
|
-
|
|
1043
|
+
set: function(value) {
|
|
1044
|
+
if (typeof value === "string") {
|
|
1045
|
+
this.__media.mediaText = value;
|
|
1046
|
+
} else {
|
|
1047
|
+
this.__media = value;
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
});
|
|
1051
|
+
|
|
1052
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
|
|
1053
|
+
get: function() {
|
|
1054
|
+
return this.__layerName;
|
|
1055
|
+
}
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
|
|
1059
|
+
get: function() {
|
|
1060
|
+
return this.__supportsText;
|
|
1061
|
+
}
|
|
1062
|
+
});
|
|
1063
|
+
|
|
1064
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "styleSheet", {
|
|
1065
|
+
get: function() {
|
|
1066
|
+
return this.__styleSheet;
|
|
1067
|
+
}
|
|
1068
|
+
});
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* NON-STANDARD
|
|
1072
|
+
* Rule text parser.
|
|
1073
|
+
* @param {string} cssText
|
|
1074
|
+
*/
|
|
1075
|
+
Object.defineProperty(CSSOM.CSSImportRule.prototype, "parse", {
|
|
1076
|
+
value: function(cssText) {
|
|
1020
1077
|
var i = 0;
|
|
1021
1078
|
|
|
1022
1079
|
/**
|
|
@@ -1195,71 +1252,57 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
1195
1252
|
}
|
|
1196
1253
|
});
|
|
1197
1254
|
|
|
1198
|
-
|
|
1255
|
+
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
|
|
1259
|
+
|
|
1260
|
+
/**
|
|
1261
|
+
* @constructor
|
|
1262
|
+
* @see https://drafts.csswg.org/cssom/#the-cssnamespacerule-interface
|
|
1263
|
+
*/
|
|
1264
|
+
CSSOM.CSSNamespaceRule = function CSSNamespaceRule() {
|
|
1265
|
+
CSSOM.CSSRule.call(this);
|
|
1266
|
+
this.__prefix = "";
|
|
1267
|
+
this.__namespaceURI = "";
|
|
1268
|
+
};
|
|
1269
|
+
|
|
1270
|
+
CSSOM.CSSNamespaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1271
|
+
CSSOM.CSSNamespaceRule.prototype.constructor = CSSOM.CSSNamespaceRule;
|
|
1272
|
+
|
|
1273
|
+
Object.setPrototypeOf(CSSOM.CSSNamespaceRule, CSSOM.CSSRule);
|
|
1274
|
+
|
|
1275
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "type", {
|
|
1276
|
+
value: 10,
|
|
1277
|
+
writable: false
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
|
|
1199
1281
|
get: function() {
|
|
1200
|
-
return this.
|
|
1282
|
+
return "@namespace" + (this.prefix && " " + this.prefix) + " url(\"" + this.namespaceURI + "\");";
|
|
1201
1283
|
}
|
|
1202
1284
|
});
|
|
1203
1285
|
|
|
1204
|
-
Object.defineProperty(CSSOM.
|
|
1286
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
|
|
1205
1287
|
get: function() {
|
|
1206
|
-
return this.
|
|
1207
|
-
},
|
|
1208
|
-
set: function(value) {
|
|
1209
|
-
if (typeof value === "string") {
|
|
1210
|
-
this.__media.mediaText = value;
|
|
1211
|
-
} else {
|
|
1212
|
-
this.__media = value;
|
|
1213
|
-
}
|
|
1214
|
-
}
|
|
1215
|
-
});
|
|
1216
|
-
|
|
1217
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "layerName", {
|
|
1218
|
-
get: function() {
|
|
1219
|
-
return this.__layerName;
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
|
|
1223
|
-
Object.defineProperty(CSSOM.CSSImportRule.prototype, "supportsText", {
|
|
1224
|
-
get: function() {
|
|
1225
|
-
return this.__supportsText;
|
|
1288
|
+
return this.__prefix;
|
|
1226
1289
|
}
|
|
1227
1290
|
});
|
|
1228
1291
|
|
|
1229
|
-
Object.defineProperty(CSSOM.
|
|
1292
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
|
|
1230
1293
|
get: function() {
|
|
1231
|
-
return this.
|
|
1294
|
+
return this.__namespaceURI;
|
|
1232
1295
|
}
|
|
1233
1296
|
});
|
|
1234
1297
|
|
|
1235
1298
|
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
1299
|
/**
|
|
1241
|
-
*
|
|
1242
|
-
*
|
|
1300
|
+
* NON-STANDARD
|
|
1301
|
+
* Rule text parser.
|
|
1302
|
+
* @param {string} cssText
|
|
1243
1303
|
*/
|
|
1244
|
-
CSSOM.CSSNamespaceRule
|
|
1245
|
-
|
|
1246
|
-
this.__prefix = "";
|
|
1247
|
-
this.__namespaceURI = "";
|
|
1248
|
-
};
|
|
1249
|
-
|
|
1250
|
-
CSSOM.CSSNamespaceRule.prototype = new CSSOM.CSSRule();
|
|
1251
|
-
CSSOM.CSSNamespaceRule.prototype.constructor = CSSOM.CSSNamespaceRule;
|
|
1252
|
-
|
|
1253
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "type", {
|
|
1254
|
-
value: 10,
|
|
1255
|
-
writable: false
|
|
1256
|
-
});
|
|
1257
|
-
|
|
1258
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
|
|
1259
|
-
get: function() {
|
|
1260
|
-
return "@namespace" + (this.prefix && " " + this.prefix) + " url(\"" + this.namespaceURI + "\");";
|
|
1261
|
-
},
|
|
1262
|
-
set: function(cssText) {
|
|
1304
|
+
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "parse", {
|
|
1305
|
+
value: function(cssText) {
|
|
1263
1306
|
var newPrefix = "";
|
|
1264
1307
|
var newNamespaceURI = "";
|
|
1265
1308
|
|
|
@@ -1307,19 +1350,6 @@ Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "cssText", {
|
|
|
1307
1350
|
}
|
|
1308
1351
|
});
|
|
1309
1352
|
|
|
1310
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "prefix", {
|
|
1311
|
-
get: function() {
|
|
1312
|
-
return this.__prefix;
|
|
1313
|
-
}
|
|
1314
|
-
});
|
|
1315
|
-
|
|
1316
|
-
Object.defineProperty(CSSOM.CSSNamespaceRule.prototype, "namespaceURI", {
|
|
1317
|
-
get: function() {
|
|
1318
|
-
return this.__namespaceURI;
|
|
1319
|
-
}
|
|
1320
|
-
});
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
1353
|
|
|
1324
1354
|
|
|
1325
1355
|
|
|
@@ -1333,9 +1363,16 @@ CSSOM.CSSFontFaceRule = function CSSFontFaceRule() {
|
|
|
1333
1363
|
this.__style.parentRule = this;
|
|
1334
1364
|
};
|
|
1335
1365
|
|
|
1336
|
-
CSSOM.CSSFontFaceRule.prototype =
|
|
1366
|
+
CSSOM.CSSFontFaceRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1337
1367
|
CSSOM.CSSFontFaceRule.prototype.constructor = CSSOM.CSSFontFaceRule;
|
|
1338
|
-
|
|
1368
|
+
|
|
1369
|
+
Object.setPrototypeOf(CSSOM.CSSFontFaceRule, CSSOM.CSSRule);
|
|
1370
|
+
|
|
1371
|
+
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "type", {
|
|
1372
|
+
value: 5,
|
|
1373
|
+
writable: false
|
|
1374
|
+
});
|
|
1375
|
+
|
|
1339
1376
|
//FIXME
|
|
1340
1377
|
//CSSOM.CSSFontFaceRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1341
1378
|
//CSSOM.CSSFontFaceRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -1368,26 +1405,42 @@ Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
|
|
|
1368
1405
|
/**
|
|
1369
1406
|
* @constructor
|
|
1370
1407
|
* @see http://www.w3.org/TR/shadow-dom/#host-at-rule
|
|
1408
|
+
* @see http://html5index.org/Shadow%20DOM%20-%20CSSHostRule.html
|
|
1409
|
+
* @deprecated This rule was part of early Shadow DOM drafts but was removed in favor of the more flexible :host and :host-context() pseudo-classes in modern CSS for Web Components.
|
|
1371
1410
|
*/
|
|
1372
1411
|
CSSOM.CSSHostRule = function CSSHostRule() {
|
|
1373
1412
|
CSSOM.CSSRule.call(this);
|
|
1374
1413
|
this.cssRules = new CSSOM.CSSRuleList();
|
|
1375
1414
|
};
|
|
1376
1415
|
|
|
1377
|
-
CSSOM.CSSHostRule.prototype =
|
|
1416
|
+
CSSOM.CSSHostRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1378
1417
|
CSSOM.CSSHostRule.prototype.constructor = CSSOM.CSSHostRule;
|
|
1379
|
-
|
|
1418
|
+
|
|
1419
|
+
Object.setPrototypeOf(CSSOM.CSSHostRule, CSSOM.CSSRule);
|
|
1420
|
+
|
|
1421
|
+
Object.defineProperty(CSSOM.CSSHostRule.prototype, "type", {
|
|
1422
|
+
value: 1001,
|
|
1423
|
+
writable: false
|
|
1424
|
+
});
|
|
1425
|
+
|
|
1380
1426
|
//FIXME
|
|
1381
1427
|
//CSSOM.CSSHostRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1382
1428
|
//CSSOM.CSSHostRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
1383
1429
|
|
|
1384
1430
|
Object.defineProperty(CSSOM.CSSHostRule.prototype, "cssText", {
|
|
1385
1431
|
get: function() {
|
|
1386
|
-
var
|
|
1387
|
-
|
|
1388
|
-
|
|
1432
|
+
var values = "";
|
|
1433
|
+
var valuesArr = [" {"];
|
|
1434
|
+
if (this.cssRules.length) {
|
|
1435
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
1436
|
+
if (rule.cssText !== "") {
|
|
1437
|
+
acc.push(rule.cssText);
|
|
1438
|
+
}
|
|
1439
|
+
return acc;
|
|
1440
|
+
}, []).join("\n "));
|
|
1389
1441
|
}
|
|
1390
|
-
|
|
1442
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
1443
|
+
return "@host" + values;
|
|
1391
1444
|
}
|
|
1392
1445
|
});
|
|
1393
1446
|
|
|
@@ -1404,20 +1457,34 @@ CSSOM.CSSStartingStyleRule = function CSSStartingStyleRule() {
|
|
|
1404
1457
|
CSSOM.CSSGroupingRule.call(this);
|
|
1405
1458
|
};
|
|
1406
1459
|
|
|
1407
|
-
CSSOM.CSSStartingStyleRule.prototype =
|
|
1460
|
+
CSSOM.CSSStartingStyleRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
1408
1461
|
CSSOM.CSSStartingStyleRule.prototype.constructor = CSSOM.CSSStartingStyleRule;
|
|
1409
|
-
|
|
1462
|
+
|
|
1463
|
+
Object.setPrototypeOf(CSSOM.CSSStartingStyleRule, CSSOM.CSSGroupingRule);
|
|
1464
|
+
|
|
1465
|
+
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "type", {
|
|
1466
|
+
value: 1002,
|
|
1467
|
+
writable: false
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1410
1470
|
//FIXME
|
|
1411
1471
|
//CSSOM.CSSStartingStyleRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1412
1472
|
//CSSOM.CSSStartingStyleRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
1413
1473
|
|
|
1414
1474
|
Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
|
|
1415
1475
|
get: function() {
|
|
1416
|
-
var
|
|
1417
|
-
|
|
1418
|
-
|
|
1476
|
+
var values = "";
|
|
1477
|
+
var valuesArr = [" {"];
|
|
1478
|
+
if (this.cssRules.length) {
|
|
1479
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
1480
|
+
if (rule.cssText !== "") {
|
|
1481
|
+
acc.push(rule.cssText);
|
|
1482
|
+
}
|
|
1483
|
+
return acc;
|
|
1484
|
+
}, []).join("\n "));
|
|
1419
1485
|
}
|
|
1420
|
-
|
|
1486
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
1487
|
+
return "@starting-style" + values;
|
|
1421
1488
|
}
|
|
1422
1489
|
});
|
|
1423
1490
|
|
|
@@ -1427,15 +1494,38 @@ Object.defineProperty(CSSOM.CSSStartingStyleRule.prototype, "cssText", {
|
|
|
1427
1494
|
|
|
1428
1495
|
|
|
1429
1496
|
/**
|
|
1430
|
-
* @constructor
|
|
1431
1497
|
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
|
|
1432
1498
|
*/
|
|
1433
1499
|
CSSOM.StyleSheet = function StyleSheet() {
|
|
1500
|
+
this.__href = null;
|
|
1501
|
+
this.__ownerNode = null;
|
|
1502
|
+
this.__title = null;
|
|
1434
1503
|
this.__media = new CSSOM.MediaList();
|
|
1435
1504
|
this.__parentStyleSheet = null;
|
|
1505
|
+
this.disabled = false;
|
|
1436
1506
|
};
|
|
1437
1507
|
|
|
1438
1508
|
Object.defineProperties(CSSOM.StyleSheet.prototype, {
|
|
1509
|
+
type: {
|
|
1510
|
+
get: function() {
|
|
1511
|
+
return "text/css";
|
|
1512
|
+
}
|
|
1513
|
+
},
|
|
1514
|
+
href: {
|
|
1515
|
+
get: function() {
|
|
1516
|
+
return this.__href;
|
|
1517
|
+
}
|
|
1518
|
+
},
|
|
1519
|
+
ownerNode: {
|
|
1520
|
+
get: function() {
|
|
1521
|
+
return this.__ownerNode;
|
|
1522
|
+
}
|
|
1523
|
+
},
|
|
1524
|
+
title: {
|
|
1525
|
+
get: function() {
|
|
1526
|
+
return this.__title;
|
|
1527
|
+
}
|
|
1528
|
+
},
|
|
1439
1529
|
media: {
|
|
1440
1530
|
get: function() {
|
|
1441
1531
|
return this.__media;
|
|
@@ -1461,20 +1551,52 @@ Object.defineProperties(CSSOM.StyleSheet.prototype, {
|
|
|
1461
1551
|
|
|
1462
1552
|
/**
|
|
1463
1553
|
* @constructor
|
|
1554
|
+
* @param {CSSStyleSheetInit} [opts] - CSSStyleSheetInit options.
|
|
1555
|
+
* @param {string} [opts.baseURL] - The base URL of the stylesheet.
|
|
1556
|
+
* @param {boolean} [opts.disabled] - The disabled attribute of the stylesheet.
|
|
1557
|
+
* @param {MediaList | string} [opts.media] - The media attribute of the stylesheet.
|
|
1464
1558
|
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleSheet
|
|
1465
1559
|
*/
|
|
1466
|
-
CSSOM.CSSStyleSheet = function CSSStyleSheet() {
|
|
1560
|
+
CSSOM.CSSStyleSheet = function CSSStyleSheet(opts) {
|
|
1467
1561
|
CSSOM.StyleSheet.call(this);
|
|
1468
|
-
this.
|
|
1562
|
+
this.__constructed = true;
|
|
1563
|
+
this.__cssRules = new CSSOM.CSSRuleList();
|
|
1564
|
+
this.__ownerRule = null;
|
|
1565
|
+
|
|
1566
|
+
if (opts && typeof opts === "object") {
|
|
1567
|
+
if (opts.baseURL && typeof opts.baseURL === "string") {
|
|
1568
|
+
this.__baseURL = opts.baseURL;
|
|
1569
|
+
}
|
|
1570
|
+
if (opts.media && typeof opts.media === "string") {
|
|
1571
|
+
this.media.mediaText = opts.media;
|
|
1572
|
+
}
|
|
1573
|
+
if (typeof opts.disabled === "boolean") {
|
|
1574
|
+
this.disabled = opts.disabled;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1469
1577
|
};
|
|
1470
1578
|
|
|
1471
1579
|
|
|
1472
|
-
CSSOM.CSSStyleSheet.prototype =
|
|
1580
|
+
CSSOM.CSSStyleSheet.prototype = Object.create(CSSOM.StyleSheet.prototype);
|
|
1473
1581
|
CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
1474
1582
|
|
|
1583
|
+
Object.setPrototypeOf(CSSOM.CSSStyleSheet, CSSOM.StyleSheet);
|
|
1584
|
+
|
|
1585
|
+
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "cssRules", {
|
|
1586
|
+
get: function() {
|
|
1587
|
+
return this.__cssRules;
|
|
1588
|
+
}
|
|
1589
|
+
});
|
|
1590
|
+
|
|
1475
1591
|
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "rules", {
|
|
1476
1592
|
get: function() {
|
|
1477
|
-
return this.
|
|
1593
|
+
return this.__cssRules;
|
|
1594
|
+
}
|
|
1595
|
+
});
|
|
1596
|
+
|
|
1597
|
+
Object.defineProperty(CSSOM.CSSStyleSheet.prototype, "ownerRule", {
|
|
1598
|
+
get: function() {
|
|
1599
|
+
return this.__ownerRule;
|
|
1478
1600
|
}
|
|
1479
1601
|
});
|
|
1480
1602
|
|
|
@@ -1677,6 +1799,84 @@ CSSOM.CSSStyleSheet.prototype.removeRule = function(index) {
|
|
|
1677
1799
|
this.deleteRule(index);
|
|
1678
1800
|
};
|
|
1679
1801
|
|
|
1802
|
+
|
|
1803
|
+
/**
|
|
1804
|
+
* Replaces the rules of a {@link CSSStyleSheet}
|
|
1805
|
+
*
|
|
1806
|
+
* @returns a promise
|
|
1807
|
+
* @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replace
|
|
1808
|
+
*/
|
|
1809
|
+
CSSOM.CSSStyleSheet.prototype.replace = function(text) {
|
|
1810
|
+
var _Promise;
|
|
1811
|
+
if (CSSOM.getGlobalObject() && CSSOM.getGlobalObject()['Promise']) {
|
|
1812
|
+
_Promise = CSSOM.getGlobalObject()['Promise'];
|
|
1813
|
+
} else {
|
|
1814
|
+
_Promise = Promise;
|
|
1815
|
+
}
|
|
1816
|
+
var sheet = this;
|
|
1817
|
+
return new _Promise(function (resolve, reject) {
|
|
1818
|
+
// If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
|
|
1819
|
+
if (!sheet.__constructed || sheet.__disallowModification) {
|
|
1820
|
+
reject(errorUtils.createError(sheet, 'DOMException',
|
|
1821
|
+
"Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
|
|
1822
|
+
'NotAllowedError'));
|
|
1823
|
+
}
|
|
1824
|
+
// Set the disallow modification flag.
|
|
1825
|
+
sheet.__disallowModification = true;
|
|
1826
|
+
|
|
1827
|
+
// In parallel, do these steps:
|
|
1828
|
+
setTimeout(function() {
|
|
1829
|
+
// Let rules be the result of running parse a stylesheet's contents from text.
|
|
1830
|
+
var rules = new CSSOM.CSSRuleList();
|
|
1831
|
+
CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
|
|
1832
|
+
// If rules contains one or more @import rules, remove those rules from rules.
|
|
1833
|
+
var i = 0;
|
|
1834
|
+
while (i < rules.length) {
|
|
1835
|
+
if (rules[i].constructor.name === 'CSSImportRule') {
|
|
1836
|
+
rules.splice(i, 1);
|
|
1837
|
+
} else {
|
|
1838
|
+
i++;
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
// Set sheet's CSS rules to rules.
|
|
1842
|
+
sheet.__cssRules = rules;
|
|
1843
|
+
// Unset sheet’s disallow modification flag.
|
|
1844
|
+
delete sheet.__disallowModification;
|
|
1845
|
+
// Resolve promise with sheet.
|
|
1846
|
+
resolve(sheet);
|
|
1847
|
+
})
|
|
1848
|
+
});
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* Synchronously replaces the rules of a {@link CSSStyleSheet}
|
|
1853
|
+
*
|
|
1854
|
+
* @see https://www.w3.org/TR/cssom-1/#dom-cssstylesheet-replacesync
|
|
1855
|
+
*/
|
|
1856
|
+
CSSOM.CSSStyleSheet.prototype.replaceSync = function(text) {
|
|
1857
|
+
var sheet = this;
|
|
1858
|
+
// If the constructed flag is not set, or the disallow modification flag is set, throw a NotAllowedError DOMException.
|
|
1859
|
+
if (!sheet.__constructed || sheet.__disallowModification) {
|
|
1860
|
+
errorUtils.throwError(sheet, 'DOMException',
|
|
1861
|
+
"Failed to execute 'replaceSync' on '" + sheet.constructor.name + "': Not allowed.",
|
|
1862
|
+
'NotAllowedError');
|
|
1863
|
+
}
|
|
1864
|
+
// Let rules be the result of running parse a stylesheet's contents from text.
|
|
1865
|
+
var rules = new CSSOM.CSSRuleList();
|
|
1866
|
+
CSSOM.parse(text, { styleSheet: sheet, cssRules: rules });
|
|
1867
|
+
// If rules contains one or more @import rules, remove those rules from rules.
|
|
1868
|
+
var i = 0;
|
|
1869
|
+
while (i < rules.length) {
|
|
1870
|
+
if (rules[i].constructor.name === 'CSSImportRule') {
|
|
1871
|
+
rules.splice(i, 1);
|
|
1872
|
+
} else {
|
|
1873
|
+
i++;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
// Set sheet's CSS rules to rules.
|
|
1877
|
+
sheet.__cssRules = rules;
|
|
1878
|
+
}
|
|
1879
|
+
|
|
1680
1880
|
/**
|
|
1681
1881
|
* NON-STANDARD
|
|
1682
1882
|
* @return {string} serialize stylesheet
|
|
@@ -1736,20 +1936,33 @@ CSSOM.CSSKeyframesRule = function CSSKeyframesRule() {
|
|
|
1736
1936
|
});
|
|
1737
1937
|
};
|
|
1738
1938
|
|
|
1739
|
-
CSSOM.CSSKeyframesRule.prototype =
|
|
1939
|
+
CSSOM.CSSKeyframesRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1740
1940
|
CSSOM.CSSKeyframesRule.prototype.constructor = CSSOM.CSSKeyframesRule;
|
|
1741
|
-
|
|
1941
|
+
|
|
1942
|
+
Object.setPrototypeOf(CSSOM.CSSKeyframesRule, CSSOM.CSSRule);
|
|
1943
|
+
|
|
1944
|
+
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "type", {
|
|
1945
|
+
value: 7,
|
|
1946
|
+
writable: false
|
|
1947
|
+
});
|
|
1742
1948
|
|
|
1743
1949
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframesRule.cpp
|
|
1744
1950
|
Object.defineProperty(CSSOM.CSSKeyframesRule.prototype, "cssText", {
|
|
1745
1951
|
get: function() {
|
|
1746
|
-
var
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1952
|
+
var values = "";
|
|
1953
|
+
var valuesArr = [" {"];
|
|
1954
|
+
if (this.cssRules.length) {
|
|
1955
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
1956
|
+
if (rule.cssText !== "") {
|
|
1957
|
+
acc.push(rule.cssText);
|
|
1958
|
+
}
|
|
1959
|
+
return acc;
|
|
1960
|
+
}, []).join("\n "));
|
|
1961
|
+
}
|
|
1962
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
1750
1963
|
var cssWideKeywords = ['initial', 'inherit', 'revert', 'revert-layer', 'unset', 'none'];
|
|
1751
1964
|
var processedName = cssWideKeywords.includes(this.name) ? '"' + this.name + '"' : this.name;
|
|
1752
|
-
return "@" + (this._vendorPrefix || '') + "keyframes " + processedName +
|
|
1965
|
+
return "@" + (this._vendorPrefix || '') + "keyframes " + processedName + values;
|
|
1753
1966
|
}
|
|
1754
1967
|
});
|
|
1755
1968
|
|
|
@@ -1931,9 +2144,16 @@ CSSOM.CSSKeyframeRule = function CSSKeyframeRule() {
|
|
|
1931
2144
|
this.__style.parentRule = this;
|
|
1932
2145
|
};
|
|
1933
2146
|
|
|
1934
|
-
CSSOM.CSSKeyframeRule.prototype =
|
|
2147
|
+
CSSOM.CSSKeyframeRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
1935
2148
|
CSSOM.CSSKeyframeRule.prototype.constructor = CSSOM.CSSKeyframeRule;
|
|
1936
|
-
|
|
2149
|
+
|
|
2150
|
+
Object.setPrototypeOf(CSSOM.CSSKeyframeRule, CSSOM.CSSRule);
|
|
2151
|
+
|
|
2152
|
+
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "type", {
|
|
2153
|
+
value: 8,
|
|
2154
|
+
writable: false
|
|
2155
|
+
});
|
|
2156
|
+
|
|
1937
2157
|
//FIXME
|
|
1938
2158
|
//CSSOM.CSSKeyframeRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
1939
2159
|
//CSSOM.CSSKeyframeRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -2024,6 +2244,7 @@ CSSOM.MatcherList.prototype = {
|
|
|
2024
2244
|
/**
|
|
2025
2245
|
* @constructor
|
|
2026
2246
|
* @see https://developer.mozilla.org/en/CSS/@-moz-document
|
|
2247
|
+
* @deprecated This rule is a non-standard Mozilla-specific extension and is not part of any official CSS specification.
|
|
2027
2248
|
*/
|
|
2028
2249
|
CSSOM.CSSDocumentRule = function CSSDocumentRule() {
|
|
2029
2250
|
CSSOM.CSSRule.call(this);
|
|
@@ -2031,9 +2252,16 @@ CSSOM.CSSDocumentRule = function CSSDocumentRule() {
|
|
|
2031
2252
|
this.cssRules = new CSSOM.CSSRuleList();
|
|
2032
2253
|
};
|
|
2033
2254
|
|
|
2034
|
-
CSSOM.CSSDocumentRule.prototype =
|
|
2255
|
+
CSSOM.CSSDocumentRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
2035
2256
|
CSSOM.CSSDocumentRule.prototype.constructor = CSSOM.CSSDocumentRule;
|
|
2036
|
-
|
|
2257
|
+
|
|
2258
|
+
Object.setPrototypeOf(CSSOM.CSSDocumentRule, CSSOM.CSSRule);
|
|
2259
|
+
|
|
2260
|
+
Object.defineProperty(CSSOM.CSSDocumentRule.prototype, "type", {
|
|
2261
|
+
value: 10,
|
|
2262
|
+
writable: false
|
|
2263
|
+
});
|
|
2264
|
+
|
|
2037
2265
|
//FIXME
|
|
2038
2266
|
//CSSOM.CSSDocumentRule.prototype.insertRule = CSSStyleSheet.prototype.insertRule;
|
|
2039
2267
|
//CSSOM.CSSDocumentRule.prototype.deleteRule = CSSStyleSheet.prototype.deleteRule;
|
|
@@ -2102,9 +2330,11 @@ CSSOM.CSSValueExpression = function CSSValueExpression(token, idx) {
|
|
|
2102
2330
|
this._idx = idx;
|
|
2103
2331
|
};
|
|
2104
2332
|
|
|
2105
|
-
CSSOM.CSSValueExpression.prototype =
|
|
2333
|
+
CSSOM.CSSValueExpression.prototype = Object.create(CSSOM.CSSValue.prototype);
|
|
2106
2334
|
CSSOM.CSSValueExpression.prototype.constructor = CSSOM.CSSValueExpression;
|
|
2107
2335
|
|
|
2336
|
+
Object.setPrototypeOf(CSSOM.CSSValueExpression, CSSOM.CSSValue);
|
|
2337
|
+
|
|
2108
2338
|
/**
|
|
2109
2339
|
* parse css expression() value
|
|
2110
2340
|
*
|
|
@@ -2439,9 +2669,10 @@ CSSOM.CSSScopeRule = function CSSScopeRule() {
|
|
|
2439
2669
|
this.__end = null;
|
|
2440
2670
|
};
|
|
2441
2671
|
|
|
2442
|
-
CSSOM.CSSScopeRule.prototype =
|
|
2672
|
+
CSSOM.CSSScopeRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2443
2673
|
CSSOM.CSSScopeRule.prototype.constructor = CSSOM.CSSScopeRule;
|
|
2444
2674
|
|
|
2675
|
+
Object.setPrototypeOf(CSSOM.CSSScopeRule, CSSOM.CSSGroupingRule);
|
|
2445
2676
|
|
|
2446
2677
|
Object.defineProperties(CSSOM.CSSScopeRule.prototype, {
|
|
2447
2678
|
type: {
|
|
@@ -2450,11 +2681,18 @@ Object.defineProperties(CSSOM.CSSScopeRule.prototype, {
|
|
|
2450
2681
|
},
|
|
2451
2682
|
cssText: {
|
|
2452
2683
|
get: function () {
|
|
2453
|
-
|
|
2454
|
-
|
|
2455
|
-
|
|
2684
|
+
var values = "";
|
|
2685
|
+
var valuesArr = [" {"];
|
|
2686
|
+
if (this.cssRules.length) {
|
|
2687
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
2688
|
+
if (rule.cssText !== "") {
|
|
2689
|
+
acc.push(rule.cssText);
|
|
2690
|
+
}
|
|
2691
|
+
return acc;
|
|
2692
|
+
}, []).join("\n "));
|
|
2456
2693
|
}
|
|
2457
|
-
|
|
2694
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
2695
|
+
return "@scope" + (this.start ? " (" + this.start + ")" : "") + (this.end ? " to (" + this.end + ")" : "") + values;
|
|
2458
2696
|
},
|
|
2459
2697
|
configurable: true,
|
|
2460
2698
|
enumerable: true,
|
|
@@ -2483,21 +2721,32 @@ CSSOM.CSSLayerBlockRule = function CSSLayerBlockRule() {
|
|
|
2483
2721
|
this.name = "";
|
|
2484
2722
|
};
|
|
2485
2723
|
|
|
2486
|
-
CSSOM.CSSLayerBlockRule.prototype =
|
|
2724
|
+
CSSOM.CSSLayerBlockRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2487
2725
|
CSSOM.CSSLayerBlockRule.prototype.constructor = CSSOM.CSSLayerBlockRule;
|
|
2488
|
-
|
|
2726
|
+
|
|
2727
|
+
Object.setPrototypeOf(CSSOM.CSSLayerBlockRule, CSSOM.CSSRule);
|
|
2728
|
+
|
|
2729
|
+
Object.defineProperty(CSSOM.CSSLayerBlockRule.prototype, "type", {
|
|
2730
|
+
value: 18,
|
|
2731
|
+
writable: false
|
|
2732
|
+
});
|
|
2489
2733
|
|
|
2490
2734
|
Object.defineProperties(CSSOM.CSSLayerBlockRule.prototype, {
|
|
2491
2735
|
cssText: {
|
|
2492
2736
|
get: function () {
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2737
|
+
var values = "";
|
|
2738
|
+
var valuesArr = [" {"];
|
|
2739
|
+
if (this.cssRules.length) {
|
|
2740
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
2741
|
+
if (rule.cssText !== "") {
|
|
2742
|
+
acc.push(rule.cssText);
|
|
2743
|
+
}
|
|
2744
|
+
return acc;
|
|
2745
|
+
}, []).join("\n "));
|
|
2496
2746
|
}
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
enumerable: true,
|
|
2747
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
2748
|
+
return "@layer" + (this.name ? " " + this.name : "") + values;
|
|
2749
|
+
}
|
|
2501
2750
|
},
|
|
2502
2751
|
});
|
|
2503
2752
|
|
|
@@ -2513,17 +2762,21 @@ CSSOM.CSSLayerStatementRule = function CSSLayerStatementRule() {
|
|
|
2513
2762
|
this.nameList = [];
|
|
2514
2763
|
};
|
|
2515
2764
|
|
|
2516
|
-
CSSOM.CSSLayerStatementRule.prototype =
|
|
2765
|
+
CSSOM.CSSLayerStatementRule.prototype = Object.create(CSSOM.CSSRule.prototype);
|
|
2517
2766
|
CSSOM.CSSLayerStatementRule.prototype.constructor = CSSOM.CSSLayerStatementRule;
|
|
2518
|
-
|
|
2767
|
+
|
|
2768
|
+
Object.setPrototypeOf(CSSOM.CSSLayerStatementRule, CSSOM.CSSRule);
|
|
2769
|
+
|
|
2770
|
+
Object.defineProperty(CSSOM.CSSLayerStatementRule.prototype, "type", {
|
|
2771
|
+
value: 0,
|
|
2772
|
+
writable: false
|
|
2773
|
+
});
|
|
2519
2774
|
|
|
2520
2775
|
Object.defineProperties(CSSOM.CSSLayerStatementRule.prototype, {
|
|
2521
2776
|
cssText: {
|
|
2522
2777
|
get: function () {
|
|
2523
2778
|
return "@layer " + this.nameList.join(", ") + ";";
|
|
2524
|
-
}
|
|
2525
|
-
configurable: true,
|
|
2526
|
-
enumerable: true,
|
|
2779
|
+
}
|
|
2527
2780
|
},
|
|
2528
2781
|
});
|
|
2529
2782
|
|
|
@@ -2541,9 +2794,11 @@ CSSOM.CSSPageRule = function CSSPageRule() {
|
|
|
2541
2794
|
this.__style.parentRule = this;
|
|
2542
2795
|
};
|
|
2543
2796
|
|
|
2544
|
-
CSSOM.CSSPageRule.prototype =
|
|
2797
|
+
CSSOM.CSSPageRule.prototype = Object.create(CSSOM.CSSGroupingRule.prototype);
|
|
2545
2798
|
CSSOM.CSSPageRule.prototype.constructor = CSSOM.CSSPageRule;
|
|
2546
2799
|
|
|
2800
|
+
Object.setPrototypeOf(CSSOM.CSSPageRule, CSSOM.CSSGroupingRule);
|
|
2801
|
+
|
|
2547
2802
|
Object.defineProperty(CSSOM.CSSPageRule.prototype, "type", {
|
|
2548
2803
|
value: 6,
|
|
2549
2804
|
writable: false
|
|
@@ -2623,171 +2878,24 @@ Object.defineProperty(CSSOM.CSSPageRule.prototype, "style", {
|
|
|
2623
2878
|
|
|
2624
2879
|
Object.defineProperty(CSSOM.CSSPageRule.prototype, "cssText", {
|
|
2625
2880
|
get: function() {
|
|
2626
|
-
var values = ""
|
|
2881
|
+
var values = "";
|
|
2627
2882
|
if (this.cssRules.length) {
|
|
2628
2883
|
var valuesArr = [" {"];
|
|
2629
2884
|
this.style.cssText && valuesArr.push(this.style.cssText);
|
|
2630
|
-
valuesArr.push(this.cssRules.
|
|
2631
|
-
|
|
2885
|
+
valuesArr.push(this.cssRules.reduce(function(acc, rule){
|
|
2886
|
+
if (rule.cssText !== "") {
|
|
2887
|
+
acc.push(rule.cssText);
|
|
2888
|
+
}
|
|
2889
|
+
return acc;
|
|
2890
|
+
}, []).join("\n "));
|
|
2891
|
+
values = valuesArr.join("\n ") + "\n}";
|
|
2632
2892
|
} else {
|
|
2633
2893
|
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
2634
2894
|
}
|
|
2635
2895
|
return "@page" + (this.selectorText ? " " + this.selectorText : "") + values;
|
|
2636
|
-
},
|
|
2637
|
-
set: function(cssText) {
|
|
2638
|
-
if (typeof value === "string") {
|
|
2639
|
-
var rule = CSSOM.CSSPageRule.parse(cssText);
|
|
2640
|
-
this.__style = rule.style;
|
|
2641
|
-
this.selectorText = rule.selectorText;
|
|
2642
|
-
}
|
|
2643
2896
|
}
|
|
2644
2897
|
});
|
|
2645
2898
|
|
|
2646
|
-
/**
|
|
2647
|
-
* NON-STANDARD
|
|
2648
|
-
* lightweight version of parse.js.
|
|
2649
|
-
* @param {string} ruleText
|
|
2650
|
-
* @return CSSPageRule
|
|
2651
|
-
*/
|
|
2652
|
-
CSSOM.CSSPageRule.parse = function(ruleText) {
|
|
2653
|
-
var i = 0;
|
|
2654
|
-
var state = "selector";
|
|
2655
|
-
var index;
|
|
2656
|
-
var j = i;
|
|
2657
|
-
var buffer = "";
|
|
2658
|
-
|
|
2659
|
-
var SIGNIFICANT_WHITESPACE = {
|
|
2660
|
-
"selector": true,
|
|
2661
|
-
"value": true
|
|
2662
|
-
};
|
|
2663
|
-
|
|
2664
|
-
var pageRule = new CSSOM.CSSPageRule();
|
|
2665
|
-
var name, priority="";
|
|
2666
|
-
|
|
2667
|
-
for (var character; (character = ruleText.charAt(i)); i++) {
|
|
2668
|
-
|
|
2669
|
-
switch (character) {
|
|
2670
|
-
|
|
2671
|
-
case " ":
|
|
2672
|
-
case "\t":
|
|
2673
|
-
case "\r":
|
|
2674
|
-
case "\n":
|
|
2675
|
-
case "\f":
|
|
2676
|
-
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
2677
|
-
// Squash 2 or more white-spaces in the row into 1
|
|
2678
|
-
switch (ruleText.charAt(i - 1)) {
|
|
2679
|
-
case " ":
|
|
2680
|
-
case "\t":
|
|
2681
|
-
case "\r":
|
|
2682
|
-
case "\n":
|
|
2683
|
-
case "\f":
|
|
2684
|
-
break;
|
|
2685
|
-
default:
|
|
2686
|
-
buffer += " ";
|
|
2687
|
-
break;
|
|
2688
|
-
}
|
|
2689
|
-
}
|
|
2690
|
-
break;
|
|
2691
|
-
|
|
2692
|
-
// String
|
|
2693
|
-
case '"':
|
|
2694
|
-
j = i + 1;
|
|
2695
|
-
index = ruleText.indexOf('"', j) + 1;
|
|
2696
|
-
if (!index) {
|
|
2697
|
-
throw '" is missing';
|
|
2698
|
-
}
|
|
2699
|
-
buffer += ruleText.slice(i, index);
|
|
2700
|
-
i = index - 1;
|
|
2701
|
-
break;
|
|
2702
|
-
|
|
2703
|
-
case "'":
|
|
2704
|
-
j = i + 1;
|
|
2705
|
-
index = ruleText.indexOf("'", j) + 1;
|
|
2706
|
-
if (!index) {
|
|
2707
|
-
throw "' is missing";
|
|
2708
|
-
}
|
|
2709
|
-
buffer += ruleText.slice(i, index);
|
|
2710
|
-
i = index - 1;
|
|
2711
|
-
break;
|
|
2712
|
-
|
|
2713
|
-
// Comment
|
|
2714
|
-
case "/":
|
|
2715
|
-
if (ruleText.charAt(i + 1) === "*") {
|
|
2716
|
-
i += 2;
|
|
2717
|
-
index = ruleText.indexOf("*/", i);
|
|
2718
|
-
if (index === -1) {
|
|
2719
|
-
throw new SyntaxError("Missing */");
|
|
2720
|
-
} else {
|
|
2721
|
-
i = index + 1;
|
|
2722
|
-
}
|
|
2723
|
-
} else {
|
|
2724
|
-
buffer += character;
|
|
2725
|
-
}
|
|
2726
|
-
break;
|
|
2727
|
-
|
|
2728
|
-
case "{":
|
|
2729
|
-
if (state === "selector") {
|
|
2730
|
-
pageRule.selectorText = buffer.trim();
|
|
2731
|
-
buffer = "";
|
|
2732
|
-
state = "name";
|
|
2733
|
-
}
|
|
2734
|
-
break;
|
|
2735
|
-
|
|
2736
|
-
case ":":
|
|
2737
|
-
if (state === "name") {
|
|
2738
|
-
name = buffer.trim();
|
|
2739
|
-
buffer = "";
|
|
2740
|
-
state = "value";
|
|
2741
|
-
} else {
|
|
2742
|
-
buffer += character;
|
|
2743
|
-
}
|
|
2744
|
-
break;
|
|
2745
|
-
|
|
2746
|
-
case "!":
|
|
2747
|
-
if (state === "value" && ruleText.indexOf("!important", i) === i) {
|
|
2748
|
-
priority = "important";
|
|
2749
|
-
i += "important".length;
|
|
2750
|
-
} else {
|
|
2751
|
-
buffer += character;
|
|
2752
|
-
}
|
|
2753
|
-
break;
|
|
2754
|
-
|
|
2755
|
-
case ";":
|
|
2756
|
-
if (state === "value") {
|
|
2757
|
-
pageRule.style.setProperty(name, buffer.trim(), priority);
|
|
2758
|
-
priority = "";
|
|
2759
|
-
buffer = "";
|
|
2760
|
-
state = "name";
|
|
2761
|
-
} else {
|
|
2762
|
-
buffer += character;
|
|
2763
|
-
}
|
|
2764
|
-
break;
|
|
2765
|
-
|
|
2766
|
-
case "}":
|
|
2767
|
-
if (state === "value") {
|
|
2768
|
-
pageRule.style.setProperty(name, buffer.trim(), priority);
|
|
2769
|
-
priority = "";
|
|
2770
|
-
buffer = "";
|
|
2771
|
-
} else if (state === "name") {
|
|
2772
|
-
break;
|
|
2773
|
-
} else {
|
|
2774
|
-
buffer += character;
|
|
2775
|
-
}
|
|
2776
|
-
state = "selector";
|
|
2777
|
-
break;
|
|
2778
|
-
|
|
2779
|
-
default:
|
|
2780
|
-
buffer += character;
|
|
2781
|
-
break;
|
|
2782
|
-
|
|
2783
|
-
}
|
|
2784
|
-
}
|
|
2785
|
-
|
|
2786
|
-
return pageRule;
|
|
2787
|
-
|
|
2788
|
-
};
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
2899
|
|
|
2792
2900
|
|
|
2793
2901
|
|
|
@@ -2796,7 +2904,11 @@ CSSOM.CSSPageRule.parse = function(ruleText) {
|
|
|
2796
2904
|
*
|
|
2797
2905
|
* @param {string} token - The CSS string to parse.
|
|
2798
2906
|
* @param {object} [opts] - Optional parsing options.
|
|
2799
|
-
* @param {object} [opts.globalObject] - An optional global object to
|
|
2907
|
+
* @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.
|
|
2908
|
+
* @param {Element | ProcessingInstruction} [opts.ownerNode] - The owner node of the stylesheet.
|
|
2909
|
+
* @param {CSSRule} [opts.ownerRule] - The owner rule of the stylesheet.
|
|
2910
|
+
* @param {CSSOM.CSSStyleSheet} [opts.styleSheet] - Reuse a style sheet instead of creating a new one (e.g. as `parentStyleSheet`)
|
|
2911
|
+
* @param {CSSOM.CSSRuleList} [opts.cssRules] - Prepare all rules in this list instead of mutating the style sheet continually
|
|
2800
2912
|
* @param {function|boolean} [errorHandler] - Optional error handler function or `true` to use `console.error`.
|
|
2801
2913
|
* @returns {CSSOM.CSSStyleSheet} The parsed CSSStyleSheet object.
|
|
2802
2914
|
*/
|
|
@@ -2843,14 +2955,35 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
2843
2955
|
"pageBlock": true
|
|
2844
2956
|
};
|
|
2845
2957
|
|
|
2846
|
-
var styleSheet
|
|
2958
|
+
var styleSheet;
|
|
2959
|
+
if (opts && opts.styleSheet) {
|
|
2960
|
+
styleSheet = opts.styleSheet;
|
|
2961
|
+
} else {
|
|
2962
|
+
styleSheet = new CSSOM.CSSStyleSheet()
|
|
2963
|
+
styleSheet.__constructed = false;
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
var topScope;
|
|
2967
|
+
if (opts && opts.cssRules) {
|
|
2968
|
+
topScope = { cssRules: opts.cssRules };
|
|
2969
|
+
} else {
|
|
2970
|
+
topScope = styleSheet;
|
|
2971
|
+
}
|
|
2847
2972
|
|
|
2848
2973
|
if (opts && opts.globalObject) {
|
|
2849
|
-
|
|
2974
|
+
CSSOM.setup({ globalObject: opts.globalObject });
|
|
2975
|
+
}
|
|
2976
|
+
|
|
2977
|
+
if (opts && opts.ownerNode) {
|
|
2978
|
+
styleSheet.__ownerNode = opts.ownerNode;
|
|
2979
|
+
}
|
|
2980
|
+
|
|
2981
|
+
if (opts && opts.ownerRule) {
|
|
2982
|
+
styleSheet.__ownerRule = opts.ownerRule;
|
|
2850
2983
|
}
|
|
2851
2984
|
|
|
2852
2985
|
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
2853
|
-
var currentScope =
|
|
2986
|
+
var currentScope = topScope;
|
|
2854
2987
|
|
|
2855
2988
|
// @type CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSKeyframesRule|CSSDocumentRule
|
|
2856
2989
|
var parentRule;
|
|
@@ -2858,7 +2991,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
2858
2991
|
var ancestorRules = [];
|
|
2859
2992
|
var prevScope;
|
|
2860
2993
|
|
|
2861
|
-
var name, priority="", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, pageRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
2994
|
+
var name, priority = "", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, pageRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
2862
2995
|
|
|
2863
2996
|
// Track defined namespace prefixes for validation
|
|
2864
2997
|
var definedNamespacePrefixes = {};
|
|
@@ -2956,14 +3089,14 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
2956
3089
|
var ruleClosingMatch = matchBalancedBlock(str, fromIndex);
|
|
2957
3090
|
if (ruleClosingMatch) {
|
|
2958
3091
|
var ignoreRange = ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
2959
|
-
i+= ignoreRange;
|
|
3092
|
+
i += ignoreRange;
|
|
2960
3093
|
if (token.charAt(i) === '}') {
|
|
2961
3094
|
i -= 1;
|
|
2962
3095
|
}
|
|
2963
3096
|
} else {
|
|
2964
3097
|
i += str.length;
|
|
2965
3098
|
}
|
|
2966
|
-
return i;
|
|
3099
|
+
return i;
|
|
2967
3100
|
}
|
|
2968
3101
|
|
|
2969
3102
|
/**
|
|
@@ -2973,29 +3106,29 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
2973
3106
|
*/
|
|
2974
3107
|
function parseScopePrelude(preludeContent) {
|
|
2975
3108
|
var parts = preludeContent.split(/\s*\)\s*to\s+\(/);
|
|
2976
|
-
|
|
3109
|
+
|
|
2977
3110
|
// Restore the parentheses that were consumed by the split
|
|
2978
3111
|
if (parts.length === 2) {
|
|
2979
3112
|
parts[0] = parts[0] + ')';
|
|
2980
3113
|
parts[1] = '(' + parts[1];
|
|
2981
3114
|
}
|
|
2982
|
-
|
|
3115
|
+
|
|
2983
3116
|
var hasStart = parts[0] &&
|
|
2984
3117
|
parts[0].charAt(0) === '(' &&
|
|
2985
3118
|
parts[0].charAt(parts[0].length - 1) === ')';
|
|
2986
3119
|
var hasEnd = parts[1] &&
|
|
2987
3120
|
parts[1].charAt(0) === '(' &&
|
|
2988
3121
|
parts[1].charAt(parts[1].length - 1) === ')';
|
|
2989
|
-
|
|
3122
|
+
|
|
2990
3123
|
// Handle case: @scope to (<end>)
|
|
2991
3124
|
var hasOnlyEnd = !hasStart &&
|
|
2992
3125
|
!hasEnd &&
|
|
2993
3126
|
parts[0].indexOf('to (') === 0 &&
|
|
2994
3127
|
parts[0].charAt(parts[0].length - 1) === ')';
|
|
2995
|
-
|
|
3128
|
+
|
|
2996
3129
|
var startSelector = '';
|
|
2997
3130
|
var endSelector = '';
|
|
2998
|
-
|
|
3131
|
+
|
|
2999
3132
|
if (hasStart) {
|
|
3000
3133
|
startSelector = parts[0].slice(1, -1).trim();
|
|
3001
3134
|
}
|
|
@@ -3005,7 +3138,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3005
3138
|
if (hasOnlyEnd) {
|
|
3006
3139
|
endSelector = parts[0].slice(4, -1).trim();
|
|
3007
3140
|
}
|
|
3008
|
-
|
|
3141
|
+
|
|
3009
3142
|
return {
|
|
3010
3143
|
startSelector: startSelector,
|
|
3011
3144
|
endSelector: endSelector,
|
|
@@ -3043,11 +3176,11 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3043
3176
|
var inDoubleQuote = false;
|
|
3044
3177
|
var inAttr = false;
|
|
3045
3178
|
var stack = useStack ? [] : null;
|
|
3046
|
-
|
|
3179
|
+
|
|
3047
3180
|
for (var i = 0; i < selector.length; i++) {
|
|
3048
3181
|
var char = selector[i];
|
|
3049
3182
|
var prevChar = i > 0 ? selector[i - 1] : '';
|
|
3050
|
-
|
|
3183
|
+
|
|
3051
3184
|
if (inSingleQuote) {
|
|
3052
3185
|
if (char === "'" && prevChar !== "\\") {
|
|
3053
3186
|
inSingleQuote = false;
|
|
@@ -3098,7 +3231,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3098
3231
|
}
|
|
3099
3232
|
}
|
|
3100
3233
|
}
|
|
3101
|
-
|
|
3234
|
+
|
|
3102
3235
|
// Check if everything is balanced
|
|
3103
3236
|
if (useStack) {
|
|
3104
3237
|
return stack.length === 0 && bracketDepth === 0 && !inSingleQuote && !inDoubleQuote && !inAttr;
|
|
@@ -3148,7 +3281,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3148
3281
|
/(?:^|[\s>+~,\[])cue\s*\(/i,
|
|
3149
3282
|
/(?:^|[\s>+~,\[])cue-region\s*\(/i
|
|
3150
3283
|
];
|
|
3151
|
-
|
|
3284
|
+
|
|
3152
3285
|
for (var i = 0; i < invalidPatterns.length; i++) {
|
|
3153
3286
|
if (invalidPatterns[i].test(selector)) {
|
|
3154
3287
|
return true;
|
|
@@ -3179,7 +3312,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3179
3312
|
var ruleRegExp = new RegExp(atRuleKey + sourceRuleRegExp.source, sourceRuleRegExp.flags);
|
|
3180
3313
|
var ruleSlice = token.slice(i);
|
|
3181
3314
|
// Not all rules can be nested, if the rule cannot be nested and is in the root scope, do not perform the check
|
|
3182
|
-
var shouldPerformCheck = cannotBeNested && currentScope !==
|
|
3315
|
+
var shouldPerformCheck = cannotBeNested && currentScope !== topScope ? false : true;
|
|
3183
3316
|
// First, check if there is no invalid characters just after the at-rule
|
|
3184
3317
|
if (shouldPerformCheck && ruleSlice.search(ruleRegExp) === 0) {
|
|
3185
3318
|
// Find the closest allowed character before the at-rule (a opening or closing brace, a semicolon or a comment ending)
|
|
@@ -3194,7 +3327,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3194
3327
|
isValid = true;
|
|
3195
3328
|
}
|
|
3196
3329
|
}
|
|
3197
|
-
|
|
3330
|
+
|
|
3198
3331
|
// Additional validation for @scope rule
|
|
3199
3332
|
if (isValid && atRuleKey === "@scope") {
|
|
3200
3333
|
var openBraceIndex = ruleSlice.indexOf('{');
|
|
@@ -3213,7 +3346,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3213
3346
|
var hasStart = parsedScopePrelude.hasStart;
|
|
3214
3347
|
var hasEnd = parsedScopePrelude.hasEnd;
|
|
3215
3348
|
var hasOnlyEnd = parsedScopePrelude.hasOnlyEnd;
|
|
3216
|
-
|
|
3349
|
+
|
|
3217
3350
|
// Validation rules for @scope:
|
|
3218
3351
|
// 1. Empty selectors in parentheses are invalid: @scope () {} or @scope (.a) to () {}
|
|
3219
3352
|
if ((hasStart && startSelector === '') || (hasEnd && endSelector === '') || (hasOnlyEnd && endSelector === '')) {
|
|
@@ -3249,13 +3382,13 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3249
3382
|
if (openBraceIndex !== -1) {
|
|
3250
3383
|
// Extract the rule prelude (everything between the at-rule and {)
|
|
3251
3384
|
var rulePrelude = ruleSlice.slice(0, openBraceIndex).trim();
|
|
3252
|
-
|
|
3385
|
+
|
|
3253
3386
|
// Skip past at-rule keyword and whitespace
|
|
3254
3387
|
var preludeContent = rulePrelude.slice("@page".length).trim();
|
|
3255
3388
|
|
|
3256
3389
|
if (preludeContent.length > 0) {
|
|
3257
3390
|
var trimmedValue = preludeContent.trim();
|
|
3258
|
-
|
|
3391
|
+
|
|
3259
3392
|
// Empty selector is valid for @page
|
|
3260
3393
|
if (trimmedValue !== '') {
|
|
3261
3394
|
// Parse @page selectorText for page name and pseudo-pages
|
|
@@ -3279,7 +3412,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3279
3412
|
|
|
3280
3413
|
// Validate pseudo-pages if present
|
|
3281
3414
|
if (pseudoPages) {
|
|
3282
|
-
var pseudos = pseudoPages.split(':').filter(function(p) { return p; });
|
|
3415
|
+
var pseudos = pseudoPages.split(':').filter(function (p) { return p; });
|
|
3283
3416
|
var validPseudos = ['left', 'right', 'first', 'blank'];
|
|
3284
3417
|
var allValid = true;
|
|
3285
3418
|
for (var j = 0; j < pseudos.length; j++) {
|
|
@@ -3288,7 +3421,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3288
3421
|
break;
|
|
3289
3422
|
}
|
|
3290
3423
|
}
|
|
3291
|
-
|
|
3424
|
+
|
|
3292
3425
|
if (!allValid) {
|
|
3293
3426
|
isValid = false;
|
|
3294
3427
|
}
|
|
@@ -3297,21 +3430,21 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3297
3430
|
isValid = false;
|
|
3298
3431
|
}
|
|
3299
3432
|
}
|
|
3300
|
-
|
|
3433
|
+
|
|
3301
3434
|
}
|
|
3302
3435
|
}
|
|
3303
3436
|
}
|
|
3304
|
-
|
|
3437
|
+
|
|
3305
3438
|
if (!isValid) {
|
|
3306
3439
|
// If it's invalid the browser will simply ignore the entire invalid block
|
|
3307
3440
|
// Use regex to find the closing brace of the invalid rule
|
|
3308
|
-
|
|
3441
|
+
|
|
3309
3442
|
// Regex used above is not ES5 compliant. Using alternative.
|
|
3310
3443
|
// var ruleStatementMatch = ruleSlice.match(atRulesStatemenRegExp); //
|
|
3311
3444
|
var ruleStatementMatch = atRulesStatemenRegExpES5Alternative(ruleSlice);
|
|
3312
3445
|
|
|
3313
3446
|
// If it's a statement inside a nested rule, ignore only the statement
|
|
3314
|
-
if (ruleStatementMatch && currentScope !==
|
|
3447
|
+
if (ruleStatementMatch && currentScope !== topScope) {
|
|
3315
3448
|
var ignoreEnd = ruleStatementMatch[0].indexOf(";");
|
|
3316
3449
|
i += ruleStatementMatch.index + ignoreEnd;
|
|
3317
3450
|
return;
|
|
@@ -3320,7 +3453,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3320
3453
|
// Check if there's a semicolon before the invalid at-rule and the first opening brace
|
|
3321
3454
|
if (atRuleKey === "@layer") {
|
|
3322
3455
|
var ruleSemicolonAndOpeningBraceMatch = ruleSlice.match(forwardRuleSemicolonAndOpeningBraceRegExp);
|
|
3323
|
-
if (ruleSemicolonAndOpeningBraceMatch && ruleSemicolonAndOpeningBraceMatch[1] === ";"
|
|
3456
|
+
if (ruleSemicolonAndOpeningBraceMatch && ruleSemicolonAndOpeningBraceMatch[1] === ";") {
|
|
3324
3457
|
// Ignore the rule block until the semicolon
|
|
3325
3458
|
i += ruleSemicolonAndOpeningBraceMatch.index + ruleSemicolonAndOpeningBraceMatch[0].length;
|
|
3326
3459
|
state = "before-selector";
|
|
@@ -3336,6 +3469,255 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3336
3469
|
}
|
|
3337
3470
|
}
|
|
3338
3471
|
|
|
3472
|
+
// Helper functions for looseSelectorValidator
|
|
3473
|
+
// Defined outside to avoid recreation on every validation call
|
|
3474
|
+
|
|
3475
|
+
/**
|
|
3476
|
+
* Check if character is a valid identifier start
|
|
3477
|
+
* @param {string} c - Character to check
|
|
3478
|
+
* @returns {boolean}
|
|
3479
|
+
*/
|
|
3480
|
+
function isIdentStart(c) {
|
|
3481
|
+
return /[a-zA-Z_\u00A0-\uFFFF]/.test(c);
|
|
3482
|
+
}
|
|
3483
|
+
|
|
3484
|
+
/**
|
|
3485
|
+
* Check if character is a valid identifier character
|
|
3486
|
+
* @param {string} c - Character to check
|
|
3487
|
+
* @returns {boolean}
|
|
3488
|
+
*/
|
|
3489
|
+
function isIdentChar(c) {
|
|
3490
|
+
return /[a-zA-Z0-9_\u00A0-\uFFFF\-]/.test(c);
|
|
3491
|
+
}
|
|
3492
|
+
|
|
3493
|
+
/**
|
|
3494
|
+
* Helper function to validate CSS selector syntax without regex backtracking.
|
|
3495
|
+
* Iteratively parses the selector string to identify valid components.
|
|
3496
|
+
*
|
|
3497
|
+
* Supports:
|
|
3498
|
+
* - Escaped special characters (e.g., .class\!, #id\@name)
|
|
3499
|
+
* - Namespace selectors (ns|element, *|element, |element)
|
|
3500
|
+
* - All standard CSS selectors (class, ID, type, attribute, pseudo, etc.)
|
|
3501
|
+
* - Combinators (>, +, ~, whitespace)
|
|
3502
|
+
* - Nesting selector (&)
|
|
3503
|
+
*
|
|
3504
|
+
* This approach eliminates exponential backtracking by using explicit character-by-character
|
|
3505
|
+
* parsing instead of nested quantifiers in regex.
|
|
3506
|
+
*
|
|
3507
|
+
* @param {string} selector - The selector to validate
|
|
3508
|
+
* @returns {boolean} - True if valid selector syntax
|
|
3509
|
+
*/
|
|
3510
|
+
function looseSelectorValidator(selector) {
|
|
3511
|
+
if (!selector || selector.length === 0) {
|
|
3512
|
+
return false;
|
|
3513
|
+
}
|
|
3514
|
+
|
|
3515
|
+
var i = 0;
|
|
3516
|
+
var len = selector.length;
|
|
3517
|
+
var hasMatchedComponent = false;
|
|
3518
|
+
|
|
3519
|
+
// Helper: Skip escaped character (backslash + any char)
|
|
3520
|
+
function skipEscape() {
|
|
3521
|
+
if (i < len && selector[i] === '\\') {
|
|
3522
|
+
i += 2; // Skip backslash and next character
|
|
3523
|
+
return true;
|
|
3524
|
+
}
|
|
3525
|
+
return false;
|
|
3526
|
+
}
|
|
3527
|
+
|
|
3528
|
+
// Helper: Parse identifier (with possible escapes)
|
|
3529
|
+
function parseIdentifier() {
|
|
3530
|
+
var start = i;
|
|
3531
|
+
while (i < len) {
|
|
3532
|
+
if (skipEscape()) {
|
|
3533
|
+
continue;
|
|
3534
|
+
} else if (isIdentChar(selector[i])) {
|
|
3535
|
+
i++;
|
|
3536
|
+
} else {
|
|
3537
|
+
break;
|
|
3538
|
+
}
|
|
3539
|
+
}
|
|
3540
|
+
return i > start;
|
|
3541
|
+
}
|
|
3542
|
+
|
|
3543
|
+
// Helper: Parse namespace prefix (optional)
|
|
3544
|
+
function parseNamespace() {
|
|
3545
|
+
var start = i;
|
|
3546
|
+
|
|
3547
|
+
// Match: *| or identifier| or |
|
|
3548
|
+
if (i < len && selector[i] === '*') {
|
|
3549
|
+
i++;
|
|
3550
|
+
} else if (i < len && (isIdentStart(selector[i]) || selector[i] === '\\')) {
|
|
3551
|
+
parseIdentifier();
|
|
3552
|
+
}
|
|
3553
|
+
|
|
3554
|
+
if (i < len && selector[i] === '|') {
|
|
3555
|
+
i++;
|
|
3556
|
+
return true;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
// Rollback if no pipe found
|
|
3560
|
+
i = start;
|
|
3561
|
+
return false;
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
// Helper: Parse pseudo-class/element arguments (with balanced parens)
|
|
3565
|
+
function parsePseudoArgs() {
|
|
3566
|
+
if (i >= len || selector[i] !== '(') {
|
|
3567
|
+
return false;
|
|
3568
|
+
}
|
|
3569
|
+
|
|
3570
|
+
i++; // Skip opening paren
|
|
3571
|
+
var depth = 1;
|
|
3572
|
+
var inString = false;
|
|
3573
|
+
var stringChar = '';
|
|
3574
|
+
|
|
3575
|
+
while (i < len && depth > 0) {
|
|
3576
|
+
var c = selector[i];
|
|
3577
|
+
|
|
3578
|
+
if (c === '\\' && i + 1 < len) {
|
|
3579
|
+
i += 2; // Skip escaped character
|
|
3580
|
+
} else if (!inString && (c === '"' || c === '\'')) {
|
|
3581
|
+
inString = true;
|
|
3582
|
+
stringChar = c;
|
|
3583
|
+
i++;
|
|
3584
|
+
} else if (inString && c === stringChar) {
|
|
3585
|
+
inString = false;
|
|
3586
|
+
i++;
|
|
3587
|
+
} else if (!inString && c === '(') {
|
|
3588
|
+
depth++;
|
|
3589
|
+
i++;
|
|
3590
|
+
} else if (!inString && c === ')') {
|
|
3591
|
+
depth--;
|
|
3592
|
+
i++;
|
|
3593
|
+
} else {
|
|
3594
|
+
i++;
|
|
3595
|
+
}
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
return depth === 0;
|
|
3599
|
+
}
|
|
3600
|
+
|
|
3601
|
+
// Main parsing loop
|
|
3602
|
+
while (i < len) {
|
|
3603
|
+
var matched = false;
|
|
3604
|
+
var start = i;
|
|
3605
|
+
|
|
3606
|
+
// Skip whitespace
|
|
3607
|
+
while (i < len && /\s/.test(selector[i])) {
|
|
3608
|
+
i++;
|
|
3609
|
+
}
|
|
3610
|
+
if (i > start) {
|
|
3611
|
+
hasMatchedComponent = true;
|
|
3612
|
+
continue;
|
|
3613
|
+
}
|
|
3614
|
+
|
|
3615
|
+
// Match combinators: >, +, ~
|
|
3616
|
+
if (i < len && /[>+~]/.test(selector[i])) {
|
|
3617
|
+
i++;
|
|
3618
|
+
hasMatchedComponent = true;
|
|
3619
|
+
// Skip trailing whitespace
|
|
3620
|
+
while (i < len && /\s/.test(selector[i])) {
|
|
3621
|
+
i++;
|
|
3622
|
+
}
|
|
3623
|
+
continue;
|
|
3624
|
+
}
|
|
3625
|
+
|
|
3626
|
+
// Match nesting selector: &
|
|
3627
|
+
if (i < len && selector[i] === '&') {
|
|
3628
|
+
i++;
|
|
3629
|
+
hasMatchedComponent = true;
|
|
3630
|
+
matched = true;
|
|
3631
|
+
}
|
|
3632
|
+
// Match class selector: .identifier
|
|
3633
|
+
else if (i < len && selector[i] === '.') {
|
|
3634
|
+
i++;
|
|
3635
|
+
if (parseIdentifier()) {
|
|
3636
|
+
hasMatchedComponent = true;
|
|
3637
|
+
matched = true;
|
|
3638
|
+
}
|
|
3639
|
+
}
|
|
3640
|
+
// Match ID selector: #identifier
|
|
3641
|
+
else if (i < len && selector[i] === '#') {
|
|
3642
|
+
i++;
|
|
3643
|
+
if (parseIdentifier()) {
|
|
3644
|
+
hasMatchedComponent = true;
|
|
3645
|
+
matched = true;
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
// Match pseudo-class/element: :identifier or ::identifier
|
|
3649
|
+
else if (i < len && selector[i] === ':') {
|
|
3650
|
+
i++;
|
|
3651
|
+
if (i < len && selector[i] === ':') {
|
|
3652
|
+
i++; // Pseudo-element
|
|
3653
|
+
}
|
|
3654
|
+
if (parseIdentifier()) {
|
|
3655
|
+
parsePseudoArgs(); // Optional arguments
|
|
3656
|
+
hasMatchedComponent = true;
|
|
3657
|
+
matched = true;
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
// Match attribute selector: [...]
|
|
3661
|
+
else if (i < len && selector[i] === '[') {
|
|
3662
|
+
i++;
|
|
3663
|
+
var depth = 1;
|
|
3664
|
+
while (i < len && depth > 0) {
|
|
3665
|
+
if (selector[i] === '\\') {
|
|
3666
|
+
i += 2;
|
|
3667
|
+
} else if (selector[i] === '\'') {
|
|
3668
|
+
i++;
|
|
3669
|
+
while (i < len && selector[i] !== '\'') {
|
|
3670
|
+
if (selector[i] === '\\') i += 2;
|
|
3671
|
+
else i++;
|
|
3672
|
+
}
|
|
3673
|
+
if (i < len) i++; // Skip closing quote
|
|
3674
|
+
} else if (selector[i] === '"') {
|
|
3675
|
+
i++;
|
|
3676
|
+
while (i < len && selector[i] !== '"') {
|
|
3677
|
+
if (selector[i] === '\\') i += 2;
|
|
3678
|
+
else i++;
|
|
3679
|
+
}
|
|
3680
|
+
if (i < len) i++; // Skip closing quote
|
|
3681
|
+
} else if (selector[i] === '[') {
|
|
3682
|
+
depth++;
|
|
3683
|
+
i++;
|
|
3684
|
+
} else if (selector[i] === ']') {
|
|
3685
|
+
depth--;
|
|
3686
|
+
i++;
|
|
3687
|
+
} else {
|
|
3688
|
+
i++;
|
|
3689
|
+
}
|
|
3690
|
+
}
|
|
3691
|
+
if (depth === 0) {
|
|
3692
|
+
hasMatchedComponent = true;
|
|
3693
|
+
matched = true;
|
|
3694
|
+
}
|
|
3695
|
+
}
|
|
3696
|
+
// Match type selector with optional namespace: [namespace|]identifier
|
|
3697
|
+
else if (i < len && (isIdentStart(selector[i]) || selector[i] === '\\' || selector[i] === '*' || selector[i] === '|')) {
|
|
3698
|
+
parseNamespace(); // Optional namespace prefix
|
|
3699
|
+
|
|
3700
|
+
if (i < len && selector[i] === '*') {
|
|
3701
|
+
i++; // Universal selector
|
|
3702
|
+
hasMatchedComponent = true;
|
|
3703
|
+
matched = true;
|
|
3704
|
+
} else if (i < len && (isIdentStart(selector[i]) || selector[i] === '\\')) {
|
|
3705
|
+
if (parseIdentifier()) {
|
|
3706
|
+
hasMatchedComponent = true;
|
|
3707
|
+
matched = true;
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3711
|
+
|
|
3712
|
+
// If no match found, invalid selector
|
|
3713
|
+
if (!matched && i === start) {
|
|
3714
|
+
return false;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
|
|
3718
|
+
return hasMatchedComponent;
|
|
3719
|
+
}
|
|
3720
|
+
|
|
3339
3721
|
/**
|
|
3340
3722
|
* Validates a basic CSS selector, allowing for deeply nested balanced parentheses in pseudo-classes.
|
|
3341
3723
|
* This function replaces the previous basicSelectorRegExp.
|
|
@@ -3360,6 +3742,12 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3360
3742
|
* @returns {boolean}
|
|
3361
3743
|
*/
|
|
3362
3744
|
function basicSelectorValidator(selector) {
|
|
3745
|
+
// Guard against extremely long selectors to prevent potential regex performance issues
|
|
3746
|
+
// Reasonable selectors are typically under 1000 characters
|
|
3747
|
+
if (selector.length > 10000) {
|
|
3748
|
+
return false;
|
|
3749
|
+
}
|
|
3750
|
+
|
|
3363
3751
|
// Validate balanced syntax with attribute tracking and stack-based parentheses matching
|
|
3364
3752
|
if (!validateBalancedSyntax(selector, true, true)) {
|
|
3365
3753
|
return false;
|
|
@@ -3382,33 +3770,71 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3382
3770
|
|
|
3383
3771
|
// Check for invalid pseudo-class usage with quoted strings
|
|
3384
3772
|
// Pseudo-classes like :lang(), :dir(), :nth-*() should not accept quoted strings
|
|
3385
|
-
|
|
3386
|
-
var
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3773
|
+
// Using iterative parsing instead of regex to avoid exponential backtracking
|
|
3774
|
+
var noQuotesPseudos = ['lang', 'dir', 'nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type'];
|
|
3775
|
+
|
|
3776
|
+
for (var idx = 0; idx < selector.length; idx++) {
|
|
3777
|
+
// Look for pseudo-class/element start
|
|
3778
|
+
if (selector[idx] === ':') {
|
|
3779
|
+
var pseudoStart = idx;
|
|
3780
|
+
idx++;
|
|
3781
|
+
|
|
3782
|
+
// Skip second colon for pseudo-elements
|
|
3783
|
+
if (idx < selector.length && selector[idx] === ':') {
|
|
3784
|
+
idx++;
|
|
3785
|
+
}
|
|
3786
|
+
|
|
3787
|
+
// Extract pseudo name
|
|
3788
|
+
var nameStart = idx;
|
|
3789
|
+
while (idx < selector.length && /[a-zA-Z0-9\-]/.test(selector[idx])) {
|
|
3790
|
+
idx++;
|
|
3791
|
+
}
|
|
3792
|
+
|
|
3793
|
+
if (idx === nameStart) {
|
|
3794
|
+
continue; // No name found
|
|
3795
|
+
}
|
|
3796
|
+
|
|
3797
|
+
var pseudoName = selector.substring(nameStart, idx).toLowerCase();
|
|
3798
|
+
|
|
3799
|
+
// Check if this pseudo has arguments
|
|
3800
|
+
if (idx < selector.length && selector[idx] === '(') {
|
|
3801
|
+
idx++;
|
|
3802
|
+
var contentStart = idx;
|
|
3803
|
+
var depth = 1;
|
|
3804
|
+
|
|
3805
|
+
// Find matching closing paren (handle nesting)
|
|
3806
|
+
while (idx < selector.length && depth > 0) {
|
|
3807
|
+
if (selector[idx] === '\\') {
|
|
3808
|
+
idx += 2; // Skip escaped character
|
|
3809
|
+
} else if (selector[idx] === '(') {
|
|
3810
|
+
depth++;
|
|
3811
|
+
idx++;
|
|
3812
|
+
} else if (selector[idx] === ')') {
|
|
3813
|
+
depth--;
|
|
3814
|
+
idx++;
|
|
3815
|
+
} else {
|
|
3816
|
+
idx++;
|
|
3817
|
+
}
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
if (depth === 0) {
|
|
3821
|
+
var pseudoContent = selector.substring(contentStart, idx - 1);
|
|
3822
|
+
|
|
3823
|
+
// Check if this pseudo should not have quoted strings
|
|
3824
|
+
for (var j = 0; j < noQuotesPseudos.length; j++) {
|
|
3825
|
+
if (pseudoName === noQuotesPseudos[j] && /['"]/.test(pseudoContent)) {
|
|
3826
|
+
return false;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
}
|
|
3400
3830
|
}
|
|
3401
3831
|
}
|
|
3402
3832
|
}
|
|
3403
3833
|
|
|
3404
|
-
//
|
|
3405
|
-
|
|
3406
|
-
// Modified to support namespace selectors: *|element, prefix|element, |element
|
|
3407
|
-
// Fixed attribute selector regex to properly handle |=, ~=, ^=, $=, *= operators
|
|
3408
|
-
var looseSelectorRegExp = /^((?:(?:\*|[a-zA-Z_\u00A0-\uFFFF\\][a-zA-Z0-9_\u00A0-\uFFFF\-\\]*|)\|)?[a-zA-Z_\u00A0-\uFFFF\\][a-zA-Z0-9_\u00A0-\uFFFF\-\\]*|(?:(?:\*|[a-zA-Z_\u00A0-\uFFFF\\][a-zA-Z0-9_\u00A0-\uFFFF\-\\]*|)\|)?\*|#[a-zA-Z0-9_\u00A0-\uFFFF\-\\]+|\.[a-zA-Z0-9_\u00A0-\uFFFF\-\\]+|\[(?:[^\[\]'"]|'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*")*(?:\s+[iI])?\]|::?[a-zA-Z0-9_\u00A0-\uFFFF\-\\]+(?:\((.*)\))?|&|\s*[>+~]\s*|\s+)+$/;
|
|
3409
|
-
return looseSelectorRegExp.test(selector);
|
|
3834
|
+
// Use the iterative validator to avoid regex backtracking issues
|
|
3835
|
+
return looseSelectorValidator(selector);
|
|
3410
3836
|
}
|
|
3411
|
-
|
|
3837
|
+
|
|
3412
3838
|
/**
|
|
3413
3839
|
* Regular expression to match CSS pseudo-classes with arguments.
|
|
3414
3840
|
*
|
|
@@ -3424,9 +3850,96 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3424
3850
|
* - :nth-child(2n+1)
|
|
3425
3851
|
* - :has(.sel:nth-child(3n))
|
|
3426
3852
|
* - :not(".foo, .bar")
|
|
3427
|
-
*
|
|
3853
|
+
*
|
|
3854
|
+
* REPLACED WITH FUNCTION to avoid exponential backtracking.
|
|
3428
3855
|
*/
|
|
3429
|
-
|
|
3856
|
+
|
|
3857
|
+
/**
|
|
3858
|
+
* Extract pseudo-classes with arguments from a selector using iterative parsing.
|
|
3859
|
+
* Replaces the previous globalPseudoClassRegExp to avoid exponential backtracking.
|
|
3860
|
+
*
|
|
3861
|
+
* Handles:
|
|
3862
|
+
* - Regular content without parentheses or quotes
|
|
3863
|
+
* - Single-quoted strings
|
|
3864
|
+
* - Double-quoted strings
|
|
3865
|
+
* - Nested parentheses (arbitrary depth)
|
|
3866
|
+
*
|
|
3867
|
+
* @param {string} selector - The CSS selector to parse
|
|
3868
|
+
* @returns {Array} Array of matches, each with: [fullMatch, pseudoName, pseudoArgs, startIndex]
|
|
3869
|
+
*/
|
|
3870
|
+
function extractPseudoClasses(selector) {
|
|
3871
|
+
var matches = [];
|
|
3872
|
+
|
|
3873
|
+
for (var i = 0; i < selector.length; i++) {
|
|
3874
|
+
// Look for pseudo-class start (single or double colon)
|
|
3875
|
+
if (selector[i] === ':') {
|
|
3876
|
+
var pseudoStart = i;
|
|
3877
|
+
i++;
|
|
3878
|
+
|
|
3879
|
+
// Skip second colon for pseudo-elements (::)
|
|
3880
|
+
if (i < selector.length && selector[i] === ':') {
|
|
3881
|
+
i++;
|
|
3882
|
+
}
|
|
3883
|
+
|
|
3884
|
+
// Extract pseudo name
|
|
3885
|
+
var nameStart = i;
|
|
3886
|
+
while (i < selector.length && /[a-zA-Z\-]/.test(selector[i])) {
|
|
3887
|
+
i++;
|
|
3888
|
+
}
|
|
3889
|
+
|
|
3890
|
+
if (i === nameStart) {
|
|
3891
|
+
continue; // No name found
|
|
3892
|
+
}
|
|
3893
|
+
|
|
3894
|
+
var pseudoName = selector.substring(nameStart, i);
|
|
3895
|
+
|
|
3896
|
+
// Check if this pseudo has arguments
|
|
3897
|
+
if (i < selector.length && selector[i] === '(') {
|
|
3898
|
+
i++;
|
|
3899
|
+
var argsStart = i;
|
|
3900
|
+
var depth = 1;
|
|
3901
|
+
var inSingleQuote = false;
|
|
3902
|
+
var inDoubleQuote = false;
|
|
3903
|
+
|
|
3904
|
+
// Find matching closing paren (handle nesting and strings)
|
|
3905
|
+
while (i < selector.length && depth > 0) {
|
|
3906
|
+
var ch = selector[i];
|
|
3907
|
+
|
|
3908
|
+
if (ch === '\\') {
|
|
3909
|
+
i += 2; // Skip escaped character
|
|
3910
|
+
} else if (ch === "'" && !inDoubleQuote) {
|
|
3911
|
+
inSingleQuote = !inSingleQuote;
|
|
3912
|
+
i++;
|
|
3913
|
+
} else if (ch === '"' && !inSingleQuote) {
|
|
3914
|
+
inDoubleQuote = !inDoubleQuote;
|
|
3915
|
+
i++;
|
|
3916
|
+
} else if (ch === '(' && !inSingleQuote && !inDoubleQuote) {
|
|
3917
|
+
depth++;
|
|
3918
|
+
i++;
|
|
3919
|
+
} else if (ch === ')' && !inSingleQuote && !inDoubleQuote) {
|
|
3920
|
+
depth--;
|
|
3921
|
+
i++;
|
|
3922
|
+
} else {
|
|
3923
|
+
i++;
|
|
3924
|
+
}
|
|
3925
|
+
}
|
|
3926
|
+
|
|
3927
|
+
if (depth === 0) {
|
|
3928
|
+
var pseudoArgs = selector.substring(argsStart, i - 1);
|
|
3929
|
+
var fullMatch = selector.substring(pseudoStart, i);
|
|
3930
|
+
|
|
3931
|
+
// Store match in same format as regex: [fullMatch, pseudoName, pseudoArgs, startIndex]
|
|
3932
|
+
matches.push([fullMatch, pseudoName, pseudoArgs, pseudoStart]);
|
|
3933
|
+
}
|
|
3934
|
+
|
|
3935
|
+
// Move back one since loop will increment
|
|
3936
|
+
i--;
|
|
3937
|
+
}
|
|
3938
|
+
}
|
|
3939
|
+
}
|
|
3940
|
+
|
|
3941
|
+
return matches;
|
|
3942
|
+
}
|
|
3430
3943
|
|
|
3431
3944
|
/**
|
|
3432
3945
|
* Parses a CSS selector string and splits it into parts, handling nested parentheses.
|
|
@@ -3521,18 +4034,30 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3521
4034
|
return validatedSelectorsCache[selector];
|
|
3522
4035
|
}
|
|
3523
4036
|
|
|
3524
|
-
// Use
|
|
3525
|
-
var pseudoClassMatches =
|
|
3526
|
-
var pseudoClassRegExp = new RegExp(globalPseudoClassRegExp.source, globalPseudoClassRegExp.flags);
|
|
3527
|
-
var match;
|
|
3528
|
-
while ((match = pseudoClassRegExp.exec(selector)) !== null) {
|
|
3529
|
-
pseudoClassMatches.push(match);
|
|
3530
|
-
}
|
|
4037
|
+
// Use function-based parsing to extract pseudo-classes (avoids backtracking)
|
|
4038
|
+
var pseudoClassMatches = extractPseudoClasses(selector);
|
|
3531
4039
|
|
|
3532
4040
|
for (var j = 0; j < pseudoClassMatches.length; j++) {
|
|
3533
4041
|
var pseudoClass = pseudoClassMatches[j][1];
|
|
3534
4042
|
if (selectorListPseudoClasses.hasOwnProperty(pseudoClass)) {
|
|
3535
4043
|
var nestedSelectors = parseAndSplitNestedSelectors(pseudoClassMatches[j][2]);
|
|
4044
|
+
|
|
4045
|
+
// Check if ANY selector in the list contains & (nesting selector)
|
|
4046
|
+
// If so, skip validation for the entire selector list since & will be replaced at runtime
|
|
4047
|
+
var hasAmpersand = false;
|
|
4048
|
+
for (var k = 0; k < nestedSelectors.length; k++) {
|
|
4049
|
+
if (/&/.test(nestedSelectors[k])) {
|
|
4050
|
+
hasAmpersand = true;
|
|
4051
|
+
break;
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
|
|
4055
|
+
// If any selector has &, skip validation for this entire pseudo-class
|
|
4056
|
+
if (hasAmpersand) {
|
|
4057
|
+
continue;
|
|
4058
|
+
}
|
|
4059
|
+
|
|
4060
|
+
// Otherwise, validate each selector normally
|
|
3536
4061
|
for (var i = 0; i < nestedSelectors.length; i++) {
|
|
3537
4062
|
var nestedSelector = nestedSelectors[i];
|
|
3538
4063
|
if (!validatedSelectorsCache.hasOwnProperty(nestedSelector)) {
|
|
@@ -3569,10 +4094,10 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3569
4094
|
var inAttr = false;
|
|
3570
4095
|
var inSingleQuote = false;
|
|
3571
4096
|
var inDoubleQuote = false;
|
|
3572
|
-
|
|
4097
|
+
|
|
3573
4098
|
for (var i = 0; i < selector.length; i++) {
|
|
3574
4099
|
var char = selector[i];
|
|
3575
|
-
|
|
4100
|
+
|
|
3576
4101
|
if (inSingleQuote) {
|
|
3577
4102
|
if (char === "'" && selector[i - 1] !== "\\") {
|
|
3578
4103
|
inSingleQuote = false;
|
|
@@ -3599,18 +4124,18 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3599
4124
|
}
|
|
3600
4125
|
}
|
|
3601
4126
|
}
|
|
3602
|
-
|
|
4127
|
+
|
|
3603
4128
|
if (pipeIndex === -1) {
|
|
3604
4129
|
return true; // No namespace, always valid
|
|
3605
4130
|
}
|
|
3606
|
-
|
|
4131
|
+
|
|
3607
4132
|
var namespacePrefix = selector.substring(0, pipeIndex);
|
|
3608
|
-
|
|
4133
|
+
|
|
3609
4134
|
// Universal namespace (*|) and default namespace (|) are always valid
|
|
3610
4135
|
if (namespacePrefix === '*' || namespacePrefix === '') {
|
|
3611
4136
|
return true;
|
|
3612
4137
|
}
|
|
3613
|
-
|
|
4138
|
+
|
|
3614
4139
|
// Check if the custom namespace prefix is defined
|
|
3615
4140
|
return definedNamespacePrefixes.hasOwnProperty(namespacePrefix);
|
|
3616
4141
|
}
|
|
@@ -3619,22 +4144,92 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3619
4144
|
* Processes a CSS selector text
|
|
3620
4145
|
*
|
|
3621
4146
|
* @param {string} selectorText - The CSS selector text to process
|
|
3622
|
-
* @returns {string} The processed selector text with normalized whitespace
|
|
4147
|
+
* @returns {string} The processed selector text with normalized whitespace and invalid selectors removed
|
|
3623
4148
|
*/
|
|
3624
4149
|
function processSelectorText(selectorText) {
|
|
3625
|
-
//
|
|
3626
|
-
|
|
3627
|
-
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
3628
|
-
|
|
3629
|
-
/**
|
|
3630
|
-
* Normalizes whitespace and preserving quoted strings.
|
|
3631
|
-
* Replaces all newline characters (CRLF, CR, or LF) with spaces while keeping quoted
|
|
3632
|
-
* strings (single or double quotes) intact, including any escaped characters within them.
|
|
3633
|
-
*/
|
|
3634
|
-
return selectorText.replace(/(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g, function(match, _, newline) {
|
|
4150
|
+
// Normalize whitespace first
|
|
4151
|
+
var normalized = selectorText.replace(/(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g, function (match, _, newline) {
|
|
3635
4152
|
if (newline) return " ";
|
|
3636
4153
|
return match;
|
|
3637
4154
|
});
|
|
4155
|
+
|
|
4156
|
+
// Recursively process pseudo-classes to handle nesting
|
|
4157
|
+
return processNestedPseudoClasses(normalized);
|
|
4158
|
+
}
|
|
4159
|
+
|
|
4160
|
+
/**
|
|
4161
|
+
* Recursively processes pseudo-classes to filter invalid selectors
|
|
4162
|
+
*
|
|
4163
|
+
* @param {string} selectorText - The CSS selector text to process
|
|
4164
|
+
* @param {number} depth - Current recursion depth (to prevent infinite loops)
|
|
4165
|
+
* @returns {string} The processed selector text with invalid selectors removed
|
|
4166
|
+
*/
|
|
4167
|
+
function processNestedPseudoClasses(selectorText, depth) {
|
|
4168
|
+
// Prevent infinite recursion
|
|
4169
|
+
if (typeof depth === 'undefined') {
|
|
4170
|
+
depth = 0;
|
|
4171
|
+
}
|
|
4172
|
+
if (depth > 10) {
|
|
4173
|
+
return selectorText;
|
|
4174
|
+
}
|
|
4175
|
+
|
|
4176
|
+
var pseudoClassMatches = extractPseudoClasses(selectorText);
|
|
4177
|
+
|
|
4178
|
+
// If no pseudo-classes found, return as-is
|
|
4179
|
+
if (pseudoClassMatches.length === 0) {
|
|
4180
|
+
return selectorText;
|
|
4181
|
+
}
|
|
4182
|
+
|
|
4183
|
+
// Build result by processing matches from right to left (to preserve positions)
|
|
4184
|
+
var result = selectorText;
|
|
4185
|
+
|
|
4186
|
+
for (var j = pseudoClassMatches.length - 1; j >= 0; j--) {
|
|
4187
|
+
var pseudoClass = pseudoClassMatches[j][1];
|
|
4188
|
+
if (selectorListPseudoClasses.hasOwnProperty(pseudoClass)) {
|
|
4189
|
+
var fullMatch = pseudoClassMatches[j][0];
|
|
4190
|
+
var pseudoArgs = pseudoClassMatches[j][2];
|
|
4191
|
+
var matchStart = pseudoClassMatches[j][3];
|
|
4192
|
+
|
|
4193
|
+
// Check if ANY selector contains & BEFORE processing
|
|
4194
|
+
var nestedSelectorsRaw = parseAndSplitNestedSelectors(pseudoArgs);
|
|
4195
|
+
var hasAmpersand = false;
|
|
4196
|
+
for (var k = 0; k < nestedSelectorsRaw.length; k++) {
|
|
4197
|
+
if (/&/.test(nestedSelectorsRaw[k])) {
|
|
4198
|
+
hasAmpersand = true;
|
|
4199
|
+
break;
|
|
4200
|
+
}
|
|
4201
|
+
}
|
|
4202
|
+
|
|
4203
|
+
// If & is present, skip all processing (keep everything unchanged)
|
|
4204
|
+
if (hasAmpersand) {
|
|
4205
|
+
continue;
|
|
4206
|
+
}
|
|
4207
|
+
|
|
4208
|
+
// Recursively process the arguments
|
|
4209
|
+
var processedArgs = processNestedPseudoClasses(pseudoArgs, depth + 1);
|
|
4210
|
+
var nestedSelectors = parseAndSplitNestedSelectors(processedArgs);
|
|
4211
|
+
|
|
4212
|
+
// Filter out invalid selectors
|
|
4213
|
+
var validSelectors = [];
|
|
4214
|
+
for (var i = 0; i < nestedSelectors.length; i++) {
|
|
4215
|
+
var nestedSelector = nestedSelectors[i];
|
|
4216
|
+
if (basicSelectorValidator(nestedSelector)) {
|
|
4217
|
+
validSelectors.push(nestedSelector);
|
|
4218
|
+
}
|
|
4219
|
+
}
|
|
4220
|
+
|
|
4221
|
+
// Reconstruct the pseudo-class with only valid selectors
|
|
4222
|
+
var newArgs = validSelectors.join(', ');
|
|
4223
|
+
var newPseudoClass = ':' + pseudoClass + '(' + newArgs + ')';
|
|
4224
|
+
|
|
4225
|
+
// Replace in the result string using position (processing right to left preserves positions)
|
|
4226
|
+
result = result.substring(0, matchStart) + newPseudoClass + result.substring(matchStart + fullMatch.length);
|
|
4227
|
+
}
|
|
4228
|
+
}
|
|
4229
|
+
|
|
4230
|
+
return result;
|
|
4231
|
+
|
|
4232
|
+
return normalized;
|
|
3638
4233
|
}
|
|
3639
4234
|
|
|
3640
4235
|
/**
|
|
@@ -3648,6 +4243,12 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3648
4243
|
// TODO: The same validations here needs to be reused in CSSStyleRule.selectorText setter
|
|
3649
4244
|
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
3650
4245
|
|
|
4246
|
+
// Check for empty selector lists in pseudo-classes (e.g., :is(), :not(), :where(), :has())
|
|
4247
|
+
// These are invalid after filtering out invalid selectors
|
|
4248
|
+
if (/:(?:is|not|where|has)\(\s*\)/.test(selectorText)) {
|
|
4249
|
+
return false;
|
|
4250
|
+
}
|
|
4251
|
+
|
|
3651
4252
|
// Check for newlines inside single or double quotes using regex
|
|
3652
4253
|
// This matches any quoted string (single or double) containing a newline
|
|
3653
4254
|
var quotedNewlineRegExp = /(['"])(?:\\.|[^\\])*?\1/g;
|
|
@@ -3668,6 +4269,12 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3668
4269
|
return true;
|
|
3669
4270
|
}
|
|
3670
4271
|
|
|
4272
|
+
function pushToAncestorRules(rule) {
|
|
4273
|
+
if (ancestorRules.indexOf(rule) === -1) {
|
|
4274
|
+
ancestorRules.push(rule);
|
|
4275
|
+
}
|
|
4276
|
+
}
|
|
4277
|
+
|
|
3671
4278
|
function parseError(message, isNested) {
|
|
3672
4279
|
var lines = token.substring(0, i).split('\n');
|
|
3673
4280
|
var lineCount = lines.length;
|
|
@@ -3681,12 +4288,22 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3681
4288
|
// Print the error but continue parsing the sheet
|
|
3682
4289
|
try {
|
|
3683
4290
|
throw error;
|
|
3684
|
-
} catch(e) {
|
|
4291
|
+
} catch (e) {
|
|
3685
4292
|
errorHandler && errorHandler(e);
|
|
3686
4293
|
}
|
|
3687
4294
|
};
|
|
3688
4295
|
|
|
4296
|
+
// Helper functions to check character types
|
|
4297
|
+
function isSelectorStartChar(char) {
|
|
4298
|
+
return '.:#&*['.indexOf(char) !== -1;
|
|
4299
|
+
}
|
|
4300
|
+
|
|
4301
|
+
function isWhitespaceChar(char) {
|
|
4302
|
+
return ' \t\n\r'.indexOf(char) !== -1;
|
|
4303
|
+
}
|
|
4304
|
+
|
|
3689
4305
|
var endingIndex = token.length - 1;
|
|
4306
|
+
var initialEndingIndex = endingIndex;
|
|
3690
4307
|
|
|
3691
4308
|
for (var character; (character = token.charAt(i)); i++) {
|
|
3692
4309
|
if (i === endingIndex) {
|
|
@@ -3695,804 +4312,1031 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
3695
4312
|
case "namespaceRule":
|
|
3696
4313
|
case "layerBlock":
|
|
3697
4314
|
if (character !== ";") {
|
|
3698
|
-
token += ";"
|
|
4315
|
+
token += ";";
|
|
4316
|
+
endingIndex += 1;
|
|
4317
|
+
}
|
|
4318
|
+
break;
|
|
4319
|
+
case "value":
|
|
4320
|
+
if (character !== "}") {
|
|
4321
|
+
if (character === ";") {
|
|
4322
|
+
token += "}"
|
|
4323
|
+
} else {
|
|
4324
|
+
token += ";";
|
|
4325
|
+
}
|
|
4326
|
+
endingIndex += 1;
|
|
4327
|
+
break;
|
|
4328
|
+
}
|
|
4329
|
+
case "name":
|
|
4330
|
+
case "before-name":
|
|
4331
|
+
if (character === "}") {
|
|
4332
|
+
token += " "
|
|
4333
|
+
} else {
|
|
4334
|
+
token += "}"
|
|
4335
|
+
}
|
|
4336
|
+
endingIndex += 1
|
|
4337
|
+
break;
|
|
4338
|
+
case "before-selector":
|
|
4339
|
+
if (character !== "}" && currentScope !== styleSheet) {
|
|
4340
|
+
token += "}"
|
|
4341
|
+
endingIndex += 1
|
|
4342
|
+
break;
|
|
3699
4343
|
}
|
|
3700
4344
|
}
|
|
3701
4345
|
}
|
|
3702
|
-
|
|
3703
|
-
switch (character) {
|
|
3704
4346
|
|
|
3705
|
-
|
|
3706
|
-
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
|
|
3713
|
-
|
|
4347
|
+
// Handle escape sequences before processing special characters
|
|
4348
|
+
// If we encounter a backslash, add both the backslash and the next character to buffer
|
|
4349
|
+
// and skip the next iteration to prevent the escaped character from being interpreted
|
|
4350
|
+
if (character === '\\' && i + 1 < token.length) {
|
|
4351
|
+
buffer += character + token.charAt(i + 1);
|
|
4352
|
+
i++; // Skip the next character
|
|
4353
|
+
continue;
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
switch (character) {
|
|
3714
4357
|
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
if (
|
|
3721
|
-
|
|
4358
|
+
case " ":
|
|
4359
|
+
case "\t":
|
|
4360
|
+
case "\r":
|
|
4361
|
+
case "\n":
|
|
4362
|
+
case "\f":
|
|
4363
|
+
if (SIGNIFICANT_WHITESPACE[state]) {
|
|
4364
|
+
buffer += character;
|
|
3722
4365
|
}
|
|
3723
|
-
} while (token[index - 2] === '\\');
|
|
3724
|
-
if (index === 0) {
|
|
3725
4366
|
break;
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
|
|
3733
|
-
|
|
3734
|
-
state = 'importRule';
|
|
3735
|
-
if (i === endingIndex) {
|
|
3736
|
-
token += ';'
|
|
4367
|
+
|
|
4368
|
+
// String
|
|
4369
|
+
case '"':
|
|
4370
|
+
index = i + 1;
|
|
4371
|
+
do {
|
|
4372
|
+
index = token.indexOf('"', index) + 1;
|
|
4373
|
+
if (!index) {
|
|
4374
|
+
parseError('Unmatched "');
|
|
3737
4375
|
}
|
|
4376
|
+
} while (token[index - 2] === '\\');
|
|
4377
|
+
if (index === 0) {
|
|
3738
4378
|
break;
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
|
|
4379
|
+
}
|
|
4380
|
+
buffer += token.slice(i, index);
|
|
4381
|
+
i = index - 1;
|
|
4382
|
+
switch (state) {
|
|
4383
|
+
case 'before-value':
|
|
4384
|
+
state = 'value';
|
|
4385
|
+
break;
|
|
4386
|
+
case 'importRule-begin':
|
|
4387
|
+
state = 'importRule';
|
|
4388
|
+
if (i === endingIndex) {
|
|
4389
|
+
token += ';'
|
|
4390
|
+
}
|
|
4391
|
+
break;
|
|
4392
|
+
case 'namespaceRule-begin':
|
|
4393
|
+
state = 'namespaceRule';
|
|
4394
|
+
if (i === endingIndex) {
|
|
4395
|
+
token += ';'
|
|
4396
|
+
}
|
|
4397
|
+
break;
|
|
4398
|
+
}
|
|
4399
|
+
break;
|
|
4400
|
+
|
|
4401
|
+
case "'":
|
|
4402
|
+
index = i + 1;
|
|
4403
|
+
do {
|
|
4404
|
+
index = token.indexOf("'", index) + 1;
|
|
4405
|
+
if (!index) {
|
|
4406
|
+
parseError("Unmatched '");
|
|
3743
4407
|
}
|
|
4408
|
+
} while (token[index - 2] === '\\');
|
|
4409
|
+
if (index === 0) {
|
|
3744
4410
|
break;
|
|
3745
|
-
|
|
3746
|
-
|
|
4411
|
+
}
|
|
4412
|
+
buffer += token.slice(i, index);
|
|
4413
|
+
i = index - 1;
|
|
4414
|
+
switch (state) {
|
|
4415
|
+
case 'before-value':
|
|
4416
|
+
state = 'value';
|
|
4417
|
+
break;
|
|
4418
|
+
case 'importRule-begin':
|
|
4419
|
+
state = 'importRule';
|
|
4420
|
+
break;
|
|
4421
|
+
case 'namespaceRule-begin':
|
|
4422
|
+
state = 'namespaceRule';
|
|
4423
|
+
break;
|
|
4424
|
+
}
|
|
4425
|
+
break;
|
|
3747
4426
|
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
4427
|
+
// Comment
|
|
4428
|
+
case "/":
|
|
4429
|
+
if (token.charAt(i + 1) === "*") {
|
|
4430
|
+
i += 2;
|
|
4431
|
+
index = token.indexOf("*/", i);
|
|
4432
|
+
if (index === -1) {
|
|
4433
|
+
i = token.length - 1;
|
|
4434
|
+
buffer = "";
|
|
4435
|
+
} else {
|
|
4436
|
+
i = index + 1;
|
|
4437
|
+
}
|
|
4438
|
+
} else {
|
|
4439
|
+
buffer += character;
|
|
4440
|
+
}
|
|
4441
|
+
if (state === "importRule-begin") {
|
|
4442
|
+
buffer += " ";
|
|
4443
|
+
state = "importRule";
|
|
4444
|
+
}
|
|
4445
|
+
if (state === "namespaceRule-begin") {
|
|
4446
|
+
buffer += " ";
|
|
4447
|
+
state = "namespaceRule";
|
|
3754
4448
|
}
|
|
3755
|
-
} while (token[index - 2] === '\\');
|
|
3756
|
-
if (index === 0) {
|
|
3757
4449
|
break;
|
|
3758
|
-
|
|
3759
|
-
|
|
3760
|
-
|
|
3761
|
-
|
|
3762
|
-
|
|
3763
|
-
|
|
4450
|
+
|
|
4451
|
+
// At-rule
|
|
4452
|
+
case "@":
|
|
4453
|
+
if (nestedSelectorRule) {
|
|
4454
|
+
if (styleRule && styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4455
|
+
currentScope.cssRules.push(styleRule);
|
|
4456
|
+
}
|
|
4457
|
+
if (nestedSelectorRule.parentRule && nestedSelectorRule.parentRule.constructor.name === "CSSStyleRule") {
|
|
4458
|
+
styleRule = nestedSelectorRule.parentRule;
|
|
4459
|
+
}
|
|
4460
|
+
// Don't reset nestedSelectorRule here - preserve it through @-rules
|
|
4461
|
+
}
|
|
4462
|
+
if (token.indexOf("@-moz-document", i) === i) {
|
|
4463
|
+
validateAtRule("@-moz-document", function () {
|
|
4464
|
+
state = "documentRule-begin";
|
|
4465
|
+
documentRule = new CSSOM.CSSDocumentRule();
|
|
4466
|
+
documentRule.__starts = i;
|
|
4467
|
+
i += "-moz-document".length;
|
|
4468
|
+
});
|
|
4469
|
+
buffer = "";
|
|
3764
4470
|
break;
|
|
3765
|
-
|
|
3766
|
-
|
|
4471
|
+
} else if (token.indexOf("@media", i) === i) {
|
|
4472
|
+
validateAtRule("@media", function () {
|
|
4473
|
+
state = "atBlock";
|
|
4474
|
+
mediaRule = new CSSOM.CSSMediaRule();
|
|
4475
|
+
mediaRule.__starts = i;
|
|
4476
|
+
i += "media".length;
|
|
4477
|
+
});
|
|
4478
|
+
buffer = "";
|
|
3767
4479
|
break;
|
|
3768
|
-
|
|
3769
|
-
|
|
4480
|
+
} else if (token.indexOf("@container", i) === i) {
|
|
4481
|
+
validateAtRule("@container", function () {
|
|
4482
|
+
state = "containerBlock";
|
|
4483
|
+
containerRule = new CSSOM.CSSContainerRule();
|
|
4484
|
+
containerRule.__starts = i;
|
|
4485
|
+
i += "container".length;
|
|
4486
|
+
});
|
|
4487
|
+
buffer = "";
|
|
3770
4488
|
break;
|
|
3771
|
-
|
|
3772
|
-
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
index = token.indexOf("*/", i);
|
|
3779
|
-
if (index === -1) {
|
|
3780
|
-
i = token.length - 1;
|
|
4489
|
+
} else if (token.indexOf("@counter-style", i) === i) {
|
|
4490
|
+
validateAtRule("@counter-style", function () {
|
|
4491
|
+
state = "counterStyleBlock"
|
|
4492
|
+
counterStyleRule = new CSSOM.CSSCounterStyleRule();
|
|
4493
|
+
counterStyleRule.__starts = i;
|
|
4494
|
+
i += "counter-style".length;
|
|
4495
|
+
}, true);
|
|
3781
4496
|
buffer = "";
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
state = "importRule";
|
|
3791
|
-
}
|
|
3792
|
-
if (state === "namespaceRule-begin") {
|
|
3793
|
-
buffer += " ";
|
|
3794
|
-
state = "namespaceRule";
|
|
3795
|
-
}
|
|
3796
|
-
break;
|
|
3797
|
-
|
|
3798
|
-
// At-rule
|
|
3799
|
-
case "@":
|
|
3800
|
-
if (token.indexOf("@-moz-document", i) === i) {
|
|
3801
|
-
validateAtRule("@-moz-document", function(){
|
|
3802
|
-
state = "documentRule-begin";
|
|
3803
|
-
documentRule = new CSSOM.CSSDocumentRule();
|
|
3804
|
-
documentRule.__starts = i;
|
|
3805
|
-
i += "-moz-document".length;
|
|
3806
|
-
});
|
|
3807
|
-
buffer = "";
|
|
3808
|
-
break;
|
|
3809
|
-
} else if (token.indexOf("@media", i) === i) {
|
|
3810
|
-
validateAtRule("@media", function(){
|
|
3811
|
-
state = "atBlock";
|
|
3812
|
-
mediaRule = new CSSOM.CSSMediaRule();
|
|
3813
|
-
mediaRule.__starts = i;
|
|
3814
|
-
i += "media".length;
|
|
3815
|
-
});
|
|
3816
|
-
buffer = "";
|
|
3817
|
-
break;
|
|
3818
|
-
} else if (token.indexOf("@container", i) === i) {
|
|
3819
|
-
validateAtRule("@container", function(){
|
|
3820
|
-
state = "containerBlock";
|
|
3821
|
-
containerRule = new CSSOM.CSSContainerRule();
|
|
3822
|
-
containerRule.__starts = i;
|
|
3823
|
-
i += "container".length;
|
|
3824
|
-
});
|
|
3825
|
-
buffer = "";
|
|
3826
|
-
break;
|
|
3827
|
-
} else if (token.indexOf("@counter-style", i) === i) {
|
|
3828
|
-
validateAtRule("@counter-style", function(){
|
|
3829
|
-
state = "counterStyleBlock"
|
|
3830
|
-
counterStyleRule = new CSSOM.CSSCounterStyleRule();
|
|
3831
|
-
counterStyleRule.__starts = i;
|
|
3832
|
-
i += "counter-style".length;
|
|
3833
|
-
}, true);
|
|
3834
|
-
buffer = "";
|
|
3835
|
-
break;
|
|
3836
|
-
} else if (token.indexOf("@scope", i) === i) {
|
|
3837
|
-
validateAtRule("@scope", function(){
|
|
3838
|
-
state = "scopeBlock";
|
|
3839
|
-
scopeRule = new CSSOM.CSSScopeRule();
|
|
3840
|
-
scopeRule.__starts = i;
|
|
3841
|
-
i += "scope".length;
|
|
3842
|
-
});
|
|
3843
|
-
buffer = "";
|
|
3844
|
-
break;
|
|
3845
|
-
} else if (token.indexOf("@layer", i) === i) {
|
|
3846
|
-
validateAtRule("@layer", function(){
|
|
3847
|
-
state = "layerBlock"
|
|
3848
|
-
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
3849
|
-
layerBlockRule.__starts = i;
|
|
3850
|
-
i += "layer".length;
|
|
3851
|
-
});
|
|
3852
|
-
buffer = "";
|
|
3853
|
-
break;
|
|
3854
|
-
} else if (token.indexOf("@page", i) === i) {
|
|
3855
|
-
validateAtRule("@page", function(){
|
|
3856
|
-
state = "pageBlock"
|
|
3857
|
-
pageRule = new CSSOM.CSSPageRule();
|
|
3858
|
-
pageRule.__starts = i;
|
|
3859
|
-
i += "page".length;
|
|
3860
|
-
});
|
|
3861
|
-
buffer = "";
|
|
3862
|
-
break;
|
|
3863
|
-
} else if (token.indexOf("@supports", i) === i) {
|
|
3864
|
-
validateAtRule("@supports", function(){
|
|
3865
|
-
state = "conditionBlock";
|
|
3866
|
-
supportsRule = new CSSOM.CSSSupportsRule();
|
|
3867
|
-
supportsRule.__starts = i;
|
|
3868
|
-
i += "supports".length;
|
|
3869
|
-
});
|
|
3870
|
-
buffer = "";
|
|
3871
|
-
break;
|
|
3872
|
-
} else if (token.indexOf("@host", i) === i) {
|
|
3873
|
-
validateAtRule("@host", function(){
|
|
3874
|
-
state = "hostRule-begin";
|
|
3875
|
-
i += "host".length;
|
|
3876
|
-
hostRule = new CSSOM.CSSHostRule();
|
|
3877
|
-
hostRule.__starts = i;
|
|
3878
|
-
});
|
|
3879
|
-
buffer = "";
|
|
3880
|
-
break;
|
|
3881
|
-
} else if (token.indexOf("@starting-style", i) === i) {
|
|
3882
|
-
validateAtRule("@starting-style", function(){
|
|
3883
|
-
state = "startingStyleRule-begin";
|
|
3884
|
-
i += "starting-style".length;
|
|
3885
|
-
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
3886
|
-
startingStyleRule.__starts = i;
|
|
3887
|
-
});
|
|
3888
|
-
buffer = "";
|
|
3889
|
-
break;
|
|
3890
|
-
} else if (token.indexOf("@import", i) === i) {
|
|
3891
|
-
buffer = "";
|
|
3892
|
-
validateAtRule("@import", function(){
|
|
3893
|
-
state = "importRule-begin";
|
|
3894
|
-
i += "import".length;
|
|
3895
|
-
buffer += "@import";
|
|
3896
|
-
}, true);
|
|
3897
|
-
break;
|
|
3898
|
-
} else if (token.indexOf("@namespace", i) === i) {
|
|
3899
|
-
buffer = "";
|
|
3900
|
-
validateAtRule("@namespace", function(){
|
|
3901
|
-
state = "namespaceRule-begin";
|
|
3902
|
-
i += "namespace".length;
|
|
3903
|
-
buffer += "@namespace";
|
|
3904
|
-
}, true);
|
|
3905
|
-
break;
|
|
3906
|
-
} else if (token.indexOf("@font-face", i) === i) {
|
|
3907
|
-
buffer = "";
|
|
3908
|
-
validateAtRule("@font-face", function(){
|
|
3909
|
-
state = "fontFaceRule-begin";
|
|
3910
|
-
i += "font-face".length;
|
|
3911
|
-
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
3912
|
-
fontFaceRule.__starts = i;
|
|
3913
|
-
}, true);
|
|
3914
|
-
break;
|
|
3915
|
-
} else {
|
|
3916
|
-
atKeyframesRegExp.lastIndex = i;
|
|
3917
|
-
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
3918
|
-
if (matchKeyframes && matchKeyframes.index === i) {
|
|
3919
|
-
state = "keyframesRule-begin";
|
|
3920
|
-
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
3921
|
-
keyframesRule.__starts = i;
|
|
3922
|
-
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
3923
|
-
i += matchKeyframes[0].length - 1;
|
|
4497
|
+
break;
|
|
4498
|
+
} else if (token.indexOf("@scope", i) === i) {
|
|
4499
|
+
validateAtRule("@scope", function () {
|
|
4500
|
+
state = "scopeBlock";
|
|
4501
|
+
scopeRule = new CSSOM.CSSScopeRule();
|
|
4502
|
+
scopeRule.__starts = i;
|
|
4503
|
+
i += "scope".length;
|
|
4504
|
+
});
|
|
3924
4505
|
buffer = "";
|
|
3925
4506
|
break;
|
|
3926
|
-
} else if (
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
4507
|
+
} else if (token.indexOf("@layer", i) === i) {
|
|
4508
|
+
validateAtRule("@layer", function () {
|
|
4509
|
+
state = "layerBlock"
|
|
4510
|
+
layerBlockRule = new CSSOM.CSSLayerBlockRule();
|
|
4511
|
+
layerBlockRule.__starts = i;
|
|
4512
|
+
i += "layer".length;
|
|
4513
|
+
});
|
|
4514
|
+
buffer = "";
|
|
4515
|
+
break;
|
|
4516
|
+
} else if (token.indexOf("@page", i) === i) {
|
|
4517
|
+
validateAtRule("@page", function () {
|
|
4518
|
+
state = "pageBlock"
|
|
4519
|
+
pageRule = new CSSOM.CSSPageRule();
|
|
4520
|
+
pageRule.__starts = i;
|
|
4521
|
+
i += "page".length;
|
|
4522
|
+
});
|
|
4523
|
+
buffer = "";
|
|
4524
|
+
break;
|
|
4525
|
+
} else if (token.indexOf("@supports", i) === i) {
|
|
4526
|
+
validateAtRule("@supports", function () {
|
|
4527
|
+
state = "conditionBlock";
|
|
4528
|
+
supportsRule = new CSSOM.CSSSupportsRule();
|
|
4529
|
+
supportsRule.__starts = i;
|
|
4530
|
+
i += "supports".length;
|
|
4531
|
+
});
|
|
4532
|
+
buffer = "";
|
|
4533
|
+
break;
|
|
4534
|
+
} else if (token.indexOf("@host", i) === i) {
|
|
4535
|
+
validateAtRule("@host", function () {
|
|
4536
|
+
state = "hostRule-begin";
|
|
4537
|
+
i += "host".length;
|
|
4538
|
+
hostRule = new CSSOM.CSSHostRule();
|
|
4539
|
+
hostRule.__starts = i;
|
|
4540
|
+
});
|
|
4541
|
+
buffer = "";
|
|
4542
|
+
break;
|
|
4543
|
+
} else if (token.indexOf("@starting-style", i) === i) {
|
|
4544
|
+
validateAtRule("@starting-style", function () {
|
|
4545
|
+
state = "startingStyleRule-begin";
|
|
4546
|
+
i += "starting-style".length;
|
|
4547
|
+
startingStyleRule = new CSSOM.CSSStartingStyleRule();
|
|
4548
|
+
startingStyleRule.__starts = i;
|
|
4549
|
+
});
|
|
4550
|
+
buffer = "";
|
|
4551
|
+
break;
|
|
4552
|
+
} else if (token.indexOf("@import", i) === i) {
|
|
4553
|
+
buffer = "";
|
|
4554
|
+
validateAtRule("@import", function () {
|
|
4555
|
+
state = "importRule-begin";
|
|
4556
|
+
i += "import".length;
|
|
4557
|
+
buffer += "@import";
|
|
4558
|
+
}, true);
|
|
4559
|
+
break;
|
|
4560
|
+
} else if (token.indexOf("@namespace", i) === i) {
|
|
4561
|
+
buffer = "";
|
|
4562
|
+
validateAtRule("@namespace", function () {
|
|
4563
|
+
state = "namespaceRule-begin";
|
|
4564
|
+
i += "namespace".length;
|
|
4565
|
+
buffer += "@namespace";
|
|
4566
|
+
}, true);
|
|
4567
|
+
break;
|
|
4568
|
+
} else if (token.indexOf("@font-face", i) === i) {
|
|
4569
|
+
buffer = "";
|
|
4570
|
+
// @font-face can be nested only inside CSSScopeRule or CSSConditionRule
|
|
4571
|
+
// and only if there's no CSSStyleRule in the parent chain
|
|
4572
|
+
var cannotBeNested = true;
|
|
4573
|
+
if (currentScope !== topScope) {
|
|
4574
|
+
var hasStyleRuleInChain = false;
|
|
4575
|
+
var hasValidParent = false;
|
|
4576
|
+
|
|
4577
|
+
// Check currentScope
|
|
4578
|
+
if (currentScope.constructor.name === 'CSSStyleRule') {
|
|
4579
|
+
hasStyleRuleInChain = true;
|
|
4580
|
+
} else if (currentScope instanceof CSSOM.CSSScopeRule || currentScope instanceof CSSOM.CSSConditionRule) {
|
|
4581
|
+
hasValidParent = true;
|
|
4582
|
+
}
|
|
3932
4583
|
|
|
3933
|
-
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
3937
|
-
|
|
3938
|
-
|
|
3939
|
-
|
|
3940
|
-
|
|
3941
|
-
|
|
3942
|
-
|
|
3943
|
-
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
4584
|
+
// Check ancestorRules for CSSStyleRule
|
|
4585
|
+
if (!hasStyleRuleInChain) {
|
|
4586
|
+
for (var j = 0; j < ancestorRules.length; j++) {
|
|
4587
|
+
if (ancestorRules[j].constructor.name === 'CSSStyleRule') {
|
|
4588
|
+
hasStyleRuleInChain = true;
|
|
4589
|
+
break;
|
|
4590
|
+
}
|
|
4591
|
+
if (ancestorRules[j] instanceof CSSOM.CSSScopeRule || ancestorRules[j] instanceof CSSOM.CSSConditionRule) {
|
|
4592
|
+
hasValidParent = true;
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
}
|
|
4596
|
+
|
|
4597
|
+
// Allow nesting if we have a valid parent and no style rule in the chain
|
|
4598
|
+
if (hasValidParent && !hasStyleRuleInChain) {
|
|
4599
|
+
cannotBeNested = false;
|
|
4600
|
+
}
|
|
4601
|
+
}
|
|
4602
|
+
validateAtRule("@font-face", function () {
|
|
4603
|
+
state = "fontFaceRule-begin";
|
|
4604
|
+
i += "font-face".length;
|
|
4605
|
+
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
4606
|
+
fontFaceRule.__starts = i;
|
|
4607
|
+
}, cannotBeNested);
|
|
4608
|
+
break;
|
|
4609
|
+
} else {
|
|
4610
|
+
atKeyframesRegExp.lastIndex = i;
|
|
4611
|
+
var matchKeyframes = atKeyframesRegExp.exec(token);
|
|
4612
|
+
if (matchKeyframes && matchKeyframes.index === i) {
|
|
4613
|
+
state = "keyframesRule-begin";
|
|
4614
|
+
keyframesRule = new CSSOM.CSSKeyframesRule();
|
|
4615
|
+
keyframesRule.__starts = i;
|
|
4616
|
+
keyframesRule._vendorPrefix = matchKeyframes[1]; // Will come out as undefined if no prefix was found
|
|
4617
|
+
i += matchKeyframes[0].length - 1;
|
|
3947
4618
|
buffer = "";
|
|
3948
|
-
state = "before-selector";
|
|
3949
|
-
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
3950
4619
|
break;
|
|
4620
|
+
} else if (state === "selector") {
|
|
4621
|
+
state = "atRule";
|
|
3951
4622
|
}
|
|
3952
4623
|
}
|
|
4624
|
+
buffer += character;
|
|
4625
|
+
break;
|
|
3953
4626
|
|
|
3954
|
-
|
|
3955
|
-
|
|
3956
|
-
|
|
3957
|
-
}
|
|
3958
|
-
|
|
3959
|
-
currentScope = parentRule = styleRule;
|
|
3960
|
-
styleRule.selectorText = processSelectorText(buffer.trim());
|
|
3961
|
-
styleRule.style.__starts = i;
|
|
3962
|
-
styleRule.__parentStyleSheet = styleSheet;
|
|
3963
|
-
buffer = "";
|
|
3964
|
-
state = "before-name";
|
|
3965
|
-
} else if (state === "atBlock") {
|
|
3966
|
-
mediaRule.media.mediaText = buffer.trim();
|
|
3967
|
-
|
|
3968
|
-
if (parentRule) {
|
|
3969
|
-
mediaRule.__parentRule = parentRule;
|
|
3970
|
-
ancestorRules.push(parentRule);
|
|
3971
|
-
}
|
|
3972
|
-
|
|
3973
|
-
currentScope = parentRule = mediaRule;
|
|
3974
|
-
mediaRule.__parentStyleSheet = styleSheet;
|
|
3975
|
-
buffer = "";
|
|
3976
|
-
state = "before-selector";
|
|
3977
|
-
} else if (state === "containerBlock") {
|
|
3978
|
-
containerRule.__conditionText = buffer.trim();
|
|
3979
|
-
|
|
3980
|
-
if (parentRule) {
|
|
3981
|
-
containerRule.__parentRule = parentRule;
|
|
3982
|
-
ancestorRules.push(parentRule);
|
|
3983
|
-
}
|
|
3984
|
-
currentScope = parentRule = containerRule;
|
|
3985
|
-
containerRule.__parentStyleSheet = styleSheet;
|
|
3986
|
-
buffer = "";
|
|
3987
|
-
state = "before-selector";
|
|
3988
|
-
} else if (state === "counterStyleBlock") {
|
|
3989
|
-
// TODO: Validate counter-style name. At least that it cannot be empty nor multiple
|
|
3990
|
-
counterStyleRule.name = buffer.trim().replace(/\n/g, "");
|
|
3991
|
-
currentScope = parentRule = counterStyleRule;
|
|
3992
|
-
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
3993
|
-
buffer = "";
|
|
3994
|
-
} else if (state === "conditionBlock") {
|
|
3995
|
-
supportsRule.__conditionText = buffer.trim();
|
|
3996
|
-
|
|
3997
|
-
if (parentRule) {
|
|
3998
|
-
supportsRule.__parentRule = parentRule;
|
|
3999
|
-
ancestorRules.push(parentRule);
|
|
4000
|
-
}
|
|
4001
|
-
|
|
4002
|
-
currentScope = parentRule = supportsRule;
|
|
4003
|
-
supportsRule.__parentStyleSheet = styleSheet;
|
|
4004
|
-
buffer = "";
|
|
4005
|
-
state = "before-selector";
|
|
4006
|
-
} else if (state === "scopeBlock") {
|
|
4007
|
-
var parsedScopePrelude = parseScopePrelude(buffer.trim());
|
|
4008
|
-
|
|
4009
|
-
if (parsedScopePrelude.hasStart) {
|
|
4010
|
-
scopeRule.__start = parsedScopePrelude.startSelector;
|
|
4627
|
+
case "{":
|
|
4628
|
+
if (currentScope === topScope) {
|
|
4629
|
+
nestedSelectorRule = null;
|
|
4011
4630
|
}
|
|
4012
|
-
if (
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4631
|
+
if (state === 'before-selector') {
|
|
4632
|
+
parseError("Unexpected {");
|
|
4633
|
+
i = ignoreBalancedBlock(i, token.slice(i));
|
|
4634
|
+
break;
|
|
4017
4635
|
}
|
|
4636
|
+
if (state === "selector" || state === "atRule") {
|
|
4637
|
+
if (!nestedSelectorRule && buffer.indexOf(";") !== -1) {
|
|
4638
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
4639
|
+
if (ruleClosingMatch) {
|
|
4640
|
+
styleRule = null;
|
|
4641
|
+
buffer = "";
|
|
4642
|
+
state = "before-selector";
|
|
4643
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length;
|
|
4644
|
+
break;
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4018
4647
|
|
|
4019
|
-
|
|
4020
|
-
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
scopeRule.__parentStyleSheet = styleSheet;
|
|
4025
|
-
buffer = "";
|
|
4026
|
-
state = "before-selector";
|
|
4027
|
-
} else if (state === "layerBlock") {
|
|
4028
|
-
layerBlockRule.name = buffer.trim();
|
|
4648
|
+
// Ensure styleRule exists before trying to set properties on it
|
|
4649
|
+
if (!styleRule) {
|
|
4650
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
4651
|
+
styleRule.__starts = i;
|
|
4652
|
+
}
|
|
4029
4653
|
|
|
4030
|
-
|
|
4654
|
+
var originalParentRule = parentRule;
|
|
4031
4655
|
|
|
4032
|
-
if (isValidName) {
|
|
4033
4656
|
if (parentRule) {
|
|
4034
|
-
|
|
4035
|
-
|
|
4657
|
+
styleRule.__parentRule = parentRule;
|
|
4658
|
+
pushToAncestorRules(parentRule);
|
|
4036
4659
|
}
|
|
4037
|
-
|
|
4038
|
-
currentScope = parentRule = layerBlockRule;
|
|
4039
|
-
layerBlockRule.__parentStyleSheet = styleSheet;
|
|
4040
|
-
}
|
|
4041
|
-
buffer = "";
|
|
4042
|
-
state = "before-selector";
|
|
4043
|
-
} else if (state === "pageBlock") {
|
|
4044
|
-
pageRule.selectorText = buffer.trim();
|
|
4045
|
-
|
|
4046
|
-
if (parentRule) {
|
|
4047
|
-
pageRule.__parentRule = parentRule;
|
|
4048
|
-
ancestorRules.push(parentRule);
|
|
4049
|
-
}
|
|
4050
|
-
|
|
4051
|
-
currentScope = parentRule = pageRule;
|
|
4052
|
-
pageRule.__parentStyleSheet = styleSheet;
|
|
4053
|
-
styleRule = pageRule;
|
|
4054
|
-
buffer = "";
|
|
4055
|
-
state = "before-name";
|
|
4056
|
-
} else if (state === "hostRule-begin") {
|
|
4057
|
-
if (parentRule) {
|
|
4058
|
-
ancestorRules.push(parentRule);
|
|
4059
|
-
}
|
|
4060
|
-
|
|
4061
|
-
currentScope = parentRule = hostRule;
|
|
4062
|
-
hostRule.__parentStyleSheet = styleSheet;
|
|
4063
|
-
buffer = "";
|
|
4064
|
-
state = "before-selector";
|
|
4065
|
-
} else if (state === "startingStyleRule-begin") {
|
|
4066
|
-
if (parentRule) {
|
|
4067
|
-
startingStyleRule.__parentRule = parentRule;
|
|
4068
|
-
ancestorRules.push(parentRule);
|
|
4069
|
-
}
|
|
4070
4660
|
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
}
|
|
4080
|
-
fontFaceRule.__parentStyleSheet = styleSheet;
|
|
4081
|
-
styleRule = fontFaceRule;
|
|
4082
|
-
buffer = "";
|
|
4083
|
-
state = "before-name";
|
|
4084
|
-
} else if (state === "keyframesRule-begin") {
|
|
4085
|
-
keyframesRule.name = buffer.trim();
|
|
4086
|
-
if (parentRule) {
|
|
4087
|
-
ancestorRules.push(parentRule);
|
|
4088
|
-
keyframesRule.__parentRule = parentRule;
|
|
4089
|
-
}
|
|
4090
|
-
keyframesRule.__parentStyleSheet = styleSheet;
|
|
4091
|
-
currentScope = parentRule = keyframesRule;
|
|
4092
|
-
buffer = "";
|
|
4093
|
-
state = "keyframeRule-begin";
|
|
4094
|
-
} else if (state === "keyframeRule-begin") {
|
|
4095
|
-
styleRule = new CSSOM.CSSKeyframeRule();
|
|
4096
|
-
styleRule.keyText = buffer.trim();
|
|
4097
|
-
styleRule.__starts = i;
|
|
4098
|
-
buffer = "";
|
|
4099
|
-
state = "before-name";
|
|
4100
|
-
} else if (state === "documentRule-begin") {
|
|
4101
|
-
// FIXME: what if this '{' is in the url text of the match function?
|
|
4102
|
-
documentRule.matcher.matcherText = buffer.trim();
|
|
4103
|
-
if (parentRule) {
|
|
4104
|
-
ancestorRules.push(parentRule);
|
|
4105
|
-
documentRule.__parentRule = parentRule;
|
|
4106
|
-
}
|
|
4107
|
-
currentScope = parentRule = documentRule;
|
|
4108
|
-
documentRule.__parentStyleSheet = styleSheet;
|
|
4109
|
-
buffer = "";
|
|
4110
|
-
state = "before-selector";
|
|
4111
|
-
} else if (state === "before-name" || state === "name") {
|
|
4112
|
-
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4113
|
-
if (styleRule.style.length) {
|
|
4114
|
-
parentRule.cssRules.push(styleRule);
|
|
4115
|
-
styleRule.__parentRule = parentRule;
|
|
4116
|
-
styleRule.__parentStyleSheet = styleSheet;
|
|
4117
|
-
ancestorRules.push(parentRule);
|
|
4661
|
+
currentScope = parentRule = styleRule;
|
|
4662
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
4663
|
+
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
4664
|
+
if (originalParentRule && originalParentRule.constructor.name === "CSSStyleRule") {
|
|
4665
|
+
styleRule.selectorText = parseAndSplitNestedSelectors(processedSelectorText).map(function (sel) {
|
|
4666
|
+
// Add & at the beginning if there's no & in the selector, or if it starts with a combinator
|
|
4667
|
+
return (sel.indexOf('&') === -1 || startsWithCombinatorRegExp.test(sel)) ? '& ' + sel : sel;
|
|
4668
|
+
}).join(', ');
|
|
4118
4669
|
} else {
|
|
4119
|
-
|
|
4120
|
-
ancestorRules.push(parentRule);
|
|
4670
|
+
styleRule.selectorText = processedSelectorText;
|
|
4121
4671
|
}
|
|
4122
|
-
|
|
4123
|
-
currentScope = parentRule = styleRule;
|
|
4124
|
-
ancestorRules.push(parentRule);
|
|
4672
|
+
styleRule.style.__starts = i;
|
|
4125
4673
|
styleRule.__parentStyleSheet = styleSheet;
|
|
4126
|
-
}
|
|
4127
|
-
|
|
4128
|
-
styleRule = new CSSOM.CSSStyleRule();
|
|
4129
|
-
var processedSelectorText = processSelectorText(buffer.trim());
|
|
4130
|
-
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
4131
|
-
if (parentRule.constructor.name !== "CSSStyleRule" && parentRule.parentRule === null) {
|
|
4132
|
-
styleRule.selectorText = processedSelectorText;
|
|
4133
|
-
} else {
|
|
4134
|
-
styleRule.selectorText = parseAndSplitNestedSelectors(processedSelectorText).map(function(sel) {
|
|
4135
|
-
// Add & at the beginning if there's no & in the selector, or if it starts with a combinator
|
|
4136
|
-
return (sel.indexOf('&') === -1 || startsWithCombinatorRegExp.test(sel)) ? '& ' + sel : sel;
|
|
4137
|
-
}).join(', ');
|
|
4138
|
-
}
|
|
4139
|
-
styleRule.style.__starts = i - buffer.length;
|
|
4140
|
-
styleRule.__parentRule = parentRule;
|
|
4141
|
-
nestedSelectorRule = styleRule;
|
|
4142
|
-
|
|
4143
|
-
buffer = "";
|
|
4144
|
-
state = "before-name";
|
|
4145
|
-
}
|
|
4146
|
-
break;
|
|
4147
|
-
|
|
4148
|
-
case ":":
|
|
4149
|
-
if (state === "name") {
|
|
4150
|
-
// It can be a nested selector, let's check
|
|
4151
|
-
var openBraceBeforeMatch = token.slice(i).match(/[{;}]/);
|
|
4152
|
-
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
4153
|
-
if (hasOpenBraceBefore) {
|
|
4154
|
-
// Is a selector
|
|
4155
|
-
buffer += character;
|
|
4156
|
-
} else {
|
|
4157
|
-
// Is a declaration
|
|
4158
|
-
name = buffer.trim();
|
|
4159
4674
|
buffer = "";
|
|
4160
|
-
state = "before-
|
|
4161
|
-
}
|
|
4162
|
-
|
|
4163
|
-
buffer += character;
|
|
4164
|
-
}
|
|
4165
|
-
break;
|
|
4166
|
-
|
|
4167
|
-
case "(":
|
|
4168
|
-
if (state === 'value') {
|
|
4169
|
-
// ie css expression mode
|
|
4170
|
-
if (buffer.trim() === 'expression') {
|
|
4171
|
-
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
|
|
4675
|
+
state = "before-name";
|
|
4676
|
+
} else if (state === "atBlock") {
|
|
4677
|
+
mediaRule.media.mediaText = buffer.trim();
|
|
4172
4678
|
|
|
4173
|
-
if (
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4679
|
+
if (parentRule) {
|
|
4680
|
+
mediaRule.__parentRule = parentRule;
|
|
4681
|
+
pushToAncestorRules(parentRule);
|
|
4682
|
+
// If entering @media from within a CSSStyleRule, set nestedSelectorRule
|
|
4683
|
+
// so that & selectors and declarations work correctly inside
|
|
4684
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4685
|
+
nestedSelectorRule = parentRule;
|
|
4686
|
+
}
|
|
4178
4687
|
}
|
|
4179
|
-
} else {
|
|
4180
|
-
state = 'value-parenthesis';
|
|
4181
|
-
//always ensure this is reset to 1 on transition
|
|
4182
|
-
//from value to value-parenthesis
|
|
4183
|
-
valueParenthesisDepth = 1;
|
|
4184
|
-
buffer += character;
|
|
4185
|
-
}
|
|
4186
|
-
} else if (state === 'value-parenthesis') {
|
|
4187
|
-
valueParenthesisDepth++;
|
|
4188
|
-
buffer += character;
|
|
4189
|
-
} else {
|
|
4190
|
-
buffer += character;
|
|
4191
|
-
}
|
|
4192
|
-
break;
|
|
4193
4688
|
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
case "!":
|
|
4203
|
-
if (state === "value" && token.indexOf("!important", i) === i) {
|
|
4204
|
-
priority = "important";
|
|
4205
|
-
i += "important".length;
|
|
4206
|
-
} else {
|
|
4207
|
-
buffer += character;
|
|
4208
|
-
}
|
|
4209
|
-
break;
|
|
4689
|
+
currentScope = parentRule = mediaRule;
|
|
4690
|
+
pushToAncestorRules(mediaRule);
|
|
4691
|
+
mediaRule.__parentStyleSheet = styleSheet;
|
|
4692
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4693
|
+
buffer = "";
|
|
4694
|
+
state = "before-selector";
|
|
4695
|
+
} else if (state === "containerBlock") {
|
|
4696
|
+
containerRule.__conditionText = buffer.trim();
|
|
4210
4697
|
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4698
|
+
if (parentRule) {
|
|
4699
|
+
containerRule.__parentRule = parentRule;
|
|
4700
|
+
pushToAncestorRules(parentRule);
|
|
4701
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4702
|
+
nestedSelectorRule = parentRule;
|
|
4703
|
+
}
|
|
4704
|
+
}
|
|
4705
|
+
currentScope = parentRule = containerRule;
|
|
4706
|
+
pushToAncestorRules(containerRule);
|
|
4707
|
+
containerRule.__parentStyleSheet = styleSheet;
|
|
4708
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4216
4709
|
buffer = "";
|
|
4217
|
-
state = "before-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4710
|
+
state = "before-selector";
|
|
4711
|
+
} else if (state === "counterStyleBlock") {
|
|
4712
|
+
var counterStyleName = buffer.trim().replace(/\n/g, "");
|
|
4713
|
+
// Validate: name cannot be empty, contain whitespace, or contain dots
|
|
4714
|
+
var isValidCounterStyleName = counterStyleName.length > 0 && !/[\s.]/.test(counterStyleName);
|
|
4715
|
+
|
|
4716
|
+
if (isValidCounterStyleName) {
|
|
4717
|
+
counterStyleRule.name = counterStyleName;
|
|
4718
|
+
currentScope = parentRule = counterStyleRule;
|
|
4719
|
+
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
4720
|
+
}
|
|
4222
4721
|
buffer = "";
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4722
|
+
} else if (state === "conditionBlock") {
|
|
4723
|
+
supportsRule.__conditionText = buffer.trim();
|
|
4724
|
+
|
|
4725
|
+
if (parentRule) {
|
|
4726
|
+
supportsRule.__parentRule = parentRule;
|
|
4727
|
+
pushToAncestorRules(parentRule);
|
|
4728
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4729
|
+
nestedSelectorRule = parentRule;
|
|
4730
|
+
}
|
|
4731
|
+
}
|
|
4732
|
+
|
|
4733
|
+
currentScope = parentRule = supportsRule;
|
|
4734
|
+
pushToAncestorRules(supportsRule);
|
|
4735
|
+
supportsRule.__parentStyleSheet = styleSheet;
|
|
4736
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4226
4737
|
buffer = "";
|
|
4227
4738
|
state = "before-selector";
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
if (isValid) {
|
|
4234
|
-
importRule = new CSSOM.CSSImportRule();
|
|
4235
|
-
importRule.__parentStyleSheet = importRule.styleSheet.__parentStyleSheet = styleSheet;
|
|
4236
|
-
importRule.cssText = buffer + character;
|
|
4237
|
-
styleSheet.cssRules.push(importRule);
|
|
4739
|
+
} else if (state === "scopeBlock") {
|
|
4740
|
+
var parsedScopePrelude = parseScopePrelude(buffer.trim());
|
|
4741
|
+
|
|
4742
|
+
if (parsedScopePrelude.hasStart) {
|
|
4743
|
+
scopeRule.__start = parsedScopePrelude.startSelector;
|
|
4238
4744
|
}
|
|
4745
|
+
if (parsedScopePrelude.hasEnd) {
|
|
4746
|
+
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4747
|
+
}
|
|
4748
|
+
if (parsedScopePrelude.hasOnlyEnd) {
|
|
4749
|
+
scopeRule.__end = parsedScopePrelude.endSelector;
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
if (parentRule) {
|
|
4753
|
+
scopeRule.__parentRule = parentRule;
|
|
4754
|
+
pushToAncestorRules(parentRule);
|
|
4755
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4756
|
+
nestedSelectorRule = parentRule;
|
|
4757
|
+
}
|
|
4758
|
+
}
|
|
4759
|
+
currentScope = parentRule = scopeRule;
|
|
4760
|
+
pushToAncestorRules(scopeRule);
|
|
4761
|
+
scopeRule.__parentStyleSheet = styleSheet;
|
|
4762
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4239
4763
|
buffer = "";
|
|
4240
4764
|
state = "before-selector";
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
if (
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
namespaceRule = testNamespaceRule;
|
|
4253
|
-
namespaceRule.__parentStyleSheet = styleSheet;
|
|
4254
|
-
styleSheet.cssRules.push(namespaceRule);
|
|
4255
|
-
|
|
4256
|
-
// Track the namespace prefix for validation
|
|
4257
|
-
if (namespaceRule.prefix) {
|
|
4258
|
-
definedNamespacePrefixes[namespaceRule.prefix] = namespaceRule.namespaceURI;
|
|
4765
|
+
} else if (state === "layerBlock") {
|
|
4766
|
+
layerBlockRule.name = buffer.trim();
|
|
4767
|
+
|
|
4768
|
+
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(cssCustomIdentifierRegExp) !== null;
|
|
4769
|
+
|
|
4770
|
+
if (isValidName) {
|
|
4771
|
+
if (parentRule) {
|
|
4772
|
+
layerBlockRule.__parentRule = parentRule;
|
|
4773
|
+
pushToAncestorRules(parentRule);
|
|
4774
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4775
|
+
nestedSelectorRule = parentRule;
|
|
4259
4776
|
}
|
|
4260
|
-
} catch(e) {
|
|
4261
|
-
parseError(e.message);
|
|
4262
4777
|
}
|
|
4778
|
+
|
|
4779
|
+
currentScope = parentRule = layerBlockRule;
|
|
4780
|
+
pushToAncestorRules(layerBlockRule);
|
|
4781
|
+
layerBlockRule.__parentStyleSheet = styleSheet;
|
|
4263
4782
|
}
|
|
4783
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4264
4784
|
buffer = "";
|
|
4265
4785
|
state = "before-selector";
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
var nameListStr = buffer.trim().split(",").map(function (name) {
|
|
4269
|
-
return name.trim();
|
|
4270
|
-
});
|
|
4271
|
-
var isInvalid = parentRule !== undefined || nameListStr.some(function (name) {
|
|
4272
|
-
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
4273
|
-
});
|
|
4786
|
+
} else if (state === "pageBlock") {
|
|
4787
|
+
pageRule.selectorText = buffer.trim();
|
|
4274
4788
|
|
|
4275
|
-
if (
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
layerStatementRule.__starts = layerBlockRule.__starts;
|
|
4279
|
-
layerStatementRule.__ends = i;
|
|
4280
|
-
layerStatementRule.nameList = nameListStr;
|
|
4281
|
-
styleSheet.cssRules.push(layerStatementRule);
|
|
4789
|
+
if (parentRule) {
|
|
4790
|
+
pageRule.__parentRule = parentRule;
|
|
4791
|
+
pushToAncestorRules(parentRule);
|
|
4282
4792
|
}
|
|
4793
|
+
|
|
4794
|
+
currentScope = parentRule = pageRule;
|
|
4795
|
+
pageRule.__parentStyleSheet = styleSheet;
|
|
4796
|
+
styleRule = pageRule;
|
|
4797
|
+
buffer = "";
|
|
4798
|
+
state = "before-name";
|
|
4799
|
+
} else if (state === "hostRule-begin") {
|
|
4800
|
+
if (parentRule) {
|
|
4801
|
+
pushToAncestorRules(parentRule);
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
currentScope = parentRule = hostRule;
|
|
4805
|
+
pushToAncestorRules(hostRule);
|
|
4806
|
+
hostRule.__parentStyleSheet = styleSheet;
|
|
4283
4807
|
buffer = "";
|
|
4284
4808
|
state = "before-selector";
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4809
|
+
} else if (state === "startingStyleRule-begin") {
|
|
4810
|
+
if (parentRule) {
|
|
4811
|
+
startingStyleRule.__parentRule = parentRule;
|
|
4812
|
+
pushToAncestorRules(parentRule);
|
|
4813
|
+
if (parentRule.constructor.name === "CSSStyleRule" && !nestedSelectorRule) {
|
|
4814
|
+
nestedSelectorRule = parentRule;
|
|
4815
|
+
}
|
|
4816
|
+
}
|
|
4291
4817
|
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
buffer = "";
|
|
4299
|
-
state = "before-selector";
|
|
4300
|
-
}
|
|
4818
|
+
currentScope = parentRule = startingStyleRule;
|
|
4819
|
+
pushToAncestorRules(startingStyleRule);
|
|
4820
|
+
startingStyleRule.__parentStyleSheet = styleSheet;
|
|
4821
|
+
styleRule = null; // Reset styleRule when entering @-rule
|
|
4822
|
+
buffer = "";
|
|
4823
|
+
state = "before-selector";
|
|
4301
4824
|
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
priority = "";
|
|
4306
|
-
/* falls through */
|
|
4307
|
-
case "before-value":
|
|
4308
|
-
case "before-name":
|
|
4309
|
-
case "name":
|
|
4310
|
-
styleRule.__ends = i + 1;
|
|
4311
|
-
|
|
4312
|
-
if (parentRule === styleRule) {
|
|
4313
|
-
parentRule = ancestorRules.pop()
|
|
4825
|
+
} else if (state === "fontFaceRule-begin") {
|
|
4826
|
+
if (parentRule) {
|
|
4827
|
+
fontFaceRule.__parentRule = parentRule;
|
|
4314
4828
|
}
|
|
4315
|
-
|
|
4829
|
+
fontFaceRule.__parentStyleSheet = styleSheet;
|
|
4830
|
+
styleRule = fontFaceRule;
|
|
4831
|
+
buffer = "";
|
|
4832
|
+
state = "before-name";
|
|
4833
|
+
} else if (state === "keyframesRule-begin") {
|
|
4834
|
+
keyframesRule.name = buffer.trim();
|
|
4316
4835
|
if (parentRule) {
|
|
4317
|
-
|
|
4836
|
+
pushToAncestorRules(parentRule);
|
|
4837
|
+
keyframesRule.__parentRule = parentRule;
|
|
4318
4838
|
}
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4839
|
+
keyframesRule.__parentStyleSheet = styleSheet;
|
|
4840
|
+
currentScope = parentRule = keyframesRule;
|
|
4841
|
+
buffer = "";
|
|
4842
|
+
state = "keyframeRule-begin";
|
|
4843
|
+
} else if (state === "keyframeRule-begin") {
|
|
4844
|
+
styleRule = new CSSOM.CSSKeyframeRule();
|
|
4845
|
+
styleRule.keyText = buffer.trim();
|
|
4846
|
+
styleRule.__starts = i;
|
|
4847
|
+
buffer = "";
|
|
4848
|
+
state = "before-name";
|
|
4849
|
+
} else if (state === "documentRule-begin") {
|
|
4850
|
+
// FIXME: what if this '{' is in the url text of the match function?
|
|
4851
|
+
documentRule.matcher.matcherText = buffer.trim();
|
|
4852
|
+
if (parentRule) {
|
|
4853
|
+
pushToAncestorRules(parentRule);
|
|
4854
|
+
documentRule.__parentRule = parentRule;
|
|
4855
|
+
}
|
|
4856
|
+
currentScope = parentRule = documentRule;
|
|
4857
|
+
pushToAncestorRules(documentRule);
|
|
4858
|
+
documentRule.__parentStyleSheet = styleSheet;
|
|
4859
|
+
buffer = "";
|
|
4860
|
+
state = "before-selector";
|
|
4861
|
+
} else if (state === "before-name" || state === "name") {
|
|
4862
|
+
// @font-face and similar rules don't support nested selectors
|
|
4863
|
+
// If we encounter a nested selector block inside them, skip it
|
|
4864
|
+
if (styleRule.constructor.name === "CSSFontFaceRule" ||
|
|
4865
|
+
styleRule.constructor.name === "CSSKeyframeRule" ||
|
|
4866
|
+
(styleRule.constructor.name === "CSSPageRule" && parentRule === styleRule)) {
|
|
4867
|
+
// Skip the nested block
|
|
4868
|
+
var ruleClosingMatch = token.slice(i).match(forwardRuleClosingBraceRegExp);
|
|
4869
|
+
if (ruleClosingMatch) {
|
|
4870
|
+
i += ruleClosingMatch.index + ruleClosingMatch[0].length - 1;
|
|
4871
|
+
buffer = "";
|
|
4872
|
+
state = "before-name";
|
|
4873
|
+
break;
|
|
4874
|
+
}
|
|
4323
4875
|
}
|
|
4324
4876
|
|
|
4325
|
-
if (styleRule.constructor.name === "
|
|
4326
|
-
if (styleRule
|
|
4327
|
-
|
|
4877
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
4878
|
+
if (styleRule.style.length) {
|
|
4879
|
+
parentRule.cssRules.push(styleRule);
|
|
4880
|
+
styleRule.__parentRule = parentRule;
|
|
4881
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
4882
|
+
pushToAncestorRules(parentRule);
|
|
4883
|
+
} else {
|
|
4884
|
+
// If the styleRule is empty, we can assume that it's a nested selector
|
|
4885
|
+
pushToAncestorRules(parentRule);
|
|
4328
4886
|
}
|
|
4329
|
-
parseError('Invalid CSSStyleRule (selectorText = "' + styleRule.selectorText + '")', styleRule.parentRule !== null);
|
|
4330
4887
|
} else {
|
|
4331
|
-
currentScope
|
|
4888
|
+
currentScope = parentRule = styleRule;
|
|
4889
|
+
pushToAncestorRules(parentRule);
|
|
4890
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
4332
4891
|
}
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4892
|
+
|
|
4893
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
4894
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
4895
|
+
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
4896
|
+
if (parentRule.constructor.name === "CSSScopeRule" || (parentRule.constructor.name !== "CSSStyleRule" && parentRule.parentRule === null)) {
|
|
4897
|
+
styleRule.selectorText = processedSelectorText;
|
|
4336
4898
|
} else {
|
|
4337
|
-
|
|
4899
|
+
styleRule.selectorText = parseAndSplitNestedSelectors(processedSelectorText).map(function (sel) {
|
|
4900
|
+
// Add & at the beginning if there's no & in the selector, or if it starts with a combinator
|
|
4901
|
+
return (sel.indexOf('&') === -1 || startsWithCombinatorRegExp.test(sel)) ? '& ' + sel : sel;
|
|
4902
|
+
}).join(', ');
|
|
4903
|
+
}
|
|
4904
|
+
styleRule.style.__starts = i - buffer.length;
|
|
4905
|
+
styleRule.__parentRule = parentRule;
|
|
4906
|
+
// Only set nestedSelectorRule if we're directly inside a CSSStyleRule or CSSScopeRule,
|
|
4907
|
+
// not inside other grouping rules like @media/@supports
|
|
4908
|
+
if (parentRule.constructor.name === "CSSStyleRule" || parentRule.constructor.name === "CSSScopeRule") {
|
|
4909
|
+
nestedSelectorRule = styleRule;
|
|
4338
4910
|
}
|
|
4339
4911
|
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
|
|
4912
|
+
buffer = "";
|
|
4913
|
+
state = "before-name";
|
|
4914
|
+
}
|
|
4915
|
+
break;
|
|
4916
|
+
|
|
4917
|
+
case ":":
|
|
4918
|
+
if (state === "name") {
|
|
4919
|
+
// It can be a nested selector, let's check
|
|
4920
|
+
var openBraceBeforeMatch = token.slice(i).match(/[{;}]/);
|
|
4921
|
+
var hasOpenBraceBefore = openBraceBeforeMatch && openBraceBeforeMatch[0] === '{';
|
|
4922
|
+
if (hasOpenBraceBefore) {
|
|
4923
|
+
// Is a selector
|
|
4924
|
+
buffer += character;
|
|
4345
4925
|
} else {
|
|
4346
|
-
|
|
4347
|
-
|
|
4926
|
+
// Is a declaration
|
|
4927
|
+
name = buffer.trim();
|
|
4928
|
+
buffer = "";
|
|
4929
|
+
state = "before-value";
|
|
4348
4930
|
}
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4931
|
+
} else {
|
|
4932
|
+
buffer += character;
|
|
4933
|
+
}
|
|
4934
|
+
break;
|
|
4935
|
+
|
|
4936
|
+
case "(":
|
|
4937
|
+
if (state === 'value') {
|
|
4938
|
+
// ie css expression mode
|
|
4939
|
+
if (buffer.trim() === 'expression') {
|
|
4940
|
+
var info = (new CSSOM.CSSValueExpression(token, i)).parse();
|
|
4941
|
+
|
|
4942
|
+
if (info.error) {
|
|
4943
|
+
parseError(info.error);
|
|
4944
|
+
} else {
|
|
4945
|
+
buffer += info.expression;
|
|
4946
|
+
i = info.idx;
|
|
4359
4947
|
}
|
|
4360
|
-
|
|
4361
|
-
|
|
4948
|
+
} else {
|
|
4949
|
+
state = 'value-parenthesis';
|
|
4950
|
+
//always ensure this is reset to 1 on transition
|
|
4951
|
+
//from value to value-parenthesis
|
|
4952
|
+
valueParenthesisDepth = 1;
|
|
4953
|
+
buffer += character;
|
|
4362
4954
|
}
|
|
4955
|
+
} else if (state === 'value-parenthesis') {
|
|
4956
|
+
valueParenthesisDepth++;
|
|
4957
|
+
buffer += character;
|
|
4958
|
+
} else {
|
|
4959
|
+
buffer += character;
|
|
4960
|
+
}
|
|
4961
|
+
break;
|
|
4363
4962
|
|
|
4963
|
+
case ")":
|
|
4964
|
+
if (state === 'value-parenthesis') {
|
|
4965
|
+
valueParenthesisDepth--;
|
|
4966
|
+
if (valueParenthesisDepth === 0) state = 'value';
|
|
4967
|
+
}
|
|
4968
|
+
buffer += character;
|
|
4969
|
+
break;
|
|
4364
4970
|
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4382
|
-
|
|
4383
|
-
|
|
4384
|
-
|
|
4385
|
-
|
|
4386
|
-
|
|
4971
|
+
case "!":
|
|
4972
|
+
if (state === "value" && token.indexOf("!important", i) === i) {
|
|
4973
|
+
priority = "important";
|
|
4974
|
+
i += "important".length;
|
|
4975
|
+
} else {
|
|
4976
|
+
buffer += character;
|
|
4977
|
+
}
|
|
4978
|
+
break;
|
|
4979
|
+
|
|
4980
|
+
case ";":
|
|
4981
|
+
switch (state) {
|
|
4982
|
+
case "before-value":
|
|
4983
|
+
case "before-name":
|
|
4984
|
+
parseError("Unexpected ;");
|
|
4985
|
+
buffer = "";
|
|
4986
|
+
state = "before-name";
|
|
4987
|
+
break;
|
|
4988
|
+
case "value":
|
|
4989
|
+
styleRule.style.setProperty(name, buffer.trim(), priority, parseError);
|
|
4990
|
+
priority = "";
|
|
4991
|
+
buffer = "";
|
|
4992
|
+
state = "before-name";
|
|
4993
|
+
break;
|
|
4994
|
+
case "atRule":
|
|
4995
|
+
buffer = "";
|
|
4996
|
+
state = "before-selector";
|
|
4997
|
+
break;
|
|
4998
|
+
case "importRule":
|
|
4999
|
+
var isValid = topScope.cssRules.length === 0 || topScope.cssRules.some(function (rule) {
|
|
5000
|
+
return ['CSSImportRule', 'CSSLayerStatementRule'].indexOf(rule.constructor.name) !== -1
|
|
5001
|
+
});
|
|
5002
|
+
if (isValid) {
|
|
5003
|
+
importRule = new CSSOM.CSSImportRule();
|
|
5004
|
+
importRule.__parentStyleSheet = importRule.styleSheet.__parentStyleSheet = styleSheet;
|
|
5005
|
+
importRule.parse(buffer + character);
|
|
5006
|
+
topScope.cssRules.push(importRule);
|
|
5007
|
+
}
|
|
5008
|
+
buffer = "";
|
|
5009
|
+
state = "before-selector";
|
|
5010
|
+
break;
|
|
5011
|
+
case "namespaceRule":
|
|
5012
|
+
var isValid = topScope.cssRules.length === 0 || topScope.cssRules.every(function (rule) {
|
|
5013
|
+
return ['CSSImportRule', 'CSSLayerStatementRule', 'CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
|
|
5014
|
+
});
|
|
5015
|
+
if (isValid) {
|
|
5016
|
+
try {
|
|
5017
|
+
// Validate namespace syntax before creating the rule
|
|
5018
|
+
var testNamespaceRule = new CSSOM.CSSNamespaceRule();
|
|
5019
|
+
testNamespaceRule.parse(buffer + character);
|
|
5020
|
+
|
|
5021
|
+
namespaceRule = testNamespaceRule;
|
|
5022
|
+
namespaceRule.__parentStyleSheet = styleSheet;
|
|
5023
|
+
topScope.cssRules.push(namespaceRule);
|
|
5024
|
+
|
|
5025
|
+
// Track the namespace prefix for validation
|
|
5026
|
+
if (namespaceRule.prefix) {
|
|
5027
|
+
definedNamespacePrefixes[namespaceRule.prefix] = namespaceRule.namespaceURI;
|
|
5028
|
+
}
|
|
5029
|
+
} catch (e) {
|
|
5030
|
+
parseError(e.message);
|
|
5031
|
+
}
|
|
5032
|
+
}
|
|
5033
|
+
buffer = "";
|
|
5034
|
+
state = "before-selector";
|
|
5035
|
+
break;
|
|
5036
|
+
case "layerBlock":
|
|
5037
|
+
var nameListStr = buffer.trim().split(",").map(function (name) {
|
|
5038
|
+
return name.trim();
|
|
5039
|
+
});
|
|
5040
|
+
var isInvalid = nameListStr.some(function (name) {
|
|
5041
|
+
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
5042
|
+
});
|
|
5043
|
+
|
|
5044
|
+
// Check if there's a CSSStyleRule in the parent chain
|
|
5045
|
+
var hasStyleRuleParent = false;
|
|
5046
|
+
if (parentRule) {
|
|
5047
|
+
var checkParent = parentRule;
|
|
5048
|
+
while (checkParent) {
|
|
5049
|
+
if (checkParent.constructor.name === "CSSStyleRule") {
|
|
5050
|
+
hasStyleRuleParent = true;
|
|
5051
|
+
break;
|
|
4387
5052
|
}
|
|
5053
|
+
checkParent = checkParent.__parentRule;
|
|
5054
|
+
}
|
|
5055
|
+
}
|
|
5056
|
+
|
|
5057
|
+
if (!isInvalid && !hasStyleRuleParent) {
|
|
5058
|
+
layerStatementRule = new CSSOM.CSSLayerStatementRule();
|
|
5059
|
+
layerStatementRule.__parentStyleSheet = styleSheet;
|
|
5060
|
+
layerStatementRule.__starts = layerBlockRule.__starts;
|
|
5061
|
+
layerStatementRule.__ends = i;
|
|
5062
|
+
layerStatementRule.nameList = nameListStr;
|
|
5063
|
+
|
|
5064
|
+
// Add to parent rule if nested, otherwise to top scope
|
|
5065
|
+
if (parentRule) {
|
|
5066
|
+
layerStatementRule.__parentRule = parentRule;
|
|
5067
|
+
parentRule.cssRules.push(layerStatementRule);
|
|
4388
5068
|
} else {
|
|
4389
|
-
|
|
4390
|
-
currentScope = parentRule;
|
|
4391
|
-
currentScope !== prevScope && currentScope.cssRules.push(prevScope);
|
|
4392
|
-
break;
|
|
5069
|
+
topScope.cssRules.push(layerStatementRule);
|
|
4393
5070
|
}
|
|
4394
5071
|
}
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
5072
|
+
buffer = "";
|
|
5073
|
+
state = "before-selector";
|
|
5074
|
+
break;
|
|
5075
|
+
default:
|
|
5076
|
+
buffer += character;
|
|
5077
|
+
break;
|
|
5078
|
+
}
|
|
5079
|
+
break;
|
|
5080
|
+
|
|
5081
|
+
case "}":
|
|
5082
|
+
if (state === "counterStyleBlock") {
|
|
5083
|
+
// FIXME : Implement missing properties on CSSCounterStyleRule interface and update parse method
|
|
5084
|
+
// For now it's just assigning entire rule text
|
|
5085
|
+
counterStyleRule.parse("@counter-style " + counterStyleRule.name + " { " + buffer + " }");
|
|
5086
|
+
buffer = "";
|
|
5087
|
+
state = "before-selector";
|
|
5088
|
+
}
|
|
5089
|
+
|
|
5090
|
+
switch (state) {
|
|
5091
|
+
case "value":
|
|
5092
|
+
styleRule.style.setProperty(name, buffer.trim(), priority, parseError);
|
|
5093
|
+
priority = "";
|
|
5094
|
+
/* falls through */
|
|
5095
|
+
case "before-value":
|
|
5096
|
+
case "before-name":
|
|
5097
|
+
case "name":
|
|
5098
|
+
styleRule.__ends = i + 1;
|
|
5099
|
+
|
|
5100
|
+
if (parentRule === styleRule) {
|
|
5101
|
+
parentRule = ancestorRules.pop()
|
|
5102
|
+
}
|
|
5103
|
+
|
|
5104
|
+
if (parentRule) {
|
|
5105
|
+
styleRule.__parentRule = parentRule;
|
|
4403
5106
|
}
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
if (openingBraceLen === closingBraceLen) {
|
|
4414
|
-
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
4415
|
-
nestedSelectorRule.__ends = i + 1;
|
|
5107
|
+
styleRule.__parentStyleSheet = styleSheet;
|
|
5108
|
+
|
|
5109
|
+
if (currentScope === styleRule) {
|
|
5110
|
+
currentScope = parentRule || topScope;
|
|
5111
|
+
}
|
|
5112
|
+
|
|
5113
|
+
if (styleRule.constructor.name === "CSSStyleRule" && !isValidSelectorText(styleRule.selectorText)) {
|
|
5114
|
+
if (styleRule === nestedSelectorRule) {
|
|
4416
5115
|
nestedSelectorRule = null;
|
|
4417
|
-
parentRule = null;
|
|
4418
5116
|
}
|
|
5117
|
+
parseError('Invalid CSSStyleRule (selectorText = "' + styleRule.selectorText + '")', styleRule.parentRule !== null);
|
|
4419
5118
|
} else {
|
|
4420
|
-
parentRule
|
|
5119
|
+
if (styleRule.parentRule) {
|
|
5120
|
+
styleRule.parentRule.cssRules.push(styleRule);
|
|
5121
|
+
} else {
|
|
5122
|
+
currentScope.cssRules.push(styleRule);
|
|
5123
|
+
}
|
|
5124
|
+
}
|
|
5125
|
+
buffer = "";
|
|
5126
|
+
if (currentScope.constructor === CSSOM.CSSKeyframesRule) {
|
|
5127
|
+
state = "keyframeRule-begin";
|
|
5128
|
+
} else {
|
|
5129
|
+
state = "before-selector";
|
|
5130
|
+
}
|
|
4421
5131
|
|
|
5132
|
+
if (styleRule.constructor.name === "CSSNestedDeclarations") {
|
|
5133
|
+
if (currentScope !== topScope) {
|
|
5134
|
+
// Only set nestedSelectorRule if currentScope is CSSStyleRule or CSSScopeRule
|
|
5135
|
+
// Not for other grouping rules like @media/@supports
|
|
5136
|
+
if (currentScope.constructor.name === "CSSStyleRule" || currentScope.constructor.name === "CSSScopeRule") {
|
|
5137
|
+
nestedSelectorRule = currentScope;
|
|
5138
|
+
}
|
|
5139
|
+
}
|
|
5140
|
+
styleRule = null;
|
|
5141
|
+
} else {
|
|
5142
|
+
// Update nestedSelectorRule when closing a CSSStyleRule
|
|
5143
|
+
if (styleRule === nestedSelectorRule) {
|
|
5144
|
+
var selector = styleRule.selectorText && styleRule.selectorText.trim();
|
|
5145
|
+
// Check if this is proper nesting (&.class, &:pseudo) vs prepended & (& :is, & .class with space)
|
|
5146
|
+
// Prepended & has pattern "& X" where X starts with : or .
|
|
5147
|
+
var isPrependedAmpersand = selector && selector.match(/^&\s+[:\.]/);
|
|
5148
|
+
|
|
5149
|
+
// Check if parent is a grouping rule that can contain nested selectors
|
|
5150
|
+
var isGroupingRule = currentScope && currentScope instanceof CSSOM.CSSGroupingRule;
|
|
5151
|
+
|
|
5152
|
+
if (!isPrependedAmpersand && isGroupingRule) {
|
|
5153
|
+
// Proper nesting - set nestedSelectorRule to parent for more nested selectors
|
|
5154
|
+
// But only if it's a CSSStyleRule or CSSScopeRule, not other grouping rules like @media
|
|
5155
|
+
if (currentScope.constructor.name === "CSSStyleRule" || currentScope.constructor.name === "CSSScopeRule") {
|
|
5156
|
+
nestedSelectorRule = currentScope;
|
|
5157
|
+
}
|
|
5158
|
+
// If currentScope is another type of grouping rule (like @media), keep nestedSelectorRule unchanged
|
|
5159
|
+
} else {
|
|
5160
|
+
// Prepended & or not nested in grouping rule - reset to prevent CSSNestedDeclarations
|
|
5161
|
+
nestedSelectorRule = null;
|
|
5162
|
+
}
|
|
5163
|
+
} else if (nestedSelectorRule && currentScope instanceof CSSOM.CSSGroupingRule) {
|
|
5164
|
+
// When closing a nested rule that's not the nestedSelectorRule itself,
|
|
5165
|
+
// maintain nestedSelectorRule if we're still inside a grouping rule
|
|
5166
|
+
// This ensures declarations after nested selectors inside @media/@supports etc. work correctly
|
|
5167
|
+
}
|
|
5168
|
+
styleRule = null;
|
|
5169
|
+
break;
|
|
4422
5170
|
}
|
|
4423
|
-
|
|
5171
|
+
case "keyframeRule-begin":
|
|
5172
|
+
case "before-selector":
|
|
5173
|
+
case "selector":
|
|
5174
|
+
// End of media/supports/document rule.
|
|
5175
|
+
if (!parentRule) {
|
|
5176
|
+
parseError("Unexpected }");
|
|
5177
|
+
|
|
5178
|
+
var hasPreviousStyleRule = currentScope.cssRules.length && currentScope.cssRules[currentScope.cssRules.length - 1].constructor.name === "CSSStyleRule";
|
|
5179
|
+
if (hasPreviousStyleRule) {
|
|
5180
|
+
i = ignoreBalancedBlock(i, token.slice(i), 1);
|
|
5181
|
+
}
|
|
4424
5182
|
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
break;
|
|
4428
|
-
}
|
|
4429
|
-
break;
|
|
5183
|
+
break;
|
|
5184
|
+
}
|
|
4430
5185
|
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
|
|
4437
|
-
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4443
|
-
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
|
|
4450
|
-
|
|
4451
|
-
|
|
5186
|
+
while (ancestorRules.length > 0) {
|
|
5187
|
+
parentRule = ancestorRules.pop();
|
|
5188
|
+
|
|
5189
|
+
if (parentRule instanceof CSSOM.CSSGroupingRule && (parentRule.constructor.name !== 'CSSStyleRule' || parentRule.__parentRule)) {
|
|
5190
|
+
if (nestedSelectorRule) {
|
|
5191
|
+
if (nestedSelectorRule.parentRule) {
|
|
5192
|
+
prevScope = nestedSelectorRule;
|
|
5193
|
+
currentScope = nestedSelectorRule.parentRule;
|
|
5194
|
+
if (currentScope.cssRules.findIndex(function (rule) {
|
|
5195
|
+
return rule === prevScope
|
|
5196
|
+
}) === -1) {
|
|
5197
|
+
currentScope.cssRules.push(prevScope);
|
|
5198
|
+
}
|
|
5199
|
+
nestedSelectorRule = currentScope;
|
|
5200
|
+
} else {
|
|
5201
|
+
// If nestedSelectorRule doesn't have a parentRule, we're closing a grouping rule
|
|
5202
|
+
// inside a top-level CSSStyleRule. We need to push currentScope to the parentRule.
|
|
5203
|
+
prevScope = currentScope;
|
|
5204
|
+
// Push to actual parent from ancestorRules if available
|
|
5205
|
+
var actualParent = ancestorRules.length > 0 ? ancestorRules[ancestorRules.length - 1] : nestedSelectorRule;
|
|
5206
|
+
actualParent !== prevScope && actualParent.cssRules.push(prevScope);
|
|
5207
|
+
// Update currentScope to the nestedSelectorRule before breaking
|
|
5208
|
+
currentScope = actualParent;
|
|
5209
|
+
parentRule = actualParent;
|
|
5210
|
+
break;
|
|
5211
|
+
}
|
|
5212
|
+
} else {
|
|
5213
|
+
prevScope = currentScope;
|
|
5214
|
+
parentRule !== prevScope && parentRule.cssRules.push(prevScope);
|
|
5215
|
+
break;
|
|
5216
|
+
}
|
|
4452
5217
|
}
|
|
4453
5218
|
}
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
if
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4469
|
-
|
|
4470
|
-
|
|
5219
|
+
|
|
5220
|
+
// If currentScope has a __parentRule and wasn't added yet, add it
|
|
5221
|
+
if (ancestorRules.length === 0 && currentScope.__parentRule && currentScope.__parentRule.cssRules) {
|
|
5222
|
+
if (currentScope.__parentRule.cssRules.findIndex(function (rule) {
|
|
5223
|
+
return rule === currentScope
|
|
5224
|
+
}) === -1) {
|
|
5225
|
+
currentScope.__parentRule.cssRules.push(currentScope);
|
|
5226
|
+
}
|
|
5227
|
+
}
|
|
5228
|
+
|
|
5229
|
+
// Only handle top-level rule closing if we processed all ancestors
|
|
5230
|
+
if (ancestorRules.length === 0 && currentScope.parentRule == null) {
|
|
5231
|
+
currentScope.__ends = i + 1;
|
|
5232
|
+
if (currentScope !== topScope && topScope.cssRules.findIndex(function (rule) {
|
|
5233
|
+
return rule === currentScope
|
|
5234
|
+
}) === -1) {
|
|
5235
|
+
topScope.cssRules.push(currentScope);
|
|
5236
|
+
}
|
|
5237
|
+
currentScope = topScope;
|
|
5238
|
+
if (nestedSelectorRule === parentRule) {
|
|
5239
|
+
// Check if this selector is really starting inside another selector
|
|
5240
|
+
var nestedSelectorTokenToCurrentSelectorToken = token.slice(nestedSelectorRule.__starts, i + 1);
|
|
5241
|
+
var openingBraceMatch = nestedSelectorTokenToCurrentSelectorToken.match(/{/g);
|
|
5242
|
+
var closingBraceMatch = nestedSelectorTokenToCurrentSelectorToken.match(/}/g);
|
|
5243
|
+
var openingBraceLen = openingBraceMatch && openingBraceMatch.length;
|
|
5244
|
+
var closingBraceLen = closingBraceMatch && closingBraceMatch.length;
|
|
5245
|
+
|
|
5246
|
+
if (openingBraceLen === closingBraceLen) {
|
|
5247
|
+
// If the number of opening and closing braces are equal, we can assume that the new selector is starting outside the nestedSelectorRule
|
|
5248
|
+
nestedSelectorRule.__ends = i + 1;
|
|
5249
|
+
nestedSelectorRule = null;
|
|
5250
|
+
parentRule = null;
|
|
5251
|
+
}
|
|
4471
5252
|
} else {
|
|
5253
|
+
parentRule = null;
|
|
5254
|
+
}
|
|
5255
|
+
} else {
|
|
5256
|
+
currentScope = parentRule;
|
|
5257
|
+
}
|
|
5258
|
+
|
|
5259
|
+
buffer = "";
|
|
5260
|
+
state = "before-selector";
|
|
5261
|
+
break;
|
|
5262
|
+
}
|
|
5263
|
+
break;
|
|
5264
|
+
|
|
5265
|
+
default:
|
|
5266
|
+
switch (state) {
|
|
5267
|
+
case "before-selector":
|
|
5268
|
+
state = "selector";
|
|
5269
|
+
if ((styleRule || scopeRule) && parentRule) {
|
|
5270
|
+
// Assuming it's a declaration inside Nested Selector OR a Nested Declaration
|
|
5271
|
+
// If Declaration inside Nested Selector let's keep the same styleRule
|
|
5272
|
+
if (!isSelectorStartChar(character) && !isWhitespaceChar(character) && parentRule instanceof CSSOM.CSSGroupingRule) {
|
|
5273
|
+
// parentRule.__parentRule = styleRule;
|
|
5274
|
+
state = "before-name";
|
|
5275
|
+
if (styleRule !== parentRule) {
|
|
5276
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
5277
|
+
styleRule.__starts = i;
|
|
5278
|
+
}
|
|
5279
|
+
}
|
|
5280
|
+
|
|
5281
|
+
} else if (nestedSelectorRule && parentRule && parentRule instanceof CSSOM.CSSGroupingRule) {
|
|
5282
|
+
if (isSelectorStartChar(character)) {
|
|
5283
|
+
// If starting with a selector character, create CSSStyleRule instead of CSSNestedDeclarations
|
|
4472
5284
|
styleRule = new CSSOM.CSSStyleRule();
|
|
4473
|
-
styleRule.__starts = i;
|
|
5285
|
+
styleRule.__starts = i;
|
|
5286
|
+
} else if (!isWhitespaceChar(character)) {
|
|
5287
|
+
// Starting a declaration (not whitespace, not a selector)
|
|
5288
|
+
state = "before-name";
|
|
5289
|
+
// Check if we should create CSSNestedDeclarations
|
|
5290
|
+
// This happens if: parent has cssRules OR nestedSelectorRule exists (indicating CSSStyleRule in hierarchy)
|
|
5291
|
+
if (parentRule.cssRules.length || nestedSelectorRule) {
|
|
5292
|
+
currentScope = parentRule;
|
|
5293
|
+
// Only set nestedSelectorRule if parentRule is CSSStyleRule or CSSScopeRule
|
|
5294
|
+
if (parentRule.constructor.name === "CSSStyleRule" || parentRule.constructor.name === "CSSScopeRule") {
|
|
5295
|
+
nestedSelectorRule = parentRule;
|
|
5296
|
+
}
|
|
5297
|
+
styleRule = new CSSOM.CSSNestedDeclarations();
|
|
5298
|
+
styleRule.__starts = i;
|
|
5299
|
+
} else {
|
|
5300
|
+
if (parentRule.constructor.name === "CSSStyleRule") {
|
|
5301
|
+
styleRule = parentRule;
|
|
5302
|
+
} else {
|
|
5303
|
+
styleRule = new CSSOM.CSSStyleRule();
|
|
5304
|
+
styleRule.__starts = i;
|
|
5305
|
+
}
|
|
5306
|
+
}
|
|
4474
5307
|
}
|
|
4475
5308
|
}
|
|
4476
|
-
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4485
|
-
|
|
4486
|
-
|
|
4487
|
-
|
|
4488
|
-
|
|
4489
|
-
|
|
4490
|
-
|
|
4491
|
-
|
|
4492
|
-
|
|
5309
|
+
break;
|
|
5310
|
+
case "before-name":
|
|
5311
|
+
state = "name";
|
|
5312
|
+
break;
|
|
5313
|
+
case "before-value":
|
|
5314
|
+
state = "value";
|
|
5315
|
+
break;
|
|
5316
|
+
case "importRule-begin":
|
|
5317
|
+
state = "importRule";
|
|
5318
|
+
break;
|
|
5319
|
+
case "namespaceRule-begin":
|
|
5320
|
+
state = "namespaceRule";
|
|
5321
|
+
break;
|
|
5322
|
+
}
|
|
5323
|
+
buffer += character;
|
|
5324
|
+
break;
|
|
5325
|
+
}
|
|
5326
|
+
|
|
5327
|
+
// Auto-close all unclosed nested structures
|
|
5328
|
+
// Check AFTER processing the character, at the ORIGINAL ending index
|
|
5329
|
+
// Only add closing braces if CSS is incomplete (not at top scope)
|
|
5330
|
+
if (i === initialEndingIndex && (currentScope !== topScope || ancestorRules.length > 0)) {
|
|
5331
|
+
var needsClosing = ancestorRules.length;
|
|
5332
|
+
if (currentScope !== topScope && ancestorRules.indexOf(currentScope) === -1) {
|
|
5333
|
+
needsClosing += 1;
|
|
5334
|
+
}
|
|
5335
|
+
// Add closing braces for all unclosed structures
|
|
5336
|
+
for (var closeIdx = 0; closeIdx < needsClosing; closeIdx++) {
|
|
5337
|
+
token += "}";
|
|
5338
|
+
endingIndex += 1;
|
|
4493
5339
|
}
|
|
4494
|
-
buffer += character;
|
|
4495
|
-
break;
|
|
4496
5340
|
}
|
|
4497
5341
|
}
|
|
4498
5342
|
|