website-highlighter 1.2.0 → 1.4.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 +22 -4
- package/dist/website-highlighter.js +205 -103
- package/dist/website-highlighter.umd.cjs +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,7 @@ Import the default function and pass the text you want to find. The library find
|
|
|
16
16
|
import WebsiteHighlighter from 'website-highlighter'
|
|
17
17
|
|
|
18
18
|
const article = document.querySelector('article')
|
|
19
|
-
const { range, value } = WebsiteHighlighter('custom highlight api', {
|
|
19
|
+
const { range, value } = await WebsiteHighlighter('custom highlight api', {
|
|
20
20
|
root: article
|
|
21
21
|
})
|
|
22
22
|
|
|
@@ -36,7 +36,19 @@ Add styles for the highlight name:
|
|
|
36
36
|
If no root is passed, the library searches `document.body`.
|
|
37
37
|
|
|
38
38
|
```js
|
|
39
|
-
WebsiteHighlighter('some text on the page')
|
|
39
|
+
await WebsiteHighlighter('some text on the page')
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## CDN Usage
|
|
43
|
+
|
|
44
|
+
The browser bundle can be loaded from a CDN as a single file. Fuzzy matching uses an inline Blob worker when the browser allows it, so you do not need to host a separate worker script.
|
|
45
|
+
|
|
46
|
+
```html
|
|
47
|
+
<script type="module">
|
|
48
|
+
import WebsiteHighlighter from 'https://cdn.example.com/website-highlighter.js'
|
|
49
|
+
|
|
50
|
+
await WebsiteHighlighter('some text on the page')
|
|
51
|
+
</script>
|
|
40
52
|
```
|
|
41
53
|
|
|
42
54
|
## Iframe Usage
|
|
@@ -71,14 +83,20 @@ highlightInIframe(iframe, 'text inside the iframe', 'https://example.com')
|
|
|
71
83
|
|
|
72
84
|
### `WebsiteHighlighter(text, options)`
|
|
73
85
|
|
|
74
|
-
Finds the best fuzzy match for `text`, applies the `website-highlighter` custom highlight,
|
|
86
|
+
Finds the best fuzzy match for `text`, applies the `website-highlighter` custom highlight, scrolls the matched range into view, and resolves to `{ range, value }`.
|
|
75
87
|
|
|
76
88
|
- `text`: string to search for.
|
|
77
89
|
- `options.root`: optional DOM node to search. Defaults to `document.body`.
|
|
78
|
-
- `options.threshold`: optional minimum match score from `0` to `1`. When greater than `0`, the function
|
|
90
|
+
- `options.threshold`: optional minimum match score from `0` to `1`. When greater than `0`, the function retries until the threshold is met or retries are exhausted.
|
|
79
91
|
- `options.retries`: optional retry count. Defaults to `6`.
|
|
80
92
|
- `options.retryInterval`: optional retry delay in milliseconds. Defaults to `500`.
|
|
81
93
|
|
|
94
|
+
Fuzzy matching runs in a worker when the browser allows it. If worker creation is unavailable or blocked, the library falls back to synchronous matching on the main thread.
|
|
95
|
+
|
|
96
|
+
### `getMatcherMode()`
|
|
97
|
+
|
|
98
|
+
Returns `'worker'` or `'sync'` for the most recent match. This is intended for diagnostics and demos.
|
|
99
|
+
|
|
82
100
|
### `highlightInIframe(iframe, text, targetOrigin)`
|
|
83
101
|
|
|
84
102
|
Posts a highlight request to an iframe.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
class
|
|
1
|
+
class I {
|
|
2
2
|
/**
|
|
3
3
|
* Calculates the Levenshtein distance for all substrings and returns their
|
|
4
4
|
* distance and insertion-deletion offset.
|
|
@@ -9,16 +9,16 @@ class M {
|
|
|
9
9
|
* @return {array} Array of all substring matches in pairs [distance, offset]
|
|
10
10
|
*/
|
|
11
11
|
getEditDistances(e, t) {
|
|
12
|
-
var
|
|
13
|
-
for (let
|
|
14
|
-
let
|
|
15
|
-
for (let
|
|
16
|
-
let
|
|
17
|
-
l ===
|
|
12
|
+
var r = new Array(t.length + 1).fill([0, 0]);
|
|
13
|
+
for (let s = 0; s < e.length; s++) {
|
|
14
|
+
let o = [[s + 1, 0]];
|
|
15
|
+
for (let i = 0; i < t.length; i++) {
|
|
16
|
+
let a = e[s] != t[i], l = r[i + 1][0] + 1, c = o[i][0] + 1, g = r[i][0] + a, f = Math.min(l, Math.min(c, g)), d = [f, r[i][1]];
|
|
17
|
+
l === f ? d[1] = r[i + 1][1] - 1 : c === f && (d[1] = o[i][1] + 1), o.push(d);
|
|
18
18
|
}
|
|
19
|
-
|
|
19
|
+
r = o;
|
|
20
20
|
}
|
|
21
|
-
return
|
|
21
|
+
return r;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* Search haystack for all instances of needle and returns an array of
|
|
@@ -30,149 +30,251 @@ class M {
|
|
|
30
30
|
* @return {array} Array of best substring matches.
|
|
31
31
|
*/
|
|
32
32
|
getMatches(e, t) {
|
|
33
|
-
let
|
|
34
|
-
for (let
|
|
35
|
-
let l =
|
|
36
|
-
l <
|
|
33
|
+
let r = this.getEditDistances(e, t), s = [0], o = r[0][0];
|
|
34
|
+
for (let a = 1; a < r.length; a++) {
|
|
35
|
+
let l = r[a][0];
|
|
36
|
+
l < o ? (s = [a], o = l) : l == o && s.push(a);
|
|
37
37
|
}
|
|
38
|
-
let
|
|
39
|
-
for (let
|
|
40
|
-
let l =
|
|
38
|
+
let i = [];
|
|
39
|
+
for (let a of s) {
|
|
40
|
+
let l = r[a], c = {
|
|
41
41
|
distance: l[0],
|
|
42
|
-
start:
|
|
42
|
+
start: a - e.length - l[1],
|
|
43
43
|
//simplification of startPos = endPos − (needleLength + insertions − deletions)
|
|
44
|
-
end:
|
|
44
|
+
end: a
|
|
45
45
|
};
|
|
46
|
-
|
|
46
|
+
i.push(c);
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return i;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
function
|
|
52
|
-
return new
|
|
51
|
+
function v(n, e) {
|
|
52
|
+
return new I().getMatches(n, e);
|
|
53
53
|
}
|
|
54
|
-
function
|
|
55
|
-
const t =
|
|
56
|
-
let
|
|
57
|
-
for (const
|
|
58
|
-
(
|
|
59
|
-
const
|
|
60
|
-
return { value: e.slice(
|
|
54
|
+
function x(n, e) {
|
|
55
|
+
const t = v(n, e);
|
|
56
|
+
let r;
|
|
57
|
+
for (const a of t)
|
|
58
|
+
(r === void 0 || a.distance < r.distance) && (r = a);
|
|
59
|
+
const s = Math.max(r.start, 0), o = Math.min(Math.max(r.end, s), e.length);
|
|
60
|
+
return { value: e.slice(s, o), start: s, end: o, distance: r.distance };
|
|
61
61
|
}
|
|
62
|
-
function
|
|
63
|
-
|
|
64
|
-
|
|
62
|
+
const y = `(function(){"use strict";class h{getEditDistances(s,i){var t=new Array(i.length+1).fill([0,0]);for(let e=0;e<s.length;e++){let r=[[e+1,0]];for(let l=0;l<i.length;l++){let n=s[e]!=i[l],a=t[l+1][0]+1,o=r[l][0]+1,m=t[l][0]+n,u=Math.min(a,Math.min(o,m)),f=[u,t[l][1]];a===u?f[1]=t[l+1][1]-1:o===u&&(f[1]=r[l][1]+1),r.push(f)}t=r}return t}getMatches(s,i){let t=this.getEditDistances(s,i),e=[0],r=t[0][0];for(let n=1;n<t.length;n++){let a=t[n][0];a<r?(e=[n],r=a):a==r&&e.push(n)}let l=[];for(let n of e){let a=t[n],o={distance:a[0],start:n-s.length-a[1],end:n};l.push(o)}return l}}function g(c,s){return new h().getMatches(c,s)}function d(c,s){const i=g(c,s);let t;for(const n of i)(t===void 0||n.distance<t.distance)&&(t=n);const e=Math.max(t.start,0),r=Math.min(Math.max(t.end,e),s.length);return{value:s.slice(e,r),start:e,end:r,distance:t.distance}}self.addEventListener("message",c=>{const{id:s,query:i,source:t}=c.data;try{self.postMessage({id:s,result:d(i,t)})}catch(e){self.postMessage({id:s,error:e instanceof Error?e.message:String(e)})}})})();
|
|
63
|
+
`, b = typeof self < "u" && self.Blob && new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);", y], { type: "text/javascript;charset=utf-8" });
|
|
64
|
+
function W(n) {
|
|
65
|
+
let e;
|
|
66
|
+
try {
|
|
67
|
+
if (e = b && (self.URL || self.webkitURL).createObjectURL(b), !e) throw "";
|
|
68
|
+
const t = new Worker(e, {
|
|
69
|
+
name: n?.name
|
|
70
|
+
});
|
|
71
|
+
return t.addEventListener("error", () => {
|
|
72
|
+
(self.URL || self.webkitURL).revokeObjectURL(e);
|
|
73
|
+
}), t;
|
|
74
|
+
} catch {
|
|
75
|
+
return new Worker(
|
|
76
|
+
"data:text/javascript;charset=utf-8," + encodeURIComponent(y),
|
|
77
|
+
{
|
|
78
|
+
name: n?.name
|
|
79
|
+
}
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
let u, H = 0, p = !1, M = "sync";
|
|
84
|
+
const h = /* @__PURE__ */ new Map();
|
|
85
|
+
function S(n) {
|
|
86
|
+
for (const { reject: e } of h.values())
|
|
87
|
+
e(n);
|
|
88
|
+
h.clear();
|
|
89
|
+
}
|
|
90
|
+
function E(n) {
|
|
91
|
+
p = !0, u && (u.terminate(), u = void 0), S(n);
|
|
92
|
+
}
|
|
93
|
+
function C() {
|
|
94
|
+
if (!(p || typeof Worker > "u")) {
|
|
95
|
+
if (u) return u;
|
|
96
|
+
try {
|
|
97
|
+
u = new W();
|
|
98
|
+
} catch {
|
|
99
|
+
p = !0;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
return u.addEventListener("message", (n) => {
|
|
103
|
+
const e = h.get(n.data?.id);
|
|
104
|
+
e && (h.delete(n.data.id), n.data.error ? e.reject(new Error(n.data.error)) : e.resolve(n.data.result));
|
|
105
|
+
}), u.addEventListener("error", (n) => {
|
|
106
|
+
E(n.error ?? new Error(n.message || "Worker matcher failed."));
|
|
107
|
+
}), u.addEventListener("messageerror", () => {
|
|
108
|
+
E(new Error("Worker matcher could not deserialize a message."));
|
|
109
|
+
}), u;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function O(n, e) {
|
|
113
|
+
const t = C();
|
|
114
|
+
if (!t) return;
|
|
115
|
+
const r = H++;
|
|
116
|
+
return new Promise((s, o) => {
|
|
117
|
+
h.set(r, { resolve: s, reject: o });
|
|
118
|
+
try {
|
|
119
|
+
t.postMessage({ id: r, query: n, source: e });
|
|
120
|
+
} catch (i) {
|
|
121
|
+
h.delete(r), o(i);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function D() {
|
|
126
|
+
return M;
|
|
127
|
+
}
|
|
128
|
+
async function N(n, e) {
|
|
129
|
+
const t = O(n, e);
|
|
130
|
+
if (t)
|
|
131
|
+
try {
|
|
132
|
+
const r = await t;
|
|
133
|
+
return M = "worker", r;
|
|
134
|
+
} catch (r) {
|
|
135
|
+
E(r);
|
|
136
|
+
}
|
|
137
|
+
return M = "sync", x(n, e);
|
|
138
|
+
}
|
|
139
|
+
function U(n, e, t) {
|
|
140
|
+
const r = n.textContent ?? "";
|
|
141
|
+
if (!Number.isInteger(e) || !Number.isInteger(t) || e < 0 || e >= t || t > r.length)
|
|
65
142
|
throw new RangeError(
|
|
66
|
-
`Invalid range [${e}, ${t}) for text length ${
|
|
143
|
+
`Invalid range [${e}, ${t}) for text length ${r.length}`
|
|
67
144
|
);
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
145
|
+
const s = n.ownerDocument, o = s.createTreeWalker(
|
|
146
|
+
n,
|
|
147
|
+
s.defaultView.NodeFilter.SHOW_TEXT
|
|
71
148
|
);
|
|
72
|
-
let
|
|
73
|
-
for (let
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
149
|
+
let i = 0, a = null, l = 0, c = null, g = 0;
|
|
150
|
+
for (let d = o.nextNode(); d; d = o.nextNode()) {
|
|
151
|
+
const m = i + d.data.length;
|
|
152
|
+
if (a === null && e >= i && e < m && (a = d, l = e - i), c === null && t > i && t <= m && (c = d, g = t - i), a && c)
|
|
76
153
|
break;
|
|
77
|
-
|
|
154
|
+
i = m;
|
|
78
155
|
}
|
|
79
|
-
if (!
|
|
156
|
+
if (!a || !c)
|
|
80
157
|
throw new Error(
|
|
81
158
|
"Could not map offsets to the DOM. The DOM may have changed."
|
|
82
159
|
);
|
|
83
|
-
const
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
const
|
|
87
|
-
let
|
|
88
|
-
function
|
|
89
|
-
return new Promise((e) => globalThis.setTimeout(e,
|
|
90
|
-
}
|
|
91
|
-
function
|
|
92
|
-
const t =
|
|
93
|
-
return t.MutationObserver ? new Promise((
|
|
94
|
-
let
|
|
95
|
-
const
|
|
96
|
-
t.clearTimeout(
|
|
160
|
+
const f = s.createRange();
|
|
161
|
+
return f.setStart(a, l), f.setEnd(c, g), f;
|
|
162
|
+
}
|
|
163
|
+
const w = "website-highlighter", R = `${w}:response`, k = 500;
|
|
164
|
+
let j = 0;
|
|
165
|
+
function $(n) {
|
|
166
|
+
return new Promise((e) => globalThis.setTimeout(e, n));
|
|
167
|
+
}
|
|
168
|
+
function q(n, e) {
|
|
169
|
+
const t = n.ownerDocument?.defaultView ?? window;
|
|
170
|
+
return t.MutationObserver ? new Promise((r) => {
|
|
171
|
+
let s;
|
|
172
|
+
const o = new t.MutationObserver(() => {
|
|
173
|
+
t.clearTimeout(s), o.disconnect(), r(!0);
|
|
97
174
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}, e),
|
|
175
|
+
s = t.setTimeout(() => {
|
|
176
|
+
o.disconnect(), r(!1);
|
|
177
|
+
}, e), o.observe(n, {
|
|
101
178
|
childList: !0,
|
|
102
179
|
characterData: !0,
|
|
103
180
|
subtree: !0
|
|
104
181
|
});
|
|
105
|
-
}) :
|
|
182
|
+
}) : $(e).then(() => !1);
|
|
106
183
|
}
|
|
107
|
-
function
|
|
108
|
-
const
|
|
109
|
-
return
|
|
184
|
+
function P(n, e, t) {
|
|
185
|
+
const r = Math.max(n.length, e.length);
|
|
186
|
+
return r === 0 ? 1 : (r - t) / r;
|
|
110
187
|
}
|
|
111
|
-
function
|
|
112
|
-
const
|
|
113
|
-
|
|
188
|
+
function _(n) {
|
|
189
|
+
const { startContainer: e } = n;
|
|
190
|
+
return e.nodeType === e.ELEMENT_NODE ? e : e.parentElement;
|
|
191
|
+
}
|
|
192
|
+
function V(n, e) {
|
|
193
|
+
const t = n.getClientRects()[0];
|
|
194
|
+
if (!t) {
|
|
195
|
+
_(n)?.scrollIntoView({
|
|
196
|
+
block: "center",
|
|
197
|
+
inline: "nearest",
|
|
198
|
+
behavior: "smooth"
|
|
199
|
+
});
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
const r = e.innerHeight || e.document.documentElement.clientHeight, s = t.top + e.scrollY - r / 2 + t.height / 2;
|
|
203
|
+
e.scrollTo({
|
|
204
|
+
top: Math.max(0, s),
|
|
205
|
+
behavior: "smooth"
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
async function L(n, e) {
|
|
209
|
+
const t = e.textContent ?? "", r = e.ownerDocument?.defaultView ?? window;
|
|
210
|
+
if (!r.CSS?.highlights || !r.Highlight) throw new Error("This browser does not support the CSS Custom Highlight API.");
|
|
211
|
+
const { start: s, end: o, value: i, distance: a } = await N(n, t);
|
|
114
212
|
return {
|
|
115
213
|
haystack: t,
|
|
116
|
-
range:
|
|
117
|
-
value:
|
|
118
|
-
view:
|
|
119
|
-
score:
|
|
214
|
+
range: s < o ? U(e, s, o) : null,
|
|
215
|
+
value: i,
|
|
216
|
+
view: r,
|
|
217
|
+
score: P(n, i, a)
|
|
120
218
|
};
|
|
121
219
|
}
|
|
122
|
-
function
|
|
123
|
-
if (!
|
|
124
|
-
return t.CSS.highlights.set(
|
|
220
|
+
function T({ range: n, value: e, view: t }) {
|
|
221
|
+
if (!n) throw new Error("Could not find text to highlight.");
|
|
222
|
+
return t.CSS.highlights.set(w, new t.Highlight(n)), V(n, t), { range: n, value: e };
|
|
125
223
|
}
|
|
126
|
-
async function
|
|
127
|
-
let
|
|
224
|
+
async function z(n, e, t, r, s) {
|
|
225
|
+
let o = 0;
|
|
128
226
|
for (; ; ) {
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
for (;
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
227
|
+
const i = await L(n, e);
|
|
228
|
+
if (i.score >= t) return T(i);
|
|
229
|
+
for (; o < r; ) {
|
|
230
|
+
const a = await q(e, s);
|
|
231
|
+
if (o += 1, a) break;
|
|
134
232
|
}
|
|
135
|
-
if (
|
|
233
|
+
if (o >= r) throw new Error(`Could not find "${n}" with threshold ${t}. Best match was "${i.value}".`);
|
|
136
234
|
}
|
|
137
235
|
}
|
|
138
|
-
function
|
|
236
|
+
function F() {
|
|
237
|
+
return D();
|
|
238
|
+
}
|
|
239
|
+
async function A(n, {
|
|
139
240
|
root: e = document.body,
|
|
140
241
|
threshold: t = 0,
|
|
141
|
-
retries:
|
|
142
|
-
retryInterval:
|
|
242
|
+
retries: r = 6,
|
|
243
|
+
retryInterval: s = k
|
|
143
244
|
} = {}) {
|
|
144
|
-
return t > 0 ?
|
|
145
|
-
}
|
|
146
|
-
function
|
|
147
|
-
if (!
|
|
148
|
-
const
|
|
149
|
-
let
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
type:
|
|
153
|
-
id:
|
|
245
|
+
return t > 0 ? z(n, e, t, r, s) : T(await L(n, e));
|
|
246
|
+
}
|
|
247
|
+
function B(n, e, t = "*") {
|
|
248
|
+
if (!n?.contentWindow) throw new TypeError("Expected an iframe with a contentWindow");
|
|
249
|
+
const r = `${Date.now()}-${j++}`, s = n.contentWindow;
|
|
250
|
+
let o;
|
|
251
|
+
function i() {
|
|
252
|
+
s.postMessage({
|
|
253
|
+
type: w,
|
|
254
|
+
id: r,
|
|
154
255
|
text: e
|
|
155
256
|
}, t);
|
|
156
257
|
}
|
|
157
|
-
function
|
|
158
|
-
l.source ===
|
|
258
|
+
function a(l) {
|
|
259
|
+
l.source === s && l.data?.type === R && l.data.id === r && (window.clearInterval(o), window.removeEventListener("message", a));
|
|
159
260
|
}
|
|
160
|
-
window.addEventListener("message",
|
|
261
|
+
window.addEventListener("message", a), i(), o = window.setInterval(i, k);
|
|
161
262
|
}
|
|
162
263
|
if (typeof window < "u") {
|
|
163
|
-
let
|
|
264
|
+
let n = function(t) {
|
|
164
265
|
return t.origin === "null" ? "*" : t.origin;
|
|
165
266
|
}, e = function(t) {
|
|
166
267
|
t.source?.postMessage({
|
|
167
|
-
type:
|
|
268
|
+
type: R,
|
|
168
269
|
id: t.data.id
|
|
169
|
-
},
|
|
270
|
+
}, n(t));
|
|
170
271
|
};
|
|
171
272
|
window.addEventListener("message", (t) => {
|
|
172
|
-
t.data?.type ===
|
|
273
|
+
t.data?.type === w && (e(t), A(t.data.text, { threshold: 0.9 }).catch((r) => console.error(r)));
|
|
173
274
|
});
|
|
174
275
|
}
|
|
175
276
|
export {
|
|
176
|
-
|
|
177
|
-
|
|
277
|
+
A as default,
|
|
278
|
+
F as getMatcherMode,
|
|
279
|
+
B as highlightInIframe
|
|
178
280
|
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(f,w){typeof exports=="object"&&typeof module<"u"?w(exports):typeof define=="function"&&define.amd?define(["exports"],w):(f=typeof globalThis<"u"?globalThis:f||self,w(f.WebsiteHighlighter={}))})(this,(function(f){"use strict";class w{getEditDistances(e,t){var r=new Array(t.length+1).fill([0,0]);for(let i=0;i<e.length;i++){let o=[[i+1,0]];for(let s=0;s<t.length;s++){let a=e[i]!=t[s],l=r[s+1][0]+1,u=o[s][0]+1,p=r[s][0]+a,h=Math.min(l,Math.min(u,p)),d=[h,r[s][1]];l===h?d[1]=r[s+1][1]-1:u===h&&(d[1]=o[s][1]+1),o.push(d)}r=o}return r}getMatches(e,t){let r=this.getEditDistances(e,t),i=[0],o=r[0][0];for(let a=1;a<r.length;a++){let l=r[a][0];l<o?(i=[a],o=l):l==o&&i.push(a)}let s=[];for(let a of i){let l=r[a],u={distance:l[0],start:a-e.length-l[1],end:a};s.push(u)}return s}}function x(n,e){return new w().getMatches(n,e)}function H(n,e){const t=x(n,e);let r;for(const a of t)(r===void 0||a.distance<r.distance)&&(r=a);const i=Math.max(r.start,0),o=Math.min(Math.max(r.end,i),e.length);return{value:e.slice(i,o),start:i,end:o,distance:r.distance}}const R=`(function(){"use strict";class h{getEditDistances(s,i){var t=new Array(i.length+1).fill([0,0]);for(let e=0;e<s.length;e++){let r=[[e+1,0]];for(let l=0;l<i.length;l++){let n=s[e]!=i[l],a=t[l+1][0]+1,o=r[l][0]+1,m=t[l][0]+n,u=Math.min(a,Math.min(o,m)),f=[u,t[l][1]];a===u?f[1]=t[l+1][1]-1:o===u&&(f[1]=r[l][1]+1),r.push(f)}t=r}return t}getMatches(s,i){let t=this.getEditDistances(s,i),e=[0],r=t[0][0];for(let n=1;n<t.length;n++){let a=t[n][0];a<r?(e=[n],r=a):a==r&&e.push(n)}let l=[];for(let n of e){let a=t[n],o={distance:a[0],start:n-s.length-a[1],end:n};l.push(o)}return l}}function g(c,s){return new h().getMatches(c,s)}function d(c,s){const i=g(c,s);let t;for(const n of i)(t===void 0||n.distance<t.distance)&&(t=n);const e=Math.max(t.start,0),r=Math.min(Math.max(t.end,e),s.length);return{value:s.slice(e,r),start:e,end:r,distance:t.distance}}self.addEventListener("message",c=>{const{id:s,query:i,source:t}=c.data;try{self.postMessage({id:s,result:d(i,t)})}catch(e){self.postMessage({id:s,error:e instanceof Error?e.message:String(e)})}})})();
|
|
2
|
+
`,k=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",R],{type:"text/javascript;charset=utf-8"});function S(n){let e;try{if(e=k&&(self.URL||self.webkitURL).createObjectURL(k),!e)throw"";const t=new Worker(e,{name:n?.name});return t.addEventListener("error",()=>{(self.URL||self.webkitURL).revokeObjectURL(e)}),t}catch{return new Worker("data:text/javascript;charset=utf-8,"+encodeURIComponent(R),{name:n?.name})}}let c,C=0,M=!1,b="sync";const g=new Map;function O(n){for(const{reject:e}of g.values())e(n);g.clear()}function E(n){M=!0,c&&(c.terminate(),c=void 0),O(n)}function D(){if(!(M||typeof Worker>"u")){if(c)return c;try{c=new S}catch{M=!0;return}return c.addEventListener("message",n=>{const e=g.get(n.data?.id);e&&(g.delete(n.data.id),n.data.error?e.reject(new Error(n.data.error)):e.resolve(n.data.result))}),c.addEventListener("error",n=>{E(n.error??new Error(n.message||"Worker matcher failed."))}),c.addEventListener("messageerror",()=>{E(new Error("Worker matcher could not deserialize a message."))}),c}}function j(n,e){const t=D();if(!t)return;const r=C++;return new Promise((i,o)=>{g.set(r,{resolve:i,reject:o});try{t.postMessage({id:r,query:n,source:e})}catch(s){g.delete(r),o(s)}})}function N(){return b}async function U(n,e){const t=j(n,e);if(t)try{const r=await t;return b="worker",r}catch(r){E(r)}return b="sync",H(n,e)}function P(n,e,t){const r=n.textContent??"";if(!Number.isInteger(e)||!Number.isInteger(t)||e<0||e>=t||t>r.length)throw new RangeError(`Invalid range [${e}, ${t}) for text length ${r.length}`);const i=n.ownerDocument,o=i.createTreeWalker(n,i.defaultView.NodeFilter.SHOW_TEXT);let s=0,a=null,l=0,u=null,p=0;for(let d=o.nextNode();d;d=o.nextNode()){const y=s+d.data.length;if(a===null&&e>=s&&e<y&&(a=d,l=e-s),u===null&&t>s&&t<=y&&(u=d,p=t-s),a&&u)break;s=y}if(!a||!u)throw new Error("Could not map offsets to the DOM. The DOM may have changed.");const h=i.createRange();return h.setStart(a,l),h.setEnd(u,p),h}const m="website-highlighter",T=`${m}:response`,I=500;let _=0;function $(n){return new Promise(e=>globalThis.setTimeout(e,n))}function q(n,e){const t=n.ownerDocument?.defaultView??window;return t.MutationObserver?new Promise(r=>{let i;const o=new t.MutationObserver(()=>{t.clearTimeout(i),o.disconnect(),r(!0)});i=t.setTimeout(()=>{o.disconnect(),r(!1)},e),o.observe(n,{childList:!0,characterData:!0,subtree:!0})}):$(e).then(()=>!1)}function V(n,e,t){const r=Math.max(n.length,e.length);return r===0?1:(r-t)/r}function z(n){const{startContainer:e}=n;return e.nodeType===e.ELEMENT_NODE?e:e.parentElement}function A(n,e){const t=n.getClientRects()[0];if(!t){z(n)?.scrollIntoView({block:"center",inline:"nearest",behavior:"smooth"});return}const r=e.innerHeight||e.document.documentElement.clientHeight,i=t.top+e.scrollY-r/2+t.height/2;e.scrollTo({top:Math.max(0,i),behavior:"smooth"})}async function L(n,e){const t=e.textContent??"",r=e.ownerDocument?.defaultView??window;if(!r.CSS?.highlights||!r.Highlight)throw new Error("This browser does not support the CSS Custom Highlight API.");const{start:i,end:o,value:s,distance:a}=await U(n,t);return{haystack:t,range:i<o?P(e,i,o):null,value:s,view:r,score:V(n,s,a)}}function v({range:n,value:e,view:t}){if(!n)throw new Error("Could not find text to highlight.");return t.CSS.highlights.set(m,new t.Highlight(n)),A(n,t),{range:n,value:e}}async function F(n,e,t,r,i){let o=0;for(;;){const s=await L(n,e);if(s.score>=t)return v(s);for(;o<r;){const a=await q(e,i);if(o+=1,a)break}if(o>=r)throw new Error(`Could not find "${n}" with threshold ${t}. Best match was "${s.value}".`)}}function B(){return N()}async function W(n,{root:e=document.body,threshold:t=0,retries:r=6,retryInterval:i=I}={}){return t>0?F(n,e,t,r,i):v(await L(n,e))}function G(n,e,t="*"){if(!n?.contentWindow)throw new TypeError("Expected an iframe with a contentWindow");const r=`${Date.now()}-${_++}`,i=n.contentWindow;let o;function s(){i.postMessage({type:m,id:r,text:e},t)}function a(l){l.source===i&&l.data?.type===T&&l.data.id===r&&(window.clearInterval(o),window.removeEventListener("message",a))}window.addEventListener("message",a),s(),o=window.setInterval(s,I)}if(typeof window<"u"){let n=function(t){return t.origin==="null"?"*":t.origin},e=function(t){t.source?.postMessage({type:T,id:t.data.id},n(t))};window.addEventListener("message",t=>{t.data?.type===m&&(e(t),W(t.data.text,{threshold:.9}).catch(r=>console.error(r)))})}f.default=W,f.getMatcherMode=B,f.highlightInIframe=G,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|