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
This commit is contained in:
Geoff Lankow 2021-02-16 12:12:36 +02:00
Родитель a0622c7ff4
Коммит 00ea9380c8
5 изменённых файлов: 217 добавлений и 175 удалений

Просмотреть файл

@ -478,7 +478,8 @@ class nsContextMenu {
this.onCanvas || this.onCanvas ||
this.onLink || this.onLink ||
this.onImage || this.onImage ||
this.onPlayableMedia || this.onAudio ||
this.onVideo ||
this.onTextInput this.onTextInput
); );
// Ensure these commands are updated with their current status. // Ensure these commands are updated with their current status.
@ -740,179 +741,6 @@ class nsContextMenu {
this.checkLastSeparator(this.xulMenu); 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() { setMessageTargets() {
if (this.browser) { if (this.browser) {
this.inAMessage = ["imap", "mailbox", "news", "snews"].includes( this.inAMessage = ["imap", "mailbox", "news", "snews"].includes(
@ -1003,7 +831,7 @@ class nsContextMenu {
*/ */
saveImage() { saveImage() {
saveURL( saveURL(
this.imageURL, this.imageInfo.currentSrc,
null, null,
"SaveImageTitle", "SaveImageTitle",
false, false,

Просмотреть файл

@ -16,9 +16,26 @@ var { MessageGenerator } = ChromeUtils.import(
const TEST_DOCUMENT_URL = const TEST_DOCUMENT_URL =
"http://mochi.test:8888/browser/comm/mail/base/test/browser/files/sampleContent.html"; "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; 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) { function checkMenuitems(menu, ...expectedItems) {
if (expectedItems.length == 0) { if (expectedItems.length == 0) {
// Menu should not be shown. // Menu should not be shown.
@ -47,6 +64,8 @@ async function checkABrowser(browser) {
let mailContext = browser.ownerDocument.getElementById("mailContext"); let mailContext = browser.ownerDocument.getElementById("mailContext");
// Just some text.
let shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); let shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown");
await BrowserTestUtils.synthesizeMouseAtCenter( await BrowserTestUtils.synthesizeMouseAtCenter(
"p", "p",
@ -62,6 +81,8 @@ async function checkABrowser(browser) {
); );
mailContext.hidePopup(); mailContext.hidePopup();
// A link.
shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown");
await BrowserTestUtils.synthesizeMouseAtCenter( await BrowserTestUtils.synthesizeMouseAtCenter(
"a", "a",
@ -78,6 +99,8 @@ async function checkABrowser(browser) {
); );
mailContext.hidePopup(); mailContext.hidePopup();
// A text input widget.
await BrowserTestUtils.synthesizeMouseAtCenter("input", {}, browser); await BrowserTestUtils.synthesizeMouseAtCenter("input", {}, browser);
shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown"); shownPromise = BrowserTestUtils.waitForEvent(mailContext, "popupshown");
await BrowserTestUtils.synthesizeMouseAtCenter( await BrowserTestUtils.synthesizeMouseAtCenter(
@ -96,6 +119,37 @@ async function checkABrowser(browser) {
"mailContext-spell-check-enabled" "mailContext-spell-check-enabled"
); );
mailContext.hidePopup(); 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() { add_task(async function testMessagePane() {
@ -107,6 +161,8 @@ add_task(async function testMessagePane() {
testFolder = rootFolder testFolder = rootFolder
.getChildNamed("test") .getChildNamed("test")
.QueryInterface(Ci.nsIMsgLocalMailFolder); .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 messages = new MessageGenerator().makeMessages({ count: 5 });
let messageStrings = messages.map(message => message.toMboxString()); let messageStrings = messages.map(message => message.toMboxString());
testFolder.addMessageBatch(messageStrings); testFolder.addMessageBatch(messageStrings);
@ -279,6 +335,7 @@ add_task(async function testExtensionPopupWindow() {
"sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response =>
response.text() 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 => "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response =>
response.text() response.text()
), ),
"tb-logo.png": await getImageArrayBuffer(),
}, },
manifest: { manifest: {
applications: { applications: {
@ -338,6 +396,7 @@ add_task(async function testExtensionComposeAction() {
"sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response =>
response.text() response.text()
), ),
"tb-logo.png": await getImageArrayBuffer(),
}, },
manifest: { manifest: {
applications: { applications: {
@ -391,6 +450,7 @@ add_task(async function testExtensionMessageDisplayAction() {
"sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response => "sampleContent.html": await fetch(TEST_DOCUMENT_URL).then(response =>
response.text() response.text()
), ),
"tb-logo.png": await getImageArrayBuffer(),
}, },
manifest: { manifest: {
applications: { applications: {

Просмотреть файл

@ -0,0 +1,153 @@
From andy@anway.invalid
Content-Type: multipart/related;
boundary="--------------CHOPCHOP0"
Subject: Big Meeting Today
From: "Andy Anway" <andy@anway.invalid>
To: "Bob Bell" <bob@bell.invalid>
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
<p>This is a page of sample content for tests.</p>
<p><a href="https://www.thunderbird.net/">Link to a web page</a></p>
<form>
<input type="text" />
</form>
<p><img src="cid:logo" width="304" height="84" /></p>
----------------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: <logo>
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--

Просмотреть файл

@ -10,5 +10,6 @@
<form> <form>
<input type="text" /> <input type="text" />
</form> </form>
<p><img src="tb-logo.png" width="304" height="84" /></p>
</body> </body>
</html> </html>

Двоичные данные
mail/base/test/browser/files/tb-logo.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 6.3 KiB