Bug 684445 - Orion source editor should have built-in context menu; r=rcampbell f=rcampbell

This commit is contained in:
Mihai Sucan 2012-02-27 20:08:45 +02:00
Родитель a25f68694c
Коммит a414046b7f
10 изменённых файлов: 237 добавлений и 53 удалений

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

@ -831,6 +831,7 @@ var Scratchpad = {
mode: SourceEditor.MODES.JAVASCRIPT,
showLineNumbers: true,
initialText: initialText,
contextMenu: "scratchpad-text-popup",
};
let editorPlaceholder = document.getElementById("scratchpad-editor");
@ -848,8 +849,6 @@ var Scratchpad = {
*/
_onEditorLoad: function SP__onEditorLoad(aState)
{
this.editor.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
this.onContextMenu);
this.editor.addEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
this._onDirtyChanged);
this.editor.focus();
@ -876,22 +875,6 @@ var Scratchpad = {
this.editor.setCaretOffset(caretOffset + aText.length);
},
/**
* The contextmenu event handler for the source editor. This method opens the
* Scratchpad context menu popup at the pointer location.
*
* @param object aEvent
* An event object coming from the SourceEditor. This object needs to
* hold the screenX and screenY properties.
*/
onContextMenu: function SP_onContextMenu(aEvent)
{
let menu = document.getElementById("scratchpad-text-popup");
if (menu.state == "closed") {
menu.openPopupAtScreen(aEvent.screenX, aEvent.screenY, true);
}
},
/**
* The Source Editor DirtyChanged event handler. This function updates the
* Scratchpad window title to show an asterisk when there are unsaved changes.
@ -906,23 +889,6 @@ var Scratchpad = {
Scratchpad._updateTitle();
},
/**
* The popupshowing event handler for the Edit menu. This method updates the
* enabled/disabled state of the Undo and Redo commands, based on the editor
* state such that the menu items render correctly for the user when the menu
* shows.
*/
onEditPopupShowing: function SP_onEditPopupShowing()
{
goUpdateGlobalEditMenuItems();
let undo = document.getElementById("sp-cmd-undo");
undo.setAttribute("disabled", !this.editor.canUndo());
let redo = document.getElementById("sp-cmd-redo");
redo.setAttribute("disabled", !this.editor.canRedo());
},
/**
* Undo the last action of the user.
*/
@ -954,8 +920,6 @@ var Scratchpad = {
this.resetContext();
this.editor.removeEventListener(SourceEditor.EVENTS.DIRTY_CHANGED,
this._onDirtyChanged);
this.editor.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
this.onContextMenu);
this.editor.destroy();
this.editor = null;
this.initialized = false;

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

@ -81,11 +81,11 @@
<command id="sp-cmd-resetContext" oncommand="Scratchpad.resetContext();"/>
<command id="sp-cmd-errorConsole" oncommand="Scratchpad.openErrorConsole();" disabled="true"/>
<command id="sp-cmd-webConsole" oncommand="Scratchpad.openWebConsole();"/>
<command id="sp-cmd-undo" oncommand="Scratchpad.undo();" disabled="true"/>
<command id="sp-cmd-redo" oncommand="Scratchpad.redo();" disabled="true"/>
<command id="sp-cmd-documentationLink" oncommand="Scratchpad.openDocumentationPage();"/>
</commandset>
<keyset id="sourceEditorKeys"/>
<keyset id="sp-keyset">
<key id="sp-key-window"
key="&newWindowCmd.commandkey;"
@ -123,9 +123,9 @@
modifiers="accel"/>
<key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
<key id="key_undo" key="&undoCmd.key;" modifiers="accel"
oncommand="Scratchpad.undo();"/>
command="se-cmd-undo"/>
<key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"
oncommand="Scratchpad.redo();"/>
command="se-cmd-redo"/>
<key id="sp-key-run"
key="&run.key;"
command="sp-cmd-run"
@ -168,10 +168,6 @@
command="cmd_findPrevious"
modifiers="shift"/>
#endif
<key id="key_gotoLine"
key="&gotoLineCmd.key;"
command="cmd_gotoLine"
modifiers="accel"/>
<key id="key_openHelp"
keycode="VK_F1"
command="sp-cmd-documentationLink"/>
@ -223,17 +219,17 @@
<menu id="sp-edit-menu" label="&editMenu.label;"
accesskey="&editMenu.accesskey;">
<menupopup id="sp-menu_editpopup"
onpopupshowing="Scratchpad.onEditPopupShowing()">
onpopupshowing="goUpdateGlobalEditMenuItems()">
<menuitem id="sp-menu-undo"
label="&undoCmd.label;"
key="key_undo"
accesskey="&undoCmd.accesskey;"
command="sp-cmd-undo"/>
command="se-cmd-undo"/>
<menuitem id="sp-menu-redo"
label="&redoCmd.label;"
key="key_redo"
accesskey="&redoCmd.accesskey;"
command="sp-cmd-redo"/>
command="se-cmd-redo"/>
<menuseparator/>
<menuitem id="sp-menu-cut"
label="&cutCmd.label;"

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

@ -32,8 +32,6 @@ function runTests()
"sp-text-resetContext": "resetContext",
"sp-menu-content": "setContentContext",
"sp-menu-browser": "setBrowserContext",
"sp-menu-undo": "undo",
"sp-menu-redo": "redo",
};
let lastMethodCalled = null;

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

@ -147,6 +147,7 @@ function SourceEditor() {
this._onOrionSelection = this._onOrionSelection.bind(this);
this._onTextChanged = this._onTextChanged.bind(this);
this._onOrionContextMenu = this._onOrionContextMenu.bind(this);
this._eventTarget = {};
this._eventListenersQueue = [];
@ -173,6 +174,7 @@ SourceEditor.prototype = {
_iframeWindow: null,
_eventTarget: null,
_eventListenersQueue: null,
_contextMenu: null,
_dirty: false,
/**
@ -287,6 +289,17 @@ SourceEditor.prototype = {
this.addEventListener(SourceEditor.EVENTS.TEXT_CHANGED,
this._onTextChanged);
if (typeof config.contextMenu == "string") {
let chromeDocument = this.parentElement.ownerDocument;
this._contextMenu = chromeDocument.getElementById(config.contextMenu);
} else if (typeof config.contextMenu == "object" ) {
this._contextMenu = config._contextMenu;
}
if (this._contextMenu) {
this.addEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
this._onOrionContextMenu);
}
let KeyBinding = window.require("orion/textview/keyBinding").KeyBinding;
let TextDND = window.require("orion/textview/textDND").TextDND;
let Rulers = window.require("orion/textview/rulers");
@ -605,6 +618,22 @@ SourceEditor.prototype = {
this._updateDirty();
},
/**
* The Orion contextmenu event handler. This method opens the default or
* the custom context menu popup at the pointer location.
*
* @param object aEvent
* The contextmenu event object coming from Orion. This object should
* hold the screenX and screenY properties.
*/
_onOrionContextMenu: function SE__onOrionContextMenu(aEvent)
{
if (this._contextMenu.state == "closed") {
this._contextMenu.openPopupAtScreen(aEvent.screenX || 0,
aEvent.screenY || 0, true);
}
},
/**
* Update the dirty state of the editor based on the undo stack.
* @private
@ -893,18 +922,28 @@ SourceEditor.prototype = {
/**
* Undo a change in the editor.
*
* @return boolean
* True if there was a change undone, false otherwise.
*/
undo: function SE_undo()
{
return this._undoStack.undo();
let result = this._undoStack.undo();
this.ui._onUndoRedo();
return result;
},
/**
* Redo a change in the editor.
*
* @return boolean
* True if there was a change redone, false otherwise.
*/
redo: function SE_redo()
{
return this._undoStack.redo();
let result = this._undoStack.redo();
this.ui._onUndoRedo();
return result;
},
/**
@ -936,6 +975,7 @@ SourceEditor.prototype = {
{
this._undoStack.reset();
this._updateDirty();
this.ui._onUndoRedo();
},
/**
@ -1404,6 +1444,13 @@ SourceEditor.prototype = {
this._onTextChanged);
this._onTextChanged = null;
if (this._contextMenu) {
this.removeEventListener(SourceEditor.EVENTS.CONTEXT_MENU,
this._onOrionContextMenu);
this._contextMenu = null;
}
this._onOrionContextMenu = null;
if (this._primarySelectionTimeout) {
let window = this.parentElement.ownerDocument.defaultView;
window.clearTimeout(this._primarySelectionTimeout);

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

@ -35,13 +35,80 @@
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<!DOCTYPE overlay SYSTEM "chrome://browser/locale/devtools/sourceeditor.dtd">
<overlay id="sourceEditorOverlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<!-- This Source Editor overlay requires the editMenuOverlay.xul to be loaded.
The globalOverlay.js script is also required in the XUL document where
the source-editor-overlay.xul is loaded. -->
<commandset id="sourceEditorCommands">
<command id="cmd_find" oncommand="goDoCommand('cmd_find')"/>
<command id="cmd_findAgain" oncommand="goDoCommand('cmd_findAgain')" disabled="true"/>
<command id="cmd_findPrevious" oncommand="goDoCommand('cmd_findPrevious')" disabled="true"/>
<command id="cmd_gotoLine" oncommand="goDoCommand('cmd_gotoLine')"/>
<command id="se-cmd-undo" oncommand="goDoCommand('se-cmd-undo')" disabled="true"/>
<command id="se-cmd-redo" oncommand="goDoCommand('se-cmd-redo')" disabled="true"/>
</commandset>
<keyset id="sourceEditorKeys">
<key id="key_gotoLine"
key="&gotoLineCmd.key;"
command="cmd_gotoLine"
modifiers="accel"/>
</keyset>
<menupopup id="sourceEditorContextMenu"
onpopupshowing="goUpdateGlobalEditMenuItems()">
<menuitem id="se-menu-undo"
label="&undoCmd.label;"
key="key_undo"
accesskey="&undoCmd.accesskey;"
command="se-cmd-undo"/>
<menuseparator/>
<menuitem id="se-menu-cut"
label="&cutCmd.label;"
key="key_cut"
accesskey="&cutCmd.accesskey;"
command="cmd_cut"/>
<menuitem id="se-menu-copy"
label="&copyCmd.label;"
key="key_copy"
accesskey="&copyCmd.accesskey;"
command="cmd_copy"/>
<menuitem id="se-menu-paste"
label="&pasteCmd.label;"
key="key_paste"
accesskey="&pasteCmd.accesskey;"
command="cmd_paste"/>
<menuitem id="se-menu-delete"
label="&deleteCmd.label;"
key="key_delete"
accesskey="&deleteCmd.accesskey;"
command="cmd_delete"/>
<menuseparator/>
<menuitem id="se-menu-selectAll"
label="&selectAllCmd.label;"
key="key_selectAll"
accesskey="&selectAllCmd.accesskey;"
command="cmd_selectAll"/>
<menuseparator/>
<menuitem id="se-menu-find"
label="&findCmd.label;"
accesskey="&findCmd.accesskey;"
key="key_find"
command="cmd_find"/>
<menuitem id="se-menu-findAgain"
label="&findAgainCmd.label;"
accesskey="&findAgainCmd.accesskey;"
key="key_findAgain"
command="cmd_findAgain"/>
<menuseparator/>
<menuitem id="se-menu-gotoLine"
label="&gotoLineCmd.label;"
accesskey="&gotoLineCmd.accesskey;"
key="key_gotoLine"
command="cmd_gotoLine"/>
</menupopup>
</overlay>

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

@ -50,6 +50,7 @@ var EXPORTED_SYMBOLS = ["SourceEditorUI"];
function SourceEditorUI(aEditor)
{
this.editor = aEditor;
this._onDirtyChanged = this._onDirtyChanged.bind(this);
}
SourceEditorUI.prototype = {
@ -72,6 +73,8 @@ SourceEditorUI.prototype = {
if (this._ownerWindow.controllers) {
this._controller = new SourceEditorController(this.editor);
this._ownerWindow.controllers.insertControllerAt(0, this._controller);
this.editor.addEventListener(this.editor.EVENTS.DIRTY_CHANGED,
this._onDirtyChanged);
}
},
@ -177,12 +180,40 @@ SourceEditorUI.prototype = {
}
},
/**
* This is executed after each undo/redo operation.
* @private
*/
_onUndoRedo: function SEU__onUndoRedo()
{
if (this._ownerWindow.goUpdateCommand) {
this._ownerWindow.goUpdateCommand("se-cmd-undo");
this._ownerWindow.goUpdateCommand("se-cmd-redo");
}
},
/**
* The DirtyChanged event handler for the editor. This tracks the editor state
* changes to make sure the Source Editor overlay Undo/Redo commands are kept
* up to date.
* @private
*/
_onDirtyChanged: function SEU__onDirtyChanged()
{
this._onUndoRedo();
},
/**
* Destroy the SourceEditorUI instance. This is called by the
* SourceEditor.destroy() method.
*/
destroy: function SEU_destroy()
{
if (this._ownerWindow.controllers) {
this.editor.removeEventListener(this.editor.EVENTS.DIRTY_CHANGED,
this._onDirtyChanged);
}
this._ownerWindow = null;
this.editor = null;
this._controller = null;
@ -220,6 +251,8 @@ SourceEditorController.prototype = {
case "cmd_findAgain":
case "cmd_findPrevious":
case "cmd_gotoLine":
case "se-cmd-undo":
case "se-cmd-redo":
result = true;
break;
default:
@ -251,6 +284,12 @@ SourceEditorController.prototype = {
case "cmd_findPrevious":
result = this._editor.lastFind && this._editor.lastFind.lastFound != -1;
break;
case "se-cmd-undo":
result = this._editor.canUndo();
break;
case "se-cmd-redo":
result = this._editor.canRedo();
break;
default:
result = false;
break;
@ -281,6 +320,12 @@ SourceEditorController.prototype = {
case "cmd_gotoLine":
this._editor.ui.gotoLine();
break;
case "se-cmd-undo":
this._editor.undo();
break;
case "se-cmd-redo":
this._editor.redo();
break;
}
},

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

@ -199,6 +199,22 @@ SourceEditor.DEFAULTS = {
* @type array
*/
keys: null,
/**
* The editor context menu you want to display when the user right-clicks
* within the editor. This property can be:
* - a string that tells the ID of the xul:menupopup you want. This needs to
* be available within the editor parentElement.ownerDocument.
* - an nsIDOMElement object reference pointing to the xul:menupopup you
* want to open when the contextmenu event is fired.
*
* Set this property to a falsey value to disable the default context menu.
*
* @see SourceEditor.EVENTS.CONTEXT_MENU for more control over the contextmenu
* event.
* @type string|nsIDOMElement
*/
contextMenu: "sourceEditorContextMenu",
};
/**
@ -216,6 +232,8 @@ SourceEditor.EVENTS = {
* This value comes from the DOM contextmenu event.screenX property.
* - screenY - the pointer location on the y axis, relative to the screen.
* This value comes from the DOM contextmenu event.screenY property.
*
* @see SourceEditor.DEFAULTS.contextMenu
*/
CONTEXT_MENU: "ContextMenu",
@ -312,6 +330,12 @@ function extend(aDestination, aSource)
* Add methods common to all components.
*/
extend(SourceEditor.prototype, {
// Expose the static constants on the SourceEditor instances.
EVENTS: SourceEditor.EVENTS,
MODES: SourceEditor.MODES,
THEMES: SourceEditor.THEMES,
DEFAULTS: SourceEditor.DEFAULTS,
_lastFind: null,
/**

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

@ -45,6 +45,8 @@
<?xml-stylesheet href="chrome://browser/skin/devtools/splitview.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/styleeditor.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/styleeditor.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<?xul-overlay href="chrome://browser/content/source-editor-overlay.xul"?>
<xul:window xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
xmlns="http://www.w3.org/1999/xhtml"
id="style-editor-chrome-window"
@ -54,10 +56,18 @@
persist="screenX screenY width height sizemode">
<xul:script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
<xul:popupset id="style-editor-popups">
<xul:menupopup id="sourceEditorContextMenu"/>
</xul:popupset>
<xul:commandset id="editMenuCommands"/>
<xul:commandset id="sourceEditorCommands"/>
<xul:commandset id="style-editor-commandset">
<xul:command id="style-editor-cmd-close" oncommand="window.close();"/>
</xul:commandset>
<xul:keyset id="editMenuKeys"/>
<xul:keyset id="sourceEditorKeys"/>
<xul:keyset id="style-editor-keyset">
<xul:key id="style-editor-key-close"
key="&closeCmd.key;"

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

@ -0,0 +1,32 @@
<!-- LOCALIZATION NOTE : FILE This file contains the Source Editor component
- strings. The source editor component is used within the Scratchpad and
- Style Editor tools. -->
<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
<!-- LOCALIZATION NOTE : FILE The correct localization of this file might be to
- keep it in English, or another language commonly spoken among web developers.
- You want to make that choice consistent across the developer tools.
- A good criteria is the language in which you'd find the best
- documentation on web development on the web. -->
<!ENTITY undoCmd.label "Undo">
<!ENTITY undoCmd.accesskey "U">
<!ENTITY cutCmd.label "Cut">
<!ENTITY cutCmd.accesskey "t">
<!ENTITY copyCmd.label "Copy">
<!ENTITY copyCmd.accesskey "C">
<!ENTITY pasteCmd.label "Paste">
<!ENTITY pasteCmd.accesskey "P">
<!ENTITY deleteCmd.label "Delete">
<!ENTITY deleteCmd.accesskey "D">
<!ENTITY selectAllCmd.label "Select All">
<!ENTITY selectAllCmd.accesskey "A">
<!ENTITY findCmd.label "Find…">
<!ENTITY findCmd.accesskey "F">
<!ENTITY findAgainCmd.label "Find Again…">
<!ENTITY findAgainCmd.accesskey "g">
<!ENTITY gotoLineCmd.label "Jump to line…">
<!ENTITY gotoLineCmd.key "J">
<!ENTITY gotoLineCmd.accesskey "J">

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

@ -30,6 +30,7 @@
locale/browser/devtools/styleinspector.dtd (%chrome/browser/devtools/styleinspector.dtd)
locale/browser/devtools/webConsole.dtd (%chrome/browser/devtools/webConsole.dtd)
locale/browser/devtools/sourceeditor.properties (%chrome/browser/devtools/sourceeditor.properties)
locale/browser/devtools/sourceeditor.dtd (%chrome/browser/devtools/sourceeditor.dtd)
locale/browser/newTab.dtd (%chrome/browser/newTab.dtd)
locale/browser/newTab.properties (%chrome/browser/newTab.properties)
locale/browser/openLocation.dtd (%chrome/browser/openLocation.dtd)