@sv443-network/userutils 0.1.4 → 0.2.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/CHANGELOG.md +3 -15
- package/README.md +163 -31
- package/dist/index.d.mts +34 -11
- package/dist/index.d.ts +34 -11
- package/dist/index.js +15 -14
- package/dist/index.mjs +2 -2
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,22 +1,10 @@
|
|
|
1
1
|
# @sv443-network/userutils
|
|
2
2
|
|
|
3
|
-
## 0.
|
|
3
|
+
## 0.2.0
|
|
4
4
|
|
|
5
|
-
###
|
|
6
|
-
|
|
7
|
-
- a1e8dec: please just work thanks
|
|
8
|
-
|
|
9
|
-
## 0.1.3
|
|
10
|
-
|
|
11
|
-
### Patch Changes
|
|
12
|
-
|
|
13
|
-
- 9673cad: more testing
|
|
14
|
-
|
|
15
|
-
## 0.1.2
|
|
16
|
-
|
|
17
|
-
### Patch Changes
|
|
5
|
+
### Minor Changes
|
|
18
6
|
|
|
19
|
-
-
|
|
7
|
+
- 0cf2254: add onSelector() to call a listener once a selector is found in the DOM
|
|
20
8
|
|
|
21
9
|
## 0.1.1
|
|
22
10
|
|
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@ Contains builtin TypeScript declarations.
|
|
|
8
8
|
- [Installation](#installation)
|
|
9
9
|
- [Features](#features)
|
|
10
10
|
- [onSelector()](#onselector) - call a listener once a selector is found in the DOM
|
|
11
|
+
- [initOnSelector()](#initonselector) - needs to be called once to be able to use `onSelector()`
|
|
11
12
|
- [autoPlural()](#autoplural) - automatically pluralize a string
|
|
12
13
|
- [clamp()](#clamp) - clamp a number between a min and max value
|
|
13
14
|
- [pauseFor()](#pausefor) - pause the execution of a function for a given amount of time
|
|
@@ -54,16 +55,89 @@ If you like using this library, please consider [supporting development](https:/
|
|
|
54
55
|
## Features:
|
|
55
56
|
|
|
56
57
|
### onSelector()
|
|
57
|
-
|
|
58
|
+
Usage:
|
|
59
|
+
```ts
|
|
60
|
+
onSelector<TElement = HTMLElement>(selector: string, options: {
|
|
61
|
+
listener: (elements: TElement | NodeListOf<TElement>) => void,
|
|
62
|
+
all?: boolean,
|
|
63
|
+
continuous?: boolean,
|
|
64
|
+
}): void
|
|
65
|
+
```
|
|
58
66
|
|
|
59
67
|
Registers a listener to be called whenever the element(s) behind a selector is/are found in the DOM.
|
|
60
|
-
|
|
68
|
+
If the selector already exists, the listener will be called immediately.
|
|
69
|
+
|
|
70
|
+
If `all` is set to `true`, querySelectorAll() will be used instead and the listener will return a NodeList of matching elements.
|
|
71
|
+
This will also include elements that were already found in a previous listener call.
|
|
72
|
+
If set to `false` (default), querySelector() will be used and only the first element will be returned.
|
|
73
|
+
|
|
74
|
+
If `continuous` is set to `true`, the listener will not be deregistered after it was called once (defaults to false).
|
|
61
75
|
|
|
62
|
-
|
|
76
|
+
When using TypeScript, the generic `TElement` can be used to specify the type of the element(s) that the listener will return.
|
|
77
|
+
|
|
78
|
+
⚠️ In order to use this function, [`initOnSelector()`](#initonselector) has to be called as soon as possible.
|
|
79
|
+
This initialization function has to be called after `DOMContentLoaded` is fired (or immediately if `@run-at document-end` is set).
|
|
80
|
+
|
|
81
|
+
Calling onSelector() before `DOMContentLoaded` is fired will not throw an error, but it also won't trigger listeners until the DOM is accessible.
|
|
82
|
+
|
|
83
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
84
|
+
|
|
63
85
|
```ts
|
|
64
|
-
|
|
86
|
+
document.addEventListener("DOMContentLoaded", initOnSelector);
|
|
87
|
+
|
|
88
|
+
// Continuously checks if `div` elements are added to the DOM, then returns all of them (even previously detected ones) in a NodeList
|
|
89
|
+
onSelector("div", {
|
|
90
|
+
listener: (element) => {
|
|
91
|
+
console.log("Elements found:", element);
|
|
92
|
+
},
|
|
93
|
+
all: true,
|
|
94
|
+
continuous: true,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Checks if an input element with a value attribute of "5" is added to the DOM, then returns it and deregisters the listener
|
|
98
|
+
onSelector("input[value=\"5\"]", {
|
|
99
|
+
listener: (element) => {
|
|
100
|
+
console.log("Element found:", element);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
65
103
|
```
|
|
66
104
|
|
|
105
|
+
</details>
|
|
106
|
+
|
|
107
|
+
<br>
|
|
108
|
+
|
|
109
|
+
### initOnSelector()
|
|
110
|
+
Usage:
|
|
111
|
+
```ts
|
|
112
|
+
initOnSelector(options: {
|
|
113
|
+
attributes?: boolean,
|
|
114
|
+
characterData?: boolean,
|
|
115
|
+
}): void
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Initializes the MutationObserver that is used by [`onSelector()`](#onselector) to check for the registered selectors whenever a DOM change occurs on the `<body>`
|
|
119
|
+
By default, this only checks if elements are added or removed (at any depth).
|
|
120
|
+
|
|
121
|
+
Set `attributes` to `true` to also check for attribute changes on every single descendant of the `<body>` (defaults to false).
|
|
122
|
+
Set `characterData` to `true` to also check for character data changes on every single descendant of the `<body>` (defaults to false).
|
|
123
|
+
|
|
124
|
+
⚠️ Using these extra options can have a performance impact on larger sites or sites with a constantly changing DOM.
|
|
125
|
+
|
|
126
|
+
⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
127
|
+
|
|
128
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
document.addEventListener("DOMContentLoaded", () => {
|
|
132
|
+
initOnSelector({
|
|
133
|
+
attributes: true,
|
|
134
|
+
characterData: true,
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
</details>
|
|
140
|
+
|
|
67
141
|
<br>
|
|
68
142
|
|
|
69
143
|
### autoPlural()
|
|
@@ -72,7 +146,8 @@ Usage: `autoPlural(str: string, num: number | Array | NodeList): string`
|
|
|
72
146
|
Automatically pluralizes a string if the given number is not 1.
|
|
73
147
|
If an array or NodeList is passed, the length of it will be used.
|
|
74
148
|
|
|
75
|
-
Example
|
|
149
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
150
|
+
|
|
76
151
|
```ts
|
|
77
152
|
autoPlural("apple", 0); // "apples"
|
|
78
153
|
autoPlural("apple", 1); // "apple"
|
|
@@ -82,6 +157,8 @@ autoPlural("apple", [1]); // "apple"
|
|
|
82
157
|
autoPlural("apple", [1, 2]); // "apples"
|
|
83
158
|
```
|
|
84
159
|
|
|
160
|
+
</details>
|
|
161
|
+
|
|
85
162
|
<br>
|
|
86
163
|
|
|
87
164
|
### clamp()
|
|
@@ -89,13 +166,16 @@ Usage: `clamp(num: number, min: number, max: number): number`
|
|
|
89
166
|
|
|
90
167
|
Clamps a number between a min and max value.
|
|
91
168
|
|
|
92
|
-
Example
|
|
169
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
170
|
+
|
|
93
171
|
```ts
|
|
94
172
|
clamp(5, 0, 10); // 5
|
|
95
173
|
clamp(-1, 0, 10); // 0
|
|
96
174
|
clamp(Infinity, 0, 10); // 10
|
|
97
175
|
```
|
|
98
176
|
|
|
177
|
+
</details>
|
|
178
|
+
|
|
99
179
|
<br>
|
|
100
180
|
|
|
101
181
|
### pauseFor()
|
|
@@ -103,7 +183,8 @@ Usage: `pauseFor(ms: number): Promise<void>`
|
|
|
103
183
|
|
|
104
184
|
Pauses async execution for a given amount of time.
|
|
105
185
|
|
|
106
|
-
Example
|
|
186
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
187
|
+
|
|
107
188
|
```ts
|
|
108
189
|
async function run() {
|
|
109
190
|
console.log("Hello");
|
|
@@ -112,6 +193,8 @@ async function run() {
|
|
|
112
193
|
}
|
|
113
194
|
```
|
|
114
195
|
|
|
196
|
+
</details>
|
|
197
|
+
|
|
115
198
|
<br>
|
|
116
199
|
|
|
117
200
|
### debounce()
|
|
@@ -121,13 +204,16 @@ Debounces a function, meaning that it will only be called once after a given amo
|
|
|
121
204
|
This is very useful for functions that are called repeatedly, like event listeners, to remove extraneous calls.
|
|
122
205
|
The timeout will default to 300ms if left undefined.
|
|
123
206
|
|
|
124
|
-
Example
|
|
207
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
208
|
+
|
|
125
209
|
```ts
|
|
126
210
|
window.addEventListener("resize", debounce((event) => {
|
|
127
211
|
console.log("Window was resized:", event);
|
|
128
212
|
}, 500)); // 500ms timeout
|
|
129
213
|
```
|
|
130
214
|
|
|
215
|
+
</details>
|
|
216
|
+
|
|
131
217
|
<br>
|
|
132
218
|
|
|
133
219
|
### getUnsafeWindow()
|
|
@@ -136,7 +222,8 @@ Usage: `getUnsafeWindow(): Window`
|
|
|
136
222
|
Returns the unsafeWindow object or falls back to the regular window object if the `@grant unsafeWindow` is not given.
|
|
137
223
|
Userscripts are sandboxed and do not have access to the regular window object, so this function is useful for websites that reject some events that were dispatched by the userscript.
|
|
138
224
|
|
|
139
|
-
Example
|
|
225
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
226
|
+
|
|
140
227
|
```ts
|
|
141
228
|
const mouseEvent = new MouseEvent("click", {
|
|
142
229
|
view: getUnsafeWindow(),
|
|
@@ -144,15 +231,20 @@ const mouseEvent = new MouseEvent("click", {
|
|
|
144
231
|
document.body.dispatchEvent(mouseEvent);
|
|
145
232
|
```
|
|
146
233
|
|
|
234
|
+
</details>
|
|
235
|
+
|
|
147
236
|
<br>
|
|
148
237
|
|
|
149
238
|
### insertAfter()
|
|
150
239
|
Usage: `insertAfter(beforeElement: HTMLElement, afterElement: HTMLElement): HTMLElement`
|
|
151
240
|
|
|
152
241
|
Inserts the element passed as `afterElement` as a sibling after the passed `beforeElement`.
|
|
153
|
-
The `afterElement` will be returned.
|
|
242
|
+
The passed `afterElement` will be returned.
|
|
243
|
+
|
|
244
|
+
⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
154
245
|
|
|
155
|
-
Example
|
|
246
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
247
|
+
|
|
156
248
|
```ts
|
|
157
249
|
const beforeElement = document.querySelector("#before");
|
|
158
250
|
const afterElement = document.createElement("div");
|
|
@@ -160,15 +252,20 @@ afterElement.innerText = "After";
|
|
|
160
252
|
insertAfter(beforeElement, afterElement);
|
|
161
253
|
```
|
|
162
254
|
|
|
255
|
+
</details>
|
|
256
|
+
|
|
163
257
|
<br>
|
|
164
258
|
|
|
165
259
|
### addParent()
|
|
166
260
|
Usage: `addParent(element: HTMLElement, newParent: HTMLElement): HTMLElement`
|
|
167
261
|
|
|
168
262
|
Adds a parent element around the passed `element` and returns the new parent.
|
|
169
|
-
Previously registered event listeners
|
|
263
|
+
Previously registered event listeners are kept intact.
|
|
170
264
|
|
|
171
|
-
|
|
265
|
+
⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
266
|
+
|
|
267
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
268
|
+
|
|
172
269
|
```ts
|
|
173
270
|
const element = document.querySelector("#element");
|
|
174
271
|
const newParent = document.createElement("a");
|
|
@@ -176,15 +273,18 @@ newParent.href = "https://example.org/";
|
|
|
176
273
|
addParent(element, newParent);
|
|
177
274
|
```
|
|
178
275
|
|
|
276
|
+
</details>
|
|
277
|
+
|
|
179
278
|
<br>
|
|
180
279
|
|
|
181
280
|
### addGlobalStyle()
|
|
182
281
|
Usage: `addGlobalStyle(css: string): void`
|
|
183
282
|
|
|
184
283
|
Adds a global style to the page in form of a `<style>` element that's inserted into the `<head>`.
|
|
185
|
-
This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
284
|
+
⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
186
285
|
|
|
187
|
-
Example
|
|
286
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
287
|
+
|
|
188
288
|
```ts
|
|
189
289
|
document.addEventListener("DOMContentLoaded", () => {
|
|
190
290
|
addGlobalStyle(`
|
|
@@ -195,43 +295,61 @@ document.addEventListener("DOMContentLoaded", () => {
|
|
|
195
295
|
});
|
|
196
296
|
```
|
|
197
297
|
|
|
298
|
+
</details>
|
|
299
|
+
|
|
198
300
|
<br>
|
|
199
301
|
|
|
200
302
|
### preloadImages()
|
|
201
|
-
Usage: `preloadImages(
|
|
303
|
+
Usage: `preloadImages(urls: string[], rejects?: boolean): Promise<void>`
|
|
202
304
|
|
|
203
305
|
Preloads images into browser cache by creating an invisible `<img>` element for each URL passed.
|
|
204
306
|
The images will be loaded in parallel and the returned Promise will only resolve once all images have been loaded.
|
|
205
|
-
The resulting PromiseSettledResult array will contain the image elements if resolved, or an ErrorEvent if rejected.
|
|
307
|
+
The resulting PromiseSettledResult array will contain the image elements if resolved, or an ErrorEvent if rejected, but only if `rejects` is set to true.
|
|
206
308
|
|
|
207
|
-
Example
|
|
309
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
310
|
+
|
|
208
311
|
```ts
|
|
209
|
-
preloadImages(
|
|
312
|
+
preloadImages([
|
|
210
313
|
"https://example.org/image1.png",
|
|
211
314
|
"https://example.org/image2.png",
|
|
212
315
|
"https://example.org/image3.png",
|
|
213
|
-
)
|
|
214
|
-
|
|
215
|
-
|
|
316
|
+
], true)
|
|
317
|
+
.then((results) => {
|
|
318
|
+
console.log("Images preloaded. Results:", results);
|
|
319
|
+
});
|
|
216
320
|
```
|
|
217
321
|
|
|
322
|
+
</details>
|
|
323
|
+
|
|
218
324
|
<br>
|
|
219
325
|
|
|
220
326
|
### fetchAdvanced()
|
|
221
|
-
Usage:
|
|
327
|
+
Usage:
|
|
328
|
+
```ts
|
|
329
|
+
fetchAdvanced(url: string, options?: {
|
|
330
|
+
timeout?: number,
|
|
331
|
+
// any other options from fetch() except for signal
|
|
332
|
+
}): Promise<Response>
|
|
333
|
+
```
|
|
222
334
|
|
|
223
335
|
A wrapper around the native `fetch()` function that adds options like a timeout property.
|
|
224
336
|
The timeout will default to 10 seconds if left undefined.
|
|
225
337
|
|
|
226
|
-
Example
|
|
338
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
339
|
+
|
|
227
340
|
```ts
|
|
228
|
-
fetchAdvanced("https://example.org/", {
|
|
341
|
+
fetchAdvanced("https://api.example.org/data", {
|
|
229
342
|
timeout: 5000,
|
|
230
|
-
|
|
231
|
-
|
|
343
|
+
headers: {
|
|
344
|
+
"Accept": "application/json",
|
|
345
|
+
},
|
|
346
|
+
}).then(async (response) => {
|
|
347
|
+
console.log("Data:", await response.json());
|
|
232
348
|
});
|
|
233
349
|
```
|
|
234
350
|
|
|
351
|
+
</details>
|
|
352
|
+
|
|
235
353
|
<br>
|
|
236
354
|
|
|
237
355
|
### openInNewTab()
|
|
@@ -241,29 +359,38 @@ Creates an invisible anchor with a `_blank` target and clicks it.
|
|
|
241
359
|
Contrary to `window.open()`, this has a lesser chance to get blocked by the browser's popup blocker and doesn't open the URL as a new window.
|
|
242
360
|
This function has to be run in relatively quick succession in response to a user interaction event, else the browser might reject it.
|
|
243
361
|
|
|
244
|
-
|
|
362
|
+
⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
|
|
363
|
+
|
|
364
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
365
|
+
|
|
245
366
|
```ts
|
|
246
367
|
document.querySelector("#button").addEventListener("click", () => {
|
|
247
368
|
openInNewTab("https://example.org/");
|
|
248
369
|
});
|
|
249
370
|
```
|
|
250
371
|
|
|
372
|
+
</details>
|
|
373
|
+
|
|
251
374
|
<br>
|
|
252
375
|
|
|
253
376
|
### interceptEvent()
|
|
254
377
|
Usage: `interceptEvent(eventObject: EventTarget, eventName: string, predicate: () => boolean): void`
|
|
255
378
|
|
|
256
379
|
Intercepts all events dispatched on the `eventObject` and prevents the listeners from being called as long as the predicate function returns a truthy value.
|
|
257
|
-
This function should be called as soon as possible (I recommend using `@run-at document-start`), as it will only intercept events that are added after this function is called.
|
|
258
380
|
Calling this function will set the `Error.stackTraceLimit` to 1000 to ensure the stack trace is preserved.
|
|
259
381
|
|
|
260
|
-
|
|
382
|
+
⚠️ This function should be called as soon as possible (I recommend using `@run-at document-start`), as it will only intercept events that are *attached* after this function is called.
|
|
383
|
+
|
|
384
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
385
|
+
|
|
261
386
|
```ts
|
|
262
387
|
interceptEvent(document.body, "click", () => {
|
|
263
388
|
return true; // prevent all click events on the body
|
|
264
389
|
});
|
|
265
390
|
```
|
|
266
391
|
|
|
392
|
+
</details>
|
|
393
|
+
|
|
267
394
|
<br>
|
|
268
395
|
|
|
269
396
|
### interceptWindowEvent()
|
|
@@ -272,13 +399,18 @@ Usage: `interceptWindowEvent(eventName: string, predicate: () => boolean): void`
|
|
|
272
399
|
Intercepts all events dispatched on the `window` object and prevents the listeners from being called as long as the predicate function returns a truthy value.
|
|
273
400
|
This is essentially the same as [`interceptEvent()`](#interceptevent), but automatically uses the `unsafeWindow` (or falls back to regular `window`).
|
|
274
401
|
|
|
275
|
-
|
|
402
|
+
⚠️ This function should be called as soon as possible (I recommend using `@run-at document-start`), as it will only intercept events that are *attached* after this function is called.
|
|
403
|
+
|
|
404
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
405
|
+
|
|
276
406
|
```ts
|
|
277
407
|
interceptWindowEvent("beforeunload", () => {
|
|
278
408
|
return true; // prevent the pesky "Are you sure you want to leave this page?" popup
|
|
279
409
|
});
|
|
280
410
|
```
|
|
281
411
|
|
|
412
|
+
</details>
|
|
413
|
+
|
|
282
414
|
|
|
283
415
|
<br><br>
|
|
284
416
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
type
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
type InitOnSelectorOpts = {
|
|
2
|
+
/** Set to true if mutations to any element's attributes are to also trigger the onSelector check (warning: this might draw a lot of performance on larger sites) */
|
|
3
|
+
attributes?: boolean;
|
|
4
|
+
/** Set to true if mutations to any element's character data are to also trigger the onSelector check (warning: this might draw a lot of performance on larger sites) */
|
|
5
|
+
characterData?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type OnSelectorOpts<TElem extends Element = HTMLElement> = SelectorOptsOne<TElem> | SelectorOptsAll<TElem>;
|
|
8
|
+
type SelectorOptsOne<TElem extends Element> = SelectorOptsBase & {
|
|
9
|
+
/** Whether to use `querySelectorAll()` instead - default is false */
|
|
10
|
+
all?: false;
|
|
11
|
+
/** Gets called whenever the selector was found in the DOM */
|
|
12
|
+
listener: (element: TElem) => void;
|
|
13
|
+
};
|
|
14
|
+
type SelectorOptsAll<TElem extends Element> = SelectorOptsBase & {
|
|
15
|
+
/** Whether to use `querySelectorAll()` instead - default is false */
|
|
16
|
+
all: true;
|
|
17
|
+
/** Gets called whenever the selector was found in the DOM */
|
|
18
|
+
listener: (elements: NodeListOf<TElem>) => void;
|
|
19
|
+
};
|
|
20
|
+
type SelectorOptsBase = {
|
|
21
|
+
/** Whether to call the listener continuously instead of once - default is false */
|
|
7
22
|
continuous?: boolean;
|
|
8
23
|
};
|
|
9
24
|
type FetchAdvancedOpts = RequestInit & Partial<{
|
|
25
|
+
/** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
|
|
10
26
|
timeout: number;
|
|
11
27
|
}>;
|
|
12
28
|
|
|
@@ -77,10 +93,17 @@ declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate
|
|
|
77
93
|
* Calls the `listener` as soon as the `selector` exists in the DOM.
|
|
78
94
|
* Listeners are deleted when they are called once, unless `options.continuous` is set.
|
|
79
95
|
* Multiple listeners with the same selector may be registered.
|
|
80
|
-
* @
|
|
96
|
+
* @param selector The selector to listen for
|
|
97
|
+
* @param options Used for switching to `querySelectorAll()` and for calling the listener continuously
|
|
98
|
+
* @template TElem The type of element that the listener will return as its argument (defaults to the generic HTMLElement)
|
|
99
|
+
*/
|
|
100
|
+
declare function onSelector<TElem extends Element = HTMLElement>(selector: string, options: OnSelectorOpts<TElem>): void;
|
|
101
|
+
/** Removes all listeners registered in `onSelector()` that have the given selector */
|
|
102
|
+
declare function removeOnSelector(selector: string): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Initializes a MutationObserver that checks for all registered selectors whenever an element is added to or removed from the `<body>`
|
|
105
|
+
* @param opts For fine-tuning when the MutationObserver checks for the selectors
|
|
81
106
|
*/
|
|
82
|
-
declare function
|
|
83
|
-
/** Removes all listeners registered in `onSelector()` with a matching selector property */
|
|
84
|
-
declare function removeOnSelector(selector: string): void;
|
|
107
|
+
declare function initOnSelector(opts?: InitOnSelectorOpts): void;
|
|
85
108
|
|
|
86
|
-
export { FetchAdvancedOpts,
|
|
109
|
+
export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, onSelector, openInNewTab, pauseFor, preloadImages, removeOnSelector };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,28 @@
|
|
|
1
|
-
type
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
type InitOnSelectorOpts = {
|
|
2
|
+
/** Set to true if mutations to any element's attributes are to also trigger the onSelector check (warning: this might draw a lot of performance on larger sites) */
|
|
3
|
+
attributes?: boolean;
|
|
4
|
+
/** Set to true if mutations to any element's character data are to also trigger the onSelector check (warning: this might draw a lot of performance on larger sites) */
|
|
5
|
+
characterData?: boolean;
|
|
6
|
+
};
|
|
7
|
+
type OnSelectorOpts<TElem extends Element = HTMLElement> = SelectorOptsOne<TElem> | SelectorOptsAll<TElem>;
|
|
8
|
+
type SelectorOptsOne<TElem extends Element> = SelectorOptsBase & {
|
|
9
|
+
/** Whether to use `querySelectorAll()` instead - default is false */
|
|
10
|
+
all?: false;
|
|
11
|
+
/** Gets called whenever the selector was found in the DOM */
|
|
12
|
+
listener: (element: TElem) => void;
|
|
13
|
+
};
|
|
14
|
+
type SelectorOptsAll<TElem extends Element> = SelectorOptsBase & {
|
|
15
|
+
/** Whether to use `querySelectorAll()` instead - default is false */
|
|
16
|
+
all: true;
|
|
17
|
+
/** Gets called whenever the selector was found in the DOM */
|
|
18
|
+
listener: (elements: NodeListOf<TElem>) => void;
|
|
19
|
+
};
|
|
20
|
+
type SelectorOptsBase = {
|
|
21
|
+
/** Whether to call the listener continuously instead of once - default is false */
|
|
7
22
|
continuous?: boolean;
|
|
8
23
|
};
|
|
9
24
|
type FetchAdvancedOpts = RequestInit & Partial<{
|
|
25
|
+
/** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
|
|
10
26
|
timeout: number;
|
|
11
27
|
}>;
|
|
12
28
|
|
|
@@ -77,10 +93,17 @@ declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate
|
|
|
77
93
|
* Calls the `listener` as soon as the `selector` exists in the DOM.
|
|
78
94
|
* Listeners are deleted when they are called once, unless `options.continuous` is set.
|
|
79
95
|
* Multiple listeners with the same selector may be registered.
|
|
80
|
-
* @
|
|
96
|
+
* @param selector The selector to listen for
|
|
97
|
+
* @param options Used for switching to `querySelectorAll()` and for calling the listener continuously
|
|
98
|
+
* @template TElem The type of element that the listener will return as its argument (defaults to the generic HTMLElement)
|
|
99
|
+
*/
|
|
100
|
+
declare function onSelector<TElem extends Element = HTMLElement>(selector: string, options: OnSelectorOpts<TElem>): void;
|
|
101
|
+
/** Removes all listeners registered in `onSelector()` that have the given selector */
|
|
102
|
+
declare function removeOnSelector(selector: string): boolean;
|
|
103
|
+
/**
|
|
104
|
+
* Initializes a MutationObserver that checks for all registered selectors whenever an element is added to or removed from the `<body>`
|
|
105
|
+
* @param opts For fine-tuning when the MutationObserver checks for the selectors
|
|
81
106
|
*/
|
|
82
|
-
declare function
|
|
83
|
-
/** Removes all listeners registered in `onSelector()` with a matching selector property */
|
|
84
|
-
declare function removeOnSelector(selector: string): void;
|
|
107
|
+
declare function initOnSelector(opts?: InitOnSelectorOpts): void;
|
|
85
108
|
|
|
86
|
-
export { FetchAdvancedOpts,
|
|
109
|
+
export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, onSelector, openInNewTab, pauseFor, preloadImages, removeOnSelector };
|
package/dist/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var b=Object.defineProperty,v=Object.defineProperties;var y=Object.getOwnPropertyDescriptors;var m=Object.getOwnPropertySymbols;var x=Object.prototype.hasOwnProperty,g=Object.prototype.propertyIsEnumerable;var f=(t,e,n)=>e in t?b(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,u=(t,e)=>{for(var n in e||(e={}))x.call(e,n)&&f(t,n,e[n]);if(m)for(var n of m(e))g.call(e,n)&&f(t,n,e[n]);return t},d=(t,e)=>v(t,y(e));var E=(t,e,n)=>new Promise((r,o)=>{var s=c=>{try{l(n.next(c));}catch(p){o(p);}},i=c=>{try{l(n.throw(c));}catch(p){o(p);}},l=c=>c.done?r(c.value):Promise.resolve(c.value).then(s,i);l((n=n.apply(t,e)).next());});function w(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function M(t,e,n){return Math.max(Math.min(t,n),e)}function S(t){return new Promise(e=>{setTimeout(e,t);})}function A(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function h(){try{return unsafeWindow}catch(t){return window}}function _(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function k(t,e){let n=t.parentNode;if(!n)throw new Error("Element doesn't have a parent node");return n.replaceChild(e,t),e.appendChild(t),e}function H(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function I(t,e=!1){let n=t.map(r=>new Promise((o,s)=>{let i=new Image;i.src=r,i.addEventListener("load",()=>o(i)),i.addEventListener("error",l=>e&&s(l));}));return Promise.allSettled(n)}function j(n){return E(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,o=new AbortController,s=setTimeout(()=>o.abort(),r),i=yield fetch(t,d(u({},e),{signal:o.signal}));return clearTimeout(s),i})}function N(t){let e=document.createElement("a");Object.assign(e,{className:"userutils-open-in-new-tab",target:"_blank",rel:"noopener noreferrer",href:t}),e.style.display="none",document.body.appendChild(e),e.click(),setTimeout(e.remove,50);}function O(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){element.__proto__.addEventListener=function(...o){if(!(o[0]===e&&n()))return r.apply(this,o)};}(t.__proto__.addEventListener);}function P(t,e){return O(h(),t,e)}var a=new Map;function W(t,e){let n=[];a.has(t)&&(n=a.get(t)),n.push(e),a.set(t,n),T(t,n);}function q(t){return a.delete(t)}function T(t,e){let n=[];e.forEach((r,o)=>{try{let s=r.all?document.querySelectorAll(t):document.querySelector(t);s&&(r.listener(s),r.continuous||n.push(o));}catch(s){}}),n.length>0&&a.set(t,e.filter((r,o)=>!n.includes(o)));}function $(t={}){new MutationObserver(()=>{for(let[n,r]of a.entries())T(n,r);}).observe(document.body,d(u({},t),{childList:!0}));}
|
|
4
4
|
|
|
5
|
-
exports.addGlobalStyle =
|
|
6
|
-
exports.addParent =
|
|
7
|
-
exports.autoPlural =
|
|
8
|
-
exports.clamp =
|
|
5
|
+
exports.addGlobalStyle = H;
|
|
6
|
+
exports.addParent = k;
|
|
7
|
+
exports.autoPlural = w;
|
|
8
|
+
exports.clamp = M;
|
|
9
9
|
exports.debounce = A;
|
|
10
|
-
exports.fetchAdvanced =
|
|
11
|
-
exports.getUnsafeWindow =
|
|
12
|
-
exports.
|
|
13
|
-
exports.
|
|
14
|
-
exports.
|
|
15
|
-
exports.
|
|
10
|
+
exports.fetchAdvanced = j;
|
|
11
|
+
exports.getUnsafeWindow = h;
|
|
12
|
+
exports.initOnSelector = $;
|
|
13
|
+
exports.insertAfter = _;
|
|
14
|
+
exports.interceptEvent = O;
|
|
15
|
+
exports.interceptWindowEvent = P;
|
|
16
|
+
exports.onSelector = W;
|
|
16
17
|
exports.openInNewTab = N;
|
|
17
|
-
exports.pauseFor =
|
|
18
|
-
exports.preloadImages =
|
|
19
|
-
exports.removeOnSelector =
|
|
18
|
+
exports.pauseFor = S;
|
|
19
|
+
exports.preloadImages = I;
|
|
20
|
+
exports.removeOnSelector = q;
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var b=Object.defineProperty,v=Object.defineProperties;var y=Object.getOwnPropertyDescriptors;var m=Object.getOwnPropertySymbols;var x=Object.prototype.hasOwnProperty,g=Object.prototype.propertyIsEnumerable;var f=(t,e,n)=>e in t?b(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,u=(t,e)=>{for(var n in e||(e={}))x.call(e,n)&&f(t,n,e[n]);if(m)for(var n of m(e))g.call(e,n)&&f(t,n,e[n]);return t},d=(t,e)=>v(t,y(e));var E=(t,e,n)=>new Promise((r,o)=>{var s=c=>{try{l(n.next(c));}catch(p){o(p);}},i=c=>{try{l(n.throw(c));}catch(p){o(p);}},l=c=>c.done?r(c.value):Promise.resolve(c.value).then(s,i);l((n=n.apply(t,e)).next());});function w(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function M(t,e,n){return Math.max(Math.min(t,n),e)}function S(t){return new Promise(e=>{setTimeout(e,t);})}function A(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function h(){try{return unsafeWindow}catch(t){return window}}function _(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function k(t,e){let n=t.parentNode;if(!n)throw new Error("Element doesn't have a parent node");return n.replaceChild(e,t),e.appendChild(t),e}function H(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function I(t,e=!1){let n=t.map(r=>new Promise((o,s)=>{let i=new Image;i.src=r,i.addEventListener("load",()=>o(i)),i.addEventListener("error",l=>e&&s(l));}));return Promise.allSettled(n)}function j(n){return E(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,o=new AbortController,s=setTimeout(()=>o.abort(),r),i=yield fetch(t,d(u({},e),{signal:o.signal}));return clearTimeout(s),i})}function N(t){let e=document.createElement("a");Object.assign(e,{className:"userutils-open-in-new-tab",target:"_blank",rel:"noopener noreferrer",href:t}),e.style.display="none",document.body.appendChild(e),e.click(),setTimeout(e.remove,50);}function O(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){element.__proto__.addEventListener=function(...o){if(!(o[0]===e&&n()))return r.apply(this,o)};}(t.__proto__.addEventListener);}function P(t,e){return O(h(),t,e)}var a=new Map;function W(t,e){let n=[];a.has(t)&&(n=a.get(t)),n.push(e),a.set(t,n),T(t,n);}function q(t){return a.delete(t)}function T(t,e){let n=[];e.forEach((r,o)=>{try{let s=r.all?document.querySelectorAll(t):document.querySelector(t);s&&(r.listener(s),r.continuous||n.push(o));}catch(s){}}),n.length>0&&a.set(t,e.filter((r,o)=>!n.includes(o)));}function $(t={}){new MutationObserver(()=>{for(let[n,r]of a.entries())T(n,r);}).observe(document.body,d(u({},t),{childList:!0}));}
|
|
2
2
|
|
|
3
|
-
export {
|
|
3
|
+
export { H as addGlobalStyle, k as addParent, w as autoPlural, M as clamp, A as debounce, j as fetchAdvanced, h as getUnsafeWindow, $ as initOnSelector, _ as insertAfter, O as interceptEvent, P as interceptWindowEvent, W as onSelector, N as openInNewTab, S as pauseFor, I as preloadImages, q as removeOnSelector };
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sv443-network/userutils",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more ",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
8
8
|
"scripts": {
|
|
9
9
|
"lint": "tsc && eslint .",
|
|
10
|
-
"
|
|
11
|
-
"build": "npm run
|
|
12
|
-
"
|
|
10
|
+
"build-common": "tsup lib/index.ts --format cjs,esm --dts --clean --treeshake",
|
|
11
|
+
"build": "npm run build-common -- --minify",
|
|
12
|
+
"dev": "npm run build-common -- --sourcemap --watch",
|
|
13
13
|
"publish-package": "npm run build && changeset publish"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|