@angular/platform-server 22.2.0-rc.0 → 22.2.1
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/fesm2022/_server-chunk.mjs +31 -20
- package/fesm2022/_server-chunk.mjs.map +1 -1
- package/fesm2022/init.mjs +1 -1
- package/fesm2022/platform-server.mjs +2 -2
- package/fesm2022/platform-server.mjs.map +1 -1
- package/fesm2022/testing.mjs +5 -5
- package/package.json +5 -5
- package/third_party/domino/bundled-domino.mjs +178 -81
- package/third_party/domino/bundled-domino.mjs.map +1 -1
- package/types/init.d.ts +1 -1
- package/types/platform-server.d.ts +1 -1
- package/types/testing.d.ts +1 -1
|
@@ -758,6 +758,18 @@ function requireNodeUtils () {
|
|
|
758
758
|
NOFRAMES: true
|
|
759
759
|
};
|
|
760
760
|
|
|
761
|
+
// HTML's *escapable raw text* elements (a.k.a. RCDATA). Unlike the raw-text
|
|
762
|
+
// elements above, their text content IS escaped for character references --
|
|
763
|
+
// but the element is still terminated only by its own closing tag. So any
|
|
764
|
+
// payload that we emit verbatim underneath one of them (comment data,
|
|
765
|
+
// processing-instruction data, or the serialization of a nested raw-content
|
|
766
|
+
// element) must have that closing tag escaped, or it breaks the element open.
|
|
767
|
+
// https://html.spec.whatwg.org/multipage/syntax.html#escapable-raw-text-elements
|
|
768
|
+
var hasEscapableRawContent = {
|
|
769
|
+
TEXTAREA: true,
|
|
770
|
+
TITLE: true
|
|
771
|
+
};
|
|
772
|
+
|
|
761
773
|
var emptyElements = {
|
|
762
774
|
area: true,
|
|
763
775
|
base: true,
|
|
@@ -779,14 +791,6 @@ function requireNodeUtils () {
|
|
|
779
791
|
wbr: true
|
|
780
792
|
};
|
|
781
793
|
|
|
782
|
-
var extraNewLine = {
|
|
783
|
-
/* Removed in https://github.com/whatwg/html/issues/944
|
|
784
|
-
pre: true,
|
|
785
|
-
textarea: true,
|
|
786
|
-
listing: true
|
|
787
|
-
*/
|
|
788
|
-
};
|
|
789
|
-
|
|
790
794
|
const ESCAPE_REGEXP = /[&<>\u00A0]/g;
|
|
791
795
|
const ESCAPE_ATTR_REGEXP = /[&"<>\u00A0]/g;
|
|
792
796
|
|
|
@@ -848,12 +852,22 @@ function requireNodeUtils () {
|
|
|
848
852
|
return a.name;
|
|
849
853
|
}
|
|
850
854
|
|
|
855
|
+
function serializedTagName(node) {
|
|
856
|
+
var ns = node.namespaceURI;
|
|
857
|
+
return (ns === NAMESPACE.HTML || ns === NAMESPACE.SVG || ns === NAMESPACE.MATHML)
|
|
858
|
+
? node.localName
|
|
859
|
+
: node.tagName;
|
|
860
|
+
}
|
|
861
|
+
|
|
851
862
|
function fallbackRawContentTags(node) {
|
|
852
863
|
const tags = [];
|
|
853
864
|
while (node) {
|
|
854
865
|
if (node.nodeType === 1 /*ELEMENT_NODE*/) {
|
|
855
|
-
|
|
856
|
-
|
|
866
|
+
const tagname = serializedTagName(node);
|
|
867
|
+
if (tagname &&
|
|
868
|
+
(hasRawContentFallback[tagname.toUpperCase()] ||
|
|
869
|
+
hasEscapableRawContent[tagname.toUpperCase()])) {
|
|
870
|
+
tags.push(tagname);
|
|
857
871
|
}
|
|
858
872
|
node = node.parentNode;
|
|
859
873
|
} else if (node.nodeType === 11 /*DOCUMENT_FRAGMENT_NODE*/ && node._host) {
|
|
@@ -996,7 +1010,7 @@ function requireNodeUtils () {
|
|
|
996
1010
|
case 1: //ELEMENT_NODE
|
|
997
1011
|
var ns = kid.namespaceURI;
|
|
998
1012
|
var html = ns === NAMESPACE.HTML;
|
|
999
|
-
var tagname = (
|
|
1013
|
+
var tagname = serializedTagName(kid);
|
|
1000
1014
|
|
|
1001
1015
|
s += '<' + tagname;
|
|
1002
1016
|
|
|
@@ -1019,7 +1033,6 @@ function requireNodeUtils () {
|
|
|
1019
1033
|
ss = escapeMatchingClosingTag(ss, fallbackTag);
|
|
1020
1034
|
}
|
|
1021
1035
|
}
|
|
1022
|
-
if (html && extraNewLine[tagname] && ss.charAt(0)==='\n') s += '\n';
|
|
1023
1036
|
// Serialize children and add end tag for all others
|
|
1024
1037
|
s += ss;
|
|
1025
1038
|
s += '</' + tagname + '>';
|
|
@@ -3058,6 +3071,9 @@ function requireSelect () {
|
|
|
3058
3071
|
return attr.indexOf(val) !== -1;
|
|
3059
3072
|
},
|
|
3060
3073
|
'~=': function(attr, val) {
|
|
3074
|
+
// An empty token never matches and would prevent the search from advancing.
|
|
3075
|
+
if (val === '') return false;
|
|
3076
|
+
|
|
3061
3077
|
var i
|
|
3062
3078
|
, s
|
|
3063
3079
|
, f
|
|
@@ -3174,7 +3190,14 @@ function requireSelect () {
|
|
|
3174
3190
|
*/
|
|
3175
3191
|
|
|
3176
3192
|
var rules = {
|
|
3177
|
-
escape
|
|
3193
|
+
// A hexadecimal escape takes the longest run of hex digits it can, up to six.
|
|
3194
|
+
// Spelling that as `[0-9A-Fa-f]{1,6}` also lets the engine hand digits back to
|
|
3195
|
+
// the `[-_a-zA-Z0-9]` branch of `cssid`, so `\aaa` has three readings and an
|
|
3196
|
+
// identifier built from n such runs has 3^n of them: a selector that ultimately
|
|
3197
|
+
// fails to parse costs exponential time. Pinning the run to either "exactly six"
|
|
3198
|
+
// or "fewer than six, and not followed by another hex digit" leaves a single
|
|
3199
|
+
// reading without changing which escapes are accepted.
|
|
3200
|
+
escape: /\\(?:[^0-9A-Fa-f\r\n]|(?:[0-9A-Fa-f]{6}|[0-9A-Fa-f]{1,5}(?![0-9A-Fa-f]))[\r\n\t ]?)/g,
|
|
3178
3201
|
str_escape: /(escape)|\\(\n|\r\n?|\f)/g,
|
|
3179
3202
|
nonascii: /[\u00A0-\uFFFF]/,
|
|
3180
3203
|
cssid: /(?:(?!-?[0-9])(?:escape|nonascii|[-_a-zA-Z0-9])+)/,
|
|
@@ -3184,7 +3207,15 @@ function requireSelect () {
|
|
|
3184
3207
|
combinator: /^(?: +([^ \w*.#\\]) +|( )+|([^ \w*.#\\]))(?! *$)/,
|
|
3185
3208
|
attr: /^\[(cssid)(?:([^\w]?=)(inside))?\]/,
|
|
3186
3209
|
pseudo: /^(:cssid)(?:\((inside)\))?/,
|
|
3187
|
-
|
|
3210
|
+
// Every alternative below is disjoint on its first character, so a value has
|
|
3211
|
+
// exactly one reading: `\` always starts an escape pair (the plain branch and
|
|
3212
|
+
// the in-string branch both exclude it) and `<` always opens a nested group.
|
|
3213
|
+
// Letting them overlap instead -- `\\["'>]` against `[^"'>]`, which also
|
|
3214
|
+
// matches a lone `\` -- gives `\"` two readings and a value of n of them 2^n,
|
|
3215
|
+
// the same exponential parse as `escape` above. The trailing `\\?` keeps a
|
|
3216
|
+
// lone backslash before the closing delimiter acceptable, as browsers do,
|
|
3217
|
+
// without putting that choice inside the loop.
|
|
3218
|
+
inside: /(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|<[^"'>]*>|\\[\s\S]|[^\\"'<>])*\\?/,
|
|
3188
3219
|
ident: /^(cssid)$/
|
|
3189
3220
|
};
|
|
3190
3221
|
|
|
@@ -3208,7 +3239,10 @@ function requireSelect () {
|
|
|
3208
3239
|
*/
|
|
3209
3240
|
|
|
3210
3241
|
var compile = function(sel_) {
|
|
3211
|
-
|
|
3242
|
+
// `String.prototype.trim` removes exactly the code points `\s` matches, but scans
|
|
3243
|
+
// instead of backtracking. `/^\s+|\s+$/g` makes `\s+$` retry from every position in
|
|
3244
|
+
// an interior whitespace run, which is quadratic in the length of that run.
|
|
3245
|
+
var sel = sel_.trim()
|
|
3212
3246
|
, test
|
|
3213
3247
|
, filter = []
|
|
3214
3248
|
, buff = []
|
|
@@ -3321,9 +3355,16 @@ function requireSelect () {
|
|
|
3321
3355
|
// attr value
|
|
3322
3356
|
if (cap[4]) {
|
|
3323
3357
|
var value = cap[6];
|
|
3324
|
-
|
|
3358
|
+
// `["'\s]\s*I$` is equivalent to `["'\s]I$`: when `\s*` takes anything at all, the
|
|
3359
|
+
// character before the `I` is itself whitespace and so satisfies `["'\s]` on its own.
|
|
3360
|
+
// The shorter spelling cannot retry from every position of a long whitespace run.
|
|
3361
|
+
var i = /["'\s]I$/i.test(value);
|
|
3325
3362
|
if (i) {
|
|
3326
|
-
|
|
3363
|
+
// Drop the `I` and the whitespace run immediately before it -- the same text
|
|
3364
|
+
// `/\s*I$/` matched, found by scanning back rather than by backtracking.
|
|
3365
|
+
var end = value.length - 1;
|
|
3366
|
+
while (end > 0 && /\s/.test(value.charAt(end - 1))) { end--; }
|
|
3367
|
+
value = value.slice(0, end);
|
|
3327
3368
|
}
|
|
3328
3369
|
return selectors.attr(decodeid(cap[4]), cap[5] || '-', unquote(value), i);
|
|
3329
3370
|
}
|
|
@@ -3733,7 +3774,8 @@ function requireElement () {
|
|
|
3733
3774
|
this._tagName = undefined;
|
|
3734
3775
|
|
|
3735
3776
|
// These properties maintain the set of attributes
|
|
3736
|
-
|
|
3777
|
+
// Map keeps numeric attribute names out of sparse object-index storage.
|
|
3778
|
+
this._attrsByQName = new Map(); // The qname->Attr map
|
|
3737
3779
|
this._attrsByLName = Object.create(null); // The ns|lname->Attr map
|
|
3738
3780
|
this._attrKeys = []; // attr index -> ns|lname
|
|
3739
3781
|
}
|
|
@@ -4239,7 +4281,7 @@ function requireElement () {
|
|
|
4239
4281
|
qname = String(qname);
|
|
4240
4282
|
if (/[A-Z]/.test(qname) && this.isHTML)
|
|
4241
4283
|
qname = utils.toASCIILowerCase(qname);
|
|
4242
|
-
var attr = this._attrsByQName
|
|
4284
|
+
var attr = this._attrsByQName.get(qname);
|
|
4243
4285
|
if (!attr) return null;
|
|
4244
4286
|
|
|
4245
4287
|
if (Array.isArray(attr)) // If there is more than one
|
|
@@ -4259,7 +4301,7 @@ function requireElement () {
|
|
|
4259
4301
|
qname = String(qname);
|
|
4260
4302
|
if (/[A-Z]/.test(qname) && this.isHTML)
|
|
4261
4303
|
qname = utils.toASCIILowerCase(qname);
|
|
4262
|
-
return this._attrsByQName
|
|
4304
|
+
return this._attrsByQName.has(qname);
|
|
4263
4305
|
}},
|
|
4264
4306
|
|
|
4265
4307
|
hasAttributeNS: { value: function hasAttributeNS(ns, lname) {
|
|
@@ -4278,7 +4320,7 @@ function requireElement () {
|
|
|
4278
4320
|
if (!xml.isValidName(qname)) utils.InvalidCharacterError();
|
|
4279
4321
|
if (/[A-Z]/.test(qname) && this.isHTML)
|
|
4280
4322
|
qname = utils.toASCIILowerCase(qname);
|
|
4281
|
-
var a = this._attrsByQName
|
|
4323
|
+
var a = this._attrsByQName.get(qname);
|
|
4282
4324
|
if (a === undefined) {
|
|
4283
4325
|
if (force === undefined || force === true) {
|
|
4284
4326
|
this._setAttribute(qname, '');
|
|
@@ -4299,7 +4341,7 @@ function requireElement () {
|
|
|
4299
4341
|
// XXX: the spec says that this next search should be done
|
|
4300
4342
|
// on the local name, but I think that is an error.
|
|
4301
4343
|
// email pending on www-dom about it.
|
|
4302
|
-
var attr = this._attrsByQName
|
|
4344
|
+
var attr = this._attrsByQName.get(qname);
|
|
4303
4345
|
var isnew;
|
|
4304
4346
|
if (!attr) {
|
|
4305
4347
|
attr = this._newattr(qname);
|
|
@@ -4312,7 +4354,7 @@ function requireElement () {
|
|
|
4312
4354
|
// Now set the attribute value on the new or existing Attr object.
|
|
4313
4355
|
// The Attr.value setter method handles mutation events, etc.
|
|
4314
4356
|
attr.value = value;
|
|
4315
|
-
|
|
4357
|
+
setNamedProperty(this._attributes, qname, attr);
|
|
4316
4358
|
if (isnew && this._newattrhook) this._newattrhook(qname, value);
|
|
4317
4359
|
}},
|
|
4318
4360
|
|
|
@@ -4387,7 +4429,7 @@ function requireElement () {
|
|
|
4387
4429
|
utils.InUseAttributeError();
|
|
4388
4430
|
}
|
|
4389
4431
|
var result = null;
|
|
4390
|
-
var oldAttrs = this._attrsByQName
|
|
4432
|
+
var oldAttrs = this._attrsByQName.get(attr.name);
|
|
4391
4433
|
if (oldAttrs) {
|
|
4392
4434
|
if (!Array.isArray(oldAttrs)) { oldAttrs = [ oldAttrs ]; }
|
|
4393
4435
|
if (oldAttrs.some(function(a) { return a===attr; })) {
|
|
@@ -4426,7 +4468,7 @@ function requireElement () {
|
|
|
4426
4468
|
if (/[A-Z]/.test(qname) && this.isHTML)
|
|
4427
4469
|
qname = utils.toASCIILowerCase(qname);
|
|
4428
4470
|
|
|
4429
|
-
var attr = this._attrsByQName
|
|
4471
|
+
var attr = this._attrsByQName.get(qname);
|
|
4430
4472
|
if (!attr) return;
|
|
4431
4473
|
|
|
4432
4474
|
// If there is more than one match for this qname
|
|
@@ -4437,13 +4479,13 @@ function requireElement () {
|
|
|
4437
4479
|
attr = attr.shift(); // remove it from the array
|
|
4438
4480
|
}
|
|
4439
4481
|
else {
|
|
4440
|
-
this._attrsByQName
|
|
4482
|
+
this._attrsByQName.set(qname, attr[1]);
|
|
4441
4483
|
attr = attr[0];
|
|
4442
4484
|
}
|
|
4443
4485
|
}
|
|
4444
4486
|
else {
|
|
4445
4487
|
// only a single match, so remove the qname mapping
|
|
4446
|
-
this._attrsByQName
|
|
4488
|
+
this._attrsByQName.delete(qname);
|
|
4447
4489
|
}
|
|
4448
4490
|
|
|
4449
4491
|
var ns = attr.namespaceURI;
|
|
@@ -4455,7 +4497,7 @@ function requireElement () {
|
|
|
4455
4497
|
var i = this._attrKeys.indexOf(key);
|
|
4456
4498
|
if (this._attributes) {
|
|
4457
4499
|
Array.prototype.splice.call(this._attributes, i, 1);
|
|
4458
|
-
this._attributes
|
|
4500
|
+
setNamedProperty(this._attributes, qname, undefined);
|
|
4459
4501
|
}
|
|
4460
4502
|
this._attrKeys.splice(i, 1);
|
|
4461
4503
|
|
|
@@ -4524,20 +4566,20 @@ function requireElement () {
|
|
|
4524
4566
|
// prefix will never have two matching Attr objects (because
|
|
4525
4567
|
// setAttributeNS doesn't allow a non-null namespace with a
|
|
4526
4568
|
// null prefix.
|
|
4527
|
-
var attr = this._attrsByQName
|
|
4569
|
+
var attr = this._attrsByQName.get(qname);
|
|
4528
4570
|
return attr ? attr.value : null;
|
|
4529
4571
|
}},
|
|
4530
4572
|
|
|
4531
4573
|
// The raw version of setAttribute for reflected idl attributes.
|
|
4532
4574
|
_setattr: { value: function _setattr(qname, value) {
|
|
4533
|
-
var attr = this._attrsByQName
|
|
4575
|
+
var attr = this._attrsByQName.get(qname);
|
|
4534
4576
|
var isnew;
|
|
4535
4577
|
if (!attr) {
|
|
4536
4578
|
attr = this._newattr(qname);
|
|
4537
4579
|
isnew = true;
|
|
4538
4580
|
}
|
|
4539
4581
|
attr.value = String(value);
|
|
4540
|
-
|
|
4582
|
+
setNamedProperty(this._attributes, qname, attr);
|
|
4541
4583
|
if (isnew && this._newattrhook) this._newattrhook(qname, value);
|
|
4542
4584
|
}},
|
|
4543
4585
|
|
|
@@ -4546,7 +4588,7 @@ function requireElement () {
|
|
|
4546
4588
|
_newattr: { value: function _newattr(qname) {
|
|
4547
4589
|
var attr = new Attr(this, qname, null, null);
|
|
4548
4590
|
var key = '|' + qname;
|
|
4549
|
-
this._attrsByQName
|
|
4591
|
+
this._attrsByQName.set(qname, attr);
|
|
4550
4592
|
this._attrsByLName[key] = attr;
|
|
4551
4593
|
if (this._attributes) {
|
|
4552
4594
|
this._attributes[this._attrKeys.length] = attr;
|
|
@@ -4555,52 +4597,48 @@ function requireElement () {
|
|
|
4555
4597
|
return attr;
|
|
4556
4598
|
}},
|
|
4557
4599
|
|
|
4558
|
-
// Add a qname->Attr mapping to the _attrsByQName
|
|
4600
|
+
// Add a qname->Attr mapping to the _attrsByQName map, taking into
|
|
4559
4601
|
// account that there may be more than one attr object with the
|
|
4560
4602
|
// same qname
|
|
4561
4603
|
_addQName: { value: function(attr) {
|
|
4562
4604
|
var qname = attr.name;
|
|
4563
|
-
var existing = this._attrsByQName
|
|
4605
|
+
var existing = this._attrsByQName.get(qname);
|
|
4564
4606
|
if (!existing) {
|
|
4565
|
-
this._attrsByQName
|
|
4607
|
+
this._attrsByQName.set(qname, attr);
|
|
4566
4608
|
}
|
|
4567
4609
|
else if (Array.isArray(existing)) {
|
|
4568
4610
|
existing.push(attr);
|
|
4569
4611
|
}
|
|
4570
4612
|
else {
|
|
4571
|
-
this._attrsByQName
|
|
4613
|
+
this._attrsByQName.set(qname, [existing, attr]);
|
|
4572
4614
|
}
|
|
4573
|
-
|
|
4615
|
+
setNamedProperty(this._attributes, qname, attr);
|
|
4574
4616
|
}},
|
|
4575
4617
|
|
|
4576
|
-
// Remove a qname->Attr mapping
|
|
4618
|
+
// Remove a qname->Attr mapping from the _attrsByQName map, taking into
|
|
4577
4619
|
// account that there may be more than one attr object with the
|
|
4578
4620
|
// same qname
|
|
4579
4621
|
_removeQName: { value: function(attr) {
|
|
4580
4622
|
var qname = attr.name;
|
|
4581
|
-
var target = this._attrsByQName
|
|
4623
|
+
var target = this._attrsByQName.get(qname);
|
|
4582
4624
|
|
|
4583
4625
|
if (Array.isArray(target)) {
|
|
4584
4626
|
var idx = target.indexOf(attr);
|
|
4585
4627
|
utils.assert(idx !== -1); // It must be here somewhere
|
|
4586
4628
|
if (target.length === 2) {
|
|
4587
|
-
this._attrsByQName
|
|
4588
|
-
|
|
4589
|
-
this._attributes[qname] = this._attrsByQName[qname];
|
|
4590
|
-
}
|
|
4629
|
+
this._attrsByQName.set(qname, target[1-idx]);
|
|
4630
|
+
setNamedProperty(this._attributes, qname, this._attrsByQName.get(qname));
|
|
4591
4631
|
} else {
|
|
4592
4632
|
target.splice(idx, 1);
|
|
4593
4633
|
if (this._attributes && this._attributes[qname] === attr) {
|
|
4594
|
-
this._attributes
|
|
4634
|
+
setNamedProperty(this._attributes, qname, target[0]);
|
|
4595
4635
|
}
|
|
4596
4636
|
}
|
|
4597
4637
|
}
|
|
4598
4638
|
else {
|
|
4599
4639
|
utils.assert(target === attr); // If only one, it must match
|
|
4600
|
-
this._attrsByQName
|
|
4601
|
-
|
|
4602
|
-
this._attributes[qname] = undefined;
|
|
4603
|
-
}
|
|
4640
|
+
this._attrsByQName.delete(qname);
|
|
4641
|
+
setNamedProperty(this._attributes, qname, undefined);
|
|
4604
4642
|
}
|
|
4605
4643
|
}},
|
|
4606
4644
|
|
|
@@ -4782,15 +4820,30 @@ function requireElement () {
|
|
|
4782
4820
|
// Sneakily export this class for use by Document.createAttribute()
|
|
4783
4821
|
Element._Attr = Attr;
|
|
4784
4822
|
|
|
4823
|
+
// WebIDL reserves array indices for indexed access, even outside the list.
|
|
4824
|
+
// Mirroring numeric names would also create sparse object-index storage.
|
|
4825
|
+
function isArrayIndex(qname) {
|
|
4826
|
+
if (qname.length > 10) { return false; }
|
|
4827
|
+
var index = qname >>> 0;
|
|
4828
|
+
// Reject noncanonical spellings and 2^32-1, which is not an array index.
|
|
4829
|
+
return index !== 0xFFFFFFFF && String(index) === qname;
|
|
4830
|
+
}
|
|
4831
|
+
|
|
4832
|
+
// Mirror a qname->Attr mapping onto an already-created NamedNodeMap.
|
|
4833
|
+
function setNamedProperty(attributes, qname, attr) {
|
|
4834
|
+
if (attributes && !isArrayIndex(qname)) { attributes[qname] = attr; }
|
|
4835
|
+
}
|
|
4836
|
+
|
|
4785
4837
|
// The attributes property of an Element will be an instance of this class.
|
|
4786
4838
|
// This class is really just a dummy, though. It only defines a length
|
|
4787
4839
|
// property and an item() method. The AttrArrayProxy that
|
|
4788
4840
|
// defines the public API just uses the Element object itself.
|
|
4789
4841
|
function AttributesArray(elt) {
|
|
4790
4842
|
NamedNodeMap.call(this, elt);
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4843
|
+
var self = this;
|
|
4844
|
+
elt._attrsByQName.forEach(function(attr, qname) {
|
|
4845
|
+
setNamedProperty(self, qname, attr);
|
|
4846
|
+
});
|
|
4794
4847
|
for (var i = 0; i < elt._attrKeys.length; i++) {
|
|
4795
4848
|
this[i] = elt._attrsByLName[elt._attrKeys[i]];
|
|
4796
4849
|
}
|
|
@@ -8698,7 +8751,18 @@ function requireDocument () {
|
|
|
8698
8751
|
// We may need to update this mapping every time a node is rooted
|
|
8699
8752
|
// or uprooted, and any time an attribute is added, removed or changed
|
|
8700
8753
|
// on a rooted element.
|
|
8701
|
-
|
|
8754
|
+
//
|
|
8755
|
+
// The mapping is built lazily: it stays null until something actually
|
|
8756
|
+
// looks an element up by id, and only then is it populated from the
|
|
8757
|
+
// nodes currently rooted in this document. After that it is kept up to
|
|
8758
|
+
// date by root()/uproot() and by the id attribute change handler, just as
|
|
8759
|
+
// it always was. Documents that are never queried by id -- in particular
|
|
8760
|
+
// the private documents the fragment parser creates and throws away for
|
|
8761
|
+
// every innerHTML assignment -- no longer pay for an index nobody reads.
|
|
8762
|
+
//
|
|
8763
|
+
// A Map keeps ids such as `1023` out of sparse object-index storage, the
|
|
8764
|
+
// same reason Element uses one for qualified attribute names.
|
|
8765
|
+
this._byId = null;
|
|
8702
8766
|
|
|
8703
8767
|
// This property holds a monotonically increasing value akin to
|
|
8704
8768
|
// a timestamp used to record the last modification time of nodes
|
|
@@ -8966,7 +9030,9 @@ function requireDocument () {
|
|
|
8966
9030
|
}},
|
|
8967
9031
|
|
|
8968
9032
|
getElementById: { value: function(id) {
|
|
8969
|
-
|
|
9033
|
+
// Coercion can mutate the document, so do it before building the index.
|
|
9034
|
+
id = String(id);
|
|
9035
|
+
var n = this._idIndex().get(id);
|
|
8970
9036
|
if (!n) return null;
|
|
8971
9037
|
if (n instanceof MultiId) { // there was more than one element with this id
|
|
8972
9038
|
return n.getFirst();
|
|
@@ -8976,7 +9042,29 @@ function requireDocument () {
|
|
|
8976
9042
|
|
|
8977
9043
|
_hasMultipleElementsWithId: { value: function(id) {
|
|
8978
9044
|
// Used internally by querySelectorAll optimization
|
|
8979
|
-
return (this.
|
|
9045
|
+
return (this._idIndex().get(id) instanceof MultiId);
|
|
9046
|
+
}},
|
|
9047
|
+
|
|
9048
|
+
// The id -> element map, materialized on demand. Everything that reads the
|
|
9049
|
+
// index goes through here; everything that writes it (addId/delId) leaves it
|
|
9050
|
+
// alone while it is absent.
|
|
9051
|
+
_idIndex: { value: function _idIndex() {
|
|
9052
|
+
var byId = this._byId;
|
|
9053
|
+
if (byId !== null) return byId;
|
|
9054
|
+
byId = this._byId = new Map();
|
|
9055
|
+
// Populate from the elements rooted in this document right now. _nodes
|
|
9056
|
+
// is the registry root() and uproot() maintain, so walking it -- rather
|
|
9057
|
+
// than the tree -- gives exactly the entries the index would hold had it
|
|
9058
|
+
// been kept up to date all along, and needs no traversal state.
|
|
9059
|
+
var nodes = this._nodes;
|
|
9060
|
+
for (var nid = 1, end = this._nextnid; nid < end; nid++) {
|
|
9061
|
+
var n = nodes[nid];
|
|
9062
|
+
if (n !== undefined && n.nodeType === Node.ELEMENT_NODE) {
|
|
9063
|
+
var id = n.getAttributeNS(null, 'id');
|
|
9064
|
+
if (id) this.addId(id, n);
|
|
9065
|
+
}
|
|
9066
|
+
}
|
|
9067
|
+
return byId;
|
|
8980
9068
|
}},
|
|
8981
9069
|
|
|
8982
9070
|
// Just copy this method from the Element prototype
|
|
@@ -9269,16 +9357,18 @@ function requireDocument () {
|
|
|
9269
9357
|
|
|
9270
9358
|
// Add a mapping from id to n for n.ownerDocument
|
|
9271
9359
|
addId: { value: function addId(id, n) {
|
|
9272
|
-
var
|
|
9360
|
+
var byId = this._byId;
|
|
9361
|
+
if (byId === null) return; // no index yet; it will pick n up when built
|
|
9362
|
+
var val = byId.get(id);
|
|
9273
9363
|
if (!val) {
|
|
9274
|
-
|
|
9364
|
+
byId.set(id, n);
|
|
9275
9365
|
}
|
|
9276
9366
|
else {
|
|
9277
9367
|
// TODO: Add a way to opt-out console warnings
|
|
9278
9368
|
//console.warn('Duplicate element id ' + id);
|
|
9279
9369
|
if (!(val instanceof MultiId)) {
|
|
9280
9370
|
val = new MultiId(val);
|
|
9281
|
-
|
|
9371
|
+
byId.set(id, val);
|
|
9282
9372
|
}
|
|
9283
9373
|
val.add(n);
|
|
9284
9374
|
}
|
|
@@ -9286,17 +9376,19 @@ function requireDocument () {
|
|
|
9286
9376
|
|
|
9287
9377
|
// Delete the mapping from id to n for n.ownerDocument
|
|
9288
9378
|
delId: { value: function delId(id, n) {
|
|
9289
|
-
var
|
|
9379
|
+
var byId = this._byId;
|
|
9380
|
+
if (byId === null) return; // no index yet; nothing to remove n from
|
|
9381
|
+
var val = byId.get(id);
|
|
9290
9382
|
utils.assert(val);
|
|
9291
9383
|
|
|
9292
9384
|
if (val instanceof MultiId) {
|
|
9293
9385
|
val.del(n);
|
|
9294
9386
|
if (val.length === 1) { // convert back to a single node
|
|
9295
|
-
|
|
9387
|
+
byId.set(id, val.downgrade());
|
|
9296
9388
|
}
|
|
9297
9389
|
}
|
|
9298
9390
|
else {
|
|
9299
|
-
|
|
9391
|
+
byId.delete(id);
|
|
9300
9392
|
}
|
|
9301
9393
|
}},
|
|
9302
9394
|
|
|
@@ -9412,8 +9504,10 @@ function requireDocument () {
|
|
|
9412
9504
|
n.ownerDocument._nodes[n._nid] = n;
|
|
9413
9505
|
// Manage id to element mapping
|
|
9414
9506
|
if (n.nodeType === Node.ELEMENT_NODE) {
|
|
9415
|
-
|
|
9416
|
-
|
|
9507
|
+
if (n.ownerDocument._byId !== null) {
|
|
9508
|
+
var id = n.getAttributeNS(null, 'id');
|
|
9509
|
+
if (id) n.ownerDocument.addId(id, n);
|
|
9510
|
+
}
|
|
9417
9511
|
|
|
9418
9512
|
// Script elements need to know when they're inserted
|
|
9419
9513
|
// into the document
|
|
@@ -9423,8 +9517,8 @@ function requireDocument () {
|
|
|
9423
9517
|
|
|
9424
9518
|
function uproot(n) {
|
|
9425
9519
|
// Manage id to element mapping
|
|
9426
|
-
if (n.nodeType === Node.ELEMENT_NODE) {
|
|
9427
|
-
var id = n.
|
|
9520
|
+
if (n.nodeType === Node.ELEMENT_NODE && n.ownerDocument._byId !== null) {
|
|
9521
|
+
var id = n.getAttributeNS(null, 'id');
|
|
9428
9522
|
if (id) n.ownerDocument.delId(id, n);
|
|
9429
9523
|
}
|
|
9430
9524
|
n.ownerDocument._nodes[n._nid] = undefined;
|
|
@@ -9467,18 +9561,23 @@ function requireDocument () {
|
|
|
9467
9561
|
recursivelySetOwner(kid, owner);
|
|
9468
9562
|
}
|
|
9469
9563
|
|
|
9470
|
-
// A class for storing multiple nodes with the same ID
|
|
9564
|
+
// A class for storing multiple nodes with the same ID.
|
|
9565
|
+
//
|
|
9566
|
+
// A Map keeps the node ids used as keys out of sparse object-index storage:
|
|
9567
|
+
// a plain object keyed by integers gets an elements backing store sized to
|
|
9568
|
+
// the largest key, which for node ids means one as large as the document for
|
|
9569
|
+
// every id that is duplicated.
|
|
9471
9570
|
function MultiId(node) {
|
|
9472
|
-
this.nodes =
|
|
9473
|
-
this.nodes
|
|
9571
|
+
this.nodes = new Map();
|
|
9572
|
+
this.nodes.set(node._nid, node);
|
|
9474
9573
|
this.length = 1;
|
|
9475
9574
|
this.firstNode = undefined;
|
|
9476
9575
|
}
|
|
9477
9576
|
|
|
9478
9577
|
// Add a node to the list, with O(1) time
|
|
9479
9578
|
MultiId.prototype.add = function(node) {
|
|
9480
|
-
if (!this.nodes
|
|
9481
|
-
this.nodes
|
|
9579
|
+
if (!this.nodes.has(node._nid)) {
|
|
9580
|
+
this.nodes.set(node._nid, node);
|
|
9482
9581
|
this.length++;
|
|
9483
9582
|
this.firstNode = undefined;
|
|
9484
9583
|
}
|
|
@@ -9486,8 +9585,7 @@ function requireDocument () {
|
|
|
9486
9585
|
|
|
9487
9586
|
// Remove a node from the list, with O(1) time
|
|
9488
9587
|
MultiId.prototype.del = function(node) {
|
|
9489
|
-
if (this.nodes
|
|
9490
|
-
delete this.nodes[node._nid];
|
|
9588
|
+
if (this.nodes.delete(node._nid)) {
|
|
9491
9589
|
this.length--;
|
|
9492
9590
|
this.firstNode = undefined;
|
|
9493
9591
|
}
|
|
@@ -9499,13 +9597,13 @@ function requireDocument () {
|
|
|
9499
9597
|
MultiId.prototype.getFirst = function() {
|
|
9500
9598
|
/* jshint bitwise: false */
|
|
9501
9599
|
if (!this.firstNode) {
|
|
9502
|
-
var
|
|
9503
|
-
|
|
9504
|
-
if (
|
|
9505
|
-
|
|
9506
|
-
|
|
9600
|
+
var self = this;
|
|
9601
|
+
this.nodes.forEach(function(node) {
|
|
9602
|
+
if (self.firstNode === undefined ||
|
|
9603
|
+
self.firstNode.compareDocumentPosition(node) & Node.DOCUMENT_POSITION_PRECEDING) {
|
|
9604
|
+
self.firstNode = node;
|
|
9507
9605
|
}
|
|
9508
|
-
}
|
|
9606
|
+
});
|
|
9509
9607
|
}
|
|
9510
9608
|
return this.firstNode;
|
|
9511
9609
|
};
|
|
@@ -9513,10 +9611,7 @@ function requireDocument () {
|
|
|
9513
9611
|
// If there is only one node left, return it. Otherwise return "this".
|
|
9514
9612
|
MultiId.prototype.downgrade = function() {
|
|
9515
9613
|
if (this.length === 1) {
|
|
9516
|
-
|
|
9517
|
-
for (nid in this.nodes) {
|
|
9518
|
-
return this.nodes[nid];
|
|
9519
|
-
}
|
|
9614
|
+
return this.nodes.values().next().value;
|
|
9520
9615
|
}
|
|
9521
9616
|
return this;
|
|
9522
9617
|
};
|
|
@@ -11437,6 +11532,8 @@ function requireHTMLParser () {
|
|
|
11437
11532
|
for(var i = 0, n = oldattrs.length; i < n; i++) {
|
|
11438
11533
|
var oldname = oldattrs[i][0];
|
|
11439
11534
|
var oldval = oldattrs[i][1];
|
|
11535
|
+
// Bare attributes have an empty string value in the DOM.
|
|
11536
|
+
if (oldval === undefined) oldval = "";
|
|
11440
11537
|
if (!newelt.hasAttribute(oldname)) return false;
|
|
11441
11538
|
if (newelt.getAttribute(oldname) !== oldval) return false;
|
|
11442
11539
|
}
|