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 CHANGED
@@ -19,9 +19,10 @@ const safe = (execute, val) => {
19
19
  return val || "";
20
20
  }
21
21
  };
22
- var Idiomorph = /* @__PURE__ */ function() {
23
- let EMPTY_SET = /* @__PURE__ */ new Set();
24
- let defaults = {
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: function(elt) {
39
- return elt.getAttribute("im-preserve") === "true";
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
- if (oldNode instanceof Document) {
50
- oldNode = oldNode.documentElement;
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 (typeof newContent === "string") {
53
- newContent = parseContent(newContent);
102
+ if (activeElement && !activeElement.selectionEnd && selectionEnd) {
103
+ activeElement.setSelectionRange(selectionStart, selectionEnd);
54
104
  }
55
- let normalizedContent = normalizeContent(newContent);
56
- let ctx = createMorphContext(oldNode, normalizedContent, config2);
57
- return morphNormalizedContent(oldNode, normalizedContent, ctx);
105
+ return results;
58
106
  }
59
- function morphNormalizedContent(oldNode, normalizedNewContent, ctx) {
60
- var _a, _b;
61
- if (ctx.head.block) {
62
- let oldHead = oldNode.querySelector("head");
63
- let newHead = normalizedNewContent.querySelector("head");
64
- if (oldHead && newHead) {
65
- let promises = handleHeadElement(newHead, oldHead, ctx);
66
- Promise.all(promises).then(function() {
67
- morphNormalizedContent(
68
- oldNode,
69
- normalizedNewContent,
70
- Object.assign(ctx, {
71
- head: {
72
- block: false,
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
- return;
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
- if (ctx.morphStyle === "innerHTML") {
82
- morphChildren(normalizedNewContent, oldNode, ctx);
83
- if (ctx.config.twoPass) {
84
- restoreFromPantry(oldNode, ctx);
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
- return Array.from(oldNode.children);
87
- } else if (ctx.morphStyle === "outerHTML" || ctx.morphStyle == null) {
88
- let bestMatch = findBestNodeMatch(normalizedNewContent, oldNode, ctx);
89
- let previousSibling = (_a = bestMatch == null ? void 0 : bestMatch.previousSibling) != null ? _a : null;
90
- let nextSibling = (_b = bestMatch == null ? void 0 : bestMatch.nextSibling) != null ? _b : null;
91
- let morphedNode = morphOldNodeTo(oldNode, bestMatch, ctx);
92
- if (bestMatch) {
93
- if (morphedNode) {
94
- const elements = insertSiblings(
95
- previousSibling,
96
- morphedNode,
97
- nextSibling
98
- );
99
- if (ctx.config.twoPass) {
100
- restoreFromPantry(morphedNode.parentNode, ctx);
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
- function ignoreValueOfActiveElement(possibleActiveElement, ctx) {
112
- return !!ctx.ignoreActiveValue && possibleActiveElement === document.activeElement && possibleActiveElement !== document.body;
113
- }
114
- function morphOldNodeTo(oldNode, newContent, ctx) {
115
- var _a, _b;
116
- if (ctx.ignoreActive && oldNode === document.activeElement) ;
117
- else if (newContent == null) {
118
- if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
119
- (_a = oldNode.parentNode) == null ? void 0 : _a.removeChild(oldNode);
120
- ctx.callbacks.afterNodeRemoved(oldNode);
121
- return null;
122
- } else if (!isSoftMatch(oldNode, newContent)) {
123
- if (ctx.callbacks.beforeNodeRemoved(oldNode) === false) return oldNode;
124
- if (ctx.callbacks.beforeNodeAdded(newContent) === false) return oldNode;
125
- (_b = oldNode.parentNode) == null ? void 0 : _b.replaceChild(newContent, oldNode);
126
- ctx.callbacks.afterNodeAdded(newContent);
127
- ctx.callbacks.afterNodeRemoved(oldNode);
128
- return newContent;
129
- } else {
130
- if (ctx.callbacks.beforeNodeMorphed(oldNode, newContent) === false)
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
- syncNodeFrom(newContent, oldNode, ctx);
305
+ morphAttributes(oldNode, newContent, ctx);
142
306
  if (!ignoreValueOfActiveElement(oldNode, ctx)) {
143
- morphChildren(newContent, oldNode, ctx);
307
+ morphChildren(ctx, oldNode, newContent);
144
308
  }
145
309
  }
146
310
  ctx.callbacks.afterNodeMorphed(oldNode, newContent);
147
311
  return oldNode;
148
312
  }
149
- return null;
150
- }
151
- function morphChildren(newParent, oldParent, ctx) {
152
- if (newParent instanceof HTMLTemplateElement && oldParent instanceof HTMLTemplateElement) {
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
- newChild.id
166
- )) {
167
- oldParent.appendChild(newChild);
168
- } else {
169
- if (ctx.callbacks.beforeNodeAdded(newChild) === false) continue;
170
- oldParent.appendChild(newChild);
171
- ctx.callbacks.afterNodeAdded(newChild);
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
- removeIdsFromConsideration(ctx, newChild);
174
- continue;
175
- }
176
- if (isIdSetMatch(newChild, insertionPoint, ctx)) {
177
- morphOldNodeTo(insertionPoint, newChild, ctx);
178
- insertionPoint = insertionPoint.nextSibling;
179
- removeIdsFromConsideration(ctx, newChild);
180
- continue;
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 (toEl.getAttribute(fromAttribute.name) !== fromAttribute.value) {
250
- toEl.setAttribute(fromAttribute.name, fromAttribute.value);
344
+ if (!ignoreValueOfActiveElement(oldElt, ctx)) {
345
+ syncInputValue(oldElt, newElt, ctx);
251
346
  }
252
347
  }
253
- for (let i = toAttributes.length - 1; 0 <= i; i--) {
254
- const toAttribute = toAttributes[i];
255
- if (!toAttribute) continue;
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
- if (type === 8 || type === 3) {
265
- if (to.nodeValue !== from.nodeValue) {
266
- to.nodeValue = from.nodeValue;
267
- }
268
- }
269
- if (!ignoreValueOfActiveElement(to, ctx)) {
270
- syncInputValue(from, to, ctx);
271
- }
272
- }
273
- function syncBooleanAttribute(from, to, attributeName, ctx) {
274
- if (!(from instanceof Element && to instanceof Element)) return;
275
- const fromLiveValue = from[attributeName], toLiveValue = to[attributeName];
276
- if (fromLiveValue !== toLiveValue) {
277
- let ignoreUpdate = ignoreAttribute(attributeName, to, "update", ctx);
278
- if (!ignoreUpdate) {
279
- to[attributeName] = from[attributeName];
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
- if (!ignoreAttribute(attributeName, to, "remove", ctx)) {
287
- to.removeAttribute(attributeName);
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
- function syncInputValue(from, to, ctx) {
293
- if (from instanceof HTMLInputElement && to instanceof HTMLInputElement && from.type !== "file") {
294
- let fromValue = from.value;
295
- let toValue = to.value;
296
- syncBooleanAttribute(from, to, "checked", ctx);
297
- syncBooleanAttribute(from, to, "disabled", ctx);
298
- if (!from.hasAttribute("value")) {
299
- if (!ignoreAttribute("value", to, "remove", ctx)) {
300
- to.value = "";
301
- to.removeAttribute("value");
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
- } else if (fromValue !== toValue) {
304
- if (!ignoreAttribute("value", to, "update", ctx)) {
305
- to.setAttribute("value", fromValue);
306
- to.value = fromValue;
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
- } else if (from instanceof HTMLOptionElement && to instanceof HTMLOptionElement) {
310
- syncBooleanAttribute(from, to, "selected", ctx);
311
- } else if (from instanceof HTMLTextAreaElement && to instanceof HTMLTextAreaElement) {
312
- let fromValue = from.value;
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
- if (to.firstChild && to.firstChild.nodeValue !== fromValue) {
321
- to.firstChild.nodeValue = fromValue;
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(newHeadTag, currentHead, ctx) {
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 newHeadTag.children) {
446
+ for (const newHeadChild of newHead.children) {
333
447
  srcToNewHeadNodes.set(newHeadChild.outerHTML, newHeadChild);
334
448
  }
335
- for (const currentHeadElt of currentHead.children) {
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 (headMergeStyle === "append") {
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
- currentHead.appendChild(newElt);
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
- currentHead.removeChild(removedElement);
498
+ oldHead.removeChild(removedElement);
385
499
  ctx.callbacks.afterNodeRemoved(removedElement);
386
500
  }
387
501
  }
388
- ctx.head.afterHeadMorphed(currentHead, {
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 noOp() {
396
- }
397
- function mergeDefaults(config2) {
398
- let finalConfig = Object.assign({}, defaults);
399
- Object.assign(finalConfig, config2);
400
- finalConfig.callbacks = Object.assign(
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
- return false;
443
- }
444
- function isSoftMatch(oldNode, newNode) {
445
- if (oldNode == null || newNode == null) {
446
- return false;
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
- if (
449
- /** @type {Element} */
450
- oldNode.id && /** @type {Element} */
451
- oldNode.id !== /** @type {Element} */
452
- newNode.id
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
- return oldNode.nodeType === newNode.nodeType && /** @type {Element} */
457
- oldNode.tagName === /** @type {Element} */
458
- newNode.tagName;
459
- }
460
- function removeNodesBetween(startInclusive, endExclusive, ctx) {
461
- let cursor = startInclusive;
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
- removeIdsFromConsideration(ctx, endExclusive);
471
- return endExclusive.nextSibling;
472
- }
473
- function findIdSetMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
474
- let newChildPotentialIdCount = getIdIntersectionCount(
475
- ctx,
476
- newChild,
477
- oldParent
478
- );
479
- let potentialMatch = null;
480
- if (newChildPotentialIdCount > 0) {
481
- potentialMatch = insertionPoint;
482
- let otherMatchCount = 0;
483
- while (potentialMatch != null) {
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
- return potentialMatch;
499
- }
500
- function findSoftMatch(newContent, oldParent, newChild, insertionPoint, ctx) {
501
- let potentialSoftMatch = insertionPoint;
502
- let nextSibling = newChild.nextSibling;
503
- let siblingSoftMatchCount = 0;
504
- while (potentialSoftMatch != null) {
505
- if (getIdIntersectionCount(ctx, potentialSoftMatch, newContent) > 0) {
506
- return null;
507
- }
508
- if (isSoftMatch(potentialSoftMatch, newChild)) {
509
- return potentialSoftMatch;
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
- if (isSoftMatch(potentialSoftMatch, nextSibling)) {
512
- siblingSoftMatchCount++;
513
- nextSibling = /** @type {Node} */
514
- nextSibling.nextSibling;
515
- if (siblingSoftMatchCount >= 2) {
516
- return null;
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
- potentialSoftMatch = potentialSoftMatch.nextSibling;
601
+ for (const id of duplicateIds) {
602
+ persistentIds.delete(id);
603
+ }
604
+ return persistentIds;
520
605
  }
521
- return potentialSoftMatch;
522
- }
523
- const generatedByIdiomorph = /* @__PURE__ */ new WeakSet();
524
- function parseContent(newContent) {
525
- let parser = new DOMParser();
526
- let contentWithSvgsRemoved = newContent.replace(
527
- /<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,
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
- let htmlElement = content.firstChild;
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
- function normalizeContent(newContent) {
558
- if (newContent == null) {
559
- const dummyParent = document.createElement("div");
560
- return dummyParent;
561
- } else if (generatedByIdiomorph.has(
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
- } else if (newContent instanceof Node) {
570
- const dummyParent = document.createElement("div");
571
- dummyParent.append(newContent);
572
- return dummyParent;
573
- } else {
574
- const dummyParent = document.createElement("div");
575
- for (const elt of [...newContent]) {
576
- dummyParent.append(elt);
577
- }
578
- return dummyParent;
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
- ctx.pantry.insertBefore(node, null);
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
- function restoreFromPantry(root, ctx) {
669
- if (root instanceof Element) {
670
- Array.from(ctx.pantry.children).reverse().forEach((element) => {
671
- var _a;
672
- const matchElement = root.querySelector(`#${element.id}`);
673
- if (matchElement) {
674
- if ((_a = matchElement.parentElement) == null ? void 0 : _a.moveBefore) {
675
- matchElement.parentElement.moveBefore(element, matchElement);
676
- while (matchElement.hasChildNodes()) {
677
- element.moveBefore(matchElement.firstChild, null);
678
- }
679
- } else {
680
- matchElement.before(element);
681
- while (matchElement.firstChild) {
682
- element.insertBefore(matchElement.firstChild, null);
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
- return nodes;
732
- }
733
- function populateIdMapForNode(node, idMap) {
734
- let nodeParent = node.parentElement;
735
- for (const elt of nodesWithIds(node)) {
736
- let current = elt;
737
- while (current !== nodeParent && current != null) {
738
- let idSet = idMap.get(current);
739
- if (idSet == null) {
740
- idSet = /* @__PURE__ */ new Set();
741
- idMap.set(current, idSet);
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
- idSet.add(elt.id);
744
- current = current.parentElement;
745
- }
746
- }
747
- }
748
- function createIdMap(oldContent, newContent) {
749
- let idMap = /* @__PURE__ */ new Map();
750
- populateIdMapForNode(oldContent, idMap);
751
- populateIdMapForNode(newContent, idMap);
752
- return idMap;
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 matchIdSet;
764
- }
699
+ return { normalizeElement: normalizeElement2, normalizeParent: normalizeParent2 };
700
+ }();
765
701
  return {
766
702
  morph,
767
703
  defaults