@sv443-network/userutils 9.2.1 → 9.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +10 -6
- package/dist/index.cjs +242 -37
- package/dist/index.global.js +243 -38
- package/dist/index.js +241 -38
- package/dist/lib/DataStoreSerializer.d.ts +47 -10
- package/dist/lib/Debouncer.d.ts +2 -0
- package/dist/lib/Mixins.d.ts +127 -0
- package/dist/lib/NanoEmitter.d.ts +52 -5
- package/dist/lib/dom.d.ts +1 -1
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/misc.d.ts +6 -0
- package/dist/lib/translation.d.ts +1 -1
- package/package.json +18 -6
- package/README-summary.md +0 -213
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# @sv443-network/userutils
|
|
2
2
|
|
|
3
|
+
## 9.4.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 5075831: Added `Mixins` class for allowing multiple sources to modify values in a controlled way
|
|
8
|
+
- 99dedfd: Added unit tests
|
|
9
|
+
- 7530fd0: Added `Debouncer.getListeners()` method to get an array of all listener functions
|
|
10
|
+
- 48306da: Added `stores` filter parameter to the `DataStoreSerializer` methods `loadStoresData()`, `resetStoresData()` and `deleteStoresData()`
|
|
11
|
+
|
|
12
|
+
### Patch Changes
|
|
13
|
+
|
|
14
|
+
- f6a68c7: Fixed error when calling `interceptEvent()` in a non-GM environment
|
|
15
|
+
|
|
16
|
+
## 9.3.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- 89d7970: Added `DataStoreSerializer` methods `serializePartial()` and `deserializePartial()` for partial data exports and imports
|
|
21
|
+
- 5d71770: Added function `purifyObj()` to remove an object's prototype chain (i.e. omit all inherited properties like `toString`, `__proto__`, etc.)
|
|
22
|
+
|
|
3
23
|
## 9.2.1
|
|
4
24
|
|
|
5
25
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<!-- #region Description -->
|
|
4
4
|
## UserUtils
|
|
5
5
|
General purpose DOM/GreaseMonkey library that allows you to register listeners for when CSS selectors exist, intercept events, create persistent & synchronous data stores, modify the DOM more easily and much more.
|
|
6
|
-
Contains builtin TypeScript declarations. Supports ESM and CJS imports via a bundler and global declaration via `@require`
|
|
6
|
+
Contains builtin TypeScript declarations. Supports ESM and CJS imports via a bundler and global declaration via `@require` or `<script>`
|
|
7
7
|
The library works in any DOM environment with or without the [GreaseMonkey API](https://wiki.greasespot.net/Greasemonkey_Manual:API), but some features will be unavailable or limited.
|
|
8
8
|
|
|
9
9
|
You may want to check out my [template for userscripts in TypeScript](https://github.com/Sv443/Userscript.ts) that you can use to get started quickly. It also includes this library by default.
|
|
@@ -11,12 +11,14 @@ If you like using this library, please consider [supporting the development ❤
|
|
|
11
11
|
|
|
12
12
|
<br>
|
|
13
13
|
|
|
14
|
-
[](https://bundlephobia.com/package/@sv443-network/userutils)
|
|
15
|
+
[](https://coveralls.io/github/Sv443-Network/UserUtils)
|
|
16
|
+
[](https://bundlephobia.com/package/@sv443-network/userutils)
|
|
17
|
+
[](https://bundlephobia.com/package/@sv443-network/userutils)
|
|
17
18
|
|
|
18
|
-
[](https://dc.sv443.net/)
|
|
20
|
+
[](https://github.com/Sv443-Network/UserUtils/stargazers)
|
|
21
|
+
[](https://github.com/sponsors/Sv443)
|
|
20
22
|
|
|
21
23
|
<sup>
|
|
22
24
|
View the documentation of previous major releases:
|
|
@@ -63,6 +65,7 @@ View the documentation of previous major releases:
|
|
|
63
65
|
- [`DataStore`](./docs.md#datastore) - class that manages a hybrid sync & async persistent JSON database, including data migration
|
|
64
66
|
- [`DataStoreSerializer`](./docs.md#datastoreserializer) - class for importing & exporting data of multiple DataStore instances, including compression, checksumming and running migrations
|
|
65
67
|
- [`Dialog`](./docs.md#dialog) - class for creating custom modal dialogs with a promise-based API and a generic, default style
|
|
68
|
+
- [`Mixins`](./docs.md#mixins) - class for creating mixin functions that allow multiple sources to modify a target value in a highly flexible way
|
|
66
69
|
- [`NanoEmitter`](./docs.md#nanoemitter) - tiny event emitter class with a focus on performance and simplicity (based on [nanoevents](https://npmjs.com/package/nanoevents))
|
|
67
70
|
- [`Debouncer`](./docs.md#debouncer) - class for debouncing function calls with a given timeout
|
|
68
71
|
- [`debounce()`](./docs.md#debounce) - function wrapper for the Debouncer class for easier usage
|
|
@@ -77,6 +80,7 @@ View the documentation of previous major releases:
|
|
|
77
80
|
- [`consumeGen()`](./docs.md#consumegen) - consumes a ValueGen and returns the value
|
|
78
81
|
- [`consumeStringGen()`](./docs.md#consumestringgen) - consumes a StringGen and returns the string
|
|
79
82
|
- [`getListLength()`](./docs.md#getlistlength) - get the length of any object with a numeric `length`, `count` or `size` property
|
|
83
|
+
- [`purifyObj()`](./docs.md#purifyobj) - removes the prototype chain (all default properties like `toString`, `__proto__`, etc.) from an object
|
|
80
84
|
- [**Arrays:**](./docs.md#arrays)
|
|
81
85
|
- [`randomItem()`](./docs.md#randomitem) - returns a random item from an array
|
|
82
86
|
- [`randomItemIndex()`](./docs.md#randomitemindex) - returns a tuple of a random item and its index from an array
|
package/dist/index.cjs
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
var nanoevents = require('nanoevents');
|
|
4
4
|
|
|
5
5
|
var __defProp = Object.defineProperty;
|
|
6
|
+
var __defProps = Object.defineProperties;
|
|
7
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
8
|
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
7
9
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
10
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
@@ -18,6 +20,7 @@ var __spreadValues = (a, b) => {
|
|
|
18
20
|
}
|
|
19
21
|
return a;
|
|
20
22
|
};
|
|
23
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
21
24
|
var __objRest = (source, exclude) => {
|
|
22
25
|
var target = {};
|
|
23
26
|
for (var prop in source)
|
|
@@ -250,16 +253,16 @@ function addGlobalStyle(style) {
|
|
|
250
253
|
function preloadImages(srcUrls, rejects = false) {
|
|
251
254
|
const promises = srcUrls.map((src) => new Promise((res, rej) => {
|
|
252
255
|
const image = new Image();
|
|
253
|
-
image.src = src;
|
|
254
256
|
image.addEventListener("load", () => res(image));
|
|
255
257
|
image.addEventListener("error", (evt) => rejects && rej(evt));
|
|
258
|
+
image.src = src;
|
|
256
259
|
}));
|
|
257
260
|
return Promise.allSettled(promises);
|
|
258
261
|
}
|
|
259
262
|
function openInNewTab(href, background, additionalProps) {
|
|
260
|
-
var _a;
|
|
261
263
|
try {
|
|
262
|
-
(
|
|
264
|
+
if (typeof window.GM === "object")
|
|
265
|
+
GM.openInTab(href, background);
|
|
263
266
|
} catch (e) {
|
|
264
267
|
const openElem = document.createElement("a");
|
|
265
268
|
Object.assign(openElem, __spreadValues({
|
|
@@ -276,12 +279,17 @@ function openInNewTab(href, background, additionalProps) {
|
|
|
276
279
|
});
|
|
277
280
|
document.body.appendChild(openElem);
|
|
278
281
|
openElem.click();
|
|
279
|
-
setTimeout(
|
|
282
|
+
setTimeout(() => {
|
|
283
|
+
try {
|
|
284
|
+
openElem.remove();
|
|
285
|
+
} catch (e2) {
|
|
286
|
+
}
|
|
287
|
+
}, 0);
|
|
280
288
|
}
|
|
281
289
|
}
|
|
282
290
|
function interceptEvent(eventObject, eventName, predicate = () => true) {
|
|
283
291
|
var _a;
|
|
284
|
-
if (((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey" && (eventObject === window || eventObject === getUnsafeWindow()))
|
|
292
|
+
if (typeof window.GM === "object" && ((_a = GM == null ? undefined : GM.info) == null ? undefined : _a.scriptHandler) && GM.info.scriptHandler === "FireMonkey" && (eventObject === window || eventObject === getUnsafeWindow()))
|
|
285
293
|
throw new PlatformError("Intercepting window events is not supported on FireMonkey due to the isolated context the userscript runs in.");
|
|
286
294
|
Error.stackTraceLimit = Math.max(Error.stackTraceLimit, 100);
|
|
287
295
|
if (isNaN(Error.stackTraceLimit))
|
|
@@ -441,6 +449,8 @@ function computeHash(input, algorithm = "SHA-256") {
|
|
|
441
449
|
});
|
|
442
450
|
}
|
|
443
451
|
function randomId(length = 16, radix = 16, enhancedEntropy = false, randomCase = true) {
|
|
452
|
+
if (length < 1)
|
|
453
|
+
throw new RangeError("The length argument must be at least 1");
|
|
444
454
|
if (radix < 2 || radix > 36)
|
|
445
455
|
throw new RangeError("The radix argument must be between 2 and 36");
|
|
446
456
|
let arr = [];
|
|
@@ -747,14 +757,15 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
747
757
|
});
|
|
748
758
|
}
|
|
749
759
|
/**
|
|
750
|
-
* Serializes the data stores into a string.
|
|
760
|
+
* Serializes only a subset of the data stores into a string.
|
|
761
|
+
* @param stores An array of store IDs or functions that take a store ID and return a boolean
|
|
751
762
|
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
752
763
|
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
753
764
|
*/
|
|
754
|
-
|
|
765
|
+
serializePartial(stores, useEncoding = true, stringified = true) {
|
|
755
766
|
return __async(this, null, function* () {
|
|
756
767
|
const serData = [];
|
|
757
|
-
for (const storeInst of this.stores) {
|
|
768
|
+
for (const storeInst of this.stores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
|
|
758
769
|
const data = useEncoding && storeInst.encodingEnabled() ? yield storeInst.encodeData(JSON.stringify(storeInst.getData())) : JSON.stringify(storeInst.getData());
|
|
759
770
|
serData.push({
|
|
760
771
|
id: storeInst.id,
|
|
@@ -768,15 +779,25 @@ var DataStoreSerializer = class _DataStoreSerializer {
|
|
|
768
779
|
});
|
|
769
780
|
}
|
|
770
781
|
/**
|
|
771
|
-
*
|
|
782
|
+
* Serializes the data stores into a string.
|
|
783
|
+
* @param useEncoding Whether to encode the data using each DataStore's `encodeData()` method
|
|
784
|
+
* @param stringified Whether to return the result as a string or as an array of `SerializedDataStore` objects
|
|
785
|
+
*/
|
|
786
|
+
serialize(useEncoding = true, stringified = true) {
|
|
787
|
+
return __async(this, null, function* () {
|
|
788
|
+
return this.serializePartial(this.stores.map((s) => s.id), useEncoding, stringified);
|
|
789
|
+
});
|
|
790
|
+
}
|
|
791
|
+
/**
|
|
792
|
+
* Deserializes the data exported via {@linkcode serialize()} and imports only a subset into the DataStore instances.
|
|
772
793
|
* Also triggers the migration process if the data format has changed.
|
|
773
794
|
*/
|
|
774
|
-
|
|
795
|
+
deserializePartial(stores, data) {
|
|
775
796
|
return __async(this, null, function* () {
|
|
776
|
-
const deserStores = typeof
|
|
777
|
-
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.
|
|
797
|
+
const deserStores = typeof data === "string" ? JSON.parse(data) : data;
|
|
798
|
+
if (!Array.isArray(deserStores) || !deserStores.every(_DataStoreSerializer.isSerializedDataStoreObj))
|
|
778
799
|
throw new TypeError("Invalid serialized data format! Expected an array of SerializedDataStore objects.");
|
|
779
|
-
for (const storeData of deserStores) {
|
|
800
|
+
for (const storeData of deserStores.filter((s) => typeof stores === "function" ? stores(s.id) : stores.includes(s.id))) {
|
|
780
801
|
const storeInst = this.stores.find((s) => s.id === storeData.id);
|
|
781
802
|
if (!storeInst)
|
|
782
803
|
throw new Error(`DataStore instance with ID "${storeData.id}" not found! Make sure to provide it in the DataStoreSerializer constructor.`);
|
|
@@ -795,44 +816,71 @@ Has: ${checksum}`);
|
|
|
795
816
|
}
|
|
796
817
|
});
|
|
797
818
|
}
|
|
819
|
+
/**
|
|
820
|
+
* Deserializes the data exported via {@linkcode serialize()} and imports the data into all matching DataStore instances.
|
|
821
|
+
* Also triggers the migration process if the data format has changed.
|
|
822
|
+
*/
|
|
823
|
+
deserialize(data) {
|
|
824
|
+
return __async(this, null, function* () {
|
|
825
|
+
return this.deserializePartial(this.stores.map((s) => s.id), data);
|
|
826
|
+
});
|
|
827
|
+
}
|
|
798
828
|
/**
|
|
799
829
|
* Loads the persistent data of the DataStore instances into the in-memory cache.
|
|
800
830
|
* Also triggers the migration process if the data format has changed.
|
|
831
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be loaded
|
|
801
832
|
* @returns Returns a PromiseSettledResult array with the results of each DataStore instance in the format `{ id: string, data: object }`
|
|
802
833
|
*/
|
|
803
|
-
loadStoresData() {
|
|
834
|
+
loadStoresData(stores) {
|
|
804
835
|
return __async(this, null, function* () {
|
|
805
|
-
return Promise.allSettled(
|
|
806
|
-
(store) => __async(this, null, function* () {
|
|
836
|
+
return Promise.allSettled(
|
|
837
|
+
this.getStoresFiltered(stores).map((store) => __async(this, null, function* () {
|
|
807
838
|
return {
|
|
808
839
|
id: store.id,
|
|
809
840
|
data: yield store.loadData()
|
|
810
841
|
};
|
|
811
|
-
})
|
|
812
|
-
)
|
|
842
|
+
}))
|
|
843
|
+
);
|
|
813
844
|
});
|
|
814
845
|
}
|
|
815
|
-
/**
|
|
816
|
-
|
|
846
|
+
/**
|
|
847
|
+
* Resets the persistent and in-memory data of the DataStore instances to their default values.
|
|
848
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
849
|
+
*/
|
|
850
|
+
resetStoresData(stores) {
|
|
817
851
|
return __async(this, null, function* () {
|
|
818
|
-
return Promise.allSettled(
|
|
852
|
+
return Promise.allSettled(
|
|
853
|
+
this.getStoresFiltered(stores).map((store) => store.saveDefaultData())
|
|
854
|
+
);
|
|
819
855
|
});
|
|
820
856
|
}
|
|
821
857
|
/**
|
|
822
858
|
* Deletes the persistent data of the DataStore instances.
|
|
823
|
-
* Leaves the in-memory data untouched.
|
|
859
|
+
* Leaves the in-memory data untouched.
|
|
860
|
+
* @param stores An array of store IDs or a function that takes the store IDs and returns a boolean - if omitted, all stores will be affected
|
|
824
861
|
*/
|
|
825
|
-
deleteStoresData() {
|
|
862
|
+
deleteStoresData(stores) {
|
|
826
863
|
return __async(this, null, function* () {
|
|
827
|
-
return Promise.allSettled(
|
|
864
|
+
return Promise.allSettled(
|
|
865
|
+
this.getStoresFiltered(stores).map((store) => store.deleteData())
|
|
866
|
+
);
|
|
828
867
|
});
|
|
829
868
|
}
|
|
869
|
+
/** Checks if a given value is an array of SerializedDataStore objects */
|
|
870
|
+
static isSerializedDataStoreObjArray(obj) {
|
|
871
|
+
return Array.isArray(obj) && obj.every((o) => typeof o === "object" && o !== null && "id" in o && "data" in o && "formatVersion" in o && "encoded" in o);
|
|
872
|
+
}
|
|
830
873
|
/** Checks if a given value is a SerializedDataStore object */
|
|
831
|
-
static
|
|
874
|
+
static isSerializedDataStoreObj(obj) {
|
|
832
875
|
return typeof obj === "object" && obj !== null && "id" in obj && "data" in obj && "formatVersion" in obj && "encoded" in obj;
|
|
833
876
|
}
|
|
877
|
+
/** Returns the DataStore instances whose IDs match the provided array or function */
|
|
878
|
+
getStoresFiltered(stores) {
|
|
879
|
+
return this.stores.filter((s) => typeof stores === "undefined" ? true : Array.isArray(stores) ? stores.includes(s.id) : stores(s.id));
|
|
880
|
+
}
|
|
834
881
|
};
|
|
835
882
|
var NanoEmitter = class {
|
|
883
|
+
/** Creates a new instance of NanoEmitter - a lightweight event emitter with helper methods and a strongly typed event map */
|
|
836
884
|
constructor(options = {}) {
|
|
837
885
|
__publicField(this, "events", nanoevents.createNanoEvents());
|
|
838
886
|
__publicField(this, "eventUnsubscribes", []);
|
|
@@ -841,7 +889,27 @@ var NanoEmitter = class {
|
|
|
841
889
|
publicEmit: false
|
|
842
890
|
}, options);
|
|
843
891
|
}
|
|
844
|
-
/**
|
|
892
|
+
/**
|
|
893
|
+
* Subscribes to an event and calls the callback when it's emitted.
|
|
894
|
+
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
895
|
+
* @returns Returns a function that can be called to unsubscribe the event listener
|
|
896
|
+
* @example ```ts
|
|
897
|
+
* const emitter = new NanoEmitter<{
|
|
898
|
+
* foo: (bar: string) => void;
|
|
899
|
+
* }>({
|
|
900
|
+
* publicEmit: true,
|
|
901
|
+
* });
|
|
902
|
+
*
|
|
903
|
+
* let i = 0;
|
|
904
|
+
* const unsub = emitter.on("foo", (bar) => {
|
|
905
|
+
* // unsubscribe after 10 events:
|
|
906
|
+
* if(++i === 10) unsub();
|
|
907
|
+
* console.log(bar);
|
|
908
|
+
* });
|
|
909
|
+
*
|
|
910
|
+
* emitter.emit("foo", "bar");
|
|
911
|
+
* ```
|
|
912
|
+
*/
|
|
845
913
|
on(event, cb) {
|
|
846
914
|
let unsub;
|
|
847
915
|
const unsubProxy = () => {
|
|
@@ -854,19 +922,43 @@ var NanoEmitter = class {
|
|
|
854
922
|
this.eventUnsubscribes.push(unsub);
|
|
855
923
|
return unsubProxy;
|
|
856
924
|
}
|
|
857
|
-
/**
|
|
925
|
+
/**
|
|
926
|
+
* Subscribes to an event and calls the callback or resolves the Promise only once when it's emitted.
|
|
927
|
+
* @param event The event to subscribe to. Use `as "_"` in case your event names aren't thoroughly typed (like when using a template literal, e.g. \`event-${val}\` as "_")
|
|
928
|
+
* @param cb The callback to call when the event is emitted - if provided or not, the returned Promise will resolve with the event arguments
|
|
929
|
+
* @returns Returns a Promise that resolves with the event arguments when the event is emitted
|
|
930
|
+
* @example ```ts
|
|
931
|
+
* const emitter = new NanoEmitter<{
|
|
932
|
+
* foo: (bar: string) => void;
|
|
933
|
+
* }>();
|
|
934
|
+
*
|
|
935
|
+
* // Promise syntax:
|
|
936
|
+
* const [bar] = await emitter.once("foo");
|
|
937
|
+
* console.log(bar);
|
|
938
|
+
*
|
|
939
|
+
* // Callback syntax:
|
|
940
|
+
* emitter.once("foo", (bar) => console.log(bar));
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
858
943
|
once(event, cb) {
|
|
859
944
|
return new Promise((resolve) => {
|
|
860
945
|
let unsub;
|
|
861
946
|
const onceProxy = (...args) => {
|
|
862
|
-
unsub();
|
|
863
947
|
cb == null ? undefined : cb(...args);
|
|
948
|
+
unsub == null ? undefined : unsub();
|
|
864
949
|
resolve(args);
|
|
865
950
|
};
|
|
866
|
-
unsub = this.on(event, onceProxy);
|
|
951
|
+
unsub = this.events.on(event, onceProxy);
|
|
952
|
+
this.eventUnsubscribes.push(unsub);
|
|
867
953
|
});
|
|
868
954
|
}
|
|
869
|
-
/**
|
|
955
|
+
/**
|
|
956
|
+
* Emits an event on this instance.
|
|
957
|
+
* ⚠️ Needs `publicEmit` to be set to true in the NanoEmitter constructor or super() call!
|
|
958
|
+
* @param event The event to emit
|
|
959
|
+
* @param args The arguments to pass to the event listeners
|
|
960
|
+
* @returns Returns true if `publicEmit` is true and the event was emitted successfully
|
|
961
|
+
*/
|
|
870
962
|
emit(event, ...args) {
|
|
871
963
|
if (this.emitterOptions.publicEmit) {
|
|
872
964
|
this.events.emit(event, ...args);
|
|
@@ -874,7 +966,7 @@ var NanoEmitter = class {
|
|
|
874
966
|
}
|
|
875
967
|
return false;
|
|
876
968
|
}
|
|
877
|
-
/** Unsubscribes all event listeners */
|
|
969
|
+
/** Unsubscribes all event listeners from this instance */
|
|
878
970
|
unsubscribeAll() {
|
|
879
971
|
for (const unsub of this.eventUnsubscribes)
|
|
880
972
|
unsub();
|
|
@@ -914,6 +1006,10 @@ var Debouncer = class extends NanoEmitter {
|
|
|
914
1006
|
removeAllListeners() {
|
|
915
1007
|
this.listeners = [];
|
|
916
1008
|
}
|
|
1009
|
+
/** Returns all registered listeners */
|
|
1010
|
+
getListeners() {
|
|
1011
|
+
return this.listeners;
|
|
1012
|
+
}
|
|
917
1013
|
//#region timeout
|
|
918
1014
|
/** Sets the timeout for the debouncer */
|
|
919
1015
|
setTimeout(timeout) {
|
|
@@ -942,7 +1038,7 @@ var Debouncer = class extends NanoEmitter {
|
|
|
942
1038
|
const cl = (...a) => {
|
|
943
1039
|
this.queuedCall = undefined;
|
|
944
1040
|
this.emit("call", ...a);
|
|
945
|
-
this.listeners.forEach((l) => l.
|
|
1041
|
+
this.listeners.forEach((l) => l.call(this, ...a));
|
|
946
1042
|
};
|
|
947
1043
|
const setRepeatTimeout = () => {
|
|
948
1044
|
this.activeTimeout = setTimeout(() => {
|
|
@@ -1416,8 +1512,6 @@ function autoPlural(term, num, pluralType = "auto") {
|
|
|
1416
1512
|
return `${term}${n === 1 ? "" : "s"}`;
|
|
1417
1513
|
case "-ies":
|
|
1418
1514
|
return `${String(term).slice(0, -1)}${n === 1 ? "y" : "ies"}`;
|
|
1419
|
-
default:
|
|
1420
|
-
return String(term);
|
|
1421
1515
|
}
|
|
1422
1516
|
}
|
|
1423
1517
|
function insertValues(input, ...values) {
|
|
@@ -1472,6 +1566,115 @@ function consumeStringGen(strGen) {
|
|
|
1472
1566
|
function getListLength(obj, zeroOnInvalid = true) {
|
|
1473
1567
|
return "length" in obj ? obj.length : "size" in obj ? obj.size : "count" in obj ? obj.count : zeroOnInvalid ? 0 : NaN;
|
|
1474
1568
|
}
|
|
1569
|
+
function purifyObj(obj) {
|
|
1570
|
+
return Object.assign(/* @__PURE__ */ Object.create(null), obj);
|
|
1571
|
+
}
|
|
1572
|
+
|
|
1573
|
+
// lib/Mixins.ts
|
|
1574
|
+
var Mixins = class {
|
|
1575
|
+
/**
|
|
1576
|
+
* Creates a new Mixins instance.
|
|
1577
|
+
* @param config Configuration object to customize the behavior.
|
|
1578
|
+
*/
|
|
1579
|
+
constructor(config = {}) {
|
|
1580
|
+
/** List of all registered mixins */
|
|
1581
|
+
__publicField(this, "mixins", []);
|
|
1582
|
+
/** Default configuration object for mixins */
|
|
1583
|
+
__publicField(this, "defaultMixinCfg");
|
|
1584
|
+
/** Whether the priorities should auto-increment if not specified */
|
|
1585
|
+
__publicField(this, "autoIncPrioEnabled");
|
|
1586
|
+
/** The current auto-increment priority counter */
|
|
1587
|
+
__publicField(this, "autoIncPrioCounter", /* @__PURE__ */ new Map());
|
|
1588
|
+
var _a, _b, _c;
|
|
1589
|
+
this.defaultMixinCfg = purifyObj({
|
|
1590
|
+
priority: (_a = config.defaultPriority) != null ? _a : 0,
|
|
1591
|
+
stopPropagation: (_b = config.defaultStopPropagation) != null ? _b : false,
|
|
1592
|
+
signal: config.defaultSignal
|
|
1593
|
+
});
|
|
1594
|
+
this.autoIncPrioEnabled = (_c = config.autoIncrementPriority) != null ? _c : false;
|
|
1595
|
+
}
|
|
1596
|
+
//#region public
|
|
1597
|
+
/**
|
|
1598
|
+
* Adds a mixin function to the given {@linkcode mixinKey}.
|
|
1599
|
+
* If no priority is specified, it will be calculated via the protected method {@linkcode calcPriority()} based on the constructor configuration, or fall back to the default priority.
|
|
1600
|
+
* @param mixinKey The key to identify the mixin function.
|
|
1601
|
+
* @param mixinFn The function to be called to apply the mixin. The first argument is the input value, the second argument is the context object (if any).
|
|
1602
|
+
* @param config Configuration object to customize the mixin behavior, or just the priority if a number is passed.
|
|
1603
|
+
* @returns Returns a cleanup function, to be called when this mixin is no longer needed.
|
|
1604
|
+
*/
|
|
1605
|
+
add(mixinKey, mixinFn, config = purifyObj({})) {
|
|
1606
|
+
const calcPrio = typeof config === "number" ? config : this.calcPriority(mixinKey, config);
|
|
1607
|
+
const mixin = purifyObj(__spreadValues(__spreadValues(__spreadProps(__spreadValues({}, this.defaultMixinCfg), {
|
|
1608
|
+
key: mixinKey,
|
|
1609
|
+
fn: mixinFn
|
|
1610
|
+
}), typeof config === "object" ? config : {}), typeof calcPrio === "number" && !isNaN(calcPrio) ? { priority: calcPrio } : {}));
|
|
1611
|
+
this.mixins.push(mixin);
|
|
1612
|
+
const rem = () => {
|
|
1613
|
+
this.mixins = this.mixins.filter((m) => m !== mixin);
|
|
1614
|
+
};
|
|
1615
|
+
if (mixin.signal)
|
|
1616
|
+
mixin.signal.addEventListener("abort", rem, { once: true });
|
|
1617
|
+
return rem;
|
|
1618
|
+
}
|
|
1619
|
+
/** Returns a list of all added mixins with their keys and configuration objects, but not their functions */
|
|
1620
|
+
list() {
|
|
1621
|
+
return this.mixins.map((_a) => {
|
|
1622
|
+
var _b = _a, rest = __objRest(_b, ["fn"]);
|
|
1623
|
+
return rest;
|
|
1624
|
+
});
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Applies all mixins with the given key to the input value, respecting the priority and stopPropagation settings.
|
|
1628
|
+
* If additional context is set in the MixinMap, it will need to be passed as the third argument.
|
|
1629
|
+
* @returns The modified value after all mixins have been applied.
|
|
1630
|
+
*/
|
|
1631
|
+
resolve(mixinKey, inputValue, ...inputCtx) {
|
|
1632
|
+
const mixins = this.mixins.filter((m) => m.key === mixinKey);
|
|
1633
|
+
const sortedMixins = [...mixins].sort((a, b) => b.priority - a.priority);
|
|
1634
|
+
let result = inputValue;
|
|
1635
|
+
for (let i = 0; i < sortedMixins.length; i++) {
|
|
1636
|
+
const mixin = sortedMixins[i];
|
|
1637
|
+
result = mixin.fn(result, ...inputCtx);
|
|
1638
|
+
if (result instanceof Promise) {
|
|
1639
|
+
return (() => __async(this, null, function* () {
|
|
1640
|
+
result = yield result;
|
|
1641
|
+
if (mixin.stopPropagation)
|
|
1642
|
+
return result;
|
|
1643
|
+
for (let j = i + 1; j < sortedMixins.length; j++) {
|
|
1644
|
+
const mixin2 = sortedMixins[j];
|
|
1645
|
+
result = yield mixin2.fn(result, ...inputCtx);
|
|
1646
|
+
if (mixin2.stopPropagation)
|
|
1647
|
+
break;
|
|
1648
|
+
}
|
|
1649
|
+
return result;
|
|
1650
|
+
}))();
|
|
1651
|
+
} else if (mixin.stopPropagation)
|
|
1652
|
+
break;
|
|
1653
|
+
}
|
|
1654
|
+
return result;
|
|
1655
|
+
}
|
|
1656
|
+
//#region protected
|
|
1657
|
+
/** Calculates the priority for a mixin based on the given configuration and the current auto-increment state of the instance */
|
|
1658
|
+
calcPriority(mixinKey, config) {
|
|
1659
|
+
var _a;
|
|
1660
|
+
if (config.priority !== undefined)
|
|
1661
|
+
return undefined;
|
|
1662
|
+
if (!this.autoIncPrioEnabled)
|
|
1663
|
+
return (_a = config.priority) != null ? _a : this.defaultMixinCfg.priority;
|
|
1664
|
+
if (!this.autoIncPrioCounter.has(mixinKey))
|
|
1665
|
+
this.autoIncPrioCounter.set(mixinKey, this.defaultMixinCfg.priority);
|
|
1666
|
+
let prio = this.autoIncPrioCounter.get(mixinKey);
|
|
1667
|
+
while (this.mixins.some((m) => m.key === mixinKey && m.priority === prio))
|
|
1668
|
+
prio++;
|
|
1669
|
+
this.autoIncPrioCounter.set(mixinKey, prio + 1);
|
|
1670
|
+
return prio;
|
|
1671
|
+
}
|
|
1672
|
+
/** Removes all mixins with the given key */
|
|
1673
|
+
removeAll(mixinKey) {
|
|
1674
|
+
this.mixins.filter((m) => m.key === mixinKey);
|
|
1675
|
+
this.mixins = this.mixins.filter((m) => m.key !== mixinKey);
|
|
1676
|
+
}
|
|
1677
|
+
};
|
|
1475
1678
|
|
|
1476
1679
|
// lib/SelectorObserver.ts
|
|
1477
1680
|
var SelectorObserver = class {
|
|
@@ -1730,15 +1933,15 @@ function getFallbackLanguage() {
|
|
|
1730
1933
|
return fallbackLang;
|
|
1731
1934
|
}
|
|
1732
1935
|
function addTransform(transform) {
|
|
1733
|
-
const [
|
|
1936
|
+
const [regex, fn] = transform;
|
|
1734
1937
|
valTransforms.push({
|
|
1735
1938
|
fn,
|
|
1736
|
-
regex
|
|
1939
|
+
regex
|
|
1737
1940
|
});
|
|
1738
1941
|
}
|
|
1739
1942
|
function deleteTransform(patternOrFn) {
|
|
1740
1943
|
const idx = valTransforms.findIndex(
|
|
1741
|
-
(t) => typeof patternOrFn === "function" ? t.fn === patternOrFn :
|
|
1944
|
+
(t) => typeof patternOrFn === "function" ? t.fn === patternOrFn : t.regex === patternOrFn
|
|
1742
1945
|
);
|
|
1743
1946
|
if (idx !== -1) {
|
|
1744
1947
|
valTransforms.splice(idx, 1);
|
|
@@ -1815,6 +2018,7 @@ exports.DataStoreSerializer = DataStoreSerializer;
|
|
|
1815
2018
|
exports.Debouncer = Debouncer;
|
|
1816
2019
|
exports.Dialog = Dialog;
|
|
1817
2020
|
exports.MigrationError = MigrationError;
|
|
2021
|
+
exports.Mixins = Mixins;
|
|
1818
2022
|
exports.NanoEmitter = NanoEmitter;
|
|
1819
2023
|
exports.PlatformError = PlatformError;
|
|
1820
2024
|
exports.SelectorObserver = SelectorObserver;
|
|
@@ -1853,6 +2057,7 @@ exports.openInNewTab = openInNewTab;
|
|
|
1853
2057
|
exports.pauseFor = pauseFor;
|
|
1854
2058
|
exports.preloadImages = preloadImages;
|
|
1855
2059
|
exports.probeElementStyle = probeElementStyle;
|
|
2060
|
+
exports.purifyObj = purifyObj;
|
|
1856
2061
|
exports.randRange = randRange;
|
|
1857
2062
|
exports.randomId = randomId;
|
|
1858
2063
|
exports.randomItem = randomItem;
|