vue-intergrall-plugins 0.0.504 → 0.0.510

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +185 -185
  2. package/dist/vue-intergrall-plugins.esm.js +596 -513
  3. package/dist/vue-intergrall-plugins.min.js +1 -1
  4. package/dist/vue-intergrall-plugins.ssr.js +607 -541
  5. package/package.json +67 -66
  6. package/src/lib-components/Buttons/IconButton.vue +27 -27
  7. package/src/lib-components/Buttons/SimpleButton.vue +140 -140
  8. package/src/lib-components/Cards/Card.vue +429 -429
  9. package/src/lib-components/Cards/CardCheck.vue +35 -35
  10. package/src/lib-components/Cards/CardFile.vue +157 -157
  11. package/src/lib-components/Chat/BtnDownloadAllFiles.vue +36 -36
  12. package/src/lib-components/Chat/BtnEmojis.vue +131 -131
  13. package/src/lib-components/Chat/BtnExpand.vue +17 -17
  14. package/src/lib-components/Chat/BtnFiles.vue +541 -541
  15. package/src/lib-components/Chat/BtnMic.vue +60 -60
  16. package/src/lib-components/Chat/BtnScreenShare.vue +36 -36
  17. package/src/lib-components/Chat/BtnStandardMessages.vue +17 -17
  18. package/src/lib-components/Chat/ExpandTextarea.vue +410 -410
  19. package/src/lib-components/Chat/MultipleFilePreview.vue +266 -266
  20. package/src/lib-components/Chat/Picker.vue +405 -405
  21. package/src/lib-components/Chat/RemainingCharacters.vue +28 -28
  22. package/src/lib-components/Chat/SingleFilePreview.vue +94 -94
  23. package/src/lib-components/Chat/SkeletonPicker.vue +110 -110
  24. package/src/lib-components/Chat/StandardMessages.vue +245 -245
  25. package/src/lib-components/Chat/TextFooter.vue +1030 -1030
  26. package/src/lib-components/Email/EmailFile.vue +125 -125
  27. package/src/lib-components/Email/EmailItem.vue +185 -185
  28. package/src/lib-components/Loader/Loader.vue +78 -78
  29. package/src/lib-components/Messages/AnexoMensagem.vue +442 -442
  30. package/src/lib-components/Messages/CardAttachment.vue +61 -61
  31. package/src/lib-components/Messages/CardMessages.vue +666 -666
  32. package/src/lib-components/Messages/ChatMessages.vue +1082 -1077
  33. package/src/lib-components/Messages/InteratividadeBotoes.vue +165 -165
  34. package/src/lib-components/Messages/InteratividadeFormulario.vue +392 -392
  35. package/src/lib-components/Messages/InteratividadePopup.vue +88 -88
  36. package/src/lib-components/Messages/LinkPreview.vue +163 -163
  37. package/src/lib-components/Midea/Player.vue +25 -0
  38. package/src/lib-components/Scroll/ScrollContent.vue +166 -166
  39. package/src/lib-components/Templates/TemplateGenerator.vue +576 -576
  40. package/src/lib-components/Templates/TemplateMessage.vue +83 -83
  41. package/src/lib-components/Templates/TemplateSingle.vue +481 -481
@@ -1,541 +1,541 @@
1
- <template>
2
- <span
3
- class="text-footer-actions--btn"
4
- :class="{ 'files-activated': openFiles || file.name }"
5
- @click="openFilesByClip()"
6
- >
7
- <!-- || file.length -->
8
- <!-- <transition name="fade">
9
- <span v-if="fileSize > 0" @click.stop="toggleFilePreview" v-tippy :content="`Visualizar ${fileSize} arquivo(s)`" class="files-counter">
10
- {{ fileSize }}
11
- </span>
12
- </transition> -->
13
- <fa-icon :icon="['fas', 'paperclip']" :title="dictionary.title_selecionar_anexo" />
14
- <transition name="fade">
15
- <span
16
- v-if="fileSize > 0"
17
- @click.stop="toggleFilePreview"
18
- v-tippy
19
- :content="
20
- !fileSettings.handleFilePreview
21
- ? dictionary.msg_abrir_anexos
22
- : `${file.length} anexo(s) selecionado(s)`
23
- "
24
- :class="`${
25
- fileSettings.filePreviewStyle == 2 ? 'files-counter-2' : 'files-counter'
26
- }`"
27
- >
28
- <template v-if="fileSettings.filePreviewStyle == 1">
29
- {{ fileSize }}
30
- </template>
31
- <template v-else>
32
- <fa-icon :icon="['fas', 'eye']" />
33
- </template>
34
- </span>
35
- </transition>
36
- <transition name="show">
37
- <div
38
- v-if="openFiles && hasButtonFiles"
39
- class="text-footer-files-container"
40
- :class="{ horizontal: cssStyle.outsideButtons }"
41
- >
42
- <template v-if="!fileSettings.multiple">
43
- <div
44
- class="files-btn images"
45
- :class="{ 'margin-bottom': cssStyle.outsideButtons }"
46
- :title="dictionary.title_anexo_img"
47
- @click="openSelectFileHandler('img')"
48
- >
49
- <fa-icon :icon="['fas', 'image']" />
50
- </div>
51
- <div
52
- class="files-btn docs"
53
- :title="dictionary.title_anexo_doc"
54
- @click="openSelectFileHandler('doc')"
55
- >
56
- <fa-icon :icon="['fas', 'file-alt']" />
57
- </div>
58
- </template>
59
- <div
60
- v-else
61
- class="files-btn both"
62
- :title="dictionary.title_anexo_arq"
63
- @click="openSelectFileHandler('both')"
64
- >
65
- <fa-icon :icon="['fas', 'image']" />
66
- <fa-icon :icon="['fas', 'file-alt']" />
67
- </div>
68
- <div
69
- v-if="fileSettings.systemButton"
70
- class="files-btn system"
71
- :title="dictionary.title_anexo_sistema"
72
- @click="openSelectFileHandler('system')"
73
- >
74
- <fa-icon :icon="['fas', 'server']" />
75
- </div>
76
- </div>
77
- </transition>
78
- <div class="files-pointers d-none">
79
- <input
80
- v-if="fileSettings.multiple"
81
- type="file"
82
- :id="`both-${textId}`"
83
- :accept="acceptedExtensions"
84
- multiple
85
- @change="fileUpload($event, 'both')"
86
- />
87
- <input
88
- v-if="!fileSettings.multiple"
89
- type="file"
90
- :id="`img-${textId}`"
91
- :accept="acceptedExtensions"
92
- @change="fileUpload($event, 'img')"
93
- />
94
- <input
95
- v-if="!fileSettings.multiple"
96
- type="file"
97
- :id="`doc-${textId}`"
98
- :accept="acceptedExtensions"
99
- @change="fileUpload($event, 'doc')"
100
- />
101
- </div>
102
- <transition name="fade">
103
- <div
104
- class="text-footer-preview-container"
105
- @click.stop
106
- v-show="showFilePreview"
107
- :class="[previewContainerClass]"
108
- v-on-clickaway="away"
109
- >
110
- <SingleFilePreview
111
- v-if="!fileSettings.multiple && showFilePreview"
112
- :dictionary="dictionary"
113
- :file="file"
114
- :isDoc="isDoc"
115
- :fileFormatError="fileFormatError"
116
- :validFileFormats="validFileFormats"
117
- :imagePreview="imagePreview"
118
- :textId="textId"
119
- @delete-file="deleteFile"
120
- @open-image="openImage"
121
- @close="away"
122
- />
123
- <MultipleFilePreview
124
- v-else-if="fileSettings.multiple && showFilePreview"
125
- :dictionary="dictionary"
126
- :file="file"
127
- :fileFormatError="fileFormatError"
128
- :validFileFormats="validFileFormats"
129
- @delete-file="deleteFile"
130
- @delete-specific-file="deleteSpecificFile"
131
- @open-image="openImage"
132
- @close="away"
133
- />
134
- </div>
135
- </transition>
136
- </span>
137
- </template>
138
-
139
- <style>
140
- .fade-enter-active,
141
- .fade-leave-active {
142
- transition: opacity 0.3s;
143
- }
144
- .fade-enter,
145
- .fade-leave-to {
146
- opacity: 0;
147
- }
148
-
149
- .files-counter {
150
- position: absolute;
151
- top: unset;
152
- transform: translate(17.5px, -15px);
153
- background-color: #888;
154
- z-index: 1;
155
- font-size: 8px;
156
- width: 15px;
157
- height: 15px;
158
- border-radius: 50%;
159
- display: flex;
160
- justify-content: center;
161
- align-items: center;
162
- cursor: pointer;
163
- opacity: 0.9;
164
- transition: all 300ms;
165
- color: #fff;
166
- font-weight: 900;
167
- }
168
- .files-counter:hover {
169
- opacity: 1;
170
- }
171
- .files-counter-2 {
172
- transform: translate(-15px, 28px);
173
- opacity: 0.9;
174
- position: absolute;
175
- display: flex;
176
- justify-content: center;
177
- align-items: center;
178
- color: #888;
179
- font-size: 12.8px;
180
- }
181
- .files-counter-2 svg {
182
- margin-left: 5px;
183
- }
184
- .files-counter-2:hover {
185
- opacity: 1;
186
- text-decoration: underline;
187
- }
188
- </style>
189
-
190
- <script>
191
- import { mixin as clickaway } from "vue-clickaway";
192
- import SingleFilePreview from "./SingleFilePreview";
193
- import MultipleFilePreview from "./MultipleFilePreview";
194
-
195
- export default {
196
- components: { SingleFilePreview, MultipleFilePreview },
197
- mixins: [clickaway],
198
- props: {
199
- textId: {
200
- type: String,
201
- required: true,
202
- },
203
- dictionary: {
204
- type: Object,
205
- required: true,
206
- },
207
- fileSettings: {
208
- type: Object,
209
- required: false,
210
- },
211
- cssStyle: {
212
- type: Object,
213
- required: false,
214
- },
215
- hasButtonFiles: {
216
- type: Boolean,
217
- required: false,
218
- },
219
- externalFiles: {
220
- type: Array,
221
- required: false,
222
- },
223
- },
224
- data() {
225
- return {
226
- file: [],
227
- fileSize: 0,
228
- openFiles: false,
229
- showFilePreview: false,
230
- imagePreview: "",
231
- isDoc: false,
232
- fileFormatError: false,
233
- validFileFormats: "",
234
- hasAnyFile: false,
235
- externalFilesAux: [],
236
- };
237
- },
238
- computed: {
239
- previewContainerClass() {
240
- if (this.fileFormatError) return "isError";
241
- if (this.fileSettings.multiple) return "isMultiple";
242
- if (this.isDoc) return "isDoc";
243
- return "isMsg";
244
- },
245
- acceptedExtensions() {
246
- let str = "";
247
- if (this.fileSettings.docsExtensions && this.fileSettings.imagesExtensions) {
248
- str = `${this.fileSettings.docsExtensions
249
- .split("|")
250
- .join(",")}${this.fileSettings.imagesExtensions.split("|").join(",")}`;
251
- } else if (this.fileSettings.docsExtensions) {
252
- str = this.fileSettings.docsExtensions.split("|").join(",");
253
- } else if (this.fileSettings.imagesExtensions) {
254
- str = this.fileSettings.imagesExtensions.split("|").join(",");
255
- }
256
- if (str) {
257
- const arr = str.split(",").map((ext) => {
258
- ext = ext && ext.startsWith(".") ? ext : `.${ext}`;
259
- return ext;
260
- });
261
- str = arr.join(",");
262
- }
263
- if (this.fileSettings.multiple) return str ? str : "image/*,application/*";
264
- if (this.isDoc) return str ? str : "application/*";
265
- return str ? str : "image/*";
266
- },
267
- },
268
- watch: {
269
- externalFiles() {
270
- if (!this.externalFiles.length) return;
271
- if (this.externalFiles.length > this.fileSettings.max) {
272
- this.$emit("reset-file-system");
273
- return this.$toasted.global.defaultInfo({
274
- msg: `Limite de ${this.fileSettings.max} arquivos`,
275
- });
276
- }
277
- this.file = [];
278
- this.externalFilesAux = Array.from(this.externalFiles);
279
- this.externalFilesAux.forEach((files) => {
280
- this.file.push(files);
281
- });
282
- this.fileSize = this.file.length;
283
- this.multipleFileUpload();
284
- },
285
- },
286
- methods: {
287
- openFilesByClip() {
288
- if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
289
- if (this.fileSettings.multiple && !this.hasButtonFiles) {
290
- return this.openSelectFileHandler("both");
291
- }
292
- return this.toggleFiles();
293
- },
294
- away() {
295
- this.showFilePreview = false;
296
- },
297
- toggleFiles() {
298
- this.openFiles = !this.openFiles;
299
- },
300
- openSelectFileHandler(type) {
301
- if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
302
- if (type == "system") return this.$emit("open-file-system");
303
- if (this.fileSettings.multiple) {
304
- type = "both";
305
- }
306
- const fileInput = document.querySelector(`#${type}-${this.textId}`);
307
- if (fileInput) fileInput.click();
308
- if (!fileInput)
309
- if (!document.querySelector(".toasted.toasted-primary.error"))
310
- this.$toasted.global.defaultError();
311
- },
312
- isFileValid(type, fileName, fileType) {
313
- if (
314
- (type == "img" && !this.fileSettings.imagesExtensions) ||
315
- (type == "doc" && !this.fileSettings.docsExtensions)
316
- ) {
317
- this.$toasted.global.defaultInfo({
318
- msg: this.dictionary.sem_extensoes_parametrizadas,
319
- });
320
- this.hasAnyFile = false;
321
- return false;
322
- }
323
- const extensions =
324
- type === "img"
325
- ? this.fileSettings.imagesExtensions
326
- : this.fileSettings.docsExtensions;
327
- const regex = new RegExp("(" + extensions + ")", "i");
328
- if (regex.test(fileName) || regex.test(fileType)) return true;
329
- this.hasAnyFile = false;
330
- this.showToastedValidFormats();
331
- return false;
332
- },
333
- showToastedValidFormats() {
334
- if (!document.querySelector(".toasted.toasted-primary.error"))
335
- this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido });
336
- const str = {
337
- img: this.fileSettings.imagesExtensions.split("|").join(", "),
338
- doc: this.fileSettings.docsExtensions.split("|").join(", "),
339
- };
340
- if (!document.querySelector(".toasted.toasted-primary.info"))
341
- this.$toasted.global.showValidFormats({
342
- msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}`,
343
- });
344
- },
345
- fileUpload(event, type, externalCall) {
346
- try {
347
- this.fileSize = 0;
348
- if (this.fileFormatError) this.file = [];
349
- this.openFiles = false;
350
- const filesAux = !externalCall
351
- ? event.target.files
352
- ? event.target.files
353
- : event.dataTransfer.files
354
- : event;
355
- const isStackable = this.fileSettings.stackFiles && this.fileSettings.multiple;
356
- this.file = filesAux.length
357
- ? isStackable
358
- ? this.file.concat(...filesAux)
359
- : filesAux
360
- : this.file;
361
- if (!this.file.length) return;
362
-
363
- let sizeInBytes = 0;
364
- Array.from(this.file).forEach((file) => (sizeInBytes += file.size));
365
- const sizeInMb = parseFloat((sizeInBytes / (1024 * 1024)).toFixed(2));
366
- if (sizeInMb == 0) {
367
- this.file = [];
368
- return this.$toasted.global.defaultInfo({
369
- msg: this.dictionary.msg_arquivo_invalido,
370
- });
371
- }
372
- if (sizeInMb >= 15) {
373
- this.file = [];
374
- return this.$toasted.global.defaultInfo({ msg: `Limite de 15 MB por arquivo` });
375
- }
376
-
377
- if (this.file.length > this.fileSettings.max) {
378
- this.file = [];
379
- return this.$toasted.global.defaultInfo({
380
- msg: `Limite de ${this.fileSettings.max} arquivos`,
381
- });
382
- }
383
- this.hasAnyFile = true;
384
- this.fileSize = this.file.length;
385
- if (!this.fileSettings.multiple) {
386
- this.file = this.file[0];
387
- this.singleFileUpload(type, this.file.name, this.file.type);
388
- } else {
389
- this.multipleFileUpload();
390
- }
391
- } catch (e) {
392
- console.error("Error file upload");
393
- console.error(e);
394
- }
395
- },
396
- returnFileType(file) {
397
- if (!this.fileSettings.imagesExtensions && !this.fileSettings.docsExtensions)
398
- return "";
399
-
400
- const imgRegex = new RegExp("\.(" + this.fileSettings.imagesExtensions + ")", "i");
401
- if (imgRegex.test(file.name)) return "img";
402
-
403
- const docRegex = new RegExp("\.(" + this.fileSettings.docsExtensions + ")", "i");
404
- if (docRegex.test(file.name)) return "doc";
405
-
406
- return "";
407
- },
408
- multipleFileUpload() {
409
- const hasImgExt = this.fileSettings.imagesExtensions ? true : false;
410
- const hasDocExt = this.fileSettings.docsExtensions ? true : false;
411
- if (!hasImgExt && !hasDocExt) {
412
- this.file = [];
413
- this.fileSize = 0;
414
- return this.$toasted.global.defaultInfo({
415
- msg: this.dictionary.sem_extensoes_parametrizadas,
416
- });
417
- }
418
- let waitForImageLoad = false;
419
- let hasAnyInvalidFile = false;
420
- this.file = Array.from(this.file);
421
- this.file.forEach((file) => {
422
- const singleFileType = this.returnFileType(file);
423
- if (!singleFileType) file.invalid = true;
424
- file.imgOrDoc = singleFileType ? singleFileType : "";
425
- if (this.isFileValid(file.imgOrDoc, file.name, file.type)) {
426
- if (file.imgOrDoc == "img") {
427
- const fileReader = new FileReader();
428
- waitForImageLoad = true;
429
- fileReader.onload = () => (file.src = fileReader.result);
430
- fileReader.onloadend = () => this.emitFileVars(true);
431
- fileReader.readAsDataURL(file);
432
- }
433
- if (file.imgOrDoc === "doc") this.isDoc = true;
434
- file.invalid = false;
435
- this.fileFormatError = !hasAnyInvalidFile ? false : true;
436
- } else {
437
- hasAnyInvalidFile = true;
438
- file.invalid = true;
439
- this.fileFormatError = true;
440
- if (hasImgExt && !hasDocExt)
441
- this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions
442
- .split("|")
443
- .join(", ")}`;
444
- if (hasDocExt && hasImgExt)
445
- this.validFileFormats = `Documentos: ${this.fileSettings.docsExtensions
446
- .split("|")
447
- .join(", ")}`;
448
- if (hasImgExt && hasDocExt)
449
- this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions
450
- .split("|")
451
- .join(", ")} - Documentos: ${this.fileSettings.docsExtensions
452
- .split("|")
453
- .join(", ")}`;
454
- }
455
- });
456
-
457
- if (this.fileFormatError) {
458
- this.file = [];
459
- this.fileSize = 0;
460
- }
461
-
462
- if (this.isDoc && !waitForImageLoad) this.emitFileVars();
463
- },
464
- singleFileUpload(type, fileName, fileType) {
465
- if (this.isFileValid(type, fileName, fileType)) {
466
- const fileReader = new FileReader();
467
- if (type === "img") {
468
- fileReader.onload = () => (this.imagePreview = fileReader.result);
469
- fileReader.onloadend = () => this.emitFileVars();
470
- fileReader.readAsDataURL(this.file);
471
- }
472
- if (type === "doc") this.isDoc = true;
473
-
474
- this.fileFormatError = false;
475
- } else {
476
- this.fileFormatError = true;
477
- const hasImgExt = this.fileSettings.imagesExtensions ? true : false;
478
- const hasDocExt = this.fileSettings.docsExtensions ? true : false;
479
- if (hasImgExt && !hasDocExt)
480
- this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions}`;
481
- if (hasDocExt && hasImgExt)
482
- this.validFileFormats = `Documentos: ${this.fileSettings.docsExtensions}`;
483
- if (hasImgExt && hasDocExt)
484
- this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions} - Documentos: ${this.fileSettings.docsExtensions}`;
485
- }
486
-
487
- if (this.isDoc) this.emitFileVars();
488
- },
489
- toggleFilePreview() {
490
- if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
491
- if (this.fileSettings.handleFilePreview) {
492
- this.emitFileVars();
493
- return this.$emit("handle-file-preview");
494
- }
495
- this.showFilePreview = !this.showFilePreview;
496
- if (this.showFilePreview && this.openFiles) this.toggleFiles();
497
- },
498
- emitFileVars() {
499
- const vars = {
500
- file: this.file,
501
- isDoc: this.isDoc,
502
- imagePreview: this.imagePreview,
503
- fileFormatError: this.fileFormatError,
504
- hasAnyFile: this.hasAnyFile,
505
- };
506
-
507
- this.$emit("set-file-vars", vars);
508
- this.$parent.focusTextarea();
509
- },
510
- deleteSpecificFile(obj) {
511
- const { fileName } = obj;
512
- this.file = this.file.filter((file) => {
513
- return file.name != fileName;
514
- });
515
- this.fileSize = this.file.length;
516
- this.file.length ? this.emitFileVars(true) : this.deleteFile();
517
- },
518
- deleteFile() {
519
- this.fileSize = this.file.length;
520
- this.$emit("set-file-vars", {
521
- file: [],
522
- isDoc: false,
523
- imagePreview: "",
524
- fileFormatError: false,
525
- hasAnyFile: false,
526
- });
527
-
528
- this.file = [];
529
- this.isDoc = false;
530
- this.showFilePreview = false;
531
- this.hasAnyFile = false;
532
- this.imagePreview = "";
533
- this.fileFormatError = false;
534
- this.validFileFormats = "";
535
- },
536
- openImage(imagePreview) {
537
- this.$emit("open-image", !imagePreview ? this.imagePreview : imagePreview);
538
- },
539
- },
540
- };
541
- </script>
1
+ <template>
2
+ <span
3
+ class="text-footer-actions--btn"
4
+ :class="{ 'files-activated': openFiles || file.name }"
5
+ @click="openFilesByClip()"
6
+ >
7
+ <!-- || file.length -->
8
+ <!-- <transition name="fade">
9
+ <span v-if="fileSize > 0" @click.stop="toggleFilePreview" v-tippy :content="`Visualizar ${fileSize} arquivo(s)`" class="files-counter">
10
+ {{ fileSize }}
11
+ </span>
12
+ </transition> -->
13
+ <fa-icon :icon="['fas', 'paperclip']" :title="dictionary.title_selecionar_anexo" />
14
+ <transition name="fade">
15
+ <span
16
+ v-if="fileSize > 0"
17
+ @click.stop="toggleFilePreview"
18
+ v-tippy
19
+ :content="
20
+ !fileSettings.handleFilePreview
21
+ ? dictionary.msg_abrir_anexos
22
+ : `${file.length} anexo(s) selecionado(s)`
23
+ "
24
+ :class="`${
25
+ fileSettings.filePreviewStyle == 2 ? 'files-counter-2' : 'files-counter'
26
+ }`"
27
+ >
28
+ <template v-if="fileSettings.filePreviewStyle == 1">
29
+ {{ fileSize }}
30
+ </template>
31
+ <template v-else>
32
+ <fa-icon :icon="['fas', 'eye']" />
33
+ </template>
34
+ </span>
35
+ </transition>
36
+ <transition name="show">
37
+ <div
38
+ v-if="openFiles && hasButtonFiles"
39
+ class="text-footer-files-container"
40
+ :class="{ horizontal: cssStyle.outsideButtons }"
41
+ >
42
+ <template v-if="!fileSettings.multiple">
43
+ <div
44
+ class="files-btn images"
45
+ :class="{ 'margin-bottom': cssStyle.outsideButtons }"
46
+ :title="dictionary.title_anexo_img"
47
+ @click="openSelectFileHandler('img')"
48
+ >
49
+ <fa-icon :icon="['fas', 'image']" />
50
+ </div>
51
+ <div
52
+ class="files-btn docs"
53
+ :title="dictionary.title_anexo_doc"
54
+ @click="openSelectFileHandler('doc')"
55
+ >
56
+ <fa-icon :icon="['fas', 'file-alt']" />
57
+ </div>
58
+ </template>
59
+ <div
60
+ v-else
61
+ class="files-btn both"
62
+ :title="dictionary.title_anexo_arq"
63
+ @click="openSelectFileHandler('both')"
64
+ >
65
+ <fa-icon :icon="['fas', 'image']" />
66
+ <fa-icon :icon="['fas', 'file-alt']" />
67
+ </div>
68
+ <div
69
+ v-if="fileSettings.systemButton"
70
+ class="files-btn system"
71
+ :title="dictionary.title_anexo_sistema"
72
+ @click="openSelectFileHandler('system')"
73
+ >
74
+ <fa-icon :icon="['fas', 'server']" />
75
+ </div>
76
+ </div>
77
+ </transition>
78
+ <div class="files-pointers d-none">
79
+ <input
80
+ v-if="fileSettings.multiple"
81
+ type="file"
82
+ :id="`both-${textId}`"
83
+ :accept="acceptedExtensions"
84
+ multiple
85
+ @change="fileUpload($event, 'both')"
86
+ />
87
+ <input
88
+ v-if="!fileSettings.multiple"
89
+ type="file"
90
+ :id="`img-${textId}`"
91
+ :accept="acceptedExtensions"
92
+ @change="fileUpload($event, 'img')"
93
+ />
94
+ <input
95
+ v-if="!fileSettings.multiple"
96
+ type="file"
97
+ :id="`doc-${textId}`"
98
+ :accept="acceptedExtensions"
99
+ @change="fileUpload($event, 'doc')"
100
+ />
101
+ </div>
102
+ <transition name="fade">
103
+ <div
104
+ class="text-footer-preview-container"
105
+ @click.stop
106
+ v-show="showFilePreview"
107
+ :class="[previewContainerClass]"
108
+ v-on-clickaway="away"
109
+ >
110
+ <SingleFilePreview
111
+ v-if="!fileSettings.multiple && showFilePreview"
112
+ :dictionary="dictionary"
113
+ :file="file"
114
+ :isDoc="isDoc"
115
+ :fileFormatError="fileFormatError"
116
+ :validFileFormats="validFileFormats"
117
+ :imagePreview="imagePreview"
118
+ :textId="textId"
119
+ @delete-file="deleteFile"
120
+ @open-image="openImage"
121
+ @close="away"
122
+ />
123
+ <MultipleFilePreview
124
+ v-else-if="fileSettings.multiple && showFilePreview"
125
+ :dictionary="dictionary"
126
+ :file="file"
127
+ :fileFormatError="fileFormatError"
128
+ :validFileFormats="validFileFormats"
129
+ @delete-file="deleteFile"
130
+ @delete-specific-file="deleteSpecificFile"
131
+ @open-image="openImage"
132
+ @close="away"
133
+ />
134
+ </div>
135
+ </transition>
136
+ </span>
137
+ </template>
138
+
139
+ <style>
140
+ .fade-enter-active,
141
+ .fade-leave-active {
142
+ transition: opacity 0.3s;
143
+ }
144
+ .fade-enter,
145
+ .fade-leave-to {
146
+ opacity: 0;
147
+ }
148
+
149
+ .files-counter {
150
+ position: absolute;
151
+ top: unset;
152
+ transform: translate(17.5px, -15px);
153
+ background-color: #888;
154
+ z-index: 1;
155
+ font-size: 8px;
156
+ width: 15px;
157
+ height: 15px;
158
+ border-radius: 50%;
159
+ display: flex;
160
+ justify-content: center;
161
+ align-items: center;
162
+ cursor: pointer;
163
+ opacity: 0.9;
164
+ transition: all 300ms;
165
+ color: #fff;
166
+ font-weight: 900;
167
+ }
168
+ .files-counter:hover {
169
+ opacity: 1;
170
+ }
171
+ .files-counter-2 {
172
+ transform: translate(-15px, 28px);
173
+ opacity: 0.9;
174
+ position: absolute;
175
+ display: flex;
176
+ justify-content: center;
177
+ align-items: center;
178
+ color: #888;
179
+ font-size: 12.8px;
180
+ }
181
+ .files-counter-2 svg {
182
+ margin-left: 5px;
183
+ }
184
+ .files-counter-2:hover {
185
+ opacity: 1;
186
+ text-decoration: underline;
187
+ }
188
+ </style>
189
+
190
+ <script>
191
+ import { mixin as clickaway } from "vue-clickaway";
192
+ import SingleFilePreview from "./SingleFilePreview";
193
+ import MultipleFilePreview from "./MultipleFilePreview";
194
+
195
+ export default {
196
+ components: { SingleFilePreview, MultipleFilePreview },
197
+ mixins: [clickaway],
198
+ props: {
199
+ textId: {
200
+ type: String,
201
+ required: true,
202
+ },
203
+ dictionary: {
204
+ type: Object,
205
+ required: true,
206
+ },
207
+ fileSettings: {
208
+ type: Object,
209
+ required: false,
210
+ },
211
+ cssStyle: {
212
+ type: Object,
213
+ required: false,
214
+ },
215
+ hasButtonFiles: {
216
+ type: Boolean,
217
+ required: false,
218
+ },
219
+ externalFiles: {
220
+ type: Array,
221
+ required: false,
222
+ },
223
+ },
224
+ data() {
225
+ return {
226
+ file: [],
227
+ fileSize: 0,
228
+ openFiles: false,
229
+ showFilePreview: false,
230
+ imagePreview: "",
231
+ isDoc: false,
232
+ fileFormatError: false,
233
+ validFileFormats: "",
234
+ hasAnyFile: false,
235
+ externalFilesAux: [],
236
+ };
237
+ },
238
+ computed: {
239
+ previewContainerClass() {
240
+ if (this.fileFormatError) return "isError";
241
+ if (this.fileSettings.multiple) return "isMultiple";
242
+ if (this.isDoc) return "isDoc";
243
+ return "isMsg";
244
+ },
245
+ acceptedExtensions() {
246
+ let str = "";
247
+ if (this.fileSettings.docsExtensions && this.fileSettings.imagesExtensions) {
248
+ str = `${this.fileSettings.docsExtensions
249
+ .split("|")
250
+ .join(",")}${this.fileSettings.imagesExtensions.split("|").join(",")}`;
251
+ } else if (this.fileSettings.docsExtensions) {
252
+ str = this.fileSettings.docsExtensions.split("|").join(",");
253
+ } else if (this.fileSettings.imagesExtensions) {
254
+ str = this.fileSettings.imagesExtensions.split("|").join(",");
255
+ }
256
+ if (str) {
257
+ const arr = str.split(",").map((ext) => {
258
+ ext = ext && ext.startsWith(".") ? ext : `.${ext}`;
259
+ return ext;
260
+ });
261
+ str = arr.join(",");
262
+ }
263
+ if (this.fileSettings.multiple) return str ? str : "image/*,application/*";
264
+ if (this.isDoc) return str ? str : "application/*";
265
+ return str ? str : "image/*";
266
+ },
267
+ },
268
+ watch: {
269
+ externalFiles() {
270
+ if (!this.externalFiles.length) return;
271
+ if (this.externalFiles.length > this.fileSettings.max) {
272
+ this.$emit("reset-file-system");
273
+ return this.$toasted.global.defaultInfo({
274
+ msg: `Limite de ${this.fileSettings.max} arquivos`,
275
+ });
276
+ }
277
+ this.file = [];
278
+ this.externalFilesAux = Array.from(this.externalFiles);
279
+ this.externalFilesAux.forEach((files) => {
280
+ this.file.push(files);
281
+ });
282
+ this.fileSize = this.file.length;
283
+ this.multipleFileUpload();
284
+ },
285
+ },
286
+ methods: {
287
+ openFilesByClip() {
288
+ if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
289
+ if (this.fileSettings.multiple && !this.hasButtonFiles) {
290
+ return this.openSelectFileHandler("both");
291
+ }
292
+ return this.toggleFiles();
293
+ },
294
+ away() {
295
+ this.showFilePreview = false;
296
+ },
297
+ toggleFiles() {
298
+ this.openFiles = !this.openFiles;
299
+ },
300
+ openSelectFileHandler(type) {
301
+ if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
302
+ if (type == "system") return this.$emit("open-file-system");
303
+ if (this.fileSettings.multiple) {
304
+ type = "both";
305
+ }
306
+ const fileInput = document.querySelector(`#${type}-${this.textId}`);
307
+ if (fileInput) fileInput.click();
308
+ if (!fileInput)
309
+ if (!document.querySelector(".toasted.toasted-primary.error"))
310
+ this.$toasted.global.defaultError();
311
+ },
312
+ isFileValid(type, fileName, fileType) {
313
+ if (
314
+ (type == "img" && !this.fileSettings.imagesExtensions) ||
315
+ (type == "doc" && !this.fileSettings.docsExtensions)
316
+ ) {
317
+ this.$toasted.global.defaultInfo({
318
+ msg: this.dictionary.sem_extensoes_parametrizadas,
319
+ });
320
+ this.hasAnyFile = false;
321
+ return false;
322
+ }
323
+ const extensions =
324
+ type === "img"
325
+ ? this.fileSettings.imagesExtensions
326
+ : this.fileSettings.docsExtensions;
327
+ const regex = new RegExp("(" + extensions + ")", "i");
328
+ if (regex.test(fileName) || regex.test(fileType)) return true;
329
+ this.hasAnyFile = false;
330
+ this.showToastedValidFormats();
331
+ return false;
332
+ },
333
+ showToastedValidFormats() {
334
+ if (!document.querySelector(".toasted.toasted-primary.error"))
335
+ this.$toasted.global.defaultError({ msg: this.dictionary.msg_formato_invalido });
336
+ const str = {
337
+ img: this.fileSettings.imagesExtensions.split("|").join(", "),
338
+ doc: this.fileSettings.docsExtensions.split("|").join(", "),
339
+ };
340
+ if (!document.querySelector(".toasted.toasted-primary.info"))
341
+ this.$toasted.global.showValidFormats({
342
+ msg: `Imagens: ${str.img} - Documentos: ${str.doc} ${this.dictionary.msg_extensoes_aceitas}`,
343
+ });
344
+ },
345
+ fileUpload(event, type, externalCall) {
346
+ try {
347
+ this.fileSize = 0;
348
+ if (this.fileFormatError) this.file = [];
349
+ this.openFiles = false;
350
+ const filesAux = !externalCall
351
+ ? event.target.files
352
+ ? event.target.files
353
+ : event.dataTransfer.files
354
+ : event;
355
+ const isStackable = this.fileSettings.stackFiles && this.fileSettings.multiple;
356
+ this.file = filesAux.length
357
+ ? isStackable
358
+ ? this.file.concat(...filesAux)
359
+ : filesAux
360
+ : this.file;
361
+ if (!this.file.length) return;
362
+
363
+ let sizeInBytes = 0;
364
+ Array.from(this.file).forEach((file) => (sizeInBytes += file.size));
365
+ const sizeInMb = parseFloat((sizeInBytes / (1024 * 1024)).toFixed(2));
366
+ if (sizeInMb == 0) {
367
+ this.file = [];
368
+ return this.$toasted.global.defaultInfo({
369
+ msg: this.dictionary.msg_arquivo_invalido,
370
+ });
371
+ }
372
+ if (sizeInMb >= 15) {
373
+ this.file = [];
374
+ return this.$toasted.global.defaultInfo({ msg: `Limite de 15 MB por arquivo` });
375
+ }
376
+
377
+ if (this.file.length > this.fileSettings.max) {
378
+ this.file = [];
379
+ return this.$toasted.global.defaultInfo({
380
+ msg: `Limite de ${this.fileSettings.max} arquivos`,
381
+ });
382
+ }
383
+ this.hasAnyFile = true;
384
+ this.fileSize = this.file.length;
385
+ if (!this.fileSettings.multiple) {
386
+ this.file = this.file[0];
387
+ this.singleFileUpload(type, this.file.name, this.file.type);
388
+ } else {
389
+ this.multipleFileUpload();
390
+ }
391
+ } catch (e) {
392
+ console.error("Error file upload");
393
+ console.error(e);
394
+ }
395
+ },
396
+ returnFileType(file) {
397
+ if (!this.fileSettings.imagesExtensions && !this.fileSettings.docsExtensions)
398
+ return "";
399
+
400
+ const imgRegex = new RegExp("\.(" + this.fileSettings.imagesExtensions + ")", "i");
401
+ if (imgRegex.test(file.name)) return "img";
402
+
403
+ const docRegex = new RegExp("\.(" + this.fileSettings.docsExtensions + ")", "i");
404
+ if (docRegex.test(file.name)) return "doc";
405
+
406
+ return "";
407
+ },
408
+ multipleFileUpload() {
409
+ const hasImgExt = this.fileSettings.imagesExtensions ? true : false;
410
+ const hasDocExt = this.fileSettings.docsExtensions ? true : false;
411
+ if (!hasImgExt && !hasDocExt) {
412
+ this.file = [];
413
+ this.fileSize = 0;
414
+ return this.$toasted.global.defaultInfo({
415
+ msg: this.dictionary.sem_extensoes_parametrizadas,
416
+ });
417
+ }
418
+ let waitForImageLoad = false;
419
+ let hasAnyInvalidFile = false;
420
+ this.file = Array.from(this.file);
421
+ this.file.forEach((file) => {
422
+ const singleFileType = this.returnFileType(file);
423
+ if (!singleFileType) file.invalid = true;
424
+ file.imgOrDoc = singleFileType ? singleFileType : "";
425
+ if (this.isFileValid(file.imgOrDoc, file.name, file.type)) {
426
+ if (file.imgOrDoc == "img") {
427
+ const fileReader = new FileReader();
428
+ waitForImageLoad = true;
429
+ fileReader.onload = () => (file.src = fileReader.result);
430
+ fileReader.onloadend = () => this.emitFileVars(true);
431
+ fileReader.readAsDataURL(file);
432
+ }
433
+ if (file.imgOrDoc === "doc") this.isDoc = true;
434
+ file.invalid = false;
435
+ this.fileFormatError = !hasAnyInvalidFile ? false : true;
436
+ } else {
437
+ hasAnyInvalidFile = true;
438
+ file.invalid = true;
439
+ this.fileFormatError = true;
440
+ if (hasImgExt && !hasDocExt)
441
+ this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions
442
+ .split("|")
443
+ .join(", ")}`;
444
+ if (hasDocExt && hasImgExt)
445
+ this.validFileFormats = `Documentos: ${this.fileSettings.docsExtensions
446
+ .split("|")
447
+ .join(", ")}`;
448
+ if (hasImgExt && hasDocExt)
449
+ this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions
450
+ .split("|")
451
+ .join(", ")} - Documentos: ${this.fileSettings.docsExtensions
452
+ .split("|")
453
+ .join(", ")}`;
454
+ }
455
+ });
456
+
457
+ if (this.fileFormatError) {
458
+ this.file = [];
459
+ this.fileSize = 0;
460
+ }
461
+
462
+ if (this.isDoc && !waitForImageLoad) this.emitFileVars();
463
+ },
464
+ singleFileUpload(type, fileName, fileType) {
465
+ if (this.isFileValid(type, fileName, fileType)) {
466
+ const fileReader = new FileReader();
467
+ if (type === "img") {
468
+ fileReader.onload = () => (this.imagePreview = fileReader.result);
469
+ fileReader.onloadend = () => this.emitFileVars();
470
+ fileReader.readAsDataURL(this.file);
471
+ }
472
+ if (type === "doc") this.isDoc = true;
473
+
474
+ this.fileFormatError = false;
475
+ } else {
476
+ this.fileFormatError = true;
477
+ const hasImgExt = this.fileSettings.imagesExtensions ? true : false;
478
+ const hasDocExt = this.fileSettings.docsExtensions ? true : false;
479
+ if (hasImgExt && !hasDocExt)
480
+ this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions}`;
481
+ if (hasDocExt && hasImgExt)
482
+ this.validFileFormats = `Documentos: ${this.fileSettings.docsExtensions}`;
483
+ if (hasImgExt && hasDocExt)
484
+ this.validFileFormats = `Imagens: ${this.fileSettings.imagesExtensions} - Documentos: ${this.fileSettings.docsExtensions}`;
485
+ }
486
+
487
+ if (this.isDoc) this.emitFileVars();
488
+ },
489
+ toggleFilePreview() {
490
+ if (this.fileSettings.handleFileClick) return this.$emit("handle-file-click");
491
+ if (this.fileSettings.handleFilePreview) {
492
+ this.emitFileVars();
493
+ return this.$emit("handle-file-preview");
494
+ }
495
+ this.showFilePreview = !this.showFilePreview;
496
+ if (this.showFilePreview && this.openFiles) this.toggleFiles();
497
+ },
498
+ emitFileVars() {
499
+ const vars = {
500
+ file: this.file,
501
+ isDoc: this.isDoc,
502
+ imagePreview: this.imagePreview,
503
+ fileFormatError: this.fileFormatError,
504
+ hasAnyFile: this.hasAnyFile,
505
+ };
506
+
507
+ this.$emit("set-file-vars", vars);
508
+ this.$parent.focusTextarea();
509
+ },
510
+ deleteSpecificFile(obj) {
511
+ const { fileName } = obj;
512
+ this.file = this.file.filter((file) => {
513
+ return file.name != fileName;
514
+ });
515
+ this.fileSize = this.file.length;
516
+ this.file.length ? this.emitFileVars(true) : this.deleteFile();
517
+ },
518
+ deleteFile() {
519
+ this.fileSize = this.file.length;
520
+ this.$emit("set-file-vars", {
521
+ file: [],
522
+ isDoc: false,
523
+ imagePreview: "",
524
+ fileFormatError: false,
525
+ hasAnyFile: false,
526
+ });
527
+
528
+ this.file = [];
529
+ this.isDoc = false;
530
+ this.showFilePreview = false;
531
+ this.hasAnyFile = false;
532
+ this.imagePreview = "";
533
+ this.fileFormatError = false;
534
+ this.validFileFormats = "";
535
+ },
536
+ openImage(imagePreview) {
537
+ this.$emit("open-image", !imagePreview ? this.imagePreview : imagePreview);
538
+ },
539
+ },
540
+ };
541
+ </script>