mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 844371 - Add Cut to the text field context menu. r=fryn r=mbrubeck
This commit is contained in:
parent
d7983ccc33
commit
67eca776d5
@ -34,24 +34,46 @@ var ContextCommands = {
|
||||
|
||||
// Text specific
|
||||
|
||||
cut: function cc_cut() {
|
||||
let target = ContextMenuUI.popupState.target;
|
||||
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (target.localName === "browser") {
|
||||
// content
|
||||
if (ContextMenuUI.popupState.string) {
|
||||
this.sendCommand("cut");
|
||||
|
||||
SelectionHelperUI.closeEditSessionAndClear();
|
||||
}
|
||||
} else {
|
||||
// chrome
|
||||
target.editor.cut();
|
||||
}
|
||||
|
||||
target.focus();
|
||||
},
|
||||
|
||||
copy: function cc_copy() {
|
||||
let target = ContextMenuUI.popupState.target;
|
||||
|
||||
if (!target)
|
||||
return;
|
||||
|
||||
if (target.localName == "browser") {
|
||||
// content
|
||||
if (ContextMenuUI.popupState.string != "undefined") {
|
||||
this.clipboard.copyString(ContextMenuUI.popupState.string,
|
||||
this.docRef);
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.textCopied"));
|
||||
if (ContextMenuUI.popupState.string) {
|
||||
this.sendCommand("copy");
|
||||
|
||||
SelectionHelperUI.closeEditSessionAndClear();
|
||||
}
|
||||
} else {
|
||||
// chrome
|
||||
target.editor.copy();
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.textCopied"));
|
||||
}
|
||||
|
||||
if (target)
|
||||
target.focus();
|
||||
target.focus();
|
||||
},
|
||||
|
||||
paste: function cc_paste() {
|
||||
@ -149,7 +171,6 @@ var ContextCommands = {
|
||||
copyLink: function cc_copyLink() {
|
||||
this.clipboard.copyString(ContextMenuUI.popupState.linkURL,
|
||||
this.docRef);
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
|
||||
},
|
||||
|
||||
bookmarkLink: function cc_bookmarkLink() {
|
||||
@ -162,8 +183,6 @@ var ContextCommands = {
|
||||
} catch (e) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.showToast(Strings.browser.GetStringFromName("alertLinkBookmarked"));
|
||||
},
|
||||
|
||||
// Image specific
|
||||
@ -180,7 +199,6 @@ var ContextCommands = {
|
||||
copyImageSrc: function cc_copyImageSrc() {
|
||||
this.clipboard.copyString(ContextMenuUI.popupState.mediaURL,
|
||||
this.docRef);
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
|
||||
},
|
||||
|
||||
openImageInNewTab: function cc_openImageInNewTab() {
|
||||
@ -196,7 +214,6 @@ var ContextCommands = {
|
||||
copyVideoSrc: function cc_copyVideoSrc() {
|
||||
this.clipboard.copyString(ContextMenuUI.popupState.mediaURL,
|
||||
this.docRef);
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.linkCopied"));
|
||||
},
|
||||
|
||||
openVideoInNewTab: function cc_openVideoInNewTab() {
|
||||
@ -269,12 +286,7 @@ var ContextCommands = {
|
||||
});
|
||||
},
|
||||
|
||||
showToast: function showToast(aString) {
|
||||
let toaster = Cc["@mozilla.org/toaster-alerts-service;1"].getService(Ci.nsIAlertsService);
|
||||
toaster.showAlertNotification(null, aString, "", false, "", null);
|
||||
},
|
||||
|
||||
sendCommand: function cc_playVideo(aCommand) {
|
||||
sendCommand: function sendCommand(aCommand) {
|
||||
// Send via message manager over to ContextMenuHandler
|
||||
let browser = ContextMenuUI.popupState.target;
|
||||
browser.messageManager.sendAsyncMessage("Browser:ContextCommand", { command: aCommand });
|
||||
|
@ -375,6 +375,7 @@
|
||||
|
||||
let json = { types: ["input-text"], string: "" };
|
||||
if (selectionStart != selectionEnd) {
|
||||
json.types.push("cut");
|
||||
json.types.push("copy");
|
||||
json.string = aTextbox.value.slice(selectionStart, selectionEnd);
|
||||
} else if (aTextbox.value) {
|
||||
|
@ -546,8 +546,12 @@
|
||||
<!-- ux spec: https://bug782810.bugzilla.mozilla.org/attachment.cgi?id=714804 -->
|
||||
|
||||
<!-- Text related -->
|
||||
<!-- for text inputs, this will copy selected text, or if no text is selected, copy all -->
|
||||
<richlistitem id="context-copy" type="copy,selectable" onclick="ContextCommands.copy();">
|
||||
<!-- for text inputs, this will cut selected text -->
|
||||
<richlistitem id="context-cut" type="cut" onclick="ContextCommands.cut();">
|
||||
<label value="&contextTextCut.label;"/>
|
||||
</richlistitem>
|
||||
<!-- for text inputs, this will copy selected text -->
|
||||
<richlistitem id="context-copy" type="copy" onclick="ContextCommands.copy();">
|
||||
<label value="&contextTextCopy.label;"/>
|
||||
</richlistitem>
|
||||
<!-- only displayed if there is text on the clipboard -->
|
||||
|
@ -8,6 +8,7 @@ dump("### ContextMenuHandler.js loaded\n");
|
||||
|
||||
var ContextMenuHandler = {
|
||||
_types: [],
|
||||
_previousState: null,
|
||||
|
||||
init: function ch_init() {
|
||||
// Events we catch from content during the bubbling phase
|
||||
@ -56,6 +57,18 @@ var ContextMenuHandler = {
|
||||
let command = aMessage.json.command;
|
||||
|
||||
switch (command) {
|
||||
case "cut":
|
||||
this._onCut();
|
||||
break;
|
||||
|
||||
case "copy":
|
||||
this._onCopy();
|
||||
break;
|
||||
|
||||
case "paste":
|
||||
this._onPaste();
|
||||
break;
|
||||
|
||||
case "play":
|
||||
case "pause":
|
||||
if (node instanceof Ci.nsIDOMHTMLMediaElement)
|
||||
@ -75,10 +88,6 @@ var ContextMenuHandler = {
|
||||
this._onSelectAll();
|
||||
break;
|
||||
|
||||
case "paste":
|
||||
this._onPaste();
|
||||
break;
|
||||
|
||||
case "copy-image-contents":
|
||||
this._onCopyImage();
|
||||
break;
|
||||
@ -88,7 +97,7 @@ var ContextMenuHandler = {
|
||||
/*
|
||||
* Handler for selection overlay context menu events.
|
||||
*/
|
||||
_onContextAtPoint: function _onContextCommand(aMessage) {
|
||||
_onContextAtPoint: function _onContextAtPoint(aMessage) {
|
||||
// we need to find popupNode as if the context menu were
|
||||
// invoked on underlying content.
|
||||
let { element, frameX, frameY } =
|
||||
@ -151,6 +160,35 @@ var ContextMenuHandler = {
|
||||
Util.copyImageToClipboard(this._target);
|
||||
},
|
||||
|
||||
_onCut: function _onCut() {
|
||||
if (this._isTextInput(this._target)) {
|
||||
let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement);
|
||||
if (edit) {
|
||||
edit.editor.cut();
|
||||
} else {
|
||||
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
|
||||
}
|
||||
}
|
||||
this.reset();
|
||||
},
|
||||
|
||||
_onCopy: function _onCopy() {
|
||||
if (this._isTextInput(this._target)) {
|
||||
let edit = this._target.QueryInterface(Ci.nsIDOMNSEditableElement);
|
||||
if (edit) {
|
||||
edit.editor.copy();
|
||||
} else {
|
||||
Util.dumpLn("error: target element does not support nsIDOMNSEditableElement");
|
||||
}
|
||||
} else {
|
||||
let selectionText = this._previousState.string;
|
||||
|
||||
Cc["@mozilla.org/widget/clipboardhelper;1"]
|
||||
.getService(Ci.nsIClipboardHelper).copyString(selectionText);
|
||||
}
|
||||
this.reset();
|
||||
},
|
||||
|
||||
/******************************************************
|
||||
* Utility routines
|
||||
*/
|
||||
@ -205,6 +243,9 @@ var ContextMenuHandler = {
|
||||
linkTitle: "",
|
||||
linkProtocol: null,
|
||||
mediaURL: "",
|
||||
contentType: "",
|
||||
contentDisposition: "",
|
||||
string: "",
|
||||
};
|
||||
|
||||
// Do checks for nodes that never have children.
|
||||
@ -266,6 +307,7 @@ var ContextMenuHandler = {
|
||||
// Don't include "copy" for password fields.
|
||||
if (!(elem instanceof Ci.nsIDOMHTMLInputElement) || elem.mozIsTextField(true)) {
|
||||
if (selectionStart != selectionEnd) {
|
||||
state.types.push("cut");
|
||||
state.types.push("copy");
|
||||
state.string = elem.value.slice(selectionStart, selectionEnd);
|
||||
}
|
||||
@ -334,6 +376,8 @@ var ContextMenuHandler = {
|
||||
if (this._types[i].handler(state, popupNode))
|
||||
state.types.push(this._types[i].name);
|
||||
|
||||
this._previousState = state;
|
||||
|
||||
sendAsyncMessage("Content:ContextMenu", state);
|
||||
},
|
||||
|
||||
|
@ -502,9 +502,6 @@ var SelectionHelperUI = {
|
||||
},
|
||||
|
||||
_onSelectionCopied: function _onSelectionCopied(json) {
|
||||
if (json.succeeded) {
|
||||
this.showToast(Strings.browser.GetStringFromName("selectionHelper.textCopied"));
|
||||
}
|
||||
this.closeEditSessionAndClear();
|
||||
},
|
||||
|
||||
@ -687,11 +684,4 @@ var SelectionHelperUI = {
|
||||
json.change = aMarker.tag;
|
||||
this._sendAsyncMessage("Browser:SelectionMove", json);
|
||||
},
|
||||
|
||||
showToast: function showToast(aString) {
|
||||
let toaster =
|
||||
Cc["@mozilla.org/toaster-alerts-service;1"]
|
||||
.getService(Ci.nsIAlertsService);
|
||||
toaster.showAlertNotification(null, aString, "", false, "", null);
|
||||
},
|
||||
};
|
||||
|
@ -43,6 +43,7 @@ gTests.push({
|
||||
yield addTab(chromeRoot + "browser_context_menu_tests_02.html");
|
||||
|
||||
purgeEventQueue();
|
||||
emptyClipboard();
|
||||
|
||||
let win = Browser.selectedTab.browser.contentWindow;
|
||||
|
||||
@ -68,10 +69,21 @@ gTests.push({
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
"context-search"]);
|
||||
|
||||
let menuItem = document.getElementById("context-copy");
|
||||
promise = waitForEvent(document, "popuphidden");
|
||||
ContextMenuUI.hide();
|
||||
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
|
||||
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
|
||||
// The wait is needed to give time to populate the clipboard.
|
||||
let string = "";
|
||||
yield waitForCondition(function () {
|
||||
string = SpecialPowers.getClipboardData("text/unicode");
|
||||
return string === span.textContent;
|
||||
});
|
||||
ok(string === span.textContent, "copied selected text from span");
|
||||
|
||||
win.getSelection().removeAllRanges();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
@ -136,21 +148,46 @@ gTests.push({
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
checkContextUIMenuItemVisibility(["context-select",
|
||||
"context-select-all"]);
|
||||
|
||||
// copy menu item should not exist when no text is selected
|
||||
let menuItem = document.getElementById("context-copy");
|
||||
ok(menuItem && menuItem.hidden, "menu item is not visible");
|
||||
|
||||
promise = waitForEvent(document, "popuphidden");
|
||||
ContextMenuUI.hide();
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// context in input with selection copied to clipboard
|
||||
|
||||
let input = win.document.getElementById("text3-input");
|
||||
input.value = "hello, I'm sorry but I must be going.";
|
||||
input.setSelectionRange(0, 5);
|
||||
promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(win, input, 20, 10);
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy",
|
||||
"context-select",
|
||||
"context-select-all"]);
|
||||
|
||||
// copy menu item should copy all text
|
||||
let menuItem = document.getElementById("context-copy");
|
||||
ok(menuItem, "menu item exists");
|
||||
ok(!menuItem.hidden, "menu item visible");
|
||||
|
||||
let popupPromise = waitForEvent(document, "popuphidden");
|
||||
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
|
||||
|
||||
yield popupPromise;
|
||||
ok(popupPromise && !(popupPromise instanceof Error), "promise error");
|
||||
|
||||
let string = SpecialPowers.getClipboardData("text/unicode");
|
||||
ok(string, "hello, I'm sorry but I must be going.", "copy all");
|
||||
ok(string === "hello", "copied selected text");
|
||||
|
||||
emptyClipboard();
|
||||
|
||||
@ -168,8 +205,8 @@ gTests.push({
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
"context-search"]);
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy"]);
|
||||
|
||||
promise = waitForEvent(document, "popuphidden");
|
||||
ContextMenuUI.hide();
|
||||
@ -191,8 +228,8 @@ gTests.push({
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
// selected text context:
|
||||
checkContextUIMenuItemVisibility(["context-copy",
|
||||
"context-search",
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy",
|
||||
"context-paste"]);
|
||||
|
||||
promise = waitForEvent(document, "popuphidden");
|
||||
@ -200,6 +237,41 @@ gTests.push({
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// context in input with selection cut to clipboard
|
||||
|
||||
emptyClipboard();
|
||||
|
||||
let input = win.document.getElementById("text3-input");
|
||||
input.value = "hello, I'm sorry but I must be going.";
|
||||
input.setSelectionRange(0, 5);
|
||||
promise = waitForEvent(document, "popupshown");
|
||||
sendContextMenuClickToElement(win, input, 20, 10);
|
||||
yield promise;
|
||||
ok(promise && !(promise instanceof Error), "promise error");
|
||||
|
||||
// should be visible
|
||||
ok(ContextMenuUI._menuPopup._visible, "is visible");
|
||||
|
||||
checkContextUIMenuItemVisibility(["context-cut",
|
||||
"context-copy",
|
||||
"context-select",
|
||||
"context-select-all"]);
|
||||
|
||||
let menuItem = document.getElementById("context-cut");
|
||||
let popupPromise = waitForEvent(document, "popuphidden");
|
||||
EventUtils.synthesizeMouse(menuItem, 10, 10, {}, win);
|
||||
|
||||
yield popupPromise;
|
||||
ok(popupPromise && !(popupPromise instanceof Error), "promise error");
|
||||
|
||||
let string = SpecialPowers.getClipboardData("text/unicode");
|
||||
let inputValue = input.value;
|
||||
ok(string === "hello", "cut selected text in clipboard");
|
||||
ok(inputValue === ", I'm sorry but I must be going.", "cut selected text from input value");
|
||||
|
||||
emptyClipboard();
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// context in empty input, data on clipboard (paste operation)
|
||||
|
||||
|
@ -51,6 +51,7 @@
|
||||
<!ENTITY consoleErrColumn.label "Column:">
|
||||
|
||||
<!-- TEXT CONTEXT MENU -->
|
||||
<!ENTITY contextTextCut.label "Cut">
|
||||
<!ENTITY contextTextCopy.label "Copy">
|
||||
<!ENTITY contextTextPaste.label "Paste">
|
||||
<!-- unique item that is only added to the url bar context menu -->
|
||||
|
@ -87,7 +87,3 @@ opensearch.search=Search: %S
|
||||
# %S is the name of the app, like "YouTube" or "Picassa"
|
||||
openinapp.specific=Open in %S App
|
||||
openinapp.general=Open in Another App
|
||||
|
||||
# Selection alerts
|
||||
selectionHelper.textCopied=Text copied to clipboard
|
||||
selectionHelper.linkCopied=Link copied to clipboard
|
||||
|
Loading…
Reference in New Issue
Block a user