@masterkeymaterial/ui 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -59
- package/ng-package.json +10 -0
- package/package.json +5 -14
- package/src/elements/ui-button/ui-button.css +229 -0
- package/src/elements/ui-button/ui-button.html +12 -0
- package/src/elements/ui-button/ui-button.ts +133 -0
- package/src/elements/ui-check-box/ui-check-box.css +66 -0
- package/src/elements/ui-check-box/ui-check-box.html +5 -0
- package/src/elements/ui-check-box/ui-check-box.ts +65 -0
- package/src/elements/ui-chip/ui-chip.css +24 -0
- package/src/elements/ui-chip/ui-chip.html +3 -0
- package/src/elements/ui-chip/ui-chip.ts +25 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.css +91 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.html +8 -0
- package/src/elements/ui-drop-zone/ui-drop-zone.ts +153 -0
- package/src/elements/ui-file-list/ui-file-list.css +43 -0
- package/src/elements/ui-file-list/ui-file-list.html +17 -0
- package/src/elements/ui-file-list/ui-file-list.ts +22 -0
- package/src/elements/ui-list-errors/ui-list-errors.css +30 -0
- package/src/elements/ui-list-errors/ui-list-errors.html +10 -0
- package/src/elements/ui-list-errors/ui-list-errors.ts +14 -0
- package/src/elements/ui-loading/ui-loading.css +13 -0
- package/src/elements/ui-loading/ui-loading.html +1 -0
- package/src/elements/ui-loading/ui-loading.ts +10 -0
- package/src/elements/ui-menu/ui-menu.css +69 -0
- package/src/elements/ui-menu/ui-menu.html +20 -0
- package/src/elements/ui-menu/ui-menu.ts +267 -0
- package/src/elements/ui-procurar/ui-procurar.css +48 -0
- package/src/elements/ui-procurar/ui-procurar.html +14 -0
- package/src/elements/ui-procurar/ui-procurar.ts +82 -0
- package/src/elements/ui-progress/ui-progress.css +0 -0
- package/src/elements/ui-progress/ui-progress.html +1 -0
- package/src/elements/ui-progress/ui-progress.ts +15 -0
- package/src/elements/ui-select/ui-select.css +211 -0
- package/src/elements/ui-select/ui-select.html +46 -0
- package/src/elements/ui-select/ui-select.ts +482 -0
- package/src/elements/ui-slide/ui-slide.css +75 -0
- package/src/elements/ui-slide/ui-slide.html +7 -0
- package/src/elements/ui-slide/ui-slide.ts +61 -0
- package/src/fields/Base/BaseFieldsForm/BaseFieldsForm.component.ts +113 -0
- package/src/fields/Base/BaseFieldsValues/BaseFieldsValues.ts +112 -0
- package/src/fields/Formulario/Formulario.ts +1056 -0
- package/src/fields/Formulario/form-action/form-action.css +98 -0
- package/src/fields/Formulario/form-action/form-action.html +75 -0
- package/src/fields/Formulario/form-action/form-action.ts +187 -0
- package/src/fields/Formulario/form-controls/form-controls.css +108 -0
- package/src/fields/Formulario/form-controls/form-controls.html +105 -0
- package/src/fields/Formulario/form-controls/form-controls.ts +122 -0
- package/src/fields/Formulario/form-fase/form-fase.css +84 -0
- package/src/fields/Formulario/form-fase/form-fase.html +24 -0
- package/src/fields/Formulario/form-fase/form-fase.ts +157 -0
- package/src/fields/Formulario/form-filter/form-filter.css +50 -0
- package/src/fields/Formulario/form-filter/form-filter.html +25 -0
- package/src/fields/Formulario/form-filter/form-filter.ts +53 -0
- package/src/fields/Formulario/form-no-action/form-no-action.css +32 -0
- package/src/fields/Formulario/form-no-action/form-no-action.html +12 -0
- package/src/fields/Formulario/form-no-action/form-no-action.ts +21 -0
- package/src/fields/Formulario/formated-values/formated-values.css +104 -0
- package/src/fields/Formulario/formated-values/formated-values.html +15 -0
- package/src/fields/Formulario/formated-values/formated-values.ts +186 -0
- package/src/fields/Formulario/single-values/single-values.css +88 -0
- package/src/fields/Formulario/single-values/single-values.html +11 -0
- package/src/fields/Formulario/single-values/single-values.ts +65 -0
- package/src/fields/autocomplete/autocomplete.css +94 -0
- package/src/fields/autocomplete/autocomplete.html +38 -0
- package/src/fields/autocomplete/autocomplete.ts +294 -0
- package/src/fields/button/button.css +7 -0
- package/src/fields/button/button.html +19 -0
- package/src/fields/button/button.ts +38 -0
- package/src/fields/checkbox/checkbox.css +27 -0
- package/src/fields/checkbox/checkbox.html +20 -0
- package/src/fields/checkbox/checkbox.ts +44 -0
- package/src/fields/color/CirculoColorido/circulocolorido.css +50 -0
- package/src/fields/color/CirculoColorido/circulocolorido.html +8 -0
- package/src/fields/color/CirculoColorido/circulocolorido.ts +24 -0
- package/src/fields/color/color.css +15 -0
- package/src/fields/color/color.html +24 -0
- package/src/fields/color/color.ts +47 -0
- package/src/fields/date/date.html +19 -0
- package/src/fields/date/date.ts +29 -0
- package/src/fields/datetime/datetime.html +19 -0
- package/src/fields/datetime/datetime.ts +29 -0
- package/src/fields/display/display.css +7 -0
- package/src/fields/display/display.html +20 -0
- package/src/fields/display/display.ts +43 -0
- package/src/fields/editor/editor.css +51 -0
- package/src/fields/editor/editor.html +37 -0
- package/src/fields/editor/editor.ts +218 -0
- package/src/fields/email/email.html +19 -0
- package/src/fields/email/email.ts +29 -0
- package/src/fields/fields.css +180 -0
- package/src/fields/generic/generic.html +3 -0
- package/src/fields/generic/generic.ts +91 -0
- package/src/fields/hidden/hidden.html +3 -0
- package/src/fields/hidden/hidden.ts +20 -0
- package/src/fields/icon/icon.css +19 -0
- package/src/fields/icon/icon.html +27 -0
- package/src/fields/icon/icon.ts +31 -0
- package/src/fields/multifactor/multifactor.css +21 -0
- package/src/fields/multifactor/multifactor.html +39 -0
- package/src/fields/multifactor/multifactor.ts +106 -0
- package/src/fields/multikv/multikv.css +43 -0
- package/src/fields/multikv/multikv.html +47 -0
- package/src/fields/multikv/multikv.ts +88 -0
- package/src/fields/multitext/multitext.css +36 -0
- package/src/fields/multitext/multitext.html +38 -0
- package/src/fields/multitext/multitext.ts +75 -0
- package/src/fields/number/number.html +20 -0
- package/src/fields/number/number.ts +35 -0
- package/src/fields/password/password.html +23 -0
- package/src/fields/password/password.ts +37 -0
- package/src/fields/search/search.css +0 -0
- package/src/fields/search/search.html +19 -0
- package/src/fields/search/search.ts +54 -0
- package/src/fields/select/select.css +15 -0
- package/src/fields/select/select.html +18 -0
- package/src/fields/select/select.ts +52 -0
- package/src/fields/slide/slide.css +27 -0
- package/src/fields/slide/slide.html +20 -0
- package/src/fields/slide/slide.ts +45 -0
- package/src/fields/text/text.html +19 -0
- package/src/fields/text/text.ts +30 -0
- package/src/fields/textarea/textarea.css +4 -0
- package/src/fields/textarea/textarea.html +20 -0
- package/src/fields/textarea/textarea.ts +31 -0
- package/src/fields/time/time.html +19 -0
- package/src/fields/time/time.ts +29 -0
- package/src/fields/upload/upload.css +24 -0
- package/src/fields/upload/upload.html +41 -0
- package/src/fields/upload/upload.ts +137 -0
- package/src/interfaces/interfaces.ts +61 -0
- package/src/public-api.ts +38 -0
- package/src/util/ClassOf.pipe.ts +11 -0
- package/src/util/JsonColorido.pipe.ts +11 -0
- package/src/util/util.ts +2151 -0
- package/tsconfig.lib.json +16 -0
- package/tsconfig.lib.prod.json +9 -0
- package/tsconfig.spec.json +13 -0
- package/fesm2022/masterkeymaterial-ui.mjs +0 -6457
- package/fesm2022/masterkeymaterial-ui.mjs.map +0 -1
- package/types/masterkeymaterial-ui.d.ts +0 -928
package/src/util/util.ts
ADDED
|
@@ -0,0 +1,2151 @@
|
|
|
1
|
+
import { WritableSignal } from "@angular/core";
|
|
2
|
+
import { IFieldComponent } from "../fields/Formulario/Formulario";
|
|
3
|
+
|
|
4
|
+
export class LibUtil {
|
|
5
|
+
|
|
6
|
+
static loglevel = 0;
|
|
7
|
+
static formConfigs: Partial<IFieldComponent<any>> = {};
|
|
8
|
+
|
|
9
|
+
static classof = (o: any): IClassOf => {
|
|
10
|
+
let nomeClasse = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
|
|
11
|
+
if (nomeClasse == "number") {
|
|
12
|
+
if (o.toString() == "NaN") {
|
|
13
|
+
nomeClasse = "nan";
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return nomeClasse as IClassOf;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
static wait = (ms: number) => {
|
|
20
|
+
// Essa mecânica usa um setTimeout. A mecânica do Queue não foi implementada
|
|
21
|
+
return new Promise(r => setTimeout(r, ms))
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
static clonar = (i: any) => {
|
|
25
|
+
// Clona com a técnica de montar e desmontar string.
|
|
26
|
+
// Não funciona para objetos com serviços (Date, File, Map, Set, etc)
|
|
27
|
+
let parsed = null;
|
|
28
|
+
try {
|
|
29
|
+
let stringified = JSON.stringify(i);
|
|
30
|
+
if (stringified == null) return null;
|
|
31
|
+
if (stringified == "") return "";
|
|
32
|
+
parsed = JSON.parse(stringified);
|
|
33
|
+
if (parsed == null) return null;
|
|
34
|
+
} catch (e) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
return parsed;
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
static limparObject = (o: any) => {
|
|
41
|
+
// Converte (Object) Limpar Nulos e Vazios
|
|
42
|
+
if (LibUtil.classof(o) == "object") {
|
|
43
|
+
for (let propName in o) {
|
|
44
|
+
if (
|
|
45
|
+
o[propName as keyof typeof o] === null ||
|
|
46
|
+
o[propName as keyof typeof o] === undefined ||
|
|
47
|
+
o[propName as keyof typeof o] === "" ||
|
|
48
|
+
o[propName as keyof typeof o] === "undefined"
|
|
49
|
+
) {
|
|
50
|
+
delete o[propName as keyof typeof o];
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return o;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
static mascarar = (texto: any, mascara: any): string | undefined => {
|
|
58
|
+
// Informando uma máscara e um texto, retorna dado mascarado.
|
|
59
|
+
// Mascaras: 0=Numero, A=Letra, Outros repete.
|
|
60
|
+
if (LibUtil.classof(mascara) != "string") {
|
|
61
|
+
// Se passar uma funcao para a mascara, Executa a função enviando o texto e deve retornar uma string da mascara para esse texto.
|
|
62
|
+
if (LibUtil.classof(mascara) == "function") {
|
|
63
|
+
mascara = mascara(texto); // Sobreextreve a mascara a ser executada pelo retorno da função.
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (mascara) {
|
|
67
|
+
if (texto) {
|
|
68
|
+
if (LibUtil.classof(texto) != "string") texto = texto?.toString();
|
|
69
|
+
if (LibUtil.classof(mascara) != "string") mascara = mascara?.toString(); // Se a chegar até aqui e ainda não for string
|
|
70
|
+
let ms = [...LibUtil.clonar(mascara)];
|
|
71
|
+
let ss = [...LibUtil.clonar(texto)];
|
|
72
|
+
// this.l("ss: ", ss);
|
|
73
|
+
let ts: any = [];
|
|
74
|
+
let pm = 0;
|
|
75
|
+
ss.forEach(s => {
|
|
76
|
+
let t = null;
|
|
77
|
+
if (/[0-9]/.test(s)) {
|
|
78
|
+
t = "0";
|
|
79
|
+
} else if (/[a-zA-Z]/.test(s)) {
|
|
80
|
+
t = "A";
|
|
81
|
+
} else {
|
|
82
|
+
t = " ";
|
|
83
|
+
}
|
|
84
|
+
ts.push(t);
|
|
85
|
+
pm++;
|
|
86
|
+
});
|
|
87
|
+
// this.l("ts: ", ts);
|
|
88
|
+
// this.l("ms: ", ms);
|
|
89
|
+
let r: any = [];
|
|
90
|
+
for (let tp = 0, mp = 0; (tp < ts.length) && (mp < ms.length); tp++, mp++) {
|
|
91
|
+
if (((ms[mp] === "0" || ms[mp] === "A") && (ms[mp] == ts[tp]))
|
|
92
|
+
|| (ms[mp] === "S" && (ts[tp] === "A" || ts[tp] === "0"))) {
|
|
93
|
+
// FORMATO IGUAL.
|
|
94
|
+
r.push(ss[tp]);
|
|
95
|
+
} else {
|
|
96
|
+
// MESMO CARACTER
|
|
97
|
+
if (ss[tp] === ms[mp]) {
|
|
98
|
+
r.push(ss[tp]);
|
|
99
|
+
} else {
|
|
100
|
+
// this.l("> ", ss[tp], " vs ", ms[mp])
|
|
101
|
+
// Mágica: Coloca o especial que o usuário não colocou.
|
|
102
|
+
if (ms[mp] != "0" && ms[mp] != "A" && ms[mp] != "S") {
|
|
103
|
+
r.push(ms[mp]);
|
|
104
|
+
tp--;
|
|
105
|
+
} else {
|
|
106
|
+
mp--;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return r.join("");
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
console.log("❌ Mascarar Requer Texto: ", texto, " e Mascara: ", mascara);
|
|
115
|
+
}
|
|
116
|
+
return undefined;
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
static tryParseJSON(val: any): any[] | null {
|
|
120
|
+
try {
|
|
121
|
+
return JSON.parse(val);
|
|
122
|
+
} catch (e) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
static contem = (strMaior: string, strMenor: string): boolean => {
|
|
128
|
+
// Comparardor de string CONTEM
|
|
129
|
+
strMaior = LibUtil.removeAcentos(strMaior).toLowerCase();
|
|
130
|
+
strMenor = LibUtil.removeAcentos(strMenor).toLowerCase();
|
|
131
|
+
return (strMaior.includes(strMenor));
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
static removeAcentos = (s: string): string => {
|
|
135
|
+
if (s == null) return "";
|
|
136
|
+
// Remove acentos e depois chama Apenas Números e Letras.
|
|
137
|
+
s = s.toString();
|
|
138
|
+
let r = "";
|
|
139
|
+
let sS = "áàãâäéèêëíìîïóòõôöúùûüçÁÀÃÂÄÉÈÊËÍÌÎÏÓÒÕÖÔÚÙÛÜÇ";
|
|
140
|
+
let sN = "aaaaaeeeeiiiiooooouuuucAAAAAEEEEIIIIOOOOOUUUUC";
|
|
141
|
+
for (let p = 0; p < s.length; p++) {
|
|
142
|
+
let pSS = sS.indexOf(s.charAt(p)); // <= Procura
|
|
143
|
+
if (pSS != -1) {
|
|
144
|
+
r += sN.charAt(pSS); // Substitui mesma posicao
|
|
145
|
+
} else {
|
|
146
|
+
r += s.charAt(p);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return r;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
static fileReader = async (arquivo: File, eventos?: Function): Promise<string | null> => {
|
|
153
|
+
return new Promise((r) => {
|
|
154
|
+
let leitor = new FileReader();
|
|
155
|
+
let gatilhos = (event: any) => {
|
|
156
|
+
if (event.type == "error") {
|
|
157
|
+
r(null);
|
|
158
|
+
}
|
|
159
|
+
else if (event.type == "loadend") {
|
|
160
|
+
// Quando terminar, o result já é a string completa.
|
|
161
|
+
let buffer = leitor.result as string;
|
|
162
|
+
r(buffer);
|
|
163
|
+
}
|
|
164
|
+
if (eventos)
|
|
165
|
+
eventos(event, Math.trunc((event.loaded / event.total) * 100));
|
|
166
|
+
}
|
|
167
|
+
if (arquivo) {
|
|
168
|
+
if (arquivo.name != "") {
|
|
169
|
+
leitor.addEventListener("loadstart", gatilhos);
|
|
170
|
+
leitor.addEventListener("progress", gatilhos);
|
|
171
|
+
leitor.addEventListener("error", gatilhos);
|
|
172
|
+
leitor.addEventListener("abort", gatilhos);
|
|
173
|
+
leitor.addEventListener("load", gatilhos);
|
|
174
|
+
leitor.addEventListener("loadend", gatilhos);
|
|
175
|
+
leitor.readAsDataURL(arquivo);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
LOG(1, "⚠️ fileReader() - Nome do arquivo necessário: ", arquivo.name);
|
|
179
|
+
r(null);
|
|
180
|
+
}
|
|
181
|
+
} else {
|
|
182
|
+
LOG(1, "⚠️ fileReader() - Arquivo Nulo: ", arquivo);
|
|
183
|
+
r(null);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
static removeHtmlTags(texto: string): string {
|
|
189
|
+
return texto.replace(/<\/?[^>]+(>|$)/g, "");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Salva a posição do cursor
|
|
193
|
+
static saveCursorPosition(element: any, plus: number = 0): { start: number; end: number, plus: number } | null {
|
|
194
|
+
const selection = window.getSelection();
|
|
195
|
+
if (!selection || selection.rangeCount === 0) return null;
|
|
196
|
+
const range = selection.getRangeAt(0);
|
|
197
|
+
const preCaretRange = range.cloneRange();
|
|
198
|
+
if (!element) return null;
|
|
199
|
+
preCaretRange.selectNodeContents(element);
|
|
200
|
+
preCaretRange.setEnd(range.startContainer, range.startOffset);
|
|
201
|
+
const start = preCaretRange.toString().length;
|
|
202
|
+
return {
|
|
203
|
+
start: start,
|
|
204
|
+
end: start + range.toString().length,
|
|
205
|
+
plus
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Restaura a posição do cursor
|
|
210
|
+
static restoreCursorPosition(element: any, position: { start: number; end: number, plus: number }) {
|
|
211
|
+
if (!element) return;
|
|
212
|
+
const selection = window.getSelection();
|
|
213
|
+
if (!selection) return;
|
|
214
|
+
let charIndex = 0;
|
|
215
|
+
const range = document.createRange();
|
|
216
|
+
range.setStart(element, 0);
|
|
217
|
+
range.collapse(true);
|
|
218
|
+
const nodeIterator = (node: Node): boolean => {
|
|
219
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
220
|
+
const textNode = node as Text;
|
|
221
|
+
const nextCharIndex = charIndex + (textNode.length || 0);
|
|
222
|
+
if (position.start >= charIndex && position.start <= nextCharIndex) {
|
|
223
|
+
range.setStart(textNode, position.start - charIndex);
|
|
224
|
+
range.setEnd(textNode, position.start - charIndex);
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
charIndex = nextCharIndex;
|
|
228
|
+
} else {
|
|
229
|
+
for (let i = 0; i < node.childNodes.length; i++) {
|
|
230
|
+
if (nodeIterator(node.childNodes[i])) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return false;
|
|
236
|
+
};
|
|
237
|
+
nodeIterator(element);
|
|
238
|
+
selection.removeAllRanges();
|
|
239
|
+
selection.addRange(range);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static formatJson(texto: string, colorir: boolean = false): string {
|
|
243
|
+
let retorno = "";
|
|
244
|
+
try {
|
|
245
|
+
retorno = JSON.stringify(texto, null, 2);
|
|
246
|
+
} catch (e) {
|
|
247
|
+
LOG(1, "⚠️ JSON Inválido: Não foi possível formatar o JSON.");
|
|
248
|
+
return texto;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (colorir) {
|
|
252
|
+
let keyNameStart: string = '<span class="json-key">';
|
|
253
|
+
let nullStart: string = '<span class="json-null">';
|
|
254
|
+
let numberStart: string = '<span class="json-number">';
|
|
255
|
+
let booleanStart: string = '<span class="json-boolean">';
|
|
256
|
+
let stringStart: string = '<span class="json-string">';
|
|
257
|
+
let spanEnd: string = '</span>';
|
|
258
|
+
// Identificar a posição das chaves do json e adicionar as tags de span
|
|
259
|
+
retorno = retorno.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
260
|
+
retorno = retorno.replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g, function (match) {
|
|
261
|
+
let cls = nullStart;
|
|
262
|
+
if (/^"/.test(match)) {
|
|
263
|
+
if (/:$/.test(match)) {
|
|
264
|
+
cls = keyNameStart;
|
|
265
|
+
} else {
|
|
266
|
+
cls = stringStart;
|
|
267
|
+
}
|
|
268
|
+
} else if (/true|false/.test(match)) {
|
|
269
|
+
cls = booleanStart;
|
|
270
|
+
} else if (/null/.test(match)) {
|
|
271
|
+
cls = nullStart;
|
|
272
|
+
} else if (/undefined/.test(match)) {
|
|
273
|
+
cls = nullStart;
|
|
274
|
+
} else {
|
|
275
|
+
cls = numberStart;
|
|
276
|
+
}
|
|
277
|
+
return cls + match + spanEnd;
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Remove aspas duplas das chaves (mantém aspas dos valores string)
|
|
282
|
+
retorno = retorno.replace(/"([^"]+)"(\s*):/g, '$1$2:');
|
|
283
|
+
|
|
284
|
+
return retorno;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
static async copy(content: string): Promise<void> {
|
|
288
|
+
try {
|
|
289
|
+
await this.copyHtml(content);
|
|
290
|
+
} catch (erro) {
|
|
291
|
+
LOG(1, "❌ %cFalha ao copiar como HTML, tentando como texto puro", "color:red;", erro);
|
|
292
|
+
this.copyPlainText(content);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
private static copyPlainText(text: string) {
|
|
297
|
+
const elemento = document.createElement('textarea');
|
|
298
|
+
elemento.style.position = 'fixed';
|
|
299
|
+
elemento.style.opacity = '0';
|
|
300
|
+
elemento.style.whiteSpace = 'pre';
|
|
301
|
+
elemento.value = text;
|
|
302
|
+
document.body.appendChild(elemento);
|
|
303
|
+
elemento.select();
|
|
304
|
+
elemento.setSelectionRange(0, 99999);
|
|
305
|
+
const result = document.execCommand('copy');
|
|
306
|
+
if (!result) {
|
|
307
|
+
LOG(1, "❌ Falha ao copiar via execCommand.");
|
|
308
|
+
}
|
|
309
|
+
LOG(1, "🫤! Cópia via execCommand: ", text);
|
|
310
|
+
elemento.remove();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
private static async copyHtml(html?: string) {
|
|
314
|
+
if (!html) {
|
|
315
|
+
html = "";
|
|
316
|
+
LOG(1, "❌ %cNão foi possível copiar.", "color:red;");
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
try {
|
|
320
|
+
// Remove tags HTML para gerar a versão texto puro
|
|
321
|
+
const plainText = this.stripHtmlTags(html);
|
|
322
|
+
if (navigator.clipboard && window.isSecureContext) {
|
|
323
|
+
const clipboardItem = new ClipboardItem({
|
|
324
|
+
'text/plain': new Blob([plainText], { type: 'text/plain' }),
|
|
325
|
+
'text/html': new Blob([html], { type: 'text/html' })
|
|
326
|
+
});
|
|
327
|
+
await navigator.clipboard.write([clipboardItem]);
|
|
328
|
+
console.groupCollapsed("✅ %cCopiado para a área de transferência.", "color:aquamarine;");
|
|
329
|
+
LOG(1, plainText);
|
|
330
|
+
console.groupEnd();
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Fallback: copia HTML usando execCommand
|
|
335
|
+
const elemento = document.createElement('div');
|
|
336
|
+
elemento.style.position = 'fixed';
|
|
337
|
+
elemento.style.opacity = '0';
|
|
338
|
+
elemento.innerHTML = html;
|
|
339
|
+
document.body.appendChild(elemento);
|
|
340
|
+
|
|
341
|
+
const range = document.createRange();
|
|
342
|
+
range.selectNodeContents(elemento);
|
|
343
|
+
const selection = window.getSelection();
|
|
344
|
+
selection?.removeAllRanges();
|
|
345
|
+
selection?.addRange(range);
|
|
346
|
+
|
|
347
|
+
document.execCommand('copy');
|
|
348
|
+
console.groupCollapsed("➡️ %cCopiado para a área de transferência. (execCommand)", "color:lightblue;");
|
|
349
|
+
LOG(1, plainText);
|
|
350
|
+
console.groupEnd();
|
|
351
|
+
elemento.remove();
|
|
352
|
+
} catch (erro) {
|
|
353
|
+
LOG(1, "❌ Erro ao copiar:", erro);
|
|
354
|
+
throw erro;
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
private static stripHtmlTags(html: string): string {
|
|
359
|
+
// Cria um elemento temporário para extrair texto puro
|
|
360
|
+
const temp = document.createElement('div');
|
|
361
|
+
temp.innerHTML = html;
|
|
362
|
+
// Substitui <br> por quebras de linha antes de extrair o texto
|
|
363
|
+
temp.innerHTML = temp.innerHTML.replace(/<br\s*\/?>/gi, '\n');
|
|
364
|
+
return temp.textContent || temp.innerText || '';
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
static apenasNumeros = (s: string | number = ""): string => {
|
|
368
|
+
if (s == null) return "";
|
|
369
|
+
// Ignora qualquer outro caracter além de Numeros
|
|
370
|
+
return s.toString().replace(/(?![0-9])./g, "");
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
static frequencia = (array: any): any => {
|
|
374
|
+
// Retorna o total de encontro na array.
|
|
375
|
+
// Quando é objeto converte pra string pra poder contar
|
|
376
|
+
let f: any = {};
|
|
377
|
+
for (let e of array) {
|
|
378
|
+
let s = e;
|
|
379
|
+
if (LibUtil.classof(e) == "object") s = JSON.stringify(e);
|
|
380
|
+
f[s] ? f[s]++ : (f[s] = 1);
|
|
381
|
+
}
|
|
382
|
+
return f;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
static formats: IUtilFormatters = {
|
|
386
|
+
cpf: {
|
|
387
|
+
mask: "000.000.000-00",
|
|
388
|
+
regex: "^([0-9]{3}([\.]?[0-9]{3}){2}[-]?[0-9]{2})$",
|
|
389
|
+
validate: (cpf: any) => {
|
|
390
|
+
let m1 = [10, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
391
|
+
let m2 = [11, 10, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
392
|
+
if (!cpf) { return false; }
|
|
393
|
+
cpf = LibUtil.apenasNumeros(cpf);
|
|
394
|
+
if (cpf.length != 11) { return false; }
|
|
395
|
+
let temp = cpf.slice(0, 9);
|
|
396
|
+
let c = 0;
|
|
397
|
+
for (let i = 0; i < 9; i++) { c += Number(temp.charAt(i)) * m1[i]; }
|
|
398
|
+
let r = c % 11;
|
|
399
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
400
|
+
temp += r.toString();
|
|
401
|
+
c = 0;
|
|
402
|
+
for (let i = 0; i < 10; i++) { c += Number(temp.charAt(i)) * m2[i]; }
|
|
403
|
+
r = c % 11;
|
|
404
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
405
|
+
if (cpf.charAt(10) != r.toString()) {
|
|
406
|
+
return false;
|
|
407
|
+
};
|
|
408
|
+
let char0 = cpf.charAt(0);
|
|
409
|
+
let repChar0 = LibUtil.frequencia(cpf)[char0];
|
|
410
|
+
if (repChar0 >= 11) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
cnpj: {
|
|
417
|
+
mask: "00.000.000/0000-00",
|
|
418
|
+
regex: "^([0-9]{2}([\.]?[0-9]{3}){2}[\/]?[0-9]{4}[-]?[0-9]{2})$",
|
|
419
|
+
validate: (cnpj: any) => {
|
|
420
|
+
let m1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
421
|
+
let m2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
|
|
422
|
+
if (!cnpj) { return false; }
|
|
423
|
+
cnpj = LibUtil.apenasNumeros(cnpj);
|
|
424
|
+
if (cnpj.length != 14) { return false; }
|
|
425
|
+
let temp = cnpj.slice(0, 12);
|
|
426
|
+
let c = 0;
|
|
427
|
+
for (let i = 0; i < 12; i++) { c += Number(temp.charAt(i)) * m1[i]; }
|
|
428
|
+
let r = (c % 11);
|
|
429
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
430
|
+
temp += r.toString();
|
|
431
|
+
c = 0;
|
|
432
|
+
for (let i = 0; i < 13; i++) { c += Number(temp.charAt(i)) * m2[i]; }
|
|
433
|
+
r = (c % 11);
|
|
434
|
+
(r < 2) ? r = 0 : r = 11 - r;
|
|
435
|
+
return cnpj.charAt(13) == r.toString();
|
|
436
|
+
}
|
|
437
|
+
},
|
|
438
|
+
cpf_cnpj: {
|
|
439
|
+
mask: (str: string) => {
|
|
440
|
+
if (LibUtil.apenasNumeros(str).length <= 11) {
|
|
441
|
+
return "000.000.000-00"
|
|
442
|
+
} else {
|
|
443
|
+
return "00.000.000/0000-00"
|
|
444
|
+
};
|
|
445
|
+
},
|
|
446
|
+
regex: "^([0-9]{2}([\.]?[0-9]{3}){2}[\/]?[0-9]{4}[-]?[0-9]{2})|([0-9]{3}([\.]?[0-9]{3}){2}[-]?[0-9]{2})$",
|
|
447
|
+
validate: (cpf_cnpj: any) => {
|
|
448
|
+
if (LibUtil.apenasNumeros(cpf_cnpj).length <= 11) {
|
|
449
|
+
return LibUtil.formats.cpf.validate?.(cpf_cnpj) ?? false;
|
|
450
|
+
} else {
|
|
451
|
+
return LibUtil.formats.cnpj.validate?.(cpf_cnpj) ?? false;
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
},
|
|
455
|
+
cnh: {
|
|
456
|
+
mask: "00000000000",
|
|
457
|
+
regex: "^([0-9]{11})$",
|
|
458
|
+
validate: (cnh: any) => {
|
|
459
|
+
if (!cnh) { return false; }
|
|
460
|
+
cnh = LibUtil.apenasNumeros(cnh);
|
|
461
|
+
if (cnh.length != 11) { return false; }
|
|
462
|
+
return true;
|
|
463
|
+
},
|
|
464
|
+
},
|
|
465
|
+
pis: {
|
|
466
|
+
mask: "000.00000.00-0",
|
|
467
|
+
regex: "^([0-9]{3}[\.]?[0-9]{5}[\.]?[0-9]{2}[-]?[0-9]{1})$",
|
|
468
|
+
validate: (pis: any) => {
|
|
469
|
+
if (!pis) { return false; }
|
|
470
|
+
pis = LibUtil.apenasNumeros(pis);
|
|
471
|
+
if (pis.length != 11) { return false; }
|
|
472
|
+
return true;
|
|
473
|
+
},
|
|
474
|
+
},
|
|
475
|
+
dia: {
|
|
476
|
+
mask: "00",
|
|
477
|
+
regex: "^(0[1-9]|[1-9]|[1-2][0-9]|3[0-1])$",
|
|
478
|
+
validate: (dia: any) => {
|
|
479
|
+
if (!dia) { return false; }
|
|
480
|
+
dia = LibUtil.apenasNumeros(dia);
|
|
481
|
+
let diaNum = Number(dia);
|
|
482
|
+
return diaNum >= 1 && diaNum <= 31;
|
|
483
|
+
},
|
|
484
|
+
},
|
|
485
|
+
mes: {
|
|
486
|
+
mask: "00",
|
|
487
|
+
regex: "^(0[1-9]|1[0-2])$",
|
|
488
|
+
validate: (mes: any) => {
|
|
489
|
+
if (!mes) { return false; }
|
|
490
|
+
mes = LibUtil.apenasNumeros(mes);
|
|
491
|
+
let mesNum = Number(mes);
|
|
492
|
+
return mesNum >= 1 && mesNum <= 12;
|
|
493
|
+
},
|
|
494
|
+
},
|
|
495
|
+
ano: {
|
|
496
|
+
mask: "0000",
|
|
497
|
+
regex: "^([0-2]?([0-9]){3})$",
|
|
498
|
+
validate: (ano: any) => {
|
|
499
|
+
if (!ano) { return false; }
|
|
500
|
+
ano = LibUtil.apenasNumeros(ano);
|
|
501
|
+
let anoNum = Number(ano);
|
|
502
|
+
return anoNum >= 1000 && anoNum <= 2999;
|
|
503
|
+
},
|
|
504
|
+
},
|
|
505
|
+
anoRecente: {
|
|
506
|
+
mask: "0000",
|
|
507
|
+
regex: "^(19([0-9]){2})|(20([0-9]){2})|(21([0-9]){2})$",
|
|
508
|
+
validate: (anoRecente: any) => {
|
|
509
|
+
if (!anoRecente) { return false; }
|
|
510
|
+
anoRecente = LibUtil.apenasNumeros(anoRecente);
|
|
511
|
+
let anoNum = Number(anoRecente);
|
|
512
|
+
return anoNum >= 1900 && anoNum <= 2199;
|
|
513
|
+
},
|
|
514
|
+
},
|
|
515
|
+
data: {
|
|
516
|
+
mask: "0000-00-00",
|
|
517
|
+
regex: "^([0-9]{4}(-[0-9]{2}){2})$",
|
|
518
|
+
validate: (data: any) => {
|
|
519
|
+
if (!data) { return false; }
|
|
520
|
+
data = LibUtil.apenasNumeros(data);
|
|
521
|
+
return new RegExp(LibUtil.formats.data.regex).test(data);
|
|
522
|
+
},
|
|
523
|
+
},
|
|
524
|
+
dataIso: {
|
|
525
|
+
mask: "0000-00-00T00:00:00.000Z",
|
|
526
|
+
regex: "^([0-9]{4}(-[0-9]{2}){2}T[0-9]{2}(:[0-9]{2}){2}\.[0-9]{3}Z)$",
|
|
527
|
+
validate: (dataIso: any) => {
|
|
528
|
+
if (!dataIso) { return false; }
|
|
529
|
+
dataIso = LibUtil.apenasNumeros(dataIso);
|
|
530
|
+
return new RegExp(LibUtil.formats.dataIso.regex).test(dataIso);
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
numero: {
|
|
534
|
+
mask: "#0",
|
|
535
|
+
regex: "^[0-9]*$",
|
|
536
|
+
validate: (numero: any) => {
|
|
537
|
+
if (!numero) { return false; }
|
|
538
|
+
numero = LibUtil.apenasNumeros(numero);
|
|
539
|
+
return numero.length > 0;
|
|
540
|
+
},
|
|
541
|
+
},
|
|
542
|
+
decimal: {
|
|
543
|
+
mask: "#0,00",
|
|
544
|
+
regex: "^[0-9,]*$",
|
|
545
|
+
validate: (decimal: any) => {
|
|
546
|
+
if (!decimal) { return false; }
|
|
547
|
+
return new RegExp(LibUtil.formats.decimal.regex).test(decimal);
|
|
548
|
+
},
|
|
549
|
+
},
|
|
550
|
+
letra: {
|
|
551
|
+
mask: "A",
|
|
552
|
+
regex: "^[A-Za-z]*$",
|
|
553
|
+
validate: (letra: any) => {
|
|
554
|
+
if (!letra) { return false; }
|
|
555
|
+
return new RegExp(LibUtil.formats.letra.regex).test(letra);
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
numeroELetra: {
|
|
559
|
+
mask: "S",
|
|
560
|
+
regex: "^[A-Za-z0-9]*$",
|
|
561
|
+
validate: (numeroELetra: any) => {
|
|
562
|
+
if (!numeroELetra) { return false; }
|
|
563
|
+
return new RegExp(LibUtil.formats.numeroELetra.regex).test(numeroELetra);
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
ip: {
|
|
567
|
+
mask: "000.000.000.000",
|
|
568
|
+
regex: "^([0-2]?[0-9]?[0-9]([\.][0-2]?[0-9]?[0-9]){3})$",
|
|
569
|
+
validate: (ip: any) => {
|
|
570
|
+
if (!ip) { return false; }
|
|
571
|
+
const regex = new RegExp(LibUtil.formats.ip.regex);
|
|
572
|
+
if (!regex.test(ip)) { return false; }
|
|
573
|
+
const parts = ip.split('.').map(Number);
|
|
574
|
+
return parts.every((part: number) => part >= 0 && part <= 255);
|
|
575
|
+
}
|
|
576
|
+
},
|
|
577
|
+
email: {
|
|
578
|
+
mask: "S",
|
|
579
|
+
regex: "^(([a-zA-Z0-9_+-\.]+)+)@([a-zA-Z0-9_+-\.]+\.[a-zA-Z]+)+$",
|
|
580
|
+
validate: (email: any) => {
|
|
581
|
+
if (!email) { return false; }
|
|
582
|
+
return new RegExp(LibUtil.formats.email.regex).test(email);
|
|
583
|
+
}
|
|
584
|
+
},
|
|
585
|
+
cep: {
|
|
586
|
+
mask: "00000-000",
|
|
587
|
+
regex: "^([0-9]{5}[-]?[0-9]{3})$",
|
|
588
|
+
validate: (cep: any) => {
|
|
589
|
+
if (!cep) { return false; }
|
|
590
|
+
cep = LibUtil.apenasNumeros(cep);
|
|
591
|
+
return new RegExp(LibUtil.formats.cep.regex).test(cep);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
static stringToDataBR = (data: string | null | undefined): string | null => {
|
|
597
|
+
let resultado = null;
|
|
598
|
+
if (LibUtil.classof(data) == "null" || LibUtil.classof(data) == "undefined") {
|
|
599
|
+
return null;
|
|
600
|
+
} else if (LibUtil.classof(data) == "string") {
|
|
601
|
+
// Quando a data é "YYYY-MM-DD", ascrescenta 1 espaço para UTC.
|
|
602
|
+
if (new RegExp("^[12][0-9]{3}[-][0-1][0-9][-][0-3][0-9]$").test(data!)) {
|
|
603
|
+
data += " ";
|
|
604
|
+
}
|
|
605
|
+
// Tentativa Direta:
|
|
606
|
+
resultado = new Date(data!).toLocaleString().replace(",", "");
|
|
607
|
+
|
|
608
|
+
// Falhando, tenta converter pra número.
|
|
609
|
+
if (resultado.toUpperCase() == "INVALID DATE") {
|
|
610
|
+
resultado = new Date(Number(data)).toLocaleString().replace(",", "");
|
|
611
|
+
|
|
612
|
+
// Agora tenta ver se a data inicia no formato br já
|
|
613
|
+
if (resultado.toUpperCase() == "INVALID DATE") {
|
|
614
|
+
// DD/MM/YYYY ?
|
|
615
|
+
if (new RegExp("^[0-3][0-9][/][0-1][0-9][/][0-2][0-9]{3}").test(data!)) {
|
|
616
|
+
resultado = new Date(LibUtil.dataToIsoData(data!)).toLocaleString().replace(",", "");
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
} else {
|
|
621
|
+
LOG(1, "❌ stringToDataBR(): A data precisa ser formato string: ", data, LibUtil.classof(data));
|
|
622
|
+
}
|
|
623
|
+
return resultado;
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// ISO 8601 (Padrão Internacional)
|
|
627
|
+
static dataToIsoData = (data: string): string => {
|
|
628
|
+
// Converter de DD/MM/YYYY para YYYY-MM-DD
|
|
629
|
+
if (new RegExp("^[0-3][0-9][/][0-1][0-9][/][0-2][0-9]{3}").test(data)) {
|
|
630
|
+
|
|
631
|
+
}
|
|
632
|
+
if (new RegExp("^[0-3][0-9][/][0-1][0-9][/][0-2][0-9]{3}").test(data)) {
|
|
633
|
+
let novaData = data.slice(6, 10) + "-" + data.slice(3, 5) + "-" + data.slice(0, 2);
|
|
634
|
+
let resto = data.slice(10, data.length);
|
|
635
|
+
if (resto != "" && new RegExp("^ [0-2][0-9]:[0-5][0-9]:[0-5][0-9]").test(resto)) {
|
|
636
|
+
novaData += resto;
|
|
637
|
+
}
|
|
638
|
+
return novaData;
|
|
639
|
+
}
|
|
640
|
+
return data; // < Se falhar
|
|
641
|
+
};
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
|
|
658
|
+
|
|
659
|
+
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
// ============================ SIGNALS DIRETO => CRUD E UTEIS ============================ \\
|
|
663
|
+
|
|
664
|
+
// SET (SIGNAL)
|
|
665
|
+
static sinalSet<T>(sinal: WritableSignal<any | undefined>, item: Partial<T>) {
|
|
666
|
+
sinal.update(i => {
|
|
667
|
+
if (!i) return item;
|
|
668
|
+
return { ...i, ...item };
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// CREATE (SIGNAL)
|
|
673
|
+
static sinalCreate<T>(sinal: WritableSignal<any[] | undefined>, item: T) {
|
|
674
|
+
sinal.update(i => {
|
|
675
|
+
if (!i) return [item];
|
|
676
|
+
return [...i, item];
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
// UPDATE (SIGNAL)
|
|
681
|
+
static sinalUpdate<T>(sinal: WritableSignal<any[] | undefined>, item: Partial<T>, k: string, v?: string) {
|
|
682
|
+
if (v != null && item) {
|
|
683
|
+
sinal.update(i => {
|
|
684
|
+
if (!i) return i;
|
|
685
|
+
return i.map((o: T) => o[k as keyof T] === v ? { ...o, ...item } : o);
|
|
686
|
+
});
|
|
687
|
+
} else {
|
|
688
|
+
if (v == null) {
|
|
689
|
+
// PATCH UPDATE
|
|
690
|
+
let value = item[k as keyof T];
|
|
691
|
+
if (value != null) {
|
|
692
|
+
sinal.update(i => {
|
|
693
|
+
if (!i) return i;
|
|
694
|
+
return i.map((o: T) => o[k as keyof T] === value ? { ...o, ...item } : o);
|
|
695
|
+
});
|
|
696
|
+
} else {
|
|
697
|
+
LOG(1, `⚠️ sinalUpdate: A chave ${k} está nula. Passe o V desta chave para atualizar.`);
|
|
698
|
+
}
|
|
699
|
+
} else {
|
|
700
|
+
LOG(1, `❌ Item ${k} chegou nulo para Update.`);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// DELETE (SIGNAL)
|
|
706
|
+
static sinalDelete<T>(sinal: WritableSignal<any[] | undefined>, k: string, v?: string) {
|
|
707
|
+
if (v != null) {
|
|
708
|
+
sinal.update(i => {
|
|
709
|
+
if (!i) return i;
|
|
710
|
+
return i.filter((o: T) => o[k as keyof T] !== v);
|
|
711
|
+
});
|
|
712
|
+
} else {
|
|
713
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para Delete.`);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
// CLEAR (SIGNAL)
|
|
718
|
+
static sinalClear<T>(sinal: WritableSignal<any[] | undefined>) {
|
|
719
|
+
sinal.set(undefined);
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
// EXISTS (SIGNAL) - Verifica se um item existe na lista
|
|
723
|
+
static sinalExists<T>(sinal: WritableSignal<any[] | undefined>, k: Extract<keyof T, string>, v: string): boolean {
|
|
724
|
+
if (v != null) {
|
|
725
|
+
const items = sinal();
|
|
726
|
+
if (!items) return false;
|
|
727
|
+
return items.some((o: T) => o[k] === v);
|
|
728
|
+
} else {
|
|
729
|
+
return false;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
// MOVE UP (SIGNAL) - Move um item uma posição para cima
|
|
735
|
+
static sinalMoveUp<T>(sinal: WritableSignal<any[] | undefined>, k: Extract<keyof T, string>, v: string) {
|
|
736
|
+
if (v != null) {
|
|
737
|
+
sinal.update(i => {
|
|
738
|
+
if (!i || i.length <= 1) return i;
|
|
739
|
+
const index = i.findIndex((o: T) => o[k] === v);
|
|
740
|
+
if (index <= 0) return i; // Já está no topo ou não encontrado
|
|
741
|
+
|
|
742
|
+
const newArray = [...i];
|
|
743
|
+
[newArray[index - 1], newArray[index]] = [newArray[index], newArray[index - 1]];
|
|
744
|
+
return newArray;
|
|
745
|
+
});
|
|
746
|
+
} else {
|
|
747
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para MoveUp.`);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
// MOVE DOWN (SIGNAL) - Move um item uma posição para baixo
|
|
752
|
+
static sinalMoveDown<T>(sinal: WritableSignal<any[] | undefined>, k: Extract<keyof T, string>, v: string) {
|
|
753
|
+
if (v != null) {
|
|
754
|
+
sinal.update(i => {
|
|
755
|
+
if (!i || i.length <= 1) return i;
|
|
756
|
+
|
|
757
|
+
const index = i.findIndex((o: T) => o[k] === v);
|
|
758
|
+
if (index < 0 || index >= i.length - 1) return i; // Já está no final ou não encontrado
|
|
759
|
+
|
|
760
|
+
const newArray = [...i];
|
|
761
|
+
[newArray[index], newArray[index + 1]] = [newArray[index + 1], newArray[index]];
|
|
762
|
+
return newArray;
|
|
763
|
+
});
|
|
764
|
+
} else {
|
|
765
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para MoveDown.`);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// MOVE TO INDEX (SIGNAL) - Move um item para uma posição específica
|
|
770
|
+
static sinalMoveToIndex<T>(sinal: WritableSignal<any[] | undefined>, k: Extract<keyof T, string>, v: string, targetIndex: number) {
|
|
771
|
+
if (v != null) {
|
|
772
|
+
sinal.update(i => {
|
|
773
|
+
if (!i || i.length <= 1) return i;
|
|
774
|
+
const currentIndex = i.findIndex((o: T) => o[k] === v);
|
|
775
|
+
if (currentIndex < 0 || targetIndex < 0 || targetIndex >= i.length || currentIndex === targetIndex) {
|
|
776
|
+
return i; // Item não encontrado, índice inválido ou já está na posição
|
|
777
|
+
}
|
|
778
|
+
const newArray = [...i];
|
|
779
|
+
const [movedItem] = newArray.splice(currentIndex, 1);
|
|
780
|
+
newArray.splice(targetIndex, 0, movedItem);
|
|
781
|
+
return newArray;
|
|
782
|
+
});
|
|
783
|
+
} else {
|
|
784
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para MoveToIndex.`);
|
|
785
|
+
}
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
static FlatRecursivo<T>(lista: T[], keyRecursive: keyof T): T[] {
|
|
789
|
+
if (LibUtil.classof(lista) != "array") return [];
|
|
790
|
+
|
|
791
|
+
let novaArray: T[] = [];
|
|
792
|
+
lista.map(objeto => {
|
|
793
|
+
if (LibUtil.classof(objeto) != "object") return;
|
|
794
|
+
let novoObjeto: T = {} as T;
|
|
795
|
+
for (let prop in objeto) {
|
|
796
|
+
if (prop != keyRecursive) novoObjeto[prop] = objeto[prop];
|
|
797
|
+
}
|
|
798
|
+
novaArray = [...novaArray, novoObjeto];
|
|
799
|
+
let children = objeto[keyRecursive] as T[];
|
|
800
|
+
if (children != null) {
|
|
801
|
+
novaArray = [...novaArray, ...LibUtil.FlatRecursivo(children, keyRecursive)];
|
|
802
|
+
}
|
|
803
|
+
})
|
|
804
|
+
return novaArray;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// ============================ SIGNALS RECURSIVO => CRUD E UTEIS ============================ \\
|
|
808
|
+
|
|
809
|
+
// Adiciona um novo item em uma estrutura hierárquica baseado na chave pai
|
|
810
|
+
// CREATE RECURSIVE (SIGNAL)
|
|
811
|
+
static sinalCreateRecursive<T>(sinal: WritableSignal<any[] | undefined>, item: T, keyRecursive: keyof T, keyPai: Extract<keyof T, string>, valuePai?: string) {
|
|
812
|
+
sinal.update(i => {
|
|
813
|
+
if (!i) return [item];
|
|
814
|
+
if (valuePai != null) {
|
|
815
|
+
return i.map((o: T) => {
|
|
816
|
+
return LibUtil._recursiveCreate<T>(o, item, keyRecursive, keyPai, valuePai);
|
|
817
|
+
});
|
|
818
|
+
} else {
|
|
819
|
+
// Sem Pai inserir direto na raiz
|
|
820
|
+
return [...i, item];
|
|
821
|
+
}
|
|
822
|
+
});
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Encontra o item pai pela chave e adiciona o novo item no array de filhos
|
|
826
|
+
static _recursiveCreate<T>(atual: T, novo: T, keyRecursive: keyof T, keyPai: Extract<keyof T, string>, valuePai: string): T {
|
|
827
|
+
if (atual[keyPai] === valuePai) {
|
|
828
|
+
// Encontrou o pai, adiciona o item no array recursivo
|
|
829
|
+
if (atual[keyRecursive] == null) {
|
|
830
|
+
(atual[keyRecursive] as T[]) = [novo];
|
|
831
|
+
} else {
|
|
832
|
+
(atual[keyRecursive] as T[]) = [...(atual[keyRecursive] as T[]), novo];
|
|
833
|
+
}
|
|
834
|
+
return atual;
|
|
835
|
+
}
|
|
836
|
+
if (atual[keyRecursive] == null || (atual[keyRecursive] as T[])?.length == 0) return atual;
|
|
837
|
+
(atual[keyRecursive] as T[]) = [
|
|
838
|
+
...(atual[keyRecursive] as T[]).map(child => {
|
|
839
|
+
return LibUtil._recursiveCreate(child, novo, keyRecursive, keyPai, valuePai);
|
|
840
|
+
})
|
|
841
|
+
];
|
|
842
|
+
return atual;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
// Atualiza um item específico em uma estrutura hierárquica
|
|
846
|
+
// UPDATE RECURSIVE (SIGNAL)
|
|
847
|
+
static sinalUpdateRecursive<T>(sinal: WritableSignal<any[] | undefined>, item: Partial<T>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string) {
|
|
848
|
+
if (v != null) {
|
|
849
|
+
sinal.update(i => {
|
|
850
|
+
if (!i) return i;
|
|
851
|
+
return i.map((o: T) => {
|
|
852
|
+
return LibUtil._recursiveUpdate<T>(o, item, keyRecursive, k, v);
|
|
853
|
+
});
|
|
854
|
+
});
|
|
855
|
+
} else {
|
|
856
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para Update Recursivo.`);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
// Encontra o item pela chave e atualiza suas propriedades
|
|
861
|
+
static _recursiveUpdate<T>(atual: T, novo: Partial<T>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): T {
|
|
862
|
+
if (atual[k] === v) {
|
|
863
|
+
LOG(1, "Editado", { ...atual, ...novo })
|
|
864
|
+
return { ...atual, ...novo };
|
|
865
|
+
}
|
|
866
|
+
if (atual[keyRecursive] == null || (atual[keyRecursive] as T[])?.length == 0) return atual;
|
|
867
|
+
(atual[keyRecursive] as T[]) = [
|
|
868
|
+
...(atual[keyRecursive] as T[]).map(child => {
|
|
869
|
+
return LibUtil._recursiveUpdate(child, novo, keyRecursive, k, v);
|
|
870
|
+
})
|
|
871
|
+
];
|
|
872
|
+
return atual;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
// Remove um item específico de uma estrutura hierárquica
|
|
876
|
+
// DELETE RECURSIVE (SIGNAL)
|
|
877
|
+
static sinalDeleteRecursive<T>(sinal: WritableSignal<any[] | undefined>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string) {
|
|
878
|
+
if (v != null) {
|
|
879
|
+
sinal.update(i => {
|
|
880
|
+
if (!i) return i;
|
|
881
|
+
// Primeiro verifica se precisa deletar no nível raiz
|
|
882
|
+
const filteredRoot = i.filter((o: T) => o[k] !== v);
|
|
883
|
+
// Se encontrou e removeu no nível raiz, retorna o array filtrado
|
|
884
|
+
if (filteredRoot.length !== i.length) {
|
|
885
|
+
return filteredRoot;
|
|
886
|
+
}
|
|
887
|
+
// Se não encontrou no nível raiz, processa recursivamente
|
|
888
|
+
return i.map((o: T) => {
|
|
889
|
+
return LibUtil._recursiveDelete<T>(o, keyRecursive, k, v);
|
|
890
|
+
});
|
|
891
|
+
});
|
|
892
|
+
} else {
|
|
893
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para Delete Recursivo.`);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
// Encontra e remove o item pela chave, filtrando do array de filhos
|
|
897
|
+
static _recursiveDelete<T>(atual: T, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): T {
|
|
898
|
+
// Se tem filhos, processa os filhos
|
|
899
|
+
if (atual[keyRecursive] && (atual[keyRecursive] as T[])?.length > 0) {
|
|
900
|
+
const children = atual[keyRecursive] as T[];
|
|
901
|
+
// Remove o item dos filhos se existir e processa recursivamente os filhos restantes
|
|
902
|
+
const filteredChildren = children
|
|
903
|
+
.filter(child => child[k] !== v)
|
|
904
|
+
.map(child => LibUtil._recursiveDelete(child, keyRecursive, k, v));
|
|
905
|
+
return { ...atual, [keyRecursive]: filteredChildren };
|
|
906
|
+
}
|
|
907
|
+
return atual;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
// EXISTS RECURSIVE (SIGNAL) - Verifica se um item existe em uma estrutura hierárquica
|
|
911
|
+
static sinalExistsRecursive<T>(sinal: WritableSignal<any[] | undefined>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): boolean {
|
|
912
|
+
if (v != null) {
|
|
913
|
+
const items = sinal();
|
|
914
|
+
if (!items) return false;
|
|
915
|
+
return items.some((o: T) => {
|
|
916
|
+
return LibUtil._recursiveExists<T>(o, keyRecursive, k, v);
|
|
917
|
+
});
|
|
918
|
+
} else {
|
|
919
|
+
return false;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// Função auxiliar para busca recursiva
|
|
924
|
+
static _recursiveExists<T>(atual: T, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): boolean {
|
|
925
|
+
// Verifica se o item atual é o que estamos procurando
|
|
926
|
+
if (atual[k] === v) return true;
|
|
927
|
+
// Se tem filhos, procura recursivamente
|
|
928
|
+
if (atual[keyRecursive] && (atual[keyRecursive] as T[])?.length > 0) {
|
|
929
|
+
const children = atual[keyRecursive] as T[];
|
|
930
|
+
return children.some(child => LibUtil._recursiveExists(child, keyRecursive, k, v));
|
|
931
|
+
}
|
|
932
|
+
return false;
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
// Move um item uma posição para cima na hierarquia
|
|
936
|
+
// MOVE UP RECURSIVE (SIGNAL) - Para estruturas hierárquicas
|
|
937
|
+
static sinalMoveUpRecursive<T>(sinal: WritableSignal<any[] | undefined>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string) {
|
|
938
|
+
if (v != null) {
|
|
939
|
+
sinal.update(i => {
|
|
940
|
+
if (!i || i.length <= 1) return i;
|
|
941
|
+
// Primeiro verifica se precisa mover no nível raiz
|
|
942
|
+
const rootIndex = i.findIndex((o: T) => o[k] === v);
|
|
943
|
+
if (rootIndex > 0) {
|
|
944
|
+
const newArray = [...i];
|
|
945
|
+
[newArray[rootIndex - 1], newArray[rootIndex]] = [newArray[rootIndex], newArray[rootIndex - 1]];
|
|
946
|
+
return newArray;
|
|
947
|
+
}
|
|
948
|
+
// Se não encontrou no nível raiz, processa recursivamente
|
|
949
|
+
return i.map((o: T) => {
|
|
950
|
+
return LibUtil._recursiveMoveUp<T>(o, keyRecursive, k, v);
|
|
951
|
+
});
|
|
952
|
+
});
|
|
953
|
+
} else {
|
|
954
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para MoveUp Recursivo.`);
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// Encontra o item e troca sua posição com o anterior no array
|
|
959
|
+
static _recursiveMoveUp<T>(atual: T, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): T {
|
|
960
|
+
// Se tem filhos, processa os filhos primeiro
|
|
961
|
+
if (atual[keyRecursive] && (atual[keyRecursive] as T[])?.length > 0) {
|
|
962
|
+
const children = atual[keyRecursive] as T[];
|
|
963
|
+
// Verifica se precisa mover dentro dos filhos
|
|
964
|
+
const targetIndex = children.findIndex(child => child[k] === v);
|
|
965
|
+
if (targetIndex > 0) {
|
|
966
|
+
const newChildren = [...children];
|
|
967
|
+
[newChildren[targetIndex - 1], newChildren[targetIndex]] = [newChildren[targetIndex], newChildren[targetIndex - 1]];
|
|
968
|
+
return { ...atual, [keyRecursive]: newChildren };
|
|
969
|
+
}
|
|
970
|
+
// Se não encontrou, processa recursivamente os filhos
|
|
971
|
+
const processedChildren = children.map(child =>
|
|
972
|
+
LibUtil._recursiveMoveUp(child, keyRecursive, k, v)
|
|
973
|
+
);
|
|
974
|
+
return { ...atual, [keyRecursive]: processedChildren };
|
|
975
|
+
}
|
|
976
|
+
return atual;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// Move um item uma posição para baixo na hierarquia
|
|
980
|
+
// MOVE DOWN RECURSIVE (SIGNAL) - Para estruturas hierárquicas
|
|
981
|
+
static sinalMoveDownRecursive<T>(sinal: WritableSignal<any[] | undefined>, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string) {
|
|
982
|
+
if (v != null) {
|
|
983
|
+
sinal.update(i => {
|
|
984
|
+
if (!i || i.length <= 1) return i;
|
|
985
|
+
// Primeiro verifica se precisa mover no nível raiz
|
|
986
|
+
const rootIndex = i.findIndex((o: T) => o[k] === v);
|
|
987
|
+
if (rootIndex >= 0 && rootIndex < i.length - 1) {
|
|
988
|
+
const newArray = [...i];
|
|
989
|
+
[newArray[rootIndex], newArray[rootIndex + 1]] = [newArray[rootIndex + 1], newArray[rootIndex]];
|
|
990
|
+
return newArray;
|
|
991
|
+
}
|
|
992
|
+
// Se não encontrou no nível raiz, processa recursivamente
|
|
993
|
+
return i.map((o: T) => {
|
|
994
|
+
return LibUtil._recursiveMoveDown<T>(o, keyRecursive, k, v);
|
|
995
|
+
});
|
|
996
|
+
});
|
|
997
|
+
} else {
|
|
998
|
+
LOG(1, `⚠️ Chave ${k} chegou nula para MoveDown Recursivo.`);
|
|
999
|
+
}
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
// Encontra o item e troca sua posição com o próximo no array
|
|
1003
|
+
static _recursiveMoveDown<T>(atual: T, keyRecursive: keyof T, k: Extract<keyof T, string>, v: string): T {
|
|
1004
|
+
if (atual[keyRecursive] && (atual[keyRecursive] as T[])?.length > 0) {
|
|
1005
|
+
const children = atual[keyRecursive] as T[];
|
|
1006
|
+
// Verifica se precisa mover dentro dos filhos
|
|
1007
|
+
const targetIndex = children.findIndex(child => child[k] === v);
|
|
1008
|
+
if (targetIndex >= 0 && targetIndex < children.length - 1) {
|
|
1009
|
+
const newChildren = [...children];
|
|
1010
|
+
[newChildren[targetIndex], newChildren[targetIndex + 1]] = [newChildren[targetIndex + 1], newChildren[targetIndex]];
|
|
1011
|
+
return { ...atual, [keyRecursive]: newChildren };
|
|
1012
|
+
}
|
|
1013
|
+
// Se não encontrou, processa recursivamente os filhos
|
|
1014
|
+
const processedChildren = children.map(child =>
|
|
1015
|
+
LibUtil._recursiveMoveDown(child, keyRecursive, k, v)
|
|
1016
|
+
);
|
|
1017
|
+
return { ...atual, [keyRecursive]: processedChildren };
|
|
1018
|
+
}
|
|
1019
|
+
return atual;
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
static sinalSetOrderRecursive<T>(sinal: WritableSignal<any[] | undefined>, keyRecursive: keyof T, k: Extract<keyof T, string>, propOrder: keyof T) {
|
|
1023
|
+
sinal.update(i => {
|
|
1024
|
+
if (!i) return i;
|
|
1025
|
+
return i.map((o: T, i) => {
|
|
1026
|
+
return LibUtil._recursiveSetOrder<T>(o, keyRecursive, k, propOrder, i);
|
|
1027
|
+
});
|
|
1028
|
+
});
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
static _recursiveSetOrder<T>(atual: T, keyRecursive: keyof T, k: Extract<keyof T, string>, propOrder: keyof T, index: number): T {
|
|
1032
|
+
atual = { ...atual, [propOrder]: index };
|
|
1033
|
+
if (atual[keyRecursive] == null || (atual[keyRecursive] as T[])?.length == 0) return atual;
|
|
1034
|
+
(atual[keyRecursive] as T[]) = [
|
|
1035
|
+
...(atual[keyRecursive] as T[]).map((child, i) => {
|
|
1036
|
+
return LibUtil._recursiveSetOrder(child, keyRecursive, k, propOrder, i);
|
|
1037
|
+
})
|
|
1038
|
+
];
|
|
1039
|
+
return atual;
|
|
1040
|
+
}
|
|
1041
|
+
|
|
1042
|
+
// ============================ ATALHOS PERSONALIZADOS ============================ \\
|
|
1043
|
+
|
|
1044
|
+
static Q = (query: any) => {
|
|
1045
|
+
// Busca elemento único, podendo buscar ele mesmo. (Bifurcacado)
|
|
1046
|
+
if (LibUtil.classof(query) == "string") return document.querySelector(query);
|
|
1047
|
+
return query;
|
|
1048
|
+
};
|
|
1049
|
+
|
|
1050
|
+
static QAll = (query: any): any[] => {
|
|
1051
|
+
// Sempre retorna uma array de encontrados. Inclusive uma array com um LibUtil.Q
|
|
1052
|
+
if (LibUtil.classof(query) == "string") {
|
|
1053
|
+
// Se buscando uma string, retorna a array do select encontrado
|
|
1054
|
+
return Array.from(document.querySelectorAll(query));
|
|
1055
|
+
} else if (LibUtil.classof(query).endsWith("Element")) {
|
|
1056
|
+
// Quando buscar um único elemento, retorna o elemento em uma lista.
|
|
1057
|
+
return [query];
|
|
1058
|
+
} else if (LibUtil.classof(query) == "array") {
|
|
1059
|
+
// Quando buscar uma array, retorna a propria array. (Bifurcado)
|
|
1060
|
+
return query;
|
|
1061
|
+
} else {
|
|
1062
|
+
LOG(1, "⚠️ QAll() - Requer String / Elemento / Array. ClassOf: ", LibUtil.classof(query), " Query: ", query);
|
|
1063
|
+
return [];
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
|
|
1067
|
+
static QverOff = (query: Element | HTMLElement | string | null = "body"): any[] => {
|
|
1068
|
+
// Adiciona Classe Oculto em todos os elementos do Query
|
|
1069
|
+
// Retorna uma array de elementos por causa do QAll
|
|
1070
|
+
return LibUtil.aCadaElemento(query, (e: any) => {
|
|
1071
|
+
e?.classList.add("oculto");
|
|
1072
|
+
});
|
|
1073
|
+
};
|
|
1074
|
+
|
|
1075
|
+
static QverOn = (query: Element | HTMLElement | string | null = "body") => {
|
|
1076
|
+
// Remove classe Oculto em todos os elementos do Query
|
|
1077
|
+
// Retorna uma array de elementos por causa do QAll
|
|
1078
|
+
return LibUtil.aCadaElemento(query, (e: any) => {
|
|
1079
|
+
e?.classList.remove("oculto");
|
|
1080
|
+
});
|
|
1081
|
+
};
|
|
1082
|
+
|
|
1083
|
+
static dataGetMs = (data: string | null = null): number => {
|
|
1084
|
+
// Retorna Milisegundos da data no formato Javascript
|
|
1085
|
+
if (data != null) {
|
|
1086
|
+
if (data.length > 10) {
|
|
1087
|
+
// Recomendado que os dados cheguem: 'YYYY-MM-DD HH:MM:SS'
|
|
1088
|
+
return new Date(data).getTime(); // Recomendado que os dados
|
|
1089
|
+
} else {
|
|
1090
|
+
let dataCortada = data.split("-");
|
|
1091
|
+
let oDia: number = Number(dataCortada[2]);
|
|
1092
|
+
let oMes: number = Number(dataCortada[1]) - 1;
|
|
1093
|
+
let oAno: number = Number(dataCortada[0]);
|
|
1094
|
+
return new Date(oAno, oMes, oDia).getTime();
|
|
1095
|
+
}
|
|
1096
|
+
} else return new Date().getTime();
|
|
1097
|
+
};
|
|
1098
|
+
|
|
1099
|
+
static dataMsToSegundos = (num: number, reverse: boolean = false) => {
|
|
1100
|
+
if (reverse) {
|
|
1101
|
+
return num * 1000;
|
|
1102
|
+
}
|
|
1103
|
+
return Math.trunc(num / 1000); // 1000 ms == 1s
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
static dataMsToDias = (num: number, reverse: boolean = false) => {
|
|
1107
|
+
// 1000 * 3600 * 24 Considerando todo dia tiver 24 horas (~23h 56m 4.1s)
|
|
1108
|
+
// (360º translacao / 86400000) = ~4.1
|
|
1109
|
+
// Então o erro de 1 dia ocorre 1x ao ano (Dia represeta 1436min).
|
|
1110
|
+
// Por isso, é melhor trabalhar com Dias em vez de outro formato maior.
|
|
1111
|
+
if (reverse) {
|
|
1112
|
+
return Math.trunc(num * 86400000);
|
|
1113
|
+
}
|
|
1114
|
+
return Math.trunc(num / 86400000);
|
|
1115
|
+
};
|
|
1116
|
+
|
|
1117
|
+
static dataGetSegundosDiferenca = (msDe: number, msAte: number | null = null): number => {
|
|
1118
|
+
// Retorna a diferença de segundos entre dois MS
|
|
1119
|
+
if (msAte == null) msAte = LibUtil.dataGetMs();
|
|
1120
|
+
return LibUtil.dataMsToSegundos(msAte - msDe);
|
|
1121
|
+
};
|
|
1122
|
+
|
|
1123
|
+
static dataGetDiasDiferenca = (msDe: number, msAte: number | null = null): number => {
|
|
1124
|
+
// Retorna a diferença de dias entre dois MS
|
|
1125
|
+
if (msAte == null) msAte = LibUtil.dataGetMs();
|
|
1126
|
+
return LibUtil.dataMsToDias(msAte - msDe);
|
|
1127
|
+
};
|
|
1128
|
+
|
|
1129
|
+
static dataShowTempoDiferenca = (msDe: number | string, msAte: number | string | null = null) => {
|
|
1130
|
+
if (LibUtil.classof(msDe) == "string") msDe = LibUtil.dataGetMs(msDe as string);
|
|
1131
|
+
if (LibUtil.classof(msAte) == "string") msAte = LibUtil.dataGetMs(msAte as string);
|
|
1132
|
+
let dias = LibUtil.dataGetDiasDiferenca(msDe as number, msAte as number | null);
|
|
1133
|
+
if (dias < 0) {
|
|
1134
|
+
dias = dias * -1;
|
|
1135
|
+
}
|
|
1136
|
+
let strTempo = "";
|
|
1137
|
+
if (dias > 29) { // Em Meses
|
|
1138
|
+
if (dias < 60) {
|
|
1139
|
+
strTempo = "1 mês";
|
|
1140
|
+
} else {
|
|
1141
|
+
if (dias > 365) { // Em Anos (+ Meses restantes)
|
|
1142
|
+
let anos = Math.floor(dias / 365);
|
|
1143
|
+
let diasRestoAno = dias % 365;
|
|
1144
|
+
if (anos < 2) {
|
|
1145
|
+
strTempo += anos + " ano ";
|
|
1146
|
+
} else {
|
|
1147
|
+
strTempo += anos + " anos ";
|
|
1148
|
+
}
|
|
1149
|
+
if (diasRestoAno > 30) {
|
|
1150
|
+
if (diasRestoAno < 60) {
|
|
1151
|
+
strTempo += "1 mês";
|
|
1152
|
+
} else {
|
|
1153
|
+
strTempo += Math.floor(diasRestoAno / 30) + " meses";
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
} else {
|
|
1157
|
+
strTempo = Math.floor(dias / 30) + " meses";
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
} else {
|
|
1161
|
+
if (dias < 1) {
|
|
1162
|
+
let segundos = LibUtil.dataGetSegundosDiferenca(msDe as number, msAte as number);
|
|
1163
|
+
if (segundos > 7199) { // Em Horas
|
|
1164
|
+
strTempo = Math.floor(segundos / 3600) + " horas";
|
|
1165
|
+
} else {
|
|
1166
|
+
if (segundos > 3599) {
|
|
1167
|
+
strTempo = "1 hora";
|
|
1168
|
+
} else {
|
|
1169
|
+
if (segundos > 119) { // Em Minutos
|
|
1170
|
+
strTempo = Math.floor(segundos / 60) + " minutos";
|
|
1171
|
+
} else {
|
|
1172
|
+
if (segundos > 59) {
|
|
1173
|
+
strTempo = "1 minuto";
|
|
1174
|
+
} else {
|
|
1175
|
+
strTempo = Math.floor(segundos) + " segundos";
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
} else { // Em Dias
|
|
1181
|
+
strTempo = dias + " dias";
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
if (strTempo.includes("NaN")) return "";
|
|
1185
|
+
return strTempo;
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1188
|
+
static displayCelular = (area: string, numero: string, isoDDI?: string): string => {
|
|
1189
|
+
if (numero == null) numero = ""
|
|
1190
|
+
else numero = LibUtil.apenasNumeros(numero);
|
|
1191
|
+
if (area == null) area = "";
|
|
1192
|
+
else area = LibUtil.apenasEstes(area, "0-9\+");
|
|
1193
|
+
if (numero == "" && area == "") return "";
|
|
1194
|
+
let displayArea = area;
|
|
1195
|
+
let displayNumero = numero;
|
|
1196
|
+
let displayFlag = "";
|
|
1197
|
+
if (numero != "" && displayArea == "") displayArea = "+55"
|
|
1198
|
+
if (displayArea == "+55") {
|
|
1199
|
+
numero = numero.slice(0, 11); // No brasil o limite é 9.
|
|
1200
|
+
displayNumero = numero;
|
|
1201
|
+
let apenasCelular = numero.slice(2, 11);
|
|
1202
|
+
if (apenasCelular.length == 9) {
|
|
1203
|
+
apenasCelular = apenasCelular.slice(0, 5) + "-" + apenasCelular.slice(5, 9);
|
|
1204
|
+
}
|
|
1205
|
+
displayNumero = "(" + numero.slice(0, 2) + ") " + apenasCelular;
|
|
1206
|
+
}
|
|
1207
|
+
if (isoDDI != null) {
|
|
1208
|
+
displayFlag = LibUtil.displayFlag(isoDDI);
|
|
1209
|
+
}
|
|
1210
|
+
return `${displayFlag}<a href="tel:${area || ""}${numero || ""}">${displayArea} ${displayNumero}</a>`
|
|
1211
|
+
}
|
|
1212
|
+
|
|
1213
|
+
static displayFlag = (pais: string): string => {
|
|
1214
|
+
if (pais != null) {
|
|
1215
|
+
return `<img class="flagSizeIco" src="/images/Paises/${pais || "transparent"}.svg" alt="${pais || "transparent"}" onerror="base_imgonerror(this);"> `
|
|
1216
|
+
}
|
|
1217
|
+
return "";
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
static diaEMes(data: string): string {
|
|
1221
|
+
//Retorna: 01 de Abril
|
|
1222
|
+
let arrData = LibUtil.stringToDataBR(data)?.split(" ")?.[0]?.split("/");
|
|
1223
|
+
return arrData?.[0] + " de " + LibUtil.meses.get(Number(arrData?.[1] || 0))?.[0];
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
// =============== Gerenciamento Monetário / Numérico / Locale =================== \\
|
|
1227
|
+
static toNumber = (valor: any, casas: number = 2): number => {
|
|
1228
|
+
// Informando String/Number, converte para o número de casas c.casas (padrão 2).
|
|
1229
|
+
// LibUtil.toNumber("R$ 1.222,333") => 1222.33
|
|
1230
|
+
if (valor != null) {
|
|
1231
|
+
if (LibUtil.classof(valor) == "string") {
|
|
1232
|
+
// Possiveis separadores
|
|
1233
|
+
let us = [".", ","].reduce((x, y) => (valor.lastIndexOf(x) > valor.lastIndexOf(y)) ? x : y);
|
|
1234
|
+
let posPonto = valor.lastIndexOf(us)
|
|
1235
|
+
if (posPonto >= 0) {
|
|
1236
|
+
let i = valor.slice(0, posPonto);
|
|
1237
|
+
let d = valor.slice(posPonto + 1).slice(0, 2).padEnd(2, "0");
|
|
1238
|
+
i = [...i.toString()].filter(a => { return new RegExp(LibUtil.formats.numero.regex).test(a) }).join("");
|
|
1239
|
+
d = [...d.toString()].filter(a => { return new RegExp(LibUtil.formats.numero.regex).test(a) }).join("");
|
|
1240
|
+
valor = i + "." + d;
|
|
1241
|
+
} else {
|
|
1242
|
+
valor = [...valor.toString()].filter(a => { return new RegExp(LibUtil.formats.numero.regex).test(a) }).join("").padStart(3, "0")
|
|
1243
|
+
valor = valor.padStart(casas, "0");
|
|
1244
|
+
valor = valor.slice(0, -(casas)) + (casas > 0 ? "." : "") + valor.slice(-(casas));
|
|
1245
|
+
}
|
|
1246
|
+
} else if (LibUtil.classof(valor) == "number") {
|
|
1247
|
+
valor = valor.toFixed(casas); // <= Vira String, mas essa função apenas devolve Number
|
|
1248
|
+
} else {
|
|
1249
|
+
LOG(1, "❌ toNumber() - Formato de entrada não implementado: ", LibUtil.classof(valor));
|
|
1250
|
+
}
|
|
1251
|
+
return Number(valor); // <= OutPut Number
|
|
1252
|
+
}
|
|
1253
|
+
return 0; // <= OutPut Number
|
|
1254
|
+
};
|
|
1255
|
+
|
|
1256
|
+
// ============================= ARMAZENADORES ESTÁTICOS ============================ \\
|
|
1257
|
+
static a: any = {
|
|
1258
|
+
ALL: "*/*", // ContentType Blob
|
|
1259
|
+
FORMDATA: "multipart/form-data", // ContentType FORM
|
|
1260
|
+
GET: "GET", // Api Method GET
|
|
1261
|
+
HTML: "text/html", // ContentType HTML
|
|
1262
|
+
JSON: "application/json", // ContentType JSON
|
|
1263
|
+
POST: "POST", // Api Method POST
|
|
1264
|
+
DELETE: "DELETE", // Api Method DELETE
|
|
1265
|
+
SVGINI: "<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' fill='currentColor' viewBox='0 0 16 16'>",
|
|
1266
|
+
SVGFIM: "</svg>",
|
|
1267
|
+
timers: [] as any, // Array para guardar timers em andamento ou finalizados
|
|
1268
|
+
wpool: null as any | null, // WorkerPool quando iniciado
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
static meses = new Map([
|
|
1272
|
+
[1, ["Janeiro", "JAN", "01"]],
|
|
1273
|
+
[2, ["Fevereiro", "FEV", "02"]],
|
|
1274
|
+
[3, ["Março", "MAR", "03"]],
|
|
1275
|
+
[4, ["Abril", "ABR", "04"]],
|
|
1276
|
+
[5, ["Maio", "MAI", "05"]],
|
|
1277
|
+
[6, ["Junho", "JUN", "06"]],
|
|
1278
|
+
[7, ["Julho", "JUL", "07"]],
|
|
1279
|
+
[8, ["Agosto", "AGO", "08"]],
|
|
1280
|
+
[9, ["Setembro", "SET", "09"]],
|
|
1281
|
+
[10, ["Outubro", "OUT", "10"]],
|
|
1282
|
+
[11, ["Novembro", "NOV", "11"]],
|
|
1283
|
+
[12, ["Dezembro", "DEZ", "12"]],
|
|
1284
|
+
]);
|
|
1285
|
+
|
|
1286
|
+
// ============================ TOOLS e JS HELPERS ================================ \\
|
|
1287
|
+
|
|
1288
|
+
static isJson = (s: any): boolean => {
|
|
1289
|
+
try {
|
|
1290
|
+
JSON.parse(s);
|
|
1291
|
+
} catch (e) {
|
|
1292
|
+
return false;
|
|
1293
|
+
}
|
|
1294
|
+
return true;
|
|
1295
|
+
};
|
|
1296
|
+
|
|
1297
|
+
static stringify = (o: any): string => {
|
|
1298
|
+
// Converte o Objeto em String JSON, e aproveita e já remove alguns caracteres de controle.
|
|
1299
|
+
return JSON.stringify(o)
|
|
1300
|
+
?.replace(new RegExp("\n", 'g'), "")
|
|
1301
|
+
?.replace(new RegExp("\r", 'g'), "")
|
|
1302
|
+
?.replace(new RegExp("\t", 'g'), "")
|
|
1303
|
+
?.replace(new RegExp("\b", 'g'), "")
|
|
1304
|
+
?.replace(new RegExp("\f", 'g'), "")
|
|
1305
|
+
};
|
|
1306
|
+
|
|
1307
|
+
static parseJSON = (t: any) => {
|
|
1308
|
+
// Se for um JSON válido. Retorna o objeto, se não null.
|
|
1309
|
+
if (t === "") return "";
|
|
1310
|
+
let resultado = null;
|
|
1311
|
+
try {
|
|
1312
|
+
resultado = JSON.parse(t);
|
|
1313
|
+
} catch (e) {
|
|
1314
|
+
LOG(1, "❌ JSON Inválido: Não foi possível converter o JSON.");
|
|
1315
|
+
return null;
|
|
1316
|
+
}
|
|
1317
|
+
return resultado;
|
|
1318
|
+
};
|
|
1319
|
+
|
|
1320
|
+
// String qualquer em string com números
|
|
1321
|
+
static convertToNumeric = (texto: string): Array<number> => {
|
|
1322
|
+
let arrayDeNumeros = [];
|
|
1323
|
+
for (const char of texto) {
|
|
1324
|
+
arrayDeNumeros.push(char.codePointAt(0) || 0);
|
|
1325
|
+
}
|
|
1326
|
+
return arrayDeNumeros;
|
|
1327
|
+
}
|
|
1328
|
+
|
|
1329
|
+
// COnversor para Texto.
|
|
1330
|
+
static convertToTexto = (arrayNumeros: Array<number>): string => {
|
|
1331
|
+
return String.fromCodePoint(...arrayNumeros);
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
// Conversor para Texto, separado por virgula
|
|
1335
|
+
static convertToTexto2 = (stringNumeros: string): string => {
|
|
1336
|
+
return String.fromCodePoint(...stringNumeros.split(",").map(i => Number(i)));
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
static aCadaElemento = (query: any, fn: Function): any[] => {
|
|
1340
|
+
// A cada elemento encontrado pelo QAll executa a funcao
|
|
1341
|
+
let elementos = LibUtil.QAll(query);
|
|
1342
|
+
elementos.forEach((e: any) => {
|
|
1343
|
+
fn(e);
|
|
1344
|
+
});
|
|
1345
|
+
// Sempre retorna uma array por caus do QAll
|
|
1346
|
+
return elementos;
|
|
1347
|
+
};
|
|
1348
|
+
|
|
1349
|
+
// Executa a FUNCAO em todas as propriedades deste OA. Inclusive Obj.Obj... (Matriz de Dados)
|
|
1350
|
+
static aCadaSubPropriedade = (OA: any, funcao: Function | null = null, exceto: string = "Object") => {
|
|
1351
|
+
let c = 0;
|
|
1352
|
+
for (let a in OA) {
|
|
1353
|
+
if (LibUtil.classof(OA[a]) != exceto) {
|
|
1354
|
+
if (funcao) {
|
|
1355
|
+
funcao(OA[a], a, OA);
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
c++;
|
|
1359
|
+
// Se o atual é objeto, itera internamente
|
|
1360
|
+
if (LibUtil.classof(OA[a]) == "object") {
|
|
1361
|
+
c += LibUtil.aCadaSubPropriedade(OA[a], funcao, exceto);
|
|
1362
|
+
}
|
|
1363
|
+
// Se o atual é array, itera internamente
|
|
1364
|
+
if (LibUtil.classof(OA[a]) == "array") {
|
|
1365
|
+
c += LibUtil.aCadaSubPropriedade(OA[a], funcao, exceto);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return c;
|
|
1369
|
+
};
|
|
1370
|
+
|
|
1371
|
+
static apenasEstes = (s: string = "", regexPossiveis: string = "0-9\+"): string => {
|
|
1372
|
+
if (s == null) return "";
|
|
1373
|
+
let regex = new RegExp("(?![" + regexPossiveis + "]).");
|
|
1374
|
+
return s.toString().replace(regex, "");
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
static getV = (keys: string | string[], objeto: any): any => {
|
|
1378
|
+
// Retorna o valor do chave informada, podendo ser obj.obj.chave
|
|
1379
|
+
// LibUtil.getV("a.b.c",{a:{b:{c:"d"}}})
|
|
1380
|
+
if (LibUtil.classof(objeto) == "object") {
|
|
1381
|
+
if (LibUtil.classof(keys) == "string") {
|
|
1382
|
+
if (keys.includes(".")) {
|
|
1383
|
+
// Multi
|
|
1384
|
+
let ks: string[] = (keys as string).split(".");
|
|
1385
|
+
let lastObj = objeto;
|
|
1386
|
+
let lastV = {};
|
|
1387
|
+
// Iterar o Keys, Ver Obj atual e Setar Conteudo;
|
|
1388
|
+
ks.forEach((k) => {
|
|
1389
|
+
if (lastObj) { // Pode ficar nulo durante
|
|
1390
|
+
lastV = lastObj[k];
|
|
1391
|
+
if (typeof lastV == "object") {
|
|
1392
|
+
lastObj = lastV;
|
|
1393
|
+
} else {
|
|
1394
|
+
lastObj = null;
|
|
1395
|
+
}
|
|
1396
|
+
}
|
|
1397
|
+
});
|
|
1398
|
+
return lastV;
|
|
1399
|
+
} else {
|
|
1400
|
+
// Simples
|
|
1401
|
+
return objeto[(keys as string)];
|
|
1402
|
+
}
|
|
1403
|
+
} else if (LibUtil.classof(keys) == "array") {
|
|
1404
|
+
// Array de Keys. Faz um loop e de forma recursiva tenta pegar o valor. Se o valor não for nulo, interrompe e retorna.
|
|
1405
|
+
let lastV = null;
|
|
1406
|
+
for (let k of (keys as string[])) {
|
|
1407
|
+
lastV = LibUtil.getV(k, objeto);
|
|
1408
|
+
if (lastV != null) {
|
|
1409
|
+
return lastV;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
} else {
|
|
1413
|
+
LOG(1, "❌ getV() - Nome da propriedade precisa ser em String. (" + LibUtil.classof(keys) + "):", keys);
|
|
1414
|
+
}
|
|
1415
|
+
} else {
|
|
1416
|
+
LOG(1, "❌ Para ver a chave, o parametro objeto precisa receber um objeto. (" + typeof objeto + ")");
|
|
1417
|
+
}
|
|
1418
|
+
return null;
|
|
1419
|
+
};
|
|
1420
|
+
|
|
1421
|
+
static setV = (keys: string, value: any, objeto: any) => {
|
|
1422
|
+
// Retorna o valor do chave informada, podendo ser obj.obj.chave
|
|
1423
|
+
// LibUtil.setV("a.b.c","mudei",{a:{b:{c:"d"}}})
|
|
1424
|
+
if (typeof objeto == "object") {
|
|
1425
|
+
if (LibUtil.classof(keys) == "string") {
|
|
1426
|
+
if (keys.includes(".")) {
|
|
1427
|
+
// Multi
|
|
1428
|
+
let ks: string[] = keys.split(".");
|
|
1429
|
+
let lastObj = objeto;
|
|
1430
|
+
// Iterar o Keys, Ver Obj atual e Setar Conteudo;
|
|
1431
|
+
ks.forEach((k) => {
|
|
1432
|
+
if (ks.indexOf(k) == (ks.length - 1)) {
|
|
1433
|
+
// Último
|
|
1434
|
+
lastObj[k] = value;
|
|
1435
|
+
} else {
|
|
1436
|
+
if (LibUtil.classof(lastObj[k]) != "object") {
|
|
1437
|
+
lastObj[k] = {};
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
lastObj = lastObj[k];
|
|
1441
|
+
});
|
|
1442
|
+
return objeto;
|
|
1443
|
+
} else {
|
|
1444
|
+
// Set direto, não tem ponto e é string
|
|
1445
|
+
objeto[keys] = value;
|
|
1446
|
+
return objeto;
|
|
1447
|
+
}
|
|
1448
|
+
} else {
|
|
1449
|
+
LOG(1, "❌ setV() - Nome da propriedade precisa ser em string. (" + LibUtil.classof(keys) + "):", keys);
|
|
1450
|
+
}
|
|
1451
|
+
} else {
|
|
1452
|
+
LOG(1, "❌ setV() - Objeto precisa receber um objeto. (" + typeof objeto + ")");
|
|
1453
|
+
}
|
|
1454
|
+
return null;
|
|
1455
|
+
};
|
|
1456
|
+
|
|
1457
|
+
static geraObjForm = (form: any) => {
|
|
1458
|
+
// Gerar Objeto a partir de um Form Entries
|
|
1459
|
+
if (LibUtil.classof(form) != "object") {
|
|
1460
|
+
// Se vier o Elemento Form / o Query do Form
|
|
1461
|
+
form = LibUtil.Q(form);
|
|
1462
|
+
}
|
|
1463
|
+
// Coleta apenas os campos com value.
|
|
1464
|
+
let rObjeto: any = [...form.querySelectorAll(" *[name]")]
|
|
1465
|
+
.map(o => { return { [o.name]: o.value } })
|
|
1466
|
+
.reduce((a, o) => { a = { ...a, ...o }; return a; }, {});
|
|
1467
|
+
if (form) {
|
|
1468
|
+
|
|
1469
|
+
for (let [k, v] of Object.entries(rObjeto)) {
|
|
1470
|
+
LibUtil.setV(k, v, rObjeto);
|
|
1471
|
+
if (k.includes(".")) {
|
|
1472
|
+
delete rObjeto[k];
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
Array.from(form.querySelectorAll("mk-sel")).forEach((e: any) => {
|
|
1476
|
+
// rObjeto[mk.name] = mk.value;
|
|
1477
|
+
LibUtil.setV(e.name, e.value, rObjeto);
|
|
1478
|
+
});
|
|
1479
|
+
// Aqui apenas coleta os mkBot que foram modificados pelo usuário.
|
|
1480
|
+
Array.from(form.querySelectorAll("mk-bot.changed")).forEach((e: any) => {
|
|
1481
|
+
// rObjeto[mk.name] = mk.value;
|
|
1482
|
+
LibUtil.setV(e.name, e.value, rObjeto);
|
|
1483
|
+
});
|
|
1484
|
+
}
|
|
1485
|
+
return rObjeto;
|
|
1486
|
+
}
|
|
1487
|
+
|
|
1488
|
+
static funcoesDinamicas = new Map<string, Function>();
|
|
1489
|
+
static aCada1s = () => {
|
|
1490
|
+
Array.from(LibUtil.funcoesDinamicas.values()).map((fn: Function) => { if (fn != null) fn() });
|
|
1491
|
+
setTimeout(() => {
|
|
1492
|
+
LibUtil.aCada1s();
|
|
1493
|
+
}, 1000);
|
|
1494
|
+
};
|
|
1495
|
+
|
|
1496
|
+
static cortarString = (linha: string, regex: string, casas: any) => {
|
|
1497
|
+
let resultado: any = "";
|
|
1498
|
+
try {
|
|
1499
|
+
resultado = new RegExp(regex).exec(linha)?.groups?.["ok"];
|
|
1500
|
+
} catch (e) {
|
|
1501
|
+
LOG(1, "Regex Inválido. ", e);
|
|
1502
|
+
return "0";
|
|
1503
|
+
}
|
|
1504
|
+
if ((!casas) || (casas == "") || (casas <= 0)) casas = 0;
|
|
1505
|
+
return `${LibUtil.toNumber(resultado, casas)}`;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
static uuid = () => {
|
|
1509
|
+
// Padrão UUIDV4 - Gerador de identificador unico
|
|
1510
|
+
return "10000000-1000-4000-8000-100000000000".replace(/[018]/g, (c: any) => { // c = String
|
|
1511
|
+
return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16);
|
|
1512
|
+
}).toString().toUpperCase();
|
|
1513
|
+
}
|
|
1514
|
+
|
|
1515
|
+
// mk.isRoute("/Pesagem$") // <= Rota termina com /Pesagem
|
|
1516
|
+
static isRoute = (rotaRegex: string) => {
|
|
1517
|
+
return new RegExp(rotaRegex).test(window.location.pathname);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
static verificarIgualdade(array: any[], propriedades: string[]) {
|
|
1521
|
+
// Verifica se várias propriedades estão iguais em todos os objetos de um array.
|
|
1522
|
+
if (array.length <= 1) return true;
|
|
1523
|
+
const primeiro = array[0];
|
|
1524
|
+
return array.every(objeto => {
|
|
1525
|
+
return propriedades.every(propriedade => {
|
|
1526
|
+
// Verifica se a propriedade existe em ambos os objetos antes da comparação
|
|
1527
|
+
if (!(propriedade in objeto) || !(propriedade in primeiro)) {
|
|
1528
|
+
LOG(1, `⚠️ Propriedade '${propriedade}' ausente em um ou mais objetos.`);
|
|
1529
|
+
return false; // considera falso se a propriedade não existir
|
|
1530
|
+
}
|
|
1531
|
+
return objeto[propriedade] === primeiro[propriedade];
|
|
1532
|
+
});
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
|
|
1536
|
+
static individualNoObjeto(array: any[], propriedade: string): any[] {
|
|
1537
|
+
// Ignora os Objetos que esta Propriedade se repetir.
|
|
1538
|
+
let novoSet = new Set(array.map((o) => { return o[propriedade] }));
|
|
1539
|
+
return array.map((o) => {
|
|
1540
|
+
if (novoSet.has(o[propriedade])) {
|
|
1541
|
+
novoSet.delete(o[propriedade]);
|
|
1542
|
+
return o;
|
|
1543
|
+
} else return null;
|
|
1544
|
+
}).filter(o => o);
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
static hasFaltante(array: any[], propriedades: string[]) {
|
|
1548
|
+
// Verifica as propriedades informadas estão disponíveis em todos os objetos do array.
|
|
1549
|
+
if (array.length <= 0) return false;
|
|
1550
|
+
return array.every(objeto => {
|
|
1551
|
+
return propriedades.every(propriedade => {
|
|
1552
|
+
if (!(propriedade in objeto)) {
|
|
1553
|
+
return true;
|
|
1554
|
+
}
|
|
1555
|
+
return false;
|
|
1556
|
+
});
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
static somarEmObjeto(lista: any[], propriedade: string) {
|
|
1561
|
+
// Soma uma determinada propriedade em uma lista
|
|
1562
|
+
return lista.reduce((acc: number, val: any) => {
|
|
1563
|
+
if (LibUtil.classof(val[propriedade]) == "number") {
|
|
1564
|
+
return acc + val[propriedade];
|
|
1565
|
+
}
|
|
1566
|
+
return acc;
|
|
1567
|
+
}, 0);
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1570
|
+
static capitalize = (texto?: string | null): string => {
|
|
1571
|
+
let arrayTexto = texto?.toString().split(" ");
|
|
1572
|
+
return arrayTexto?.map(str => {
|
|
1573
|
+
let str_low = str.toLowerCase();
|
|
1574
|
+
if (["da", "de", "do", "das", "dos", "e"].includes(str_low)) {
|
|
1575
|
+
return str_low;
|
|
1576
|
+
} else {
|
|
1577
|
+
return str_low.charAt(0).toUpperCase() + str_low.slice(1);
|
|
1578
|
+
}
|
|
1579
|
+
}).join(" ") || "";
|
|
1580
|
+
};
|
|
1581
|
+
|
|
1582
|
+
static GetParam = (name: string | null = null, url: string | null = null) => {
|
|
1583
|
+
// Coleta o valor do parametro da url.
|
|
1584
|
+
if (!url) url = document.location.toString();
|
|
1585
|
+
if (name != null) {
|
|
1586
|
+
return new URL(url).searchParams.get(name);
|
|
1587
|
+
} else {
|
|
1588
|
+
return new URL(url).searchParams.toString();
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1591
|
+
|
|
1592
|
+
static getParamObject = (url?: string) => {
|
|
1593
|
+
if (!url) url = document.location.toString();
|
|
1594
|
+
return url?.split("?")[1]?.split("&")?.reduce((acc: any, val: string) => {
|
|
1595
|
+
const [key, value] = val.split("=");
|
|
1596
|
+
acc[key] = value;
|
|
1597
|
+
return acc;
|
|
1598
|
+
}, {});
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
static toQueryString(obj?: any, urlAtual: string = ""): string {
|
|
1602
|
+
if (obj) {
|
|
1603
|
+
// Quando é GET, modifica a URL e acrescenta os QUERYSTRING do objeto enviado por parametro.
|
|
1604
|
+
if (obj != null) {
|
|
1605
|
+
if (!urlAtual.includes("?")) {
|
|
1606
|
+
urlAtual = urlAtual + "?"; // Cria o divisor entre os dados do query e o endereço destino.
|
|
1607
|
+
}
|
|
1608
|
+
let queryStrings = "";
|
|
1609
|
+
if (LibUtil.classof(obj) == "object") {
|
|
1610
|
+
for (let propriedade in obj) {
|
|
1611
|
+
if (LibUtil.classof(obj[propriedade]) == "object") {
|
|
1612
|
+
let propJson = JSON.stringify(obj[propriedade]);
|
|
1613
|
+
queryStrings += `&${propriedade}=${propJson}`;
|
|
1614
|
+
LOG(1, `⚠️ toQueryString() - Uma propriedade enviada: '${propriedade}' era um objeto. Url`, urlAtual);
|
|
1615
|
+
} else {
|
|
1616
|
+
if (obj[propriedade] != null) {
|
|
1617
|
+
queryStrings += `&${propriedade}=${obj[propriedade]}`;
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
} else {
|
|
1622
|
+
LOG(1, "❌ Dados enviados via GET precisam ser Object. Dados: ", LibUtil.classof(obj));
|
|
1623
|
+
}
|
|
1624
|
+
urlAtual = urlAtual + queryStrings;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
if (urlAtual.endsWith("?")) urlAtual = urlAtual.slice(0, -1); // Remove o ? final se não tiver nada depois.
|
|
1628
|
+
urlAtual = urlAtual.replaceAll("?&", "?");
|
|
1629
|
+
return urlAtual;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
/**
|
|
1633
|
+
* Mapeia uma EntidadeA para EntidadeB usando o TRANSFORMA
|
|
1634
|
+
* É nescessário informar o DE/PARA/TRANSFORMA de cada propriedade.
|
|
1635
|
+
*/
|
|
1636
|
+
static mapearEntidade<T, U>(
|
|
1637
|
+
entidadeOrigem: T,
|
|
1638
|
+
mapeamento: MapeamentoItem<T, U>[]
|
|
1639
|
+
): U {
|
|
1640
|
+
const entidadeDestino: any = {};
|
|
1641
|
+
mapeamento.forEach(item => {
|
|
1642
|
+
const valor = entidadeOrigem[item.de];
|
|
1643
|
+
if (valor !== undefined) {
|
|
1644
|
+
entidadeDestino[item.para] = item.transforma(valor);
|
|
1645
|
+
} else {
|
|
1646
|
+
entidadeDestino[item.para] = null;
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
return entidadeDestino as U;
|
|
1650
|
+
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Faz uma tentativa de obter uma url, mas se falhar, retorna nulo
|
|
1655
|
+
*/
|
|
1656
|
+
static getURL(urlQuery?: string) {
|
|
1657
|
+
let url;
|
|
1658
|
+
if (urlQuery) {
|
|
1659
|
+
try {
|
|
1660
|
+
url = new URL(urlQuery);
|
|
1661
|
+
} catch (e) {
|
|
1662
|
+
LOG(1, "❌ URL INVÁLIDA: ", urlQuery);
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
return url;
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
static conversorCSS(texto: string): string[] {
|
|
1669
|
+
const regex = /\.([a-z0-9-]+)\s*{.*?}/g;
|
|
1670
|
+
let arrayTexto = texto.replace(/\s+/g, ' ').replace(/[\r\n]/g, '').replace(regex, (match, group1) => group1 + ",").trim().split(",");
|
|
1671
|
+
return arrayTexto.map(i => i.trim()).filter(o => o != "");
|
|
1672
|
+
}
|
|
1673
|
+
|
|
1674
|
+
static sort<T, K extends keyof T>(array: T[], propriedade: K): T[] {
|
|
1675
|
+
return array.sort((a, b) => (a[propriedade] < b[propriedade] ? -1 : 1));
|
|
1676
|
+
}
|
|
1677
|
+
|
|
1678
|
+
static converteEnterEmBr(texto: string): string {
|
|
1679
|
+
return texto.replace(/\n/g, "<br>");
|
|
1680
|
+
}
|
|
1681
|
+
|
|
1682
|
+
static hasHtmlTags(texto: string): boolean {
|
|
1683
|
+
const regex = /<\/?[a-z][\s\S]*>/i;
|
|
1684
|
+
return regex.test(texto);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
|
|
1688
|
+
/**
|
|
1689
|
+
* Une duas listas quando elas tem uma propriedade em comum
|
|
1690
|
+
* @param listaA Lista a ser sobreescrita ou preenchida
|
|
1691
|
+
* @param listaB Lista com os dados para preencher ou sobreescrever
|
|
1692
|
+
* @param propEmComum Nome da propriedade que, se estiver em comum nas listas, será populado, do contrário não.
|
|
1693
|
+
* @returns Lista Unida por um Filtro.
|
|
1694
|
+
*/
|
|
1695
|
+
static Union(listaA: any[], listaB: any[], propEmComum?: string): any[] {
|
|
1696
|
+
let resultado = listaA.map(itensA => ({
|
|
1697
|
+
...itensA,
|
|
1698
|
+
...listaB.filter(o => o[propEmComum as keyof typeof o]?.toString() == itensA[propEmComum as keyof typeof listaA]?.toString())[0],
|
|
1699
|
+
}));
|
|
1700
|
+
G_START(3, "Unindo Listas...")
|
|
1701
|
+
LOG(3, "ListaA: ", listaA);
|
|
1702
|
+
LOG(3, "ListaB: ", listaB);
|
|
1703
|
+
LOG(3, "Resultado: ", resultado);
|
|
1704
|
+
G_END(3);
|
|
1705
|
+
return resultado;
|
|
1706
|
+
}
|
|
1707
|
+
|
|
1708
|
+
/**
|
|
1709
|
+
* Gera uma string menor que a informada.
|
|
1710
|
+
* @returns
|
|
1711
|
+
*/
|
|
1712
|
+
static gerarHashCurto(texto: string, tamanho: number = 8): string {
|
|
1713
|
+
let hash = 0;
|
|
1714
|
+
for (let i = 0; i < texto.length; i++) {
|
|
1715
|
+
hash = ((hash << 5) - hash) + texto.charCodeAt(i);
|
|
1716
|
+
hash = hash & hash; // Converte para inteiro de 32 bits
|
|
1717
|
+
}
|
|
1718
|
+
// Converter para string hexadecimal positiva e pegar os primeiros caracteres
|
|
1719
|
+
return Math.abs(hash).toString(16).substring(0, tamanho);
|
|
1720
|
+
}
|
|
1721
|
+
|
|
1722
|
+
static gerarNomeColection(nomeSistema: string, colecao: string): string {
|
|
1723
|
+
return LibUtil.gerarHashCurto(nomeSistema) + "_" + colecao;
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
static apenasNumerosLetras = (s: string = ""): string => {
|
|
1728
|
+
if (s == null) return "";
|
|
1729
|
+
// Ignora qualquer outro caracter além de Numeros e Letras formato ocidental
|
|
1730
|
+
return s.replace(/(?![a-zA-Z0-9])./g, "");
|
|
1731
|
+
};
|
|
1732
|
+
|
|
1733
|
+
static removeEspecias = (s: string): string => {
|
|
1734
|
+
if (s == null) return "";
|
|
1735
|
+
// Remove acentos e depois chama Apenas Números e Letras.
|
|
1736
|
+
s = s.toString();
|
|
1737
|
+
return LibUtil.apenasNumerosLetras(LibUtil.removeAcentos(s));
|
|
1738
|
+
};
|
|
1739
|
+
|
|
1740
|
+
static LerTexto = async (texto = "Teste som: 1, 2, 3.", locutor = 0) => {
|
|
1741
|
+
let lerVoz = window.speechSynthesis;
|
|
1742
|
+
let listaVozes = lerVoz.getVoices().filter(o => o.lang.toLowerCase() == "pt-br");
|
|
1743
|
+
let locutorEncontrado = listaVozes[locutor] || listaVozes[0] || null;
|
|
1744
|
+
return new Promise((r) => {
|
|
1745
|
+
if (lerVoz.speaking) {
|
|
1746
|
+
LOG(1, ">> Ainda está reproduzindo. Tente mais tarde.");
|
|
1747
|
+
return;
|
|
1748
|
+
}
|
|
1749
|
+
if (texto != "") {
|
|
1750
|
+
const ssu = new SpeechSynthesisUtterance(texto);
|
|
1751
|
+
ssu.lang = "pt-BR";
|
|
1752
|
+
ssu.voice = locutorEncontrado;
|
|
1753
|
+
ssu.pitch = 0; // Tom de voz
|
|
1754
|
+
ssu.rate = 1.5; // Velocidade
|
|
1755
|
+
ssu.onend = (ev) => { r(true) };
|
|
1756
|
+
ssu.onerror = (ev) => { LOG(1, "❌ Erro: ", ev.error); r(false) };
|
|
1757
|
+
lerVoz.cancel();
|
|
1758
|
+
lerVoz.speak(ssu);
|
|
1759
|
+
}
|
|
1760
|
+
});
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
static async LerProximoERemover(playlist: string[]) {
|
|
1764
|
+
if (await LibUtil.LerTexto(playlist[0]) == true) {
|
|
1765
|
+
playlist.shift();
|
|
1766
|
+
}
|
|
1767
|
+
return playlist;
|
|
1768
|
+
}
|
|
1769
|
+
|
|
1770
|
+
static LeituraInterrompida() {
|
|
1771
|
+
window.speechSynthesis.cancel();
|
|
1772
|
+
}
|
|
1773
|
+
|
|
1774
|
+
static gerarNumeroInteiro(min: number, max: number): any {
|
|
1775
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
static SelectInner(e: HTMLInputElement) {
|
|
1779
|
+
// Seleciona texto do elemento
|
|
1780
|
+
if (window.getSelection) {
|
|
1781
|
+
const selection = window.getSelection();
|
|
1782
|
+
const range = document.createRange();
|
|
1783
|
+
range.selectNodeContents(e);
|
|
1784
|
+
selection?.removeAllRanges();
|
|
1785
|
+
selection?.addRange(range);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
|
|
1789
|
+
static generatePrimaryKey(item: any, primarykey: string): any {
|
|
1790
|
+
if (item == null) {
|
|
1791
|
+
LOG(1, "❌ Não foi possível gerar uma chave, pois o objeto ainda não está preenchido.")
|
|
1792
|
+
return item;
|
|
1793
|
+
}
|
|
1794
|
+
|
|
1795
|
+
if (LibUtil.classof(item) != "object") {
|
|
1796
|
+
LOG(1, "⚠️ Não foi possível gerar uma chave neste tipo de variável: ", LibUtil.classof(item));
|
|
1797
|
+
return item;
|
|
1798
|
+
}
|
|
1799
|
+
|
|
1800
|
+
if (item[primarykey] != null) {
|
|
1801
|
+
LOG(5, "Chave não gerada no objeto, pois já estava preenchido com:", item[primarykey]);
|
|
1802
|
+
return item;
|
|
1803
|
+
}
|
|
1804
|
+
|
|
1805
|
+
item[primarykey] = LibUtil.uuid();
|
|
1806
|
+
return item;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
static hslToHex(h: number, s: number, l: number) {
|
|
1810
|
+
// Normalize saturation and lightness to a 0-1 range
|
|
1811
|
+
s /= 100;
|
|
1812
|
+
l /= 100;
|
|
1813
|
+
|
|
1814
|
+
let c = (1 - Math.abs(2 * l - 1)) * s,
|
|
1815
|
+
x = c * (1 - Math.abs(((h / 60) % 2) - 1)),
|
|
1816
|
+
m = l - c / 2,
|
|
1817
|
+
r = 0,
|
|
1818
|
+
g = 0,
|
|
1819
|
+
b = 0;
|
|
1820
|
+
|
|
1821
|
+
if (0 <= h && h < 60) {
|
|
1822
|
+
r = c;
|
|
1823
|
+
g = x;
|
|
1824
|
+
b = 0;
|
|
1825
|
+
} else if (60 <= h && h < 120) {
|
|
1826
|
+
r = x;
|
|
1827
|
+
g = c;
|
|
1828
|
+
b = 0;
|
|
1829
|
+
} else if (120 <= h && h < 180) {
|
|
1830
|
+
r = 0;
|
|
1831
|
+
g = c;
|
|
1832
|
+
b = x;
|
|
1833
|
+
} else if (180 <= h && h < 240) {
|
|
1834
|
+
r = 0;
|
|
1835
|
+
g = x;
|
|
1836
|
+
b = c;
|
|
1837
|
+
} else if (240 <= h && h < 300) {
|
|
1838
|
+
r = x;
|
|
1839
|
+
g = 0;
|
|
1840
|
+
b = c;
|
|
1841
|
+
} else if (300 <= h && h < 360) {
|
|
1842
|
+
r = c;
|
|
1843
|
+
g = 0;
|
|
1844
|
+
b = x;
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// Convert RGB values to 0-255 range
|
|
1848
|
+
r = Math.round((r + m) * 255);
|
|
1849
|
+
g = Math.round((g + m) * 255);
|
|
1850
|
+
b = Math.round((b + m) * 255);
|
|
1851
|
+
|
|
1852
|
+
// Convert RGB components to hexadecimal and pad with leading zero if needed
|
|
1853
|
+
const toHex = (c: any) => {
|
|
1854
|
+
const hex = c.toString(16);
|
|
1855
|
+
return hex.length === 1 ? '0' + hex : hex;
|
|
1856
|
+
};
|
|
1857
|
+
|
|
1858
|
+
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
static isFilled(dados: any): boolean {
|
|
1862
|
+
if (LibUtil.classof(dados) == "array") {
|
|
1863
|
+
if ((dados as Array<any>).length && (dados as Array<any>).length > 0) {
|
|
1864
|
+
return true;
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
return false;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
static replace(regex: string, valor: string | number): string {
|
|
1871
|
+
if (typeof valor === "number") valor = valor.toString();
|
|
1872
|
+
return valor.replace(new RegExp(regex, 'g'), '');
|
|
1873
|
+
}
|
|
1874
|
+
|
|
1875
|
+
// Mínimo 2 timestamps
|
|
1876
|
+
static calculateJitter(timestamps: number[]): number {
|
|
1877
|
+
if (timestamps.length < 2) return 0;
|
|
1878
|
+
|
|
1879
|
+
const delays = [];
|
|
1880
|
+
for (let i = 1; i < timestamps.length; i++) {
|
|
1881
|
+
delays.push(timestamps[i] - timestamps[i - 1]);
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
if (delays.length < 2) return 0;
|
|
1885
|
+
let totalJitterDifference = 0;
|
|
1886
|
+
|
|
1887
|
+
for (let i = 1; i < delays.length; i++) {
|
|
1888
|
+
totalJitterDifference += Math.abs(delays[i] - delays[i - 1]);
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
return totalJitterDifference / (delays.length - 1);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// Soma os valores dos arrays por índice
|
|
1895
|
+
static somarPorIndice = (arrays: number[][]): number[] => {
|
|
1896
|
+
if (arrays.length === 0) return [];
|
|
1897
|
+
return arrays.reduce((acc, arr) =>
|
|
1898
|
+
arr.map((val, i) => (acc[i] || 0) + val)
|
|
1899
|
+
);
|
|
1900
|
+
}
|
|
1901
|
+
|
|
1902
|
+
// Soma os valores dos arrays
|
|
1903
|
+
static somarArrayInterna = (arrays: number[][]): number[] => {
|
|
1904
|
+
if (arrays.length === 0) return [];
|
|
1905
|
+
return arrays.map(a => a.reduce((acc, v) => acc + v, 0));
|
|
1906
|
+
}
|
|
1907
|
+
|
|
1908
|
+
// Faz o download de um Blob()
|
|
1909
|
+
static downloadBlob = (blob: Blob, nomeArquivo: string) => {
|
|
1910
|
+
const url = URL.createObjectURL(blob);
|
|
1911
|
+
const a = document.createElement('a');
|
|
1912
|
+
a.href = url;
|
|
1913
|
+
a.download = nomeArquivo;
|
|
1914
|
+
document.body.appendChild(a);
|
|
1915
|
+
a.click();
|
|
1916
|
+
document.body.removeChild(a);
|
|
1917
|
+
URL.revokeObjectURL(url);
|
|
1918
|
+
}
|
|
1919
|
+
|
|
1920
|
+
static wordsToCamelCase(texto: string): string {
|
|
1921
|
+
// Se houver espaços, traços, undercores, converte para camelCase
|
|
1922
|
+
return texto.split(/[\s-_]+/)
|
|
1923
|
+
.map((word, index) =>
|
|
1924
|
+
index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
|
|
1925
|
+
).join('');
|
|
1926
|
+
}
|
|
1927
|
+
|
|
1928
|
+
static camelCase(texto: string): string {
|
|
1929
|
+
return texto.charAt(0).toLowerCase() + texto.slice(1);
|
|
1930
|
+
}
|
|
1931
|
+
|
|
1932
|
+
static pascalCase(texto: string): string {
|
|
1933
|
+
return texto.charAt(0).toUpperCase() + texto.slice(1);
|
|
1934
|
+
}
|
|
1935
|
+
|
|
1936
|
+
static dashedCase(texto: string): string {
|
|
1937
|
+
// Converte camelCase ou PascalCase para dashed-case
|
|
1938
|
+
return texto.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
static separaWordsCase(texto: string): string {
|
|
1942
|
+
// Separa as palavras ao trocar de letra minúscula para maiúscula.
|
|
1943
|
+
// CodigoIBGE => Codigo IBGE
|
|
1944
|
+
let textoSeparado = texto.replace(/([a-z])([A-Z])/g, '$1 $2');
|
|
1945
|
+
return textoSeparado;
|
|
1946
|
+
}
|
|
1947
|
+
|
|
1948
|
+
// Separa as palavras por espaço, traço ou underline, e retorna um array com as palavras.
|
|
1949
|
+
static wordsArray(texto: string): string[] {
|
|
1950
|
+
return texto.split(/[\s-_]+/).filter(word => word.length > 0);
|
|
1951
|
+
}
|
|
1952
|
+
|
|
1953
|
+
static tentaAcentuarTexto(s: string | string[]): string {
|
|
1954
|
+
// Utiliza regras de acentuação de português para tentar acentuar a palavra informada.
|
|
1955
|
+
if (LibUtil.classof(s) == "array") {
|
|
1956
|
+
return (s as string[]).map((palavra) => LibUtil.tentaAcentuarTexto(palavra)).join(" ");
|
|
1957
|
+
}
|
|
1958
|
+
let texto = (s as string);
|
|
1959
|
+
if (texto.endsWith("ao")) {
|
|
1960
|
+
texto = texto.slice(0, -2) + "ão"; // Ex: mão
|
|
1961
|
+
}
|
|
1962
|
+
if (texto.endsWith("oes")) {
|
|
1963
|
+
texto = texto.slice(0, -3) + "ões"; // Ex: permissões
|
|
1964
|
+
}
|
|
1965
|
+
if (texto.endsWith("cao") || texto.endsWith("çao") || (texto.endsWith("cão") && texto != "cão")) {
|
|
1966
|
+
texto = texto.slice(0, -3) + "ção"; // Ex: ação
|
|
1967
|
+
}
|
|
1968
|
+
if (texto.endsWith("coes") || texto.endsWith("çoes") || texto.endsWith("cões")) {
|
|
1969
|
+
texto = texto.slice(0, -4) + "ções"; // Ex: observações
|
|
1970
|
+
}
|
|
1971
|
+
|
|
1972
|
+
return texto;
|
|
1973
|
+
}
|
|
1974
|
+
|
|
1975
|
+
static pluralOf(word: string | string[]): string {
|
|
1976
|
+
// Retorna o plural da palavra informada em português
|
|
1977
|
+
if (LibUtil.classof(word) == "array") {
|
|
1978
|
+
return (word as string[]).map((palavra) => LibUtil.pluralOf(palavra)).join(" ");
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
let texto = (word as string);
|
|
1982
|
+
if (texto.endsWith("ão")) {
|
|
1983
|
+
return texto.slice(0, -2) + "ões";
|
|
1984
|
+
} else if (texto.endsWith("ões")) {
|
|
1985
|
+
return texto.slice(0, -3) + "ões";
|
|
1986
|
+
} else if (texto.endsWith("r") || texto.endsWith("s") || texto.endsWith("z")) {
|
|
1987
|
+
return texto + "es";
|
|
1988
|
+
} else if (texto.endsWith("m")) {
|
|
1989
|
+
return texto.slice(0, -1) + "ns";
|
|
1990
|
+
} else if (texto.endsWith("l")) {
|
|
1991
|
+
return texto.slice(0, -1) + "is";
|
|
1992
|
+
} else {
|
|
1993
|
+
return texto + "s";
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
static setLogLevel(level: number): void {
|
|
1998
|
+
LibUtil.loglevel = level;
|
|
1999
|
+
}
|
|
2000
|
+
|
|
2001
|
+
static setFormConfigs(configs: Partial<IFieldComponent<any>>): void {
|
|
2002
|
+
LibUtil.formConfigs = configs;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
static paraPortugues(texto: string): string {
|
|
2006
|
+
let acentuado = LibUtil.tentaAcentuarTexto(LibUtil.wordsArray(LibUtil.separaWordsCase(texto)))
|
|
2007
|
+
return LibUtil.replaceDicionario(acentuado);
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
static paraPortuguesPlural(texto: string): string {
|
|
2011
|
+
let plural = LibUtil.pluralOf(LibUtil.paraPortugues(texto))
|
|
2012
|
+
return plural;
|
|
2013
|
+
}
|
|
2014
|
+
|
|
2015
|
+
// Dicionário
|
|
2016
|
+
static replaceDicionario(texto: string): string {
|
|
2017
|
+
if (texto.startsWith("Is ")) {
|
|
2018
|
+
texto = texto.replace(/^Is /, "É ");
|
|
2019
|
+
}
|
|
2020
|
+
texto = texto.replaceAll("Codigo", "Código");
|
|
2021
|
+
texto = texto.replaceAll("Icone", "Ícone");
|
|
2022
|
+
texto = texto.replaceAll("Enderec", "Endereç");
|
|
2023
|
+
texto = texto.replaceAll("Balanc", "Balanç");
|
|
2024
|
+
texto = texto.replaceAll("Usuari", "Usuári");
|
|
2025
|
+
texto = texto.replaceAll("Lancamento", "Lançamento");
|
|
2026
|
+
texto = texto.replaceAll("Referencia", "Referência");
|
|
2027
|
+
texto = texto.replaceAll("Ultim", "Últim");
|
|
2028
|
+
texto = texto.replaceAll("Numero", "Número");
|
|
2029
|
+
texto = texto.replaceAll("Inicio", "Início");
|
|
2030
|
+
texto = texto.replaceAll("Socio", "Sócio");
|
|
2031
|
+
texto = texto.replaceAll("Socia", "Sócia");
|
|
2032
|
+
texto = texto.replaceAll("Especie", "Espécie");
|
|
2033
|
+
texto = texto.replaceAll("Cobranca", "Cobrança");
|
|
2034
|
+
texto = texto.replaceAll("Modulo", "Módulo");
|
|
2035
|
+
texto = texto.replaceAll("Servico", "Serviço");
|
|
2036
|
+
texto = texto.replaceAll("Aliquota", "Alíquota");
|
|
2037
|
+
texto = texto.replaceAll("Calculo", "Cálculo");
|
|
2038
|
+
texto = texto.replaceAll("Unitario", "Unitário");
|
|
2039
|
+
texto = texto.replaceAll("Procedencia", "Procedência");
|
|
2040
|
+
texto = texto.replaceAll("Mudanca", "Mudança");
|
|
2041
|
+
texto = texto.replaceAll("Pratica", "Prática");
|
|
2042
|
+
texto = texto.replaceAll("Propria", "Própria");
|
|
2043
|
+
texto = texto.replaceAll("Impropria", "Imprópria");
|
|
2044
|
+
texto = texto.replaceAll("Responsavel", "Responsável");
|
|
2045
|
+
texto = texto.replaceAll("Conjuge", "Cônjuge");
|
|
2046
|
+
texto = texto.replaceAll("Cafe", "Café");
|
|
2047
|
+
texto = texto.replaceAll("Transferencia", "Transferência");
|
|
2048
|
+
texto = texto.replaceAll("Bancaria", "Bancária");
|
|
2049
|
+
texto = texto.replaceAll("Agencia", "Agência");
|
|
2050
|
+
texto = texto.replaceAll("Digito", "Dígito");
|
|
2051
|
+
|
|
2052
|
+
if (texto.includes("Mes ")) texto = texto.replaceAll("Mes ", "Mês ");
|
|
2053
|
+
if (texto.endsWith("Mes")) texto = texto.replace(/Mes$/, "Mês");
|
|
2054
|
+
if (texto.includes("Ate ")) texto = texto.replaceAll("Ate ", "Até ");
|
|
2055
|
+
if (texto.endsWith("Ate")) texto = texto.replace(/Ate$/, "Até");
|
|
2056
|
+
if (texto.includes("Socio ")) texto = texto.replaceAll("Socio ", "Sócio ");
|
|
2057
|
+
if (texto.endsWith("Socio")) texto = texto.replace(/Socio$/, "Sócio");
|
|
2058
|
+
if (texto.includes("Socia ")) texto = texto.replaceAll("Socia ", "Sócia ");
|
|
2059
|
+
if (texto.endsWith("Socia")) texto = texto.replace(/Socia$/, "Sócia");
|
|
2060
|
+
return texto;
|
|
2061
|
+
}
|
|
2062
|
+
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
|
|
2066
|
+
|
|
2067
|
+
|
|
2068
|
+
////////////////////////////////////
|
|
2069
|
+
// CONSOLES: LOG - WARN - ERR ...
|
|
2070
|
+
////////////////////////////////////
|
|
2071
|
+
// LibUtil.loglevel: 1,2,3 => Bigger will see more
|
|
2072
|
+
|
|
2073
|
+
export const LOG = (level: number, ...attr: any) => {
|
|
2074
|
+
if (LibUtil.loglevel >= level) {
|
|
2075
|
+
return console.log(...attr);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
// export const WARN = (level: number, ...attr: any) => {
|
|
2080
|
+
// if (LibUtil.loglevel >= level) {
|
|
2081
|
+
// return console.warn(...attr);
|
|
2082
|
+
// }
|
|
2083
|
+
// }
|
|
2084
|
+
|
|
2085
|
+
// export const ERR = (level: number, ...attr: any) => {
|
|
2086
|
+
// if (LibUtil.loglevel >= level) {
|
|
2087
|
+
// return console.error(...attr);
|
|
2088
|
+
// }
|
|
2089
|
+
// }
|
|
2090
|
+
|
|
2091
|
+
export const G_START = (level: number, ...attr: any) => {
|
|
2092
|
+
if (LibUtil.loglevel >= level) {
|
|
2093
|
+
return console.groupCollapsed(...attr);
|
|
2094
|
+
}
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
export const G_START_OPEN = (level: number, ...attr: any) => {
|
|
2098
|
+
if (LibUtil.loglevel >= level) {
|
|
2099
|
+
return console.group(...attr);
|
|
2100
|
+
}
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
export const G_END = (level: number, ...attr: any) => {
|
|
2104
|
+
if (LibUtil.loglevel >= level) {
|
|
2105
|
+
return console.groupEnd();
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
2108
|
+
|
|
2109
|
+
// LOG COLAPSADO
|
|
2110
|
+
export const LOGC = (level: number, title: string, ...attr: any) => {
|
|
2111
|
+
G_START(level, title);
|
|
2112
|
+
LOG(level, ...attr);
|
|
2113
|
+
G_END(level);
|
|
2114
|
+
}
|
|
2115
|
+
|
|
2116
|
+
|
|
2117
|
+
|
|
2118
|
+
export type IClassOf = "string" | "number" | "nan" | "object" | "array" | "boolean" | "undefined" | "null" | "function" | "date" | "regexp" | "error" | "symbol" | "bigint"
|
|
2119
|
+
|
|
2120
|
+
export interface IFormatter {
|
|
2121
|
+
mask: string | ((value: any) => string);
|
|
2122
|
+
regex: string;
|
|
2123
|
+
validate: (value: any) => boolean;
|
|
2124
|
+
}
|
|
2125
|
+
|
|
2126
|
+
export interface IUtilFormatters {
|
|
2127
|
+
cpf: IFormatter;
|
|
2128
|
+
cnpj: IFormatter;
|
|
2129
|
+
cpf_cnpj: IFormatter;
|
|
2130
|
+
cnh: IFormatter;
|
|
2131
|
+
pis: IFormatter;
|
|
2132
|
+
dia: IFormatter;
|
|
2133
|
+
mes: IFormatter;
|
|
2134
|
+
ano: IFormatter;
|
|
2135
|
+
anoRecente: IFormatter;
|
|
2136
|
+
data: IFormatter;
|
|
2137
|
+
dataIso: IFormatter;
|
|
2138
|
+
numero: IFormatter;
|
|
2139
|
+
decimal: IFormatter;
|
|
2140
|
+
letra: IFormatter;
|
|
2141
|
+
numeroELetra: IFormatter;
|
|
2142
|
+
ip: IFormatter;
|
|
2143
|
+
email: IFormatter;
|
|
2144
|
+
cep: IFormatter;
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
export interface MapeamentoItem<T, U> {
|
|
2148
|
+
de: keyof T;
|
|
2149
|
+
para: keyof U;
|
|
2150
|
+
transforma: (v: T[keyof T]) => U[keyof U];
|
|
2151
|
+
}
|