jails-js 6.0.1 → 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 +530 -594
- package/dist/index.js.map +1 -1
- package/dist/jails.js +1 -1
- package/dist/jails.js.map +1 -1
- package/package.json +5 -4
- package/readme.md +1 -1
- /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();
|
95
|
+
}
|
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();
|
51
101
|
}
|
52
|
-
if (
|
53
|
-
|
102
|
+
if (activeElement && !activeElement.selectionEnd && selectionEnd) {
|
103
|
+
activeElement.setSelectionRange(selectionStart, selectionEnd);
|
54
104
|
}
|
55
|
-
|
56
|
-
let ctx = createMorphContext(oldNode, normalizedContent, config2);
|
57
|
-
return morphNormalizedContent(oldNode, normalizedContent, ctx);
|
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
|
+
}
|
199
|
+
}
|
200
|
+
if (cursor.contains(document.activeElement)) break;
|
201
|
+
cursor = cursor.nextSibling;
|
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;
|
101
212
|
}
|
102
|
-
return elements;
|
103
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
|