-
Notifications
You must be signed in to change notification settings - Fork 155
/
Copy pathutil.ts
495 lines (478 loc) · 15.5 KB
/
util.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/explicit-module-boundary-types */
/**
* Common utility methods
*/
export interface IKeyValue extends CSSStyleDeclaration {
[key: string]: any;
}
const instances: string = 'ej2_instances';
declare let window: {
msCrypto: Crypto;
} & Window;
let uid: number = 0;
let isBlazorPlatform: boolean = false;
/**
* Function to check whether the platform is blazor or not.
*
* @returns {void} result
* @private
*/
export function disableBlazorMode(): void {
isBlazorPlatform = false;
}
/**
* Create Instance from constructor function with desired parameters.
*
* @param {Function} classFunction - Class function to which need to create instance
* @param {any[]} params - Parameters need to passed while creating instance
* @returns {any} ?
* @private
*/
export function createInstance(classFunction: Function, params: any[]): any {
const arrayParam: Object[] = params;
arrayParam.unshift(undefined);
return new (Function.prototype.bind.apply(classFunction, arrayParam));
}
/**
* To run a callback function immediately after the browser has completed other operations.
*
* @param {Function} handler - callback function to be triggered.
* @returns {Function} ?
* @private
*/
export function setImmediate(handler: Function): Function {
let unbind: Function;
const num: any = new Uint16Array(5);
const intCrypto: Crypto = window.msCrypto || window.crypto;
intCrypto.getRandomValues(num);
let secret: string = 'ej2' + combineArray(num);
let messageHandler: Function = (event: any): void => {
if (event.source === window && typeof event.data === 'string' && event.data.length <= 32 && event.data === secret) {
handler();
unbind();
}
};
window.addEventListener('message', <EventListener>messageHandler, false);
window.postMessage(secret, '*');
return unbind = () => {
window.removeEventListener('message', <EventListener>messageHandler);
handler = messageHandler = secret = undefined;
};
}
/**
* To get nameSpace value from the desired object.
*
* @param {string} nameSpace - String value to the get the inner object
* @param {any} obj - Object to get the inner object value.
* @returns {any} ?
* @private
*/
export function getValue(nameSpace: string, obj: any): any {
let value: any = obj;
const splits: string[] = nameSpace.replace(/\[/g, '.').replace(/\]/g, '').split('.');
for (let i: number = 0; i < splits.length && !isUndefined(value); i++) {
value = value[splits[parseInt(i.toString(), 10)]];
}
return value;
}
/**
* To set value for the nameSpace in desired object.
*
* @param {string} nameSpace - String value to the get the inner object
* @param {any} value - Value that you need to set.
* @param {any} obj - Object to get the inner object value.
* @returns {any} ?
* @private
*/
export function setValue(nameSpace: string, value: any, obj: any): any {
const keys: string[] = nameSpace.replace(/\[/g, '.').replace(/\]/g, '').split('.');
const start: any = obj || {};
let fromObj: any = start;
let i: number;
const length: number = keys.length;
let key: string;
for (i = 0; i < length; i++) {
key = keys[parseInt(i.toString(), 10)];
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
continue;
}
if (i + 1 === length) {
fromObj[`${key}`] = value === undefined ? {} : value;
} else if (isNullOrUndefined(fromObj[`${key}`])) {
fromObj[`${key}`] = {};
}
fromObj = fromObj[`${key}`];
}
return start;
}
/**
* Delete an item from Object
*
* @param {any} obj - Object in which we need to delete an item.
* @param {string} key - String value to the get the inner object
* @returns {void} ?
* @private
*/
export function deleteObject(obj: any, key: string): void {
delete obj[`${key}`];
}
/**
*@private
*/
export const containerObject: any = typeof window !== 'undefined' ? window : {};
/**
* Check weather the given argument is only object.
*
* @param {any} obj - Object which is need to check.
* @returns {boolean} ?
* @private
*/
export function isObject(obj: any): boolean {
const objCon: {} = {};
return (!isNullOrUndefined(obj) && obj.constructor === objCon.constructor);
}
/**
* To get enum value by giving the string.
*
* @param {any} enumObject - Enum object.
* @param {string} enumValue - Enum value to be searched
* @returns {any} ?
* @private
*/
export function getEnumValue(enumObject: any, enumValue: string | number): any {
return (<any>enumObject[`${enumValue}`]);
}
/**
* Merge the source object into destination object.
*
* @param {any} source - source object which is going to merge with destination object
* @param {any} destination - object need to be merged
* @returns {void} ?
* @private
*/
export function merge(source: Object, destination: Object): void {
if (!isNullOrUndefined(destination)) {
const temrObj: IKeyValue = source as IKeyValue;
const tempProp: IKeyValue = destination as IKeyValue;
const keys: string[] = Object.keys(destination);
const deepmerge: string = 'deepMerge';
for (const key of keys) {
if (!isNullOrUndefined(temrObj[`${deepmerge}`]) && (temrObj[`${deepmerge}`].indexOf(key) !== -1) &&
(isObject(tempProp[`${key}`]) || Array.isArray(tempProp[`${key}`]))) {
extend(temrObj[`${key}`], temrObj[`${key}`], tempProp[`${key}`], true);
} else {
temrObj[`${key}`] = tempProp[`${key}`];
}
}
}
}
/**
* Extend the two object with newer one.
*
* @param {any} copied - Resultant object after merged
* @param {Object} first - First object need to merge
* @param {Object} second - Second object need to merge
* @param {boolean} deep ?
* @returns {Object} ?
* @private
*/
export function extend(copied: Object, first: Object, second?: Object, deep?: boolean): Object {
const result: IKeyValue = copied && typeof copied === 'object' ? copied as IKeyValue : {} as IKeyValue;
let length: number = arguments.length;
const args: Object = [copied, first, second, deep];
if (deep) {
length = length - 1;
}
for (let i: number = 1; i < length; i++) {
if (!args[parseInt(i.toString(), 10)]) {
continue;
}
const obj1: { [key: string]: Object } = args[parseInt(i.toString(), 10)];
Object.keys(obj1).forEach((key: string) => {
const src: Object = result[`${key}`];
const copy: Object = obj1[`${key}`];
let clone: Object;
const isArrayChanged: boolean = Array.isArray(copy) && Array.isArray(src) && (copy.length !== src.length);
const blazorEventExtend: any = isBlazor() ? (!(src instanceof Event) && !isArrayChanged) : true;
if (deep && blazorEventExtend && (isObject(copy) || Array.isArray(copy))) {
if (isObject(copy)) {
clone = src ? src : {};
if (Array.isArray(clone) && Object.prototype.hasOwnProperty.call(clone, 'isComplexArray')) {
extend(clone, {}, copy, deep);
} else {
result[`${key}`] = extend(clone, {}, copy, deep);
}
} else {
/* istanbul ignore next */
clone = isBlazor() ? src && Object.keys(copy).length : src ? src : [];
result[`${key}`] = extend([], clone, copy, (clone && (clone as any).length) || (copy && (copy as any).length));
}
} else {
result[`${key}`] = copy;
}
});
}
return result;
}
/**
* To check whether the object is null or undefined.
*
* @param {any} value - To check the object is null or undefined
* @returns {boolean} ?
* @private
*/
export function isNullOrUndefined<T>(value: T): boolean {
return value === undefined || value === null;
}
/**
* To check whether the object is undefined.
*
* @param {any} value - To check the object is undefined
* @returns {boolean} ?
* @private
*/
export function isUndefined<T>(value: T): boolean {
return ('undefined' === typeof value);
}
/**
* To return the generated unique name
*
* @param {string} definedName - To concatenate the unique id to provided name
* @returns {string} ?
* @private
*/
export function getUniqueID(definedName?: string): string {
return definedName + '_' + uid++;
}
/**
* It limits the rate at which a function can fire. The function will fire only once every provided second instead of as quickly.
*
* @param {Function} eventFunction - Specifies the function to run when the event occurs
* @param {number} delay - A number that specifies the milliseconds for function delay call option
* @returns {Function} ?
* @private
*/
export function debounce(eventFunction: Function, delay: number): Function {
let out: any;
return function (...args: any): void {
const later: TimeoutHandler = () => {
out = null;
return eventFunction.apply(this, args);
};
clearTimeout(out);
out = setTimeout(later, delay);
};
}
/**
* To convert the object to string for query url
*
* @param {Object} data ?
* @returns {string} ?
* @private
*/
export function queryParams(data: any): string {
const array: string[] = [];
const keys: string[] = Object.keys(data);
for (const key of keys) {
array.push(encodeURIComponent(key) + '=' + encodeURIComponent('' + data[`${key}`]));
}
return array.join('&');
}
/**
* To check whether the given array contains object.
*
* @param {any} value - Specifies the T type array to be checked.
* @returns {boolean} ?
* @private
*/
export function isObjectArray<T>(value: T[]): boolean {
const parser: Function = Object.prototype.toString;
if (parser.call(value) === '[object Array]') {
if (parser.call(value[0]) === '[object Object]') {
return true;
}
}
return false;
}
/**
* To check whether the child element is descendant to parent element or parent and child are same element.
*
* @param {Element} child - Specifies the child element to compare with parent.
* @param {Element} parent - Specifies the parent element.
* @returns {boolean} ?
* @private
*/
export function compareElementParent(child: Element, parent: Element): boolean {
const node: Node = child;
if (node === parent) {
return true;
} else if (node === document || !node) {
return false;
} else {
return compareElementParent(<Element>node.parentNode, parent);
}
}
/**
* To throw custom error message.
*
* @param {string} message - Specifies the error message to be thrown.
* @returns {void} ?
* @private
*/
export function throwError(message: string): void {
try {
throw new Error(message);
} catch (e) {
throw new Error(e.message + '\n' + e.stack);
}
}
/**
* This function is used to print given element
*
* @param {Element} element - Specifies the print content element.
* @param {Window} printWindow - Specifies the print window.
* @returns {Window} ?
* @private
*/
export function print(element: Element, printWindow?: Window): Window {
const div: Element = document.createElement('div');
const links: HTMLElement[] = [].slice.call(document.getElementsByTagName('head')[0].querySelectorAll('base, link, style'));
const blinks: HTMLElement[] = [].slice.call(document.getElementsByTagName('body')[0].querySelectorAll('link, style'));
if (blinks.length) {
for (let l: number = 0, len: number = blinks.length; l < len; l++) {
links.push(blinks[parseInt(l.toString(), 10)]);
}
}
let reference: string = '';
if (isNullOrUndefined(printWindow)) {
printWindow = window.open('', 'print', 'height=452,width=1024,tabbar=no');
}
div.appendChild(element.cloneNode(true) as Element);
for (let i: number = 0, len: number = links.length; i < len; i++) {
reference += links[parseInt(i.toString(), 10)].outerHTML;
}
printWindow.document.write('<!DOCTYPE html> <html><head>' + reference + '</head><body>' + div.innerHTML +
'<script> (function() { window.ready = true; })(); </script>' + '</body></html>');
printWindow.document.close();
printWindow.focus();
const interval: any = setInterval(
() => {
if ((<{ ready: Function } & Window>printWindow).ready) {
printWindow.print();
printWindow.close();
clearInterval(interval);
}
},
500);
return printWindow;
}
/**
* Function to normalize the units applied to the element.
*
* @param {number|string} value ?
* @returns {string} result
* @private
*/
export function formatUnit(value: number | string): string {
const result: string = <string>value + '';
if (result.match(/auto|cm|mm|in|px|pt|pc|%|em|ex|ch|rem|vw|vh|vmin|vmax/)) {
return result;
}
return result + 'px';
}
/**
* Function to check whether the platform is blazor or not.
*
* @returns {void} result
* @private
*/
export function enableBlazorMode(): void {
isBlazorPlatform = true;
}
/**
* Function to check whether the platform is blazor or not.
*
* @returns {boolean} result
* @private
*/
export function isBlazor(): boolean {
return isBlazorPlatform;
}
/**
* Function to convert xPath to DOM element in blazor platform
*
* @returns {HTMLElement} result
* @param {HTMLElement | object} element ?
* @private
*/
export function getElement(element: object): HTMLElement {
const xPath: string = 'xPath';
if (!(element instanceof Node) && isBlazor() && !isNullOrUndefined(element[`${xPath}`])) {
return document.evaluate(element[`${xPath}`], document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue as HTMLElement;
}
return element as HTMLElement;
}
/**
* Function to fetch the Instances of a HTML element for the given component.
*
* @param {string | HTMLElement} element ?
* @param {any} component ?
* @returns {Object} ?
* @private
*/
export function getInstance(element: string | HTMLElement, component: any): Object {
const elem: any = (typeof (element) === 'string') ? document.querySelector(element) : element;
if (elem[`${instances}`]) {
for (const inst of elem[`${instances}`]) {
if (inst instanceof component) {
return inst;
}
}
}
return null;
}
/**
* Function to add instances for the given element.
*
* @param {string | HTMLElement} element ?
* @param {Object} instance ?
* @returns {void} ?
* @private
*/
export function addInstance(element: string | HTMLElement, instance: Object): void {
const elem: any = (typeof (element) === 'string') ? document.querySelector(element) : element;
if (elem[`${instances}`]) {
elem[`${instances}`].push(instance);
} else {
elem[`${instances}`] = [instance];
}
}
/**
* Function to generate the unique id.
*
* @returns {any} ?
* @private
*/
export function uniqueID(): any {
if ((typeof window) === 'undefined') {
return;
}
const num: any = new Uint16Array(5);
const intCrypto: Crypto = window.msCrypto || window.crypto;
return intCrypto.getRandomValues(num);
}
interface TimeoutHandler {
(): Function;
}
/**
*
* @param {Int16Array} num ?
* @returns {string} ?
*/
function combineArray(num: Int16Array): string {
let ret: string = '';
for (let i: number = 0; i < 5; i++) {
ret += (i ? ',' : '') + num[parseInt(i.toString(), 10)];
}
return ret;
}