Bug 1033855 - Do not show delete context menu item for project root. r=harth

This commit is contained in:
Brian Grinstead 2014-07-07 13:47:00 +02:00
Родитель c0cb00234a
Коммит e14da131f5
5 изменённых файлов: 101 добавлений и 70 удалений

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

@ -17,7 +17,7 @@ var DeletePlugin = Class({
this.host.addCommand(this, {
id: "cmd-delete"
});
this.host.createMenuItem({
this.contextMenuItem = this.host.createMenuItem({
parent: this.host.contextMenuPopup,
label: getLocalizedString("projecteditor.deleteLabel"),
command: "cmd-delete"
@ -34,6 +34,19 @@ var DeletePlugin = Class({
);
},
onContextMenuOpen: function(resource) {
// Do not allow deletion of the top level items in the tree. In the
// case of the Web IDE in particular this can leave the UI in a weird
// state. If we'd like to add ability to delete the project folder from
// the tree in the future, then the UI could be cleaned up by listening
// to the ProjectTree's "resource-removed" event.
if (!resource.parent) {
this.contextMenuItem.setAttribute("hidden", "true");
} else {
this.contextMenuItem.removeAttribute("hidden");
}
},
onCommand: function(cmd) {
if (cmd === "cmd-delete") {
let tree = this.host.projectTree;

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

@ -62,6 +62,7 @@ require("projecteditor/plugins/status-bar/plugin");
* - "onEditorCursorActivity": When there is cursor activity in a text editor
* - "onCommand": When a command happens
* - "onEditorDestroyed": When editor is destroyed
* - "onContextMenuOpen": When the context menu is opened on the project tree
*
* The events can be bound like so:
* projecteditor.on("onEditorCreated", (editor) => { });
@ -87,6 +88,7 @@ var ProjectEditor = Class({
this._onEditorActivated = this._onEditorActivated.bind(this);
this._onEditorDeactivated = this._onEditorDeactivated.bind(this);
this._updateMenuItems = this._updateMenuItems.bind(this);
this._updateContextMenuItems = this._updateContextMenuItems.bind(this);
this.destroy = this.destroy.bind(this);
this.menubar = options.menubar || null;
this.menuindex = options.menuindex || null;
@ -231,6 +233,7 @@ var ProjectEditor = Class({
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();
@ -269,6 +272,15 @@ var ProjectEditor = Class({
}
},
/**
* Enable / disable necessary context menu items by passing an event
* onto plugins.
*/
_updateContextMenuItems: function() {
let resource = this.projectTree.getSelectedResource();
this.pluginDispatch("onContextMenuOpen", resource);
},
/**
* Destroy all objects on the iframe unload event.
*/

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

@ -13,68 +13,73 @@ let test = asyncTest(function*() {
let root = [...projecteditor.project.allStores()][0].root;
is(root.path, TEMP_PATH, "The root store is set to the correct temp path.");
for (let child of root.children) {
yield deleteWithContextMenu(projecteditor.projectTree.getViewContainer(child));
yield deleteWithContextMenu(projecteditor, projecteditor.projectTree.getViewContainer(child));
}
function onPopupShow(contextMenu) {
let defer = promise.defer();
contextMenu.addEventListener("popupshown", function onpopupshown() {
contextMenu.removeEventListener("popupshown", onpopupshown);
defer.resolve();
});
return defer.promise;
}
yield testDeleteOnRoot(projecteditor, projecteditor.projectTree.getViewContainer(root));
});
function openContextMenuOn(node) {
EventUtils.synthesizeMouseAtCenter(
node,
{button: 2, type: "contextmenu"},
node.ownerDocument.defaultView
);
}
function deleteWithContextMenu(container) {
let defer = promise.defer();
function openContextMenuOn(node) {
EventUtils.synthesizeMouseAtCenter(
node,
{button: 2, type: "contextmenu"},
node.ownerDocument.defaultView
);
}
let resource = container.resource;
let popup = projecteditor.contextMenuPopup;
info ("Going to attempt deletion for: " + resource.path)
function testDeleteOnRoot(projecteditor, container) {
let popup = projecteditor.contextMenuPopup;
let oncePopupShown = onPopupShow(popup);
openContextMenuOn(container.label);
yield oncePopupShown;
onPopupShow(popup).then(function () {
let deleteCommand = popup.querySelector("[command=cmd-delete]");
ok (deleteCommand, "Delete command exists in popup");
is (deleteCommand.getAttribute("hidden"), "", "Delete command is visible");
is (deleteCommand.getAttribute("disabled"), "", "Delete command is enabled");
let deleteCommand = popup.querySelector("[command=cmd-delete]");
ok (deleteCommand, "Delete command exists in popup");
is (deleteCommand.getAttribute("hidden"), "true", "Delete command is hidden");
}
function onConfirmShown(aSubject) {
info("confirm dialog observed as expected");
Services.obs.removeObserver(onConfirmShown, "common-dialog-loaded");
Services.obs.removeObserver(onConfirmShown, "tabmodal-dialog-loaded");
function deleteWithContextMenu(projecteditor, container) {
let defer = promise.defer();
projecteditor.project.on("refresh-complete", function refreshComplete() {
projecteditor.project.off("refresh-complete", refreshComplete);
OS.File.stat(resource.path).then(() => {
ok (false, "The file was not deleted");
defer.resolve();
}, (ex) => {
ok (ex instanceof OS.File.Error && ex.becauseNoSuchFile, "OS.File.stat promise was rejected because the file is gone");
defer.resolve();
});
let popup = projecteditor.contextMenuPopup;
let resource = container.resource;
info ("Going to attempt deletion for: " + resource.path);
onPopupShow(popup).then(function () {
let deleteCommand = popup.querySelector("[command=cmd-delete]");
ok (deleteCommand, "Delete command exists in popup");
is (deleteCommand.getAttribute("hidden"), "", "Delete command is visible");
is (deleteCommand.getAttribute("disabled"), "", "Delete command is enabled");
function onConfirmShown(aSubject) {
info("confirm dialog observed as expected");
Services.obs.removeObserver(onConfirmShown, "common-dialog-loaded");
Services.obs.removeObserver(onConfirmShown, "tabmodal-dialog-loaded");
projecteditor.project.on("refresh-complete", function refreshComplete() {
projecteditor.project.off("refresh-complete", refreshComplete);
OS.File.stat(resource.path).then(() => {
ok (false, "The file was not deleted");
defer.resolve();
}, (ex) => {
ok (ex instanceof OS.File.Error && ex.becauseNoSuchFile, "OS.File.stat promise was rejected because the file is gone");
defer.resolve();
});
});
// Click the 'OK' button
aSubject.Dialog.ui.button0.click();
}
// Click the 'OK' button
aSubject.Dialog.ui.button0.click();
}
Services.obs.addObserver(onConfirmShown, "common-dialog-loaded", false);
Services.obs.addObserver(onConfirmShown, "tabmodal-dialog-loaded", false);
Services.obs.addObserver(onConfirmShown, "common-dialog-loaded", false);
Services.obs.addObserver(onConfirmShown, "tabmodal-dialog-loaded", false);
deleteCommand.click();
popup.hidePopup();
});
deleteCommand.click();
popup.hidePopup();
});
openContextMenuOn(container.label);
openContextMenuOn(container.label);
return defer.promise;
}
});
return defer.promise;
}

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

@ -106,21 +106,3 @@ function openAndCloseMenu(menu) {
EventUtils.synthesizeMouseAtCenter(menu, {}, menu.ownerDocument.defaultView);
yield hidden;
}
function onPopupShow(menu) {
let defer = promise.defer();
menu.addEventListener("popupshown", function onpopupshown() {
menu.removeEventListener("popupshown", onpopupshown);
defer.resolve();
});
return defer.promise;
}
function onPopupHidden(menu) {
let defer = promise.defer();
menu.addEventListener("popuphidden", function onpopupshown() {
menu.removeEventListener("popuphidden", onpopupshown);
defer.resolve();
});
return defer.promise;
}

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

@ -303,3 +303,22 @@ function onceEditorSave(projecteditor) {
});
return def.promise;
}
function onPopupShow(menu) {
let defer = promise.defer();
menu.addEventListener("popupshown", function onpopupshown() {
menu.removeEventListener("popupshown", onpopupshown);
defer.resolve();
});
return defer.promise;
}
function onPopupHidden(menu) {
let defer = promise.defer();
menu.addEventListener("popuphidden", function onpopuphidden() {
menu.removeEventListener("popuphidden", onpopuphidden);
defer.resolve();
});
return defer.promise;
}