vue-intergrall-plugins 1.1.52 → 1.1.54

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.
@@ -1,741 +1,741 @@
1
- <template>
2
- <div
3
- :class="['email-item box-shadow-active', isOpen ? isOpenClass : `${isClosedClass} cursor-pointer`, showInfos ? 'info-open' : '', origem, customClass]"
4
- @click="openByItem($event)">
5
- <div v-if="showInfos" class="email-overlay"></div>
6
- <div class="email-author" v-if="autor" :class="[origem, isMainEmail ? 'main' : '']" @click.stop="toggleIsOpen"
7
- :key="autor">
8
- <span :title="statusTitle"><fa-icon :icon="['fas', status !== 'C' ? 'reply' : 'times']" :class="[origem]" /></span>
9
- <p class="email-author-name" v-text="returnAuthorName" :title="returnAuthorName"></p>
10
- <span :title="`E-mail ${origem === 'outros' ? 'recebido' : 'enviado'}`">
11
- <fa-icon :icon="['fas', origem === 'outros' ? 'user' : 'headset']" class="email-to-svg" />
12
- </span>
13
- </div>
14
- <div class="email-custom-buttons" v-if="customButtons && customButtons.length" @click.stop>
15
- <span v-for="(button, index) in customButtons" :key="button.id || index" v-show="button.use"
16
- @click="button.callback ? button.callback(returnParams(button.params)) : $emit(button.emitName, returnParams(button.params))" :class="`${button.customClass || 'menu-mensagem'}`"
17
- v-tippy :content="button.tippyContent">
18
- <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
19
- <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
20
- </span>
21
- </div>
22
- <div
23
- v-if="customActionButtons && customActionButtons.length && customActionButtons[0].type === 'ja-spam'"
24
- :key="customActionButtons[0].id"
25
- class="ja-marcado-spam"
26
- >
27
- <span class="icon-tittle-ja-spam">
28
- <fa-icon :icon="['fas', 'exclamation-triangle']" style="color:#FF0000; margin-right:8px; font-size:16px;" />
29
- {{ customActionButtons[0].label }}
30
- </span>
31
- <div @click.stop class="ja-marcado-spam-buttons">
32
- <button
33
- :disabled="customActionButtons[0].btn1.disabled"
34
- class="btn-nao-spam"
35
- @click="customActionButtons[0].btn1.callback"
36
- style="position: relative;"
37
- >
38
- <VueLoader
39
- v-if="customActionButtons[0].btn1.loading"
40
- :hasBg="false"
41
- class="btn-loader"
42
- />
43
- <span :style="{ opacity: customActionButtons[0].btn1.loading ? 0 : 1 }">
44
- {{ customActionButtons[0].btn1.label }}
45
- </span>
46
- </button>
47
- <button
48
- :disabled="customActionButtons[0].btn2.disabled"
49
- class="btn-e-spam"
50
- @click="customActionButtons[0].btn2.callback"
51
- style="position: relative;"
52
- >
53
- <VueLoader
54
- v-if="customActionButtons[0].btn2.loading"
55
- :hasBg="false"
56
- class="btn-loader"
57
- />
58
- <span :style="{ opacity: customActionButtons[0].btn2.loading ? 0 : 1 }">
59
- <fa-icon v-if="customActionButtons[0].btn2.icon"
60
- class="icon-btn-encerrar-spam"
61
- :icon="['fas', customActionButtons[0].btn2.icon === 'exit' ? 'sign-out-alt' : customActionButtons[0].btn2.icon]"
62
- style="margin-right: 6px;"
63
- />
64
- {{ customActionButtons[0].btn2.label }}
65
- </span>
66
- </button>
67
- </div>
68
- </div>
69
- <div class="email-custom-action-buttons" v-if="customActionButtons && customActionButtons.length" @click.stop>
70
- <template v-for="(button, index) in customActionButtons">
71
- <button
72
- v-if="button.type !== 'ja-spam'"
73
- :key="button.id || index"
74
- v-show="button.use"
75
- @click="button.callback(returnParams(button.params))"
76
- :class="`${button.customClass || 'email-custom-action-button'}`"
77
- v-tippy
78
- :content="button.tippyContent"
79
- >
80
- <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
81
- <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
82
- <span v-if="button.label" class="email-custom-action-label" v-text="button.label"></span>
83
- </button>
84
- </template>
85
- </div>
86
- <div class="email-header" @click.stop="toggleIsOpen">
87
- <p class="email-subject" :title="returnMainValue()">
88
- {{ returnMainValue() }}
89
- </p>
90
- <div
91
- class="divBtnReplyEmail" :class="[isOpen ? 'reply-email-open' : '']" v-if="status === 'C'">
92
- <strong class="strongMsg">{{ status_msg }} </strong>
93
- <button
94
- v-if="hasReplyEmail"
95
- class="btnReplyEmail"
96
- @click.stop="emitReplyEmail"
97
- ><strong>Reenviar</strong>
98
- </button>
99
- </div>
100
- <div class="header-container">
101
- <div :class="`email-header-content${isOpen ? ' open' : ''}`">
102
- <div class="email-header-infos">
103
- <template>
104
- <div v-if="para && para.length" class="email-to-from-container" ref="emailToContainer">
105
- <EmailTo v-for="(recipient, index) in para" :key="`to-${recipient.email}`"
106
- :currentName="formattedToName(recipient.name, index, para.length)" :email="recipient.email"
107
- :showMail="isOpen" />
108
- </div>
109
-
110
- <div v-if="copia && copia.length" class="email-cc-container">
111
- <EmailTo v-for="(recipient, index) in copia" :key="`cc-${recipient.email}`"
112
- :currentName="formattedCcName(recipient.name, index, copia.length)" :email="recipient.email"
113
- :showMail="isOpen" />
114
- </div>
115
- <div class="email-to-btn" v-show="isOpen" @click.stop="toggleShowInfos()">
116
- <fa-icon :icon="['fas', 'caret-down']" />
117
- </div>
118
- </template>
119
- <div v-if="!isMainEmail && isOpen" class="email-subject-secondary">
120
- <span class="email-subject-span"
121
- v-text="`Assunto: ${htmlEntityToEmoji(replaceUnicodeWithEmoji(assunto)) || '(Sem assunto)'}`"></span>
122
- </div>
123
- </div>
124
- </div>
125
- <span :class="`email-date ${isOpen ? isOpenClass : isClosedClass}`" :title="formattedDate" ref="emailDate"
126
- v-show="formattedDate">
127
- <fa-icon :icon="['fas', 'calendar']" />
128
- {{ formattedDate }}
129
- </span>
130
- </div>
131
- <ul v-if="showInfos" ref="emailToInfos" class="email-to-infos box-shadow" v-clickaway="() => showInfos = false"
132
- @click.stop>
133
- <li v-for="(info, index) in mailInfos" :key="`info-${index}`" class="email-info">
134
- <span v-text="info.label"></span>
135
- {{ info.value }}
136
- </li>
137
- </ul>
138
- <span v-if="isOpen" :class="['email-actions box-shadow', { active: actionsOpen }, { main: isMainEmail }]"
139
- @click.stop="toggleActions">
140
- <span></span>
141
- <span></span>
142
- <span></span>
143
- </span>
144
- <ul class="email-actions-list box-shadow" v-if="actionsOpen && isOpen" v-clickaway="closeActions" @click.stop>
145
- <li class="email-action" @click.stop="toggleOpenMessage">
146
- {{ !openMessage ? 'Visualizar' : 'Esconder' }} texto do e-mail (html)
147
- </li>
148
- </ul>
149
- </div>
150
- <div class="email-content" v-show="isOpen" ref="emailIframeParent">
151
- <VueLoader v-if="isIframeLoading" />
152
- <div v-if="hasError" class="email-error-content">
153
- <p>Erro ao carregar o e-mail</p>
154
- <button class="box-shadow" @click="handleTryAgain()">Tentar novamente</button>
155
- </div>
156
- <iframe v-show="!hasError" ref="emailIframe"
157
- :class="`email-html ${isIframeLoading ? 'visibility-hidden' : ''}`"></iframe>
158
- <span class="email-raw" v-if="openMessage">{{ mensagem }}</span>
159
- </div>
160
- <div v-if="filteredFiles && filteredFiles.length" class="email-files" v-show="isOpen">
161
- <EmailFile v-for="(anexo, index) in filteredFiles" :key="index" :anexo="anexo" :dominio="dominio" />
162
- </div>
163
- <div
164
- v-if="filteredFiles && filteredFiles.length && !isOpen"
165
- class="email-attachments-clip cursor-pointer"
166
- @click.stop="openAndScrollToAttachments"
167
- >
168
- <span class="clip-icon">
169
- <fa-icon :icon="['fas', 'paperclip']" />
170
- <span class="clip-badge">{{ filteredFiles.length }}</span>
171
- </span>
172
- </div>
173
- <!-- Status da mensagem -->
174
- <transition name="fade" mode="out-in">
175
- <span class="check" v-if="status == 'D'" :content="contentTooltip" v-tippy key="check-padrao">
176
- <fa-icon :icon="['fas', 'check']" />
177
- </span>
178
- <span class="check cinza" v-else-if="status == 'Q'" :content="contentTooltip" v-tippy key="check-cinza">
179
- <fa-icon :icon="['fas', 'check']" />
180
- </span>
181
- <span class="check preto" v-else-if="status == 'G'" :content="contentTooltip" v-tippy key="check-preto">
182
- <fa-icon :icon="['fas', 'check']" />
183
- </span>
184
- <span class="check preto" v-else-if="status == 'E'" :content="contentTooltip" v-tippy key="double-check-preto">
185
- <fa-icon :icon="['fas', 'check-double']" />
186
- </span>
187
- <span class="check visualizado" v-else-if="status == 'L'" :content="contentTooltip" v-tippy
188
- key="double-check-visualizado">
189
- <fa-icon :icon="['fas', 'check-double']" />
190
- </span>
191
- <!-- Status finalizador -->
192
- <span class="check vermelho" v-else-if="status == 'C' || status == 'ERRO'" :content="contentTooltip" v-tippy
193
- key="times-circle">
194
- <fa-icon :icon="['fas', 'times-circle']" />
195
- </span>
196
- <!-- Status finalizador -->
197
- <span class="check vermelho" v-else-if="status == 'T'" :content="contentTooltip" v-tippy key="hourglass">
198
- <fa-icon :icon="['fas', 'hourglass']" />
199
- </span>
200
- <!-- Status finalizador -->
201
- <span class="check vermelho" v-else-if="status == 'O'" :content="contentTooltip" v-tippy key="deleted">
202
- <fa-icon :icon="['fas', 'times']" />
203
- </span>
204
- <!-- Status de mensagem deletada -->
205
- </transition>
206
- </div>
207
- </template>
208
-
209
- <script>
210
- import EmailFile from "./EmailFile.vue";
211
- import EmailTo from "./EmailTo.vue";
212
- import { textoLongo } from "@/mixins/formatarTexto";
213
- import Clickaway from '@/directives/clickaway';
214
- import '../../styles/style.css';
215
-
216
- export default {
217
- mixins: [textoLongo],
218
- directives: {
219
- clickaway: Clickaway
220
- },
221
- components: { EmailFile, EmailTo },
222
- props: {
223
- dominio: {
224
- type: String,
225
- required: true
226
- },
227
- dicionario: {
228
- type: Object,
229
- required: true
230
- },
231
- customClass: {
232
- type: String,
233
- default: ''
234
- },
235
- from: {
236
- type: Array,
237
- default: () => []
238
- },
239
- para: {
240
- type: Array,
241
- default: () => []
242
- },
243
- copia: {
244
- type: Array,
245
- default: () => []
246
- },
247
- html: {
248
- type: String,
249
- default: ""
250
- },
251
- assunto: {
252
- type: String,
253
- default: ""
254
- },
255
- dataHora: {
256
- type: String,
257
- default: ""
258
- },
259
- mensagem: {
260
- type: String,
261
- default: ""
262
- },
263
- anexos: {
264
- type: [Array, String],
265
- default: () => []
266
- },
267
- iniciarAberto: {
268
- type: Boolean,
269
- default: false
270
- },
271
- dataServer: {
272
- type: String,
273
- default: ""
274
- },
275
- isOpenClass: {
276
- type: String,
277
- default: 'bg-dark-white-2'
278
- },
279
- isClosedClass: {
280
- type: String,
281
- default: 'bg-white'
282
- },
283
- refKey: {
284
- type: String,
285
- },
286
- showRawMessageInsideEmail: {
287
- type: Boolean,
288
- default: false
289
- },
290
- origem: {
291
- type: String,
292
- default: 'outros'
293
- },
294
- autor: {
295
- type: String
296
- },
297
- isMainEmail: {
298
- type: Boolean,
299
- default: true
300
- },
301
- customButtons: {
302
- type: Array
303
- },
304
- customActionButtons: {
305
- type: Array
306
- },
307
- status: {
308
- type: String,
309
- default: ''
310
- },
311
- status_msg: {
312
- type: String,
313
- default: ''
314
- },
315
- hasReplyEmail: {
316
- type: Boolean,
317
- default: false
318
- },
319
- id_lig: {
320
- type: String,
321
- },
322
- token_cliente: {
323
- type: String,
324
- },
325
- infos: {
326
- type: Object,
327
- default: () => ({}),
328
- },
329
- jaMarcadoSpam: {
330
- type: Boolean,
331
- default: false
332
- },
333
- msgTooltip: {
334
- type: String,
335
- default: ''
336
- }
337
- },
338
- data() {
339
- return {
340
- isOpen: this.iniciarAberto,
341
- openMessage: false,
342
- actionsOpen: false,
343
- showInfos: false,
344
- isIframeLoading: true,
345
- hasError: false,
346
- errorCount: 0,
347
- scrollToFile: false,
348
- };
349
- },
350
- computed: {
351
- statusTitle() {
352
- if(this.status !== 'C') {
353
- return `Enviado por: ${this.autor}`
354
- }
355
-
356
- if(!this.status_msg) {
357
- return `Enviado com erro por: ${this.autor}`
358
- }
359
-
360
- return `Enviado com erro por: ${this.autor} - ${this.status_msg}`
361
- },
362
- paraCopia() {
363
- if (!this.copia || !this.copia.length) return this.para && this.para.length ? this.para : []
364
- return this.para && this.para.length ? this.para.concat(this.copia) : this.copia
365
- },
366
- formattedDate() {
367
- return this.formataDateHoraDateFns(this.dataHora, this.dataServer, this.dicionario);
368
- },
369
- contentTooltip: {
370
- get() {
371
- if(!this.status || !this.msgTooltip) return ''
372
- if (this.status && !this.msgTooltip) {
373
- const msgStatus = "msg_status_" + this.status;
374
- return (this.strTooltipAux = this.dicionario[msgStatus]);
375
- } else if (this.status && this.msgTooltip) {
376
- return (this.strTooltipAux = this.msgTooltip);
377
- }
378
- },
379
- set(msg) {
380
- return (this.contentTooltip = msg);
381
- },
382
- },
383
- mailInfos() {
384
- const formatAsString = (arr) => {
385
- let str = ''
386
- arr.forEach(({ name, email }, index) => {
387
- if (!name && !email) str += ''
388
- else str += `${name || ''} ${email ? `<${email}>` : ''}${((name || email) && index !== arr.length - 1) ? ', ' : ''}`
389
- })
390
- return str
391
- }
392
-
393
- const infos = [
394
- {
395
- label: 'De:',
396
- value: this.from && this.from.length ? formatAsString(this.from) : '--'
397
- },
398
- {
399
- label: 'Para:',
400
- value: this.para && this.para.length ? formatAsString(this.para) : '--'
401
- },
402
- {
403
- label: 'Assunto:',
404
- value: this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
405
- },
406
- {
407
- label: 'Data:',
408
- value: this.formataDataHora(this.dataHora) || '--'
409
- },
410
- ]
411
-
412
- if (this.copia && this.copia.length) {
413
- infos.splice(2, 0, {
414
- label: `${this.dicionario.tit_copia}:` || 'Copia:',
415
- value: formatAsString(this.copia)
416
- })
417
- }
418
-
419
- return infos
420
- },
421
- filteredFiles() {
422
- if (!this.anexos || !this.anexos.length) return
423
-
424
- return this.anexos.filter(anexo => {
425
- return !this.html.includes(anexo.name);
426
- })
427
- },
428
- returnAuthorName() {
429
- if (!this.from || !this.from.length) return this.autor || ''
430
- const { email, name } = this.from[0]
431
- if (!name) return email
432
- if (!email) return name
433
- if (this.isOpen) return `${name} (${email})`
434
- return name
435
- },
436
- formattedToName() {
437
- return (name, index, length) => {
438
- let addVirgulaDps = index < length - 1
439
- const text = index === 0 ? `Para: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
440
- return text
441
- }
442
- },
443
- formattedCcName() {
444
- return (name, index, length) => {
445
- let addVirgulaDps = index < length - 1
446
- const text = index === 0 ? `${this.dicionario.tit_copia || 'Cópia'}: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
447
- return text
448
- }
449
- }
450
- },
451
- watch: {
452
- isOpen: 'updateIframeContent'
453
- },
454
- mounted() {
455
- this.updateIframeContent();
456
- this.adjustMaxWidth()
457
-
458
- if (this.refKey) this.$root.$refs[`${refKey}`] = this
459
-
460
- setTimeout(() => {
461
- if (this.isIframeLoading) this.adjustIframeHeight()
462
- }, 15000);
463
- },
464
- methods: {
465
- openAndScrollToAttachments() {
466
- if (!this.isOpen) {
467
- this.scrollToFile = true;
468
- this.isIframeLoading = true;
469
- this.isOpen = true;
470
- } else if (!this.isIframeLoading) {
471
- this.scrollToAttachments();
472
- } else {
473
- this.scrollToFile = true;
474
- }
475
- },
476
- scrollToAttachments() {
477
- this.$nextTick(() => {
478
- const files = this.$el.querySelector('.email-files');
479
- if (files) {
480
- files.scrollIntoView({ behavior: 'smooth', block: 'center' });
481
- }
482
- });
483
- },
484
- handleTryAgain() {
485
- this.isOpen = true
486
- this.isIframeLoading = true
487
- this.hasError = false
488
-
489
- this.$nextTick(this.updateIframeContent())
490
- },
491
-
492
- emitReplyEmail() {
493
- if(!this.hasReplyEmail) return
494
-
495
- this.$emit('reply-email', {
496
- html: this.html,
497
- mensagem: this.mensagem,
498
- assunto: this.assunto,
499
- from: this.from,
500
- para: this.para,
501
- dataHora: this.dataHora,
502
- anexos: this.anexos,
503
- status: this.status,
504
- status_msg: this.status_msg,
505
- copia: this.copia,
506
- origem: this.origem,
507
- autor: this.autor,
508
- id_lig: this.id_lig,
509
- token_cliente: this.token_cliente,
510
- infos: this.infos,
511
- });
512
- },
513
-
514
- gerarMensagemEstilizada(msg) {
515
- try {
516
- const currentStyles = [
517
- { tagAbertura: "<i>", tagFechamento: "</i>", find: /_(.*?)_/g },
518
- { tagAbertura: "<b>", tagFechamento: "</b>", find: /\*(.*?)\*/g },
519
- { tagAbertura: "<del>", tagFechamento: "</del>", find: /~(.*?)~/g }
520
- ]
521
-
522
- const isLetterOrUnderscore = (char) => {
523
- return /[a-zA-Z_]/.test(char)
524
- }
525
-
526
- const isValidMatch = (message, fullMatch, startIndex) => {
527
- const beforeChar = message[startIndex - 1]
528
- const afterChar = message[startIndex + fullMatch.length]
529
- return (
530
- (beforeChar === undefined || !isLetterOrUnderscore(beforeChar)) &&
531
- (afterChar === undefined || !isLetterOrUnderscore(afterChar))
532
- )
533
- }
534
-
535
- let message = msg
536
-
537
- for (const { tagAbertura, tagFechamento, find } of currentStyles) {
538
- let match
539
- while ((match = find.exec(message)) !== null) {
540
- const fullMatch = match[0]
541
- const content = match[1]
542
- const startIndex = match.index
543
-
544
- if (isValidMatch(message, fullMatch, startIndex)) {
545
- const endIndex = startIndex + fullMatch.length
546
- const replacedContent = `${tagAbertura}${content}${tagFechamento}`
547
- message = message.slice(0, startIndex) + replacedContent + message.slice(endIndex)
548
- }
549
- }
550
- }
551
-
552
- return message
553
- } catch (err) {
554
- console.error('Erro ao gerar mensagem estilizada: ', err)
555
- return msg
556
- }
557
- },
558
- updateIframeContent() {
559
- this.$nextTick(() => {
560
- if (this.isOpen && this.isIframeLoading) {
561
- const iframe = this.$refs.emailIframe;
562
- if (!iframe) {
563
- console.warn('Iframe not found');
564
- this.isIframeLoading = false
565
- return
566
- }
567
- const doc = iframe.contentDocument || iframe.contentWindow.document;
568
- if (!doc) {
569
- console.warn('Document not found in iframe');
570
- this.isIframeLoading = false
571
- return
572
- }
573
- let content = this.html || ''
574
- if(!content || !content.length) {
575
- console.warn('No content to display in iframe');
576
- this.isIframeLoading = false
577
- return
578
- }
579
- if (!/<[a-z][\s\S]*>/i.test(content)) {
580
- content = content.replace(/\n/g, '<br>');
581
- content = this.gerarMensagemEstilizada(content)
582
- content = `<p>${content}</p>`;
583
- }
584
-
585
- doc.open();
586
- doc.write(content);
587
- doc.close();
588
-
589
- const images = doc.getElementsByTagName('img');
590
- let imagesLoaded = 0;
591
-
592
- const imageLoadHandler = () => {
593
- imagesLoaded++;
594
- if (imagesLoaded === images.length) {
595
- this.adjustIframeHeight();
596
- }
597
- };
598
-
599
- if (images.length === 0) {
600
- this.adjustIframeHeight();
601
- } else {
602
- for (let img of images) {
603
- img.addEventListener('load', imageLoadHandler);
604
- img.addEventListener('error', imageLoadHandler);
605
- }
606
- }
607
- }
608
- });
609
- },
610
- adjustIframeHeight() {
611
- this.$nextTick(() => {
612
- const iframe = this.$refs.emailIframe;
613
- const emailParent = this.$refs.emailIframeParent
614
- if (iframe && emailParent) {
615
- setTimeout(() => {
616
- const doc = iframe.contentDocument || iframe.contentWindow.document;
617
- const margin = 20
618
- const value = doc.documentElement.offsetHeight + margin
619
- if (value === 0 || doc.documentElement.querySelector('body').innerHTML === '') {
620
- this.errorCount++
621
- if (this.errorCount > 3) {
622
- this.hasError = true
623
- if (this.isIframeLoading) this.isIframeLoading = false
624
- return
625
- }
626
- this.isIframeLoading = true
627
- this.updateIframeContent()
628
- return
629
- }
630
- if (this.hasError || this.errorCount > 0) {
631
- this.hasError = false
632
- this.errorCount = 0
633
- }
634
- iframe.style.height = `${value}px`;
635
- emailParent.style.minHeight = `${value}px`
636
- if (this.scrollToFile) {
637
- this.scrollToFile = false;
638
- this.scrollToAttachments();
639
- }
640
- }, 100)
641
- }
642
-
643
- if (this.isIframeLoading) this.isIframeLoading = false
644
- });
645
- },
646
- toggleShowInfos() {
647
- this.showInfos = !this.showInfos;
648
- if (this.showInfos) {
649
- this.$nextTick(() => {
650
- this.adjustTopPosition();
651
- });
652
- }
653
- },
654
- adjustTopPosition() {
655
- const ulElement = this.$refs.emailToInfos;
656
- if (!ulElement) return
657
- const ulHeight = ulElement.offsetHeight;
658
- const maxHeight = 300
659
- const finalHeight = ulHeight < maxHeight ? ulHeight : maxHeight
660
- ulElement.style.bottom = `-${finalHeight}px`;
661
- },
662
- toggleIsOpen() {
663
- this.isOpen = !this.isOpen;
664
- if (this.isOpen) {
665
- this.isIframeLoading = true;
666
- } else {
667
- this.actionsOpen = false;
668
- this.openMessage = false;
669
- this.showInfos = false;
670
- this.scrollToFile = false;
671
- }
672
- },
673
- adjustMaxWidth() {
674
- this.$nextTick(() => {
675
- const toContainer = this.$refs.emailToContainer
676
- const dateContainer = this.$refs.emailDate
677
- if (!toContainer || !dateContainer) return
678
- toContainer.style.maxWidth = `calc(100% - ${dateContainer.offsetWidth}px)`
679
- })
680
- },
681
- toggleActions() {
682
- this.actionsOpen = !this.actionsOpen;
683
- },
684
- toggleOpenMessage() {
685
- if (this.showRawMessageInsideEmail) {
686
- this.openMessage = !this.openMessage;
687
- }
688
-
689
- this.$emit('open-message', {
690
- dicionario: this.dicionario,
691
- from: this.from,
692
- para: this.para,
693
- html: this.html,
694
- assunto: this.assunto,
695
- dataHora: this.dataHora,
696
- mensagem: this.mensagem,
697
- anexos: this.filteredFiles,
698
- dataServer: this.dataServer,
699
- dominio: this.dominio
700
- })
701
- },
702
- closeActions() {
703
- this.actionsOpen = false;
704
- },
705
- returnMainValue() {
706
- if (this.isMainEmail) return this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
707
- return ''
708
- },
709
- openByItem(event) {
710
- if (this.isOpen) return;
711
-
712
- event.preventDefault();
713
- event.stopPropagation();
714
-
715
- this.toggleIsOpen();
716
- },
717
- returnParams(params) {
718
- const defaultParams = {
719
- message: this.mensagem,
720
- };
721
-
722
- if (!params) return defaultParams;
723
-
724
- const keys = params.instanceKeys.split("|");
725
- if (!keys || !keys.length)
726
- return {
727
- defaultParams,
728
- ...params.values,
729
- };
730
-
731
- const customParams = { ...params.values };
732
- keys.forEach((key) => {
733
- if (this[key]) customParams[key] = this[key];
734
- else console.warn(`Cant find ${key} on 'this' instance`);
735
- });
736
-
737
- return Object.keys(customParams).length ? customParams : defaultParams;
738
- }
739
- }
740
- };
1
+ <template>
2
+ <div
3
+ :class="['email-item box-shadow-active', isOpen ? isOpenClass : `${isClosedClass} cursor-pointer`, showInfos ? 'info-open' : '', origem, customClass]"
4
+ @click="openByItem($event)">
5
+ <div v-if="showInfos" class="email-overlay"></div>
6
+ <div class="email-author" v-if="autor" :class="[origem, isMainEmail ? 'main' : '']" @click.stop="toggleIsOpen"
7
+ :key="autor">
8
+ <span :title="statusTitle"><fa-icon :icon="['fas', status !== 'C' ? 'reply' : 'times']" :class="[origem]" /></span>
9
+ <p class="email-author-name" v-text="returnAuthorName" :title="returnAuthorName"></p>
10
+ <span :title="`E-mail ${origem === 'outros' ? 'recebido' : 'enviado'}`">
11
+ <fa-icon :icon="['fas', origem === 'outros' ? 'user' : 'headset']" class="email-to-svg" />
12
+ </span>
13
+ </div>
14
+ <div class="email-custom-buttons" v-if="customButtons && customButtons.length" @click.stop>
15
+ <span v-for="(button, index) in customButtons" :key="button.id || index" v-show="button.use"
16
+ @click="button.callback ? button.callback(returnParams(button.params)) : $emit(button.emitName, returnParams(button.params))" :class="`${button.customClass || 'menu-mensagem'}`"
17
+ v-tippy :content="button.tippyContent">
18
+ <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
19
+ <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
20
+ </span>
21
+ </div>
22
+ <div
23
+ v-if="customActionButtons && customActionButtons.length && customActionButtons[0].type === 'ja-spam'"
24
+ :key="customActionButtons[0].id"
25
+ class="ja-marcado-spam"
26
+ >
27
+ <span class="icon-tittle-ja-spam">
28
+ <fa-icon :icon="['fas', 'exclamation-triangle']" style="color:#FF0000; margin-right:8px; font-size:16px;" />
29
+ {{ customActionButtons[0].label }}
30
+ </span>
31
+ <div @click.stop class="ja-marcado-spam-buttons">
32
+ <button
33
+ :disabled="customActionButtons[0].btn1.disabled"
34
+ class="btn-nao-spam"
35
+ @click="customActionButtons[0].btn1.callback"
36
+ style="position: relative;"
37
+ >
38
+ <VueLoader
39
+ v-if="customActionButtons[0].btn1.loading"
40
+ :hasBg="false"
41
+ class="btn-loader"
42
+ />
43
+ <span :style="{ opacity: customActionButtons[0].btn1.loading ? 0 : 1 }">
44
+ {{ customActionButtons[0].btn1.label }}
45
+ </span>
46
+ </button>
47
+ <button
48
+ :disabled="customActionButtons[0].btn2.disabled"
49
+ class="btn-e-spam"
50
+ @click="customActionButtons[0].btn2.callback"
51
+ style="position: relative;"
52
+ >
53
+ <VueLoader
54
+ v-if="customActionButtons[0].btn2.loading"
55
+ :hasBg="false"
56
+ class="btn-loader"
57
+ />
58
+ <span :style="{ opacity: customActionButtons[0].btn2.loading ? 0 : 1 }">
59
+ <fa-icon v-if="customActionButtons[0].btn2.icon"
60
+ class="icon-btn-encerrar-spam"
61
+ :icon="['fas', customActionButtons[0].btn2.icon === 'exit' ? 'sign-out-alt' : customActionButtons[0].btn2.icon]"
62
+ style="margin-right: 6px;"
63
+ />
64
+ {{ customActionButtons[0].btn2.label }}
65
+ </span>
66
+ </button>
67
+ </div>
68
+ </div>
69
+ <div class="email-custom-action-buttons" v-if="customActionButtons && customActionButtons.length" @click.stop>
70
+ <template v-for="(button, index) in customActionButtons">
71
+ <button
72
+ v-if="button.type !== 'ja-spam'"
73
+ :key="button.id || index"
74
+ v-show="button.use"
75
+ @click="button.callback(returnParams(button.params))"
76
+ :class="`${button.customClass || 'email-custom-action-button'}`"
77
+ v-tippy
78
+ :content="button.tippyContent"
79
+ >
80
+ <fa-icon :icon="['fas', button.icon || 'question-circle']" v-if="!button.svgIcon" />
81
+ <span v-else v-html="button.svgIcon" :class="button.svgClass ? button.svgClass : ''"></span>
82
+ <span v-if="button.label" class="email-custom-action-label" v-text="button.label"></span>
83
+ </button>
84
+ </template>
85
+ </div>
86
+ <div class="email-header" @click.stop="toggleIsOpen">
87
+ <p class="email-subject" :title="returnMainValue()">
88
+ {{ returnMainValue() }}
89
+ </p>
90
+ <div
91
+ class="divBtnReplyEmail" :class="[isOpen ? 'reply-email-open' : '']" v-if="status === 'C'">
92
+ <strong class="strongMsg">{{ status_msg }} </strong>
93
+ <button
94
+ v-if="hasReplyEmail"
95
+ class="btnReplyEmail"
96
+ @click.stop="emitReplyEmail"
97
+ ><strong>Reenviar</strong>
98
+ </button>
99
+ </div>
100
+ <div class="header-container">
101
+ <div :class="`email-header-content${isOpen ? ' open' : ''}`">
102
+ <div class="email-header-infos">
103
+ <template>
104
+ <div v-if="para && para.length" class="email-to-from-container" ref="emailToContainer">
105
+ <EmailTo v-for="(recipient, index) in para" :key="`to-${recipient.email}`"
106
+ :currentName="formattedToName(recipient.name, index, para.length)" :email="recipient.email"
107
+ :showMail="isOpen" />
108
+ </div>
109
+
110
+ <div v-if="copia && copia.length" class="email-cc-container">
111
+ <EmailTo v-for="(recipient, index) in copia" :key="`cc-${recipient.email}`"
112
+ :currentName="formattedCcName(recipient.name, index, copia.length)" :email="recipient.email"
113
+ :showMail="isOpen" />
114
+ </div>
115
+ <div class="email-to-btn" v-show="isOpen" @click.stop="toggleShowInfos()">
116
+ <fa-icon :icon="['fas', 'caret-down']" />
117
+ </div>
118
+ </template>
119
+ <div v-if="!isMainEmail && isOpen" class="email-subject-secondary">
120
+ <span class="email-subject-span"
121
+ v-text="`Assunto: ${htmlEntityToEmoji(replaceUnicodeWithEmoji(assunto)) || '(Sem assunto)'}`"></span>
122
+ </div>
123
+ </div>
124
+ </div>
125
+ <span :class="`email-date ${isOpen ? isOpenClass : isClosedClass}`" :title="formattedDate" ref="emailDate"
126
+ v-show="formattedDate">
127
+ <fa-icon :icon="['fas', 'calendar']" />
128
+ {{ formattedDate }}
129
+ </span>
130
+ </div>
131
+ <ul v-if="showInfos" ref="emailToInfos" class="email-to-infos box-shadow" v-clickaway="() => showInfos = false"
132
+ @click.stop>
133
+ <li v-for="(info, index) in mailInfos" :key="`info-${index}`" class="email-info">
134
+ <span v-text="info.label"></span>
135
+ {{ info.value }}
136
+ </li>
137
+ </ul>
138
+ <span v-if="isOpen" :class="['email-actions box-shadow', { active: actionsOpen }, { main: isMainEmail }]"
139
+ @click.stop="toggleActions">
140
+ <span></span>
141
+ <span></span>
142
+ <span></span>
143
+ </span>
144
+ <ul class="email-actions-list box-shadow" v-if="actionsOpen && isOpen" v-clickaway="closeActions" @click.stop>
145
+ <li class="email-action" @click.stop="toggleOpenMessage">
146
+ {{ !openMessage ? 'Visualizar' : 'Esconder' }} texto do e-mail (html)
147
+ </li>
148
+ </ul>
149
+ </div>
150
+ <div class="email-content" v-show="isOpen" ref="emailIframeParent">
151
+ <VueLoader v-if="isIframeLoading" />
152
+ <div v-if="hasError" class="email-error-content">
153
+ <p>Erro ao carregar o e-mail</p>
154
+ <button class="box-shadow" @click="handleTryAgain()">Tentar novamente</button>
155
+ </div>
156
+ <iframe v-show="!hasError" ref="emailIframe"
157
+ :class="`email-html ${isIframeLoading ? 'visibility-hidden' : ''}`"></iframe>
158
+ <span class="email-raw" v-if="openMessage">{{ mensagem }}</span>
159
+ </div>
160
+ <div v-if="filteredFiles && filteredFiles.length" class="email-files" v-show="isOpen">
161
+ <EmailFile v-for="(anexo, index) in filteredFiles" :key="index" :anexo="anexo" :dominio="dominio" />
162
+ </div>
163
+ <div
164
+ v-if="filteredFiles && filteredFiles.length && !isOpen"
165
+ class="email-attachments-clip cursor-pointer"
166
+ @click.stop="openAndScrollToAttachments"
167
+ >
168
+ <span class="clip-icon">
169
+ <fa-icon :icon="['fas', 'paperclip']" />
170
+ <span class="clip-badge">{{ filteredFiles.length }}</span>
171
+ </span>
172
+ </div>
173
+ <!-- Status da mensagem -->
174
+ <transition name="fade" mode="out-in">
175
+ <span class="check" v-if="status == 'D'" :content="contentTooltip" v-tippy key="check-padrao">
176
+ <fa-icon :icon="['fas', 'check']" />
177
+ </span>
178
+ <span class="check cinza" v-else-if="status == 'Q'" :content="contentTooltip" v-tippy key="check-cinza">
179
+ <fa-icon :icon="['fas', 'check']" />
180
+ </span>
181
+ <span class="check preto" v-else-if="status == 'G'" :content="contentTooltip" v-tippy key="check-preto">
182
+ <fa-icon :icon="['fas', 'check']" />
183
+ </span>
184
+ <span class="check preto" v-else-if="status == 'E'" :content="contentTooltip" v-tippy key="double-check-preto">
185
+ <fa-icon :icon="['fas', 'check-double']" />
186
+ </span>
187
+ <span class="check visualizado" v-else-if="status == 'L'" :content="contentTooltip" v-tippy
188
+ key="double-check-visualizado">
189
+ <fa-icon :icon="['fas', 'check-double']" />
190
+ </span>
191
+ <!-- Status finalizador -->
192
+ <span class="check vermelho" v-else-if="status == 'C' || status == 'ERRO'" :content="contentTooltip" v-tippy
193
+ key="times-circle">
194
+ <fa-icon :icon="['fas', 'times-circle']" />
195
+ </span>
196
+ <!-- Status finalizador -->
197
+ <span class="check vermelho" v-else-if="status == 'T'" :content="contentTooltip" v-tippy key="hourglass">
198
+ <fa-icon :icon="['fas', 'hourglass']" />
199
+ </span>
200
+ <!-- Status finalizador -->
201
+ <span class="check vermelho" v-else-if="status == 'O'" :content="contentTooltip" v-tippy key="deleted">
202
+ <fa-icon :icon="['fas', 'times']" />
203
+ </span>
204
+ <!-- Status de mensagem deletada -->
205
+ </transition>
206
+ </div>
207
+ </template>
208
+
209
+ <script>
210
+ import EmailFile from "./EmailFile.vue";
211
+ import EmailTo from "./EmailTo.vue";
212
+ import { textoLongo } from "@/mixins/formatarTexto";
213
+ import Clickaway from '@/directives/clickaway';
214
+ import '../../styles/style.css';
215
+
216
+ export default {
217
+ mixins: [textoLongo],
218
+ directives: {
219
+ clickaway: Clickaway
220
+ },
221
+ components: { EmailFile, EmailTo },
222
+ props: {
223
+ dominio: {
224
+ type: String,
225
+ required: true
226
+ },
227
+ dicionario: {
228
+ type: Object,
229
+ required: true
230
+ },
231
+ customClass: {
232
+ type: String,
233
+ default: ''
234
+ },
235
+ from: {
236
+ type: Array,
237
+ default: () => []
238
+ },
239
+ para: {
240
+ type: Array,
241
+ default: () => []
242
+ },
243
+ copia: {
244
+ type: Array,
245
+ default: () => []
246
+ },
247
+ html: {
248
+ type: String,
249
+ default: ""
250
+ },
251
+ assunto: {
252
+ type: String,
253
+ default: ""
254
+ },
255
+ dataHora: {
256
+ type: String,
257
+ default: ""
258
+ },
259
+ mensagem: {
260
+ type: String,
261
+ default: ""
262
+ },
263
+ anexos: {
264
+ type: [Array, String],
265
+ default: () => []
266
+ },
267
+ iniciarAberto: {
268
+ type: Boolean,
269
+ default: false
270
+ },
271
+ dataServer: {
272
+ type: String,
273
+ default: ""
274
+ },
275
+ isOpenClass: {
276
+ type: String,
277
+ default: 'bg-dark-white-2'
278
+ },
279
+ isClosedClass: {
280
+ type: String,
281
+ default: 'bg-white'
282
+ },
283
+ refKey: {
284
+ type: String,
285
+ },
286
+ showRawMessageInsideEmail: {
287
+ type: Boolean,
288
+ default: false
289
+ },
290
+ origem: {
291
+ type: String,
292
+ default: 'outros'
293
+ },
294
+ autor: {
295
+ type: String
296
+ },
297
+ isMainEmail: {
298
+ type: Boolean,
299
+ default: true
300
+ },
301
+ customButtons: {
302
+ type: Array
303
+ },
304
+ customActionButtons: {
305
+ type: Array
306
+ },
307
+ status: {
308
+ type: String,
309
+ default: ''
310
+ },
311
+ status_msg: {
312
+ type: String,
313
+ default: ''
314
+ },
315
+ hasReplyEmail: {
316
+ type: Boolean,
317
+ default: false
318
+ },
319
+ id_lig: {
320
+ type: String,
321
+ },
322
+ token_cliente: {
323
+ type: String,
324
+ },
325
+ infos: {
326
+ type: Object,
327
+ default: () => ({}),
328
+ },
329
+ jaMarcadoSpam: {
330
+ type: Boolean,
331
+ default: false
332
+ },
333
+ msgTooltip: {
334
+ type: String,
335
+ default: ''
336
+ }
337
+ },
338
+ data() {
339
+ return {
340
+ isOpen: this.iniciarAberto,
341
+ openMessage: false,
342
+ actionsOpen: false,
343
+ showInfos: false,
344
+ isIframeLoading: true,
345
+ hasError: false,
346
+ errorCount: 0,
347
+ scrollToFile: false,
348
+ };
349
+ },
350
+ computed: {
351
+ statusTitle() {
352
+ if(this.status !== 'C') {
353
+ return `Enviado por: ${this.autor}`
354
+ }
355
+
356
+ if(!this.status_msg) {
357
+ return `Enviado com erro por: ${this.autor}`
358
+ }
359
+
360
+ return `Enviado com erro por: ${this.autor} - ${this.status_msg}`
361
+ },
362
+ paraCopia() {
363
+ if (!this.copia || !this.copia.length) return this.para && this.para.length ? this.para : []
364
+ return this.para && this.para.length ? this.para.concat(this.copia) : this.copia
365
+ },
366
+ formattedDate() {
367
+ return this.formataDateHoraDateFns(this.dataHora, this.dataServer, this.dicionario);
368
+ },
369
+ contentTooltip: {
370
+ get() {
371
+ if(!this.status || !this.msgTooltip) return ''
372
+ if (this.status && !this.msgTooltip) {
373
+ const msgStatus = "msg_status_" + this.status;
374
+ return (this.strTooltipAux = this.dicionario[msgStatus]);
375
+ } else if (this.status && this.msgTooltip) {
376
+ return (this.strTooltipAux = this.msgTooltip);
377
+ }
378
+ },
379
+ set(msg) {
380
+ return (this.contentTooltip = msg);
381
+ },
382
+ },
383
+ mailInfos() {
384
+ const formatAsString = (arr) => {
385
+ let str = ''
386
+ arr.forEach(({ name, email }, index) => {
387
+ if (!name && !email) str += ''
388
+ else str += `${name || ''} ${email ? `<${email}>` : ''}${((name || email) && index !== arr.length - 1) ? ', ' : ''}`
389
+ })
390
+ return str
391
+ }
392
+
393
+ const infos = [
394
+ {
395
+ label: 'De:',
396
+ value: this.from && this.from.length ? formatAsString(this.from) : '--'
397
+ },
398
+ {
399
+ label: 'Para:',
400
+ value: this.para && this.para.length ? formatAsString(this.para) : '--'
401
+ },
402
+ {
403
+ label: 'Assunto:',
404
+ value: this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
405
+ },
406
+ {
407
+ label: 'Data:',
408
+ value: this.formataDataHora(this.dataHora) || '--'
409
+ },
410
+ ]
411
+
412
+ if (this.copia && this.copia.length) {
413
+ infos.splice(2, 0, {
414
+ label: `${this.dicionario.tit_copia}:` || 'Copia:',
415
+ value: formatAsString(this.copia)
416
+ })
417
+ }
418
+
419
+ return infos
420
+ },
421
+ filteredFiles() {
422
+ if (!this.anexos || !this.anexos.length) return
423
+
424
+ return this.anexos.filter(anexo => {
425
+ return !this.html.includes(anexo.name);
426
+ })
427
+ },
428
+ returnAuthorName() {
429
+ if (!this.from || !this.from.length) return this.autor || ''
430
+ const { email, name } = this.from[0]
431
+ if (!name) return email
432
+ if (!email) return name
433
+ if (this.isOpen) return `${name} (${email})`
434
+ return name
435
+ },
436
+ formattedToName() {
437
+ return (name, index, length) => {
438
+ let addVirgulaDps = index < length - 1
439
+ const text = index === 0 ? `Para: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
440
+ return text
441
+ }
442
+ },
443
+ formattedCcName() {
444
+ return (name, index, length) => {
445
+ let addVirgulaDps = index < length - 1
446
+ const text = index === 0 ? `${this.dicionario.tit_copia || 'Cópia'}: ${name || ''}` : name ? `${name}${addVirgulaDps ? ', ' : ''}` : '';
447
+ return text
448
+ }
449
+ }
450
+ },
451
+ watch: {
452
+ isOpen: 'updateIframeContent'
453
+ },
454
+ mounted() {
455
+ this.updateIframeContent();
456
+ this.adjustMaxWidth()
457
+
458
+ if (this.refKey) this.$root.$refs[`${refKey}`] = this
459
+
460
+ setTimeout(() => {
461
+ if (this.isIframeLoading) this.adjustIframeHeight()
462
+ }, 15000);
463
+ },
464
+ methods: {
465
+ openAndScrollToAttachments() {
466
+ if (!this.isOpen) {
467
+ this.scrollToFile = true;
468
+ this.isIframeLoading = true;
469
+ this.isOpen = true;
470
+ } else if (!this.isIframeLoading) {
471
+ this.scrollToAttachments();
472
+ } else {
473
+ this.scrollToFile = true;
474
+ }
475
+ },
476
+ scrollToAttachments() {
477
+ this.$nextTick(() => {
478
+ const files = this.$el.querySelector('.email-files');
479
+ if (files) {
480
+ files.scrollIntoView({ behavior: 'smooth', block: 'center' });
481
+ }
482
+ });
483
+ },
484
+ handleTryAgain() {
485
+ this.isOpen = true
486
+ this.isIframeLoading = true
487
+ this.hasError = false
488
+
489
+ this.$nextTick(this.updateIframeContent())
490
+ },
491
+
492
+ emitReplyEmail() {
493
+ if(!this.hasReplyEmail) return
494
+
495
+ this.$emit('reply-email', {
496
+ html: this.html,
497
+ mensagem: this.mensagem,
498
+ assunto: this.assunto,
499
+ from: this.from,
500
+ para: this.para,
501
+ dataHora: this.dataHora,
502
+ anexos: this.anexos,
503
+ status: this.status,
504
+ status_msg: this.status_msg,
505
+ copia: this.copia,
506
+ origem: this.origem,
507
+ autor: this.autor,
508
+ id_lig: this.id_lig,
509
+ token_cliente: this.token_cliente,
510
+ infos: this.infos,
511
+ });
512
+ },
513
+
514
+ gerarMensagemEstilizada(msg) {
515
+ try {
516
+ const currentStyles = [
517
+ { tagAbertura: "<i>", tagFechamento: "</i>", find: /_(.*?)_/g },
518
+ { tagAbertura: "<b>", tagFechamento: "</b>", find: /\*(.*?)\*/g },
519
+ { tagAbertura: "<del>", tagFechamento: "</del>", find: /~(.*?)~/g }
520
+ ]
521
+
522
+ const isLetterOrUnderscore = (char) => {
523
+ return /[a-zA-Z_]/.test(char)
524
+ }
525
+
526
+ const isValidMatch = (message, fullMatch, startIndex) => {
527
+ const beforeChar = message[startIndex - 1]
528
+ const afterChar = message[startIndex + fullMatch.length]
529
+ return (
530
+ (beforeChar === undefined || !isLetterOrUnderscore(beforeChar)) &&
531
+ (afterChar === undefined || !isLetterOrUnderscore(afterChar))
532
+ )
533
+ }
534
+
535
+ let message = msg
536
+
537
+ for (const { tagAbertura, tagFechamento, find } of currentStyles) {
538
+ let match
539
+ while ((match = find.exec(message)) !== null) {
540
+ const fullMatch = match[0]
541
+ const content = match[1]
542
+ const startIndex = match.index
543
+
544
+ if (isValidMatch(message, fullMatch, startIndex)) {
545
+ const endIndex = startIndex + fullMatch.length
546
+ const replacedContent = `${tagAbertura}${content}${tagFechamento}`
547
+ message = message.slice(0, startIndex) + replacedContent + message.slice(endIndex)
548
+ }
549
+ }
550
+ }
551
+
552
+ return message
553
+ } catch (err) {
554
+ console.error('Erro ao gerar mensagem estilizada: ', err)
555
+ return msg
556
+ }
557
+ },
558
+ updateIframeContent() {
559
+ this.$nextTick(() => {
560
+ if (this.isOpen && this.isIframeLoading) {
561
+ const iframe = this.$refs.emailIframe;
562
+ if (!iframe) {
563
+ console.warn('Iframe not found');
564
+ this.isIframeLoading = false
565
+ return
566
+ }
567
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
568
+ if (!doc) {
569
+ console.warn('Document not found in iframe');
570
+ this.isIframeLoading = false
571
+ return
572
+ }
573
+ let content = this.html || ''
574
+ if(!content || !content.length) {
575
+ console.warn('No content to display in iframe');
576
+ this.isIframeLoading = false
577
+ return
578
+ }
579
+ if (!/<[a-z][\s\S]*>/i.test(content)) {
580
+ content = content.replace(/\n/g, '<br>');
581
+ content = this.gerarMensagemEstilizada(content)
582
+ content = `<p>${content}</p>`;
583
+ }
584
+
585
+ doc.open();
586
+ doc.write(content);
587
+ doc.close();
588
+
589
+ const images = doc.getElementsByTagName('img');
590
+ let imagesLoaded = 0;
591
+
592
+ const imageLoadHandler = () => {
593
+ imagesLoaded++;
594
+ if (imagesLoaded === images.length) {
595
+ this.adjustIframeHeight();
596
+ }
597
+ };
598
+
599
+ if (images.length === 0) {
600
+ this.adjustIframeHeight();
601
+ } else {
602
+ for (let img of images) {
603
+ img.addEventListener('load', imageLoadHandler);
604
+ img.addEventListener('error', imageLoadHandler);
605
+ }
606
+ }
607
+ }
608
+ });
609
+ },
610
+ adjustIframeHeight() {
611
+ this.$nextTick(() => {
612
+ const iframe = this.$refs.emailIframe;
613
+ const emailParent = this.$refs.emailIframeParent
614
+ if (iframe && emailParent) {
615
+ setTimeout(() => {
616
+ const doc = iframe.contentDocument || iframe.contentWindow.document;
617
+ const margin = 20
618
+ const value = doc.documentElement.offsetHeight + margin
619
+ if (value === 0 || doc.documentElement.querySelector('body').innerHTML === '') {
620
+ this.errorCount++
621
+ if (this.errorCount > 3) {
622
+ this.hasError = true
623
+ if (this.isIframeLoading) this.isIframeLoading = false
624
+ return
625
+ }
626
+ this.isIframeLoading = true
627
+ this.updateIframeContent()
628
+ return
629
+ }
630
+ if (this.hasError || this.errorCount > 0) {
631
+ this.hasError = false
632
+ this.errorCount = 0
633
+ }
634
+ iframe.style.height = `${value}px`;
635
+ emailParent.style.minHeight = `${value}px`
636
+ if (this.scrollToFile) {
637
+ this.scrollToFile = false;
638
+ this.scrollToAttachments();
639
+ }
640
+ }, 100)
641
+ }
642
+
643
+ if (this.isIframeLoading) this.isIframeLoading = false
644
+ });
645
+ },
646
+ toggleShowInfos() {
647
+ this.showInfos = !this.showInfos;
648
+ if (this.showInfos) {
649
+ this.$nextTick(() => {
650
+ this.adjustTopPosition();
651
+ });
652
+ }
653
+ },
654
+ adjustTopPosition() {
655
+ const ulElement = this.$refs.emailToInfos;
656
+ if (!ulElement) return
657
+ const ulHeight = ulElement.offsetHeight;
658
+ const maxHeight = 300
659
+ const finalHeight = ulHeight < maxHeight ? ulHeight : maxHeight
660
+ ulElement.style.bottom = `-${finalHeight}px`;
661
+ },
662
+ toggleIsOpen() {
663
+ this.isOpen = !this.isOpen;
664
+ if (this.isOpen) {
665
+ this.isIframeLoading = true;
666
+ } else {
667
+ this.actionsOpen = false;
668
+ this.openMessage = false;
669
+ this.showInfos = false;
670
+ this.scrollToFile = false;
671
+ }
672
+ },
673
+ adjustMaxWidth() {
674
+ this.$nextTick(() => {
675
+ const toContainer = this.$refs.emailToContainer
676
+ const dateContainer = this.$refs.emailDate
677
+ if (!toContainer || !dateContainer) return
678
+ toContainer.style.maxWidth = `calc(100% - ${dateContainer.offsetWidth}px)`
679
+ })
680
+ },
681
+ toggleActions() {
682
+ this.actionsOpen = !this.actionsOpen;
683
+ },
684
+ toggleOpenMessage() {
685
+ if (this.showRawMessageInsideEmail) {
686
+ this.openMessage = !this.openMessage;
687
+ }
688
+
689
+ this.$emit('open-message', {
690
+ dicionario: this.dicionario,
691
+ from: this.from,
692
+ para: this.para,
693
+ html: this.html,
694
+ assunto: this.assunto,
695
+ dataHora: this.dataHora,
696
+ mensagem: this.mensagem,
697
+ anexos: this.filteredFiles,
698
+ dataServer: this.dataServer,
699
+ dominio: this.dominio
700
+ })
701
+ },
702
+ closeActions() {
703
+ this.actionsOpen = false;
704
+ },
705
+ returnMainValue() {
706
+ if (this.isMainEmail) return this.htmlEntityToEmoji(this.replaceUnicodeWithEmoji(this.assunto)) || '(Sem assunto)'
707
+ return ''
708
+ },
709
+ openByItem(event) {
710
+ if (this.isOpen) return;
711
+
712
+ event.preventDefault();
713
+ event.stopPropagation();
714
+
715
+ this.toggleIsOpen();
716
+ },
717
+ returnParams(params) {
718
+ const defaultParams = {
719
+ message: this.mensagem,
720
+ };
721
+
722
+ if (!params) return defaultParams;
723
+
724
+ const keys = params.instanceKeys.split("|");
725
+ if (!keys || !keys.length)
726
+ return {
727
+ defaultParams,
728
+ ...params.values,
729
+ };
730
+
731
+ const customParams = { ...params.values };
732
+ keys.forEach((key) => {
733
+ if (this[key]) customParams[key] = this[key];
734
+ else console.warn(`Cant find ${key} on 'this' instance`);
735
+ });
736
+
737
+ return Object.keys(customParams).length ? customParams : defaultParams;
738
+ }
739
+ }
740
+ };
741
741
  </script>