@mml-io/networked-dom-web 0.25.0 → 0.26.0
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/DOMSanitizer.d.ts +21 -3
- package/build/DOMSanitizer.d.ts.map +1 -1
- package/build/DocumentInterface.d.ts +84 -0
- package/build/DocumentInterface.d.ts.map +1 -0
- package/build/ElementUtils.d.ts +5 -4
- package/build/ElementUtils.d.ts.map +1 -1
- package/build/NetworkedDOMWebsocket.d.ts +7 -9
- package/build/NetworkedDOMWebsocket.d.ts.map +1 -1
- package/build/NetworkedDOMWebsocketAdapterBase.d.ts +52 -0
- package/build/NetworkedDOMWebsocketAdapterBase.d.ts.map +1 -0
- package/build/NetworkedDOMWebsocketV01Adapter.d.ts +6 -16
- package/build/NetworkedDOMWebsocketV01Adapter.d.ts.map +1 -1
- package/build/NetworkedDOMWebsocketV02Adapter.d.ts +7 -15
- package/build/NetworkedDOMWebsocketV02Adapter.d.ts.map +1 -1
- package/build/PortalUtils.d.ts +31 -0
- package/build/PortalUtils.d.ts.map +1 -0
- package/build/index.d.ts +3 -0
- package/build/index.d.ts.map +1 -1
- package/build/index.js +416 -258
- package/build/index.js.map +4 -4
- package/package.json +3 -3
package/build/index.js
CHANGED
|
@@ -1,49 +1,93 @@
|
|
|
1
|
+
// src/DocumentInterface.ts
|
|
2
|
+
var VIRTUAL_ELEMENT_BRAND = /* @__PURE__ */ Symbol.for("mml-virtual-element");
|
|
3
|
+
var VIRTUAL_TEXT_BRAND = /* @__PURE__ */ Symbol.for("mml-virtual-text");
|
|
4
|
+
var VIRTUAL_DOCUMENT_BRAND = /* @__PURE__ */ Symbol.for("mml-virtual-document");
|
|
5
|
+
var VIRTUAL_FRAGMENT_BRAND = /* @__PURE__ */ Symbol.for("mml-virtual-fragment");
|
|
6
|
+
function isElementLike(node) {
|
|
7
|
+
return typeof node.setAttribute === "function";
|
|
8
|
+
}
|
|
9
|
+
function isPortalElement(element) {
|
|
10
|
+
return typeof element.getPortalElement === "function";
|
|
11
|
+
}
|
|
12
|
+
|
|
1
13
|
// src/DOMSanitizer.ts
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
14
|
+
var _DOMSanitizer = class _DOMSanitizer {
|
|
15
|
+
/**
|
|
16
|
+
* Returns true if a tag with the given name should be stripped of all
|
|
17
|
+
* content and attributes during sanitisation.
|
|
18
|
+
*/
|
|
19
|
+
static isBlockedTag(tagName) {
|
|
20
|
+
return _DOMSanitizer.BLOCKED_TAGS.has(tagName.toLowerCase());
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Given a tag name and sanitisation options, returns the sanitised tag name.
|
|
24
|
+
* Non-prefixed tags are renamed (e.g. "div" → "x-div"). Returns null for
|
|
25
|
+
* blocked tags that should be skipped entirely.
|
|
26
|
+
*/
|
|
27
|
+
static sanitiseTagName(tagName, options) {
|
|
28
|
+
const tag = tagName.toLowerCase();
|
|
29
|
+
if (_DOMSanitizer.isBlockedTag(tag)) {
|
|
30
|
+
return null;
|
|
10
31
|
}
|
|
11
|
-
if (
|
|
12
|
-
|
|
13
|
-
const tag = node.nodeName.toLowerCase();
|
|
14
|
-
if (!tag.startsWith(options.tagPrefix.toLowerCase())) {
|
|
15
|
-
node = _DOMSanitizer.replaceNodeTagName(
|
|
16
|
-
node,
|
|
17
|
-
options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`
|
|
18
|
-
);
|
|
19
|
-
}
|
|
20
|
-
}
|
|
32
|
+
if (options.tagPrefix && !tag.startsWith(options.tagPrefix.toLowerCase())) {
|
|
33
|
+
return (options.replacementTagPrefix ?? "x-") + tag;
|
|
21
34
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
35
|
+
return tag;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Sanitises a DOM node in-place. When tag replacement occurs (via tagPrefix option),
|
|
39
|
+
* the returned node may be a different object than the input node.
|
|
40
|
+
*/
|
|
41
|
+
static sanitise(node, options = {}, doc) {
|
|
42
|
+
if (_DOMSanitizer.isBlockedTag(node.nodeName)) {
|
|
43
|
+
if (isElementLike(node)) {
|
|
44
|
+
node.innerHTML = "";
|
|
45
|
+
_DOMSanitizer.stripAllAttributes(node);
|
|
46
|
+
}
|
|
25
47
|
} else {
|
|
26
|
-
if (node
|
|
27
|
-
|
|
48
|
+
if (isElementLike(node)) {
|
|
49
|
+
let element = node;
|
|
50
|
+
for (const attr of element.getAttributeNames()) {
|
|
51
|
+
if (!_DOMSanitizer.IsValidAttributeName(attr)) {
|
|
52
|
+
element.removeAttribute(attr);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (options.tagPrefix) {
|
|
56
|
+
const tag = element.nodeName.toLowerCase();
|
|
57
|
+
if (!tag.startsWith(options.tagPrefix.toLowerCase())) {
|
|
58
|
+
element = _DOMSanitizer.replaceNodeTagName(
|
|
59
|
+
element,
|
|
60
|
+
(options.replacementTagPrefix ?? "x-") + tag,
|
|
61
|
+
doc
|
|
62
|
+
);
|
|
63
|
+
node = element;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
for (const attr of element.getAttributeNames()) {
|
|
28
67
|
if (!_DOMSanitizer.shouldAcceptAttribute(attr)) {
|
|
29
|
-
|
|
68
|
+
element.removeAttribute(attr);
|
|
30
69
|
}
|
|
31
70
|
}
|
|
32
71
|
}
|
|
33
72
|
for (let i = 0; i < node.childNodes.length; i++) {
|
|
34
|
-
_DOMSanitizer.sanitise(node.childNodes[i], options);
|
|
73
|
+
_DOMSanitizer.sanitise(node.childNodes[i], options, doc);
|
|
35
74
|
}
|
|
36
75
|
}
|
|
37
76
|
return node;
|
|
38
77
|
}
|
|
39
|
-
static replaceNodeTagName(node, newTagName) {
|
|
78
|
+
static replaceNodeTagName(node, newTagName, doc) {
|
|
40
79
|
var _a;
|
|
41
|
-
|
|
42
|
-
|
|
80
|
+
if (!doc && typeof document === "undefined") {
|
|
81
|
+
throw new Error(
|
|
82
|
+
"DOMSanitizer.replaceNodeTagName requires a document factory (IDocumentFactory) in non-browser environments"
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
const docFactory = doc ?? document;
|
|
86
|
+
const replacementNode = docFactory.createElement(newTagName);
|
|
43
87
|
while (node.firstChild) {
|
|
44
88
|
replacementNode.appendChild(node.firstChild);
|
|
45
89
|
}
|
|
46
|
-
for (index = node.attributes.length - 1; index >= 0; --index) {
|
|
90
|
+
for (let index = node.attributes.length - 1; index >= 0; --index) {
|
|
47
91
|
replacementNode.setAttribute(node.attributes[index].name, node.attributes[index].value);
|
|
48
92
|
}
|
|
49
93
|
(_a = node.parentNode) == null ? void 0 : _a.replaceChild(replacementNode, node);
|
|
@@ -83,13 +127,9 @@ var DOMSanitizer = class _DOMSanitizer {
|
|
|
83
127
|
return !attribute.startsWith("on");
|
|
84
128
|
}
|
|
85
129
|
};
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
isNetworkedDOMProtocolSubProtocol_v0_2,
|
|
90
|
-
networkedDOMProtocolSubProtocol_v0_1,
|
|
91
|
-
networkedDOMProtocolSubProtocol_v0_2_SubVersionsList
|
|
92
|
-
} from "@mml-io/networked-dom-protocol";
|
|
130
|
+
/** Tags whose content and attributes are always stripped. */
|
|
131
|
+
_DOMSanitizer.BLOCKED_TAGS = /* @__PURE__ */ new Set(["script", "object", "iframe"]);
|
|
132
|
+
var DOMSanitizer = _DOMSanitizer;
|
|
93
133
|
|
|
94
134
|
// src/ElementUtils.ts
|
|
95
135
|
var ALWAYS_DISALLOWED_TAGS = /* @__PURE__ */ new Set(["foreignobject", "iframe", "script"]);
|
|
@@ -215,7 +255,13 @@ function remapAttributeName(attrName) {
|
|
|
215
255
|
}
|
|
216
256
|
return attrName;
|
|
217
257
|
}
|
|
218
|
-
function createElementWithSVGSupport(tag, options = {}) {
|
|
258
|
+
function createElementWithSVGSupport(tag, options = {}, doc) {
|
|
259
|
+
if (!doc && typeof document === "undefined") {
|
|
260
|
+
throw new Error(
|
|
261
|
+
"createElementWithSVGSupport requires a document factory (IDocumentFactory) in non-browser environments"
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
const docFactory = doc ?? document;
|
|
219
265
|
let filteredTag = tag.toLowerCase();
|
|
220
266
|
if (ALWAYS_DISALLOWED_TAGS.has(filteredTag.toLowerCase())) {
|
|
221
267
|
console.error("Disallowing tag", filteredTag);
|
|
@@ -228,14 +274,17 @@ function createElementWithSVGSupport(tag, options = {}) {
|
|
|
228
274
|
if (svgTagMapping) {
|
|
229
275
|
filteredTag = svgTagMapping;
|
|
230
276
|
const xmlns = "http://www.w3.org/2000/svg";
|
|
231
|
-
|
|
277
|
+
if (docFactory.createElementNS) {
|
|
278
|
+
return docFactory.createElementNS(xmlns, filteredTag);
|
|
279
|
+
}
|
|
280
|
+
return docFactory.createElement(filteredTag);
|
|
232
281
|
} else {
|
|
233
282
|
if (options.tagPrefix) {
|
|
234
283
|
if (!tag.toLowerCase().startsWith(options.tagPrefix.toLowerCase())) {
|
|
235
284
|
filteredTag = options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`;
|
|
236
285
|
}
|
|
237
286
|
}
|
|
238
|
-
return
|
|
287
|
+
return docFactory.createElement(filteredTag);
|
|
239
288
|
}
|
|
240
289
|
}
|
|
241
290
|
function setElementAttribute(element, key, value) {
|
|
@@ -245,23 +294,69 @@ function setElementAttribute(element, key, value) {
|
|
|
245
294
|
}
|
|
246
295
|
}
|
|
247
296
|
function getChildrenTarget(parent) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
targetForChildren = parent.getPortalElement();
|
|
297
|
+
if (isPortalElement(parent)) {
|
|
298
|
+
return parent.getPortalElement();
|
|
251
299
|
}
|
|
252
|
-
return
|
|
300
|
+
return parent;
|
|
253
301
|
}
|
|
254
302
|
function getRemovalTarget(parent) {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
targetForRemoval = parent.getPortalElement();
|
|
303
|
+
if (isPortalElement(parent)) {
|
|
304
|
+
return parent.getPortalElement();
|
|
258
305
|
}
|
|
259
|
-
return
|
|
306
|
+
return parent;
|
|
260
307
|
}
|
|
261
308
|
|
|
262
|
-
// src/
|
|
263
|
-
|
|
264
|
-
|
|
309
|
+
// src/NetworkedDOMWebsocket.ts
|
|
310
|
+
import {
|
|
311
|
+
isNetworkedDOMProtocolSubProtocol_v0_2,
|
|
312
|
+
networkedDOMProtocolSubProtocol_v0_1,
|
|
313
|
+
networkedDOMProtocolSubProtocol_v0_2_SubVersionsList
|
|
314
|
+
} from "@mml-io/networked-dom-protocol";
|
|
315
|
+
|
|
316
|
+
// src/PortalUtils.ts
|
|
317
|
+
function resolveChildFactory(parentNode, elementFactoryOverride) {
|
|
318
|
+
var _a;
|
|
319
|
+
if (isElementLike(parentNode) && isPortalElement(parentNode)) {
|
|
320
|
+
const portalFactory = (_a = parentNode.getPortalDocumentFactory) == null ? void 0 : _a.call(parentNode);
|
|
321
|
+
if (portalFactory) {
|
|
322
|
+
return portalFactory;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
return elementFactoryOverride.get(parentNode);
|
|
326
|
+
}
|
|
327
|
+
function resolvePortalChildFactory(element, currentFactory) {
|
|
328
|
+
var _a;
|
|
329
|
+
if (isPortalElement(element)) {
|
|
330
|
+
const portalFactory = (_a = element.getPortalDocumentFactory) == null ? void 0 : _a.call(element);
|
|
331
|
+
if (portalFactory) {
|
|
332
|
+
return { childFactory: portalFactory, usingPortalFactory: true };
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
return { childFactory: currentFactory, usingPortalFactory: false };
|
|
336
|
+
}
|
|
337
|
+
function recordFactoryOverride(element, factory, defaultFactory, elementFactoryOverride) {
|
|
338
|
+
if (factory !== defaultFactory) {
|
|
339
|
+
elementFactoryOverride.set(element, factory);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
function flushPendingPortalChildren(pendingPortalChildren) {
|
|
343
|
+
for (const [portalParent, children] of pendingPortalChildren) {
|
|
344
|
+
const target = getChildrenTarget(portalParent);
|
|
345
|
+
for (const child of children) {
|
|
346
|
+
target.appendChild(child);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
pendingPortalChildren.clear();
|
|
350
|
+
}
|
|
351
|
+
function bufferPortalChild(pendingPortalChildren, portalParent, child) {
|
|
352
|
+
const pending = pendingPortalChildren.get(portalParent) ?? [];
|
|
353
|
+
pending.push(child);
|
|
354
|
+
pendingPortalChildren.set(portalParent, pending);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
// src/NetworkedDOMWebsocketAdapterBase.ts
|
|
358
|
+
var NetworkedDOMWebsocketAdapterBase = class {
|
|
359
|
+
constructor(websocket, parentElement, connectedCallback, timeCallback, options = {}, doc) {
|
|
265
360
|
this.websocket = websocket;
|
|
266
361
|
this.parentElement = parentElement;
|
|
267
362
|
this.connectedCallback = connectedCallback;
|
|
@@ -270,7 +365,119 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
270
365
|
this.idToElement = /* @__PURE__ */ new Map();
|
|
271
366
|
this.elementToId = /* @__PURE__ */ new Map();
|
|
272
367
|
this.currentRoot = null;
|
|
368
|
+
this.pendingPortalChildren = /* @__PURE__ */ new Map();
|
|
369
|
+
this.elementFactoryOverride = /* @__PURE__ */ new Map();
|
|
273
370
|
this.websocket.binaryType = "arraybuffer";
|
|
371
|
+
if (!doc && typeof document === "undefined") {
|
|
372
|
+
throw new Error(
|
|
373
|
+
"NetworkedDOMWebsocketAdapter requires a document factory (IDocumentFactory) in non-browser environments"
|
|
374
|
+
);
|
|
375
|
+
}
|
|
376
|
+
this.docFactory = doc ?? document;
|
|
377
|
+
}
|
|
378
|
+
clearContents() {
|
|
379
|
+
this.idToElement.clear();
|
|
380
|
+
this.elementToId.clear();
|
|
381
|
+
this.elementFactoryOverride.clear();
|
|
382
|
+
this.pendingPortalChildren.clear();
|
|
383
|
+
if (this.currentRoot) {
|
|
384
|
+
this.currentRoot.remove();
|
|
385
|
+
this.currentRoot = null;
|
|
386
|
+
return true;
|
|
387
|
+
}
|
|
388
|
+
return false;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Creates a text node, registers it in the id maps, and returns it.
|
|
392
|
+
*/
|
|
393
|
+
createTextNode(nodeId, text, factory) {
|
|
394
|
+
const textNode = factory.createTextNode("");
|
|
395
|
+
textNode.textContent = text;
|
|
396
|
+
this.idToElement.set(nodeId, textNode);
|
|
397
|
+
this.elementToId.set(textNode, nodeId);
|
|
398
|
+
return textNode;
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Inserts elements into the correct position within a parent, using
|
|
402
|
+
* previousElement/nextElement for positioning. Creates a DocumentFragment
|
|
403
|
+
* when inserting before a reference node.
|
|
404
|
+
*/
|
|
405
|
+
insertElements(targetForChildren, elementsToAdd, previousElement, nextElement, factory) {
|
|
406
|
+
if (elementsToAdd.length === 0) return;
|
|
407
|
+
if (previousElement) {
|
|
408
|
+
if (nextElement) {
|
|
409
|
+
const docFrag = factory.createDocumentFragment();
|
|
410
|
+
docFrag.append(...elementsToAdd);
|
|
411
|
+
targetForChildren.insertBefore(docFrag, nextElement);
|
|
412
|
+
} else {
|
|
413
|
+
targetForChildren.append(...elementsToAdd);
|
|
414
|
+
}
|
|
415
|
+
} else {
|
|
416
|
+
targetForChildren.prepend(...elementsToAdd);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Recursively removes element-to-id mappings for all descendants of a parent.
|
|
421
|
+
* V02 overrides this to also handle hidden placeholder elements.
|
|
422
|
+
*/
|
|
423
|
+
removeChildElementIds(parent) {
|
|
424
|
+
if (isElementLike(parent)) {
|
|
425
|
+
const portal = getChildrenTarget(parent);
|
|
426
|
+
if (portal !== parent) {
|
|
427
|
+
this.removeChildElementIds(portal);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
431
|
+
const child = parent.childNodes[i];
|
|
432
|
+
const childId = this.elementToId.get(child);
|
|
433
|
+
if (!childId) {
|
|
434
|
+
this.handleUnregisteredChild(child);
|
|
435
|
+
} else {
|
|
436
|
+
this.elementToId.delete(child);
|
|
437
|
+
this.idToElement.delete(childId);
|
|
438
|
+
this.elementFactoryOverride.delete(child);
|
|
439
|
+
}
|
|
440
|
+
this.removeChildElementIds(child);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Called during removeChildElementIds when a child has no registered id.
|
|
445
|
+
* V01 logs an error. V02 overrides to check for placeholder elements.
|
|
446
|
+
*/
|
|
447
|
+
handleUnregisteredChild(child) {
|
|
448
|
+
console.error("Inner child of removed element had no id", child);
|
|
449
|
+
}
|
|
450
|
+
/**
|
|
451
|
+
* Resets state and applies a snapshot element to the parent.
|
|
452
|
+
* Appending to the tree triggers MElement connectedCallbacks (which set up portals),
|
|
453
|
+
* then pending portal children are flushed.
|
|
454
|
+
*/
|
|
455
|
+
resetAndApplySnapshot(element) {
|
|
456
|
+
if (this.currentRoot) {
|
|
457
|
+
this.removeChildElementIds(this.currentRoot);
|
|
458
|
+
const rootId = this.elementToId.get(this.currentRoot);
|
|
459
|
+
if (rootId !== void 0) {
|
|
460
|
+
this.elementToId.delete(this.currentRoot);
|
|
461
|
+
this.idToElement.delete(rootId);
|
|
462
|
+
this.elementFactoryOverride.delete(this.currentRoot);
|
|
463
|
+
}
|
|
464
|
+
this.currentRoot.remove();
|
|
465
|
+
this.currentRoot = null;
|
|
466
|
+
this.pendingPortalChildren.clear();
|
|
467
|
+
}
|
|
468
|
+
if (!isHTMLElement(element, this.parentElement)) {
|
|
469
|
+
throw new Error("Snapshot element is not an HTMLElement");
|
|
470
|
+
}
|
|
471
|
+
this.currentRoot = element;
|
|
472
|
+
this.parentElement.append(element);
|
|
473
|
+
flushPendingPortalChildren(this.pendingPortalChildren);
|
|
474
|
+
}
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
// src/NetworkedDOMWebsocketV01Adapter.ts
|
|
478
|
+
var NetworkedDOMWebsocketV01Adapter = class extends NetworkedDOMWebsocketAdapterBase {
|
|
479
|
+
constructor(websocket, parentElement, connectedCallback, timeCallback, options = {}, doc) {
|
|
480
|
+
super(websocket, parentElement, connectedCallback, timeCallback, options, doc);
|
|
274
481
|
}
|
|
275
482
|
handleEvent(element, event) {
|
|
276
483
|
const nodeId = this.elementToId.get(element);
|
|
@@ -293,16 +500,6 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
293
500
|
send(fromClientMessage) {
|
|
294
501
|
this.websocket.send(JSON.stringify(fromClientMessage));
|
|
295
502
|
}
|
|
296
|
-
clearContents() {
|
|
297
|
-
this.idToElement.clear();
|
|
298
|
-
this.elementToId.clear();
|
|
299
|
-
if (this.currentRoot) {
|
|
300
|
-
this.currentRoot.remove();
|
|
301
|
-
this.currentRoot = null;
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
return false;
|
|
305
|
-
}
|
|
306
503
|
receiveMessage(event) {
|
|
307
504
|
try {
|
|
308
505
|
const messages = JSON.parse(event.data);
|
|
@@ -374,14 +571,15 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
374
571
|
console.warn("No nodeId in childrenChanged message");
|
|
375
572
|
return;
|
|
376
573
|
}
|
|
377
|
-
const
|
|
378
|
-
if (!
|
|
574
|
+
const parentNode = this.idToElement.get(nodeId);
|
|
575
|
+
if (!parentNode) {
|
|
379
576
|
throw new Error("No parent found for childrenChanged message");
|
|
380
577
|
}
|
|
381
|
-
if (!isHTMLElement(
|
|
578
|
+
if (!isHTMLElement(parentNode, this.parentElement)) {
|
|
382
579
|
throw new Error("Parent is not an HTMLElement (that supports children)");
|
|
383
580
|
}
|
|
384
|
-
const
|
|
581
|
+
const childFactory = resolveChildFactory(parentNode, this.elementFactoryOverride);
|
|
582
|
+
const targetForChildren = getChildrenTarget(parentNode);
|
|
385
583
|
let nextElement = null;
|
|
386
584
|
let previousElement = null;
|
|
387
585
|
if (previousNodeId) {
|
|
@@ -393,23 +591,20 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
393
591
|
}
|
|
394
592
|
const elementsToAdd = [];
|
|
395
593
|
for (const addedNode of addedNodes) {
|
|
396
|
-
const childElement = this.handleNewElement(addedNode);
|
|
594
|
+
const childElement = this.handleNewElement(addedNode, childFactory);
|
|
397
595
|
if (childElement) {
|
|
398
596
|
elementsToAdd.push(childElement);
|
|
399
597
|
}
|
|
400
598
|
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
} else {
|
|
411
|
-
targetForChildren.prepend(...elementsToAdd);
|
|
412
|
-
}
|
|
599
|
+
this.insertElements(
|
|
600
|
+
targetForChildren,
|
|
601
|
+
elementsToAdd,
|
|
602
|
+
previousElement,
|
|
603
|
+
nextElement,
|
|
604
|
+
childFactory ?? this.docFactory
|
|
605
|
+
);
|
|
606
|
+
if (this.pendingPortalChildren.size > 0) {
|
|
607
|
+
flushPendingPortalChildren(this.pendingPortalChildren);
|
|
413
608
|
}
|
|
414
609
|
for (const removedNode of removedNodes) {
|
|
415
610
|
const childElement = this.idToElement.get(removedNode);
|
|
@@ -418,46 +613,19 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
418
613
|
}
|
|
419
614
|
this.elementToId.delete(childElement);
|
|
420
615
|
this.idToElement.delete(removedNode);
|
|
421
|
-
const targetForRemoval = getRemovalTarget(
|
|
616
|
+
const targetForRemoval = getRemovalTarget(parentNode);
|
|
422
617
|
targetForRemoval.removeChild(childElement);
|
|
423
618
|
if (isHTMLElement(childElement, this.parentElement)) {
|
|
424
619
|
this.removeChildElementIds(childElement);
|
|
425
620
|
}
|
|
426
621
|
}
|
|
427
622
|
}
|
|
428
|
-
removeChildElementIds(parent) {
|
|
429
|
-
const portal = getChildrenTarget(parent);
|
|
430
|
-
if (portal !== parent) {
|
|
431
|
-
this.removeChildElementIds(portal);
|
|
432
|
-
}
|
|
433
|
-
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
434
|
-
const child = parent.childNodes[i];
|
|
435
|
-
const childId = this.elementToId.get(child);
|
|
436
|
-
if (!childId) {
|
|
437
|
-
console.error("Inner child of removed element had no id", child);
|
|
438
|
-
} else {
|
|
439
|
-
this.elementToId.delete(child);
|
|
440
|
-
this.idToElement.delete(childId);
|
|
441
|
-
}
|
|
442
|
-
this.removeChildElementIds(child);
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
623
|
handleSnapshot(message) {
|
|
446
|
-
if (this.currentRoot) {
|
|
447
|
-
this.currentRoot.remove();
|
|
448
|
-
this.currentRoot = null;
|
|
449
|
-
this.elementToId.clear();
|
|
450
|
-
this.idToElement.clear();
|
|
451
|
-
}
|
|
452
624
|
const element = this.handleNewElement(message.snapshot);
|
|
453
625
|
if (!element) {
|
|
454
626
|
throw new Error("Snapshot element not created");
|
|
455
627
|
}
|
|
456
|
-
|
|
457
|
-
throw new Error("Snapshot element is not an HTMLElement");
|
|
458
|
-
}
|
|
459
|
-
this.currentRoot = element;
|
|
460
|
-
this.parentElement.append(element);
|
|
628
|
+
this.resetAndApplySnapshot(element);
|
|
461
629
|
}
|
|
462
630
|
handleAttributeChange(message) {
|
|
463
631
|
const { nodeId, attribute, newValue } = message;
|
|
@@ -465,29 +633,25 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
465
633
|
console.warn("No nodeId in attributeChange message");
|
|
466
634
|
return;
|
|
467
635
|
}
|
|
468
|
-
const
|
|
469
|
-
if (
|
|
470
|
-
if (isHTMLElement(
|
|
636
|
+
const node = this.idToElement.get(nodeId);
|
|
637
|
+
if (node) {
|
|
638
|
+
if (isHTMLElement(node, this.parentElement)) {
|
|
471
639
|
if (newValue === null) {
|
|
472
|
-
|
|
640
|
+
node.removeAttribute(attribute);
|
|
473
641
|
} else {
|
|
474
|
-
setElementAttribute(
|
|
642
|
+
setElementAttribute(node, attribute, newValue);
|
|
475
643
|
}
|
|
476
644
|
} else {
|
|
477
|
-
console.error("Element is not an HTMLElement and cannot support attributes",
|
|
645
|
+
console.error("Element is not an HTMLElement and cannot support attributes", node);
|
|
478
646
|
}
|
|
479
647
|
} else {
|
|
480
648
|
console.error("No element found for attributeChange message");
|
|
481
649
|
}
|
|
482
650
|
}
|
|
483
|
-
handleNewElement(message) {
|
|
651
|
+
handleNewElement(message, factoryOverride) {
|
|
652
|
+
const factory = factoryOverride ?? this.docFactory;
|
|
484
653
|
if (message.type === "text") {
|
|
485
|
-
|
|
486
|
-
const textNode = document.createTextNode("");
|
|
487
|
-
textNode.textContent = text2;
|
|
488
|
-
this.idToElement.set(nodeId2, textNode);
|
|
489
|
-
this.elementToId.set(textNode, nodeId2);
|
|
490
|
-
return textNode;
|
|
654
|
+
return this.createTextNode(message.nodeId, message.text, factory);
|
|
491
655
|
}
|
|
492
656
|
const { tag, nodeId, attributes, children, text } = message;
|
|
493
657
|
if (nodeId === void 0 || nodeId === null) {
|
|
@@ -502,18 +666,14 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
502
666
|
);
|
|
503
667
|
}
|
|
504
668
|
if (tag === "#text") {
|
|
505
|
-
|
|
506
|
-
textNode.textContent = text || null;
|
|
507
|
-
this.idToElement.set(nodeId, textNode);
|
|
508
|
-
this.elementToId.set(textNode, nodeId);
|
|
509
|
-
return textNode;
|
|
669
|
+
return this.createTextNode(nodeId, text || "", factory);
|
|
510
670
|
}
|
|
511
671
|
let element;
|
|
512
672
|
try {
|
|
513
|
-
element = createElementWithSVGSupport(tag, this.options);
|
|
673
|
+
element = createElementWithSVGSupport(tag, this.options, factory);
|
|
514
674
|
} catch (e) {
|
|
515
675
|
console.error(`Error creating element: (${tag})`, e);
|
|
516
|
-
element =
|
|
676
|
+
element = factory.createElement("x-div");
|
|
517
677
|
}
|
|
518
678
|
this.idToElement.set(nodeId, element);
|
|
519
679
|
this.elementToId.set(element, nodeId);
|
|
@@ -521,11 +681,17 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
521
681
|
const value = attributes[key];
|
|
522
682
|
setElementAttribute(element, key, value);
|
|
523
683
|
}
|
|
684
|
+
recordFactoryOverride(element, factory, this.docFactory, this.elementFactoryOverride);
|
|
685
|
+
const { childFactory, usingPortalFactory } = resolvePortalChildFactory(element, factory);
|
|
524
686
|
if (children) {
|
|
525
687
|
for (const child of children) {
|
|
526
|
-
const childElement = this.handleNewElement(child);
|
|
688
|
+
const childElement = this.handleNewElement(child, childFactory);
|
|
527
689
|
if (childElement) {
|
|
528
|
-
|
|
690
|
+
if (usingPortalFactory) {
|
|
691
|
+
bufferPortalChild(this.pendingPortalChildren, element, childElement);
|
|
692
|
+
} else {
|
|
693
|
+
element.append(childElement);
|
|
694
|
+
}
|
|
529
695
|
}
|
|
530
696
|
}
|
|
531
697
|
}
|
|
@@ -543,21 +709,13 @@ import {
|
|
|
543
709
|
} from "@mml-io/networked-dom-protocol";
|
|
544
710
|
var connectionId = 1;
|
|
545
711
|
var hiddenTag = "x-hidden";
|
|
546
|
-
var NetworkedDOMWebsocketV02Adapter = class {
|
|
547
|
-
constructor(websocket, parentElement, connectedCallback, timeCallback, options = {}) {
|
|
548
|
-
|
|
549
|
-
this.parentElement = parentElement;
|
|
550
|
-
this.connectedCallback = connectedCallback;
|
|
551
|
-
this.timeCallback = timeCallback;
|
|
552
|
-
this.options = options;
|
|
553
|
-
this.idToElement = /* @__PURE__ */ new Map();
|
|
554
|
-
this.elementToId = /* @__PURE__ */ new Map();
|
|
712
|
+
var NetworkedDOMWebsocketV02Adapter = class extends NetworkedDOMWebsocketAdapterBase {
|
|
713
|
+
constructor(websocket, parentElement, connectedCallback, timeCallback, options = {}, doc) {
|
|
714
|
+
super(websocket, parentElement, connectedCallback, timeCallback, options, doc);
|
|
555
715
|
this.placeholderToId = /* @__PURE__ */ new Map();
|
|
556
716
|
this.hiddenPlaceholderElements = /* @__PURE__ */ new Map();
|
|
557
|
-
this.currentRoot = null;
|
|
558
717
|
this.batchMode = false;
|
|
559
718
|
this.batchMessages = [];
|
|
560
|
-
this.websocket.binaryType = "arraybuffer";
|
|
561
719
|
this.protocolSubversion = getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow(
|
|
562
720
|
websocket.protocol
|
|
563
721
|
);
|
|
@@ -593,14 +751,11 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
593
751
|
this.websocket.send(writer.getBuffer());
|
|
594
752
|
}
|
|
595
753
|
clearContents() {
|
|
596
|
-
this.
|
|
597
|
-
this.
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
return true;
|
|
602
|
-
}
|
|
603
|
-
return false;
|
|
754
|
+
this.placeholderToId.clear();
|
|
755
|
+
this.hiddenPlaceholderElements.clear();
|
|
756
|
+
this.batchMessages = [];
|
|
757
|
+
this.batchMode = false;
|
|
758
|
+
return super.clearContents();
|
|
604
759
|
}
|
|
605
760
|
receiveMessage(event) {
|
|
606
761
|
try {
|
|
@@ -695,13 +850,14 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
695
850
|
if (!node) {
|
|
696
851
|
throw new Error("No node found for changeHiddenFrom message");
|
|
697
852
|
}
|
|
698
|
-
const
|
|
853
|
+
const element = node;
|
|
854
|
+
const parent = element.parentElement;
|
|
699
855
|
if (!parent) {
|
|
700
856
|
throw new Error("Node has no parent");
|
|
701
857
|
}
|
|
702
|
-
const placeholder =
|
|
703
|
-
parent.replaceChild(placeholder,
|
|
704
|
-
this.hiddenPlaceholderElements.set(nodeId, { placeholder, element
|
|
858
|
+
const placeholder = this.docFactory.createElement(hiddenTag);
|
|
859
|
+
parent.replaceChild(placeholder, element);
|
|
860
|
+
this.hiddenPlaceholderElements.set(nodeId, { placeholder, element });
|
|
705
861
|
this.placeholderToId.set(placeholder, nodeId);
|
|
706
862
|
} else if (removeHiddenFrom.length > 0 && removeHiddenFrom.indexOf(connectionId) !== -1) {
|
|
707
863
|
if (!hiddenElement) {
|
|
@@ -723,18 +879,19 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
723
879
|
console.warn("No nodeId in childrenChanged message");
|
|
724
880
|
return;
|
|
725
881
|
}
|
|
726
|
-
let
|
|
727
|
-
if (!
|
|
882
|
+
let parentNode = this.idToElement.get(nodeId);
|
|
883
|
+
if (!parentNode) {
|
|
728
884
|
throw new Error("No parent found for childrenChanged message");
|
|
729
885
|
}
|
|
730
886
|
const hiddenParent = this.hiddenPlaceholderElements.get(nodeId);
|
|
731
887
|
if (hiddenParent) {
|
|
732
|
-
|
|
888
|
+
parentNode = hiddenParent.element;
|
|
733
889
|
}
|
|
734
|
-
if (!isHTMLElement(
|
|
890
|
+
if (!isHTMLElement(parentNode, this.parentElement)) {
|
|
735
891
|
throw new Error("Parent is not an HTMLElement (that supports children)");
|
|
736
892
|
}
|
|
737
|
-
const
|
|
893
|
+
const childFactory = resolveChildFactory(parentNode, this.elementFactoryOverride);
|
|
894
|
+
const targetForChildren = getChildrenTarget(parentNode);
|
|
738
895
|
let nextElement = null;
|
|
739
896
|
let previousElement = null;
|
|
740
897
|
if (previousNodeId) {
|
|
@@ -746,23 +903,20 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
746
903
|
}
|
|
747
904
|
const elementsToAdd = [];
|
|
748
905
|
for (const addedNode of addedNodes) {
|
|
749
|
-
const childElement = this.handleNewElement(addedNode);
|
|
906
|
+
const childElement = this.handleNewElement(addedNode, childFactory);
|
|
750
907
|
if (childElement) {
|
|
751
908
|
elementsToAdd.push(childElement);
|
|
752
909
|
}
|
|
753
910
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
} else {
|
|
764
|
-
targetForChildren.prepend(...elementsToAdd);
|
|
765
|
-
}
|
|
911
|
+
this.insertElements(
|
|
912
|
+
targetForChildren,
|
|
913
|
+
elementsToAdd,
|
|
914
|
+
previousElement,
|
|
915
|
+
nextElement,
|
|
916
|
+
childFactory ?? this.docFactory
|
|
917
|
+
);
|
|
918
|
+
if (this.pendingPortalChildren.size > 0) {
|
|
919
|
+
flushPendingPortalChildren(this.pendingPortalChildren);
|
|
766
920
|
}
|
|
767
921
|
}
|
|
768
922
|
handleChildrenRemoved(message) {
|
|
@@ -771,11 +925,11 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
771
925
|
console.warn("No nodeId in childrenChanged message");
|
|
772
926
|
return;
|
|
773
927
|
}
|
|
774
|
-
const
|
|
775
|
-
if (!
|
|
928
|
+
const parentNode = this.idToElement.get(nodeId);
|
|
929
|
+
if (!parentNode) {
|
|
776
930
|
throw new Error("No parent found for childrenChanged message");
|
|
777
931
|
}
|
|
778
|
-
if (!isHTMLElement(
|
|
932
|
+
if (!isHTMLElement(parentNode, this.parentElement)) {
|
|
779
933
|
throw new Error("Parent is not an HTMLElement (that supports children)");
|
|
780
934
|
}
|
|
781
935
|
for (const removedNode of removedNodes) {
|
|
@@ -785,7 +939,7 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
785
939
|
}
|
|
786
940
|
this.elementToId.delete(childElement);
|
|
787
941
|
this.idToElement.delete(removedNode);
|
|
788
|
-
const targetForRemoval = getRemovalTarget(
|
|
942
|
+
const targetForRemoval = getRemovalTarget(parentNode);
|
|
789
943
|
const hiddenElement = this.hiddenPlaceholderElements.get(removedNode);
|
|
790
944
|
if (hiddenElement) {
|
|
791
945
|
const placeholder = hiddenElement.placeholder;
|
|
@@ -811,62 +965,36 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
811
965
|
}
|
|
812
966
|
}
|
|
813
967
|
}
|
|
814
|
-
|
|
815
|
-
const
|
|
816
|
-
if (
|
|
817
|
-
this.
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
for (let i = 0; i < childNodes.length; i++) {
|
|
821
|
-
const child = childNodes[i];
|
|
822
|
-
const childId = this.elementToId.get(child);
|
|
823
|
-
if (!childId) {
|
|
824
|
-
const placeholderId = this.placeholderToId.get(child);
|
|
825
|
-
if (placeholderId) {
|
|
826
|
-
const childElement = this.idToElement.get(placeholderId);
|
|
827
|
-
if (childElement) {
|
|
828
|
-
this.elementToId.delete(childElement);
|
|
829
|
-
} else {
|
|
830
|
-
console.error(
|
|
831
|
-
"Inner child of removed placeholder element not found by id",
|
|
832
|
-
placeholderId
|
|
833
|
-
);
|
|
834
|
-
}
|
|
835
|
-
this.idToElement.delete(placeholderId);
|
|
836
|
-
this.placeholderToId.delete(child);
|
|
837
|
-
this.hiddenPlaceholderElements.delete(placeholderId);
|
|
838
|
-
this.removeChildElementIds(childElement);
|
|
839
|
-
} else {
|
|
840
|
-
console.error(
|
|
841
|
-
"Inner child of removed element had no id",
|
|
842
|
-
child.outerHTML
|
|
843
|
-
);
|
|
844
|
-
}
|
|
968
|
+
handleUnregisteredChild(child) {
|
|
969
|
+
const placeholderId = this.placeholderToId.get(child);
|
|
970
|
+
if (placeholderId) {
|
|
971
|
+
const childElement = this.idToElement.get(placeholderId);
|
|
972
|
+
if (childElement) {
|
|
973
|
+
this.elementToId.delete(childElement);
|
|
845
974
|
} else {
|
|
846
|
-
|
|
847
|
-
this.idToElement.delete(childId);
|
|
848
|
-
this.removeChildElementIds(child);
|
|
975
|
+
console.error("Inner child of removed placeholder element not found by id", placeholderId);
|
|
849
976
|
}
|
|
977
|
+
this.idToElement.delete(placeholderId);
|
|
978
|
+
this.placeholderToId.delete(child);
|
|
979
|
+
this.hiddenPlaceholderElements.delete(placeholderId);
|
|
980
|
+
if (childElement) {
|
|
981
|
+
this.removeChildElementIds(childElement);
|
|
982
|
+
}
|
|
983
|
+
} else {
|
|
984
|
+
console.error(
|
|
985
|
+
"Inner child of removed element had no id",
|
|
986
|
+
(child == null ? void 0 : child.outerHTML) ?? child
|
|
987
|
+
);
|
|
850
988
|
}
|
|
851
989
|
}
|
|
852
990
|
handleSnapshot(message) {
|
|
853
991
|
var _a;
|
|
854
|
-
if (this.currentRoot) {
|
|
855
|
-
this.currentRoot.remove();
|
|
856
|
-
this.currentRoot = null;
|
|
857
|
-
this.elementToId.clear();
|
|
858
|
-
this.idToElement.clear();
|
|
859
|
-
}
|
|
860
992
|
(_a = this.timeCallback) == null ? void 0 : _a.call(this, message.documentTime);
|
|
861
993
|
const element = this.handleNewElement(message.snapshot);
|
|
862
994
|
if (!element) {
|
|
863
995
|
throw new Error("Snapshot element not created");
|
|
864
996
|
}
|
|
865
|
-
|
|
866
|
-
throw new Error("Snapshot element is not an HTMLElement");
|
|
867
|
-
}
|
|
868
|
-
this.currentRoot = element;
|
|
869
|
-
this.parentElement.append(element);
|
|
997
|
+
this.resetAndApplySnapshot(element);
|
|
870
998
|
}
|
|
871
999
|
handleDocumentTime(message) {
|
|
872
1000
|
var _a;
|
|
@@ -878,35 +1006,31 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
878
1006
|
console.warn("No nodeId in attributeChange message");
|
|
879
1007
|
return;
|
|
880
1008
|
}
|
|
881
|
-
let
|
|
1009
|
+
let node = this.idToElement.get(nodeId);
|
|
882
1010
|
const hiddenElement = this.hiddenPlaceholderElements.get(nodeId);
|
|
883
1011
|
if (hiddenElement) {
|
|
884
|
-
|
|
1012
|
+
node = hiddenElement.element;
|
|
885
1013
|
}
|
|
886
|
-
if (
|
|
887
|
-
if (isHTMLElement(
|
|
1014
|
+
if (node) {
|
|
1015
|
+
if (isHTMLElement(node, this.parentElement)) {
|
|
888
1016
|
for (const [key, newValue] of attributes) {
|
|
889
1017
|
if (newValue === null) {
|
|
890
|
-
|
|
1018
|
+
node.removeAttribute(key);
|
|
891
1019
|
} else {
|
|
892
|
-
setElementAttribute(
|
|
1020
|
+
setElementAttribute(node, key, newValue);
|
|
893
1021
|
}
|
|
894
1022
|
}
|
|
895
1023
|
} else {
|
|
896
|
-
console.error("Element is not an HTMLElement and cannot support attributes",
|
|
1024
|
+
console.error("Element is not an HTMLElement and cannot support attributes", node);
|
|
897
1025
|
}
|
|
898
1026
|
} else {
|
|
899
1027
|
console.error("No element found for attributeChange message");
|
|
900
1028
|
}
|
|
901
1029
|
}
|
|
902
|
-
handleNewElement(message) {
|
|
1030
|
+
handleNewElement(message, factoryOverride) {
|
|
1031
|
+
const factory = factoryOverride ?? this.docFactory;
|
|
903
1032
|
if (message.type === "text") {
|
|
904
|
-
|
|
905
|
-
const textNode = document.createTextNode("");
|
|
906
|
-
textNode.textContent = text2;
|
|
907
|
-
this.idToElement.set(nodeId2, textNode);
|
|
908
|
-
this.elementToId.set(textNode, nodeId2);
|
|
909
|
-
return textNode;
|
|
1033
|
+
return this.createTextNode(message.nodeId, message.text, factory);
|
|
910
1034
|
}
|
|
911
1035
|
const { tag, nodeId, attributes, children, text, hiddenFrom } = message;
|
|
912
1036
|
if (this.idToElement.has(nodeId)) {
|
|
@@ -918,34 +1042,36 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
918
1042
|
throw new Error("Received nodeId to add that is already present: " + nodeId);
|
|
919
1043
|
}
|
|
920
1044
|
if (tag === "#text") {
|
|
921
|
-
|
|
922
|
-
textNode.textContent = text || null;
|
|
923
|
-
this.idToElement.set(nodeId, textNode);
|
|
924
|
-
this.elementToId.set(textNode, nodeId);
|
|
925
|
-
return textNode;
|
|
1045
|
+
return this.createTextNode(nodeId, text || "", factory);
|
|
926
1046
|
}
|
|
927
1047
|
let element;
|
|
928
1048
|
try {
|
|
929
|
-
element = createElementWithSVGSupport(tag, this.options);
|
|
1049
|
+
element = createElementWithSVGSupport(tag, this.options, factory);
|
|
930
1050
|
} catch (e) {
|
|
931
1051
|
console.error(`Error creating element: (${tag})`, e);
|
|
932
|
-
element =
|
|
1052
|
+
element = factory.createElement("x-div");
|
|
933
1053
|
}
|
|
934
1054
|
for (const [key, value] of attributes) {
|
|
935
1055
|
if (value !== null) {
|
|
936
1056
|
setElementAttribute(element, key, value);
|
|
937
1057
|
}
|
|
938
1058
|
}
|
|
1059
|
+
recordFactoryOverride(element, factory, this.docFactory, this.elementFactoryOverride);
|
|
1060
|
+
const { childFactory, usingPortalFactory } = resolvePortalChildFactory(element, factory);
|
|
939
1061
|
if (children) {
|
|
940
1062
|
for (const child of children) {
|
|
941
|
-
const childElement = this.handleNewElement(child);
|
|
1063
|
+
const childElement = this.handleNewElement(child, childFactory);
|
|
942
1064
|
if (childElement) {
|
|
943
|
-
|
|
1065
|
+
if (usingPortalFactory) {
|
|
1066
|
+
bufferPortalChild(this.pendingPortalChildren, element, childElement);
|
|
1067
|
+
} else {
|
|
1068
|
+
element.append(childElement);
|
|
1069
|
+
}
|
|
944
1070
|
}
|
|
945
1071
|
}
|
|
946
1072
|
}
|
|
947
1073
|
if (hiddenFrom && hiddenFrom.length > 0 && hiddenFrom.indexOf(connectionId) !== -1) {
|
|
948
|
-
const placeholder =
|
|
1074
|
+
const placeholder = this.docFactory.createElement(hiddenTag);
|
|
949
1075
|
this.hiddenPlaceholderElements.set(nodeId, { placeholder, element });
|
|
950
1076
|
this.placeholderToId.set(placeholder, nodeId);
|
|
951
1077
|
this.idToElement.set(nodeId, element);
|
|
@@ -996,13 +1122,14 @@ function NetworkedDOMWebsocketStatusToString(status) {
|
|
|
996
1122
|
}
|
|
997
1123
|
}
|
|
998
1124
|
var NetworkedDOMWebsocket = class {
|
|
999
|
-
constructor(url, websocketFactory, parentElement, timeCallback, statusUpdateCallback, options = {}) {
|
|
1125
|
+
constructor(url, websocketFactory, parentElement, timeCallback, statusUpdateCallback, options = {}, doc) {
|
|
1000
1126
|
this.url = url;
|
|
1001
1127
|
this.websocketFactory = websocketFactory;
|
|
1002
1128
|
this.parentElement = parentElement;
|
|
1003
1129
|
this.timeCallback = timeCallback;
|
|
1004
1130
|
this.statusUpdateCallback = statusUpdateCallback;
|
|
1005
1131
|
this.options = options;
|
|
1132
|
+
this.doc = doc;
|
|
1006
1133
|
this.websocket = null;
|
|
1007
1134
|
this.websocketAdapter = null;
|
|
1008
1135
|
this.stopped = false;
|
|
@@ -1047,7 +1174,8 @@ var NetworkedDOMWebsocket = class {
|
|
|
1047
1174
|
this.setStatus(2 /* Connected */);
|
|
1048
1175
|
},
|
|
1049
1176
|
this.timeCallback,
|
|
1050
|
-
this.options
|
|
1177
|
+
this.options,
|
|
1178
|
+
this.doc
|
|
1051
1179
|
);
|
|
1052
1180
|
} else {
|
|
1053
1181
|
websocketAdapter = new NetworkedDOMWebsocketV01Adapter(
|
|
@@ -1058,7 +1186,8 @@ var NetworkedDOMWebsocket = class {
|
|
|
1058
1186
|
this.setStatus(2 /* Connected */);
|
|
1059
1187
|
},
|
|
1060
1188
|
this.timeCallback,
|
|
1061
|
-
this.options
|
|
1189
|
+
this.options,
|
|
1190
|
+
this.doc
|
|
1062
1191
|
);
|
|
1063
1192
|
}
|
|
1064
1193
|
this.websocketAdapter = websocketAdapter;
|
|
@@ -1150,29 +1279,58 @@ var NetworkedDOMWebsocket = class {
|
|
|
1150
1279
|
}
|
|
1151
1280
|
};
|
|
1152
1281
|
function isHTMLElement(node, rootNode) {
|
|
1153
|
-
if (node
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
if (
|
|
1157
|
-
|
|
1282
|
+
if (!node || typeof node !== "object") return false;
|
|
1283
|
+
const nodeLike = node;
|
|
1284
|
+
if (nodeLike[VIRTUAL_ELEMENT_BRAND] === true) return true;
|
|
1285
|
+
if (typeof HTMLElement !== "undefined" && node instanceof HTMLElement) return true;
|
|
1286
|
+
if (typeof Element !== "undefined" && node instanceof Element) return true;
|
|
1287
|
+
const rootNodeRecord = rootNode;
|
|
1288
|
+
if (rootNodeRecord == null ? void 0 : rootNodeRecord.ownerDocument) {
|
|
1289
|
+
const ownerDoc = rootNodeRecord.ownerDocument;
|
|
1290
|
+
const defaultView = ownerDoc.defaultView;
|
|
1291
|
+
if (defaultView == null ? void 0 : defaultView.HTMLElement) {
|
|
1292
|
+
return node instanceof defaultView.HTMLElement;
|
|
1293
|
+
}
|
|
1158
1294
|
}
|
|
1159
|
-
return
|
|
1295
|
+
return false;
|
|
1160
1296
|
}
|
|
1161
1297
|
function isText(node, rootNode) {
|
|
1162
|
-
if (node
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
if (
|
|
1166
|
-
|
|
1298
|
+
if (!node || typeof node !== "object") return false;
|
|
1299
|
+
const nodeLike = node;
|
|
1300
|
+
if (nodeLike[VIRTUAL_TEXT_BRAND] === true) return true;
|
|
1301
|
+
if (typeof Text !== "undefined" && node instanceof Text) return true;
|
|
1302
|
+
const rootNodeRecord = rootNode;
|
|
1303
|
+
if (rootNodeRecord == null ? void 0 : rootNodeRecord.ownerDocument) {
|
|
1304
|
+
const ownerDoc = rootNodeRecord.ownerDocument;
|
|
1305
|
+
const defaultView = ownerDoc.defaultView;
|
|
1306
|
+
if (defaultView == null ? void 0 : defaultView.Text) {
|
|
1307
|
+
return node instanceof defaultView.Text;
|
|
1308
|
+
}
|
|
1167
1309
|
}
|
|
1168
|
-
return
|
|
1310
|
+
return false;
|
|
1169
1311
|
}
|
|
1170
1312
|
export {
|
|
1171
1313
|
DOMSanitizer,
|
|
1172
1314
|
NetworkedDOMWebsocket,
|
|
1173
1315
|
NetworkedDOMWebsocketStatus,
|
|
1174
1316
|
NetworkedDOMWebsocketStatusToString,
|
|
1317
|
+
VIRTUAL_DOCUMENT_BRAND,
|
|
1318
|
+
VIRTUAL_ELEMENT_BRAND,
|
|
1319
|
+
VIRTUAL_FRAGMENT_BRAND,
|
|
1320
|
+
VIRTUAL_TEXT_BRAND,
|
|
1321
|
+
bufferPortalChild,
|
|
1322
|
+
createElementWithSVGSupport,
|
|
1323
|
+
flushPendingPortalChildren,
|
|
1324
|
+
getChildrenTarget,
|
|
1325
|
+
getRemovalTarget,
|
|
1326
|
+
isElementLike,
|
|
1175
1327
|
isHTMLElement,
|
|
1176
|
-
|
|
1328
|
+
isPortalElement,
|
|
1329
|
+
isText,
|
|
1330
|
+
recordFactoryOverride,
|
|
1331
|
+
remapAttributeName,
|
|
1332
|
+
resolveChildFactory,
|
|
1333
|
+
resolvePortalChildFactory,
|
|
1334
|
+
setElementAttribute
|
|
1177
1335
|
};
|
|
1178
1336
|
//# sourceMappingURL=index.js.map
|