From 00ea9380c88e70c10eb96c7f802f21a822de947f Mon Sep 17 00:00:00 2001 From: Geoff Lankow Date: Tue, 16 Feb 2021 12:12:36 +0200 Subject: [PATCH] Bug 1691935 - Fix and test context menu Save Image As. r=mkmelin Replaces two fields that were only set by setTarget and removes setTarget, which is now unused. Differential Revision: https://phabricator.services.mozilla.com/D105258 --HG-- rename : mail/components/extensions/test/browser/data/tb-logo.png => mail/base/test/browser/files/tb-logo.png extra : amend_source : 7da62929e76db457f59b483e786a0b723142f690 --- mail/base/content/nsContextMenu.js | 178 +----------------- mail/base/test/browser/browser_mailContext.js | 60 ++++++ .../base/test/browser/files/sampleContent.eml | 153 +++++++++++++++ .../test/browser/files/sampleContent.html | 1 + mail/base/test/browser/files/tb-logo.png | Bin 0 -> 6462 bytes 5 files changed, 217 insertions(+), 175 deletions(-) create mode 100644 mail/base/test/browser/files/sampleContent.eml create mode 100644 mail/base/test/browser/files/tb-logo.png diff --git a/mail/base/content/nsContextMenu.js b/mail/base/content/nsContextMenu.js index 275587b7f7..2726b5ed15 100644 --- a/mail/base/content/nsContextMenu.js +++ b/mail/base/content/nsContextMenu.js @@ -478,7 +478,8 @@ class nsContextMenu { this.onCanvas || this.onLink || this.onImage || - this.onPlayableMedia || + this.onAudio || + this.onVideo || this.onTextInput ); // Ensure these commands are updated with their current status. @@ -740,179 +741,6 @@ class nsContextMenu { this.checkLastSeparator(this.xulMenu); } - /* eslint-disable complexity */ - /** - * Set the nsContextMenu properties based on the selected node and - * its ancestors. - */ - setTarget(aNode) { - // Clear any old spellchecking items from the menu, this used to - // be in the menu hiding code but wasn't getting called in all - // situations. Here, we can ensure it gets cleaned up any time the - // menu is shown. Note: must be before uninit because that clears the - // internal vars - // We also need to do that before we possibly bail because we just clicked - // on some XUL node. Otherwise, dictionary choices just accumulate until we - // right-click on some HTML element again. - gSpellChecker.clearSuggestionsFromMenu(); - gSpellChecker.clearDictionaryListFromMenu(); - gSpellChecker.uninit(); - - if ( - aNode.namespaceURI == - "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" - ) { - if (aNode.localName == "treecol") { - // The column header was clicked, show the column picker. - let treecols = aNode.parentNode; - let treeColPicker = treecols.querySelector("treecolpicker"); - let popup = treeColPicker.querySelector(`menupopup[anonid="popup"]`); - treeColPicker.buildPopup(popup); - popup.openPopup(aNode, "before_start", 0, 0, true); - this.shouldDisplay = false; - } - return; - } - this.onImage = false; - this.onLoadedImage = false; - this.onMetaDataItem = false; - this.onTextInput = false; - this.onEditable = false; - this.imageURL = ""; - this.onLink = false; - this.onVideo = false; - this.onAudio = false; - this.mediaURL = ""; - this.linkURL = ""; - this.linkURI = null; - this.linkProtocol = null; - this.onMathML = false; - - this.target = aNode; - - // Set up early the right flags for editable / not editable. - let editFlags = SpellCheckHelper.isEditable(this.target, window); - this.onTextInput = (editFlags & SpellCheckHelper.TEXTINPUT) !== 0; - this.onEditable = (editFlags & SpellCheckHelper.EDITABLE) !== 0; - - // First, do checks for nodes that never have children. - if (this.target.nodeType == Node.ELEMENT_NODE) { - if ( - this.target instanceof Ci.nsIImageLoadingContent && - this.target.currentURI - ) { - this.onImage = true; - this.onMetaDataItem = true; - - var request = this.target.getRequest( - Ci.nsIImageLoadingContent.CURRENT_REQUEST - ); - if (request && request.imageStatus & request.STATUS_SIZE_AVAILABLE) { - this.onLoadedImage = true; - } - - this.imageURL = this.target.currentURI.spec; - } else if (this.target instanceof HTMLInputElement) { - this.onTextInput = this.isTargetATextBox(this.target); - } else if ( - editFlags & - (SpellCheckHelper.INPUT | SpellCheckHelper.TEXTAREA) - ) { - if (!this.target.readOnly) { - this.onEditable = true; - gSpellChecker.init(this.target.editor); - gSpellChecker.initFromEvent( - document.popupRangeParent, - document.popupRangeOffset - ); - } - } else if (editFlags & SpellCheckHelper.CONTENTEDITABLE) { - let targetWin = this.target.ownerGlobal; - let editingSession = targetWin - ?.getInterface(Ci.nsIWebNavigation) - .QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIEditingSession); - gSpellChecker.init(editingSession.getEditorForWindow(targetWin)); - gSpellChecker.initFromEvent( - document.popupRangeParent, - document.popupRangeOffset - ); - } else if (this.target instanceof HTMLCanvasElement) { - this.onCanvas = true; - } else if (this.target instanceof HTMLVideoElement) { - this.onVideo = true; - this.onPlayableMedia = true; - this.mediaURL = this.target.currentSrc || this.target.src; - } else if (this.target instanceof HTMLAudioElement) { - this.onAudio = true; - this.onPlayableMedia = true; - this.mediaURL = this.target.currentSrc || this.target.src; - // Browser supports background images here but we don't need to. - } - } - - // Second, bubble out, looking for items of interest that might be - // parents of the click target, picking the innermost of each. - const XMLNS = "http://www.w3.org/XML/1998/namespace"; - var elem = this.target; - while (elem) { - if (elem.nodeType == Node.ELEMENT_NODE) { - // Link? - if ( - !this.onLink && - ((elem instanceof HTMLAnchorElement && elem.href) || - (elem instanceof HTMLAreaElement && elem.href) || - elem instanceof HTMLLinkElement || - elem.getAttributeNS("http://www.w3.org/1999/xlink", "type") == - "simple") - ) { - // Target is a link or a descendant of a link. - this.onLink = true; - this.onMetaDataItem = true; - // Remember corresponding element. - this.link = elem; - this.linkURL = this.getLinkURL(); - this.linkURI = this.getLinkURI(); - this.linkProtocol = this.getLinkProtocol(); - this.onMailtoLink = this.linkProtocol == "mailto"; - this.onSaveableLink = this.isLinkSaveable(); - } - - // Text input? - if (!this.onTextInput) { - this.onTextInput = this.isTargetATextBox(elem); - } - - // Metadata item? - if (!this.onMetaDataItem) { - if ( - (elem instanceof HTMLQuoteElement && elem.cite) || - (elem instanceof HTMLTableElement && elem.summary) || - (elem instanceof HTMLModElement && (elem.cite || elem.dateTime)) || - (elem instanceof HTMLElement && (elem.title || elem.lang)) || - elem.getAttributeNS(XMLNS, "lang") - ) { - this.onMetaDataItem = true; - } - } - - // Browser supports background images here but we don't need to. - } - elem = elem.parentNode; - } - - // See if the user clicked on MathML. - const NS_MathML = "http://www.w3.org/1998/Math/MathML"; - if ( - (this.target.nodeType == Node.TEXT_NODE && - this.target.parentNode.namespaceURI == NS_MathML) || - this.target.namespaceURI == NS_MathML - ) { - this.onMathML = true; - } - } - /* eslint-enable complexity */ - setMessageTargets() { if (this.browser) { this.inAMessage = ["imap", "mailbox", "news", "snews"].includes( @@ -1003,7 +831,7 @@ class nsContextMenu { */ saveImage() { saveURL( - this.imageURL, + this.imageInfo.currentSrc, null, "SaveImageTitle", false, diff --git a/mail/base/test/browser/browser_mailContext.js b/mail/base/test/browser/browser_mailContext.js index 9ddcf98fbe..7d3af6cfb4 100644 --- a/mail/base/test/browser/browser_mailContext.js +++ b/mail/base/test/browser/browser_mailContext.js @@ -16,9 +16,26 @@ var { MessageGenerator } = ChromeUtils.import( const TEST_DOCUMENT_URL = "http://mochi.test:8888/browser/comm/mail/base/test/browser/files/sampleContent.html"; +const TEST_MESSAGE_URL = + "http://mochi.test:8888/browser/comm/mail/base/test/browser/files/sampleContent.eml"; +const TEST_IMAGE_URL = + "http://mochi.test:8888/browser/comm/mail/base/test/browser/files/tb-logo.png"; let testFolder; +async function getImageArrayBuffer() { + let response = await fetch(TEST_IMAGE_URL); + let blob = await response.blob(); + + return new Promise((resolve, reject) => { + let reader = new FileReader(); + reader.addEventListener("loadend", event => { + resolve(event.target.result); + }); + reader.readAsArrayBuffer(blob); + }); +} + function checkMenuitems(menu, ...expectedItems) { if (expectedItems.length == 0) { // Menu should not be shown. @@ -47,6 +64,8 @@ async function checkABrowser(browser) { let mailContext = browser.ownerDocument.getElementById("mailContext"); + // Just some text. + let shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); await BrowserTestUtils.synthesizeMouseAtCenter( "p", @@ -62,6 +81,8 @@ async function checkABrowser(browser) { ); mailContext.hidePopup(); + // A link. + shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); await BrowserTestUtils.synthesizeMouseAtCenter( "a", @@ -78,6 +99,8 @@ async function checkABrowser(browser) { ); mailContext.hidePopup(); + // A text input widget. + await BrowserTestUtils.synthesizeMouseAtCenter("input", {}, browser); shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); await BrowserTestUtils.synthesizeMouseAtCenter( @@ -96,6 +119,37 @@ async function checkABrowser(browser) { "mailContext-spell-check-enabled" ); mailContext.hidePopup(); + + // An image. Also checks Save Image As works. + + shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); + await BrowserTestUtils.synthesizeMouseAtCenter( + "img", + { type: "contextmenu" }, + browser + ); + await shownPromise; + checkMenuitems( + mailContext, + "mailContext-selectall", + "mailContext-copyimage", + "mailContext-saveimage" + ); + + let pickerPromise = new Promise(resolve => { + SpecialPowers.MockFilePicker.init(window); + SpecialPowers.MockFilePicker.showCallback = picker => { + resolve(picker.defaultString); + return Ci.nsIFilePicker.returnCancel; + }; + }); + EventUtils.synthesizeMouseAtCenter( + browser.ownerDocument.getElementById("mailContext-saveimage"), + {}, + browser.ownerGlobal + ); + Assert.equal(await pickerPromise, "tb-logo.png"); + SpecialPowers.MockFilePicker.cleanup(); } add_task(async function testMessagePane() { @@ -107,6 +161,8 @@ add_task(async function testMessagePane() { testFolder = rootFolder .getChildNamed("test") .QueryInterface(Ci.nsIMsgLocalMailFolder); + let message = await fetch(TEST_MESSAGE_URL).then(r => r.text()); + testFolder.addMessageBatch([message]); let messages = new MessageGenerator().makeMessages({ count: 5 }); let messageStrings = messages.map(message => message.toMboxString()); testFolder.addMessageBatch(messageStrings); @@ -279,6 +335,7 @@ add_task(async function testExtensionPopupWindow() { "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => response.text() ), + "tb-logo.png": await getImageArrayBuffer(), }, }); @@ -300,6 +357,7 @@ add_task(async function testExtensionBrowserAction() { "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => response.text() ), + "tb-logo.png": await getImageArrayBuffer(), }, manifest: { applications: { @@ -338,6 +396,7 @@ add_task(async function testExtensionComposeAction() { "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => response.text() ), + "tb-logo.png": await getImageArrayBuffer(), }, manifest: { applications: { @@ -391,6 +450,7 @@ add_task(async function testExtensionMessageDisplayAction() { "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => response.text() ), + "tb-logo.png": await getImageArrayBuffer(), }, manifest: { applications: { diff --git a/mail/base/test/browser/files/sampleContent.eml b/mail/base/test/browser/files/sampleContent.eml new file mode 100644 index 0000000000..89ca45360b --- /dev/null +++ b/mail/base/test/browser/files/sampleContent.eml @@ -0,0 +1,153 @@ +From andy@anway.invalid +Content-Type: multipart/related; + boundary="--------------CHOPCHOP0" +Subject: Big Meeting Today +From: "Andy Anway" +To: "Bob Bell" +Message-Id: <0@made.up.invalid> +Date: Tue, 01 Feb 2000 00:00:00 +1300 + +This is a multi-part message in MIME format. +----------------CHOPCHOP0 +Content-Type: text/html; charset=ISO-8859-1; format=flowed +Content-Transfer-Encoding: 7bit + +

This is a page of sample content for tests.

+

Link to a web page

+
+ +
+

+ + +----------------CHOPCHOP0 +Content-Type: image/png; charset=ISO-8859-1; format=flowed; + name="tb-logo.png" +Content-Transfer-Encoding: base64 +Content-Disposition: attachment; + filename="tb-logo.png" +Content-ID: + +iVBORw0KGgoAAAANSUhEUgAAATAAAABUCAMAAAAyN5s5AAAC91BMVEVMaXErLDVPU1wYFx1O +T1RPT1RNT1MTExoFBwZNTlNOTlNNT1RNTlNMTFRNTlMGBgoDBgYFBQZNTlQGBgdOTlNNTlMA +AwMEBQVNTlNOUFRMTFUAAABNTlMEBgdNT1QFBwoEBAZOTlNNTlMuOoNNTlQACghNTlRNTlNO +T1RNTlMTDytNT1N/qs1NTlMxPolNTlSZydyfmI8pMHosPIYaFSFNTlMdEkRNUFVNTlMrM38U +EBczT5hNTlMtNX8UDy8+XqIqN4AkGmCTiIEwN4JHaKgRCygnLHdzmsNYdq2Fd3N2nMRvlL8g +G00RCi0TCzAsQYsqHGJMbq5pjLsWDj9HYqV/qdh6nsxpYFljhsL////7+PL38+z59u////z8 ++/f8+vT28ufz7+UoG2D+/fnx7ODu6NvRyb3g2c7k39bSzcXr5NbIvq/Z0si9sqLJw7jDuKjb +0cCJhYHOxbbn3s/n5eGjn5mtqKPY1M+0r6rl2MS9ubVwbW54dXZgXl5HREZnZWHHxcJWVlU/ +PjevpJXazbR/fX0cJGV/d29UaaFPTka5rZx0b2P/++T77c9UVEphW01BQFtXTl6QnavN3exg +hcBIa65bgL0rS5dOcbGKt9NKZ6dPdLZdhbk8ZKlDcbNVd7RWe7l0pcszX6c5WpyKvN5EYaI9 +aK8yWaNJdrRff7OBsdc0RZUvUppukr8xN3knRZItLXkoUqFiisUoPIlsnMVpirxKfcdekL+Z +yusoQY4EAQktOIQOBVVWicRBaqgqMmp3msRTgr40VJ1SiLhAbrFwmc1glc5DWaEqMoBRcKtp +kMh0ntRMfrlHdronKVek1vYVCzd/ptg7aaEYGG83UZM6X6JDc6taea1cZXwkIUJDV5kLAyW3 +6P2PwOlhp+A4QIIcDg8+TpYoIXQiFVY0SYuClLAFABlZKzUdFWgyN4zU//82MTUrIGkpHWVO +T1SUjoosIm0eK3oSCS89RYwpGjNNQHREVIaXdlSjqrsmJCHZ+P6hTAAuJnRz9RRfAAAAWXRS +TlMAAw0H2DaeARv9u/JCJ39bSVawUY/kECNSFBsL6jdqQS2nyiBjFnOGWS6XSv75/cP+/Y1X +gpf+INIxbcWMRrneatP7sn305HhA1FEovMfh4/W3xtjNzNPUx47MeaUAABWdSURBVHhe7JTH +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 + +----------------CHOPCHOP0-- + diff --git a/mail/base/test/browser/files/sampleContent.html b/mail/base/test/browser/files/sampleContent.html index 9975a72d5e..ee11d14fdd 100644 --- a/mail/base/test/browser/files/sampleContent.html +++ b/mail/base/test/browser/files/sampleContent.html @@ -10,5 +10,6 @@
+

diff --git a/mail/base/test/browser/files/tb-logo.png b/mail/base/test/browser/files/tb-logo.png new file mode 100644 index 0000000000000000000000000000000000000000..aac56e25465a4fa6a2bcf4f87f2fb662bea20bbe GIT binary patch literal 6462 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 Y8^pccOn(_7*#H0l07*qoM6N<$f_}y@uK)l5 literal 0 HcmV?d00001