@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.d.ts +74 -95
- package/dist/index.js +649 -619
- package/dist/index.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +1 -1
- package/src/index.ts +18 -3
- package/tests/tests.ts +129 -0
package/dist/index.js
CHANGED
|
@@ -1,645 +1,675 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
function
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
function
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
-
|
|
138
|
+
export function getSafeURL(url) {
|
|
139
|
+
url = url ? url : location.href;
|
|
140
|
+
return encodeURI(decodeSafeURL(url));
|
|
137
141
|
}
|
|
138
|
-
function parseURL(url) {
|
|
139
|
-
|
|
142
|
+
export function parseURL(url) {
|
|
143
|
+
return new URL(url);
|
|
140
144
|
}
|
|
141
|
-
function encodeQueryString(url) {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
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
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
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
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
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
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
258
|
+
const attr = attributes[i];
|
|
259
|
+
if (attr) {
|
|
260
|
+
result[attr.name] = attr.value;
|
|
261
|
+
}
|
|
246
262
|
}
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
function
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
function
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
function
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
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
|
-
|
|
407
|
-
|
|
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
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
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
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
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
|
-
|
|
445
|
-
|
|
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
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
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
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
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
|
-
|
|
544
|
-
|
|
545
|
-
|
|
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
|
-
|
|
548
|
-
|
|
549
|
-
|
|
582
|
+
// at least one value is not empty
|
|
583
|
+
if (Boolean(val1) || Boolean(val2)) {
|
|
584
|
+
return val1 != val2;
|
|
550
585
|
}
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
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
|
-
|
|
560
|
-
|
|
561
|
-
const
|
|
562
|
-
if (
|
|
563
|
-
|
|
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
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
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
|