@sv443-network/userutils 3.0.0 → 4.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 +21 -0
- package/README.md +214 -92
- package/dist/index.global.js +58 -41
- package/dist/index.js +57 -40
- package/dist/index.mjs +55 -40
- package/dist/lib/SelectorObserver.d.ts +2 -2
- package/dist/lib/array.d.ts +5 -5
- package/dist/lib/dom.d.ts +10 -47
- package/dist/lib/misc.d.ts +23 -2
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @sv443-network/userutils
|
|
2
2
|
|
|
3
|
+
## 4.1.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 885323d: Added function `observeElementProp` to allow observing element property changes
|
|
8
|
+
|
|
9
|
+
## 4.0.0
|
|
10
|
+
|
|
11
|
+
### Major Changes
|
|
12
|
+
|
|
13
|
+
- dae5450: Removed `amplifyMedia` function due to massive inconsistencies in sound quality
|
|
14
|
+
|
|
15
|
+
### Minor Changes
|
|
16
|
+
|
|
17
|
+
- 168c2aa: Added functions `compress` and `decompress` to compress and decompress strings using gzip or deflate
|
|
18
|
+
- 49bc85e: Added utility types `NonEmptyString` and `LooseUnion`
|
|
19
|
+
|
|
20
|
+
### Patch Changes
|
|
21
|
+
|
|
22
|
+
- 2ae665d: fixed wrong TS type for SelectorObserver options in constructor
|
|
23
|
+
|
|
3
24
|
## 3.0.0
|
|
4
25
|
|
|
5
26
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -4,13 +4,15 @@
|
|
|
4
4
|
## UserUtils
|
|
5
5
|
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.
|
|
6
6
|
|
|
7
|
-
Contains builtin TypeScript declarations. Fully web compatible and supports ESM
|
|
7
|
+
Contains builtin TypeScript declarations. Fully web compatible and supports ESM and CJS imports and global declaration.
|
|
8
8
|
If you like using this library, please consider [supporting the development ❤️](https://github.com/sponsors/Sv443)
|
|
9
9
|
|
|
10
10
|
<br>
|
|
11
|
+
<sub>
|
|
11
12
|
|
|
12
|
-
View the documentation of previous major releases: [2.0.1](https://github.com/Sv443-Network/UserUtils/blob/v2.0.1/README.md), [1.2.0](https://github.com/Sv443-Network/UserUtils/blob/v1.2.0/README.md), [0.5.3](https://github.com/Sv443-Network/UserUtils/blob/v0.5.3/README.md)
|
|
13
|
+
View the documentation of previous major releases: [3.0.0](https://github.com/Sv443-Network/UserUtils/blob/v3.0.0/README.md), [2.0.1](https://github.com/Sv443-Network/UserUtils/blob/v2.0.1/README.md), [1.2.0](https://github.com/Sv443-Network/UserUtils/blob/v1.2.0/README.md), [0.5.3](https://github.com/Sv443-Network/UserUtils/blob/v0.5.3/README.md)
|
|
13
14
|
|
|
15
|
+
</sub>
|
|
14
16
|
</div>
|
|
15
17
|
<br>
|
|
16
18
|
|
|
@@ -30,8 +32,8 @@ View the documentation of previous major releases: [2.0.1](https://github.com/Sv
|
|
|
30
32
|
- [openInNewTab()](#openinnewtab) - open a link in a new tab
|
|
31
33
|
- [interceptEvent()](#interceptevent) - conditionally intercepts events registered by `addEventListener()` on any given EventTarget object
|
|
32
34
|
- [interceptWindowEvent()](#interceptwindowevent) - conditionally intercepts events registered by `addEventListener()` on the window object
|
|
33
|
-
- [amplifyMedia()](#amplifymedia) - amplify an audio or video element's volume past the maximum of 100%
|
|
34
35
|
- [isScrollable()](#isscrollable) - check if an element has a horizontal or vertical scroll bar
|
|
36
|
+
- [observeElementProp()](#observeelementprop) - observe changes to an element's property that can't be observed with MutationObserver
|
|
35
37
|
- [**Math:**](#math)
|
|
36
38
|
- [clamp()](#clamp) - constrain a number between a min and max value
|
|
37
39
|
- [mapRange()](#maprange) - map a number from one range to the same spot in another range
|
|
@@ -44,6 +46,8 @@ View the documentation of previous major releases: [2.0.1](https://github.com/Sv
|
|
|
44
46
|
- [debounce()](#debounce) - call a function only once, after a given amount of time
|
|
45
47
|
- [fetchAdvanced()](#fetchadvanced) - wrapper around the fetch API with a timeout option
|
|
46
48
|
- [insertValues()](#insertvalues) - insert values into a string at specified placeholders
|
|
49
|
+
- [compress()](#compress) - compress a string with Gzip or Deflate
|
|
50
|
+
- [decompress()](#decompress) - decompress a previously compressed string
|
|
47
51
|
- [**Arrays:**](#arrays)
|
|
48
52
|
- [randomItem()](#randomitem) - returns a random item from an array
|
|
49
53
|
- [randomItemIndex()](#randomitemindex) - returns a tuple of a random item and its index from an array
|
|
@@ -56,7 +60,9 @@ View the documentation of previous major releases: [2.0.1](https://github.com/Sv
|
|
|
56
60
|
- [tr.getLanguage()](#trgetlanguage) - returns the currently active language
|
|
57
61
|
- [**Utility types for TypeScript:**](#utility-types)
|
|
58
62
|
- [Stringifiable](#stringifiable) - any value that is a string or can be converted to one (implicitly or explicitly)
|
|
59
|
-
- [NonEmptyArray](
|
|
63
|
+
- [NonEmptyArray](#nonemptyarray) - any array that should have at least one item
|
|
64
|
+
- [NonEmptyString](#nonemptystring) - any string that should have at least one character
|
|
65
|
+
- [LooseUnion](#looseunion) - a union that gives autocomplete in the IDE but also allows any other value of the same type
|
|
60
66
|
|
|
61
67
|
<br><br>
|
|
62
68
|
|
|
@@ -647,120 +653,78 @@ interceptWindowEvent("beforeunload");
|
|
|
647
653
|
|
|
648
654
|
<br>
|
|
649
655
|
|
|
650
|
-
###
|
|
656
|
+
### isScrollable()
|
|
651
657
|
Usage:
|
|
652
658
|
```ts
|
|
653
|
-
|
|
659
|
+
isScrollable(element: Element): { horizontal: boolean, vertical: boolean }
|
|
654
660
|
```
|
|
655
661
|
|
|
656
|
-
|
|
657
|
-
This
|
|
658
|
-
Make sure to limit the value to a reasonable value ([clamp()](#clamp) is good for this), as it may otherwise cause bleeding eardrums.
|
|
659
|
-
|
|
660
|
-
The default gain value passed to the GainNode is `1.0`
|
|
661
|
-
It may be read and changed at any point by calling the `getGain()` and `setGain()` methods of the returned object.
|
|
662
|
-
|
|
663
|
-
To activate the amplification for the first time, call the `enable()` method of the returned object.
|
|
664
|
-
|
|
665
|
-
This is the processing workflow applied to the media element:
|
|
666
|
-
`MediaElement (source)` => `GainNode (pre-amplifier)` => 10x `BiquadFilterNode` => `GainNode (post-amplifier)` => `destination`
|
|
667
|
-
|
|
668
|
-
⚠️ This function has to be run in response to a user interaction event, else the browser will reject it because of the strict autoplay policy.
|
|
669
|
-
⚠️ Make sure to call the returned function `enable()` after calling this function to actually enable the amplification.
|
|
670
|
-
|
|
671
|
-
The returned object of the type `AmplifyMediaResult` has the following properties:
|
|
672
|
-
**Important properties:**
|
|
673
|
-
| Property | Description |
|
|
674
|
-
| :-- | :-- |
|
|
675
|
-
| `enable()` | Call to enable the amplification for the first time or re-enable it if it was disabled before |
|
|
676
|
-
| `disable()` | Call to disable amplification |
|
|
677
|
-
| `enabled` | Whether the amplification is currently enabled |
|
|
678
|
-
| `setGain()` | Used to change the gain value from the default given by the parameter `initialGain` |
|
|
679
|
-
| `getGain()` | Returns the current gain value |
|
|
680
|
-
|
|
681
|
-
**Other properties:**
|
|
682
|
-
| Property | Description |
|
|
683
|
-
| :-- | :-- |
|
|
684
|
-
| `context` | The AudioContext instance used as the audio destination and context within the nodes are created |
|
|
685
|
-
| `sourceNode` | A MediaElementSourceNode instance created from the passed `mediaElement` |
|
|
686
|
-
| `gainNode` | The GainNode instance used for volume amplification |
|
|
662
|
+
Checks if an element has a horizontal or vertical scroll bar.
|
|
663
|
+
This uses the computed style of the element, so it will also work if the element is hidden.
|
|
687
664
|
|
|
688
|
-
<br>
|
|
689
|
-
|
|
690
665
|
<details><summary><b>Example - click to view</b></summary>
|
|
691
666
|
|
|
692
667
|
```ts
|
|
693
|
-
import {
|
|
694
|
-
import type { AmplifyMediaResult } from "@sv443-network/userutils";
|
|
695
|
-
|
|
696
|
-
const audioElement = document.querySelector<HTMLAudioElement>("audio");
|
|
697
|
-
|
|
698
|
-
let ampResult: AmplifyMediaResult | undefined;
|
|
699
|
-
|
|
700
|
-
function updateGainValue(gainValue: number) {
|
|
701
|
-
if(!ampResult)
|
|
702
|
-
return;
|
|
703
|
-
// constrain the value to between 0 and 3 for safety
|
|
704
|
-
ampResult.setGain(clamp(gainValue, 0, 3));
|
|
705
|
-
|
|
706
|
-
console.log("Gain set to", ampResult.getGain());
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
const amplifyButton = document.querySelector<HTMLButtonElement>("button#amplify");
|
|
711
|
-
|
|
712
|
-
// amplifyMedia() needs to be called in response to a user interaction event:
|
|
713
|
-
amplifyButton.addEventListener("click", () => {
|
|
714
|
-
// only needs to be initialized once, afterwards the returned object
|
|
715
|
-
// can be used to change settings and enable/disable the amplification
|
|
716
|
-
if(!ampResult) {
|
|
717
|
-
// initialize amplification and set it to ~2x
|
|
718
|
-
ampResult = amplifyMedia(audioElement, 2.0);
|
|
719
|
-
}
|
|
720
|
-
if(!ampResult.enabled) {
|
|
721
|
-
// enable the amplification
|
|
722
|
-
ampResult.enable();
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
updateGainValue(3.5); // try to set gain to ~3.5x
|
|
726
|
-
|
|
727
|
-
console.log(ampResult.getGain()); // 3.0 (because of the clamp())
|
|
728
|
-
});
|
|
729
|
-
|
|
668
|
+
import { isScrollable } from "@sv443-network/userutils";
|
|
730
669
|
|
|
731
|
-
const
|
|
670
|
+
const element = document.querySelector("#element");
|
|
671
|
+
const { horizontal, vertical } = isScrollable(element);
|
|
732
672
|
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
// disable the amplification
|
|
736
|
-
ampResult.disable();
|
|
737
|
-
}
|
|
738
|
-
});
|
|
673
|
+
console.log("Element has a horizontal scroll bar:", horizontal);
|
|
674
|
+
console.log("Element has a vertical scroll bar:", vertical);
|
|
739
675
|
```
|
|
740
676
|
|
|
741
677
|
</details>
|
|
742
678
|
|
|
743
679
|
<br>
|
|
744
680
|
|
|
745
|
-
###
|
|
681
|
+
### observeElementProp()
|
|
746
682
|
Usage:
|
|
747
683
|
```ts
|
|
748
|
-
|
|
684
|
+
observeElementProp(
|
|
685
|
+
element: Element,
|
|
686
|
+
property: string,
|
|
687
|
+
callback: (oldValue: any, newValue: any) => void
|
|
688
|
+
): void
|
|
749
689
|
```
|
|
750
690
|
|
|
751
|
-
|
|
752
|
-
|
|
691
|
+
This function observes changes to the given property of a given element.
|
|
692
|
+
While regular HTML attributes can be observed using a MutationObserver, this is not always possible for properties that are assigned on the JS object.
|
|
693
|
+
This function shims the setter of the provided property and calls the callback function whenever it is changed through any means.
|
|
694
|
+
|
|
695
|
+
When using TypeScript, the types for `element`, `property` and the arguments for `callback` will be automatically inferred.
|
|
753
696
|
|
|
754
697
|
<details><summary><b>Example - click to view</b></summary>
|
|
755
698
|
|
|
756
699
|
```ts
|
|
757
|
-
import {
|
|
700
|
+
import { observeElementProp } from "@sv443-network/userutils";
|
|
758
701
|
|
|
759
|
-
const
|
|
760
|
-
const { horizontal, vertical } = isScrollable(element);
|
|
702
|
+
const myInput = document.querySelector("input#my-input");
|
|
761
703
|
|
|
762
|
-
|
|
763
|
-
|
|
704
|
+
let value = 0;
|
|
705
|
+
|
|
706
|
+
setInterval(() => {
|
|
707
|
+
value += 1;
|
|
708
|
+
myInput.value = String(value);
|
|
709
|
+
}, 1000);
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
const observer = new MutationObserver((mutations) => {
|
|
713
|
+
// will never be called:
|
|
714
|
+
console.log("MutationObserver mutation:", mutations);
|
|
715
|
+
});
|
|
716
|
+
|
|
717
|
+
// one would think this should work, but "value" is a JS object *property*, not a DOM *attribute*
|
|
718
|
+
observer.observe(myInput, {
|
|
719
|
+
attributes: true,
|
|
720
|
+
attributeFilter: ["value"],
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
observeElementProp(myInput, "value", (oldValue, newValue) => {
|
|
725
|
+
// will be called every time the value changes:
|
|
726
|
+
console.log("Value changed from", oldValue, "to", newValue);
|
|
727
|
+
});
|
|
764
728
|
```
|
|
765
729
|
|
|
766
730
|
</details>
|
|
@@ -1121,6 +1085,106 @@ fetchAdvanced("https://jokeapi.dev/joke/Any?safe-mode", {
|
|
|
1121
1085
|
|
|
1122
1086
|
</details>
|
|
1123
1087
|
|
|
1088
|
+
<br>
|
|
1089
|
+
|
|
1090
|
+
### insertValues()
|
|
1091
|
+
Usage:
|
|
1092
|
+
```ts
|
|
1093
|
+
insertValues(input: string, ...values: Stringifiable[]): string
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
Inserts values into a string in the format `%n`, where `n` is the number of the value, starting at 1.
|
|
1097
|
+
The values will be stringified using `toString()` (see [Stringifiable](#stringifiable)) before being inserted into the input string.
|
|
1098
|
+
If not enough values are passed, the remaining placeholders will be left untouched.
|
|
1099
|
+
|
|
1100
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
1101
|
+
|
|
1102
|
+
```ts
|
|
1103
|
+
import { insertValues } from "@sv443-network/userutils";
|
|
1104
|
+
|
|
1105
|
+
insertValues("Hello, %1!", "World"); // "Hello, World!"
|
|
1106
|
+
insertValues("Hello, %1! My name is %2.", "World", "John"); // "Hello, World! My name is John."
|
|
1107
|
+
insertValues("Testing %1", { toString: () => "foo" }); // "Testing foo"
|
|
1108
|
+
|
|
1109
|
+
// using an array for the values and not passing enough arguments:
|
|
1110
|
+
const values = ["foo", "bar", "baz"];
|
|
1111
|
+
insertValues("Testing %1, %2, %3 and %4", ...values); // "Testing foo, bar and baz and %4"
|
|
1112
|
+
```
|
|
1113
|
+
|
|
1114
|
+
</details>
|
|
1115
|
+
|
|
1116
|
+
<br>
|
|
1117
|
+
|
|
1118
|
+
### compress()
|
|
1119
|
+
Usage:
|
|
1120
|
+
```ts
|
|
1121
|
+
compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "base64"): Promise<string>
|
|
1122
|
+
compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
Compresses a string or ArrayBuffer using the specified compression format. Most browsers should support at least `gzip` and `deflate`
|
|
1126
|
+
The `outputType` dictates which format the output will be in. It will default to `base64` if left undefined.
|
|
1127
|
+
|
|
1128
|
+
⚠️ You need to provide the `@grant unsafeWindow` directive if you are using the `base64` output type or you will get a TypeError.
|
|
1129
|
+
⚠️ Not all browsers might support compression. Please check [on this page](https://developer.mozilla.org/en-US/docs/Web/API/CompressionStream#browser_compatibility) for compatibility and supported compression formats.
|
|
1130
|
+
|
|
1131
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
1132
|
+
|
|
1133
|
+
```ts
|
|
1134
|
+
import { compress } from "@sv443-network/userutils";
|
|
1135
|
+
|
|
1136
|
+
// using gzip:
|
|
1137
|
+
|
|
1138
|
+
const fooGz = await compress("Hello, World!", "gzip");
|
|
1139
|
+
const barGz = await compress("Hello, World!".repeat(20), "gzip");
|
|
1140
|
+
|
|
1141
|
+
// not as efficient with short strings but can save quite a lot of space with larger strings:
|
|
1142
|
+
console.log(fooGz); // "H4sIAAAAAAAAE/NIzcnJ11EIzy/KSVEEANDDSuwNAAAA"
|
|
1143
|
+
console.log(barGz); // "H4sIAAAAAAAAE/NIzcnJ11EIzy/KSVH0GJkcAKOPcmYEAQAA"
|
|
1144
|
+
|
|
1145
|
+
// depending on the type of data you might want to use a different compression format like deflate:
|
|
1146
|
+
|
|
1147
|
+
const fooDeflate = await compress("Hello, World!", "deflate");
|
|
1148
|
+
const barDeflate = await compress("Hello, World!".repeat(20), "deflate");
|
|
1149
|
+
|
|
1150
|
+
// again, it's not as efficient initially but gets better with longer inputs:
|
|
1151
|
+
console.log(fooDeflate); // "eJzzSM3JyddRCM8vyklRBAAfngRq"
|
|
1152
|
+
console.log(barDeflate); // "eJzzSM3JyddRCM8vyklR9BiZHAAIEVg1"
|
|
1153
|
+
```
|
|
1154
|
+
|
|
1155
|
+
</details>
|
|
1156
|
+
|
|
1157
|
+
<br>
|
|
1158
|
+
|
|
1159
|
+
### decompress()
|
|
1160
|
+
Usage:
|
|
1161
|
+
```ts
|
|
1162
|
+
decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>
|
|
1163
|
+
decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>
|
|
1164
|
+
```
|
|
1165
|
+
|
|
1166
|
+
Decompresses a string or ArrayBuffer that has been previously [compressed](#compress) using the specified compression format. Most browsers should support at least `gzip` and `deflate`
|
|
1167
|
+
The `outputType` dictates which format the output will be in. It will default to `string` if left undefined.
|
|
1168
|
+
|
|
1169
|
+
⚠️ You need to provide the `@grant unsafeWindow` directive if you are using the `string` output type or you will get a TypeError.
|
|
1170
|
+
⚠️ Not all browsers might support decompression. Please check [on this page](https://developer.mozilla.org/en-US/docs/Web/API/DecompressionStream#browser_compatibility) for compatibility and supported compression formats.
|
|
1171
|
+
|
|
1172
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
1173
|
+
|
|
1174
|
+
```ts
|
|
1175
|
+
import { compress, decompress } from "@sv443-network/userutils";
|
|
1176
|
+
|
|
1177
|
+
const compressed = await compress("Hello, World!".repeat(20), "gzip");
|
|
1178
|
+
|
|
1179
|
+
console.log(compressed); // "H4sIAAAAAAAAE/NIzcnJ11EIzy/KSVH0GJkcAKOPcmYEAQAA"
|
|
1180
|
+
|
|
1181
|
+
const decompressed = await decompress(compressed, "gzip");
|
|
1182
|
+
|
|
1183
|
+
console.log(decompressed); // "Hello, World!"
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
</details>
|
|
1187
|
+
|
|
1124
1188
|
<br><br>
|
|
1125
1189
|
|
|
1126
1190
|
<!-- #SECTION Arrays -->
|
|
@@ -1442,6 +1506,11 @@ logSomething(barObject); // Type Error
|
|
|
1442
1506
|
<br>
|
|
1443
1507
|
|
|
1444
1508
|
## NonEmptyArray
|
|
1509
|
+
Usage:
|
|
1510
|
+
```ts
|
|
1511
|
+
NonEmptyArray<TItem = unknown>
|
|
1512
|
+
```
|
|
1513
|
+
|
|
1445
1514
|
This type describes an array that has at least one item.
|
|
1446
1515
|
Use the generic parameter to specify the type of the items in the array.
|
|
1447
1516
|
|
|
@@ -1465,6 +1534,59 @@ logFirstItem(["04abc", "69"]); // 4
|
|
|
1465
1534
|
|
|
1466
1535
|
</details>
|
|
1467
1536
|
|
|
1537
|
+
<br>
|
|
1538
|
+
|
|
1539
|
+
## NonEmptyString
|
|
1540
|
+
Usage:
|
|
1541
|
+
```ts
|
|
1542
|
+
NonEmptyString<TString extends string>
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1545
|
+
This type describes a string that has at least one character.
|
|
1546
|
+
|
|
1547
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
1548
|
+
|
|
1549
|
+
```ts
|
|
1550
|
+
import type { NonEmptyString } from "@sv443-network/userutils";
|
|
1551
|
+
|
|
1552
|
+
function convertToNumber<T extends string>(str: NonEmptyString<T>) {
|
|
1553
|
+
console.log(parseInt(str));
|
|
1554
|
+
}
|
|
1555
|
+
|
|
1556
|
+
convertToNumber("04abc"); // "4"
|
|
1557
|
+
convertToNumber(""); // type error: Argument of type 'string' is not assignable to parameter of type 'never'
|
|
1558
|
+
```
|
|
1559
|
+
|
|
1560
|
+
</details>
|
|
1561
|
+
|
|
1562
|
+
<br>
|
|
1563
|
+
|
|
1564
|
+
## LooseUnion
|
|
1565
|
+
Usage:
|
|
1566
|
+
```ts
|
|
1567
|
+
LooseUnion<TUnion extends string | number | object>
|
|
1568
|
+
```
|
|
1569
|
+
|
|
1570
|
+
A type that offers autocomplete in the IDE for the passed union but also allows any value of the same type to be passed.
|
|
1571
|
+
Supports unions of strings, numbers and objects.
|
|
1572
|
+
|
|
1573
|
+
<details><summary><b>Example - click to view</b></summary>
|
|
1574
|
+
|
|
1575
|
+
```ts
|
|
1576
|
+
function foo(bar: LooseUnion<"a" | "b" | "c">) {
|
|
1577
|
+
console.log(bar);
|
|
1578
|
+
}
|
|
1579
|
+
|
|
1580
|
+
// when typing the following, autocomplete suggests "a", "b" and "c"
|
|
1581
|
+
// foo("
|
|
1582
|
+
|
|
1583
|
+
foo("a"); // included in autocomplete, no type error
|
|
1584
|
+
foo(""); // *not* included in autocomplete, still no type error
|
|
1585
|
+
foo(1); // type error: Argument of type '1' is not assignable to parameter of type 'LooseUnion<"a" | "b" | "c">'
|
|
1586
|
+
```
|
|
1587
|
+
|
|
1588
|
+
</details>
|
|
1589
|
+
|
|
1468
1590
|
<br><br><br><br>
|
|
1469
1591
|
|
|
1470
1592
|
<!-- #MARKER Footer -->
|
package/dist/index.global.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
// ==UserLibrary==
|
|
10
10
|
// @name UserUtils
|
|
11
11
|
// @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
|
|
12
|
-
// @version
|
|
12
|
+
// @version 4.1.0
|
|
13
13
|
// @license MIT
|
|
14
14
|
// @copyright Sv443 (https://github.com/Sv443)
|
|
15
15
|
|
|
@@ -326,43 +326,6 @@ var UserUtils = (function (exports) {
|
|
|
326
326
|
function interceptWindowEvent(eventName, predicate = () => true) {
|
|
327
327
|
return interceptEvent(getUnsafeWindow(), eventName, predicate);
|
|
328
328
|
}
|
|
329
|
-
function amplifyMedia(mediaElement, initialGain = 1) {
|
|
330
|
-
const context = new (window.AudioContext || window.webkitAudioContext)();
|
|
331
|
-
const props = {
|
|
332
|
-
context,
|
|
333
|
-
sourceNode: context.createMediaElementSource(mediaElement),
|
|
334
|
-
gainNode: context.createGain(),
|
|
335
|
-
/** Sets the gain of the amplifying GainNode */
|
|
336
|
-
setGain(gain) {
|
|
337
|
-
props.gainNode.gain.value = gain;
|
|
338
|
-
},
|
|
339
|
-
/** Returns the current gain of the amplifying GainNode */
|
|
340
|
-
getGain() {
|
|
341
|
-
return props.gainNode.gain.value;
|
|
342
|
-
},
|
|
343
|
-
/** Whether the amplification is currently enabled */
|
|
344
|
-
enabled: false,
|
|
345
|
-
/** Enable the amplification for the first time or if it was disabled before */
|
|
346
|
-
enable() {
|
|
347
|
-
if (props.enabled)
|
|
348
|
-
return;
|
|
349
|
-
props.enabled = true;
|
|
350
|
-
props.sourceNode.connect(props.gainNode);
|
|
351
|
-
props.gainNode.connect(props.context.destination);
|
|
352
|
-
},
|
|
353
|
-
/** Disable the amplification */
|
|
354
|
-
disable() {
|
|
355
|
-
if (!props.enabled)
|
|
356
|
-
return;
|
|
357
|
-
props.enabled = false;
|
|
358
|
-
props.sourceNode.disconnect(props.gainNode);
|
|
359
|
-
props.gainNode.disconnect(props.context.destination);
|
|
360
|
-
props.sourceNode.connect(props.context.destination);
|
|
361
|
-
}
|
|
362
|
-
};
|
|
363
|
-
props.setGain(initialGain);
|
|
364
|
-
return props;
|
|
365
|
-
}
|
|
366
329
|
function isScrollable(element) {
|
|
367
330
|
const { overflowX, overflowY } = getComputedStyle(element);
|
|
368
331
|
return {
|
|
@@ -370,6 +333,28 @@ var UserUtils = (function (exports) {
|
|
|
370
333
|
horizontal: (overflowX === "scroll" || overflowX === "auto") && element.scrollWidth > element.clientWidth
|
|
371
334
|
};
|
|
372
335
|
}
|
|
336
|
+
function observeElementProp(element, property, callback) {
|
|
337
|
+
const elementPrototype = Object.getPrototypeOf(element);
|
|
338
|
+
if (elementPrototype.hasOwnProperty(property)) {
|
|
339
|
+
const descriptor = Object.getOwnPropertyDescriptor(elementPrototype, property);
|
|
340
|
+
Object.defineProperty(element, property, {
|
|
341
|
+
get: function() {
|
|
342
|
+
var _a;
|
|
343
|
+
return (_a = descriptor == null ? void 0 : descriptor.get) == null ? void 0 : _a.apply(this, arguments);
|
|
344
|
+
},
|
|
345
|
+
set: function() {
|
|
346
|
+
var _a;
|
|
347
|
+
const oldValue = this[property];
|
|
348
|
+
(_a = descriptor == null ? void 0 : descriptor.set) == null ? void 0 : _a.apply(this, arguments);
|
|
349
|
+
const newValue = this[property];
|
|
350
|
+
if (typeof callback === "function") {
|
|
351
|
+
callback.bind(this, oldValue, newValue);
|
|
352
|
+
}
|
|
353
|
+
return newValue;
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
}
|
|
373
358
|
|
|
374
359
|
// lib/misc.ts
|
|
375
360
|
function autoPlural(word, num) {
|
|
@@ -401,13 +386,43 @@ var UserUtils = (function (exports) {
|
|
|
401
386
|
return res;
|
|
402
387
|
});
|
|
403
388
|
}
|
|
404
|
-
function insertValues(
|
|
405
|
-
return
|
|
389
|
+
function insertValues(input, ...values) {
|
|
390
|
+
return input.replace(/%\d/gm, (match) => {
|
|
406
391
|
var _a, _b;
|
|
407
392
|
const argIndex = Number(match.substring(1)) - 1;
|
|
408
393
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
409
394
|
});
|
|
410
395
|
}
|
|
396
|
+
function compress(input, compressionFormat, outputType = "base64") {
|
|
397
|
+
return __async(this, null, function* () {
|
|
398
|
+
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
399
|
+
const comp = new CompressionStream(compressionFormat);
|
|
400
|
+
const writer = comp.writable.getWriter();
|
|
401
|
+
writer.write(byteArray);
|
|
402
|
+
writer.close();
|
|
403
|
+
const buf = yield new Response(comp.readable).arrayBuffer();
|
|
404
|
+
return outputType === "arrayBuffer" ? buf : ab2str(buf);
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function decompress(input, compressionFormat, outputType = "string") {
|
|
408
|
+
return __async(this, null, function* () {
|
|
409
|
+
const byteArray = typeof input === "string" ? str2ab(input) : input;
|
|
410
|
+
const decomp = new DecompressionStream(compressionFormat);
|
|
411
|
+
const writer = decomp.writable.getWriter();
|
|
412
|
+
writer.write(byteArray);
|
|
413
|
+
writer.close();
|
|
414
|
+
const buf = yield new Response(decomp.readable).arrayBuffer();
|
|
415
|
+
return outputType === "arrayBuffer" ? buf : new TextDecoder().decode(buf);
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
function ab2str(buf) {
|
|
419
|
+
return getUnsafeWindow().btoa(
|
|
420
|
+
new Uint8Array(buf).reduce((data, byte) => data + String.fromCharCode(byte), "")
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
function str2ab(str) {
|
|
424
|
+
return Uint8Array.from(getUnsafeWindow().atob(str), (c) => c.charCodeAt(0));
|
|
425
|
+
}
|
|
411
426
|
|
|
412
427
|
// lib/SelectorObserver.ts
|
|
413
428
|
var SelectorObserver = class {
|
|
@@ -579,10 +594,11 @@ var UserUtils = (function (exports) {
|
|
|
579
594
|
exports.SelectorObserver = SelectorObserver;
|
|
580
595
|
exports.addGlobalStyle = addGlobalStyle;
|
|
581
596
|
exports.addParent = addParent;
|
|
582
|
-
exports.amplifyMedia = amplifyMedia;
|
|
583
597
|
exports.autoPlural = autoPlural;
|
|
584
598
|
exports.clamp = clamp;
|
|
599
|
+
exports.compress = compress;
|
|
585
600
|
exports.debounce = debounce;
|
|
601
|
+
exports.decompress = decompress;
|
|
586
602
|
exports.fetchAdvanced = fetchAdvanced;
|
|
587
603
|
exports.getUnsafeWindow = getUnsafeWindow;
|
|
588
604
|
exports.insertAfter = insertAfter;
|
|
@@ -591,6 +607,7 @@ var UserUtils = (function (exports) {
|
|
|
591
607
|
exports.interceptWindowEvent = interceptWindowEvent;
|
|
592
608
|
exports.isScrollable = isScrollable;
|
|
593
609
|
exports.mapRange = mapRange;
|
|
610
|
+
exports.observeElementProp = observeElementProp;
|
|
594
611
|
exports.openInNewTab = openInNewTab;
|
|
595
612
|
exports.pauseFor = pauseFor;
|
|
596
613
|
exports.preloadImages = preloadImages;
|
package/dist/index.js
CHANGED
|
@@ -305,43 +305,6 @@ function interceptEvent(eventObject, eventName, predicate = () => true) {
|
|
|
305
305
|
function interceptWindowEvent(eventName, predicate = () => true) {
|
|
306
306
|
return interceptEvent(getUnsafeWindow(), eventName, predicate);
|
|
307
307
|
}
|
|
308
|
-
function amplifyMedia(mediaElement, initialGain = 1) {
|
|
309
|
-
const context = new (window.AudioContext || window.webkitAudioContext)();
|
|
310
|
-
const props = {
|
|
311
|
-
context,
|
|
312
|
-
sourceNode: context.createMediaElementSource(mediaElement),
|
|
313
|
-
gainNode: context.createGain(),
|
|
314
|
-
/** Sets the gain of the amplifying GainNode */
|
|
315
|
-
setGain(gain) {
|
|
316
|
-
props.gainNode.gain.value = gain;
|
|
317
|
-
},
|
|
318
|
-
/** Returns the current gain of the amplifying GainNode */
|
|
319
|
-
getGain() {
|
|
320
|
-
return props.gainNode.gain.value;
|
|
321
|
-
},
|
|
322
|
-
/** Whether the amplification is currently enabled */
|
|
323
|
-
enabled: false,
|
|
324
|
-
/** Enable the amplification for the first time or if it was disabled before */
|
|
325
|
-
enable() {
|
|
326
|
-
if (props.enabled)
|
|
327
|
-
return;
|
|
328
|
-
props.enabled = true;
|
|
329
|
-
props.sourceNode.connect(props.gainNode);
|
|
330
|
-
props.gainNode.connect(props.context.destination);
|
|
331
|
-
},
|
|
332
|
-
/** Disable the amplification */
|
|
333
|
-
disable() {
|
|
334
|
-
if (!props.enabled)
|
|
335
|
-
return;
|
|
336
|
-
props.enabled = false;
|
|
337
|
-
props.sourceNode.disconnect(props.gainNode);
|
|
338
|
-
props.gainNode.disconnect(props.context.destination);
|
|
339
|
-
props.sourceNode.connect(props.context.destination);
|
|
340
|
-
}
|
|
341
|
-
};
|
|
342
|
-
props.setGain(initialGain);
|
|
343
|
-
return props;
|
|
344
|
-
}
|
|
345
308
|
function isScrollable(element) {
|
|
346
309
|
const { overflowX, overflowY } = getComputedStyle(element);
|
|
347
310
|
return {
|
|
@@ -349,6 +312,28 @@ function isScrollable(element) {
|
|
|
349
312
|
horizontal: (overflowX === "scroll" || overflowX === "auto") && element.scrollWidth > element.clientWidth
|
|
350
313
|
};
|
|
351
314
|
}
|
|
315
|
+
function observeElementProp(element, property, callback) {
|
|
316
|
+
const elementPrototype = Object.getPrototypeOf(element);
|
|
317
|
+
if (elementPrototype.hasOwnProperty(property)) {
|
|
318
|
+
const descriptor = Object.getOwnPropertyDescriptor(elementPrototype, property);
|
|
319
|
+
Object.defineProperty(element, property, {
|
|
320
|
+
get: function() {
|
|
321
|
+
var _a;
|
|
322
|
+
return (_a = descriptor == null ? void 0 : descriptor.get) == null ? void 0 : _a.apply(this, arguments);
|
|
323
|
+
},
|
|
324
|
+
set: function() {
|
|
325
|
+
var _a;
|
|
326
|
+
const oldValue = this[property];
|
|
327
|
+
(_a = descriptor == null ? void 0 : descriptor.set) == null ? void 0 : _a.apply(this, arguments);
|
|
328
|
+
const newValue = this[property];
|
|
329
|
+
if (typeof callback === "function") {
|
|
330
|
+
callback.bind(this, oldValue, newValue);
|
|
331
|
+
}
|
|
332
|
+
return newValue;
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
352
337
|
|
|
353
338
|
// lib/misc.ts
|
|
354
339
|
function autoPlural(word, num) {
|
|
@@ -380,13 +365,43 @@ function fetchAdvanced(_0) {
|
|
|
380
365
|
return res;
|
|
381
366
|
});
|
|
382
367
|
}
|
|
383
|
-
function insertValues(
|
|
384
|
-
return
|
|
368
|
+
function insertValues(input, ...values) {
|
|
369
|
+
return input.replace(/%\d/gm, (match) => {
|
|
385
370
|
var _a, _b;
|
|
386
371
|
const argIndex = Number(match.substring(1)) - 1;
|
|
387
372
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
388
373
|
});
|
|
389
374
|
}
|
|
375
|
+
function compress(input, compressionFormat, outputType = "base64") {
|
|
376
|
+
return __async(this, null, function* () {
|
|
377
|
+
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
378
|
+
const comp = new CompressionStream(compressionFormat);
|
|
379
|
+
const writer = comp.writable.getWriter();
|
|
380
|
+
writer.write(byteArray);
|
|
381
|
+
writer.close();
|
|
382
|
+
const buf = yield new Response(comp.readable).arrayBuffer();
|
|
383
|
+
return outputType === "arrayBuffer" ? buf : ab2str(buf);
|
|
384
|
+
});
|
|
385
|
+
}
|
|
386
|
+
function decompress(input, compressionFormat, outputType = "string") {
|
|
387
|
+
return __async(this, null, function* () {
|
|
388
|
+
const byteArray = typeof input === "string" ? str2ab(input) : input;
|
|
389
|
+
const decomp = new DecompressionStream(compressionFormat);
|
|
390
|
+
const writer = decomp.writable.getWriter();
|
|
391
|
+
writer.write(byteArray);
|
|
392
|
+
writer.close();
|
|
393
|
+
const buf = yield new Response(decomp.readable).arrayBuffer();
|
|
394
|
+
return outputType === "arrayBuffer" ? buf : new TextDecoder().decode(buf);
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
function ab2str(buf) {
|
|
398
|
+
return getUnsafeWindow().btoa(
|
|
399
|
+
new Uint8Array(buf).reduce((data, byte) => data + String.fromCharCode(byte), "")
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
function str2ab(str) {
|
|
403
|
+
return Uint8Array.from(getUnsafeWindow().atob(str), (c) => c.charCodeAt(0));
|
|
404
|
+
}
|
|
390
405
|
|
|
391
406
|
// lib/SelectorObserver.ts
|
|
392
407
|
var SelectorObserver = class {
|
|
@@ -558,10 +573,11 @@ exports.ConfigManager = ConfigManager;
|
|
|
558
573
|
exports.SelectorObserver = SelectorObserver;
|
|
559
574
|
exports.addGlobalStyle = addGlobalStyle;
|
|
560
575
|
exports.addParent = addParent;
|
|
561
|
-
exports.amplifyMedia = amplifyMedia;
|
|
562
576
|
exports.autoPlural = autoPlural;
|
|
563
577
|
exports.clamp = clamp;
|
|
578
|
+
exports.compress = compress;
|
|
564
579
|
exports.debounce = debounce;
|
|
580
|
+
exports.decompress = decompress;
|
|
565
581
|
exports.fetchAdvanced = fetchAdvanced;
|
|
566
582
|
exports.getUnsafeWindow = getUnsafeWindow;
|
|
567
583
|
exports.insertAfter = insertAfter;
|
|
@@ -570,6 +586,7 @@ exports.interceptEvent = interceptEvent;
|
|
|
570
586
|
exports.interceptWindowEvent = interceptWindowEvent;
|
|
571
587
|
exports.isScrollable = isScrollable;
|
|
572
588
|
exports.mapRange = mapRange;
|
|
589
|
+
exports.observeElementProp = observeElementProp;
|
|
573
590
|
exports.openInNewTab = openInNewTab;
|
|
574
591
|
exports.pauseFor = pauseFor;
|
|
575
592
|
exports.preloadImages = preloadImages;
|
package/dist/index.mjs
CHANGED
|
@@ -303,43 +303,6 @@ function interceptEvent(eventObject, eventName, predicate = () => true) {
|
|
|
303
303
|
function interceptWindowEvent(eventName, predicate = () => true) {
|
|
304
304
|
return interceptEvent(getUnsafeWindow(), eventName, predicate);
|
|
305
305
|
}
|
|
306
|
-
function amplifyMedia(mediaElement, initialGain = 1) {
|
|
307
|
-
const context = new (window.AudioContext || window.webkitAudioContext)();
|
|
308
|
-
const props = {
|
|
309
|
-
context,
|
|
310
|
-
sourceNode: context.createMediaElementSource(mediaElement),
|
|
311
|
-
gainNode: context.createGain(),
|
|
312
|
-
/** Sets the gain of the amplifying GainNode */
|
|
313
|
-
setGain(gain) {
|
|
314
|
-
props.gainNode.gain.value = gain;
|
|
315
|
-
},
|
|
316
|
-
/** Returns the current gain of the amplifying GainNode */
|
|
317
|
-
getGain() {
|
|
318
|
-
return props.gainNode.gain.value;
|
|
319
|
-
},
|
|
320
|
-
/** Whether the amplification is currently enabled */
|
|
321
|
-
enabled: false,
|
|
322
|
-
/** Enable the amplification for the first time or if it was disabled before */
|
|
323
|
-
enable() {
|
|
324
|
-
if (props.enabled)
|
|
325
|
-
return;
|
|
326
|
-
props.enabled = true;
|
|
327
|
-
props.sourceNode.connect(props.gainNode);
|
|
328
|
-
props.gainNode.connect(props.context.destination);
|
|
329
|
-
},
|
|
330
|
-
/** Disable the amplification */
|
|
331
|
-
disable() {
|
|
332
|
-
if (!props.enabled)
|
|
333
|
-
return;
|
|
334
|
-
props.enabled = false;
|
|
335
|
-
props.sourceNode.disconnect(props.gainNode);
|
|
336
|
-
props.gainNode.disconnect(props.context.destination);
|
|
337
|
-
props.sourceNode.connect(props.context.destination);
|
|
338
|
-
}
|
|
339
|
-
};
|
|
340
|
-
props.setGain(initialGain);
|
|
341
|
-
return props;
|
|
342
|
-
}
|
|
343
306
|
function isScrollable(element) {
|
|
344
307
|
const { overflowX, overflowY } = getComputedStyle(element);
|
|
345
308
|
return {
|
|
@@ -347,6 +310,28 @@ function isScrollable(element) {
|
|
|
347
310
|
horizontal: (overflowX === "scroll" || overflowX === "auto") && element.scrollWidth > element.clientWidth
|
|
348
311
|
};
|
|
349
312
|
}
|
|
313
|
+
function observeElementProp(element, property, callback) {
|
|
314
|
+
const elementPrototype = Object.getPrototypeOf(element);
|
|
315
|
+
if (elementPrototype.hasOwnProperty(property)) {
|
|
316
|
+
const descriptor = Object.getOwnPropertyDescriptor(elementPrototype, property);
|
|
317
|
+
Object.defineProperty(element, property, {
|
|
318
|
+
get: function() {
|
|
319
|
+
var _a;
|
|
320
|
+
return (_a = descriptor == null ? void 0 : descriptor.get) == null ? void 0 : _a.apply(this, arguments);
|
|
321
|
+
},
|
|
322
|
+
set: function() {
|
|
323
|
+
var _a;
|
|
324
|
+
const oldValue = this[property];
|
|
325
|
+
(_a = descriptor == null ? void 0 : descriptor.set) == null ? void 0 : _a.apply(this, arguments);
|
|
326
|
+
const newValue = this[property];
|
|
327
|
+
if (typeof callback === "function") {
|
|
328
|
+
callback.bind(this, oldValue, newValue);
|
|
329
|
+
}
|
|
330
|
+
return newValue;
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
}
|
|
350
335
|
|
|
351
336
|
// lib/misc.ts
|
|
352
337
|
function autoPlural(word, num) {
|
|
@@ -378,13 +363,43 @@ function fetchAdvanced(_0) {
|
|
|
378
363
|
return res;
|
|
379
364
|
});
|
|
380
365
|
}
|
|
381
|
-
function insertValues(
|
|
382
|
-
return
|
|
366
|
+
function insertValues(input, ...values) {
|
|
367
|
+
return input.replace(/%\d/gm, (match) => {
|
|
383
368
|
var _a, _b;
|
|
384
369
|
const argIndex = Number(match.substring(1)) - 1;
|
|
385
370
|
return (_b = (_a = values[argIndex]) != null ? _a : match) == null ? void 0 : _b.toString();
|
|
386
371
|
});
|
|
387
372
|
}
|
|
373
|
+
function compress(input, compressionFormat, outputType = "base64") {
|
|
374
|
+
return __async(this, null, function* () {
|
|
375
|
+
const byteArray = typeof input === "string" ? new TextEncoder().encode(input) : input;
|
|
376
|
+
const comp = new CompressionStream(compressionFormat);
|
|
377
|
+
const writer = comp.writable.getWriter();
|
|
378
|
+
writer.write(byteArray);
|
|
379
|
+
writer.close();
|
|
380
|
+
const buf = yield new Response(comp.readable).arrayBuffer();
|
|
381
|
+
return outputType === "arrayBuffer" ? buf : ab2str(buf);
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
function decompress(input, compressionFormat, outputType = "string") {
|
|
385
|
+
return __async(this, null, function* () {
|
|
386
|
+
const byteArray = typeof input === "string" ? str2ab(input) : input;
|
|
387
|
+
const decomp = new DecompressionStream(compressionFormat);
|
|
388
|
+
const writer = decomp.writable.getWriter();
|
|
389
|
+
writer.write(byteArray);
|
|
390
|
+
writer.close();
|
|
391
|
+
const buf = yield new Response(decomp.readable).arrayBuffer();
|
|
392
|
+
return outputType === "arrayBuffer" ? buf : new TextDecoder().decode(buf);
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
function ab2str(buf) {
|
|
396
|
+
return getUnsafeWindow().btoa(
|
|
397
|
+
new Uint8Array(buf).reduce((data, byte) => data + String.fromCharCode(byte), "")
|
|
398
|
+
);
|
|
399
|
+
}
|
|
400
|
+
function str2ab(str) {
|
|
401
|
+
return Uint8Array.from(getUnsafeWindow().atob(str), (c) => c.charCodeAt(0));
|
|
402
|
+
}
|
|
388
403
|
|
|
389
404
|
// lib/SelectorObserver.ts
|
|
390
405
|
var SelectorObserver = class {
|
|
@@ -552,4 +567,4 @@ tr.getLanguage = () => {
|
|
|
552
567
|
return curLang;
|
|
553
568
|
};
|
|
554
569
|
|
|
555
|
-
export { ConfigManager, SelectorObserver, addGlobalStyle, addParent,
|
|
570
|
+
export { ConfigManager, SelectorObserver, addGlobalStyle, addParent, autoPlural, clamp, compress, debounce, decompress, fetchAdvanced, getUnsafeWindow, insertAfter, insertValues, interceptEvent, interceptWindowEvent, isScrollable, mapRange, observeElementProp, openInNewTab, pauseFor, preloadImages, randRange, randomId, randomItem, randomItemIndex, randomizeArray, takeRandomItem, tr };
|
|
@@ -34,13 +34,13 @@ export declare class SelectorObserver {
|
|
|
34
34
|
* @param baseElementSelector The selector of the element to observe
|
|
35
35
|
* @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
|
|
36
36
|
*/
|
|
37
|
-
constructor(baseElementSelector: string, options
|
|
37
|
+
constructor(baseElementSelector: string, options?: SelectorObserverOptions);
|
|
38
38
|
/**
|
|
39
39
|
* Creates a new SelectorObserver that will observe the children of the given base element for changes (only creation and deletion of elements by default)
|
|
40
40
|
* @param baseElement The element to observe
|
|
41
41
|
* @param options Fine-tune what triggers the MutationObserver's checking function - `subtree` and `childList` are set to true by default
|
|
42
42
|
*/
|
|
43
|
-
constructor(baseElement: Element, options
|
|
43
|
+
constructor(baseElement: Element, options?: SelectorObserverOptions);
|
|
44
44
|
private checkAllSelectors;
|
|
45
45
|
private checkSelector;
|
|
46
46
|
private debounce;
|
package/dist/lib/array.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/** Describes an array with at least one item */
|
|
2
|
-
export type NonEmptyArray<
|
|
2
|
+
export type NonEmptyArray<TArray = unknown> = [TArray, ...TArray[]];
|
|
3
3
|
/** Returns a random item from the passed array */
|
|
4
|
-
export declare function randomItem<
|
|
4
|
+
export declare function randomItem<TItem = unknown>(array: TItem[]): TItem | undefined;
|
|
5
5
|
/**
|
|
6
6
|
* Returns a tuple of a random item and its index from the passed array
|
|
7
7
|
* Returns `[undefined, undefined]` if the passed array is empty
|
|
8
8
|
*/
|
|
9
|
-
export declare function randomItemIndex<
|
|
9
|
+
export declare function randomItemIndex<TItem = unknown>(array: TItem[]): [item?: TItem, index?: number];
|
|
10
10
|
/** Returns a random item from the passed array and mutates the array to remove the item */
|
|
11
|
-
export declare function takeRandomItem<
|
|
11
|
+
export declare function takeRandomItem<TItem = unknown>(arr: TItem[]): TItem | undefined;
|
|
12
12
|
/** Returns a copy of the array with its items in a random order */
|
|
13
|
-
export declare function randomizeArray<
|
|
13
|
+
export declare function randomizeArray<TItem = unknown>(array: TItem[]): TItem[];
|
package/dist/lib/dom.d.ts
CHANGED
|
@@ -45,55 +45,18 @@ export declare function interceptEvent<TEvtObj extends EventTarget, TPredicateEv
|
|
|
45
45
|
* Calling this function will set the `Error.stackTraceLimit` to 1000 to ensure the stack trace is preserved.
|
|
46
46
|
*/
|
|
47
47
|
export declare function interceptWindowEvent<TEvtKey extends keyof WindowEventMap>(eventName: TEvtKey, predicate?: (event: WindowEventMap[TEvtKey]) => boolean): void;
|
|
48
|
-
/** An object which contains the results of {@linkcode amplifyMedia()} */
|
|
49
|
-
export type AmplifyMediaResult = ReturnType<typeof amplifyMedia>;
|
|
50
|
-
/**
|
|
51
|
-
* Amplifies the gain of the passed media element's audio by the specified value.
|
|
52
|
-
* This function supports any MediaElement instance like `<audio>` or `<video>`
|
|
53
|
-
*
|
|
54
|
-
* This is the audio processing workflow:
|
|
55
|
-
* `MediaElement (source)` => `GainNode (amplification)` => `destination`
|
|
56
|
-
*
|
|
57
|
-
* ⚠️ This function has to be run in response to a user interaction event, else the browser will reject it because of the strict autoplay policy.
|
|
58
|
-
* ⚠️ Make sure to call the returned function `enable()` after calling this function to actually enable the amplification.
|
|
59
|
-
* ⚠️ You should implement a safety limit by using the [`clamp()`](https://github.com/Sv443-Network/UserUtils#clamp) function to prevent any accidental bleeding eardrums.
|
|
60
|
-
*
|
|
61
|
-
* @param mediaElement The media element to amplify (e.g. `<audio>` or `<video>`)
|
|
62
|
-
* @param initialGain The initial gain to apply to the GainNode responsible for volume amplification (floating point number, default is `1.0`)
|
|
63
|
-
* @returns Returns an object with the following properties:
|
|
64
|
-
* **Important properties:**
|
|
65
|
-
* | Property | Description |
|
|
66
|
-
* | :-- | :-- |
|
|
67
|
-
* | `enable()` | Call to enable the amplification for the first time or re-enable it if it was disabled before |
|
|
68
|
-
* | `disable()` | Call to disable amplification |
|
|
69
|
-
* | `enabled` | Whether the amplification is currently enabled |
|
|
70
|
-
* | `setGain()` | Used to change the gain value from the default given by the parameter {@linkcode initialGain} |
|
|
71
|
-
* | `getGain()` | Returns the current gain value |
|
|
72
|
-
*
|
|
73
|
-
* **Other properties:**
|
|
74
|
-
* | Property | Description |
|
|
75
|
-
* | :-- | :-- |
|
|
76
|
-
* | `context` | The AudioContext instance |
|
|
77
|
-
* | `sourceNode` | A MediaElementSourceNode instance created from the passed {@linkcode mediaElement} |
|
|
78
|
-
* | `gainNode` | The GainNode instance used for volume amplification |
|
|
79
|
-
*/
|
|
80
|
-
export declare function amplifyMedia<TElem extends HTMLMediaElement>(mediaElement: TElem, initialGain?: number): {
|
|
81
|
-
context: AudioContext;
|
|
82
|
-
sourceNode: MediaElementAudioSourceNode;
|
|
83
|
-
gainNode: GainNode;
|
|
84
|
-
/** Sets the gain of the amplifying GainNode */
|
|
85
|
-
setGain(gain: number): void;
|
|
86
|
-
/** Returns the current gain of the amplifying GainNode */
|
|
87
|
-
getGain(): number;
|
|
88
|
-
/** Whether the amplification is currently enabled */
|
|
89
|
-
enabled: boolean;
|
|
90
|
-
/** Enable the amplification for the first time or if it was disabled before */
|
|
91
|
-
enable(): void;
|
|
92
|
-
/** Disable the amplification */
|
|
93
|
-
disable(): void;
|
|
94
|
-
};
|
|
95
48
|
/** Checks if an element is scrollable in the horizontal and vertical directions */
|
|
96
49
|
export declare function isScrollable(element: Element): {
|
|
97
50
|
vertical: boolean;
|
|
98
51
|
horizontal: boolean;
|
|
99
52
|
};
|
|
53
|
+
/**
|
|
54
|
+
* Executes the callback when the passed element's property changes.
|
|
55
|
+
* Contrary to an element's attributes, properties can usually not be observed with a MutationObserver.
|
|
56
|
+
* This function shims the getter and setter of the property to invoke the callback.
|
|
57
|
+
*
|
|
58
|
+
* [Source](https://stackoverflow.com/a/61975440)
|
|
59
|
+
* @param property The name of the property to observe
|
|
60
|
+
* @param callback Callback to execute when the value is changed
|
|
61
|
+
*/
|
|
62
|
+
export declare function observeElementProp<TElem extends Element = HTMLElement, TPropKey extends keyof TElem = keyof TElem>(element: TElem, property: TPropKey, callback: (oldVal: TElem[TPropKey], newVal: TElem[TPropKey]) => void): void;
|
package/dist/lib/misc.d.ts
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
export type Stringifiable = string | {
|
|
3
3
|
toString(): string;
|
|
4
4
|
};
|
|
5
|
+
/**
|
|
6
|
+
* A type that offers autocomplete for the passed union but also allows any arbitrary value of the same type to be passed.
|
|
7
|
+
* Supports unions of strings, numbers and objects.
|
|
8
|
+
*/
|
|
9
|
+
export type LooseUnion<TUnion extends string | number | object> = (TUnion) | (TUnion extends string ? (string & {}) : (TUnion extends number ? (number & {}) : (TUnion extends Record<keyof any, unknown> ? (object & {}) : never)));
|
|
10
|
+
/**
|
|
11
|
+
* A type that allows all strings except for empty ones
|
|
12
|
+
* @example
|
|
13
|
+
* function foo<T extends string>(bar: NonEmptyString<T>) {
|
|
14
|
+
* console.log(bar);
|
|
15
|
+
* }
|
|
16
|
+
*/
|
|
17
|
+
export type NonEmptyString<TString extends string> = TString extends "" ? never : TString;
|
|
5
18
|
/**
|
|
6
19
|
* Automatically appends an `s` to the passed {@linkcode word}, if {@linkcode num} is not equal to 1
|
|
7
20
|
* @param word A word in singular form, to auto-convert to plural
|
|
@@ -25,7 +38,15 @@ export declare function fetchAdvanced(url: string, options?: FetchAdvancedOpts):
|
|
|
25
38
|
/**
|
|
26
39
|
* Inserts the passed values into a string at the respective placeholders.
|
|
27
40
|
* The placeholder format is `%n`, where `n` is the 1-indexed argument number.
|
|
28
|
-
* @param
|
|
41
|
+
* @param input The string to insert the values into
|
|
29
42
|
* @param values The values to insert, in order, starting at `%1`
|
|
30
43
|
*/
|
|
31
|
-
export declare function insertValues(
|
|
44
|
+
export declare function insertValues(input: string, ...values: Stringifiable[]): string;
|
|
45
|
+
/** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as a base64 string */
|
|
46
|
+
export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "base64"): Promise<string>;
|
|
47
|
+
/** Compresses a string or an ArrayBuffer using the provided {@linkcode compressionFormat} and returns it as an ArrayBuffer */
|
|
48
|
+
export declare function compress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
|
|
49
|
+
/** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to a string */
|
|
50
|
+
export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType?: "string"): Promise<string>;
|
|
51
|
+
/** Decompresses a previously compressed base64 string or ArrayBuffer, with the format passed by {@linkcode compressionFormat}, converted to an ArrayBuffer */
|
|
52
|
+
export declare function decompress(input: string | ArrayBuffer, compressionFormat: CompressionFormat, outputType: "arrayBuffer"): Promise<ArrayBuffer>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sv443-network/userutils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
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",
|