@mml-io/networked-dom-web 0.19.7 → 0.21.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.
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { NetworkedDOMWebsocketOptions } from "./NetworkedDOMWebsocket";
|
|
2
|
+
/**
|
|
3
|
+
* Remaps attribute names to their proper case for SVG elements
|
|
4
|
+
*/
|
|
5
|
+
export declare function remapAttributeName(attrName: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Creates an HTML Element (and optionally SVG Elements) with proper namespace handling
|
|
8
|
+
*/
|
|
9
|
+
export declare function createElementWithSVGSupport(tag: string, options?: NetworkedDOMWebsocketOptions): Element;
|
|
10
|
+
/**
|
|
11
|
+
* Sets attributes on an element with proper SVG attribute name mapping
|
|
12
|
+
*/
|
|
13
|
+
export declare function setElementAttribute(element: Element, key: string, value: string): void;
|
|
14
|
+
/**
|
|
15
|
+
* Gets the target element for children operations, handling portal elements
|
|
16
|
+
*/
|
|
17
|
+
export declare function getChildrenTarget(parent: Element): Element;
|
|
18
|
+
/**
|
|
19
|
+
* Gets the target element for removal operations, handling portal elements
|
|
20
|
+
*/
|
|
21
|
+
export declare function getRemovalTarget(parent: Element): Element;
|
|
@@ -10,6 +10,8 @@ export declare function NetworkedDOMWebsocketStatusToString(status: NetworkedDOM
|
|
|
10
10
|
export type NetworkedDOMWebsocketOptions = {
|
|
11
11
|
tagPrefix?: string;
|
|
12
12
|
replacementTagPrefix?: string;
|
|
13
|
+
allowSVGElements?: boolean;
|
|
14
|
+
connectionToken?: string | null;
|
|
13
15
|
};
|
|
14
16
|
export type NetworkedDOMWebsocketAdapter = {
|
|
15
17
|
receiveMessage: (message: MessageEvent) => void;
|
|
@@ -11,6 +11,7 @@ export declare class NetworkedDOMWebsocketV02Adapter implements NetworkedDOMWebs
|
|
|
11
11
|
private currentRoot;
|
|
12
12
|
private batchMode;
|
|
13
13
|
private batchMessages;
|
|
14
|
+
private readonly protocolSubversion;
|
|
14
15
|
constructor(websocket: WebSocket, parentElement: HTMLElement, connectedCallback: () => void, timeCallback?: ((time: number) => void) | undefined, options?: NetworkedDOMWebsocketOptions);
|
|
15
16
|
handleEvent(element: HTMLElement, event: CustomEvent<{
|
|
16
17
|
element: HTMLElement;
|
package/build/index.js
CHANGED
|
@@ -60,7 +60,7 @@ var DOMSanitizer = class _DOMSanitizer {
|
|
|
60
60
|
return c >= "0" && c <= "9";
|
|
61
61
|
}
|
|
62
62
|
static IsASCIIAlpha(c) {
|
|
63
|
-
return c >= "a" && c <= "z";
|
|
63
|
+
return c >= "a" && c <= "z" || c >= "A" && c <= "Z";
|
|
64
64
|
}
|
|
65
65
|
static IsValidAttributeName(characters) {
|
|
66
66
|
const c = characters[0];
|
|
@@ -86,10 +86,179 @@ var DOMSanitizer = class _DOMSanitizer {
|
|
|
86
86
|
|
|
87
87
|
// src/NetworkedDOMWebsocket.ts
|
|
88
88
|
import {
|
|
89
|
+
isNetworkedDOMProtocolSubProtocol_v0_2,
|
|
89
90
|
networkedDOMProtocolSubProtocol_v0_1,
|
|
90
|
-
|
|
91
|
+
networkedDOMProtocolSubProtocol_v0_2_SubVersionsList
|
|
91
92
|
} from "@mml-io/networked-dom-protocol";
|
|
92
93
|
|
|
94
|
+
// src/ElementUtils.ts
|
|
95
|
+
var ALWAYS_DISALLOWED_TAGS = /* @__PURE__ */ new Set(["foreignobject", "iframe", "script"]);
|
|
96
|
+
var SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map(
|
|
97
|
+
[
|
|
98
|
+
"svg",
|
|
99
|
+
"defs",
|
|
100
|
+
"g",
|
|
101
|
+
"text",
|
|
102
|
+
"filter",
|
|
103
|
+
"stop",
|
|
104
|
+
"path",
|
|
105
|
+
"rect",
|
|
106
|
+
"line",
|
|
107
|
+
"circle",
|
|
108
|
+
"animate",
|
|
109
|
+
"altGlyph",
|
|
110
|
+
"altGlyphDef",
|
|
111
|
+
"altGlyphItem",
|
|
112
|
+
"animateColor",
|
|
113
|
+
"animateMotion",
|
|
114
|
+
"animateTransform",
|
|
115
|
+
"clipPath",
|
|
116
|
+
"feBlend",
|
|
117
|
+
"feDropShadow",
|
|
118
|
+
"feColorMatrix",
|
|
119
|
+
"feComponentTransfer",
|
|
120
|
+
"feComposite",
|
|
121
|
+
"feConvolveMatrix",
|
|
122
|
+
"feDiffuseLighting",
|
|
123
|
+
"feDisplacementMap",
|
|
124
|
+
"feDistantLight",
|
|
125
|
+
"feFlood",
|
|
126
|
+
"feFuncA",
|
|
127
|
+
"feFuncB",
|
|
128
|
+
"feFuncG",
|
|
129
|
+
"feFuncR",
|
|
130
|
+
"feGaussianBlur",
|
|
131
|
+
"feImage",
|
|
132
|
+
"feMerge",
|
|
133
|
+
"feMergeNode",
|
|
134
|
+
"feMorphology",
|
|
135
|
+
"feOffset",
|
|
136
|
+
"fePointLight",
|
|
137
|
+
"feSpecularLighting",
|
|
138
|
+
"feSpotLight",
|
|
139
|
+
"feTile",
|
|
140
|
+
"feTurbulence",
|
|
141
|
+
"glyphRef",
|
|
142
|
+
"linearGradient",
|
|
143
|
+
"radialGradient",
|
|
144
|
+
"textPath"
|
|
145
|
+
// `foreignObject` is explicitly disallowed because it allows injecting arbitrary HTML
|
|
146
|
+
// "foreignObject",
|
|
147
|
+
].map((tn) => [tn.toLowerCase(), tn])
|
|
148
|
+
);
|
|
149
|
+
var SVG_ATTRS_ADJUSTMENT_MAP = new Map(
|
|
150
|
+
[
|
|
151
|
+
"attributeName",
|
|
152
|
+
"attributeType",
|
|
153
|
+
"baseFrequency",
|
|
154
|
+
"baseProfile",
|
|
155
|
+
"calcMode",
|
|
156
|
+
"clipPathUnits",
|
|
157
|
+
"diffuseConstant",
|
|
158
|
+
"edgeMode",
|
|
159
|
+
"filterUnits",
|
|
160
|
+
"glyphRef",
|
|
161
|
+
"gradientTransform",
|
|
162
|
+
"gradientUnits",
|
|
163
|
+
"kernelMatrix",
|
|
164
|
+
"kernelUnitLength",
|
|
165
|
+
"keyPoints",
|
|
166
|
+
"keySplines",
|
|
167
|
+
"keyTimes",
|
|
168
|
+
"lengthAdjust",
|
|
169
|
+
"limitingConeAngle",
|
|
170
|
+
"markerHeight",
|
|
171
|
+
"markerUnits",
|
|
172
|
+
"markerWidth",
|
|
173
|
+
"maskContentUnits",
|
|
174
|
+
"maskUnits",
|
|
175
|
+
"numOctaves",
|
|
176
|
+
"pathLength",
|
|
177
|
+
"patternContentUnits",
|
|
178
|
+
"patternTransform",
|
|
179
|
+
"patternUnits",
|
|
180
|
+
"pointsAtX",
|
|
181
|
+
"pointsAtY",
|
|
182
|
+
"pointsAtZ",
|
|
183
|
+
"preserveAlpha",
|
|
184
|
+
"preserveAspectRatio",
|
|
185
|
+
"primitiveUnits",
|
|
186
|
+
"refX",
|
|
187
|
+
"refY",
|
|
188
|
+
"repeatCount",
|
|
189
|
+
"repeatDur",
|
|
190
|
+
"requiredExtensions",
|
|
191
|
+
"requiredFeatures",
|
|
192
|
+
"specularConstant",
|
|
193
|
+
"specularExponent",
|
|
194
|
+
"spreadMethod",
|
|
195
|
+
"startOffset",
|
|
196
|
+
"stdDeviation",
|
|
197
|
+
"stitchTiles",
|
|
198
|
+
"surfaceScale",
|
|
199
|
+
"systemLanguage",
|
|
200
|
+
"tableValues",
|
|
201
|
+
"targetX",
|
|
202
|
+
"targetY",
|
|
203
|
+
"textLength",
|
|
204
|
+
"viewBox",
|
|
205
|
+
"viewTarget",
|
|
206
|
+
"xChannelSelector",
|
|
207
|
+
"yChannelSelector",
|
|
208
|
+
"zoomAndPan"
|
|
209
|
+
].map((attr) => [attr.toLowerCase(), attr])
|
|
210
|
+
);
|
|
211
|
+
function remapAttributeName(attrName) {
|
|
212
|
+
const remapped = SVG_ATTRS_ADJUSTMENT_MAP.get(attrName.toLowerCase());
|
|
213
|
+
if (remapped) {
|
|
214
|
+
return remapped;
|
|
215
|
+
}
|
|
216
|
+
return attrName;
|
|
217
|
+
}
|
|
218
|
+
function createElementWithSVGSupport(tag, options = {}) {
|
|
219
|
+
let filteredTag = tag.toLowerCase();
|
|
220
|
+
if (ALWAYS_DISALLOWED_TAGS.has(filteredTag.toLowerCase())) {
|
|
221
|
+
console.error("Disallowing tag", filteredTag);
|
|
222
|
+
filteredTag = options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`;
|
|
223
|
+
}
|
|
224
|
+
let svgTagMapping;
|
|
225
|
+
if (options.allowSVGElements) {
|
|
226
|
+
svgTagMapping = SVG_TAG_NAMES_ADJUSTMENT_MAP.get(filteredTag);
|
|
227
|
+
}
|
|
228
|
+
if (svgTagMapping) {
|
|
229
|
+
filteredTag = svgTagMapping;
|
|
230
|
+
const xmlns = "http://www.w3.org/2000/svg";
|
|
231
|
+
return document.createElementNS(xmlns, filteredTag);
|
|
232
|
+
} else {
|
|
233
|
+
if (options.tagPrefix) {
|
|
234
|
+
if (!tag.toLowerCase().startsWith(options.tagPrefix.toLowerCase())) {
|
|
235
|
+
filteredTag = options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return document.createElement(filteredTag);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function setElementAttribute(element, key, value) {
|
|
242
|
+
if (DOMSanitizer.shouldAcceptAttribute(key)) {
|
|
243
|
+
const remappedKey = remapAttributeName(key);
|
|
244
|
+
element.setAttribute(remappedKey, value);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
function getChildrenTarget(parent) {
|
|
248
|
+
let targetForChildren = parent;
|
|
249
|
+
if (parent.getPortalElement) {
|
|
250
|
+
targetForChildren = parent.getPortalElement();
|
|
251
|
+
}
|
|
252
|
+
return targetForChildren;
|
|
253
|
+
}
|
|
254
|
+
function getRemovalTarget(parent) {
|
|
255
|
+
let targetForRemoval = parent;
|
|
256
|
+
if (parent.getPortalElement) {
|
|
257
|
+
targetForRemoval = parent.getPortalElement();
|
|
258
|
+
}
|
|
259
|
+
return targetForRemoval;
|
|
260
|
+
}
|
|
261
|
+
|
|
93
262
|
// src/NetworkedDOMWebsocketV01Adapter.ts
|
|
94
263
|
var NetworkedDOMWebsocketV01Adapter = class {
|
|
95
264
|
constructor(websocket, parentElement, connectedCallback, timeCallback, options = {}) {
|
|
@@ -209,6 +378,7 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
209
378
|
if (!isHTMLElement(parent, this.parentElement)) {
|
|
210
379
|
throw new Error("Parent is not an HTMLElement (that supports children)");
|
|
211
380
|
}
|
|
381
|
+
const targetForChildren = getChildrenTarget(parent);
|
|
212
382
|
let nextElement = null;
|
|
213
383
|
let previousElement = null;
|
|
214
384
|
if (previousNodeId) {
|
|
@@ -230,12 +400,12 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
230
400
|
if (nextElement) {
|
|
231
401
|
const docFrag = new DocumentFragment();
|
|
232
402
|
docFrag.append(...elementsToAdd);
|
|
233
|
-
|
|
403
|
+
targetForChildren.insertBefore(docFrag, nextElement);
|
|
234
404
|
} else {
|
|
235
|
-
|
|
405
|
+
targetForChildren.append(...elementsToAdd);
|
|
236
406
|
}
|
|
237
407
|
} else {
|
|
238
|
-
|
|
408
|
+
targetForChildren.prepend(...elementsToAdd);
|
|
239
409
|
}
|
|
240
410
|
}
|
|
241
411
|
for (const removedNode of removedNodes) {
|
|
@@ -245,15 +415,20 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
245
415
|
}
|
|
246
416
|
this.elementToId.delete(childElement);
|
|
247
417
|
this.idToElement.delete(removedNode);
|
|
248
|
-
parent
|
|
418
|
+
const targetForRemoval = getRemovalTarget(parent);
|
|
419
|
+
targetForRemoval.removeChild(childElement);
|
|
249
420
|
if (isHTMLElement(childElement, this.parentElement)) {
|
|
250
421
|
this.removeChildElementIds(childElement);
|
|
251
422
|
}
|
|
252
423
|
}
|
|
253
424
|
}
|
|
254
425
|
removeChildElementIds(parent) {
|
|
255
|
-
|
|
256
|
-
|
|
426
|
+
const portal = getChildrenTarget(parent);
|
|
427
|
+
if (portal !== parent) {
|
|
428
|
+
this.removeChildElementIds(portal);
|
|
429
|
+
}
|
|
430
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
431
|
+
const child = parent.childNodes[i];
|
|
257
432
|
const childId = this.elementToId.get(child);
|
|
258
433
|
if (!childId) {
|
|
259
434
|
console.error("Inner child of removed element had no id", child);
|
|
@@ -293,9 +468,7 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
293
468
|
if (newValue === null) {
|
|
294
469
|
element.removeAttribute(attribute);
|
|
295
470
|
} else {
|
|
296
|
-
|
|
297
|
-
element.setAttribute(attribute, newValue);
|
|
298
|
-
}
|
|
471
|
+
setElementAttribute(element, attribute, newValue);
|
|
299
472
|
}
|
|
300
473
|
} else {
|
|
301
474
|
console.error("Element is not an HTMLElement and cannot support attributes", element);
|
|
@@ -334,13 +507,7 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
334
507
|
}
|
|
335
508
|
let element;
|
|
336
509
|
try {
|
|
337
|
-
|
|
338
|
-
if (this.options.tagPrefix) {
|
|
339
|
-
if (!tag.toLowerCase().startsWith(this.options.tagPrefix.toLowerCase())) {
|
|
340
|
-
filteredTag = this.options.replacementTagPrefix ? this.options.replacementTagPrefix + tag : `x-${tag}`;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
element = document.createElement(filteredTag);
|
|
510
|
+
element = createElementWithSVGSupport(tag, this.options);
|
|
344
511
|
} catch (e) {
|
|
345
512
|
console.error(`Error creating element: (${tag})`, e);
|
|
346
513
|
element = document.createElement("x-div");
|
|
@@ -348,10 +515,8 @@ var NetworkedDOMWebsocketV01Adapter = class {
|
|
|
348
515
|
this.idToElement.set(nodeId, element);
|
|
349
516
|
this.elementToId.set(element, nodeId);
|
|
350
517
|
for (const key in attributes) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
element.setAttribute(key, value);
|
|
354
|
-
}
|
|
518
|
+
const value = attributes[key];
|
|
519
|
+
setElementAttribute(element, key, value);
|
|
355
520
|
}
|
|
356
521
|
if (children) {
|
|
357
522
|
for (const child of children) {
|
|
@@ -370,7 +535,8 @@ import {
|
|
|
370
535
|
BufferReader,
|
|
371
536
|
BufferWriter,
|
|
372
537
|
decodeServerMessages,
|
|
373
|
-
encodeClientMessage
|
|
538
|
+
encodeClientMessage,
|
|
539
|
+
getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow
|
|
374
540
|
} from "@mml-io/networked-dom-protocol";
|
|
375
541
|
var connectionId = 1;
|
|
376
542
|
var hiddenTag = "x-hidden";
|
|
@@ -388,7 +554,14 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
388
554
|
this.batchMode = false;
|
|
389
555
|
this.batchMessages = [];
|
|
390
556
|
this.websocket.binaryType = "arraybuffer";
|
|
391
|
-
this.
|
|
557
|
+
this.protocolSubversion = getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow(
|
|
558
|
+
websocket.protocol
|
|
559
|
+
);
|
|
560
|
+
this.send({
|
|
561
|
+
type: "connectUsers",
|
|
562
|
+
connectionIds: [connectionId],
|
|
563
|
+
connectionTokens: [this.options.connectionToken ?? null]
|
|
564
|
+
});
|
|
392
565
|
}
|
|
393
566
|
handleEvent(element, event) {
|
|
394
567
|
const nodeId = this.elementToId.get(element);
|
|
@@ -412,7 +585,7 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
412
585
|
}
|
|
413
586
|
send(message) {
|
|
414
587
|
const writer = new BufferWriter(256);
|
|
415
|
-
encodeClientMessage(message, writer);
|
|
588
|
+
encodeClientMessage(message, writer, this.protocolSubversion);
|
|
416
589
|
this.websocket.send(writer.getBuffer());
|
|
417
590
|
}
|
|
418
591
|
clearContents() {
|
|
@@ -553,6 +726,7 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
553
726
|
if (!isHTMLElement(parent, this.parentElement)) {
|
|
554
727
|
throw new Error("Parent is not an HTMLElement (that supports children)");
|
|
555
728
|
}
|
|
729
|
+
const targetForChildren = getChildrenTarget(parent);
|
|
556
730
|
let nextElement = null;
|
|
557
731
|
let previousElement = null;
|
|
558
732
|
if (previousNodeId) {
|
|
@@ -574,12 +748,12 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
574
748
|
if (nextElement) {
|
|
575
749
|
const docFrag = new DocumentFragment();
|
|
576
750
|
docFrag.append(...elementsToAdd);
|
|
577
|
-
|
|
751
|
+
targetForChildren.insertBefore(docFrag, nextElement);
|
|
578
752
|
} else {
|
|
579
|
-
|
|
753
|
+
targetForChildren.append(...elementsToAdd);
|
|
580
754
|
}
|
|
581
755
|
} else {
|
|
582
|
-
|
|
756
|
+
targetForChildren.prepend(...elementsToAdd);
|
|
583
757
|
}
|
|
584
758
|
}
|
|
585
759
|
}
|
|
@@ -607,15 +781,20 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
607
781
|
this.elementToId.delete(childElement);
|
|
608
782
|
this.idToElement.delete(removedNode);
|
|
609
783
|
this.hiddenPlaceholderElements.delete(removedNode);
|
|
610
|
-
parent
|
|
784
|
+
const targetForRemoval = getRemovalTarget(parent);
|
|
785
|
+
targetForRemoval.removeChild(childElement);
|
|
611
786
|
if (isHTMLElement(childElement, this.parentElement)) {
|
|
612
787
|
this.removeChildElementIds(childElement);
|
|
613
788
|
}
|
|
614
789
|
}
|
|
615
790
|
}
|
|
616
791
|
removeChildElementIds(parent) {
|
|
617
|
-
|
|
618
|
-
|
|
792
|
+
const portal = getChildrenTarget(parent);
|
|
793
|
+
if (portal !== parent) {
|
|
794
|
+
this.removeChildElementIds(portal);
|
|
795
|
+
}
|
|
796
|
+
for (let i = 0; i < parent.childNodes.length; i++) {
|
|
797
|
+
const child = parent.childNodes[i];
|
|
619
798
|
const childId = this.elementToId.get(child);
|
|
620
799
|
if (!childId) {
|
|
621
800
|
console.error("Inner child of removed element had no id", child);
|
|
@@ -667,9 +846,7 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
667
846
|
if (newValue === null) {
|
|
668
847
|
element.removeAttribute(key);
|
|
669
848
|
} else {
|
|
670
|
-
|
|
671
|
-
element.setAttribute(key, newValue);
|
|
672
|
-
}
|
|
849
|
+
setElementAttribute(element, key, newValue);
|
|
673
850
|
}
|
|
674
851
|
}
|
|
675
852
|
} else {
|
|
@@ -706,22 +883,14 @@ var NetworkedDOMWebsocketV02Adapter = class {
|
|
|
706
883
|
}
|
|
707
884
|
let element;
|
|
708
885
|
try {
|
|
709
|
-
|
|
710
|
-
if (this.options.tagPrefix) {
|
|
711
|
-
if (!tag.toLowerCase().startsWith(this.options.tagPrefix.toLowerCase())) {
|
|
712
|
-
filteredTag = this.options.replacementTagPrefix ? this.options.replacementTagPrefix + tag : `x-${tag}`;
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
element = document.createElement(filteredTag);
|
|
886
|
+
element = createElementWithSVGSupport(tag, this.options);
|
|
716
887
|
} catch (e) {
|
|
717
888
|
console.error(`Error creating element: (${tag})`, e);
|
|
718
889
|
element = document.createElement("x-div");
|
|
719
890
|
}
|
|
720
891
|
for (const [key, value] of attributes) {
|
|
721
892
|
if (value !== null) {
|
|
722
|
-
|
|
723
|
-
element.setAttribute(key, value);
|
|
724
|
-
}
|
|
893
|
+
setElementAttribute(element, key, value);
|
|
725
894
|
}
|
|
726
895
|
}
|
|
727
896
|
if (children) {
|
|
@@ -800,7 +969,7 @@ var NetworkedDOMWebsocket = class {
|
|
|
800
969
|
}
|
|
801
970
|
static createWebSocket(url) {
|
|
802
971
|
return new WebSocket(url, [
|
|
803
|
-
|
|
972
|
+
...networkedDOMProtocolSubProtocol_v0_2_SubVersionsList,
|
|
804
973
|
networkedDOMProtocolSubProtocol_v0_1
|
|
805
974
|
]);
|
|
806
975
|
}
|
|
@@ -823,7 +992,7 @@ var NetworkedDOMWebsocket = class {
|
|
|
823
992
|
websocket.addEventListener("open", () => {
|
|
824
993
|
clearTimeout(timeoutId);
|
|
825
994
|
this.websocket = websocket;
|
|
826
|
-
const isV02 = websocket.protocol
|
|
995
|
+
const isV02 = isNetworkedDOMProtocolSubProtocol_v0_2(websocket.protocol);
|
|
827
996
|
let websocketAdapter;
|
|
828
997
|
if (isV02) {
|
|
829
998
|
websocketAdapter = new NetworkedDOMWebsocketV02Adapter(
|
|
@@ -937,7 +1106,7 @@ var NetworkedDOMWebsocket = class {
|
|
|
937
1106
|
}
|
|
938
1107
|
};
|
|
939
1108
|
function isHTMLElement(node, rootNode) {
|
|
940
|
-
if (node instanceof HTMLElement) {
|
|
1109
|
+
if (node instanceof HTMLElement || node instanceof Element) {
|
|
941
1110
|
return true;
|
|
942
1111
|
}
|
|
943
1112
|
if (!rootNode.ownerDocument.defaultView) {
|
package/build/index.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../src/DOMSanitizer.ts", "../src/NetworkedDOMWebsocket.ts", "../src/NetworkedDOMWebsocketV01Adapter.ts", "../src/NetworkedDOMWebsocketV02Adapter.ts"],
|
|
4
|
-
"sourcesContent": ["export type DOMSanitizerOptions = {\n tagPrefix?: string; // e.g. \"m-\" to restrict to only custom elements with a tag name starting with \"m-\"\n replacementTagPrefix?: string; // e.g. \"x-\" to replace non-prefixed tags with a new prefix (e.g. \"div\" -> \"x-div\")\n};\n\nexport class DOMSanitizer {\n static sanitise(node: HTMLElement, options: DOMSanitizerOptions = {}) {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n if (!DOMSanitizer.IsValidAttributeName(attr)) {\n node.removeAttribute(attr);\n }\n }\n }\n\n if (node instanceof HTMLElement) {\n if (options.tagPrefix) {\n const tag = node.nodeName.toLowerCase();\n if (!tag.startsWith(options.tagPrefix.toLowerCase())) {\n node = DOMSanitizer.replaceNodeTagName(\n node,\n options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`,\n );\n }\n }\n }\n\n if (node.nodeName === \"SCRIPT\" || node.nodeName === \"OBJECT\" || node.nodeName === \"IFRAME\") {\n // set contents to empty string\n node.innerHTML = \"\";\n DOMSanitizer.stripAllAttributes(node);\n } else {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n if (!DOMSanitizer.shouldAcceptAttribute(attr)) {\n node.removeAttribute(attr);\n }\n }\n }\n for (let i = 0; i < node.childNodes.length; i++) {\n DOMSanitizer.sanitise(node.childNodes[i] as HTMLElement, options);\n }\n }\n return node;\n }\n\n static replaceNodeTagName(node: HTMLElement, newTagName: string) {\n const replacementNode = document.createElement(newTagName);\n let index;\n while (node.firstChild) {\n replacementNode.appendChild(node.firstChild);\n }\n for (index = node.attributes.length - 1; index >= 0; --index) {\n replacementNode.setAttribute(node.attributes[index].name, node.attributes[index].value);\n }\n node.parentNode?.replaceChild(replacementNode, node);\n return replacementNode;\n }\n\n static stripAllAttributes(node: HTMLElement) {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n node.removeAttribute(attr);\n }\n }\n }\n\n static IsASCIIDigit(c: string): boolean {\n return c >= \"0\" && c <= \"9\";\n }\n\n static IsASCIIAlpha(c: string) {\n return c >= \"a\" && c <= \"z\";\n }\n\n static IsValidAttributeName(characters: string): boolean {\n const c = characters[0];\n if (!(DOMSanitizer.IsASCIIAlpha(c) || c === \":\" || c === \"_\")) {\n return false;\n }\n\n for (let i = 1; i < characters.length; i++) {\n const c = characters[i];\n if (\n !(\n DOMSanitizer.IsASCIIDigit(c) ||\n DOMSanitizer.IsASCIIAlpha(c) ||\n c === \":\" ||\n c === \"_\" ||\n c === \"-\" ||\n c === \".\"\n )\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n static shouldAcceptAttribute(attribute: string) {\n if (!DOMSanitizer.IsValidAttributeName(attribute)) {\n console.warn(\"Invalid attribute name\", attribute);\n return false;\n }\n\n // TODO - this might be overly restrictive - apologies to someone that finds this because you have a non-event attribute filtered by this\n return !attribute.startsWith(\"on\");\n }\n}\n", "import {\n networkedDOMProtocolSubProtocol_v0_1,\n networkedDOMProtocolSubProtocol_v0_2,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport { NetworkedDOMWebsocketV01Adapter } from \"./NetworkedDOMWebsocketV01Adapter\";\nimport { NetworkedDOMWebsocketV02Adapter } from \"./NetworkedDOMWebsocketV02Adapter\";\n\nconst startingBackoffTimeMilliseconds = 100;\nconst maximumBackoffTimeMilliseconds = 10000;\nconst maximumWebsocketConnectionTimeout = 5000;\n\nexport type NetworkedDOMWebsocketFactory = (url: string) => WebSocket;\n\nexport enum NetworkedDOMWebsocketStatus {\n Connecting,\n ConnectionOpen, // The websocket is open and connected, but no messages have been received yet\n Connected, // The websocket is open and connected, and messages are being received\n Reconnecting,\n Disconnected,\n}\n\nexport function NetworkedDOMWebsocketStatusToString(status: NetworkedDOMWebsocketStatus): string {\n switch (status) {\n case NetworkedDOMWebsocketStatus.Connecting:\n return \"Connecting...\";\n case NetworkedDOMWebsocketStatus.ConnectionOpen:\n return \"Connection Open\";\n case NetworkedDOMWebsocketStatus.Connected:\n return \"Connected\";\n case NetworkedDOMWebsocketStatus.Reconnecting:\n return \"Reconnecting...\";\n case NetworkedDOMWebsocketStatus.Disconnected:\n return \"Disconnected\";\n default:\n return \"Unknown\";\n }\n}\n\nexport type NetworkedDOMWebsocketOptions = {\n tagPrefix?: string; // e.g. \"m-\" to restrict to only custom elements with a tag name starting with \"m-\"\n replacementTagPrefix?: string; // e.g. \"x-\" to replace non-prefixed tags with a new prefix (e.g. \"div\" -> \"x-div\")\n};\n\nexport type NetworkedDOMWebsocketAdapter = {\n receiveMessage: (message: MessageEvent) => void;\n handleEvent: (element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) => void;\n clearContents: () => boolean;\n};\n\n/**\n * NetworkedDOMWebsocket is a client for a NetworkedDOMServer. It connects to a server on the provided url and receives\n * updates to the DOM. It also sends events to the server for interactions with the DOM.\n *\n * The NetworkedDOMWebsocket is attached to a parentElement and synchronizes the received DOM under that element.\n */\nexport class NetworkedDOMWebsocket {\n private websocket: WebSocket | null = null;\n private websocketAdapter: NetworkedDOMWebsocketAdapter | null = null;\n\n private stopped = false;\n private backoffTime = startingBackoffTimeMilliseconds;\n private status: NetworkedDOMWebsocketStatus | null = null;\n\n public static createWebSocket(url: string): WebSocket {\n return new WebSocket(url, [\n networkedDOMProtocolSubProtocol_v0_2,\n networkedDOMProtocolSubProtocol_v0_1,\n ]);\n }\n\n constructor(\n private url: string,\n private websocketFactory: NetworkedDOMWebsocketFactory,\n private parentElement: HTMLElement,\n private timeCallback?: (time: number) => void,\n private statusUpdateCallback?: (status: NetworkedDOMWebsocketStatus) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.setStatus(NetworkedDOMWebsocketStatus.Connecting);\n this.startWebSocketConnectionAttempt();\n }\n\n private setStatus(status: NetworkedDOMWebsocketStatus) {\n if (this.status !== status) {\n this.status = status;\n if (this.statusUpdateCallback) {\n this.statusUpdateCallback(status);\n }\n }\n }\n\n private createWebsocketWithTimeout(timeout: number): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const websocket = this.websocketFactory(this.url);\n const timeoutId = setTimeout(() => {\n reject(new Error(\"websocket connection timed out\"));\n websocket.close();\n }, timeout);\n websocket.binaryType = \"arraybuffer\";\n websocket.addEventListener(\"open\", () => {\n clearTimeout(timeoutId);\n\n this.websocket = websocket;\n const isV02 = websocket.protocol === networkedDOMProtocolSubProtocol_v0_2;\n let websocketAdapter: NetworkedDOMWebsocketAdapter;\n if (isV02) {\n websocketAdapter = new NetworkedDOMWebsocketV02Adapter(\n websocket,\n this.parentElement,\n () => {\n this.backoffTime = startingBackoffTimeMilliseconds;\n this.setStatus(NetworkedDOMWebsocketStatus.Connected);\n },\n this.timeCallback,\n this.options,\n );\n } else {\n websocketAdapter = new NetworkedDOMWebsocketV01Adapter(\n websocket,\n this.parentElement,\n () => {\n this.backoffTime = startingBackoffTimeMilliseconds;\n this.setStatus(NetworkedDOMWebsocketStatus.Connected);\n },\n this.timeCallback,\n this.options,\n );\n }\n this.websocketAdapter = websocketAdapter;\n\n websocket.addEventListener(\"message\", (event) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket message event because it is no longer current\");\n websocket.close();\n return;\n }\n websocketAdapter.receiveMessage(event);\n });\n\n const onWebsocketClose = async () => {\n let hadContents = false;\n if (this.websocketAdapter) {\n hadContents = this.websocketAdapter.clearContents();\n }\n if (this.stopped) {\n // This closing is expected. The client closed the websocket.\n this.setStatus(NetworkedDOMWebsocketStatus.Disconnected);\n return;\n }\n if (!hadContents) {\n // The websocket did not deliver any contents. It may have been successfully opened, but immediately closed. This client should back off to prevent this happening in a rapid loop.\n await this.waitBackoffTime();\n }\n // The websocket closed unexpectedly. Try to reconnect.\n this.setStatus(NetworkedDOMWebsocketStatus.Reconnecting);\n this.startWebSocketConnectionAttempt();\n };\n\n websocket.addEventListener(\"close\", () => {\n if (websocket !== this.websocket) {\n console.warn(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n onWebsocketClose();\n });\n websocket.addEventListener(\"error\", (e) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket error event because it is no longer current\");\n return;\n }\n console.error(\"NetworkedDOMWebsocket error\", e);\n onWebsocketClose();\n });\n\n this.setStatus(NetworkedDOMWebsocketStatus.ConnectionOpen);\n resolve(websocket);\n });\n websocket.addEventListener(\"error\", (e) => {\n clearTimeout(timeoutId);\n reject(e);\n });\n });\n }\n\n private async waitBackoffTime(): Promise<void> {\n console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);\n await new Promise((resolve) => setTimeout(resolve, this.backoffTime));\n this.backoffTime = Math.min(\n // Introduce a small amount of randomness to prevent clients from retrying in lockstep\n this.backoffTime * (1.5 + Math.random() * 0.5),\n maximumBackoffTimeMilliseconds,\n );\n }\n\n private async startWebSocketConnectionAttempt() {\n if (this.stopped) {\n return;\n }\n while (true) {\n if (this.stopped) {\n return;\n }\n try {\n await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);\n break;\n } catch (e) {\n console.error(\"Websocket connection failed\", e);\n // Connection failed, retry with backoff\n this.setStatus(NetworkedDOMWebsocketStatus.Reconnecting);\n await this.waitBackoffTime();\n }\n }\n }\n\n public stop() {\n this.stopped = true;\n if (this.websocket !== null) {\n this.websocket.close();\n this.websocket = null;\n }\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n if (this.websocketAdapter) {\n this.websocketAdapter.handleEvent(element, event);\n }\n }\n}\n\nexport function isHTMLElement(node: unknown, rootNode: HTMLElement): node is HTMLElement {\n if (node instanceof HTMLElement) {\n return true;\n }\n if (!rootNode.ownerDocument.defaultView) {\n return false;\n }\n return node instanceof rootNode.ownerDocument.defaultView.HTMLElement;\n}\n\nexport function isText(node: unknown, rootNode: HTMLElement): node is Text {\n if (node instanceof Text) {\n return true;\n }\n if (!rootNode.ownerDocument.defaultView) {\n return false;\n }\n return node instanceof rootNode.ownerDocument.defaultView.Text;\n}\n", "import {\n NetworkedDOMV01AttributeChangedDiff,\n NetworkedDOMV01ChildrenChangedDiff,\n NetworkedDOMV01ClientMessage,\n NetworkedDOMV01NodeDescription,\n NetworkedDOMV01RemoteEvent,\n NetworkedDOMV01ServerMessage,\n NetworkedDOMV01SnapshotMessage,\n NetworkedDOMV01TextChangedDiff,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport { DOMSanitizer } from \"./DOMSanitizer\";\nimport {\n isHTMLElement,\n isText,\n NetworkedDOMWebsocketAdapter,\n NetworkedDOMWebsocketOptions,\n} from \"./NetworkedDOMWebsocket\";\n\nexport class NetworkedDOMWebsocketV01Adapter implements NetworkedDOMWebsocketAdapter {\n private idToElement = new Map<number, Node>();\n private elementToId = new Map<Node, number>();\n private currentRoot: HTMLElement | null = null;\n\n constructor(\n private websocket: WebSocket,\n private parentElement: HTMLElement,\n private connectedCallback: () => void,\n private timeCallback?: (time: number) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.websocket.binaryType = \"arraybuffer\";\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n const nodeId = this.elementToId.get(element);\n if (nodeId === undefined || nodeId === null) {\n throw new Error(\"Element not found\");\n }\n\n const detailWithoutElement: Partial<typeof event.detail> = {\n ...event.detail,\n };\n delete detailWithoutElement.element;\n\n const remoteEvent: NetworkedDOMV01RemoteEvent = {\n type: \"event\",\n nodeId,\n name: event.type,\n bubbles: event.bubbles,\n params: detailWithoutElement,\n };\n\n this.send(remoteEvent);\n }\n\n private send(fromClientMessage: NetworkedDOMV01ClientMessage) {\n this.websocket.send(JSON.stringify(fromClientMessage));\n }\n\n public clearContents(): boolean {\n this.idToElement.clear();\n this.elementToId.clear();\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n return true;\n }\n return false;\n }\n\n receiveMessage(event: MessageEvent) {\n const messages = JSON.parse(event.data) as Array<NetworkedDOMV01ServerMessage>;\n for (const message of messages) {\n switch (message.type) {\n case \"error\":\n console.error(\"Error from server\", message);\n break;\n case \"warning\":\n console.warn(\"Warning from server\", message);\n break;\n default: {\n if (message.documentTime) {\n if (this.timeCallback) {\n this.timeCallback(message.documentTime);\n }\n }\n switch (message.type) {\n case \"snapshot\":\n this.handleSnapshot(message);\n this.connectedCallback();\n break;\n case \"attributeChange\":\n this.handleAttributeChange(message);\n break;\n case \"childrenChanged\":\n this.handleChildrenChanged(message);\n break;\n case \"textChanged\":\n this.handleTextChanged(message);\n break;\n case \"ping\":\n this.send({\n type: \"pong\",\n pong: message.ping,\n });\n break;\n default:\n console.warn(\"unknown message type\", message);\n break;\n }\n }\n }\n }\n }\n\n private handleTextChanged(message: NetworkedDOMV01TextChangedDiff) {\n const { nodeId, text } = message;\n\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in textChanged message\");\n return;\n }\n const node = this.idToElement.get(nodeId);\n if (!node) {\n throw new Error(\"No node found for textChanged message\");\n }\n if (!isText(node, this.parentElement)) {\n throw new Error(\"Node for textChanged message is not a Text node\");\n }\n node.textContent = text;\n }\n\n private handleChildrenChanged(message: NetworkedDOMV01ChildrenChangedDiff) {\n const { nodeId, addedNodes, removedNodes, previousNodeId } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n const parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n let nextElement = null;\n let previousElement = null;\n if (previousNodeId) {\n previousElement = this.idToElement.get(previousNodeId);\n if (!previousElement) {\n throw new Error(\"No previous element found for childrenChanged message\");\n }\n nextElement = previousElement.nextSibling;\n }\n\n const elementsToAdd = [];\n for (const addedNode of addedNodes) {\n const childElement = this.handleNewElement(addedNode);\n if (childElement) {\n elementsToAdd.push(childElement);\n }\n }\n if (elementsToAdd.length) {\n if (previousElement) {\n if (nextElement) {\n // There is a previous and next element - insertBefore the next element\n const docFrag = new DocumentFragment();\n docFrag.append(...elementsToAdd);\n parent.insertBefore(docFrag, nextElement);\n } else {\n // No next element - must be the last children\n parent.append(...elementsToAdd);\n }\n } else {\n // No previous element - must be the first children\n parent.prepend(...elementsToAdd);\n }\n }\n for (const removedNode of removedNodes) {\n const childElement = this.idToElement.get(removedNode);\n if (!childElement) {\n throw new Error(`Child element not found: ${removedNode}`);\n }\n this.elementToId.delete(childElement);\n this.idToElement.delete(removedNode);\n parent.removeChild(childElement);\n if (isHTMLElement(childElement, this.parentElement)) {\n // If child is capable of supporting children then remove any that exist\n this.removeChildElementIds(childElement);\n }\n }\n }\n\n private removeChildElementIds(parent: HTMLElement) {\n for (let i = 0; i < parent.children.length; i++) {\n const child = parent.children[i];\n const childId = this.elementToId.get(child as HTMLElement);\n if (!childId) {\n console.error(\"Inner child of removed element had no id\", child);\n } else {\n this.elementToId.delete(child);\n this.idToElement.delete(childId);\n }\n this.removeChildElementIds(child as HTMLElement);\n }\n }\n\n private handleSnapshot(message: NetworkedDOMV01SnapshotMessage) {\n // This websocket is successfully connected. Reset the backoff time.\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n this.elementToId.clear();\n this.idToElement.clear();\n }\n\n // create a tree of DOM elements\n // NOTE: the MElement constructors are not executed during this stage\n const element = this.handleNewElement(message.snapshot);\n if (!element) {\n throw new Error(\"Snapshot element not created\");\n }\n if (!isHTMLElement(element, this.parentElement)) {\n throw new Error(\"Snapshot element is not an HTMLElement\");\n }\n this.currentRoot = element;\n // appending to the tree causes MElements to be constructed\n this.parentElement.append(element);\n }\n\n private handleAttributeChange(message: NetworkedDOMV01AttributeChangedDiff) {\n const { nodeId, attribute, newValue } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in attributeChange message\");\n return;\n }\n const element = this.idToElement.get(nodeId);\n if (element) {\n if (isHTMLElement(element, this.parentElement)) {\n if (newValue === null) {\n element.removeAttribute(attribute);\n } else {\n if (DOMSanitizer.shouldAcceptAttribute(attribute)) {\n element.setAttribute(attribute, newValue);\n }\n }\n } else {\n console.error(\"Element is not an HTMLElement and cannot support attributes\", element);\n }\n } else {\n console.error(\"No element found for attributeChange message\");\n }\n }\n\n private handleNewElement(message: NetworkedDOMV01NodeDescription): Node | null {\n if (message.type === \"text\") {\n const { nodeId, text } = message;\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n const { tag, nodeId, attributes, children, text } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in handleNewElement message\", message);\n return null;\n }\n if (this.idToElement.has(nodeId)) {\n console.error(\n \"Received nodeId to add that is already present\",\n nodeId,\n this.idToElement.get(nodeId),\n );\n }\n if (tag === \"#text\") {\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text || null;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n\n let element;\n try {\n let filteredTag = tag;\n if (this.options.tagPrefix) {\n if (!tag.toLowerCase().startsWith(this.options.tagPrefix.toLowerCase())) {\n filteredTag = this.options.replacementTagPrefix\n ? this.options.replacementTagPrefix + tag\n : `x-${tag}`;\n }\n }\n element = document.createElement(filteredTag);\n } catch (e) {\n console.error(`Error creating element: (${tag})`, e);\n element = document.createElement(\"x-div\");\n }\n this.idToElement.set(nodeId, element);\n this.elementToId.set(element, nodeId);\n for (const key in attributes) {\n if (DOMSanitizer.shouldAcceptAttribute(key)) {\n const value = attributes[key];\n element.setAttribute(key, value);\n }\n }\n if (children) {\n for (const child of children) {\n const childElement = this.handleNewElement(child);\n if (childElement) {\n element.append(childElement);\n }\n }\n }\n return element;\n }\n}\n", "import {\n BufferReader,\n BufferWriter,\n decodeServerMessages,\n encodeClientMessage,\n NetworkedDOMV02AttributesChangedDiff,\n NetworkedDOMV02ChangeHiddenFromDiff,\n NetworkedDOMV02ChildrenAddedDiff,\n NetworkedDOMV02ChildrenRemovedDiff,\n NetworkedDOMV02ClientMessage,\n NetworkedDOMV02DocumentTimeMessage,\n NetworkedDOMV02NodeDescription,\n NetworkedDOMV02PingMessage,\n NetworkedDOMV02RemoteEvent,\n NetworkedDOMV02ServerMessage,\n NetworkedDOMV02SnapshotMessage,\n NetworkedDOMV02TextChangedDiff,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport { DOMSanitizer } from \"./DOMSanitizer\";\nimport {\n isHTMLElement,\n isText,\n NetworkedDOMWebsocketAdapter,\n NetworkedDOMWebsocketOptions,\n} from \"./NetworkedDOMWebsocket\";\n\n// This client uses a single connection id\nconst connectionId = 1;\n\n// If an element should not be visible to this client, it will be replaced with this tag and attributes will be stored ready to be applied if it is unhidden.\nconst hiddenTag = \"x-hidden\";\n\nexport class NetworkedDOMWebsocketV02Adapter implements NetworkedDOMWebsocketAdapter {\n private idToElement = new Map<number, Node>();\n private elementToId = new Map<Node, number>();\n private hiddenPlaceholderElements = new Map<\n number,\n {\n placeholder: Node;\n element: Node;\n }\n >();\n private currentRoot: HTMLElement | null = null;\n private batchMode = false;\n private batchMessages: Array<NetworkedDOMV02ServerMessage> = [];\n\n constructor(\n private websocket: WebSocket,\n private parentElement: HTMLElement,\n private connectedCallback: () => void,\n private timeCallback?: (time: number) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.websocket.binaryType = \"arraybuffer\";\n this.send({ type: \"connectUsers\", connectionIds: [connectionId] });\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n const nodeId = this.elementToId.get(element);\n if (nodeId === undefined || nodeId === null) {\n console.error(\"Element not found for event\", { nodeId, element, event });\n return;\n }\n\n const detailWithoutElement: Partial<typeof event.detail> = {\n ...event.detail,\n };\n delete detailWithoutElement.element;\n\n const remoteEvent: NetworkedDOMV02RemoteEvent = {\n type: \"event\",\n nodeId,\n connectionId,\n name: event.type,\n bubbles: event.bubbles,\n params: detailWithoutElement,\n };\n\n this.send(remoteEvent);\n }\n\n private send(message: NetworkedDOMV02ClientMessage) {\n const writer = new BufferWriter(256);\n encodeClientMessage(message, writer);\n this.websocket.send(writer.getBuffer());\n }\n\n public clearContents(): boolean {\n this.idToElement.clear();\n this.elementToId.clear();\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n return true;\n }\n return false;\n }\n\n public receiveMessage(event: MessageEvent) {\n const reader = new BufferReader(new Uint8Array(event.data));\n const messages = decodeServerMessages(reader);\n for (const message of messages) {\n if (message.type === \"batchStart\") {\n // Need to wait for batchEnd before applying messages\n this.batchMode = true;\n } else if (message.type === \"batchEnd\") {\n // Apply all messages\n this.batchMode = false;\n for (const message of this.batchMessages) {\n this.applyMessage(message);\n }\n this.batchMessages = [];\n } else {\n if (this.batchMode) {\n this.batchMessages.push(message);\n } else {\n this.applyMessage(message);\n }\n }\n }\n }\n\n private applyMessage(message: NetworkedDOMV02ServerMessage) {\n switch (message.type) {\n case \"error\":\n console.error(\"Error from server\", message);\n break;\n case \"warning\":\n console.warn(\"Warning from server\", message);\n break;\n case \"snapshot\":\n this.handleSnapshot(message);\n this.connectedCallback();\n break;\n case \"attributesChanged\":\n this.handleAttributeChange(message);\n break;\n case \"documentTime\":\n this.handleDocumentTime(message);\n break;\n case \"childrenAdded\":\n this.handleChildrenAdded(message);\n break;\n case \"changeHiddenFrom\":\n this.handleChangeHiddenFrom(message);\n break;\n case \"changeVisibleTo\":\n // no-op for end user clients\n break;\n case \"childrenRemoved\":\n this.handleChildrenRemoved(message);\n break;\n case \"textChanged\":\n this.handleTextChanged(message);\n break;\n case \"ping\":\n this.handlePing(message);\n break;\n default:\n console.warn(\"unknown message type\", message);\n break;\n }\n }\n\n private handleTextChanged(message: NetworkedDOMV02TextChangedDiff) {\n const { nodeId, text } = message;\n\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in textChanged message\");\n return;\n }\n const node = this.idToElement.get(nodeId);\n if (!node) {\n throw new Error(\"No node found for textChanged message\");\n }\n if (!isText(node, this.parentElement)) {\n throw new Error(\"Node for textChanged message is not a Text node\");\n }\n node.textContent = text;\n }\n\n private handleChangeHiddenFrom(message: NetworkedDOMV02ChangeHiddenFromDiff) {\n const { nodeId, addHiddenFrom, removeHiddenFrom } = message;\n const node = this.idToElement.get(nodeId);\n const hiddenElement = this.hiddenPlaceholderElements.get(nodeId);\n if (addHiddenFrom.length > 0 && addHiddenFrom.indexOf(connectionId) !== -1) {\n // This element is being hidden\n if (hiddenElement) {\n // This element is already hidden\n return;\n }\n if (!node) {\n throw new Error(\"No node found for changeHiddenFrom message\");\n }\n const parent = node.parentElement;\n if (!parent) {\n throw new Error(\"Node has no parent\");\n }\n const placeholder = document.createElement(hiddenTag);\n parent.replaceChild(placeholder, node);\n this.hiddenPlaceholderElements.set(nodeId, { placeholder, element: node });\n } else if (removeHiddenFrom.length > 0 && removeHiddenFrom.indexOf(connectionId) !== -1) {\n // This element is being unhidden\n if (!hiddenElement) {\n // This element is not hidden\n return;\n }\n const { placeholder, element } = hiddenElement;\n const parent = placeholder.parentElement;\n if (!parent) {\n throw new Error(\"Placeholder has no parent\");\n }\n parent.replaceChild(element, placeholder);\n this.hiddenPlaceholderElements.delete(nodeId);\n }\n }\n\n private handleChildrenAdded(message: NetworkedDOMV02ChildrenAddedDiff) {\n const { nodeId, addedNodes, previousNodeId } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n let parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n\n const hiddenParent = this.hiddenPlaceholderElements.get(nodeId);\n if (hiddenParent) {\n // This element is hidden - add the children to the hidden element (not the placeholder)\n parent = hiddenParent.element;\n } else {\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n let nextElement = null;\n let previousElement = null;\n if (previousNodeId) {\n previousElement = this.idToElement.get(previousNodeId);\n if (!previousElement) {\n throw new Error(\"No previous element found for childrenChanged message\");\n }\n nextElement = previousElement.nextSibling;\n }\n\n const elementsToAdd = [];\n for (const addedNode of addedNodes) {\n const childElement = this.handleNewElement(addedNode);\n if (childElement) {\n elementsToAdd.push(childElement);\n }\n }\n if (elementsToAdd.length) {\n if (previousElement) {\n if (nextElement) {\n // There is a previous and next element - insertBefore the next element\n const docFrag = new DocumentFragment();\n docFrag.append(...elementsToAdd);\n parent.insertBefore(docFrag, nextElement);\n } else {\n // No next element - must be the last children\n parent.append(...elementsToAdd);\n }\n } else {\n // No previous element - must be the first children\n parent.prepend(...elementsToAdd);\n }\n }\n }\n\n private handleChildrenRemoved(message: NetworkedDOMV02ChildrenRemovedDiff) {\n const { nodeId, removedNodes } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n const parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n\n for (const removedNode of removedNodes) {\n const childElement = this.idToElement.get(removedNode);\n if (!childElement) {\n throw new Error(`Child element not found: ${removedNode}`);\n }\n this.elementToId.delete(childElement);\n this.idToElement.delete(removedNode);\n this.hiddenPlaceholderElements.delete(removedNode);\n parent.removeChild(childElement);\n if (isHTMLElement(childElement, this.parentElement)) {\n // If child is capable of supporting children then remove any that exist\n this.removeChildElementIds(childElement);\n }\n }\n }\n\n private removeChildElementIds(parent: HTMLElement) {\n for (let i = 0; i < parent.children.length; i++) {\n const child = parent.children[i];\n const childId = this.elementToId.get(child as HTMLElement);\n if (!childId) {\n console.error(\"Inner child of removed element had no id\", child);\n } else {\n this.elementToId.delete(child);\n this.idToElement.delete(childId);\n this.hiddenPlaceholderElements.delete(childId);\n }\n this.removeChildElementIds(child as HTMLElement);\n }\n }\n\n private handleSnapshot(message: NetworkedDOMV02SnapshotMessage) {\n // This websocket is successfully connected. Reset the backoff time.\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n this.elementToId.clear();\n this.idToElement.clear();\n }\n\n this.timeCallback?.(message.documentTime);\n\n // create a tree of DOM elements\n // NOTE: the MElement constructors are not executed during this stage\n const element = this.handleNewElement(message.snapshot);\n if (!element) {\n throw new Error(\"Snapshot element not created\");\n }\n if (!isHTMLElement(element, this.parentElement)) {\n throw new Error(\"Snapshot element is not an HTMLElement\");\n }\n this.currentRoot = element;\n // appending to the tree causes MElements to be constructed\n this.parentElement.append(element);\n }\n\n private handleDocumentTime(message: NetworkedDOMV02DocumentTimeMessage) {\n this.timeCallback?.(message.documentTime);\n }\n\n private handleAttributeChange(message: NetworkedDOMV02AttributesChangedDiff) {\n const { nodeId, attributes } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in attributeChange message\");\n return;\n }\n let element = this.idToElement.get(nodeId);\n const hiddenElement = this.hiddenPlaceholderElements.get(nodeId);\n if (hiddenElement) {\n // This element is hidden - apply the attributes to the hidden element\n element = hiddenElement.element;\n }\n if (element) {\n if (isHTMLElement(element, this.parentElement)) {\n for (const [key, newValue] of attributes) {\n if (newValue === null) {\n element.removeAttribute(key);\n } else {\n if (DOMSanitizer.shouldAcceptAttribute(key)) {\n element.setAttribute(key, newValue);\n }\n }\n }\n } else {\n console.error(\"Element is not an HTMLElement and cannot support attributes\", element);\n }\n } else {\n console.error(\"No element found for attributeChange message\");\n }\n }\n\n private handleNewElement(message: NetworkedDOMV02NodeDescription): Node | null {\n if (message.type === \"text\") {\n const { nodeId, text } = message;\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n const { tag, nodeId, attributes, children, text, hiddenFrom } = message;\n if (this.idToElement.has(nodeId)) {\n console.error(\n \"Received nodeId to add that is already present\",\n nodeId,\n this.idToElement.get(nodeId),\n );\n return null;\n }\n\n if (tag === \"#text\") {\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text || null;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n\n let element;\n try {\n let filteredTag = tag;\n if (this.options.tagPrefix) {\n if (!tag.toLowerCase().startsWith(this.options.tagPrefix.toLowerCase())) {\n filteredTag = this.options.replacementTagPrefix\n ? this.options.replacementTagPrefix + tag\n : `x-${tag}`;\n }\n }\n element = document.createElement(filteredTag);\n } catch (e) {\n console.error(`Error creating element: (${tag})`, e);\n element = document.createElement(\"x-div\");\n }\n for (const [key, value] of attributes) {\n if (value !== null) {\n if (DOMSanitizer.shouldAcceptAttribute(key)) {\n element.setAttribute(key, value);\n }\n }\n }\n if (children) {\n for (const child of children) {\n const childElement = this.handleNewElement(child);\n if (childElement) {\n element.append(childElement);\n }\n }\n }\n\n if (hiddenFrom && hiddenFrom.length > 0 && hiddenFrom.indexOf(connectionId) !== -1) {\n // This element is hidden - create a placeholder that will be in the DOM to maintain structure, but keep the underlying element hidden\n const placeholder = document.createElement(hiddenTag);\n this.idToElement.set(nodeId, placeholder);\n this.elementToId.set(placeholder, nodeId);\n this.hiddenPlaceholderElements.set(nodeId, { placeholder, element });\n return placeholder;\n } else {\n this.idToElement.set(nodeId, element);\n this.elementToId.set(element, nodeId);\n return element;\n }\n }\n\n private handlePing(message: NetworkedDOMV02PingMessage) {\n this.timeCallback?.(message.documentTime);\n this.send({\n type: \"pong\",\n pong: message.ping,\n });\n }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
3
|
+
"sources": ["../src/DOMSanitizer.ts", "../src/NetworkedDOMWebsocket.ts", "../src/ElementUtils.ts", "../src/NetworkedDOMWebsocketV01Adapter.ts", "../src/NetworkedDOMWebsocketV02Adapter.ts"],
|
|
4
|
+
"sourcesContent": ["export type DOMSanitizerOptions = {\n tagPrefix?: string; // e.g. \"m-\" to restrict to only custom elements with a tag name starting with \"m-\"\n replacementTagPrefix?: string; // e.g. \"x-\" to replace non-prefixed tags with a new prefix (e.g. \"div\" -> \"x-div\")\n};\n\nexport class DOMSanitizer {\n static sanitise(node: HTMLElement, options: DOMSanitizerOptions = {}) {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n if (!DOMSanitizer.IsValidAttributeName(attr)) {\n node.removeAttribute(attr);\n }\n }\n }\n\n if (node instanceof HTMLElement) {\n if (options.tagPrefix) {\n const tag = node.nodeName.toLowerCase();\n if (!tag.startsWith(options.tagPrefix.toLowerCase())) {\n node = DOMSanitizer.replaceNodeTagName(\n node,\n options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`,\n );\n }\n }\n }\n\n if (node.nodeName === \"SCRIPT\" || node.nodeName === \"OBJECT\" || node.nodeName === \"IFRAME\") {\n // set contents to empty string\n node.innerHTML = \"\";\n DOMSanitizer.stripAllAttributes(node);\n } else {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n if (!DOMSanitizer.shouldAcceptAttribute(attr)) {\n node.removeAttribute(attr);\n }\n }\n }\n for (let i = 0; i < node.childNodes.length; i++) {\n DOMSanitizer.sanitise(node.childNodes[i] as HTMLElement, options);\n }\n }\n return node;\n }\n\n static replaceNodeTagName(node: HTMLElement, newTagName: string) {\n const replacementNode = document.createElement(newTagName);\n let index;\n while (node.firstChild) {\n replacementNode.appendChild(node.firstChild);\n }\n for (index = node.attributes.length - 1; index >= 0; --index) {\n replacementNode.setAttribute(node.attributes[index].name, node.attributes[index].value);\n }\n node.parentNode?.replaceChild(replacementNode, node);\n return replacementNode;\n }\n\n static stripAllAttributes(node: HTMLElement) {\n if (node.getAttributeNames) {\n for (const attr of node.getAttributeNames()) {\n node.removeAttribute(attr);\n }\n }\n }\n\n static IsASCIIDigit(c: string): boolean {\n return c >= \"0\" && c <= \"9\";\n }\n\n static IsASCIIAlpha(c: string) {\n return (c >= \"a\" && c <= \"z\") || (c >= \"A\" && c <= \"Z\");\n }\n\n static IsValidAttributeName(characters: string): boolean {\n const c = characters[0];\n if (!(DOMSanitizer.IsASCIIAlpha(c) || c === \":\" || c === \"_\")) {\n return false;\n }\n\n for (let i = 1; i < characters.length; i++) {\n const c = characters[i];\n if (\n !(\n DOMSanitizer.IsASCIIDigit(c) ||\n DOMSanitizer.IsASCIIAlpha(c) ||\n c === \":\" ||\n c === \"_\" ||\n c === \"-\" ||\n c === \".\"\n )\n ) {\n return false;\n }\n }\n\n return true;\n }\n\n static shouldAcceptAttribute(attribute: string) {\n if (!DOMSanitizer.IsValidAttributeName(attribute)) {\n console.warn(\"Invalid attribute name\", attribute);\n return false;\n }\n\n // TODO - this might be overly restrictive - apologies to someone that finds this because you have a non-event attribute filtered by this\n return !attribute.startsWith(\"on\");\n }\n}\n", "import {\n isNetworkedDOMProtocolSubProtocol_v0_2,\n networkedDOMProtocolSubProtocol_v0_1,\n networkedDOMProtocolSubProtocol_v0_2_SubVersionsList,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport { NetworkedDOMWebsocketV01Adapter } from \"./NetworkedDOMWebsocketV01Adapter\";\nimport { NetworkedDOMWebsocketV02Adapter } from \"./NetworkedDOMWebsocketV02Adapter\";\n\nconst startingBackoffTimeMilliseconds = 100;\nconst maximumBackoffTimeMilliseconds = 10000;\nconst maximumWebsocketConnectionTimeout = 5000;\n\nexport type NetworkedDOMWebsocketFactory = (url: string) => WebSocket;\n\nexport enum NetworkedDOMWebsocketStatus {\n Connecting,\n ConnectionOpen, // The websocket is open and connected, but no messages have been received yet\n Connected, // The websocket is open and connected, and messages are being received\n Reconnecting,\n Disconnected,\n}\n\nexport function NetworkedDOMWebsocketStatusToString(status: NetworkedDOMWebsocketStatus): string {\n switch (status) {\n case NetworkedDOMWebsocketStatus.Connecting:\n return \"Connecting...\";\n case NetworkedDOMWebsocketStatus.ConnectionOpen:\n return \"Connection Open\";\n case NetworkedDOMWebsocketStatus.Connected:\n return \"Connected\";\n case NetworkedDOMWebsocketStatus.Reconnecting:\n return \"Reconnecting...\";\n case NetworkedDOMWebsocketStatus.Disconnected:\n return \"Disconnected\";\n default:\n return \"Unknown\";\n }\n}\n\nexport type NetworkedDOMWebsocketOptions = {\n tagPrefix?: string; // e.g. \"m-\" to restrict to only custom elements with a tag name starting with \"m-\"\n replacementTagPrefix?: string; // e.g. \"x-\" to replace non-prefixed tags with a new prefix (e.g. \"div\" -> \"x-div\")\n allowSVGElements?: boolean; // Whether to allow SVG namespace elements to be created. Default is false.\n connectionToken?: string | null; // Optional token to send to the server for authentication/authorization\n};\n\nexport type NetworkedDOMWebsocketAdapter = {\n receiveMessage: (message: MessageEvent) => void;\n handleEvent: (element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) => void;\n clearContents: () => boolean;\n};\n\n/**\n * NetworkedDOMWebsocket is a client for a NetworkedDOMServer. It connects to a server on the provided url and receives\n * updates to the DOM. It also sends events to the server for interactions with the DOM.\n *\n * The NetworkedDOMWebsocket is attached to a parentElement and synchronizes the received DOM under that element.\n */\nexport class NetworkedDOMWebsocket {\n private websocket: WebSocket | null = null;\n private websocketAdapter: NetworkedDOMWebsocketAdapter | null = null;\n\n private stopped = false;\n private backoffTime = startingBackoffTimeMilliseconds;\n private status: NetworkedDOMWebsocketStatus | null = null;\n\n public static createWebSocket(url: string): WebSocket {\n return new WebSocket(url, [\n ...networkedDOMProtocolSubProtocol_v0_2_SubVersionsList,\n networkedDOMProtocolSubProtocol_v0_1,\n ]);\n }\n\n constructor(\n private url: string,\n private websocketFactory: NetworkedDOMWebsocketFactory,\n private parentElement: HTMLElement,\n private timeCallback?: (time: number) => void,\n private statusUpdateCallback?: (status: NetworkedDOMWebsocketStatus) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.setStatus(NetworkedDOMWebsocketStatus.Connecting);\n this.startWebSocketConnectionAttempt();\n }\n\n private setStatus(status: NetworkedDOMWebsocketStatus) {\n if (this.status !== status) {\n this.status = status;\n if (this.statusUpdateCallback) {\n this.statusUpdateCallback(status);\n }\n }\n }\n\n private createWebsocketWithTimeout(timeout: number): Promise<WebSocket> {\n return new Promise((resolve, reject) => {\n const websocket = this.websocketFactory(this.url);\n const timeoutId = setTimeout(() => {\n reject(new Error(\"websocket connection timed out\"));\n websocket.close();\n }, timeout);\n websocket.binaryType = \"arraybuffer\";\n websocket.addEventListener(\"open\", () => {\n clearTimeout(timeoutId);\n\n this.websocket = websocket;\n const isV02 = isNetworkedDOMProtocolSubProtocol_v0_2(websocket.protocol);\n let websocketAdapter: NetworkedDOMWebsocketAdapter;\n if (isV02) {\n websocketAdapter = new NetworkedDOMWebsocketV02Adapter(\n websocket,\n this.parentElement,\n () => {\n this.backoffTime = startingBackoffTimeMilliseconds;\n this.setStatus(NetworkedDOMWebsocketStatus.Connected);\n },\n this.timeCallback,\n this.options,\n );\n } else {\n websocketAdapter = new NetworkedDOMWebsocketV01Adapter(\n websocket,\n this.parentElement,\n () => {\n this.backoffTime = startingBackoffTimeMilliseconds;\n this.setStatus(NetworkedDOMWebsocketStatus.Connected);\n },\n this.timeCallback,\n this.options,\n );\n }\n this.websocketAdapter = websocketAdapter;\n\n websocket.addEventListener(\"message\", (event) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket message event because it is no longer current\");\n websocket.close();\n return;\n }\n websocketAdapter.receiveMessage(event);\n });\n\n const onWebsocketClose = async () => {\n let hadContents = false;\n if (this.websocketAdapter) {\n hadContents = this.websocketAdapter.clearContents();\n }\n if (this.stopped) {\n // This closing is expected. The client closed the websocket.\n this.setStatus(NetworkedDOMWebsocketStatus.Disconnected);\n return;\n }\n if (!hadContents) {\n // The websocket did not deliver any contents. It may have been successfully opened, but immediately closed. This client should back off to prevent this happening in a rapid loop.\n await this.waitBackoffTime();\n }\n // The websocket closed unexpectedly. Try to reconnect.\n this.setStatus(NetworkedDOMWebsocketStatus.Reconnecting);\n this.startWebSocketConnectionAttempt();\n };\n\n websocket.addEventListener(\"close\", () => {\n if (websocket !== this.websocket) {\n console.warn(\"Ignoring websocket close event because it is no longer current\");\n return;\n }\n onWebsocketClose();\n });\n websocket.addEventListener(\"error\", (e) => {\n if (websocket !== this.websocket) {\n console.log(\"Ignoring websocket error event because it is no longer current\");\n return;\n }\n console.error(\"NetworkedDOMWebsocket error\", e);\n onWebsocketClose();\n });\n\n this.setStatus(NetworkedDOMWebsocketStatus.ConnectionOpen);\n resolve(websocket);\n });\n websocket.addEventListener(\"error\", (e) => {\n clearTimeout(timeoutId);\n reject(e);\n });\n });\n }\n\n private async waitBackoffTime(): Promise<void> {\n console.warn(`Websocket connection to '${this.url}' failed: retrying in ${this.backoffTime}ms`);\n await new Promise((resolve) => setTimeout(resolve, this.backoffTime));\n this.backoffTime = Math.min(\n // Introduce a small amount of randomness to prevent clients from retrying in lockstep\n this.backoffTime * (1.5 + Math.random() * 0.5),\n maximumBackoffTimeMilliseconds,\n );\n }\n\n private async startWebSocketConnectionAttempt() {\n if (this.stopped) {\n return;\n }\n while (true) {\n if (this.stopped) {\n return;\n }\n try {\n await this.createWebsocketWithTimeout(maximumWebsocketConnectionTimeout);\n break;\n } catch (e) {\n console.error(\"Websocket connection failed\", e);\n // Connection failed, retry with backoff\n this.setStatus(NetworkedDOMWebsocketStatus.Reconnecting);\n await this.waitBackoffTime();\n }\n }\n }\n\n public stop() {\n this.stopped = true;\n if (this.websocket !== null) {\n this.websocket.close();\n this.websocket = null;\n }\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n if (this.websocketAdapter) {\n this.websocketAdapter.handleEvent(element, event);\n }\n }\n}\n\nexport function isHTMLElement(node: unknown, rootNode: HTMLElement): node is HTMLElement {\n if (node instanceof HTMLElement || node instanceof Element) {\n return true;\n }\n if (!rootNode.ownerDocument.defaultView) {\n return false;\n }\n return node instanceof rootNode.ownerDocument.defaultView.HTMLElement;\n}\n\nexport function isText(node: unknown, rootNode: HTMLElement): node is Text {\n if (node instanceof Text) {\n return true;\n }\n if (!rootNode.ownerDocument.defaultView) {\n return false;\n }\n return node instanceof rootNode.ownerDocument.defaultView.Text;\n}\n", "import { DOMSanitizer } from \"./DOMSanitizer\";\nimport { NetworkedDOMWebsocketOptions } from \"./NetworkedDOMWebsocket\";\n\n// These tags are always disallowed because they allow arbitrary HTML to be injected\nconst ALWAYS_DISALLOWED_TAGS = new Set([\"foreignobject\", \"iframe\", \"script\"]);\n\nconst SVG_TAG_NAMES_ADJUSTMENT_MAP = new Map(\n [\n \"svg\",\n \"defs\",\n \"g\",\n \"text\",\n \"filter\",\n \"stop\",\n \"path\",\n \"rect\",\n \"line\",\n \"circle\",\n \"animate\",\n \"altGlyph\",\n \"altGlyphDef\",\n \"altGlyphItem\",\n \"animateColor\",\n \"animateMotion\",\n \"animateTransform\",\n \"clipPath\",\n \"feBlend\",\n \"feDropShadow\",\n \"feColorMatrix\",\n \"feComponentTransfer\",\n \"feComposite\",\n \"feConvolveMatrix\",\n \"feDiffuseLighting\",\n \"feDisplacementMap\",\n \"feDistantLight\",\n \"feFlood\",\n \"feFuncA\",\n \"feFuncB\",\n \"feFuncG\",\n \"feFuncR\",\n \"feGaussianBlur\",\n \"feImage\",\n \"feMerge\",\n \"feMergeNode\",\n \"feMorphology\",\n \"feOffset\",\n \"fePointLight\",\n \"feSpecularLighting\",\n \"feSpotLight\",\n \"feTile\",\n \"feTurbulence\",\n \"glyphRef\",\n \"linearGradient\",\n \"radialGradient\",\n \"textPath\",\n // `foreignObject` is explicitly disallowed because it allows injecting arbitrary HTML\n // \"foreignObject\",\n ].map((tn) => [tn.toLowerCase(), tn]),\n);\n\nconst SVG_ATTRS_ADJUSTMENT_MAP = new Map(\n [\n \"attributeName\",\n \"attributeType\",\n \"baseFrequency\",\n \"baseProfile\",\n \"calcMode\",\n \"clipPathUnits\",\n \"diffuseConstant\",\n \"edgeMode\",\n \"filterUnits\",\n \"glyphRef\",\n \"gradientTransform\",\n \"gradientUnits\",\n \"kernelMatrix\",\n \"kernelUnitLength\",\n \"keyPoints\",\n \"keySplines\",\n \"keyTimes\",\n \"lengthAdjust\",\n \"limitingConeAngle\",\n \"markerHeight\",\n \"markerUnits\",\n \"markerWidth\",\n \"maskContentUnits\",\n \"maskUnits\",\n \"numOctaves\",\n \"pathLength\",\n \"patternContentUnits\",\n \"patternTransform\",\n \"patternUnits\",\n \"pointsAtX\",\n \"pointsAtY\",\n \"pointsAtZ\",\n \"preserveAlpha\",\n \"preserveAspectRatio\",\n \"primitiveUnits\",\n \"refX\",\n \"refY\",\n \"repeatCount\",\n \"repeatDur\",\n \"requiredExtensions\",\n \"requiredFeatures\",\n \"specularConstant\",\n \"specularExponent\",\n \"spreadMethod\",\n \"startOffset\",\n \"stdDeviation\",\n \"stitchTiles\",\n \"surfaceScale\",\n \"systemLanguage\",\n \"tableValues\",\n \"targetX\",\n \"targetY\",\n \"textLength\",\n \"viewBox\",\n \"viewTarget\",\n \"xChannelSelector\",\n \"yChannelSelector\",\n \"zoomAndPan\",\n ].map((attr) => [attr.toLowerCase(), attr]),\n);\n\n/**\n * Remaps attribute names to their proper case for SVG elements\n */\nexport function remapAttributeName(attrName: string): string {\n const remapped = SVG_ATTRS_ADJUSTMENT_MAP.get(attrName.toLowerCase());\n if (remapped) {\n return remapped;\n }\n return attrName;\n}\n\n/**\n * Creates an HTML Element (and optionally SVG Elements) with proper namespace handling\n */\nexport function createElementWithSVGSupport(\n tag: string,\n options: NetworkedDOMWebsocketOptions = {},\n): Element {\n let filteredTag = tag.toLowerCase();\n\n if (ALWAYS_DISALLOWED_TAGS.has(filteredTag.toLowerCase())) {\n console.error(\"Disallowing tag\", filteredTag);\n filteredTag = options.replacementTagPrefix ? options.replacementTagPrefix + tag : `x-${tag}`;\n }\n\n let svgTagMapping;\n if (options.allowSVGElements) {\n svgTagMapping = SVG_TAG_NAMES_ADJUSTMENT_MAP.get(filteredTag);\n }\n\n if (svgTagMapping) {\n filteredTag = svgTagMapping;\n const xmlns = \"http://www.w3.org/2000/svg\";\n return document.createElementNS(xmlns, filteredTag);\n } else {\n if (options.tagPrefix) {\n if (!tag.toLowerCase().startsWith(options.tagPrefix.toLowerCase())) {\n filteredTag = options.replacementTagPrefix\n ? options.replacementTagPrefix + tag\n : `x-${tag}`;\n }\n }\n return document.createElement(filteredTag);\n }\n}\n\n/**\n * Sets attributes on an element with proper SVG attribute name mapping\n */\nexport function setElementAttribute(element: Element, key: string, value: string): void {\n if (DOMSanitizer.shouldAcceptAttribute(key)) {\n const remappedKey = remapAttributeName(key);\n element.setAttribute(remappedKey, value);\n }\n}\n\n/**\n * Gets the target element for children operations, handling portal elements\n */\nexport function getChildrenTarget(parent: Element): Element {\n let targetForChildren = parent;\n if ((parent as any).getPortalElement) {\n targetForChildren = (parent as any).getPortalElement();\n }\n return targetForChildren;\n}\n\n/**\n * Gets the target element for removal operations, handling portal elements\n */\nexport function getRemovalTarget(parent: Element): Element {\n let targetForRemoval = parent;\n if ((parent as any).getPortalElement) {\n targetForRemoval = (parent as any).getPortalElement();\n }\n return targetForRemoval;\n}\n", "import {\n NetworkedDOMV01AttributeChangedDiff,\n NetworkedDOMV01ChildrenChangedDiff,\n NetworkedDOMV01ClientMessage,\n NetworkedDOMV01NodeDescription,\n NetworkedDOMV01RemoteEvent,\n NetworkedDOMV01ServerMessage,\n NetworkedDOMV01SnapshotMessage,\n NetworkedDOMV01TextChangedDiff,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport {\n createElementWithSVGSupport,\n getChildrenTarget,\n getRemovalTarget,\n setElementAttribute,\n} from \"./ElementUtils\";\nimport {\n isHTMLElement,\n isText,\n NetworkedDOMWebsocketAdapter,\n NetworkedDOMWebsocketOptions,\n} from \"./NetworkedDOMWebsocket\";\n\nexport class NetworkedDOMWebsocketV01Adapter implements NetworkedDOMWebsocketAdapter {\n private idToElement = new Map<number, Node>();\n private elementToId = new Map<Node, number>();\n private currentRoot: HTMLElement | null = null;\n\n constructor(\n private websocket: WebSocket,\n private parentElement: HTMLElement,\n private connectedCallback: () => void,\n private timeCallback?: (time: number) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.websocket.binaryType = \"arraybuffer\";\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n const nodeId = this.elementToId.get(element);\n if (nodeId === undefined || nodeId === null) {\n throw new Error(\"Element not found\");\n }\n\n const detailWithoutElement: Partial<typeof event.detail> = {\n ...event.detail,\n };\n delete detailWithoutElement.element;\n\n const remoteEvent: NetworkedDOMV01RemoteEvent = {\n type: \"event\",\n nodeId,\n name: event.type,\n bubbles: event.bubbles,\n params: detailWithoutElement,\n };\n\n this.send(remoteEvent);\n }\n\n private send(fromClientMessage: NetworkedDOMV01ClientMessage) {\n this.websocket.send(JSON.stringify(fromClientMessage));\n }\n\n public clearContents(): boolean {\n this.idToElement.clear();\n this.elementToId.clear();\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n return true;\n }\n return false;\n }\n\n receiveMessage(event: MessageEvent) {\n const messages = JSON.parse(event.data) as Array<NetworkedDOMV01ServerMessage>;\n for (const message of messages) {\n switch (message.type) {\n case \"error\":\n console.error(\"Error from server\", message);\n break;\n case \"warning\":\n console.warn(\"Warning from server\", message);\n break;\n default: {\n if (message.documentTime) {\n if (this.timeCallback) {\n this.timeCallback(message.documentTime);\n }\n }\n switch (message.type) {\n case \"snapshot\":\n this.handleSnapshot(message);\n this.connectedCallback();\n break;\n case \"attributeChange\":\n this.handleAttributeChange(message);\n break;\n case \"childrenChanged\":\n this.handleChildrenChanged(message);\n break;\n case \"textChanged\":\n this.handleTextChanged(message);\n break;\n case \"ping\":\n this.send({\n type: \"pong\",\n pong: message.ping,\n });\n break;\n default:\n console.warn(\"unknown message type\", message);\n break;\n }\n }\n }\n }\n }\n\n private handleTextChanged(message: NetworkedDOMV01TextChangedDiff) {\n const { nodeId, text } = message;\n\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in textChanged message\");\n return;\n }\n const node = this.idToElement.get(nodeId);\n if (!node) {\n throw new Error(\"No node found for textChanged message\");\n }\n if (!isText(node, this.parentElement)) {\n throw new Error(\"Node for textChanged message is not a Text node\");\n }\n node.textContent = text;\n }\n\n private handleChildrenChanged(message: NetworkedDOMV01ChildrenChangedDiff) {\n const { nodeId, addedNodes, removedNodes, previousNodeId } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n const parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n\n const targetForChildren = getChildrenTarget(parent);\n\n let nextElement = null;\n let previousElement = null;\n if (previousNodeId) {\n previousElement = this.idToElement.get(previousNodeId);\n if (!previousElement) {\n throw new Error(\"No previous element found for childrenChanged message\");\n }\n nextElement = previousElement.nextSibling;\n }\n\n const elementsToAdd = [];\n for (const addedNode of addedNodes) {\n const childElement = this.handleNewElement(addedNode);\n if (childElement) {\n elementsToAdd.push(childElement);\n }\n }\n if (elementsToAdd.length) {\n if (previousElement) {\n if (nextElement) {\n // There is a previous and next element - insertBefore the next element\n const docFrag = new DocumentFragment();\n docFrag.append(...elementsToAdd);\n targetForChildren.insertBefore(docFrag, nextElement);\n } else {\n // No next element - must be the last children\n targetForChildren.append(...elementsToAdd);\n }\n } else {\n // No previous element - must be the first children\n targetForChildren.prepend(...elementsToAdd);\n }\n }\n for (const removedNode of removedNodes) {\n const childElement = this.idToElement.get(removedNode);\n if (!childElement) {\n throw new Error(`Child element not found: ${removedNode}`);\n }\n this.elementToId.delete(childElement);\n this.idToElement.delete(removedNode);\n const targetForRemoval = getRemovalTarget(parent);\n targetForRemoval.removeChild(childElement);\n if (isHTMLElement(childElement, this.parentElement)) {\n // If child is capable of supporting children then remove any that exist\n this.removeChildElementIds(childElement);\n }\n }\n }\n\n private removeChildElementIds(parent: HTMLElement) {\n // If portal element, remove from portal element\n const portal = getChildrenTarget(parent);\n if (portal !== parent) {\n this.removeChildElementIds(portal as HTMLElement);\n }\n for (let i = 0; i < parent.childNodes.length; i++) {\n const child = parent.childNodes[i];\n const childId = this.elementToId.get(child as HTMLElement);\n if (!childId) {\n console.error(\"Inner child of removed element had no id\", child);\n } else {\n this.elementToId.delete(child);\n this.idToElement.delete(childId);\n }\n this.removeChildElementIds(child as HTMLElement);\n }\n }\n\n private handleSnapshot(message: NetworkedDOMV01SnapshotMessage) {\n // This websocket is successfully connected. Reset the backoff time.\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n this.elementToId.clear();\n this.idToElement.clear();\n }\n\n // create a tree of DOM elements\n // NOTE: the MElement constructors are not executed during this stage\n const element = this.handleNewElement(message.snapshot);\n if (!element) {\n throw new Error(\"Snapshot element not created\");\n }\n if (!isHTMLElement(element, this.parentElement)) {\n throw new Error(\"Snapshot element is not an HTMLElement\");\n }\n this.currentRoot = element;\n // appending to the tree causes MElements to be constructed\n this.parentElement.append(element);\n }\n\n private handleAttributeChange(message: NetworkedDOMV01AttributeChangedDiff) {\n const { nodeId, attribute, newValue } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in attributeChange message\");\n return;\n }\n const element = this.idToElement.get(nodeId);\n if (element) {\n if (isHTMLElement(element, this.parentElement)) {\n if (newValue === null) {\n element.removeAttribute(attribute);\n } else {\n setElementAttribute(element, attribute, newValue);\n }\n } else {\n console.error(\"Element is not an HTMLElement and cannot support attributes\", element);\n }\n } else {\n console.error(\"No element found for attributeChange message\");\n }\n }\n\n private handleNewElement(message: NetworkedDOMV01NodeDescription): Node | null {\n if (message.type === \"text\") {\n const { nodeId, text } = message;\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n const { tag, nodeId, attributes, children, text } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in handleNewElement message\", message);\n return null;\n }\n if (this.idToElement.has(nodeId)) {\n console.error(\n \"Received nodeId to add that is already present\",\n nodeId,\n this.idToElement.get(nodeId),\n );\n }\n if (tag === \"#text\") {\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text || null;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n\n let element;\n try {\n element = createElementWithSVGSupport(tag, this.options);\n } catch (e) {\n console.error(`Error creating element: (${tag})`, e);\n element = document.createElement(\"x-div\");\n }\n this.idToElement.set(nodeId, element);\n this.elementToId.set(element, nodeId);\n for (const key in attributes) {\n const value = attributes[key];\n setElementAttribute(element, key, value);\n }\n if (children) {\n for (const child of children) {\n const childElement = this.handleNewElement(child);\n if (childElement) {\n element.append(childElement);\n }\n }\n }\n return element;\n }\n}\n", "import {\n BufferReader,\n BufferWriter,\n decodeServerMessages,\n encodeClientMessage,\n getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow,\n networkedDOMProtocolSubProtocol_v0_2_Subversion,\n networkedDOMProtocolSubProtocol_v0_2_SubversionNumber,\n NetworkedDOMV02AttributesChangedDiff,\n NetworkedDOMV02ChangeHiddenFromDiff,\n NetworkedDOMV02ChildrenAddedDiff,\n NetworkedDOMV02ChildrenRemovedDiff,\n NetworkedDOMV02ClientMessage,\n NetworkedDOMV02DocumentTimeMessage,\n NetworkedDOMV02NodeDescription,\n NetworkedDOMV02PingMessage,\n NetworkedDOMV02RemoteEvent,\n NetworkedDOMV02ServerMessage,\n NetworkedDOMV02SnapshotMessage,\n NetworkedDOMV02TextChangedDiff,\n} from \"@mml-io/networked-dom-protocol\";\n\nimport {\n createElementWithSVGSupport,\n getChildrenTarget,\n getRemovalTarget,\n setElementAttribute,\n} from \"./ElementUtils\";\nimport {\n isHTMLElement,\n isText,\n NetworkedDOMWebsocketAdapter,\n NetworkedDOMWebsocketOptions,\n} from \"./NetworkedDOMWebsocket\";\n\n// This client uses a single connection id\nconst connectionId = 1;\n\n// If an element should not be visible to this client, it will be replaced with this tag and attributes will be stored ready to be applied if it is unhidden.\nconst hiddenTag = \"x-hidden\";\n\nexport class NetworkedDOMWebsocketV02Adapter implements NetworkedDOMWebsocketAdapter {\n private idToElement = new Map<number, Node>();\n private elementToId = new Map<Node, number>();\n private hiddenPlaceholderElements = new Map<\n number,\n {\n placeholder: Node;\n element: Node;\n }\n >();\n private currentRoot: HTMLElement | null = null;\n private batchMode = false;\n private batchMessages: Array<NetworkedDOMV02ServerMessage> = [];\n private readonly protocolSubversion: networkedDOMProtocolSubProtocol_v0_2_SubversionNumber;\n\n constructor(\n private websocket: WebSocket,\n private parentElement: HTMLElement,\n private connectedCallback: () => void,\n private timeCallback?: (time: number) => void,\n private options: NetworkedDOMWebsocketOptions = {},\n ) {\n this.websocket.binaryType = \"arraybuffer\";\n this.protocolSubversion = getNetworkedDOMProtocolSubProtocol_v0_2SubversionOrThrow(\n websocket.protocol as networkedDOMProtocolSubProtocol_v0_2_Subversion,\n );\n this.send({\n type: \"connectUsers\",\n connectionIds: [connectionId],\n connectionTokens: [this.options.connectionToken ?? null],\n });\n }\n\n public handleEvent(element: HTMLElement, event: CustomEvent<{ element: HTMLElement }>) {\n const nodeId = this.elementToId.get(element);\n if (nodeId === undefined || nodeId === null) {\n console.error(\"Element not found for event\", { nodeId, element, event });\n return;\n }\n\n const detailWithoutElement: Partial<typeof event.detail> = {\n ...event.detail,\n };\n delete detailWithoutElement.element;\n\n const remoteEvent: NetworkedDOMV02RemoteEvent = {\n type: \"event\",\n nodeId,\n connectionId,\n name: event.type,\n bubbles: event.bubbles,\n params: detailWithoutElement,\n };\n\n this.send(remoteEvent);\n }\n\n private send(message: NetworkedDOMV02ClientMessage) {\n const writer = new BufferWriter(256);\n encodeClientMessage(message, writer, this.protocolSubversion);\n this.websocket.send(writer.getBuffer());\n }\n\n public clearContents(): boolean {\n this.idToElement.clear();\n this.elementToId.clear();\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n return true;\n }\n return false;\n }\n\n public receiveMessage(event: MessageEvent) {\n const reader = new BufferReader(new Uint8Array(event.data));\n const messages = decodeServerMessages(reader);\n for (const message of messages) {\n if (message.type === \"batchStart\") {\n // Need to wait for batchEnd before applying messages\n this.batchMode = true;\n } else if (message.type === \"batchEnd\") {\n // Apply all messages\n this.batchMode = false;\n for (const message of this.batchMessages) {\n this.applyMessage(message);\n }\n this.batchMessages = [];\n } else {\n if (this.batchMode) {\n this.batchMessages.push(message);\n } else {\n this.applyMessage(message);\n }\n }\n }\n }\n\n private applyMessage(message: NetworkedDOMV02ServerMessage) {\n switch (message.type) {\n case \"error\":\n console.error(\"Error from server\", message);\n break;\n case \"warning\":\n console.warn(\"Warning from server\", message);\n break;\n case \"snapshot\":\n this.handleSnapshot(message);\n this.connectedCallback();\n break;\n case \"attributesChanged\":\n this.handleAttributeChange(message);\n break;\n case \"documentTime\":\n this.handleDocumentTime(message);\n break;\n case \"childrenAdded\":\n this.handleChildrenAdded(message);\n break;\n case \"changeHiddenFrom\":\n this.handleChangeHiddenFrom(message);\n break;\n case \"changeVisibleTo\":\n // no-op for end user clients\n break;\n case \"childrenRemoved\":\n this.handleChildrenRemoved(message);\n break;\n case \"textChanged\":\n this.handleTextChanged(message);\n break;\n case \"ping\":\n this.handlePing(message);\n break;\n default:\n console.warn(\"unknown message type\", message);\n break;\n }\n }\n\n private handleTextChanged(message: NetworkedDOMV02TextChangedDiff) {\n const { nodeId, text } = message;\n\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in textChanged message\");\n return;\n }\n const node = this.idToElement.get(nodeId);\n if (!node) {\n throw new Error(\"No node found for textChanged message\");\n }\n if (!isText(node, this.parentElement)) {\n throw new Error(\"Node for textChanged message is not a Text node\");\n }\n node.textContent = text;\n }\n\n private handleChangeHiddenFrom(message: NetworkedDOMV02ChangeHiddenFromDiff) {\n const { nodeId, addHiddenFrom, removeHiddenFrom } = message;\n const node = this.idToElement.get(nodeId);\n const hiddenElement = this.hiddenPlaceholderElements.get(nodeId);\n if (addHiddenFrom.length > 0 && addHiddenFrom.indexOf(connectionId) !== -1) {\n // This element is being hidden\n if (hiddenElement) {\n // This element is already hidden\n return;\n }\n if (!node) {\n throw new Error(\"No node found for changeHiddenFrom message\");\n }\n const parent = node.parentElement;\n if (!parent) {\n throw new Error(\"Node has no parent\");\n }\n const placeholder = document.createElement(hiddenTag);\n parent.replaceChild(placeholder, node);\n this.hiddenPlaceholderElements.set(nodeId, { placeholder, element: node });\n } else if (removeHiddenFrom.length > 0 && removeHiddenFrom.indexOf(connectionId) !== -1) {\n // This element is being unhidden\n if (!hiddenElement) {\n // This element is not hidden\n return;\n }\n const { placeholder, element } = hiddenElement;\n const parent = placeholder.parentElement;\n if (!parent) {\n throw new Error(\"Placeholder has no parent\");\n }\n parent.replaceChild(element, placeholder);\n this.hiddenPlaceholderElements.delete(nodeId);\n }\n }\n\n private handleChildrenAdded(message: NetworkedDOMV02ChildrenAddedDiff) {\n const { nodeId, addedNodes, previousNodeId } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n let parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n\n const hiddenParent = this.hiddenPlaceholderElements.get(nodeId);\n if (hiddenParent) {\n // This element is hidden - add the children to the hidden element (not the placeholder)\n parent = hiddenParent.element;\n } else {\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n\n const targetForChildren = getChildrenTarget(parent);\n\n let nextElement = null;\n let previousElement = null;\n if (previousNodeId) {\n previousElement = this.idToElement.get(previousNodeId);\n if (!previousElement) {\n throw new Error(\"No previous element found for childrenChanged message\");\n }\n nextElement = previousElement.nextSibling;\n }\n\n const elementsToAdd = [];\n for (const addedNode of addedNodes) {\n const childElement = this.handleNewElement(addedNode);\n if (childElement) {\n elementsToAdd.push(childElement);\n }\n }\n if (elementsToAdd.length) {\n if (previousElement) {\n if (nextElement) {\n // There is a previous and next element - insertBefore the next element\n const docFrag = new DocumentFragment();\n docFrag.append(...elementsToAdd);\n targetForChildren.insertBefore(docFrag, nextElement);\n } else {\n // No next element - must be the last children\n targetForChildren.append(...elementsToAdd);\n }\n } else {\n // No previous element - must be the first children\n targetForChildren.prepend(...elementsToAdd);\n }\n }\n }\n\n private handleChildrenRemoved(message: NetworkedDOMV02ChildrenRemovedDiff) {\n const { nodeId, removedNodes } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in childrenChanged message\");\n return;\n }\n const parent = this.idToElement.get(nodeId);\n if (!parent) {\n throw new Error(\"No parent found for childrenChanged message\");\n }\n if (!parent.isConnected) {\n console.error(\"Parent is not connected\", parent);\n }\n if (!isHTMLElement(parent, this.parentElement)) {\n throw new Error(\"Parent is not an HTMLElement (that supports children)\");\n }\n\n for (const removedNode of removedNodes) {\n const childElement = this.idToElement.get(removedNode);\n if (!childElement) {\n throw new Error(`Child element not found: ${removedNode}`);\n }\n this.elementToId.delete(childElement);\n this.idToElement.delete(removedNode);\n this.hiddenPlaceholderElements.delete(removedNode);\n\n const targetForRemoval = getRemovalTarget(parent);\n\n targetForRemoval.removeChild(childElement);\n if (isHTMLElement(childElement, this.parentElement)) {\n // If child is capable of supporting children then remove any that exist\n this.removeChildElementIds(childElement);\n }\n }\n }\n\n private removeChildElementIds(parent: HTMLElement) {\n // If portal element, remove from portal element\n const portal = getChildrenTarget(parent);\n if (portal !== parent) {\n this.removeChildElementIds(portal as HTMLElement);\n }\n for (let i = 0; i < parent.childNodes.length; i++) {\n const child = parent.childNodes[i];\n const childId = this.elementToId.get(child as HTMLElement);\n if (!childId) {\n console.error(\"Inner child of removed element had no id\", child);\n } else {\n this.elementToId.delete(child);\n this.idToElement.delete(childId);\n this.hiddenPlaceholderElements.delete(childId);\n }\n this.removeChildElementIds(child as HTMLElement);\n }\n }\n\n private handleSnapshot(message: NetworkedDOMV02SnapshotMessage) {\n // This websocket is successfully connected. Reset the backoff time.\n if (this.currentRoot) {\n this.currentRoot.remove();\n this.currentRoot = null;\n this.elementToId.clear();\n this.idToElement.clear();\n }\n\n this.timeCallback?.(message.documentTime);\n\n // create a tree of DOM elements\n // NOTE: the MElement constructors are not executed during this stage\n const element = this.handleNewElement(message.snapshot);\n if (!element) {\n throw new Error(\"Snapshot element not created\");\n }\n if (!isHTMLElement(element, this.parentElement)) {\n throw new Error(\"Snapshot element is not an HTMLElement\");\n }\n this.currentRoot = element;\n // appending to the tree causes MElements to be constructed\n this.parentElement.append(element);\n }\n\n private handleDocumentTime(message: NetworkedDOMV02DocumentTimeMessage) {\n this.timeCallback?.(message.documentTime);\n }\n\n private handleAttributeChange(message: NetworkedDOMV02AttributesChangedDiff) {\n const { nodeId, attributes } = message;\n if (nodeId === undefined || nodeId === null) {\n console.warn(\"No nodeId in attributeChange message\");\n return;\n }\n let element = this.idToElement.get(nodeId);\n const hiddenElement = this.hiddenPlaceholderElements.get(nodeId);\n if (hiddenElement) {\n // This element is hidden - apply the attributes to the hidden element\n element = hiddenElement.element;\n }\n if (element) {\n if (isHTMLElement(element, this.parentElement)) {\n for (const [key, newValue] of attributes) {\n if (newValue === null) {\n element.removeAttribute(key);\n } else {\n setElementAttribute(element, key, newValue);\n }\n }\n } else {\n console.error(\"Element is not an HTMLElement and cannot support attributes\", element);\n }\n } else {\n console.error(\"No element found for attributeChange message\");\n }\n }\n\n private handleNewElement(message: NetworkedDOMV02NodeDescription): Node | null {\n if (message.type === \"text\") {\n const { nodeId, text } = message;\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n const { tag, nodeId, attributes, children, text, hiddenFrom } = message;\n if (this.idToElement.has(nodeId)) {\n console.error(\n \"Received nodeId to add that is already present\",\n nodeId,\n this.idToElement.get(nodeId),\n );\n return null;\n }\n\n if (tag === \"#text\") {\n const textNode = document.createTextNode(\"\");\n textNode.textContent = text || null;\n this.idToElement.set(nodeId, textNode);\n this.elementToId.set(textNode, nodeId);\n return textNode;\n }\n\n let element: Element;\n try {\n element = createElementWithSVGSupport(tag, this.options);\n } catch (e) {\n console.error(`Error creating element: (${tag})`, e);\n element = document.createElement(\"x-div\");\n }\n for (const [key, value] of attributes) {\n if (value !== null) {\n setElementAttribute(element, key, value);\n }\n }\n if (children) {\n for (const child of children) {\n const childElement = this.handleNewElement(child);\n if (childElement) {\n element.append(childElement);\n }\n }\n }\n\n if (hiddenFrom && hiddenFrom.length > 0 && hiddenFrom.indexOf(connectionId) !== -1) {\n // This element is hidden - create a placeholder that will be in the DOM to maintain structure, but keep the underlying element hidden\n const placeholder = document.createElement(hiddenTag);\n this.idToElement.set(nodeId, placeholder);\n this.elementToId.set(placeholder, nodeId);\n this.hiddenPlaceholderElements.set(nodeId, { placeholder, element });\n return placeholder;\n } else {\n this.idToElement.set(nodeId, element);\n this.elementToId.set(element, nodeId);\n return element;\n }\n }\n\n private handlePing(message: NetworkedDOMV02PingMessage) {\n this.timeCallback?.(message.documentTime);\n this.send({\n type: \"pong\",\n pong: message.ping,\n });\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["c", "nodeId", "text", "message", "nodeId", "text", "NetworkedDOMWebsocketStatus"]
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mml-io/networked-dom-web",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
"test-iterate": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@mml-io/networked-dom-protocol": "^0.
|
|
23
|
+
"@mml-io/networked-dom-protocol": "^0.21.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
26
|
"jest-canvas-mock": "2.5.2",
|
|
27
|
-
"jest-environment-jsdom": "
|
|
27
|
+
"jest-environment-jsdom": "30.0.4",
|
|
28
28
|
"jest-expect-message": "1.1.3"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "7763fa330ffdc27b578d0cc4f757506630076271"
|
|
31
31
|
}
|