vue-intergrall-plugins 0.0.285 → 0.0.287

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