From 609cdfc4461846bf88b5da6727c5561824d70c46 Mon Sep 17 00:00:00 2001 From: Brian Grinstead Date: Thu, 31 Jul 2014 08:44:00 -0400 Subject: [PATCH] Bug 1022083 - Project Editor: Add context menu in sourceeditor. r=harth --- .../chrome/content/projecteditor.xul | 8 +++ browser/devtools/projecteditor/lib/editors.js | 4 +- .../projecteditor/lib/projecteditor.js | 11 +++- .../devtools/projecteditor/test/browser.ini | 2 + .../browser_projecteditor_contextmenu_01.js | 27 ++++++++ .../browser_projecteditor_contextmenu_02.js | 62 +++++++++++++++++++ .../test/browser_projecteditor_menubar_02.js | 6 +- browser/devtools/sourceeditor/editor.js | 8 ++- 8 files changed, 118 insertions(+), 10 deletions(-) create mode 100644 browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js create mode 100644 browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_02.js diff --git a/browser/devtools/projecteditor/chrome/content/projecteditor.xul b/browser/devtools/projecteditor/chrome/content/projecteditor.xul index ba5efeaf7f3..56ced8d22e2 100644 --- a/browser/devtools/projecteditor/chrome/content/projecteditor.xul +++ b/browser/devtools/projecteditor/chrome/content/projecteditor.xul @@ -53,6 +53,14 @@ + + + + + + + + diff --git a/browser/devtools/projecteditor/lib/editors.js b/browser/devtools/projecteditor/lib/editors.js index 0732f549550..662fb45ab86 100644 --- a/browser/devtools/projecteditor/lib/editors.js +++ b/browser/devtools/projecteditor/lib/editors.js @@ -51,6 +51,7 @@ var ItchEditor = Class({ * ItchEditor.prototype.initialize.apply(this, arguments) */ initialize: function(host) { + this.host = host; this.doc = host.document; this.label = ""; this.elt = this.doc.createElement("vbox"); @@ -165,7 +166,8 @@ var TextEditor = Class({ lineNumbers: true, extraKeys: this.extraKeys, themeSwitching: false, - autocomplete: true + autocomplete: true, + contextMenu: this.host.textEditorContextMenuPopup }); // Trigger a few editor specific events on `this`. diff --git a/browser/devtools/projecteditor/lib/projecteditor.js b/browser/devtools/projecteditor/lib/projecteditor.js index 2c739d74e7e..92bda556aba 100644 --- a/browser/devtools/projecteditor/lib/projecteditor.js +++ b/browser/devtools/projecteditor/lib/projecteditor.js @@ -175,6 +175,12 @@ var ProjectEditor = Class({ _buildMenubar: function() { + this.contextMenuPopup = this.document.getElementById("context-menu-popup"); + this.contextMenuPopup.addEventListener("popupshowing", this._updateContextMenuItems); + + this.textEditorContextMenuPopup = this.document.getElementById("texteditor-context-popup"); + this.textEditorContextMenuPopup.addEventListener("popupshowing", this._updateMenuItems); + this.editMenu = this.document.getElementById("edit-menu"); this.fileMenu = this.document.getElementById("file-menu"); @@ -191,6 +197,7 @@ var ProjectEditor = Class({ body.appendChild(this.editorCommandset); body.appendChild(this.editorKeyset); body.appendChild(this.contextMenuPopup); + body.appendChild(this.textEditorContextMenuPopup); let index = this.menuindex || 0; this.menubar.insertBefore(this.editMenu, this.menubar.children[index]); @@ -232,9 +239,6 @@ var ProjectEditor = Class({ this.editorCommandset = this.document.getElementById("editMenuCommands"); this.editorKeyset = this.document.getElementById("editMenuKeys"); - this.contextMenuPopup = this.document.getElementById("context-menu-popup"); - this.contextMenuPopup.addEventListener("popupshowing", this._updateContextMenuItems); - this.projectEditorCommandset.addEventListener("command", (evt) => { evt.stopPropagation(); evt.preventDefault(); @@ -313,6 +317,7 @@ var ProjectEditor = Class({ this.editorCommandset.remove(); this.editorKeyset.remove(); this.contextMenuPopup.remove(); + this.textEditorContextMenuPopup.remove(); this.editMenu.remove(); this.fileMenu.remove(); diff --git a/browser/devtools/projecteditor/test/browser.ini b/browser/devtools/projecteditor/test/browser.ini index 925675d34bf..36ad8090c41 100644 --- a/browser/devtools/projecteditor/test/browser.ini +++ b/browser/devtools/projecteditor/test/browser.ini @@ -7,6 +7,8 @@ support-files = [browser_projecteditor_app_options.js] skip-if = buildapp == 'mulet' +[browser_projecteditor_contextmenu_01.js] +[browser_projecteditor_contextmenu_02.js] [browser_projecteditor_delete_file.js] skip-if = buildapp == 'mulet' [browser_projecteditor_editing_01.js] diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js new file mode 100644 index 00000000000..e95f0af2261 --- /dev/null +++ b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_01.js @@ -0,0 +1,27 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Test that context menus append to the correct document. + +let test = asyncTest(function*() { + let projecteditor = yield addProjectEditorTabForTempDirectory({ + menubar: false + }); + ok(projecteditor, "ProjectEditor has loaded"); + + let contextMenuPopup = projecteditor.document.querySelector("#context-menu-popup"); + let textEditorContextMenuPopup = projecteditor.document.querySelector("#texteditor-context-popup"); + ok (contextMenuPopup, "The menu has loaded in the projecteditor document"); + ok (textEditorContextMenuPopup, "The menu has loaded in the projecteditor document"); + + let projecteditor2 = yield addProjectEditorTabForTempDirectory(); + let contextMenuPopup = projecteditor2.document.getElementById("context-menu-popup"); + let textEditorContextMenuPopup = projecteditor2.document.getElementById("texteditor-context-popup"); + ok (!contextMenuPopup, "The menu has NOT loaded in the projecteditor document"); + ok (!textEditorContextMenuPopup, "The menu has NOT loaded in the projecteditor document"); + ok (content.document.querySelector("#context-menu-popup"), "The menu has loaded in the specified element"); + ok (content.document.querySelector("#texteditor-context-popup"), "The menu has loaded in the specified element"); +}); \ No newline at end of file diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_02.js b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_02.js new file mode 100644 index 00000000000..274fcebc3fd --- /dev/null +++ b/browser/devtools/projecteditor/test/browser_projecteditor_contextmenu_02.js @@ -0,0 +1,62 @@ +/* vim: set ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +loadHelperScript("helper_edits.js"); + +// Test context menu enabled / disabled state in editor + +let test = asyncTest(function*() { + let projecteditor = yield addProjectEditorTabForTempDirectory(); + ok (projecteditor, "ProjectEditor has loaded"); + + let {textEditorContextMenuPopup} = projecteditor; + + let cmdDelete = textEditorContextMenuPopup.querySelector("[command=cmd_delete]"); + let cmdSelectAll = textEditorContextMenuPopup.querySelector("[command=cmd_selectAll]"); + let cmdCut = textEditorContextMenuPopup.querySelector("[command=cmd_cut]"); + let cmdCopy = textEditorContextMenuPopup.querySelector("[command=cmd_copy]"); + let cmdPaste = textEditorContextMenuPopup.querySelector("[command=cmd_paste]"); + + info ("Opening resource"); + let resource = projecteditor.project.allResources()[2]; + yield selectFile(projecteditor, resource); + let editor = projecteditor.currentEditor; + editor.editor.focus(); + + info ("Opening context menu on resource"); + yield openContextMenuForEditor(editor, textEditorContextMenuPopup); + + is (cmdDelete.getAttribute("disabled"), "true", "cmdDelete is disabled"); + is (cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled"); + is (cmdCut.getAttribute("disabled"), "true", "cmdCut is disabled"); + is (cmdCopy.getAttribute("disabled"), "true", "cmdCopy is disabled"); + is (cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); + + info ("Setting a selection and repening context menu on resource"); + yield closeContextMenuForEditor(editor, textEditorContextMenuPopup); + editor.editor.setSelection({line: 0, ch: 0}, {line: 0, ch: 2}); + yield openContextMenuForEditor(editor, textEditorContextMenuPopup); + + is (cmdDelete.getAttribute("disabled"), "", "cmdDelete is enabled"); + is (cmdSelectAll.getAttribute("disabled"), "", "cmdSelectAll is enabled"); + is (cmdCut.getAttribute("disabled"), "", "cmdCut is enabled"); + is (cmdCopy.getAttribute("disabled"), "", "cmdCopy is enabled"); + is (cmdPaste.getAttribute("disabled"), "", "cmdPaste is enabled"); +}); + +function openContextMenuForEditor(editor, contextMenu) { + let editorDoc = editor.editor.container.contentDocument; + let shown = onPopupShow(contextMenu); + EventUtils.synthesizeMouse(editorDoc.body, 2, 2, + {type: "contextmenu", button: 2}, editorDoc.defaultView); + yield shown; +} +function closeContextMenuForEditor(editor, contextMenu) { + let editorDoc = editor.editor.container.contentDocument; + let hidden = onPopupHidden(contextMenu); + contextMenu.hidePopup(); + yield hidden; +} \ No newline at end of file diff --git a/browser/devtools/projecteditor/test/browser_projecteditor_menubar_02.js b/browser/devtools/projecteditor/test/browser_projecteditor_menubar_02.js index fe4fb569b34..373658be026 100644 --- a/browser/devtools/projecteditor/test/browser_projecteditor_menubar_02.js +++ b/browser/devtools/projecteditor/test/browser_projecteditor_menubar_02.js @@ -82,7 +82,7 @@ let test = asyncTest(function*() { let editor = projecteditor.currentEditor; editor.editor.focus(); - EventUtils.synthesizeKey("foo", { }, projecteditor.window); + EventUtils.synthesizeKey("f", { }, projecteditor.window); yield openAndCloseMenu(fileMenu); yield openAndCloseMenu(editMenu); @@ -99,10 +99,10 @@ let test = asyncTest(function*() { }); function openAndCloseMenu(menu) { - let shown = onPopupShow(menu) + let shown = onPopupShow(menu); EventUtils.synthesizeMouseAtCenter(menu, {}, menu.ownerDocument.defaultView); yield shown; - let hidden = onPopupHidden(menu) + let hidden = onPopupHidden(menu); EventUtils.synthesizeMouseAtCenter(menu, {}, menu.ownerDocument.defaultView); yield hidden; } diff --git a/browser/devtools/sourceeditor/editor.js b/browser/devtools/sourceeditor/editor.js index dc88d8bf5d6..ddf7f31a0f1 100644 --- a/browser/devtools/sourceeditor/editor.js +++ b/browser/devtools/sourceeditor/editor.js @@ -131,8 +131,8 @@ Editor.modes = { * properties go to CodeMirror's documentation (see below). * * Other than that, it accepts one additional and optional - * property contextMenu. This property should be an ID of - * an element we can use as a context menu. + * property contextMenu. This property should be an element, or + * an ID of an element that we can use as a context menu. * * This object is also an event emitter. * @@ -286,7 +286,9 @@ Editor.prototype = { cm.getWrapperElement().addEventListener("contextmenu", (ev) => { ev.preventDefault(); if (!this.config.contextMenu) return; - let popup = el.ownerDocument.getElementById(this.config.contextMenu); + let popup = this.config.contextMenu; + if (typeof popup == "string") + popup = el.ownerDocument.getElementById(this.config.contextMenu); popup.openPopupAtScreen(ev.screenX, ev.screenY, true); }, false);