hyperclayjs 1.27.0 → 1.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -4
- package/package.json +1 -1
- package/src/communication/live-sync.js +300 -40
- package/src/hyperclay.js +4 -1
- package/src/ui/prompts.js +15 -10
- package/src/vendor/hyper-html-api.vendor.js +13 -0
- package/src/vendor/hyper-morph.vendor.js +2 -2
package/README.md
CHANGED
|
@@ -86,7 +86,7 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
86
86
|
|
|
87
87
|
| Module | Size | Description |
|
|
88
88
|
|--------|------|-------------|
|
|
89
|
-
| dialogs | 8.
|
|
89
|
+
| dialogs | 8.5KB | ask(), consent(), tell(), snippet() dialog functions |
|
|
90
90
|
| the-modal | 22.5KB | Full modal window creation system - window.theModal |
|
|
91
91
|
| toast | 15.8KB | Success/error message notifications, toast(msg, msgType) |
|
|
92
92
|
|
|
@@ -123,14 +123,15 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
123
123
|
| Module | Size | Description |
|
|
124
124
|
|--------|------|-------------|
|
|
125
125
|
| file-upload | 11.3KB | File upload with progress |
|
|
126
|
-
| live-sync |
|
|
126
|
+
| live-sync | 25.3KB | Real-time DOM sync across browsers |
|
|
127
127
|
| send-message | 1.3KB | Message sending utility |
|
|
128
128
|
|
|
129
129
|
### Vendor Libraries (Third-party libraries)
|
|
130
130
|
|
|
131
131
|
| Module | Size | Description |
|
|
132
132
|
|--------|------|-------------|
|
|
133
|
-
| hyper-
|
|
133
|
+
| hyper-html-api | 14.6KB | Declarative extract/apply engine driven by a rules tag — foundation for CMS and upgrade flows |
|
|
134
|
+
| hyper-morph | 18.7KB | DOM morphing with content-based element matching |
|
|
134
135
|
|
|
135
136
|
## Presets
|
|
136
137
|
|
|
@@ -144,7 +145,7 @@ Standard feature set for most use cases
|
|
|
144
145
|
|
|
145
146
|
**Modules:** `save-core`, `snapshot`, `save-system`, `unsaved-warning`, `edit-mode-helpers`, `persist`, `option-visibility`, `event-attrs`, `dom-helpers`, `toast`, `save-toast`, `export-to-window`, `view-mode-excludes-edit-modules`
|
|
146
147
|
|
|
147
|
-
### Everything (~
|
|
148
|
+
### Everything (~262KB)
|
|
148
149
|
All available features
|
|
149
150
|
|
|
150
151
|
Includes all available modules across all categories.
|
package/package.json
CHANGED
|
@@ -50,16 +50,31 @@ class LiveSync {
|
|
|
50
50
|
// High-water mark of server seqs we've seen on this channel (own echoes
|
|
51
51
|
// count too). Server-broadcast payloads carry a monotonic seq
|
|
52
52
|
// (Date.now()-based). We drop anything <= this to guard against rare
|
|
53
|
-
// cases where a stale message lands after a newer one
|
|
53
|
+
// cases where a stale message lands after a newer one, e.g. buffered
|
|
54
54
|
// replay, alt backend after reconnect, or an own-save echo arriving
|
|
55
55
|
// after a peer's newer broadcast.
|
|
56
56
|
this.lastSeenSeq = 0;
|
|
57
57
|
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
//
|
|
61
|
-
//
|
|
62
|
-
|
|
58
|
+
// rAF-paced single-flight queue. Incoming updates overwrite a pending
|
|
59
|
+
// slot; on each animation frame, if a slot is set and no morph is in
|
|
60
|
+
// flight, run one morph against the latest pending payload. Burst
|
|
61
|
+
// arrivals collapse to one morph per frame, keeping the receiver from
|
|
62
|
+
// falling behind under load. A morph with external scripts returns a
|
|
63
|
+
// Promise, so the in-flight flag prevents overlap.
|
|
64
|
+
this._pendingHtml = null;
|
|
65
|
+
this._pendingSeq = null;
|
|
66
|
+
this._pendingIdentityMap = null;
|
|
67
|
+
this._morphInFlight = false;
|
|
68
|
+
this._rafHandle = null;
|
|
69
|
+
|
|
70
|
+
// Identity tracking for content-based morphing across live-sync updates.
|
|
71
|
+
// Synthetic IDs (`<clientId>:<counter>`) live here only — never written to
|
|
72
|
+
// the DOM, never serialized into saved HTML. The WeakMap holds them
|
|
73
|
+
// against the live elements so that the next save can produce the same
|
|
74
|
+
// identityMap, and afterNodeMorphed transfers IDs from incoming parsed
|
|
75
|
+
// elements onto the live elements they morphed into.
|
|
76
|
+
this.idCounter = this._loadIdCounter();
|
|
77
|
+
this.liveWeakMap = new WeakMap();
|
|
63
78
|
|
|
64
79
|
// Callbacks
|
|
65
80
|
this.onConnect = null;
|
|
@@ -127,7 +142,6 @@ class LiveSync {
|
|
|
127
142
|
// Reset state for new connection
|
|
128
143
|
this.lastHtml = null;
|
|
129
144
|
this.lastSeenSeq = 0;
|
|
130
|
-
this._applyChain = Promise.resolve();
|
|
131
145
|
|
|
132
146
|
console.log('[LiveSync] Starting for:', this.currentFile);
|
|
133
147
|
this.connect();
|
|
@@ -150,6 +164,149 @@ class LiveSync {
|
|
|
150
164
|
}
|
|
151
165
|
|
|
152
166
|
clearTimeout(this.debounceTimer);
|
|
167
|
+
|
|
168
|
+
// Cancel any pending frame and clear the queue. A morph already in
|
|
169
|
+
// flight cannot be aborted; the isDestroyed check in _runPending guards
|
|
170
|
+
// its post-morph rescheduling so the queue stops cleanly.
|
|
171
|
+
if (this._rafHandle != null) {
|
|
172
|
+
this._cancelFrame(this._rafHandle);
|
|
173
|
+
this._rafHandle = null;
|
|
174
|
+
}
|
|
175
|
+
this._pendingHtml = null;
|
|
176
|
+
this._pendingSeq = null;
|
|
177
|
+
this._pendingIdentityMap = null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
_loadIdCounter() {
|
|
181
|
+
try {
|
|
182
|
+
const raw = sessionStorage.getItem('livesync-id-counter');
|
|
183
|
+
const n = parseInt(raw || '0', 10);
|
|
184
|
+
return Number.isFinite(n) && n > 0 ? n : 0;
|
|
185
|
+
} catch (e) {
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
_persistIdCounter() {
|
|
191
|
+
try {
|
|
192
|
+
sessionStorage.setItem('livesync-id-counter', String(this.idCounter));
|
|
193
|
+
} catch (e) {
|
|
194
|
+
// Storage full / sandboxed — fall back to in-memory only.
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
_mintId() {
|
|
199
|
+
this.idCounter++;
|
|
200
|
+
this._persistIdCounter();
|
|
201
|
+
return `${this.clientId}:${this.idCounter}`;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Walk the live DOM and the snapshot clone in lockstep. Path keys come
|
|
206
|
+
* from the clone (= what the receiver will see, after [snapshot-remove]
|
|
207
|
+
* and snapshotHooks). WeakMap lookup happens against the live element so
|
|
208
|
+
* synthetic IDs persist across saves.
|
|
209
|
+
*
|
|
210
|
+
* The live walk filters [snapshot-remove] to mirror the clone's earlier
|
|
211
|
+
* strip in captureSnapshot. If child counts diverge anywhere (an
|
|
212
|
+
* onbeforesnapshot handler added/removed siblings on the clone), the
|
|
213
|
+
* subtree is skipped — better to fall back to content scoring there than
|
|
214
|
+
* emit misaligned IDs.
|
|
215
|
+
*
|
|
216
|
+
* @param {Element} liveRoot
|
|
217
|
+
* @param {Element} cloneRoot
|
|
218
|
+
* @returns {Object} identityMap keyed by dot-path
|
|
219
|
+
*/
|
|
220
|
+
_buildIdentityMap(liveRoot, cloneRoot) {
|
|
221
|
+
const map = {};
|
|
222
|
+
if (!liveRoot || !cloneRoot) return map;
|
|
223
|
+
|
|
224
|
+
const visit = (live, clone, path) => {
|
|
225
|
+
let id = this.liveWeakMap.get(live);
|
|
226
|
+
if (!id) {
|
|
227
|
+
id = this._mintId();
|
|
228
|
+
this.liveWeakMap.set(live, id);
|
|
229
|
+
}
|
|
230
|
+
map[path] = id;
|
|
231
|
+
|
|
232
|
+
const liveKids = [];
|
|
233
|
+
for (const c of live.children) {
|
|
234
|
+
if (!c.hasAttribute('snapshot-remove')) liveKids.push(c);
|
|
235
|
+
}
|
|
236
|
+
const cloneKids = clone.children;
|
|
237
|
+
|
|
238
|
+
if (liveKids.length !== cloneKids.length) {
|
|
239
|
+
this._log(
|
|
240
|
+
`identity map: subtree skipped at "${path}" (live=${liveKids.length}, clone=${cloneKids.length})`
|
|
241
|
+
);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
for (let i = 0; i < liveKids.length; i++) {
|
|
246
|
+
visit(liveKids[i], cloneKids[i], path === '' ? String(i) : `${path}.${i}`);
|
|
247
|
+
}
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
visit(liveRoot, cloneRoot, '');
|
|
251
|
+
return map;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Walk a single parsed tree, invoking cb(element, path) at each Element.
|
|
256
|
+
* Paths use the same dot-segment scheme as _buildIdentityMap so the
|
|
257
|
+
* receiver can look up IDs by the path the sender emitted.
|
|
258
|
+
*/
|
|
259
|
+
_walkParsedTree(root, cb) {
|
|
260
|
+
if (!root) return;
|
|
261
|
+
const visit = (el, path) => {
|
|
262
|
+
cb(el, path);
|
|
263
|
+
const kids = el.children;
|
|
264
|
+
for (let i = 0; i < kids.length; i++) {
|
|
265
|
+
visit(kids[i], path === '' ? String(i) : `${path}.${i}`);
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
visit(root, '');
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Fill liveWeakMap entries for live elements that the matcher's
|
|
273
|
+
* afterNodeMorphed didn't reach. createNode's no-id-children
|
|
274
|
+
* optimization (hyper-morph importNode path) inserts a clone of the
|
|
275
|
+
* parsed element without invoking morphNode, so afterNodeMorphed never
|
|
276
|
+
* fires for those subtrees and their synthetic IDs would be lost. On
|
|
277
|
+
* the receiver's next save, _buildIdentityMap would mint fresh IDs for
|
|
278
|
+
* the same logical elements, breaking convergence for newly-added
|
|
279
|
+
* ambiguous siblings — exactly the case identity-map exists to fix.
|
|
280
|
+
*
|
|
281
|
+
* Walks live and parsed in lockstep using the same path scheme as
|
|
282
|
+
* _buildIdentityMap. Filters [snapshot-remove] from the live side to
|
|
283
|
+
* stay aligned with the sender's clone view. Aborts a subtree on
|
|
284
|
+
* child-count divergence (e.g. local save-ignore additions) — those
|
|
285
|
+
* elements fall through to content scoring on the next round, which
|
|
286
|
+
* is the same fallback as a sender-side lockstep skip.
|
|
287
|
+
*
|
|
288
|
+
* @param {Element} liveRoot - post-morph live tree root
|
|
289
|
+
* @param {Element} parsedRoot - parsed-tree root (still has identityMap WeakMap entries)
|
|
290
|
+
* @param {Object} identityMap - path → id map from the SSE payload
|
|
291
|
+
*/
|
|
292
|
+
_fillInIdsAfterMorph(liveRoot, parsedRoot, identityMap) {
|
|
293
|
+
if (!liveRoot || !parsedRoot || !identityMap) return;
|
|
294
|
+
const visit = (live, parsed, path) => {
|
|
295
|
+
const id = identityMap[path];
|
|
296
|
+
if (id && !this.liveWeakMap.has(live)) {
|
|
297
|
+
this.liveWeakMap.set(live, id);
|
|
298
|
+
}
|
|
299
|
+
const liveKids = [];
|
|
300
|
+
for (const c of live.children) {
|
|
301
|
+
if (!c.hasAttribute('snapshot-remove')) liveKids.push(c);
|
|
302
|
+
}
|
|
303
|
+
const parsedKids = parsed.children;
|
|
304
|
+
if (liveKids.length !== parsedKids.length) return;
|
|
305
|
+
for (let i = 0; i < liveKids.length; i++) {
|
|
306
|
+
visit(liveKids[i], parsedKids[i], path === '' ? String(i) : `${path}.${i}`);
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
visit(liveRoot, parsedRoot, '');
|
|
153
310
|
}
|
|
154
311
|
|
|
155
312
|
/**
|
|
@@ -210,7 +367,7 @@ class LiveSync {
|
|
|
210
367
|
return;
|
|
211
368
|
}
|
|
212
369
|
|
|
213
|
-
const { html, sender, seq } = data;
|
|
370
|
+
const { html, sender, seq, identityMap } = data;
|
|
214
371
|
|
|
215
372
|
// Staleness check runs FIRST — compared against the high-water mark of
|
|
216
373
|
// seqs we've seen (own echoes count too, see below). `seq` is optional
|
|
@@ -240,8 +397,8 @@ class LiveSync {
|
|
|
240
397
|
}
|
|
241
398
|
|
|
242
399
|
this._log(`Received update from: ${sender} (my clientId: ${this.clientId}, seq=${seq})`);
|
|
243
|
-
this.applyUpdate(html, seq);
|
|
244
|
-
if (this.onUpdate) this.onUpdate({ html, sender, seq });
|
|
400
|
+
this.applyUpdate(html, seq, identityMap);
|
|
401
|
+
if (this.onUpdate) this.onUpdate({ html, sender, seq, identityMap });
|
|
245
402
|
};
|
|
246
403
|
|
|
247
404
|
// Native EventSource auto-reconnects on transient errors
|
|
@@ -268,12 +425,17 @@ class LiveSync {
|
|
|
268
425
|
return;
|
|
269
426
|
}
|
|
270
427
|
|
|
271
|
-
const { documentElement } = event.detail;
|
|
272
|
-
if (!
|
|
428
|
+
const { documentElement: clone } = event.detail;
|
|
429
|
+
if (!clone) return;
|
|
273
430
|
|
|
431
|
+
// Capture both synchronously inside the event handler — captureSnapshot's
|
|
432
|
+
// caller continues to mutate the clone (strip [save-remove], run hooks)
|
|
433
|
+
// after dispatchEvent returns, so reading outerHTML and walking children
|
|
434
|
+
// must happen now.
|
|
274
435
|
this._log('snapshot-ready received, preparing to send');
|
|
275
|
-
const html =
|
|
276
|
-
this.
|
|
436
|
+
const html = clone.outerHTML;
|
|
437
|
+
const identityMap = this._buildIdentityMap(document.documentElement, clone);
|
|
438
|
+
this.sendUpdate(html, identityMap);
|
|
277
439
|
};
|
|
278
440
|
|
|
279
441
|
document.addEventListener('hyperclay:snapshot-ready', this._snapshotHandler);
|
|
@@ -283,7 +445,7 @@ class LiveSync {
|
|
|
283
445
|
* Send full HTML to the server (debounced)
|
|
284
446
|
* Only updates lastHtml after successful save
|
|
285
447
|
*/
|
|
286
|
-
sendUpdate(html) {
|
|
448
|
+
sendUpdate(html, identityMap) {
|
|
287
449
|
clearTimeout(this.debounceTimer);
|
|
288
450
|
|
|
289
451
|
this.debounceTimer = setTimeout(() => {
|
|
@@ -300,7 +462,8 @@ class LiveSync {
|
|
|
300
462
|
headers: { 'Content-Type': 'application/json', 'Page-URL': window.location.href },
|
|
301
463
|
body: JSON.stringify({
|
|
302
464
|
html: html,
|
|
303
|
-
sender: this.clientId
|
|
465
|
+
sender: this.clientId,
|
|
466
|
+
identityMap: identityMap
|
|
304
467
|
})
|
|
305
468
|
}).then(response => {
|
|
306
469
|
if (response.ok) {
|
|
@@ -316,39 +479,96 @@ class LiveSync {
|
|
|
316
479
|
}
|
|
317
480
|
|
|
318
481
|
/**
|
|
319
|
-
* Apply an update received from the server.
|
|
320
|
-
* Morphs the entire document (head and body).
|
|
482
|
+
* Apply an update received from the server. Morphs the entire document.
|
|
321
483
|
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
484
|
+
* Updates land in a single pending slot. On each animation frame, the
|
|
485
|
+
* latest pending payload is morphed once; intermediate updates that
|
|
486
|
+
* arrived between frames are skipped because they would be replaced
|
|
487
|
+
* milliseconds later anyway. Burst arrivals collapse to roughly one morph
|
|
488
|
+
* per frame, so the receiver always shows current state instead of
|
|
489
|
+
* playing back a backlog of stale snapshots.
|
|
324
490
|
*
|
|
325
491
|
* @param {string} html - Full document HTML
|
|
326
492
|
* @param {number} [seq] - Optional monotonic seq from the server
|
|
327
|
-
* @
|
|
493
|
+
* @param {Object} [identityMap] - Optional element-identity map from sender
|
|
328
494
|
*/
|
|
329
|
-
applyUpdate(html, seq) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
495
|
+
applyUpdate(html, seq, identityMap) {
|
|
496
|
+
if (this.isDestroyed) return;
|
|
497
|
+
this._pendingHtml = html;
|
|
498
|
+
this._pendingSeq = seq;
|
|
499
|
+
this._pendingIdentityMap = identityMap;
|
|
500
|
+
this._scheduleNextFrame();
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Schedule the next-frame morph if one isn't already pending. Skipped when
|
|
505
|
+
* a morph is in flight; the morph's post-completion check will reschedule
|
|
506
|
+
* if a newer payload arrived during it.
|
|
507
|
+
*/
|
|
508
|
+
_scheduleNextFrame() {
|
|
509
|
+
if (this.isDestroyed) return;
|
|
510
|
+
if (this._rafHandle != null) return;
|
|
511
|
+
if (this._morphInFlight) return;
|
|
512
|
+
this._rafHandle = this._requestFrame(() => this._runPending());
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
/**
|
|
516
|
+
* Drain the pending slot once. Errors are caught and logged so a single
|
|
517
|
+
* failed morph does not stop the queue.
|
|
518
|
+
*/
|
|
519
|
+
async _runPending() {
|
|
520
|
+
this._rafHandle = null;
|
|
521
|
+
if (this.isDestroyed) return;
|
|
522
|
+
|
|
523
|
+
const html = this._pendingHtml;
|
|
524
|
+
const seq = this._pendingSeq;
|
|
525
|
+
const identityMap = this._pendingIdentityMap;
|
|
526
|
+
this._pendingHtml = null;
|
|
527
|
+
this._pendingSeq = null;
|
|
528
|
+
this._pendingIdentityMap = null;
|
|
529
|
+
if (html == null) return;
|
|
530
|
+
|
|
531
|
+
this._morphInFlight = true;
|
|
532
|
+
try {
|
|
533
|
+
await this._doApplyUpdate(html, seq, identityMap);
|
|
534
|
+
} catch (err) {
|
|
535
|
+
console.error('[LiveSync] applyUpdate failed:', err);
|
|
536
|
+
} finally {
|
|
537
|
+
this._morphInFlight = false;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// A newer payload may have arrived during the morph. Schedule another
|
|
541
|
+
// frame to drain it. Without this, late-arriving updates would sit
|
|
542
|
+
// forever until the next applyUpdate call.
|
|
543
|
+
if (!this.isDestroyed && this._pendingHtml != null) {
|
|
544
|
+
this._scheduleNextFrame();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
_requestFrame(cb) {
|
|
549
|
+
if (typeof window !== 'undefined' && typeof window.requestAnimationFrame === 'function') {
|
|
550
|
+
return window.requestAnimationFrame(cb);
|
|
551
|
+
}
|
|
552
|
+
return setTimeout(cb, 16);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
_cancelFrame(handle) {
|
|
556
|
+
if (typeof window !== 'undefined' && typeof window.cancelAnimationFrame === 'function') {
|
|
557
|
+
window.cancelAnimationFrame(handle);
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
clearTimeout(handle);
|
|
342
561
|
}
|
|
343
562
|
|
|
344
563
|
/**
|
|
345
|
-
* Actual morph work. Do not call directly
|
|
346
|
-
*
|
|
564
|
+
* Actual morph work. Do not call directly. Use applyUpdate() so calls
|
|
565
|
+
* pass through the rAF queue and don't overlap.
|
|
347
566
|
* @param {string} html
|
|
348
567
|
* @param {number} [seq]
|
|
568
|
+
* @param {Object} [identityMap]
|
|
349
569
|
* @returns {Promise<void>}
|
|
350
570
|
*/
|
|
351
|
-
async _doApplyUpdate(html, seq) {
|
|
571
|
+
async _doApplyUpdate(html, seq, identityMap) {
|
|
352
572
|
this._log('applyUpdate - pausing mutations and morphing');
|
|
353
573
|
this.isPaused = true;
|
|
354
574
|
|
|
@@ -366,6 +586,32 @@ class LiveSync {
|
|
|
366
586
|
const parser = new DOMParser();
|
|
367
587
|
const newDoc = parser.parseFromString(html, 'text/html');
|
|
368
588
|
|
|
589
|
+
// Build the parsed-tree WeakMap from the incoming identityMap. The
|
|
590
|
+
// sender emitted paths off its clone, which is exactly what we just
|
|
591
|
+
// parsed, so the same path scheme indexes into both trees.
|
|
592
|
+
const parsedWeakMap = new WeakMap();
|
|
593
|
+
if (identityMap && typeof identityMap === 'object' && !Array.isArray(identityMap)) {
|
|
594
|
+
this._walkParsedTree(newDoc.documentElement, (el, path) => {
|
|
595
|
+
const id = identityMap[path];
|
|
596
|
+
if (id) parsedWeakMap.set(el, id);
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
const liveWeakMap = this.liveWeakMap;
|
|
601
|
+
// Priority: synthetic IDs win when present (they're updated after every
|
|
602
|
+
// morph via afterNodeMorphed). data-id / id is the durable fallback that
|
|
603
|
+
// covers the bootstrap window and any element that hasn't been paired yet.
|
|
604
|
+
const key = (el) =>
|
|
605
|
+
liveWeakMap.get(el) ||
|
|
606
|
+
parsedWeakMap.get(el) ||
|
|
607
|
+
(el.getAttribute && el.getAttribute('data-id')) ||
|
|
608
|
+
el.id ||
|
|
609
|
+
null;
|
|
610
|
+
const afterNodeMorphed = (oldEl, newEl) => {
|
|
611
|
+
const id = parsedWeakMap.get(newEl);
|
|
612
|
+
if (id) liveWeakMap.set(oldEl, id);
|
|
613
|
+
};
|
|
614
|
+
|
|
369
615
|
try {
|
|
370
616
|
// Morph entire document. We MUST await — HyperMorph.morph returns a
|
|
371
617
|
// Promise when `scripts: { handle: true }` needs to wait for external
|
|
@@ -376,12 +622,24 @@ class LiveSync {
|
|
|
376
622
|
morphStyle: 'outerHTML',
|
|
377
623
|
ignoreActiveValue: true,
|
|
378
624
|
head: { style: 'merge' },
|
|
379
|
-
scripts: { handle: true, matchMode: 'smart' }
|
|
625
|
+
scripts: { handle: true, matchMode: 'smart' },
|
|
626
|
+
key,
|
|
627
|
+
callbacks: { afterNodeMorphed }
|
|
380
628
|
});
|
|
381
629
|
|
|
382
630
|
// Restore viewport. Done after morph so layout has settled.
|
|
383
631
|
window.scrollTo(scrollX, scrollY);
|
|
384
632
|
|
|
633
|
+
// Fill in any IDs the matcher's afterNodeMorphed missed. Brand-new
|
|
634
|
+
// elements come in via hyper-morph's importNode optimization, which
|
|
635
|
+
// skips morphNode and thus afterNodeMorphed; their parsedWeakMap IDs
|
|
636
|
+
// never make it onto liveWeakMap. Without this pass, the receiver
|
|
637
|
+
// would mint fresh IDs on its next save for those elements,
|
|
638
|
+
// breaking convergence exactly for newly-added ambiguous siblings.
|
|
639
|
+
if (identityMap && typeof identityMap === 'object' && !Array.isArray(identityMap)) {
|
|
640
|
+
this._fillInIdsAfterMorph(document.documentElement, newDoc.documentElement, identityMap);
|
|
641
|
+
}
|
|
642
|
+
|
|
385
643
|
// Only mark lastHtml after a successful morph so that a failed apply
|
|
386
644
|
// doesn't desync our state and cause the next outbound save to be
|
|
387
645
|
// mistakenly skipped as "unchanged". Note: lastSeenSeq is advanced at
|
|
@@ -449,6 +707,8 @@ if (typeof window !== 'undefined') {
|
|
|
449
707
|
}
|
|
450
708
|
}
|
|
451
709
|
|
|
452
|
-
// Export for hyperclayjs module system
|
|
453
|
-
|
|
710
|
+
// Export for hyperclayjs module system. The class itself is exported so
|
|
711
|
+
// tests can create fresh instances without driving the singleton's
|
|
712
|
+
// EventSource/snapshot wiring.
|
|
713
|
+
export { liveSync, LiveSync };
|
|
454
714
|
export default liveSync;
|
package/src/hyperclay.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* DO NOT EDIT THIS FILE DIRECTLY — it is generated from build/hyperclay.template.js
|
|
3
3
|
*
|
|
4
|
-
* HyperclayJS v1.
|
|
4
|
+
* HyperclayJS v1.28.0 - Minimal Browser-Native Loader
|
|
5
5
|
*
|
|
6
6
|
* Modules auto-init when imported (no separate init call needed).
|
|
7
7
|
* Include `export-to-window` feature to export to window.hyperclay.
|
|
@@ -61,6 +61,7 @@ const MODULE_PATHS = {
|
|
|
61
61
|
"style-injection": "./dom-utilities/insertStyleTag.js",
|
|
62
62
|
"form-data": "./dom-utilities/getDataFromForm.js",
|
|
63
63
|
"hyper-morph": "./vendor/hyper-morph.vendor.js",
|
|
64
|
+
"hyper-html-api": "./vendor/hyper-html-api.vendor.js",
|
|
64
65
|
"slugify": "./string-utilities/slugify.js",
|
|
65
66
|
"copy-to-clipboard": "./string-utilities/copy-to-clipboard.js",
|
|
66
67
|
"query-params": "./string-utilities/query.js",
|
|
@@ -187,6 +188,7 @@ const PRESETS = {
|
|
|
187
188
|
"style-injection",
|
|
188
189
|
"form-data",
|
|
189
190
|
"hyper-morph",
|
|
191
|
+
"hyper-html-api",
|
|
190
192
|
"slugify",
|
|
191
193
|
"copy-to-clipboard",
|
|
192
194
|
"query-params",
|
|
@@ -337,6 +339,7 @@ export const insertStyleTag = window.hyperclayModules['style-injection']?.insert
|
|
|
337
339
|
export const getDataFromForm = window.hyperclayModules['form-data']?.getDataFromForm ?? window.hyperclayModules['form-data']?.default;
|
|
338
340
|
export const HyperMorph = window.hyperclayModules['hyper-morph']?.HyperMorph ?? window.hyperclayModules['hyper-morph']?.default;
|
|
339
341
|
export const morph = window.hyperclayModules['hyper-morph']?.morph ?? window.hyperclayModules['hyper-morph']?.default;
|
|
342
|
+
export const HyperHtmlApi = window.hyperclayModules['hyper-html-api']?.HyperHtmlApi ?? window.hyperclayModules['hyper-html-api']?.default;
|
|
340
343
|
export const slugify = window.hyperclayModules['slugify']?.slugify ?? window.hyperclayModules['slugify']?.default;
|
|
341
344
|
export const copyToClipboard = window.hyperclayModules['copy-to-clipboard']?.copyToClipboard ?? window.hyperclayModules['copy-to-clipboard']?.default;
|
|
342
345
|
export const query = window.hyperclayModules['query-params']?.query ?? window.hyperclayModules['query-params']?.default;
|
package/src/ui/prompts.js
CHANGED
|
@@ -26,17 +26,22 @@ function createModal(promptText, yesCallback, extraContent = "", includeInput =
|
|
|
26
26
|
promptResult = document.querySelector(".micromodal__input").value;
|
|
27
27
|
if (!promptResult) return false; // keep modal open on empty input
|
|
28
28
|
}
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
29
|
+
// Run the validation callback synchronously so a throw can keep the
|
|
30
|
+
// modal open (callers rely on this — e.g. delete-site confirms by
|
|
31
|
+
// throwing when the typed name doesn't match).
|
|
32
|
+
if (yesCallback) {
|
|
33
|
+
try {
|
|
34
|
+
yesCallback(promptResult);
|
|
35
|
+
} catch (err) {
|
|
36
|
+
toast(err.message || 'An error occurred', 'error');
|
|
37
|
+
return false; // keep modal open, user can retry
|
|
36
38
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
39
|
+
}
|
|
40
|
+
// Defer resolve so downstream .then() handlers don't fire inside this
|
|
41
|
+
// modal's onYes loop — themodal is a singleton, and chained ask()/
|
|
42
|
+
// consent() calls need a clean themodal to set up their state.
|
|
43
|
+
setTimeout(() => resolve(promptResult), 0);
|
|
44
|
+
return true; // allow modal to close
|
|
40
45
|
});
|
|
41
46
|
|
|
42
47
|
themodal.onNo = () => {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
var HyperHtmlApi=(()=>{var B=Object.defineProperty;var ce=Object.getOwnPropertyDescriptor;var le=Object.getOwnPropertyNames;var ae=Object.prototype.hasOwnProperty;var ee=(e,t)=>{for(var r in t)B(e,r,{get:t[r],enumerable:!0})},ue=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of le(t))!ae.call(e,n)&&n!==r&&B(e,n,{get:()=>t[n],enumerable:!(o=ce(t,n))||o.enumerable});return e};var de=e=>ue(B({},"__esModule",{value:!0}),e);var Be={};ee(Be,{cms:()=>ie,default:()=>qe,engine:()=>se,upgrade:()=>fe});var C=["textContent","innerText","innerHTML","outerHTML","value","checked","selected","disabled","readOnly","type","tagName","nodeName","nodeType","nodeValue","childElementCount","id","className","classList","href","src","action","baseURI","offsetWidth","offsetHeight","clientWidth","clientHeight","scrollWidth","scrollHeight","dataset","currentSrc","duration","paused","title","documentURI","contentType"],O=new Set(C);var D={};ee(D,{EmptyListInsert:()=>b,MaxRuleDepthExceeded:()=>E,RulesParseError:()=>x,ShapeMismatch:()=>M,UnknownRulesVersion:()=>T,UpgradeAlreadyRegistered:()=>w});var x=class extends Error{constructor(t,r){super(t),this.name="RulesParseError",this.cause=r}},T=class extends Error{constructor(t){super(`unknown rules version: ${t}. Library supports "1".`),this.name="UnknownRulesVersion",this.version=t}},E=class extends Error{constructor(t){super(`rule depth exceeded 20 at path: ${t.join(".")}`),this.name="MaxRuleDepthExceeded",this.path=t}},M=class extends Error{constructor(t){super(`shape mismatch: ${t.length} field(s) failed validation`),this.name="ShapeMismatch",this.mismatches=t}},b=class extends Error{constructor(t){super(`cannot add items to empty list at "${t.join(".")}" \u2014 no sibling to clone as template. Seed the list with a hidden item first.`),this.name="EmptyListInsert",this.path=t}},w=class extends Error{constructor(){super("upgrade transform already registered; only one registration is allowed per page."),this.name="UpgradeAlreadyRegistered"}};var pe=20;function A(e,t,r){return $(e,t,r,{depth:0,path:[]})}function $(e,t,r,o){if(o.depth>pe)throw new E(o.path);if(typeof r=="string")return he(e,t,r);if(Array.isArray(r)){let[n,s]=r;return e.find(t,n).map((i,f)=>$(e,i,s,{depth:o.depth+1,path:[...o.path,f]}))}if(typeof r=="object"&&r!==null){let n={};for(let[s,c]of Object.entries(r))n[s]=$(e,t,c,{depth:o.depth+1,path:[...o.path,s]});return n}return null}function he(e,t,r){if(r.endsWith("[]")){let n=r.slice(0,-2);return e.find(t,n).map(s=>e.text(s))}if(r.startsWith("@"))return te(e,t,r.slice(1));if(r.includes("@")){let[n,s]=r.split("@"),c=n?e.find(t,n):[t];return c.length===0?null:te(e,c[0],s)}if(r===".")return e.text(t);let o=e.find(t,r);return o.length===0?null:e.text(o[0])}function te(e,t,r){if(O.has(r)){let n=e.prop(t,r);return n==null?null:String(n)}let o=e.attr(t,r);return o||null}var ye=.5;function W(e,t,r,o,n,s,c){let i=e.find(t,r);if(n.length===0){i.forEach(d=>e.remove(d));return}if(n.length>i.length&&i.length===0)throw new b(s.path);let a=i.map(d=>me(e,d,o)),u=null;if(i.length>0){u=e.clone(i[0]);let d=e.stripIds(u);d>0&&console.warn(`[hyper-html-api] stripped ${d} id attribute(s) from cloned template at "${s.path.join(".")||"(root)"}"`)}let p=ge(n,a,o),l=e.parent(i[0]),R=Ae(e,l,i[0]),y=new Set,h=n.map((d,m)=>{let S=p[m];if(S>=0)return y.add(S),i[S];let v=e.clone(u);return e.stripIds(v),v});i.forEach((d,m)=>{y.has(m)||e.remove(d)}),y.forEach(d=>e.remove(i[d])),h.forEach((d,m)=>{e.insertAt(l,d,R+m)}),h.forEach((d,m)=>{if(o===null){let S=n[m];e.text(d,S==null?"":String(S))}else c(e,d,o,n[m],{depth:s.depth+1,path:[...s.path,m]})})}function me(e,t,r){return r===null?e.text(t):A(e,t,r)}function ge(e,t,r){let o=new Array(e.length).fill(-1),n=new Set;return e.forEach((s,c)=>{let i=-1,f=-1;t.forEach((a,u)=>{if(n.has(u))return;let p=Ee(s,a,r),l=p===f&&i>=0?Math.abs(u-c)<Math.abs(i-c):!1;(p>f||l)&&(f=p,i=u)}),f>=ye&&(o[c]=i,n.add(i))}),o}function Ee(e,t,r){if(r===null)return e===t?1:0;let o=Object.keys(r||{});if(o.length===0)return 0;let n=0;for(let s of o)JSON.stringify(e?.[s])===JSON.stringify(t?.[s])&&n++;return n/o.length}function Ae(e,t,r){let o=e.children(t);for(let n=0;n<o.length;n++)if(e.sameNode(o[n],r))return n;return-1}var Re=20,re=new Set(["checked","selected","disabled","readOnly","paused"]);function L(e,t,r,o){let n=[];if(F(r,o,[],n),n.length)throw new M(n);j(e,t,r,o,{depth:0,path:[]})}function j(e,t,r,o,n){if(n.depth>Re)throw new E(n.path);if(o!==void 0){if(typeof r=="string")return Se(e,t,r,o,n);if(Array.isArray(r)){let[s,c]=r;return W(e,t,s,c,o,n,j)}if(typeof r=="object"&&r!==null)for(let[s,c]of Object.entries(r))j(e,t,c,o==null?o:o[s],{depth:n.depth+1,path:[...n.path,s]})}}function Se(e,t,r,o,n){if(r.endsWith("[]")){let c=r.slice(0,-2);return W(e,t,c,null,o,n,j)}if(r.startsWith("@"))return ne(e,t,r.slice(1),o);if(r.includes("@")){let[c,i]=r.split("@"),f=c?e.find(t,c):[t];return f.length===0?void 0:ne(e,f[0],i,o)}if(r==="."){e.text(t,o==null?"":String(o));return}let s=e.find(t,r);s.length!==0&&e.text(s[0],o==null?"":String(o))}function ne(e,t,r,o){O.has(r)?e.prop(t,r,xe(r,o)):e.attr(t,r,o==null?"":String(o))}function xe(e,t){return t==null?re.has(e)?!1:"":re.has(e)?!!t:t}function F(e,t,r,o){if(!(t==null||t==="")){if(typeof e=="string"){if(e.endsWith("[]")){Array.isArray(t)?t.forEach((n,s)=>{typeof n=="object"&&n!==null&&o.push({path:N([...r,s]),expected:"scalar",got:I(n)})}):o.push({path:N(r),expected:"array",got:I(t)});return}typeof t=="object"&&o.push({path:N(r),expected:"scalar",got:I(t)});return}if(Array.isArray(e)){if(!Array.isArray(t)){o.push({path:N(r),expected:"array",got:I(t)});return}let n=e[1];t.forEach((s,c)=>F(n,s,[...r,c],o));return}if(typeof e=="object"&&e!==null){if(Array.isArray(t)||typeof t!="object"){o.push({path:N(r),expected:"object",got:I(t)});return}for(let[n,s]of Object.entries(e))F(s,t[n],[...r,n],o)}}}function I(e){return e===null?"null":Array.isArray(e)?"array":typeof e}function N(e){return e.join(".")}function P(e){try{return JSON.parse(e)}catch(t){throw new x(`hyper-html-api script tags require strict JSON. Relaxed JSON (unquoted keys, single quotes, trailing commas) is only supported in the ?data= URL parameter. Original error: ${t.message}`,t)}}function J(e){try{return JSON.parse(e)}catch{}let t={BRACE_OPEN:"{",BRACE_CLOSE:"}",BRACKET_OPEN:"[",BRACKET_CLOSE:"]",COLON:":",COMMA:",",STRING:"STRING",SELECTOR:"SELECTOR",IDENTIFIER:"IDENTIFIER",NUMBER:"NUMBER",BOOLEAN:"BOOLEAN"};function r(n){let s=[],c=0;for(;c<n.length;){let i=n[c];if(/\s/.test(i)){c++;continue}if("{}".includes(i)){s.push({type:i,value:i}),c++;continue}if(i==="["){let p=!1,l=c+1;for(;l<n.length&&/\s/.test(n[l]);)l++;if(l<n.length&&/[a-zA-Z_]/.test(n[l])&&(p=!0),!p){s.push({type:i,value:i}),c++;continue}}if(i==="]"){s.push({type:i,value:i}),c++;continue}if(i===":"){s.push({type:t.COLON,value:i}),c++;continue}if(i===","){s.push({type:t.COMMA,value:i}),c++;continue}if(i==='"'||i==="'"){let p=i,l=c+1;for(;l<n.length&&n[l]!==p;)n[l]==="\\"&&l++,l++;s.push({type:t.STRING,value:n.substring(c+1,l),quoted:!0}),c=l+1;continue}let f=c,a;for(;f<n.length&&!/[{},]/.test(n[f]);)if(n[f]===":"){let p=[":first",":last",":nth-child",":nth-of-type",":first-child",":last-child",":first-of-type",":last-of-type",":only-child",":only-of-type",":hover",":focus",":active",":visited",":disabled",":enabled",":checked",":empty",":root",":target",":not",":before",":after",":nth-last-child",":nth-last-of-type"],l=!1;for(let R of p){let y=R.substring(1);if(n.substring(f+1,f+1+y.length)===y){l=!0,f+=y.length;break}}if(!l)break}else if(n[f]==="["){for(f++;f<n.length&&n[f]!=="]";){if(n[f]==='"'||n[f]==="'"){let p=n[f];for(f++;f<n.length&&n[f]!==p;)n[f]==="\\"&&f++,f++}f++}f<n.length&&n[f]==="]"&&f++}else f++;a=n.substring(c,f);let u=t.IDENTIFIER;/^-?\d+(\.\d+)?$/.test(a)?u=t.NUMBER:a==="true"||a==="false"||a==="null"?u=t.BOOLEAN:/^[.#@\[]|[.#@\[]| /.test(a)&&(u=t.SELECTOR),s.push({type:u,value:a,quoted:!1}),c=f}return s}function o(n){let s="";for(let c=0;c<n.length;c++){let i=n[c];if("{}".includes(i.type)||"[]".includes(i.type)){s+=i.value;continue}if(i.type===t.COLON){s+=i.value;continue}if(i.type===t.COMMA){s+=i.value;continue}if(i.type===t.STRING&&i.quoted){s+=`"${i.value}"`;continue}if(i.type===t.NUMBER||i.type===t.BOOLEAN){s+=i.value;continue}if(i.type===t.SELECTOR||i.type===t.IDENTIFIER){s+=`"${i.value}"`;continue}s+=`"${i.value}"`}return s}try{let n=r(e),s=o(n);return JSON.parse(s)}catch(n){throw new x("Invalid extraction rules syntax: "+n.message,n)}}var Oe="hyper-html-api",Te="1";function _(e,t){let r=e.find(t,`script#${Oe}`,{includeRulesTag:!0});if(r.length===0)return null;let o=r[0],n=e.attr(o,"data-rules-version");if(n!==Te)throw new T(n);let s=e.text(o);return{rules:P(s),tagNode:o}}var G=null;function V(e){if(typeof e!="function")throw new TypeError("registerUpgrade expects a function (v1Data) => v2Data");if(G)throw new w;G=e}function H(){return G}function U(e,t){let r={carriedOver:0,discarded:0,listItems:0},o=Y(t,e,r);return X(t,e,r),{data:o,summary:r}}function Y(e,t,r){if(typeof e=="string")return e.endsWith("[]")?Array.isArray(t)?(r.listItems+=t.length,r.carriedOver+=t.length,t):void 0:t==null?void 0:(r.carriedOver++,t);if(Array.isArray(e)){let[,o]=e;return Array.isArray(t)?(r.listItems+=t.length,t.map(n=>Y(o,n,r))):void 0}if(typeof e=="object"&&e!==null){let o={};for(let[n,s]of Object.entries(e)){let c=Y(s,t?.[n],r);c!==void 0&&(o[n]=c)}return o}}function X(e,t,r){if(t!=null){if(typeof e=="object"&&e!==null&&!Array.isArray(e)){if(typeof t!="object"||Array.isArray(t))return;let o=new Set(Object.keys(e));for(let n of Object.keys(t))o.has(n)?X(e[n],t[n],r):r.discarded+=k(t[n]);return}if(Array.isArray(e)&&Array.isArray(t)){let o=e[1];t.forEach(n=>X(o,n,r));return}typeof e=="string"&&!e.endsWith("[]")&&typeof t=="object"&&t!==null&&(r.discarded+=k(t))}}function k(e){return e==null?0:Array.isArray(e)?e.reduce((t,r)=>t+k(r),0):typeof e=="object"?Object.values(e).reduce((t,r)=>t+k(r),0):1}async function z({sourceUrl:e,v1Data:t,v1Version:r=null,parent:o=typeof window<"u"?window:null,timeoutMs:n=15e3,hidden:s=!0}={}){if(!o)throw new Error("upgrade.run requires a window context");if(!e)throw new Error("upgrade.run requires sourceUrl");let c=be(e,o.location.origin),i=new URL(c,o.location.href).origin,f=o.document.createElement("iframe");s&&(f.style.cssText="position:absolute;left:-9999px;top:-9999px;width:1px;height:1px;border:0;"),f.setAttribute("aria-hidden","true"),f.src=c,o.document.body.appendChild(f);let a=()=>{};try{return await new Promise((u,p)=>{let l=setTimeout(()=>{p(new Error(`upgrade.run: helper iframe timed out after ${n}ms`))},n),R=y=>{if(y.source!==f.contentWindow||y.origin!==i)return;let h=y.data;if(!(!h||typeof h!="object")){if(h.type==="hha:upgrade-ready"){f.contentWindow.postMessage({type:"hha:upgrade-data",v1Data:t,v1Version:r},i);return}if(h.type==="hha:upgrade-result"){clearTimeout(l),u({html:h.html,summary:h.summary});return}if(h.type==="hha:upgrade-error"){clearTimeout(l);let d=new Error(h.message||"helper error");d.name=h.name||"UpgradeHelperError",p(d);return}}};o.addEventListener("message",R),a=()=>{o.removeEventListener("message",R),clearTimeout(l),f.parentNode&&f.parentNode.removeChild(f)}})}finally{a()}}function be(e,t){let r=new URL(e,typeof location<"u"?location.href:void 0);return r.searchParams.set("_hyperHtmlApi","upgrade-helper"),r.searchParams.set("parentOrigin",t),r.toString()}var we="hyper-html-api";function Ie(e){return e&&e.nodeType===1&&e.id===we&&e.tagName==="SCRIPT"}function Ne(e){return e?(e.nodeType===9||e.nodeType===11,e):null}var Le={find(e,t,r={}){let o=Ne(e);if(!o||!o.querySelectorAll)return[];let n=Array.from(o.querySelectorAll(t));return r.includeRulesTag?n:n.filter(s=>!Ie(s))},parent(e){return e?e.parentElement:null},children(e){return e?Array.from(e.children):[]},text(e,t){if(t===void 0)return(e.textContent||"").trim();e.textContent=t},attr(e,t,r){if(r===void 0)return e.hasAttribute&&e.hasAttribute(t)?e.getAttribute(t):null;e.setAttribute(t,r)},prop(e,t,r){if(r===void 0){let o=e?e[t]:void 0;return o!==void 0?o:null}e[t]=r},clone(e){return e.cloneNode(!0)},insertAt(e,t,r){let o=e.children[r]||null;e.insertBefore(t,o)},remove(e){e&&e.parentNode&&e.parentNode.removeChild(e)},stripIds(e){let t=0;return e.id&&(e.removeAttribute("id"),t++),(e.querySelectorAll?e.querySelectorAll("[id]"):[]).forEach(o=>{o.removeAttribute("id"),t++}),t},sameNode(e,t){return e===t}},g=Le;var Pe="_hyperHtmlApi",_e="upgrade-helper",Ue="parentOrigin";function q(e=typeof location<"u"?location:null){if(!e)return!1;try{return new URLSearchParams(e.search).get(Pe)===_e}catch{return!1}}function oe(e=typeof location<"u"?location:null){return e?new URLSearchParams(e.search).get(Ue):null}function Z({win:e,doc:t,parentOrigin:r}={}){if(e=e||(typeof window<"u"?window:null),t=t||(typeof document<"u"?document:null),!e||!t||(r=r||oe(e.location),!r))return;let o=()=>Ce({win:e,doc:t,parentOrigin:r});t.readyState==="loading"?t.addEventListener("DOMContentLoaded",o,{once:!0}):o()}function Ce({win:e,doc:t,parentOrigin:r}){let o;try{o=_(g,t.body)}catch(f){return K(e,r,f)}if(!o)return K(e,r,new Error("helper-mode: no rules tag in v2 document"));let n=o.rules,s=je(t,"hyper-version"),c=!!H(),i=f=>{if(f.source!==e.parent||f.origin!==r)return;let a=f.data;if(!(!a||a.type!=="hha:upgrade-data")){e.removeEventListener("message",i);try{let u=De({doc:t,rules:n,v1Data:a.v1Data});e.parent.postMessage({type:"hha:upgrade-result",html:u.html,summary:u.summary},r)}catch(u){K(e,r,u)}}};e.addEventListener("message",i),e.parent.postMessage({type:"hha:upgrade-ready",rules:n,version:s,hasTransform:c},r)}function De({doc:e,rules:t,v1Data:r}){let o=H(),n=r,s=!1;o&&(n=o(r),s=!0);let{data:c,summary:i}=U(n,t);L(g,e.body,t,c);let f=A(g,e.body,t);return{html:`<!DOCTYPE html>
|
|
2
|
+
`+e.documentElement.outerHTML,summary:{...i,transformApplied:s,appliedFieldCount:Q(f)}}}function K(e,t,r){e.parent.postMessage({type:"hha:upgrade-error",name:r?.name||"Error",message:r?.message||String(r)},t)}function je(e,t){let r=e.querySelector(`meta[name="${t}"]`);return r?r.getAttribute("content"):null}function Q(e){return e==null?0:Array.isArray(e)?e.reduce((t,r)=>t+Q(r),0):typeof e=="object"?Object.values(e).reduce((t,r)=>t+Q(r),0):1}var se={extract:(e,t)=>A(g,e,t),apply:(e,t,r)=>L(g,e,t,r),findRulesIn:e=>_(g,e),parseStrict:P,parseRelaxed:J,errors:D,DOM_PROPERTIES:C},ie={},fe={registerUpgrade:V,run:z,shapeMatch:U,isHelperMode:q};typeof window<"u"&&q(window.location)&&Z({win:window,doc:document});var ke={engine:se,cms:ie,upgrade:fe},qe=ke;return de(Be);})();
|
|
3
|
+
|
|
4
|
+
// Auto-export to window unless suppressed by loader
|
|
5
|
+
if (!window.__hyperclayNoAutoExport) {
|
|
6
|
+
window.hyperclay = window.hyperclay || {};
|
|
7
|
+
window.hyperclay.htmlApi = HyperHtmlApi;
|
|
8
|
+
window.HyperHtmlApi = HyperHtmlApi;
|
|
9
|
+
window.h = window.hyperclay;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { HyperHtmlApi };
|
|
13
|
+
export default HyperHtmlApi;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var HyperMorph=(()=>{var V=Object.defineProperty;var K=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var Y=Object.prototype.hasOwnProperty;var J=(s,o)=>{for(var u in o)V(s,u,{get:o[u],enumerable:!0})},Q=(s,o,u,d)=>{if(o&&typeof o=="object"||typeof o=="function")for(let h of G(o))!Y.call(s,h)&&h!==u&&V(s,h,{get:()=>o[h],enumerable:!(d=K(o,h))||d.enumerable});return s};var X=s=>Q(V({},"__esModule",{value:!0}),s);var pe={};J(pe,{HyperMorph:()=>$,default:()=>he,defaults:()=>fe,morph:()=>de});var F={includeClasses:!0,includeAttributes:["href","src","name","type","role","aria-label","alt","title"],excludeAttributePrefixes:["data-morph-","data-hyper-","data-im-"],textHintLength:64,excludeIds:!0,maxPathDepth:4,landmarks:["HEADER","NAV","MAIN","ASIDE","FOOTER","SECTION","ARTICLE"],weights:{signature:100,pathSegment:10,textMatch:20,textMismatch:25,uniqueCandidate:50,positionPenalty:1},minConfidence:101};function Z(s){let o=5381;for(let u=0;u<s.length;u++)o=(o<<5)+o^s.charCodeAt(u);return Math.abs(o).toString(36)}function ee(s){if(s.classList&&s.classList.length>0)return Array.from(s.classList).sort().join(" ");let o=s.getAttribute?.("class");return o?o.split(/\s+/).filter(Boolean).sort().join(" "):""}function te(s,o){let u=[];for(let d of s.attributes||[]){let h=d.name;h==="id"||h==="class"||o.excludeAttributePrefixes.some(y=>h.startsWith(y))||o.includeAttributes.includes(h)&&u.push(`${h}=${d.value}`)}return u.sort().join("|")}function ne(s,o){return(s.textContent||"").replace(/\s+/g," ").trim().slice(0,o.textHintLength)}function re(s,o){let u=[s.tagName];return o.includeClasses&&u.push(ee(s)),u.push(te(s,o)),Z(u.join("|"))}function se(s){let o=s.tagName,u=1,d=s.previousElementSibling;for(;d;)d.tagName===o&&u++,d=d.previousElementSibling;return u}function ie(s,o){return s.id||s.getAttribute?.("role")?!0:o.landmarks.includes(s.tagName)}function ae(s){if(s.id)return`#${s.id}`;let o=s.getAttribute?.("role");return o?`@${o}`:s.tagName}function oe(s,o){let u=[],d=s;for(;d&&d.tagName&&u.length<o.maxPathDepth;){let h=`${d.tagName}:${se(d)}`;if(u.unshift(h),d!==s&&ie(d,o)){u.unshift(ae(d));break}d=d.parentElement}return u}function ue(s,o){let u=0,d=s.length-1,h=o.length-1;for(;d>=0&&h>=0&&s[d]===o[h];)u++,d--,h--;return u}function C(s,o,u){if(u.has(s))return u.get(s);let d={signature:re(s,o),path:oe(s,o),textHint:ne(s,o)};return u.set(s,d),d}function z(s,o,u,d){if(d.has(s))return d.get(s);let h=new Map,y=s.querySelectorAll("*"),H=0;for(let S of y){let I=C(S,o,u);I.domIndex=H++,h.has(I.signature)||h.set(I.signature,[]),h.get(I.signature).push(S)}return d.set(s,h),h}function ce(s,o,u){u.delete(s),o.delete(s);let d=s.querySelectorAll("*");for(let h of d)o.delete(h)}function q(s,o,u,d,h){let y=C(s,u,d),H=C(o,u,d),S=u.weights,I={},E=0;if(y.signature!==H.signature)return{score:0,breakdown:{rejected:"signature mismatch"}};E+=S.signature,I.signature=S.signature;let T=ue(y.path,H.path)*S.pathSegment;E+=T,I.path=T;let k=!0;if(y.textHint&&H.textHint?y.textHint===H.textHint?(E+=S.textMatch,I.text=S.textMatch):(E-=S.textMismatch,I.text=-S.textMismatch,k=!1):y.textHint!==H.textHint&&(E-=S.textMismatch,I.text=-S.textMismatch,k=!1),h.candidateCount===1&&k&&(E+=S.uniqueCandidate,I.unique=S.uniqueCandidate),typeof y.domIndex=="number"&&typeof H.domIndex=="number"){let N=Math.abs(y.domIndex-H.domIndex),R=Math.min(N*S.positionPenalty,20);E-=R,I.drift=-R}return{score:E,breakdown:I}}function D(s,o,u,d,h){if(u.excludeIds&&s.id)return null;let y=z(o,u,d,h),H=C(s,u,d);if(typeof H.domIndex!="number"){let k=0,N=s.previousElementSibling;for(;N;)k++,N=N.previousElementSibling;H.domIndex=k}let S=y.get(H.signature)||[],I=u.excludeIds?S.filter(k=>!k.id):S;if(I.length===0)return null;let E=null,x=0,T=null;for(let k of I){let{score:N,breakdown:R}=q(s,k,u,d,{candidateCount:I.length});N>x&&(x=N,E=k,T=R)}return x<u.minConfidence?null:{element:E,confidence:x,breakdown:T}}function W(s,o,u,d,h){let y=o.querySelectorAll("*"),H=z(s,u,d,h),S=0;for(let T of y){let k=C(T,u,d);k.domIndex=S++}let I=[];for(let T of y){if(u.excludeIds&&T.id)continue;let k=C(T,u,d),N=H.get(k.signature)||[],R=u.excludeIds?N.filter(B=>!B.id):N;for(let B of R){let{score:l,breakdown:A}=q(T,B,u,d,{candidateCount:R.length});l>=u.minConfidence&&I.push({newEl:T,oldEl:B,score:l,breakdown:A})}}I.sort((T,k)=>k.score-T.score);let E=new Map,x=new Set;for(let{newEl:T,oldEl:k}of I)E.has(T)||x.has(k)||(E.set(T,k),x.add(k));return E}function P(s,o,u,d){let h=C(s,u,d),y=C(o,u,d),{score:H,breakdown:S}=q(s,o,u,d,{candidateCount:1});return{matches:H>=u.minConfidence,score:H,breakdown:S,newMeta:{signature:h.signature,path:h.path,textHint:h.textHint},oldMeta:{signature:y.signature,path:y.path,textHint:y.textHint}}}function U(s={}){let o={...F,...s,weights:{...F.weights,...s.weights}},u=new WeakMap,d=new WeakMap;return{findMatch:(h,y)=>D(h,y,o,u,d),computeMatches:(h,y)=>W(h,y,o,u,d),explain:(h,y)=>P(h,y,o,u),invalidate:h=>ce(h,u,d),session:()=>{let h=new WeakMap,y=new WeakMap;return{findMatch:(H,S)=>D(H,S,o,h,y),computeMatches:(H,S)=>W(H,S,o,h,y),explain:(H,S)=>P(H,S,o,h)}},getConfig:()=>({...o})}}var le=U(),$=(function(){"use strict";let s=()=>{};function o(l){if(!(l instanceof Element))return!1;if(l.hasAttribute("save-ignore"))return!0;if(l.tagName==="LINK"||l.tagName==="SCRIPT"){let A=l.getAttribute("src")||l.getAttribute("href")||"";if(A.startsWith("chrome-extension://")||A.startsWith("moz-extension://")||A.startsWith("safari-web-extension://"))return!0}return!1}function u(l,A){if(A!=="smart")return l.outerHTML;let p=l.getAttribute("src"),v=l.getAttribute("type")||"text/javascript";if(p)try{let b=new URL(p,window.location.href);return`ext:${v}:${b.origin}${b.pathname}${b.search}`}catch{return`ext:${v}:${p}`}else{let b=l.textContent.trim(),g=5381;for(let r=0;r<b.length;r++)g=(g<<5)+g^b.charCodeAt(r);return`inline:${v}:${Math.abs(g).toString(36)}`}}let d={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:s,afterNodeAdded:s,beforeNodeMorphed:s,afterNodeMorphed:s,beforeNodeRemoved:s,afterNodeRemoved:s,beforeAttributeUpdated:s},head:{style:"merge",shouldPreserve:l=>l.getAttribute("im-preserve")==="true",shouldReAppend:l=>l.getAttribute("im-re-append")==="true",shouldRemove:s,afterHeadMorphed:s},scripts:{handle:!1,matchMode:"outerHTML",shouldPreserve:l=>l.getAttribute("im-preserve")==="true",shouldReAppend:l=>l.getAttribute("im-re-append")==="true",shouldRemove:s,afterScriptsHandled:s},restoreFocus:!0},h={computeMatches(l,A){let{computeMatches:p}=le.session();return p(l,A)}};function y(l,A,p={}){l=R(l);let v=B(A),b=N(l,v,p),g=b.scripts.matchMode,r=new Set(Array.from(l.querySelectorAll("script")).map(n=>u(n,g))),c=S(b,()=>x(b,l,v,n=>n.morphStyle==="innerHTML"?(I(n,l,v),Array.from(l.childNodes)):H(n,l,v)));b.pantry.remove();let e=k(l,r,b);return e.length>0?c instanceof Promise?c.then(n=>Promise.all(e).then(()=>n)):Promise.all(e).then(()=>c):c}function H(l,A,p){let v=B(A);return I(l,v,p,A,A.nextSibling),Array.from(v.childNodes)}function S(l,A){if(!l.config.restoreFocus)return A();let p=document.activeElement;if(!(p instanceof HTMLInputElement||p instanceof HTMLTextAreaElement))return A();let{id:v,selectionStart:b,selectionEnd:g}=p,r=A();return v&&v!==document.activeElement?.getAttribute("id")&&(p=l.target.querySelector(`[id="${v}"]`),p?.focus()),p&&!p.selectionEnd&&g!=null&&p.setSelectionRange(b,g),r}let I=(function(){function l(e,n,i,t=null,a=null){n instanceof HTMLTemplateElement&&i instanceof HTMLTemplateElement&&(n=n.content,i=i.content),t||=n.firstChild;for(let f of i.childNodes){if(o(f))continue;if(t&&t!=a){let M=p(e,f,t,a);if(M){M!==t&&b(e,t,M),E(M,f,e),t=M.nextSibling;continue}}if(f instanceof Element){let M=f.getAttribute("id");if(e.persistentIds.has(M)){let w=g(n,M,t,e);E(w,f,e),t=w.nextSibling;continue}if(!e.idMap.has(f)){let w=e.hyperMatches.get(f);if(w&&!e.idMap.has(w)){c(n,w,t),E(w,f,e),t=w.nextSibling;continue}}}let m=A(n,f,t,e);m&&(t=m.nextSibling)}for(;t&&t!=a;){let f=t;t=t.nextSibling,o(f)||v(e,f)}}function A(e,n,i,t){if(t.callbacks.beforeNodeAdded(n)===!1)return null;if(t.idMap.has(n)){let a=document.createElement(n.tagName);return e.insertBefore(a,i),E(a,n,t),t.callbacks.afterNodeAdded(a),a}else{let a=document.importNode(n,!0);return e.insertBefore(a,i),t.callbacks.afterNodeAdded(a),a}}let p=(function(){function e(t,a,f,m){let M=a instanceof Element&&!t.idMap.has(a)?t.hyperMatches.get(a):null,w=null,O=a.nextSibling,j=0,L=f;for(;L&&L!=m;){if(i(L,a)){if(n(t,L,a)||L===M&&!t.idMap.has(L))return L;if(w===null){let _=L instanceof Element&&t.hyperMatchedOldElements.has(L);!t.idMap.has(L)&&!_&&(w=L)}}if(w===null&&O&&i(L,O)&&(j++,O=O.nextSibling,j>=2&&(w=void 0)),t.activeElementAndParents.includes(L))break;L=L.nextSibling}return w||null}function n(t,a,f){let m=t.idMap.get(a),M=t.idMap.get(f);if(!M||!m)return!1;for(let w of m)if(M.has(w))return!0;return!1}function i(t,a){let f=t,m=a;return f.nodeType===m.nodeType&&f.tagName===m.tagName&&(!f.getAttribute?.("id")||f.getAttribute?.("id")===m.getAttribute?.("id"))}return e})();function v(e,n){let i=n instanceof Element&&e.hyperMatchedOldElements.has(n)&&!e.idMap.has(n);if(e.idMap.has(n)||i)c(e.pantry,n,null);else{if(e.callbacks.beforeNodeRemoved(n)===!1)return;n.parentNode?.removeChild(n),e.callbacks.afterNodeRemoved(n)}}function b(e,n,i){let t=n;for(;t&&t!==i;){let a=t;t=t.nextSibling,o(a)||v(e,a)}return t}function g(e,n,i,t){let a=t.target.getAttribute?.("id")===n&&t.target||t.target.querySelector(`[id="${n}"]`)||t.pantry.querySelector(`[id="${n}"]`);return r(a,t),c(e,a,i),a}function r(e,n){let i=e.getAttribute("id");for(;e=e.parentNode;){let t=n.idMap.get(e);t&&(t.delete(i),t.size||n.idMap.delete(e))}}function c(e,n,i){if(e.moveBefore)try{e.moveBefore(n,i)}catch{e.insertBefore(n,i)}else e.insertBefore(n,i)}return l})(),E=(function(){function l(r,c,e){return e.ignoreActive&&r===document.activeElement?null:(e.callbacks.beforeNodeMorphed(r,c)===!1||(r instanceof HTMLHeadElement&&e.head.ignore||(r instanceof HTMLHeadElement&&e.head.style!=="morph"?T(r,c,e):(A(r,c,e),g(r,e)||I(e,r,c))),e.callbacks.afterNodeMorphed(r,c)),r)}function A(r,c,e){let n=c.nodeType;if(n===1){let i=r,t=c,a=i.attributes,f=t.attributes;for(let m of f)b(m.name,i,"update",e)||i.getAttribute(m.name)!==m.value&&i.setAttribute(m.name,m.value);for(let m=a.length-1;0<=m;m--){let M=a[m];if(M&&!t.hasAttribute(M.name)){if(b(M.name,i,"remove",e))continue;i.removeAttribute(M.name)}}g(i,e)||p(i,t,e)}(n===8||n===3)&&r.nodeValue!==c.nodeValue&&(r.nodeValue=c.nodeValue)}function p(r,c,e){if(r instanceof HTMLInputElement&&c instanceof HTMLInputElement&&c.type!=="file"){let n=c.value,i=r.value;v(r,c,"checked",e),v(r,c,"disabled",e),c.hasAttribute("value")?i!==n&&(b("value",r,"update",e)||(r.setAttribute("value",n),r.value=n)):b("value",r,"remove",e)||(r.value="",r.removeAttribute("value"))}else if(r instanceof HTMLOptionElement&&c instanceof HTMLOptionElement)v(r,c,"selected",e);else if(r instanceof HTMLTextAreaElement&&c instanceof HTMLTextAreaElement){let n=c.value,i=r.value;if(b("value",r,"update",e))return;n!==i&&(r.value=n),r.firstChild&&r.firstChild.nodeValue!==n&&(r.firstChild.nodeValue=n)}}function v(r,c,e,n){let i=c[e],t=r[e];if(i!==t){let a=b(e,r,"update",n);a||(r[e]=c[e]),i?a||r.setAttribute(e,""):b(e,r,"remove",n)||r.removeAttribute(e)}}function b(r,c,e,n){return r==="value"&&n.ignoreActiveValue&&c===document.activeElement?!0:n.callbacks.beforeAttributeUpdated(r,c,e)===!1}function g(r,c){return!!c.ignoreActiveValue&&r===document.activeElement&&r!==document.body}return l})();function x(l,A,p,v){if(l.head.block){let b=A.querySelector("head"),g=p.querySelector("head");if(b&&g){let r=T(b,g,l);return Promise.all(r).then(()=>{let c=Object.assign(l,{head:{block:!1,ignore:!0}});return v(c)})}}return v(l)}function T(l,A,p){let v=[],b=[],g=[],r=[],c=p.scripts.matchMode,e=t=>{if(t.tagName==="SCRIPT")return u(t,c);if(t.tagName==="LINK"&&c==="smart"){let a=t.getAttribute("href");if(a)try{let f=new URL(a,window.location.href);return`link:${t.getAttribute("rel")||""}:${f.origin}${f.pathname}${f.search}`}catch{}}return t.outerHTML},n=new Map;for(let t of A.children)o(t)||n.set(e(t),t);for(let t of l.children){let a=e(t),f=n.has(a),m=p.head.shouldReAppend(t),M=p.head.shouldPreserve(t);f||M?m?b.push(t):(n.delete(a),g.push(t)):p.head.style==="append"?m&&(b.push(t),r.push(t)):p.head.shouldRemove(t)!==!1&&!o(t)&&b.push(t)}r.push(...n.values());let i=[];for(let t of r){let a=document.createRange().createContextualFragment(t.outerHTML).firstChild;if(p.callbacks.beforeNodeAdded(a)!==!1){if("href"in a&&a.href||"src"in a&&a.src){let f,m=new Promise(function(M){f=M});a.addEventListener("load",function(){f()}),i.push(m)}l.appendChild(a),p.callbacks.afterNodeAdded(a),v.push(a)}}for(let t of b)p.callbacks.beforeNodeRemoved(t)!==!1&&(l.removeChild(t),p.callbacks.afterNodeRemoved(t));return p.head.afterHeadMorphed(l,{added:v,kept:g,removed:b}),i}function k(l,A,p){if(!p.scripts.handle)return[];let v=[],b=[],g=[],r=[],c=p.scripts.matchMode,e=Array.from(l.querySelectorAll("script"));for(let i of e){let t=u(i,c),a=A.has(t),f=p.scripts.shouldPreserve(i),m=p.scripts.shouldReAppend(i);a||f?m?(b.push(i),r.push(i)):g.push(i):r.push(i)}for(let i of A){let t=e.some(a=>a.outerHTML===i)}let n=[];for(let i of r){if(p.callbacks.beforeNodeAdded(i)===!1)continue;let t=document.createRange().createContextualFragment(i.outerHTML).firstChild;if(t.src){let a,f=new Promise(function(m){a=m});t.addEventListener("load",function(){a()}),t.addEventListener("error",function(){a()}),n.push(f)}i.replaceWith(t),p.callbacks.afterNodeAdded(t),v.push(t)}return p.scripts.afterScriptsHandled(l,{added:v,kept:g,removed:b}),n}let N=(function(){function l(e,n,i){let{persistentIds:t,idMap:a}=r(e,n),f=h.computeMatches(e,n),m=new Set;for(let O of f.values())m.add(O);let M=A(i),w=M.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(w))throw`Do not understand how to morph style ${w}`;return{target:e,newContent:n,config:M,morphStyle:w,ignoreActive:M.ignoreActive,ignoreActiveValue:M.ignoreActiveValue,restoreFocus:M.restoreFocus,idMap:a,persistentIds:t,hyperMatches:f,hyperMatchedOldElements:m,pantry:p(),activeElementAndParents:v(e),callbacks:M.callbacks,head:M.head,scripts:M.scripts}}function A(e){let n=Object.assign({},d);return Object.assign(n,e),n.callbacks=Object.assign({},d.callbacks,e.callbacks),n.head=Object.assign({},d.head,e.head),n.scripts=Object.assign({},d.scripts,e.scripts),n}function p(){let e=document.createElement("div");return e.hidden=!0,document.body.insertAdjacentElement("afterend",e),e}function v(e){let n=[],i=document.activeElement;if(i?.tagName!=="BODY"&&e.contains(i))for(;i&&(n.push(i),i!==e);)i=i.parentElement;return n}function b(e){let n=Array.from(e.querySelectorAll("[id]"));return e.getAttribute?.("id")&&n.push(e),n}function g(e,n,i,t){for(let a of t){let f=a.getAttribute("id");if(n.has(f)){let m=a;for(;m;){let M=e.get(m);if(M==null&&(M=new Set,e.set(m,M)),M.add(f),m===i)break;m=m.parentElement}}}}function r(e,n){let i=b(e),t=b(n),a=c(i,t),f=new Map;g(f,a,e,i);let m=n.__hyperMorphRoot||n;return g(f,a,m,t),{persistentIds:a,idMap:f}}function c(e,n){let i=new Set,t=new Map;for(let{id:f,tagName:m}of e)t.has(f)?i.add(f):t.set(f,m);let a=new Set;for(let{id:f,tagName:m}of n)a.has(f)?i.add(f):t.get(f)===m&&a.add(f);for(let f of i)a.delete(f);return a}return l})(),{normalizeElement:R,normalizeParent:B}=(function(){let l=new WeakSet;function A(g){return g instanceof Document?g.documentElement:g}function p(g){if(g==null)return document.createElement("div");if(typeof g=="string")return p(b(g));if(l.has(g))return g;if(g instanceof Node){if(g.parentNode)return new v(g);{let r=document.createElement("div");return r.append(g),r}}else{let r=document.createElement("div");for(let c of[...g])r.append(c);return r}}class v{constructor(r){this.originalNode=r,this.realParentNode=r.parentNode,this.previousSibling=r.previousSibling,this.nextSibling=r.nextSibling}get childNodes(){let r=[],c=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;c&&c!=this.nextSibling;)r.push(c),c=c.nextSibling;return r}querySelectorAll(r){return this.childNodes.reduce((c,e)=>{if(e instanceof Element){e.matches(r)&&c.push(e);let n=e.querySelectorAll(r);for(let i=0;i<n.length;i++)c.push(n[i])}return c},[])}insertBefore(r,c){return this.realParentNode.insertBefore(r,c)}moveBefore(r,c){return this.realParentNode.moveBefore(r,c)}get __hyperMorphRoot(){return this.originalNode}}function b(g){let r=new DOMParser,c=g.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(c.match(/<\/html>/)||c.match(/<\/head>/)||c.match(/<\/body>/)){let e=r.parseFromString(g,"text/html");if(c.match(/<\/html>/))return l.add(e),e;{let n=e.firstChild;return n&&l.add(n),n}}else{let n=r.parseFromString("<body><template>"+g+"</template></body>","text/html").body.querySelector("template").content;return l.add(n),n}}return{normalizeElement:A,normalizeParent:p}})();return{morph:y,defaults:d}})();var de=$.morph,fe=$.defaults,he=$;return X(pe);})();
|
|
1
|
+
var HyperMorph=(()=>{var z=Object.defineProperty;var ne=Object.getOwnPropertyDescriptor;var re=Object.getOwnPropertyNames;var se=Object.prototype.hasOwnProperty;var ie=(s,c)=>{for(var a in c)z(s,a,{get:c[a],enumerable:!0})},ae=(s,c,a,d)=>{if(c&&typeof c=="object"||typeof c=="function")for(let h of re(c))!se.call(s,h)&&h!==a&&z(s,h,{get:()=>c[h],enumerable:!(d=ne(c,h))||d.enumerable});return s};var oe=s=>ae(z({},"__esModule",{value:!0}),s);var we={};ie(we,{HyperMorph:()=>W,default:()=>ke,defaults:()=>Se,morph:()=>ye});var J={includeClasses:!0,includeAttributes:["href","src","name","type","role","aria-label","alt","title"],excludeAttributePrefixes:["data-morph-","data-hyper-","data-im-"],textHintLength:64,excludeIds:!0,maxPathDepth:4,landmarks:["HEADER","NAV","MAIN","ASIDE","FOOTER","SECTION","ARTICLE"],weights:{signature:100,pathSegment:10,textMatch:20,textMismatch:25,uniqueCandidate:50,positionPenalty:1,slotMatch:30},minConfidence:101};function ce(s){let c=5381;for(let a=0;a<s.length;a++)c=(c<<5)+c^s.charCodeAt(a);return Math.abs(c).toString(36)}function ue(s){if(s.classList&&s.classList.length>0)return Array.from(s.classList).sort().join(" ");let c=s.getAttribute?.("class");return c?c.split(/\s+/).filter(Boolean).sort().join(" "):""}function le(s,c){let a=[];for(let d of s.attributes||[]){let h=d.name;h==="id"||h==="class"||c.excludeAttributePrefixes.some(w=>h.startsWith(w))||c.includeAttributes.includes(h)&&a.push(`${h}=${d.value}`)}return a.sort().join("|")}function de(s,c){return(s.textContent||"").replace(/\s+/g," ").trim().slice(0,c.textHintLength)}function fe(s,c){let a=[s.tagName];return c.includeClasses&&a.push(ue(s)),a.push(le(s,c)),ce(a.join("|"))}function he(s){let c=s.tagName,a=1,d=s.previousElementSibling;for(;d;)d.tagName===c&&a++,d=d.previousElementSibling;return a}function pe(s,c){return s.id||s.getAttribute?.("role")?!0:c.landmarks.includes(s.tagName)}function me(s){if(s.id)return`#${s.id}`;let c=s.getAttribute?.("role");return c?`@${c}`:s.tagName}function ge(s,c){let a=[],d=s;for(;d&&d.tagName&&a.length<c.maxPathDepth;){let h=`${d.tagName}:${he(d)}`;if(a.unshift(h),d!==s&&pe(d,c)){a.unshift(me(d));break}d=d.parentElement}return a}function be(s,c){let a=0,d=s.length-1,h=c.length-1;for(;d>=0&&h>=0&&s[d]===c[h];)a++,d--,h--;return a}function q(s,c,a){if(a.has(s))return a.get(s);let d={signature:fe(s,c),path:ge(s,c),textHint:de(s,c)};return a.set(s,d),d}function ee(s,c,a,d){if(d.has(s))return d.get(s);let h=new Map,w=s.querySelectorAll("*"),E=0;for(let S of w){let H=q(S,c,a);H.domIndex=E++,h.has(H.signature)||h.set(H.signature,[]),h.get(H.signature).push(S)}return d.set(s,h),h}function Me(s,c,a){a.delete(s),c.delete(s);let d=s.querySelectorAll("*");for(let h of d)c.delete(h)}function U(s,c,a,d,h){let w=q(s,a,d),E=q(c,a,d),S=a.weights,H={},T=0;if(w.signature!==E.signature)return{score:0,breakdown:{rejected:"signature mismatch"}};T+=S.signature,H.signature=S.signature;let k=be(w.path,E.path)*S.pathSegment;T+=k,H.path=k;let v=!0;if(w.textHint&&E.textHint?w.textHint===E.textHint?(T+=S.textMatch,H.text=S.textMatch):(T-=S.textMismatch,H.text=-S.textMismatch,v=!1):w.textHint!==E.textHint&&(T-=S.textMismatch,H.text=-S.textMismatch,v=!1),h.candidateCount===1&&v&&(T+=S.uniqueCandidate,H.unique=S.uniqueCandidate),typeof w.domIndex=="number"&&typeof E.domIndex=="number"){let I=Math.abs(w.domIndex-E.domIndex),L=Math.min(I*S.positionPenalty,20);T-=L,H.drift=-L}return{score:T,breakdown:H}}function Q(s,c,a,d,h){if(a.excludeIds&&s.id)return null;let w=ee(c,a,d,h),E=q(s,a,d);if(typeof E.domIndex!="number"){let v=0,I=s.previousElementSibling;for(;I;)v++,I=I.previousElementSibling;E.domIndex=v}let S=w.get(E.signature)||[],H=a.excludeIds?S.filter(v=>!v.id):S;if(H.length===0)return null;let T=null,O=0,k=null;for(let v of H){let{score:I,breakdown:L}=U(s,v,a,d,{candidateCount:H.length});I>O&&(O=I,T=v,k=L)}return O<a.minConfidence?null:{element:T,confidence:O,breakdown:k}}function ve(s,c,a,d){let h=[],w=a.weights.signature+a.weights.slotMatch,E={slot:w};function S(k){if(k.children)return k.children;let v=k.childNodes;if(!v)return[];let I=[];for(let L=0;L<v.length;L++)v[L].nodeType===1&&I.push(v[L]);return I}function H(k,v){let I=S(k),L=S(v);if(I.length===L.length)for(let C=0;C<I.length;C++){let u=I[C],M=L[C];if(a.excludeIds&&(u.id||M.id)||u.tagName!==M.tagName)continue;let p=q(u,a,d).signature,A=q(M,a,d).signature;p!==A&&h.push({newEl:u,oldEl:M,score:w,breakdown:E}),H(u,M)}}function T(k,v){for(;;){if(k.tagName===v.tagName)return[k,v];let I=S(k);if(!k.tagName&&I.length===1){k=I[0];continue}let L=S(v);if(L.length===1&&L[0].tagName===k.tagName){v=L[0];continue}return null}}let O=T(s,c);return O&&H(O[0],O[1]),h}function X(s,c,a,d,h){let w=c.querySelectorAll("*"),E=ee(s,a,d,h),S=0;for(let k of w){let v=q(k,a,d);v.domIndex=S++}let H=[];for(let k of w){if(a.excludeIds&&k.id)continue;let v=q(k,a,d),I=E.get(v.signature)||[],L=a.excludeIds?I.filter(C=>!C.id):I;for(let C of L){let{score:u,breakdown:M}=U(k,C,a,d,{candidateCount:L.length});u>=a.minConfidence&&H.push({newEl:k,oldEl:C,score:u,breakdown:M})}}if(a.weights.slotMatch>0){let k=ve(c,s,a,d);for(let v of k)H.push(v)}H.sort((k,v)=>v.score-k.score);let T=new Map,O=new Set;for(let{newEl:k,oldEl:v}of H)T.has(k)||O.has(v)||(T.set(k,v),O.add(v));return T}function Z(s,c,a,d){let h=q(s,a,d),w=q(c,a,d),{score:E,breakdown:S}=U(s,c,a,d,{candidateCount:1});return{matches:E>=a.minConfidence,score:E,breakdown:S,newMeta:{signature:h.signature,path:h.path,textHint:h.textHint},oldMeta:{signature:w.signature,path:w.path,textHint:w.textHint}}}function te(s={}){let c={...J,...s,weights:{...J.weights,...s.weights}},a=new WeakMap,d=new WeakMap;return{findMatch:(h,w)=>Q(h,w,c,a,d),computeMatches:(h,w)=>X(h,w,c,a,d),explain:(h,w)=>Z(h,w,c,a),invalidate:h=>Me(h,a,d),session:()=>{let h=new WeakMap,w=new WeakMap;return{findMatch:(E,S)=>Q(E,S,c,h,w),computeMatches:(E,S)=>X(E,S,c,h,w),explain:(E,S)=>Z(E,S,c,h)}},getConfig:()=>({...c})}}var Ae=te(),W=(function(){"use strict";let s=()=>{};function c(u){if(!(u instanceof Element))return!1;if(u.hasAttribute("save-ignore"))return!0;if(u.tagName==="LINK"||u.tagName==="SCRIPT"){let M=u.getAttribute("src")||u.getAttribute("href")||"";if(M.startsWith("chrome-extension://")||M.startsWith("moz-extension://")||M.startsWith("safari-web-extension://"))return!0}return!1}function a(u,M){if(M!=="smart")return u.outerHTML;let p=u.getAttribute("src"),A=u.getAttribute("type")||"text/javascript";if(p)try{let b=new URL(p,window.location.href);return`ext:${A}:${b.origin}${b.pathname}${b.search}`}catch{return`ext:${A}:${p}`}else{let b=u.textContent.trim(),g=5381;for(let r=0;r<b.length;r++)g=(g<<5)+g^b.charCodeAt(r);return`inline:${A}:${Math.abs(g).toString(36)}`}}let d={morphStyle:"outerHTML",callbacks:{beforeNodeAdded:s,afterNodeAdded:s,beforeNodeMorphed:s,afterNodeMorphed:s,beforeNodeRemoved:s,afterNodeRemoved:s,beforeAttributeUpdated:s},head:{style:"merge",shouldPreserve:u=>u.getAttribute("im-preserve")==="true",shouldReAppend:u=>u.getAttribute("im-re-append")==="true",shouldRemove:s,afterHeadMorphed:s},scripts:{handle:!1,matchMode:"outerHTML",shouldPreserve:u=>u.getAttribute("im-preserve")==="true",shouldReAppend:u=>u.getAttribute("im-re-append")==="true",shouldRemove:s,afterScriptsHandled:s},restoreFocus:!0},h={computeMatches(u,M){let{computeMatches:p}=Ae.session();return p(u,M)}};function w(u,M,p={}){u=L(u);let A=C(M),b=I(u,A,p),g=b.scripts.matchMode,r=new Set(Array.from(u.querySelectorAll("script")).map(n=>a(n,g))),l=S(b,()=>O(b,u,A,n=>n.morphStyle==="innerHTML"?(H(n,u,A),Array.from(u.childNodes)):E(n,u,A)));b.pantry.remove();let e=v(u,r,b);return e.length>0?l instanceof Promise?l.then(n=>Promise.all(e).then(()=>n)):Promise.all(e).then(()=>l):l}function E(u,M,p){let A=C(M);return H(u,A,p,M,M.nextSibling),Array.from(A.childNodes)}function S(u,M){if(!u.config.restoreFocus)return M();let p=document.activeElement;if(!(p instanceof HTMLInputElement||p instanceof HTMLTextAreaElement))return M();let{id:A,selectionStart:b,selectionEnd:g}=p,r=M();return A&&A!==document.activeElement?.getAttribute("id")&&(p=u.target.querySelector(`[id="${A}"]`),p?.focus()),p&&!p.selectionEnd&&g!=null&&p.setSelectionRange(b,g),r}let H=(function(){function u(e,n,i,t=null,o=null){n instanceof HTMLTemplateElement&&i instanceof HTMLTemplateElement&&(n=n.content,i=i.content),t||=n.firstChild;for(let f of i.childNodes){if(c(f))continue;if(t&&t!=o){let y=p(e,f,t,o);if(y){y!==t&&b(e,t,y),T(y,f,e),t=y.nextSibling;continue}}if(f instanceof Element){let y=f.getAttribute("id");if(e.persistentIds.has(y)){let N=g(n,y,t,e);T(N,f,e),t=N.nextSibling;continue}if(!e.idMap.has(f)){let N=e.hyperMatches.get(f);if(N&&!e.idMap.has(N)){l(n,N,t),T(N,f,e),t=N.nextSibling;continue}}}let m=M(n,f,t,e);m&&(t=m.nextSibling)}for(;t&&t!=o;){let f=t;t=t.nextSibling,c(f)||A(e,f)}}function M(e,n,i,t){if(t.callbacks.beforeNodeAdded(n)===!1)return null;if(t.idMap.has(n)){let o=document.createElement(n.tagName);return e.insertBefore(o,i),T(o,n,t),t.callbacks.afterNodeAdded(o),o}else{let o=document.importNode(n,!0);return e.insertBefore(o,i),t.callbacks.afterNodeAdded(o),o}}let p=(function(){function e(t,o,f,m){let y=o instanceof Element&&!t.idMap.has(o)?t.hyperMatches.get(o):null,N=null,$=o.nextSibling,D=0,x=f;for(;x&&x!=m;){if(i(x,o)){if(n(t,x,o)||x===y&&!t.idMap.has(x))return x;if(N===null){let V=x instanceof Element&&t.hyperMatchedOldElements.has(x);!t.idMap.has(x)&&!V&&(N=x)}}if(N===null&&$&&i(x,$)&&(D++,$=$.nextSibling,D>=2&&(N=void 0)),t.activeElementAndParents.includes(x))break;x=x.nextSibling}return N||null}function n(t,o,f){let m=t.idMap.get(o),y=t.idMap.get(f);if(!y||!m)return!1;for(let N of m)if(y.has(N))return!0;return!1}function i(t,o){let f=t,m=o;return f.nodeType===m.nodeType&&f.tagName===m.tagName&&(!f.getAttribute?.("id")||f.getAttribute?.("id")===m.getAttribute?.("id"))}return e})();function A(e,n){let i=n instanceof Element&&e.hyperMatchedOldElements.has(n)&&!e.idMap.has(n);if(e.idMap.has(n)||i)l(e.pantry,n,null);else{if(e.callbacks.beforeNodeRemoved(n)===!1)return;n.parentNode?.removeChild(n),e.callbacks.afterNodeRemoved(n)}}function b(e,n,i){let t=n;for(;t&&t!==i;){let o=t;t=t.nextSibling,c(o)||A(e,o)}return t}function g(e,n,i,t){let o=t.target.getAttribute?.("id")===n&&t.target||t.target.querySelector(`[id="${n}"]`)||t.pantry.querySelector(`[id="${n}"]`);return r(o,t),l(e,o,i),o}function r(e,n){let i=e.getAttribute("id");for(;e=e.parentNode;){let t=n.idMap.get(e);t&&(t.delete(i),t.size||n.idMap.delete(e))}}function l(e,n,i){if(e.moveBefore)try{e.moveBefore(n,i)}catch{e.insertBefore(n,i)}else e.insertBefore(n,i)}return u})(),T=(function(){function u(r,l,e){return e.ignoreActive&&r===document.activeElement?null:(e.callbacks.beforeNodeMorphed(r,l)===!1||(r instanceof HTMLHeadElement&&e.head.ignore||(r instanceof HTMLHeadElement&&e.head.style!=="morph"?k(r,l,e):(M(r,l,e),g(r,e)||H(e,r,l))),e.callbacks.afterNodeMorphed(r,l)),r)}function M(r,l,e){let n=l.nodeType;if(n===1){let i=r,t=l,o=i.attributes,f=t.attributes;for(let m of f)b(m.name,i,"update",e)||i.getAttribute(m.name)!==m.value&&i.setAttribute(m.name,m.value);for(let m=o.length-1;0<=m;m--){let y=o[m];if(y&&!t.hasAttribute(y.name)){if(b(y.name,i,"remove",e))continue;i.removeAttribute(y.name)}}g(i,e)||p(i,t,e)}(n===8||n===3)&&r.nodeValue!==l.nodeValue&&(r.nodeValue=l.nodeValue)}function p(r,l,e){if(r instanceof HTMLInputElement&&l instanceof HTMLInputElement&&l.type!=="file"){let n=l.value,i=r.value;A(r,l,"checked",e),A(r,l,"disabled",e),l.hasAttribute("value")?i!==n&&(b("value",r,"update",e)||(r.setAttribute("value",n),r.value=n)):b("value",r,"remove",e)||(r.value="",r.removeAttribute("value"))}else if(r instanceof HTMLOptionElement&&l instanceof HTMLOptionElement)A(r,l,"selected",e);else if(r instanceof HTMLTextAreaElement&&l instanceof HTMLTextAreaElement){let n=l.value,i=r.value;if(b("value",r,"update",e))return;n!==i&&(r.value=n),r.firstChild&&r.firstChild.nodeValue!==n&&(r.firstChild.nodeValue=n)}}function A(r,l,e,n){let i=l[e],t=r[e];if(i!==t){let o=b(e,r,"update",n);o||(r[e]=l[e]),i?o||r.setAttribute(e,""):b(e,r,"remove",n)||r.removeAttribute(e)}}function b(r,l,e,n){return r==="value"&&n.ignoreActiveValue&&l===document.activeElement?!0:n.callbacks.beforeAttributeUpdated(r,l,e)===!1}function g(r,l){return!!l.ignoreActiveValue&&r===document.activeElement&&r!==document.body}return u})();function O(u,M,p,A){if(u.head.block){let b=M.querySelector("head"),g=p.querySelector("head");if(b&&g){let r=k(b,g,u);return Promise.all(r).then(()=>{let l=Object.assign(u,{head:{block:!1,ignore:!0}});return A(l)})}}return A(u)}function k(u,M,p){let A=[],b=[],g=[],r=[],l=p.scripts.matchMode,e=t=>{if(t.tagName==="SCRIPT")return a(t,l);if(t.tagName==="LINK"&&l==="smart"){let o=t.getAttribute("href");if(o)try{let f=new URL(o,window.location.href);return`link:${t.getAttribute("rel")||""}:${f.origin}${f.pathname}${f.search}`}catch{}}return t.outerHTML},n=new Map;for(let t of M.children)c(t)||n.set(e(t),t);for(let t of u.children){let o=e(t),f=n.has(o),m=p.head.shouldReAppend(t),y=p.head.shouldPreserve(t);f||y?m?b.push(t):(n.delete(o),g.push(t)):p.head.style==="append"?m&&(b.push(t),r.push(t)):p.head.shouldRemove(t)!==!1&&!c(t)&&b.push(t)}r.push(...n.values());let i=[];for(let t of r){let o=document.createRange().createContextualFragment(t.outerHTML).firstChild;if(p.callbacks.beforeNodeAdded(o)!==!1){if("href"in o&&o.href||"src"in o&&o.src){let f,m=new Promise(function(y){f=y});o.addEventListener("load",function(){f()}),i.push(m)}u.appendChild(o),p.callbacks.afterNodeAdded(o),A.push(o)}}for(let t of b)p.callbacks.beforeNodeRemoved(t)!==!1&&(u.removeChild(t),p.callbacks.afterNodeRemoved(t));return p.head.afterHeadMorphed(u,{added:A,kept:g,removed:b}),i}function v(u,M,p){if(!p.scripts.handle)return[];let A=[],b=[],g=[],r=[],l=p.scripts.matchMode,e=Array.from(u.querySelectorAll("script"));for(let i of e){let t=a(i,l),o=M.has(t),f=p.scripts.shouldPreserve(i),m=p.scripts.shouldReAppend(i);o||f?m?(b.push(i),r.push(i)):g.push(i):r.push(i)}for(let i of M){let t=e.some(o=>o.outerHTML===i)}let n=[];for(let i of r){if(p.callbacks.beforeNodeAdded(i)===!1)continue;let t=document.createRange().createContextualFragment(i.outerHTML).firstChild;if(t.src){let o,f=new Promise(function(m){o=m});t.addEventListener("load",function(){o()}),t.addEventListener("error",function(){o()}),n.push(f)}i.replaceWith(t),p.callbacks.afterNodeAdded(t),A.push(t)}return p.scripts.afterScriptsHandled(u,{added:A,kept:g,removed:b}),n}let I=(function(){function u(e,n,i){let{persistentIds:t,idMap:o}=r(e,n),f=h.computeMatches(e,n);if(typeof i.key=="function"){let $=new Map,D=new Set,x=R=>{let B=i.key(R);B!=null&&($.has(B)?D.add(B):$.set(B,R))};e instanceof Element&&x(e);for(let R of e.querySelectorAll("*"))x(R);for(let R of D)$.delete(R);let V=new Map;for(let[R,B]of f)V.set(B,R);let P=n.__hyperMorphRoot||n,F=new Map,G=new Set,Y=R=>{let B=i.key(R);B!=null&&(F.has(B)?G.add(B):F.set(B,R))};P instanceof Element&&Y(P);for(let R of P.querySelectorAll("*"))Y(R);for(let R of G)F.delete(R);for(let[R,B]of F){let j=$.get(R);if(!j||j.tagName!==B.tagName)continue;let K=V.get(j);K&&K!==B&&f.delete(K);let _=f.get(B);_&&_!==j&&V.delete(_),f.set(B,j),V.set(j,B)}}let m=new Set;for(let $ of f.values())m.add($);let y=M(i),N=y.morphStyle||"outerHTML";if(!["innerHTML","outerHTML"].includes(N))throw`Do not understand how to morph style ${N}`;return{target:e,newContent:n,config:y,morphStyle:N,ignoreActive:y.ignoreActive,ignoreActiveValue:y.ignoreActiveValue,restoreFocus:y.restoreFocus,idMap:o,persistentIds:t,hyperMatches:f,hyperMatchedOldElements:m,pantry:p(),activeElementAndParents:A(e),callbacks:y.callbacks,head:y.head,scripts:y.scripts}}function M(e){let n=Object.assign({},d);return Object.assign(n,e),n.callbacks=Object.assign({},d.callbacks,e.callbacks),n.head=Object.assign({},d.head,e.head),n.scripts=Object.assign({},d.scripts,e.scripts),n}function p(){let e=document.createElement("div");return e.hidden=!0,document.body.insertAdjacentElement("afterend",e),e}function A(e){let n=[],i=document.activeElement;if(i?.tagName!=="BODY"&&e.contains(i))for(;i&&(n.push(i),i!==e);)i=i.parentElement;return n}function b(e){let n=Array.from(e.querySelectorAll("[id]"));return e.getAttribute?.("id")&&n.push(e),n}function g(e,n,i,t){for(let o of t){let f=o.getAttribute("id");if(n.has(f)){let m=o;for(;m;){let y=e.get(m);if(y==null&&(y=new Set,e.set(m,y)),y.add(f),m===i)break;m=m.parentElement}}}}function r(e,n){let i=b(e),t=b(n),o=l(i,t),f=new Map;g(f,o,e,i);let m=n.__hyperMorphRoot||n;return g(f,o,m,t),{persistentIds:o,idMap:f}}function l(e,n){let i=new Set,t=new Map;for(let{id:f,tagName:m}of e)t.has(f)?i.add(f):t.set(f,m);let o=new Set;for(let{id:f,tagName:m}of n)o.has(f)?i.add(f):t.get(f)===m&&o.add(f);for(let f of i)o.delete(f);return o}return u})(),{normalizeElement:L,normalizeParent:C}=(function(){let u=new WeakSet;function M(g){return g instanceof Document?g.documentElement:g}function p(g){if(g==null)return document.createElement("div");if(typeof g=="string")return p(b(g));if(u.has(g))return g;if(g instanceof Node){if(g.parentNode)return new A(g);{let r=document.createElement("div");return r.append(g),r}}else{let r=document.createElement("div");for(let l of[...g])r.append(l);return r}}class A{constructor(r){this.originalNode=r,this.realParentNode=r.parentNode,this.previousSibling=r.previousSibling,this.nextSibling=r.nextSibling}get childNodes(){let r=[],l=this.previousSibling?this.previousSibling.nextSibling:this.realParentNode.firstChild;for(;l&&l!=this.nextSibling;)r.push(l),l=l.nextSibling;return r}querySelectorAll(r){return this.childNodes.reduce((l,e)=>{if(e instanceof Element){e.matches(r)&&l.push(e);let n=e.querySelectorAll(r);for(let i=0;i<n.length;i++)l.push(n[i])}return l},[])}insertBefore(r,l){return this.realParentNode.insertBefore(r,l)}moveBefore(r,l){return this.realParentNode.moveBefore(r,l)}get __hyperMorphRoot(){return this.originalNode}}function b(g){let r=new DOMParser,l=g.replace(/<svg(\s[^>]*>|>)([\s\S]*?)<\/svg>/gim,"");if(l.match(/<\/html>/)||l.match(/<\/head>/)||l.match(/<\/body>/)){let e=r.parseFromString(g,"text/html");if(l.match(/<\/html>/))return u.add(e),e;{let n=e.firstChild;return n&&u.add(n),n}}else{let n=r.parseFromString("<body><template>"+g+"</template></body>","text/html").body.querySelector("template").content;return u.add(n),n}}return{normalizeElement:M,normalizeParent:p}})();return{morph:w,defaults:d}})();var ye=W.morph,Se=W.defaults,ke=W;return oe(we);})();
|
|
2
2
|
|
|
3
3
|
// Convenience morph wrapper with data-id support
|
|
4
4
|
var morph = function(oldEl, newEl, options = {}) {
|
|
5
5
|
return HyperMorph.morph(oldEl, newEl, {
|
|
6
|
-
key: (el) => el.getAttribute('data-id') || el.id,
|
|
6
|
+
key: (el) => (el.getAttribute && el.getAttribute('data-id')) || el.id || null,
|
|
7
7
|
...options
|
|
8
8
|
});
|
|
9
9
|
};
|