vue-intergrall-plugins 1.1.89 → 1.2.0

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