diff --git a/extension/img/svgs/reply-all-icon.svg b/extension/img/svgs/reply-all-icon.svg new file mode 100644 index 00000000000..30828ebd030 --- /dev/null +++ b/extension/img/svgs/reply-all-icon.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/extension/js/common/xss-safe-factory.ts b/extension/js/common/xss-safe-factory.ts index 26a97152388..471ed1206e5 100644 --- a/extension/js/common/xss-safe-factory.ts +++ b/extension/js/common/xss-safe-factory.ts @@ -269,9 +269,15 @@ export class XssSafeFactory { `; }; - public actionsMenuBtn = (action: 'reply' | 'forward') => { - return `
- secure ${action} + public actionsMenuBtn = (replyOption: ReplyOption) => { + const actionText = replyOption.replace('a_', '').replace('_', ' '); + const action = { + underscore: actionText.replace(' ', '_'), + hyphen: actionText.replace(' ', '-'), + }; + // * The action_${action.underscoreSeparated}_message_button is used as an identifier in GmailElementReplacer.actionActivateSecureReplyHandler() + return `
+ secure ${actionText}
`; }; diff --git a/extension/js/content_scripts/webmail/gmail/gmail-element-replacer.ts b/extension/js/content_scripts/webmail/gmail/gmail-element-replacer.ts index 56add5bfd16..48abe4c3eb1 100644 --- a/extension/js/content_scripts/webmail/gmail/gmail-element-replacer.ts +++ b/extension/js/content_scripts/webmail/gmail/gmail-element-replacer.ts @@ -151,8 +151,9 @@ export class GmailElementReplacer extends WebmailElementReplacer { $(document).on('click', 'div.aHU.hx', event => { const $actionsBtn = $(event.currentTarget).find(this.sel.msgActionsBtn); if ($actionsBtn.length && !$('.action_menu_message_button').length) { - this.addMenuButton('reply', '#r'); - this.addMenuButton('forward', '#r3'); + this.addMenuButton('a_reply', '#r'); + this.addMenuButton('a_reply_all', '#r2'); + this.addMenuButton('a_forward', '#r3'); } }); }; @@ -290,13 +291,15 @@ export class GmailElementReplacer extends WebmailElementReplacer { return !!$('iframe.pgp_block').filter(':visible').length; }; - private addMenuButton = (action: 'reply' | 'forward', selector: string) => { + private addMenuButton = (replyOption: ReplyOption, selector: string) => { const gmailActionsMenuContainer = $(this.sel.msgActionsMenu).find(selector); - const button = $(this.factory.actionsMenuBtn(action)).insertAfter(gmailActionsMenuContainer); // xss-safe-factory - button.on( - 'click', - Ui.event.handle((el, ev: JQuery.Event) => this.actionActivateSecureReplyHandler(el, ev)) - ); + if ($(selector).css('display') === 'block') { + const button = $(this.factory.actionsMenuBtn(replyOption)).insertAfter(gmailActionsMenuContainer); // xss-safe-factory + button.on( + 'click', + Ui.event.handle((el, ev: JQuery.Event) => this.actionActivateSecureReplyHandler(el, ev)) + ); + } }; private replaceConvoBtns = (force = false) => { @@ -370,7 +373,14 @@ export class GmailElementReplacer extends WebmailElementReplacer { private actionActivateSecureReplyHandler = async (btn: HTMLElement, event: JQuery.Event) => { event.stopImmediatePropagation(); const secureReplyInvokedFromMenu = btn.className.includes('action_menu_message_button'); - const replyOption: ReplyOption = btn.className.includes('reply') ? 'a_reply' : 'a_forward'; + let replyOption: ReplyOption; + if (btn.className.includes('reply-all')) { + replyOption = 'a_reply_all'; + } else if (btn.className.includes('forward')) { + replyOption = 'a_forward'; + } else { + replyOption = 'a_reply'; + } if ($('#switch_to_encrypted_reply').length) { $('#switch_to_encrypted_reply').trigger('click'); return; diff --git a/extension/manifest.json b/extension/manifest.json index 8c57be8e8c8..176223d2b23 100644 --- a/extension/manifest.json +++ b/extension/manifest.json @@ -78,6 +78,7 @@ "resources": [ "/css/webmail.css", "/img/svgs/reply-icon.svg", + "/img/svgs/reply-all-icon.svg", "/img/svgs/forward-icon.svg", "/img/svgs/spinner-white-small.svg", "/img/svgs/spinner-green-small.svg", diff --git a/test/source/tests/gmail.ts b/test/source/tests/gmail.ts index b360f2d0df8..fe76f69adcb 100644 --- a/test/source/tests/gmail.ts +++ b/test/source/tests/gmail.ts @@ -463,22 +463,21 @@ export const defineGmailTests = (testVariant: TestVariant, testWithBrowser: Test await BrowserRecipe.setUpCommonAcct(t, browser, 'ci.tests.gmail'); const gmailPage = await openGmailPage(t, browser); await gotoGmailPage(gmailPage, '/FMfcgzGtwgfMhWTlgRwwKWzRhqNZzwXz'); // go to encrypted convo - await Util.sleep(5); const actionsMenuSelector = '.J-J5-Ji.aap'; await gmailPage.waitAndClick(actionsMenuSelector); - await Util.sleep(3); expect(await gmailPage.isElementPresent('@action-reply-message-button')); + expect(await gmailPage.isElementPresent('@action-reply-all-message-button')); + expect(await gmailPage.isElementPresent('@action-forward-message-button')); await gmailPage.waitAndClick('@action-reply-message-button'); const replyBox = await gmailPage.getFrame(['/chrome/elements/compose.htm'], { sleep: 5 }); - await Util.sleep(3); await replyBox.waitForContent('@input-body', ''); await gmailPage.waitAndClick(actionsMenuSelector); - await Util.sleep(3); - expect(await gmailPage.isElementPresent('@action-forward-message-button')); - await gmailPage.waitAndClick('@action-forward-message-button'); + await gmailPage.waitAndClick('@action-reply-all-message-button'); const replyBox2 = await gmailPage.getFrame(['/chrome/elements/compose.htm'], { sleep: 5 }); - await Util.sleep(3); - await replyBox2.waitForContent('@input-body', '---------- Forwarded message ---------'); + await replyBox2.waitForContent('@input-body', ''); + await gmailPage.waitAndClick('@action-forward-message-button'); + const replyBox3 = await gmailPage.getFrame(['/chrome/elements/compose.htm'], { sleep: 5 }); + await replyBox3.waitForContent('@input-body', '---------- Forwarded message ---------'); }) );