@sv443-network/userutils 1.0.0 → 1.1.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,15 @@
1
1
  # @sv443-network/userutils
2
2
 
3
+ ## 1.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - db5cded: Added `isScrollable()` to check whether an element has a horizontal or vertical scroll bar
8
+
9
+ ### Patch Changes
10
+
11
+ - 9e26464: Replaced most occurrences of `HTMLElement` in the docs with `Element` for better compatibility
12
+
3
13
  ## 1.0.0
4
14
 
5
15
  ### Major Changes
package/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  ## UserUtils
4
4
  Zero-dependency library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, manage persistent user configurations, modify the DOM more easily and more.
5
+
5
6
  Contains builtin TypeScript declarations. Webpack compatible and supports ESM and CJS.
6
7
  If you like using this library, please consider [supporting the development ❤️](https://github.com/sponsors/Sv443)
7
8
 
@@ -26,6 +27,7 @@ If you like using this library, please consider [supporting the development ❤
26
27
  - [interceptEvent()](#interceptevent) - conditionally intercepts events registered by `addEventListener()` on any given EventTarget object
27
28
  - [interceptWindowEvent()](#interceptwindowevent) - conditionally intercepts events registered by `addEventListener()` on the window object
28
29
  - [amplifyMedia()](#amplifymedia) - amplify an audio or video element's volume past the maximum of 100%
30
+ - [isScrollable()](#isscrollable) - check if an element has a horizontal or vertical scroll bar
29
31
  - [Math:](#math)
30
32
  - [clamp()](#clamp) - constrain a number between a min and max value
31
33
  - [mapRange()](#maprange) - map a number from one range to the same spot in another range
@@ -80,14 +82,13 @@ If you like using this library, please consider [supporting the development ❤
80
82
 
81
83
  ## Preamble:
82
84
  This library is written in TypeScript and contains builtin TypeScript declarations.
83
- The usages and examples in this readme are written in TypeScript, but the library can also be used in plain JavaScript.
84
-
85
- Some features require the `@run-at` or `@grant` directives to be tweaked in the userscript header or have other requirements.
86
- Their documentation will contain a section marked by a warning emoji (⚠️) that will go into more detail.
87
85
 
88
86
  Each feature has example code that can be expanded by clicking on the text "Example - click to view".
87
+ The usages and examples are written in TypeScript, but the library can also be used in plain JavaScript after removing the type annotations (and changing the imports if you are using CommonJS).
88
+ If the usage section contains multiple definitions of the function, each occurrence represents an overload and you can choose which one you want to use.
89
89
 
90
- If the usage section contains multiple definitions of the function, each occurrence represents an overload and you can choose which one you want to use.
90
+ Some features require the `@run-at` or `@grant` directives to be tweaked in the userscript header or have other requirements.
91
+ Their documentation will contain a section marked by a warning emoji (⚠️) that will go into more detail.
91
92
 
92
93
  <br><br>
93
94
 
@@ -123,6 +124,7 @@ If set to `false` (default), querySelector() will be used and only the first mat
123
124
  If `continuous` is set to `true`, the listener will not be deregistered after it was called once (defaults to false).
124
125
 
125
126
  When using TypeScript, the generic `TElement` can be used to specify the type of the element(s) that the listener will return.
127
+ It will default to `HTMLElement` if left undefined.
126
128
 
127
129
  ⚠️ In order to use this function, [`initOnSelector()`](#initonselector) has to be called as soon as possible.
128
130
  This initialization function has to be called after `DOMContentLoaded` is fired (or immediately if `@run-at document-end` is set).
@@ -132,6 +134,8 @@ Calling onSelector() before `DOMContentLoaded` is fired will not throw an error,
132
134
  <details><summary><h4>Example - click to view</h4></summary>
133
135
 
134
136
  ```ts
137
+ import { initOnSelector, onSelector } from "@sv443-network/userutils";
138
+
135
139
  document.addEventListener("DOMContentLoaded", initOnSelector);
136
140
 
137
141
  // Continuously checks if `div` elements are added to the DOM, then returns all of them (even previously detected ones) in a NodeList
@@ -177,6 +181,8 @@ You may see all options [here](https://developer.mozilla.org/en-US/docs/Web/API/
177
181
  <details><summary><h4>Example - click to view</h4></summary>
178
182
 
179
183
  ```ts
184
+ import { initOnSelector } from "@sv443-network/userutils";
185
+
180
186
  document.addEventListener("DOMContentLoaded", () => {
181
187
  initOnSelector({
182
188
  attributes: true,
@@ -201,6 +207,8 @@ Since multiple listeners can be registered for the same selector, the value of t
201
207
  <details><summary><h4>Example - click to view</h4></summary>
202
208
 
203
209
  ```ts
210
+ import { initOnSelector, onSelector, getSelectorMap } from "@sv443-network/userutils";
211
+
204
212
  document.addEventListener("DOMContentLoaded", initOnSelector);
205
213
 
206
214
  onSelector<HTMLDivElement>("div", {
@@ -244,6 +252,8 @@ Userscripts are sandboxed and do not have access to the regular window object, s
244
252
  <details><summary><h4>Example - click to view</h4></summary>
245
253
 
246
254
  ```ts
255
+ import { getUnsafeWindow } from "@sv443-network/userutils";
256
+
247
257
  // trick the site into thinking the mouse was moved:
248
258
  const mouseEvent = new MouseEvent("mousemove", {
249
259
  view: getUnsafeWindow(),
@@ -252,6 +262,7 @@ const mouseEvent = new MouseEvent("mousemove", {
252
262
  movementX: 10,
253
263
  movementY: 0,
254
264
  });
265
+
255
266
  document.body.dispatchEvent(mouseEvent);
256
267
  ```
257
268
 
@@ -262,7 +273,7 @@ document.body.dispatchEvent(mouseEvent);
262
273
  ### insertAfter()
263
274
  Usage:
264
275
  ```ts
265
- insertAfter(beforeElement: HTMLElement, afterElement: HTMLElement): HTMLElement
276
+ insertAfter(beforeElement: Element, afterElement: Element): Element
266
277
  ```
267
278
 
268
279
  Inserts the element passed as `afterElement` as a sibling after the passed `beforeElement`.
@@ -273,10 +284,13 @@ The passed `afterElement` will be returned.
273
284
  <details><summary><h4>Example - click to view</h4></summary>
274
285
 
275
286
  ```ts
287
+ import { insertAfter } from "@sv443-network/userutils";
288
+
276
289
  // insert a <div> as a sibling next to an element
277
290
  const beforeElement = document.querySelector("#before");
278
291
  const afterElement = document.createElement("div");
279
292
  afterElement.innerText = "After";
293
+
280
294
  insertAfter(beforeElement, afterElement);
281
295
  ```
282
296
 
@@ -287,7 +301,7 @@ insertAfter(beforeElement, afterElement);
287
301
  ### addParent()
288
302
  Usage:
289
303
  ```ts
290
- addParent(element: HTMLElement, newParent: HTMLElement): HTMLElement
304
+ addParent(element: Element, newParent: Element): Element
291
305
  ```
292
306
 
293
307
  Adds a parent element around the passed `element` and returns the new parent.
@@ -298,10 +312,13 @@ Previously registered event listeners are kept intact.
298
312
  <details><summary><h4>Example - click to view</h4></summary>
299
313
 
300
314
  ```ts
315
+ import { addParent } from "@sv443-network/userutils";
316
+
301
317
  // add an <a> around an element
302
318
  const element = document.querySelector("#element");
303
319
  const newParent = document.createElement("a");
304
320
  newParent.href = "https://example.org/";
321
+
305
322
  addParent(element, newParent);
306
323
  ```
307
324
 
@@ -321,6 +338,8 @@ Adds a global style to the page in form of a `<style>` element that's inserted i
321
338
  <details><summary><h4>Example - click to view</h4></summary>
322
339
 
323
340
  ```ts
341
+ import { addGlobalStyle } from "@sv443-network/userutils";
342
+
324
343
  document.addEventListener("DOMContentLoaded", () => {
325
344
  addGlobalStyle(`
326
345
  body {
@@ -347,6 +366,8 @@ The resulting PromiseSettledResult array will contain the image elements if reso
347
366
  <details><summary><h4>Example - click to view</h4></summary>
348
367
 
349
368
  ```ts
369
+ import { preloadImages } from "@sv443-network/userutils";
370
+
350
371
  preloadImages([
351
372
  "https://example.org/image1.png",
352
373
  "https://example.org/image2.png",
@@ -376,6 +397,8 @@ This function has to be run in response to a user interaction event, else the br
376
397
  <details><summary><h4>Example - click to view</h4></summary>
377
398
 
378
399
  ```ts
400
+ import { openInNewTab } from "@sv443-network/userutils";
401
+
379
402
  document.querySelector("#my-button").addEventListener("click", () => {
380
403
  openInNewTab("https://example.org/");
381
404
  });
@@ -391,7 +414,7 @@ Usage:
391
414
  interceptEvent(
392
415
  eventObject: EventTarget,
393
416
  eventName: string,
394
- predicate: () => boolean
417
+ predicate: (event: Event) => boolean
395
418
  ): void
396
419
  ```
397
420
 
@@ -403,7 +426,10 @@ Calling this function will set the `Error.stackTraceLimit` to 1000 (if it's not
403
426
  <details><summary><h4>Example - click to view</h4></summary>
404
427
 
405
428
  ```ts
406
- interceptEvent(document.body, "click", () => {
429
+ import { interceptEvent } from "@sv443-network/userutils";
430
+
431
+ interceptEvent(document.body, "click", (event) => {
432
+ console.log("Intercepting click event:", event);
407
433
  return true; // prevent all click events on the body element
408
434
  });
409
435
  ```
@@ -417,7 +443,7 @@ Usage:
417
443
  ```ts
418
444
  interceptWindowEvent(
419
445
  eventName: string,
420
- predicate: () => boolean
446
+ predicate: (event: Event) => boolean
421
447
  ): void
422
448
  ```
423
449
 
@@ -425,11 +451,14 @@ Intercepts all events dispatched on the `window` object and prevents the listene
425
451
  This is essentially the same as [`interceptEvent()`](#interceptevent), but automatically uses the `unsafeWindow` (or falls back to regular `window`).
426
452
 
427
453
  ⚠️ 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.
454
+ ⚠️ In order for all events to be interceptable, the directive `@grant unsafeWindow` should be set.
428
455
 
429
456
  <details><summary><h4>Example - click to view</h4></summary>
430
457
 
431
458
  ```ts
432
- interceptWindowEvent("beforeunload", () => {
459
+ import { interceptWindowEvent } from "@sv443-network/userutils";
460
+
461
+ interceptWindowEvent("beforeunload", (event) => {
433
462
  return true; // prevent the pesky "Are you sure you want to leave this page?" popup
434
463
  });
435
464
  ```
@@ -463,6 +492,8 @@ The returned AmplifyMediaResult object has the following properties:
463
492
  <details><summary><h4>Example - click to view</h4></summary>
464
493
 
465
494
  ```ts
495
+ import { amplifyMedia } from "@sv443-network/userutils";
496
+
466
497
  const audio = document.querySelector<HTMLAudioElement>("audio");
467
498
  const button = document.querySelector<HTMLButtonElement>("button");
468
499
 
@@ -485,6 +516,31 @@ button.addEventListener("click", () => {
485
516
 
486
517
  </details>
487
518
 
519
+ <br>
520
+
521
+ ### isScrollable()
522
+ Usage:
523
+ ```ts
524
+ isScrollable(element: Element): { horizontal: boolean, vertical: boolean }
525
+ ```
526
+
527
+ Checks if an element has a horizontal or vertical scroll bar.
528
+ This uses the computed style of the element, so it will also work if the element is hidden.
529
+
530
+ <details><summary><h4>Example - click to view</h4></summary>
531
+
532
+ ```ts
533
+ import { isScrollable } from "@sv443-network/userutils";
534
+
535
+ const element = document.querySelector("#element");
536
+ const { horizontal, vertical } = isScrollable(element);
537
+
538
+ console.log("Element has a horizontal scroll bar:", horizontal);
539
+ console.log("Element has a vertical scroll bar:", vertical);
540
+ ```
541
+
542
+ </details>
543
+
488
544
  <br><br>
489
545
 
490
546
  ## Math:
@@ -500,6 +556,8 @@ Clamps a number between a min and max boundary (inclusive).
500
556
  <details><summary><h4>Example - click to view</h4></summary>
501
557
 
502
558
  ```ts
559
+ import { clamp } from "@sv443-network/userutils";
560
+
503
561
  clamp(7, 0, 10); // 7
504
562
  clamp(-1, 0, 10); // 0
505
563
  clamp(5, -5, 0); // 0
@@ -531,6 +589,8 @@ Maps a number from one range to the spot it would be in another range.
531
589
  <details><summary><h4>Example - click to view</h4></summary>
532
590
 
533
591
  ```ts
592
+ import { mapRange } from "@sv443-network/userutils";
593
+
534
594
  mapRange(5, 0, 10, 0, 100); // 50
535
595
  mapRange(5, 0, 10, 0, 50); // 25
536
596
 
@@ -556,6 +616,8 @@ If only one argument is passed, it will be used as the `max` value and `min` wil
556
616
  <details><summary><h4>Example - click to view</h4></summary>
557
617
 
558
618
  ```ts
619
+ import { randRange } from "@sv443-network/userutils";
620
+
559
621
  randRange(0, 10); // 4
560
622
  randRange(10, 20); // 17
561
623
  randRange(10); // 7
@@ -609,6 +671,7 @@ Writes the default configuration given in `options.defaultConfig` synchronously
609
671
  Fully deletes the configuration from persistent storage.
610
672
  The internal cache will be left untouched, so any subsequent calls to `getData()` will return the data that was last loaded.
611
673
  If `loadData()` or `setData()` are called after this, the persistent storage will be populated again.
674
+ If you want to use this method, the additional directive `@grant GM.deleteValue` is required.
612
675
 
613
676
  <br>
614
677
 
@@ -708,6 +771,8 @@ If an array or NodeList is passed, the amount of contained items will be used.
708
771
  <details><summary><h4>Example - click to view</h4></summary>
709
772
 
710
773
  ```ts
774
+ import { autoPlural } from "@sv443-network/userutils";
775
+
711
776
  autoPlural("apple", 0); // "apples"
712
777
  autoPlural("apple", 1); // "apple"
713
778
  autoPlural("apple", 2); // "apples"
@@ -734,6 +799,8 @@ Pauses async execution for a given amount of time.
734
799
  <details><summary><h4>Example - click to view</h4></summary>
735
800
 
736
801
  ```ts
802
+ import { pauseFor } from "@sv443-network/userutils";
803
+
737
804
  async function run() {
738
805
  console.log("Hello");
739
806
  await pauseFor(3000); // waits for 3 seconds
@@ -759,6 +826,8 @@ The timeout will default to 300ms if left undefined.
759
826
  <details><summary><h4>Example - click to view</h4></summary>
760
827
 
761
828
  ```ts
829
+ import { debounce } from "@sv443-network/userutils";
830
+
762
831
  window.addEventListener("resize", debounce((event) => {
763
832
  console.log("Window was resized:", event);
764
833
  }, 500)); // 500ms timeout
@@ -783,7 +852,9 @@ The timeout will default to 10 seconds if left undefined.
783
852
  <details><summary><h4>Example - click to view</h4></summary>
784
853
 
785
854
  ```ts
786
- fetchAdvanced("https://api.example.org/data", {
855
+ import { fetchAdvanced } from "@sv443-network/userutils";
856
+
857
+ fetchAdvanced("https://jokeapi.dev/joke/Any?safe-mode", {
787
858
  timeout: 5000,
788
859
  // also accepts any other fetch options like headers:
789
860
  headers: {
@@ -812,6 +883,8 @@ Returns undefined if the array is empty.
812
883
  <details><summary><h4>Example - click to view</h4></summary>
813
884
 
814
885
  ```ts
886
+ import { randomItem } from "@sv443-network/userutils";
887
+
815
888
  randomItem(["foo", "bar", "baz"]); // "bar"
816
889
  randomItem([ ]); // undefined
817
890
  ```
@@ -832,12 +905,15 @@ If the array is empty, it will return undefined for both values.
832
905
  <details><summary><h4>Example - click to view</h4></summary>
833
906
 
834
907
  ```ts
908
+ import { randomItemIndex } from "@sv443-network/userutils";
909
+
835
910
  randomItemIndex(["foo", "bar", "baz"]); // ["bar", 1]
836
911
  randomItemIndex([ ]); // [undefined, undefined]
912
+
837
913
  // using array destructuring:
838
- const [item, index] = randomItemIndex(["foo", "bar", "baz"]);
914
+ const [item, index] = randomItemIndex(["foo", "bar", "baz"]); // ["bar", 1]
839
915
  // or if you only want the index:
840
- const [, index] = randomItemIndex(["foo", "bar", "baz"]);
916
+ const [, index] = randomItemIndex(["foo", "bar", "baz"]); // 1
841
917
  ```
842
918
 
843
919
  </details>
@@ -856,6 +932,8 @@ Returns undefined if the array is empty.
856
932
  <details><summary><h4>Example - click to view</h4></summary>
857
933
 
858
934
  ```ts
935
+ import { takeRandomItem } from "@sv443-network/userutils";
936
+
859
937
  const arr = ["foo", "bar", "baz"];
860
938
  takeRandomItem(arr); // "bar"
861
939
  console.log(arr); // ["foo", "baz"]
@@ -877,7 +955,14 @@ If the array is empty, the originally passed empty array will be returned withou
877
955
  <details><summary><h4>Example - click to view</h4></summary>
878
956
 
879
957
  ```ts
880
- randomizeArray([1, 2, 3, 4, 5, 6]); // [3, 1, 5, 2, 4, 6]
958
+ import { randomizeArray } from "@sv443-network/userutils";
959
+
960
+ const foo = [1, 2, 3, 4, 5, 6];
961
+
962
+ console.log(randomizeArray(foo)); // [3, 1, 5, 2, 4, 6]
963
+ console.log(randomizeArray(foo)); // [4, 5, 2, 1, 6, 3]
964
+
965
+ console.log(foo); // [1, 2, 3, 4, 5, 6] - original array is not mutated
881
966
  ```
882
967
 
883
968
  </details>
package/dist/index.js CHANGED
@@ -1,29 +1,30 @@
1
1
  'use strict';
2
2
 
3
- var v=Object.defineProperty,x=Object.defineProperties;var w=Object.getOwnPropertyDescriptors;var h=Object.getOwnPropertySymbols;var M=Object.prototype.hasOwnProperty,O=Object.prototype.propertyIsEnumerable;var p=(t,e,n)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,f=(t,e)=>{for(var n in e||(e={}))M.call(e,n)&&p(t,n,e[n]);if(h)for(var n of h(e))O.call(e,n)&&p(t,n,e[n]);return t},b=(t,e)=>x(t,w(e));var m=(t,e,n)=>(p(t,typeof e!="symbol"?e+"":e,n),n);var l=(t,e,n)=>new Promise((r,i)=>{var o=s=>{try{u(n.next(s));}catch(c){i(c);}},a=s=>{try{u(n.throw(s));}catch(c){i(c);}},u=s=>s.done?r(s.value):Promise.resolve(s.value).then(o,a);u((n=n.apply(t,e)).next());});function D(t,e,n){return Math.max(Math.min(t,n),e)}function L(t,e,n,r,i){return Number(e)===0&&Number(r)===0?t*(i/n):(t-e)*((i-r)/(n-e))+r}function g(...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 V(t){return T(t)[0]}function T(t){if(t.length===0)return [void 0,void 0];let e=g(t.length-1);return [t[e],e]}function $(t){let[e,n]=T(t);if(n!==void 0)return t.splice(n,1),e}function k(t){let e=[...t];if(t.length===0)return t;for(let n=e.length-1;n>0;n--){let r=Math.floor(g(0,1e4)/1e4*(n+1));[e[n],e[r]]=[e[r],e[n]];}return e}var y=class{constructor(e){m(this,"id");m(this,"formatVersion");m(this,"defaultConfig");m(this,"cachedConfig");m(this,"migrations");this.id=e.id,this.formatVersion=e.formatVersion,this.defaultConfig=e.defaultConfig,this.cachedConfig=e.defaultConfig,this.migrations=e.migrations;}loadData(){return l(this,null,function*(){try{let e=yield GM.getValue(`_uucfg-${this.id}`,this.defaultConfig),n=Number(yield GM.getValue(`_uucfgver-${this.id}`));if(typeof e!="string")return yield this.saveDefaultData(),this.defaultConfig;isNaN(n)&&(yield GM.setValue(`_uucfgver-${this.id}`,n=this.formatVersion));let r=JSON.parse(e);return n<this.formatVersion&&this.migrations&&(r=yield this.runMigrations(r,n)),this.cachedConfig=typeof r=="object"?r:void 0}catch(e){return yield this.saveDefaultData(),this.defaultConfig}})}getData(){return this.deepCopy(this.cachedConfig)}setData(e){return this.cachedConfig=e,new Promise(n=>l(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(e)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),n();}))}saveDefaultData(){return l(this,null,function*(){return this.cachedConfig=this.defaultConfig,new Promise(e=>l(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(this.defaultConfig)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),e();}))})}deleteConfig(){return l(this,null,function*(){yield Promise.allSettled([GM.deleteValue(`_uucfg-${this.id}`),GM.deleteValue(`_uucfgver-${this.id}`)]);})}runMigrations(e,n){return l(this,null,function*(){if(!this.migrations)return e;let r=e,i=Object.entries(this.migrations).sort(([a],[u])=>Number(a)-Number(u)),o=n;for(let[a,u]of i){let s=Number(a);if(n<this.formatVersion&&n<s)try{let c=u(r);r=c instanceof Promise?yield c:c,o=n=s;}catch(c){console.error(`Error while running migration function for format version ${a}:`,c);}}return yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(r)),GM.setValue(`_uucfgver-${this.id}`,o)]),r})}deepCopy(e){return JSON.parse(JSON.stringify(e))}};function S(){try{return unsafeWindow}catch(t){return window}}function R(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function _(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 j(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function F(t,e=!1){let n=t.map(r=>new Promise((i,o)=>{let a=new Image;a.src=r,a.addEventListener("load",()=>i(a)),a.addEventListener("error",u=>e&&o(u));}));return Promise.allSettled(n)}function J(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 N(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){t.__proto__.addEventListener=function(...i){var a,u;let o=typeof i[1]=="function"?i[1]:(u=(a=i[1])==null?void 0:a.handleEvent)!=null?u:()=>{};i[1]=function(...s){if(!(i[0]===e&&n(Array.isArray(s)?s[0]:s)))return o.apply(this,s)},r.apply(this,i);};}(t.__proto__.addEventListener);}function W(t,e){return N(S(),t,e)}function B(t,e=1){let n=new(window.AudioContext||window.webkitAudioContext),r={mediaElement:t,amplify:i=>{r.gain.gain.value=i;},getAmpLevel:()=>r.gain.gain.value,context:n,source:n.createMediaElementSource(t),gain:n.createGain()};return r.source.connect(r.gain),r.gain.connect(n.destination),r.amplify(e),r}function K(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function z(t){return new Promise(e=>{setTimeout(()=>e(),t);})}function U(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function Q(n){return l(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,i=new AbortController,o=setTimeout(()=>i.abort(),r),a=yield fetch(t,b(f({},e),{signal:i.signal}));return clearTimeout(o),a})}var d=new Map;function Z(t,e){let n=[];d.has(t)&&(n=d.get(t)),n.push(e),d.set(t,n),E(t,n);}function ee(t){return d.delete(t)}function E(t,e){let n=[];if(e.forEach((r,i)=>{try{let o=r.all?document.querySelectorAll(t):document.querySelector(t);(o!==null&&o instanceof NodeList&&o.length>0||o!==null)&&(r.listener(o),r.continuous||n.push(i));}catch(o){console.error(`Couldn't call listener for selector '${t}'`,o);}}),n.length>0){let r=e.filter((i,o)=>!n.includes(o));r.length===0?d.delete(t):d.set(t,r);}}function te(t={}){new MutationObserver(()=>{for(let[n,r]of d.entries())E(n,r);}).observe(document.body,f({subtree:!0,childList:!0},t));}function ne(){return d}
3
+ var v=Object.defineProperty,x=Object.defineProperties;var w=Object.getOwnPropertyDescriptors;var h=Object.getOwnPropertySymbols;var O=Object.prototype.hasOwnProperty,M=Object.prototype.propertyIsEnumerable;var p=(t,e,n)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,f=(t,e)=>{for(var n in e||(e={}))O.call(e,n)&&p(t,n,e[n]);if(h)for(var n of h(e))M.call(e,n)&&p(t,n,e[n]);return t},b=(t,e)=>x(t,w(e));var m=(t,e,n)=>(p(t,typeof e!="symbol"?e+"":e,n),n);var c=(t,e,n)=>new Promise((r,i)=>{var o=s=>{try{u(n.next(s));}catch(l){i(l);}},a=s=>{try{u(n.throw(s));}catch(l){i(l);}},u=s=>s.done?r(s.value):Promise.resolve(s.value).then(o,a);u((n=n.apply(t,e)).next());});function D(t,e,n){return Math.max(Math.min(t,n),e)}function L(t,e,n,r,i){return Number(e)===0&&Number(r)===0?t*(i/n):(t-e)*((i-r)/(n-e))+r}function g(...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 V(t){return T(t)[0]}function T(t){if(t.length===0)return [void 0,void 0];let e=g(t.length-1);return [t[e],e]}function $(t){let[e,n]=T(t);if(n!==void 0)return t.splice(n,1),e}function k(t){let e=[...t];if(t.length===0)return t;for(let n=e.length-1;n>0;n--){let r=Math.floor(g(0,1e4)/1e4*(n+1));[e[n],e[r]]=[e[r],e[n]];}return e}var y=class{constructor(e){m(this,"id");m(this,"formatVersion");m(this,"defaultConfig");m(this,"cachedConfig");m(this,"migrations");this.id=e.id,this.formatVersion=e.formatVersion,this.defaultConfig=e.defaultConfig,this.cachedConfig=e.defaultConfig,this.migrations=e.migrations;}loadData(){return c(this,null,function*(){try{let e=yield GM.getValue(`_uucfg-${this.id}`,this.defaultConfig),n=Number(yield GM.getValue(`_uucfgver-${this.id}`));if(typeof e!="string")return yield this.saveDefaultData(),this.defaultConfig;isNaN(n)&&(yield GM.setValue(`_uucfgver-${this.id}`,n=this.formatVersion));let r=JSON.parse(e);return n<this.formatVersion&&this.migrations&&(r=yield this.runMigrations(r,n)),this.cachedConfig=typeof r=="object"?r:void 0}catch(e){return yield this.saveDefaultData(),this.defaultConfig}})}getData(){return this.deepCopy(this.cachedConfig)}setData(e){return this.cachedConfig=e,new Promise(n=>c(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(e)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),n();}))}saveDefaultData(){return c(this,null,function*(){return this.cachedConfig=this.defaultConfig,new Promise(e=>c(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(this.defaultConfig)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),e();}))})}deleteConfig(){return c(this,null,function*(){yield Promise.allSettled([GM.deleteValue(`_uucfg-${this.id}`),GM.deleteValue(`_uucfgver-${this.id}`)]);})}runMigrations(e,n){return c(this,null,function*(){if(!this.migrations)return e;let r=e,i=Object.entries(this.migrations).sort(([a],[u])=>Number(a)-Number(u)),o=n;for(let[a,u]of i){let s=Number(a);if(n<this.formatVersion&&n<s)try{let l=u(r);r=l instanceof Promise?yield l:l,o=n=s;}catch(l){console.error(`Error while running migration function for format version ${a}:`,l);}}return yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(r)),GM.setValue(`_uucfgver-${this.id}`,o)]),r})}deepCopy(e){return JSON.parse(JSON.stringify(e))}};function S(){try{return unsafeWindow}catch(t){return window}}function _(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function j(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 W(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function F(t,e=!1){let n=t.map(r=>new Promise((i,o)=>{let a=new Image;a.src=r,a.addEventListener("load",()=>i(a)),a.addEventListener("error",u=>e&&o(u));}));return Promise.allSettled(n)}function H(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 C(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){t.__proto__.addEventListener=function(...i){var a,u;let o=typeof i[1]=="function"?i[1]:(u=(a=i[1])==null?void 0:a.handleEvent)!=null?u:()=>{};i[1]=function(...s){if(!(i[0]===e&&n(Array.isArray(s)?s[0]:s)))return o.apply(this,s)},r.apply(this,i);};}(t.__proto__.addEventListener);}function J(t,e){return C(S(),t,e)}function q(t,e=1){let n=new(window.AudioContext||window.webkitAudioContext),r={mediaElement:t,amplify:i=>{r.gain.gain.value=i;},getAmpLevel:()=>r.gain.gain.value,context:n,source:n.createMediaElementSource(t),gain:n.createGain()};return r.source.connect(r.gain),r.gain.connect(n.destination),r.amplify(e),r}function K(t){let{overflowX:e,overflowY:n}=getComputedStyle(t);return {vertical:(n==="scroll"||n==="auto")&&t.scrollHeight>t.clientHeight,horizontal:(e==="scroll"||e==="auto")&&t.scrollWidth>t.clientWidth}}function B(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function U(t){return new Promise(e=>{setTimeout(()=>e(),t);})}function X(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function Y(n){return c(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,i=new AbortController,o=setTimeout(()=>i.abort(),r),a=yield fetch(t,b(f({},e),{signal:i.signal}));return clearTimeout(o),a})}var d=new Map;function ee(t,e){let n=[];d.has(t)&&(n=d.get(t)),n.push(e),d.set(t,n),E(t,n);}function te(t){return d.delete(t)}function E(t,e){let n=[];if(e.forEach((r,i)=>{try{let o=r.all?document.querySelectorAll(t):document.querySelector(t);(o!==null&&o instanceof NodeList&&o.length>0||o!==null)&&(r.listener(o),r.continuous||n.push(i));}catch(o){console.error(`Couldn't call listener for selector '${t}'`,o);}}),n.length>0){let r=e.filter((i,o)=>!n.includes(o));r.length===0?d.delete(t):d.set(t,r);}}function ne(t={}){new MutationObserver(()=>{for(let[n,r]of d.entries())E(n,r);}).observe(document.body,f({subtree:!0,childList:!0},t));}function re(){return d}
4
4
 
5
5
  exports.ConfigManager = y;
6
- exports.addGlobalStyle = j;
7
- exports.addParent = _;
8
- exports.amplifyMedia = B;
9
- exports.autoPlural = K;
6
+ exports.addGlobalStyle = W;
7
+ exports.addParent = j;
8
+ exports.amplifyMedia = q;
9
+ exports.autoPlural = B;
10
10
  exports.clamp = D;
11
- exports.debounce = U;
12
- exports.fetchAdvanced = Q;
13
- exports.getSelectorMap = ne;
11
+ exports.debounce = X;
12
+ exports.fetchAdvanced = Y;
13
+ exports.getSelectorMap = re;
14
14
  exports.getUnsafeWindow = S;
15
- exports.initOnSelector = te;
16
- exports.insertAfter = R;
17
- exports.interceptEvent = N;
18
- exports.interceptWindowEvent = W;
15
+ exports.initOnSelector = ne;
16
+ exports.insertAfter = _;
17
+ exports.interceptEvent = C;
18
+ exports.interceptWindowEvent = J;
19
+ exports.isScrollable = K;
19
20
  exports.mapRange = L;
20
- exports.onSelector = Z;
21
- exports.openInNewTab = J;
22
- exports.pauseFor = z;
21
+ exports.onSelector = ee;
22
+ exports.openInNewTab = H;
23
+ exports.pauseFor = U;
23
24
  exports.preloadImages = F;
24
25
  exports.randRange = g;
25
26
  exports.randomItem = V;
26
27
  exports.randomItemIndex = T;
27
28
  exports.randomizeArray = k;
28
- exports.removeOnSelector = ee;
29
+ exports.removeOnSelector = te;
29
30
  exports.takeRandomItem = $;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- var v=Object.defineProperty,x=Object.defineProperties;var w=Object.getOwnPropertyDescriptors;var h=Object.getOwnPropertySymbols;var M=Object.prototype.hasOwnProperty,O=Object.prototype.propertyIsEnumerable;var p=(t,e,n)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,f=(t,e)=>{for(var n in e||(e={}))M.call(e,n)&&p(t,n,e[n]);if(h)for(var n of h(e))O.call(e,n)&&p(t,n,e[n]);return t},b=(t,e)=>x(t,w(e));var m=(t,e,n)=>(p(t,typeof e!="symbol"?e+"":e,n),n);var l=(t,e,n)=>new Promise((r,i)=>{var o=s=>{try{u(n.next(s));}catch(c){i(c);}},a=s=>{try{u(n.throw(s));}catch(c){i(c);}},u=s=>s.done?r(s.value):Promise.resolve(s.value).then(o,a);u((n=n.apply(t,e)).next());});function D(t,e,n){return Math.max(Math.min(t,n),e)}function L(t,e,n,r,i){return Number(e)===0&&Number(r)===0?t*(i/n):(t-e)*((i-r)/(n-e))+r}function g(...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 V(t){return T(t)[0]}function T(t){if(t.length===0)return [void 0,void 0];let e=g(t.length-1);return [t[e],e]}function $(t){let[e,n]=T(t);if(n!==void 0)return t.splice(n,1),e}function k(t){let e=[...t];if(t.length===0)return t;for(let n=e.length-1;n>0;n--){let r=Math.floor(g(0,1e4)/1e4*(n+1));[e[n],e[r]]=[e[r],e[n]];}return e}var y=class{constructor(e){m(this,"id");m(this,"formatVersion");m(this,"defaultConfig");m(this,"cachedConfig");m(this,"migrations");this.id=e.id,this.formatVersion=e.formatVersion,this.defaultConfig=e.defaultConfig,this.cachedConfig=e.defaultConfig,this.migrations=e.migrations;}loadData(){return l(this,null,function*(){try{let e=yield GM.getValue(`_uucfg-${this.id}`,this.defaultConfig),n=Number(yield GM.getValue(`_uucfgver-${this.id}`));if(typeof e!="string")return yield this.saveDefaultData(),this.defaultConfig;isNaN(n)&&(yield GM.setValue(`_uucfgver-${this.id}`,n=this.formatVersion));let r=JSON.parse(e);return n<this.formatVersion&&this.migrations&&(r=yield this.runMigrations(r,n)),this.cachedConfig=typeof r=="object"?r:void 0}catch(e){return yield this.saveDefaultData(),this.defaultConfig}})}getData(){return this.deepCopy(this.cachedConfig)}setData(e){return this.cachedConfig=e,new Promise(n=>l(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(e)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),n();}))}saveDefaultData(){return l(this,null,function*(){return this.cachedConfig=this.defaultConfig,new Promise(e=>l(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(this.defaultConfig)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),e();}))})}deleteConfig(){return l(this,null,function*(){yield Promise.allSettled([GM.deleteValue(`_uucfg-${this.id}`),GM.deleteValue(`_uucfgver-${this.id}`)]);})}runMigrations(e,n){return l(this,null,function*(){if(!this.migrations)return e;let r=e,i=Object.entries(this.migrations).sort(([a],[u])=>Number(a)-Number(u)),o=n;for(let[a,u]of i){let s=Number(a);if(n<this.formatVersion&&n<s)try{let c=u(r);r=c instanceof Promise?yield c:c,o=n=s;}catch(c){console.error(`Error while running migration function for format version ${a}:`,c);}}return yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(r)),GM.setValue(`_uucfgver-${this.id}`,o)]),r})}deepCopy(e){return JSON.parse(JSON.stringify(e))}};function S(){try{return unsafeWindow}catch(t){return window}}function R(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function _(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 j(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function F(t,e=!1){let n=t.map(r=>new Promise((i,o)=>{let a=new Image;a.src=r,a.addEventListener("load",()=>i(a)),a.addEventListener("error",u=>e&&o(u));}));return Promise.allSettled(n)}function J(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 N(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){t.__proto__.addEventListener=function(...i){var a,u;let o=typeof i[1]=="function"?i[1]:(u=(a=i[1])==null?void 0:a.handleEvent)!=null?u:()=>{};i[1]=function(...s){if(!(i[0]===e&&n(Array.isArray(s)?s[0]:s)))return o.apply(this,s)},r.apply(this,i);};}(t.__proto__.addEventListener);}function W(t,e){return N(S(),t,e)}function B(t,e=1){let n=new(window.AudioContext||window.webkitAudioContext),r={mediaElement:t,amplify:i=>{r.gain.gain.value=i;},getAmpLevel:()=>r.gain.gain.value,context:n,source:n.createMediaElementSource(t),gain:n.createGain()};return r.source.connect(r.gain),r.gain.connect(n.destination),r.amplify(e),r}function K(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function z(t){return new Promise(e=>{setTimeout(()=>e(),t);})}function U(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function Q(n){return l(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,i=new AbortController,o=setTimeout(()=>i.abort(),r),a=yield fetch(t,b(f({},e),{signal:i.signal}));return clearTimeout(o),a})}var d=new Map;function Z(t,e){let n=[];d.has(t)&&(n=d.get(t)),n.push(e),d.set(t,n),E(t,n);}function ee(t){return d.delete(t)}function E(t,e){let n=[];if(e.forEach((r,i)=>{try{let o=r.all?document.querySelectorAll(t):document.querySelector(t);(o!==null&&o instanceof NodeList&&o.length>0||o!==null)&&(r.listener(o),r.continuous||n.push(i));}catch(o){console.error(`Couldn't call listener for selector '${t}'`,o);}}),n.length>0){let r=e.filter((i,o)=>!n.includes(o));r.length===0?d.delete(t):d.set(t,r);}}function te(t={}){new MutationObserver(()=>{for(let[n,r]of d.entries())E(n,r);}).observe(document.body,f({subtree:!0,childList:!0},t));}function ne(){return d}
1
+ var v=Object.defineProperty,x=Object.defineProperties;var w=Object.getOwnPropertyDescriptors;var h=Object.getOwnPropertySymbols;var O=Object.prototype.hasOwnProperty,M=Object.prototype.propertyIsEnumerable;var p=(t,e,n)=>e in t?v(t,e,{enumerable:!0,configurable:!0,writable:!0,value:n}):t[e]=n,f=(t,e)=>{for(var n in e||(e={}))O.call(e,n)&&p(t,n,e[n]);if(h)for(var n of h(e))M.call(e,n)&&p(t,n,e[n]);return t},b=(t,e)=>x(t,w(e));var m=(t,e,n)=>(p(t,typeof e!="symbol"?e+"":e,n),n);var c=(t,e,n)=>new Promise((r,i)=>{var o=s=>{try{u(n.next(s));}catch(l){i(l);}},a=s=>{try{u(n.throw(s));}catch(l){i(l);}},u=s=>s.done?r(s.value):Promise.resolve(s.value).then(o,a);u((n=n.apply(t,e)).next());});function D(t,e,n){return Math.max(Math.min(t,n),e)}function L(t,e,n,r,i){return Number(e)===0&&Number(r)===0?t*(i/n):(t-e)*((i-r)/(n-e))+r}function g(...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 V(t){return T(t)[0]}function T(t){if(t.length===0)return [void 0,void 0];let e=g(t.length-1);return [t[e],e]}function $(t){let[e,n]=T(t);if(n!==void 0)return t.splice(n,1),e}function k(t){let e=[...t];if(t.length===0)return t;for(let n=e.length-1;n>0;n--){let r=Math.floor(g(0,1e4)/1e4*(n+1));[e[n],e[r]]=[e[r],e[n]];}return e}var y=class{constructor(e){m(this,"id");m(this,"formatVersion");m(this,"defaultConfig");m(this,"cachedConfig");m(this,"migrations");this.id=e.id,this.formatVersion=e.formatVersion,this.defaultConfig=e.defaultConfig,this.cachedConfig=e.defaultConfig,this.migrations=e.migrations;}loadData(){return c(this,null,function*(){try{let e=yield GM.getValue(`_uucfg-${this.id}`,this.defaultConfig),n=Number(yield GM.getValue(`_uucfgver-${this.id}`));if(typeof e!="string")return yield this.saveDefaultData(),this.defaultConfig;isNaN(n)&&(yield GM.setValue(`_uucfgver-${this.id}`,n=this.formatVersion));let r=JSON.parse(e);return n<this.formatVersion&&this.migrations&&(r=yield this.runMigrations(r,n)),this.cachedConfig=typeof r=="object"?r:void 0}catch(e){return yield this.saveDefaultData(),this.defaultConfig}})}getData(){return this.deepCopy(this.cachedConfig)}setData(e){return this.cachedConfig=e,new Promise(n=>c(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(e)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),n();}))}saveDefaultData(){return c(this,null,function*(){return this.cachedConfig=this.defaultConfig,new Promise(e=>c(this,null,function*(){yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(this.defaultConfig)),GM.setValue(`_uucfgver-${this.id}`,this.formatVersion)]),e();}))})}deleteConfig(){return c(this,null,function*(){yield Promise.allSettled([GM.deleteValue(`_uucfg-${this.id}`),GM.deleteValue(`_uucfgver-${this.id}`)]);})}runMigrations(e,n){return c(this,null,function*(){if(!this.migrations)return e;let r=e,i=Object.entries(this.migrations).sort(([a],[u])=>Number(a)-Number(u)),o=n;for(let[a,u]of i){let s=Number(a);if(n<this.formatVersion&&n<s)try{let l=u(r);r=l instanceof Promise?yield l:l,o=n=s;}catch(l){console.error(`Error while running migration function for format version ${a}:`,l);}}return yield Promise.allSettled([GM.setValue(`_uucfg-${this.id}`,JSON.stringify(r)),GM.setValue(`_uucfgver-${this.id}`,o)]),r})}deepCopy(e){return JSON.parse(JSON.stringify(e))}};function S(){try{return unsafeWindow}catch(t){return window}}function _(t,e){var n;return (n=t.parentNode)==null||n.insertBefore(e,t.nextSibling),e}function j(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 W(t){let e=document.createElement("style");e.innerHTML=t,document.head.appendChild(e);}function F(t,e=!1){let n=t.map(r=>new Promise((i,o)=>{let a=new Image;a.src=r,a.addEventListener("load",()=>i(a)),a.addEventListener("error",u=>e&&o(u));}));return Promise.allSettled(n)}function H(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 C(t,e,n){typeof Error.stackTraceLimit=="number"&&Error.stackTraceLimit<1e3&&(Error.stackTraceLimit=1e3),function(r){t.__proto__.addEventListener=function(...i){var a,u;let o=typeof i[1]=="function"?i[1]:(u=(a=i[1])==null?void 0:a.handleEvent)!=null?u:()=>{};i[1]=function(...s){if(!(i[0]===e&&n(Array.isArray(s)?s[0]:s)))return o.apply(this,s)},r.apply(this,i);};}(t.__proto__.addEventListener);}function J(t,e){return C(S(),t,e)}function q(t,e=1){let n=new(window.AudioContext||window.webkitAudioContext),r={mediaElement:t,amplify:i=>{r.gain.gain.value=i;},getAmpLevel:()=>r.gain.gain.value,context:n,source:n.createMediaElementSource(t),gain:n.createGain()};return r.source.connect(r.gain),r.gain.connect(n.destination),r.amplify(e),r}function K(t){let{overflowX:e,overflowY:n}=getComputedStyle(t);return {vertical:(n==="scroll"||n==="auto")&&t.scrollHeight>t.clientHeight,horizontal:(e==="scroll"||e==="auto")&&t.scrollWidth>t.clientWidth}}function B(t,e){return (Array.isArray(e)||e instanceof NodeList)&&(e=e.length),`${t}${e===1?"":"s"}`}function U(t){return new Promise(e=>{setTimeout(()=>e(),t);})}function X(t,e=300){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>t.apply(this,r),e);}}function Y(n){return c(this,arguments,function*(t,e={}){let{timeout:r=1e4}=e,i=new AbortController,o=setTimeout(()=>i.abort(),r),a=yield fetch(t,b(f({},e),{signal:i.signal}));return clearTimeout(o),a})}var d=new Map;function ee(t,e){let n=[];d.has(t)&&(n=d.get(t)),n.push(e),d.set(t,n),E(t,n);}function te(t){return d.delete(t)}function E(t,e){let n=[];if(e.forEach((r,i)=>{try{let o=r.all?document.querySelectorAll(t):document.querySelector(t);(o!==null&&o instanceof NodeList&&o.length>0||o!==null)&&(r.listener(o),r.continuous||n.push(i));}catch(o){console.error(`Couldn't call listener for selector '${t}'`,o);}}),n.length>0){let r=e.filter((i,o)=>!n.includes(o));r.length===0?d.delete(t):d.set(t,r);}}function ne(t={}){new MutationObserver(()=>{for(let[n,r]of d.entries())E(n,r);}).observe(document.body,f({subtree:!0,childList:!0},t));}function re(){return d}
2
2
 
3
- export { y as ConfigManager, j as addGlobalStyle, _ as addParent, B as amplifyMedia, K as autoPlural, D as clamp, U as debounce, Q as fetchAdvanced, ne as getSelectorMap, S as getUnsafeWindow, te as initOnSelector, R as insertAfter, N as interceptEvent, W as interceptWindowEvent, L as mapRange, Z as onSelector, J as openInNewTab, z as pauseFor, F as preloadImages, g as randRange, V as randomItem, T as randomItemIndex, k as randomizeArray, ee as removeOnSelector, $ as takeRandomItem };
3
+ export { y as ConfigManager, W as addGlobalStyle, j as addParent, q as amplifyMedia, B as autoPlural, D as clamp, X as debounce, Y as fetchAdvanced, re as getSelectorMap, S as getUnsafeWindow, ne as initOnSelector, _ as insertAfter, C as interceptEvent, J as interceptWindowEvent, K as isScrollable, L as mapRange, ee as onSelector, H as openInNewTab, U as pauseFor, F as preloadImages, g as randRange, V as randomItem, T as randomItemIndex, k as randomizeArray, te as removeOnSelector, $ as takeRandomItem };
package/dist/lib/dom.d.ts CHANGED
@@ -6,12 +6,12 @@ export declare function getUnsafeWindow(): Window;
6
6
  * Inserts `afterElement` as a sibling just after the provided `beforeElement`
7
7
  * @returns Returns the `afterElement`
8
8
  */
9
- export declare function insertAfter(beforeElement: HTMLElement, afterElement: HTMLElement): HTMLElement;
9
+ export declare function insertAfter(beforeElement: Element, afterElement: Element): Element;
10
10
  /**
11
11
  * Adds a parent container around the provided element
12
12
  * @returns Returns the new parent element
13
13
  */
14
- export declare function addParent(element: HTMLElement, newParent: HTMLElement): HTMLElement;
14
+ export declare function addParent(element: Element, newParent: Element): Element;
15
15
  /**
16
16
  * Adds global CSS style in the form of a `<style>` element in the document's `<head>`
17
17
  * This needs to be run after the `DOMContentLoaded` event has fired on the document object (or instantly if `@run-at document-end` is used).
@@ -67,3 +67,8 @@ export declare function amplifyMedia<TElem extends HTMLMediaElement>(mediaElemen
67
67
  source: MediaElementAudioSourceNode;
68
68
  gain: GainNode;
69
69
  };
70
+ /** Checks if an element is scrollable in the horizontal and vertical directions */
71
+ export declare function isScrollable(element: Element): {
72
+ vertical: boolean;
73
+ horizontal: boolean;
74
+ };
@@ -1,18 +1,18 @@
1
1
  /** Options for the `onSelector()` function */
2
2
  export type OnSelectorOpts<TElem extends Element = HTMLElement> = SelectorOptsOne<TElem> | SelectorOptsAll<TElem>;
3
- type SelectorOptsOne<TElem extends Element> = SelectorOptsBase & {
3
+ type SelectorOptsOne<TElem extends Element> = SelectorOptsCommon & {
4
4
  /** Whether to use `querySelectorAll()` instead - default is false */
5
5
  all?: false;
6
6
  /** Gets called whenever the selector was found in the DOM */
7
7
  listener: (element: TElem) => void;
8
8
  };
9
- type SelectorOptsAll<TElem extends Element> = SelectorOptsBase & {
9
+ type SelectorOptsAll<TElem extends Element> = SelectorOptsCommon & {
10
10
  /** Whether to use `querySelectorAll()` instead - default is false */
11
11
  all: true;
12
12
  /** Gets called whenever the selector was found in the DOM */
13
13
  listener: (elements: NodeListOf<TElem>) => void;
14
14
  };
15
- type SelectorOptsBase = {
15
+ type SelectorOptsCommon = {
16
16
  /** Whether to call the listener continuously instead of once - default is false */
17
17
  continuous?: boolean;
18
18
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sv443-network/userutils",
3
- "version": "1.0.0",
4
- "description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, modify the DOM more easily and more ",
3
+ "version": "1.1.0",
4
+ "description": "Library with various utilities for userscripts - register listeners for when CSS selectors exist, intercept events, manage persistent user configurations, modify the DOM more easily and more",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/lib/index.d.ts",
@@ -48,7 +48,8 @@
48
48
  "files": [
49
49
  "/dist/index.js",
50
50
  "/dist/index.mjs",
51
- "/dist/lib/**.*",
51
+ "/dist/index.global.js",
52
+ "/dist/lib/**.d.ts",
52
53
  "/package.json",
53
54
  "/README.md",
54
55
  "/CHANGELOG.md",