зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1021827 - Show menu items for project editor inside of App Manager;r=paul
This commit is contained in:
Родитель
bcb978a289
Коммит
6f7d010a58
|
@ -10,7 +10,7 @@ browser.jar:
|
|||
content/browser/devtools/projecteditor.xul (projecteditor/chrome/content/projecteditor.xul)
|
||||
content/browser/devtools/readdir.js (projecteditor/lib/helpers/readdir.js)
|
||||
content/browser/devtools/projecteditor-loader.xul (projecteditor/chrome/content/projecteditor-loader.xul)
|
||||
content/browser/devtools/projecteditor-test.html (projecteditor/chrome/content/projecteditor-test.html)
|
||||
content/browser/devtools/projecteditor-test.xul (projecteditor/chrome/content/projecteditor-test.xul)
|
||||
content/browser/devtools/projecteditor-loader.js (projecteditor/chrome/content/projecteditor-loader.js)
|
||||
content/browser/devtools/netmonitor.xul (netmonitor/netmonitor.xul)
|
||||
content/browser/devtools/netmonitor.css (netmonitor/netmonitor.css)
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<meta charset='utf-8' />
|
||||
</head>
|
||||
<body>
|
||||
<style type="text/css">
|
||||
html { height: 100%; }
|
||||
body {display: flex; padding: 0; margin: 0; min-height: 100%; }
|
||||
iframe {flex: 1; border: 0;}
|
||||
</style>
|
||||
<iframe id='projecteditor-iframe'></iframe>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- 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/. -->
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:html="http://www.w3.org/1999/xhtml">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<commandset id="editMenuCommands"/>
|
||||
</commandset>
|
||||
<menubar></menubar>
|
||||
<iframe id='projecteditor-iframe' flex="1"></iframe>
|
||||
</window>
|
|
@ -46,18 +46,12 @@
|
|||
<menuitem id="menu_cut"/>
|
||||
<menuitem id="menu_copy"/>
|
||||
<menuitem id="menu_paste"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_selectAll"/>
|
||||
<menuseparator/>
|
||||
<menuitem id="menu_find"/>
|
||||
<menuitem id="menu_findAgain"/>
|
||||
</menupopup>
|
||||
</menu>
|
||||
</menubar>
|
||||
|
||||
|
||||
<popupset>
|
||||
<menupopup id="directory-menu-popup">
|
||||
<menupopup id="context-menu-popup">
|
||||
</menupopup>
|
||||
</popupset>
|
||||
|
||||
|
|
|
@ -26,6 +26,12 @@ var ItchEditor = Class({
|
|||
*/
|
||||
hidesToolbar: false,
|
||||
|
||||
/**
|
||||
* A boolean specifying whether the editor can be edited / saved.
|
||||
* For instance, a 'save' doesn't make sense on an image.
|
||||
*/
|
||||
isEditable: false,
|
||||
|
||||
toString: function() {
|
||||
return this.label || "";
|
||||
},
|
||||
|
@ -35,17 +41,19 @@ var ItchEditor = Class({
|
|||
},
|
||||
|
||||
/**
|
||||
* Initialize the editor with a single document. This should be called
|
||||
* Initialize the editor with a single host. This should be called
|
||||
* by objects extending this object with:
|
||||
* ItchEditor.prototype.initialize.apply(this, arguments)
|
||||
*/
|
||||
initialize: function(document) {
|
||||
this.doc = document;
|
||||
initialize: function(host) {
|
||||
this.doc = host.document;
|
||||
this.label = "";
|
||||
this.elt = this.doc.createElement("vbox");
|
||||
this.elt.setAttribute("flex", "1");
|
||||
this.elt.editor = this;
|
||||
this.toolbar = this.doc.querySelector("#projecteditor-toolbar");
|
||||
this.projectEditorKeyset = host.projectEditorKeyset;
|
||||
this.projectEditorCommandset = host.projectEditorCommandset;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -103,6 +111,8 @@ exports.ItchEditor = ItchEditor;
|
|||
var TextEditor = Class({
|
||||
extends: ItchEditor,
|
||||
|
||||
isEditable: true,
|
||||
|
||||
/**
|
||||
* Extra keyboard shortcuts to use with the editor. Shortcuts defined
|
||||
* within projecteditor should be triggered when they happen in the editor, and
|
||||
|
@ -114,7 +124,7 @@ var TextEditor = Class({
|
|||
|
||||
// Copy all of the registered keys into extraKeys object, to notify CodeMirror
|
||||
// that it should be ignoring these keys
|
||||
[...this.doc.querySelectorAll("#projecteditor-keyset key")].forEach((key) => {
|
||||
[...this.projectEditorKeyset.querySelectorAll("key")].forEach((key) => {
|
||||
let keyUpper = key.getAttribute("key").toUpperCase();
|
||||
let toolModifiers = key.getAttribute("modifiers");
|
||||
let modifiers = {
|
||||
|
@ -124,9 +134,10 @@ var TextEditor = Class({
|
|||
|
||||
// On the key press, we will dispatch the event within projecteditor.
|
||||
extraKeys[Editor.accel(keyUpper, modifiers)] = () => {
|
||||
let event = this.doc.createEvent('Event');
|
||||
let doc = this.projectEditorCommandset.ownerDocument;
|
||||
let event = doc.createEvent('Event');
|
||||
event.initEvent('command', true, true);
|
||||
let command = this.doc.querySelector("#" + key.getAttribute("command"));
|
||||
let command = this.projectEditorCommandset.querySelector("#" + key.getAttribute("command"));
|
||||
command.dispatchEvent(event);
|
||||
};
|
||||
});
|
||||
|
@ -227,22 +238,22 @@ var TextEditor = Class({
|
|||
/**
|
||||
* Wrapper for TextEditor using JavaScript syntax highlighting.
|
||||
*/
|
||||
function JSEditor(document) {
|
||||
return TextEditor(document, Editor.modes.js);
|
||||
function JSEditor(host) {
|
||||
return TextEditor(host, Editor.modes.js);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for TextEditor using CSS syntax highlighting.
|
||||
*/
|
||||
function CSSEditor(document) {
|
||||
return TextEditor(document, Editor.modes.css);
|
||||
function CSSEditor(host) {
|
||||
return TextEditor(host, Editor.modes.css);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for TextEditor using HTML syntax highlighting.
|
||||
*/
|
||||
function HTMLEditor(document) {
|
||||
return TextEditor(document, Editor.modes.html);
|
||||
function HTMLEditor(host) {
|
||||
return TextEditor(host, Editor.modes.html);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,7 @@ var AppProjectEditor = Class({
|
|||
|
||||
hidesToolbar: true,
|
||||
|
||||
initialize: function(document, host) {
|
||||
initialize: function(host) {
|
||||
ItchEditor.prototype.initialize.apply(this, arguments);
|
||||
this.appended = promise.resolve();
|
||||
this.host = host;
|
||||
|
|
|
@ -14,11 +14,11 @@ var DeletePlugin = Class({
|
|||
shouldConfirm: true,
|
||||
|
||||
init: function(host) {
|
||||
this.host.addCommand({
|
||||
this.host.addCommand(this, {
|
||||
id: "cmd-delete"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: "#directory-menu-popup",
|
||||
parent: this.host.contextMenuPopup,
|
||||
label: getLocalizedString("projecteditor.deleteLabel"),
|
||||
command: "cmd-delete"
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@ const { ItchEditor } = require("projecteditor/editors");
|
|||
var ImageEditor = Class({
|
||||
extends: ItchEditor,
|
||||
|
||||
initialize: function(document) {
|
||||
initialize: function() {
|
||||
ItchEditor.prototype.initialize.apply(this, arguments);
|
||||
this.label = "image";
|
||||
this.appended = promise.resolve();
|
||||
|
|
|
@ -12,24 +12,23 @@ const { getLocalizedString } = require("projecteditor/helpers/l10n");
|
|||
var NewFile = Class({
|
||||
extends: Plugin,
|
||||
|
||||
init: function(host) {
|
||||
this.host.createMenuItem({
|
||||
parent: "#file-menu-popup",
|
||||
label: getLocalizedString("projecteditor.newLabel"),
|
||||
command: "cmd-new",
|
||||
key: "key-new"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: "#directory-menu-popup",
|
||||
label: getLocalizedString("projecteditor.newLabel"),
|
||||
command: "cmd-new"
|
||||
});
|
||||
|
||||
this.command = this.host.addCommand({
|
||||
init: function() {
|
||||
this.command = this.host.addCommand(this, {
|
||||
id: "cmd-new",
|
||||
key: getLocalizedString("projecteditor.new.commandkey"),
|
||||
modifiers: "accel"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: this.host.fileMenuPopup,
|
||||
label: getLocalizedString("projecteditor.newLabel"),
|
||||
command: "cmd-new",
|
||||
key: "key_cmd-new"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: this.host.contextMenuPopup,
|
||||
label: getLocalizedString("projecteditor.newLabel"),
|
||||
command: "cmd-new"
|
||||
});
|
||||
},
|
||||
|
||||
onCommand: function(cmd) {
|
||||
|
|
|
@ -15,29 +15,33 @@ var SavePlugin = Class({
|
|||
|
||||
init: function(host) {
|
||||
|
||||
this.host.addCommand({
|
||||
id: "cmd-saveas",
|
||||
key: getLocalizedString("projecteditor.save.commandkey"),
|
||||
modifiers: "accel shift"
|
||||
});
|
||||
this.host.addCommand({
|
||||
this.host.addCommand(this, {
|
||||
id: "cmd-save",
|
||||
key: getLocalizedString("projecteditor.save.commandkey"),
|
||||
modifiers: "accel"
|
||||
});
|
||||
this.host.addCommand(this, {
|
||||
id: "cmd-saveas",
|
||||
key: getLocalizedString("projecteditor.save.commandkey"),
|
||||
modifiers: "accel shift"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: this.host.fileMenuPopup,
|
||||
label: getLocalizedString("projecteditor.saveLabel"),
|
||||
command: "cmd-save",
|
||||
key: "key_cmd-save"
|
||||
});
|
||||
this.host.createMenuItem({
|
||||
parent: this.host.fileMenuPopup,
|
||||
label: getLocalizedString("projecteditor.saveAsLabel"),
|
||||
command: "cmd-saveas",
|
||||
key: "key_cmd-saveas"
|
||||
});
|
||||
},
|
||||
|
||||
// Wait until we can add things into the app manager menu
|
||||
// this.host.createMenuItem({
|
||||
// parent: "#file-menu-popup",
|
||||
// label: "Save",
|
||||
// command: "cmd-save",
|
||||
// key: "key-save"
|
||||
// });
|
||||
// this.host.createMenuItem({
|
||||
// parent: "#file-menu-popup",
|
||||
// label: "Save As",
|
||||
// command: "cmd-saveas",
|
||||
// });
|
||||
isCommandEnabled: function(cmd) {
|
||||
let currentEditor = this.host.currentEditor;
|
||||
return currentEditor.isEditable;
|
||||
},
|
||||
|
||||
onCommand: function(cmd) {
|
||||
|
|
|
@ -76,15 +76,24 @@ var ProjectEditor = Class({
|
|||
* The iframe to inject the DOM into. If this is not
|
||||
* specified, then this.load(frame) will need to be called
|
||||
* before accessing ProjectEditor.
|
||||
* @param Object options
|
||||
* - menubar: a <menubar> element to inject menus into
|
||||
* - menuindex: Integer child index to insert menus
|
||||
*/
|
||||
initialize: function(iframe) {
|
||||
initialize: function(iframe, options = {}) {
|
||||
this._onTreeSelected = this._onTreeSelected.bind(this);
|
||||
this._onTreeResourceRemoved = this._onTreeResourceRemoved.bind(this);
|
||||
this._onEditorCreated = this._onEditorCreated.bind(this);
|
||||
this._onEditorActivated = this._onEditorActivated.bind(this);
|
||||
this._onEditorDeactivated = this._onEditorDeactivated.bind(this);
|
||||
this._updateEditorMenuItems = this._updateEditorMenuItems.bind(this);
|
||||
|
||||
this._updateMenuItems = this._updateMenuItems.bind(this);
|
||||
this.destroy = this.destroy.bind(this);
|
||||
this.menubar = options.menubar || null;
|
||||
this.menuindex = options.menuindex || null;
|
||||
this._menuEnabled = true;
|
||||
this._destroyed = false;
|
||||
this._loaded = false;
|
||||
this._pluginCommands = new Map();
|
||||
if (iframe) {
|
||||
this.load(iframe);
|
||||
}
|
||||
|
@ -111,7 +120,12 @@ var ProjectEditor = Class({
|
|||
this.iframe = iframe;
|
||||
|
||||
let domReady = () => {
|
||||
if (this._destroyed) {
|
||||
deferred.reject("Error: ProjectEditor has been destroyed before loading");
|
||||
return;
|
||||
}
|
||||
this._onLoad();
|
||||
this._loaded = true;
|
||||
deferred.resolve(this);
|
||||
};
|
||||
|
||||
|
@ -130,9 +144,11 @@ var ProjectEditor = Class({
|
|||
this.document = this.iframe.contentDocument;
|
||||
this.window = this.iframe.contentWindow;
|
||||
|
||||
this._initCommands();
|
||||
this._buildMenubar();
|
||||
this._buildSidebar();
|
||||
|
||||
this.window.addEventListener("unload", this.destroy.bind(this));
|
||||
this.window.addEventListener("unload", this.destroy, false);
|
||||
|
||||
// Editor management
|
||||
this.shells = new ShellDeck(this, this.document);
|
||||
|
@ -143,9 +159,6 @@ var ProjectEditor = Class({
|
|||
let shellContainer = this.document.querySelector("#shells-deck-container");
|
||||
shellContainer.appendChild(this.shells.elt);
|
||||
|
||||
let popup = this.document.querySelector("#edit-menu-popup");
|
||||
popup.addEventListener("popupshowing", this.updateEditorMenuItems);
|
||||
|
||||
// We are not allowing preset projects for now - rebuild a fresh one
|
||||
// each time.
|
||||
this.setProject(new Project({
|
||||
|
@ -155,10 +168,40 @@ var ProjectEditor = Class({
|
|||
openFiles: []
|
||||
}));
|
||||
|
||||
this._initCommands();
|
||||
this._initPlugins();
|
||||
},
|
||||
|
||||
_buildMenubar: function() {
|
||||
|
||||
this.editMenu = this.document.getElementById("edit-menu");
|
||||
this.fileMenu = this.document.getElementById("file-menu");
|
||||
|
||||
this.editMenuPopup = this.document.getElementById("edit-menu-popup");
|
||||
this.fileMenuPopup = this.document.getElementById("file-menu-popup");
|
||||
this.editMenu.addEventListener("popupshowing", this._updateMenuItems);
|
||||
this.fileMenu.addEventListener("popupshowing", this._updateMenuItems);
|
||||
|
||||
if (this.menubar) {
|
||||
let body = this.menubar.ownerDocument.body ||
|
||||
this.menubar.ownerDocument.querySelector("window");
|
||||
body.appendChild(this.projectEditorCommandset);
|
||||
body.appendChild(this.projectEditorKeyset);
|
||||
body.appendChild(this.editorCommandset);
|
||||
body.appendChild(this.editorKeyset);
|
||||
body.appendChild(this.contextMenuPopup);
|
||||
|
||||
let index = this.menuindex || 0;
|
||||
this.menubar.insertBefore(this.editMenu, this.menubar.children[index]);
|
||||
this.menubar.insertBefore(this.fileMenu, this.menubar.children[index]);
|
||||
} else {
|
||||
this.document.getElementById("projecteditor-menubar").style.display = "block";
|
||||
}
|
||||
|
||||
// Insert a controller to allow enabling and disabling of menu items.
|
||||
this._commandWindow = this.editorCommandset.ownerDocument.defaultView;
|
||||
this._commandController = getCommandController(this);
|
||||
this._commandWindow.controllers.insertControllerAt(0, this._commandController);
|
||||
},
|
||||
|
||||
/**
|
||||
* Create the project tree sidebar that lists files.
|
||||
|
@ -166,7 +209,8 @@ var ProjectEditor = Class({
|
|||
_buildSidebar: function() {
|
||||
this.projectTree = new ProjectTreeView(this.document, {
|
||||
resourceVisible: this.resourceVisible.bind(this),
|
||||
resourceFormatter: this.resourceFormatter.bind(this)
|
||||
resourceFormatter: this.resourceFormatter.bind(this),
|
||||
contextMenuPopup: this.contextMenuPopup
|
||||
});
|
||||
on(this, this.projectTree, "selection", this._onTreeSelected);
|
||||
on(this, this.projectTree, "resource-removed", this._onTreeResourceRemoved);
|
||||
|
@ -179,8 +223,16 @@ var ProjectEditor = Class({
|
|||
* Set up listeners for commands to dispatch to all of the plugins
|
||||
*/
|
||||
_initCommands: function() {
|
||||
this.commands = this.document.querySelector("#projecteditor-commandset");
|
||||
this.commands.addEventListener("command", (evt) => {
|
||||
|
||||
this.projectEditorCommandset = this.document.getElementById("projecteditor-commandset");
|
||||
this.projectEditorKeyset = this.document.getElementById("projecteditor-keyset");
|
||||
|
||||
this.editorCommandset = this.document.getElementById("editMenuCommands");
|
||||
this.editorKeyset = this.document.getElementById("editMenuKeys");
|
||||
|
||||
this.contextMenuPopup = this.document.getElementById("context-menu-popup");
|
||||
|
||||
this.projectEditorCommandset.addEventListener("command", (evt) => {
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
this.pluginDispatch("onCommand", evt.target.id, evt.target);
|
||||
|
@ -207,17 +259,35 @@ var ProjectEditor = Class({
|
|||
/**
|
||||
* Enable / disable necessary menu items using globalOverlay.js.
|
||||
*/
|
||||
_updateEditorMenuItems: function() {
|
||||
this.window.goUpdateGlobalEditMenuItems();
|
||||
this.window.goUpdateGlobalEditMenuItems();
|
||||
let commands = ['cmd_undo', 'cmd_redo', 'cmd_delete', 'cmd_findAgain'];
|
||||
commands.forEach(this.window.goUpdateCommand);
|
||||
_updateMenuItems: function() {
|
||||
let window = this.editMenu.ownerDocument.defaultView;
|
||||
let commands = ['cmd_undo', 'cmd_redo', 'cmd_delete', 'cmd_cut', 'cmd_copy', 'cmd_paste'];
|
||||
commands.forEach(window.goUpdateCommand);
|
||||
|
||||
for (let c of this._pluginCommands.keys()) {
|
||||
window.goUpdateCommand(c);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Destroy all objects on the iframe unload event.
|
||||
*/
|
||||
destroy: function() {
|
||||
this._destroyed = true;
|
||||
|
||||
|
||||
// If been destroyed before the iframe finished loading, then
|
||||
// the properties below will not exist.
|
||||
if (!this._loaded) {
|
||||
this.iframe.setAttribute("src", "about:blank");
|
||||
return;
|
||||
}
|
||||
|
||||
// Reset the src for the iframe so if it reused for a new ProjectEditor
|
||||
// instance, the load will fire properly.
|
||||
this.window.removeEventListener("unload", this.destroy, false);
|
||||
this.iframe.setAttribute("src", "about:blank");
|
||||
|
||||
this._plugins.forEach(plugin => { plugin.destroy(); });
|
||||
|
||||
forget(this, this.projectTree);
|
||||
|
@ -226,6 +296,17 @@ var ProjectEditor = Class({
|
|||
|
||||
this.shells.destroy();
|
||||
|
||||
this.projectEditorCommandset.remove();
|
||||
this.projectEditorKeyset.remove();
|
||||
this.editorCommandset.remove();
|
||||
this.editorKeyset.remove();
|
||||
this.contextMenuPopup.remove();
|
||||
this.editMenu.remove();
|
||||
this.fileMenu.remove();
|
||||
|
||||
this._commandWindow.controllers.removeController(this._commandController);
|
||||
this._commandController = null;
|
||||
|
||||
forget(this, this.project);
|
||||
this.project.destroy();
|
||||
this.project = null;
|
||||
|
@ -384,11 +465,13 @@ var ProjectEditor = Class({
|
|||
* @returns DOMElement
|
||||
* The command element that has been created.
|
||||
*/
|
||||
addCommand: function(definition) {
|
||||
let command = this.document.createElement("command");
|
||||
addCommand: function(plugin, definition) {
|
||||
this._pluginCommands.set(definition.id, plugin);
|
||||
let document = this.projectEditorKeyset.ownerDocument;
|
||||
let command = document.createElement("command");
|
||||
command.setAttribute("id", definition.id);
|
||||
if (definition.key) {
|
||||
let key = this.document.createElement("key");
|
||||
let key = document.createElement("key");
|
||||
key.id = "key_" + definition.id;
|
||||
|
||||
let keyName = definition.key;
|
||||
|
@ -399,10 +482,10 @@ var ProjectEditor = Class({
|
|||
}
|
||||
key.setAttribute("modifiers", definition.modifiers);
|
||||
key.setAttribute("command", definition.id);
|
||||
this.document.getElementById("projecteditor-keyset").appendChild(key);
|
||||
this.projectEditorKeyset.appendChild(key);
|
||||
}
|
||||
command.setAttribute("oncommand", "void(0);"); // needed. See bug 371900
|
||||
this.document.getElementById("projecteditor-commandset").appendChild(command);
|
||||
this.projectEditorCommandset.appendChild(command);
|
||||
return command;
|
||||
},
|
||||
|
||||
|
@ -610,6 +693,49 @@ var ProjectEditor = Class({
|
|||
get currentEditor() {
|
||||
return this.shells.currentEditor;
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether or not menu items should be able to be enabled.
|
||||
* Note that even if this is true, certain menu items will not be
|
||||
* enabled until the correct state is achieved (for instance, the
|
||||
* 'copy' menu item is only enabled when there is a selection).
|
||||
* But if this is false, then nothing will be enabled.
|
||||
*/
|
||||
set menuEnabled(val) {
|
||||
this._menuEnabled = val;
|
||||
this._updateMenuItems();
|
||||
},
|
||||
|
||||
get menuEnabled() {
|
||||
return this._menuEnabled;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Returns a controller object that can be used for
|
||||
* editor-specific commands such as find, jump to line,
|
||||
* copy/paste, etc.
|
||||
*/
|
||||
function getCommandController(host) {
|
||||
return {
|
||||
supportsCommand: function (cmd) {
|
||||
return host._pluginCommands.get(cmd);
|
||||
},
|
||||
|
||||
isCommandEnabled: function (cmd) {
|
||||
if (!host.menuEnabled) {
|
||||
return false;
|
||||
}
|
||||
let plugin = host._pluginCommands.get(cmd);
|
||||
if (plugin && plugin.isCommandEnabled) {
|
||||
return plugin.isCommandEnabled(cmd);
|
||||
}
|
||||
return true;
|
||||
},
|
||||
doCommand: function(cmd) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
exports.ProjectEditor = ProjectEditor;
|
||||
|
|
|
@ -36,7 +36,7 @@ var Shell = Class({
|
|||
|
||||
let constructor = this._editorTypeForResource();
|
||||
|
||||
this.editor = constructor(this.doc, this.host);
|
||||
this.editor = constructor(this.host);
|
||||
this.editor.shell = this;
|
||||
this.editorAppended = this.editor.appended;
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ var ResourceContainer = Class({
|
|||
*/
|
||||
openContextMenu: function(ev) {
|
||||
ev.preventDefault();
|
||||
let popup = this.tree.doc.getElementById("directory-menu-popup");
|
||||
let popup = this.tree.options.contextMenuPopup;
|
||||
popup.openPopupAtScreen(ev.screenX, ev.screenY, true);
|
||||
},
|
||||
|
||||
|
@ -208,13 +208,14 @@ var TreeView = Class({
|
|||
/**
|
||||
* @param Document document
|
||||
* @param Object options
|
||||
* - contextMenuPopup: a <menupopup> element
|
||||
* - resourceFormatter: a function(Resource, DOMNode)
|
||||
* that renders the resource into the view
|
||||
* - resourceVisible: a function(Resource) -> Boolean
|
||||
* that determines if the resource should show up.
|
||||
*/
|
||||
initialize: function(document, options) {
|
||||
this.doc = document;
|
||||
initialize: function(doc, options) {
|
||||
this.doc = doc;
|
||||
this.options = merge({
|
||||
resourceFormatter: function(resource, elt) {
|
||||
elt.textContent = resource.toString();
|
||||
|
@ -223,14 +224,14 @@ var TreeView = Class({
|
|||
this.models = new Set();
|
||||
this.roots = new Set();
|
||||
this._containers = new Map();
|
||||
this.elt = document.createElementNS(HTML_NS, "div");
|
||||
this.elt = this.doc.createElementNS(HTML_NS, "div");
|
||||
this.elt.tree = this;
|
||||
this.elt.className = "sources-tree";
|
||||
this.elt.setAttribute("with-arrows", "true");
|
||||
this.elt.setAttribute("theme", "dark");
|
||||
this.elt.setAttribute("flex", "1");
|
||||
|
||||
this.children = document.createElementNS(HTML_NS, "ul");
|
||||
this.children = this.doc.createElementNS(HTML_NS, "ul");
|
||||
this.elt.appendChild(this.children);
|
||||
|
||||
this.resourceChildrenChanged = this.resourceChildrenChanged.bind(this);
|
||||
|
|
|
@ -12,6 +12,8 @@ support-files =
|
|||
[browser_projecteditor_external_change.js]
|
||||
[browser_projecteditor_immediate_destroy.js]
|
||||
[browser_projecteditor_init.js]
|
||||
[browser_projecteditor_menubar_01.js]
|
||||
[browser_projecteditor_menubar_02.js]
|
||||
[browser_projecteditor_new_file.js]
|
||||
[browser_projecteditor_stores.js]
|
||||
[browser_projecteditor_tree_selection.js]
|
||||
|
|
|
@ -37,7 +37,7 @@ let test = asyncTest(function*() {
|
|||
let defer = promise.defer();
|
||||
|
||||
let resource = container.resource;
|
||||
let popup = projecteditor.document.getElementById("directory-menu-popup");
|
||||
let popup = projecteditor.contextMenuPopup;
|
||||
info ("Going to attempt deletion for: " + resource.path)
|
||||
|
||||
onPopupShow(popup).then(function () {
|
||||
|
|
|
@ -10,8 +10,9 @@
|
|||
let test = asyncTest(function* () {
|
||||
|
||||
info ("Testing tab closure when projecteditor is in various states");
|
||||
let loaderUrl = "chrome://browser/content/devtools/projecteditor-test.xul";
|
||||
|
||||
yield addTab("chrome://browser/content/devtools/projecteditor-test.html").then(() => {
|
||||
yield addTab(loaderUrl).then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
|
||||
|
@ -19,7 +20,7 @@ let test = asyncTest(function* () {
|
|||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
yield addTab("chrome://browser/content/devtools/projecteditor-test.html").then(() => {
|
||||
yield addTab(loaderUrl).then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
|
||||
|
@ -30,7 +31,7 @@ let test = asyncTest(function* () {
|
|||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
yield addTab("chrome://browser/content/devtools/projecteditor-test.html").then(() => {
|
||||
yield addTab(loaderUrl).then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
|
||||
|
@ -43,7 +44,7 @@ let test = asyncTest(function* () {
|
|||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
|
||||
yield addTab("chrome://browser/content/devtools/projecteditor-test.html").then(() => {
|
||||
yield addTab(loaderUrl).then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
|
||||
|
@ -56,6 +57,29 @@ let test = asyncTest(function* () {
|
|||
});
|
||||
});
|
||||
|
||||
yield addTab(loaderUrl).then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
|
||||
let projecteditor = ProjectEditor.ProjectEditor(iframe);
|
||||
ok (projecteditor, "ProjectEditor has been initialized");
|
||||
|
||||
let loadedDone = promise.defer();
|
||||
projecteditor.loaded.then(() => {
|
||||
ok (false, "Loaded has finished after destroy() has been called");
|
||||
loadedDone.resolve();
|
||||
}, () => {
|
||||
ok (true, "Loaded has been rejected after destroy() has been called");
|
||||
loadedDone.resolve();
|
||||
});
|
||||
|
||||
projecteditor.destroy();
|
||||
|
||||
return loadedDone.promise.then(() => {
|
||||
gBrowser.removeCurrentTab();
|
||||
});
|
||||
});
|
||||
|
||||
finish();
|
||||
});
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
/* 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 menu bar appends to the correct document.
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let projecteditor = yield addProjectEditorTabForTempDirectory({
|
||||
menubar: false
|
||||
});
|
||||
ok(projecteditor, "ProjectEditor has loaded");
|
||||
|
||||
let fileMenu = projecteditor.document.getElementById("file-menu");
|
||||
let editMenu = projecteditor.document.getElementById("edit-menu");
|
||||
ok (fileMenu, "The menu has loaded in the projecteditor document");
|
||||
ok (editMenu, "The menu has loaded in the projecteditor document");
|
||||
|
||||
let projecteditor2 = yield addProjectEditorTabForTempDirectory();
|
||||
let menubar = projecteditor2.menubar;
|
||||
let fileMenu = projecteditor2.document.getElementById("file-menu");
|
||||
let editMenu = projecteditor2.document.getElementById("edit-menu");
|
||||
ok (!fileMenu, "The menu has NOT loaded in the projecteditor document");
|
||||
ok (!editMenu, "The menu has NOT loaded in the projecteditor document");
|
||||
ok (content.document.querySelector("#file-menu"), "The menu has loaded in the specified element");
|
||||
ok (content.document.querySelector("#edit-menu"), "The menu has loaded in the specified element");
|
||||
});
|
|
@ -0,0 +1,126 @@
|
|||
/* 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 menu bar enabled / disabled state.
|
||||
|
||||
let test = asyncTest(function*() {
|
||||
let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||
let menubar = projecteditor.menubar;
|
||||
|
||||
// let projecteditor = yield addProjectEditorTabForTempDirectory();
|
||||
ok(projecteditor, "ProjectEditor has loaded");
|
||||
|
||||
let fileMenu = menubar.querySelector("#file-menu");
|
||||
let editMenu = menubar.querySelector("#edit-menu");
|
||||
ok (fileMenu, "The menu has loaded in the projecteditor document");
|
||||
ok (editMenu, "The menu has loaded in the projecteditor document");
|
||||
|
||||
let cmdNew = fileMenu.querySelector("[command=cmd-new]");
|
||||
let cmdSave = fileMenu.querySelector("[command=cmd-save]");
|
||||
let cmdSaveas = fileMenu.querySelector("[command=cmd-saveas]");
|
||||
|
||||
let cmdUndo = editMenu.querySelector("[command=cmd_undo]");
|
||||
let cmdRedo = editMenu.querySelector("[command=cmd_redo]");
|
||||
let cmdCut = editMenu.querySelector("[command=cmd_cut]");
|
||||
let cmdCopy = editMenu.querySelector("[command=cmd_copy]");
|
||||
let cmdPaste = editMenu.querySelector("[command=cmd_paste]");
|
||||
|
||||
info ("Checking initial state of menus");
|
||||
yield openAndCloseMenu(fileMenu);
|
||||
yield openAndCloseMenu(editMenu);
|
||||
|
||||
is (cmdNew.getAttribute("disabled"), "", "File menu item is enabled");
|
||||
is (cmdSave.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
is (cmdSaveas.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
|
||||
is (cmdUndo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdRedo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCut.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCopy.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdPaste.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
|
||||
projecteditor.menuEnabled = false;
|
||||
|
||||
info ("Checking with menuEnabled = false");
|
||||
yield openAndCloseMenu(fileMenu);
|
||||
yield openAndCloseMenu(editMenu);
|
||||
|
||||
is (cmdNew.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
is (cmdSave.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
is (cmdSaveas.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
|
||||
is (cmdUndo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdRedo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCut.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCopy.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdPaste.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
|
||||
info ("Checking with menuEnabled=true");
|
||||
projecteditor.menuEnabled = true;
|
||||
|
||||
yield openAndCloseMenu(fileMenu);
|
||||
yield openAndCloseMenu(editMenu);
|
||||
|
||||
is (cmdNew.getAttribute("disabled"), "", "File menu item is enabled");
|
||||
is (cmdSave.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
is (cmdSaveas.getAttribute("disabled"), "true", "File menu item is disabled");
|
||||
|
||||
is (cmdUndo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdRedo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCut.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCopy.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdPaste.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
|
||||
info ("Checking with resource selected");
|
||||
let resource = projecteditor.project.allResources()[2];
|
||||
yield selectFile(projecteditor, resource);
|
||||
let editor = projecteditor.currentEditor;
|
||||
|
||||
editor.editor.focus();
|
||||
EventUtils.synthesizeKey("foo", { }, projecteditor.window);
|
||||
|
||||
yield openAndCloseMenu(fileMenu);
|
||||
yield openAndCloseMenu(editMenu);
|
||||
|
||||
is (cmdNew.getAttribute("disabled"), "", "File menu item is enabled");
|
||||
is (cmdSave.getAttribute("disabled"), "", "File menu item is enabled");
|
||||
is (cmdSaveas.getAttribute("disabled"), "", "File menu item is enabled");
|
||||
|
||||
is (cmdUndo.getAttribute("disabled"), "", "Edit menu item is enabled");
|
||||
is (cmdRedo.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCut.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdCopy.getAttribute("disabled"), "true", "Edit menu item is disabled");
|
||||
is (cmdPaste.getAttribute("disabled"), "", "Edit menu item is enabled");
|
||||
});
|
||||
|
||||
function openAndCloseMenu(menu) {
|
||||
let shown = onPopupShow(menu)
|
||||
EventUtils.synthesizeMouseAtCenter(menu, {}, menu.ownerDocument.defaultView);
|
||||
yield shown;
|
||||
let hidden = onPopupHidden(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;
|
||||
}
|
|
@ -88,25 +88,29 @@ function loadHelperScript(filePath) {
|
|||
Services.scriptloader.loadSubScript(testDir + "/" + filePath, this);
|
||||
}
|
||||
|
||||
function addProjectEditorTabForTempDirectory() {
|
||||
function addProjectEditorTabForTempDirectory(opts = {}) {
|
||||
TEMP_PATH = buildTempDirectoryStructure();
|
||||
let CUSTOM_OPTS = {
|
||||
let customOpts = {
|
||||
name: "Test",
|
||||
iconUrl: "chrome://browser/skin/devtools/tool-options.svg",
|
||||
projectOverviewURL: SAMPLE_WEBAPP_URL
|
||||
};
|
||||
|
||||
return addProjectEditorTab().then((projecteditor) => {
|
||||
return projecteditor.setProjectToAppPath(TEMP_PATH, CUSTOM_OPTS).then(() => {
|
||||
return addProjectEditorTab(opts).then((projecteditor) => {
|
||||
return projecteditor.setProjectToAppPath(TEMP_PATH, customOpts).then(() => {
|
||||
return projecteditor;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addProjectEditorTab() {
|
||||
return addTab("chrome://browser/content/devtools/projecteditor-test.html").then(() => {
|
||||
function addProjectEditorTab(opts = {}) {
|
||||
return addTab("chrome://browser/content/devtools/projecteditor-test.xul").then(() => {
|
||||
let iframe = content.document.getElementById("projecteditor-iframe");
|
||||
let projecteditor = ProjectEditor.ProjectEditor(iframe);
|
||||
if (opts.menubar !== false) {
|
||||
opts.menubar = content.document.querySelector("menubar");
|
||||
}
|
||||
let projecteditor = ProjectEditor.ProjectEditor(iframe, opts);
|
||||
|
||||
|
||||
ok (iframe, "Tab has placeholder iframe for projecteditor");
|
||||
ok (projecteditor, "ProjectEditor has been initialized");
|
||||
|
|
|
@ -321,13 +321,34 @@ let UI = {
|
|||
|
||||
// ProjectEditor & details screen
|
||||
|
||||
destroyProjectEditor: function() {
|
||||
if (this.projecteditor) {
|
||||
this.projecteditor.destroy();
|
||||
this.projecteditor = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateProjectEditorMenusVisibility: function() {
|
||||
if (this.projecteditor) {
|
||||
let panel = document.querySelector("#deck").selectedPanel;
|
||||
if (panel && panel.id == "deck-panel-projecteditor") {
|
||||
this.projecteditor.menuEnabled = true;
|
||||
} else {
|
||||
this.projecteditor.menuEnabled = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
getProjectEditor: function() {
|
||||
if (this.projecteditor) {
|
||||
return this.projecteditor.loaded;
|
||||
}
|
||||
|
||||
let projecteditorIframe = document.querySelector("#deck-panel-projecteditor");
|
||||
this.projecteditor = ProjectEditor.ProjectEditor(projecteditorIframe);
|
||||
this.projecteditor = ProjectEditor.ProjectEditor(projecteditorIframe, {
|
||||
menubar: document.querySelector("#main-menubar"),
|
||||
menuindex: 1
|
||||
});
|
||||
this.projecteditor.on("onEditorSave", (editor, resource) => {
|
||||
AppManager.validateProject(AppManager.selectedProject);
|
||||
});
|
||||
|
@ -409,12 +430,14 @@ let UI = {
|
|||
let deck = document.querySelector("#deck");
|
||||
let panel = deck.querySelector("#deck-panel-" + id);
|
||||
deck.selectedPanel = panel;
|
||||
this.updateProjectEditorMenusVisibility();
|
||||
},
|
||||
|
||||
resetDeck: function() {
|
||||
this.resetFocus();
|
||||
let deck = document.querySelector("#deck");
|
||||
deck.selectedPanel = null;
|
||||
this.updateProjectEditorMenusVisibility();
|
||||
},
|
||||
|
||||
/********** COMMANDS **********/
|
||||
|
@ -822,7 +845,11 @@ let Cmds = {
|
|||
},
|
||||
|
||||
toggleEditors: function() {
|
||||
Services.prefs.setBoolPref("devtools.webide.showProjectEditor", !UI.isProjectEditorEnabled());
|
||||
let isNowEnabled = !UI.isProjectEditorEnabled();
|
||||
Services.prefs.setBoolPref("devtools.webide.showProjectEditor", isNowEnabled);
|
||||
if (!isNowEnabled) {
|
||||
UI.destroyProjectEditor();
|
||||
}
|
||||
UI.openProject();
|
||||
},
|
||||
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
%webideDTD;
|
||||
]>
|
||||
|
||||
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin/global.css"?>
|
||||
<?xml-stylesheet href="chrome://webide/skin/webide.css"?>
|
||||
|
||||
|
@ -23,6 +25,7 @@
|
|||
width="640" height="480"
|
||||
persist="screenX screenY width height">
|
||||
|
||||
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"></script>
|
||||
<script type="application/javascript" src="webide.js"></script>
|
||||
<script type="application/javascript" src="cli.js"></script>
|
||||
|
||||
|
|
|
@ -32,10 +32,19 @@ projecteditor.deleteFolderPromptMessage=Are you sure you want to delete this fol
|
|||
projecteditor.deleteFilePromptMessage=Are you sure you want to delete this file?
|
||||
|
||||
# LOCALIZATION NOTE (projecteditor.newLabel):
|
||||
# This string is displayed as a context menu item for adding a new file to
|
||||
# This string is displayed as a menu item for adding a new file to
|
||||
# the directory.
|
||||
projecteditor.newLabel=New…
|
||||
|
||||
# LOCALIZATION NOTE (projecteditor.saveLabel):
|
||||
# This string is displayed as a menu item for saving the current file.
|
||||
projecteditor.saveLabel=Save
|
||||
|
||||
# LOCALIZATION NOTE (projecteditor.saveAsLabel):
|
||||
# This string is displayed as a menu item for saving the current file
|
||||
# with a new name.
|
||||
projecteditor.saveAsLabel=Save As…
|
||||
|
||||
# LOCALIZATION NOTE (projecteditor.selectFileLabel):
|
||||
# This string is displayed as the title on the file picker when saving a file.
|
||||
projecteditor.selectFileLabel=Select a File
|
||||
|
|
|
@ -26,8 +26,6 @@
|
|||
}
|
||||
|
||||
#projecteditor-menubar {
|
||||
/* XXX: Hide menu bar until we have option to add menu items
|
||||
to an existing one. */
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче