@acemir/cssom 0.9.20 → 0.9.21
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 +638 -84
- 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 +152 -24
- 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.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;
|
|
@@ -880,7 +986,8 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
880
986
|
i += 2;
|
|
881
987
|
index = token.indexOf("*/", i);
|
|
882
988
|
if (index === -1) {
|
|
883
|
-
|
|
989
|
+
i = token.length - 1;
|
|
990
|
+
buffer = "";
|
|
884
991
|
} else {
|
|
885
992
|
i = index + 1;
|
|
886
993
|
}
|
|
@@ -953,6 +1060,15 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
953
1060
|
});
|
|
954
1061
|
buffer = "";
|
|
955
1062
|
break;
|
|
1063
|
+
} else if (token.indexOf("@page", i) === i) {
|
|
1064
|
+
validateAtRule("@page", function(){
|
|
1065
|
+
state = "pageBlock"
|
|
1066
|
+
pageRule = new CSSOM.CSSPageRule();
|
|
1067
|
+
pageRule.__starts = i;
|
|
1068
|
+
i += "page".length;
|
|
1069
|
+
});
|
|
1070
|
+
buffer = "";
|
|
1071
|
+
break;
|
|
956
1072
|
} else if (token.indexOf("@supports", i) === i) {
|
|
957
1073
|
validateAtRule("@supports", function(){
|
|
958
1074
|
state = "conditionBlock";
|
|
@@ -1050,10 +1166,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1050
1166
|
}
|
|
1051
1167
|
|
|
1052
1168
|
currentScope = parentRule = styleRule;
|
|
1053
|
-
styleRule.selectorText = buffer.trim()
|
|
1054
|
-
if (newline) return " ";
|
|
1055
|
-
return match;
|
|
1056
|
-
});
|
|
1169
|
+
styleRule.selectorText = processSelectorText(buffer.trim());
|
|
1057
1170
|
styleRule.style.__starts = i;
|
|
1058
1171
|
styleRule.__parentStyleSheet = styleSheet;
|
|
1059
1172
|
buffer = "";
|
|
@@ -1071,7 +1184,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1071
1184
|
buffer = "";
|
|
1072
1185
|
state = "before-selector";
|
|
1073
1186
|
} else if (state === "containerBlock") {
|
|
1074
|
-
containerRule.
|
|
1187
|
+
containerRule.__conditionText = buffer.trim();
|
|
1075
1188
|
|
|
1076
1189
|
if (parentRule) {
|
|
1077
1190
|
containerRule.__parentRule = parentRule;
|
|
@@ -1088,7 +1201,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1088
1201
|
counterStyleRule.__parentStyleSheet = styleSheet;
|
|
1089
1202
|
buffer = "";
|
|
1090
1203
|
} else if (state === "conditionBlock") {
|
|
1091
|
-
supportsRule.
|
|
1204
|
+
supportsRule.__conditionText = buffer.trim();
|
|
1092
1205
|
|
|
1093
1206
|
if (parentRule) {
|
|
1094
1207
|
supportsRule.__parentRule = parentRule;
|
|
@@ -1123,7 +1236,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1123
1236
|
} else if (state === "layerBlock") {
|
|
1124
1237
|
layerBlockRule.name = buffer.trim();
|
|
1125
1238
|
|
|
1126
|
-
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(
|
|
1239
|
+
var isValidName = layerBlockRule.name.length === 0 || layerBlockRule.name.match(cssCustomIdentifierRegExp) !== null;
|
|
1127
1240
|
|
|
1128
1241
|
if (isValidName) {
|
|
1129
1242
|
if (parentRule) {
|
|
@@ -1136,6 +1249,19 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1136
1249
|
}
|
|
1137
1250
|
buffer = "";
|
|
1138
1251
|
state = "before-selector";
|
|
1252
|
+
} else if (state === "pageBlock") {
|
|
1253
|
+
pageRule.selectorText = buffer.trim();
|
|
1254
|
+
|
|
1255
|
+
if (parentRule) {
|
|
1256
|
+
pageRule.__parentRule = parentRule;
|
|
1257
|
+
ancestorRules.push(parentRule);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
currentScope = parentRule = pageRule;
|
|
1261
|
+
pageRule.__parentStyleSheet = styleSheet;
|
|
1262
|
+
styleRule = pageRule;
|
|
1263
|
+
buffer = "";
|
|
1264
|
+
state = "before-name";
|
|
1139
1265
|
} else if (state === "hostRule-begin") {
|
|
1140
1266
|
if (parentRule) {
|
|
1141
1267
|
ancestorRules.push(parentRule);
|
|
@@ -1209,10 +1335,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1209
1335
|
}
|
|
1210
1336
|
|
|
1211
1337
|
styleRule = new CSSOM.CSSStyleRule();
|
|
1212
|
-
var processedSelectorText = buffer.trim()
|
|
1213
|
-
if (newline) return " ";
|
|
1214
|
-
return match;
|
|
1215
|
-
});
|
|
1338
|
+
var processedSelectorText = processSelectorText(buffer.trim());
|
|
1216
1339
|
// In a nested selector, ensure each selector contains '&' at the beginning, except for selectors that already have '&' somewhere
|
|
1217
1340
|
if (parentRule.constructor.name !== "CSSStyleRule" && parentRule.parentRule === null) {
|
|
1218
1341
|
styleRule.selectorText = processedSelectorText;
|
|
@@ -1336,7 +1459,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1336
1459
|
testNamespaceRule.cssText = buffer + character;
|
|
1337
1460
|
|
|
1338
1461
|
namespaceRule = testNamespaceRule;
|
|
1339
|
-
namespaceRule.__parentStyleSheet =
|
|
1462
|
+
namespaceRule.__parentStyleSheet = styleSheet;
|
|
1340
1463
|
styleSheet.cssRules.push(namespaceRule);
|
|
1341
1464
|
|
|
1342
1465
|
// Track the namespace prefix for validation
|
|
@@ -1355,7 +1478,7 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1355
1478
|
return name.trim();
|
|
1356
1479
|
});
|
|
1357
1480
|
var isInvalid = parentRule !== undefined || nameListStr.some(function (name) {
|
|
1358
|
-
return name.trim().match(
|
|
1481
|
+
return name.trim().match(cssCustomIdentifierRegExp) === null;
|
|
1359
1482
|
});
|
|
1360
1483
|
|
|
1361
1484
|
if (!isInvalid) {
|
|
@@ -1582,6 +1705,10 @@ CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
|
1582
1705
|
}
|
|
1583
1706
|
}
|
|
1584
1707
|
|
|
1708
|
+
if (buffer.trim() !== "") {
|
|
1709
|
+
parseError("Unexpected end of input");
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1585
1712
|
return styleSheet;
|
|
1586
1713
|
};
|
|
1587
1714
|
|
|
@@ -1611,6 +1738,7 @@ CSSOM.CSSDocumentRule = require('./CSSDocumentRule').CSSDocumentRule;
|
|
|
1611
1738
|
CSSOM.CSSScopeRule = require('./CSSScopeRule').CSSScopeRule;
|
|
1612
1739
|
CSSOM.CSSLayerBlockRule = require("./CSSLayerBlockRule").CSSLayerBlockRule;
|
|
1613
1740
|
CSSOM.CSSLayerStatementRule = require("./CSSLayerStatementRule").CSSLayerStatementRule;
|
|
1741
|
+
CSSOM.CSSPageRule = require("./CSSPageRule").CSSPageRule;
|
|
1614
1742
|
// Use cssstyle if available
|
|
1615
1743
|
try {
|
|
1616
1744
|
CSSOM.CSSStyleDeclaration = require("cssstyle").CSSStyleDeclaration;
|