import $ from '$'; import ko from 'ko'; import key from 'key'; import { DATA_IMAGE_USER_DOT_PIC, UNUSED_OPTION_VALUE } from 'Common/Consts'; import { Capa, ComposeType, ClientSideKeyName, KeyState, FolderType, Focused, Layout, Magics, MessageSetAction } from 'Common/Enums'; import { $htmlCL, leftPanelDisabled, keyScopeReal, useKeyboardShortcuts, moveAction } from 'Common/Globals'; import { isNonEmptyArray, windowResize, windowResizeCallback, inFocus, removeSelection, removeInFocus, mailToHelper, isTransparent } from 'Common/Utils'; import Audio from 'Common/Audio'; import * as Events from 'Common/Events'; import { i18n } from 'Common/Translator'; import { attachmentDownload } from 'Common/Links'; import { getUserPic, storeMessageFlagsToCache } from 'Common/Cache'; import AppStore from 'Stores/User/App'; import SettingsStore from 'Stores/User/Settings'; import AccountStore from 'Stores/User/Account'; import FolderStore from 'Stores/User/Folder'; import MessageStore from 'Stores/User/Message'; import * as Local from 'Storage/Client'; import * as Settings from 'Storage/Settings'; import Remote from 'Remote/User/Ajax'; import Promises from 'Promises/User/Ajax'; import { getApp } from 'Helper/Apps/User'; import { view, command, ViewType, showScreenPopup, createCommand } from 'Knoin/Knoin'; import { AbstractViewNext } from 'Knoin/AbstractViewNext'; @view({ name: 'View/User/MailBox/MessageView', type: ViewType.Right, templateID: 'MailMessageView' }) class MessageViewMailBoxUserView extends AbstractViewNext { constructor() { super(); let lastEmail = ''; const createCommandReplyHelper = (type) => createCommand(() => { this.lastReplyAction(type); this.replyOrforward(type); }, this.canBeRepliedOrForwarded); const createCommandActionHelper = (folderType, useFolder) => createCommand(() => { const message = this.message(); if (message && this.allowMessageListActions) { this.message(null); getApp().deleteMessagesFromFolder(folderType, message.folderFullNameRaw, [message.uid], useFolder); } }, this.messageVisibility); this.oDom = null; this.oHeaderDom = null; this.oMessageScrollerDom = null; this.bodyBackgroundColor = ko.observable(''); this.pswp = null; this.moveAction = moveAction; this.allowComposer = !!Settings.capa(Capa.Composer); this.allowMessageActions = !!Settings.capa(Capa.MessageActions); this.allowMessageListActions = !!Settings.capa(Capa.MessageListActions); this.logoImg = (Settings.settingsGet('UserLogoMessage')||'').trim(); this.logoIframe = (Settings.settingsGet('UserIframeMessage')||'').trim(); this.mobile = !!Settings.appSettingsGet('mobile'); this.attachmentsActions = AppStore.attachmentsActions; this.message = MessageStore.message; this.messageListChecked = MessageStore.messageListChecked; this.hasCheckedMessages = MessageStore.hasCheckedMessages; this.messageListCheckedOrSelectedUidsWithSubMails = MessageStore.messageListCheckedOrSelectedUidsWithSubMails; this.messageLoadingThrottle = MessageStore.messageLoadingThrottle; this.messagesBodiesDom = MessageStore.messagesBodiesDom; this.useThreads = SettingsStore.useThreads; this.replySameFolder = SettingsStore.replySameFolder; this.layout = SettingsStore.layout; this.usePreviewPane = SettingsStore.usePreviewPane; this.isMessageSelected = MessageStore.isMessageSelected; this.messageActiveDom = MessageStore.messageActiveDom; this.messageError = MessageStore.messageError; this.fullScreenMode = MessageStore.messageFullScreenMode; this.messageListOfThreadsLoading = ko.observable(false).extend({ rateLimit: 1 }); this.highlightUnselectedAttachments = ko.observable(false).extend({ falseTimeout: 2000 }); this.showAttachmnetControls = ko.observable(false); this.showAttachmnetControlsState = (v) => { Local.set(ClientSideKeyName.MessageAttachmnetControls, !!v); }; this.allowAttachmnetControls = ko.computed( () => this.attachmentsActions().length && Settings.capa(Capa.AttachmentsActions) ); this.downloadAsZipAllowed = ko.computed( () => this.attachmentsActions().includes('zip') && this.allowAttachmnetControls() ); this.downloadAsZipLoading = ko.observable(false); this.downloadAsZipError = ko.observable(false).extend({ falseTimeout: 7000 }); this.showAttachmnetControls.subscribe((v) => { if (this.message()) { this.message().attachments().forEach(item => { if (item) { item.checked(!!v); } }); } }); this.lastReplyAction_ = ko.observable(''); this.lastReplyAction = ko.computed({ read: this.lastReplyAction_, write: (value) => { this.lastReplyAction_( [ComposeType.Reply, ComposeType.ReplyAll, ComposeType.Forward].includes(value) ? ComposeType.Reply : value ); } }); this.lastReplyAction(Local.get(ClientSideKeyName.LastReplyAction) || ComposeType.Reply); this.lastReplyAction_.subscribe((value) => { Local.set(ClientSideKeyName.LastReplyAction, value); }); this.showFullInfo = ko.observable('1' === Local.get(ClientSideKeyName.MessageHeaderFullInfo)); this.moreDropdownTrigger = ko.observable(false); this.messageDomFocused = ko.observable(false).extend({ rateLimit: 0 }); this.messageVisibility = ko.computed(() => !this.messageLoadingThrottle() && !!this.message()); this.message.subscribe((message) => { if (!message) { MessageStore.selectorMessageSelected(null); } }); this.canBeRepliedOrForwarded = ko.computed(() => { const v = this.messageVisibility(); return !this.isDraftFolder() && v; }); // commands this.replyCommand = createCommandReplyHelper(ComposeType.Reply); this.replyAllCommand = createCommandReplyHelper(ComposeType.ReplyAll); this.forwardCommand = createCommandReplyHelper(ComposeType.Forward); this.forwardAsAttachmentCommand = createCommandReplyHelper(ComposeType.ForwardAsAttachment); this.editAsNewCommand = createCommandReplyHelper(ComposeType.EditAsNew); this.deleteCommand = createCommandActionHelper(FolderType.Trash, true); this.deleteWithoutMoveCommand = createCommandActionHelper(FolderType.Trash, false); this.archiveCommand = createCommandActionHelper(FolderType.Archive, true); this.spamCommand = createCommandActionHelper(FolderType.Spam, true); this.notSpamCommand = createCommandActionHelper(FolderType.NotSpam, true); // viewer this.viewBodyTopValue = ko.observable(0); this.viewFolder = ''; this.viewUid = ''; this.viewHash = ''; this.viewSubject = ko.observable(''); this.viewFromShort = ko.observable(''); this.viewFromDkimData = ko.observable(['none', '']); this.viewToShort = ko.observable(''); this.viewFrom = ko.observable(''); this.viewTo = ko.observable(''); this.viewCc = ko.observable(''); this.viewBcc = ko.observable(''); this.viewReplyTo = ko.observable(''); this.viewTimeStamp = ko.observable(0); this.viewSize = ko.observable(''); this.viewLineAsCss = ko.observable(''); this.viewViewLink = ko.observable(''); this.viewUnsubscribeLink = ko.observable(''); this.viewDownloadLink = ko.observable(''); this.viewUserPic = ko.observable(DATA_IMAGE_USER_DOT_PIC); this.viewUserPicVisible = ko.observable(false); this.viewIsImportant = ko.observable(false); this.viewIsFlagged = ko.observable(false); this.viewFromDkimVisibility = ko.computed(() => 'none' !== this.viewFromDkimData()[0]); this.viewFromDkimStatusIconClass = ko.computed(() => { switch (this.viewFromDkimData()[0]) { case 'none': return 'icon-none iconcolor-display-none'; case 'pass': return 'icon-ok iconcolor-green'; default: return 'icon-warning-alt iconcolor-red'; } }); this.viewFromDkimStatusTitle = ko.computed(() => { const status = this.viewFromDkimData(); if (isNonEmptyArray(status)) { if (status[0] && status[1]) { return status[1]; } else if (status[0]) { return 'DKIM: ' + status[0]; } } return ''; }); this.messageActiveDom.subscribe((dom) => { this.bodyBackgroundColor(dom ? this.detectDomBackgroundColor(dom) : ''); }, this); this.message.subscribe((message) => { this.messageActiveDom(null); if (message) { this.showAttachmnetControls(false); if (Local.get(ClientSideKeyName.MessageAttachmnetControls)) { setTimeout(() => { this.showAttachmnetControls(true); }, Magics.Time50ms); } if (this.viewHash !== message.hash) { this.scrollMessageToTop(); } this.viewFolder = message.folderFullNameRaw; this.viewUid = message.uid; this.viewHash = message.hash; this.viewSubject(message.subject()); this.viewFromShort(message.fromToLine(true, true)); this.viewFromDkimData(message.fromDkimData()); this.viewToShort(message.toToLine(true, true)); this.viewFrom(message.fromToLine(false)); this.viewTo(message.toToLine(false)); this.viewCc(message.ccToLine(false)); this.viewBcc(message.bccToLine(false)); this.viewReplyTo(message.replyToToLine(false)); this.viewTimeStamp(message.dateTimeStampInUTC()); this.viewSize(message.friendlySize()); this.viewLineAsCss(message.lineAsCss()); this.viewViewLink(message.viewLink()); this.viewUnsubscribeLink(message.getFirstUnsubsribeLink()); this.viewDownloadLink(message.downloadLink()); this.viewIsImportant(message.isImportant()); this.viewIsFlagged(message.flagged()); lastEmail = message.fromAsSingleEmail(); getUserPic(lastEmail, (pic, email) => { if (pic !== this.viewUserPic() && lastEmail === email) { this.viewUserPicVisible(false); this.viewUserPic(DATA_IMAGE_USER_DOT_PIC); if (pic) { this.viewUserPicVisible(true); this.viewUserPic(pic); } } }); } else { this.viewFolder = ''; this.viewUid = ''; this.viewHash = ''; this.scrollMessageToTop(); } }); this.message.viewTrigger.subscribe(() => { const message = this.message(); if (message) { this.viewIsFlagged(message.flagged()); } else { this.viewIsFlagged(false); } }); this.fullScreenMode.subscribe((value) => { $htmlCL.toggle('rl-message-fullscreen', value); windowResize(); }); this.messageLoadingThrottle.subscribe(windowResizeCallback); this.messageFocused = ko.computed(() => Focused.MessageView === AppStore.focusedState()); this.messageListAndMessageViewLoading = ko.computed( () => MessageStore.messageListCompleteLoadingThrottle() || MessageStore.messageLoadingThrottle() ); Events.sub('mailbox.message-view.toggle-full-screen', () => { this.toggleFullScreen(); }); this.attachmentPreview = this.attachmentPreview.bind(this); } @command() closeMessageCommand() { MessageStore.message(null); } @command((self) => self.messageVisibility()) messageVisibilityCommand() {} // eslint-disable-line no-empty-function @command((self) => self.messageVisibility()) messageEditCommand() { this.editMessage(); } @command((self) => !self.messageListAndMessageViewLoading()) goUpCommand() { Events.pub('mailbox.message-list.selector.go-up', [Layout.NoPreview === this.layout() ? !!this.message() : true]); } @command((self) => !self.messageListAndMessageViewLoading()) goDownCommand() { Events.pub('mailbox.message-list.selector.go-down', [Layout.NoPreview === this.layout() ? !!this.message() : true]); } detectDomBackgroundColor(dom) { let limit = 5, result = ''; const fFindDom = function(inputDom) { const children = inputDom ? inputDom.children() : null; return children && 1 === children.length && children.is('table,div,center') ? children : null; }, fFindColor = function(inputDom) { let color = ''; if (inputDom) { color = inputDom.css('background-color') || ''; if (!inputDom.is('table')) { color = isTransparent(color) ? '' : color; } } return color; }; if (dom && 1 === dom.length) { let aC = dom; while (!result) { limit -= 1; if (0 >= limit) { break; } aC = fFindDom(aC); if (aC) { result = fFindColor(aC); } else { break; } } result = isTransparent(result) ? '' : result; } return result; } fullScreen() { this.fullScreenMode(true); windowResize(); } unFullScreen() { this.fullScreenMode(false); windowResize(); } toggleFullScreen() { removeSelection(); this.fullScreenMode(!this.fullScreenMode()); windowResize(); } /** * @param {string} sType * @returns {void} */ replyOrforward(sType) { if (Settings.capa(Capa.Composer)) { showScreenPopup(require('View/Popup/Compose'), [sType, MessageStore.message()]); } } checkHeaderHeight() { if (this.oHeaderDom) { this.viewBodyTopValue( this.message() ? this.oHeaderDom.height() + Magics.Size20px /* padding-(top/bottom): 20px */ + Magics.Size1px /* borded-bottom: 1px */ : 0 ); } } // displayMailToPopup(sMailToUrl) { // sMailToUrl = sMailToUrl.replace(/\?.+$/, ''); // // var // sResult = '', // aTo = [], // EmailModel = require('Model/Email').default, // fParseEmailLine = function(sLine) { // return sLine ? [window.decodeURIComponent(sLine)].map(sItem => { // var oEmailModel = new EmailModel(); // oEmailModel.parse(sItem); // return oEmailModel.email ? oEmailModel : null; // }).filter(value => !!value) : null; // } // ; // // aTo = fParseEmailLine(sMailToUrl); // sResult = aTo && aTo[0] ? aTo[0].email : ''; // // return sResult; // } /** * @param {Object} oAttachment * @returns {boolean} */ attachmentPreview(attachment) { if (attachment && attachment.isImage() && !attachment.isLinked && this.message() && this.message().attachments()) { let index = 0, listIndex = 0; const div = $('