hyperclayjs 1.26.2 → 1.27.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 -5
- package/package.json +1 -1
- package/src/communication/live-sync.js +105 -22
- package/src/hyperclay.js +1 -1
- package/src/string-utilities/slugify.js +9 -2
- package/src/ui/prompts.js +22 -26
- package/src/ui/theModal.js +3 -0
- package/src/vendor/hyper-morph.vendor.js +1 -1
package/README.md
CHANGED
|
@@ -86,8 +86,8 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
86
86
|
|
|
87
87
|
| Module | Size | Description |
|
|
88
88
|
|--------|------|-------------|
|
|
89
|
-
| dialogs | 8.
|
|
90
|
-
| the-modal | 22.
|
|
89
|
+
| dialogs | 8.2KB | ask(), consent(), tell(), snippet() dialog functions |
|
|
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
|
|
|
93
93
|
### Utilities (Core utilities (often auto-included))
|
|
@@ -116,14 +116,14 @@ import 'hyperclayjs/presets/standard.js';
|
|
|
116
116
|
|--------|------|-------------|
|
|
117
117
|
| copy-to-clipboard | 0.9KB | Clipboard utility |
|
|
118
118
|
| query-params | 0.3KB | Parse URL search params |
|
|
119
|
-
| slugify |
|
|
119
|
+
| slugify | 1KB | URL-friendly slug generator |
|
|
120
120
|
|
|
121
121
|
### Communication & Files (File handling and messaging)
|
|
122
122
|
|
|
123
123
|
| Module | Size | Description |
|
|
124
124
|
|--------|------|-------------|
|
|
125
125
|
| file-upload | 11.3KB | File upload with progress |
|
|
126
|
-
| live-sync |
|
|
126
|
+
| live-sync | 15.5KB | Real-time DOM sync across browsers |
|
|
127
127
|
| send-message | 1.3KB | Message sending utility |
|
|
128
128
|
|
|
129
129
|
### Vendor Libraries (Third-party libraries)
|
|
@@ -144,7 +144,7 @@ Standard feature set for most use cases
|
|
|
144
144
|
|
|
145
145
|
**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
146
|
|
|
147
|
-
### Everything (~
|
|
147
|
+
### Everything (~235.8KB)
|
|
148
148
|
All available features
|
|
149
149
|
|
|
150
150
|
Includes all available modules across all categories.
|
package/package.json
CHANGED
|
@@ -47,6 +47,20 @@ class LiveSync {
|
|
|
47
47
|
// Store handler reference for cleanup
|
|
48
48
|
this._snapshotHandler = null;
|
|
49
49
|
|
|
50
|
+
// High-water mark of server seqs we've seen on this channel (own echoes
|
|
51
|
+
// count too). Server-broadcast payloads carry a monotonic seq
|
|
52
|
+
// (Date.now()-based). We drop anything <= this to guard against rare
|
|
53
|
+
// cases where a stale message lands after a newer one — e.g. buffered
|
|
54
|
+
// replay, alt backend after reconnect, or an own-save echo arriving
|
|
55
|
+
// after a peer's newer broadcast.
|
|
56
|
+
this.lastSeenSeq = 0;
|
|
57
|
+
|
|
58
|
+
// Promise chain used to serialize overlapping applyUpdate() calls.
|
|
59
|
+
// A morph with external scripts returns a Promise; without chaining, two
|
|
60
|
+
// SSE events arriving back-to-back would interleave their morphs on the
|
|
61
|
+
// same DOM.
|
|
62
|
+
this._applyChain = Promise.resolve();
|
|
63
|
+
|
|
50
64
|
// Callbacks
|
|
51
65
|
this.onConnect = null;
|
|
52
66
|
this.onDisconnect = null;
|
|
@@ -112,6 +126,8 @@ class LiveSync {
|
|
|
112
126
|
|
|
113
127
|
// Reset state for new connection
|
|
114
128
|
this.lastHtml = null;
|
|
129
|
+
this.lastSeenSeq = 0;
|
|
130
|
+
this._applyChain = Promise.resolve();
|
|
115
131
|
|
|
116
132
|
console.log('[LiveSync] Starting for:', this.currentFile);
|
|
117
133
|
this.connect();
|
|
@@ -194,9 +210,24 @@ class LiveSync {
|
|
|
194
210
|
return;
|
|
195
211
|
}
|
|
196
212
|
|
|
197
|
-
const { html, sender } = data;
|
|
213
|
+
const { html, sender, seq } = data;
|
|
198
214
|
|
|
199
|
-
//
|
|
215
|
+
// Staleness check runs FIRST — compared against the high-water mark of
|
|
216
|
+
// seqs we've seen (own echoes count too, see below). `seq` is optional
|
|
217
|
+
// for back-compat with older server builds that don't stamp it.
|
|
218
|
+
if (typeof seq === 'number' && seq <= this.lastSeenSeq) {
|
|
219
|
+
this._log(`Dropping stale message: seq=${seq}, lastSeen=${this.lastSeenSeq}`);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Advance the watermark before the sender filter so that our own save
|
|
224
|
+
// echoes count toward "seen". Without this, a later buffered/replayed
|
|
225
|
+
// peer message with a smaller seq could rewind us past our local edit.
|
|
226
|
+
if (typeof seq === 'number') {
|
|
227
|
+
this.lastSeenSeq = seq;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Ignore own changes — already reflected in the DOM, nothing to morph
|
|
200
231
|
if (sender === this.clientId) {
|
|
201
232
|
this._log('Ignoring own message (sender matches clientId)');
|
|
202
233
|
return;
|
|
@@ -208,9 +239,9 @@ class LiveSync {
|
|
|
208
239
|
return;
|
|
209
240
|
}
|
|
210
241
|
|
|
211
|
-
this._log(`Received update from: ${sender} (my clientId: ${this.clientId})`);
|
|
212
|
-
this.applyUpdate(html);
|
|
213
|
-
if (this.onUpdate) this.onUpdate({ html, sender });
|
|
242
|
+
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 });
|
|
214
245
|
};
|
|
215
246
|
|
|
216
247
|
// Native EventSource auto-reconnects on transient errors
|
|
@@ -285,13 +316,48 @@ class LiveSync {
|
|
|
285
316
|
}
|
|
286
317
|
|
|
287
318
|
/**
|
|
288
|
-
* Apply an update received from the server
|
|
289
|
-
* Morphs the entire document (head and body)
|
|
319
|
+
* Apply an update received from the server.
|
|
320
|
+
* Morphs the entire document (head and body).
|
|
321
|
+
*
|
|
322
|
+
* Serialized via a promise chain so concurrent SSE events don't produce
|
|
323
|
+
* overlapping morphs (morph can return a Promise when external scripts load).
|
|
324
|
+
*
|
|
325
|
+
* @param {string} html - Full document HTML
|
|
326
|
+
* @param {number} [seq] - Optional monotonic seq from the server
|
|
327
|
+
* @returns {Promise<void>}
|
|
328
|
+
*/
|
|
329
|
+
applyUpdate(html, seq) {
|
|
330
|
+
// Serialize concurrent updates onto a single promise chain. `.catch` on
|
|
331
|
+
// the combined result both logs the failure (so it isn't a silent
|
|
332
|
+
// unhandled rejection) AND heals the chain so subsequent updates aren't
|
|
333
|
+
// blocked by it. `_applyChain` and the returned promise are the same
|
|
334
|
+
// caught promise — callers that fire-and-forget are safe.
|
|
335
|
+
const result = this._applyChain
|
|
336
|
+
.then(() => this._doApplyUpdate(html, seq))
|
|
337
|
+
.catch((err) => {
|
|
338
|
+
console.error('[LiveSync] applyUpdate failed:', err);
|
|
339
|
+
});
|
|
340
|
+
this._applyChain = result;
|
|
341
|
+
return result;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Actual morph work. Do not call directly — use applyUpdate() so calls
|
|
346
|
+
* serialize.
|
|
347
|
+
* @param {string} html
|
|
348
|
+
* @param {number} [seq]
|
|
349
|
+
* @returns {Promise<void>}
|
|
290
350
|
*/
|
|
291
|
-
|
|
351
|
+
async _doApplyUpdate(html, seq) {
|
|
292
352
|
this._log('applyUpdate - pausing mutations and morphing');
|
|
293
353
|
this.isPaused = true;
|
|
294
|
-
|
|
354
|
+
|
|
355
|
+
// Preserve scroll position: a remote edit that inserts or removes content
|
|
356
|
+
// above the viewport would otherwise cause a visible jump. Capturing here
|
|
357
|
+
// and restoring after the morph keeps the viewport stable. Browser
|
|
358
|
+
// scroll-clamping handles the case where the document is now shorter.
|
|
359
|
+
const scrollX = window.scrollX;
|
|
360
|
+
const scrollY = window.scrollY;
|
|
295
361
|
|
|
296
362
|
// Pause mutation observer so morph doesn't trigger autosave
|
|
297
363
|
Mutation.pause();
|
|
@@ -300,19 +366,36 @@ class LiveSync {
|
|
|
300
366
|
const parser = new DOMParser();
|
|
301
367
|
const newDoc = parser.parseFromString(html, 'text/html');
|
|
302
368
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
369
|
+
try {
|
|
370
|
+
// Morph entire document. We MUST await — HyperMorph.morph returns a
|
|
371
|
+
// Promise when `scripts: { handle: true }` needs to wait for external
|
|
372
|
+
// scripts to load. If we don't await, Mutation.resume() fires before
|
|
373
|
+
// late-loading scripts execute, and any DOM mutations they trigger look
|
|
374
|
+
// like user edits → the receiving tab rebroadcasts them (feedback loop).
|
|
375
|
+
await HyperMorph.morph(document.documentElement, newDoc.documentElement, {
|
|
376
|
+
morphStyle: 'outerHTML',
|
|
377
|
+
ignoreActiveValue: true,
|
|
378
|
+
head: { style: 'merge' },
|
|
379
|
+
scripts: { handle: true, matchMode: 'smart' }
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
// Restore viewport. Done after morph so layout has settled.
|
|
383
|
+
window.scrollTo(scrollX, scrollY);
|
|
384
|
+
|
|
385
|
+
// Only mark lastHtml after a successful morph so that a failed apply
|
|
386
|
+
// doesn't desync our state and cause the next outbound save to be
|
|
387
|
+
// mistakenly skipped as "unchanged". Note: lastSeenSeq is advanced at
|
|
388
|
+
// receive time (in onmessage) so the staleness check covers own-save
|
|
389
|
+
// echoes even when they don't reach this point.
|
|
390
|
+
this.lastHtml = html;
|
|
391
|
+
} finally {
|
|
392
|
+
this._log('applyUpdate - morph complete, resuming mutations');
|
|
393
|
+
Mutation.resume();
|
|
394
|
+
// Defer past microtask boundary — MutationObserver callbacks fire before
|
|
395
|
+
// this, so isPaused catches any stray snapshots from the morph itself.
|
|
396
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
397
|
+
this.isPaused = false;
|
|
398
|
+
}
|
|
316
399
|
}
|
|
317
400
|
|
|
318
401
|
/**
|
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.27.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.
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
// e.g. "Hello there" → "hello-there"
|
|
2
|
+
// Preserves .html/.htmlclay extensions
|
|
2
3
|
function slugify (text) {
|
|
3
|
-
|
|
4
|
+
if (text == null) return '';
|
|
5
|
+
const extMatch = text.toString().match(/\.(html|htmlclay)$/i);
|
|
6
|
+
const ext = extMatch ? extMatch[0].toLowerCase() : '';
|
|
7
|
+
const base = extMatch ? text.toString().slice(0, -ext.length) : text.toString();
|
|
8
|
+
|
|
9
|
+
return base.toLowerCase()
|
|
4
10
|
.normalize('NFD') // separate accents from letters
|
|
5
11
|
.replace(/[\u0300-\u036f]/g, '') // remove accents
|
|
6
12
|
.replace(/\s+/g, '-') // replace spaces with -
|
|
7
13
|
.replace(/[^\w\-]+/g, '') // remove all non-word chars
|
|
8
14
|
.replace(/\-\-+/g, '-') // replace multiple - with single -
|
|
9
15
|
.replace(/^-+/, '') // trim - from start of text
|
|
10
|
-
.replace(/-+$/, '')
|
|
16
|
+
.replace(/-+$/, '') // trim - from end of text
|
|
17
|
+
+ ext;
|
|
11
18
|
}
|
|
12
19
|
|
|
13
20
|
// Auto-export to window unless suppressed by loader
|
package/src/ui/prompts.js
CHANGED
|
@@ -21,30 +21,26 @@ function createModal(promptText, yesCallback, extraContent = "", includeInput =
|
|
|
21
21
|
|
|
22
22
|
const promise = new Promise((resolve, reject) => {
|
|
23
23
|
themodal.onYes(() => {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (yesCallback) yesCallback(promptResult);
|
|
29
|
-
resolve(promptResult);
|
|
30
|
-
return true; // Allow modal to close
|
|
31
|
-
}
|
|
32
|
-
} else {
|
|
33
|
-
if (yesCallback) yesCallback();
|
|
34
|
-
resolve();
|
|
35
|
-
return true; // Allow modal to close
|
|
36
|
-
}
|
|
37
|
-
} catch (error) {
|
|
38
|
-
// Show error message as toast
|
|
39
|
-
toast(error.message || 'An error occurred', 'error');
|
|
40
|
-
// Keep modal open - don't reject or resolve
|
|
41
|
-
// User can try again
|
|
42
|
-
return false; // Prevent modal from closing
|
|
24
|
+
let promptResult;
|
|
25
|
+
if (includeInput) {
|
|
26
|
+
promptResult = document.querySelector(".micromodal__input").value;
|
|
27
|
+
if (!promptResult) return false; // keep modal open on empty input
|
|
43
28
|
}
|
|
29
|
+
// Defer so the modal's close sequence completes before callbacks fire —
|
|
30
|
+
// chained ask()/consent() calls then land in a clean themodal instead of
|
|
31
|
+
// piggybacking on this modal's onYes loop (themodal is a singleton).
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
if (yesCallback) {
|
|
34
|
+
try { yesCallback(promptResult); }
|
|
35
|
+
catch (err) { toast(err.message || 'An error occurred', 'error'); }
|
|
36
|
+
}
|
|
37
|
+
resolve(promptResult);
|
|
38
|
+
}, 0);
|
|
39
|
+
return true; // Allow modal to close
|
|
44
40
|
});
|
|
45
41
|
|
|
46
42
|
themodal.onNo = () => {
|
|
47
|
-
reject
|
|
43
|
+
setTimeout(reject, 0);
|
|
48
44
|
};
|
|
49
45
|
});
|
|
50
46
|
|
|
@@ -95,12 +91,12 @@ export function tell(promptText, ...content) {
|
|
|
95
91
|
|
|
96
92
|
const promise = new Promise((resolve, reject) => {
|
|
97
93
|
themodal.onYes(() => {
|
|
98
|
-
resolve
|
|
94
|
+
setTimeout(resolve, 0);
|
|
99
95
|
return true;
|
|
100
96
|
});
|
|
101
97
|
|
|
102
98
|
themodal.onNo = () => {
|
|
103
|
-
reject
|
|
99
|
+
setTimeout(reject, 0);
|
|
104
100
|
};
|
|
105
101
|
});
|
|
106
102
|
|
|
@@ -159,22 +155,22 @@ export function snippet(title, content, extraContent = '') {
|
|
|
159
155
|
}, 0);
|
|
160
156
|
|
|
161
157
|
themodal.onYes(() => {
|
|
162
|
-
// Clean up the event listener
|
|
158
|
+
// Clean up the event listener synchronously — the DOM may be torn down
|
|
159
|
+
// before our deferred resolve fires otherwise.
|
|
163
160
|
const modalContainer = document.querySelector('.micromodal-parent');
|
|
164
161
|
if (modalContainer) {
|
|
165
162
|
modalContainer.removeEventListener('click', handleCopy);
|
|
166
163
|
}
|
|
167
|
-
resolve
|
|
164
|
+
setTimeout(resolve, 0);
|
|
168
165
|
return true;
|
|
169
166
|
});
|
|
170
167
|
|
|
171
168
|
themodal.onNo = () => {
|
|
172
|
-
// Clean up the event listener
|
|
173
169
|
const modalContainer = document.querySelector('.micromodal-parent');
|
|
174
170
|
if (modalContainer) {
|
|
175
171
|
modalContainer.removeEventListener('click', handleCopy);
|
|
176
172
|
}
|
|
177
|
-
resolve
|
|
173
|
+
setTimeout(resolve, 0);
|
|
178
174
|
};
|
|
179
175
|
});
|
|
180
176
|
|
package/src/ui/theModal.js
CHANGED
|
@@ -369,6 +369,7 @@ const modalCss = `<style class="micromodal-css">
|
|
|
369
369
|
.micromodal__container {
|
|
370
370
|
position: relative;
|
|
371
371
|
width: 100%;
|
|
372
|
+
min-width: 0;
|
|
372
373
|
max-width: min(550px, calc(100vw - 2rem));
|
|
373
374
|
max-height: calc(100vh - 4rem);
|
|
374
375
|
max-height: calc(100dvh - 2rem);
|
|
@@ -419,6 +420,7 @@ const modalCss = `<style class="micromodal-css">
|
|
|
419
420
|
|
|
420
421
|
.micromodal .micromodal__content {
|
|
421
422
|
margin-bottom: 14px;
|
|
423
|
+
overflow-wrap: anywhere;
|
|
422
424
|
}
|
|
423
425
|
|
|
424
426
|
.micromodal .micromodal__heading {
|
|
@@ -426,6 +428,7 @@ const modalCss = `<style class="micromodal-css">
|
|
|
426
428
|
flex-direction: column;
|
|
427
429
|
gap: 2px;
|
|
428
430
|
margin-bottom: 8px;
|
|
431
|
+
overflow-wrap: anywhere;
|
|
429
432
|
}
|
|
430
433
|
|
|
431
434
|
.micromodal .micromodal__input {
|
|
@@ -1,4 +1,4 @@
|
|
|
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}`}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}`}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 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);})();
|
|
2
2
|
|
|
3
3
|
// Convenience morph wrapper with data-id support
|
|
4
4
|
var morph = function(oldEl, newEl, options = {}) {
|