@nativerent/js-utils 1.2.1 → 1.2.3

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/index.js CHANGED
@@ -1,645 +1,675 @@
1
- 'use strict';
2
-
3
- function debounce(fn, delay) {
4
- let timeout;
5
- return function(...args) {
6
- clearTimeout(timeout);
7
- timeout = setTimeout(() => fn.apply(null, args), delay);
8
- };
9
- }
10
- function throttle(fn, delay) {
11
- let lastCall = 0;
12
- return function(...args) {
13
- const now = (/* @__PURE__ */ new Date()).getTime();
14
- if (now - lastCall < delay) {
15
- return;
1
+ export function debounce(fn, delay) {
2
+ let timeout;
3
+ return function (...args) {
4
+ clearTimeout(timeout);
5
+ timeout = setTimeout(() => fn.apply(null, args), delay);
6
+ };
7
+ }
8
+ export function throttle(fn, delay) {
9
+ let lastCall = 0;
10
+ return function (...args) {
11
+ const now = new Date().getTime();
12
+ if (now - lastCall < delay) {
13
+ return;
14
+ }
15
+ lastCall = now;
16
+ fn(...args);
17
+ };
18
+ }
19
+ export function isObject(value) {
20
+ return !!value && typeof value === "object" && !Array.isArray(value);
21
+ }
22
+ export function isFn(value) {
23
+ return typeof value === "function";
24
+ }
25
+ export function isStr(value) {
26
+ return typeof value === "string";
27
+ }
28
+ export function isString(value) {
29
+ return typeof value === "string";
30
+ }
31
+ /**
32
+ * Check if the given argument is a string which is not empty
33
+ */
34
+ export function isNotEmptyString(value) {
35
+ return isString(value) && value.length > 0;
36
+ }
37
+ export function isHTMLElement(value) {
38
+ return value instanceof HTMLElement || value instanceof SVGElement;
39
+ }
40
+ export function isNum(value) {
41
+ return typeof value === "number";
42
+ }
43
+ export function isBool(value) {
44
+ return typeof value === "boolean";
45
+ }
46
+ export function isUndef(value) {
47
+ return typeof value === "undefined";
48
+ }
49
+ export function isNullOrUndef(value) {
50
+ return value === null || typeof value === "undefined";
51
+ }
52
+ export function isDefined(value) {
53
+ return !isUndef(value);
54
+ }
55
+ /**
56
+ * Returns an array containing all the elements of array1 that are not in array2 and vice-versa
57
+ */
58
+ export function arrayDiff(array1, array2) {
59
+ return array1
60
+ .filter((value) => !array2.includes(value))
61
+ .concat(array2.filter((value) => !array1.includes(value)));
62
+ }
63
+ /**
64
+ * Returns an array of elements present in array1 and array2
65
+ */
66
+ export function arrayIntersect(array1, array2) {
67
+ const set = new Set(array2);
68
+ return array1.filter((value) => set.has(value));
69
+ }
70
+ export function deepCloneObject(object) {
71
+ return JSON.parse(JSON.stringify(object));
72
+ }
73
+ // todo: non-px values
74
+ export function getNumericStyleProp(prop, el) {
75
+ const styles = window.getComputedStyle(el);
76
+ return !isNullOrUndef(styles[prop]) ? parseFloat(styles[prop] || 0) : 0;
77
+ }
78
+ export function objectHasProp(obj, prop) {
79
+ return Object.prototype.hasOwnProperty.call(obj, prop);
80
+ }
81
+ /**
82
+ * Custom version of Object.keys()
83
+ */
84
+ export function getObjectKeys(object) {
85
+ let key;
86
+ let keys = [];
87
+ for (key in object) {
88
+ if (Object.prototype.hasOwnProperty.call(object, key)) {
89
+ keys.push(key);
90
+ }
16
91
  }
17
- lastCall = now;
18
- fn(...args);
19
- };
20
- }
21
- function isObject(value) {
22
- return !!value && typeof value === "object" && !Array.isArray(value);
23
- }
24
- function isFn(value) {
25
- return typeof value === "function";
26
- }
27
- function isStr(value) {
28
- return typeof value === "string";
29
- }
30
- function isString(value) {
31
- return typeof value === "string";
32
- }
33
- function isNotEmptyString(value) {
34
- return isString(value) && value.length;
35
- }
36
- function isHTMLElement(value) {
37
- return value instanceof HTMLElement || value instanceof SVGElement;
38
- }
39
- function isNum(value) {
40
- return typeof value === "number";
41
- }
42
- function isBool(value) {
43
- return typeof value === "boolean";
44
- }
45
- function isUndef(value) {
46
- return typeof value === "undefined";
47
- }
48
- function isNullOrUndef(value) {
49
- return value === null || typeof value === "undefined";
50
- }
51
- function isDefined(value) {
52
- return !isUndef(value);
53
- }
54
- function arrayDiff(array1, array2) {
55
- return array1.filter((value) => !array2.includes(value)).concat(array2.filter((value) => !array1.includes(value)));
56
- }
57
- function arrayIntersect(array1, array2) {
58
- return array1.filter((value) => array2.includes(value));
59
- }
60
- function deepCloneObject(object) {
61
- return JSON.parse(JSON.stringify(object));
62
- }
63
- function getNumericStyleProp(prop, el) {
64
- const styles = window.getComputedStyle(el);
65
- return !isNullOrUndef(styles[prop]) ? parseInt(styles[prop].slice(0, -2)) : 0;
66
- }
67
- function objectHasProp(obj, prop) {
68
- return Object.prototype.hasOwnProperty.call(obj, prop);
69
- }
70
- function getObjectKeys(object) {
71
- let key;
72
- let keys = [];
73
- for (key in object) {
74
- if (Object.prototype.hasOwnProperty.call(object, key)) {
75
- keys.push(key);
92
+ return keys;
93
+ }
94
+ /**
95
+ * Convert an object to a query string
96
+ * Works with primitive objects
97
+ */
98
+ export function objectToQueryString(object) {
99
+ return Object.entries(object)
100
+ .map(([k, v]) => {
101
+ if (Array.isArray(v)) {
102
+ return v
103
+ .map((item) => `${k}[]=${encodeURIComponent(item || "")}`)
104
+ .join("&");
105
+ }
106
+ else if (isObject(v)) {
107
+ return `${k}=${encodeURIComponent(JSON.stringify(v))}`;
108
+ }
109
+ return `${k}=${encodeURIComponent(v || "")}`;
110
+ })
111
+ .join("&");
112
+ }
113
+ export function countObjectInnerLength(object) {
114
+ return Object.values(object).reduce((sum, arr) => sum + (arr?.length ?? 0), 0);
115
+ }
116
+ /**
117
+ * Check if the element is in viewport
118
+ */
119
+ export function isElementVisible(element, minVisiblePercent = 50) {
120
+ const { top, bottom, height } = element.getBoundingClientRect();
121
+ if (!height)
122
+ return false;
123
+ const viewportTop = 0;
124
+ const viewportBottom = window.innerHeight;
125
+ const visibleTop = Math.max(top, viewportTop);
126
+ const visibleBottom = Math.min(bottom, viewportBottom);
127
+ const visibleHeight = Math.max(0, visibleBottom - visibleTop);
128
+ return (visibleHeight / height) * 100 >= minVisiblePercent;
129
+ }
130
+ export function decodeSafeURL(url) {
131
+ try {
132
+ return decodeURI(url);
76
133
  }
77
- }
78
- return keys;
79
- }
80
- function objectToQueryString(object) {
81
- return Object.entries(object).map(([k, v]) => {
82
- if (Array.isArray(v)) {
83
- return v.map((item) => `${k}[]=${encodeURIComponent(item || "")}`).join("&");
84
- } else if (isObject(v)) {
85
- return `${k}=${encodeURIComponent(JSON.stringify(v))}`;
134
+ catch {
135
+ return url;
86
136
  }
87
- return `${k}=${encodeURIComponent(v || "")}`;
88
- }).join("&");
89
- }
90
- function countObjectInnerLength(object) {
91
- const obj = Object.values(object);
92
- const len = obj.length;
93
- if (len === 0) {
94
- return 0;
95
- } else if (len === 1) {
96
- return obj[0].length;
97
- } else {
98
- return obj.reduce((acc, cur) => {
99
- if (Array.isArray(acc)) {
100
- acc = acc.length;
101
- }
102
- if (cur) {
103
- acc += cur.length;
104
- }
105
- return acc;
106
- });
107
- }
108
- }
109
- function isElementVisible(element, minVisiblePercent = 50) {
110
- const elementCoords = element.getBoundingClientRect();
111
- const elementHeight = elementCoords.height;
112
- if (!elementHeight) {
113
- return false;
114
- }
115
- const elementTop = elementCoords.top;
116
- const elementBottom = elementCoords.bottom;
117
- const viewPortHeight = window.innerHeight;
118
- const elementVisibleHeight = elementTop > 0 ? (
119
- // the element is in or below viewport
120
- viewPortHeight - elementTop
121
- ) : (
122
- // the element is still in or above viewport
123
- elementBottom
124
- );
125
- return elementVisibleHeight / elementHeight * 100 >= minVisiblePercent;
126
- }
127
- function decodeSafeURL(url) {
128
- try {
129
- return decodeURI(url);
130
- } catch (e) {
131
- return url;
132
- }
133
137
  }
134
- function getSafeURL(url) {
135
- url = url ? url : location.href;
136
- return encodeURI(decodeSafeURL(url));
138
+ export function getSafeURL(url) {
139
+ url = url ? url : location.href;
140
+ return encodeURI(decodeSafeURL(url));
137
141
  }
138
- function parseURL(url) {
139
- return new URL(url);
142
+ export function parseURL(url) {
143
+ return new URL(url);
140
144
  }
141
- function encodeQueryString(url) {
142
- if (url.length > 0) {
143
- const index = url.indexOf("?");
144
- if (index >= 0) {
145
- return url.substring(0, index) + parseURL(url).search;
145
+ export function encodeQueryString(url) {
146
+ if (url.length > 0) {
147
+ const index = url.indexOf("?");
148
+ if (index >= 0) {
149
+ return url.substring(0, index) + parseURL(url).search;
150
+ }
146
151
  }
147
- }
148
- return url;
149
- }
150
- function injectScript(filename) {
151
- const script = document.createElement("script");
152
- script.src = filename;
153
- script.async = true;
154
- document.head.appendChild(script);
155
- }
156
- function injectStyleLink(filename) {
157
- const link = document.createElement("link");
158
- link.rel = "stylesheet";
159
- link.href = filename;
160
- document.head.appendChild(link);
161
- }
162
- function toBinaryStr(str) {
163
- const encoder = new TextEncoder();
164
- const charCodes = encoder.encode(str);
165
- return String.fromCharCode(...charCodes);
166
- }
167
- function getHtmlElement(id) {
168
- return document.getElementById(id);
169
- }
170
- function stringToHtmlElements(html) {
171
- const template = createHtmlElement("div");
172
- template.innerHTML = html.replace(/[\r\n]/gm, "").trim();
173
- return template.childNodes;
174
- }
175
- function createHtmlElement(type, attributes = {}) {
176
- const attrs = getObjectKeys(attributes);
177
- const element = document.createElement(type);
178
- if (attrs.length) {
179
- attrs.forEach((name) => {
180
- element.setAttribute(name, attributes[name]);
181
- });
182
- }
183
- return element;
184
- }
185
- function insertHtmlElements(nodes, appendTo) {
186
- appendTo = appendTo || document.body;
187
- const fragment = new DocumentFragment();
188
- for (let i = 0; i < nodes.length; i++) {
189
- if (!isHTMLElement(nodes[i]) && nodes[i].nodeType !== 3) {
190
- continue;
152
+ return url;
153
+ }
154
+ export function injectScript(filename) {
155
+ const script = document.createElement("script");
156
+ script.src = filename;
157
+ script.async = true;
158
+ document.head.appendChild(script);
159
+ }
160
+ export function injectStyleLink(filename) {
161
+ const link = document.createElement("link");
162
+ link.rel = "stylesheet";
163
+ link.href = filename;
164
+ document.head.appendChild(link);
165
+ }
166
+ export function toBinaryStr(str) {
167
+ const CHUNK = 0x8000; // String.fromCharCode(...charCodes) can overflow the call stack with large strings
168
+ const bytes = new TextEncoder().encode(str);
169
+ let result = "";
170
+ for (let i = 0; i < bytes.length; i += CHUNK) {
171
+ result += String.fromCharCode(...bytes.subarray(i, i + CHUNK));
191
172
  }
192
- const node = nodes[i];
193
- let newNode;
194
- switch (node.nodeName.toLowerCase()) {
195
- case "script":
196
- const src = node.getAttribute("src");
197
- if (!isNullOrUndef(src) && src.length > 0) {
198
- newNode = createScriptElement(
199
- src,
200
- false,
201
- flatHtmlAttributes(node.attributes)
202
- );
203
- } else {
204
- newNode = createScriptElement(
205
- node.innerHTML,
206
- true,
207
- flatHtmlAttributes(node.attributes)
208
- );
173
+ return result;
174
+ }
175
+ /**
176
+ * Find a DOM element where an ad unit should be rendered to
177
+ */
178
+ export function getHtmlElement(id) {
179
+ return document.getElementById(id);
180
+ }
181
+ /**
182
+ * Convert an HTML string into a list of nodes
183
+ */
184
+ export function stringToHtmlElements(html) {
185
+ const template = createHtmlElement("div");
186
+ template.innerHTML = html.replace(/[\r\n]/gm, "").trim();
187
+ return template.childNodes;
188
+ }
189
+ /**
190
+ * Creates an HTML element and sets attributes
191
+ */
192
+ export function createHtmlElement(type, attributes = {}) {
193
+ const el = document.createElement(type);
194
+ for (const [k, v] of Object.entries(attributes))
195
+ el.setAttribute(k, v);
196
+ return el;
197
+ }
198
+ /**
199
+ * Insert HTML elements into DOM
200
+ */
201
+ export function insertHtmlElements(nodes, appendTo = document.body) {
202
+ const fragment = document.createDocumentFragment();
203
+ for (let i = 0; i < nodes.length; i++) {
204
+ const node = nodes[i];
205
+ // Allow elements + text nodes only
206
+ if (!isHTMLElement(node) && node?.nodeType !== Node.TEXT_NODE) {
207
+ continue;
208
+ }
209
+ let newNode;
210
+ // Text node
211
+ if (node?.nodeType === Node.TEXT_NODE) {
212
+ newNode = document.createTextNode(node.textContent ?? "");
213
+ fragment.appendChild(newNode);
214
+ continue;
209
215
  }
210
- break;
211
- case "style":
212
- newNode = createStyleElement(node.textContent);
213
- break;
214
- case "svg":
215
- newNode = createSvgElement(
216
- node.innerHTML,
217
- flatHtmlAttributes(node.attributes)
218
- );
219
- break;
220
- case "#text":
221
- newNode = document.createTextNode(node.textContent ?? "");
222
- break;
223
- default:
224
- newNode = createHtmlElement(
225
- node.tagName,
226
- flatHtmlAttributes(node.attributes)
227
- );
228
- if (node.childNodes.length) {
229
- insertHtmlElements(node.childNodes, newNode);
230
- } else {
231
- newNode.innerHTML = node.innerHTML;
216
+ // Element node from here on
217
+ const el = node;
218
+ const tag = el.tagName.toLowerCase();
219
+ switch (tag) {
220
+ case "script": {
221
+ const src = el.getAttribute("src");
222
+ newNode =
223
+ !isNullOrUndef(src) && src.length > 0
224
+ ? createScriptElement(src, false, flatHtmlAttributes(el.attributes))
225
+ : createScriptElement(el.textContent ?? "", true, flatHtmlAttributes(el.attributes));
226
+ break;
227
+ }
228
+ case "style":
229
+ newNode = createStyleElement(el.textContent);
230
+ break;
231
+ case "svg":
232
+ newNode = createSvgElement(el.innerHTML, flatHtmlAttributes(el.attributes));
233
+ break;
234
+ default: {
235
+ const created = createHtmlElement(el.tagName, flatHtmlAttributes(el.attributes));
236
+ // Recurse for children (handles mixed element/text)
237
+ if (el.childNodes.length) {
238
+ insertHtmlElements(el.childNodes, created);
239
+ }
240
+ else {
241
+ created.textContent = el.textContent ?? "";
242
+ }
243
+ newNode = created;
244
+ }
232
245
  }
246
+ fragment.appendChild(newNode);
233
247
  }
234
- fragment.appendChild(newNode);
235
- }
236
- appendTo.appendChild(fragment);
237
- }
238
- function flatHtmlAttributes(attributes) {
239
- let flatAttributes = {};
240
- if (!isNullOrUndef(attributes)) {
248
+ appendTo.appendChild(fragment);
249
+ }
250
+ /**
251
+ * Make a simple object which contains only attribute name and value
252
+ */
253
+ export function flatHtmlAttributes(attributes) {
254
+ if (!attributes)
255
+ return {};
256
+ const result = {};
241
257
  for (let i = 0; i < attributes.length; i++) {
242
- let attr = attributes[i];
243
- if (!isUndef(attr)) {
244
- flatAttributes[attr.name] = attr.value;
245
- }
258
+ const attr = attributes[i];
259
+ if (attr) {
260
+ result[attr.name] = attr.value;
261
+ }
246
262
  }
247
- }
248
- return flatAttributes;
249
- }
250
- function createScriptElement(js, inline = false, attributes = {}) {
251
- const attrs = isObject(attributes) ? getObjectKeys(attributes) : [];
252
- const element = createHtmlElement("script");
253
- if (attrs.length) {
254
- attrs.forEach((name) => {
255
- element.setAttribute(name, attributes[name]);
256
- });
257
- }
258
- if (inline) {
259
- element.appendChild(document.createTextNode(js));
260
- } else {
261
- element.async = true;
262
- element.src = js;
263
- }
264
- return element;
265
- }
266
- function createStyleElement(css) {
267
- const element = createHtmlElement("style");
268
- if (css) {
269
- element.appendChild(document.createTextNode(css));
270
- }
271
- return element;
272
- }
273
- function createLinkElement(href) {
274
- const element = createHtmlElement("link");
275
- element.rel = "stylesheet";
276
- element.href = href;
277
- return element;
278
- }
279
- function createSvgElement(content, attributes) {
280
- const attrs = getObjectKeys(attributes);
281
- const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
282
- if (attrs.length) {
283
- attrs.forEach((name) => {
284
- element.setAttribute(name, attributes[name]);
285
- });
286
- }
287
- element.innerHTML = content;
288
- return element;
289
- }
290
- function createPixelElement(src) {
291
- const image = document.createElement("img");
292
- image.src = src;
293
- image.width = 1;
294
- image.height = 1;
295
- image.style.position = "absolute";
296
- image.style.left = "-99999px";
297
- return image;
298
- }
299
- function insertJs(js, inline = false) {
300
- const element = createScriptElement(js, inline);
301
- document.head.appendChild(element);
302
- }
303
- function insertCss(css, className, external = false) {
304
- const element = external ? createLinkElement(css) : createStyleElement(css);
305
- if (className) {
306
- element.className = className;
307
- }
308
- document.head.appendChild(element);
309
- }
310
- function getScreenSize() {
311
- let width, height;
312
- if (window.screen) {
313
- width = screen.width;
314
- height = screen.height;
315
- } else {
316
- width = window.innerWidth;
317
- height = window.innerHeight;
318
- }
319
- return {
320
- width,
321
- height
322
- };
323
- }
324
- function getRandomInt(min = 0, max = 4294967295) {
325
- min = Math.ceil(min);
326
- max = Math.floor(max);
327
- return Math.floor(Math.random() * (max - min)) + min;
328
- }
329
- function hashCode(str) {
330
- let hash = 0, chr;
331
- for (let i = 0; i < str.length; i++) {
332
- chr = str.charCodeAt(i);
333
- hash = (hash << 5) - hash + chr;
334
- hash |= 0;
335
- }
336
- return hash >>> 0;
337
- }
338
- function onDOMReady(callback, ...args) {
339
- if (document.readyState === "interactive" || document.readyState === "complete") {
340
- callback(...args);
341
- } else {
342
- document.addEventListener("DOMContentLoaded", () => callback(...args));
343
- }
344
- }
345
- function toPercent(a, b) {
346
- return b > 0 ? a / b * 100 : 0;
347
- }
348
- function toCamelCase(string) {
349
- return string.split(new RegExp(/[-_.]/)).reduce(
350
- (a, b) => a + b.charAt(0).toUpperCase() + b.slice(1)
351
- );
352
- }
353
- function toSnakeCase(string) {
354
- return toCamelCase(string).replace(/(^[A-Z])?([A-Z])/gm, "$1_$2").toLowerCase();
355
- }
356
- function capitalize(string) {
357
- return string.charAt(0).toUpperCase() + string.slice(1);
358
- }
359
- function sortByAlphabet(first, second) {
360
- return first.toLowerCase() > second.toLowerCase() ? 1 : -1;
361
- }
362
- function getRandomStr(length) {
363
- length = length ? length > 100 ? 100 : length : 10;
364
- let str = Math.random().toString(36).substring(2);
365
- while (str.length < length) {
366
- str += Math.random().toString(36).substring(2);
367
- }
368
- const result = str.slice(-length);
369
- return isNaN(Number(result)) ? result : getRandomStr(length);
370
- }
371
- function getRandomItem(items) {
372
- return items[Math.floor(Math.random() * items.length)];
373
- }
374
- function sumArray(values) {
375
- if (values.every((value) => isNaN(value))) {
376
- return "";
377
- } else {
378
- return values.reduce((sum, curr) => {
379
- const value = Number(curr);
380
- if (!isNaN(value)) {
381
- return sum + value;
382
- } else {
383
- return sum;
384
- }
385
- }, 0);
386
- }
387
- }
388
- function filterObjectKeysByValues(obj, values) {
389
- values = Array.isArray(values) ? values : Array(values);
390
- const keys = [];
391
- for (const key in obj) {
392
- if (!values.includes(obj[key])) {
393
- keys.push(key);
263
+ return result;
264
+ }
265
+ /**
266
+ * Create a <script> element
267
+ */
268
+ export function createScriptElement(js, inline = false, attributes = {}) {
269
+ const el = document.createElement("script");
270
+ for (const [k, v] of Object.entries(attributes)) {
271
+ el.setAttribute(k, v);
272
+ }
273
+ if (inline) {
274
+ el.appendChild(document.createTextNode(js));
275
+ }
276
+ else {
277
+ el.async = true;
278
+ el.src = js;
279
+ }
280
+ return el;
281
+ }
282
+ /**
283
+ * Create a <style> element
284
+ */
285
+ export function createStyleElement(css) {
286
+ const element = createHtmlElement("style");
287
+ if (css) {
288
+ element.appendChild(document.createTextNode(css));
289
+ }
290
+ return element;
291
+ }
292
+ /**
293
+ * Create a <link> element
294
+ */
295
+ export function createLinkElement(href) {
296
+ const element = createHtmlElement("link");
297
+ element.rel = "stylesheet";
298
+ element.href = href;
299
+ return element;
300
+ }
301
+ /**
302
+ * Create svg elements
303
+ */
304
+ export function createSvgElement(content, attributes = {}) {
305
+ const element = document.createElementNS("http://www.w3.org/2000/svg", "svg");
306
+ for (const [name, value] of Object.entries(attributes)) {
307
+ element.setAttribute(name, value);
308
+ }
309
+ element.innerHTML = content.trim();
310
+ return element;
311
+ }
312
+ /**
313
+ * Create an image element to use as a tracking pixel
314
+ */
315
+ export function createPixelElement(src) {
316
+ const image = document.createElement("img");
317
+ image.alt = "";
318
+ image.src = src;
319
+ image.width = 1;
320
+ image.height = 1;
321
+ image.loading = "eager";
322
+ image.setAttribute("aria-hidden", "true");
323
+ image.style.position = "absolute";
324
+ image.style.left = "-99999px";
325
+ return image;
326
+ }
327
+ /**
328
+ * Append a new script element to the DOM head
329
+ */
330
+ export function insertJs(js, inline = false) {
331
+ const element = createScriptElement(js, inline);
332
+ document.head.appendChild(element);
333
+ }
334
+ /**
335
+ * Append a new style element to the DOM head
336
+ */
337
+ export function insertCss(css, className, external = false) {
338
+ const element = external ? createLinkElement(css) : createStyleElement(css);
339
+ if (className) {
340
+ element.className = className;
341
+ }
342
+ document.head.appendChild(element);
343
+ }
344
+ /**
345
+ * Get screen sizes
346
+ */
347
+ export function getScreenSize() {
348
+ const width = window.screen?.width ?? window.innerWidth;
349
+ const height = window.screen?.height ?? window.innerHeight;
350
+ return { width, height };
351
+ }
352
+ /**
353
+ * Get a random integer between min and max
354
+ */
355
+ export function getRandomInt(min = 0, max = 4294967295) {
356
+ min = Math.ceil(min);
357
+ max = Math.floor(max);
358
+ if (max <= min) {
359
+ return min;
360
+ }
361
+ return Math.floor(Math.random() * (max - min)) + min;
362
+ }
363
+ /**
364
+ * Implementation of Java's String.hashCode() method
365
+ */
366
+ export function hashCode(str) {
367
+ let hash = 0, chr;
368
+ for (let i = 0; i < str.length; i++) {
369
+ chr = str.charCodeAt(i);
370
+ hash = (hash << 5) - hash + chr;
371
+ hash |= 0; // convert to 32bit integer
372
+ }
373
+ return hash >>> 0;
374
+ }
375
+ /**
376
+ * Executes a callback as soon as DOM is interactive
377
+ */
378
+ export function onDOMReady(callback, ...args) {
379
+ if (document.readyState === "interactive" ||
380
+ document.readyState === "complete") {
381
+ callback(...args);
382
+ }
383
+ else {
384
+ document.addEventListener("DOMContentLoaded", () => callback(...args));
394
385
  }
395
- }
396
- return keys;
397
- }
398
- function getFromObject(object, key) {
399
- return key.split(".").reduce((a, b) => {
400
- return a[b];
401
- }, object);
402
- }
403
- function fireBlurEvent(element, delay = 0) {
404
- fireEvent("blur", element, delay);
405
386
  }
406
- function fireInputEvent(element, delay = 0) {
407
- fireEvent("input", element, delay);
387
+ /**
388
+ * Calculate the percentage of two values
389
+ *
390
+ * @param a
391
+ * @param b
392
+ * @return number
393
+ */
394
+ export function toPercent(a, b) {
395
+ return b > 0 ? (a / b) * 100 : 0;
396
+ }
397
+ /**
398
+ * Make a camelCase string
399
+ *
400
+ * @param string
401
+ * @return string
402
+ */
403
+ export function toCamelCase(string) {
404
+ return string
405
+ .split(new RegExp(/[-_.]/))
406
+ .reduce((a, b) => a + b.charAt(0).toUpperCase() + b.slice(1));
407
+ }
408
+ /**
409
+ * Make a snake_case string
410
+ *
411
+ * @param string
412
+ * @return string
413
+ */
414
+ export function toSnakeCase(string) {
415
+ return toCamelCase(string)
416
+ .replace(/(^[A-Z])?([A-Z])/gm, "$1_$2")
417
+ .toLowerCase();
418
+ }
419
+ /**
420
+ * Transform the first letter of the given string to the upper case
421
+ *
422
+ * @param string
423
+ * @return string
424
+ */
425
+ export function capitalize(string) {
426
+ return string.charAt(0).toUpperCase() + string.slice(1);
427
+ }
428
+ /**
429
+ * Registry independent string sorting
430
+ *
431
+ * @param first
432
+ * @param second
433
+ */
434
+ export function sortByAlphabet(first, second) {
435
+ return first.toLowerCase() > second.toLowerCase() ? 1 : -1;
436
+ }
437
+ /**
438
+ * @param length
439
+ * @return string of max length 100
440
+ */
441
+ export function getRandomStr(length) {
442
+ length = length ? (length > 100 ? 100 : length) : 10;
443
+ let str = Math.random().toString(36).substring(2);
444
+ while (str.length < length) {
445
+ str += Math.random().toString(36).substring(2);
446
+ }
447
+ const result = str.slice(-length);
448
+ return isNaN(Number(result)) ? result : getRandomStr(length);
449
+ }
450
+ export function getRandomItem(items) {
451
+ return items[Math.floor(Math.random() * items.length)];
452
+ }
453
+ /**
454
+ * Summarize elements of the given array
455
+ *
456
+ * @param values
457
+ * @return number | string - a summary of all the numbers in the array or an empty string if
458
+ * there was only NaNs
459
+ */
460
+ export function sumArray(values) {
461
+ if (values.every((value) => isNaN(value))) {
462
+ return "";
463
+ }
464
+ else {
465
+ return values.reduce((sum, curr) => {
466
+ const value = Number(curr);
467
+ if (!isNaN(value)) {
468
+ return sum + value;
469
+ }
470
+ else {
471
+ return sum;
472
+ }
473
+ }, 0);
474
+ }
408
475
  }
409
- function fireEvent(eventName, element, delay = 0) {
410
- setTimeout(() => {
411
- if (isString(element)) {
412
- element = document.querySelector(element);
476
+ /**
477
+ * Returns an array of the object keys which values are not present in filter
478
+ *
479
+ * @param obj
480
+ * @param values
481
+ */
482
+ export function filterObjectKeysByValues(obj, values) {
483
+ values = Array.isArray(values) ? values : Array(values);
484
+ const keys = [];
485
+ for (const key in obj) {
486
+ if (!values.includes(obj[key])) {
487
+ keys.push(key);
488
+ }
413
489
  }
414
- if (!isNullOrUndef(element)) {
415
- element.dispatchEvent(
416
- new Event(eventName, {
417
- bubbles: true
418
- })
419
- );
490
+ return keys;
491
+ }
492
+ export function getFromObject(object, key) {
493
+ return key.split(".").reduce((a, b) => {
494
+ return a[b];
495
+ }, object);
496
+ }
497
+ export function fireBlurEvent(element, delay = 0) {
498
+ fireEvent("blur", element, delay);
499
+ }
500
+ export function fireInputEvent(element, delay = 0) {
501
+ fireEvent("input", element, delay);
502
+ }
503
+ export function fireEvent(eventName, element, delay = 0) {
504
+ setTimeout(() => {
505
+ const target = isString(element)
506
+ ? document.querySelector(element)
507
+ : element;
508
+ if (target) {
509
+ target.dispatchEvent(new Event(eventName, { bubbles: true }));
510
+ }
511
+ }, delay);
512
+ }
513
+ export function hasObjectChanged(oldObj, values, checkNewKeys = false) {
514
+ const newMap = new Map(values);
515
+ // check keys from old
516
+ for (const key of Object.keys(oldObj)) {
517
+ let oldVal = oldObj[key];
518
+ let newVal = newMap.get(key);
519
+ if (isObject(oldVal)) {
520
+ if (!isObject(newVal))
521
+ return true;
522
+ if (hasObjectChanged(oldVal, Object.entries(newVal), checkNewKeys))
523
+ return true;
524
+ continue;
525
+ }
526
+ if (Array.isArray(oldVal) || Array.isArray(newVal)) {
527
+ const oldArr = Array.isArray(oldVal) ? oldVal : [];
528
+ const newArr = Array.isArray(newVal) ? newVal : [];
529
+ if (arrayDiff(newArr, oldArr).length > 0)
530
+ return true;
531
+ continue;
532
+ }
533
+ if (areDiff(newVal, oldVal))
534
+ return true;
420
535
  }
421
- }, delay);
422
- }
423
- function hasObjectChanged(object, values) {
424
- let hasChanged = false;
425
- for (const key in object) {
426
- let oldVal = object[key];
427
- let [, newVal] = values.find(([newKey]) => key === newKey);
428
- if (isObject(oldVal)) {
429
- if (!isObject(newVal)) {
430
- hasChanged = true;
431
- } else {
432
- hasChanged = hasObjectChanged(oldVal, Object.entries(newVal));
433
- }
434
- } else if (Array.isArray(newVal) || Array.isArray(oldVal)) {
435
- newVal = Array.isArray(newVal) ? newVal : [];
436
- oldVal = Array.isArray(oldVal) ? oldVal : [];
437
- hasChanged = getObjectKeys(oldVal).length !== getObjectKeys(newVal).length;
438
- if (!hasChanged) {
439
- hasChanged = arrayDiff(newVal, oldVal).length > 0;
440
- }
441
- } else {
442
- hasChanged = areDiff(newVal, oldVal);
536
+ // optional: check keys that exist only in new
537
+ if (checkNewKeys) {
538
+ for (const key of newMap.keys()) {
539
+ if (!(key in oldObj))
540
+ return true;
541
+ }
443
542
  }
444
- if (hasChanged) {
445
- break;
543
+ return false;
544
+ }
545
+ export function roundBigNum(number) {
546
+ const digitsNum = Math.trunc(number).toString().length;
547
+ let roundTo = 0;
548
+ switch (true) {
549
+ case digitsNum > 2 && digitsNum < 5:
550
+ roundTo = 100;
551
+ break;
552
+ case digitsNum >= 5:
553
+ roundTo = 10000;
554
+ break;
446
555
  }
447
- }
448
- return hasChanged;
449
- }
450
- function roundBigNum(number) {
451
- const digitsNum = Math.trunc(number).toString().length;
452
- let roundTo = 0;
453
- switch (true) {
454
- case (digitsNum > 2 && digitsNum < 5):
455
- roundTo = 100;
456
- break;
457
- case digitsNum >= 5:
458
- roundTo = 1e4;
459
- break;
460
- }
461
- return roundTo ? Math.round(number / roundTo) * roundTo : number;
462
- }
463
- function extractNumbers(value) {
464
- if (!isStr(value) && !isNum(value)) {
465
- return "";
466
- }
467
- return value.toString().replace(/[^0-9]/g, "");
468
- }
469
- function removeSpaces(value) {
470
- if (!isStr(value) && !isNum(value)) {
471
- return "";
472
- }
473
- return value.toString().replace(/\s/g, "");
474
- }
475
- function roundUp(num, precision) {
476
- const multiplier = Number("1".padEnd(precision + 1, "0"));
477
- return Math.ceil(num * multiplier) / multiplier;
478
- }
479
- function roundDown(num, precision) {
480
- const multiplier = Number("1".padEnd(precision + 1, "0"));
481
- return Math.floor(num * multiplier) / multiplier;
482
- }
483
- function areDiff(val1, val2, strict) {
484
- if (strict) {
485
- return val1 !== val2;
486
- }
487
- if (Boolean(val1) || Boolean(val2)) {
488
- return val1 != val2;
489
- }
490
- return false;
491
- }
492
- function flattenObject(obj, prefix = "") {
493
- return Object.keys(obj).reduce((acc, k) => {
494
- const pre = prefix.length ? prefix + "." : "";
495
- if ((isObject(obj[k]) || Array.isArray(obj[k])) && getObjectKeys(obj[k]).length > 0) {
496
- Object.assign(acc, flattenObject(obj[k], pre + k));
497
- } else {
498
- acc[pre + k] = obj[k];
556
+ return roundTo ? Math.round(number / roundTo) * roundTo : number;
557
+ }
558
+ export function extractNumbers(value) {
559
+ if (!isString(value) && !isNum(value)) {
560
+ return "";
499
561
  }
500
- return acc;
501
- }, {});
502
- }
503
- function flattenObjectAsArray(obj) {
504
- const result = {};
505
- const flat = flattenObject(obj);
506
- Object.keys(flat).forEach((key) => {
507
- const newKey = key.replaceAll(/\.([^.]+)/g, "[$1]");
508
- result[newKey] = flat[key];
509
- });
510
- return result;
511
- }
512
- function parseObjectPathStr(pathStr) {
513
- const pathParts = pathStr.replace(/\[/g, ".").replace(/\]/g, "").split(".");
514
- if (pathParts.length > 1 && pathParts[1].includes("[")) {
515
- return [pathParts[0], ...parseObjectPathStr(pathParts[1])];
516
- }
517
- return pathParts;
518
- }
519
- function formatNumber(num, fractionDigits) {
520
- fractionDigits = isNullOrUndef(fractionDigits) ? 2 : fractionDigits;
521
- return new Intl.NumberFormat("ru-RU", {
522
- style: "decimal",
523
- minimumFractionDigits: fractionDigits,
524
- maximumFractionDigits: fractionDigits
525
- }).format(Number(num)).replace(",", ".").replace(/\u00A0/g, " ");
526
- }
527
- function formatNumberWithSign(num, fractionDigits) {
528
- return formatWithSign(num, formatNumber(num, fractionDigits));
529
- }
530
- function formatPercent(num) {
531
- return formatNumber(num) + "%";
532
- }
533
- function formatWithSign(num, numString) {
534
- numString = numString ? numString : num.toString();
535
- return (Number(num) < 0 ? "" : "+") + numString;
536
- }
537
- function autoSizeText(el, height, minFontSize, maxFontSize = 50) {
538
- let attempts = 30;
539
- const resizeText = () => {
540
- if (getTextHeight() === 0) {
541
- return;
562
+ return value.toString().replace(/[^0-9]/g, "");
563
+ }
564
+ export function removeSpaces(value) {
565
+ if (!isString(value) && !isNum(value)) {
566
+ return "";
542
567
  }
543
- while (attempts && getTextHeight() > height) {
544
- attempts--;
545
- reduceText();
568
+ return value.toString().replace(/\s/g, "");
569
+ }
570
+ export function roundUp(num, precision) {
571
+ const multiplier = Number("1".padEnd(precision + 1, "0"));
572
+ return Math.ceil(num * multiplier) / multiplier;
573
+ }
574
+ export function roundDown(num, precision) {
575
+ const multiplier = Number("1".padEnd(precision + 1, "0"));
576
+ return Math.floor(num * multiplier) / multiplier;
577
+ }
578
+ export function areDiff(val1, val2, strict) {
579
+ if (strict) {
580
+ return val1 !== val2;
546
581
  }
547
- while (attempts && getTextHeight() < height) {
548
- attempts--;
549
- enlargeText();
582
+ // at least one value is not empty
583
+ if (Boolean(val1) || Boolean(val2)) {
584
+ return val1 != val2;
550
585
  }
551
- };
552
- const reduceText = () => {
553
- const fontSize = getNumericStyleProp("fontSize", el);
554
- const newFontSize = fontSize - 1;
555
- if (fontSize > 1 && newFontSize >= minFontSize) {
556
- el.style.fontSize = `${newFontSize}px`;
586
+ // both empty, but not equally empty!
587
+ // each one may be one of: empty string, null or undefined
588
+ return false;
589
+ }
590
+ export function flattenObject(obj, prefix = "") {
591
+ const pre = prefix ? `${prefix}.` : "";
592
+ return Object.keys(obj).reduce((acc, k) => {
593
+ const val = obj[k];
594
+ const key = `${pre}${k}`;
595
+ if (isObject(val) || Array.isArray(val)) {
596
+ Object.assign(acc, flattenObject(val, key));
597
+ }
598
+ else {
599
+ acc[key] = val;
600
+ }
601
+ return acc;
602
+ }, {});
603
+ }
604
+ export function flattenObjectAsArray(obj) {
605
+ const flat = flattenObject(obj);
606
+ const result = {};
607
+ for (const key of Object.keys(flat)) {
608
+ const newKey = key.replace(/\.([^.]+)/g, "[$1]");
609
+ result[newKey] = flat[key];
557
610
  }
558
- };
559
- const enlargeText = () => {
560
- const fontSize = getNumericStyleProp("fontSize", el);
561
- const newFontSize = fontSize + 1;
562
- if (newFontSize <= maxFontSize) {
563
- el.style.fontSize = `${newFontSize}px`;
611
+ return result;
612
+ }
613
+ export function parseObjectPathStr(pathStr) {
614
+ const pathParts = pathStr.replace(/\[/g, ".").replace(/\]/g, "").split(".");
615
+ if (pathParts[0] && pathParts[1] && pathParts[1].includes("[")) {
616
+ return [pathParts[0], ...parseObjectPathStr(pathParts[1])];
564
617
  }
565
- };
566
- const getTextHeight = () => Math.floor(
567
- el.scrollHeight - getNumericStyleProp("paddingTop", el) - getNumericStyleProp("paddingBottom", el)
568
- );
569
- resizeText();
570
- }
571
-
572
- exports.areDiff = areDiff;
573
- exports.arrayDiff = arrayDiff;
574
- exports.arrayIntersect = arrayIntersect;
575
- exports.autoSizeText = autoSizeText;
576
- exports.capitalize = capitalize;
577
- exports.countObjectInnerLength = countObjectInnerLength;
578
- exports.createHtmlElement = createHtmlElement;
579
- exports.createLinkElement = createLinkElement;
580
- exports.createPixelElement = createPixelElement;
581
- exports.createScriptElement = createScriptElement;
582
- exports.createStyleElement = createStyleElement;
583
- exports.createSvgElement = createSvgElement;
584
- exports.debounce = debounce;
585
- exports.decodeSafeURL = decodeSafeURL;
586
- exports.deepCloneObject = deepCloneObject;
587
- exports.encodeQueryString = encodeQueryString;
588
- exports.extractNumbers = extractNumbers;
589
- exports.filterObjectKeysByValues = filterObjectKeysByValues;
590
- exports.fireBlurEvent = fireBlurEvent;
591
- exports.fireEvent = fireEvent;
592
- exports.fireInputEvent = fireInputEvent;
593
- exports.flatHtmlAttributes = flatHtmlAttributes;
594
- exports.flattenObject = flattenObject;
595
- exports.flattenObjectAsArray = flattenObjectAsArray;
596
- exports.formatNumber = formatNumber;
597
- exports.formatNumberWithSign = formatNumberWithSign;
598
- exports.formatPercent = formatPercent;
599
- exports.formatWithSign = formatWithSign;
600
- exports.getFromObject = getFromObject;
601
- exports.getHtmlElement = getHtmlElement;
602
- exports.getNumericStyleProp = getNumericStyleProp;
603
- exports.getObjectKeys = getObjectKeys;
604
- exports.getRandomInt = getRandomInt;
605
- exports.getRandomItem = getRandomItem;
606
- exports.getRandomStr = getRandomStr;
607
- exports.getSafeURL = getSafeURL;
608
- exports.getScreenSize = getScreenSize;
609
- exports.hasObjectChanged = hasObjectChanged;
610
- exports.hashCode = hashCode;
611
- exports.injectScript = injectScript;
612
- exports.injectStyleLink = injectStyleLink;
613
- exports.insertCss = insertCss;
614
- exports.insertHtmlElements = insertHtmlElements;
615
- exports.insertJs = insertJs;
616
- exports.isBool = isBool;
617
- exports.isDefined = isDefined;
618
- exports.isElementVisible = isElementVisible;
619
- exports.isFn = isFn;
620
- exports.isHTMLElement = isHTMLElement;
621
- exports.isNotEmptyString = isNotEmptyString;
622
- exports.isNullOrUndef = isNullOrUndef;
623
- exports.isNum = isNum;
624
- exports.isObject = isObject;
625
- exports.isStr = isStr;
626
- exports.isString = isString;
627
- exports.isUndef = isUndef;
628
- exports.objectHasProp = objectHasProp;
629
- exports.objectToQueryString = objectToQueryString;
630
- exports.onDOMReady = onDOMReady;
631
- exports.parseObjectPathStr = parseObjectPathStr;
632
- exports.parseURL = parseURL;
633
- exports.removeSpaces = removeSpaces;
634
- exports.roundBigNum = roundBigNum;
635
- exports.roundDown = roundDown;
636
- exports.roundUp = roundUp;
637
- exports.sortByAlphabet = sortByAlphabet;
638
- exports.stringToHtmlElements = stringToHtmlElements;
639
- exports.sumArray = sumArray;
640
- exports.throttle = throttle;
641
- exports.toBinaryStr = toBinaryStr;
642
- exports.toCamelCase = toCamelCase;
643
- exports.toPercent = toPercent;
644
- exports.toSnakeCase = toSnakeCase;
645
- //# sourceMappingURL=index.js.map
618
+ return pathParts;
619
+ }
620
+ export function formatNumber(num, fractionDigits) {
621
+ fractionDigits = isNullOrUndef(fractionDigits) ? 2 : fractionDigits;
622
+ return new Intl.NumberFormat("ru-RU", {
623
+ style: "decimal",
624
+ minimumFractionDigits: fractionDigits,
625
+ maximumFractionDigits: fractionDigits,
626
+ })
627
+ .format(Number(num))
628
+ .replace(",", ".")
629
+ .replace(/\u00A0/g, " "); // charCode 160, White-space
630
+ }
631
+ export function formatNumberWithSign(num, fractionDigits) {
632
+ return formatWithSign(num, formatNumber(num, fractionDigits));
633
+ }
634
+ export function formatPercent(num) {
635
+ return formatNumber(num) + "%";
636
+ }
637
+ export function formatWithSign(num, numString) {
638
+ numString = numString ? numString : num.toString();
639
+ return (Number(num) < 0 ? "" : "+") + numString;
640
+ }
641
+ export function autoSizeText(el, height, minFontSize, maxFontSize = 50) {
642
+ let attempts = 30;
643
+ const resizeText = () => {
644
+ if (getTextHeight() === 0) {
645
+ return;
646
+ }
647
+ while (attempts && getTextHeight() > height) {
648
+ attempts--;
649
+ reduceText();
650
+ }
651
+ while (attempts && getTextHeight() < height) {
652
+ attempts--;
653
+ enlargeText();
654
+ }
655
+ };
656
+ const reduceText = () => {
657
+ const fontSize = getNumericStyleProp("fontSize", el);
658
+ const newFontSize = fontSize - 1;
659
+ if (fontSize > 1 && newFontSize >= minFontSize) {
660
+ el.style.fontSize = `${newFontSize}px`;
661
+ }
662
+ };
663
+ const enlargeText = () => {
664
+ const fontSize = getNumericStyleProp("fontSize", el);
665
+ const newFontSize = fontSize + 1;
666
+ if (newFontSize <= maxFontSize) {
667
+ el.style.fontSize = `${newFontSize}px`;
668
+ }
669
+ };
670
+ const getTextHeight = () => Math.floor(el.scrollHeight -
671
+ getNumericStyleProp("paddingTop", el) -
672
+ getNumericStyleProp("paddingBottom", el));
673
+ resizeText();
674
+ }
675
+ //# sourceMappingURL=index.js.map