@lowentry/utils 1.10.5 → 1.11.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lowentry/utils",
3
- "version": "1.10.5",
3
+ "version": "1.11.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./index.js",
package/src/LeUtils.js CHANGED
@@ -45,6 +45,67 @@ export const LeUtils = {
45
45
  */
46
46
  equals:FastDeepEqual,
47
47
 
48
+ /**
49
+ * Returns a deep copy of the given value.
50
+ *
51
+ * @param {*} value
52
+ * @returns {*}
53
+ */
54
+ clone:
55
+ (value) => CloneDeep(value, true),
56
+
57
+ /**
58
+ * Executes the given callback when the document is ready.
59
+ *
60
+ * @param {Function} callback
61
+ * @returns {{remove:Function}}
62
+ */
63
+ onDomReady:
64
+ (callback) =>
65
+ {
66
+ if((typeof window === 'undefined') || !document)
67
+ {
68
+ // no document, so we can't wait for it to be ready
69
+ return {
70
+ remove:() =>
71
+ {
72
+ },
73
+ };
74
+ }
75
+
76
+ if((document.readyState === 'interactive') || (document.readyState === 'complete'))
77
+ {
78
+ return LeUtils.setTimeout(callback, 0);
79
+ }
80
+ else
81
+ {
82
+ let listening = true;
83
+ const callbackWrapper = () =>
84
+ {
85
+ if(listening)
86
+ {
87
+ listening = false;
88
+ document.removeEventListener('DOMContentLoaded', callbackWrapper);
89
+ callback();
90
+ }
91
+ };
92
+
93
+ document.addEventListener('DOMContentLoaded', callbackWrapper);
94
+
95
+ return {
96
+ remove:
97
+ () =>
98
+ {
99
+ if(listening)
100
+ {
101
+ listening = false;
102
+ document.removeEventListener('DOMContentLoaded', callbackWrapper);
103
+ }
104
+ },
105
+ };
106
+ }
107
+ },
108
+
48
109
  /**
49
110
  * Parses the given version string, and returns an object with the major, minor, and patch numbers, as well as some comparison functions.
50
111
  *
@@ -925,6 +986,15 @@ export const LeUtils = {
925
986
  setTimeout:
926
987
  (callback, ms) =>
927
988
  {
989
+ if(typeof window === 'undefined')
990
+ {
991
+ return {
992
+ remove:() =>
993
+ {
994
+ },
995
+ };
996
+ }
997
+
928
998
  ms = FLOAT_LAX(ms);
929
999
 
930
1000
  let lastTime = performance.now();
@@ -986,6 +1056,15 @@ export const LeUtils = {
986
1056
  }
987
1057
  }
988
1058
 
1059
+ if(typeof window === 'undefined')
1060
+ {
1061
+ return {
1062
+ remove:() =>
1063
+ {
1064
+ },
1065
+ };
1066
+ }
1067
+
989
1068
  let lastTime = performance.now();
990
1069
  let handler = setInterval(() =>
991
1070
  {
@@ -1030,6 +1109,15 @@ export const LeUtils = {
1030
1109
  setAnimationFrameTimeout:
1031
1110
  (callback, frames = 1) =>
1032
1111
  {
1112
+ if(typeof window === 'undefined')
1113
+ {
1114
+ return {
1115
+ remove:() =>
1116
+ {
1117
+ },
1118
+ };
1119
+ }
1120
+
1033
1121
  frames = INT_LAX_ANY(frames, 1);
1034
1122
 
1035
1123
  let run = true;
@@ -1106,6 +1194,15 @@ export const LeUtils = {
1106
1194
  }
1107
1195
  }
1108
1196
 
1197
+ if(typeof window === 'undefined')
1198
+ {
1199
+ return {
1200
+ remove:() =>
1201
+ {
1202
+ },
1203
+ };
1204
+ }
1205
+
1109
1206
  let run = true;
1110
1207
  let requestAnimationFrameId = null;
1111
1208
  let lastTime = performance.now();
@@ -1186,6 +1283,84 @@ export const LeUtils = {
1186
1283
  return new Promise(resolve => LeUtils.setAnimationFrameTimeout(resolve, frames));
1187
1284
  },
1188
1285
 
1286
+ /**
1287
+ * Allows you to do a fetch, with built-in retry and abort functionality.
1288
+ *
1289
+ * @param {string} url
1290
+ * @param {Object} [options]
1291
+ * @returns {{promise:Promise<*>, then:Function, catch:Function, finally:Function, remove:Function, isRemoved:Function}}
1292
+ */
1293
+ fetch:
1294
+ (url, options) =>
1295
+ {
1296
+ let currentRetries = 0;
1297
+ const retries = INT_LAX(options?.retries, 0);
1298
+ const signal = new AbortController();
1299
+ const promise = new Promise((resolve, reject) =>
1300
+ {
1301
+ const attemptFetch = () =>
1302
+ {
1303
+ if(signal.signal.aborted)
1304
+ {
1305
+ reject(new Error('Aborted'));
1306
+ return;
1307
+ }
1308
+
1309
+ fetch(url, {
1310
+ signal,
1311
+ ...(options ?? {}),
1312
+ retries:undefined,
1313
+ delay: undefined,
1314
+ }).then((response) =>
1315
+ {
1316
+ if(!response.ok)
1317
+ {
1318
+ throw new Error('Network request failed: ' + response.status + ' ' + response.statusText);
1319
+ }
1320
+ return response;
1321
+ }).then((response) =>
1322
+ {
1323
+ resolve(response);
1324
+ }).catch((error) =>
1325
+ {
1326
+ if(currentRetries >= retries)
1327
+ {
1328
+ reject(error);
1329
+ return;
1330
+ }
1331
+ currentRetries++;
1332
+ setTimeout(attemptFetch, (typeof options?.delay === 'function') ? INT_LAX_ANY(options?.delay(currentRetries), 500) : (INT_LAX_ANY(options?.delay, 500)));
1333
+ });
1334
+ };
1335
+ attemptFetch();
1336
+ });
1337
+
1338
+ let result = {};
1339
+ result.promise = promise;
1340
+ result.then = (...args) =>
1341
+ {
1342
+ promise.then(...args);
1343
+ return result;
1344
+ };
1345
+ result.catch = (...args) =>
1346
+ {
1347
+ promise.catch(...args);
1348
+ return result;
1349
+ };
1350
+ result.finally = (...args) =>
1351
+ {
1352
+ promise.finally(...args);
1353
+ return result;
1354
+ };
1355
+ result.remove = (...args) =>
1356
+ {
1357
+ signal.abort(...args);
1358
+ return result;
1359
+ };
1360
+ result.isRemoved = () => signal.signal.aborted;
1361
+ return result;
1362
+ },
1363
+
1189
1364
  /**
1190
1365
  * Returns true if the user is on a smartphone device (mobile).
1191
1366
  * Will return false if the user is on a tablet or on a desktop.
@@ -1419,9 +1594,27 @@ export const LeUtils = {
1419
1594
  purgeErrorMessage:
1420
1595
  (error) =>
1421
1596
  {
1422
- const message = STRING(((typeof error === 'string') ? error : (error.message ?? JSON.stringify(error))));
1423
- const messageParts = message.split('threw an error:');
1424
- return messageParts[messageParts.length - 1].trim();
1597
+ if(error?.message)
1598
+ {
1599
+ error = error.message;
1600
+ }
1601
+ if(typeof error === 'string')
1602
+ {
1603
+ const errorParts = error.split('threw an error:');
1604
+ error = errorParts[errorParts.length - 1];
1605
+ }
1606
+ else
1607
+ {
1608
+ try
1609
+ {
1610
+ error = JSON.stringify(error);
1611
+ }
1612
+ catch(e)
1613
+ {
1614
+ error = 'An unknown error occurred';
1615
+ }
1616
+ }
1617
+ return error.trim();
1425
1618
  },
1426
1619
 
1427
1620
  /**
@@ -1535,6 +1728,10 @@ export const LeUtils = {
1535
1728
  let now;
1536
1729
  try
1537
1730
  {
1731
+ if(typeof window === 'undefined')
1732
+ {
1733
+ throw new Error();
1734
+ }
1538
1735
  // noinspection JSDeprecatedSymbols
1539
1736
  now = (performance.timeOrigin || performance.timing.navigationStart) + performance.now();
1540
1737
  if(typeof now !== 'number')
@@ -1639,6 +1836,10 @@ export const LeUtils = {
1639
1836
  {
1640
1837
  try
1641
1838
  {
1839
+ if(typeof window === 'undefined')
1840
+ {
1841
+ throw new Error();
1842
+ }
1642
1843
  // noinspection JSDeprecatedSymbols
1643
1844
  now = (performance.timeOrigin || performance.timing.navigationStart) + performance.now();
1644
1845
  if(typeof now !== 'number')
@@ -1698,7 +1899,7 @@ export const LeUtils = {
1698
1899
  getImagePixels:
1699
1900
  (image) =>
1700
1901
  {
1701
- if(!document)
1902
+ if((typeof window === 'undefined') || !document)
1702
1903
  {
1703
1904
  return new Uint8ClampedArray();
1704
1905
  }
@@ -1738,7 +1939,7 @@ export const LeUtils = {
1738
1939
  getColoredImage:
1739
1940
  (image, color) =>
1740
1941
  {
1741
- if(!document)
1942
+ if((typeof window === 'undefined') || !document)
1742
1943
  {
1743
1944
  return LeUtils.getEmptyImageSrc();
1744
1945
  }
@@ -2257,6 +2458,10 @@ export const LeUtils = {
2257
2458
  downloadFile:
2258
2459
  (base64string, fileName, mimeType) =>
2259
2460
  {
2461
+ if((typeof window === 'undefined') || !document)
2462
+ {
2463
+ return;
2464
+ }
2260
2465
  const link = document.createElement('a');
2261
2466
  link.setAttribute('download', (typeof fileName === 'string') ? fileName : 'file');
2262
2467
  link.href = 'data:' + mimeType + ';base64,' + base64string;
@@ -2824,6 +3029,17 @@ export const LeUtils = {
2824
3029
  createWorkerThread:
2825
3030
  (name) =>
2826
3031
  {
3032
+ if((typeof window === 'undefined') || (typeof Worker === 'undefined'))
3033
+ {
3034
+ return {
3035
+ worker: null,
3036
+ sendMessage:new Promise((resolve, reject) =>
3037
+ {
3038
+ reject('Workers are not supported in this environment');
3039
+ }),
3040
+ };
3041
+ }
3042
+
2827
3043
  const worker = new Worker('/workers/' + name + '.worker.js');
2828
3044
  let listeners = {};
2829
3045
 
@@ -2901,15 +3117,6 @@ export const LeUtils = {
2901
3117
  };
2902
3118
  })(),
2903
3119
 
2904
- /**
2905
- * Returns a deep copy of the given value.
2906
- *
2907
- * @param {*} value
2908
- * @returns {*}
2909
- */
2910
- clone:
2911
- (value) => CloneDeep(value, true),
2912
-
2913
3120
  /**
2914
3121
  * Purges the given email address, returning an empty string if it's invalid.
2915
3122
  *
@@ -2934,6 +3141,10 @@ export const LeUtils = {
2934
3141
  */
2935
3142
  isFocusClear:(() =>
2936
3143
  {
3144
+ if((typeof window === 'undefined') || !document)
3145
+ {
3146
+ return () => true;
3147
+ }
2937
3148
  const inputTypes = ['text', 'search', 'email', 'number', 'password', 'tel', 'time', 'url', 'week', 'month', 'date', 'datetime-local'];
2938
3149
  return () => !((document?.activeElement?.tagName?.toLowerCase() === 'input') && inputTypes.includes(document?.activeElement?.type?.toLowerCase()));
2939
3150
  })(),
@@ -2952,11 +3163,11 @@ export const LeUtils = {
2952
3163
  {
2953
3164
  userLocale = (() =>
2954
3165
  {
2955
- if(typeof window === 'undefined')
3166
+ if((typeof window === 'undefined') || !navigator)
2956
3167
  {
2957
3168
  return 'en-US';
2958
3169
  }
2959
- let locales = window.navigator.languages;
3170
+ let locales = navigator?.languages ?? [];
2960
3171
  if(!IS_ARRAY(locales) || (locales.length <= 0))
2961
3172
  {
2962
3173
  return 'en-US';
@@ -2993,9 +3204,9 @@ export const LeUtils = {
2993
3204
  userLocaleDateFormat = (() =>
2994
3205
  {
2995
3206
  let char = '/';
2996
- if((typeof window !== 'undefined') && (typeof Intl !== 'undefined') && (typeof Intl.DateTimeFormat !== 'undefined'))
3207
+ if((typeof window !== 'undefined') && (typeof window.Intl !== 'undefined') && (typeof window.Intl.DateTimeFormat !== 'undefined'))
2997
3208
  {
2998
- const formattedDate = new Intl.DateTimeFormat(LeUtils.getUserLocale()).format();
3209
+ const formattedDate = new window.Intl.DateTimeFormat(LeUtils.getUserLocale()).format();
2999
3210
  if(formattedDate.includes('-'))
3000
3211
  {
3001
3212
  char = '-';