@acemir/cssom 0.9.17 → 0.9.19
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 +196 -50
- package/lib/CSSFontFaceRule.js +1 -1
- package/lib/CSSGroupingRule.js +43 -5
- package/lib/CSSImportRule.js +5 -5
- package/lib/CSSKeyframeRule.js +1 -1
- package/lib/CSSRule.js +22 -1
- package/lib/CSSStyleRule.js +1 -1
- package/lib/CSSStyleSheet.js +99 -11
- package/lib/errorUtils.js +10 -21
- package/lib/parse.js +14 -4
- package/package.json +1 -1
package/build/CSSOM.js
CHANGED
|
@@ -5,27 +5,27 @@ var CSSOM = {};
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Gets the appropriate error constructor from the global object context.
|
|
8
|
-
* Tries to find the error constructor from parentStyleSheet.
|
|
9
|
-
* then from
|
|
8
|
+
* Tries to find the error constructor from parentStyleSheet.__globalObject,
|
|
9
|
+
* then from __globalObject, then falls back to the native constructor.
|
|
10
10
|
*
|
|
11
11
|
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
|
|
12
12
|
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
|
|
13
13
|
* @return {Function} The error constructor
|
|
14
14
|
*/
|
|
15
15
|
function getErrorConstructor(context, errorType) {
|
|
16
|
-
// Try parentStyleSheet.
|
|
17
|
-
if (context.parentStyleSheet && context.parentStyleSheet.
|
|
18
|
-
return context.parentStyleSheet.
|
|
16
|
+
// Try parentStyleSheet.__globalObject first
|
|
17
|
+
if (context.parentStyleSheet && context.parentStyleSheet.__globalObject && context.parentStyleSheet.__globalObject[errorType]) {
|
|
18
|
+
return context.parentStyleSheet.__globalObject[errorType];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
// Try __parentStyleSheet (alternative naming)
|
|
22
|
-
if (context.__parentStyleSheet && context.__parentStyleSheet.
|
|
23
|
-
return context.__parentStyleSheet.
|
|
22
|
+
if (context.__parentStyleSheet && context.__parentStyleSheet.__globalObject && context.__parentStyleSheet.__globalObject[errorType]) {
|
|
23
|
+
return context.__parentStyleSheet.__globalObject[errorType];
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
// Try
|
|
27
|
-
if (context.
|
|
28
|
-
return context.
|
|
26
|
+
// Try __globalObject on the context itself
|
|
27
|
+
if (context.__globalObject && context.__globalObject[errorType]) {
|
|
28
|
+
return context.__globalObject[errorType];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
// Fall back to native constructor
|
|
@@ -66,16 +66,6 @@ function throwMissingArguments(context, methodName, objectName, required, provid
|
|
|
66
66
|
throwError(context, 'TypeError', message);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/**
|
|
70
|
-
* Throws a RangeError for index out of bounds.
|
|
71
|
-
*
|
|
72
|
-
* @param {Object} context - The CSSOM object
|
|
73
|
-
* @param {string} [message] - Optional custom message, defaults to 'INDEX_SIZE_ERR'
|
|
74
|
-
*/
|
|
75
|
-
function throwIndexSizeError(context, message) {
|
|
76
|
-
throwError(context, 'RangeError', message || 'INDEX_SIZE_ERR');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
69
|
/**
|
|
80
70
|
* Throws a DOMException for parse errors.
|
|
81
71
|
*
|
|
@@ -111,7 +101,6 @@ var errorUtils = {
|
|
|
111
101
|
getErrorConstructor: getErrorConstructor,
|
|
112
102
|
throwError: throwError,
|
|
113
103
|
throwMissingArguments: throwMissingArguments,
|
|
114
|
-
throwIndexSizeError: throwIndexSizeError,
|
|
115
104
|
throwParseError: throwParseError,
|
|
116
105
|
throwIndexError: throwIndexError
|
|
117
106
|
};
|
|
@@ -312,6 +301,27 @@ CSSOM.CSSRule = function CSSRule() {
|
|
|
312
301
|
this.__parentStyleSheet = null;
|
|
313
302
|
};
|
|
314
303
|
|
|
304
|
+
CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
|
|
305
|
+
CSSOM.CSSRule.STYLE_RULE = 1;
|
|
306
|
+
CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
|
|
307
|
+
CSSOM.CSSRule.IMPORT_RULE = 3;
|
|
308
|
+
CSSOM.CSSRule.MEDIA_RULE = 4;
|
|
309
|
+
CSSOM.CSSRule.FONT_FACE_RULE = 5;
|
|
310
|
+
CSSOM.CSSRule.PAGE_RULE = 6;
|
|
311
|
+
CSSOM.CSSRule.KEYFRAMES_RULE = 7;
|
|
312
|
+
CSSOM.CSSRule.KEYFRAME_RULE = 8;
|
|
313
|
+
CSSOM.CSSRule.MARGIN_RULE = 9;
|
|
314
|
+
CSSOM.CSSRule.NAMESPACE_RULE = 10;
|
|
315
|
+
CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
|
|
316
|
+
CSSOM.CSSRule.SUPPORTS_RULE = 12;
|
|
317
|
+
CSSOM.CSSRule.DOCUMENT_RULE = 13;
|
|
318
|
+
CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
|
|
319
|
+
CSSOM.CSSRule.VIEWPORT_RULE = 15;
|
|
320
|
+
CSSOM.CSSRule.REGION_STYLE_RULE = 16;
|
|
321
|
+
CSSOM.CSSRule.CONTAINER_RULE = 17;
|
|
322
|
+
CSSOM.CSSRule.LAYER_BLOCK_RULE = 18;
|
|
323
|
+
CSSOM.CSSRule.STARTING_STYLE_RULE = 1002;
|
|
324
|
+
|
|
315
325
|
Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
316
326
|
|
|
317
327
|
constructor: { value: CSSOM.CSSRule },
|
|
@@ -348,7 +358,7 @@ Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
|
348
358
|
CONTAINER_RULE: { value: 17, enumerable: true },
|
|
349
359
|
LAYER_BLOCK_RULE: { value: 18, enumerable: true },
|
|
350
360
|
STARTING_STYLE_RULE: { value: 1002, enumerable: true },
|
|
351
|
-
})
|
|
361
|
+
});
|
|
352
362
|
|
|
353
363
|
|
|
354
364
|
|
|
@@ -422,10 +432,41 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
422
432
|
* @return {number} The index within the grouping rule's collection of the newly inserted rule.
|
|
423
433
|
*/
|
|
424
434
|
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
|
|
425
|
-
if (
|
|
426
|
-
errorUtils.
|
|
435
|
+
if (rule === undefined && index === undefined) {
|
|
436
|
+
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
|
|
427
437
|
}
|
|
428
|
-
|
|
438
|
+
if (index === void 0) {
|
|
439
|
+
index = 0;
|
|
440
|
+
}
|
|
441
|
+
index = Number(index);
|
|
442
|
+
if (index < 0) {
|
|
443
|
+
index = 4294967296 + index;
|
|
444
|
+
}
|
|
445
|
+
if (index > this.cssRules.length) {
|
|
446
|
+
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
var ruleToParse = String(rule);
|
|
450
|
+
var parsedSheet = CSSOM.parse(ruleToParse);
|
|
451
|
+
if (parsedSheet.cssRules.length !== 1) {
|
|
452
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
453
|
+
}
|
|
454
|
+
var cssRule = parsedSheet.cssRules[0];
|
|
455
|
+
|
|
456
|
+
// Check for rules that cannot be inserted inside a CSSGroupingRule
|
|
457
|
+
if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
458
|
+
var ruleKeyword = cssRule.constructor.name === 'CSSImportRule' ? '@import' : '@namespace';
|
|
459
|
+
errorUtils.throwError(this, 'DOMException',
|
|
460
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
|
|
461
|
+
"'" + ruleKeyword + "' rules cannot be inserted inside a group rule.",
|
|
462
|
+
'HierarchyRequestError');
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Check for CSSLayerStatementRule (@layer statement rules)
|
|
466
|
+
if (cssRule.constructor.name === 'CSSLayerStatementRule') {
|
|
467
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
468
|
+
}
|
|
469
|
+
|
|
429
470
|
cssRule.__parentRule = this;
|
|
430
471
|
this.cssRules.splice(index, 0, cssRule);
|
|
431
472
|
return index;
|
|
@@ -444,8 +485,15 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
444
485
|
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
|
|
445
486
|
*/
|
|
446
487
|
CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
|
|
447
|
-
if (index
|
|
448
|
-
errorUtils.
|
|
488
|
+
if (index === undefined) {
|
|
489
|
+
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
|
|
490
|
+
}
|
|
491
|
+
index = Number(index);
|
|
492
|
+
if (index < 0) {
|
|
493
|
+
index = 4294967296 + index;
|
|
494
|
+
}
|
|
495
|
+
if (index >= this.cssRules.length) {
|
|
496
|
+
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
449
497
|
}
|
|
450
498
|
this.cssRules.splice(index, 1)[0].__parentRule = null;
|
|
451
499
|
};
|
|
@@ -542,7 +590,7 @@ Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
|
542
590
|
valuesArr.push(this.cssRules.map(function(rule){ return rule.cssText }).join("\n "));
|
|
543
591
|
values = valuesArr.join("\n ") + "\n}"
|
|
544
592
|
} else {
|
|
545
|
-
values = " { " + this.style.cssText + " }";
|
|
593
|
+
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
546
594
|
}
|
|
547
595
|
text = this.selectorText + values;
|
|
548
596
|
} else {
|
|
@@ -899,7 +947,7 @@ CSSOM.CSSImportRule.prototype.type = 3;
|
|
|
899
947
|
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
900
948
|
get: function() {
|
|
901
949
|
var mediaText = this.media.mediaText;
|
|
902
|
-
return "@import url(" + this.href + ")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
950
|
+
return "@import url(\"" + this.href + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
903
951
|
},
|
|
904
952
|
set: function(cssText) {
|
|
905
953
|
var i = 0;
|
|
@@ -917,7 +965,7 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
917
965
|
var index;
|
|
918
966
|
|
|
919
967
|
var layerRegExp = /layer\(([^)]*)\)/;
|
|
920
|
-
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)$/;
|
|
968
|
+
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/;
|
|
921
969
|
var supportsRegExp = /supports\(([^)]+)\)/;
|
|
922
970
|
var doubleOrMoreSpacesRegExp = /\s{2,}/g;
|
|
923
971
|
|
|
@@ -1000,12 +1048,12 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
1000
1048
|
|
|
1001
1049
|
if (layerMatch) {
|
|
1002
1050
|
var layerName = layerMatch[1].trim();
|
|
1003
|
-
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
|
|
1004
|
-
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
1005
|
-
.trim();
|
|
1006
1051
|
|
|
1007
1052
|
if (layerName.match(layerRuleNameRegExp) !== null) {
|
|
1008
1053
|
this.layerName = layerMatch[1].trim();
|
|
1054
|
+
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
|
|
1055
|
+
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
1056
|
+
.trim();
|
|
1009
1057
|
} else {
|
|
1010
1058
|
// REVIEW: In the browser, an empty layer() is not processed as a unamed layer
|
|
1011
1059
|
// and treats the rest of the string as mediaText, ignoring the parse of supports()
|
|
@@ -1156,7 +1204,7 @@ Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "style", {
|
|
|
1156
1204
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
|
|
1157
1205
|
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
|
|
1158
1206
|
get: function() {
|
|
1159
|
-
return "@font-face { " + this.style.cssText + " }";
|
|
1207
|
+
return "@font-face {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
1160
1208
|
}
|
|
1161
1209
|
});
|
|
1162
1210
|
|
|
@@ -1279,24 +1327,112 @@ CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
|
1279
1327
|
*/
|
|
1280
1328
|
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
1281
1329
|
if (rule === undefined && index === undefined) {
|
|
1282
|
-
errorUtils.throwMissingArguments(this, 'insertRule',
|
|
1330
|
+
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
|
|
1283
1331
|
}
|
|
1284
1332
|
if (index === void 0) {
|
|
1285
1333
|
index = 0;
|
|
1286
1334
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1335
|
+
index = Number(index);
|
|
1336
|
+
if (index < 0) {
|
|
1337
|
+
index = 4294967296 + index;
|
|
1289
1338
|
}
|
|
1339
|
+
if (index > this.cssRules.length) {
|
|
1340
|
+
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
1341
|
+
}
|
|
1342
|
+
|
|
1290
1343
|
var ruleToParse = String(rule);
|
|
1291
1344
|
var parsedSheet = CSSOM.parse(ruleToParse);
|
|
1292
1345
|
if (parsedSheet.cssRules.length !== 1) {
|
|
1293
|
-
|
|
1294
|
-
if (ruleToParse.trimStart().startsWith('@namespace')) {
|
|
1295
|
-
domExceptionName = "InvalidStateError";
|
|
1296
|
-
}
|
|
1297
|
-
errorUtils.throwParseError(this, 'insertRule', 'CSSStyleSheet', ruleToParse, domExceptionName);
|
|
1346
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
1298
1347
|
}
|
|
1299
1348
|
var cssRule = parsedSheet.cssRules[0];
|
|
1349
|
+
|
|
1350
|
+
// Helper function to find the last index of a specific rule constructor
|
|
1351
|
+
function findLastIndexOfConstructor(rules, constructorName) {
|
|
1352
|
+
for (var i = rules.length - 1; i >= 0; i--) {
|
|
1353
|
+
if (rules[i].constructor.name === constructorName) {
|
|
1354
|
+
return i;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
return -1;
|
|
1358
|
+
}
|
|
1359
|
+
|
|
1360
|
+
// Helper function to find the first index of a rule that's NOT of specified constructors
|
|
1361
|
+
function findFirstNonConstructorIndex(rules, constructorNames) {
|
|
1362
|
+
for (var i = 0; i < rules.length; i++) {
|
|
1363
|
+
if (constructorNames.indexOf(rules[i].constructor.name) === -1) {
|
|
1364
|
+
return i;
|
|
1365
|
+
}
|
|
1366
|
+
}
|
|
1367
|
+
return rules.length;
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
// Validate rule ordering based on CSS specification
|
|
1371
|
+
if (cssRule.constructor.name === 'CSSImportRule') {
|
|
1372
|
+
// @import rules cannot be inserted after @layer rules that already exist
|
|
1373
|
+
// They can only be inserted at the beginning or after other @import rules
|
|
1374
|
+
var firstLayerIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
|
|
1375
|
+
if (firstLayerIndex < this.cssRules.length && this.cssRules[firstLayerIndex].constructor.name === 'CSSLayerStatementRule' && index > firstLayerIndex) {
|
|
1376
|
+
errorUtils.throwError(this, 'DOMException',
|
|
1377
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
1378
|
+
'HierarchyRequestError');
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
// Also cannot insert after @namespace or other rules
|
|
1382
|
+
var firstNonImportIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
|
|
1383
|
+
if (index > firstNonImportIndex && firstNonImportIndex < this.cssRules.length &&
|
|
1384
|
+
this.cssRules[firstNonImportIndex].constructor.name !== 'CSSLayerStatementRule') {
|
|
1385
|
+
errorUtils.throwError(this, 'DOMException',
|
|
1386
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
1387
|
+
'HierarchyRequestError');
|
|
1388
|
+
}
|
|
1389
|
+
} else if (cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
1390
|
+
// @namespace rules can come after @layer and @import, but before any other rules
|
|
1391
|
+
// They cannot come before @import rules
|
|
1392
|
+
var firstImportIndex = -1;
|
|
1393
|
+
for (var i = 0; i < this.cssRules.length; i++) {
|
|
1394
|
+
if (this.cssRules[i].constructor.name === 'CSSImportRule') {
|
|
1395
|
+
firstImportIndex = i;
|
|
1396
|
+
break;
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
var firstNonImportNamespaceIndex = findFirstNonConstructorIndex(this.cssRules, [
|
|
1400
|
+
'CSSLayerStatementRule',
|
|
1401
|
+
'CSSImportRule',
|
|
1402
|
+
'CSSNamespaceRule'
|
|
1403
|
+
]);
|
|
1404
|
+
|
|
1405
|
+
// Cannot insert before @import rules
|
|
1406
|
+
if (firstImportIndex !== -1 && index <= firstImportIndex) {
|
|
1407
|
+
errorUtils.throwError(this, 'DOMException',
|
|
1408
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
1409
|
+
'HierarchyRequestError');
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
// Cannot insert after other types of rules
|
|
1413
|
+
if (index > firstNonImportNamespaceIndex) {
|
|
1414
|
+
errorUtils.throwError(this, 'DOMException',
|
|
1415
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
1416
|
+
'HierarchyRequestError');
|
|
1417
|
+
}
|
|
1418
|
+
} else if (cssRule.constructor.name === 'CSSLayerStatementRule') {
|
|
1419
|
+
// @layer statement rules can be inserted anywhere before @import and @namespace
|
|
1420
|
+
// No additional restrictions beyond what's already handled
|
|
1421
|
+
} else {
|
|
1422
|
+
// Any other rule cannot be inserted before @import and @namespace
|
|
1423
|
+
var firstNonSpecialRuleIndex = findFirstNonConstructorIndex(this.cssRules, [
|
|
1424
|
+
'CSSLayerStatementRule',
|
|
1425
|
+
'CSSImportRule',
|
|
1426
|
+
'CSSNamespaceRule'
|
|
1427
|
+
]);
|
|
1428
|
+
|
|
1429
|
+
if (index < firstNonSpecialRuleIndex) {
|
|
1430
|
+
errorUtils.throwError(this, 'DOMException',
|
|
1431
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
1432
|
+
'HierarchyRequestError');
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1300
1436
|
cssRule.__parentStyleSheet = this;
|
|
1301
1437
|
this.cssRules.splice(index, 0, cssRule);
|
|
1302
1438
|
return index;
|
|
@@ -1318,21 +1454,21 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
|
1318
1454
|
*/
|
|
1319
1455
|
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
|
|
1320
1456
|
if (index === undefined) {
|
|
1321
|
-
errorUtils.throwMissingArguments(this, 'deleteRule',
|
|
1457
|
+
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
|
|
1322
1458
|
}
|
|
1323
1459
|
index = Number(index);
|
|
1324
1460
|
if (index < 0) {
|
|
1325
1461
|
index = 4294967296 + index;
|
|
1326
1462
|
}
|
|
1327
1463
|
if (index >= this.cssRules.length) {
|
|
1328
|
-
errorUtils.throwIndexError(this, 'deleteRule',
|
|
1464
|
+
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
1329
1465
|
}
|
|
1330
1466
|
if (this.cssRules[index] && this.cssRules[index].constructor.name == "CSSNamespaceRule") {
|
|
1331
1467
|
var shouldContinue = this.cssRules.every(function (rule) {
|
|
1332
1468
|
return ['CSSImportRule','CSSLayerStatementRule','CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
|
|
1333
1469
|
});
|
|
1334
1470
|
if (!shouldContinue) {
|
|
1335
|
-
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '
|
|
1471
|
+
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '" + this.constructor.name + "': Failed to delete rule.", "InvalidStateError");
|
|
1336
1472
|
}
|
|
1337
1473
|
}
|
|
1338
1474
|
this.cssRules.splice(index, 1);
|
|
@@ -1616,7 +1752,7 @@ Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "style", {
|
|
|
1616
1752
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
|
|
1617
1753
|
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
|
|
1618
1754
|
get: function() {
|
|
1619
|
-
return this.keyText + " { " + this.style.cssText + " }";
|
|
1755
|
+
return this.keyText + " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
1620
1756
|
}
|
|
1621
1757
|
});
|
|
1622
1758
|
|
|
@@ -2150,10 +2286,16 @@ Object.defineProperties(CSSOM.CSSLayerStatementRule.prototype, {
|
|
|
2150
2286
|
|
|
2151
2287
|
|
|
2152
2288
|
/**
|
|
2153
|
-
*
|
|
2289
|
+
* Parses a CSS string and returns a CSSOM.CSSStyleSheet object representing the parsed stylesheet.
|
|
2290
|
+
*
|
|
2291
|
+
* @param {string} token - The CSS string to parse.
|
|
2292
|
+
* @param {object} [opts] - Optional parsing options.
|
|
2293
|
+
* @param {object} [opts.globalObject] - An optional global object to attach to the stylesheet. Useful on jsdom webplatform tests.
|
|
2294
|
+
* @param {function|boolean} [errorHandler] - Optional error handler function or `true` to use `console.error`.
|
|
2295
|
+
* @returns {CSSOM.CSSStyleSheet} The parsed CSSStyleSheet object.
|
|
2154
2296
|
*/
|
|
2155
|
-
CSSOM.parse = function parse(token, errorHandler) {
|
|
2156
|
-
errorHandler = errorHandler ===
|
|
2297
|
+
CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
2298
|
+
errorHandler = errorHandler === true ? (console && console.error) : errorHandler;
|
|
2157
2299
|
|
|
2158
2300
|
var i = 0;
|
|
2159
2301
|
|
|
@@ -2195,6 +2337,10 @@ CSSOM.parse = function parse(token, errorHandler) {
|
|
|
2195
2337
|
|
|
2196
2338
|
var styleSheet = new CSSOM.CSSStyleSheet();
|
|
2197
2339
|
|
|
2340
|
+
if (opts && opts.globalObject) {
|
|
2341
|
+
styleSheet.__globalObject = opts.globalObject;
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2198
2344
|
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
2199
2345
|
var currentScope = styleSheet;
|
|
2200
2346
|
|
|
@@ -2892,7 +3038,7 @@ CSSOM.parse = function parse(token, errorHandler) {
|
|
|
2892
3038
|
i += "font-face".length;
|
|
2893
3039
|
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
2894
3040
|
fontFaceRule.__starts = i;
|
|
2895
|
-
},
|
|
3041
|
+
}, true);
|
|
2896
3042
|
break;
|
|
2897
3043
|
} else {
|
|
2898
3044
|
atKeyframesRegExp.lastIndex = i;
|
package/lib/CSSFontFaceRule.js
CHANGED
|
@@ -45,7 +45,7 @@ Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "style", {
|
|
|
45
45
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSFontFaceRule.cpp
|
|
46
46
|
Object.defineProperty(CSSOM.CSSFontFaceRule.prototype, "cssText", {
|
|
47
47
|
get: function() {
|
|
48
|
-
return "@font-face { " + this.style.cssText + " }";
|
|
48
|
+
return "@font-face {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
49
49
|
}
|
|
50
50
|
});
|
|
51
51
|
|
package/lib/CSSGroupingRule.js
CHANGED
|
@@ -37,10 +37,41 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
37
37
|
* @return {number} The index within the grouping rule's collection of the newly inserted rule.
|
|
38
38
|
*/
|
|
39
39
|
CSSOM.CSSGroupingRule.prototype.insertRule = function insertRule(rule, index) {
|
|
40
|
-
if (
|
|
41
|
-
errorUtils.
|
|
40
|
+
if (rule === undefined && index === undefined) {
|
|
41
|
+
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
|
|
42
42
|
}
|
|
43
|
-
|
|
43
|
+
if (index === void 0) {
|
|
44
|
+
index = 0;
|
|
45
|
+
}
|
|
46
|
+
index = Number(index);
|
|
47
|
+
if (index < 0) {
|
|
48
|
+
index = 4294967296 + index;
|
|
49
|
+
}
|
|
50
|
+
if (index > this.cssRules.length) {
|
|
51
|
+
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
var ruleToParse = String(rule);
|
|
55
|
+
var parsedSheet = CSSOM.parse(ruleToParse);
|
|
56
|
+
if (parsedSheet.cssRules.length !== 1) {
|
|
57
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
58
|
+
}
|
|
59
|
+
var cssRule = parsedSheet.cssRules[0];
|
|
60
|
+
|
|
61
|
+
// Check for rules that cannot be inserted inside a CSSGroupingRule
|
|
62
|
+
if (cssRule.constructor.name === 'CSSImportRule' || cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
63
|
+
var ruleKeyword = cssRule.constructor.name === 'CSSImportRule' ? '@import' : '@namespace';
|
|
64
|
+
errorUtils.throwError(this, 'DOMException',
|
|
65
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': " +
|
|
66
|
+
"'" + ruleKeyword + "' rules cannot be inserted inside a group rule.",
|
|
67
|
+
'HierarchyRequestError');
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Check for CSSLayerStatementRule (@layer statement rules)
|
|
71
|
+
if (cssRule.constructor.name === 'CSSLayerStatementRule') {
|
|
72
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
73
|
+
}
|
|
74
|
+
|
|
44
75
|
cssRule.__parentRule = this;
|
|
45
76
|
this.cssRules.splice(index, 0, cssRule);
|
|
46
77
|
return index;
|
|
@@ -59,8 +90,15 @@ CSSOM.CSSGroupingRule.prototype.constructor = CSSOM.CSSGroupingRule;
|
|
|
59
90
|
* @see https://www.w3.org/TR/cssom-1/#dom-cssgroupingrule-deleterule
|
|
60
91
|
*/
|
|
61
92
|
CSSOM.CSSGroupingRule.prototype.deleteRule = function deleteRule(index) {
|
|
62
|
-
if (index
|
|
63
|
-
errorUtils.
|
|
93
|
+
if (index === undefined) {
|
|
94
|
+
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
|
|
95
|
+
}
|
|
96
|
+
index = Number(index);
|
|
97
|
+
if (index < 0) {
|
|
98
|
+
index = 4294967296 + index;
|
|
99
|
+
}
|
|
100
|
+
if (index >= this.cssRules.length) {
|
|
101
|
+
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
64
102
|
}
|
|
65
103
|
this.cssRules.splice(index, 1)[0].__parentRule = null;
|
|
66
104
|
};
|
package/lib/CSSImportRule.js
CHANGED
|
@@ -28,7 +28,7 @@ CSSOM.CSSImportRule.prototype.type = 3;
|
|
|
28
28
|
Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
29
29
|
get: function() {
|
|
30
30
|
var mediaText = this.media.mediaText;
|
|
31
|
-
return "@import url(" + this.href + ")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
31
|
+
return "@import url(\"" + this.href + "\")" + (this.layerName !== null ? " layer" + (this.layerName && "(" + this.layerName + ")") : "" ) + (this.supportsText ? " supports(" + this.supportsText + ")" : "" ) + (mediaText ? " " + mediaText : "") + ";";
|
|
32
32
|
},
|
|
33
33
|
set: function(cssText) {
|
|
34
34
|
var i = 0;
|
|
@@ -46,7 +46,7 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
46
46
|
var index;
|
|
47
47
|
|
|
48
48
|
var layerRegExp = /layer\(([^)]*)\)/;
|
|
49
|
-
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+[_a-zA-Z0-9-]*)$/;
|
|
49
|
+
var layerRuleNameRegExp = /^(-?[_a-zA-Z]+(\.[_a-zA-Z]+)*[_a-zA-Z0-9-]*)$/;
|
|
50
50
|
var supportsRegExp = /supports\(([^)]+)\)/;
|
|
51
51
|
var doubleOrMoreSpacesRegExp = /\s{2,}/g;
|
|
52
52
|
|
|
@@ -129,12 +129,12 @@ Object.defineProperty(CSSOM.CSSImportRule.prototype, "cssText", {
|
|
|
129
129
|
|
|
130
130
|
if (layerMatch) {
|
|
131
131
|
var layerName = layerMatch[1].trim();
|
|
132
|
-
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
|
|
133
|
-
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
134
|
-
.trim();
|
|
135
132
|
|
|
136
133
|
if (layerName.match(layerRuleNameRegExp) !== null) {
|
|
137
134
|
this.layerName = layerMatch[1].trim();
|
|
135
|
+
bufferTrimmed = bufferTrimmed.replace(layerRegExp, '')
|
|
136
|
+
.replace(doubleOrMoreSpacesRegExp, ' ') // Replace double or more spaces with single space
|
|
137
|
+
.trim();
|
|
138
138
|
} else {
|
|
139
139
|
// REVIEW: In the browser, an empty layer() is not processed as a unamed layer
|
|
140
140
|
// and treats the rest of the string as mediaText, ignoring the parse of supports()
|
package/lib/CSSKeyframeRule.js
CHANGED
|
@@ -46,7 +46,7 @@ Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "style", {
|
|
|
46
46
|
// http://www.opensource.apple.com/source/WebCore/WebCore-955.66.1/css/WebKitCSSKeyframeRule.cpp
|
|
47
47
|
Object.defineProperty(CSSOM.CSSKeyframeRule.prototype, "cssText", {
|
|
48
48
|
get: function() {
|
|
49
|
-
return this.keyText + " { " + this.style.cssText + " }";
|
|
49
|
+
return this.keyText + " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
|
package/lib/CSSRule.js
CHANGED
|
@@ -12,6 +12,27 @@ CSSOM.CSSRule = function CSSRule() {
|
|
|
12
12
|
this.__parentStyleSheet = null;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
CSSOM.CSSRule.UNKNOWN_RULE = 0; // obsolete
|
|
16
|
+
CSSOM.CSSRule.STYLE_RULE = 1;
|
|
17
|
+
CSSOM.CSSRule.CHARSET_RULE = 2; // obsolete
|
|
18
|
+
CSSOM.CSSRule.IMPORT_RULE = 3;
|
|
19
|
+
CSSOM.CSSRule.MEDIA_RULE = 4;
|
|
20
|
+
CSSOM.CSSRule.FONT_FACE_RULE = 5;
|
|
21
|
+
CSSOM.CSSRule.PAGE_RULE = 6;
|
|
22
|
+
CSSOM.CSSRule.KEYFRAMES_RULE = 7;
|
|
23
|
+
CSSOM.CSSRule.KEYFRAME_RULE = 8;
|
|
24
|
+
CSSOM.CSSRule.MARGIN_RULE = 9;
|
|
25
|
+
CSSOM.CSSRule.NAMESPACE_RULE = 10;
|
|
26
|
+
CSSOM.CSSRule.COUNTER_STYLE_RULE = 11;
|
|
27
|
+
CSSOM.CSSRule.SUPPORTS_RULE = 12;
|
|
28
|
+
CSSOM.CSSRule.DOCUMENT_RULE = 13;
|
|
29
|
+
CSSOM.CSSRule.FONT_FEATURE_VALUES_RULE = 14;
|
|
30
|
+
CSSOM.CSSRule.VIEWPORT_RULE = 15;
|
|
31
|
+
CSSOM.CSSRule.REGION_STYLE_RULE = 16;
|
|
32
|
+
CSSOM.CSSRule.CONTAINER_RULE = 17;
|
|
33
|
+
CSSOM.CSSRule.LAYER_BLOCK_RULE = 18;
|
|
34
|
+
CSSOM.CSSRule.STARTING_STYLE_RULE = 1002;
|
|
35
|
+
|
|
15
36
|
Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
16
37
|
|
|
17
38
|
constructor: { value: CSSOM.CSSRule },
|
|
@@ -48,7 +69,7 @@ Object.defineProperties(CSSOM.CSSRule.prototype, {
|
|
|
48
69
|
CONTAINER_RULE: { value: 17, enumerable: true },
|
|
49
70
|
LAYER_BLOCK_RULE: { value: 18, enumerable: true },
|
|
50
71
|
STARTING_STYLE_RULE: { value: 1002, enumerable: true },
|
|
51
|
-
})
|
|
72
|
+
});
|
|
52
73
|
|
|
53
74
|
//.CommonJS
|
|
54
75
|
exports.CSSRule = CSSOM.CSSRule;
|
package/lib/CSSStyleRule.js
CHANGED
|
@@ -66,7 +66,7 @@ Object.defineProperty(CSSOM.CSSStyleRule.prototype, "cssText", {
|
|
|
66
66
|
valuesArr.push(this.cssRules.map(function(rule){ return rule.cssText }).join("\n "));
|
|
67
67
|
values = valuesArr.join("\n ") + "\n}"
|
|
68
68
|
} else {
|
|
69
|
-
values = " { " + this.style.cssText + " }";
|
|
69
|
+
values = " {" + (this.style.cssText ? " " + this.style.cssText : "") + " }";
|
|
70
70
|
}
|
|
71
71
|
text = this.selectorText + values;
|
|
72
72
|
} else {
|
package/lib/CSSStyleSheet.js
CHANGED
|
@@ -39,24 +39,112 @@ CSSOM.CSSStyleSheet.prototype.constructor = CSSOM.CSSStyleSheet;
|
|
|
39
39
|
*/
|
|
40
40
|
CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
41
41
|
if (rule === undefined && index === undefined) {
|
|
42
|
-
errorUtils.throwMissingArguments(this, 'insertRule',
|
|
42
|
+
errorUtils.throwMissingArguments(this, 'insertRule', this.constructor.name);
|
|
43
43
|
}
|
|
44
44
|
if (index === void 0) {
|
|
45
45
|
index = 0;
|
|
46
46
|
}
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
index = Number(index);
|
|
48
|
+
if (index < 0) {
|
|
49
|
+
index = 4294967296 + index;
|
|
50
|
+
}
|
|
51
|
+
if (index > this.cssRules.length) {
|
|
52
|
+
errorUtils.throwIndexError(this, 'insertRule', this.constructor.name, index, this.cssRules.length);
|
|
49
53
|
}
|
|
54
|
+
|
|
50
55
|
var ruleToParse = String(rule);
|
|
51
56
|
var parsedSheet = CSSOM.parse(ruleToParse);
|
|
52
57
|
if (parsedSheet.cssRules.length !== 1) {
|
|
53
|
-
|
|
54
|
-
if (ruleToParse.trimStart().startsWith('@namespace')) {
|
|
55
|
-
domExceptionName = "InvalidStateError";
|
|
56
|
-
}
|
|
57
|
-
errorUtils.throwParseError(this, 'insertRule', 'CSSStyleSheet', ruleToParse, domExceptionName);
|
|
58
|
+
errorUtils.throwParseError(this, 'insertRule', this.constructor.name, ruleToParse, 'SyntaxError');
|
|
58
59
|
}
|
|
59
60
|
var cssRule = parsedSheet.cssRules[0];
|
|
61
|
+
|
|
62
|
+
// Helper function to find the last index of a specific rule constructor
|
|
63
|
+
function findLastIndexOfConstructor(rules, constructorName) {
|
|
64
|
+
for (var i = rules.length - 1; i >= 0; i--) {
|
|
65
|
+
if (rules[i].constructor.name === constructorName) {
|
|
66
|
+
return i;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return -1;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Helper function to find the first index of a rule that's NOT of specified constructors
|
|
73
|
+
function findFirstNonConstructorIndex(rules, constructorNames) {
|
|
74
|
+
for (var i = 0; i < rules.length; i++) {
|
|
75
|
+
if (constructorNames.indexOf(rules[i].constructor.name) === -1) {
|
|
76
|
+
return i;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return rules.length;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Validate rule ordering based on CSS specification
|
|
83
|
+
if (cssRule.constructor.name === 'CSSImportRule') {
|
|
84
|
+
// @import rules cannot be inserted after @layer rules that already exist
|
|
85
|
+
// They can only be inserted at the beginning or after other @import rules
|
|
86
|
+
var firstLayerIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
|
|
87
|
+
if (firstLayerIndex < this.cssRules.length && this.cssRules[firstLayerIndex].constructor.name === 'CSSLayerStatementRule' && index > firstLayerIndex) {
|
|
88
|
+
errorUtils.throwError(this, 'DOMException',
|
|
89
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
90
|
+
'HierarchyRequestError');
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Also cannot insert after @namespace or other rules
|
|
94
|
+
var firstNonImportIndex = findFirstNonConstructorIndex(this.cssRules, ['CSSImportRule']);
|
|
95
|
+
if (index > firstNonImportIndex && firstNonImportIndex < this.cssRules.length &&
|
|
96
|
+
this.cssRules[firstNonImportIndex].constructor.name !== 'CSSLayerStatementRule') {
|
|
97
|
+
errorUtils.throwError(this, 'DOMException',
|
|
98
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
99
|
+
'HierarchyRequestError');
|
|
100
|
+
}
|
|
101
|
+
} else if (cssRule.constructor.name === 'CSSNamespaceRule') {
|
|
102
|
+
// @namespace rules can come after @layer and @import, but before any other rules
|
|
103
|
+
// They cannot come before @import rules
|
|
104
|
+
var firstImportIndex = -1;
|
|
105
|
+
for (var i = 0; i < this.cssRules.length; i++) {
|
|
106
|
+
if (this.cssRules[i].constructor.name === 'CSSImportRule') {
|
|
107
|
+
firstImportIndex = i;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
var firstNonImportNamespaceIndex = findFirstNonConstructorIndex(this.cssRules, [
|
|
112
|
+
'CSSLayerStatementRule',
|
|
113
|
+
'CSSImportRule',
|
|
114
|
+
'CSSNamespaceRule'
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
// Cannot insert before @import rules
|
|
118
|
+
if (firstImportIndex !== -1 && index <= firstImportIndex) {
|
|
119
|
+
errorUtils.throwError(this, 'DOMException',
|
|
120
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
121
|
+
'HierarchyRequestError');
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// Cannot insert after other types of rules
|
|
125
|
+
if (index > firstNonImportNamespaceIndex) {
|
|
126
|
+
errorUtils.throwError(this, 'DOMException',
|
|
127
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
128
|
+
'HierarchyRequestError');
|
|
129
|
+
}
|
|
130
|
+
} else if (cssRule.constructor.name === 'CSSLayerStatementRule') {
|
|
131
|
+
// @layer statement rules can be inserted anywhere before @import and @namespace
|
|
132
|
+
// No additional restrictions beyond what's already handled
|
|
133
|
+
} else {
|
|
134
|
+
// Any other rule cannot be inserted before @import and @namespace
|
|
135
|
+
var firstNonSpecialRuleIndex = findFirstNonConstructorIndex(this.cssRules, [
|
|
136
|
+
'CSSLayerStatementRule',
|
|
137
|
+
'CSSImportRule',
|
|
138
|
+
'CSSNamespaceRule'
|
|
139
|
+
]);
|
|
140
|
+
|
|
141
|
+
if (index < firstNonSpecialRuleIndex) {
|
|
142
|
+
errorUtils.throwError(this, 'DOMException',
|
|
143
|
+
"Failed to execute 'insertRule' on '" + this.constructor.name + "': Failed to insert the rule.",
|
|
144
|
+
'HierarchyRequestError');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
60
148
|
cssRule.__parentStyleSheet = this;
|
|
61
149
|
this.cssRules.splice(index, 0, cssRule);
|
|
62
150
|
return index;
|
|
@@ -78,21 +166,21 @@ CSSOM.CSSStyleSheet.prototype.insertRule = function(rule, index) {
|
|
|
78
166
|
*/
|
|
79
167
|
CSSOM.CSSStyleSheet.prototype.deleteRule = function(index) {
|
|
80
168
|
if (index === undefined) {
|
|
81
|
-
errorUtils.throwMissingArguments(this, 'deleteRule',
|
|
169
|
+
errorUtils.throwMissingArguments(this, 'deleteRule', this.constructor.name);
|
|
82
170
|
}
|
|
83
171
|
index = Number(index);
|
|
84
172
|
if (index < 0) {
|
|
85
173
|
index = 4294967296 + index;
|
|
86
174
|
}
|
|
87
175
|
if (index >= this.cssRules.length) {
|
|
88
|
-
errorUtils.throwIndexError(this, 'deleteRule',
|
|
176
|
+
errorUtils.throwIndexError(this, 'deleteRule', this.constructor.name, index, this.cssRules.length);
|
|
89
177
|
}
|
|
90
178
|
if (this.cssRules[index] && this.cssRules[index].constructor.name == "CSSNamespaceRule") {
|
|
91
179
|
var shouldContinue = this.cssRules.every(function (rule) {
|
|
92
180
|
return ['CSSImportRule','CSSLayerStatementRule','CSSNamespaceRule'].indexOf(rule.constructor.name) !== -1
|
|
93
181
|
});
|
|
94
182
|
if (!shouldContinue) {
|
|
95
|
-
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '
|
|
183
|
+
errorUtils.throwError(this, 'DOMException', "Failed to execute 'deleteRule' on '" + this.constructor.name + "': Failed to delete rule.", "InvalidStateError");
|
|
96
184
|
}
|
|
97
185
|
}
|
|
98
186
|
this.cssRules.splice(index, 1);
|
package/lib/errorUtils.js
CHANGED
|
@@ -2,27 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Gets the appropriate error constructor from the global object context.
|
|
5
|
-
* Tries to find the error constructor from parentStyleSheet.
|
|
6
|
-
* then from
|
|
5
|
+
* Tries to find the error constructor from parentStyleSheet.__globalObject,
|
|
6
|
+
* then from __globalObject, then falls back to the native constructor.
|
|
7
7
|
*
|
|
8
8
|
* @param {Object} context - The CSSOM object (rule, stylesheet, etc.)
|
|
9
9
|
* @param {string} errorType - The error type ('TypeError', 'RangeError', 'DOMException', etc.)
|
|
10
10
|
* @return {Function} The error constructor
|
|
11
11
|
*/
|
|
12
12
|
function getErrorConstructor(context, errorType) {
|
|
13
|
-
// Try parentStyleSheet.
|
|
14
|
-
if (context.parentStyleSheet && context.parentStyleSheet.
|
|
15
|
-
return context.parentStyleSheet.
|
|
13
|
+
// Try parentStyleSheet.__globalObject first
|
|
14
|
+
if (context.parentStyleSheet && context.parentStyleSheet.__globalObject && context.parentStyleSheet.__globalObject[errorType]) {
|
|
15
|
+
return context.parentStyleSheet.__globalObject[errorType];
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
// Try __parentStyleSheet (alternative naming)
|
|
19
|
-
if (context.__parentStyleSheet && context.__parentStyleSheet.
|
|
20
|
-
return context.__parentStyleSheet.
|
|
19
|
+
if (context.__parentStyleSheet && context.__parentStyleSheet.__globalObject && context.__parentStyleSheet.__globalObject[errorType]) {
|
|
20
|
+
return context.__parentStyleSheet.__globalObject[errorType];
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
// Try
|
|
24
|
-
if (context.
|
|
25
|
-
return context.
|
|
23
|
+
// Try __globalObject on the context itself
|
|
24
|
+
if (context.__globalObject && context.__globalObject[errorType]) {
|
|
25
|
+
return context.__globalObject[errorType];
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
// Fall back to native constructor
|
|
@@ -63,16 +63,6 @@ function throwMissingArguments(context, methodName, objectName, required, provid
|
|
|
63
63
|
throwError(context, 'TypeError', message);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
/**
|
|
67
|
-
* Throws a RangeError for index out of bounds.
|
|
68
|
-
*
|
|
69
|
-
* @param {Object} context - The CSSOM object
|
|
70
|
-
* @param {string} [message] - Optional custom message, defaults to 'INDEX_SIZE_ERR'
|
|
71
|
-
*/
|
|
72
|
-
function throwIndexSizeError(context, message) {
|
|
73
|
-
throwError(context, 'RangeError', message || 'INDEX_SIZE_ERR');
|
|
74
|
-
}
|
|
75
|
-
|
|
76
66
|
/**
|
|
77
67
|
* Throws a DOMException for parse errors.
|
|
78
68
|
*
|
|
@@ -108,7 +98,6 @@ var errorUtils = {
|
|
|
108
98
|
getErrorConstructor: getErrorConstructor,
|
|
109
99
|
throwError: throwError,
|
|
110
100
|
throwMissingArguments: throwMissingArguments,
|
|
111
|
-
throwIndexSizeError: throwIndexSizeError,
|
|
112
101
|
throwParseError: throwParseError,
|
|
113
102
|
throwIndexError: throwIndexError
|
|
114
103
|
};
|
package/lib/parse.js
CHANGED
|
@@ -4,10 +4,16 @@ var CSSOM = {};
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Parses a CSS string and returns a CSSOM.CSSStyleSheet object representing the parsed stylesheet.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} token - The CSS string to parse.
|
|
10
|
+
* @param {object} [opts] - Optional parsing options.
|
|
11
|
+
* @param {object} [opts.globalObject] - An optional global object to attach to the stylesheet. Useful on jsdom webplatform tests.
|
|
12
|
+
* @param {function|boolean} [errorHandler] - Optional error handler function or `true` to use `console.error`.
|
|
13
|
+
* @returns {CSSOM.CSSStyleSheet} The parsed CSSStyleSheet object.
|
|
8
14
|
*/
|
|
9
|
-
CSSOM.parse = function parse(token, errorHandler) {
|
|
10
|
-
errorHandler = errorHandler ===
|
|
15
|
+
CSSOM.parse = function parse(token, opts, errorHandler) {
|
|
16
|
+
errorHandler = errorHandler === true ? (console && console.error) : errorHandler;
|
|
11
17
|
|
|
12
18
|
var i = 0;
|
|
13
19
|
|
|
@@ -49,6 +55,10 @@ CSSOM.parse = function parse(token, errorHandler) {
|
|
|
49
55
|
|
|
50
56
|
var styleSheet = new CSSOM.CSSStyleSheet();
|
|
51
57
|
|
|
58
|
+
if (opts && opts.globalObject) {
|
|
59
|
+
styleSheet.__globalObject = opts.globalObject;
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
// @type CSSStyleSheet|CSSMediaRule|CSSContainerRule|CSSSupportsRule|CSSFontFaceRule|CSSKeyframesRule|CSSDocumentRule
|
|
53
63
|
var currentScope = styleSheet;
|
|
54
64
|
|
|
@@ -746,7 +756,7 @@ CSSOM.parse = function parse(token, errorHandler) {
|
|
|
746
756
|
i += "font-face".length;
|
|
747
757
|
fontFaceRule = new CSSOM.CSSFontFaceRule();
|
|
748
758
|
fontFaceRule.__starts = i;
|
|
749
|
-
},
|
|
759
|
+
}, true);
|
|
750
760
|
break;
|
|
751
761
|
} else {
|
|
752
762
|
atKeyframesRegExp.lastIndex = i;
|