@acemir/cssom 0.9.20 → 0.9.22
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 +641 -86
- package/lib/CSSConditionRule.js +7 -2
- package/lib/CSSContainerRule.js +20 -12
- package/lib/CSSImportRule.js +92 -19
- package/lib/CSSMediaRule.js +13 -5
- package/lib/CSSNamespaceRule.js +27 -11
- package/lib/CSSPageRule.js +275 -0
- package/lib/CSSRule.js +6 -0
- package/lib/CSSStyleRule.js +19 -4
- package/lib/CSSStyleSheet.js +31 -7
- package/lib/StyleSheet.js +16 -1
- package/lib/index.js +1 -0
- package/lib/parse.js +155 -26
- package/package.json +1 -1
package/lib/CSSStyleSheet.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
//.CommonJS
|
|
2
2
|
var CSSOM = {
|
|
3
|
+
MediaList: require("./MediaList").MediaList,
|
|
3
4
|
StyleSheet: require("./StyleSheet").StyleSheet,
|
|
4
5
|
CSSRuleList: require("./CSSRuleList").CSSRuleList,
|
|
5
6
|
CSSStyleRule: require("./CSSStyleRule").CSSStyleRule,
|
|
@@ -59,7 +60,10 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
var ruleToParse = String(rule);
|
|
62
|
-
var
|
|
63
|
+
var parseErrors = [];
|
|
64
|
+
var parsedSheet = CSSOM.parse(ruleToParse, undefined, function(err) {
|
|
65
|
+
parseErrors.push(err);
|
|
66
|
+
} );
|
|
63
67
|
if (parsedSheet.cssRules.length !== 1) {
|
|
64
68
|
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
65
69
|
}
|
|
@@ -127,12 +131,21 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
|
127
131
|
'HierarchyRequestError');
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
// Cannot insert if there are already non-special rules
|
|
135
|
+
if (firstNonImportNamespaceIndex < this.cssRules.length) {
|
|
136
|
+
errorUtils.throwError(this, 'DOMException',
|
|
137
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
138
|
+
'InvalidStateError');
|
|
139
|
+
}
|
|
140
|
+
|
|
130
141
|
// Cannot insert after other types of rules
|
|
131
142
|
if (index > firstNonImportNamespaceIndex) {
|
|
132
143
|
errorUtils.throwError(this, 'DOMException',
|
|
133
144
|
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
134
145
|
'HierarchyRequestError');
|
|
135
146
|
}
|
|
147
|
+
|
|
148
|
+
|
|
136
149
|
} else if (cssRule.constructor.name === 'CSSLayerStatementRule') {
|
|
137
150
|
// @layer statement rules can be inserted anywhere before @import and @namespace
|
|
138
151
|
// No additional restrictions beyond what's already handled
|
|
@@ -149,6 +162,10 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
|
149
162
|
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
150
163
|
'HierarchyRequestError');
|
|
151
164
|
}
|
|
165
|
+
|
|
166
|
+
if (parseErrors.filter(function(error) { return !error.isNested; }).length !== 0) {
|
|
167
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
168
|
+
}
|
|
152
169
|
}
|
|
153
170
|
|
|
154
171
|
cssRule.__parentStyleSheet = this;
|
|
@@ -188,13 +205,20 @@ CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
|
|
|
188
205
|
if (index >= this.cssRules.length) {
|
|
189
206
|
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
190
207
|
}
|
|
191
|
-
if (this.cssRules[index]
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
208
|
+
if (this.cssRules[index]) {
|
|
209
|
+
if (this.cssRules[index].constructor.name == "CSSNamespaceRule") {
|
|
210
|
+
var shouldContinue = this.cssRules.every(function (rule) {
|
|
211
|
+
return ['CSSImportRule','CSSLayerStatementRule','CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
|
|
212
|
+
});
|
|
213
|
+
if (!shouldContinue) {
|
|
214
|
+
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '" + this.constructor.name + "': Failed to delete rule.", "InvalidStateError");
|
|
215
|
+
}
|
|
197
216
|
}
|
|
217
|
+
if (this.cssRules[index].constructor.name == "CSSImportRule") {
|
|
218
|
+
this.cssRules[index].styleSheet.__parentStyleSheet = null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
this.cssRules[index].__parentStyleSheet = null;
|
|
198
222
|
}
|
|
199
223
|
this.cssRules.splice(index, 1);
|
|
200
224
|
};
|
package/lib/StyleSheet.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
//.CommonJS
|
|
2
|
-
var CSSOM = {
|
|
2
|
+
var CSSOM = {
|
|
3
|
+
MediaList: require("./MediaList").MediaList
|
|
4
|
+
};
|
|
3
5
|
///CommonJS
|
|
4
6
|
|
|
5
7
|
|
|
@@ -8,10 +10,23 @@ var CSSOM = {};
|
|
|
8
10
|
* @see http://dev.w3.org/csswg/cssom/#the-stylesheet-interface
|
|
9
11
|
*/
|
|
10
12
|
CSSOM.StyleSheet = function StyleSheet() {
|
|
13
|
+
this.__media = new CSSOM.MediaList();
|
|
11
14
|
this.__parentStyleSheet = null;
|
|
12
15
|
};
|
|
13
16
|
|
|
14
17
|
Object.defineProperties(CSSOM.StyleSheet.prototype, {
|
|
18
|
+
media: {
|
|
19
|
+
get: function() {
|
|
20
|
+
return this.__media;
|
|
21
|
+
},
|
|
22
|
+
set: function(value) {
|
|
23
|
+
if (typeof value === "string") {
|
|
24
|
+
this.__media.mediaText = value;
|
|
25
|
+
} else {
|
|
26
|
+
this.__media = value;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
},
|
|
15
30
|
parentStyleSheet: {
|
|
16
31
|
get: function() {
|
|
17
32
|
return this.__parentStyleSheet;
|
package/lib/index.js
CHANGED
|
@@ -33,5 +33,6 @@ exports.CSSValueExpression = require('./CSSValueExpression').CSSValueExpression;
|
|
|
33
33
|
exports.CSSScopeRule = require('./CSSScopeRule').CSSScopeRule;
|
|
34
34
|
exports.CSSLayerBlockRule = require('./CSSLayerBlockRule').CSSLayerBlockRule;
|
|
35
35
|
exports.CSSLayerStatementRule = require('./CSSLayerStatementRule').CSSLayerStatementRule;
|
|
36
|
+
exports.CSSPageRule = require('./CSSPageRule').CSSPageRule;
|
|
36
37
|
exports.parse = require('./parse').parse;
|
|
37
38
|
exports.clone = require('./clone').clone;
|
package/lib/parse.js
CHANGED
|
@@ -51,7 +51,8 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
51
51
|
"counterStyleBlock": true,
|
|
52
52
|
'documentRule-begin': true,
|
|
53
53
|
"scopeBlock": true,
|
|
54
|
-
"layerBlock": true
|
|
54
|
+
"layerBlock": true,
|
|
55
|
+
"pageBlock": true
|
|
55
56
|
};
|
|
56
57
|
|
|
57
58
|
var styleSheet = new CSSOM.CSSStyleSheet();
|
|
@@ -69,7 +70,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
69
70
|
var ancestorRules = [];
|
|
70
71
|
var prevScope;
|
|
71
72
|
|
|
72
|
-
var name, priority="", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
73
|
+
var name, priority="", styleRule, mediaRule, containerRule, counterStyleRule, supportsRule, importRule, fontFaceRule, keyframesRule, documentRule, hostRule, startingStyleRule, scopeRule, pageRule, layerBlockRule, layerStatementRule, nestedSelectorRule, namespaceRule;
|
|
73
74
|
|
|
74
75
|
// Track defined namespace prefixes for validation
|
|
75
76
|
var definedNamespacePrefixes = {};
|
|
@@ -83,8 +84,9 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
83
84
|
var forwardImportRuleValidationRegExp = /(?:\s|\/\*|'|")/; // Match that the rule is followed by any whitespace, an opening comment, a single quote or double quote
|
|
84
85
|
var forwardRuleClosingBraceRegExp = /{[^{}]*}|}/; // Finds the next closing brace of a rule block
|
|
85
86
|
var forwardRuleSemicolonAndOpeningBraceRegExp = /^.*?({|;)/; // Finds the next semicolon or opening brace after the at-rule
|
|
86
|
-
var
|
|
87
|
+
var cssCustomIdentifierRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/; // Validates a css custom identifier
|
|
87
88
|
var startsWithCombinatorRegExp = /^\s*[>+~]/; // Checks if a selector starts with a CSS combinator (>, +, ~)
|
|
89
|
+
var atPageRuleSelectorRegExp = /^([^\s:]+)?((?::\w+)*)$/;
|
|
88
90
|
|
|
89
91
|
/**
|
|
90
92
|
* Searches for the first occurrence of a CSS at-rule statement terminator (`;` or `}`)
|
|
@@ -409,12 +411,12 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
409
411
|
if (isValid && atRuleKey === "@scope") {
|
|
410
412
|
var openBraceIndex = ruleSlice.indexOf('{');
|
|
411
413
|
if (openBraceIndex !== -1) {
|
|
412
|
-
// Extract the
|
|
413
|
-
var
|
|
414
|
-
|
|
415
|
-
// Skip past
|
|
416
|
-
var preludeContent =
|
|
417
|
-
|
|
414
|
+
// Extract the rule prelude (everything between the at-rule and {)
|
|
415
|
+
var rulePrelude = ruleSlice.slice(0, openBraceIndex).trim();
|
|
416
|
+
|
|
417
|
+
// Skip past at-rule keyword and whitespace
|
|
418
|
+
var preludeContent = rulePrelude.slice("@scope".length).trim();
|
|
419
|
+
|
|
418
420
|
if (preludeContent.length > 0) {
|
|
419
421
|
// Parse the scope prelude
|
|
420
422
|
var parsedScopePrelude = parseScopePrelude(preludeContent);
|
|
@@ -453,6 +455,64 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
453
455
|
// Empty prelude (@scope {}) is valid
|
|
454
456
|
}
|
|
455
457
|
}
|
|
458
|
+
|
|
459
|
+
if (isValid && atRuleKey === "@page") {
|
|
460
|
+
var openBraceIndex = ruleSlice.indexOf('{');
|
|
461
|
+
if (openBraceIndex !== -1) {
|
|
462
|
+
// Extract the rule prelude (everything between the at-rule and {)
|
|
463
|
+
var rulePrelude = ruleSlice.slice(0, openBraceIndex).trim();
|
|
464
|
+
|
|
465
|
+
// Skip past at-rule keyword and whitespace
|
|
466
|
+
var preludeContent = rulePrelude.slice("@page".length).trim();
|
|
467
|
+
|
|
468
|
+
if (preludeContent.length > 0) {
|
|
469
|
+
var trimmedValue = preludeContent.trim();
|
|
470
|
+
|
|
471
|
+
// Empty selector is valid for @page
|
|
472
|
+
if (trimmedValue !== '') {
|
|
473
|
+
// Parse @page selectorText for page name and pseudo-pages
|
|
474
|
+
// Valid formats:
|
|
475
|
+
// - (empty - no name, no pseudo-page)
|
|
476
|
+
// - :left, :right, :first, :blank (pseudo-page only)
|
|
477
|
+
// - named (named page only)
|
|
478
|
+
// - named:first (named page with single pseudo-page)
|
|
479
|
+
// - named:first:left (named page with multiple pseudo-pages)
|
|
480
|
+
var match = trimmedValue.match(atPageRuleSelectorRegExp);
|
|
481
|
+
if (match) {
|
|
482
|
+
var pageName = match[1] || '';
|
|
483
|
+
var pseudoPages = match[2] || '';
|
|
484
|
+
|
|
485
|
+
// Validate page name if present
|
|
486
|
+
if (pageName) {
|
|
487
|
+
if (!cssCustomIdentifierRegExp.test(pageName)) {
|
|
488
|
+
isValid = false;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Validate pseudo-pages if present
|
|
493
|
+
if (pseudoPages) {
|
|
494
|
+
var pseudos = pseudoPages.split(':').filter(function(p) { return p; });
|
|
495
|
+
var validPseudos = ['left', 'right', 'first', 'blank'];
|
|
496
|
+
var allValid = true;
|
|
497
|
+
for (var j = 0; j < pseudos.length; j++) {
|
|
498
|
+
if (validPseudos.indexOf(pseudos[j].toLowerCase()) === -1) {
|
|
499
|
+
allValid = false;
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (!allValid) {
|
|
505
|
+
isValid = false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
} else {
|
|
509
|
+
isValid = false;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
456
516
|
|
|
457
517
|
if (!isValid) {
|
|
458
518
|
// If it's invalid the browser will simply ignore the entire invalid block
|
|
@@ -532,6 +592,27 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
532
592
|
return false;
|
|
533
593
|
}
|
|
534
594
|
|
|
595
|
+
// Check for invalid pseudo-class usage with quoted strings
|
|
596
|
+
// Pseudo-classes like :lang(), :dir(), :nth-*() should not accept quoted strings
|
|
597
|
+
var pseudoPattern = /::?([a-zA-Z][\w-]*)\(([^)]+)\)/g;
|
|
598
|
+
var pseudoMatch;
|
|
599
|
+
while ((pseudoMatch = pseudoPattern.exec(selector)) !== null) {
|
|
600
|
+
var pseudoName = pseudoMatch[1];
|
|
601
|
+
var pseudoContent = pseudoMatch[2];
|
|
602
|
+
|
|
603
|
+
// List of pseudo-classes that should not accept quoted strings
|
|
604
|
+
// :lang() - accepts language codes: en, fr-CA
|
|
605
|
+
// :dir() - accepts direction: ltr, rtl
|
|
606
|
+
// :nth-*() - accepts An+B notation: 2n+1, odd, even
|
|
607
|
+
var noQuotesPseudos = ['lang', 'dir', 'nth-child', 'nth-last-child', 'nth-of-type', 'nth-last-of-type'];
|
|
608
|
+
|
|
609
|
+
for (var i = 0; i < noQuotesPseudos.length; i++) {
|
|
610
|
+
if (pseudoName === noQuotesPseudos[i] && /['"]/.test(pseudoContent)) {
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
|
|
535
616
|
// Fallback to a loose regexp for the overall selector structure (without deep paren matching)
|
|
536
617
|
// This is similar to the original, but without nested paren limitations
|
|
537
618
|
// Modified to support namespace selectors: *|element, prefix|element, |element
|
|
@@ -636,7 +717,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
636
717
|
* @returns {boolean} Returns `true` if the selector is valid, otherwise `false`.
|
|
637
718
|
*/
|
|
638
719
|
|
|
639
|
-
// Cache to store validated selectors (ES5-compliant object)
|
|
720
|
+
// Cache to store validated selectors (previously a ES6 Map, now an ES5-compliant object)
|
|
640
721
|
var validatedSelectorsCache = {};
|
|
641
722
|
|
|
642
723
|
// Only pseudo-classes that accept selector lists should recurse
|
|
@@ -746,6 +827,28 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
746
827
|
return definedNamespacePrefixes.hasOwnProperty(namespacePrefix);
|
|
747
828
|
}
|
|
748
829
|
|
|
830
|
+
/**
|
|
831
|
+
* Processes a CSS selector text
|
|
832
|
+
*
|
|
833
|
+
* @param {string} selectorText - The CSS selector text to process
|
|
834
|
+
* @returns {string} The processed selector text with normalized whitespace
|
|
835
|
+
*/
|
|
836
|
+
function processSelectorText(selectorText) {
|
|
837
|
+
// TODO: Remove invalid selectors that appears inside pseudo classes
|
|
838
|
+
// TODO: The same processing here needs to be reused in CSSStyleRule.selectorText setter
|
|
839
|
+
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
840
|
+
|
|
841
|
+
/**
|
|
842
|
+
* Normalizes whitespace and preserving quoted strings.
|
|
843
|
+
* Replaces all newline characters (CRLF, CR, or LF) with spaces while keeping quoted
|
|
844
|
+
* strings (single or double quotes) intact, including any escaped characters within them.
|
|
845
|
+
*/
|
|
846
|
+
return selectorText.replace(/(['"])(?:\\.|[^\\])*?\1|(\r\n|\r|\n)/g, function(match, _, newline) {
|
|
847
|
+
if (newline) return " ";
|
|
848
|
+
return match;
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
|
|
749
852
|
/**
|
|
750
853
|
* Checks if a given CSS selector text is valid by splitting it by commas
|
|
751
854
|
* and validating each individual selector using the `validateSelector` function.
|
|
@@ -754,6 +857,9 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
754
857
|
* @returns {boolean} Returns true if all selectors are valid, otherwise false.
|
|
755
858
|
*/
|
|
756
859
|
function isValidSelectorText(selectorText) {
|
|
860
|
+
// TODO: The same validations here needs to be reused in CSSStyleRule.selectorText setter
|
|
861
|
+
// TODO: Move these validation logic to a shared function to be reused in CSSStyleRule.selectorText setter
|
|
862
|
+
|
|
757
863
|
// Check for newlines inside single or double quotes using regex
|
|
758
864
|
// This matches any quoted string (single or double) containing a newline
|
|
759
865
|
var quotedNewlineRegExp = /(['"])(?:\\.|[^\\])*?\1/g;
|
|
@@ -774,7 +880,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
774
880
|
return true;
|
|
775
881
|
}
|
|
776
882
|
|
|
777
|
-
function parseError(message) {
|
|
883
|
+
function parseError(message, isNested) {
|
|
778
884
|
var lines = token.substring(0, i).split('\n');
|
|
779
885
|
var lineCount = lines.length;
|
|
780
886
|
var charCount = lines.pop().length + 1;
|
|
@@ -783,6 +889,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
783
889
|
/* jshint sub : true */
|
|
784
890
|
error['char'] = charCount;
|
|
785
891
|
error.styleSheet = styleSheet;
|
|
892
|
+
error.isNested = !!isNested;
|
|
786
893
|
// Print the error but continue parsing the sheet
|
|
787
894
|
try {
|
|
788
895
|
throw error;
|
|
@@ -880,7 +987,8 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
880
987
|
i += 2;
|
|
881
988
|
index = token.indexOf("*/", i);
|
|
882
989
|
if (index === -1) {
|
|
883
|
-
|
|
990
|
+
i = token.length - 1;
|
|
991
|
+
buffer = "";
|
|
884
992
|
} else {
|
|
885
993
|
i = index + 1;
|
|
886
994
|
}
|
|
@@ -953,6 +1061,15 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
953
1061
|
});
|
|
954
1062
|
buffer = "";
|
|
955
1063
|
break;
|
|
1064
|
+
} else if (token.indexOf("@page", i) === i) {
|
|
1065
|
+
validateAtRule("@page", function(){
|
|
1066
|
+
state = "pageBlock"
|
|
1067
|
+
pageRule = new CSSOM.CSSPageRule();
|
|
1068
|
+
pageRule.__starts = i;
|
|
1069
|
+
i += "page".length;
|
|
1070
|
+
});
|
|
1071
|
+
buffer = "";
|
|
1072
|
+
break;
|
|
956
1073
|
} else if (token.indexOf("@supports", i) === i) {
|
|
957
1074
|
validateAtRule("@supports", function(){
|
|
958
1075
|
state = "conditionBlock";
|
|
@@ -1050,10 +1167,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1050
1167
|
}
|
|
1051
1168
|
|
|
1052
1169
|
currentScope = parentRule = styleRule;
|
|
1053
|
-
styleRule.selectorText = buffer.trim()
|
|
1054
|
-
if (newline) return " ";
|
|
1055
|
-
return match;
|
|
1056
|
-
});
|
|
1170
|
+
styleRule.selectorText = processSelectorText(buffer.trim());
|
|
1057
1171
|
styleRule.style.__starts = i;
|
|
1058
1172
|
styleRule.__parentStyleSheet = styleSheet;
|
|
1059
1173
|
buffer = "";
|
|
@@ -1071,7 +1185,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1071
1185
|
buffer = "";
|
|
1072
1186
|
state = "before-selector";
|
|
1073
1187
|
} else if (state === "containerBlock") {
|
|
1074
|
-
containerRule.
|
|
1188
|
+
containerRule.__conditionText = buffer.trim();
|
|
1075
1189
|
|
|
1076
1190
|
if (parentRule) {
|
|
1077
1191
|
containerRule.__parentRule = parentRule;
|
|
@@ -1088,7 +1202,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1088
1202
|
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
1089
1203
|
buffer = "";
|
|
1090
1204
|
} else if (state === "conditionBlock") {
|
|
1091
|
-
supportsRule.
|
|
1205
|
+
supportsRule.__conditionText = buffer.trim();
|
|
1092
1206
|
|
|
1093
1207
|
if (parentRule) {
|
|
1094
1208
|
supportsRule.__parentRule = parentRule;
|
|
@@ -1123,7 +1237,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1123
1237
|
} else if (state === "layerBlock") {
|
|
1124
1238
|
layerBlockRule.name = buffer.trim();
|
|
1125
1239
|
|
|
1126
|
-
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(
|
|
1240
|
+
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(cssCustomIdentifierRegExp) !== null;
|
|
1127
1241
|
|
|
1128
1242
|
if (isValidName) {
|
|
1129
1243
|
if (parentRule) {
|
|
@@ -1136,6 +1250,19 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1136
1250
|
}
|
|
1137
1251
|
buffer = "";
|
|
1138
1252
|
state = "before-selector";
|
|
1253
|
+
} else if (state === "pageBlock") {
|
|
1254
|
+
pageRule.selectorText = buffer.trim();
|
|
1255
|
+
|
|
1256
|
+
if (parentRule) {
|
|
1257
|
+
pageRule.__parentRule = parentRule;
|
|
1258
|
+
ancestorRules.push(parentRule);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
currentScope = parentRule = pageRule;
|
|
1262
|
+
pageRule.__parentStyleSheet = styleSheet;
|
|
1263
|
+
styleRule = pageRule;
|
|
1264
|
+
buffer = "";
|
|
1265
|
+
state = "before-name";
|
|
1139
1266
|
} else if (state === "hostRule-begin") {
|
|
1140
1267
|
if (parentRule) {
|
|
1141
1268
|
ancestorRules.push(parentRule);
|
|
@@ -1209,10 +1336,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1209
1336
|
}
|
|
1210
1337
|
|
|
1211
1338
|
styleRule = new CSSOM.CSSStyleRule();
|
|
1212
|
-
var processedSelectorText = buffer.trim()
|
|
1213
|
-
if (newline) return " ";
|
|
1214
|
-
return match;
|
|
1215
|
-
});
|
|
1339
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
1216
1340
|
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
1217
1341
|
if (parentRule.constructor.name !== "CSSStyleRule" && parentRule.parentRule === null) {
|
|
1218
1342
|
styleRule.selectorText = processedSelectorText;
|
|
@@ -1336,7 +1460,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1336
1460
|
testNamespaceRule.cssText = buffer + character;
|
|
1337
1461
|
|
|
1338
1462
|
namespaceRule = testNamespaceRule;
|
|
1339
|
-
namespaceRule.__parentStyleSheet =
|
|
1463
|
+
namespaceRule.__parentStyleSheet = styleSheet;
|
|
1340
1464
|
styleSheet.cssRules.push(namespaceRule);
|
|
1341
1465
|
|
|
1342
1466
|
// Track the namespace prefix for validation
|
|
@@ -1355,7 +1479,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1355
1479
|
return name.trim();
|
|
1356
1480
|
});
|
|
1357
1481
|
var isInvalid = parentRule !== undefined || nameListStr.some(function (name) {
|
|
1358
|
-
return name.trim().match(
|
|
1482
|
+
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
1359
1483
|
});
|
|
1360
1484
|
|
|
1361
1485
|
if (!isInvalid) {
|
|
@@ -1412,7 +1536,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1412
1536
|
if (styleRule === nestedSelectorRule) {
|
|
1413
1537
|
nestedSelectorRule = null;
|
|
1414
1538
|
}
|
|
1415
|
-
parseError('Invalid CSSStyleRule (selectorText = "' + styleRule.selectorText + '")');
|
|
1539
|
+
parseError('Invalid CSSStyleRule (selectorText = "' + styleRule.selectorText + '")', styleRule.parentRule !== null);
|
|
1416
1540
|
} else {
|
|
1417
1541
|
currentScope.cssRules.push(styleRule);
|
|
1418
1542
|
}
|
|
@@ -1582,6 +1706,10 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1582
1706
|
}
|
|
1583
1707
|
}
|
|
1584
1708
|
|
|
1709
|
+
if (buffer.trim() !== "") {
|
|
1710
|
+
parseError("Unexpected end of input");
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1585
1713
|
return styleSheet;
|
|
1586
1714
|
};
|
|
1587
1715
|
|
|
@@ -1611,6 +1739,7 @@ CSSOM.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
|
|
|
1611
1739
|
CSSOM.CSSScopeRule = require('./CSSScopeRule').CSSScopeRule;
|
|
1612
1740
|
CSSOM.CSSLayerBlockRule = require("./CSSLayerBlockRule").CSSLayerBlockRule;
|
|
1613
1741
|
CSSOM.CSSLayerStatementRule = require("./CSSLayerStatementRule").CSSLayerStatementRule;
|
|
1742
|
+
CSSOM.CSSPageRule = require("./CSSPageRule").CSSPageRule;
|
|
1614
1743
|
// Use cssstyle if available
|
|
1615
1744
|
try {
|
|
1616
1745
|
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
|