diff --git a/extension/chrome/elements/compose-modules/compose-quote-module.ts b/extension/chrome/elements/compose-modules/compose-quote-module.ts index 7163b459ec5..f80b6a4fb3b 100644 --- a/extension/chrome/elements/compose-modules/compose-quote-module.ts +++ b/extension/chrome/elements/compose-modules/compose-quote-module.ts @@ -17,6 +17,7 @@ import { ViewModule } from '../../../js/common/view-module.js'; import { ComposeView } from '../compose.js'; import { MessageToReplyOrForward } from './compose-types.js'; import { KeyStore } from '../../../js/common/platform/store/key-store.js'; +import { Time } from '../../../js/common/browser/time.js'; export class ComposeQuoteModule extends ViewModule { public tripleDotSanitizedHtmlContent: { quote: string | undefined; footer: string | undefined } | undefined; @@ -177,6 +178,9 @@ export class ComposeQuoteModule extends ViewModule { if (decryptRes.success) { return decryptRes.content.toUtfStr(); } else if (decryptRes.error && decryptRes.error.type === DecryptErrTypes.needPassphrase) { + if (Catch.isThunderbirdMail() && this.view.useFullScreenSecureCompose) { + await Time.sleep(2300); + } BrowserMsg.send.passphraseDialog(this.view.parentTabId, { type: 'quote', longids: decryptRes.longids.needPassphrase, @@ -206,7 +210,7 @@ export class ComposeQuoteModule extends ViewModule { return; } const text = this.messageToReplyOrForward.text; - const from = this.messageToReplyOrForward.headers.from; + const from = Str.parseEmail(this.messageToReplyOrForward.headers.from || '').email; const date = new Date(String(this.messageToReplyOrForward.headers.date)); const dateStr = Str.fromDate(date).replace(' ', ' at '); const rtl = text.match(new RegExp('[' + Str.rtlChars + ']')); @@ -215,7 +219,8 @@ export class ComposeQuoteModule extends ViewModule { if (method === 'reply') { const header = `
On ${dateStr}, ${from ?? ''} wrote:
`; const sanitizedQuote = Xss.htmlSanitize(header + escapedText); - return `
${sanitizedQuote}
`; + const thunderbirdClass = this.view.useFullScreenSecureCompose ? 'class="height-0"' : ''; // fix long quoted email UI issue happens in fullscreen + return `
${sanitizedQuote}
`; } else { const header = `
` + diff --git a/extension/chrome/elements/compose-modules/compose-render-module.ts b/extension/chrome/elements/compose-modules/compose-render-module.ts index b8d056cd55f..cdc2c0e445e 100644 --- a/extension/chrome/elements/compose-modules/compose-render-module.ts +++ b/extension/chrome/elements/compose-modules/compose-render-module.ts @@ -27,7 +27,11 @@ export class ComposeRenderModule extends ViewModule { private previousReplyOption: ReplyOption | undefined; public initComposeBox = async () => { - if (this.view.isReplyBox) { + if (this.view.useFullScreenSecureCompose) { + this.view.S.cached('body').addClass('full_window'); + this.view.S.cached('password_or_pubkey').height(1); // fix UI issue in fullscreen + } + if (this.view.replyMsgId) { this.responseMethod = 'reply'; } await this.view.replyPopoverModule.render(this.view.isReplyBox); @@ -41,11 +45,11 @@ export class ComposeRenderModule extends ViewModule { this.view.draftModule.startDraftTimer(); this.view.S.cached('triple_dot').remove(); // if it's draft, footer and quote should already be included in the draft } - if (this.view.isReplyBox) { + if (this.view.replyMsgId) { await this.view.renderModule.renderReplyMsgComposeTable(); } } else { - if (this.view.isReplyBox && this.view.replyParams) { + if (this.view.replyMsgId && this.view.replyParams) { const recipients: Recipients = { to: this.view.replyParams.to, cc: this.view.replyParams.cc, @@ -99,6 +103,9 @@ export class ComposeRenderModule extends ViewModule { )?.value; } this.view.replyParams.subject = `${this.responseMethod === 'reply' ? 'Re' : 'Fwd'}: ${this.view.replyParams.subject}`; + if (this.view.useFullScreenSecureCompose) { + this.view.S.cached('input_subject').val(this.view.replyParams.subject); + } } if (!this.view.draftModule.wasMsgLoadedFromDraft) { // if there is a draft, don't attempt to pull quoted content. It's assumed to be already present in the draft @@ -260,6 +267,12 @@ export class ComposeRenderModule extends ViewModule { await this.renderReplyMsgComposeTable(); }; + public actionCloseHandler = async () => { + if (!this.view.sendBtnModule.isSendMessageInProgres() || (await Ui.modal.confirm(Lang.compose.abortSending))) { + this.view.renderModule.closeMsg(); + } + }; + private initComposeBoxStyles = () => { if (this.view.isReplyBox) { this.view.S.cached('body').addClass('reply_box'); @@ -328,16 +341,12 @@ export class ComposeRenderModule extends ViewModule { this.view.S.cached('compose_table').css('display', 'table'); await this.addComposeTableHandlers(); await this.view.senderModule.renderSendFromIfMoreThanOneAlias(); - if (this.view.isReplyBox) { + if (this.view.replyMsgId) { if (this.view.replyParams?.to.length) { // Firefox will not always respond to initial automatic $input_text.blur(): recipients may be left unrendered, as standard text, with a trailing comma await this.view.recipientsModule.parseRenderRecipients(this.view.S.cached('input_to')); // this will force firefox to render them on load } } else { - $('.close_compose_window').on( - 'click', - this.view.setHandler(() => this.actionCloseHandler(), this.view.errModule.handle(`close compose window`)) - ); this.view.S.cached('title').on('click', () => { if (this.view.sizeModule.composeWindowIsMinimized) { $('.minimize_compose_window').trigger('click'); @@ -400,12 +409,6 @@ export class ComposeRenderModule extends ViewModule { } }; - private actionCloseHandler = async () => { - if (!this.view.sendBtnModule.isSendMessageInProgres() || (await Ui.modal.confirm(Lang.compose.abortSending))) { - this.view.renderModule.closeMsg(); - } - }; - private onRecipientsClickHandler = () => { if (!this.view.S.cached('input_to').is(':focus')) { this.view.errModule.debug( diff --git a/extension/chrome/elements/compose-modules/compose-reply-btn-popover-module.ts b/extension/chrome/elements/compose-modules/compose-reply-btn-popover-module.ts index ea96cd48128..64cc4bafbf7 100644 --- a/extension/chrome/elements/compose-modules/compose-reply-btn-popover-module.ts +++ b/extension/chrome/elements/compose-modules/compose-reply-btn-popover-module.ts @@ -45,7 +45,9 @@ export class ComposeReplyBtnPopoverModule extends ViewModule { }; public changeOptionImage = (option: ReplyOption) => { - $('.reply-options-icon').attr('src', this.popoverItems[option].iconPath); + if (!this.view.useFullScreenSecureCompose) { + $('.reply-options-icon').attr('src', this.popoverItems[option].iconPath); + } }; private didOptionClick = async (option: ReplyOption) => { diff --git a/extension/chrome/elements/compose.ts b/extension/chrome/elements/compose.ts index e34353bb22c..560dc815746 100644 --- a/extension/chrome/elements/compose.ts +++ b/extension/chrome/elements/compose.ts @@ -41,6 +41,7 @@ export class ComposeView extends View { public readonly removeAfterClose: boolean; public readonly disableDraftSaving: boolean; public readonly debug: boolean; + public readonly useFullScreenSecureCompose: boolean; public readonly isReplyBox: boolean; public readonly replyMsgId: string; public readonly replyPubkeyMismatch: boolean; @@ -108,6 +109,7 @@ export class ComposeView extends View { toggle_send_options: '#toggle_send_options', toggle_reply_options: '#toggle_reply_options', icon_pubkey: '.icon.action_include_pubkey', + close_compose_window: '.close_compose_window', icon_help: '.action_feedback', icon_popout: '.popout img', triple_dot: '.action_show_prev_msg', @@ -148,6 +150,7 @@ export class ComposeView extends View { 'removeAfterClose', 'replyPubkeyMismatch', 'replyOption', + 'useFullScreenSecureCompose', ]); this.acctEmail = Assert.urlParamRequire.string(uncheckedUrlParams, 'acctEmail'); this.parentTabId = Assert.urlParamRequire.string(uncheckedUrlParams, 'parentTabId'); @@ -161,7 +164,8 @@ export class ComposeView extends View { this.replyPubkeyMismatch = uncheckedUrlParams.replyPubkeyMismatch === true; this.draftId = Assert.urlParamRequire.optionalString(uncheckedUrlParams, 'draftId') || ''; this.replyMsgId = Assert.urlParamRequire.optionalString(uncheckedUrlParams, 'replyMsgId') || ''; - this.isReplyBox = !!this.replyMsgId; + this.useFullScreenSecureCompose = uncheckedUrlParams.useFullScreenSecureCompose === true; + this.isReplyBox = !!this.replyMsgId && !this.useFullScreenSecureCompose; this.emailProvider = new Gmail(this.acctEmail); this.acctServer = new AccountServer(this.acctEmail); } @@ -201,7 +205,7 @@ export class ComposeView extends View { } BrowserMsg.listen(this.tabId); await this.renderModule.initComposeBox(); - if (this.replyOption && this.isReplyBox) { + if (this.replyOption && this.replyMsgId) { await this.renderModule.activateReplyOption(this.replyOption, true); } this.senderModule.checkEmailAliases().catch(Catch.reportErr); @@ -225,6 +229,10 @@ export class ComposeView extends View { }); this.S.cached('body').on('focusin', setActiveWindow); this.S.cached('body').on('click', setActiveWindow); + this.S.cached('close_compose_window').on( + 'click', + this.setHandler(async () => await this.renderModule.actionCloseHandler(), this.errModule.handle(`close compose window`)) + ); this.S.cached('icon_help').on( 'click', this.setHandler(async () => await this.renderModule.openSettingsWithDialog('help'), this.errModule.handle(`help dialog`)) diff --git a/extension/chrome/settings/inbox/inbox.htm b/extension/chrome/settings/inbox/inbox.htm index a8c0b61a7d8..f11593a770b 100644 --- a/extension/chrome/settings/inbox/inbox.htm +++ b/extension/chrome/settings/inbox/inbox.htm @@ -17,8 +17,10 @@