@sv443-network/userutils 0.2.0 → 0.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/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # @sv443-network/userutils
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 231a79c: Refactored code and documentation and added new functions:
8
+ - mapRange() to map a number from one range to the same spot in another range
9
+ - randRange() to generate a random number between a min and max boundary
10
+ - randomItem() to return a random item from an array
11
+ - randomItemIndex() to return a tuple of a random item and its index from an array
12
+ - takeRandomItem() to return a random item from an array and mutate it to remove the item
13
+ - randomizeArray() to return a copy of the array with its items in a random order
14
+
15
+ ### Patch Changes
16
+
17
+ - 7edf837: decrease npm bundle size
18
+
19
+ ## 0.3.0
20
+
21
+ ### Minor Changes
22
+
23
+ - 07ec443: add getSelectorMap() to return all currently registered selectors
24
+
3
25
  ## 0.2.0
4
26
 
5
27
  ### Minor Changes
package/README.md CHANGED
@@ -1,27 +1,41 @@
1
+ <div style="text-align: center;" align="center">
2
+
1
3
  ## UserUtils
2
4
  Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more.
3
- Contains builtin TypeScript declarations.
5
+ Contains builtin TypeScript declarations. Webpack compatible and supports ESM and CJS.
4
6
 
7
+ </div>
5
8
  <br>
6
9
 
7
10
  ## Table of Contents:
8
11
  - [Installation](#installation)
9
12
  - [Features](#features)
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()`
12
- - [autoPlural()](#autoplural) - automatically pluralize a string
13
- - [clamp()](#clamp) - clamp a number between a min and max value
14
- - [pauseFor()](#pausefor) - pause the execution of a function for a given amount of time
15
- - [debounce()](#debounce) - call a function only once, after a given amount of time
16
- - [getUnsafeWindow()](#getunsafewindow) - get the unsafeWindow object or fall back to the regular window object
17
- - [insertAfter()](#insertafter) - insert an element as a sibling after another element
18
- - [addParent()](#addparent) - add a parent element around another element
19
- - [addGlobalStyle()](#addglobalstyle) - add a global style to the page
20
- - [preloadImages()](#preloadimages) - preload images into the browser cache for faster loading later on
21
- - [fetchAdvanced()](#fetchadvanced) - wrapper around the fetch API with a timeout option
22
- - [openInNewTab()](#openinnewtab) - open a link in a new tab
23
- - [interceptEvent()](#interceptevent) - conditionally intercepts events registered by `addEventListener()` on any given EventTarget object
24
- - [interceptWindowEvent()](#interceptwindowevent) - conditionally intercepts events registered by `addEventListener()` on the window object
13
+ - [DOM:](#dom)
14
+ - [onSelector()](#onselector) - call a listener once a selector is found in the DOM
15
+ - [initOnSelector()](#initonselector) - needs to be called once to be able to use `onSelector()`
16
+ - [getSelectorMap()](#getselectormap) - returns all currently registered selectors, listeners and options
17
+ - [getUnsafeWindow()](#getunsafewindow) - get the unsafeWindow object or fall back to the regular window object
18
+ - [insertAfter()](#insertafter) - insert an element as a sibling after another element
19
+ - [addParent()](#addparent) - add a parent element around another element
20
+ - [addGlobalStyle()](#addglobalstyle) - add a global style to the page
21
+ - [preloadImages()](#preloadimages) - preload images into the browser cache for faster loading later on
22
+ - [openInNewTab()](#openinnewtab) - open a link in a new tab
23
+ - [interceptEvent()](#interceptevent) - conditionally intercepts events registered by `addEventListener()` on any given EventTarget object
24
+ - [interceptWindowEvent()](#interceptwindowevent) - conditionally intercepts events registered by `addEventListener()` on the window object
25
+ - [Math:](#math)
26
+ - [clamp()](#clamp) - clamp a number between a min and max value
27
+ - [mapRange()](#maprange) - map a number from one range to the same spot in another range
28
+ - [randRange()](#randrange) - generate a random number between a min and max boundary
29
+ - [Misc:](#misc)
30
+ - [autoPlural()](#autoplural) - automatically pluralize a string
31
+ - [pauseFor()](#pausefor) - pause the execution of a function for a given amount of time
32
+ - [debounce()](#debounce) - call a function only once, after a given amount of time
33
+ - [fetchAdvanced()](#fetchadvanced) - wrapper around the fetch API with a timeout option
34
+ - [Arrays:](#arrays)
35
+ - [randomItem()](#randomitem) - returns a random item from an array
36
+ - [randomItemIndex()](#randomitemindex) - returns a tuple of a random item and its index from an array
37
+ - [takeRandomItem()](#takerandomitem) - returns a random item from an array and mutates it to remove the item
38
+ - [randomizeArray()](#randomizearray) - returns a copy of the array with its items in a random order
25
39
  - [License](#license)
26
40
 
27
41
  <br><br>
@@ -54,6 +68,8 @@ If you like using this library, please consider [supporting development](https:/
54
68
 
55
69
  ## Features:
56
70
 
71
+ ## DOM:
72
+
57
73
  ### onSelector()
58
74
  Usage:
59
75
  ```ts
@@ -69,7 +85,7 @@ If the selector already exists, the listener will be called immediately.
69
85
 
70
86
  If `all` is set to `true`, querySelectorAll() will be used instead and the listener will return a NodeList of matching elements.
71
87
  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.
88
+ If set to `false` (default), querySelector() will be used and only the first matching element will be returned.
73
89
 
74
90
  If `continuous` is set to `true`, the listener will not be deregistered after it was called once (defaults to false).
75
91
 
@@ -86,18 +102,18 @@ Calling onSelector() before `DOMContentLoaded` is fired will not throw an error,
86
102
  document.addEventListener("DOMContentLoaded", initOnSelector);
87
103
 
88
104
  // 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);
105
+ onSelector<HTMLDivElement>("div", {
106
+ listener: (elements) => {
107
+ console.log("Elements found:", elements); // type = NodeListOf<HTMLDivElement>
92
108
  },
93
109
  all: true,
94
110
  continuous: true,
95
111
  });
96
112
 
97
113
  // 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\"]", {
114
+ onSelector<HTMLInputElement>("input[value=\"5\"]", {
99
115
  listener: (element) => {
100
- console.log("Element found:", element);
116
+ console.log("Element found:", element); // type = HTMLInputElement
101
117
  },
102
118
  });
103
119
  ```
@@ -109,7 +125,7 @@ onSelector("input[value=\"5\"]", {
109
125
  ### initOnSelector()
110
126
  Usage:
111
127
  ```ts
112
- initOnSelector(options: {
128
+ initOnSelector(options?: {
113
129
  attributes?: boolean,
114
130
  characterData?: boolean,
115
131
  }): void
@@ -140,76 +156,40 @@ document.addEventListener("DOMContentLoaded", () => {
140
156
 
141
157
  <br>
142
158
 
143
- ### autoPlural()
144
- Usage: `autoPlural(str: string, num: number | Array | NodeList): string`
145
-
146
- Automatically pluralizes a string if the given number is not 1.
147
- If an array or NodeList is passed, the length of it will be used.
148
-
149
- <details><summary><b>Example - click to view</b></summary>
150
-
151
- ```ts
152
- autoPlural("apple", 0); // "apples"
153
- autoPlural("apple", 1); // "apple"
154
- autoPlural("apple", 2); // "apples"
155
-
156
- autoPlural("apple", [1]); // "apple"
157
- autoPlural("apple", [1, 2]); // "apples"
158
- ```
159
-
160
- </details>
161
-
162
- <br>
163
-
164
- ### clamp()
165
- Usage: `clamp(num: number, min: number, max: number): number`
166
-
167
- Clamps a number between a min and max value.
168
-
169
- <details><summary><b>Example - click to view</b></summary>
170
-
171
- ```ts
172
- clamp(5, 0, 10); // 5
173
- clamp(-1, 0, 10); // 0
174
- clamp(Infinity, 0, 10); // 10
175
- ```
176
-
177
- </details>
178
-
179
- <br>
180
-
181
- ### pauseFor()
182
- Usage: `pauseFor(ms: number): Promise<void>`
159
+ ### getSelectorMap()
160
+ Usage: `getSelectorMap(): Map<string, OnSelectorOptions[]>`
183
161
 
184
- Pauses async execution for a given amount of time.
162
+ Returns a Map of all currently registered selectors and their options, including listener function.
163
+ Since multiple listeners can be registered for the same selector, the value of the Map is an array of `OnSelectorOptions` objects.
185
164
 
186
165
  <details><summary><b>Example - click to view</b></summary>
187
166
 
188
167
  ```ts
189
- async function run() {
190
- console.log("Hello");
191
- await pauseFor(3000); // waits for 3 seconds
192
- console.log("World");
193
- }
194
- ```
195
-
196
- </details>
168
+ document.addEventListener("DOMContentLoaded", initOnSelector);
197
169
 
198
- <br>
170
+ onSelector<HTMLDivElement>("div", {
171
+ listener: (elements) => void 0,
172
+ all: true,
173
+ continuous: true,
174
+ });
199
175
 
200
- ### debounce()
201
- Usage: `debounce(func: Function, timeout?: number): Function`
202
-
203
- Debounces a function, meaning that it will only be called once after a given amount of time.
204
- This is very useful for functions that are called repeatedly, like event listeners, to remove extraneous calls.
205
- The timeout will default to 300ms if left undefined.
206
-
207
- <details><summary><b>Example - click to view</b></summary>
176
+ onSelector<HTMLDivElement>("div", {
177
+ listener: (elements) => void 0,
178
+ });
208
179
 
209
- ```ts
210
- window.addEventListener("resize", debounce((event) => {
211
- console.log("Window was resized:", event);
212
- }, 500)); // 500ms timeout
180
+ const selectorMap = getSelectorMap();
181
+ // Map(1) {
182
+ // "div" => [
183
+ // {
184
+ // listener: (elements) => void 0,
185
+ // all: true,
186
+ // continuous: true,
187
+ // },
188
+ // {
189
+ // listener: (elements) => void 0,
190
+ // },
191
+ // ]
192
+ // }
213
193
  ```
214
194
 
215
195
  </details>
@@ -225,8 +205,13 @@ Userscripts are sandboxed and do not have access to the regular window object, s
225
205
  <details><summary><b>Example - click to view</b></summary>
226
206
 
227
207
  ```ts
228
- const mouseEvent = new MouseEvent("click", {
208
+ // trick the site into thinking the mouse was moved:
209
+ const mouseEvent = new MouseEvent("mousemove", {
229
210
  view: getUnsafeWindow(),
211
+ screenY: 69,
212
+ screenX: 420,
213
+ movementX: 10,
214
+ movementY: 0,
230
215
  });
231
216
  document.body.dispatchEvent(mouseEvent);
232
217
  ```
@@ -246,6 +231,7 @@ The passed `afterElement` will be returned.
246
231
  <details><summary><b>Example - click to view</b></summary>
247
232
 
248
233
  ```ts
234
+ // insert a <div> as a sibling next to an element
249
235
  const beforeElement = document.querySelector("#before");
250
236
  const afterElement = document.createElement("div");
251
237
  afterElement.innerText = "After";
@@ -267,6 +253,7 @@ Previously registered event listeners are kept intact.
267
253
  <details><summary><b>Example - click to view</b></summary>
268
254
 
269
255
  ```ts
256
+ // add an <a> around an element
270
257
  const element = document.querySelector("#element");
271
258
  const newParent = document.createElement("a");
272
259
  newParent.href = "https://example.org/";
@@ -323,6 +310,191 @@ preloadImages([
323
310
 
324
311
  <br>
325
312
 
313
+ ### openInNewTab()
314
+ Usage: `openInNewTab(url: string): void`
315
+
316
+ Creates an invisible anchor with a `_blank` target and clicks it.
317
+ 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.
318
+ This function has to be run in relatively quick succession in response to a user interaction event, else the browser might reject it.
319
+
320
+ ⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
321
+
322
+ <details><summary><b>Example - click to view</b></summary>
323
+
324
+ ```ts
325
+ document.querySelector("#my-button").addEventListener("click", () => {
326
+ openInNewTab("https://example.org/");
327
+ });
328
+ ```
329
+
330
+ </details>
331
+
332
+ <br>
333
+
334
+ ### interceptEvent()
335
+ Usage: `interceptEvent(eventObject: EventTarget, eventName: string, predicate: () => boolean): void`
336
+
337
+ Intercepts all events dispatched on the `eventObject` and prevents the listeners from being called as long as the predicate function returns a truthy value.
338
+ Calling this function will set the `Error.stackTraceLimit` to 1000 (if it's not already higher) to ensure the stack trace is preserved.
339
+
340
+ ⚠️ 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.
341
+
342
+ <details><summary><b>Example - click to view</b></summary>
343
+
344
+ ```ts
345
+ interceptEvent(document.body, "click", () => {
346
+ return true; // prevent all click events on the body element
347
+ });
348
+ ```
349
+
350
+ </details>
351
+
352
+ <br>
353
+
354
+ ### interceptWindowEvent()
355
+ Usage: `interceptWindowEvent(eventName: string, predicate: () => boolean): void`
356
+
357
+ 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.
358
+ This is essentially the same as [`interceptEvent()`](#interceptevent), but automatically uses the `unsafeWindow` (or falls back to regular `window`).
359
+
360
+ ⚠️ 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.
361
+
362
+ <details><summary><b>Example - click to view</b></summary>
363
+
364
+ ```ts
365
+ interceptWindowEvent("beforeunload", () => {
366
+ return true; // prevent the pesky "Are you sure you want to leave this page?" popup
367
+ });
368
+ ```
369
+
370
+ </details>
371
+
372
+ <br><br>
373
+
374
+ ## Math:
375
+
376
+ ### clamp()
377
+ Usage: `clamp(num: number, min: number, max: number): number`
378
+
379
+ Clamps a number between a min and max value.
380
+
381
+ <details><summary><b>Example - click to view</b></summary>
382
+
383
+ ```ts
384
+ clamp(5, 0, 10); // 5
385
+ clamp(-1, 0, 10); // 0
386
+ clamp(7, 0, 10); // 7
387
+ clamp(Infinity, 0, 10); // 10
388
+ ```
389
+
390
+ </details>
391
+
392
+ <br>
393
+
394
+ ### mapRange()
395
+ Usage: `mapRange(value: number, range_1_min: number, range_1_max: number, range_2_min: number, range_2_max: number): number`
396
+
397
+ Maps a number from one range to the spot it would be in another range.
398
+
399
+ <details><summary><b>Example - click to view</b></summary>
400
+
401
+ ```ts
402
+ mapRange(5, 0, 10, 0, 100); // 50
403
+ mapRange(5, 0, 10, 0, 50); // 25
404
+ // to calculate a percentage from arbitrary values, use 0 and 100 as the second range:
405
+ mapRange(4, 0, 13, 0, 100); // 30.76923076923077
406
+ ```
407
+
408
+ </details>
409
+
410
+ <br>
411
+
412
+ ### randRange()
413
+ Usages:
414
+ ```ts
415
+ randRange(min: number, max: number): number
416
+ randRange(max: number): number
417
+ ```
418
+
419
+ Returns a random number between `min` and `max` (inclusive).
420
+ If only one argument is passed, it will be used as the `max` value and `min` will be set to 0.
421
+
422
+ <details><summary><b>Example - click to view</b></summary>
423
+
424
+ ```ts
425
+ randRange(0, 10); // 4
426
+ randRange(10, 20); // 17
427
+ randRange(10); // 7
428
+ ```
429
+
430
+ </details>
431
+
432
+ <br><br>
433
+
434
+ ## Misc:
435
+
436
+ ### autoPlural()
437
+ Usage: `autoPlural(str: string, num: number | Array | NodeList): string`
438
+
439
+ Automatically pluralizes a string if the given number is not 1.
440
+ If an array or NodeList is passed, the length of it will be used.
441
+
442
+ <details><summary><b>Example - click to view</b></summary>
443
+
444
+ ```ts
445
+ autoPlural("apple", 0); // "apples"
446
+ autoPlural("apple", 1); // "apple"
447
+ autoPlural("apple", 2); // "apples"
448
+
449
+ autoPlural("apple", [1]); // "apple"
450
+ autoPlural("apple", [1, 2]); // "apples"
451
+
452
+ const items = [1, 2, 3, 4, "foo", "bar"];
453
+ console.log(`Found ${items.length} ${autoPlural("item", items)}`); // "Found 6 items"
454
+ ```
455
+
456
+ </details>
457
+
458
+ <br>
459
+
460
+ ### pauseFor()
461
+ Usage: `pauseFor(ms: number): Promise<void>`
462
+
463
+ Pauses async execution for a given amount of time.
464
+
465
+ <details><summary><b>Example - click to view</b></summary>
466
+
467
+ ```ts
468
+ async function run() {
469
+ console.log("Hello");
470
+ await pauseFor(3000); // waits for 3 seconds
471
+ console.log("World");
472
+ }
473
+ ```
474
+
475
+ </details>
476
+
477
+ <br>
478
+
479
+ ### debounce()
480
+ Usage: `debounce(func: Function, timeout?: number): Function`
481
+
482
+ Debounces a function, meaning that it will only be called once after a given amount of time.
483
+ This is very useful for functions that are called repeatedly, like event listeners, to remove extraneous calls.
484
+ The timeout will default to 300ms if left undefined.
485
+
486
+ <details><summary><b>Example - click to view</b></summary>
487
+
488
+ ```ts
489
+ window.addEventListener("resize", debounce((event) => {
490
+ console.log("Window was resized:", event);
491
+ }, 500)); // 500ms timeout
492
+ ```
493
+
494
+ </details>
495
+
496
+ <br>
497
+
326
498
  ### fetchAdvanced()
327
499
  Usage:
328
500
  ```ts
@@ -340,6 +512,7 @@ The timeout will default to 10 seconds if left undefined.
340
512
  ```ts
341
513
  fetchAdvanced("https://api.example.org/data", {
342
514
  timeout: 5000,
515
+ // also accepts any other fetch options like headers:
343
516
  headers: {
344
517
  "Accept": "application/json",
345
518
  },
@@ -350,67 +523,82 @@ fetchAdvanced("https://api.example.org/data", {
350
523
 
351
524
  </details>
352
525
 
353
- <br>
526
+ <br><br>
354
527
 
355
- ### openInNewTab()
356
- Usage: `openInNewTab(url: string): void`
357
-
358
- Creates an invisible anchor with a `_blank` target and clicks it.
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.
360
- This function has to be run in relatively quick succession in response to a user interaction event, else the browser might reject it.
528
+ ## Arrays:
529
+
530
+ ### randomItem()
531
+ Usage: `randomItem(array: Array): any`
361
532
 
362
- ⚠️ This function needs to be run after the DOM has loaded (when using `@run-at document-end` or after `DOMContentLoaded` has fired).
533
+ Returns a random item from an array.
534
+ Returns undefined if the array is empty.
363
535
 
364
536
  <details><summary><b>Example - click to view</b></summary>
365
537
 
366
538
  ```ts
367
- document.querySelector("#button").addEventListener("click", () => {
368
- openInNewTab("https://example.org/");
369
- });
539
+ randomItem(["foo", "bar", "baz"]); // "bar"
540
+ randomItem([ ]); // undefined
370
541
  ```
371
542
 
372
543
  </details>
373
544
 
374
545
  <br>
375
546
 
376
- ### interceptEvent()
377
- Usage: `interceptEvent(eventObject: EventTarget, eventName: string, predicate: () => boolean): void`
547
+ ### randomItemIndex()
548
+ Usage: `randomItemIndex(array: Array): [item: any, index: number]`
378
549
 
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.
380
- Calling this function will set the `Error.stackTraceLimit` to 1000 to ensure the stack trace is preserved.
381
-
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.
550
+ Returns a tuple of a random item and its index from an array.
551
+ If the array is empty, it will return undefined for both values.
383
552
 
384
553
  <details><summary><b>Example - click to view</b></summary>
385
554
 
386
555
  ```ts
387
- interceptEvent(document.body, "click", () => {
388
- return true; // prevent all click events on the body
389
- });
556
+ randomItemIndex(["foo", "bar", "baz"]); // ["bar", 1]
557
+ randomItemIndex([ ]); // [undefined, undefined]
558
+ // using array destructuring:
559
+ const [item, index] = randomItemIndex(["foo", "bar", "baz"]);
560
+ // or if you only want the index:
561
+ const [, index] = randomItemIndex(["foo", "bar", "baz"]);
390
562
  ```
391
563
 
392
564
  </details>
393
565
 
394
566
  <br>
395
567
 
396
- ### interceptWindowEvent()
397
- Usage: `interceptWindowEvent(eventName: string, predicate: () => boolean): void`
568
+ ### takeRandomItem()
569
+ Usage: `takeRandomItem(array: Array): any`
398
570
 
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.
400
- This is essentially the same as [`interceptEvent()`](#interceptevent), but automatically uses the `unsafeWindow` (or falls back to regular `window`).
571
+ Returns a random item from an array and mutates the array by removing the item.
572
+ Returns undefined if the array is empty.
401
573
 
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.
574
+ <details><summary><b>Example - click to view</b></summary>
575
+
576
+ ```ts
577
+ const arr = ["foo", "bar", "baz"];
578
+ takeRandomItem(arr); // "bar"
579
+ console.log(arr); // ["foo", "baz"]
580
+ ```
581
+
582
+ </details>
583
+
584
+ <br>
585
+
586
+ ### randomizeArray()
587
+ Usage: `randomizeArray(array: Array): Array`
588
+
589
+ Returns a copy of the array with its items in a random order.
590
+ If the array is empty, the originally passed array will be returned.
403
591
 
404
592
  <details><summary><b>Example - click to view</b></summary>
405
593
 
406
594
  ```ts
407
- interceptWindowEvent("beforeunload", () => {
408
- return true; // prevent the pesky "Are you sure you want to leave this page?" popup
409
- });
595
+ randomizeArray([1, 2, 3, 4, 5, 6]); // [3, 1, 5, 2, 4, 6]
410
596
  ```
411
597
 
412
598
  </details>
413
599
 
600
+ <br>
601
+
414
602
 
415
603
  <br><br>
416
604
 
package/dist/index.d.mts CHANGED
@@ -1,46 +1,3 @@
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 */
22
- continuous?: boolean;
23
- };
24
- type FetchAdvancedOpts = RequestInit & Partial<{
25
- /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
26
- timeout: number;
27
- }>;
28
-
29
- /**
30
- * Automatically appends an `s` to the passed `word`, if `num` is not equal to 1
31
- * @param word A word in singular form, to auto-convert to plural
32
- * @param num If this is an array or NodeList, the amount of items is used
33
- */
34
- declare function autoPlural(word: string, num: number | unknown[] | NodeList): string;
35
- /** Ensures the passed `value` always stays between `min` and `max` */
36
- declare function clamp(value: number, min: number, max: number): number;
37
- /** Pauses async execution for the specified time in ms */
38
- declare function pauseFor(time: number): Promise<unknown>;
39
- /**
40
- * Calls the passed `func` after the specified `timeout` in ms.
41
- * Any subsequent calls to this function will reset the timer and discard previous calls.
42
- */
43
- declare function debounce<TFunc extends (...args: TArgs[]) => void, TArgs = any>(func: TFunc, timeout?: number): (...args: TArgs[]) => void;
44
1
  /**
45
2
  * Returns `unsafeWindow` if the `@grant unsafeWindow` is given, otherwise falls back to the regular `window`
46
3
  */
@@ -67,8 +24,6 @@ declare function addGlobalStyle(style: string): void;
67
24
  * @returns Returns an array of `PromiseSettledResult` - each resolved result will contain the loaded image element, while each rejected result will contain an `ErrorEvent`
68
25
  */
69
26
  declare function preloadImages(srcUrls: string[], rejects?: boolean): Promise<PromiseSettledResult<unknown>[]>;
70
- /** Calls the fetch API with special options like a timeout */
71
- declare function fetchAdvanced(url: string, options?: FetchAdvancedOpts): Promise<Response>;
72
27
  /**
73
28
  * Creates an invisible anchor with a `_blank` target and clicks it.
74
29
  * 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.
@@ -89,6 +44,62 @@ declare function interceptEvent<TEvtObj extends EventTarget>(eventObject: TEvtOb
89
44
  */
90
45
  declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate: () => boolean): void;
91
46
 
47
+ /** Ensures the passed `value` always stays between `min` and `max` */
48
+ declare function clamp(value: number, min: number, max: number): number;
49
+ /**
50
+ * Transforms the value parameter from the numerical range `range_1_min-range_1_max` to the numerical range `range_2_min-range_2_max`
51
+ * For example, you can map the value 2 in the range of 0-5 to the range of 0-10 and you'd get a 4 as a result.
52
+ */
53
+ declare function mapRange(value: number, range_1_min: number, range_1_max: number, range_2_min: number, range_2_max: number): number;
54
+ /** Returns a random number between `min` and `max` (inclusive) */
55
+ declare function randRange(min: number, max: number): number;
56
+ /** Returns a random number between 0 and `max` (inclusive) */
57
+ declare function randRange(max: number): number;
58
+
59
+ type InitOnSelectorOpts = {
60
+ /** 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) */
61
+ attributes?: boolean;
62
+ /** 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) */
63
+ characterData?: boolean;
64
+ };
65
+ type OnSelectorOpts<TElem extends Element = HTMLElement> = SelectorOptsOne<TElem> | SelectorOptsAll<TElem>;
66
+ type SelectorOptsOne<TElem extends Element> = SelectorOptsBase & {
67
+ /** Whether to use `querySelectorAll()` instead - default is false */
68
+ all?: false;
69
+ /** Gets called whenever the selector was found in the DOM */
70
+ listener: (element: TElem) => void;
71
+ };
72
+ type SelectorOptsAll<TElem extends Element> = SelectorOptsBase & {
73
+ /** Whether to use `querySelectorAll()` instead - default is false */
74
+ all: true;
75
+ /** Gets called whenever the selector was found in the DOM */
76
+ listener: (elements: NodeListOf<TElem>) => void;
77
+ };
78
+ type SelectorOptsBase = {
79
+ /** Whether to call the listener continuously instead of once - default is false */
80
+ continuous?: boolean;
81
+ };
82
+ type FetchAdvancedOpts = RequestInit & Partial<{
83
+ /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
84
+ timeout: number;
85
+ }>;
86
+
87
+ /**
88
+ * Automatically appends an `s` to the passed `word`, if `num` is not equal to 1
89
+ * @param word A word in singular form, to auto-convert to plural
90
+ * @param num If this is an array or NodeList, the amount of items is used
91
+ */
92
+ declare function autoPlural(word: string, num: number | unknown[] | NodeList): string;
93
+ /** Pauses async execution for the specified time in ms */
94
+ declare function pauseFor(time: number): Promise<unknown>;
95
+ /**
96
+ * Calls the passed `func` after the specified `timeout` in ms.
97
+ * Any subsequent calls to this function will reset the timer and discard previous calls.
98
+ */
99
+ declare function debounce<TFunc extends (...args: TArgs[]) => void, TArgs = any>(func: TFunc, timeout?: number): (...args: TArgs[]) => void;
100
+ /** Calls the fetch API with special options like a timeout */
101
+ declare function fetchAdvanced(url: string, options?: FetchAdvancedOpts): Promise<Response>;
102
+
92
103
  /**
93
104
  * Calls the `listener` as soon as the `selector` exists in the DOM.
94
105
  * Listeners are deleted when they are called once, unless `options.continuous` is set.
@@ -98,12 +109,17 @@ declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate
98
109
  * @template TElem The type of element that the listener will return as its argument (defaults to the generic HTMLElement)
99
110
  */
100
111
  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 */
112
+ /**
113
+ * Removes all listeners registered in `onSelector()` that have the given selector
114
+ * @returns Returns true when all listeners with the associated selector were found and removed, false otherwise
115
+ */
102
116
  declare function removeOnSelector(selector: string): boolean;
103
117
  /**
104
118
  * Initializes a MutationObserver that checks for all registered selectors whenever an element is added to or removed from the `<body>`
105
119
  * @param opts For fine-tuning when the MutationObserver checks for the selectors
106
120
  */
107
121
  declare function initOnSelector(opts?: InitOnSelectorOpts): void;
122
+ /** Returns all currently registered selectors, as a map of selector strings to their associated options */
123
+ declare function getSelectorMap(): Map<string, OnSelectorOpts[]>;
108
124
 
109
- export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, onSelector, openInNewTab, pauseFor, preloadImages, removeOnSelector };
125
+ export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getSelectorMap, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, mapRange, onSelector, openInNewTab, pauseFor, preloadImages, randRange, removeOnSelector };
package/dist/index.d.ts CHANGED
@@ -1,46 +1,3 @@
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 */
22
- continuous?: boolean;
23
- };
24
- type FetchAdvancedOpts = RequestInit & Partial<{
25
- /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
26
- timeout: number;
27
- }>;
28
-
29
- /**
30
- * Automatically appends an `s` to the passed `word`, if `num` is not equal to 1
31
- * @param word A word in singular form, to auto-convert to plural
32
- * @param num If this is an array or NodeList, the amount of items is used
33
- */
34
- declare function autoPlural(word: string, num: number | unknown[] | NodeList): string;
35
- /** Ensures the passed `value` always stays between `min` and `max` */
36
- declare function clamp(value: number, min: number, max: number): number;
37
- /** Pauses async execution for the specified time in ms */
38
- declare function pauseFor(time: number): Promise<unknown>;
39
- /**
40
- * Calls the passed `func` after the specified `timeout` in ms.
41
- * Any subsequent calls to this function will reset the timer and discard previous calls.
42
- */
43
- declare function debounce<TFunc extends (...args: TArgs[]) => void, TArgs = any>(func: TFunc, timeout?: number): (...args: TArgs[]) => void;
44
1
  /**
45
2
  * Returns `unsafeWindow` if the `@grant unsafeWindow` is given, otherwise falls back to the regular `window`
46
3
  */
@@ -67,8 +24,6 @@ declare function addGlobalStyle(style: string): void;
67
24
  * @returns Returns an array of `PromiseSettledResult` - each resolved result will contain the loaded image element, while each rejected result will contain an `ErrorEvent`
68
25
  */
69
26
  declare function preloadImages(srcUrls: string[], rejects?: boolean): Promise<PromiseSettledResult<unknown>[]>;
70
- /** Calls the fetch API with special options like a timeout */
71
- declare function fetchAdvanced(url: string, options?: FetchAdvancedOpts): Promise<Response>;
72
27
  /**
73
28
  * Creates an invisible anchor with a `_blank` target and clicks it.
74
29
  * 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.
@@ -89,6 +44,62 @@ declare function interceptEvent<TEvtObj extends EventTarget>(eventObject: TEvtOb
89
44
  */
90
45
  declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate: () => boolean): void;
91
46
 
47
+ /** Ensures the passed `value` always stays between `min` and `max` */
48
+ declare function clamp(value: number, min: number, max: number): number;
49
+ /**
50
+ * Transforms the value parameter from the numerical range `range_1_min-range_1_max` to the numerical range `range_2_min-range_2_max`
51
+ * For example, you can map the value 2 in the range of 0-5 to the range of 0-10 and you'd get a 4 as a result.
52
+ */
53
+ declare function mapRange(value: number, range_1_min: number, range_1_max: number, range_2_min: number, range_2_max: number): number;
54
+ /** Returns a random number between `min` and `max` (inclusive) */
55
+ declare function randRange(min: number, max: number): number;
56
+ /** Returns a random number between 0 and `max` (inclusive) */
57
+ declare function randRange(max: number): number;
58
+
59
+ type InitOnSelectorOpts = {
60
+ /** 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) */
61
+ attributes?: boolean;
62
+ /** 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) */
63
+ characterData?: boolean;
64
+ };
65
+ type OnSelectorOpts<TElem extends Element = HTMLElement> = SelectorOptsOne<TElem> | SelectorOptsAll<TElem>;
66
+ type SelectorOptsOne<TElem extends Element> = SelectorOptsBase & {
67
+ /** Whether to use `querySelectorAll()` instead - default is false */
68
+ all?: false;
69
+ /** Gets called whenever the selector was found in the DOM */
70
+ listener: (element: TElem) => void;
71
+ };
72
+ type SelectorOptsAll<TElem extends Element> = SelectorOptsBase & {
73
+ /** Whether to use `querySelectorAll()` instead - default is false */
74
+ all: true;
75
+ /** Gets called whenever the selector was found in the DOM */
76
+ listener: (elements: NodeListOf<TElem>) => void;
77
+ };
78
+ type SelectorOptsBase = {
79
+ /** Whether to call the listener continuously instead of once - default is false */
80
+ continuous?: boolean;
81
+ };
82
+ type FetchAdvancedOpts = RequestInit & Partial<{
83
+ /** Timeout in milliseconds after which the fetch call will be canceled with an AbortController signal */
84
+ timeout: number;
85
+ }>;
86
+
87
+ /**
88
+ * Automatically appends an `s` to the passed `word`, if `num` is not equal to 1
89
+ * @param word A word in singular form, to auto-convert to plural
90
+ * @param num If this is an array or NodeList, the amount of items is used
91
+ */
92
+ declare function autoPlural(word: string, num: number | unknown[] | NodeList): string;
93
+ /** Pauses async execution for the specified time in ms */
94
+ declare function pauseFor(time: number): Promise<unknown>;
95
+ /**
96
+ * Calls the passed `func` after the specified `timeout` in ms.
97
+ * Any subsequent calls to this function will reset the timer and discard previous calls.
98
+ */
99
+ declare function debounce<TFunc extends (...args: TArgs[]) => void, TArgs = any>(func: TFunc, timeout?: number): (...args: TArgs[]) => void;
100
+ /** Calls the fetch API with special options like a timeout */
101
+ declare function fetchAdvanced(url: string, options?: FetchAdvancedOpts): Promise<Response>;
102
+
92
103
  /**
93
104
  * Calls the `listener` as soon as the `selector` exists in the DOM.
94
105
  * Listeners are deleted when they are called once, unless `options.continuous` is set.
@@ -98,12 +109,17 @@ declare function interceptWindowEvent(eventName: keyof WindowEventMap, predicate
98
109
  * @template TElem The type of element that the listener will return as its argument (defaults to the generic HTMLElement)
99
110
  */
100
111
  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 */
112
+ /**
113
+ * Removes all listeners registered in `onSelector()` that have the given selector
114
+ * @returns Returns true when all listeners with the associated selector were found and removed, false otherwise
115
+ */
102
116
  declare function removeOnSelector(selector: string): boolean;
103
117
  /**
104
118
  * Initializes a MutationObserver that checks for all registered selectors whenever an element is added to or removed from the `<body>`
105
119
  * @param opts For fine-tuning when the MutationObserver checks for the selectors
106
120
  */
107
121
  declare function initOnSelector(opts?: InitOnSelectorOpts): void;
122
+ /** Returns all currently registered selectors, as a map of selector strings to their associated options */
123
+ declare function getSelectorMap(): Map<string, OnSelectorOpts[]>;
108
124
 
109
- export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, onSelector, openInNewTab, pauseFor, preloadImages, removeOnSelector };
125
+ export { FetchAdvancedOpts, InitOnSelectorOpts, OnSelectorOpts, addGlobalStyle, addParent, autoPlural, clamp, debounce, fetchAdvanced, getSelectorMap, getUnsafeWindow, initOnSelector, insertAfter, interceptEvent, interceptWindowEvent, mapRange, onSelector, openInNewTab, pauseFor, preloadImages, randRange, removeOnSelector };
package/dist/index.js CHANGED
@@ -1,20 +1,23 @@
1
1
  'use strict';
2
2
 
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}));}
3
+ var x=Object.defineProperty,y=Object.defineProperties;var T=Object.getOwnPropertyDescriptors;var d=Object.getOwnPropertySymbols;var h=Object.prototype.hasOwnProperty,v=Object.prototype.propertyIsEnumerable;var f=(t,e,n)=>e in t?x(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,m=(t,e)=>{for(var n in e||(e={}))h.call(e,n)&&f(t,n,e[n]);if(d)for(var n of d(e))v.call(e,n)&&f(t,n,e[n]);return t},l=(t,e)=>y(t,T(e));var b=(t,e,n)=>new Promise((r,o)=>{var i=u=>{try{a(n.next(u));}catch(p){o(p);}},s=u=>{try{a(n.throw(u));}catch(p){o(p);}},a=u=>u.done?r(u.value):Promise.resolve(u.value).then(i,s);a((n=n.apply(t,e)).next());});function O(){try{return unsafeWindow}catch(t){return window}}function L(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function M(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 S(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function N(t,e=!1){let n=t.map(r=>new Promise((o,i)=>{let s=new Image;s.src=r,s.addEventListener("load",()=>o(s)),s.addEventListener("error",a=>e&&i(a));}));return Promise.allSettled(n)}function A(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 w(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 k(t,e){return w(O(),t,e)}function P(t,e,n){return Math.max(Math.min(t,n),e)}function I(t,e,n,r,o){return Number(e)===0&&Number(r)===0?t*(o/n):(t-e)*((o-r)/(n-e))+r}function j(...t){let e,n;if(typeof t[0]=="number"&&typeof t[1]=="number")[e,n]=t;else if(typeof t[0]=="number"&&typeof t[1]!="number")e=0,n=t[0];else throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof t[0]}" and "${typeof t[1]}"`);if(e=Number(e),n=Number(n),isNaN(e)||isNaN(n))throw new TypeError(`Parameters "min" and "max" can't be NaN`);if(e>n)throw new TypeError(`Parameter "min" can't be bigger than "max"`);return Math.floor(Math.random()*(n-e+1))+e}function F(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function W(t){return new Promise(e=>{setTimeout(e,t);})}function $(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function R(n){return b(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,o=new AbortController,i=setTimeout(()=>o.abort(),r),s=yield fetch(t,l(m({},e),{signal:o.signal}));return clearTimeout(i),s})}var c=new Map;function G(t,e){let n=[];c.has(t)&&(n=c.get(t)),n.push(e),c.set(t,n),E(t,n);}function U(t){return c.delete(t)}function E(t,e){let n=[];if(e.forEach((r,o)=>{try{let i=r.all?document.querySelectorAll(t):document.querySelector(t);i&&(r.listener(i),r.continuous||n.push(o));}catch(i){console.error(`Couldn't call listener for selector '${t}'`,i);}}),n.length>0){let r=e.filter((o,i)=>!n.includes(i));r.length===0?c.delete(t):c.set(t,r);}}function z(t={}){new MutationObserver(()=>{for(let[n,r]of c.entries())E(n,r);}).observe(document.body,l(m({},t),{childList:!0}));}function D(){return c}
4
4
 
5
- exports.addGlobalStyle = H;
6
- exports.addParent = k;
7
- exports.autoPlural = w;
8
- exports.clamp = M;
9
- exports.debounce = A;
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;
17
- exports.openInNewTab = N;
18
- exports.pauseFor = S;
19
- exports.preloadImages = I;
20
- exports.removeOnSelector = q;
5
+ exports.addGlobalStyle = S;
6
+ exports.addParent = M;
7
+ exports.autoPlural = F;
8
+ exports.clamp = P;
9
+ exports.debounce = $;
10
+ exports.fetchAdvanced = R;
11
+ exports.getSelectorMap = D;
12
+ exports.getUnsafeWindow = O;
13
+ exports.initOnSelector = z;
14
+ exports.insertAfter = L;
15
+ exports.interceptEvent = w;
16
+ exports.interceptWindowEvent = k;
17
+ exports.mapRange = I;
18
+ exports.onSelector = G;
19
+ exports.openInNewTab = A;
20
+ exports.pauseFor = W;
21
+ exports.preloadImages = N;
22
+ exports.randRange = j;
23
+ exports.removeOnSelector = U;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
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}));}
1
+ var x=Object.defineProperty,y=Object.defineProperties;var T=Object.getOwnPropertyDescriptors;var d=Object.getOwnPropertySymbols;var h=Object.prototype.hasOwnProperty,v=Object.prototype.propertyIsEnumerable;var f=(t,e,n)=>e in t?x(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,m=(t,e)=>{for(var n in e||(e={}))h.call(e,n)&&f(t,n,e[n]);if(d)for(var n of d(e))v.call(e,n)&&f(t,n,e[n]);return t},l=(t,e)=>y(t,T(e));var b=(t,e,n)=>new Promise((r,o)=>{var i=u=>{try{a(n.next(u));}catch(p){o(p);}},s=u=>{try{a(n.throw(u));}catch(p){o(p);}},a=u=>u.done?r(u.value):Promise.resolve(u.value).then(i,s);a((n=n.apply(t,e)).next());});function O(){try{return unsafeWindow}catch(t){return window}}function L(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function M(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 S(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function N(t,e=!1){let n=t.map(r=>new Promise((o,i)=>{let s=new Image;s.src=r,s.addEventListener("load",()=>o(s)),s.addEventListener("error",a=>e&&i(a));}));return Promise.allSettled(n)}function A(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 w(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 k(t,e){return w(O(),t,e)}function P(t,e,n){return Math.max(Math.min(t,n),e)}function I(t,e,n,r,o){return Number(e)===0&&Number(r)===0?t*(o/n):(t-e)*((o-r)/(n-e))+r}function j(...t){let e,n;if(typeof t[0]=="number"&&typeof t[1]=="number")[e,n]=t;else if(typeof t[0]=="number"&&typeof t[1]!="number")e=0,n=t[0];else throw new TypeError(`Wrong parameter(s) provided - expected: "number" and "number|undefined", got: "${typeof t[0]}" and "${typeof t[1]}"`);if(e=Number(e),n=Number(n),isNaN(e)||isNaN(n))throw new TypeError(`Parameters "min" and "max" can't be NaN`);if(e>n)throw new TypeError(`Parameter "min" can't be bigger than "max"`);return Math.floor(Math.random()*(n-e+1))+e}function F(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function W(t){return new Promise(e=>{setTimeout(e,t);})}function $(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function R(n){return b(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,o=new AbortController,i=setTimeout(()=>o.abort(),r),s=yield fetch(t,l(m({},e),{signal:o.signal}));return clearTimeout(i),s})}var c=new Map;function G(t,e){let n=[];c.has(t)&&(n=c.get(t)),n.push(e),c.set(t,n),E(t,n);}function U(t){return c.delete(t)}function E(t,e){let n=[];if(e.forEach((r,o)=>{try{let i=r.all?document.querySelectorAll(t):document.querySelector(t);i&&(r.listener(i),r.continuous||n.push(o));}catch(i){console.error(`Couldn't call listener for selector '${t}'`,i);}}),n.length>0){let r=e.filter((o,i)=>!n.includes(i));r.length===0?c.delete(t):c.set(t,r);}}function z(t={}){new MutationObserver(()=>{for(let[n,r]of c.entries())E(n,r);}).observe(document.body,l(m({},t),{childList:!0}));}function D(){return c}
2
2
 
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 };
3
+ export { S as addGlobalStyle, M as addParent, F as autoPlural, P as clamp, $ as debounce, R as fetchAdvanced, D as getSelectorMap, O as getUnsafeWindow, z as initOnSelector, L as insertAfter, w as interceptEvent, k as interceptWindowEvent, I as mapRange, G as onSelector, A as openInNewTab, W as pauseFor, N as preloadImages, j as randRange, U as removeOnSelector };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sv443-network/userutils",
3
- "version": "0.2.0",
3
+ "version": "0.4.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",