@libs-ui/utils 0.2.29 → 0.2.30-6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/base64.d.ts +5 -0
  2. package/cache.d.ts +16 -15
  3. package/color.d.ts +1 -1
  4. package/communicate-micro.d.ts +4 -5
  5. package/constants.d.ts +3 -0
  6. package/crypto-3rd.d.ts +4 -0
  7. package/crypto.d.ts +4 -0
  8. package/date.d.ts +49 -0
  9. package/dom.d.ts +36 -1
  10. package/download.d.ts +3 -0
  11. package/esm2022/base64.mjs +43 -0
  12. package/esm2022/cache.mjs +121 -132
  13. package/esm2022/color.mjs +2 -2
  14. package/esm2022/communicate-micro.mjs +26 -24
  15. package/esm2022/constants.mjs +4 -1
  16. package/esm2022/crypto-3rd.mjs +5 -1
  17. package/esm2022/crypto.mjs +5 -1
  18. package/esm2022/date.mjs +189 -0
  19. package/esm2022/dom.mjs +200 -22
  20. package/esm2022/download.mjs +37 -0
  21. package/esm2022/file.mjs +79 -0
  22. package/esm2022/format-text.mjs +150 -0
  23. package/esm2022/get-smart-axis-scale.mjs +174 -0
  24. package/esm2022/helpers.mjs +402 -91
  25. package/esm2022/http-params.mjs +15 -3
  26. package/esm2022/index.mjs +12 -5
  27. package/esm2022/inject-token.mjs +5 -0
  28. package/esm2022/key-cache.mjs +20 -8
  29. package/esm2022/language.mjs +67 -4
  30. package/esm2022/pattern.mjs +21 -21
  31. package/esm2022/random.mjs +42 -0
  32. package/esm2022/two-way-signal-object.mjs +113 -0
  33. package/esm2022/uri.mjs +22 -0
  34. package/esm2022/uuid.mjs +3 -2
  35. package/esm2022/xss-filter.mjs +10 -0
  36. package/fesm2022/libs-ui-utils.mjs +2238 -880
  37. package/fesm2022/libs-ui-utils.mjs.map +1 -1
  38. package/file.d.ts +18 -0
  39. package/format-text.d.ts +11 -0
  40. package/get-smart-axis-scale.d.ts +34 -0
  41. package/helpers.d.ts +218 -10
  42. package/http-params.d.ts +2 -2
  43. package/index.d.ts +11 -4
  44. package/inject-token.d.ts +4 -0
  45. package/language.d.ts +32 -0
  46. package/package.json +7 -4
  47. package/pattern.d.ts +20 -20
  48. package/random.d.ts +3 -0
  49. package/two-way-signal-object.d.ts +14 -0
  50. package/uri.d.ts +5 -0
  51. package/xss-filter.d.ts +3 -0
  52. package/delete-unicode.d.ts +0 -1
  53. package/escape-html.d.ts +0 -1
  54. package/esm2022/delete-unicode.mjs +0 -20
  55. package/esm2022/escape-html.mjs +0 -12
  56. package/esm2022/get-color-by-id.mjs +0 -17
  57. package/esm2022/remove-emoji.mjs +0 -10
  58. package/get-color-by-id.d.ts +0 -1
  59. package/remove-emoji.d.ts +0 -2
@@ -1,27 +1,249 @@
1
- import { TemplateRef, ElementRef, signal } from '@angular/core';
1
+ import DeviceDetector from 'device-detector-js';
2
+ import Quill from 'quill';
3
+ import { fromEvent, tap, takeUntil, mergeMap, startWith, finalize, lastValueFrom, timer, Subject, filter, Observable } from 'rxjs';
2
4
  import CryptoES from 'crypto-es';
3
5
  import { HttpParams } from '@angular/common/http';
4
- import { Subject, fromEvent, filter } from 'rxjs';
6
+ import { isSignal, TemplateRef, ElementRef, signal, InjectionToken } from '@angular/core';
7
+ import dayjs from 'dayjs';
8
+ import 'dayjs/locale/en';
9
+ import 'dayjs/locale/vi';
10
+ import customParseFormat from 'dayjs/plugin/customParseFormat';
11
+ import localeData from 'dayjs/plugin/localeData';
12
+ import timezone from 'dayjs/plugin/timezone';
13
+ import updateLocale from 'dayjs/plugin/updateLocale';
14
+ import utc from 'dayjs/plugin/utc';
5
15
 
6
- const getPlatFromBrowser = () => {
7
- const userAgent = navigator.userAgent;
8
- let tem;
9
- let match = userAgent.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || [];
10
- if (/trident/i.test(match[1])) {
11
- tem = /\brv[ :]+(\d+)/g.exec(userAgent) || [];
12
- return 'IE ' + (tem[1] || '');
16
+ /* eslint-disable no-useless-escape */
17
+ const patternEmail = () => {
18
+ return /^[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]@[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]\.[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]$/;
19
+ };
20
+ const patternUrl = () => {
21
+ return /^(http|https|ftp):(\/){2}[^\s]+[.]{1}[^\s]+$/;
22
+ };
23
+ const patternHostUrl = () => {
24
+ return /^((https|http|ftp):[/]{2}[^/\s]+)/;
25
+ };
26
+ const patternDomain = () => {
27
+ return /^([a-zA-Z0-9])(([a-z0-9-]{1,61})?[a-z0-9]{1})?(\.[a-z0-9](([a-z0-9-]{1,61})?[a-z0-9]{1})?)?(\.[a-zA-Z]{2,4})+$/;
28
+ };
29
+ const patternMobilePhone = () => {
30
+ return /^(\+?84|0|84)([0-9]{9})$/;
31
+ };
32
+ const patternPhone = () => {
33
+ return /^(\+?84|[0-9]|84)([0-9]{2,9})$/;
34
+ };
35
+ const patternPhoneNormal = () => {
36
+ return /^(\+?84|[0-9]|84)([0-9]{9,10})$/;
37
+ };
38
+ const patternNumber = () => {
39
+ return /\d+/g;
40
+ };
41
+ const patternEncodeUri = () => {
42
+ return /%([0-9A-F]{2})/g;
43
+ };
44
+ const patternName = () => {
45
+ return /^\w+[A-Za-z\s\d]+$/;
46
+ };
47
+ const patternNameUtf8 = () => {
48
+ return /^[ àáảãạăắằẵặẳâầấậẫẩđèéẻẽẹêềếểễệìíỉĩịòóỏõọôồốổỗộơờớởỡợùúủũụưừứửữựỳýỷỹÀÁẢÃẠĂẮẰẴẶẲÂẦẤẬẪẨĐÈÉẺẼẸÊỀẾỂỄỆÌÍỈĨỊÒÓỎÕỌÔỒỐỔỖỘƠỜỚỞỠỢÙÚỦŨỤƯỪỨỬỮỰỲÝỶỸA-Za-z0-9]+$/;
49
+ };
50
+ const patternNameSpecial = () => {
51
+ return /[~!@#$%^&*()-+=<>,?\/\\:;"']/;
52
+ };
53
+ const patternNameProfile = () => {
54
+ return /([\w\W\d\s]+)+/;
55
+ };
56
+ const patternEmoji = () => {
57
+ return /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g;
58
+ };
59
+ const patternRuleFieldReplace = () => {
60
+ return /[{]{2}[a-zA-Z_-]+[}]{2}/g;
61
+ };
62
+ const patternGetFieldByRuleFieldReplace = () => {
63
+ return /[a-zA-Z_-]+/g;
64
+ };
65
+ const patternPem = () => {
66
+ return /^(0|1):([0-9]{1,2}):(\{\{path-api\}\}):([a-zA-Z0-9\/]+)$/g;
67
+ };
68
+ const patternTax = () => {
69
+ return /^([0-9]){10}(-[0-9]{3})?$/;
70
+ };
71
+ const patternKey = () => {
72
+ return /^([0-9]){10}(-[0-9]{3})?$/;
73
+ };
74
+ const patternAccount = () => {
75
+ return /^(?=.*@)[a-z0-9@._-]{2,63}$/;
76
+ };
77
+
78
+ const highlightByKeyword = (value, search, ignoreHighlight, classHightLight) => {
79
+ if (!value) {
80
+ return '&mdash;';
81
+ }
82
+ try {
83
+ if (!search || ignoreHighlight) {
84
+ return value;
85
+ }
86
+ const keysReplace = getValueReplace(search, value);
87
+ if (!keysReplace || !keysReplace.length) {
88
+ return value;
89
+ }
90
+ if (!classHightLight) {
91
+ classHightLight = 'bg-[#19344a] text-white';
92
+ }
93
+ keysReplace.forEach(key => {
94
+ const regExp = new RegExp(key, 'gi');
95
+ value = value?.replace(regExp, `<span class="${classHightLight}">$&</span>`);
96
+ });
97
+ }
98
+ catch (error) {
99
+ console.log(error);
100
+ }
101
+ finally {
102
+ // eslint-disable-next-line no-unsafe-finally
103
+ return value;
104
+ }
105
+ };
106
+ const getValueReplace = (search, value) => {
107
+ const searchConvert = deleteUnicode(search).toLowerCase();
108
+ const valueConvert = deleteUnicode(value).toLowerCase();
109
+ const keys = new Set();
110
+ let i = 0;
111
+ while ((i = valueConvert.indexOf(searchConvert, i)) >= 0) {
112
+ const endIndex = i + search.length;
113
+ keys.add(value.substring(i, endIndex));
114
+ i += +valueConvert.length;
115
+ }
116
+ return Array.from(keys);
117
+ };
118
+ const formatTextCompare = (text, options) => {
119
+ if (!text) {
120
+ return text;
121
+ }
122
+ text = text.normalize("NFC");
123
+ return formatByOptions(text, options);
124
+ };
125
+ const fullNameFormat = (value) => {
126
+ if (!value) {
127
+ return value;
128
+ }
129
+ return capitalize(value, { lowercaseOtherCharacter: true, trim: true, removeMultipleSpace: true, removeEmoji: true });
130
+ };
131
+ const capitalize = (text, options) => {
132
+ if (!text) {
133
+ return text;
134
+ }
135
+ text = formatByOptions(text, options);
136
+ return text.split(' ').map(word => firstLetterToUpperCase(word)).join(' ');
137
+ };
138
+ const firstLetterToUpperCase = (text, options) => {
139
+ if (!text) {
140
+ return text;
141
+ }
142
+ return uppercaseByPosition(text, 0, options);
143
+ };
144
+ const uppercaseByPosition = (text, position, options) => {
145
+ if (!text) {
146
+ return text;
147
+ }
148
+ text = formatByOptions(text, options);
149
+ return `${text.substring(0, position)}${text.charAt(position).toUpperCase()}${text.substring(position + 1)}`;
150
+ };
151
+ const formatByOptions = (text, options) => {
152
+ if (!text || !options) {
153
+ return text;
154
+ }
155
+ if (options?.uppercaseOtherCharacter) {
156
+ text = text.toUpperCase();
13
157
  }
14
- if (match[1] === 'Chrome') {
15
- tem = userAgent.match(/\b(OPR|Edge)\/(\d+)/);
16
- if (tem !== null) {
17
- return tem.slice(1).join(' ').replace('OPR', 'Opera');
158
+ if (options?.lowercaseOtherCharacter) {
159
+ text = text.toLowerCase();
160
+ }
161
+ if (options?.removeMultipleSpace) {
162
+ text = text.replace(/\u200B|\u00A0/g, "");
163
+ text = text.replace(/\s+/g, ' ');
164
+ }
165
+ if (options?.removeEmoji) {
166
+ text = removeEmoji(text);
167
+ }
168
+ if (options?.removeUnicode) {
169
+ text = deleteUnicode(text);
170
+ }
171
+ if (options?.trim) {
172
+ text = text.trim();
173
+ }
174
+ return text;
175
+ };
176
+ const escapeHtml = (str) => {
177
+ if (!str || typeof str !== 'string') {
178
+ return str;
179
+ }
180
+ return str
181
+ .replace(/&/g, "&amp;")
182
+ .replace(/</g, "&lt;")
183
+ .replace(/>/g, "&gt;")
184
+ .replace(/"/g, "&quot;")
185
+ .replace(/'/g, "&#039;");
186
+ };
187
+ const decodeEscapeHtml = (str) => {
188
+ const htmlTag = document.createElement('textarea');
189
+ htmlTag.innerHTML = str;
190
+ while (str) {
191
+ if (str === htmlTag.value) {
192
+ str = htmlTag.value;
193
+ htmlTag.remove();
194
+ break;
18
195
  }
196
+ str = htmlTag.value;
197
+ htmlTag.innerHTML = str;
198
+ }
199
+ return str;
200
+ };
201
+ const deleteUnicode = (str) => {
202
+ str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, 'a');
203
+ str = str.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ|ễ/g, 'e');
204
+ str = str.replace(/ì|í|ị|ỉ|ĩ/g, 'i');
205
+ str = str.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, 'o');
206
+ str = str.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, 'u');
207
+ str = str.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, 'y');
208
+ str = str.replace(/đ/g, 'd');
209
+ str = str.replace(/À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ/g, 'A');
210
+ str = str.replace(/È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ/g, 'E');
211
+ str = str.replace(/Ì|Í|Ị|Ỉ|Ĩ/g, 'I');
212
+ str = str.replace(/Ò|Ó|Ọ|Ỏ|Õ|Ô|Ồ|Ố|Ộ|Ổ|Ỗ|Ơ|Ờ|Ớ|Ợ|Ở|Ỡ/g, 'O');
213
+ str = str.replace(/Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ/g, 'U');
214
+ str = str.replace(/Ỳ|Ý|Ỵ|Ỷ|Ỹ/g, 'Y');
215
+ str = str.replace(/Đ/g, 'D');
216
+ str = str.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, ""); // ̀ ́ ̃ ̉ ̣ huyền, sắc, ngã, hỏi, nặng
217
+ str = str.replace(/\u02C6|\u0306|\u031B/g, ""); // ˆ ̆ ̛ Â, Ê, Ă, Ơ, Ư
218
+ return str.normalize("NFC");
219
+ };
220
+ const removeEmoji = (text) => {
221
+ if (!text || !text.trim()) {
222
+ return text;
19
223
  }
20
- match = match[2] ? [match[1], match[2]] : [navigator.appName, navigator.appVersion, '-?'];
21
- if ((tem = userAgent.match(/version\/(\d+)/i)) !== null) {
22
- match.splice(1, 1, tem[1]);
224
+ return text.replace(patternEmoji(), '');
225
+ };
226
+
227
+ const deviceDetector = new DeviceDetector();
228
+ const parser = new DOMParser();
229
+ const quill = new Quill(document.createElement('div'));
230
+ const getDeviceInfo = () => {
231
+ return deviceDetector.parse(window.navigator.userAgent);
232
+ };
233
+ const getPlatFromBrowser = () => {
234
+ const info = getDeviceInfo();
235
+ return `${info.client?.name} ${info.client?.version}`;
236
+ };
237
+ const getEventNameHandleClick = (() => {
238
+ const deviceInfo = getDeviceInfo();
239
+ let nameEventHandleClick = deviceInfo.device?.type === 'desktop' ? 'click' : 'touchstart';
240
+ if ('onpointerdown' in window) {
241
+ nameEventHandleClick = 'pointerdown';
23
242
  }
24
- return match.join(' ');
243
+ return nameEventHandleClick;
244
+ })();
245
+ const getDocumentByString = (htmlStr) => {
246
+ return parser.parseFromString(htmlStr, 'text/html');
25
247
  };
26
248
  const cloneIBoundingClientRect = (rect) => {
27
249
  return {
@@ -29,10 +251,10 @@ const cloneIBoundingClientRect = (rect) => {
29
251
  left: rect['left'],
30
252
  width: rect['width'],
31
253
  height: rect['height'],
32
- bottom: rect['bottom']
254
+ bottom: rect['bottom'],
33
255
  };
34
256
  };
35
- const setStyles = (el, styles, render2) => {
257
+ const setStylesElement = (el, styles, render2) => {
36
258
  Object.keys(styles).forEach((key) => render2.setStyle(el, key, styles[key]));
37
259
  };
38
260
  const getViewport = (win = window) => {
@@ -68,7 +290,10 @@ const checkViewInScreen = (container, element, elementScroll, maxTopLeft) => {
68
290
  const limitLeft = leftContainer + scrollLeftContainer + widthContainer;
69
291
  const maxTopItem = top + (maxTopLeft?.top || 0);
70
292
  const maxLeftItem = left + (maxTopLeft?.left || 0);
71
- if (topContainer <= maxTopItem && maxTopItem <= limitTop && leftContainer <= maxLeftItem && maxLeftItem <= limitLeft) {
293
+ if (topContainer <= maxTopItem &&
294
+ maxTopItem <= limitTop &&
295
+ leftContainer <= maxLeftItem &&
296
+ maxLeftItem <= limitLeft) {
72
297
  return true;
73
298
  }
74
299
  return false;
@@ -82,11 +307,181 @@ const checkMouseOverInContainer = (mousePosition, element, rect) => {
82
307
  const limitLeft = left + width;
83
308
  const limitTop = top + height;
84
309
  const { clientX, clientY } = mousePosition;
85
- if (left <= clientX && clientX <= limitLeft && top <= clientY && clientY <= limitTop) {
310
+ if (left <= clientX &&
311
+ clientX <= limitLeft &&
312
+ top <= clientY &&
313
+ clientY <= limitTop) {
86
314
  return true;
87
315
  }
88
316
  return false;
89
317
  };
318
+ const getDragEventByElement = (config) => {
319
+ let timer;
320
+ const addClass = () => {
321
+ timer = setTimeout(() => {
322
+ document.body.classList.add('!select-none');
323
+ document.body.classList.add('!cursor-grabbing');
324
+ }, 250);
325
+ };
326
+ const removeClass = () => {
327
+ document.body.classList.remove('!select-none');
328
+ document.body.classList.remove('!cursor-grabbing');
329
+ clearTimeout(timer);
330
+ };
331
+ fromEvent(config.elementMouseDown, 'mouseleave')
332
+ .pipe(tap(() => document.body.classList.remove('cursor-pointer')), takeUntil(config.onDestroy))
333
+ .subscribe();
334
+ fromEvent(config.elementMouseDown, 'mouseenter')
335
+ .pipe(tap(() => document.body.classList.add('cursor-pointer')), takeUntil(config.onDestroy))
336
+ .subscribe();
337
+ const mouseDown = fromEvent(config.elementMouseDown, 'mousedown').pipe(tap((e) => {
338
+ e.stopPropagation();
339
+ addClass();
340
+ config.functionMouseDown?.(e);
341
+ }));
342
+ const mouseup = fromEvent(config.elementMouseUp || document, 'mouseup').pipe(tap((e) => {
343
+ e.stopPropagation();
344
+ removeClass();
345
+ config.functionMouseUp?.(e);
346
+ }));
347
+ const mousemove = fromEvent(config.elementMouseMove || document, 'mousemove').pipe(tap((e) => {
348
+ e.stopPropagation();
349
+ config.functionMouseMove?.(e);
350
+ }), takeUntil(mouseup));
351
+ return mouseDown.pipe(mergeMap((e) => config.isStartWithMouseDownEvent
352
+ ? mousemove.pipe(startWith(e))
353
+ : mousemove), takeUntil(config.onDestroy), finalize(removeClass));
354
+ };
355
+ const getHTMLFromQuill = async (data, options) => {
356
+ const { replaceNewLineTo = '<br>', replaceTagBRTo, replaceTags, replaceBrToDiv } = options || {};
357
+ const delta = (typeof data === 'string') ? await getDeltaFromHTML(data) : data;
358
+ if (options?.functionReplaceDelta) {
359
+ options.functionReplaceDelta(delta);
360
+ }
361
+ delta.ops.forEach((op) => {
362
+ if (op.insert) {
363
+ if (typeof op.insert === 'string') {
364
+ if (replaceNewLineTo) {
365
+ op.insert = op.insert.replace(/\n/g, replaceNewLineTo);
366
+ }
367
+ if (replaceTagBRTo) {
368
+ op.insert = op.insert.replace(/<br>/g, replaceTagBRTo);
369
+ }
370
+ if (replaceTags?.length) {
371
+ for (const tag of replaceTags) {
372
+ op.insert = op.insert.replace(new RegExp(`<${tag.tag}>`, 'g'), `<${tag.replaceTo}>`);
373
+ op.insert = op.insert.replace(new RegExp(`</${tag.tag}>`, 'g'), `</${tag.replaceTo}>`);
374
+ }
375
+ }
376
+ }
377
+ }
378
+ });
379
+ quill.setContents(delta);
380
+ let htmlText = options?.getRootHtml ? quill.root.innerHTML : quill.root.firstElementChild?.innerHTML;
381
+ if (replaceBrToDiv) {
382
+ htmlText = convertHtmlToDivBlocks(htmlText || '');
383
+ }
384
+ return decodeEscapeHtml(htmlText || '');
385
+ };
386
+ const convertHtmlToDivBlocks = (html) => {
387
+ const BREAK_TOKEN = '<<<BREAK>>>';
388
+ // Bước 1: thay <br> thành token tạm
389
+ const normalizedHtml = html.replace(/<br\s*\/?>/gi, BREAK_TOKEN);
390
+ // Bước 2: tách theo token
391
+ const parts = normalizedHtml.split(BREAK_TOKEN);
392
+ const parser = new DOMParser();
393
+ const divs = [];
394
+ for (const raw of parts) {
395
+ const trimmed = raw.trim();
396
+ if (!trimmed)
397
+ continue;
398
+ // parse mỗi phần nhỏ như một document riêng
399
+ const doc = parser.parseFromString(trimmed, 'text/html');
400
+ const body = doc.body;
401
+ // Lấy lại nội dung bên trong body
402
+ divs.push(`<div>${body.innerHTML}</div>`);
403
+ }
404
+ return divs.join('');
405
+ };
406
+ const getDeltaFromHTML = async (html) => {
407
+ quill.root.innerHTML = html;
408
+ setTimeout(() => {
409
+ console.log(quill.getContents());
410
+ }, 1000);
411
+ await lastValueFrom(timer(1000));
412
+ return quill.getContents();
413
+ };
414
+ const processPasteData = async (e, config) => {
415
+ const element = config.element;
416
+ const files = e.clipboardData?.files;
417
+ if (files?.length) {
418
+ e.preventDefault();
419
+ config.handlerPasteFile?.(files);
420
+ config.callBack?.('file');
421
+ return;
422
+ }
423
+ // Lưu selection TRƯỚC khi prevent default
424
+ const selection = window.getSelection();
425
+ let savedRange = null;
426
+ if (selection && selection.rangeCount > 0) {
427
+ const range = selection.getRangeAt(0);
428
+ // Chỉ lưu nếu range nằm trong contentText element
429
+ const container = range.commonAncestorContainer;
430
+ const isInContentElement = element.contains(container.nodeType === Node.TEXT_NODE ? container.parentNode : container);
431
+ if (isInContentElement) {
432
+ savedRange = range.cloneRange();
433
+ }
434
+ }
435
+ // Prevent default để tự xử lý paste
436
+ e.preventDefault();
437
+ // Sử dụng Quill để clean HTML content
438
+ const htmlContent = e.clipboardData?.getData('text/html') || '';
439
+ const plainText = e.clipboardData?.getData('text/plain') || '';
440
+ let contentToInsert = (plainText || '').replace(/\n/g, '<br>');
441
+ if (htmlContent) {
442
+ contentToInsert = await getHTMLFromQuill(htmlContent);
443
+ }
444
+ if (!contentToInsert) {
445
+ config.callBack?.('no-content');
446
+ return;
447
+ }
448
+ if (savedRange) {
449
+ insertContentWithRange(contentToInsert, savedRange, element);
450
+ config.callBack?.('range');
451
+ return;
452
+ }
453
+ element.innerHTML += contentToInsert;
454
+ config.callBack?.('content');
455
+ };
456
+ const insertContentWithRange = (content, savedRange, element) => {
457
+ const selection = window.getSelection();
458
+ if (!selection) {
459
+ // Fallback: append vào cuối
460
+ element.innerHTML += content;
461
+ return;
462
+ }
463
+ // Restore selection
464
+ selection.removeAllRanges();
465
+ selection.addRange(savedRange);
466
+ // Xóa nội dung đã select (nếu có)
467
+ savedRange.deleteContents();
468
+ // Tạo document fragment từ HTML content
469
+ const tempDiv = document.createElement('div');
470
+ tempDiv.innerHTML = content;
471
+ const fragment = document.createDocumentFragment();
472
+ while (tempDiv.firstChild) {
473
+ fragment.appendChild(tempDiv.firstChild);
474
+ }
475
+ // Insert fragment tại vị trí range
476
+ savedRange.insertNode(fragment);
477
+ // Di chuyển cursor đến cuối nội dung vừa insert
478
+ if (fragment.lastChild) {
479
+ savedRange.setStartAfter(fragment.lastChild);
480
+ }
481
+ savedRange.collapse(true);
482
+ selection.removeAllRanges();
483
+ selection.addRange(savedRange);
484
+ };
90
485
 
91
486
  class UtilsUrlSearchParams {
92
487
  static instance;
@@ -185,6 +580,46 @@ class UtilsUrlSearchParams {
185
580
  }
186
581
  }
187
582
 
583
+ let key$1 = '12~@#loqwsxacva(3rdhaq12';
584
+ /**
585
+ * @description Thiết lập key mã hóa
586
+ * @param value key mã hóa, độ dài bằng 24 hoặc 32 ký tự.
587
+ */
588
+ const setKeyCrypto = (value) => {
589
+ if (value.length !== 24 && value.length !== 32) {
590
+ throw Error(`key.length = ${value.length}; Key phải là 1 chuỗi dài 24 hoặc 32 ký tự`);
591
+ }
592
+ key$1 = value;
593
+ };
594
+ const keyStore$1 = () => {
595
+ return key$1;
596
+ };
597
+ const encrypt = (plainData) => {
598
+ if (!keyStore$1()) {
599
+ throw Error("lỗi chưa setup key mã hóa");
600
+ }
601
+ const key = CryptoES.enc.Hex.parse(keyStore$1());
602
+ const iv = CryptoES.enc.Hex.parse(keyStore$1());
603
+ const mode = CryptoES.mode.CBC;
604
+ const padding = CryptoES.pad.Pkcs7;
605
+ const options = { iv: iv, mode: mode, padding: padding };
606
+ return CryptoES.AES.encrypt(plainData, key, options).toString();
607
+ };
608
+ const decrypt = (encryptedData) => {
609
+ if (!keyStore$1()) {
610
+ throw Error("lỗi chưa setup key mã hóa");
611
+ }
612
+ const key = CryptoES.enc.Hex.parse(keyStore$1());
613
+ const iv = CryptoES.enc.Hex.parse(keyStore$1());
614
+ const mode = CryptoES.mode.CBC;
615
+ const padding = CryptoES.pad.Pkcs7;
616
+ const options = { iv: iv, mode: mode, padding: padding };
617
+ return CryptoES.AES.decrypt(encryptedData, key, options).toString(CryptoES.enc.Utf8);
618
+ };
619
+ const md5 = (plainData) => {
620
+ return CryptoES.MD5(plainData).toString();
621
+ };
622
+
188
623
  const uuid = () => {
189
624
  const timestamp = performance.now() * 1000;
190
625
  const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+-=[]{}|;:,.<>?/~';
@@ -199,382 +634,93 @@ const uuid = () => {
199
634
  [charArray[i], charArray[j]] = [charArray[j], charArray[i]];
200
635
  }
201
636
  const shuffledString = charArray.join('');
202
- return shuffledString;
637
+ return md5(shuffledString);
203
638
  };
204
639
 
205
640
  /* eslint-disable @typescript-eslint/no-explicit-any */
206
- const isNil = (value) => {
207
- return value === null || value === undefined;
208
- };
209
- const isEmpty = (value) => {
210
- return value === null || value === '' || value === undefined || (typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]'));
641
+ const UtilsHttpParamsRequestInstance = (options, instance) => {
642
+ return new UtilsHttpParamsRequest(options, instance);
211
643
  };
212
- const get = (obj, path, defaultValue = undefined) => {
213
- if (obj == null) {
214
- return defaultValue;
215
- }
216
- const paths = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.$1').split('.');
217
- for (let i = 0; i < paths.length; i++) {
218
- if (obj == null || !Object.prototype.hasOwnProperty.call(obj, paths[i])) {
219
- return defaultValue;
644
+ class UtilsHttpParamsRequest extends HttpParams {
645
+ params = new HttpParams();
646
+ constructor(options, instance) {
647
+ super(options);
648
+ if (!instance) {
649
+ this.params = new HttpParams(options);
650
+ return;
651
+ }
652
+ if (instance instanceof UtilsHttpParamsRequest) {
653
+ this.params = instance.getInstance();
654
+ return;
655
+ }
656
+ if (instance instanceof HttpParams) {
657
+ this.params = instance;
658
+ return;
220
659
  }
221
- obj = obj[paths[i]];
222
660
  }
223
- return obj;
224
- };
225
- const set = (obj, path, value) => {
226
- if (!obj || typeof obj !== "object") {
227
- throw new Error("The first argument must be an object");
661
+ getInstance() {
662
+ return this.params;
228
663
  }
229
- const pathArray = Array.isArray(path) ? path : path.replace(/\[(\d+)]/g, '.[$1]').split('.');
230
- let current = obj;
231
- pathArray.forEach((key, index) => {
232
- if (index < pathArray.length - 1) {
233
- if (!(key in current) || typeof current[key] !== "object") {
234
- const nextKey = pathArray[index + 1];
235
- key = key.replace(/\[(\d+)]/g, '$1');
236
- current[key] = /\[(\d+)]/g.test(nextKey) ? [] : {};
237
- }
238
- current = current[key];
664
+ setInstance(instance) {
665
+ if (instance instanceof UtilsHttpParamsRequest) {
666
+ this.params = instance.getInstance();
667
+ return;
668
+ }
669
+ if (instance instanceof HttpParams) {
670
+ this.params = instance;
239
671
  return;
240
672
  }
241
- // Gán giá trị ở cuối đường dẫn
242
- current[key] = value;
243
- });
244
- return obj;
245
- };
246
- const cloneDeep = (value) => {
247
- if (value === null || typeof value !== 'object') {
248
- return value;
249
673
  }
250
- if (value instanceof Date) {
251
- return new Date(value.getTime());
674
+ set(param, value) {
675
+ this.params = this.params.set(param, value);
676
+ return this;
252
677
  }
253
- if (value instanceof RegExp) {
254
- return new RegExp(value.source, value.flags);
678
+ has(param) {
679
+ return this.params.has(param);
255
680
  }
256
- if (value instanceof Map) {
257
- const mapCopy = new Map();
258
- value.forEach((val, key) => {
259
- mapCopy.set(cloneDeep(key), cloneDeep(val));
260
- });
261
- return mapCopy;
681
+ get(param) {
682
+ return this.params.get(param);
262
683
  }
263
- if (value instanceof Set) {
264
- const setCopy = new Set();
265
- value.forEach(val => {
266
- setCopy.add(cloneDeep(val));
267
- });
268
- return setCopy;
684
+ getAll(param) {
685
+ return this.params.getAll(param);
269
686
  }
270
- if (Array.isArray(value)) {
271
- return value.map(item => cloneDeep(item));
687
+ keys() {
688
+ return this.params.keys();
272
689
  }
273
- const result = {};
274
- for (const key in value) {
275
- if (value[key] instanceof TemplateRef || value[key] instanceof ElementRef || value[key] instanceof Element) {
276
- result[key] = value[key];
277
- continue;
278
- }
279
- if (Object.prototype.hasOwnProperty.call(value, key)) {
280
- result[key] = cloneDeep(value[key]);
281
- }
690
+ append(param, value) {
691
+ this.params = this.params.append(param, value);
692
+ return this;
282
693
  }
283
- return result;
284
- };
285
- const convertObjectToSignal = (data) => {
286
- if (data === null || typeof data !== 'object') {
287
- return data;
694
+ appendAll(params) {
695
+ this.params = this.params.appendAll(params);
696
+ return this;
288
697
  }
289
- if (Array.isArray(data)) {
290
- if (typeof data[0] !== 'object') {
291
- return signal(data);
292
- }
293
- return signal(data.map(item => convertObjectToSignal(cloneDeep(item))));
698
+ delete(param, value) {
699
+ this.params = this.params.delete(param, value);
700
+ return this;
294
701
  }
295
- data = signal(data);
296
- for (const key in data()) {
297
- const value = data()[key];
298
- if (value instanceof TemplateRef || value instanceof ElementRef || value instanceof Element || value instanceof Date || value instanceof RegExp || value instanceof Set || value instanceof Map) {
299
- continue;
300
- }
301
- if (Object.prototype.hasOwnProperty.call(data(), key)) {
302
- data()[key] = convertObjectToSignal(cloneDeep(value));
303
- }
304
- }
305
- return data;
306
- };
307
- const isSignal = (data) => {
308
- return typeof data === 'function' && data.toString().includes('Signal:');
309
- };
310
- const convertSignalToObject = (data) => {
311
- if (data === null || !isSignal(data)) {
312
- return data;
313
- }
314
- data = data();
315
- if (Array.isArray(data)) {
316
- if (!isSignal(data[0])) {
317
- return data;
318
- }
319
- return data.map(item => convertSignalToObject(cloneDeep(item)));
320
- }
321
- for (const key in data) {
322
- const value = data[key];
323
- if (!isSignal(value)) {
324
- continue;
325
- }
326
- if (Object.prototype.hasOwnProperty.call(data, key)) {
327
- data[key] = convertSignalToObject(cloneDeep(value));
328
- }
329
- }
330
- return data;
331
- };
332
- const keyBy = (data, key) => {
333
- if (!data || !data.length || !key) {
334
- return {};
335
- }
336
- return data.reduce((dir, nextItem) => {
337
- const valueOfKey = nextItem[key];
338
- if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number') {
339
- return dir;
340
- }
341
- dir[valueOfKey] = nextItem;
342
- return dir;
343
- }, {});
344
- };
345
- const groupBy = (data, key) => {
346
- if (!data || !Object.keys(data).length || !key) {
347
- return {};
348
- }
349
- return data.reduce((dir, nextItem) => {
350
- const valueOfKey = nextItem[key];
351
- if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number') {
352
- return dir;
353
- }
354
- if (!dir[valueOfKey]) {
355
- dir[valueOfKey] = [];
356
- }
357
- dir[valueOfKey].push(nextItem);
358
- return dir;
359
- }, {});
360
- };
361
- const range = (start, end, step) => {
362
- if (end === undefined || end === null) {
363
- end = start;
364
- start = 0;
365
- }
366
- if (!step) {
367
- step = end < 0 ? -1 : 1;
368
- }
369
- const valueStartByStep = step + start;
370
- const direction = start < end ? 'asc' : 'desc';
371
- if ((direction === 'asc' && (valueStartByStep < start || valueStartByStep > end)) || (direction === 'desc' && (valueStartByStep > start || valueStartByStep < end))) {
372
- return [start];
373
- }
374
- const arr = new Array();
375
- for (let index = 0; index < Math.abs(end - start); index++) {
376
- let value = start + index * step;
377
- if (index === 0) {
378
- value = start;
379
- }
380
- if ((direction === 'asc' && (value < start || value > end)) || (direction === 'desc' && (value > start || value < end))) {
381
- return arr;
382
- }
383
- arr.push(value);
384
- }
385
- return arr;
386
- };
387
- const isEqual = (value1, value2) => {
388
- if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
389
- return true;
390
- }
391
- if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2))) {
392
- return false;
393
- }
394
- if (Array.isArray(value1)) {
395
- if (value1.length !== value2.length) {
396
- return false;
397
- }
398
- return !value1.some((item, index) => !isEqual(item, value2[index]));
399
- }
400
- if (Object.keys(value1).length !== Object.keys(value2).length) {
401
- return false;
402
- }
403
- return !Object.keys(value1).some((key) => !isEqual(value1[key], value2[key]));
404
- };
405
- const uniqBy = (data, key) => {
406
- if (!key || !data || !data.length || typeof data[0] !== 'object') {
407
- console.log('vao dauy r', !key, !data, !data.length, typeof data[0] !== 'object');
408
- return Array.from(new Set(data));
409
- }
410
- const dataUnique = keyBy(data, key);
411
- return Object.keys(dataUnique).map(key => dataUnique[key]);
412
- };
413
- const generateInterface = (obj, interfaceName) => {
414
- const generateType = (value) => {
415
- if (value === null) {
416
- return 'null';
417
- }
418
- const type = typeof value;
419
- if (type === 'string') {
420
- return 'string';
421
- }
422
- if (type === 'number') {
423
- return 'number';
424
- }
425
- if (type === 'boolean') {
426
- return 'boolean';
427
- }
428
- if (type === 'undefined') {
429
- return 'any';
430
- }
431
- if (value instanceof Date) {
432
- return 'Date';
433
- }
434
- if (value instanceof RegExp) {
435
- return 'RegExp';
436
- }
437
- if (Array.isArray(value)) {
438
- if (value.length === 0) {
439
- return 'Array<any>';
440
- }
441
- return `Array<${generateType(value[0])}>`;
442
- }
443
- if (type === 'object') {
444
- let interfaceStr = '{\n';
445
- for (const key in value) {
446
- if (Object.prototype.hasOwnProperty.call(value, key)) {
447
- const valueType = generateType(value[key]);
448
- interfaceStr += ` ${key}: ${valueType};\n`;
449
- }
450
- }
451
- interfaceStr += '}';
452
- return interfaceStr;
453
- }
454
- return 'any';
455
- };
456
- const interfaceStr = `interface ${interfaceName} ${generateType(obj)}`;
457
- return interfaceStr;
458
- };
459
-
460
- ;
461
- const step = 20;
462
- const percent = 0.05;
463
- const colorStepContrastFromOrigin = (color, stepNumber) => {
464
- return colorContrastFromOrigin(color).find(item => item.step === stepNumber);
465
- };
466
- const colorContrastFromOrigin = (color) => {
467
- const parsedColorsArray = parseColorValues(color);
468
- const colors = [];
469
- let calculatedShades = [];
470
- let calculatedTints = [];
471
- if (parsedColorsArray !== null) {
472
- for (let i = 0; i < parsedColorsArray.length; i++) {
473
- calculatedShades = calculateShades(parsedColorsArray[i]);
474
- calculatedTints = calculateTints(parsedColorsArray[i]);
475
- }
476
- for (let i = 0; i <= step; i++) {
477
- colors.push({ step: i * 5, label: `${i * 5}%`, dark: `#${calculatedShades[i]}`, light: `#${calculatedTints[i]}` });
478
- }
479
- }
480
- return colors;
481
- };
482
- const parseColorValues = (colorValues) => {
483
- let colorValuesArray = colorValues.match(/\b[0-9A-Fa-f]{3}\b|[0-9A-Fa-f]{6}\b/g);
484
- if (colorValuesArray) {
485
- colorValuesArray = colorValuesArray.map((item) => {
486
- if (item.length === 3) {
487
- let newItem = item.toString().split('');
488
- newItem = newItem.reduce((acc, it) => {
489
- return acc + it + it;
490
- }, '');
491
- return newItem;
492
- }
493
- return item;
494
- });
495
- }
496
- return colorValuesArray;
497
- };
498
- const calculateShades = (colorValue) => {
499
- return calculate(colorValue, rgbShade).concat("000000");
500
- };
501
- const calculateTints = (colorValue) => {
502
- return calculate(colorValue, rgbTint).concat("ffffff");
503
- };
504
- const calculate = (colorValue, shadeOrTint) => {
505
- const color = hexToRGB(colorValue);
506
- const shadeValues = [];
507
- for (let i = 0; i < step; i++) {
508
- shadeValues[i] = rgbToHex(shadeOrTint(color, i));
509
- }
510
- return shadeValues;
511
- };
512
- const rgbShade = (rgb, i) => { return { red: rgb.red * (1 - percent * i), green: rgb.green * (1 - percent * i), blue: rgb.blue * (1 - percent * i) }; };
513
- const rgbTint = (rgb, i) => { return { red: rgb.red + (255 - rgb.red) * i * percent, green: rgb.green + (255 - rgb.green) * i * percent, blue: rgb.blue + (255 - rgb.blue) * i * percent }; };
514
- const rgbToHex = (rgb) => { return intToHex(rgb.red) + intToHex(rgb.green) + intToHex(rgb.blue); };
515
- const hexToRGB = (colorValue) => { return { red: parseInt(colorValue.substr(0, 2), 16), green: parseInt(colorValue.substr(2, 2), 16), blue: parseInt(colorValue.substr(4, 2), 16) }; };
516
- const intToHex = (rgbint) => { return pad(Math.min(Math.max(Math.round(rgbint), 0), 255).toString(16), 2); };
517
- const pad = (number, length) => {
518
- let str = '' + number;
519
- while (str.length < length) {
520
- str = '0' + str;
521
- }
522
- return str;
523
- };
524
- const listColorDefine$1 = ['#E62222', '#B81B1B', '#EB4E4E', '#F97316', '#C75C12', '#FA8F45', '#FFB700', '#CC9200', '#FFC533', '#84CC16', '#6AA312', '#9dd645', '#00BC62', '#00A757', '#33DA8A', '#06B6D4', '#1B59C4', '#4E8CF7', '#0EA5E9',
525
- '#1B59C4', '#4E8CF7', '#226FF5', '#1B59C4', '#4E8CF7', '#6366F1', '#4F52C1', '#8285F4', '#5B04B3', '#49038F', '#7C36C2', '#D946EF', '#AE38BF', '#E16BF2', '#EC4899', '#BD3A7A', '#F06DAD', '#F43F5E', '#C3324B', '#F6657E', '#757380', '#5E5C66', '#918F99',
526
- '#202020', '#1A1A1A', '#4D4D4D'
527
- ];
528
- const GetColorById = (str) => {
529
- let hashString = 0;
530
- if (!str) {
531
- return '';
532
- }
533
- for (let i = 0; i < str.length; i++) {
534
- const char = str.charCodeAt(i);
535
- hashString = ((hashString << 5) - hashString) + char;
536
- hashString = hashString & hashString;
537
- }
538
- return listColorDefine$1[Math.abs(hashString) % listColorDefine$1.length];
539
- };
540
-
541
- let key$1 = '12~@#loqwsxacva(3rdhaq12';
542
- const setKeyCrypto = (value) => {
543
- if (value.length !== 24 && value.length !== 32) {
544
- throw Error(`key.length = ${value.length}; Key phải là 1 chuỗi dài 24 hoặc 32 ký tự`);
545
- }
546
- key$1 = value;
547
- };
548
- const keyStore$1 = () => {
549
- return key$1;
550
- };
551
- const encrypt = (plainData) => {
552
- if (!keyStore$1()) {
553
- throw Error("lỗi chưa setup key mã hóa");
554
- }
555
- const key = CryptoES.enc.Hex.parse(keyStore$1());
556
- const iv = CryptoES.enc.Hex.parse(keyStore$1());
557
- const mode = CryptoES.mode.CBC;
558
- const padding = CryptoES.pad.Pkcs7;
559
- const options = { iv: iv, mode: mode, padding: padding };
560
- return CryptoES.AES.encrypt(plainData, key, options).toString();
561
- };
562
- const decrypt = (encryptedData) => {
563
- if (!keyStore$1()) {
564
- throw Error("lỗi chưa setup key mã hóa");
702
+ toString() {
703
+ return this.params.toString();
565
704
  }
566
- const key = CryptoES.enc.Hex.parse(keyStore$1());
567
- const iv = CryptoES.enc.Hex.parse(keyStore$1());
568
- const mode = CryptoES.mode.CBC;
569
- const padding = CryptoES.pad.Pkcs7;
570
- const options = { iv: iv, mode: mode, padding: padding };
571
- return CryptoES.AES.decrypt(encryptedData, key, options).toString(CryptoES.enc.Utf8);
572
- };
573
- const md5 = (plainData) => {
574
- return CryptoES.MD5(plainData).toString();
575
- };
705
+ }
706
+ // Demo su dung GET_PATH_VARIABLE
707
+ // interface Person {
708
+ // name: string;
709
+ // age: number;
710
+ // location: string;
711
+ // }
712
+ // type c = GET_PATH_VARIABLE<Person, unknown>;
713
+ // const a: c = {
714
+ // "pathVariable-age": 1,
715
+ // "pathVariable-location": '12',
716
+ // "pathVariable-name": '124',
717
+ // };
576
718
 
577
719
  let key = '12~@#loqwsxacva(3rdhaq12';
720
+ /**
721
+ * @description Thiết lập key mã hóa
722
+ * @param value key mã hóa, độ dài bằng 24 hoặc 32 ký tự.
723
+ */
578
724
  const setKeyCrypto3rd = (value) => {
579
725
  if (value.length !== 24 && value.length !== 32) {
580
726
  throw Error(`key.length = ${value.length}; Key phải là 1 chuỗi dài 24 hoặc 32 ký tự`);
@@ -607,219 +753,6 @@ const decrypt3rd = (encryptedData) => {
607
753
  return CryptoES.AES.decrypt(encryptedData, key, options).toString(CryptoES.enc.Utf8);
608
754
  };
609
755
 
610
- class UtilsKeyCodeConstant {
611
- static MAC_ENTER = 3;
612
- static BACKSPACE = 8;
613
- static TAB = 9;
614
- static NUM_CENTER = 12;
615
- static ENTER = 13;
616
- static SHIFT = 16;
617
- static CONTROL = 17;
618
- static ALT = 18;
619
- static PAUSE = 19;
620
- static CAPS_LOCK = 20;
621
- static ESCAPE = 27;
622
- static SPACE = 32;
623
- static PAGE_UP = 33;
624
- static PAGE_DOWN = 34;
625
- static END = 35;
626
- static HOME = 36;
627
- static LEFT_ARROW = 37;
628
- static UP_ARROW = 38;
629
- static RIGHT_ARROW = 39;
630
- static DOWN_ARROW = 40;
631
- static PLUS_SIGN = 43;
632
- static PRINT_SCREEN = 44;
633
- static INSERT = 45;
634
- static DELETE = 46;
635
- static ZERO = 48;
636
- static ONE = 49;
637
- static TWO = 50;
638
- static THREE = 51;
639
- static FOUR = 52;
640
- static FIVE = 53;
641
- static SIX = 54;
642
- static SEVEN = 55;
643
- static EIGHT = 56;
644
- static NINE = 57;
645
- static FF_SEMICOLON = 59; // Firefox (Gecko) fires this for semicolon instead of 186
646
- static FF_EQUALS = 61; // Firefox (Gecko) fires this for equals instead of 187
647
- static QUESTION_MARK = 63;
648
- static AT_SIGN = 64;
649
- static A = 65;
650
- static B = 66;
651
- static C = 67;
652
- static D = 68;
653
- static E = 69;
654
- static F = 70;
655
- static G = 71;
656
- static H = 72;
657
- static I = 73;
658
- static J = 74;
659
- static K = 75;
660
- static L = 76;
661
- static M = 77;
662
- static N = 78;
663
- static O = 79;
664
- static P = 80;
665
- static Q = 81;
666
- static R = 82;
667
- static S = 83;
668
- static T = 84;
669
- static U = 85;
670
- static V = 86;
671
- static W = 87;
672
- static X = 88;
673
- static Y = 89;
674
- static Z = 90;
675
- static META = 91; // WIN_KEY_LEFT
676
- static MAC_WK_CMD_LEFT = 91;
677
- static MAC_WK_CMD_RIGHT = 93;
678
- static CONTEXT_MENU = 93;
679
- static NUMPAD_ZERO = 96;
680
- static NUMPAD_ONE = 97;
681
- static NUMPAD_TWO = 98;
682
- static NUMPAD_THREE = 99;
683
- static NUMPAD_FOUR = 100;
684
- static NUMPAD_FIVE = 101;
685
- static NUMPAD_SIX = 102;
686
- static NUMPAD_SEVEN = 103;
687
- static NUMPAD_EIGHT = 104;
688
- static NUMPAD_NINE = 105;
689
- static NUMPAD_MULTIPLY = 106;
690
- static NUMPAD_PLUS = 107;
691
- static NUMPAD_MINUS = 109;
692
- static NUMPAD_PERIOD = 110;
693
- static NUMPAD_DIVIDE = 111;
694
- static F1 = 112;
695
- static F2 = 113;
696
- static F3 = 114;
697
- static F4 = 115;
698
- static F5 = 116;
699
- static F6 = 117;
700
- static F7 = 118;
701
- static F8 = 119;
702
- static F9 = 120;
703
- static F10 = 121;
704
- static F11 = 122;
705
- static F12 = 123;
706
- static NUM_LOCK = 144;
707
- static SCROLL_LOCK = 145;
708
- static FIRST_MEDIA = 166;
709
- static FF_MINUS = 173;
710
- static MUTE = 173; // Firefox (Gecko) fires 181 for MUTE
711
- static VOLUME_DOWN = 174; // Firefox (Gecko) fires 182 for VOLUME_DOWN
712
- static VOLUME_UP = 175; // Firefox (Gecko) fires 183 for VOLUME_UP
713
- static FF_MUTE = 181;
714
- static FF_VOLUME_DOWN = 182;
715
- static LAST_MEDIA = 183;
716
- static FF_VOLUME_UP = 183;
717
- static SEMICOLON = 186; // Firefox (Gecko) fires 59 for SEMICOLON
718
- static EQUALS = 187; // Firefox (Gecko) fires 61 for EQUALS
719
- static COMMA = 188;
720
- static DASH = 189; // Firefox (Gecko) fires 173 for DASH/MINUS
721
- static PERIOD = 190;
722
- static SLASH = 191;
723
- static APOSTROPHE = 192;
724
- static TILDE = 192;
725
- static OPEN_SQUARE_BRACKET = 219;
726
- static BACKSLASH = 220;
727
- static CLOSE_SQUARE_BRACKET = 221;
728
- static SINGLE_QUOTE = 222;
729
- static MAC_META = 224;
730
- }
731
-
732
- /* eslint-disable @typescript-eslint/no-explicit-any */
733
- const HttpParamsRequestInstance = (options, instance) => {
734
- return new UtilsHttpParamsRequest(options, instance);
735
- };
736
- class UtilsHttpParamsRequest extends HttpParams {
737
- params;
738
- constructor(options, instance) {
739
- super(options);
740
- if (!instance) {
741
- this.params = new HttpParams(options);
742
- return;
743
- }
744
- if (instance instanceof UtilsHttpParamsRequest) {
745
- this.params = instance.getInstance();
746
- return;
747
- }
748
- if (instance instanceof HttpParams) {
749
- this.params = instance;
750
- return;
751
- }
752
- }
753
- getInstance() {
754
- return this.params;
755
- }
756
- setInstance(instance) {
757
- if (instance instanceof UtilsHttpParamsRequest) {
758
- this.params = instance.getInstance();
759
- return;
760
- }
761
- if (instance instanceof HttpParams) {
762
- this.params = instance;
763
- return;
764
- }
765
- }
766
- set(param, value) {
767
- this.params = this.params.set(param, value);
768
- return this;
769
- }
770
- has(param) {
771
- return this.params.has(param);
772
- }
773
- get(param) {
774
- return this.params.get(param);
775
- }
776
- getAll(param) {
777
- return this.params.getAll(param);
778
- }
779
- keys() {
780
- return this.params.keys();
781
- }
782
- append(param, value) {
783
- this.params = this.params.append(param, value);
784
- return this;
785
- }
786
- appendAll(params) {
787
- this.params = this.params.appendAll(params);
788
- return this;
789
- }
790
- delete(param, value) {
791
- this.params = this.params.delete(param, value);
792
- return this;
793
- }
794
- toString() {
795
- return this.params.toString();
796
- }
797
- }
798
-
799
- class UtilsLanguageConstants {
800
- static VI = 'vi';
801
- static EN = 'en';
802
- static defaultLang = UtilsLanguageConstants.VI;
803
- }
804
- ;
805
-
806
- const getKeyCacheByArrayObject = (keyCache, argumentsValue) => {
807
- if (!keyCache || !argumentsValue) {
808
- return '';
809
- }
810
- let keyBuild = `${JSON.stringify(argumentsValue.slice(1))}-key-cache-plus`;
811
- if (argumentsValue && argumentsValue[0] instanceof HttpParams) {
812
- const httpParams = argumentsValue[0];
813
- const keys = argumentsValue[0].keys().sort((str1, str2) => str1.localeCompare(str2));
814
- keys.forEach(key => {
815
- keyBuild = `${keyBuild}${JSON.stringify(httpParams.get(key))}`;
816
- });
817
- }
818
- const keyCachePlus = md5(keyBuild);
819
- const keyCacheMD5 = md5(keyCache);
820
- return `${keyCacheMD5}-${md5(`${keyCacheMD5}-${keyCachePlus}`)}`;
821
- };
822
-
823
756
  let functionCheck = () => {
824
757
  return window.parent !== window.top;
825
758
  };
@@ -830,22 +763,34 @@ const isEmbedFrame = () => {
830
763
  return functionCheck();
831
764
  };
832
765
 
766
+ const ERROR_MESSAGE_EMPTY_VALID = 'i18n_valid_empty_message';
767
+ const ERROR_MESSAGE_PATTEN_VALID = 'i18n_valid_pattern_message';
768
+ const ERROR_MESSAGE_MIN_VALID = 'i18n_message_error_input_min_value';
769
+ const ERROR_MESSAGE_MAX_VALID = 'i18n_message_error_input_max_value';
770
+ const ERROR_MESSAGE_MIN_LENGTH = 'i18n_message_error_input_min_length';
771
+ const ERROR_MESSAGE_MAX_LENGTH = 'i18n_message_error_input_max_length';
772
+ const CHARACTER_DATA_EMPTY = '__';
773
+ const DEFAULT_START_PAGE_0 = 'defaultStartPage0';
774
+ const COMMUNICATE_MICRO_PREFIX_TYPE = '3RD_INTEGRATE_MICRO_SITE_';
775
+ const COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE = 'MICRO_SITES_ALL_MESSAGE';
776
+
833
777
  /* eslint-disable @typescript-eslint/no-explicit-any */
778
+ class UtilsCommunicateMicroKeyGlobal {
779
+ static KEY_MESSAGE_MODAL = 'LIBS_UI_MODEL_EVENT';
780
+ }
834
781
  class UtilsCommunicateMicro {
835
- static KEY_GET_ALL_MESSAGE = 'MICRO_SITES_ALL_MESSAGE';
836
- static PREFIX_TYPE = '3RD_INTEGRATE_MICRO_SITE_';
837
782
  static initdEvent;
838
783
  static subs = new Map();
839
784
  static allMessageSub = new Subject();
840
- static initEvent(currentWindow) {
785
+ static initEvent(currentWindow, onDestroy) {
841
786
  if (this.initdEvent) {
842
787
  return;
843
788
  }
844
789
  this.initdEvent = true;
845
- if (!this.subs.get(UtilsCommunicateMicro.KEY_GET_ALL_MESSAGE)) {
846
- this.subs.set(UtilsCommunicateMicro.KEY_GET_ALL_MESSAGE, UtilsCommunicateMicro.allMessageSub);
790
+ if (!this.subs.get(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE)) {
791
+ this.subs.set(COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, UtilsCommunicateMicro.allMessageSub);
847
792
  }
848
- fromEvent(currentWindow, 'message').subscribe(e => {
793
+ fromEvent(currentWindow, 'message').pipe(takeUntil(onDestroy)).subscribe(e => {
849
794
  const event = { data: { ...e.data } };
850
795
  const data = event.data;
851
796
  const type = data.type;
@@ -857,7 +802,7 @@ class UtilsCommunicateMicro {
857
802
  return;
858
803
  }
859
804
  try {
860
- if (type.includes(UtilsCommunicateMicro.PREFIX_TYPE)) {
805
+ if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
861
806
  data.response = JSON.parse(decrypt3rd(data.response));
862
807
  sub.next(event);
863
808
  this.allMessageSub.next(event);
@@ -873,6 +818,10 @@ class UtilsCommunicateMicro {
873
818
  this.allMessageSub.next(event);
874
819
  }
875
820
  });
821
+ UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage).pipe(filter(e => e.data.response !== UtilsCache.idService), takeUntil(onDestroy)).subscribe(() => {
822
+ console.log('clear all cache by event');
823
+ UtilsCache.ClearAll();
824
+ });
876
825
  }
877
826
  static PostMessageToParent(data) {
878
827
  data = this.convertData(data);
@@ -907,14 +856,13 @@ class UtilsCommunicateMicro {
907
856
  }
908
857
  data = { ...data };
909
858
  const type = data.type;
910
- if (type.includes(this.PREFIX_TYPE)) {
859
+ if (type.includes(COMMUNICATE_MICRO_PREFIX_TYPE)) {
911
860
  try {
912
861
  JSON.parse(decrypt3rd(data.response));
913
862
  return data;
914
863
  }
915
- catch (error) {
916
- console.log(error);
917
- data.response = decrypt3rd(JSON.stringify(data.response));
864
+ catch (_) {
865
+ data.response = encrypt3rd(JSON.stringify(data.response));
918
866
  return data;
919
867
  }
920
868
  }
@@ -922,9 +870,8 @@ class UtilsCommunicateMicro {
922
870
  JSON.parse(decrypt(data.response));
923
871
  return data;
924
872
  }
925
- catch (error) {
926
- console.log(error);
927
- data.response = decrypt(JSON.stringify(data.response));
873
+ catch (_) {
874
+ data.response = encrypt(JSON.stringify(data.response));
928
875
  return data;
929
876
  }
930
877
  }
@@ -944,6 +891,9 @@ class UtilsCommunicateMicro {
944
891
  if (!Array.isArray(messageType) || !messageType.length) {
945
892
  throw new Error('message type empty');
946
893
  }
894
+ if (messageType.length === 1) {
895
+ return this.GetMessage(messageType[0]);
896
+ }
947
897
  const types = messageType.sort().join(';');
948
898
  let sub = this.subs.get(types);
949
899
  if (sub) {
@@ -961,90 +911,149 @@ class UtilsCommunicateMicro {
961
911
  });
962
912
  });
963
913
  }
964
- postMessageToParent(data) {
965
- UtilsCommunicateMicro.PostMessageToParent(data);
966
- }
967
- postMessageToChildren(data) {
968
- UtilsCommunicateMicro.PostMessageToChildren(data);
914
+ }
915
+
916
+ class UtilsLanguageConstants {
917
+ static VI = "vi"; // Tiếng Việt
918
+ static EN = "en"; // Tiếng Anh
919
+ static FR = "fr"; // Tiếng Pháp
920
+ static DE = "de"; // Tiếng Đức
921
+ static ES = "es"; // Tiếng Tây Ban Nha
922
+ static ZH = "zh"; // Tiếng Trung (Giản thể)
923
+ static ZH_TW = "zh-TW"; // Tiếng Trung (Phồn thể)
924
+ static JA = "ja"; // Tiếng Nhật
925
+ static KO = "ko"; // Tiếng Hàn
926
+ static RU = "ru"; // Tiếng Nga
927
+ static IT = "it"; // Tiếng Ý
928
+ static PT = "pt"; // Tiếng Bồ Đào Nha
929
+ static TH = "th"; // Tiếng Thái
930
+ static ID = "id"; // Tiếng Indonesia
931
+ static MS = "ms"; // Tiếng Malaysia
932
+ static AR = "ar"; // Tiếng Ả Rập
933
+ static HI = "hi"; // Tiếng Hindi
934
+ static BN = "bn"; // Tiếng Bengal
935
+ static TR = "tr"; // Tiếng Thổ Nhĩ Kỳ
936
+ static NL = "nl"; // Tiếng Hà Lan
937
+ static KM = "km"; // Tiếng Khmer (Campuchia)
938
+ static LO = "lo"; // Tiếng Lào
939
+ static MY = "my"; // Tiếng Miến Điện (Myanmar)
940
+ static TL = "tl"; // Tiếng Tagalog (Philippines)
941
+ static CEB = "ceb"; // Tiếng Cebuano (Philippines)
942
+ static JV = "jv"; // Tiếng Java (Indonesia)
943
+ static SU = "su"; // Tiếng Sundanese (Indonesia)
944
+ // Ngôn ngữ mặc định
945
+ static defaultLang = UtilsLanguageConstants.VI;
946
+ // Danh sách các ngôn ngữ được hỗ trợ
947
+ static supportedLanguages = new Set([
948
+ UtilsLanguageConstants.VI,
949
+ UtilsLanguageConstants.EN,
950
+ UtilsLanguageConstants.FR,
951
+ UtilsLanguageConstants.DE,
952
+ UtilsLanguageConstants.ES,
953
+ UtilsLanguageConstants.ZH,
954
+ UtilsLanguageConstants.ZH_TW,
955
+ UtilsLanguageConstants.JA,
956
+ UtilsLanguageConstants.KO,
957
+ UtilsLanguageConstants.RU,
958
+ UtilsLanguageConstants.IT,
959
+ UtilsLanguageConstants.PT,
960
+ UtilsLanguageConstants.TH,
961
+ UtilsLanguageConstants.ID,
962
+ UtilsLanguageConstants.MS,
963
+ UtilsLanguageConstants.AR,
964
+ UtilsLanguageConstants.HI,
965
+ UtilsLanguageConstants.BN,
966
+ UtilsLanguageConstants.TR,
967
+ UtilsLanguageConstants.NL,
968
+ UtilsLanguageConstants.KM,
969
+ UtilsLanguageConstants.LO,
970
+ UtilsLanguageConstants.MY,
971
+ UtilsLanguageConstants.TL,
972
+ UtilsLanguageConstants.CEB,
973
+ UtilsLanguageConstants.JV,
974
+ UtilsLanguageConstants.SU,
975
+ ]);
976
+ /**
977
+ * Kiểm tra xem ngôn ngữ đầu vào có được hỗ trợ không
978
+ * @param lang Mã ngôn ngữ cần kiểm tra
979
+ * @returns True nếu được hỗ trợ, False nếu không
980
+ */
981
+ static isSupported(lang) {
982
+ return UtilsLanguageConstants.supportedLanguages.has(lang);
969
983
  }
970
984
  }
971
985
 
972
986
  /* eslint-disable no-async-promise-executor */
973
987
  /* eslint-disable @typescript-eslint/no-explicit-any */
974
988
  class UtilsCache {
989
+ static CACHE_EXPIRE_TIME_DEFAULT = 5 * 60;
975
990
  static CACHE_EXPIRE_NONE = -1;
991
+ static idService = uuid();
976
992
  static typeKeyClearLocalStorage = 'LIBS_UI_CLEAR_LOCAL_STORAGE_EVENT';
977
- static listKeyKeepWhenClearALll = Array();
978
993
  static languageKeyCache = 'SR3xQKxHgffiCevPQRralg';
994
+ static listKeyKeepWhenClearALll = Array();
979
995
  static initdEvent;
980
- static CACHE_EXPIRE_TIME_DEFAULT = 5 * 60;
981
- static language = signal(UtilsLanguageConstants.defaultLang);
982
- static idService = uuid();
983
996
  static storage;
984
997
  static dbName = 'libs-ui-cache';
985
998
  static itemIndexByKey = 'key';
986
999
  static dbVersion = 1;
987
1000
  static db = null;
988
1001
  static init(config) {
989
- if (UtilsCache.initdEvent) {
1002
+ if (this.initdEvent) {
990
1003
  return;
991
1004
  }
992
- UtilsCache.initdEvent = true;
1005
+ this.initdEvent = true;
993
1006
  if (config.indexedDBName) {
994
- UtilsCache.dbName = config.indexedDBName;
1007
+ this.dbName = config.indexedDBName;
995
1008
  }
996
1009
  if (config.typeKeyClearLocalStorage) {
997
- UtilsCache.typeKeyClearLocalStorage = config.typeKeyClearLocalStorage;
1010
+ this.typeKeyClearLocalStorage = config.typeKeyClearLocalStorage;
998
1011
  }
999
- if (config.listKeyKeepWhenClearALll) {
1000
- UtilsCache.listKeyKeepWhenClearALll = config.listKeyKeepWhenClearALll;
1012
+ if (config.listKeyKeepWhenClearAll) {
1013
+ this.listKeyKeepWhenClearALll = config.listKeyKeepWhenClearAll;
1001
1014
  }
1002
1015
  if (config.languageKeyCache) {
1003
- UtilsCache.languageKeyCache = config.languageKeyCache;
1016
+ this.languageKeyCache = config.languageKeyCache;
1004
1017
  }
1005
- UtilsCommunicateMicro.GetMessage(UtilsCache.typeKeyClearLocalStorage).pipe(filter(e => e.data.response !== UtilsCache.idService)).subscribe(() => {
1006
- UtilsCache.ClearAll();
1007
- });
1008
1018
  }
1009
1019
  static setLang(lang) {
1010
- if (lang !== UtilsLanguageConstants.VI && lang !== UtilsLanguageConstants.EN) {
1011
- throw Error('Language support vi | en');
1020
+ if (!UtilsLanguageConstants.isSupported(lang)) {
1021
+ throw Error(`Language not support ${lang}`);
1012
1022
  }
1013
- UtilsCache.language.set(lang);
1014
- UtilsCache.Set(UtilsCache.languageKeyCache, lang);
1023
+ this.Set(this.languageKeyCache, lang, this.CACHE_EXPIRE_NONE);
1015
1024
  }
1016
1025
  static getLang() {
1017
- return UtilsCache.language();
1026
+ return this.Get(this.languageKeyCache, UtilsLanguageConstants.defaultLang);
1018
1027
  }
1019
1028
  static openDB() {
1020
1029
  return new Promise(resolve => {
1021
- const request = indexedDB.open(UtilsCache.dbName, UtilsCache.dbVersion);
1030
+ const request = indexedDB.open(this.dbName, this.dbVersion);
1022
1031
  request.onupgradeneeded = (event) => {
1023
1032
  const db = event.target.result;
1024
- if (!db.objectStoreNames.contains(UtilsCache.dbName)) {
1025
- const objectStore = db.createObjectStore(UtilsCache.dbName, { keyPath: 'id', autoIncrement: true });
1026
- objectStore.createIndex(UtilsCache.itemIndexByKey, UtilsCache.itemIndexByKey, { unique: true });
1033
+ if (!db.objectStoreNames.contains(this.dbName)) {
1034
+ const objectStore = db.createObjectStore(this.dbName, { keyPath: this.itemIndexByKey });
1035
+ objectStore.createIndex(this.itemIndexByKey, this.itemIndexByKey, { unique: true });
1027
1036
  }
1028
1037
  };
1029
1038
  request.onsuccess = () => {
1030
- UtilsCache.db = request.result;
1031
- setTimeout(() => {
1032
- UtilsCache.DeleteKeyStartWithAsync('');
1033
- }, 2000);
1039
+ this.db = request.result;
1034
1040
  resolve(true);
1035
1041
  };
1036
1042
  request.onerror = (event) => {
1037
- console.error('Error opening IndexedDB:', event);
1043
+ console.trace('Error opening IndexedDB:', event);
1038
1044
  resolve(false);
1039
1045
  };
1040
1046
  });
1041
1047
  }
1042
1048
  static async getObjectStore() {
1043
- if (!UtilsCache.db) {
1044
- await UtilsCache.openDB();
1049
+ if (!this.db) {
1050
+ await this.openDB();
1045
1051
  }
1046
- const transaction = UtilsCache.db?.transaction([UtilsCache.dbName], 'readwrite');
1047
- return transaction?.objectStore(UtilsCache.dbName);
1052
+ const transaction = this.db?.transaction([this.dbName], 'readwrite');
1053
+ if (!transaction) {
1054
+ return null;
1055
+ }
1056
+ return transaction.objectStore(this.dbName);
1048
1057
  }
1049
1058
  static get LocalStorage() {
1050
1059
  try {
@@ -1058,12 +1067,12 @@ class UtilsCache {
1058
1067
  return this.getLocalStorageFake();
1059
1068
  }
1060
1069
  catch (error) {
1061
- console.log(error);
1070
+ console.trace(`LocalStorage `, error);
1062
1071
  return this.getLocalStorageFake();
1063
1072
  }
1064
1073
  }
1065
1074
  static getLocalStorageFakeOnSafari() {
1066
- if (typeof window.localStorage !== 'undefined' && !UtilsCache.storage && Object.keys(localStorage).length) {
1075
+ if (typeof window.localStorage !== 'undefined' && !this.storage && Object.keys(localStorage).length) {
1067
1076
  this.storage = { ...localStorage };
1068
1077
  }
1069
1078
  return {
@@ -1093,7 +1102,7 @@ class UtilsCache {
1093
1102
  };
1094
1103
  }
1095
1104
  static getLocalStorageFake() {
1096
- if (!UtilsCache.storage) {
1105
+ if (!this.storage) {
1097
1106
  this.storage = {};
1098
1107
  }
1099
1108
  return {
@@ -1113,19 +1122,18 @@ class UtilsCache {
1113
1122
  }
1114
1123
  static async GetAsync(key, default_value, isKeyMD5 = false) {
1115
1124
  key = isKeyMD5 ? key : md5(key);
1116
- return new Promise(async (resolve, reject) => {
1117
- const objectStore = await UtilsCache.getObjectStore();
1125
+ return new Promise(async (resolve) => {
1126
+ const objectStore = await this.getObjectStore();
1118
1127
  if (!objectStore) {
1119
1128
  return resolve(default_value);
1120
1129
  }
1121
- const index = objectStore.index(UtilsCache.itemIndexByKey);
1122
- const request = index.get(key);
1130
+ const request = objectStore.get(key);
1123
1131
  request.onsuccess = () => {
1124
1132
  if (!request.result) {
1125
1133
  return resolve(default_value);
1126
1134
  }
1127
1135
  const data = JSON.parse(decrypt(request.result.value));
1128
- if (data.expire === UtilsCache.CACHE_EXPIRE_NONE) {
1136
+ if (data.expire === this.CACHE_EXPIRE_NONE) {
1129
1137
  return resolve(data.json);
1130
1138
  }
1131
1139
  const currentMillisecond = (new Date().valueOf() / 1000);
@@ -1135,7 +1143,8 @@ class UtilsCache {
1135
1143
  return resolve(data.json);
1136
1144
  };
1137
1145
  request.onerror = () => {
1138
- reject(request.error);
1146
+ console.trace(`Get key ${key} Error, return default value: ${default_value}`);
1147
+ return resolve(default_value);
1139
1148
  };
1140
1149
  });
1141
1150
  }
@@ -1149,8 +1158,8 @@ class UtilsCache {
1149
1158
  }
1150
1159
  try {
1151
1160
  const data = JSON.parse(decrypt(cachedData));
1152
- if (data.expire === UtilsCache.CACHE_EXPIRE_NONE) {
1153
- return data.value;
1161
+ if (data.expire === this.CACHE_EXPIRE_NONE) {
1162
+ return data.value ?? default_value;
1154
1163
  }
1155
1164
  const currentMillisecond = (new Date().valueOf() / 1000);
1156
1165
  if (data.expire < currentMillisecond) {
@@ -1159,97 +1168,71 @@ class UtilsCache {
1159
1168
  return data.value;
1160
1169
  }
1161
1170
  catch (error) {
1162
- console.log(error);
1171
+ console.trace(`Get key ${key} Error, return default value: ${default_value}`, error);
1163
1172
  return this.GetDefaultValueBySpecificKey(key, default_value);
1164
1173
  }
1165
1174
  }
1166
1175
  static GetDefaultValueBySpecificKey(key, default_value) {
1167
1176
  return default_value;
1168
1177
  }
1169
- static async SetAsync(key, value, expireTimeBySecond = UtilsCache.CACHE_EXPIRE_TIME_DEFAULT, isKeyMD5 = false) {
1170
- return new Promise(async (resolve, reject) => {
1171
- let objectStore = await UtilsCache.getObjectStore();
1178
+ static async SetAsync(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT, isKeyMD5 = false) {
1179
+ return new Promise(async (resolve) => {
1180
+ const objectStore = await this.getObjectStore();
1172
1181
  key = isKeyMD5 ? key : md5(key);
1173
1182
  try {
1174
- const currentMillisecond = expireTimeBySecond === UtilsCache.CACHE_EXPIRE_NONE ? UtilsCache.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1183
+ const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1175
1184
  const data = {
1176
- key: key,
1177
1185
  value: encrypt(JSON.stringify({ json: value, expire: currentMillisecond })),
1178
1186
  };
1187
+ data[this.itemIndexByKey] = key;
1179
1188
  if (!objectStore) {
1180
- return resolve(-1);
1189
+ console.trace(`Can not open object store`);
1190
+ return resolve({ key, messageError: 'Can not open object store' });
1181
1191
  }
1182
- const index = objectStore.index(UtilsCache.itemIndexByKey);
1183
- const getIndexKeyRequest = index.get(key);
1184
- getIndexKeyRequest.onsuccess = async () => {
1185
- const item = getIndexKeyRequest.result;
1186
- if (item) {
1187
- await UtilsCache.ClearAsync(key, true);
1188
- objectStore = await UtilsCache.getObjectStore();
1189
- }
1190
- if (!objectStore) {
1191
- return resolve(-1);
1192
- }
1193
- const request = objectStore.add(data);
1194
- request.onsuccess = () => {
1195
- resolve(request.result);
1196
- };
1197
- request.onerror = () => {
1198
- console.log(request.error);
1199
- return resolve(-1);
1200
- };
1192
+ const request = objectStore?.put(data);
1193
+ request.onsuccess = () => {
1194
+ console.log(`Set key ${key} Success`);
1195
+ resolve(request.result);
1201
1196
  };
1202
- getIndexKeyRequest.onerror = (event) => {
1203
- console.error('Error fetching item by name:', event.target.error);
1204
- reject(event.target.error);
1197
+ request.onerror = (error) => {
1198
+ console.trace(`Set key ${key} Error`);
1199
+ resolve({ key, messageError: get(error, 'message') });
1205
1200
  };
1206
1201
  }
1207
1202
  catch (error) {
1208
- console.log(error);
1209
- resolve({});
1203
+ console.trace(`Set key ${key} Error`);
1204
+ resolve({ key, messageError: get(error, 'message') });
1210
1205
  }
1211
1206
  });
1212
1207
  }
1213
- static Set(key, value, expireTimeBySecond = UtilsCache.CACHE_EXPIRE_TIME_DEFAULT) {
1214
- if (value === undefined || value === null || value === '') {
1215
- return;
1216
- }
1217
- const currentMillisecond = expireTimeBySecond === UtilsCache.CACHE_EXPIRE_NONE ? UtilsCache.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1208
+ static Set(key, value, expireTimeBySecond = this.CACHE_EXPIRE_TIME_DEFAULT) {
1209
+ const currentMillisecond = expireTimeBySecond === this.CACHE_EXPIRE_NONE ? this.CACHE_EXPIRE_NONE : (new Date().valueOf() / 1000) + expireTimeBySecond;
1218
1210
  const data = {
1219
1211
  value: value,
1220
1212
  expire: currentMillisecond
1221
1213
  };
1222
1214
  try {
1223
1215
  this.LocalStorage.setItem(key, encrypt(JSON.stringify(data)));
1216
+ return true;
1224
1217
  }
1225
1218
  catch (error) {
1226
- console.log(error);
1219
+ console.trace(`Set key ${key} Error`, error);
1220
+ return false;
1227
1221
  }
1228
1222
  }
1229
1223
  static async ClearAsync(key, isMD5 = false) {
1230
1224
  return new Promise(async (resolve) => {
1231
- const objectStore = await UtilsCache.getObjectStore();
1225
+ const objectStore = await this.getObjectStore();
1232
1226
  if (!objectStore) {
1233
- return resolve({});
1227
+ return resolve();
1234
1228
  }
1235
- const index = objectStore.index(UtilsCache.itemIndexByKey);
1236
- const getRequest = index.get(isMD5 ? key : md5(key));
1237
- getRequest.onsuccess = () => {
1238
- const result = getRequest.result;
1239
- if (result) {
1240
- const deleteRequest = objectStore.delete(result.id); // Xóa theo id của item tìm được
1241
- deleteRequest.onsuccess = () => {
1242
- resolve({});
1243
- };
1244
- deleteRequest.onerror = () => {
1245
- resolve({});
1246
- };
1247
- return;
1248
- }
1249
- resolve({});
1229
+ const request = objectStore.delete(isMD5 ? key : md5(key));
1230
+ request.onsuccess = () => {
1231
+ resolve({ clearSuccess: true });
1250
1232
  };
1251
- getRequest.onerror = () => {
1252
- resolve({});
1233
+ request.onerror = (event) => {
1234
+ console.trace('Error deleting Key:', get(event.target.error, 'message'));
1235
+ resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
1253
1236
  };
1254
1237
  });
1255
1238
  }
@@ -1260,38 +1243,41 @@ class UtilsCache {
1260
1243
  this.LocalStorage.removeItem(key);
1261
1244
  }
1262
1245
  static ClearAllAsync() {
1263
- return new Promise((resolve, reject) => {
1264
- const request = indexedDB.deleteDatabase(this.dbName);
1246
+ return new Promise(async (resolve) => {
1247
+ const objectStore = await this.getObjectStore();
1248
+ if (!objectStore) {
1249
+ return resolve();
1250
+ }
1251
+ const request = objectStore.clear();
1265
1252
  request.onsuccess = () => {
1266
- console.log('Database deleted successfully');
1267
- resolve(true);
1253
+ console.log('clear all successfully');
1254
+ resolve({ clearSuccess: true });
1268
1255
  };
1269
1256
  request.onerror = (event) => {
1270
- console.error('Error deleting database:', event.target.error);
1271
- reject(event.target.error);
1272
- };
1273
- request.onblocked = () => {
1274
- console.warn('Delete request is blocked');
1257
+ console.trace('Error deleting key:', get(event.target.error, 'message'));
1258
+ resolve({ messageError: get(event.target.error, 'message'), clearSuccess: false });
1275
1259
  };
1276
1260
  });
1277
1261
  }
1278
1262
  static ClearAll() {
1279
- const keys = [...UtilsCache.listKeyKeepWhenClearALll];
1263
+ if (isEmbedFrame()) {
1264
+ const data = {
1265
+ type: this.typeKeyClearLocalStorage,
1266
+ response: {
1267
+ idEvent: this.idService
1268
+ }
1269
+ };
1270
+ UtilsCommunicateMicro.PostMessageToParent(data);
1271
+ }
1272
+ const keys = [...this.listKeyKeepWhenClearALll];
1280
1273
  Object.keys(this.LocalStorage).forEach(key => {
1281
1274
  if (key.includes('kc-callback-')) {
1282
1275
  keys.push(key);
1283
1276
  }
1284
1277
  });
1285
- const stores = UtilsCache.GetDataByKeys(Array.from(keys));
1278
+ const stores = this.GetDataByKeys(Array.from(keys));
1286
1279
  this.LocalStorage.clear();
1287
- UtilsCache.SetDataByKey(stores);
1288
- const data = {
1289
- type: UtilsCache.typeKeyClearLocalStorage,
1290
- response: {
1291
- idEvent: this.idService
1292
- }
1293
- };
1294
- UtilsCommunicateMicro.PostMessageToParent(data);
1280
+ this.SetDataByKey(stores);
1295
1281
  }
1296
1282
  static GetDataByKeys(keys) {
1297
1283
  const stores = new Map();
@@ -1300,62 +1286,1051 @@ class UtilsCache {
1300
1286
  stores.set(key, this.LocalStorage.getItem(key));
1301
1287
  return;
1302
1288
  }
1303
- stores.set(key, UtilsCache.Get(key));
1289
+ stores.set(key, this.Get(key));
1304
1290
  });
1305
1291
  return stores;
1306
1292
  }
1307
- static SetDataByKey(stores) {
1308
- stores.forEach((value, key) => {
1309
- if (key.includes('kc-callback-')) {
1310
- this.LocalStorage.setItem(key, value);
1293
+ static SetDataByKey(stores) {
1294
+ stores.forEach((value, key) => {
1295
+ if (key.includes('kc-callback-')) {
1296
+ this.LocalStorage.setItem(key, value);
1297
+ return;
1298
+ }
1299
+ if (key === this.languageKeyCache) {
1300
+ return this.setLang(value);
1301
+ }
1302
+ this.Set(key, value, this.CACHE_EXPIRE_NONE);
1303
+ });
1304
+ }
1305
+ static DeleteKeyStartWithAsync(keyCacheStartWith, isKeyMD5 = false) {
1306
+ return new Promise(async (resolve) => {
1307
+ const objectStore = await this.getObjectStore();
1308
+ if (!objectStore) {
1309
+ return resolve({});
1310
+ }
1311
+ // Lấy tất cả các keys từ index
1312
+ const request = objectStore.getAll();
1313
+ keyCacheStartWith = isKeyMD5 ? keyCacheStartWith : md5(keyCacheStartWith);
1314
+ request.onsuccess = (e) => {
1315
+ const data = e.target.result;
1316
+ if (!Array.isArray(data)) {
1317
+ return resolve({});
1318
+ }
1319
+ data.forEach(obj => {
1320
+ if (obj[this.itemIndexByKey].startsWith(keyCacheStartWith)) {
1321
+ this.ClearAsync(obj[this.itemIndexByKey], true);
1322
+ }
1323
+ });
1324
+ return resolve({});
1325
+ };
1326
+ request.onerror = () => {
1327
+ return resolve({});
1328
+ };
1329
+ });
1330
+ }
1331
+ static DeleteKeyStartWith(keyCache, isMD5 = false) {
1332
+ keyCache = isMD5 ? md5(keyCache) : keyCache;
1333
+ const keys = Object.keys(this.LocalStorage);
1334
+ if (!keys || !keys.length) {
1335
+ return;
1336
+ }
1337
+ keys.forEach(key => {
1338
+ if (key.startsWith(keyCache)) {
1339
+ this.Clear(key);
1340
+ }
1341
+ });
1342
+ }
1343
+ static DeleteDatabaseIndexDB(dbName) {
1344
+ return new Promise((resolve) => {
1345
+ dbName = (dbName || this.dbName);
1346
+ const request = indexedDB.deleteDatabase(dbName);
1347
+ request.onsuccess = () => {
1348
+ console.trace('Database deleted successfully');
1349
+ resolve({ deleteSuccess: true });
1350
+ };
1351
+ request.onerror = (event) => {
1352
+ const error = event.target.error;
1353
+ console.trace('Error deleting database:', error);
1354
+ resolve({ messageError: get(error || {}, 'message'), deleteSuccess: false });
1355
+ };
1356
+ request.onblocked = () => {
1357
+ console.trace('Delete request is blocked');
1358
+ resolve({ messageError: 'Delete request is blocked', deleteSuccess: false });
1359
+ };
1360
+ });
1361
+ }
1362
+ }
1363
+
1364
+ dayjs.extend(localeData);
1365
+ dayjs.extend(updateLocale);
1366
+ dayjs.extend(utc);
1367
+ dayjs.extend(timezone);
1368
+ dayjs.extend(customParseFormat);
1369
+ let timeZoneSetup = "Asia/Ho_Chi_Minh";
1370
+ const setDefaultTimeZone = (localeZone = timeZoneSetup) => {
1371
+ timeZoneSetup = localeZone;
1372
+ dayjs.tz.setDefault(localeZone);
1373
+ };
1374
+ let functionFormatDate = undefined;
1375
+ const updateFunctionFormatDate = (functionCustom) => {
1376
+ functionFormatDate = functionCustom;
1377
+ };
1378
+ /**
1379
+ * @description Lấy đối tượng dayjs theo config
1380
+ * @param config nếu không có config sẽ trả về đối tượng dayjs là thời gian hiện tại
1381
+ * @param config.date thời gian cần lấy
1382
+ * @param config.returnDayjsIfConfigDateNotExist true nếu muốn trả về đối tượng dayjs nếu config.date không có
1383
+ * @param config.utc true nếu muốn lấy thời gian UTC
1384
+ * @param config.formatOfDate định dạng thời gian đang được truyền vào
1385
+ */
1386
+ const getDayjs = (config) => {
1387
+ if (!config) {
1388
+ return dayjs().tz();
1389
+ }
1390
+ config.date = !config.date && config.returnDayjsIfConfigDateNotExist ? dayjs().tz() : config.date;
1391
+ if (typeof config.date === 'number') {
1392
+ config.date = dayjs.unix(config.date);
1393
+ }
1394
+ if (!config.date) {
1395
+ return undefined;
1396
+ }
1397
+ let { date, utc, formatOfDate } = config;
1398
+ while (isSignal(date)) {
1399
+ date = date();
1400
+ }
1401
+ while (isSignal(utc)) {
1402
+ utc = utc();
1403
+ }
1404
+ while (isSignal(formatOfDate)) {
1405
+ formatOfDate = formatOfDate();
1406
+ }
1407
+ if (utc) {
1408
+ if (formatOfDate) {
1409
+ return dayjs(date, formatOfDate).utc();
1410
+ }
1411
+ const dateInputIsUTC = (dayjs.isDayjs(date) && date.isUTC()) || (typeof date === 'string' && date.includes('Z'));
1412
+ if (dateInputIsUTC) {
1413
+ return dayjs(date);
1414
+ }
1415
+ return dayjs(date).utc();
1416
+ }
1417
+ if (typeof date === 'string' && !date.includes('Z') && !date.includes('+')) {
1418
+ return (formatOfDate ? dayjs.tz(date, formatOfDate, config.localeZone || timeZoneSetup) : dayjs.tz(date, config.localeZone || timeZoneSetup));
1419
+ }
1420
+ return (formatOfDate ? dayjs(date, formatOfDate) : dayjs(date)).tz();
1421
+ };
1422
+ /**
1423
+ * @description Kiểm tra xem hai ngày có khác nhau không (khác ngày trong tuần)
1424
+ * @param date1 ngày thứ nhất cần so sánh
1425
+ * @param date2 ngày thứ hai cần so sánh
1426
+ * @returns true nếu hai ngày khác nhau, false nếu giống nhau hoặc không thể so sánh
1427
+ */
1428
+ const isDifferenceDay = (date1, date2) => {
1429
+ if (isDifferenceMonth(date1, date2)) {
1430
+ return true;
1431
+ }
1432
+ const day1 = getDayjs({ date: date1 })?.day();
1433
+ const day2 = getDayjs({ date: date2 })?.day();
1434
+ return day1 !== day2;
1435
+ };
1436
+ /**
1437
+ * @description Kiểm tra xem hai ngày có khác tháng không
1438
+ * @param date1 ngày thứ nhất cần so sánh
1439
+ * @param date2 ngày thứ hai cần so sánh
1440
+ * @returns true nếu hai ngày khác tháng, false nếu cùng tháng hoặc không thể so sánh
1441
+ */
1442
+ const isDifferenceMonth = (date1, date2) => {
1443
+ if (isDifferenceYear(date1, date2)) {
1444
+ return true;
1445
+ }
1446
+ const month1 = getDayjs({ date: date1 })?.month();
1447
+ const month2 = getDayjs({ date: date2 })?.month();
1448
+ return month1 !== month2;
1449
+ };
1450
+ /**
1451
+ * @description Kiểm tra xem hai ngày có khác năm không
1452
+ * @param date1 ngày thứ nhất cần so sánh
1453
+ * @param date2 ngày thứ hai cần so sánh
1454
+ * @returns true nếu hai ngày khác năm, false nếu cùng năm hoặc không thể so sánh
1455
+ */
1456
+ const isDifferenceYear = (date1, date2) => {
1457
+ const year1 = getDayjs({ date: date1 })?.year();
1458
+ const year2 = getDayjs({ date: date2 })?.year();
1459
+ return year1 !== year2;
1460
+ };
1461
+ /**
1462
+ * @description Lấy ra chuỗi thời gian hiển thị theo định dạng và ngôn ngữ
1463
+ * @param date thời gian cần định dạng
1464
+ * @param format định dạng thời gian muốn lấy ra
1465
+ * @param lang lấy theo ngôn ngữ
1466
+ */
1467
+ const formatDate = (date, formatOutput = 'YYYY/MM/DD HH:mm', lang, formatInput) => {
1468
+ if (!date) {
1469
+ return '';
1470
+ }
1471
+ lang = lang || UtilsCache.getLang();
1472
+ if (functionFormatDate) {
1473
+ return functionFormatDate(date, formatOutput, lang);
1474
+ }
1475
+ date = getDayjs({ date, formatOfDate: formatInput }).locale(lang);
1476
+ if (lang === 'vi') {
1477
+ dayjs.updateLocale('vi', {
1478
+ monthsShort: 'Thg 1_Thg 2_Thg 3_Thg 4_Thg 5_Thg 6_Thg 7_Thg 8_Thg 9_Thg 10_Thg 11_Thg 12'.split('_')
1479
+ });
1480
+ }
1481
+ return date.format(getFormatData(getTypeByFormat(formatOutput), lang)) || '';
1482
+ };
1483
+ const getTypeByFormat = (format) => {
1484
+ if (format === 'dm' || format === 'dmy' || format === 'dmy hm' || format === 'my') {
1485
+ return format;
1486
+ }
1487
+ if (format === 'DD/MM/YYYY' || format === 'YYYY-MM-DD' || format === 'dd/MM/yyyy' || format === 'dd-MM-yyyy' || format === 'dd/mm/yyyy') {
1488
+ return 'dmy';
1489
+ }
1490
+ if (format === 'MM-DD' || format === 'dd/MM' || format === 'dd/mm') {
1491
+ return 'dm';
1492
+ }
1493
+ if (format === 'M/YYYY' || format === 'YYYY-MM' || format === 'MM/yyyy') {
1494
+ return 'my';
1495
+ }
1496
+ if (format === 'YYYY/MM/DD hh:mm:ss' || format === 'dmy hms' || format === 'dd/mm/yyyy hh:mm:ss') {
1497
+ return 'dmy hms';
1498
+ }
1499
+ if (format === 'hh:mm' || format === 'HH:mm') {
1500
+ return 'hh:mm';
1501
+ }
1502
+ if (format === 'hh:mm A' || format === 'HH:mm A') {
1503
+ return 'hh:mm A';
1504
+ }
1505
+ return 'dmy hm';
1506
+ };
1507
+ const getFormatData = (type, lang) => {
1508
+ switch (type) {
1509
+ case 'dm':
1510
+ if (lang === 'vi') {
1511
+ return 'D MMM';
1512
+ }
1513
+ return 'MMM D';
1514
+ case 'dmy':
1515
+ if (lang === 'vi') {
1516
+ return 'D MMM, YYYY';
1517
+ }
1518
+ return 'MMM D, YYYY';
1519
+ case 'dmy hm':
1520
+ if (lang === 'vi') {
1521
+ return 'D MMM, YYYY HH:mm';
1522
+ }
1523
+ return 'MMM D, YYYY HH:mm';
1524
+ case 'my':
1525
+ if (lang === 'vi') {
1526
+ return 'MMM, YYYY';
1527
+ }
1528
+ return 'MMM YYYY ';
1529
+ case 'dmy hms':
1530
+ if (lang === 'vi') {
1531
+ return 'D MMM, YYYY HH:mm:ss';
1532
+ }
1533
+ return 'MMM D, YYYY HH:mm:ss';
1534
+ case 'hh:mm':
1535
+ case 'HH:mm':
1536
+ return 'HH:mm';
1537
+ case 'hh:mm A':
1538
+ case 'HH:mm A':
1539
+ return 'HH:mm A';
1540
+ }
1541
+ };
1542
+
1543
+ /* eslint-disable @typescript-eslint/no-explicit-any */
1544
+ /**Các hàm tương tự thư viện lodash */
1545
+ /**
1546
+ * Kiểm tra xem một giá trị có phải là null hoặc undefined hay không
1547
+ * @param value Giá trị cần kiểm tra
1548
+ * @returns true nếu giá trị là null hoặc undefined, false nếu không
1549
+ * @example
1550
+ * isNil(null); // true
1551
+ * isNil(undefined); // true
1552
+ * isNil(0); // false
1553
+ * isNil('hello'); // false
1554
+ */
1555
+ const isNil = (value) => {
1556
+ return value === null || value === undefined;
1557
+ };
1558
+ /**
1559
+ * Kiểm tra xem một giá trị có phải là rỗng hay không
1560
+ * @param value Giá trị cần kiểm tra
1561
+ * @returns true nếu giá trị là null, rỗng hoặc undefined, false nếu không
1562
+ * @example
1563
+ * isEmpty(null); // true
1564
+ * isEmpty(''); // true
1565
+ * isEmpty(undefined); // true
1566
+ * isEmpty({}); // true
1567
+ * isEmpty([]); // true
1568
+ * isEmpty([1, 2, 3]); // false
1569
+ * isEmpty({ a: 1 }); // false
1570
+ */
1571
+ const isEmpty = (value) => {
1572
+ while (isSignal(value)) {
1573
+ value = value();
1574
+ }
1575
+ return value === null || value === '' || value === undefined || (typeof value === 'object' && (JSON.stringify(value) === '{}' || JSON.stringify(value) === '[]'));
1576
+ };
1577
+ /**
1578
+ * Loại bỏ các thuộc tính của đối tượng dựa trên một hàm điều kiện
1579
+ * @param objData Đối tượng cần xử lý
1580
+ * @param predicate Hàm điều kiện để kiểm tra giá trị của thuộc tính. Nếu hàm trả về true thì thuộc tính đó sẽ bị loại bỏ
1581
+ * @returns Đối tượng mới sau khi đã loại bỏ các thuộc tính thỏa mãn điều kiện
1582
+ * @example
1583
+ * const obj = { a: 1, b: null, c: 3, d: undefined };
1584
+ * omitBy(obj, isNil); // { a: 1, c: 3 }
1585
+ */
1586
+ const omitBy = (objData, predicate) => {
1587
+ if (!objData || typeof objData !== 'object' || Array.isArray(objData)) {
1588
+ return objData;
1589
+ }
1590
+ const newObj = {};
1591
+ Object.keys(objData).forEach((key) => {
1592
+ const valueOfKey = get(objData, key);
1593
+ if (!predicate(valueOfKey)) {
1594
+ set(newObj, key, valueOfKey);
1595
+ }
1596
+ });
1597
+ return newObj;
1598
+ };
1599
+ /**
1600
+ * Lấy giá trị từ đối tượng theo đường dẫn chỉ định
1601
+ *
1602
+ * Hàm này giúp bạn truy cập vào các thuộc tính sâu bên trong một đối tượng một cách an toàn,
1603
+ * tránh lỗi khi thuộc tính không tồn tại.
1604
+ *
1605
+ * @param obj Đối tượng nguồn cần lấy giá trị
1606
+ * @param path Đường dẫn đến thuộc tính cần lấy. Có thể là:
1607
+ * - Chuỗi: 'user.profile.name' hoặc 'items[0].title'
1608
+ * - Mảng: ['user', 'profile', 'name'] hoặc ['items', '0', 'title']
1609
+ * - Chuỗi rỗng '': trả về chính đối tượng gốc
1610
+ * @param defaultValue Giá trị mặc định trả về khi không tìm thấy thuộc tính (mặc định: undefined)
1611
+ * @param keepLastValueIfSignal Có giữ nguyên signal cuối cùng hay không (mặc định: false - sẽ gọi signal())
1612
+ * @returns Giá trị tìm được hoặc giá trị mặc định
1613
+ *
1614
+ * @example
1615
+ * // Ví dụ cơ bản
1616
+ * const user = { name: 'John', age: 30 };
1617
+ * get(user, 'name'); // 'John'
1618
+ * get(user, 'email'); // undefined
1619
+ * get(user, 'email', 'no-email'); // 'no-email'
1620
+ *
1621
+ * @example
1622
+ * // Truyền path rỗng - trả về chính đối tượng gốc
1623
+ * const data = { name: 'Alice', age: 25 };
1624
+ * get(data, ''); // { name: 'Alice', age: 25 } (chính đối tượng data)
1625
+ * get(data, '', 'default'); // { name: 'Alice', age: 25 } (bỏ qua defaultValue)
1626
+ *
1627
+ * @example
1628
+ * // Truy cập thuộc tính sâu
1629
+ * const data = {
1630
+ * user: {
1631
+ * profile: {
1632
+ * name: 'Alice',
1633
+ * settings: { theme: 'dark' }
1634
+ * }
1635
+ * }
1636
+ * };
1637
+ * get(data, 'user.profile.name'); // 'Alice'
1638
+ * get(data, 'user.profile.settings.theme'); // 'dark'
1639
+ * get(data, 'user.profile.avatar', 'default.jpg'); // 'default.jpg'
1640
+ *
1641
+ * @example
1642
+ * // Truy cập mảng
1643
+ * const items = [
1644
+ * { name: 'Item 1', price: 100 },
1645
+ * { name: 'Item 2', price: 200 }
1646
+ * ];
1647
+ * get(items, '[0].name'); // 'Item 1'
1648
+ * get(items, '[1].name'); // 'Item 2'
1649
+ * get(items, '[2].name', 'Not found'); // 'Not found'
1650
+ *
1651
+ * @example
1652
+ * // Sử dụng với mảng path
1653
+ * const nested = { a: { b: { c: 'deep value' } } };
1654
+ * get(nested, ['a', 'b', 'c']); // 'deep value'
1655
+ * get(nested, ['a', 'b', 'd'], 'default'); // 'default'
1656
+ *
1657
+ * @example
1658
+ * // Trường hợp đặc biệt
1659
+ * get(null, 'any.path'); // undefined
1660
+ * get(undefined, 'any.path', 'fallback'); // 'fallback'
1661
+ */
1662
+ const get = (obj, path, defaultValue, keepLastValueIfSignal) => {
1663
+ if (isNil(obj)) {
1664
+ return defaultValue;
1665
+ }
1666
+ while (isSignal(obj)) {
1667
+ obj = obj();
1668
+ }
1669
+ if (path === '') {
1670
+ return obj;
1671
+ }
1672
+ if (obj instanceof HttpParams) {
1673
+ return (obj.get(`${path}`) ?? defaultValue);
1674
+ }
1675
+ if (obj instanceof DOMRect) {
1676
+ return obj[path];
1677
+ }
1678
+ const paths = Array.isArray(path)
1679
+ ? path
1680
+ : path
1681
+ .replace(/\[(\d+)]/g, '.$1')
1682
+ .split('.')
1683
+ .filter((key) => key);
1684
+ for (const index in paths) {
1685
+ const key = paths[index];
1686
+ if (obj instanceof CSSStyleDeclaration) {
1687
+ obj = obj[key];
1688
+ continue;
1689
+ }
1690
+ if (obj instanceof HTMLElement) {
1691
+ obj = obj[key];
1692
+ continue;
1693
+ }
1694
+ if (isNil(obj) || !Object.prototype.hasOwnProperty.call(obj, key)) {
1695
+ return defaultValue;
1696
+ }
1697
+ const val = isSignal(obj[key]) && !keepLastValueIfSignal ? obj[key]() : obj[key];
1698
+ obj = val;
1699
+ }
1700
+ return obj;
1701
+ };
1702
+ /**
1703
+ * Thiết lập giá trị cho một thuộc tính trong đối tượng theo đường dẫn chỉ định
1704
+ * @param obj Đối tượng cần thiết lập giá trị
1705
+ * @param path Đường dẫn đến thuộc tính, có thể là chuỗi (vd: 'a.b.c') hoặc mảng (vd: ['a', 'b', 'c'])
1706
+ * @param value Giá trị cần thiết lập
1707
+ * @returns Đối tượng sau khi đã thiết lập giá trị
1708
+ * @throws Error nếu tham số đầu tiên không phải là đối tượng
1709
+ * @example
1710
+ * const obj = { a: { b: 1 } };
1711
+ * set(obj, 'a.b', 2); // { a: { b: 2 } }
1712
+ */
1713
+ const set = (obj, path, value) => {
1714
+ if (!obj || (typeof obj !== 'object' && !isSignal(obj)) || (isSignal(obj) && typeof obj() !== 'object')) {
1715
+ throw new Error('The first argument must be an object');
1716
+ }
1717
+ if (obj instanceof HttpParams) {
1718
+ return obj.set(`${path}`, value);
1719
+ }
1720
+ const pathArray = Array.isArray(path)
1721
+ ? path
1722
+ : path
1723
+ .replace(/\[(\d+)]/g, '.[$1]')
1724
+ .split('.')
1725
+ .filter((key) => key);
1726
+ let currentObjectByKey = isSignal(obj) ? obj() : obj;
1727
+ let preObjectByKey = obj;
1728
+ pathArray.forEach((key, index) => {
1729
+ if (index < pathArray.length - 1) {
1730
+ if (!(key in currentObjectByKey) || (typeof currentObjectByKey[key] !== 'object' && !isSignal(currentObjectByKey[key]))) {
1731
+ const nextKey = pathArray[index + 1];
1732
+ key = key.replace(/\[(\d+)]/g, '$1');
1733
+ currentObjectByKey[key] = /\[(\d+)]/g.test(nextKey) ? [] : {};
1734
+ }
1735
+ currentObjectByKey = key ? currentObjectByKey[key] : currentObjectByKey;
1736
+ preObjectByKey = currentObjectByKey;
1737
+ currentObjectByKey = isSignal(currentObjectByKey) ? currentObjectByKey() : currentObjectByKey;
1738
+ return;
1739
+ }
1740
+ if (typeof currentObjectByKey !== 'object') {
1741
+ return;
1742
+ }
1743
+ // Gán giá trị ở cuối đường dẫn
1744
+ key = key.replace(/\[(\d+)]/g, '$1');
1745
+ const valueOfKey = currentObjectByKey[key];
1746
+ const valueOfKeyIsSignal = isSignal(valueOfKey);
1747
+ if (valueOfKeyIsSignal && (typeof valueOfKey() !== 'object' || valueOfKey() === null)) {
1748
+ valueOfKey.set(isSignal(value) ? value() : value);
1749
+ return;
1750
+ }
1751
+ if (isSignal(preObjectByKey)) {
1752
+ preObjectByKey.update((data) => {
1753
+ const dataOfKey = data[key];
1754
+ if (isNil(dataOfKey) || !valueOfKeyIsSignal) {
1755
+ data[key] = value;
1756
+ }
1757
+ if (valueOfKeyIsSignal) {
1758
+ valueOfKey.set(isSignal(value) ? value() : value);
1759
+ }
1760
+ if (Array.isArray(data)) {
1761
+ return [...data];
1762
+ }
1763
+ return { ...data };
1764
+ });
1765
+ return;
1766
+ }
1767
+ if (valueOfKeyIsSignal) {
1768
+ valueOfKey.set(isSignal(value) ? value() : value);
1769
+ return;
1770
+ }
1771
+ currentObjectByKey[key] = value;
1772
+ });
1773
+ return obj;
1774
+ };
1775
+ /**
1776
+ * Tạo một bản sao sâu của một đối tượng hoặc giá trị bất kỳ
1777
+ * @param data Dữ liệu cần sao chép
1778
+ * @param options Tùy chọn cấu hình
1779
+ * @param options.ignoreSignal Nếu true, sẽ không sao chép các signal mà trả về signal gốc
1780
+ * @param seen WeakMap để theo dõi các tham chiếu đã được sao chép, tránh lặp vô hạn với các tham chiếu vòng
1781
+ * @returns Bản sao sâu của dữ liệu đầu vào
1782
+ * @example
1783
+ * const obj = {
1784
+ * a: 1,
1785
+ * b: { c: 2 },
1786
+ * d: [1, 2, 3]
1787
+ * };
1788
+ * const clone = cloneDeep(obj);
1789
+ * // clone là một bản sao hoàn toàn độc lập của obj
1790
+ */
1791
+ const cloneDeep = (data, options = { ignoreSignal: false }, seen = new WeakMap()) => {
1792
+ if (data === null || (typeof data !== 'object' && !isSignal(data))) {
1793
+ return data;
1794
+ }
1795
+ if (seen.has(data)) {
1796
+ return seen.get(data);
1797
+ }
1798
+ if (data instanceof HttpParams) {
1799
+ return new UtilsHttpParamsRequest(undefined, data);
1800
+ }
1801
+ if (data instanceof Date) {
1802
+ return new Date(data.getTime());
1803
+ }
1804
+ if (dayjs.isDayjs(data)) {
1805
+ return getDayjs({ date: data.valueOf() });
1806
+ }
1807
+ if (data instanceof RegExp) {
1808
+ return new RegExp(data.source, data.flags);
1809
+ }
1810
+ if (data instanceof Map) {
1811
+ const mapCopy = new Map();
1812
+ seen.set(data, mapCopy);
1813
+ data.forEach((val, key) => {
1814
+ mapCopy.set(cloneDeep(key, options, seen), cloneDeep(val, options, seen));
1815
+ });
1816
+ return mapCopy;
1817
+ }
1818
+ if (data instanceof Set) {
1819
+ const setCopy = new Set();
1820
+ seen.set(data, setCopy);
1821
+ data.forEach((val) => {
1822
+ setCopy.add(cloneDeep(val, options, seen));
1823
+ });
1824
+ return setCopy;
1825
+ }
1826
+ if (Array.isArray(data)) {
1827
+ seen.set(data, data.map((item) => cloneDeep(item, options, seen)));
1828
+ return seen.get(data);
1829
+ }
1830
+ if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
1831
+ return data;
1832
+ }
1833
+ if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable) {
1834
+ return data;
1835
+ }
1836
+ if (isSignal(data)) {
1837
+ if (options?.ignoreSignal) {
1838
+ return data;
1839
+ }
1840
+ seen.set(data, signal(cloneDeep(data(), options, seen)));
1841
+ return seen.get(data);
1842
+ }
1843
+ const result = {};
1844
+ seen.set(data, result);
1845
+ for (const key in data) {
1846
+ const value = data[key];
1847
+ if (value instanceof HttpParams) {
1848
+ result[key] = new UtilsHttpParamsRequest(undefined, value);
1849
+ continue;
1850
+ }
1851
+ if (dayjs.isDayjs(value)) {
1852
+ result[key] = getDayjs({ date: value.valueOf() });
1853
+ continue;
1854
+ }
1855
+ if (value instanceof TemplateRef || value instanceof ElementRef || value instanceof Element || value instanceof Promise || value instanceof Observable) {
1856
+ result[key] = value;
1857
+ continue;
1858
+ }
1859
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
1860
+ result[key] = cloneDeep(value, options, seen);
1861
+ }
1862
+ }
1863
+ return result;
1864
+ };
1865
+ /**
1866
+ * Chuyển đổi một mảng các đối tượng thành một đối tượng với khóa được chỉ định
1867
+ * @param data Mảng các đối tượng cần chuyển đổi
1868
+ * @param key Tên thuộc tính được sử dụng làm khóa trong đối tượng kết quả
1869
+ * @returns Đối tượng với các giá trị từ mảng được đánh key theo thuộc tính đã chỉ định
1870
+ * @example
1871
+ * const data = [
1872
+ * { id: 1, name: 'John' },
1873
+ * { id: 2, name: 'Jane' }
1874
+ * ];
1875
+ * keyBy(data, 'id');
1876
+ * // Kết quả: {
1877
+ * // '1': { id: 1, name: 'John' },
1878
+ * // '2': { id: 2, name: 'Jane' }
1879
+ * // }
1880
+ */
1881
+ const keyBy = (data, key) => {
1882
+ if (!data || !data.length || !key) {
1883
+ return {};
1884
+ }
1885
+ return data.reduce((dir, nextItem) => {
1886
+ const valueOfKey = get(nextItem, key);
1887
+ if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number' && typeof valueOfKey !== 'boolean') {
1888
+ return dir;
1889
+ }
1890
+ if (!Object.keys(dir).includes(`${valueOfKey}`)) {
1891
+ dir[`${valueOfKey}`] = nextItem;
1892
+ }
1893
+ return dir;
1894
+ }, {});
1895
+ };
1896
+ /**
1897
+ * Nhóm các đối tượng trong một mảng thành các nhóm dựa trên một thuộc tính cụ thể
1898
+ * @param data Mảng các đối tượng cần nhóm
1899
+ * @param key Tên thuộc tính được sử dụng làm khóa nhóm
1900
+ * @returns Đối tượng với các giá trị từ mảng được nhóm theo thuộc tính đã chỉ định
1901
+ * @example
1902
+ * const data = [
1903
+ * { id: 1, name: 'John' },
1904
+ * { id: 2, name: 'Jane' },
1905
+ * { id: 1, name: 'John' }
1906
+ * ];
1907
+ * groupBy(data, 'id');
1908
+ * // Kết quả: {
1909
+ * // '1': [
1910
+ * // { id: 1, name: 'John' },
1911
+ * // { id: 1, name: 'John' }
1912
+ * // ],
1913
+ * // '2': [
1914
+ * // { id: 2, name: 'Jane' }
1915
+ * // }
1916
+ */
1917
+ const groupBy = (data, key) => {
1918
+ if (!data || !data.length || !Object.keys(get(data, '0')).length || !key) {
1919
+ return {};
1920
+ }
1921
+ return data.reduce((dir, nextItem) => {
1922
+ const valueOfKey = get(nextItem, key);
1923
+ if (typeof valueOfKey !== 'string' && typeof valueOfKey !== 'number' && typeof valueOfKey !== 'boolean') {
1924
+ return dir;
1925
+ }
1926
+ if (!Object.keys(dir).includes(`${valueOfKey}`)) {
1927
+ dir[`${valueOfKey}`] = [];
1928
+ }
1929
+ dir[`${valueOfKey}`].push(nextItem);
1930
+ return dir;
1931
+ }, {});
1932
+ };
1933
+ /**
1934
+ * Tạo một mảng các số từ giá trị bắt đầu đến giá trị kết thúc với bước nhảy tùy chọn
1935
+ * @param start Giá trị bắt đầu của dãy số. Nếu chỉ có một tham số, đây sẽ là giá trị kết thúc và giá trị bắt đầu sẽ là 0
1936
+ * @param end Giá trị kết thúc của dãy số (tùy chọn)
1937
+ * @param step Bước nhảy giữa các số trong dãy (tùy chọn). Mặc định là 1 nếu end > start, -1 nếu end < start
1938
+ * @returns Mảng các số từ start đến end với bước nhảy step
1939
+ * @example
1940
+ * range(4); // [0, 1, 2, 3]
1941
+ * range(1, 5); // [1, 2, 3, 4]
1942
+ * range(0, 20, 5); // [0, 5, 10, 15]
1943
+ * range(5, 2); // [5, 4, 3]
1944
+ */
1945
+ const range = (start, end, step) => {
1946
+ if (end === undefined || end === null) {
1947
+ end = start;
1948
+ start = 0;
1949
+ }
1950
+ if (!step) {
1951
+ step = end < 0 ? -1 : 1;
1952
+ }
1953
+ if (end < start && step > 0) {
1954
+ step *= -1;
1955
+ }
1956
+ const valueStartByStep = step + start;
1957
+ const direction = start < end ? 'asc' : 'desc';
1958
+ if ((direction === 'asc' && (valueStartByStep < start || valueStartByStep > end)) || (direction === 'desc' && (valueStartByStep > start || valueStartByStep < end))) {
1959
+ return [start];
1960
+ }
1961
+ const arr = new Array();
1962
+ for (let index = 0; index < Math.abs(end - start); index++) {
1963
+ let value = start + index * step;
1964
+ if (index === 0) {
1965
+ value = start;
1966
+ }
1967
+ if ((direction === 'asc' && (value < start || value > end)) || (direction === 'desc' && (value > start || value < end))) {
1968
+ return arr;
1969
+ }
1970
+ arr.push(value);
1971
+ }
1972
+ return arr;
1973
+ };
1974
+ /**
1975
+ * So sánh hai giá trị bất kỳ có bằng nhau hay không
1976
+ * @param value1 Giá trị thứ nhất cần so sánh
1977
+ * @param value2 Giá trị thứ hai cần so sánh
1978
+ * @param exactlyPosition Có so sánh chính xác vị trí các phần tử trong mảng hay không
1979
+ * @returns true nếu hai giá trị bằng nhau, false nếu không bằng nhau
1980
+ * @example
1981
+ * isEqual([1,2,3], [1,2,3]); // true
1982
+ * isEqual([1,2,3], [3,2,1]); // true khi exactlyPosition = false
1983
+ * isEqual([1,2,3], [3,2,1]); // false khi exactlyPosition = true
1984
+ * isEqual({a:1}, {a:1}); // true
1985
+ */
1986
+ const isEqual = (value1, value2, options) => {
1987
+ const { exactlyPosition = false, ignoreExactlyDataType = false } = options || {};
1988
+ if (value1 === value2 || (value1 === null && value2 === null) || (value1 === undefined && value2 === undefined)) {
1989
+ return true;
1990
+ }
1991
+ if (ignoreExactlyDataType) {
1992
+ return isEqual(isNil(value1) ? undefined : `${value1}`, isNil(value2) ? undefined : `${value2}`);
1993
+ }
1994
+ // Handle signals
1995
+ while (isSignal(value1)) {
1996
+ value1 = value1();
1997
+ }
1998
+ while (isSignal(value2)) {
1999
+ value2 = value2();
2000
+ }
2001
+ if (typeof value1 !== 'object' || typeof value2 !== 'object' || (Array.isArray(value1) && !Array.isArray(value2)) || (!Array.isArray(value1) && Array.isArray(value2))) {
2002
+ return false;
2003
+ }
2004
+ if (Array.isArray(value1)) {
2005
+ if (value1.length !== value2.length) {
2006
+ return false;
2007
+ }
2008
+ if (!exactlyPosition) {
2009
+ return !value1.some((item) => !value2.includes(item));
2010
+ }
2011
+ return !value1.some((item, index) => !isEqual(item, value2[index], options));
2012
+ }
2013
+ if (Object.keys(value1).length !== Object.keys(value2).length) {
2014
+ return false;
2015
+ }
2016
+ return !Object.keys(value1).some((key) => !isEqual(value1[key], value2[key], options));
2017
+ };
2018
+ /**
2019
+ * Loại bỏ các phần tử trùng lặp trong mảng dựa trên một thuộc tính chỉ định
2020
+ * @param data Mảng dữ liệu cần xử lý
2021
+ * @param key Tên thuộc tính dùng để so sánh trùng lặp. Nếu không có key thì so sánh trực tiếp giá trị
2022
+ * @returns Mảng mới chứa các phần tử không trùng lặp
2023
+ * @example
2024
+ * const arr = [
2025
+ * { id: 1, name: 'A' },
2026
+ * { id: 2, name: 'B' },
2027
+ * { id: 1, name: 'C' }
2028
+ * ];
2029
+ * uniqBy(arr, 'id'); // [{ id: 1, name: 'A' }, { id: 2, name: 'B' }]
2030
+ *
2031
+ * const numbers = [1, 2, 2, 3, 3];
2032
+ * uniqBy(numbers); // [1, 2, 3]
2033
+ *
2034
+ * const numbersSignal = [signal(1), signal(2), signal(3), signal(2), signal(5), signal(4), signal(1), signal(6), signal(7), signal(6)];
2035
+ * uniqBy(numbersSignal); // [signal(1), signal(2), signal(3), signal(5), signal(4), signal(6), signal(7)]
2036
+ */
2037
+ const uniqBy = (data, key) => {
2038
+ if (!key || !data?.length || typeof get(data, '0') !== 'object') {
2039
+ // Xử lý mảng chứa signal values
2040
+ if (data[0] && isSignal(data[0])) {
2041
+ const seen = new Set();
2042
+ return data.filter((item) => {
2043
+ const value = `${get(item, '')}`;
2044
+ if (seen.has(value)) {
2045
+ return false;
2046
+ }
2047
+ seen.add(value);
2048
+ return true;
2049
+ });
2050
+ }
2051
+ // Xử lý mảng primitive values
2052
+ return Array.from(new Set(data));
2053
+ }
2054
+ const dataUnique = keyBy(data, key);
2055
+ return Object.keys(dataUnique).map((key) => dataUnique[key]);
2056
+ };
2057
+ const generateInterface = (obj, interfaceName) => {
2058
+ const generateType = (value) => {
2059
+ if (value === null) {
2060
+ return 'null';
2061
+ }
2062
+ const type = typeof value;
2063
+ if (type === 'string') {
2064
+ return 'string';
2065
+ }
2066
+ if (type === 'number') {
2067
+ return 'number';
2068
+ }
2069
+ if (type === 'boolean') {
2070
+ return 'boolean';
2071
+ }
2072
+ if (type === 'undefined') {
2073
+ return 'any';
2074
+ }
2075
+ if (value instanceof Date) {
2076
+ return 'Date';
2077
+ }
2078
+ if (value instanceof RegExp) {
2079
+ return 'RegExp';
2080
+ }
2081
+ if (Array.isArray(value)) {
2082
+ if (value.length === 0) {
2083
+ return 'Array<any>';
2084
+ }
2085
+ return `Array<${generateType(value[0])}>`;
2086
+ }
2087
+ if (type === 'object') {
2088
+ let interfaceStr = '{\n';
2089
+ for (const key in value) {
2090
+ if (Object.prototype.hasOwnProperty.call(value, key)) {
2091
+ const valueType = generateType(value[key]);
2092
+ interfaceStr += ` ${key}: ${valueType};\n`;
2093
+ }
2094
+ }
2095
+ interfaceStr += '}';
2096
+ return interfaceStr;
2097
+ }
2098
+ return 'any';
2099
+ };
2100
+ const interfaceStr = `interface ${interfaceName} ${generateType(obj)}`;
2101
+ return interfaceStr;
2102
+ };
2103
+
2104
+ ;
2105
+ const step = 20;
2106
+ const percent = 0.05;
2107
+ const colorStepContrastFromOrigin = (color, stepNumber) => {
2108
+ return colorContrastFromOrigin(color).find(item => item.step === stepNumber);
2109
+ };
2110
+ const colorContrastFromOrigin = (color) => {
2111
+ const parsedColorsArray = parseColorValues(color);
2112
+ const colors = [];
2113
+ let calculatedShades = [];
2114
+ let calculatedTints = [];
2115
+ if (parsedColorsArray !== null) {
2116
+ for (let i = 0; i < parsedColorsArray.length; i++) {
2117
+ calculatedShades = calculateShades(parsedColorsArray[i]);
2118
+ calculatedTints = calculateTints(parsedColorsArray[i]);
2119
+ }
2120
+ for (let i = 0; i <= step; i++) {
2121
+ colors.push({ step: i * 5, label: `${i * 5}%`, dark: `#${calculatedShades[i]}`, light: `#${calculatedTints[i]}` });
2122
+ }
2123
+ }
2124
+ return colors;
2125
+ };
2126
+ const parseColorValues = (colorValues) => {
2127
+ let colorValuesArray = colorValues.match(/\b[0-9A-Fa-f]{3}\b|[0-9A-Fa-f]{6}\b/g);
2128
+ if (colorValuesArray) {
2129
+ colorValuesArray = colorValuesArray.map((item) => {
2130
+ if (item.length === 3) {
2131
+ let newItem = item.toString().split('');
2132
+ newItem = newItem.reduce((acc, it) => {
2133
+ return acc + it + it;
2134
+ }, '');
2135
+ return newItem;
2136
+ }
2137
+ return item;
2138
+ });
2139
+ }
2140
+ return colorValuesArray;
2141
+ };
2142
+ const calculateShades = (colorValue) => {
2143
+ return calculate(colorValue, rgbShade).concat("000000");
2144
+ };
2145
+ const calculateTints = (colorValue) => {
2146
+ return calculate(colorValue, rgbTint).concat("ffffff");
2147
+ };
2148
+ const calculate = (colorValue, shadeOrTint) => {
2149
+ const color = hexToRGB(colorValue);
2150
+ const shadeValues = [];
2151
+ for (let i = 0; i < step; i++) {
2152
+ shadeValues[i] = rgbToHex(shadeOrTint(color, i));
2153
+ }
2154
+ return shadeValues;
2155
+ };
2156
+ const rgbShade = (rgb, i) => { return { red: rgb.red * (1 - percent * i), green: rgb.green * (1 - percent * i), blue: rgb.blue * (1 - percent * i) }; };
2157
+ const rgbTint = (rgb, i) => { return { red: rgb.red + (255 - rgb.red) * i * percent, green: rgb.green + (255 - rgb.green) * i * percent, blue: rgb.blue + (255 - rgb.blue) * i * percent }; };
2158
+ const rgbToHex = (rgb) => { return intToHex(rgb.red) + intToHex(rgb.green) + intToHex(rgb.blue); };
2159
+ const hexToRGB = (colorValue) => { return { red: parseInt(colorValue.substr(0, 2), 16), green: parseInt(colorValue.substr(2, 2), 16), blue: parseInt(colorValue.substr(4, 2), 16) }; };
2160
+ const intToHex = (rgbint) => { return pad(Math.min(Math.max(Math.round(rgbint), 0), 255).toString(16), 2); };
2161
+ const pad = (number, length) => {
2162
+ let str = '' + number;
2163
+ while (str.length < length) {
2164
+ str = '0' + str;
2165
+ }
2166
+ return str;
2167
+ };
2168
+ const listColorDefine = ['#E62222', '#B81B1B', '#EB4E4E', '#F97316', '#C75C12', '#FA8F45', '#FFB700', '#CC9200', '#FFC533', '#84CC16', '#6AA312', '#9dd645', '#00BC62', '#00A757', '#33DA8A', '#06B6D4', '#1B59C4', '#4E8CF7', '#0EA5E9',
2169
+ '#1B59C4', '#4E8CF7', '#226FF5', '#1B59C4', '#4E8CF7', '#6366F1', '#4F52C1', '#8285F4', '#5B04B3', '#49038F', '#7C36C2', '#D946EF', '#AE38BF', '#E16BF2', '#EC4899', '#BD3A7A', '#F06DAD', '#F43F5E', '#C3324B', '#F6657E', '#757380', '#5E5C66', '#918F99',
2170
+ '#202020', '#1A1A1A', '#4D4D4D'
2171
+ ];
2172
+ const getColorById = (str) => {
2173
+ let hashString = 0;
2174
+ if (!str) {
2175
+ return '';
2176
+ }
2177
+ for (let i = 0; i < str.length; i++) {
2178
+ const char = str.charCodeAt(i);
2179
+ hashString = ((hashString << 5) - hashString) + char;
2180
+ hashString = hashString & hashString;
2181
+ }
2182
+ return listColorDefine[Math.abs(hashString) % listColorDefine.length];
2183
+ };
2184
+
2185
+ class UtilsKeyCodeConstant {
2186
+ static MAC_ENTER = 3;
2187
+ static BACKSPACE = 8;
2188
+ static TAB = 9;
2189
+ static NUM_CENTER = 12;
2190
+ static ENTER = 13;
2191
+ static SHIFT = 16;
2192
+ static CONTROL = 17;
2193
+ static ALT = 18;
2194
+ static PAUSE = 19;
2195
+ static CAPS_LOCK = 20;
2196
+ static ESCAPE = 27;
2197
+ static SPACE = 32;
2198
+ static PAGE_UP = 33;
2199
+ static PAGE_DOWN = 34;
2200
+ static END = 35;
2201
+ static HOME = 36;
2202
+ static LEFT_ARROW = 37;
2203
+ static UP_ARROW = 38;
2204
+ static RIGHT_ARROW = 39;
2205
+ static DOWN_ARROW = 40;
2206
+ static PLUS_SIGN = 43;
2207
+ static PRINT_SCREEN = 44;
2208
+ static INSERT = 45;
2209
+ static DELETE = 46;
2210
+ static ZERO = 48;
2211
+ static ONE = 49;
2212
+ static TWO = 50;
2213
+ static THREE = 51;
2214
+ static FOUR = 52;
2215
+ static FIVE = 53;
2216
+ static SIX = 54;
2217
+ static SEVEN = 55;
2218
+ static EIGHT = 56;
2219
+ static NINE = 57;
2220
+ static FF_SEMICOLON = 59; // Firefox (Gecko) fires this for semicolon instead of 186
2221
+ static FF_EQUALS = 61; // Firefox (Gecko) fires this for equals instead of 187
2222
+ static QUESTION_MARK = 63;
2223
+ static AT_SIGN = 64;
2224
+ static A = 65;
2225
+ static B = 66;
2226
+ static C = 67;
2227
+ static D = 68;
2228
+ static E = 69;
2229
+ static F = 70;
2230
+ static G = 71;
2231
+ static H = 72;
2232
+ static I = 73;
2233
+ static J = 74;
2234
+ static K = 75;
2235
+ static L = 76;
2236
+ static M = 77;
2237
+ static N = 78;
2238
+ static O = 79;
2239
+ static P = 80;
2240
+ static Q = 81;
2241
+ static R = 82;
2242
+ static S = 83;
2243
+ static T = 84;
2244
+ static U = 85;
2245
+ static V = 86;
2246
+ static W = 87;
2247
+ static X = 88;
2248
+ static Y = 89;
2249
+ static Z = 90;
2250
+ static META = 91; // WIN_KEY_LEFT
2251
+ static MAC_WK_CMD_LEFT = 91;
2252
+ static MAC_WK_CMD_RIGHT = 93;
2253
+ static CONTEXT_MENU = 93;
2254
+ static NUMPAD_ZERO = 96;
2255
+ static NUMPAD_ONE = 97;
2256
+ static NUMPAD_TWO = 98;
2257
+ static NUMPAD_THREE = 99;
2258
+ static NUMPAD_FOUR = 100;
2259
+ static NUMPAD_FIVE = 101;
2260
+ static NUMPAD_SIX = 102;
2261
+ static NUMPAD_SEVEN = 103;
2262
+ static NUMPAD_EIGHT = 104;
2263
+ static NUMPAD_NINE = 105;
2264
+ static NUMPAD_MULTIPLY = 106;
2265
+ static NUMPAD_PLUS = 107;
2266
+ static NUMPAD_MINUS = 109;
2267
+ static NUMPAD_PERIOD = 110;
2268
+ static NUMPAD_DIVIDE = 111;
2269
+ static F1 = 112;
2270
+ static F2 = 113;
2271
+ static F3 = 114;
2272
+ static F4 = 115;
2273
+ static F5 = 116;
2274
+ static F6 = 117;
2275
+ static F7 = 118;
2276
+ static F8 = 119;
2277
+ static F9 = 120;
2278
+ static F10 = 121;
2279
+ static F11 = 122;
2280
+ static F12 = 123;
2281
+ static NUM_LOCK = 144;
2282
+ static SCROLL_LOCK = 145;
2283
+ static FIRST_MEDIA = 166;
2284
+ static FF_MINUS = 173;
2285
+ static MUTE = 173; // Firefox (Gecko) fires 181 for MUTE
2286
+ static VOLUME_DOWN = 174; // Firefox (Gecko) fires 182 for VOLUME_DOWN
2287
+ static VOLUME_UP = 175; // Firefox (Gecko) fires 183 for VOLUME_UP
2288
+ static FF_MUTE = 181;
2289
+ static FF_VOLUME_DOWN = 182;
2290
+ static LAST_MEDIA = 183;
2291
+ static FF_VOLUME_UP = 183;
2292
+ static SEMICOLON = 186; // Firefox (Gecko) fires 59 for SEMICOLON
2293
+ static EQUALS = 187; // Firefox (Gecko) fires 61 for EQUALS
2294
+ static COMMA = 188;
2295
+ static DASH = 189; // Firefox (Gecko) fires 173 for DASH/MINUS
2296
+ static PERIOD = 190;
2297
+ static SLASH = 191;
2298
+ static APOSTROPHE = 192;
2299
+ static TILDE = 192;
2300
+ static OPEN_SQUARE_BRACKET = 219;
2301
+ static BACKSLASH = 220;
2302
+ static CLOSE_SQUARE_BRACKET = 221;
2303
+ static SINGLE_QUOTE = 222;
2304
+ static MAC_META = 224;
2305
+ }
2306
+
2307
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2308
+ const getKeyCacheByArrayObject = (keyCache, argumentsValue) => {
2309
+ if (!keyCache || !argumentsValue) {
2310
+ return '';
2311
+ }
2312
+ let keyBuild = `${JSON.stringify(argumentsValue.slice(1))}-key-cache-plus`;
2313
+ argumentsValue.forEach((item) => {
2314
+ if (typeof item === 'object') {
2315
+ if (Array.isArray(item)) {
2316
+ keyBuild = `${keyBuild}${JSON.stringify(item)}`;
1311
2317
  return;
1312
2318
  }
1313
- if (key === UtilsCache.languageKeyCache) {
1314
- return UtilsCache.setLang(value);
1315
- }
1316
- UtilsCache.Set(key, value, UtilsCache.CACHE_EXPIRE_NONE);
1317
- });
1318
- }
1319
- static DeleteKeyStartWithAsync(keyCacheStartWith, isKeyMD5 = false) {
1320
- return new Promise(async (resolve) => {
1321
- const objectStore = await UtilsCache.getObjectStore();
1322
- if (!objectStore) {
1323
- return resolve({});
1324
- }
1325
- const index = objectStore.index(UtilsCache.itemIndexByKey);
1326
- // Lấy tất cả các keys từ index
1327
- const request = index.getAll();
1328
- keyCacheStartWith = isKeyMD5 ? keyCacheStartWith : md5(keyCacheStartWith);
1329
- request.onsuccess = (e) => {
1330
- const data = e.target.result;
1331
- if (!Array.isArray(data)) {
1332
- return resolve({});
2319
+ const keys = (item instanceof HttpParams ? item.keys() : Object.keys(item)).sort(((str1, str2) => str1.localeCompare(str2)));
2320
+ keys.forEach(key => {
2321
+ if (key.toLocaleLowerCase() === 'pem') {
2322
+ return;
1333
2323
  }
1334
- data.forEach(obj => {
1335
- if (obj.key.startsWith(keyCacheStartWith)) {
1336
- UtilsCache.ClearAsync(obj.key, true);
1337
- }
1338
- });
1339
- return resolve({});
1340
- };
1341
- request.onerror = () => {
1342
- return resolve({});
1343
- };
1344
- });
1345
- }
1346
- static DeleteKeyStartWith(keyCache, isMD5 = false) {
1347
- keyCache = isMD5 ? md5(keyCache) : keyCache;
1348
- const keys = Object.keys(UtilsCache.LocalStorage);
1349
- if (!keys || !keys.length) {
2324
+ keyBuild = `${keyBuild}${JSON.stringify(get(item, key))}`;
2325
+ });
1350
2326
  return;
1351
2327
  }
1352
- keys.forEach(key => {
1353
- if (key.startsWith(keyCache)) {
1354
- this.Clear(key);
1355
- }
1356
- });
1357
- }
1358
- }
2328
+ keyBuild = `${keyBuild}${item}`;
2329
+ });
2330
+ const keyCachePlus = md5(keyBuild);
2331
+ const keyCacheMD5 = md5(keyCache);
2332
+ return `${keyCacheMD5}-${md5(`${keyCacheMD5}-${keyCachePlus}`)}`;
2333
+ };
1359
2334
 
1360
2335
  const formatNumber = (value) => {
1361
2336
  const lang = UtilsCache.getLang();
@@ -1417,138 +2392,521 @@ const viewDataNumberByLanguage = (value, acceptNegativeValue, parseFixed = 1, ig
1417
2392
  }
1418
2393
  };
1419
2394
 
1420
- const emojiPattern = () => {
1421
- return /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g;
2395
+ let functionXssFilter = async (value) => {
2396
+ return value;
1422
2397
  };
1423
- const removeEmoji = (text) => {
1424
- if (!text || !text.trim()) {
1425
- return text;
1426
- }
1427
- return text.replace(emojiPattern(), '');
2398
+ const updateFunctionXssFilter = (functionCustom) => {
2399
+ functionXssFilter = functionCustom;
2400
+ };
2401
+ const xssFilter = async (data) => {
2402
+ return await functionXssFilter(data);
1428
2403
  };
1429
2404
 
1430
- const escapeHtml = (data) => {
1431
- if (!data || typeof data !== 'string') {
2405
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2406
+ /**
2407
+ * Chuyển đổi một đối tượng hoặc giá trị thành signal
2408
+ * @param data Dữ liệu cần chuyển đổi thành signal
2409
+ * @param cloneDeepIfNotSignal Có thực hiện sao chép sâu dữ liệu trước khi chuyển đổi hay không nếu data không phải signal. Mặc định là true.
2410
+ * Đặt false nếu muốn giữ nguyên tham chiếu đến dữ liệu gốc.
2411
+ * Nếu muốn sao chép sâu đối tượng signal thì đặt cloneDeepIfNotSignal là true và acceptConvertObjectInnerWritableSignal là true.
2412
+ * @param isSignalPrimitiveType Có chuyển đổi các giá trị nguyên thủy (string, number, boolean) thành signal hay không. Mặc định là false.
2413
+ * Đặt true nếu muốn bọc các giá trị nguyên thủy trong signal.
2414
+ * @param acceptConvertObjectInnerWritableSignal Có tiếp tục tìm kiếm và chuyển đổi các đối tượng bên trong signal hay không. Mặc định là false.
2415
+ * Đặt true nếu muốn tìm và chuyển đổi các đối tượng bên trong signal hoặc chính nó thành signal mới.
2416
+ * @returns Dữ liệu đã được chuyển đổi theo kiểu T
2417
+ */
2418
+ const convertObjectToSignal = (data, cloneDeepIfNotSignal = true, isSignalPrimitiveType = false, acceptConvertObjectInnerWritableSignal = false, seen = new WeakMap()) => {
2419
+ if ((data === null || typeof data !== 'object') && !isSignal(data)) {
2420
+ return (isSignalPrimitiveType ? signal(data) : data);
2421
+ }
2422
+ if (seen.has(data)) {
2423
+ return seen.get(data);
2424
+ }
2425
+ if (isSignal(data)) {
2426
+ if (!acceptConvertObjectInnerWritableSignal) {
2427
+ return data;
2428
+ }
2429
+ seen.set(data, convertObjectToSignal(data(), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen));
2430
+ return seen.get(data);
2431
+ }
2432
+ if (Array.isArray(data)) {
2433
+ seen.set(data, signal(data.map(item => convertObjectToSignal(item, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal, seen))));
2434
+ return seen.get(data);
2435
+ }
2436
+ if (data instanceof Map) {
2437
+ const mapCopy = new Map();
2438
+ Array.from(data.keys()).forEach(key => {
2439
+ mapCopy.set(key, convertObjectToSignal(data.get(key), cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal));
2440
+ });
2441
+ seen.set(data, signal(mapCopy));
2442
+ return seen.get(data);
2443
+ }
2444
+ if (data instanceof Promise || data instanceof Observable) {
1432
2445
  return data;
1433
2446
  }
1434
- return data
1435
- .replace(/&/g, "&amp;")
1436
- .replace(/</g, "&lt;")
1437
- .replace(/>/g, "&gt;")
1438
- .replace(/"/g, "&quot;")
1439
- .replace(/'/g, "&#039;");
1440
- };
1441
-
1442
- const deleteUnicode = (str) => {
1443
- str = str.replace(/à|á|ạ|ả|ã|â|ầ|ấ|ậ|ẩ|ẫ|ă|ằ|ắ|ặ|ẳ|ẵ/g, 'a');
1444
- str = str.replace(/è|é|ẹ|ẻ|ẽ|ê|ề|ế|ệ|ể|ễ|ễ/g, 'e');
1445
- str = str.replace(/ì|í|ị|ỉ|ĩ/g, 'i');
1446
- str = str.replace(/ò|ó|ọ|ỏ|õ|ô|ồ|ố|ộ|ổ|ỗ|ơ|ờ|ớ|ợ|ở|ỡ/g, 'o');
1447
- str = str.replace(/ù|ú|ụ|ủ|ũ|ư|ừ|ứ|ự|ử|ữ/g, 'u');
1448
- str = str.replace(/ỳ|ý|ỵ|ỷ|ỹ/g, 'y');
1449
- str = str.replace(/đ/g, 'd');
1450
- str = str.replace(/À|Á|Ạ|Ả|Ã|Â|Ầ|Ấ|Ậ|Ẩ|Ẫ|Ă|Ằ|Ắ|Ặ|Ẳ|Ẵ/g, 'A');
1451
- str = str.replace(/È|É|Ẹ|Ẻ|Ẽ|Ê|Ề|Ế|Ệ|Ể|Ễ/g, 'E');
1452
- str = str.replace(/Ì|Í|Ị|Ỉ|Ĩ/g, 'I');
1453
- str = str.replace(/Ò|Ó|Ọ|Ỏ|Õ|Ô|Ồ|Ố|Ộ|Ổ|Ỗ|Ơ|Ờ|Ớ|Ợ|Ở|Ỡ/g, 'O');
1454
- str = str.replace(/Ù|Ú|Ụ|Ủ|Ũ|Ư|Ừ|Ứ|Ự|Ử|Ữ/g, 'U');
1455
- str = str.replace(/Ỳ|Ý|Ỵ|Ỷ|Ỹ/g, 'Y');
1456
- str = str.replace(/Đ/g, 'D');
1457
- str = str.replace(/\u0300|\u0301|\u0303|\u0309|\u0323/g, ""); // ̀ ́ ̃ ̉ ̣ huyền, sắc, ngã, hỏi, nặng
1458
- str = str.replace(/\u02C6|\u0306|\u031B/g, ""); // ˆ ̆ ̛ Â, Ê, Ă, Ơ, Ư
1459
- return str.normalize();
2447
+ data = signal(cloneDeepIfNotSignal ? { ...data } : data);
2448
+ seen.set(data, data);
2449
+ for (const key in data()) {
2450
+ const value = data()[key];
2451
+ if (value instanceof TemplateRef || value instanceof File || value instanceof Blob || Object.prototype.toString.call(value) === '[object File]' || value instanceof ElementRef || value instanceof Element || value instanceof Date || value instanceof RegExp || value instanceof Set || value instanceof Map || value instanceof Promise || value instanceof Observable || value instanceof HttpParams) {
2452
+ continue;
2453
+ }
2454
+ if (Object.prototype.hasOwnProperty.call(data(), key)) {
2455
+ data()[key] = convertObjectToSignal(value, cloneDeepIfNotSignal, isSignalPrimitiveType, acceptConvertObjectInnerWritableSignal);
2456
+ }
2457
+ }
2458
+ return data;
1460
2459
  };
1461
-
1462
- const listColorDefine = ['#E62222', '#B81B1B', '#EB4E4E', '#F97316', '#C75C12', '#FA8F45', '#FFB700', '#CC9200', '#FFC533', '#84CC16', '#6AA312', '#9dd645', '#00BC62', '#00A757', '#33DA8A', '#06B6D4', '#1B59C4', '#4E8CF7', '#0EA5E9',
1463
- '#1B59C4', '#4E8CF7', '#226FF5', '#1B59C4', '#4E8CF7', '#6366F1', '#4F52C1', '#8285F4', '#5B04B3', '#49038F', '#7C36C2', '#D946EF', '#AE38BF', '#E16BF2', '#EC4899', '#BD3A7A', '#F06DAD', '#F43F5E', '#C3324B', '#F6657E', '#757380', '#5E5C66', '#918F99',
1464
- '#202020', '#1A1A1A', '#4D4D4D'
1465
- ];
1466
- const getColorById = (str) => {
1467
- let hashString = 0;
1468
- if (!str) {
1469
- return '';
2460
+ const convertSignalToObject = (data, isCloneDeep = true, seen = new WeakMap()) => {
2461
+ let ignoreCheckSeenHasDataAfterWhile = false;
2462
+ while (isSignal(data) && !seen.has(data)) {
2463
+ const dataConvert = data();
2464
+ if (typeof dataConvert === 'object') {
2465
+ if (dataConvert === null) {
2466
+ return dataConvert;
2467
+ }
2468
+ seen.set(dataConvert, dataConvert);
2469
+ data = dataConvert;
2470
+ ignoreCheckSeenHasDataAfterWhile = true;
2471
+ break;
2472
+ }
2473
+ seen.set(data, dataConvert);
2474
+ data = dataConvert;
1470
2475
  }
1471
- for (let i = 0; i < str.length; i++) {
1472
- const char = str.charCodeAt(i);
1473
- hashString = ((hashString << 5) - hashString) + char;
1474
- hashString = hashString & hashString;
2476
+ if (data === null || typeof data === 'function' || typeof data !== 'object') {
2477
+ return data;
1475
2478
  }
1476
- return listColorDefine[Math.abs(hashString) % listColorDefine.length];
2479
+ if (!ignoreCheckSeenHasDataAfterWhile && seen.has(data)) {
2480
+ return seen.get(data);
2481
+ }
2482
+ if (Array.isArray(data)) {
2483
+ if (!isSignal(data[0])) {
2484
+ return data;
2485
+ }
2486
+ seen.set(data, data.map(item => convertSignalToObject((isCloneDeep ? cloneDeep(item) : item), isCloneDeep, seen)));
2487
+ return seen.get(data);
2488
+ }
2489
+ if (data instanceof Map) {
2490
+ const mapCopy = new Map();
2491
+ Array.from(data.keys()).forEach(key => {
2492
+ mapCopy.set(key, convertSignalToObject(isCloneDeep ? cloneDeep(data.get(key)) : data.get(key), isCloneDeep));
2493
+ });
2494
+ seen.set(data, mapCopy);
2495
+ return seen.get(data);
2496
+ }
2497
+ if (data instanceof File || data instanceof Blob || Object.prototype.toString.call(data) === '[object File]') {
2498
+ return data;
2499
+ }
2500
+ if (data instanceof TemplateRef || data instanceof ElementRef || data instanceof Element || data instanceof Promise || data instanceof Observable || data instanceof HttpParams) {
2501
+ return data;
2502
+ }
2503
+ const result = isCloneDeep ? {} : data;
2504
+ seen.set(data, result);
2505
+ for (const key in data) {
2506
+ const value = data[key];
2507
+ if (Object.prototype.hasOwnProperty.call(data, key)) {
2508
+ result[key] = convertSignalToObject(isCloneDeep ? cloneDeep(value) : value, isCloneDeep);
2509
+ }
2510
+ }
2511
+ return result;
1477
2512
  };
1478
2513
 
1479
- const ERROR_MESSAGE_EMPTY_VALID = 'i18n_valid_empty_message';
1480
- const ERROR_MESSAGE_PATTEN_VALID = 'i18n_valid_pattern_message';
1481
- const ERROR_MESSAGE_MIN_VALID = 'i18n_message_error_input_min_value';
1482
- const ERROR_MESSAGE_MAX_VALID = 'i18n_message_error_input_max_value';
1483
- const ERROR_MESSAGE_MIN_LENGTH = 'i18n_message_error_input_min_length';
1484
- const ERROR_MESSAGE_MAX_LENGTH = 'i18n_message_error_input_max_length';
1485
- const CHARACTER_DATA_EMPTY = '__';
1486
-
1487
- /* eslint-disable no-useless-escape */
1488
- const PATTERN_EMAIL = () => {
1489
- return /^[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]@[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]\.[A-z0-9]+[A-z0-9\_\.\+\-]*[A-z0-9]$/;
1490
- };
1491
- const PATTERN_URL = () => {
1492
- return /^(http|https|ftp):(\/){2}[^\s]+[.]{1}[^\s]+$/;
1493
- };
1494
- const PATTERN_HOST_URL = () => {
1495
- return /^((https|http|ftp):[/]{2}[^/\s]+)/;
1496
- };
1497
- const PATTERN_DOMAIN = () => {
1498
- return /^([a-zA-Z0-9])(([a-z0-9-]{1,61})?[a-z0-9]{1})?(\.[a-z0-9](([a-z0-9-]{1,61})?[a-z0-9]{1})?)?(\.[a-zA-Z]{2,4})+$/;
1499
- };
1500
- const PATTERN_MOBILE_PHONE = () => {
1501
- return /^(\+?84|0|84)([0-9]{9})$/;
1502
- };
1503
- const PATTERN_PHONE = () => {
1504
- return /^(\+?84|[0-9]|84)([0-9]{2,9})$/;
1505
- };
1506
- const PATTERN_PHONE_NORMAL = () => {
1507
- return /^(\+?84|[0-9]|84)([0-9]{9,10})$/;
1508
- };
1509
- const PATTERN_NUMBER = () => {
1510
- return /\d+/g;
2514
+ const ENCODE_URI_PATTERN = /%([0-9A-F]{2})/g;
2515
+ const decodeURI = (value) => {
2516
+ return decodeURIComponent(value.split('').map((c) => {
2517
+ return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
2518
+ }).join(''));
2519
+ };
2520
+ const encodeURI = (value) => {
2521
+ return encodeURIComponent(value).replace(ENCODE_URI_PATTERN, (match, p1) => {
2522
+ return String.fromCharCode(parseInt(p1, 16));
2523
+ });
1511
2524
  };
1512
- const PATTERN_ENCODE_URI = () => {
1513
- return /%([0-9A-F]{2})/g;
2525
+ const endCodeUrl = (params, isBody) => {
2526
+ params = omitBy(params, param => param === '' || isNil(param));
2527
+ let res = '';
2528
+ for (const p in params) {
2529
+ res += `&${p}=${encodeURIComponent(params[p])}`;
2530
+ }
2531
+ return res === '' ? '' : `${isBody ? '' : '?'}${res.substring(1)}`;
1514
2532
  };
1515
- const PATTERN_NAME = () => {
1516
- return /^\w+[A-Za-z\s\d]+$/;
2533
+
2534
+ const base64Encode = (value) => {
2535
+ return btoa(encodeURI(value));
2536
+ };
2537
+ const base64Decode = (value) => {
2538
+ return decodeURI(atob(value));
2539
+ };
2540
+ const convertBase64ToBlob = (dataBase64) => {
2541
+ const BASE64_MARKER = ';base64,';
2542
+ if (dataBase64.indexOf(BASE64_MARKER) === -1) {
2543
+ const parts = dataBase64.split(',');
2544
+ const contentType = parts[0].split(':')[1];
2545
+ const raw = parts[1];
2546
+ const blob = new Blob([raw], { type: contentType });
2547
+ return blob;
2548
+ }
2549
+ const parts = dataBase64.split(BASE64_MARKER);
2550
+ const contentType = parts[0].split(':')[1];
2551
+ const raw = window.atob(parts[1]);
2552
+ const rawLength = raw.length;
2553
+ const uInt8Array = new Uint8Array(rawLength);
2554
+ for (let i = 0; i < rawLength; ++i) {
2555
+ uInt8Array[i] = raw.charCodeAt(i);
2556
+ }
2557
+ const blob = new Blob([uInt8Array], { type: contentType });
2558
+ return blob;
2559
+ };
2560
+ const convertFileToBase64_ObjectUrl = async (file) => {
2561
+ if (!file.type.match(/image.*/)) {
2562
+ return URL.createObjectURL(file);
2563
+ }
2564
+ return await convertFileToBase64(file);
2565
+ };
2566
+ const convertFileToBase64 = (file) => {
2567
+ return new Promise((resolve) => {
2568
+ const reader = new FileReader();
2569
+ reader.readAsDataURL(file);
2570
+ reader.onload = (event) => {
2571
+ resolve(event.target?.result ?? '');
2572
+ };
2573
+ });
1517
2574
  };
1518
- const PATTERN_NAME_UTF8 = () => {
1519
- return /^[ àáảãạăắằẵặẳâầấậẫẩđèéẻẽẹêềếểễệìíỉĩịòóỏõọôồốổỗộơờớởỡợùúủũụưừứửữựỳýỷỹÀÁẢÃẠĂẮẰẴẶẲÂẦẤẬẪẨĐÈÉẺẼẸÊỀẾỂỄỆÌÍỈĨỊÒÓỎÕỌÔỒỐỔỖỘƠỜỚỞỠỢÙÚỦŨỤƯỪỨỬỮỰỲÝỶỸA-Za-z0-9]+$/;
2575
+
2576
+ const downloadFileByUrlUseXmlRequest = (fileUrl, filename) => {
2577
+ const xmlRequest = new XMLHttpRequest();
2578
+ xmlRequest.open('GET', fileUrl, true);
2579
+ xmlRequest.responseType = 'blob';
2580
+ xmlRequest.onload = () => {
2581
+ const url = window.URL.createObjectURL(xmlRequest.response);
2582
+ downloadFileByUrl(url, filename);
2583
+ };
2584
+ xmlRequest.send();
2585
+ };
2586
+ const downloadFileByUrl = async (fileUrl, filename, onlyOpen) => {
2587
+ const downloadFileElement = document.createElement('a');
2588
+ if (!onlyOpen) {
2589
+ const response = await fetch(fileUrl);
2590
+ if (response.ok) {
2591
+ const blob = await response.blob();
2592
+ fileUrl = URL.createObjectURL(blob);
2593
+ }
2594
+ }
2595
+ downloadFileElement.href = fileUrl;
2596
+ downloadFileElement.download = filename;
2597
+ downloadFileElement.target = '_blank';
2598
+ downloadFileElement.click();
2599
+ downloadFileElement.remove();
2600
+ };
2601
+ const downloadImageFromELement = (imageElement, typeFileDownload, nameFile) => {
2602
+ const parentElement = imageElement?.src;
2603
+ const blobData = convertBase64ToBlob(parentElement);
2604
+ const blob = new Blob([blobData], { type: typeFileDownload || "image/png" });
2605
+ const url = window.URL.createObjectURL(blob);
2606
+ const link = document.createElement('a');
2607
+ link.href = url;
2608
+ link.download = nameFile || 'barcode';
2609
+ link.click();
1520
2610
  };
1521
- const PATTERN_NAME_SPECIAL = () => {
1522
- return /[~!@#$%^&*()-+=<>,?\/\\:;"']/;
2611
+
2612
+ const LINK_IMAGE_ERROR_TOKEN_INJECT = new InjectionToken('LINK_IMAGE_ERROR_TOKEN_INJECT');
2613
+ const PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT = new InjectionToken('PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT');
2614
+ const PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT = new InjectionToken('PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT');
2615
+
2616
+ const isTypeImage = (file) => file.type.match(/image.*/) ? true : false;
2617
+ const isTypeVideo = (file) => file.type.match(/video.*/) ? true : false;
2618
+ const isTypeAudio = (file) => file.type.match(/audio.*/) ? true : false;
2619
+ const isTypeFile = (file) => file instanceof File || Object.prototype.toString.call(file) === '[object File]' ? true : false;
2620
+ const ExcelExtList = ['xls', 'xlsx', 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'];
2621
+ const DocumentExtList = ['doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'pdf', 'json', 'xml', 'application/msword',
2622
+ 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
2623
+ 'application/vnd.ms-excel',
2624
+ 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
2625
+ 'application/vnd.ms-powerpoint',
2626
+ 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
2627
+ 'application/pdf',
2628
+ 'application/json',
2629
+ 'application/xml'];
2630
+ const isIncludeDocumentExtList = (ext, listExt = DocumentExtList) => listExt.includes(ext) || listExt.includes(`application/${ext}`);
2631
+ const ImageExtList = ['gif', 'jpg', 'jpeg', 'png', 'image/gif', 'image/jpeg', 'image/jpeg', 'image/png'];
2632
+ const isIncludeImageExtList = (ext, listExt = ImageExtList) => listExt.includes(ext);
2633
+ const VideoExtList = ['mp4', 'mov', 'mpg', 'avi', 'wmv', 'video/mp4', 'video/quicktime', 'video/mpeg', 'video/x-msvideo', 'video/x-ms-wmv'];
2634
+ const isIncludeVideoExtList = (ext, listExt = VideoExtList) => listExt.includes(ext);
2635
+ const AudioExtList = ['mp3', 'wav', 'ogg', 'aac', 'm4a', 'flac', 'wma', 'audio/mpeg', 'audio/wav', 'audio/ogg', 'audio/aac', 'audio/mp4', 'audio/flac', 'audio/x-ms-wma'];
2636
+ const isIncludeAudioExtList = (ext, listExt = AudioExtList) => listExt.includes(ext);
2637
+ const getFileExtension = (file) => {
2638
+ if (file instanceof File && file.type) {
2639
+ return (file.type.split('/').pop() || '').toLowerCase();
2640
+ }
2641
+ file = file;
2642
+ if (file.mimetype || file.file?.type) {
2643
+ return file.mimetype || file.file?.type;
2644
+ }
2645
+ let fileName = file.name;
2646
+ const url = get(file, 'url') || get(file, 'origin_url');
2647
+ if (!fileName && !url) {
2648
+ return;
2649
+ }
2650
+ if (!fileName && url) {
2651
+ fileName = url.split('/').pop() || '';
2652
+ set(file, 'name', fileName);
2653
+ }
2654
+ const dots = fileName.split(".");
2655
+ if (!dots) {
2656
+ return;
2657
+ }
2658
+ return (dots.pop() || '').toLowerCase();
1523
2659
  };
1524
- const PATTERN_NAME_PROFILE = () => {
1525
- return /([\w\W\d\s]+)+/;
2660
+ const getLabelBySizeFile = (size, toFixed = 2) => {
2661
+ if (size < 1024 * 1024) {
2662
+ return ` ${(size / 1024).toFixed(toFixed)} KB`;
2663
+ }
2664
+ return ` ${(size / (1024 * 1024)).toFixed(toFixed)} MB`;
1526
2665
  };
1527
- const PATTERN_EMOJI = () => {
1528
- return /(\u00a9|\u00ae|[\u2000-\u3300]|\ud83c[\ud000-\udfff]|\ud83d[\ud000-\udfff]|\ud83e[\ud000-\udfff])/g;
2666
+ const convertBlobToFile = (blob, fileName) => {
2667
+ const type = blob.type.split('/')[1];
2668
+ const name = fileName ? `${fileName.split('.')[0]}.${type}` : `${uuid()}.${type}`;
2669
+ return new File([blob], name, { type: blob.type, lastModified: Date.now() });
1529
2670
  };
1530
- const PATTERN_RULE_FIELD_REPLACE = () => {
1531
- return /[{]{2}[a-zA-Z_-]+[}]{2}/g;
2671
+ const convertUrlToFile = (url, fileName) => {
2672
+ return new Promise((resolve, reject) => {
2673
+ const xhr = new XMLHttpRequest();
2674
+ xhr.onload = function () {
2675
+ const reader = new FileReader();
2676
+ reader.onloadend = () => {
2677
+ const file = convertBase64ToBlob(reader.result);
2678
+ resolve(convertBlobToFile(file, fileName || Date.now().toLocaleString()));
2679
+ };
2680
+ reader.onerror = () => resolve(undefined);
2681
+ reader.readAsDataURL(xhr.response);
2682
+ };
2683
+ xhr.onerror = (err) => {
2684
+ reject(err);
2685
+ };
2686
+ xhr.open('GET', url);
2687
+ xhr.responseType = 'blob';
2688
+ xhr.send();
2689
+ });
1532
2690
  };
1533
- const PATTERN_GET_FIELD_BY_RULE_FIELD_REPLACE = () => {
1534
- return /[a-zA-Z_-]+/g;
2691
+
2692
+ const DEFAULT_MIN_TICK_COUNT = 5;
2693
+ const DEFAULT_MAX_TICK_COUNT = 10;
2694
+ const MIN_DISTANCE_TO_ZERO = 3;
2695
+ const NEGATIVE_THRESHOLD = -5;
2696
+ const FALLBACK_NEGATIVE_VALUE = -4;
2697
+ const MAX_POW_NUMBER = 14;
2698
+ const MAX_TEMPLATE_NUMBER = 10;
2699
+ /**
2700
+ * Tính toán smart axis scale cho biểu đồ
2701
+ *
2702
+ * @param maxData - Giá trị tối đa của dữ liệu
2703
+ * @param options - Các tùy chọn cấu hình axis scale
2704
+ * @returns Cấu hình axis scale bao gồm stepSize, max, min, tickAmount
2705
+ *
2706
+ * @throws {Error} INVALID_NEGATIVE_DATA - khi maxData < 0 mà acceptNegative = false
2707
+ * @throws {Error} MISSING_MIN_NEGATIVE - khi acceptNegative = true nhưng thiếu minNegative
2708
+ * @throws {Error} INVALID_RANGE - khi maxData < minNegative
2709
+ * @throws {Error} INVALID_MIN_NEGATIVE - khi minNegative >= 0
2710
+ *
2711
+ * @example
2712
+ * ```typescript
2713
+ * const result = getSmartAxisScale(100, { minTickCount: 5, maxTickCount: 10 });
2714
+ * // returns { stepSize: 20, max: 120, min: 0, tickAmount: 6 }
2715
+ * ```
2716
+ */
2717
+ const getSmartAxisScale = (originalMaxData, options) => {
2718
+ let maxData = originalMaxData;
2719
+ validateInputs(maxData, options);
2720
+ const minTickCount = options?.minTickCount || DEFAULT_MIN_TICK_COUNT;
2721
+ const maxTickCount = options?.maxTickCount || DEFAULT_MAX_TICK_COUNT;
2722
+ let scaleDirection = 1;
2723
+ let rangeDistance = maxData;
2724
+ if (options?.acceptNegative && !isNil(options.minNegative)) {
2725
+ if (maxData === 0) {
2726
+ maxData = -1;
2727
+ }
2728
+ if (maxData <= 0) {
2729
+ rangeDistance = options.minNegative;
2730
+ }
2731
+ if (rangeDistance > NEGATIVE_THRESHOLD) {
2732
+ rangeDistance = FALLBACK_NEGATIVE_VALUE;
2733
+ }
2734
+ if (maxData > 0) {
2735
+ rangeDistance = maxData + Math.abs(options.minNegative);
2736
+ scaleDirection = -1;
2737
+ }
2738
+ }
2739
+ if (Math.abs(rangeDistance) < MIN_DISTANCE_TO_ZERO) {
2740
+ rangeDistance = MIN_DISTANCE_TO_ZERO;
2741
+ }
2742
+ const stepCandidates = getStepCandidates(maxData, minTickCount, options?.minNegative || 0, options?.acceptStepIsTypeFloat, options?.stepCandidates, options?.acceptNegative);
2743
+ for (const step of stepCandidates) {
2744
+ let tickCount = Math.abs(Math.ceil(rangeDistance / step)) + (scaleDirection === -1 ? 2 : 1);
2745
+ let maxValue = maxData <= 0 ? 0 : step * tickCount * scaleDirection;
2746
+ let minValue = 0;
2747
+ if (tickCount >= minTickCount && tickCount <= maxTickCount) {
2748
+ if (maxData < maxValue) {
2749
+ if (options?.acceptNegative) {
2750
+ let tick = 1;
2751
+ while (!isNil(options.minNegative) && tick <= tickCount && minValue >= options.minNegative) {
2752
+ minValue = tick * step;
2753
+ tick++;
2754
+ }
2755
+ }
2756
+ const maxValuePositive = maxValue - Math.abs(minValue);
2757
+ tickCount = maxValuePositive - originalMaxData > Math.abs(step) && tickCount - 1 >= minTickCount ? tickCount - 1 : tickCount;
2758
+ maxValue = (step * tickCount * scaleDirection) - (minValue * scaleDirection);
2759
+ return {
2760
+ stepSize: Math.abs(step),
2761
+ max: maxValue,
2762
+ min: minValue,
2763
+ tickAmount: tickCount
2764
+ };
2765
+ }
2766
+ }
2767
+ }
2768
+ let step = Math.ceil(rangeDistance / minTickCount) || 1;
2769
+ let maxValue = step * minTickCount;
2770
+ if (rangeDistance === maxValue) {
2771
+ step = step + Math.ceil(step / 10);
2772
+ maxValue = step * minTickCount;
2773
+ }
2774
+ return {
2775
+ stepSize: Math.abs(step),
2776
+ max: maxValue,
2777
+ min: 0,
2778
+ tickAmount: minTickCount
2779
+ };
1535
2780
  };
1536
- const PATTERN_PEM = () => {
1537
- return /^(0|1):([0-9]{1,2}):(\{\{path-api\}\}):([a-zA-Z0-9\/]+)$/g;
2781
+ // Cache cho các giá trị lũy thừa 10 để tối ưu hiệu suất
2782
+ const POWER_CACHE = new Map();
2783
+ /**
2784
+ * Tạo danh sách các step candidates cho việc tính toán scale
2785
+ * @param maxData - Giá trị dữ liệu tối đa
2786
+ * @param minStep - Số bước tối thiểu
2787
+ * @param minNegative - Giá trị âm tối thiểu
2788
+ * @param acceptStepIsTypeFloat - Có chấp nhận step thập phân không
2789
+ * @param stepCandidatesByOptions - Step candidates do người dùng cung cấp
2790
+ * @param includeNegativeSteps - Có bao gồm các step âm không
2791
+ * @returns Danh sách các step candidates
2792
+ */
2793
+ const getStepCandidates = (maxData, minStep, minNegative, acceptStepIsTypeFloat = false, stepCandidatesByOptions, includeNegativeSteps = false) => {
2794
+ // Nếu có step candidates tùy chỉnh, sử dụng chúng
2795
+ if (stepCandidatesByOptions && stepCandidatesByOptions.length > 0) {
2796
+ return stepCandidatesByOptions;
2797
+ }
2798
+ const stepCandidates = new Array();
2799
+ const maxValueStep = Math.abs(Math.max(maxData, Math.abs(minNegative || 0))) / minStep;
2800
+ // Tạo step candidates dựa trên lũy thừa của 10
2801
+ for (let powNumber = 0; powNumber <= MAX_POW_NUMBER; powNumber++) {
2802
+ // Sử dụng cache để tối ưu hiệu suất
2803
+ if (!POWER_CACHE.has(powNumber)) {
2804
+ POWER_CACHE.set(powNumber, Math.pow(10, powNumber));
2805
+ }
2806
+ const powValue = POWER_CACHE.get(powNumber);
2807
+ for (let templateNumber = 1; templateNumber < MAX_TEMPLATE_NUMBER; templateNumber++) {
2808
+ // Thêm step thập phân nếu được chấp nhận
2809
+ if (acceptStepIsTypeFloat) {
2810
+ const step = powValue * (((templateNumber - 1) * 2 + 1) / 2);
2811
+ stepCandidates.push(step);
2812
+ }
2813
+ const step = powValue * templateNumber;
2814
+ stepCandidates.push(step);
2815
+ // Dừng khi step đã đủ lớn
2816
+ if (step >= maxValueStep) {
2817
+ checkAndSetNegativeSteps(stepCandidates, includeNegativeSteps, minNegative);
2818
+ return stepCandidates;
2819
+ }
2820
+ }
2821
+ }
2822
+ checkAndSetNegativeSteps(stepCandidates, includeNegativeSteps, minNegative);
2823
+ return stepCandidates;
1538
2824
  };
1539
- const PATTERN_TAX = () => {
1540
- return /^([0-9]){10}(-[0-9]{3})?$/;
2825
+ /**
2826
+ * Kiểm tra và thêm các step âm vào danh sách candidates nếu cần
2827
+ * @param stepCandidates - Danh sách step candidates hiện tại
2828
+ * @param acceptNegative - Có chấp nhận giá trị âm không
2829
+ * @param minNegative - Giá trị âm tối thiểu
2830
+ */
2831
+ const checkAndSetNegativeSteps = (stepCandidates, acceptNegative, minNegative) => {
2832
+ if (acceptNegative && minNegative < 0) {
2833
+ // Tạo các step âm và thêm vào đầu danh sách
2834
+ const negativeSteps = [...stepCandidates].map(step => -step);
2835
+ stepCandidates.unshift(...negativeSteps);
2836
+ }
1541
2837
  };
1542
- const PATTERN_KEY = () => {
1543
- return /^([0-9]){10}(-[0-9]{3})?$/;
2838
+ /**
2839
+ * Kiểm tra tính hợp lệ của các tham số đầu vào
2840
+ * @param maxData - Giá trị dữ liệu tối đa
2841
+ * @param options - Các tùy chọn cấu hình
2842
+ * @throws {Error} Khi các tham số không hợp lệ
2843
+ */
2844
+ const validateInputs = (maxData, options) => {
2845
+ // Kiểm tra maxData âm khi không chấp nhận giá trị âm
2846
+ if (maxData < 0 && !options?.acceptNegative) {
2847
+ throw new Error("maxData is less than 0 and acceptNegative is false");
2848
+ }
2849
+ if (options?.acceptNegative) {
2850
+ // Kiểm tra minNegative có được cung cấp không
2851
+ if (isNil(options.minNegative)) {
2852
+ throw new Error("minNegative is required when acceptNegative is true");
2853
+ }
2854
+ // Kiểm tra maxData phải >= minNegative
2855
+ if (maxData < options.minNegative) {
2856
+ throw new Error("maxData is less than minNegative");
2857
+ }
2858
+ // Kiểm tra minNegative phải là số âm
2859
+ if (options.minNegative >= 0) {
2860
+ throw new Error("minNegative must be negative");
2861
+ }
2862
+ }
1544
2863
  };
1545
- const PATTERN_ACCOUNT = () => {
1546
- return /^(?=.*@)[a-z0-9@._-]{2,63}$/;
2864
+
2865
+ const protectString = (input) => {
2866
+ const xorKey = 77;
2867
+ const encoded = input
2868
+ .split('')
2869
+ .map((char) => String.fromCharCode(char.charCodeAt(0) ^ xorKey))
2870
+ .reverse()
2871
+ .join('');
2872
+ return btoa(encoded);
2873
+ };
2874
+ const revealString = (encoded) => {
2875
+ const xorKey = 77;
2876
+ const base = atob(encoded);
2877
+ const decoded = base
2878
+ .split('')
2879
+ .reverse()
2880
+ .map(c => String.fromCharCode(c.charCodeAt(0) ^ xorKey))
2881
+ .join('');
2882
+ return decoded;
2883
+ };
2884
+ const createUniqueRandomIntGenerator = (min, max) => {
2885
+ if (max - min + 1 < min + 10) {
2886
+ throw new Error(`Range too small: need at least min + 10 unique values`);
2887
+ }
2888
+ const history = [];
2889
+ return () => {
2890
+ let num;
2891
+ let loop = 0;
2892
+ do {
2893
+ num = Math.floor(Math.random() * (max - min + 1)) + min;
2894
+ loop++;
2895
+ if (loop > 1000) {
2896
+ break;
2897
+ }
2898
+ } while (history.includes(num));
2899
+ history.push(num);
2900
+ if (history.length > 10) {
2901
+ history.shift();
2902
+ }
2903
+ return num;
2904
+ };
1547
2905
  };
1548
2906
 
1549
2907
  /**
1550
2908
  * Generated bundle index. Do not edit.
1551
2909
  */
1552
2910
 
1553
- export { CHARACTER_DATA_EMPTY, ERROR_MESSAGE_EMPTY_VALID, ERROR_MESSAGE_MAX_LENGTH, ERROR_MESSAGE_MAX_VALID, ERROR_MESSAGE_MIN_LENGTH, ERROR_MESSAGE_MIN_VALID, ERROR_MESSAGE_PATTEN_VALID, GetColorById, HttpParamsRequestInstance, PATTERN_ACCOUNT, PATTERN_DOMAIN, PATTERN_EMAIL, PATTERN_EMOJI, PATTERN_ENCODE_URI, PATTERN_GET_FIELD_BY_RULE_FIELD_REPLACE, PATTERN_HOST_URL, PATTERN_KEY, PATTERN_MOBILE_PHONE, PATTERN_NAME, PATTERN_NAME_PROFILE, PATTERN_NAME_SPECIAL, PATTERN_NAME_UTF8, PATTERN_NUMBER, PATTERN_PEM, PATTERN_PHONE, PATTERN_PHONE_NORMAL, PATTERN_RULE_FIELD_REPLACE, PATTERN_TAX, PATTERN_URL, UtilsCache, UtilsCommunicateMicro, UtilsHttpParamsRequest, UtilsKeyCodeConstant, UtilsLanguageConstants, UtilsUrlSearchParams, checkMouseOverInContainer, checkViewInScreen, cloneDeep, cloneIBoundingClientRect, colorContrastFromOrigin, colorStepContrastFromOrigin, convertObjectToSignal, convertSignalToObject, decrypt, decrypt3rd, deleteUnicode, emojiPattern, encrypt, encrypt3rd, escapeHtml, formatNumber, generateInterface, get, getColorById, getKeyCacheByArrayObject, getPlatFromBrowser, getViewport, groupBy, isEmbedFrame, isEmpty, isEqual, isNil, isSignal, keyBy, listColorDefine$1 as listColorDefine, md5, range, removeEmoji, rgbToHex, set, setCaretPosition, setKeyCrypto, setKeyCrypto3rd, setStyles, uniqBy, updateFunctionCheckEmbedFrame, uuid, viewDataNumberByLanguage };
2911
+ export { AudioExtList, CHARACTER_DATA_EMPTY, COMMUNICATE_MICRO_KEY_GET_ALL_MESSAGE, COMMUNICATE_MICRO_PREFIX_TYPE, DEFAULT_START_PAGE_0, DocumentExtList, ENCODE_URI_PATTERN, ERROR_MESSAGE_EMPTY_VALID, ERROR_MESSAGE_MAX_LENGTH, ERROR_MESSAGE_MAX_VALID, ERROR_MESSAGE_MIN_LENGTH, ERROR_MESSAGE_MIN_VALID, ERROR_MESSAGE_PATTEN_VALID, ExcelExtList, ImageExtList, LINK_IMAGE_ERROR_TOKEN_INJECT, PROCESS_BAR_STANDARD_CONFIG_DEFAULT_TOKEN_INJECT, PROCESS_BAR_STEPS_CONFIG_DEFAULT_TOKEN_INJECT, UtilsCache, UtilsCommunicateMicro, UtilsCommunicateMicroKeyGlobal, UtilsHttpParamsRequest, UtilsHttpParamsRequestInstance, UtilsKeyCodeConstant, UtilsLanguageConstants, UtilsUrlSearchParams, VideoExtList, base64Decode, base64Encode, capitalize, checkMouseOverInContainer, checkViewInScreen, cloneDeep, cloneIBoundingClientRect, colorContrastFromOrigin, colorStepContrastFromOrigin, convertBase64ToBlob, convertBlobToFile, convertFileToBase64, convertFileToBase64_ObjectUrl, convertHtmlToDivBlocks, convertObjectToSignal, convertSignalToObject, convertUrlToFile, createUniqueRandomIntGenerator, decodeEscapeHtml, decodeURI, decrypt, decrypt3rd, deleteUnicode, downloadFileByUrl, downloadFileByUrlUseXmlRequest, downloadImageFromELement, encodeURI, encrypt, encrypt3rd, endCodeUrl, escapeHtml, firstLetterToUpperCase, formatDate, formatNumber, formatTextCompare, fullNameFormat, generateInterface, get, getColorById, getDayjs, getDeltaFromHTML, getDeviceInfo, getDocumentByString, getDragEventByElement, getEventNameHandleClick, getFileExtension, getHTMLFromQuill, getKeyCacheByArrayObject, getLabelBySizeFile, getPlatFromBrowser, getSmartAxisScale, getViewport, groupBy, highlightByKeyword, insertContentWithRange, isDifferenceDay, isDifferenceMonth, isDifferenceYear, isEmbedFrame, isEmpty, isEqual, isIncludeAudioExtList, isIncludeDocumentExtList, isIncludeImageExtList, isIncludeVideoExtList, isNil, isTypeAudio, isTypeFile, isTypeImage, isTypeVideo, keyBy, listColorDefine, md5, omitBy, patternAccount, patternDomain, patternEmail, patternEmoji, patternEncodeUri, patternGetFieldByRuleFieldReplace, patternHostUrl, patternKey, patternMobilePhone, patternName, patternNameProfile, patternNameSpecial, patternNameUtf8, patternNumber, patternPem, patternPhone, patternPhoneNormal, patternRuleFieldReplace, patternTax, patternUrl, processPasteData, protectString, range, removeEmoji, revealString, rgbToHex, set, setCaretPosition, setDefaultTimeZone, setKeyCrypto, setKeyCrypto3rd, setStylesElement, uniqBy, updateFunctionCheckEmbedFrame, updateFunctionFormatDate, updateFunctionXssFilter, uppercaseByPosition, uuid, viewDataNumberByLanguage, xssFilter };
1554
2912
  //# sourceMappingURL=libs-ui-utils.mjs.map