website-highlighter 1.2.0 → 1.3.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 +185 -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, and
|
|
86
|
+
Finds the best fuzzy match for `text`, applies the `website-highlighter` custom highlight, 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 i = 0; i < e.length; i++) {
|
|
14
|
+
let o = [[i + 1, 0]];
|
|
15
|
+
for (let s = 0; s < t.length; s++) {
|
|
16
|
+
let a = e[i] != t[s], l = r[s + 1][0] + 1, c = o[s][0] + 1, g = r[s][0] + a, f = Math.min(l, Math.min(c, g)), d = [f, r[s][1]];
|
|
17
|
+
l === f ? d[1] = r[s + 1][1] - 1 : c === f && (d[1] = o[s][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,231 @@ 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), i = [0], o = r[0][0];
|
|
34
|
+
for (let a = 1; a < r.length; a++) {
|
|
35
|
+
let l = r[a][0];
|
|
36
|
+
l < o ? (i = [a], o = l) : l == o && i.push(a);
|
|
37
37
|
}
|
|
38
|
-
let
|
|
39
|
-
for (let
|
|
40
|
-
let l =
|
|
38
|
+
let s = [];
|
|
39
|
+
for (let a of i) {
|
|
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
|
+
s.push(c);
|
|
47
47
|
}
|
|
48
|
-
return
|
|
48
|
+
return s;
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
function T(
|
|
52
|
-
return new
|
|
51
|
+
function T(n, e) {
|
|
52
|
+
return new I().getMatches(n, e);
|
|
53
53
|
}
|
|
54
|
-
function
|
|
55
|
-
const t = T(
|
|
56
|
-
let
|
|
57
|
-
for (const
|
|
58
|
-
(
|
|
59
|
-
const
|
|
60
|
-
return { value: e.slice(
|
|
54
|
+
function x(n, e) {
|
|
55
|
+
const t = T(n, e);
|
|
56
|
+
let r;
|
|
57
|
+
for (const a of t)
|
|
58
|
+
(r === void 0 || a.distance < r.distance) && (r = a);
|
|
59
|
+
const i = Math.max(r.start, 0), o = Math.min(Math.max(r.end, i), e.length);
|
|
60
|
+
return { value: e.slice(i, o), start: i, 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
|
+
`, E = 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 = E && (self.URL || self.webkitURL).createObjectURL(E), !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, S = 0, p = !1, M = "sync";
|
|
84
|
+
const h = /* @__PURE__ */ new Map();
|
|
85
|
+
function H(n) {
|
|
86
|
+
for (const { reject: e } of h.values())
|
|
87
|
+
e(n);
|
|
88
|
+
h.clear();
|
|
89
|
+
}
|
|
90
|
+
function b(n) {
|
|
91
|
+
p = !0, u && (u.terminate(), u = void 0), H(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
|
+
b(n.error ?? new Error(n.message || "Worker matcher failed."));
|
|
107
|
+
}), u.addEventListener("messageerror", () => {
|
|
108
|
+
b(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 = S++;
|
|
116
|
+
return new Promise((i, o) => {
|
|
117
|
+
h.set(r, { resolve: i, reject: o });
|
|
118
|
+
try {
|
|
119
|
+
t.postMessage({ id: r, query: n, source: e });
|
|
120
|
+
} catch (s) {
|
|
121
|
+
h.delete(r), o(s);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
function D() {
|
|
126
|
+
return M;
|
|
127
|
+
}
|
|
128
|
+
async function U(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
|
+
b(r);
|
|
136
|
+
}
|
|
137
|
+
return M = "sync", x(n, e);
|
|
138
|
+
}
|
|
139
|
+
function j(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 i = n.ownerDocument, o = i.createTreeWalker(
|
|
146
|
+
n,
|
|
147
|
+
i.defaultView.NodeFilter.SHOW_TEXT
|
|
71
148
|
);
|
|
72
|
-
let
|
|
73
|
-
for (let
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
149
|
+
let s = 0, a = null, l = 0, c = null, g = 0;
|
|
150
|
+
for (let d = o.nextNode(); d; d = o.nextNode()) {
|
|
151
|
+
const m = s + d.data.length;
|
|
152
|
+
if (a === null && e >= s && e < m && (a = d, l = e - s), c === null && t > s && t <= m && (c = d, g = t - s), a && c)
|
|
76
153
|
break;
|
|
77
|
-
|
|
154
|
+
s = 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 = i.createRange();
|
|
161
|
+
return f.setStart(a, l), f.setEnd(c, g), f;
|
|
162
|
+
}
|
|
163
|
+
const w = "website-highlighter", k = `${w}:response`, R = 500;
|
|
164
|
+
let N = 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 i;
|
|
172
|
+
const o = new t.MutationObserver(() => {
|
|
173
|
+
t.clearTimeout(i), o.disconnect(), r(!0);
|
|
97
174
|
});
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
}, e),
|
|
175
|
+
i = 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 t = e.textContent ?? "",
|
|
113
|
-
if (!
|
|
188
|
+
async function L(n, e) {
|
|
189
|
+
const t = e.textContent ?? "", r = e.ownerDocument?.defaultView ?? window;
|
|
190
|
+
if (!r.CSS?.highlights || !r.Highlight) throw new Error("This browser does not support the CSS Custom Highlight API.");
|
|
191
|
+
const { start: i, end: o, value: s, distance: a } = await U(n, t);
|
|
114
192
|
return {
|
|
115
193
|
haystack: t,
|
|
116
|
-
range:
|
|
117
|
-
value:
|
|
118
|
-
view:
|
|
119
|
-
score:
|
|
194
|
+
range: i < o ? j(e, i, o) : null,
|
|
195
|
+
value: s,
|
|
196
|
+
view: r,
|
|
197
|
+
score: P(n, s, a)
|
|
120
198
|
};
|
|
121
199
|
}
|
|
122
|
-
function
|
|
123
|
-
if (!
|
|
124
|
-
return t.CSS.highlights.set(
|
|
200
|
+
function v({ range: n, value: e, view: t }) {
|
|
201
|
+
if (!n) throw new Error("Could not find text to highlight.");
|
|
202
|
+
return t.CSS.highlights.set(w, new t.Highlight(n)), { range: n, value: e };
|
|
125
203
|
}
|
|
126
|
-
async function
|
|
127
|
-
let
|
|
204
|
+
async function _(n, e, t, r, i) {
|
|
205
|
+
let o = 0;
|
|
128
206
|
for (; ; ) {
|
|
129
|
-
const
|
|
130
|
-
if (
|
|
131
|
-
for (;
|
|
132
|
-
const
|
|
133
|
-
if (
|
|
207
|
+
const s = await L(n, e);
|
|
208
|
+
if (s.score >= t) return v(s);
|
|
209
|
+
for (; o < r; ) {
|
|
210
|
+
const a = await q(e, i);
|
|
211
|
+
if (o += 1, a) break;
|
|
134
212
|
}
|
|
135
|
-
if (
|
|
213
|
+
if (o >= r) throw new Error(`Could not find "${n}" with threshold ${t}. Best match was "${s.value}".`);
|
|
136
214
|
}
|
|
137
215
|
}
|
|
138
|
-
function
|
|
216
|
+
function A() {
|
|
217
|
+
return D();
|
|
218
|
+
}
|
|
219
|
+
async function z(n, {
|
|
139
220
|
root: e = document.body,
|
|
140
221
|
threshold: t = 0,
|
|
141
|
-
retries:
|
|
142
|
-
retryInterval:
|
|
222
|
+
retries: r = 6,
|
|
223
|
+
retryInterval: i = R
|
|
143
224
|
} = {}) {
|
|
144
|
-
return t > 0 ?
|
|
145
|
-
}
|
|
146
|
-
function
|
|
147
|
-
if (!
|
|
148
|
-
const
|
|
149
|
-
let
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
type:
|
|
153
|
-
id:
|
|
225
|
+
return t > 0 ? _(n, e, t, r, i) : v(await L(n, e));
|
|
226
|
+
}
|
|
227
|
+
function F(n, e, t = "*") {
|
|
228
|
+
if (!n?.contentWindow) throw new TypeError("Expected an iframe with a contentWindow");
|
|
229
|
+
const r = `${Date.now()}-${N++}`, i = n.contentWindow;
|
|
230
|
+
let o;
|
|
231
|
+
function s() {
|
|
232
|
+
i.postMessage({
|
|
233
|
+
type: w,
|
|
234
|
+
id: r,
|
|
154
235
|
text: e
|
|
155
236
|
}, t);
|
|
156
237
|
}
|
|
157
|
-
function
|
|
158
|
-
l.source ===
|
|
238
|
+
function a(l) {
|
|
239
|
+
l.source === i && l.data?.type === k && l.data.id === r && (window.clearInterval(o), window.removeEventListener("message", a));
|
|
159
240
|
}
|
|
160
|
-
window.addEventListener("message",
|
|
241
|
+
window.addEventListener("message", a), s(), o = window.setInterval(s, R);
|
|
161
242
|
}
|
|
162
243
|
if (typeof window < "u") {
|
|
163
|
-
let
|
|
244
|
+
let n = function(t) {
|
|
164
245
|
return t.origin === "null" ? "*" : t.origin;
|
|
165
246
|
}, e = function(t) {
|
|
166
247
|
t.source?.postMessage({
|
|
167
|
-
type:
|
|
248
|
+
type: k,
|
|
168
249
|
id: t.data.id
|
|
169
|
-
},
|
|
250
|
+
}, n(t));
|
|
170
251
|
};
|
|
171
252
|
window.addEventListener("message", (t) => {
|
|
172
|
-
t.data?.type ===
|
|
253
|
+
t.data?.type === w && (e(t), z(t.data.text, { threshold: 0.9 }).catch((r) => console.error(r)));
|
|
173
254
|
});
|
|
174
255
|
}
|
|
175
256
|
export {
|
|
176
|
-
|
|
177
|
-
|
|
257
|
+
z as default,
|
|
258
|
+
A as getMatcherMode,
|
|
259
|
+
F as highlightInIframe
|
|
178
260
|
};
|
|
@@ -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 s=0;s<e.length;s++){let o=[[s+1,0]];for(let i=0;i<t.length;i++){let a=e[s]!=t[i],l=r[i+1][0]+1,u=o[i][0]+1,p=r[i][0]+a,h=Math.min(l,Math.min(u,p)),d=[h,r[i][1]];l===h?d[1]=r[i+1][1]-1:u===h&&(d[1]=o[i][1]+1),o.push(d)}r=o}return r}getMatches(e,t){let r=this.getEditDistances(e,t),s=[0],o=r[0][0];for(let a=1;a<r.length;a++){let l=r[a][0];l<o?(s=[a],o=l):l==o&&s.push(a)}let i=[];for(let a of s){let l=r[a],u={distance:l[0],start:a-e.length-l[1],end:a};i.push(u)}return i}}function x(n,e){return new w().getMatches(n,e)}function S(n,e){const t=x(n,e);let r;for(const a of t)(r===void 0||a.distance<r.distance)&&(r=a);const s=Math.max(r.start,0),o=Math.min(Math.max(r.end,s),e.length);return{value:e.slice(s,o),start:s,end:o,distance:r.distance}}const k=`(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
|
+
`,R=typeof self<"u"&&self.Blob&&new Blob(["(self.URL || self.webkitURL).revokeObjectURL(self.location.href);",k],{type:"text/javascript;charset=utf-8"});function H(n){let e;try{if(e=R&&(self.URL||self.webkitURL).createObjectURL(R),!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(k),{name:n?.name})}}let c,O=0,M=!1,b="sync";const g=new Map;function C(n){for(const{reject:e}of g.values())e(n);g.clear()}function y(n){M=!0,c&&(c.terminate(),c=void 0),C(n)}function j(){if(!(M||typeof Worker>"u")){if(c)return c;try{c=new H}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=>{y(n.error??new Error(n.message||"Worker matcher failed."))}),c.addEventListener("messageerror",()=>{y(new Error("Worker matcher could not deserialize a message."))}),c}}function D(n,e){const t=j();if(!t)return;const r=O++;return new Promise((s,o)=>{g.set(r,{resolve:s,reject:o});try{t.postMessage({id:r,query:n,source:e})}catch(i){g.delete(r),o(i)}})}function U(){return b}async function N(n,e){const t=D(n,e);if(t)try{const r=await t;return b="worker",r}catch(r){y(r)}return b="sync",S(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 s=n.ownerDocument,o=s.createTreeWalker(n,s.defaultView.NodeFilter.SHOW_TEXT);let i=0,a=null,l=0,u=null,p=0;for(let d=o.nextNode();d;d=o.nextNode()){const E=i+d.data.length;if(a===null&&e>=i&&e<E&&(a=d,l=e-i),u===null&&t>i&&t<=E&&(u=d,p=t-i),a&&u)break;i=E}if(!a||!u)throw new Error("Could not map offsets to the DOM. The DOM may have changed.");const h=s.createRange();return h.setStart(a,l),h.setEnd(u,p),h}const m="website-highlighter",v=`${m}:response`,L=500;let $=0;function q(n){return new Promise(e=>globalThis.setTimeout(e,n))}function _(n,e){const t=n.ownerDocument?.defaultView??window;return t.MutationObserver?new Promise(r=>{let s;const o=new t.MutationObserver(()=>{t.clearTimeout(s),o.disconnect(),r(!0)});s=t.setTimeout(()=>{o.disconnect(),r(!1)},e),o.observe(n,{childList:!0,characterData:!0,subtree:!0})}):q(e).then(()=>!1)}function z(n,e,t){const r=Math.max(n.length,e.length);return r===0?1:(r-t)/r}async function T(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:s,end:o,value:i,distance:a}=await N(n,t);return{haystack:t,range:s<o?P(e,s,o):null,value:i,view:r,score:z(n,i,a)}}function I({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)),{range:n,value:e}}async function A(n,e,t,r,s){let o=0;for(;;){const i=await T(n,e);if(i.score>=t)return I(i);for(;o<r;){const a=await _(e,s);if(o+=1,a)break}if(o>=r)throw new Error(`Could not find "${n}" with threshold ${t}. Best match was "${i.value}".`)}}function F(){return U()}async function W(n,{root:e=document.body,threshold:t=0,retries:r=6,retryInterval:s=L}={}){return t>0?A(n,e,t,r,s):I(await T(n,e))}function B(n,e,t="*"){if(!n?.contentWindow)throw new TypeError("Expected an iframe with a contentWindow");const r=`${Date.now()}-${$++}`,s=n.contentWindow;let o;function i(){s.postMessage({type:m,id:r,text:e},t)}function a(l){l.source===s&&l.data?.type===v&&l.data.id===r&&(window.clearInterval(o),window.removeEventListener("message",a))}window.addEventListener("message",a),i(),o=window.setInterval(i,L)}if(typeof window<"u"){let n=function(t){return t.origin==="null"?"*":t.origin},e=function(t){t.source?.postMessage({type:v,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=F,f.highlightInIframe=B,Object.defineProperties(f,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}));
|