jails-js 6.0.1-beta.9 → 6.0.2
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/dist/index.js +553 -610
- package/dist/index.js.map +1 -1
- package/dist/jails.js +1 -1
- package/dist/jails.js.map +1 -1
- package/package.json +11 -3
- package/readme.md +7 -14
- package/src/component.ts +20 -14
- package/src/element.ts +4 -2
- package/src/index.ts +1 -0
- package/tsconfig.json +3 -0
- package/types.d.ts +47 -0
- /package/{html.js → html.mjs} +0 -0
package/dist/index.js
CHANGED
@@ -19,9 +19,10 @@ const safe = (execute, val) => {
|
|
19
19
|
return val || "";
|
20
20
|
}
|
21
21
|
};
|
22
|
-
var Idiomorph =
|
23
|
-
|
24
|
-
|
22
|
+
var Idiomorph = function() {
|
23
|
+
const noOp = () => {
|
24
|
+
};
|
25
|
+
const defaults = {
|
25
26
|
morphStyle: "outerHTML",
|
26
27
|
callbacks: {
|
27
28
|
beforeNodeAdded: noOp,
|
@@ -30,309 +31,422 @@ var Idiomorph = /* @__PURE__ */ function() {
|
|
30
31
|
afterNodeMorphed: noOp,
|
31
32
|
beforeNodeRemoved: noOp,
|
32
33
|
afterNodeRemoved: noOp,
|
33
|
-
beforeAttributeUpdated: noOp
|
34
|
-
beforeNodePantried: noOp
|
34
|
+
beforeAttributeUpdated: noOp
|
35
35
|
},
|
36
36
|
head: {
|
37
37
|
style: "merge",
|
38
|
-
shouldPreserve:
|
39
|
-
|
40
|
-
},
|
41
|
-
shouldReAppend: function(elt) {
|
42
|
-
return elt.getAttribute("im-re-append") === "true";
|
43
|
-
},
|
38
|
+
shouldPreserve: (elt) => elt.getAttribute("im-preserve") === "true",
|
39
|
+
shouldReAppend: (elt) => elt.getAttribute("im-re-append") === "true",
|
44
40
|
shouldRemove: noOp,
|
45
41
|
afterHeadMorphed: noOp
|
46
|
-
}
|
42
|
+
},
|
43
|
+
restoreFocus: true
|
47
44
|
};
|
48
45
|
function morph(oldNode, newContent, config2 = {}) {
|
49
|
-
|
50
|
-
|
46
|
+
oldNode = normalizeElement(oldNode);
|
47
|
+
const newNode = normalizeParent(newContent);
|
48
|
+
const ctx = createMorphContext(oldNode, newNode, config2);
|
49
|
+
const morphedNodes = saveAndRestoreFocus(ctx, () => {
|
50
|
+
return withHeadBlocking(
|
51
|
+
ctx,
|
52
|
+
oldNode,
|
53
|
+
newNode,
|
54
|
+
/** @param {MorphContext} ctx */
|
55
|
+
(ctx2) => {
|
56
|
+
if (ctx2.morphStyle === "innerHTML") {
|
57
|
+
morphChildren(ctx2, oldNode, newNode);
|
58
|
+
return Array.from(oldNode.childNodes);
|
59
|
+
} else {
|
60
|
+
return morphOuterHTML(ctx2, oldNode, newNode);
|
61
|
+
}
|
62
|
+
}
|
63
|
+
);
|
64
|
+
});
|
65
|
+
ctx.pantry.remove();
|
66
|
+
return morphedNodes;
|
67
|
+
}
|
68
|
+
function morphOuterHTML(ctx, oldNode, newNode) {
|
69
|
+
const oldParent = normalizeParent(oldNode);
|
70
|
+
let childNodes = Array.from(oldParent.childNodes);
|
71
|
+
const index = childNodes.indexOf(oldNode);
|
72
|
+
const rightMargin = childNodes.length - (index + 1);
|
73
|
+
morphChildren(
|
74
|
+
ctx,
|
75
|
+
oldParent,
|
76
|
+
newNode,
|
77
|
+
// these two optional params are the secret sauce
|
78
|
+
oldNode,
|
79
|
+
// start point for iteration
|
80
|
+
oldNode.nextSibling
|
81
|
+
// end point for iteration
|
82
|
+
);
|
83
|
+
childNodes = Array.from(oldParent.childNodes);
|
84
|
+
return childNodes.slice(index, childNodes.length - rightMargin);
|
85
|
+
}
|
86
|
+
function saveAndRestoreFocus(ctx, fn) {
|
87
|
+
var _a;
|
88
|
+
if (!ctx.config.restoreFocus) return fn();
|
89
|
+
let activeElement = (
|
90
|
+
/** @type {HTMLInputElement|HTMLTextAreaElement|null} */
|
91
|
+
document.activeElement
|
92
|
+
);
|
93
|
+
if (!(activeElement instanceof HTMLInputElement || activeElement instanceof HTMLTextAreaElement)) {
|
94
|
+
return fn();
|
51
95
|
}
|
52
|
-
|
53
|
-
|
96
|
+
const { id: activeElementId, selectionStart, selectionEnd } = activeElement;
|
97
|
+
const results = fn();
|
98
|
+
if (activeElementId && activeElementId !== ((_a = document.activeElement) == null ? void 0 : _a.id)) {
|
99
|
+
activeElement = ctx.target.querySelector(`#${activeElementId}`);
|
100
|
+
activeElement == null ? void 0 : activeElement.focus();
|
54
101
|
}
|
55
|
-
|
56
|
-
|
57
|
-
|
102
|
+
if (activeElement && !activeElement.selectionEnd && selectionEnd) {
|
103
|
+
activeElement.setSelectionRange(selectionStart, selectionEnd);
|
104
|
+
}
|
105
|
+
return results;
|
58
106
|
}
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
ignore: true
|
74
|
-
}
|
75
|
-
})
|
107
|
+
const morphChildren = /* @__PURE__ */ function() {
|
108
|
+
function morphChildren2(ctx, oldParent, newParent, insertionPoint = null, endPoint = null) {
|
109
|
+
if (oldParent instanceof HTMLTemplateElement && newParent instanceof HTMLTemplateElement) {
|
110
|
+
oldParent = oldParent.content;
|
111
|
+
newParent = newParent.content;
|
112
|
+
}
|
113
|
+
insertionPoint || (insertionPoint = oldParent.firstChild);
|
114
|
+
for (const newChild of newParent.childNodes) {
|
115
|
+
if (insertionPoint && insertionPoint != endPoint) {
|
116
|
+
const bestMatch = findBestMatch(
|
117
|
+
ctx,
|
118
|
+
newChild,
|
119
|
+
insertionPoint,
|
120
|
+
endPoint
|
76
121
|
);
|
77
|
-
|
78
|
-
|
122
|
+
if (bestMatch) {
|
123
|
+
if (bestMatch !== insertionPoint) {
|
124
|
+
removeNodesBetween(ctx, insertionPoint, bestMatch);
|
125
|
+
}
|
126
|
+
morphNode(bestMatch, newChild, ctx);
|
127
|
+
insertionPoint = bestMatch.nextSibling;
|
128
|
+
continue;
|
129
|
+
}
|
130
|
+
}
|
131
|
+
if (newChild instanceof Element && ctx.persistentIds.has(newChild.id)) {
|
132
|
+
const movedChild = moveBeforeById(
|
133
|
+
oldParent,
|
134
|
+
newChild.id,
|
135
|
+
insertionPoint,
|
136
|
+
ctx
|
137
|
+
);
|
138
|
+
morphNode(movedChild, newChild, ctx);
|
139
|
+
insertionPoint = movedChild.nextSibling;
|
140
|
+
continue;
|
141
|
+
}
|
142
|
+
const insertedNode = createNode(
|
143
|
+
oldParent,
|
144
|
+
newChild,
|
145
|
+
insertionPoint,
|
146
|
+
ctx
|
147
|
+
);
|
148
|
+
if (insertedNode) {
|
149
|
+
insertionPoint = insertedNode.nextSibling;
|
150
|
+
}
|
151
|
+
}
|
152
|
+
while (insertionPoint && insertionPoint != endPoint) {
|
153
|
+
const tempNode = insertionPoint;
|
154
|
+
insertionPoint = insertionPoint.nextSibling;
|
155
|
+
removeNode(ctx, tempNode);
|
79
156
|
}
|
80
157
|
}
|
81
|
-
|
82
|
-
|
83
|
-
if (ctx.
|
84
|
-
|
158
|
+
function createNode(oldParent, newChild, insertionPoint, ctx) {
|
159
|
+
if (ctx.callbacks.beforeNodeAdded(newChild) === false) return null;
|
160
|
+
if (ctx.idMap.has(newChild)) {
|
161
|
+
const newEmptyChild = document.createElement(
|
162
|
+
/** @type {Element} */
|
163
|
+
newChild.tagName
|
164
|
+
);
|
165
|
+
oldParent.insertBefore(newEmptyChild, insertionPoint);
|
166
|
+
morphNode(newEmptyChild, newChild, ctx);
|
167
|
+
ctx.callbacks.afterNodeAdded(newEmptyChild);
|
168
|
+
return newEmptyChild;
|
169
|
+
} else {
|
170
|
+
const newClonedChild = document.importNode(newChild, true);
|
171
|
+
oldParent.insertBefore(newClonedChild, insertionPoint);
|
172
|
+
ctx.callbacks.afterNodeAdded(newClonedChild);
|
173
|
+
return newClonedChild;
|
85
174
|
}
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
175
|
+
}
|
176
|
+
const findBestMatch = /* @__PURE__ */ function() {
|
177
|
+
function findBestMatch2(ctx, node, startPoint, endPoint) {
|
178
|
+
let softMatch = null;
|
179
|
+
let nextSibling = node.nextSibling;
|
180
|
+
let siblingSoftMatchCount = 0;
|
181
|
+
let cursor = startPoint;
|
182
|
+
while (cursor && cursor != endPoint) {
|
183
|
+
if (isSoftMatch(cursor, node)) {
|
184
|
+
if (isIdSetMatch(ctx, cursor, node)) {
|
185
|
+
return cursor;
|
186
|
+
}
|
187
|
+
if (softMatch === null) {
|
188
|
+
if (!ctx.idMap.has(cursor)) {
|
189
|
+
softMatch = cursor;
|
190
|
+
}
|
191
|
+
}
|
192
|
+
}
|
193
|
+
if (softMatch === null && nextSibling && isSoftMatch(cursor, nextSibling)) {
|
194
|
+
siblingSoftMatchCount++;
|
195
|
+
nextSibling = nextSibling.nextSibling;
|
196
|
+
if (siblingSoftMatchCount >= 2) {
|
197
|
+
softMatch = void 0;
|
198
|
+
}
|
101
199
|
}
|
102
|
-
|
200
|
+
if (cursor.contains(document.activeElement)) break;
|
201
|
+
cursor = cursor.nextSibling;
|
103
202
|
}
|
203
|
+
return softMatch || null;
|
204
|
+
}
|
205
|
+
function isIdSetMatch(ctx, oldNode, newNode) {
|
206
|
+
let oldSet = ctx.idMap.get(oldNode);
|
207
|
+
let newSet = ctx.idMap.get(newNode);
|
208
|
+
if (!newSet || !oldSet) return false;
|
209
|
+
for (const id of oldSet) {
|
210
|
+
if (newSet.has(id)) {
|
211
|
+
return true;
|
212
|
+
}
|
213
|
+
}
|
214
|
+
return false;
|
215
|
+
}
|
216
|
+
function isSoftMatch(oldNode, newNode) {
|
217
|
+
const oldElt = (
|
218
|
+
/** @type {Element} */
|
219
|
+
oldNode
|
220
|
+
);
|
221
|
+
const newElt = (
|
222
|
+
/** @type {Element} */
|
223
|
+
newNode
|
224
|
+
);
|
225
|
+
return oldElt.nodeType === newElt.nodeType && oldElt.tagName === newElt.tagName && // If oldElt has an `id` with possible state and it doesn't match newElt.id then avoid morphing.
|
226
|
+
// We'll still match an anonymous node with an IDed newElt, though, because if it got this far,
|
227
|
+
// its not persistent, and new nodes can't have any hidden state.
|
228
|
+
(!oldElt.id || oldElt.id === newElt.id);
|
229
|
+
}
|
230
|
+
return findBestMatch2;
|
231
|
+
}();
|
232
|
+
function removeNode(ctx, node) {
|
233
|
+
var _a;
|
234
|
+
if (ctx.idMap.has(node)) {
|
235
|
+
moveBefore(ctx.pantry, node, null);
|
104
236
|
} else {
|
105
|
-
return
|
237
|
+
if (ctx.callbacks.beforeNodeRemoved(node) === false) return;
|
238
|
+
(_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
|
239
|
+
ctx.callbacks.afterNodeRemoved(node);
|
106
240
|
}
|
107
|
-
} else {
|
108
|
-
throw "Do not understand how to morph style " + ctx.morphStyle;
|
109
241
|
}
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
ctx
|
128
|
-
|
129
|
-
|
130
|
-
|
242
|
+
function removeNodesBetween(ctx, startInclusive, endExclusive) {
|
243
|
+
let cursor = startInclusive;
|
244
|
+
while (cursor && cursor !== endExclusive) {
|
245
|
+
let tempNode = (
|
246
|
+
/** @type {Node} */
|
247
|
+
cursor
|
248
|
+
);
|
249
|
+
cursor = cursor.nextSibling;
|
250
|
+
removeNode(ctx, tempNode);
|
251
|
+
}
|
252
|
+
return cursor;
|
253
|
+
}
|
254
|
+
function moveBeforeById(parentNode, id, after, ctx) {
|
255
|
+
const target = (
|
256
|
+
/** @type {Element} - will always be found */
|
257
|
+
ctx.target.querySelector(`#${id}`) || ctx.pantry.querySelector(`#${id}`)
|
258
|
+
);
|
259
|
+
removeElementFromAncestorsIdMaps(target, ctx);
|
260
|
+
moveBefore(parentNode, target, after);
|
261
|
+
return target;
|
262
|
+
}
|
263
|
+
function removeElementFromAncestorsIdMaps(element, ctx) {
|
264
|
+
const id = element.id;
|
265
|
+
while (element = element.parentNode) {
|
266
|
+
let idSet = ctx.idMap.get(element);
|
267
|
+
if (idSet) {
|
268
|
+
idSet.delete(id);
|
269
|
+
if (!idSet.size) {
|
270
|
+
ctx.idMap.delete(element);
|
271
|
+
}
|
272
|
+
}
|
273
|
+
}
|
274
|
+
}
|
275
|
+
function moveBefore(parentNode, element, after) {
|
276
|
+
if (parentNode.moveBefore) {
|
277
|
+
try {
|
278
|
+
parentNode.moveBefore(element, after);
|
279
|
+
} catch (e) {
|
280
|
+
parentNode.insertBefore(element, after);
|
281
|
+
}
|
282
|
+
} else {
|
283
|
+
parentNode.insertBefore(element, after);
|
284
|
+
}
|
285
|
+
}
|
286
|
+
return morphChildren2;
|
287
|
+
}();
|
288
|
+
const morphNode = /* @__PURE__ */ function() {
|
289
|
+
function morphNode2(oldNode, newContent, ctx) {
|
290
|
+
if (ctx.ignoreActive && oldNode === document.activeElement) {
|
291
|
+
return null;
|
292
|
+
}
|
293
|
+
if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false) {
|
131
294
|
return oldNode;
|
295
|
+
}
|
132
296
|
if (oldNode instanceof HTMLHeadElement && ctx.head.ignore) ;
|
133
297
|
else if (oldNode instanceof HTMLHeadElement && ctx.head.style !== "morph") {
|
134
298
|
handleHeadElement(
|
299
|
+
oldNode,
|
135
300
|
/** @type {HTMLHeadElement} */
|
136
301
|
newContent,
|
137
|
-
oldNode,
|
138
302
|
ctx
|
139
303
|
);
|
140
304
|
} else {
|
141
|
-
|
305
|
+
morphAttributes(oldNode, newContent, ctx);
|
142
306
|
if (!ignoreValueOfActiveElement(oldNode, ctx)) {
|
143
|
-
morphChildren(
|
307
|
+
morphChildren(ctx, oldNode, newContent);
|
144
308
|
}
|
145
309
|
}
|
146
310
|
ctx.callbacks.afterNodeMorphed(oldNode, newContent);
|
147
311
|
return oldNode;
|
148
312
|
}
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
newParent = newParent.content;
|
154
|
-
oldParent = oldParent.content;
|
155
|
-
}
|
156
|
-
let nextNewChild = newParent.firstChild;
|
157
|
-
let insertionPoint = oldParent.firstChild;
|
158
|
-
let newChild;
|
159
|
-
while (nextNewChild) {
|
160
|
-
newChild = nextNewChild;
|
161
|
-
nextNewChild = newChild.nextSibling;
|
162
|
-
if (insertionPoint == null) {
|
163
|
-
if (ctx.config.twoPass && ctx.persistentIds.has(
|
313
|
+
function morphAttributes(oldNode, newNode, ctx) {
|
314
|
+
let type = newNode.nodeType;
|
315
|
+
if (type === 1) {
|
316
|
+
const oldElt = (
|
164
317
|
/** @type {Element} */
|
165
|
-
|
166
|
-
)
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
318
|
+
oldNode
|
319
|
+
);
|
320
|
+
const newElt = (
|
321
|
+
/** @type {Element} */
|
322
|
+
newNode
|
323
|
+
);
|
324
|
+
const oldAttributes = oldElt.attributes;
|
325
|
+
const newAttributes = newElt.attributes;
|
326
|
+
for (const newAttribute of newAttributes) {
|
327
|
+
if (ignoreAttribute(newAttribute.name, oldElt, "update", ctx)) {
|
328
|
+
continue;
|
329
|
+
}
|
330
|
+
if (oldElt.getAttribute(newAttribute.name) !== newAttribute.value) {
|
331
|
+
oldElt.setAttribute(newAttribute.name, newAttribute.value);
|
332
|
+
}
|
172
333
|
}
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
let idSetMatch = findIdSetMatch(
|
183
|
-
newParent,
|
184
|
-
oldParent,
|
185
|
-
newChild,
|
186
|
-
insertionPoint,
|
187
|
-
ctx
|
188
|
-
);
|
189
|
-
if (idSetMatch) {
|
190
|
-
insertionPoint = removeNodesBetween(insertionPoint, idSetMatch, ctx);
|
191
|
-
morphOldNodeTo(idSetMatch, newChild, ctx);
|
192
|
-
removeIdsFromConsideration(ctx, newChild);
|
193
|
-
continue;
|
194
|
-
}
|
195
|
-
let softMatch = findSoftMatch(
|
196
|
-
newParent,
|
197
|
-
oldParent,
|
198
|
-
newChild,
|
199
|
-
insertionPoint,
|
200
|
-
ctx
|
201
|
-
);
|
202
|
-
if (softMatch) {
|
203
|
-
insertionPoint = removeNodesBetween(insertionPoint, softMatch, ctx);
|
204
|
-
morphOldNodeTo(softMatch, newChild, ctx);
|
205
|
-
removeIdsFromConsideration(ctx, newChild);
|
206
|
-
continue;
|
207
|
-
}
|
208
|
-
if (ctx.config.twoPass && ctx.persistentIds.has(
|
209
|
-
/** @type {Element} */
|
210
|
-
newChild.id
|
211
|
-
)) {
|
212
|
-
oldParent.insertBefore(newChild, insertionPoint);
|
213
|
-
} else {
|
214
|
-
if (ctx.callbacks.beforeNodeAdded(newChild) === false) continue;
|
215
|
-
oldParent.insertBefore(newChild, insertionPoint);
|
216
|
-
ctx.callbacks.afterNodeAdded(newChild);
|
217
|
-
}
|
218
|
-
removeIdsFromConsideration(ctx, newChild);
|
219
|
-
}
|
220
|
-
while (insertionPoint !== null) {
|
221
|
-
let tempNode = insertionPoint;
|
222
|
-
insertionPoint = insertionPoint.nextSibling;
|
223
|
-
removeNode(tempNode, ctx);
|
224
|
-
}
|
225
|
-
}
|
226
|
-
function ignoreAttribute(attr, to, updateType, ctx) {
|
227
|
-
if (attr === "value" && ctx.ignoreActiveValue && to === document.activeElement) {
|
228
|
-
return true;
|
229
|
-
}
|
230
|
-
return ctx.callbacks.beforeAttributeUpdated(attr, to, updateType) === false;
|
231
|
-
}
|
232
|
-
function syncNodeFrom(from, to, ctx) {
|
233
|
-
let type = from.nodeType;
|
234
|
-
if (type === 1) {
|
235
|
-
const fromEl = (
|
236
|
-
/** @type {Element} */
|
237
|
-
from
|
238
|
-
);
|
239
|
-
const toEl = (
|
240
|
-
/** @type {Element} */
|
241
|
-
to
|
242
|
-
);
|
243
|
-
const fromAttributes = fromEl.attributes;
|
244
|
-
const toAttributes = toEl.attributes;
|
245
|
-
for (const fromAttribute of fromAttributes) {
|
246
|
-
if (ignoreAttribute(fromAttribute.name, toEl, "update", ctx)) {
|
247
|
-
continue;
|
334
|
+
for (let i = oldAttributes.length - 1; 0 <= i; i--) {
|
335
|
+
const oldAttribute = oldAttributes[i];
|
336
|
+
if (!oldAttribute) continue;
|
337
|
+
if (!newElt.hasAttribute(oldAttribute.name)) {
|
338
|
+
if (ignoreAttribute(oldAttribute.name, oldElt, "remove", ctx)) {
|
339
|
+
continue;
|
340
|
+
}
|
341
|
+
oldElt.removeAttribute(oldAttribute.name);
|
342
|
+
}
|
248
343
|
}
|
249
|
-
if (
|
250
|
-
|
344
|
+
if (!ignoreValueOfActiveElement(oldElt, ctx)) {
|
345
|
+
syncInputValue(oldElt, newElt, ctx);
|
251
346
|
}
|
252
347
|
}
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
if (!fromEl.hasAttribute(toAttribute.name)) {
|
257
|
-
if (ignoreAttribute(toAttribute.name, toEl, "remove", ctx)) {
|
258
|
-
continue;
|
259
|
-
}
|
260
|
-
toEl.removeAttribute(toAttribute.name);
|
348
|
+
if (type === 8 || type === 3) {
|
349
|
+
if (oldNode.nodeValue !== newNode.nodeValue) {
|
350
|
+
oldNode.nodeValue = newNode.nodeValue;
|
261
351
|
}
|
262
352
|
}
|
263
353
|
}
|
264
|
-
|
265
|
-
if (
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
}
|
281
|
-
if (fromLiveValue) {
|
282
|
-
if (!ignoreUpdate) {
|
283
|
-
to.setAttribute(attributeName, fromLiveValue);
|
354
|
+
function syncInputValue(oldElement, newElement, ctx) {
|
355
|
+
if (oldElement instanceof HTMLInputElement && newElement instanceof HTMLInputElement && newElement.type !== "file") {
|
356
|
+
let newValue = newElement.value;
|
357
|
+
let oldValue = oldElement.value;
|
358
|
+
syncBooleanAttribute(oldElement, newElement, "checked", ctx);
|
359
|
+
syncBooleanAttribute(oldElement, newElement, "disabled", ctx);
|
360
|
+
if (!newElement.hasAttribute("value")) {
|
361
|
+
if (!ignoreAttribute("value", oldElement, "remove", ctx)) {
|
362
|
+
oldElement.value = "";
|
363
|
+
oldElement.removeAttribute("value");
|
364
|
+
}
|
365
|
+
} else if (oldValue !== newValue) {
|
366
|
+
if (!ignoreAttribute("value", oldElement, "update", ctx)) {
|
367
|
+
oldElement.setAttribute("value", newValue);
|
368
|
+
oldElement.value = newValue;
|
369
|
+
}
|
284
370
|
}
|
285
|
-
} else {
|
286
|
-
|
287
|
-
|
371
|
+
} else if (oldElement instanceof HTMLOptionElement && newElement instanceof HTMLOptionElement) {
|
372
|
+
syncBooleanAttribute(oldElement, newElement, "selected", ctx);
|
373
|
+
} else if (oldElement instanceof HTMLTextAreaElement && newElement instanceof HTMLTextAreaElement) {
|
374
|
+
let newValue = newElement.value;
|
375
|
+
let oldValue = oldElement.value;
|
376
|
+
if (ignoreAttribute("value", oldElement, "update", ctx)) {
|
377
|
+
return;
|
378
|
+
}
|
379
|
+
if (newValue !== oldValue) {
|
380
|
+
oldElement.value = newValue;
|
381
|
+
}
|
382
|
+
if (oldElement.firstChild && oldElement.firstChild.nodeValue !== newValue) {
|
383
|
+
oldElement.firstChild.nodeValue = newValue;
|
288
384
|
}
|
289
385
|
}
|
290
386
|
}
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
387
|
+
function syncBooleanAttribute(oldElement, newElement, attributeName, ctx) {
|
388
|
+
const newLiveValue = newElement[attributeName], oldLiveValue = oldElement[attributeName];
|
389
|
+
if (newLiveValue !== oldLiveValue) {
|
390
|
+
const ignoreUpdate = ignoreAttribute(
|
391
|
+
attributeName,
|
392
|
+
oldElement,
|
393
|
+
"update",
|
394
|
+
ctx
|
395
|
+
);
|
396
|
+
if (!ignoreUpdate) {
|
397
|
+
oldElement[attributeName] = newElement[attributeName];
|
302
398
|
}
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
399
|
+
if (newLiveValue) {
|
400
|
+
if (!ignoreUpdate) {
|
401
|
+
oldElement.setAttribute(attributeName, "");
|
402
|
+
}
|
403
|
+
} else {
|
404
|
+
if (!ignoreAttribute(attributeName, oldElement, "remove", ctx)) {
|
405
|
+
oldElement.removeAttribute(attributeName);
|
406
|
+
}
|
307
407
|
}
|
308
408
|
}
|
309
|
-
}
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
let toValue = to.value;
|
314
|
-
if (ignoreAttribute("value", to, "update", ctx)) {
|
315
|
-
return;
|
316
|
-
}
|
317
|
-
if (fromValue !== toValue) {
|
318
|
-
to.value = fromValue;
|
409
|
+
}
|
410
|
+
function ignoreAttribute(attr, element, updateType, ctx) {
|
411
|
+
if (attr === "value" && ctx.ignoreActiveValue && element === document.activeElement) {
|
412
|
+
return true;
|
319
413
|
}
|
320
|
-
|
321
|
-
|
414
|
+
return ctx.callbacks.beforeAttributeUpdated(attr, element, updateType) === false;
|
415
|
+
}
|
416
|
+
function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
|
417
|
+
return !!ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
|
418
|
+
}
|
419
|
+
return morphNode2;
|
420
|
+
}();
|
421
|
+
function withHeadBlocking(ctx, oldNode, newNode, callback) {
|
422
|
+
if (ctx.head.block) {
|
423
|
+
const oldHead = oldNode.querySelector("head");
|
424
|
+
const newHead = newNode.querySelector("head");
|
425
|
+
if (oldHead && newHead) {
|
426
|
+
const promises = handleHeadElement(oldHead, newHead, ctx);
|
427
|
+
return Promise.all(promises).then(() => {
|
428
|
+
const newCtx = Object.assign(ctx, {
|
429
|
+
head: {
|
430
|
+
block: false,
|
431
|
+
ignore: true
|
432
|
+
}
|
433
|
+
});
|
434
|
+
return callback(newCtx);
|
435
|
+
});
|
322
436
|
}
|
323
437
|
}
|
438
|
+
return callback(ctx);
|
324
439
|
}
|
325
|
-
function handleHeadElement(
|
440
|
+
function handleHeadElement(oldHead, newHead, ctx) {
|
326
441
|
let added = [];
|
327
442
|
let removed = [];
|
328
443
|
let preserved = [];
|
329
444
|
let nodesToAppend = [];
|
330
|
-
let headMergeStyle = ctx.head.style;
|
331
445
|
let srcToNewHeadNodes = /* @__PURE__ */ new Map();
|
332
|
-
for (const newHeadChild of
|
446
|
+
for (const newHeadChild of newHead.children) {
|
333
447
|
srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
|
334
448
|
}
|
335
|
-
for (const currentHeadElt of
|
449
|
+
for (const currentHeadElt of oldHead.children) {
|
336
450
|
let inNewContent = srcToNewHeadNodes.has(currentHeadElt.outerHTML);
|
337
451
|
let isReAppended = ctx.head.shouldReAppend(currentHeadElt);
|
338
452
|
let isPreserved = ctx.head.shouldPreserve(currentHeadElt);
|
@@ -344,7 +458,7 @@ var Idiomorph = /* @__PURE__ */ function() {
|
|
344
458
|
preserved.push(currentHeadElt);
|
345
459
|
}
|
346
460
|
} else {
|
347
|
-
if (
|
461
|
+
if (ctx.head.style === "append") {
|
348
462
|
if (isReAppended) {
|
349
463
|
removed.push(currentHeadElt);
|
350
464
|
nodesToAppend.push(currentHeadElt);
|
@@ -374,394 +488,216 @@ var Idiomorph = /* @__PURE__ */ function() {
|
|
374
488
|
});
|
375
489
|
promises.push(promise);
|
376
490
|
}
|
377
|
-
|
491
|
+
oldHead.appendChild(newElt);
|
378
492
|
ctx.callbacks.afterNodeAdded(newElt);
|
379
493
|
added.push(newElt);
|
380
494
|
}
|
381
495
|
}
|
382
496
|
for (const removedElement of removed) {
|
383
497
|
if (ctx.callbacks.beforeNodeRemoved(removedElement) !== false) {
|
384
|
-
|
498
|
+
oldHead.removeChild(removedElement);
|
385
499
|
ctx.callbacks.afterNodeRemoved(removedElement);
|
386
500
|
}
|
387
501
|
}
|
388
|
-
ctx.head.afterHeadMorphed(
|
502
|
+
ctx.head.afterHeadMorphed(oldHead, {
|
389
503
|
added,
|
390
504
|
kept: preserved,
|
391
505
|
removed
|
392
506
|
});
|
393
507
|
return promises;
|
394
508
|
}
|
395
|
-
function
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
defaults.callbacks,
|
403
|
-
config2.callbacks
|
404
|
-
);
|
405
|
-
finalConfig.head = Object.assign({}, defaults.head, config2.head);
|
406
|
-
return finalConfig;
|
407
|
-
}
|
408
|
-
function createMorphContext(oldNode, newContent, config2) {
|
409
|
-
const mergedConfig = mergeDefaults(config2);
|
410
|
-
return {
|
411
|
-
target: oldNode,
|
412
|
-
newContent,
|
413
|
-
config: mergedConfig,
|
414
|
-
morphStyle: mergedConfig.morphStyle,
|
415
|
-
ignoreActive: mergedConfig.ignoreActive,
|
416
|
-
ignoreActiveValue: mergedConfig.ignoreActiveValue,
|
417
|
-
idMap: createIdMap(oldNode, newContent),
|
418
|
-
deadIds: /* @__PURE__ */ new Set(),
|
419
|
-
persistentIds: mergedConfig.twoPass ? createPersistentIds(oldNode, newContent) : /* @__PURE__ */ new Set(),
|
420
|
-
pantry: mergedConfig.twoPass ? createPantry() : document.createElement("div"),
|
421
|
-
callbacks: mergedConfig.callbacks,
|
422
|
-
head: mergedConfig.head
|
423
|
-
};
|
424
|
-
}
|
425
|
-
function createPantry() {
|
426
|
-
const pantry = document.createElement("div");
|
427
|
-
pantry.hidden = true;
|
428
|
-
document.body.insertAdjacentElement("afterend", pantry);
|
429
|
-
return pantry;
|
430
|
-
}
|
431
|
-
function isIdSetMatch(node1, node2, ctx) {
|
432
|
-
if (node1 == null || node2 == null) {
|
433
|
-
return false;
|
434
|
-
}
|
435
|
-
if (node1 instanceof Element && node2 instanceof Element && node1.tagName === node2.tagName) {
|
436
|
-
if (node1.id !== "" && node1.id === node2.id) {
|
437
|
-
return true;
|
438
|
-
} else {
|
439
|
-
return getIdIntersectionCount(ctx, node1, node2) > 0;
|
509
|
+
const createMorphContext = /* @__PURE__ */ function() {
|
510
|
+
function createMorphContext2(oldNode, newContent, config2) {
|
511
|
+
const { persistentIds, idMap } = createIdMaps(oldNode, newContent);
|
512
|
+
const mergedConfig = mergeDefaults(config2);
|
513
|
+
const morphStyle = mergedConfig.morphStyle || "outerHTML";
|
514
|
+
if (!["innerHTML", "outerHTML"].includes(morphStyle)) {
|
515
|
+
throw `Do not understand how to morph style ${morphStyle}`;
|
440
516
|
}
|
517
|
+
return {
|
518
|
+
target: oldNode,
|
519
|
+
newContent,
|
520
|
+
config: mergedConfig,
|
521
|
+
morphStyle,
|
522
|
+
ignoreActive: mergedConfig.ignoreActive,
|
523
|
+
ignoreActiveValue: mergedConfig.ignoreActiveValue,
|
524
|
+
restoreFocus: mergedConfig.restoreFocus,
|
525
|
+
idMap,
|
526
|
+
persistentIds,
|
527
|
+
pantry: createPantry(),
|
528
|
+
callbacks: mergedConfig.callbacks,
|
529
|
+
head: mergedConfig.head
|
530
|
+
};
|
441
531
|
}
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
532
|
+
function mergeDefaults(config2) {
|
533
|
+
let finalConfig = Object.assign({}, defaults);
|
534
|
+
Object.assign(finalConfig, config2);
|
535
|
+
finalConfig.callbacks = Object.assign(
|
536
|
+
{},
|
537
|
+
defaults.callbacks,
|
538
|
+
config2.callbacks
|
539
|
+
);
|
540
|
+
finalConfig.head = Object.assign({}, defaults.head, config2.head);
|
541
|
+
return finalConfig;
|
447
542
|
}
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
) {
|
454
|
-
return false;
|
543
|
+
function createPantry() {
|
544
|
+
const pantry = document.createElement("div");
|
545
|
+
pantry.hidden = true;
|
546
|
+
document.body.insertAdjacentElement("afterend", pantry);
|
547
|
+
return pantry;
|
455
548
|
}
|
456
|
-
|
457
|
-
|
458
|
-
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
while (cursor !== endExclusive) {
|
463
|
-
let tempNode = (
|
464
|
-
/** @type {Node} */
|
465
|
-
cursor
|
466
|
-
);
|
467
|
-
cursor = tempNode.nextSibling;
|
468
|
-
removeNode(tempNode, ctx);
|
549
|
+
function findIdElements(root) {
|
550
|
+
let elements = Array.from(root.querySelectorAll("[id]"));
|
551
|
+
if (root.id) {
|
552
|
+
elements.push(root);
|
553
|
+
}
|
554
|
+
return elements;
|
469
555
|
}
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
if (isIdSetMatch(newChild, potentialMatch, ctx)) {
|
485
|
-
return potentialMatch;
|
486
|
-
}
|
487
|
-
otherMatchCount += getIdIntersectionCount(
|
488
|
-
ctx,
|
489
|
-
potentialMatch,
|
490
|
-
newContent
|
491
|
-
);
|
492
|
-
if (otherMatchCount > newChildPotentialIdCount) {
|
493
|
-
return null;
|
556
|
+
function populateIdMapWithTree(idMap, persistentIds, root, elements) {
|
557
|
+
for (const elt of elements) {
|
558
|
+
if (persistentIds.has(elt.id)) {
|
559
|
+
let current = elt;
|
560
|
+
while (current) {
|
561
|
+
let idSet = idMap.get(current);
|
562
|
+
if (idSet == null) {
|
563
|
+
idSet = /* @__PURE__ */ new Set();
|
564
|
+
idMap.set(current, idSet);
|
565
|
+
}
|
566
|
+
idSet.add(elt.id);
|
567
|
+
if (current === root) break;
|
568
|
+
current = current.parentElement;
|
569
|
+
}
|
494
570
|
}
|
495
|
-
potentialMatch = potentialMatch.nextSibling;
|
496
571
|
}
|
497
572
|
}
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
573
|
+
function createIdMaps(oldContent, newContent) {
|
574
|
+
const oldIdElements = findIdElements(oldContent);
|
575
|
+
const newIdElements = findIdElements(newContent);
|
576
|
+
const persistentIds = createPersistentIds(oldIdElements, newIdElements);
|
577
|
+
let idMap = /* @__PURE__ */ new Map();
|
578
|
+
populateIdMapWithTree(idMap, persistentIds, oldContent, oldIdElements);
|
579
|
+
const newRoot = newContent.__idiomorphRoot || newContent;
|
580
|
+
populateIdMapWithTree(idMap, persistentIds, newRoot, newIdElements);
|
581
|
+
return { persistentIds, idMap };
|
582
|
+
}
|
583
|
+
function createPersistentIds(oldIdElements, newIdElements) {
|
584
|
+
let duplicateIds = /* @__PURE__ */ new Set();
|
585
|
+
let oldIdTagNameMap = /* @__PURE__ */ new Map();
|
586
|
+
for (const { id, tagName } of oldIdElements) {
|
587
|
+
if (oldIdTagNameMap.has(id)) {
|
588
|
+
duplicateIds.add(id);
|
589
|
+
} else {
|
590
|
+
oldIdTagNameMap.set(id, tagName);
|
591
|
+
}
|
510
592
|
}
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
if (
|
516
|
-
|
593
|
+
let persistentIds = /* @__PURE__ */ new Set();
|
594
|
+
for (const { id, tagName } of newIdElements) {
|
595
|
+
if (persistentIds.has(id)) {
|
596
|
+
duplicateIds.add(id);
|
597
|
+
} else if (oldIdTagNameMap.get(id) === tagName) {
|
598
|
+
persistentIds.add(id);
|
517
599
|
}
|
518
600
|
}
|
519
|
-
|
601
|
+
for (const id of duplicateIds) {
|
602
|
+
persistentIds.delete(id);
|
603
|
+
}
|
604
|
+
return persistentIds;
|
520
605
|
}
|
521
|
-
return
|
522
|
-
}
|
523
|
-
const
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
""
|
529
|
-
);
|
530
|
-
if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
|
531
|
-
let content = parser.parseFromString(newContent, "text/html");
|
532
|
-
if (contentWithSvgsRemoved.match(/<\/html>/)) {
|
533
|
-
generatedByIdiomorph.add(content);
|
534
|
-
return content;
|
606
|
+
return createMorphContext2;
|
607
|
+
}();
|
608
|
+
const { normalizeElement, normalizeParent } = /* @__PURE__ */ function() {
|
609
|
+
const generatedByIdiomorph = /* @__PURE__ */ new WeakSet();
|
610
|
+
function normalizeElement2(content) {
|
611
|
+
if (content instanceof Document) {
|
612
|
+
return content.documentElement;
|
535
613
|
} else {
|
536
|
-
|
537
|
-
if (htmlElement) {
|
538
|
-
generatedByIdiomorph.add(htmlElement);
|
539
|
-
return htmlElement;
|
540
|
-
} else {
|
541
|
-
return null;
|
542
|
-
}
|
614
|
+
return content;
|
543
615
|
}
|
544
|
-
} else {
|
545
|
-
let responseDoc = parser.parseFromString(
|
546
|
-
"<body><template>" + newContent + "</template></body>",
|
547
|
-
"text/html"
|
548
|
-
);
|
549
|
-
let content = (
|
550
|
-
/** @type {HTMLTemplateElement} */
|
551
|
-
responseDoc.body.querySelector("template").content
|
552
|
-
);
|
553
|
-
generatedByIdiomorph.add(content);
|
554
|
-
return content;
|
555
616
|
}
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
/** @type {Element} */
|
563
|
-
newContent
|
564
|
-
)) {
|
565
|
-
return (
|
617
|
+
function normalizeParent2(newContent) {
|
618
|
+
if (newContent == null) {
|
619
|
+
return document.createElement("div");
|
620
|
+
} else if (typeof newContent === "string") {
|
621
|
+
return normalizeParent2(parseContent(newContent));
|
622
|
+
} else if (generatedByIdiomorph.has(
|
566
623
|
/** @type {Element} */
|
567
624
|
newContent
|
568
|
-
)
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
function insertSiblings(previousSibling, morphedNode, nextSibling) {
|
582
|
-
var _a, _b;
|
583
|
-
let stack = [];
|
584
|
-
let added = [];
|
585
|
-
while (previousSibling != null) {
|
586
|
-
stack.push(previousSibling);
|
587
|
-
previousSibling = previousSibling.previousSibling;
|
588
|
-
}
|
589
|
-
let node = stack.pop();
|
590
|
-
while (node !== void 0) {
|
591
|
-
added.push(node);
|
592
|
-
(_a = morphedNode.parentElement) == null ? void 0 : _a.insertBefore(node, morphedNode);
|
593
|
-
node = stack.pop();
|
594
|
-
}
|
595
|
-
added.push(morphedNode);
|
596
|
-
while (nextSibling != null) {
|
597
|
-
stack.push(nextSibling);
|
598
|
-
added.push(nextSibling);
|
599
|
-
nextSibling = nextSibling.nextSibling;
|
600
|
-
}
|
601
|
-
while (stack.length > 0) {
|
602
|
-
const node2 = (
|
603
|
-
/** @type {Node} */
|
604
|
-
stack.pop()
|
605
|
-
);
|
606
|
-
(_b = morphedNode.parentElement) == null ? void 0 : _b.insertBefore(node2, morphedNode.nextSibling);
|
607
|
-
}
|
608
|
-
return added;
|
609
|
-
}
|
610
|
-
function findBestNodeMatch(newContent, oldNode, ctx) {
|
611
|
-
let currentElement;
|
612
|
-
currentElement = newContent.firstChild;
|
613
|
-
let bestElement = currentElement;
|
614
|
-
let score = 0;
|
615
|
-
while (currentElement) {
|
616
|
-
let newScore = scoreElement(currentElement, oldNode, ctx);
|
617
|
-
if (newScore > score) {
|
618
|
-
bestElement = currentElement;
|
619
|
-
score = newScore;
|
620
|
-
}
|
621
|
-
currentElement = currentElement.nextSibling;
|
622
|
-
}
|
623
|
-
return bestElement;
|
624
|
-
}
|
625
|
-
function scoreElement(node1, node2, ctx) {
|
626
|
-
if (isSoftMatch(node2, node1)) {
|
627
|
-
return 0.5 + getIdIntersectionCount(
|
628
|
-
ctx,
|
629
|
-
/** @type {Node} */
|
630
|
-
node1,
|
631
|
-
node2
|
632
|
-
);
|
633
|
-
}
|
634
|
-
return 0;
|
635
|
-
}
|
636
|
-
function removeNode(tempNode, ctx) {
|
637
|
-
var _a;
|
638
|
-
removeIdsFromConsideration(ctx, tempNode);
|
639
|
-
if (ctx.config.twoPass && hasPersistentIdNodes(ctx, tempNode) && tempNode instanceof Element) {
|
640
|
-
moveToPantry(tempNode, ctx);
|
641
|
-
} else {
|
642
|
-
if (ctx.callbacks.beforeNodeRemoved(tempNode) === false) return;
|
643
|
-
(_a = tempNode.parentNode) == null ? void 0 : _a.removeChild(tempNode);
|
644
|
-
ctx.callbacks.afterNodeRemoved(tempNode);
|
645
|
-
}
|
646
|
-
}
|
647
|
-
function moveToPantry(node, ctx) {
|
648
|
-
var _a;
|
649
|
-
if (ctx.callbacks.beforeNodePantried(node) === false) return;
|
650
|
-
Array.from(node.childNodes).forEach((child) => {
|
651
|
-
moveToPantry(child, ctx);
|
652
|
-
});
|
653
|
-
if (ctx.persistentIds.has(
|
654
|
-
/** @type {Element} */
|
655
|
-
node.id
|
656
|
-
)) {
|
657
|
-
if (ctx.pantry.moveBefore) {
|
658
|
-
ctx.pantry.moveBefore(node, null);
|
625
|
+
)) {
|
626
|
+
return (
|
627
|
+
/** @type {Element} */
|
628
|
+
newContent
|
629
|
+
);
|
630
|
+
} else if (newContent instanceof Node) {
|
631
|
+
if (newContent.parentNode) {
|
632
|
+
return createDuckTypedParent(newContent);
|
633
|
+
} else {
|
634
|
+
const dummyParent = document.createElement("div");
|
635
|
+
dummyParent.append(newContent);
|
636
|
+
return dummyParent;
|
637
|
+
}
|
659
638
|
} else {
|
660
|
-
|
639
|
+
const dummyParent = document.createElement("div");
|
640
|
+
for (const elt of [...newContent]) {
|
641
|
+
dummyParent.append(elt);
|
642
|
+
}
|
643
|
+
return dummyParent;
|
661
644
|
}
|
662
|
-
} else {
|
663
|
-
if (ctx.callbacks.beforeNodeRemoved(node) === false) return;
|
664
|
-
(_a = node.parentNode) == null ? void 0 : _a.removeChild(node);
|
665
|
-
ctx.callbacks.afterNodeRemoved(node);
|
666
645
|
}
|
667
|
-
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
675
|
-
|
676
|
-
|
677
|
-
|
678
|
-
|
679
|
-
|
680
|
-
|
681
|
-
|
682
|
-
|
683
|
-
|
684
|
-
|
685
|
-
if (ctx.callbacks.beforeNodeMorphed(element, matchElement) !== false) {
|
686
|
-
syncNodeFrom(matchElement, element, ctx);
|
687
|
-
ctx.callbacks.afterNodeMorphed(element, matchElement);
|
646
|
+
function createDuckTypedParent(newContent) {
|
647
|
+
return (
|
648
|
+
/** @type {Element} */
|
649
|
+
/** @type {unknown} */
|
650
|
+
{
|
651
|
+
childNodes: [newContent],
|
652
|
+
/** @ts-ignore - cover your eyes for a minute, tsc */
|
653
|
+
querySelectorAll: (s) => {
|
654
|
+
const elements = newContent.querySelectorAll(s);
|
655
|
+
return newContent.matches(s) ? [newContent, ...elements] : elements;
|
656
|
+
},
|
657
|
+
/** @ts-ignore */
|
658
|
+
insertBefore: (n, r) => newContent.parentNode.insertBefore(n, r),
|
659
|
+
/** @ts-ignore */
|
660
|
+
moveBefore: (n, r) => newContent.parentNode.moveBefore(n, r),
|
661
|
+
// for later use with populateIdMapWithTree to halt upwards iteration
|
662
|
+
get __idiomorphRoot() {
|
663
|
+
return newContent;
|
688
664
|
}
|
689
|
-
matchElement.remove();
|
690
665
|
}
|
691
|
-
|
692
|
-
ctx.pantry.remove();
|
693
|
-
}
|
694
|
-
}
|
695
|
-
function isIdInConsideration(ctx, id) {
|
696
|
-
return !ctx.deadIds.has(id);
|
697
|
-
}
|
698
|
-
function idIsWithinNode(ctx, id, targetNode) {
|
699
|
-
let idSet = ctx.idMap.get(targetNode) || EMPTY_SET;
|
700
|
-
return idSet.has(id);
|
701
|
-
}
|
702
|
-
function removeIdsFromConsideration(ctx, node) {
|
703
|
-
let idSet = ctx.idMap.get(node) || EMPTY_SET;
|
704
|
-
for (const id of idSet) {
|
705
|
-
ctx.deadIds.add(id);
|
706
|
-
}
|
707
|
-
}
|
708
|
-
function hasPersistentIdNodes(ctx, node) {
|
709
|
-
for (const id of ctx.idMap.get(node) || EMPTY_SET) {
|
710
|
-
if (ctx.persistentIds.has(id)) {
|
711
|
-
return true;
|
712
|
-
}
|
713
|
-
}
|
714
|
-
return false;
|
715
|
-
}
|
716
|
-
function getIdIntersectionCount(ctx, node1, node2) {
|
717
|
-
let sourceSet = ctx.idMap.get(node1) || EMPTY_SET;
|
718
|
-
let matchCount = 0;
|
719
|
-
for (const id of sourceSet) {
|
720
|
-
if (isIdInConsideration(ctx, id) && idIsWithinNode(ctx, id, node2)) {
|
721
|
-
++matchCount;
|
722
|
-
}
|
723
|
-
}
|
724
|
-
return matchCount;
|
725
|
-
}
|
726
|
-
function nodesWithIds(content) {
|
727
|
-
let nodes = Array.from(content.querySelectorAll("[id]"));
|
728
|
-
if (content.id) {
|
729
|
-
nodes.push(content);
|
666
|
+
);
|
730
667
|
}
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
let
|
739
|
-
if (
|
740
|
-
|
741
|
-
|
668
|
+
function parseContent(newContent) {
|
669
|
+
let parser = new DOMParser();
|
670
|
+
let contentWithSvgsRemoved = newContent.replace(
|
671
|
+
/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,
|
672
|
+
""
|
673
|
+
);
|
674
|
+
if (contentWithSvgsRemoved.match(/<\/html>/) || contentWithSvgsRemoved.match(/<\/head>/) || contentWithSvgsRemoved.match(/<\/body>/)) {
|
675
|
+
let content = parser.parseFromString(newContent, "text/html");
|
676
|
+
if (contentWithSvgsRemoved.match(/<\/html>/)) {
|
677
|
+
generatedByIdiomorph.add(content);
|
678
|
+
return content;
|
679
|
+
} else {
|
680
|
+
let htmlElement = content.firstChild;
|
681
|
+
if (htmlElement) {
|
682
|
+
generatedByIdiomorph.add(htmlElement);
|
683
|
+
}
|
684
|
+
return htmlElement;
|
742
685
|
}
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
function createPersistentIds(oldContent, newContent) {
|
755
|
-
const toIdTagName = (node) => node.tagName + "#" + node.id;
|
756
|
-
const oldIdSet = new Set(nodesWithIds(oldContent).map(toIdTagName));
|
757
|
-
let matchIdSet = /* @__PURE__ */ new Set();
|
758
|
-
for (const newNode of nodesWithIds(newContent)) {
|
759
|
-
if (oldIdSet.has(toIdTagName(newNode))) {
|
760
|
-
matchIdSet.add(newNode.id);
|
686
|
+
} else {
|
687
|
+
let responseDoc = parser.parseFromString(
|
688
|
+
"<body><template>" + newContent + "</template></body>",
|
689
|
+
"text/html"
|
690
|
+
);
|
691
|
+
let content = (
|
692
|
+
/** @type {HTMLTemplateElement} */
|
693
|
+
responseDoc.body.querySelector("template").content
|
694
|
+
);
|
695
|
+
generatedByIdiomorph.add(content);
|
696
|
+
return content;
|
761
697
|
}
|
762
698
|
}
|
763
|
-
return
|
764
|
-
}
|
699
|
+
return { normalizeElement: normalizeElement2, normalizeParent: normalizeParent2 };
|
700
|
+
}();
|
765
701
|
return {
|
766
702
|
morph,
|
767
703
|
defaults
|
@@ -784,8 +720,10 @@ const subscribe = (name, method) => {
|
|
784
720
|
topics[name] = topics[name].filter((fn) => fn != method);
|
785
721
|
};
|
786
722
|
};
|
787
|
-
const Component = ({ name, module, dependencies, node, templates: templates2, signal }) => {
|
723
|
+
const Component = ({ name, module, dependencies, node, templates: templates2, signal, register: register2 }) => {
|
788
724
|
var _a;
|
725
|
+
let tick;
|
726
|
+
let preserve = [];
|
789
727
|
const _model = module.model || {};
|
790
728
|
const initialState = new Function(`return ${node.getAttribute("html-model") || "{}"}`)();
|
791
729
|
const tplid = node.getAttribute("tplid");
|
@@ -795,8 +733,6 @@ const Component = ({ name, module, dependencies, node, templates: templates2, si
|
|
795
733
|
const model = dup(((_a = module == null ? void 0 : module.model) == null ? void 0 : _a.apply) ? _model({ elm: node, initialState }) : _model);
|
796
734
|
const state = Object.assign({}, scope, model, initialState);
|
797
735
|
const view = module.view ? module.view : (data) => data;
|
798
|
-
let preserve = [];
|
799
|
-
let tick;
|
800
736
|
const base = {
|
801
737
|
name,
|
802
738
|
model,
|
@@ -836,8 +772,9 @@ const Component = ({ name, module, dependencies, node, templates: templates2, si
|
|
836
772
|
Object.assign(state, data);
|
837
773
|
}
|
838
774
|
const newstate = Object.assign({}, state, scope);
|
839
|
-
|
840
|
-
|
775
|
+
return new Promise((resolve) => {
|
776
|
+
render(newstate, () => resolve(newstate));
|
777
|
+
});
|
841
778
|
},
|
842
779
|
get() {
|
843
780
|
return Object.assign({}, state);
|
@@ -900,39 +837,45 @@ const Component = ({ name, module, dependencies, node, templates: templates2, si
|
|
900
837
|
Idiomorph.morph(element, clone);
|
901
838
|
}
|
902
839
|
};
|
903
|
-
const render = (data) => {
|
840
|
+
const render = (data, callback = () => {
|
841
|
+
}) => {
|
904
842
|
clearTimeout(tick);
|
905
843
|
tick = setTimeout(() => {
|
906
844
|
const html = tpl.render.call(view(data), node, safe, g);
|
907
|
-
Idiomorph.morph(node, html, IdiomorphOptions(node));
|
845
|
+
Idiomorph.morph(node, html, IdiomorphOptions(node, register2));
|
908
846
|
Promise.resolve().then(() => {
|
909
847
|
node.querySelectorAll("[tplid]").forEach((element) => {
|
910
|
-
|
911
|
-
|
912
|
-
|
848
|
+
const child = register2.get(element);
|
849
|
+
if (!child) return;
|
850
|
+
child.state.protected().forEach((key) => delete data[key]);
|
851
|
+
child.state.set(data);
|
852
|
+
});
|
853
|
+
Promise.resolve().then(() => {
|
854
|
+
g.scope = {};
|
855
|
+
callback();
|
913
856
|
});
|
914
|
-
Promise.resolve().then(() => g.scope = {});
|
915
857
|
});
|
916
858
|
});
|
917
859
|
};
|
918
860
|
render(state);
|
919
|
-
node
|
861
|
+
register2.set(node, base);
|
920
862
|
return module.default(base);
|
921
863
|
};
|
922
|
-
const IdiomorphOptions = (parent) => ({
|
864
|
+
const IdiomorphOptions = (parent, register2) => ({
|
923
865
|
callbacks: {
|
924
866
|
beforeNodeMorphed(node) {
|
925
867
|
if (node.nodeType === 1) {
|
926
868
|
if ("html-static" in node.attributes) {
|
927
869
|
return false;
|
928
870
|
}
|
929
|
-
if (node
|
871
|
+
if (register2.get(node) && node !== parent) {
|
930
872
|
return false;
|
931
873
|
}
|
932
874
|
}
|
933
875
|
}
|
934
876
|
}
|
935
877
|
});
|
878
|
+
const register$1 = /* @__PURE__ */ new WeakMap();
|
936
879
|
const Element$1 = ({ component, templates: templates2, start: start2 }) => {
|
937
880
|
const { name, module, dependencies } = component;
|
938
881
|
return class extends HTMLElement {
|
@@ -950,7 +893,8 @@ const Element$1 = ({ component, templates: templates2, start: start2 }) => {
|
|
950
893
|
module,
|
951
894
|
dependencies,
|
952
895
|
templates: templates2,
|
953
|
-
signal: this.abortController.signal
|
896
|
+
signal: this.abortController.signal,
|
897
|
+
register: register$1
|
954
898
|
});
|
955
899
|
if (rtrn && rtrn.constructor === Promise) {
|
956
900
|
rtrn.then(() => {
|
@@ -963,7 +907,6 @@ const Element$1 = ({ component, templates: templates2, start: start2 }) => {
|
|
963
907
|
disconnectedCallback() {
|
964
908
|
this.dispatchEvent(new CustomEvent(":unmount"));
|
965
909
|
this.abortController.abort();
|
966
|
-
delete this.base;
|
967
910
|
}
|
968
911
|
};
|
969
912
|
};
|