Skip to content
This repository has been archived by the owner on Nov 7, 2018. It is now read-only.

Commit

Permalink
Bug 1476097 - Use the Menu API's edit menu for all context menu textb…
Browse files Browse the repository at this point in the history
…oxes within the toolbox; r=bgrins,flod

Differential Revision: https://phabricator.services.mozilla.com/D6494
  • Loading branch information
janodvarko committed Nov 5, 2018
1 parent 2ac52f2 commit 44aa61a
Show file tree
Hide file tree
Showing 15 changed files with 301 additions and 237 deletions.
1 change: 1 addition & 0 deletions devtools/client/framework/moz.build
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ DevToolsModules(
'source-map-url-service.js',
'target-from-url.js',
'target.js',
'toolbox-context-menu.js',
'toolbox-highlighter-utils.js',
'toolbox-host-manager.js',
'toolbox-hosts.js',
Expand Down
6 changes: 3 additions & 3 deletions devtools/client/framework/test/browser_menu_api.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ async function testMenuPopup(toolbox) {
disabled: true,
}),
new MenuItem({
l10nID: "foo",
l10nID: "editmenu-undo",
}),
];

Expand Down Expand Up @@ -132,7 +132,7 @@ async function testSubmenu(toolbox) {
},
}));
menu.append(new MenuItem({
l10nID: "submenu-parent",
l10nID: "editmenu-copy",
submenu: submenu,
}));
menu.append(new MenuItem({
Expand All @@ -152,7 +152,7 @@ async function testSubmenu(toolbox) {
is(menus.length, 2, "Correct number of menus");
ok(!menus[0].hasAttribute("label"), "No label: should be set by localization");
ok(!menus[0].hasAttribute("disabled"), "Correct disabled state");
is(menus[0].getAttribute("data-l10n-id"), "submenu-parent", "Correct localization attribute");
is(menus[0].getAttribute("data-l10n-id"), "editmenu-copy", "Correct localization attribute");

is(menus[1].getAttribute("accesskey"), "A", "Correct accesskey");
ok(menus[1].hasAttribute("disabled"), "Correct disabled state");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ registerCleanupFunction(() => {
add_task(async function checkMenuEntryStates() {
info("Checking the state of edit menuitems with an empty clipboard");
const toolbox = await openNewTabAndToolbox(URL, "inspector");
const textboxContextMenu = toolbox.textBoxContextMenuPopup;

emptyClipboard();

Expand All @@ -29,21 +28,21 @@ add_task(async function checkMenuEntryStates() {
inspector.searchBox.focus();
await onFocus;

ok(textboxContextMenu, "The textbox context menu is loaded in the toolbox");

const cmdUndo = textboxContextMenu.querySelector("[command=cmd_undo]");
const cmdDelete = textboxContextMenu.querySelector("[command=cmd_delete]");
const cmdSelectAll = textboxContextMenu.querySelector("[command=cmd_selectAll]");
const cmdCut = textboxContextMenu.querySelector("[command=cmd_cut]");
const cmdCopy = textboxContextMenu.querySelector("[command=cmd_copy]");
const cmdPaste = textboxContextMenu.querySelector("[command=cmd_paste]");

info("Opening context menu");

const onContextMenuPopup = once(textboxContextMenu, "popupshowing");
textboxContextMenu.openPopupAtScreen(0, 0, true);
const onContextMenuPopup = toolbox.once("menu-open");
synthesizeContextMenuEvent(inspector.searchBox);
await onContextMenuPopup;

const textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(textboxContextMenu, "The textbox context menu is loaded in the toolbox");

const cmdUndo = textboxContextMenu.querySelector("#editmenu-undo");
const cmdDelete = textboxContextMenu.querySelector("#editmenu-delete");
const cmdSelectAll = textboxContextMenu.querySelector("#editmenu-selectAll");
const cmdCut = textboxContextMenu.querySelector("#editmenu-cut");
const cmdCopy = textboxContextMenu.querySelector("#editmenu-copy");
const cmdPaste = textboxContextMenu.querySelector("#editmenu-paste");

is(cmdUndo.getAttribute("disabled"), "true", "cmdUndo is disabled");
is(cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled");
is(cmdSelectAll.getAttribute("disabled"), "true", "cmdSelectAll is disabled");
Expand All @@ -53,6 +52,10 @@ add_task(async function checkMenuEntryStates() {
is(cmdCut.getAttribute("disabled"), "", "cmdCut is enabled");
is(cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled");
is(cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled");

const onContextMenuHidden = toolbox.once("menu-close");
EventUtils.sendKey("ESCAPE", toolbox.win);
await onContextMenuHidden;
});

add_task(async function automaticallyBindTexbox() {
Expand Down Expand Up @@ -80,35 +83,39 @@ add_task(async function automaticallyBindTexbox() {
await checkNonTextInput(doc.querySelector("input[type=radio]"), toolbox);
});

async function checkNonTextInput(input, {textBoxContextMenuPopup}) {
is(textBoxContextMenuPopup.state, "closed", "The menu is closed");
async function checkNonTextInput(input, toolbox) {
let textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(!textboxContextMenu, "The menu is closed");

info("Simulating context click on the non text input and expecting no menu to open");
const eventBubbledUp = new Promise(resolve => {
input.ownerDocument.addEventListener("contextmenu", resolve, { once: true });
});
EventUtils.synthesizeMouse(input, 2, 2, {type: "contextmenu", button: 2},
input.ownerDocument.defaultView);
synthesizeContextMenuEvent(input);
info("Waiting for event");
await eventBubbledUp;
is(textBoxContextMenuPopup.state, "closed", "The menu is still closed");

textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(!textboxContextMenu, "The menu is still closed");
}

async function checkTextBox(textBox, {textBoxContextMenuPopup}) {
is(textBoxContextMenuPopup.state, "closed", "The menu is closed");
async function checkTextBox(textBox, toolbox) {
let textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(!textboxContextMenu, "The menu is closed");

info("Simulating context click on the textbox and expecting the menu to open");
const onContextMenu = once(textBoxContextMenuPopup, "popupshown");
EventUtils.synthesizeMouse(textBox, 2, 2, {type: "contextmenu", button: 2},
textBox.ownerDocument.defaultView);
const onContextMenu = toolbox.once("menu-open");
synthesizeContextMenuEvent(textBox);
await onContextMenu;

is(textBoxContextMenuPopup.state, "open", "The menu is now visible");
textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(textboxContextMenu, "The menu is now visible");

info("Closing the menu");
const onContextMenuHidden = once(textBoxContextMenuPopup, "popuphidden");
textBoxContextMenuPopup.hidePopup();
const onContextMenuHidden = toolbox.once("menu-close");
EventUtils.sendKey("ESCAPE", toolbox.win);
await onContextMenuHidden;

is(textBoxContextMenuPopup.state, "closed", "The menu is closed again");
textboxContextMenu = toolbox.doc.getElementById("toolbox-menu");
ok(!textboxContextMenu, "The menu is closed again");
}
103 changes: 103 additions & 0 deletions devtools/client/framework/toolbox-context-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const Menu = require("devtools/client/framework/menu");
const MenuItem = require("devtools/client/framework/menu-item");

var stringsLoaded = false;

/**
* Lazily load strings for the edit menu.
*/
function loadEditMenuStrings(win) {
if (stringsLoaded) {
return;
}

if (win.MozXULElement) {
stringsLoaded = true;
win.MozXULElement.insertFTLIfNeeded("toolkit/main-window/editmenu.ftl");
}
}

/**
* Return an 'edit' menu for a input field. This integrates directly
* with docshell commands to provide the right enabled state and editor
* functionality.
*
* You'll need to call menu.popup() yourself, this just returns the Menu instance.
*
* @param {Window} win parent window reference
* @param {String} id menu ID
*
* @returns {Menu}
*/
function createEditContextMenu(win, id) {
// Localized strings for the menu are loaded lazily.
loadEditMenuStrings(win);

const docshell = win.docShell;
const menu = new Menu({id});
menu.append(new MenuItem({
id: "editmenu-undo",
l10nID: "editmenu-undo",
disabled: !docshell.isCommandEnabled("cmd_undo"),
click: () => {
docshell.doCommand("cmd_undo");
},
}));
menu.append(new MenuItem({
type: "separator",
}));
menu.append(new MenuItem({
id: "editmenu-cut",
l10nID: "editmenu-cut",
disabled: !docshell.isCommandEnabled("cmd_cut"),
click: () => {
docshell.doCommand("cmd_cut");
},
}));
menu.append(new MenuItem({
id: "editmenu-copy",
l10nID: "editmenu-copy",
disabled: !docshell.isCommandEnabled("cmd_copy"),
click: () => {
docshell.doCommand("cmd_copy");
},
}));
menu.append(new MenuItem({
id: "editmenu-paste",
l10nID: "editmenu-paste",
disabled: !docshell.isCommandEnabled("cmd_paste"),
click: () => {
docshell.doCommand("cmd_paste");
},
}));
menu.append(new MenuItem({
id: "editmenu-delete",
l10nID: "editmenu-delete",
disabled: !docshell.isCommandEnabled("cmd_delete"),
click: () => {
docshell.doCommand("cmd_delete");
},
}));
menu.append(new MenuItem({
type: "separator",
}));
menu.append(new MenuItem({
id: "editmenu-selectAll",
l10nID: "editmenu-select-all",
disabled: !docshell.isCommandEnabled("cmd_selectAll"),
click: () => {
docshell.doCommand("cmd_selectAll");
},
}));
return menu;
}

module.exports.createEditContextMenu = createEditContextMenu;
19 changes: 9 additions & 10 deletions devtools/client/framework/toolbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ loader.lazyRequireGetter(this, "NetMonitorAPI",
"devtools/client/netmonitor/src/api", true);
loader.lazyRequireGetter(this, "sortPanelDefinitions",
"devtools/client/framework/toolbox-tabs-order-manager", true);
loader.lazyRequireGetter(this, "createEditContextMenu",
"devtools/client/framework/toolbox-context-menu", true);

loader.lazyGetter(this, "domNodeConstants", () => {
return require("devtools/shared/dom-node-constants");
Expand Down Expand Up @@ -468,10 +470,6 @@ Toolbox.prototype = {
Services.prefs.addObserver("devtools.serviceWorkers.testing.enabled",
this._applyServiceWorkersTestingSettings);

this.textBoxContextMenuPopup =
this.doc.getElementById("toolbox-textbox-context-popup");
this.textBoxContextMenuPopup.addEventListener("popupshowing",
this._updateTextBoxMenuItems, true);
this.doc.addEventListener("contextmenu", (e) => {
if (e.originalTarget.closest("input[type=text]") ||
e.originalTarget.closest("input[type=search]") ||
Expand Down Expand Up @@ -2855,11 +2853,6 @@ Toolbox.prototype = {
this._saveSplitConsoleHeight);
this.webconsolePanel = null;
}
if (this.textBoxContextMenuPopup) {
this.textBoxContextMenuPopup.removeEventListener("popupshowing",
this._updateTextBoxMenuItems, true);
this.textBoxContextMenuPopup = null;
}
if (this._componentMount) {
this._componentMount.removeEventListener("keypress", this._onToolbarArrowKeypress);
this.ReactDOM.unmountComponentAtNode(this._componentMount);
Expand Down Expand Up @@ -3023,7 +3016,13 @@ Toolbox.prototype = {
* @param {Number} y
*/
openTextBoxContextMenu: function(x, y) {
this.textBoxContextMenuPopup.openPopupAtScreen(x, y, true);
const menu = createEditContextMenu(this.win, "toolbox-menu");

// Fire event for tests
menu.once("open", () => this.emit("menu-open"));
menu.once("close", () => this.emit("menu-close"));

menu.popup(x, y, { doc: this.doc });
},

/**
Expand Down
27 changes: 2 additions & 25 deletions devtools/client/framework/toolbox.xul
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
<!DOCTYPE window [
<!ENTITY % toolboxDTD SYSTEM "chrome://devtools/locale/toolbox.dtd" >
%toolboxDTD;
<!ENTITY % editMenuStrings SYSTEM "chrome://global/locale/editMenuOverlay.dtd">
%editMenuStrings;
<!ENTITY % globalKeysDTD SYSTEM "chrome://global/locale/globalKeys.dtd">
%globalKeysDTD;
]>
Expand All @@ -23,32 +21,11 @@
<script type="application/javascript"
src="chrome://global/content/viewSourceUtils.js"/>

<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="application/javascript"
src="chrome://global/content/globalOverlay.js"/>
<script type="application/javascript"
src="chrome://devtools/content/framework/toolbox-init.js"/>

#include ../../../toolkit/content/editMenuCommands.inc.xul
#include ../../../toolkit/content/editMenuKeys.inc.xul

<popupset>
<menupopup id="toolbox-textbox-context-popup">
<menuitem id="cMenu_undo" label="&undoCmd.label;"
accesskey="&undoCmd.accesskey;" command="cmd_undo"/>
<menuseparator/>
<menuitem id="cMenu_cut" label="&cutCmd.label;"
accesskey="&cutCmd.accesskey;" command="cmd_cut"/>
<menuitem id="cMenu_copy" label="&copyCmd.label;"
accesskey="&copyCmd.accesskey;" command="cmd_copy"/>
<menuitem id="cMenu_paste" label="&pasteCmd.label;"
accesskey="&pasteCmd.accesskey;" command="cmd_paste"/>
<menuitem id="cMenu_delete" label="&deleteCmd.label;"
accesskey="&deleteCmd.accesskey;" command="cmd_delete"/>
<menuseparator/>
<menuitem id="cMenu_selectAll" label="&selectAllCmd.label;"
accesskey="&selectAllCmd.accesskey;" command="cmd_selectAll"/>
</menupopup>
</popupset>

<vbox id="toolbox-container" flex="1">
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-notificationbox"/>
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-toolbar-mount"
Expand Down
Loading

0 comments on commit 44aa61a

Please sign in to comment.