@actdim/utico 0.9.3 → 0.9.4
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/dist/array.es.js.map +1 -1
- package/dist/arrayExtensions.es.js.map +1 -1
- package/dist/cache/memoryCache.es.js.map +1 -1
- package/dist/cache/persistentCache.d.ts +16 -20
- package/dist/cache/persistentCache.d.ts.map +1 -1
- package/dist/cache/persistentCache.es.js +65 -73
- package/dist/cache/persistentCache.es.js.map +1 -1
- package/dist/dataFormats.es.js.map +1 -1
- package/dist/dateTimeDataFormat.es.js.map +1 -1
- package/dist/gfx/canvasUtils.es.js.map +1 -1
- package/dist/gfx/color.es.js.map +1 -1
- package/dist/i18n/cultures.es.js.map +1 -1
- package/dist/i18n/enUsCulture.es.js.map +1 -1
- package/dist/math.es.js.map +1 -1
- package/dist/metadata.es.js.map +1 -1
- package/dist/mutex.es.js.map +1 -1
- package/dist/patterns.es.js.map +1 -1
- package/dist/store/dataStore.d.ts +33 -0
- package/dist/store/dataStore.d.ts.map +1 -0
- package/dist/store/dataStore.es.js +49 -0
- package/dist/store/dataStore.es.js.map +1 -0
- package/dist/store/persistentStore.d.ts +20 -0
- package/dist/store/persistentStore.d.ts.map +1 -0
- package/dist/store/persistentStore.es.js +96 -0
- package/dist/store/persistentStore.es.js.map +1 -0
- package/dist/store/storeContracts.d.ts +6 -0
- package/dist/store/storeContracts.d.ts.map +1 -0
- package/dist/store/storeContracts.es.js +2 -0
- package/dist/store/storeContracts.es.js.map +1 -0
- package/dist/stringCore.es.js.map +1 -1
- package/dist/structEvent.es.js.map +1 -1
- package/dist/typeCore.es.js.map +1 -1
- package/dist/typeUtils.es.js.map +1 -1
- package/dist/utils.es.js.map +1 -1
- package/dist/watchable.es.js.map +1 -1
- package/package.json +3 -4
- package/dist/cache/cacheDb.d.ts +0 -30
- package/dist/cache/cacheDb.d.ts.map +0 -1
- package/dist/cache/cacheDb.es.js +0 -47
- package/dist/cache/cacheDb.es.js.map +0 -1
- package/dist/storage/persistentStorage.d.ts +0 -11
- package/dist/storage/persistentStorage.d.ts.map +0 -1
- package/dist/storage/persistentStorage.es.js +0 -25
- package/dist/storage/persistentStorage.es.js.map +0 -1
- package/dist/storage/storageContracts.d.ts +0 -6
- package/dist/storage/storageContracts.d.ts.map +0 -1
- package/dist/storage/storageContracts.es.js +0 -2
- package/dist/storage/storageContracts.es.js.map +0 -1
package/dist/array.es.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"array.es.js","sources":["
|
|
1
|
+
{"version":3,"file":"array.es.js","sources":["../src/array.ts"],"sourcesContent":["export function copyArray(src: any[], dst: any[], srcIndex = 0, dstIndex = 0, length?: number) { \r\n return dst.copy(src, srcIndex, dstIndex, length);\r\n}"],"names":["copyArray","src","dst","srcIndex","dstIndex","length"],"mappings":"AAAO,SAASA,EAAUC,GAAYC,GAAYC,IAAW,GAAGC,IAAW,GAAGC,GAAiB;AAC3F,SAAOH,EAAI,KAAKD,GAAKE,GAAUC,GAAUC,CAAM;AACnD;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"arrayExtensions.es.js","sources":["
|
|
1
|
+
{"version":3,"file":"arrayExtensions.es.js","sources":["../src/arrayExtensions.ts"],"sourcesContent":["\r\ninterface Array<T> {\r\n find(callback: (element: T, index: number, array: Array<T>) => boolean): T; // aka firstOrDefault\r\n unfold<TItem>(callback: (element: T) => Array<TItem>): Array<TItem>; // aka selectMany\r\n max<TItem>(selector: (element: T) => TItem, defaultValue?: any): TItem;\r\n min<TItem>(selector: (element: T) => TItem, defaultValue?: any): TItem;\r\n orderBy<TItem>(selector: (element: T) => TItem): Array<T>;\r\n groupBy(selector: (element: T) => string): { [key: string]: Array<T> };\r\n // groupBy(key: string): { [key: string]: Array<T> };\t\r\n orderByDesc<TItem>(selector: (element: T) => TItem): Array<T>;\r\n distinct(): Array<T>; // unique\r\n distinct<TItem>(selector: (element: T) => TItem): Array<T>; // distinctBy/uniqueBy\r\n // TODO: pushMany aka addRange\r\n /** NOTE: there is no native array copy method (all existing methods rely on spread) */\r\n copy(src: any[], srcIndex?: number, dstIndex?: number, length?: number): this; // copyFrom\r\n copyTo(dst: any[], srcIndex?: number, dstIndex?: number, length?: number): this;\r\n}\r\n\r\n// Comparers\r\nclass Sorters {\r\n static asc(a: any, b: any) {\r\n // comparison\r\n return (a === b) ? 0\r\n : (a > b) ? 1\r\n : -1;\r\n // if (a < b) {\r\n // return -1;\r\n // }\r\n // if (a > b) {\r\n // return 1;\r\n // }\r\n // // a must be equal to b\r\n // return 0;\r\n // localeCompare?\r\n // numeric: a - b\r\n }\r\n\r\n static desc(a: any, b: any) {\r\n return -Sorters.asc(a, b);\r\n // return Sorters.asc(b, a);\r\n }\r\n}\r\n\r\nArray.prototype.unfold = function (callback: (element: any) => any[]): any[] {\r\n return this.reduce((res, element) => {\r\n Array.prototype.push.apply(res, callback(element));\r\n return res;\r\n }, []);\r\n};\r\n\r\nArray.prototype.max = function (selector: (element: any) => any, defaultValue?: any): any {\r\n if (this.length == 0) {\r\n return defaultValue;\r\n }\r\n return this.map(selector).sort(Sorters.desc)[0];\r\n\r\n // return this.reduce((x, el) => {\r\n // let order = el.Order();\r\n // return x == undefined ? order : (order > x ? order : o);\r\n // }, undefined);\r\n};\r\n\r\nArray.prototype.min = function (selector: (element: any) => any, defaultValue?: any): any {\r\n if (this.length == 0) {\r\n return defaultValue;\r\n }\r\n return this.map(selector).sort(Sorters.asc)[0];\r\n};\r\n\r\nArray.prototype.orderBy = function (selector: (element: any) => any): any[] {\r\n return this.slice(0).sort((a, b) => Sorters.asc(selector(a), selector(b)));\r\n};\r\n\r\nArray.prototype.orderByDesc = function (selector: (element: any) => any): any[] {\r\n return this.slice(0).sort((a, b) => Sorters.desc(selector(a), selector(b)));\r\n};\r\n\r\n// Array.prototype.groupBy = function (key: string): { [key: string]: any[] } {\r\n// \treturn this.reduce((result, item) => {\r\n// \t\tconst value = item[key].toString();\r\n// \t\t(result[item[key]] = result[item[key]] || []).push(item);\r\n// \t\treturn result;\r\n// \t}, {});\r\n// };\r\n\r\nArray.prototype.groupBy = function (selector: (element: any) => string): { [key: string]: any[] } {\r\n return this.reduce((result, item) => {\r\n const value = selector(item); //.toString()\r\n (result[value] = result[value] || []).push(item);\r\n return result;\r\n }, {});\r\n};\r\n\r\nclass Filters {\r\n static notNull(element: any): boolean {\r\n return element != null;\r\n }\r\n\r\n static notUndefined(element: any): boolean { // notMissing\r\n return element != undefined;\r\n }\r\n\r\n static notEmpty(element: any): boolean {\r\n return element !== '';\r\n }\r\n\r\n // unique\r\n static distinct(element, index, self) {\r\n return self.indexOf(element) === index;\r\n }\r\n}\r\n\r\n// distinctBy/uniqueBy\r\nArray.prototype.distinct = function (selector?: (element: any) => any): any[] {\r\n if (!selector) {\r\n return this.filter(Filters.distinct);\r\n // return this.sort().filter(function (element, index, self) {\r\n // return !index || element != self[index - 1];\r\n // });\r\n }\r\n\r\n // let keys = {}; // elements/items\r\n // return this.filter(function (element) {\r\n // const key = selector(element);\r\n // return keys.hasOwnProperty(key) ? false : (keys[key] = true);\r\n // });\r\n\r\n let keys = []; // elements/items\r\n return this.filter(function (element) {\r\n const key = selector(element);\r\n return keys.indexOf(key) >= 0 ? false : keys.push(key);\r\n });\r\n};\r\n\r\n// copyFrom\r\nArray.prototype.copy = function (src: any[], srcIndex = 0, dstIndex = 0, length?: number) {\r\n return copyArray(src, this, srcIndex, dstIndex, length);\r\n}\r\n\r\nArray.prototype.copyTo = function (dst: any[], srcIndex = 0, dstIndex = 0, length?: number) {\r\n return copyArray(this, dst, srcIndex, dstIndex, length);\r\n}\r\n\r\nfunction copyArray(src: any[], dst: any[], srcIndex = 0, dstIndex = 0, length?: number) {\r\n if (srcIndex == undefined || srcIndex < 0) {\r\n srcIndex = 0;\r\n }\r\n if (dstIndex == undefined || dstIndex < 0) {\r\n dstIndex = 0;\r\n }\r\n if (length == undefined) {\r\n length = Math.min(src.length, src.length - srcIndex);\r\n }\r\n let j = dstIndex;\r\n for (let i = srcIndex; i < length; i++) {\r\n dst[j] = src[i];\r\n j++;\r\n }\r\n return dst;\r\n}"],"names":["Sorters","a","b","callback","res","element","selector","defaultValue","result","item","value","Filters","index","self","keys","key","src","srcIndex","dstIndex","length","copyArray","dst","j","i"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memoryCache.es.js","sources":["
|
|
1
|
+
{"version":3,"file":"memoryCache.es.js","sources":["../../src/cache/memoryCache.ts"],"sourcesContent":["export interface IMemoryCache<TKey = any, TValue = any> {\r\n get keys(): Iterable<TKey>;\r\n\tgetKeys: () => Iterable<TKey>;\r\n\r\n get: (key: TKey) => TValue;\r\n\r\n contains: (key: TKey) => boolean;\r\n\r\n remove: (key: TKey) => void;\r\n\r\n set: (key: TKey, valueOrValueFactory: TValue | (() => TValue)) => void;\r\n\r\n\tget values(): Iterable<TValue>;\r\n getValues: () => Iterable<TValue>;\r\n\r\n getOrSet: (key: TKey, valueOrValueFactory: TValue | (() => TValue)) => TValue;\r\n\r\n clear: () => void;\r\n\r\n\tget entries(): Iterable<[TKey, TValue]>;\r\n getEntries: () => Iterable<[TKey, TValue]>;\r\n}\r\n\r\n// TODO: remove class, create factory method\r\nexport class MemoryCache<TKey = any, TValue = any> implements IMemoryCache {\r\n private map: Map<TKey, TValue>;\r\n\r\n constructor() {\r\n this.map = new Map<TKey, TValue>();\r\n }\r\n\r\n get keys() {\r\n return this.map.keys();\r\n }\r\n\r\n getKeys() {\r\n return this.keys;\r\n }\r\n\r\n get(key: TKey) {\r\n return this.map.get(key);\r\n }\r\n\r\n contains(key: TKey) {\r\n return this.map.has(key);\r\n }\r\n\r\n remove(key: TKey) {\r\n this.map.delete(key);\r\n }\r\n\r\n set(key: TKey, valueOrValueFactory: TValue | (() => TValue)) {\r\n if (valueOrValueFactory instanceof Function) {\r\n this.map.set(key, valueOrValueFactory());\r\n } else {\r\n this.map.set(key, valueOrValueFactory);\r\n }\r\n }\r\n\r\n get values() {\r\n return this.getValues();\r\n }\r\n\r\n getValues() {\r\n return this.values;\r\n }\r\n\r\n getOrSet(key: TKey, valueOrValueFactory: TValue | (() => TValue)) {\r\n if (!this.contains(key)) {\r\n // this.set(key, valueOrValueFactory);\r\n\t\t\tif (valueOrValueFactory instanceof Function) {\r\n // typeof valueOrValueFactory === \"function\"\r\n this.map.set(key, valueOrValueFactory());\r\n } else {\r\n this.map.set(key, valueOrValueFactory);\r\n }\r\n }\r\n return this.get(key);\r\n }\r\n\r\n clear() {\r\n this.map.clear();\r\n }\r\n\r\n get size() {\r\n return this.map.size;\r\n }\r\n\r\n getEntries() {\r\n return this.entries;\r\n }\r\n\r\n get entries() {\r\n return this.map.entries();\r\n }\r\n}\r\n\r\nexport const globalMemoryCache = new MemoryCache();"],"names":["MemoryCache","key","valueOrValueFactory","globalMemoryCache"],"mappings":"AAwBO,MAAMA,EAA8D;AAAA,EAC/D;AAAA,EAER,cAAc;AACV,SAAK,0BAAU,IAAA;AAAA,EACnB;AAAA,EAEA,IAAI,OAAO;AACP,WAAO,KAAK,IAAI,KAAA;AAAA,EACpB;AAAA,EAEA,UAAU;AACN,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,IAAIC,GAAW;AACX,WAAO,KAAK,IAAI,IAAIA,CAAG;AAAA,EAC3B;AAAA,EAEA,SAASA,GAAW;AAChB,WAAO,KAAK,IAAI,IAAIA,CAAG;AAAA,EAC3B;AAAA,EAEA,OAAOA,GAAW;AACd,SAAK,IAAI,OAAOA,CAAG;AAAA,EACvB;AAAA,EAEA,IAAIA,GAAWC,GAA8C;AACzD,IAAIA,aAA+B,WAC/B,KAAK,IAAI,IAAID,GAAKC,EAAA,CAAqB,IAEvC,KAAK,IAAI,IAAID,GAAKC,CAAmB;AAAA,EAE7C;AAAA,EAEA,IAAI,SAAS;AACT,WAAO,KAAK,UAAA;AAAA,EAChB;AAAA,EAEA,YAAY;AACR,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,SAASD,GAAWC,GAA8C;AAC9D,WAAK,KAAK,SAASD,CAAG,MAEvBC,aAA+B,WAEtB,KAAK,IAAI,IAAID,GAAKC,EAAA,CAAqB,IAEvC,KAAK,IAAI,IAAID,GAAKC,CAAmB,IAGtC,KAAK,IAAID,CAAG;AAAA,EACvB;AAAA,EAEA,QAAQ;AACJ,SAAK,IAAI,MAAA;AAAA,EACb;AAAA,EAEA,IAAI,OAAO;AACP,WAAO,KAAK,IAAI;AAAA,EACpB;AAAA,EAEA,aAAa;AACT,WAAO,KAAK;AAAA,EAChB;AAAA,EAEA,IAAI,UAAU;AACV,WAAO,KAAK,IAAI,QAAA;AAAA,EACpB;AACJ;AAEO,MAAME,IAAoB,IAAIH,EAAA;"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { StructEventTarget } from '
|
|
1
|
+
import { IDataEntry, IDataItem } from '../store/dataStore';
|
|
2
|
+
import { StructEventTarget } from '../structEvent';
|
|
3
3
|
type Duration = number | {
|
|
4
4
|
seconds?: number;
|
|
5
5
|
minutes?: number;
|
|
@@ -14,7 +14,7 @@ export type CacheOptions = {
|
|
|
14
14
|
slidingExpiration?: Date | number;
|
|
15
15
|
};
|
|
16
16
|
export type CacheEvictionEvent = {
|
|
17
|
-
entry:
|
|
17
|
+
entry: IDataEntry;
|
|
18
18
|
keepAliveOptions?: CacheOptions;
|
|
19
19
|
};
|
|
20
20
|
type PersistentCacheEventStruct = {
|
|
@@ -25,26 +25,22 @@ export declare class PersistentCache extends StructEventTarget<PersistentCacheEv
|
|
|
25
25
|
private _isDisposed;
|
|
26
26
|
private _jobTimerId;
|
|
27
27
|
private readonly _options;
|
|
28
|
-
constructor(
|
|
28
|
+
constructor(name: string, options: PersistentCacheOptions);
|
|
29
29
|
scheduleServiceJob(): void;
|
|
30
|
-
|
|
30
|
+
deleteExpiredAsync(date?: Date): Promise<string[]>;
|
|
31
31
|
dispose(): void;
|
|
32
|
-
private
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
[key: string]: Readonly<
|
|
32
|
+
private execAsync;
|
|
33
|
+
getKeysAsync(): Promise<string[]>;
|
|
34
|
+
getAsync(key: string): Promise<Readonly<IDataEntry & IDataItem>>;
|
|
35
|
+
bulkGetAsync(ids: string[]): Promise<{
|
|
36
|
+
[key: string]: Readonly<IDataEntry & IDataItem>;
|
|
37
37
|
}>;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
bulkDelete(ids: string[]): Promise<void>;
|
|
45
|
-
set(id: string, value: any, options: CacheOptions): Promise<void>;
|
|
46
|
-
getOrSet(key: string, factory: () => any, options: CacheOptions): Promise<void>;
|
|
47
|
-
clear(): Promise<void>;
|
|
38
|
+
containsAsync(key: string): Promise<boolean>;
|
|
39
|
+
deleteAsync(id: string): Promise<void>;
|
|
40
|
+
bulkDeleteAsync(ids: string[]): Promise<void>;
|
|
41
|
+
setAsync(id: string, value: any, options: CacheOptions): Promise<void>;
|
|
42
|
+
getOrSetAsync(key: string, factory: () => any, options: CacheOptions): Promise<void>;
|
|
43
|
+
clearAsync(): Promise<void>;
|
|
48
44
|
}
|
|
49
45
|
export {};
|
|
50
46
|
//# sourceMappingURL=persistentCache.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistentCache.d.ts","sourceRoot":"","sources":["../../src/cache/persistentCache.ts"],"names":[],"mappings":"AACA,OAAO,
|
|
1
|
+
{"version":3,"file":"persistentCache.d.ts","sourceRoot":"","sources":["../../src/cache/persistentCache.ts"],"names":[],"mappings":"AACA,OAAO,EAAa,UAAU,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtE,OAAO,EAAe,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAG/D,KAAK,QAAQ,GAAG,MAAM,GAAG;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEhF,MAAM,MAAM,sBAAsB,GAAG;IACjC,cAAc,EAAE,MAAM,CAAC;CAC1B,CAAC;AAMF,MAAM,MAAM,YAAY,GAAG;IACvB,kBAAkB,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;IACnC,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,iBAAiB,CAAC,EAAE,IAAI,GAAG,MAAM,CAAC;CACrC,CAAC;AAGF,MAAM,MAAM,kBAAkB,GAAG;IAC7B,KAAK,EAAE,UAAU,CAAC;IAElB,gBAAgB,CAAC,EAAE,YAAY,CAAC;CACnC,CAAC;AAEF,KAAK,0BAA0B,GAAG;IAC9B,KAAK,EAAE,kBAAkB,CAAC;CAC7B,CAAC;AAKF,qBAAa,eAAgB,SAAQ,iBAAiB,CAAC,0BAA0B,CAAC;IAU9E,OAAO,CAAC,GAAG,CAAY;IAEvB,OAAO,CAAC,WAAW,CAAU;IAE7B,OAAO,CAAC,WAAW,CAAS;IAE5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAyB;gBAGtC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,sBAAsB;IAazD,kBAAkB;IAiBZ,kBAAkB,CAAC,IAAI,CAAC,EAAE,IAAI;IA8BpC,OAAO;YAuBO,SAAS;IAejB,YAAY;IAIZ,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAchE,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,CAAC,UAAU,GAAG,SAAS,CAAC,CAAA;KAAE,CAAC;IA2CzF,aAAa,CAAC,GAAG,EAAE,MAAM;IAQzB,WAAW,CAAC,EAAE,EAAE,MAAM;IAOtB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE;IAO7B,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,YAAY;IA6BtD,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,EAAE,OAAO,EAAE,YAAY;IAUpE,UAAU;CAQnB"}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { keyOf as c } from "../typeUtils.es.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { DataStore as o } from "../store/dataStore.es.js";
|
|
3
|
+
import { StructEventTarget as y, StructEvent as d } from "../structEvent.es.js";
|
|
4
|
+
import { v4 as h } from "uuid";
|
|
4
5
|
const u = {
|
|
5
6
|
cleanupTimeout: 1e3
|
|
6
7
|
};
|
|
7
|
-
class
|
|
8
|
+
class f extends y {
|
|
8
9
|
// https://demo.agektmr.com/storage/
|
|
9
10
|
// https://www.html5rocks.com/en/tutorials/offline/quota-research/
|
|
10
11
|
// https://www.raymondcamden.com/2015/04/17/indexeddb-and-limits
|
|
@@ -20,43 +21,45 @@ class p extends o {
|
|
|
20
21
|
// cleanupTimeout - serviceJobTimeout
|
|
21
22
|
constructor(t, e) {
|
|
22
23
|
if (super(), !t)
|
|
23
|
-
throw new Error("
|
|
24
|
-
this._isDisposed = !1, this._jobTimerId = null, this._db = t, this._options = { ...e, ...u }, this.scheduleServiceJob();
|
|
24
|
+
throw new Error("Name cannot be empty");
|
|
25
|
+
this._isDisposed = !1, this._jobTimerId = null, this._db = new o(t), this._options = { ...e, ...u }, this.scheduleServiceJob();
|
|
25
26
|
}
|
|
26
27
|
scheduleServiceJob() {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
28
|
+
if (this._options.cleanupTimeout) {
|
|
29
|
+
const t = async () => {
|
|
30
|
+
try {
|
|
31
|
+
await this.deleteExpiredAsync();
|
|
32
|
+
} catch (e) {
|
|
33
|
+
console.error("Cache cleanup failed:", e);
|
|
34
|
+
} finally {
|
|
35
|
+
setTimeout(t, this._options.cleanupTimeout);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
setTimeout(t, this._options.cleanupTimeout);
|
|
39
|
+
}
|
|
37
40
|
}
|
|
38
|
-
//
|
|
39
|
-
async
|
|
41
|
+
// evictExpiredAsync/clearExpiredAsync
|
|
42
|
+
async deleteExpiredAsync(t) {
|
|
40
43
|
const e = [];
|
|
41
|
-
return t || (t = /* @__PURE__ */ new Date()), await this.
|
|
42
|
-
const
|
|
43
|
-
for (const
|
|
44
|
-
const
|
|
44
|
+
return t || (t = /* @__PURE__ */ new Date()), await this.execAsync(async () => {
|
|
45
|
+
const s = await this._db.registry.where(c("expiresAt")).below(t.getTime()).toArray();
|
|
46
|
+
for (const a of s) {
|
|
47
|
+
const n = new d("evict", {
|
|
45
48
|
detail: {
|
|
46
|
-
entry:
|
|
49
|
+
entry: a
|
|
47
50
|
// keepAliveOptions: {}
|
|
48
51
|
},
|
|
49
52
|
target: this,
|
|
50
53
|
cancelable: !0
|
|
51
54
|
});
|
|
52
|
-
this.dispatchEvent(
|
|
55
|
+
this.dispatchEvent(n), await this._db.registry.delete(a.id), e.push(a.id);
|
|
53
56
|
}
|
|
54
57
|
}), e;
|
|
55
58
|
}
|
|
56
59
|
dispose() {
|
|
57
60
|
this._isDisposed || (this._isDisposed = !0, this._jobTimerId && (window.clearTimeout(this._jobTimerId), this._jobTimerId = null), this._db && (this._db.isOpen() && this._db.close(), this._db = null));
|
|
58
61
|
}
|
|
59
|
-
async
|
|
62
|
+
async execAsync(t) {
|
|
60
63
|
this._db.isOpen() || await this._db.open();
|
|
61
64
|
try {
|
|
62
65
|
return await t();
|
|
@@ -64,88 +67,77 @@ class p extends o {
|
|
|
64
67
|
throw this._db.isOpen(), e;
|
|
65
68
|
}
|
|
66
69
|
}
|
|
67
|
-
async
|
|
70
|
+
async getKeysAsync() {
|
|
68
71
|
return await this._db.registry.filter((t) => !0).primaryKeys();
|
|
69
72
|
}
|
|
70
|
-
async
|
|
71
|
-
return await this.
|
|
73
|
+
async getAsync(t) {
|
|
74
|
+
return await this.execAsync(async () => {
|
|
72
75
|
const e = await this._db.registry.get(t);
|
|
73
76
|
if (e) {
|
|
74
|
-
const
|
|
75
|
-
return { ...e, ...
|
|
77
|
+
const s = await this._db.data.get(t);
|
|
78
|
+
return { ...e, ...s };
|
|
76
79
|
}
|
|
77
80
|
return null;
|
|
78
81
|
});
|
|
79
82
|
}
|
|
80
83
|
// getMany
|
|
81
|
-
async
|
|
84
|
+
async bulkGetAsync(t) {
|
|
82
85
|
const e = {};
|
|
83
|
-
return await this.
|
|
84
|
-
const
|
|
85
|
-
for (const
|
|
86
|
-
e[
|
|
87
|
-
for (const
|
|
88
|
-
e[
|
|
86
|
+
return await this.execAsync(async () => {
|
|
87
|
+
const a = (await this._db.registry.bulkGet(t)).reduce((i, r, b) => (i[r.id] = r, i), {}), n = await this._db.data.bulkGet(t);
|
|
88
|
+
for (const i of n)
|
|
89
|
+
e[i.id] = { ...a[i.id], ...i }, delete a[i.id];
|
|
90
|
+
for (const i of Object.keys(a))
|
|
91
|
+
e[i] = { ...a[i], value: void 0 };
|
|
89
92
|
return e;
|
|
90
93
|
});
|
|
91
94
|
}
|
|
92
|
-
async
|
|
93
|
-
|
|
94
|
-
return i ? i.value : e;
|
|
95
|
-
}
|
|
96
|
-
// getManyValues
|
|
97
|
-
async bulkGetValues(t) {
|
|
98
|
-
const e = {}, i = this.bulkGet(t);
|
|
99
|
-
for (const s of Object.keys(i))
|
|
100
|
-
e[s] = i[s].value;
|
|
101
|
-
return e;
|
|
102
|
-
}
|
|
103
|
-
async contains(t) {
|
|
104
|
-
return await this.exec(async () => await this._db.registry.get(t) != null);
|
|
95
|
+
async containsAsync(t) {
|
|
96
|
+
return await this.execAsync(async () => await this._db.registry.get(t) != null);
|
|
105
97
|
}
|
|
106
|
-
async
|
|
107
|
-
await this.
|
|
98
|
+
async deleteAsync(t) {
|
|
99
|
+
await this.execAsync(async () => {
|
|
108
100
|
await this._db.registry.delete(t);
|
|
109
101
|
});
|
|
110
102
|
}
|
|
111
|
-
//
|
|
112
|
-
async
|
|
113
|
-
await this.
|
|
103
|
+
// deleteManyAsync
|
|
104
|
+
async bulkDeleteAsync(t) {
|
|
105
|
+
await this.execAsync(async () => {
|
|
114
106
|
await this._db.registry.bulkDelete(t);
|
|
115
107
|
});
|
|
116
108
|
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
109
|
+
// upsertAsync
|
|
110
|
+
async setAsync(t, e, s) {
|
|
111
|
+
return await this.execAsync(async () => {
|
|
112
|
+
const a = await this._db.registry.get(t), n = (/* @__PURE__ */ new Date()).getTime();
|
|
113
|
+
t || (t = h());
|
|
114
|
+
const i = typeof s.absoluteExpiration == "number" ? s.absoluteExpiration : s.absoluteExpiration?.getTime(), r = typeof s.slidingExpiration == "number" ? s.slidingExpiration : s.slidingExpiration?.getTime();
|
|
122
115
|
await this._db.registry.put({
|
|
123
116
|
id: t,
|
|
124
|
-
createdAt:
|
|
125
|
-
accessedAt:
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
slidingExpiration: n
|
|
117
|
+
createdAt: a ? a.createdAt : n,
|
|
118
|
+
accessedAt: n,
|
|
119
|
+
updatedAt: n,
|
|
120
|
+
expiresAt: i,
|
|
121
|
+
slidingExpiration: r
|
|
130
122
|
}), await this._db.data.put({
|
|
131
123
|
id: t,
|
|
132
124
|
value: e
|
|
133
125
|
});
|
|
134
126
|
});
|
|
135
127
|
}
|
|
136
|
-
//
|
|
137
|
-
async
|
|
138
|
-
await this.
|
|
128
|
+
// getOrAddAsync
|
|
129
|
+
async getOrSetAsync(t, e, s) {
|
|
130
|
+
await this.execAsync(async () => (await this.containsAsync(t) || await this.setAsync(t, e(), s), await this.getAsync(t)));
|
|
139
131
|
}
|
|
140
|
-
//
|
|
141
|
-
async
|
|
142
|
-
await this.
|
|
132
|
+
// clearAllAsync/evictAllAsync
|
|
133
|
+
async clearAsync() {
|
|
134
|
+
await this.execAsync(async () => {
|
|
143
135
|
await this._db.registry.clear(), await this._db.data.clear();
|
|
144
136
|
});
|
|
145
137
|
}
|
|
146
|
-
// TODO: support
|
|
138
|
+
// TODO: support bulkSetAsync
|
|
147
139
|
}
|
|
148
140
|
export {
|
|
149
|
-
|
|
141
|
+
f as PersistentCache
|
|
150
142
|
};
|
|
151
143
|
//# sourceMappingURL=persistentCache.es.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"persistentCache.es.js","sources":["D:/Src/my/actdim/public/utico/src/cache/persistentCache.ts"],"sourcesContent":["import { keyOf } from \"@/typeUtils\";\r\nimport { CacheDb, ICacheEntry, ICacheDataItem } from \"./cacheDb\";\r\nimport { StructEvent, StructEventTarget } from \"@/structEvent\";\r\nimport { v4 as uuid } from \"uuid\";\r\n\r\ntype Duration = number | { seconds?: number; minutes?: number; hours?: number };\r\n\r\nexport type PersistentCacheOptions = {\r\n cleanupTimeout: number;\r\n};\r\n\r\nconst defaultPersistentCacheOptions = {\r\n cleanupTimeout: 1000\r\n} satisfies PersistentCacheOptions;\r\n\r\nexport type CacheOptions = {\r\n absoluteExpiration?: Date | number;\r\n ttl?: Duration;\r\n slidingExpiration?: Date | number; // \"autoRenewOnUse\" pattern\r\n};\r\n\r\n// CacheEntryEvictionEvent\r\nexport type CacheEvictionEvent = {\r\n entry: ICacheEntry;\r\n // or optionsOverride?\r\n keepAliveOptions?: CacheOptions; // TODO: delayed eviction (pending eviction) after gracePeriod\r\n};\r\n\r\ntype PersistentCacheEventStruct = {\r\n evict: CacheEvictionEvent;\r\n};\r\n\r\n// TODO: remove class, create factory method\r\n// implements Struct<StructEventTarget<PersistentCacheEventStruct>>\r\n// PersistentCacheManager\r\nexport class PersistentCache extends StructEventTarget<PersistentCacheEventStruct> {\r\n // https://demo.agektmr.com/storage/\r\n // https://www.html5rocks.com/en/tutorials/offline/quota-research/\r\n // https://www.raymondcamden.com/2015/04/17/indexeddb-and-limits\r\n // https://github.com/jonnysmith1981/getIndexedDbSize/blob/master/getIndexedDbSize.js\r\n // https://developer.chrome.com/apps/offline_storage#query\r\n // https://golb.hplar.ch/2018/01/IndexedDB-programming-with-Dexie-js.html\r\n // http://www.forerunnerdb.com/licensing.html\r\n // https://github.com/ignasbernotas/dexie-relationships\r\n\r\n private _db: CacheDb;\r\n\r\n private _isDisposed: boolean;\r\n\r\n private _jobTimerId: number;\r\n\r\n private readonly _options: PersistentCacheOptions;\r\n\r\n // cleanupTimeout - serviceJobTimeout\r\n constructor(db: CacheDb, options: PersistentCacheOptions) {\r\n super();\r\n if (!db) {\r\n throw new Error(\"Database cannot be null\");\r\n }\r\n this._isDisposed = false;\r\n this._jobTimerId = null;\r\n\r\n this._db = db;\r\n // if (this._db.isOpen()) {\r\n // \tthis._db.close();\r\n // }\r\n\r\n // https://docs.nestjs.com/techniques/task-scheduling\r\n this._options = { ...options, ...defaultPersistentCacheOptions };\r\n\r\n this.scheduleServiceJob();\r\n }\r\n\r\n scheduleServiceJob() {\r\n const doWork = async () => {\r\n try {\r\n // purge expired entries\r\n await this.deleteExpired();\r\n } catch (err) {\r\n console.error(\"Cache cleanup failed:\", err);\r\n } finally {\r\n setTimeout(doWork, this._options.cleanupTimeout);\r\n }\r\n };\r\n\r\n setTimeout(doWork, this._options.cleanupTimeout);\r\n }\r\n\r\n // evictExpired/clearExpired\r\n async deleteExpired(date?: Date) {\r\n const result: string[] = []; // output ids\r\n if (!date) {\r\n date = new Date();\r\n }\r\n\r\n await this.exec(async () => {\r\n const entries = await this._db.registry.where(keyOf<ICacheEntry>(\"expiresAt\")).below(date.getTime()).toArray();\r\n for (const entry of entries) {\r\n const evt = new StructEvent<PersistentCacheEventStruct, this>(\"evict\", {\r\n detail: {\r\n entry: entry\r\n // keepAliveOptions: {}\r\n },\r\n target: this,\r\n cancelable: true\r\n });\r\n this.dispatchEvent(evt);\r\n // evt.defaultPrevented?\r\n // TODO: support evt.detail.keepAliveOptions\r\n await this._db.registry.delete(entry.id);\r\n // await this._db.data.delete(entry.id);\r\n result.push(entry.id);\r\n // TODO: use bulkDelete\r\n // TODO: use transaction\r\n }\r\n });\r\n return result;\r\n }\r\n\r\n dispose() {\r\n if (!this._isDisposed) {\r\n this._isDisposed = true;\r\n\r\n if (this._jobTimerId) {\r\n window.clearTimeout(this._jobTimerId);\r\n this._jobTimerId = null;\r\n }\r\n\r\n if (this._db) {\r\n // this.exec(async () => {\r\n // \t// ...\r\n // }).then(() => {\r\n // \tthis._db = null;\r\n // });\r\n if (this._db.isOpen()) {\r\n this._db.close();\r\n }\r\n this._db = null;\r\n }\r\n }\r\n }\r\n\r\n private async exec<T>(action: () => Promise<T>) {\r\n if (!this._db.isOpen()) {\r\n await this._db.open();\r\n }\r\n try {\r\n const result = await action();\r\n return result;\r\n } catch (err) {\r\n if (this._db.isOpen()) {\r\n // this._db.close(); // generally speaking: we don't (never) need to close a connection\r\n }\r\n throw err;\r\n }\r\n }\r\n\r\n async getKeys() {\r\n return await this._db.registry.filter((_) => true).primaryKeys();\r\n }\r\n\r\n async get(key: string): Promise<Readonly<ICacheEntry & ICacheDataItem>> {\r\n return await this.exec(async () => {\r\n const entry = await this._db.registry.get(key);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n if (entry) {\r\n const data = await this._db.data.get(key);\r\n // const data = await this._db.data.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n return { ...entry, ...data };\r\n }\r\n return null;\r\n });\r\n }\r\n\r\n // getMany\r\n async bulkGet(ids: string[]): Promise<{ [key: string]: Readonly<ICacheEntry & ICacheDataItem> }> {\r\n const result: { [key: string]: Readonly<ICacheEntry & ICacheDataItem> } = {};\r\n return await this.exec(async () => {\r\n // const entries = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).anyOf(ids).toArray();\r\n const entries = await this._db.registry.bulkGet(ids);\r\n const entryMap: { [key: string]: ICacheEntry } = entries.reduce((map, entry, i) => {\r\n map[entry.id] = entry;\r\n return map;\r\n }, {});\r\n\r\n // const dataItems = this._db.data.where(keyOf<ICacheEntry>(\"id\")).anyOf(ids);\r\n // await dataItems.each((dataItem) => {\r\n // result[dataItem.id] = { ...entryMap[dataItem.id], ...dataItem };\r\n // delete entryMap[dataItem.id];\r\n // });\r\n\r\n const dataItems = await this._db.data.bulkGet(ids);\r\n for (const dataItem of dataItems) {\r\n result[dataItem.id] = { ...entryMap[dataItem.id], ...dataItem };\r\n delete entryMap[dataItem.id];\r\n }\r\n\r\n for (const key of Object.keys(entryMap)) {\r\n // abandoned/orphaned entries:\r\n result[key] = { ...entryMap[key], value: undefined };\r\n\r\n // Object.defineProperty(result[key], keyOf<ICacheDataItem>(\"value\"), {\r\n // writable: false,\r\n // get: function () {\r\n // throw new Error(\"Not found\");\r\n // }\r\n // });\r\n }\r\n\r\n return result;\r\n });\r\n }\r\n\r\n async getValue(key: string, defaultValue = undefined) {\r\n const item = await this.get(key);\r\n if (!item) {\r\n return defaultValue;\r\n } else {\r\n return item.value;\r\n }\r\n }\r\n\r\n // getManyValues\r\n async bulkGetValues(ids: string[]) {\r\n const result: { [kes: string]: any } = {};\r\n const items = this.bulkGet(ids);\r\n for (const key of Object.keys(items)) {\r\n result[key] = items[key].value;\r\n }\r\n return result;\r\n }\r\n\r\n async contains(key: string) {\r\n return await this.exec(async () => {\r\n const entry = await this._db.registry.get(key);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n return entry != undefined;\r\n });\r\n }\r\n\r\n async delete(id: string) {\r\n await this.exec(async () => {\r\n await this._db.registry.delete(id);\r\n });\r\n }\r\n\r\n // deleteMany\r\n async bulkDelete(ids: string[]) {\r\n await this.exec(async () => {\r\n await this._db.registry.bulkDelete(ids);\r\n });\r\n }\r\n\r\n async set(id: string, value: any, options: CacheOptions) {\r\n return await this.exec(async () => {\r\n const entry = await this._db.registry.get(id);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n const now = new Date().getTime();\r\n if (!id) {\r\n id = uuid();\r\n }\r\n const expiresAt =\r\n typeof options.absoluteExpiration === \"number\" ? options.absoluteExpiration : options.absoluteExpiration?.getTime();\r\n const slidingExpiration =\r\n typeof options.slidingExpiration === \"number\" ? options.slidingExpiration : options.slidingExpiration?.getTime();\r\n\r\n await this._db.registry.put({\r\n id: id,\r\n createdAt: entry ? entry.createdAt : now,\r\n accessedAt: entry ? entry.accessedAt : null, // now\r\n // updatedAt: now,\r\n expiresAt: expiresAt,\r\n slidingExpiration: slidingExpiration\r\n });\r\n await this._db.data.put({\r\n id: id,\r\n value: value\r\n });\r\n });\r\n }\r\n\r\n // getOrUpdate\r\n async getOrSet(key: string, factory: () => any, options: CacheOptions) {\r\n await this.exec(async () => {\r\n if (!(await this.contains(key))) {\r\n await this.set(key, factory(), options);\r\n }\r\n return await this.get(key);\r\n });\r\n }\r\n\r\n // clearAll/evictAll\r\n async clear() {\r\n await this.exec(async () => {\r\n await this._db.registry.clear();\r\n await this._db.data.clear();\r\n });\r\n }\r\n\r\n // TODO: support update bulkUpdate, bulkSet\r\n}\r\n\r\n// https://medium.com/square-corner-blog/useful-tools-headless-chrome-puppeteer-for-browser-automation-testing-1ac7707bad40\r\n// https://developers.google.com/web/updates/2017/06/headless-karma-mocha-chai?hl=ru\r\n// https://github.com/puppeteer/puppeteer\r\n// https://medium.com/web-standards/puppeteer-crawl-to-markdown-7752dff36b68\r\n"],"names":["defaultPersistentCacheOptions","PersistentCache","StructEventTarget","db","options","doWork","err","date","result","entries","keyOf","entry","evt","StructEvent","action","_","key","data","ids","entryMap","map","i","dataItems","dataItem","defaultValue","item","items","id","value","now","uuid","expiresAt","slidingExpiration","factory"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"persistentCache.es.js","sources":["../../src/cache/persistentCache.ts"],"sourcesContent":["import { keyOf } from \"@/typeUtils\";\r\nimport { DataStore, IDataEntry, IDataItem } from \"../store/dataStore\";\r\nimport { StructEvent, StructEventTarget } from \"@/structEvent\";\r\nimport { v4 as uuid } from \"uuid\";\r\n\r\ntype Duration = number | { seconds?: number; minutes?: number; hours?: number };\r\n\r\nexport type PersistentCacheOptions = {\r\n cleanupTimeout: number;\r\n};\r\n\r\nconst defaultPersistentCacheOptions = {\r\n cleanupTimeout: 1000\r\n} satisfies PersistentCacheOptions;\r\n\r\nexport type CacheOptions = {\r\n absoluteExpiration?: Date | number;\r\n ttl?: Duration;\r\n slidingExpiration?: Date | number; // \"autoRenewOnUse\" pattern\r\n};\r\n\r\n// CacheEntryEvictionEvent\r\nexport type CacheEvictionEvent = {\r\n entry: IDataEntry;\r\n // or optionsOverride?\r\n keepAliveOptions?: CacheOptions; // TODO: delayed eviction (pending eviction) after gracePeriod\r\n};\r\n\r\ntype PersistentCacheEventStruct = {\r\n evict: CacheEvictionEvent;\r\n};\r\n\r\n// TODO: remove class, create factory method\r\n// implements Struct<StructEventTarget<PersistentCacheEventStruct>>\r\n// PersistentCacheManager\r\nexport class PersistentCache extends StructEventTarget<PersistentCacheEventStruct> {\r\n // https://demo.agektmr.com/storage/\r\n // https://www.html5rocks.com/en/tutorials/offline/quota-research/\r\n // https://www.raymondcamden.com/2015/04/17/indexeddb-and-limits\r\n // https://github.com/jonnysmith1981/getIndexedDbSize/blob/master/getIndexedDbSize.js\r\n // https://developer.chrome.com/apps/offline_storage#query\r\n // https://golb.hplar.ch/2018/01/IndexedDB-programming-with-Dexie-js.html\r\n // http://www.forerunnerdb.com/licensing.html\r\n // https://github.com/ignasbernotas/dexie-relationships\r\n\r\n private _db: DataStore;\r\n\r\n private _isDisposed: boolean;\r\n\r\n private _jobTimerId: number;\r\n\r\n private readonly _options: PersistentCacheOptions;\r\n\r\n // cleanupTimeout - serviceJobTimeout\r\n constructor(name: string, options: PersistentCacheOptions) {\r\n super();\r\n if (!name) {\r\n throw new Error(\"Name cannot be empty\");\r\n }\r\n this._isDisposed = false;\r\n this._jobTimerId = null;\r\n this._db = new DataStore(name);\r\n // https://docs.nestjs.com/techniques/task-scheduling\r\n this._options = { ...options, ...defaultPersistentCacheOptions };\r\n this.scheduleServiceJob();\r\n }\r\n\r\n scheduleServiceJob() {\r\n if (this._options.cleanupTimeout) {\r\n const doWork = async () => {\r\n try {\r\n // purge expired entries\r\n await this.deleteExpiredAsync();\r\n } catch (err) {\r\n console.error(\"Cache cleanup failed:\", err);\r\n } finally {\r\n setTimeout(doWork, this._options.cleanupTimeout);\r\n }\r\n };\r\n setTimeout(doWork, this._options.cleanupTimeout);\r\n }\r\n }\r\n\r\n // evictExpiredAsync/clearExpiredAsync\r\n async deleteExpiredAsync(date?: Date) {\r\n const result: string[] = []; // output ids\r\n if (!date) {\r\n date = new Date();\r\n }\r\n\r\n await this.execAsync(async () => {\r\n const entries = await this._db.registry.where(keyOf<IDataEntry>(\"expiresAt\")).below(date.getTime()).toArray();\r\n for (const entry of entries) {\r\n const evt = new StructEvent<PersistentCacheEventStruct, this>(\"evict\", {\r\n detail: {\r\n entry: entry\r\n // keepAliveOptions: {}\r\n },\r\n target: this,\r\n cancelable: true\r\n });\r\n this.dispatchEvent(evt);\r\n // evt.defaultPrevented?\r\n // TODO: support evt.detail.keepAliveOptions\r\n await this._db.registry.delete(entry.id);\r\n // await this._db.data.delete(entry.id);\r\n result.push(entry.id);\r\n // TODO: use bulkDelete\r\n // TODO: use transaction\r\n }\r\n });\r\n return result;\r\n }\r\n\r\n dispose() {\r\n if (!this._isDisposed) {\r\n this._isDisposed = true;\r\n\r\n if (this._jobTimerId) {\r\n window.clearTimeout(this._jobTimerId);\r\n this._jobTimerId = null;\r\n }\r\n\r\n if (this._db) {\r\n // this.exec(async () => {\r\n // \t// ...\r\n // }).then(() => {\r\n // \tthis._db = null;\r\n // });\r\n if (this._db.isOpen()) {\r\n this._db.close();\r\n }\r\n this._db = null;\r\n }\r\n }\r\n }\r\n\r\n private async execAsync<T>(action: () => Promise<T>) {\r\n if (!this._db.isOpen()) {\r\n await this._db.open();\r\n }\r\n try {\r\n const result = await action();\r\n return result;\r\n } catch (err) {\r\n if (this._db.isOpen()) {\r\n // this._db.close(); // generally speaking: we don't (never) need to close a connection\r\n }\r\n throw err;\r\n }\r\n }\r\n\r\n async getKeysAsync() {\r\n return await this._db.registry.filter((_) => true).primaryKeys();\r\n }\r\n\r\n async getAsync(key: string): Promise<Readonly<IDataEntry & IDataItem>> {\r\n return await this.execAsync(async () => {\r\n const entry = await this._db.registry.get(key);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n if (entry) {\r\n const data = await this._db.data.get(key);\r\n // const data = await this._db.data.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n return { ...entry, ...data };\r\n }\r\n return null;\r\n });\r\n }\r\n\r\n // getMany\r\n async bulkGetAsync(ids: string[]): Promise<{ [key: string]: Readonly<IDataEntry & IDataItem> }> {\r\n const result: { [key: string]: Readonly<IDataEntry & IDataItem> } = {};\r\n return await this.execAsync(async () => {\r\n // const entries = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).anyOf(ids).toArray();\r\n const entries = await this._db.registry.bulkGet(ids);\r\n const entryMap: { [key: string]: IDataEntry } = entries.reduce((map, entry, i) => {\r\n map[entry.id] = entry;\r\n return map;\r\n }, {});\r\n\r\n // const dataItems = this._db.data.where(keyOf<ICacheEntry>(\"id\")).anyOf(ids);\r\n // await dataItems.each((dataItem) => {\r\n // result[dataItem.id] = { ...entryMap[dataItem.id], ...dataItem };\r\n // delete entryMap[dataItem.id];\r\n // });\r\n\r\n const dataItems = await this._db.data.bulkGet(ids);\r\n for (const dataItem of dataItems) {\r\n result[dataItem.id] = { ...entryMap[dataItem.id], ...dataItem };\r\n delete entryMap[dataItem.id];\r\n }\r\n\r\n // TODO: update cache entry \r\n // accessedAt,\r\n // updatedAt,\r\n // expiresAt // for sliding expiration\r\n\r\n for (const key of Object.keys(entryMap)) {\r\n // abandoned/orphaned entries:\r\n result[key] = { ...entryMap[key], value: undefined };\r\n\r\n // Object.defineProperty(result[key], keyOf<ICacheDataItem>(\"value\"), {\r\n // writable: false,\r\n // get: function () {\r\n // throw new Error(\"Not found\");\r\n // }\r\n // });\r\n }\r\n\r\n return result;\r\n });\r\n }\r\n\r\n async containsAsync(key: string) {\r\n return await this.execAsync(async () => {\r\n const entry = await this._db.registry.get(key);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n return entry != undefined;\r\n });\r\n }\r\n\r\n async deleteAsync(id: string) {\r\n await this.execAsync(async () => {\r\n await this._db.registry.delete(id);\r\n });\r\n }\r\n\r\n // deleteManyAsync\r\n async bulkDeleteAsync(ids: string[]) {\r\n await this.execAsync(async () => {\r\n await this._db.registry.bulkDelete(ids);\r\n });\r\n }\r\n\r\n // upsertAsync\r\n async setAsync(id: string, value: any, options: CacheOptions) {\r\n return await this.execAsync(async () => {\r\n const entry = await this._db.registry.get(id);\r\n // const entry = await this._db.registry.where(keyOf<ICacheEntry>(\"id\")).equals(key).first();\r\n const now = new Date().getTime();\r\n if (!id) {\r\n id = uuid();\r\n }\r\n const expiresAt =\r\n typeof options.absoluteExpiration === \"number\" ? options.absoluteExpiration : options.absoluteExpiration?.getTime();\r\n const slidingExpiration =\r\n typeof options.slidingExpiration === \"number\" ? options.slidingExpiration : options.slidingExpiration?.getTime();\r\n\r\n await this._db.registry.put({\r\n id: id,\r\n createdAt: entry ? entry.createdAt : now,\r\n accessedAt: now,\r\n updatedAt: now,\r\n expiresAt: expiresAt,\r\n slidingExpiration: slidingExpiration\r\n });\r\n await this._db.data.put({\r\n id: id,\r\n value: value\r\n });\r\n });\r\n }\r\n\r\n // getOrAddAsync\r\n async getOrSetAsync(key: string, factory: () => any, options: CacheOptions) {\r\n await this.execAsync(async () => {\r\n if (!(await this.containsAsync(key))) {\r\n await this.setAsync(key, factory(), options);\r\n }\r\n return await this.getAsync(key);\r\n });\r\n }\r\n\r\n // clearAllAsync/evictAllAsync\r\n async clearAsync() {\r\n await this.execAsync(async () => {\r\n await this._db.registry.clear();\r\n await this._db.data.clear();\r\n });\r\n }\r\n\r\n // TODO: support bulkSetAsync\r\n}\r\n\r\n// https://medium.com/square-corner-blog/useful-tools-headless-chrome-puppeteer-for-browser-automation-testing-1ac7707bad40\r\n// https://developers.google.com/web/updates/2017/06/headless-karma-mocha-chai?hl=ru\r\n// https://github.com/puppeteer/puppeteer\r\n// https://medium.com/web-standards/puppeteer-crawl-to-markdown-7752dff36b68\r\n"],"names":["defaultPersistentCacheOptions","PersistentCache","StructEventTarget","name","options","DataStore","doWork","err","date","result","entries","keyOf","entry","evt","StructEvent","action","_","key","data","ids","entryMap","map","i","dataItems","dataItem","id","value","now","uuid","expiresAt","slidingExpiration","factory"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dataFormats.es.js","sources":["
|
|
1
|
+
{"version":3,"file":"dataFormats.es.js","sources":["../src/dataFormats.ts"],"sourcesContent":["import dateTimeDataFormat from './dateTimeDataFormat';\r\nexport default {\r\n dateTime: dateTimeDataFormat\r\n};"],"names":["dataFormats","dateTimeDataFormat"],"mappings":";AACA,MAAAA,IAAe;AAAA,EACX,UAAUC;AACd;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dateTimeDataFormat.es.js","sources":["D:/Src/my/actdim/public/utico/src/dateTimeDataFormat.ts"],"sourcesContent":["import { Moment } from \"moment\";\r\nimport moment from \"moment\";\r\nimport cultures from \"./i18n/cultures\";\r\n\r\n// TODO: use Luxon\r\nconst dtFormats = cultures.invariant.dateTime.formats;\r\n\r\nexport interface IDateTimeDataFormat {\r\n serializationFormat: string;\r\n normalize: (source: string | number | Date) => Date;\r\n serialize: (source: string | number | Date | Moment) => string;\r\n deserialize: (value: string) => Moment;\r\n tryDeserialize: (value: string) => Moment;\r\n isValid: (source: string | number | Date) => boolean;\r\n}\r\n\r\nexport enum DateNumberFormat {\r\n UnixTimeMilliseconds,\r\n UnixTimeSeconds,\r\n OADate // OLE Automation Date\r\n}\r\n\r\nconst USE_LOCAL_TIME = false; // invariant dates\r\n\r\n// dotnet: \"yyyy-MM-ddTHH:mm:ss.FFF\"\r\nconst invariantFormat = \"YYYY-MM-DDTHH:mm:ss.SSS\";\r\nconst s11nFormat = \"YYYY-MM-DDTHH:mm:ss.SSS\"; // TODO: support USE_LOCAL_TIME\r\n\r\nconst m = USE_LOCAL_TIME ? moment : moment.utc;\r\nconst toDate = USE_LOCAL_TIME ? (m: Moment) => m.toDate() : (m: Moment) => new Date(m.format(invariantFormat));\r\n\r\n// https://stackoverflow.com/questions/15549823/oadate-to-milliseconds-timestamp-in-javascript\r\n/* Convert a Microsoft OADate to ECMAScript Date\r\n ** Treat all values as local.\r\n ** @param {string|number} oaDate - OADate value\r\n ** @returns {Date}\r\n */\r\nexport function getDateFromOADate(oaDate: number) {\r\n // Treat integer part is whole days\r\n const days = Math.floor(oaDate); // parseInt(oaDate + \"\")\r\n // Treat decimal part as part of 24hr day, always +ve\r\n const ms = Math.abs((oaDate - days) * 8.64e7); // +oaDate\r\n // Add days and add ms\r\n return new Date(1899, 11, 30 + days, 0, 0, 0, ms);\r\n}\r\n\r\n/* Convert an ECMAScript Date to a Microsoft OADate\r\n ** Treat all dates as local.\r\n ** @param {Date} date - Date to convert\r\n ** @returns {Date}\r\n */\r\nexport function getOADateFromDate(date: Date) {\r\n const temp = new Date(date);\r\n // Set temp to start of day and get whole days between dates\r\n const stDate = new Date(1899, 11, 30);\r\n const days = Math.round((temp.setHours(0, 0, 0, 0) - stDate.getTime()) / 8.64e7);\r\n // Get decimal part of day, OADate always assumes 24 hours in day\r\n const partDay = (Math.abs((date.getTime() - temp.getTime()) % 8.64e7) / 8.64e7).toFixed(10);\r\n return days + partDay.substr(1);\r\n}\r\n\r\nexport function getDateFromNumber(value: number, dateNumberFormat = DateNumberFormat.UnixTimeMilliseconds) {\r\n if (value == undefined) {\r\n return null;\r\n }\r\n switch (dateNumberFormat) {\r\n case DateNumberFormat.UnixTimeMilliseconds:\r\n return new Date(value);\r\n case DateNumberFormat.UnixTimeSeconds:\r\n return new Date(value * 1000);\r\n case DateNumberFormat.OADate:\r\n return getDateFromOADate(value);\r\n }\r\n}\r\n\r\nexport type DateValueFormats = {\r\n string?: string;\r\n number?: DateNumberFormat;\r\n};\r\n\r\nexport function toMoment(source: any, formats?: DateValueFormats) {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n let md: Moment;\r\n if (typeof source === \"string\") {\r\n md = parse(source, formats?.string);\r\n } else if (typeof source === \"number\") {\r\n md = moment(getDateFromNumber(source, formats?.number));\r\n } else if (source instanceof Date) {\r\n // moment.isDate?\r\n md = moment(source);\r\n } else {\r\n if (!moment.isMoment(source)) {\r\n // Invalid\r\n throw new Error(\"Unsupported Moment Source\");\r\n }\r\n md = source;\r\n }\r\n return md;\r\n}\r\n\r\nfunction parse(value: string, format?: string) {\r\n if (value == undefined) {\r\n return null;\r\n }\r\n if (format == undefined) {\r\n format = s11nFormat;\r\n }\r\n let md: Moment;\r\n if (format) {\r\n md = m(value, format, true);\r\n } else {\r\n md = m(value);\r\n // md = m(value, format, true); // ?\r\n }\r\n\r\n // assertInvariant?\r\n // !md.isSame(m(value))\r\n if (md.format(s11nFormat) !== m(value).format(s11nFormat)) {\r\n const errMsg = `Invalid date transport value: ${value}`;\r\n console.warn(errMsg);\r\n // throw new Error(errMsg);\r\n }\r\n if (!md.isValid()) {\r\n throw new Error(`Assertion. Invalid datetime format: ${value}. Expected format: ${format || s11nFormat}.`);\r\n }\r\n return md;\r\n}\r\n\r\n// dtFormats.dateTimeShort\r\nexport function formatDate(date: Date | moment.Moment, format?: string) {\r\n if (date == undefined) {\r\n return \"\";\r\n }\r\n const md = toMoment(date);\r\n if (format == undefined) {\r\n if (!md.hours() && !md.minutes() && !md.seconds()) {\r\n format = dtFormats.dateShort;\r\n } else if (md.milliseconds()) {\r\n // dtFormats.dateTime?\r\n format = dtFormats.dateTime24;\r\n } else {\r\n // dtFormats.dateTimeShort?\r\n format = dtFormats.dateTime24Short;\r\n }\r\n }\r\n return md.format(format);\r\n}\r\n\r\nconst dateTimeFormat = {\r\n serializationFormat: s11nFormat,\r\n isValid: (source: any) => {\r\n if (source == null) {\r\n return true; // no value, it is OK\r\n }\r\n if (typeof source === \"string\") {\r\n return !!parse(source, s11nFormat);\r\n }\r\n // if (typeof source === 'number') {\r\n // return true;\r\n // }\r\n if (source instanceof Date) {\r\n return true;\r\n }\r\n return false;\r\n },\r\n normalize: (source: string | number | Date | Moment) => {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n if (typeof source === \"string\") {\r\n const md = parse(source);\r\n // const md = parse(source, s11nFormat);\r\n source = md;\r\n } else if (typeof source === \"number\") {\r\n // source = getMomentFromUnixTime(source); // ?\r\n source = m(source);\r\n } else if (source instanceof Date) {\r\n // return source;\r\n // not moment.utc(source)!\r\n source = moment(source);\r\n } else {\r\n if (!moment.isMoment(source)) {\r\n // Invalid\r\n throw new Error(\"Unsupported source\");\r\n }\r\n }\r\n return toDate(source);\r\n },\r\n serialize: (source: string | number | Date | Moment, formats?: DateValueFormats) => {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n const md = toMoment(source, formats);\r\n return md.format(s11nFormat);\r\n },\r\n deserialize: (value: string) => {\r\n return parse(value);\r\n },\r\n tryDeserialize: (value: string) => {\r\n try {\r\n return dateTimeFormat.deserialize(value);\r\n } catch (err) {\r\n console.error(err);\r\n return null;\r\n }\r\n }\r\n} as IDateTimeDataFormat;\r\n\r\nexport default dateTimeFormat;\r\n"],"names":["dtFormats","cultures","DateNumberFormat","invariantFormat","s11nFormat","m","moment","toDate","getDateFromOADate","oaDate","days","ms","getOADateFromDate","date","temp","stDate","partDay","getDateFromNumber","value","dateNumberFormat","toMoment","source","formats","md","parse","format","errMsg","formatDate","dateTimeFormat","err"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dateTimeDataFormat.es.js","sources":["../src/dateTimeDataFormat.ts"],"sourcesContent":["import { Moment } from \"moment\";\r\nimport moment from \"moment\";\r\nimport cultures from \"./i18n/cultures\";\r\n\r\n// TODO: use Luxon\r\nconst dtFormats = cultures.invariant.dateTime.formats;\r\n\r\nexport interface IDateTimeDataFormat {\r\n serializationFormat: string;\r\n normalize: (source: string | number | Date) => Date;\r\n serialize: (source: string | number | Date | Moment) => string;\r\n deserialize: (value: string) => Moment;\r\n tryDeserialize: (value: string) => Moment;\r\n isValid: (source: string | number | Date) => boolean;\r\n}\r\n\r\nexport enum DateNumberFormat {\r\n UnixTimeMilliseconds,\r\n UnixTimeSeconds,\r\n OADate // OLE Automation Date\r\n}\r\n\r\nconst USE_LOCAL_TIME = false; // invariant dates\r\n\r\n// dotnet: \"yyyy-MM-ddTHH:mm:ss.FFF\"\r\nconst invariantFormat = \"YYYY-MM-DDTHH:mm:ss.SSS\";\r\nconst s11nFormat = \"YYYY-MM-DDTHH:mm:ss.SSS\"; // TODO: support USE_LOCAL_TIME\r\n\r\nconst m = USE_LOCAL_TIME ? moment : moment.utc;\r\nconst toDate = USE_LOCAL_TIME ? (m: Moment) => m.toDate() : (m: Moment) => new Date(m.format(invariantFormat));\r\n\r\n// https://stackoverflow.com/questions/15549823/oadate-to-milliseconds-timestamp-in-javascript\r\n/* Convert a Microsoft OADate to ECMAScript Date\r\n ** Treat all values as local.\r\n ** @param {string|number} oaDate - OADate value\r\n ** @returns {Date}\r\n */\r\nexport function getDateFromOADate(oaDate: number) {\r\n // Treat integer part is whole days\r\n const days = Math.floor(oaDate); // parseInt(oaDate + \"\")\r\n // Treat decimal part as part of 24hr day, always +ve\r\n const ms = Math.abs((oaDate - days) * 8.64e7); // +oaDate\r\n // Add days and add ms\r\n return new Date(1899, 11, 30 + days, 0, 0, 0, ms);\r\n}\r\n\r\n/* Convert an ECMAScript Date to a Microsoft OADate\r\n ** Treat all dates as local.\r\n ** @param {Date} date - Date to convert\r\n ** @returns {Date}\r\n */\r\nexport function getOADateFromDate(date: Date) {\r\n const temp = new Date(date);\r\n // Set temp to start of day and get whole days between dates\r\n const stDate = new Date(1899, 11, 30);\r\n const days = Math.round((temp.setHours(0, 0, 0, 0) - stDate.getTime()) / 8.64e7);\r\n // Get decimal part of day, OADate always assumes 24 hours in day\r\n const partDay = (Math.abs((date.getTime() - temp.getTime()) % 8.64e7) / 8.64e7).toFixed(10);\r\n return days + partDay.substr(1);\r\n}\r\n\r\nexport function getDateFromNumber(value: number, dateNumberFormat = DateNumberFormat.UnixTimeMilliseconds) {\r\n if (value == undefined) {\r\n return null;\r\n }\r\n switch (dateNumberFormat) {\r\n case DateNumberFormat.UnixTimeMilliseconds:\r\n return new Date(value);\r\n case DateNumberFormat.UnixTimeSeconds:\r\n return new Date(value * 1000);\r\n case DateNumberFormat.OADate:\r\n return getDateFromOADate(value);\r\n }\r\n}\r\n\r\nexport type DateValueFormats = {\r\n string?: string;\r\n number?: DateNumberFormat;\r\n};\r\n\r\nexport function toMoment(source: any, formats?: DateValueFormats) {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n let md: Moment;\r\n if (typeof source === \"string\") {\r\n md = parse(source, formats?.string);\r\n } else if (typeof source === \"number\") {\r\n md = moment(getDateFromNumber(source, formats?.number));\r\n } else if (source instanceof Date) {\r\n // moment.isDate?\r\n md = moment(source);\r\n } else {\r\n if (!moment.isMoment(source)) {\r\n // Invalid\r\n throw new Error(\"Unsupported Moment Source\");\r\n }\r\n md = source;\r\n }\r\n return md;\r\n}\r\n\r\nfunction parse(value: string, format?: string) {\r\n if (value == undefined) {\r\n return null;\r\n }\r\n if (format == undefined) {\r\n format = s11nFormat;\r\n }\r\n let md: Moment;\r\n if (format) {\r\n md = m(value, format, true);\r\n } else {\r\n md = m(value);\r\n // md = m(value, format, true); // ?\r\n }\r\n\r\n // assertInvariant?\r\n // !md.isSame(m(value))\r\n if (md.format(s11nFormat) !== m(value).format(s11nFormat)) {\r\n const errMsg = `Invalid date transport value: ${value}`;\r\n console.warn(errMsg);\r\n // throw new Error(errMsg);\r\n }\r\n if (!md.isValid()) {\r\n throw new Error(`Assertion. Invalid datetime format: ${value}. Expected format: ${format || s11nFormat}.`);\r\n }\r\n return md;\r\n}\r\n\r\n// dtFormats.dateTimeShort\r\nexport function formatDate(date: Date | moment.Moment, format?: string) {\r\n if (date == undefined) {\r\n return \"\";\r\n }\r\n const md = toMoment(date);\r\n if (format == undefined) {\r\n if (!md.hours() && !md.minutes() && !md.seconds()) {\r\n format = dtFormats.dateShort;\r\n } else if (md.milliseconds()) {\r\n // dtFormats.dateTime?\r\n format = dtFormats.dateTime24;\r\n } else {\r\n // dtFormats.dateTimeShort?\r\n format = dtFormats.dateTime24Short;\r\n }\r\n }\r\n return md.format(format);\r\n}\r\n\r\nconst dateTimeFormat = {\r\n serializationFormat: s11nFormat,\r\n isValid: (source: any) => {\r\n if (source == null) {\r\n return true; // no value, it is OK\r\n }\r\n if (typeof source === \"string\") {\r\n return !!parse(source, s11nFormat);\r\n }\r\n // if (typeof source === 'number') {\r\n // return true;\r\n // }\r\n if (source instanceof Date) {\r\n return true;\r\n }\r\n return false;\r\n },\r\n normalize: (source: string | number | Date | Moment) => {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n if (typeof source === \"string\") {\r\n const md = parse(source);\r\n // const md = parse(source, s11nFormat);\r\n source = md;\r\n } else if (typeof source === \"number\") {\r\n // source = getMomentFromUnixTime(source); // ?\r\n source = m(source);\r\n } else if (source instanceof Date) {\r\n // return source;\r\n // not moment.utc(source)!\r\n source = moment(source);\r\n } else {\r\n if (!moment.isMoment(source)) {\r\n // Invalid\r\n throw new Error(\"Unsupported source\");\r\n }\r\n }\r\n return toDate(source);\r\n },\r\n serialize: (source: string | number | Date | Moment, formats?: DateValueFormats) => {\r\n if (source == undefined) {\r\n return null;\r\n }\r\n const md = toMoment(source, formats);\r\n return md.format(s11nFormat);\r\n },\r\n deserialize: (value: string) => {\r\n return parse(value);\r\n },\r\n tryDeserialize: (value: string) => {\r\n try {\r\n return dateTimeFormat.deserialize(value);\r\n } catch (err) {\r\n console.error(err);\r\n return null;\r\n }\r\n }\r\n} as IDateTimeDataFormat;\r\n\r\nexport default dateTimeFormat;\r\n"],"names":["dtFormats","cultures","DateNumberFormat","invariantFormat","s11nFormat","m","moment","toDate","getDateFromOADate","oaDate","days","ms","getOADateFromDate","date","temp","stDate","partDay","getDateFromNumber","value","dateNumberFormat","toMoment","source","formats","md","parse","format","errMsg","formatDate","dateTimeFormat","err"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"canvasUtils.es.js","sources":["D:/Src/my/actdim/public/utico/src/gfx/canvasUtils.ts"],"sourcesContent":["const DOMURL = window.URL || window.webkitURL;\r\n\r\nexport function createCanvas(w: number, h: number /*, dpi?: number*/) {\r\n const canvas = document.createElementNS(\"http://www.w3.org/1999/xhtml\", \"canvas\") as HTMLCanvasElement;\r\n // if (!dpi) {\r\n // dpi = window.devicePixelRatio;\r\n // }\r\n // context2d\r\n const context = canvas.getContext(\"2d\");\r\n if (context) {\r\n // context.imageSmoothingEnabled = true;\r\n // context.mozImageSmoothingEnabled = true;\r\n // context.oImageSmoothingEnabled = true;\r\n // context.webkitImageSmoothingEnabled = true;\r\n context[\"imageSmoothingQuality\"] = \"high\";\r\n }\r\n canvas.width = w;\r\n // canvas.width = w * dpi;\r\n canvas.height = h;\r\n // canvas.height = h * dpi;\r\n\r\n // canvas.style.width = w + \"px\";\r\n // context.scale(dpi, dpi);\r\n return { canvas, context };\r\n}\r\n\r\nconst supportExtendedMetrics = \"actualBoundingBoxRight\" in TextMetrics.prototype;\r\n\r\nexport type TextSizeProvider = (fontSize: number) => [number, number];\r\n\r\nexport function fitText(\r\n ctx: CanvasRenderingContext2D,\r\n text = \"\",\r\n sizeProvider: TextSizeProvider,\r\n targetWidth = ctx.canvas.width,\r\n fontFamily = \"Arial\"\r\n) {\r\n let fontSize = 1;\r\n const updateFont = () => {\r\n ctx.font = fontSize + \"px \" + fontFamily;\r\n };\r\n updateFont();\r\n let width = getBBOxWidth(text);\r\n // first pass width increment = 1\r\n while (width && width <= targetWidth) {\r\n fontSize++;\r\n updateFont();\r\n width = getBBOxWidth(text);\r\n }\r\n // second pass, the other way around, with increment = -0.1\r\n while (width && width > targetWidth) {\r\n fontSize -= 0.1;\r\n updateFont();\r\n width = getBBOxWidth(text);\r\n }\r\n // revert to last valid step\r\n fontSize += 0.1;\r\n updateFont();\r\n\r\n // we need to measure where our bounding box actually starts\r\n const offsetLeft = ctx.measureText(text).actualBoundingBoxLeft || 0;\r\n const [x, y] = sizeProvider(fontSize);\r\n ctx.fillText(text, x + offsetLeft, y);\r\n\r\n function getBBOxWidth(text) {\r\n const measure = ctx.measureText(text);\r\n\r\n return supportExtendedMetrics ? measure.actualBoundingBoxLeft + measure.actualBoundingBoxRight : measure.width;\r\n }\r\n}\r\n\r\nfunction encodeUnicode(str: any) {\r\n // +(\"0x\" + s)\r\n return window.encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, s) => String.fromCharCode(parseInt(s, 16)));\r\n // old way\r\n // return window.unescape(window.encodeURIComponent(str))\r\n}\r\n\r\nexport const html2SvgAsync = (() => {\r\n const xmlSerializer = new XMLSerializer();\r\n return async (elements: HTMLElement[], viewBoxSize: number[], css: string) => {\r\n const w = viewBoxSize[0];\r\n const h = viewBoxSize[1];\r\n\r\n let html = elements\r\n .map(\r\n (el) => `<foreignObject width=\"${w}\" height=\"${h}\">\r\n <body xmlns=\"http://www.w3.org/1999/xhtml\">\r\n ${el.outerHTML}\r\n </body>\r\n </foreignObject>`\r\n )\r\n .join(\"\");\r\n html = `<style>${css}</style>${html}`;\r\n\r\n var svgElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svgElement.setAttributeNS(null, \"viewBox\", `0 0 ${w} ${h}`);\r\n svgElement.setAttributeNS(null, \"width\", w + \"\");\r\n svgElement.setAttributeNS(null, \"height\", h + \"\");\r\n svgElement.innerHTML = html;\r\n\r\n return xmlSerializer.serializeToString(svgElement); // svg string\r\n };\r\n})();\r\n\r\nexport function getSvgImageObjectUrl(svgData: string) {\r\n const svgBlob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\r\n return DOMURL.createObjectURL(svgBlob);\r\n}\r\n\r\nexport function getSvgImageDataUrl(svgData: string) {\r\n const svgBase64 = window.btoa(encodeUnicode(svgData));\r\n return \"data:image/svg+xml;base64,\" + svgBase64;\r\n // without base64 encoding (ok for simple SVGs):\r\n // return \"data:image/svg+xml;charset=utf-8,\" + window.encodeURIComponent(svgData); // \"data:image/svg+xml;utf8,\"; - incorrect!\r\n}\r\n\r\n// querySvgDataUrl\r\nexport const querySvgData = (() => {\r\n const xmlSerializer = new XMLSerializer();\r\n return (selector: string) => {\r\n const svg = document.querySelector(selector);\r\n const svgData = xmlSerializer.serializeToString(svg);\r\n return svgData;\r\n };\r\n})();\r\n\r\nexport function toObjectUrl(canvas: HTMLCanvasElement, mimeType = \"image/png\", quality?: number) {\r\n // 'image/jpeg', 'image/webp'\r\n return new Promise<string>((res, rej) => {\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n res(URL.createObjectURL(blob));\r\n },\r\n mimeType,\r\n quality\r\n );\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport function drawImageAsync(src: string, context: CanvasRenderingContext2D) {\r\n return new Promise<void>((res, rej) => {\r\n try {\r\n const image = new Image();\r\n // const image = document.createElement('img');\r\n image.crossOrigin = \"anonymous\";\r\n image.onload = () => {\r\n // image.naturalWidth, image.naturalHeight\r\n context.drawImage(image, 0, 0, image.width, image.height, 0, 0, context.canvas.width, context.canvas.height);\r\n res();\r\n };\r\n image.src = src;\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport const drawSvgAsync = (svgData: string, context: CanvasRenderingContext2D, useDataUrl = false) => {\r\n const imageSrc = useDataUrl ? getSvgImageDataUrl(svgData) : getSvgImageObjectUrl(svgData);\r\n return drawImageAsync(imageSrc, context).finally(() => DOMURL.revokeObjectURL(imageSrc));\r\n};\r\n\r\nexport function canvasToImage(canvas: HTMLCanvasElement, size?: number[], mimeType = \"image/png\", quality?: number) {\r\n // const image = document.createElement(\"img\")\r\n const image = new Image();\r\n image.crossOrigin = \"anonymous\";\r\n if (size) {\r\n if (size[0]) {\r\n image.width = size[0];\r\n }\r\n if (size[1]) {\r\n image.height = size[1];\r\n }\r\n }\r\n const imageSrc = canvas.toDataURL(mimeType, quality);\r\n image.src = imageSrc;\r\n return image;\r\n}\r\n\r\nexport async function canvasToImageAsync(canvas: HTMLCanvasElement, size?: number[], mimeType = \"image/png\", quality?: number) {\r\n // document.createElement(\"img\")\r\n const image = new Image();\r\n image.crossOrigin = \"anonymous\";\r\n if (size) {\r\n if (size[0]) {\r\n image.width = size[0];\r\n }\r\n if (size[1]) {\r\n image.height = size[1];\r\n }\r\n }\r\n const imageSrc = await toObjectUrl(canvas, mimeType, quality);\r\n image.onload = () => DOMURL.revokeObjectURL(imageSrc);\r\n image.src = imageSrc;\r\n return image;\r\n}\r\n\r\nexport async function objectUrlToDataURL(objectUrl: string): Promise<string> {\r\n const response = await fetch(objectUrl);\r\n const blob = await response.blob();\r\n\r\n return new Promise((res, rej) => {\r\n try {\r\n const reader = new FileReader();\r\n reader.onloadend = () => res(reader.result as string);\r\n reader.readAsDataURL(blob);\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport const getSvgSize = (() => {\r\n const domParser = new DOMParser();\r\n return (svg: string) => {\r\n const svgDom = domParser.parseFromString(svg, \"text/xml\");\r\n // svgElement/svgNode\r\n // const svgDoc = svgDom.documentElement;\r\n const svgDoc = svgDom.querySelector(\"svg\");\r\n return getSvgElementSize(svgDoc);\r\n };\r\n})();\r\n\r\nexport function getSvgElementSize(svgDoc: SVGSVGElement): [number, number] {\r\n let w = 0;\r\n if (svgDoc.width.baseVal.unitType === 5) {\r\n // units - pixels\r\n w = svgDoc.width.baseVal.value;\r\n }\r\n if (!w) {\r\n w = svgDoc.width.baseVal.value;\r\n }\r\n if (!w) {\r\n w = svgDoc.viewBox.baseVal.width;\r\n }\r\n\r\n let h = 0;\r\n if (svgDoc.height.baseVal.unitType === 5) {\r\n // units - pixels\r\n h = svgDoc.height.baseVal.value;\r\n }\r\n if (!h) {\r\n h = svgDoc.height.baseVal.value;\r\n }\r\n if (!h) {\r\n h = svgDoc.viewBox.baseVal.height;\r\n }\r\n\r\n // const attributes = svgDoc.attributes;\r\n // see also:\r\n // attributes.getNamedItem(\"viewBox\").value\r\n // attributes.getNamedItem('width').value - with units\r\n // attributes.getNamedItem('height').value - with units\r\n\r\n return [w, h];\r\n}\r\n\r\nexport const refineSvg = (() => {\r\n const domParser = new DOMParser();\r\n return (data: string) => {\r\n const svgDom = domParser.parseFromString(data, \"text/xml\");\r\n // const svgDoc = svgDom.documentElement;\r\n const svgDoc = svgDom.querySelector(\"svg\");\r\n const size = getSvgElementSize(svgDoc);\r\n // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=700533#c39\r\n svgDoc.setAttribute(\"width\", `${size[0]}px`);\r\n svgDoc.setAttribute(\"height\", `${size[1]}px`);\r\n return svgDoc.outerHTML;\r\n };\r\n})();\r\n\r\nexport function drawRoundedRect(\r\n context: CanvasRenderingContext2D,\r\n x: number,\r\n y: number,\r\n w: number,\r\n h: number,\r\n r:\r\n | number\r\n | {\r\n tl: number;\r\n tr: number;\r\n br: number;\r\n bl: number;\r\n }\r\n) {\r\n if (typeof r === \"number\") {\r\n r = { tl: r, tr: r, br: r, bl: r };\r\n } else {\r\n const defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };\r\n for (let side in defaultRadius) {\r\n r[side] = r[side] || defaultRadius[side];\r\n }\r\n }\r\n context.beginPath();\r\n context.moveTo(x + r.tl, y);\r\n context.lineTo(x + w - r.tr, y);\r\n context.quadraticCurveTo(x + w, y, x + w, y + r.tr);\r\n context.lineTo(x + w, y + h - r.br);\r\n context.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);\r\n context.lineTo(x + r.bl, y + h);\r\n context.quadraticCurveTo(x, y + h, x, y + h - r.bl);\r\n context.lineTo(x, y + r.tl);\r\n context.quadraticCurveTo(x, y, x + r.tl, y);\r\n context.closePath();\r\n\r\n // context.fill();\r\n // context.stroke();\r\n\r\n // simple but less accurate\r\n // if (w < 2 * r) {\r\n // r = w / 2;\r\n // }\r\n // if (h < 2 * r) {\r\n // r = h / 2;\r\n // }\r\n // context.beginPath();\r\n // context.moveTo(x + r, y);\r\n // context.arcTo(x + w, y, x + w, y + h, r);\r\n // context.arcTo(x + w, y + h, x, y + h, r);\r\n // context.arcTo(x, y + h, x, y, r);\r\n // context.arcTo(x, y, x + w, y, r);\r\n // context.closePath();\r\n\r\n // https://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas\r\n // + other: https://newfivefour.com/javascript-canvas-rounded-rectangle.html\r\n}\r\n"],"names":["DOMURL","createCanvas","w","h","canvas","context","supportExtendedMetrics","fitText","ctx","text","sizeProvider","targetWidth","fontFamily","fontSize","updateFont","width","getBBOxWidth","offsetLeft","x","y","measure","encodeUnicode","str","_","s","html2SvgAsync","xmlSerializer","elements","viewBoxSize","css","html","el","svgElement","getSvgImageObjectUrl","svgData","svgBlob","getSvgImageDataUrl","querySvgData","selector","svg","toObjectUrl","mimeType","quality","res","rej","blob","err","drawImageAsync","src","image","drawSvgAsync","useDataUrl","imageSrc","canvasToImage","size","canvasToImageAsync","objectUrlToDataURL","objectUrl","reader","getSvgSize","domParser","svgDoc","getSvgElementSize","refineSvg","data","drawRoundedRect","r","defaultRadius","side"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"canvasUtils.es.js","sources":["../../src/gfx/canvasUtils.ts"],"sourcesContent":["const DOMURL = window.URL || window.webkitURL;\r\n\r\nexport function createCanvas(w: number, h: number /*, dpi?: number*/) {\r\n const canvas = document.createElementNS(\"http://www.w3.org/1999/xhtml\", \"canvas\") as HTMLCanvasElement;\r\n // if (!dpi) {\r\n // dpi = window.devicePixelRatio;\r\n // }\r\n // context2d\r\n const context = canvas.getContext(\"2d\");\r\n if (context) {\r\n // context.imageSmoothingEnabled = true;\r\n // context.mozImageSmoothingEnabled = true;\r\n // context.oImageSmoothingEnabled = true;\r\n // context.webkitImageSmoothingEnabled = true;\r\n context[\"imageSmoothingQuality\"] = \"high\";\r\n }\r\n canvas.width = w;\r\n // canvas.width = w * dpi;\r\n canvas.height = h;\r\n // canvas.height = h * dpi;\r\n\r\n // canvas.style.width = w + \"px\";\r\n // context.scale(dpi, dpi);\r\n return { canvas, context };\r\n}\r\n\r\nconst supportExtendedMetrics = \"actualBoundingBoxRight\" in TextMetrics.prototype;\r\n\r\nexport type TextSizeProvider = (fontSize: number) => [number, number];\r\n\r\nexport function fitText(\r\n ctx: CanvasRenderingContext2D,\r\n text = \"\",\r\n sizeProvider: TextSizeProvider,\r\n targetWidth = ctx.canvas.width,\r\n fontFamily = \"Arial\"\r\n) {\r\n let fontSize = 1;\r\n const updateFont = () => {\r\n ctx.font = fontSize + \"px \" + fontFamily;\r\n };\r\n updateFont();\r\n let width = getBBOxWidth(text);\r\n // first pass width increment = 1\r\n while (width && width <= targetWidth) {\r\n fontSize++;\r\n updateFont();\r\n width = getBBOxWidth(text);\r\n }\r\n // second pass, the other way around, with increment = -0.1\r\n while (width && width > targetWidth) {\r\n fontSize -= 0.1;\r\n updateFont();\r\n width = getBBOxWidth(text);\r\n }\r\n // revert to last valid step\r\n fontSize += 0.1;\r\n updateFont();\r\n\r\n // we need to measure where our bounding box actually starts\r\n const offsetLeft = ctx.measureText(text).actualBoundingBoxLeft || 0;\r\n const [x, y] = sizeProvider(fontSize);\r\n ctx.fillText(text, x + offsetLeft, y);\r\n\r\n function getBBOxWidth(text) {\r\n const measure = ctx.measureText(text);\r\n\r\n return supportExtendedMetrics ? measure.actualBoundingBoxLeft + measure.actualBoundingBoxRight : measure.width;\r\n }\r\n}\r\n\r\nfunction encodeUnicode(str: any) {\r\n // +(\"0x\" + s)\r\n return window.encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, (_, s) => String.fromCharCode(parseInt(s, 16)));\r\n // old way\r\n // return window.unescape(window.encodeURIComponent(str))\r\n}\r\n\r\nexport const html2SvgAsync = (() => {\r\n const xmlSerializer = new XMLSerializer();\r\n return async (elements: HTMLElement[], viewBoxSize: number[], css: string) => {\r\n const w = viewBoxSize[0];\r\n const h = viewBoxSize[1];\r\n\r\n let html = elements\r\n .map(\r\n (el) => `<foreignObject width=\"${w}\" height=\"${h}\">\r\n <body xmlns=\"http://www.w3.org/1999/xhtml\">\r\n ${el.outerHTML}\r\n </body>\r\n </foreignObject>`\r\n )\r\n .join(\"\");\r\n html = `<style>${css}</style>${html}`;\r\n\r\n var svgElement = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\r\n svgElement.setAttributeNS(null, \"viewBox\", `0 0 ${w} ${h}`);\r\n svgElement.setAttributeNS(null, \"width\", w + \"\");\r\n svgElement.setAttributeNS(null, \"height\", h + \"\");\r\n svgElement.innerHTML = html;\r\n\r\n return xmlSerializer.serializeToString(svgElement); // svg string\r\n };\r\n})();\r\n\r\nexport function getSvgImageObjectUrl(svgData: string) {\r\n const svgBlob = new Blob([svgData], { type: \"image/svg+xml;charset=utf-8\" });\r\n return DOMURL.createObjectURL(svgBlob);\r\n}\r\n\r\nexport function getSvgImageDataUrl(svgData: string) {\r\n const svgBase64 = window.btoa(encodeUnicode(svgData));\r\n return \"data:image/svg+xml;base64,\" + svgBase64;\r\n // without base64 encoding (ok for simple SVGs):\r\n // return \"data:image/svg+xml;charset=utf-8,\" + window.encodeURIComponent(svgData); // \"data:image/svg+xml;utf8,\"; - incorrect!\r\n}\r\n\r\n// querySvgDataUrl\r\nexport const querySvgData = (() => {\r\n const xmlSerializer = new XMLSerializer();\r\n return (selector: string) => {\r\n const svg = document.querySelector(selector);\r\n const svgData = xmlSerializer.serializeToString(svg);\r\n return svgData;\r\n };\r\n})();\r\n\r\nexport function toObjectUrl(canvas: HTMLCanvasElement, mimeType = \"image/png\", quality?: number) {\r\n // 'image/jpeg', 'image/webp'\r\n return new Promise<string>((res, rej) => {\r\n try {\r\n canvas.toBlob(\r\n (blob) => {\r\n res(URL.createObjectURL(blob));\r\n },\r\n mimeType,\r\n quality\r\n );\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport function drawImageAsync(src: string, context: CanvasRenderingContext2D) {\r\n return new Promise<void>((res, rej) => {\r\n try {\r\n const image = new Image();\r\n // const image = document.createElement('img');\r\n image.crossOrigin = \"anonymous\";\r\n image.onload = () => {\r\n // image.naturalWidth, image.naturalHeight\r\n context.drawImage(image, 0, 0, image.width, image.height, 0, 0, context.canvas.width, context.canvas.height);\r\n res();\r\n };\r\n image.src = src;\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport const drawSvgAsync = (svgData: string, context: CanvasRenderingContext2D, useDataUrl = false) => {\r\n const imageSrc = useDataUrl ? getSvgImageDataUrl(svgData) : getSvgImageObjectUrl(svgData);\r\n return drawImageAsync(imageSrc, context).finally(() => DOMURL.revokeObjectURL(imageSrc));\r\n};\r\n\r\nexport function canvasToImage(canvas: HTMLCanvasElement, size?: number[], mimeType = \"image/png\", quality?: number) {\r\n // const image = document.createElement(\"img\")\r\n const image = new Image();\r\n image.crossOrigin = \"anonymous\";\r\n if (size) {\r\n if (size[0]) {\r\n image.width = size[0];\r\n }\r\n if (size[1]) {\r\n image.height = size[1];\r\n }\r\n }\r\n const imageSrc = canvas.toDataURL(mimeType, quality);\r\n image.src = imageSrc;\r\n return image;\r\n}\r\n\r\nexport async function canvasToImageAsync(canvas: HTMLCanvasElement, size?: number[], mimeType = \"image/png\", quality?: number) {\r\n // document.createElement(\"img\")\r\n const image = new Image();\r\n image.crossOrigin = \"anonymous\";\r\n if (size) {\r\n if (size[0]) {\r\n image.width = size[0];\r\n }\r\n if (size[1]) {\r\n image.height = size[1];\r\n }\r\n }\r\n const imageSrc = await toObjectUrl(canvas, mimeType, quality);\r\n image.onload = () => DOMURL.revokeObjectURL(imageSrc);\r\n image.src = imageSrc;\r\n return image;\r\n}\r\n\r\nexport async function objectUrlToDataURL(objectUrl: string): Promise<string> {\r\n const response = await fetch(objectUrl);\r\n const blob = await response.blob();\r\n\r\n return new Promise((res, rej) => {\r\n try {\r\n const reader = new FileReader();\r\n reader.onloadend = () => res(reader.result as string);\r\n reader.readAsDataURL(blob);\r\n } catch (err) {\r\n rej(err);\r\n }\r\n });\r\n}\r\n\r\nexport const getSvgSize = (() => {\r\n const domParser = new DOMParser();\r\n return (svg: string) => {\r\n const svgDom = domParser.parseFromString(svg, \"text/xml\");\r\n // svgElement/svgNode\r\n // const svgDoc = svgDom.documentElement;\r\n const svgDoc = svgDom.querySelector(\"svg\");\r\n return getSvgElementSize(svgDoc);\r\n };\r\n})();\r\n\r\nexport function getSvgElementSize(svgDoc: SVGSVGElement): [number, number] {\r\n let w = 0;\r\n if (svgDoc.width.baseVal.unitType === 5) {\r\n // units - pixels\r\n w = svgDoc.width.baseVal.value;\r\n }\r\n if (!w) {\r\n w = svgDoc.width.baseVal.value;\r\n }\r\n if (!w) {\r\n w = svgDoc.viewBox.baseVal.width;\r\n }\r\n\r\n let h = 0;\r\n if (svgDoc.height.baseVal.unitType === 5) {\r\n // units - pixels\r\n h = svgDoc.height.baseVal.value;\r\n }\r\n if (!h) {\r\n h = svgDoc.height.baseVal.value;\r\n }\r\n if (!h) {\r\n h = svgDoc.viewBox.baseVal.height;\r\n }\r\n\r\n // const attributes = svgDoc.attributes;\r\n // see also:\r\n // attributes.getNamedItem(\"viewBox\").value\r\n // attributes.getNamedItem('width').value - with units\r\n // attributes.getNamedItem('height').value - with units\r\n\r\n return [w, h];\r\n}\r\n\r\nexport const refineSvg = (() => {\r\n const domParser = new DOMParser();\r\n return (data: string) => {\r\n const svgDom = domParser.parseFromString(data, \"text/xml\");\r\n // const svgDoc = svgDom.documentElement;\r\n const svgDoc = svgDom.querySelector(\"svg\");\r\n const size = getSvgElementSize(svgDoc);\r\n // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=700533#c39\r\n svgDoc.setAttribute(\"width\", `${size[0]}px`);\r\n svgDoc.setAttribute(\"height\", `${size[1]}px`);\r\n return svgDoc.outerHTML;\r\n };\r\n})();\r\n\r\nexport function drawRoundedRect(\r\n context: CanvasRenderingContext2D,\r\n x: number,\r\n y: number,\r\n w: number,\r\n h: number,\r\n r:\r\n | number\r\n | {\r\n tl: number;\r\n tr: number;\r\n br: number;\r\n bl: number;\r\n }\r\n) {\r\n if (typeof r === \"number\") {\r\n r = { tl: r, tr: r, br: r, bl: r };\r\n } else {\r\n const defaultRadius = { tl: 0, tr: 0, br: 0, bl: 0 };\r\n for (let side in defaultRadius) {\r\n r[side] = r[side] || defaultRadius[side];\r\n }\r\n }\r\n context.beginPath();\r\n context.moveTo(x + r.tl, y);\r\n context.lineTo(x + w - r.tr, y);\r\n context.quadraticCurveTo(x + w, y, x + w, y + r.tr);\r\n context.lineTo(x + w, y + h - r.br);\r\n context.quadraticCurveTo(x + w, y + h, x + w - r.br, y + h);\r\n context.lineTo(x + r.bl, y + h);\r\n context.quadraticCurveTo(x, y + h, x, y + h - r.bl);\r\n context.lineTo(x, y + r.tl);\r\n context.quadraticCurveTo(x, y, x + r.tl, y);\r\n context.closePath();\r\n\r\n // context.fill();\r\n // context.stroke();\r\n\r\n // simple but less accurate\r\n // if (w < 2 * r) {\r\n // r = w / 2;\r\n // }\r\n // if (h < 2 * r) {\r\n // r = h / 2;\r\n // }\r\n // context.beginPath();\r\n // context.moveTo(x + r, y);\r\n // context.arcTo(x + w, y, x + w, y + h, r);\r\n // context.arcTo(x + w, y + h, x, y + h, r);\r\n // context.arcTo(x, y + h, x, y, r);\r\n // context.arcTo(x, y, x + w, y, r);\r\n // context.closePath();\r\n\r\n // https://stackoverflow.com/questions/1255512/how-to-draw-a-rounded-rectangle-on-html-canvas\r\n // + other: https://newfivefour.com/javascript-canvas-rounded-rectangle.html\r\n}\r\n"],"names":["DOMURL","createCanvas","w","h","canvas","context","supportExtendedMetrics","fitText","ctx","text","sizeProvider","targetWidth","fontFamily","fontSize","updateFont","width","getBBOxWidth","offsetLeft","x","y","measure","encodeUnicode","str","_","s","html2SvgAsync","xmlSerializer","elements","viewBoxSize","css","html","el","svgElement","getSvgImageObjectUrl","svgData","svgBlob","getSvgImageDataUrl","querySvgData","selector","svg","toObjectUrl","mimeType","quality","res","rej","blob","err","drawImageAsync","src","image","drawSvgAsync","useDataUrl","imageSrc","canvasToImage","size","canvasToImageAsync","objectUrlToDataURL","objectUrl","reader","getSvgSize","domParser","svgDoc","getSvgElementSize","refineSvg","data","drawRoundedRect","r","defaultRadius","side"],"mappings":"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"}
|