@webtides/element-js 1.1.6 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/dom-parts/ChildNodePart.js +52 -32
- package/src/dom-parts/TemplatePart.js +14 -13
package/package.json
CHANGED
|
@@ -3,6 +3,16 @@ import { Part } from './Part.js';
|
|
|
3
3
|
import { TemplateResult } from './TemplateResult.js';
|
|
4
4
|
import { TemplatePart } from './TemplatePart.js';
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* @param {Element} commentNode
|
|
8
|
+
* @param {Element[]} nodes
|
|
9
|
+
*/
|
|
10
|
+
const insertNodesBetweenComments = (commentNode, nodes) => {
|
|
11
|
+
for (const node of nodes) {
|
|
12
|
+
commentNode.parentNode.insertBefore(node, commentNode);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
6
16
|
/**
|
|
7
17
|
* @param {Element} commentNode
|
|
8
18
|
*/
|
|
@@ -58,11 +68,7 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
|
|
|
58
68
|
|
|
59
69
|
// If the DOM node doesn't exist, append/copy the template node
|
|
60
70
|
if (domChildNode === undefined) {
|
|
61
|
-
if (templateChildNode
|
|
62
|
-
anchorNode.before(...templateChildNode.childNodes);
|
|
63
|
-
} else if (Array.isArray(templateChildNode)) {
|
|
64
|
-
anchorNode.before(...templateChildNode);
|
|
65
|
-
} else if (typeof templateChildNode === 'object' && 'ELEMENT_NODE' in templateChildNode) {
|
|
71
|
+
if (typeof templateChildNode === 'object' && 'ELEMENT_NODE' in templateChildNode) {
|
|
66
72
|
parentNode.insertBefore(templateChildNode, anchorNode);
|
|
67
73
|
} else {
|
|
68
74
|
// TODO: this might not be performant?! Can we maybe handle this in processDomNode?!
|
|
@@ -79,12 +85,12 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
|
|
|
79
85
|
parentNode.removeChild(domChildNode);
|
|
80
86
|
} else if (Array.isArray(domChildNode) || domChildNode instanceof TemplatePart) {
|
|
81
87
|
// remove childNodes
|
|
82
|
-
const childNodes = Array.isArray(domChildNode) ? domChildNode :
|
|
88
|
+
const childNodes = Array.isArray(domChildNode) ? domChildNode : domChildNode.childNodes;
|
|
83
89
|
for (const childNode of childNodes) {
|
|
84
90
|
childNode.remove();
|
|
85
91
|
}
|
|
86
92
|
} else {
|
|
87
|
-
console.log('This should not happen... what do we do about this node?!', domChildNode);
|
|
93
|
+
console.log('This should not happen... what do we do about this node?!', { domChildNode });
|
|
88
94
|
}
|
|
89
95
|
continue;
|
|
90
96
|
}
|
|
@@ -105,13 +111,12 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
|
|
|
105
111
|
if (parentNode.contains(domChildNode)) {
|
|
106
112
|
parentNode.replaceChild(templateChildNode, domChildNode);
|
|
107
113
|
} else {
|
|
108
|
-
console.warn(
|
|
109
|
-
'This should not happen',
|
|
114
|
+
console.warn('This should not happen', {
|
|
110
115
|
parentNode,
|
|
111
|
-
parentNode.contains(domChildNode),
|
|
116
|
+
'parentNode.contains(domChildNode)': parentNode.contains(domChildNode),
|
|
112
117
|
templateChildNode,
|
|
113
118
|
domChildNode,
|
|
114
|
-
);
|
|
119
|
+
});
|
|
115
120
|
}
|
|
116
121
|
}
|
|
117
122
|
return templateChildNodes;
|
|
@@ -123,7 +128,7 @@ const diffChildNodes = function (parentNode, domChildNodes, templateChildNodes,
|
|
|
123
128
|
* @return {(function(*): void)|*}
|
|
124
129
|
*/
|
|
125
130
|
export const processNodePart = (comment, initialValue) => {
|
|
126
|
-
let nodes = initialValue instanceof TemplatePart ?
|
|
131
|
+
let nodes = initialValue instanceof TemplatePart ? initialValue.childNodes : [];
|
|
127
132
|
let oldValue = initialValue instanceof TemplatePart ? initialValue.strings : initialValue;
|
|
128
133
|
// this is for string values to be inserted into the DOM. A cached TextNode will be used so that we don't have to constantly create new DOM nodes.
|
|
129
134
|
let cachedTextNode = undefined;
|
|
@@ -166,7 +171,20 @@ export const processNodePart = (comment, initialValue) => {
|
|
|
166
171
|
removeNodesBetweenComments(comment);
|
|
167
172
|
nodes = [];
|
|
168
173
|
} else {
|
|
169
|
-
|
|
174
|
+
// TODO: this will always diff the arrays although they might not have changed...
|
|
175
|
+
const unwrapArray = (nodes) => {
|
|
176
|
+
// we have to unwrap any complex objects inside the array so that we can diff arrays of childNodes
|
|
177
|
+
return nodes.flatMap((value) => {
|
|
178
|
+
if (value instanceof TemplatePart) {
|
|
179
|
+
return value.childNodes;
|
|
180
|
+
}
|
|
181
|
+
if (Array.isArray(value)) {
|
|
182
|
+
return unwrapArray(value);
|
|
183
|
+
}
|
|
184
|
+
return value;
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
nodes = diffChildNodes(comment.parentNode, nodes, unwrapArray(newValue), comment);
|
|
170
188
|
}
|
|
171
189
|
oldValue = newValue;
|
|
172
190
|
break;
|
|
@@ -176,7 +194,7 @@ export const processNodePart = (comment, initialValue) => {
|
|
|
176
194
|
// if the new value is a node or a fragment, and it's different from the live node, then it's diffed.
|
|
177
195
|
// static strings have changed in tpl part
|
|
178
196
|
oldValue = newValue.strings;
|
|
179
|
-
nodes = diffChildNodes(comment.parentNode, nodes,
|
|
197
|
+
nodes = diffChildNodes(comment.parentNode, nodes, newValue.childNodes, comment);
|
|
180
198
|
} else if (oldValue !== newValue && 'ELEMENT_NODE' in newValue) {
|
|
181
199
|
// DOM Node changed, needs diffing
|
|
182
200
|
oldValue = newValue;
|
|
@@ -196,12 +214,6 @@ export const processNodePart = (comment, initialValue) => {
|
|
|
196
214
|
* For updating a text node, a sequence of child nodes or an array of `any` values
|
|
197
215
|
*/
|
|
198
216
|
export class ChildNodePart extends Part {
|
|
199
|
-
/** @type {Node | undefined} */
|
|
200
|
-
startNode = undefined;
|
|
201
|
-
|
|
202
|
-
/** @type {Node | undefined} */
|
|
203
|
-
endNode = undefined;
|
|
204
|
-
|
|
205
217
|
// TODO: this is only for array values
|
|
206
218
|
/** @type {Part[]} */
|
|
207
219
|
parts = [];
|
|
@@ -225,6 +237,7 @@ export class ChildNodePart extends Part {
|
|
|
225
237
|
|
|
226
238
|
super();
|
|
227
239
|
|
|
240
|
+
let endNode = undefined;
|
|
228
241
|
let serverSideRendered = false;
|
|
229
242
|
if (startNode) {
|
|
230
243
|
startNode.__part = this; // add Part to comment node for debugging in the browser
|
|
@@ -237,7 +250,7 @@ export class ChildNodePart extends Part {
|
|
|
237
250
|
childNode = childNode.nextSibling;
|
|
238
251
|
}
|
|
239
252
|
|
|
240
|
-
|
|
253
|
+
endNode = childNode;
|
|
241
254
|
childNodes.push(endNode);
|
|
242
255
|
|
|
243
256
|
// if not SSRed, childNodes will only ever have two comment nodes, the start and the end marker
|
|
@@ -246,15 +259,13 @@ export class ChildNodePart extends Part {
|
|
|
246
259
|
}
|
|
247
260
|
|
|
248
261
|
this.childNodes = childNodes;
|
|
249
|
-
this.startNode = startNode;
|
|
250
|
-
this.endNode = endNode;
|
|
251
262
|
}
|
|
252
263
|
|
|
253
264
|
// value can become array | TemplatePart | any
|
|
254
265
|
const initialValue = this.parseValue(value);
|
|
255
266
|
|
|
256
|
-
if (
|
|
257
|
-
this.processor = processNodePart(
|
|
267
|
+
if (endNode) {
|
|
268
|
+
this.processor = processNodePart(endNode, serverSideRendered ? initialValue : undefined);
|
|
258
269
|
}
|
|
259
270
|
|
|
260
271
|
if (!serverSideRendered) {
|
|
@@ -262,9 +273,9 @@ export class ChildNodePart extends Part {
|
|
|
262
273
|
this.updateParts(value);
|
|
263
274
|
}
|
|
264
275
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
276
|
+
if (!(value instanceof TemplateResult)) {
|
|
277
|
+
this.processor?.(initialValue);
|
|
278
|
+
}
|
|
268
279
|
}
|
|
269
280
|
}
|
|
270
281
|
|
|
@@ -305,11 +316,19 @@ export class ChildNodePart extends Part {
|
|
|
305
316
|
parseValue(value) {
|
|
306
317
|
if (value instanceof TemplateResult) {
|
|
307
318
|
if (!this.templatePart) {
|
|
308
|
-
const
|
|
309
|
-
(node) => node
|
|
310
|
-
|
|
311
|
-
const startNode = templatePartCommentNodes[0];
|
|
319
|
+
const startNode = Array.from(this.childNodes)
|
|
320
|
+
.filter((node) => node.nodeType === COMMENT_NODE)
|
|
321
|
+
.find((node) => node.data === 'template-part');
|
|
312
322
|
this.templatePart = new TemplatePart(startNode, value);
|
|
323
|
+
const serverSideRendered = startNode !== undefined;
|
|
324
|
+
if (!serverSideRendered) {
|
|
325
|
+
// TODO: we should already have the "endNode" from the constructor...
|
|
326
|
+
const endNode = Array.from(this.childNodes)
|
|
327
|
+
.filter((node) => node.nodeType === COMMENT_NODE)
|
|
328
|
+
.find((node) => node.data.includes('/dom-part-'));
|
|
329
|
+
// INFO: this is similar to TemplateResult#237
|
|
330
|
+
insertNodesBetweenComments(endNode, this.templatePart.childNodes);
|
|
331
|
+
}
|
|
313
332
|
}
|
|
314
333
|
return this.templatePart;
|
|
315
334
|
}
|
|
@@ -354,6 +373,7 @@ export class ChildNodePart extends Part {
|
|
|
354
373
|
}
|
|
355
374
|
parsedValues[index] = childNodePart;
|
|
356
375
|
} else {
|
|
376
|
+
// TODO: what if the value from the function is a TemplatePart or an array?! Should we do this first thing?!
|
|
357
377
|
parsedValues[index] = typeof value === 'function' ? value() : value;
|
|
358
378
|
}
|
|
359
379
|
}
|
|
@@ -33,6 +33,7 @@ export class TemplatePart extends Part {
|
|
|
33
33
|
|
|
34
34
|
super();
|
|
35
35
|
|
|
36
|
+
let endNode = undefined;
|
|
36
37
|
let serverSideRendered = false;
|
|
37
38
|
if (startNode) {
|
|
38
39
|
startNode.__part = this; // add Part to comment node for debugging in the browser
|
|
@@ -45,7 +46,7 @@ export class TemplatePart extends Part {
|
|
|
45
46
|
childNode = childNode.nextSibling;
|
|
46
47
|
}
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
endNode = childNode;
|
|
49
50
|
childNodes.push(endNode);
|
|
50
51
|
|
|
51
52
|
// if not SSRed, childNodes will only ever have two comment nodes, the start and the end marker
|
|
@@ -54,23 +55,19 @@ export class TemplatePart extends Part {
|
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
this.childNodes = childNodes;
|
|
57
|
-
this.startNode = startNode;
|
|
58
|
-
this.endNode = endNode;
|
|
59
58
|
}
|
|
60
59
|
|
|
61
60
|
this.parseValue(value);
|
|
62
61
|
|
|
63
62
|
if (!serverSideRendered) {
|
|
63
|
+
// TODO: this is causing double diffing because of the this.parseValue() before, ChildNode parts will be constructed + processed
|
|
64
64
|
this.updateParts(value.values);
|
|
65
|
-
// We need a childNodes list that is NOT live so that we don't loose elements when they get removed from the dom and we can (re)add them back in later.
|
|
66
|
-
this.childNodes = [...this.childNodes];
|
|
67
65
|
}
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
this.endNode = this.childNodes[this.childNodes.length - 1];
|
|
67
|
+
endNode = this.childNodes[this.childNodes.length - 1];
|
|
71
68
|
|
|
72
|
-
if (
|
|
73
|
-
this.processor = processNodePart(
|
|
69
|
+
if (endNode) {
|
|
70
|
+
this.processor = processNodePart(endNode, this);
|
|
74
71
|
}
|
|
75
72
|
}
|
|
76
73
|
|
|
@@ -78,10 +75,11 @@ export class TemplatePart extends Part {
|
|
|
78
75
|
* @param {TemplateResult} value
|
|
79
76
|
*/
|
|
80
77
|
update(value) {
|
|
81
|
-
this.parseValue(value);
|
|
78
|
+
const shouldUpdateDOM = this.parseValue(value);
|
|
79
|
+
if (shouldUpdateDOM) {
|
|
80
|
+
this.processor?.(this);
|
|
81
|
+
}
|
|
82
82
|
this.updateParts(value.values);
|
|
83
|
-
this.childNodes = [...this.childNodes];
|
|
84
|
-
this.processor?.(this);
|
|
85
83
|
}
|
|
86
84
|
|
|
87
85
|
/**
|
|
@@ -95,6 +93,7 @@ export class TemplatePart extends Part {
|
|
|
95
93
|
|
|
96
94
|
/**
|
|
97
95
|
* @param {TemplateResult} templateResult
|
|
96
|
+
* @return {boolean} whether the part needs to be updated in the DOM
|
|
98
97
|
*/
|
|
99
98
|
parseValue(templateResult) {
|
|
100
99
|
if (this.strings !== templateResult.strings) {
|
|
@@ -134,8 +133,10 @@ export class TemplatePart extends Part {
|
|
|
134
133
|
throw `cannot map part: ${part}`;
|
|
135
134
|
});
|
|
136
135
|
this.strings = templateResult.strings;
|
|
136
|
+
this.childNodes = [...this.childNodes];
|
|
137
|
+
return true;
|
|
137
138
|
}
|
|
138
|
-
return
|
|
139
|
+
return false;
|
|
139
140
|
}
|
|
140
141
|
|
|
141
142
|
/**
|