Bug 923514 - add plaintext paste (paste without formatting) item to page context menu for richtext / contenteditable inputs, r=bgrins,fluent-reviewers,flod

Differential Revision: https://phabricator.services.mozilla.com/D153457
This commit is contained in:
Gijs Kruitbosch
2022-08-08 18:33:45 +00:00
parent 4d2d4b462c
commit 92c61677a9
7 changed files with 132 additions and 3 deletions

View File

@@ -1097,6 +1097,8 @@ class ContextMenuChild extends JSWindowActorChild {
context.onNumeric = (editFlags & lazy.SpellCheckHelper.NUMERIC) !== 0;
context.onEditable = (editFlags & lazy.SpellCheckHelper.EDITABLE) !== 0;
context.onPassword = (editFlags & lazy.SpellCheckHelper.PASSWORD) !== 0;
context.isDesignMode =
(editFlags & lazy.SpellCheckHelper.CONTENTEDITABLE) !== 0;
context.passwordRevealed =
context.onPassword && context.target.revealPassword;
context.onSpellcheckable =

View File

@@ -296,6 +296,9 @@
<menuitem id="context-paste"
data-l10n-id="text-action-paste"
command="cmd_paste"/>
<menuitem id="context-paste-no-formatting"
data-l10n-id="text-action-paste-no-formatting"
command="cmd_pasteNoFormatting"/>
<menuitem id="context-delete"
data-l10n-id="text-action-delete"
command="cmd_delete"/>

View File

@@ -934,6 +934,7 @@ class nsContextMenu {
this.showItem("context-cut", this.onTextInput);
this.showItem("context-copy", this.isContentSelected || this.onTextInput);
this.showItem("context-paste", this.onTextInput);
this.showItem("context-paste-no-formatting", this.isDesignMode);
this.showItem("context-delete", this.onTextInput);
this.showItem(
"context-selectall",

View File

@@ -18,6 +18,7 @@ https_first_disabled = true
skip-if =
os == 'win' && bits == 64 # Bug 1719856
os == 'linux' && socketprocess_networking
[browser_contextmenu_contenteditable.js]
[browser_contextmenu_inspect.js]
skip-if = os == 'linux' && socketprocess_networking
[browser_contextmenu_keyword.js]

View File

@@ -0,0 +1,117 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let contextMenu;
const example_base =
"http://example.com/browser/browser/base/content/test/contextMenu/";
const chrome_base =
"chrome://mochitests/content/browser/browser/base/content/test/contextMenu/";
/* import-globals-from contextmenu_common.js */
Services.scriptloader.loadSubScript(
chrome_base + "contextmenu_common.js",
this
);
async function openMenuAndPaste(browser, useFormatting) {
const kElementToUse = "test-contenteditable-spellcheck-false";
let oldText = await SpecialPowers.spawn(browser, [kElementToUse], elemID => {
return content.document.getElementById(elemID).textContent;
});
// Open context menu and paste
await test_contextmenu(
"#" + kElementToUse,
[
"context-undo",
null, // whether we can undo changes mid-test.
"context-redo",
false,
"---",
null,
"context-cut",
false,
"context-copy",
false,
"context-paste",
true,
"context-paste-no-formatting",
true,
"context-delete",
false,
"context-selectall",
true,
],
{
keepMenuOpen: true,
}
);
let popupHidden = BrowserTestUtils.waitForPopupEvent(contextMenu, "hidden");
let menuID = "context-paste" + (useFormatting ? "" : "-no-formatting");
contextMenu.activateItem(document.getElementById(menuID));
await popupHidden;
await SpecialPowers.spawn(
browser,
[kElementToUse, oldText, useFormatting],
(elemID, textToReset, expectStrong) => {
let node = content.document.getElementById(elemID);
Assert.stringContains(
node.textContent,
"Bold text",
"Text should have been pasted"
);
if (expectStrong) {
isnot(
node.querySelector("strong"),
null,
"Should be markup in the text."
);
} else {
is(
node.querySelector("strong"),
null,
"Should be no markup in the text."
);
}
node.textContent = textToReset;
}
);
}
add_task(async function test_contenteditable() {
// Put some HTML on the clipboard:
const xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(
Ci.nsITransferable
);
xferable.init(null);
xferable.addDataFlavor("text/html");
xferable.setTransferData(
"text/html",
PlacesUtils.toISupportsString("<strong>Bold text</strong>")
);
xferable.addDataFlavor("text/unicode");
xferable.setTransferData(
"text/unicode",
PlacesUtils.toISupportsString("Bold text")
);
Services.clipboard.setData(
xferable,
null,
Services.clipboard.kGlobalClipboard
);
let url = example_base + "subtst_contextmenu.html";
await BrowserTestUtils.withNewTab(
{
gBrowser,
url,
},
async function(browser) {
await openMenuAndPaste(browser, false);
await openMenuAndPaste(browser, true);
}
);
});

View File

@@ -15,11 +15,10 @@ function goUpdateGlobalEditMenuItems(force) {
return;
}
goUpdateCommand("cmd_undo");
goUpdateCommand("cmd_redo");
goUpdateUndoEditMenuItems();
goUpdateCommand("cmd_cut");
goUpdateCommand("cmd_copy");
goUpdateCommand("cmd_paste");
goUpdatePasteMenuItems();
goUpdateCommand("cmd_selectAll");
goUpdateCommand("cmd_delete");
goUpdateCommand("cmd_switchTextDirection");
@@ -34,6 +33,7 @@ function goUpdateUndoEditMenuItems() {
// update menu items that depend on clipboard contents
function goUpdatePasteMenuItems() {
goUpdateCommand("cmd_paste");
goUpdateCommand("cmd_pasteNoFormatting");
}
// Inject the commandset here instead of relying on preprocessor to share this across documents.
@@ -52,6 +52,7 @@ window.addEventListener(
<command id="cmd_cut" internal="true" />
<command id="cmd_copy" internal="true" />
<command id="cmd_paste" internal="true" />
<command id="cmd_pasteNoFormatting" internal="true" />
<command id="cmd_delete" />
<command id="cmd_selectAll" internal="true" />
<command id="cmd_switchTextDirection" />

View File

@@ -34,6 +34,10 @@ text-action-paste =
.label = Paste
.accesskey = P
text-action-paste-no-formatting =
.label = Paste Without Formatting
.accesskey = m
text-action-paste-shortcut =
.key = V