Browse Source

Establish shared communicator-devtools and include scratchpad

custom-2020
Matt A. Tobin 2 years ago committed by Roy Tam
parent
commit
54e200c5db
  1. 11
      communicator/components/devtools/content/devtoolsOverlay.js
  2. 31
      communicator/components/devtools/content/devtoolsOverlay.xul
  3. 694
      communicator/components/devtools/content/scratchpad/scratchpad.js
  4. 352
      communicator/components/devtools/content/scratchpad/scratchpad.xul
  5. 8
      communicator/components/devtools/devtools-prefs.js
  6. 14
      communicator/components/devtools/jar.mn
  7. 6
      communicator/components/devtools/locale/devtoolsOverlay.dtd
  8. 123
      communicator/components/devtools/locale/scratchpad.dtd
  9. 35
      communicator/components/devtools/locale/scratchpad.properties
  10. 612
      communicator/components/devtools/modules/PropertyPanel.jsm
  11. 10
      communicator/components/devtools/moz.build
  12. 7
      communicator/components/moz.build
  13. 1
      projects/navigator/base/content/navigatorOverlay.xul
  14. 1
      projects/navigator/confvars.sh
  15. 2
      projects/navigator/themes/moz.build

11
communicator/components/devtools/content/devtoolsOverlay.js

@ -0,0 +1,11 @@
/* 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/. */
function toScratchpad() {
toOpenWindowByType("devtools:scratchpad",
"chrome://communicator/content/devtools/scratchpad.xul",
"resizable");
}

31
communicator/components/devtools/content/devtoolsOverlay.xul

@ -0,0 +1,31 @@
<?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/. -->
<!DOCTYPE overlay [
<!ENTITY % overlayDTD SYSTEM "chrome://communicator/locale/devtools/devtoolsOverlay.dtd">
%overlayDTD;
]>
<overlay id="devtools-overlay"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript" src="chrome://communicator/content/devtools/devtoolsOverlay.js" />
<menupopup id="devtoolsPopup">
<menuitem id="cmd_scratchpad"
insertafter="menu_inspector,javascriptConsole"
oncommand="toScratchpad();"
label="&scratchpad.label;"/>
</menupopup>
<menupopup id="toolsPopup">
<menuitem id="cmd_scratchpad"
insertafter="menu_inspector,javascriptConsolemenu_inspector"
oncommand="toScratchpad();"
label="&scratchpad.label;"/>
</menupopup>
</overlay>

694
communicator/components/devtools/content/scratchpad/scratchpad.js

@ -0,0 +1,694 @@
/* vim:set ts=2 sw=2 sts=2 et:
* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Scratchpad.
*
* The Initial Developer of the Original Code is
* The Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <robcee@mozilla.com> (original author)
* Erik Vold <erikvvold@gmail.com>
* David Dahl <ddahl@mozilla.com>
* Mihai Sucan <mihai.sucan@gmail.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK *****/
/*
* Original version history can be found here:
* https://github.com/mozilla/workspace
*
* Copied and relicensed from the Public Domain.
* See bug 653934 for details.
* https://bugzilla.mozilla.org/show_bug.cgi?id=653934
*/
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/NetUtil.jsm");
Cu.import("resource:///modules/communicator/devtools/PropertyPanel.jsm");
const SCRATCHPAD_CONTEXT_CONTENT = 1;
const SCRATCHPAD_CONTEXT_BROWSER = 2;
const SCRATCHPAD_WINDOW_URL = "chrome://communicator/content/devtools/scratchpad.xul";
const SCRATCHPAD_L10N = "chrome://communicator/locale/devtools/scratchpad.properties";
const SCRATCHPAD_WINDOW_FEATURES = "chrome,titlebar,toolbar,centerscreen,resizable,dialog=no";
const DEVTOOLS_CHROME_ENABLED = "devtools.chrome.enabled";
const PREF_TABSIZE = "devtools.editor.tabsize";
const PREF_EXPANDTAB = "devtools.editor.expandtab";
/**
* The scratchpad object handles the Scratchpad window functionality.
*/
var Scratchpad = {
/**
* The script execution context. This tells Scratchpad in which context the
* script shall execute.
*
* Possible values:
* - SCRATCHPAD_CONTEXT_CONTENT to execute code in the context of the current
* tab content window object.
* - SCRATCHPAD_CONTEXT_BROWSER to execute code in the context of the
* currently active chrome window object.
*/
executionContext: SCRATCHPAD_CONTEXT_CONTENT,
/**
* Retrieve the xul:textbox DOM element. This element holds the source code
* the user writes and executes.
*/
get textbox() document.getElementById("scratchpad-textbox"),
/**
* Retrieve the xul:statusbarpanel DOM element. The status bar tells the
* current code execution context.
*/
get statusbarStatus() document.getElementById("scratchpad-status"),
/**
* Get the selected text from the textbox.
*/
get selectedText()
{
return this.textbox.value.substring(this.textbox.selectionStart,
this.textbox.selectionEnd);
},
/**
* Get the most recent chrome window of type navigator:browser.
*/
get browserWindow() Services.wm.getMostRecentWindow("navigator:browser"),
/**
* Reference to the last chrome window of type navigator:browser. We use this
* to check if the chrome window changed since the last code evaluation.
*/
_previousWindow: null,
/**
* Get the gBrowser object of the most recent browser window.
*/
get gBrowser()
{
let recentWin = this.browserWindow;
return recentWin ? recentWin.gBrowser : null;
},
insertIntro: function SP_insertIntro()
{
this.textbox.value = this.strings.GetStringFromName("scratchpadIntro");
},
/**
* Cached Cu.Sandbox object for the active tab content window object.
*/
_contentSandbox: null,
/**
* Get the Cu.Sandbox object for the active tab content window object. Note
* that the returned object is cached for later reuse. The cached object is
* kept only for the current location in the current tab of the current
* browser window and it is reset for each context switch,
* navigator:browser window switch, tab switch or navigation.
*/
get contentSandbox()
{
if (!this.browserWindow) {
Cu.reportError(this.strings.
GetStringFromName("browserWindow.unavailable"));
return;
}
if (!this._contentSandbox ||
this.browserWindow != this._previousBrowserWindow ||
this._previousBrowser != this.gBrowser.selectedBrowser ||
this._previousLocation != this.gBrowser.contentWindow.location.href) {
let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
this._contentSandbox = new Cu.Sandbox(contentWindow,
{ sandboxPrototype: contentWindow, wantXrays: false });
this._previousBrowserWindow = this.browserWindow;
this._previousBrowser = this.gBrowser.selectedBrowser;
this._previousLocation = contentWindow.location.href;
}
return this._contentSandbox;
},
/**
* Cached Cu.Sandbox object for the most recently active navigator:browser
* chrome window object.
*/
_chromeSandbox: null,
/**
* Get the Cu.Sandbox object for the most recently active navigator:browser
* chrome window object. Note that the returned object is cached for later
* reuse. The cached object is kept only for the current browser window and it
* is reset for each context switch or navigator:browser window switch.
*/
get chromeSandbox()
{
if (!this.browserWindow) {
Cu.reportError(this.strings.
GetStringFromName("browserWindow.unavailable"));
return;
}
if (!this._chromeSandbox ||
this.browserWindow != this._previousBrowserWindow) {
this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
{ sandboxPrototype: this.browserWindow, wantXrays: false });
this._previousBrowserWindow = this.browserWindow;
}
return this._chromeSandbox;
},
/**
* Drop the textbox selection.
*/
deselect: function SP_deselect()
{
this.textbox.selectionEnd = this.textbox.selectionStart;
},
/**
* Select a specific range in the Scratchpad xul:textbox.
*
* @param number aStart
* Selection range start.
* @param number aEnd
* Selection range end.
*/
selectRange: function SP_selectRange(aStart, aEnd)
{
this.textbox.selectionStart = aStart;
this.textbox.selectionEnd = aEnd;
},
/**
* Evaluate a string in the active tab content window.
*
* @param string aString
* The script you want evaluated.
* @return mixed
* The script evaluation result.
*/
evalInContentSandbox: function SP_evalInContentSandbox(aString)
{
let result;
try {
result = Cu.evalInSandbox(aString, this.contentSandbox, "1.8",
"Scratchpad", 1);
}
catch (ex) {
this.openWebConsole();
let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
let scriptError = Cc["@mozilla.org/scripterror;1"].
createInstance(Ci.nsIScriptError2);
scriptError.initWithWindowID(ex.message + "\n" + ex.stack, ex.fileName,
"", ex.lineNumber, 0, scriptError.errorFlag,
"content javascript",
this.getWindowId(contentWindow));
Services.console.logMessage(scriptError);
}
return result;
},
/**
* Evaluate a string in the most recent navigator:browser chrome window.
*
* @param string aString
* The script you want evaluated.
* @return mixed
* The script evaluation result.
*/
evalInChromeSandbox: function SP_evalInChromeSandbox(aString)
{
let result;
try {
result = Cu.evalInSandbox(aString, this.chromeSandbox, "1.8",
"Scratchpad", 1);
}
catch (ex) {
Cu.reportError(ex);
Cu.reportError(ex.stack);
this.openErrorConsole();
}
return result;
},
/**
* Evaluate a string in the currently desired context, that is either the
* chrome window or the tab content window object.
*
* @param string aString
* The script you want to evaluate.
* @return mixed
* The script evaluation result.
*/
evalForContext: function SP_evaluateForContext(aString)
{
return this.executionContext == SCRATCHPAD_CONTEXT_CONTENT ?
this.evalInContentSandbox(aString) :
this.evalInChromeSandbox(aString);
},
/**
* Execute the selected text (if any) or the entire textbox content in the
* current context.
*/
run: function SP_run()
{
let selection = this.selectedText || this.textbox.value;
let result = this.evalForContext(selection);
this.deselect();
return [selection, result];
},
/**
* Execute the selected text (if any) or the entire textbox content in the
* current context. The resulting object is opened up in the Property Panel
* for inspection.
*/
inspect: function SP_inspect()
{
let [selection, result] = this.run();
if (result) {
this.openPropertyPanel(selection, result);
}
},
/**
* Execute the selected text (if any) or the entire textbox content in the
* current context. The evaluation result is inserted into the textbox after
* the selected text, or at the end of the textbox value if there is no
* selected text.
*/
display: function SP_display()
{
let selectionStart = this.textbox.selectionStart;
let selectionEnd = this.textbox.selectionEnd;
if (selectionStart == selectionEnd) {
selectionEnd = this.textbox.value.length;
}
let [selection, result] = this.run();
if (!result) {
return;
}
let firstPiece = this.textbox.value.slice(0, selectionEnd);
let lastPiece = this.textbox.value.
slice(selectionEnd, this.textbox.value.length);
let newComment = "/*\n" + result.toString() + "\n*/";
this.textbox.value = firstPiece + newComment + lastPiece;
// Select the added comment.
this.selectRange(firstPiece.length, firstPiece.length + newComment.length);
},
/**
* Open the Property Panel to inspect the given object.
*
* @param string aEvalString
* The string that was evaluated. This is re-used when the user updates
* the properties list, by clicking the Update button.
* @param object aOutputObject
* The object to inspect, which is the aEvalString evaluation result.
* @return object
* The PropertyPanel object instance.
*/
openPropertyPanel: function SP_openPropertyPanel(aEvalString, aOutputObject)
{
let self = this;
let propPanel;
// The property panel has a button:
// `Update`: reexecutes the string executed on the command line. The
// result will be inspected by this panel.
let buttons = [];
// If there is a evalString passed to this function, then add a `Update`
// button to the panel so that the evalString can be reexecuted to update
// the content of the panel.
if (aEvalString !== null) {
buttons.push({
label: this.strings.
GetStringFromName("propertyPanel.updateButton.label"),
accesskey: this.strings.
GetStringFromName("propertyPanel.updateButton.accesskey"),
oncommand: function () {
try {
let result = self.evalForContext(aEvalString);
if (result !== undefined) {
propPanel.treeView.data = result;
}
}
catch (ex) { }
}
});
}
let doc = this.browserWindow.document;
let parent = doc.getElementById("mainPopupSet");
let title = aOutputObject.toString();
propPanel = new PropertyPanel(parent, doc, title, aOutputObject, buttons);
let panel = propPanel.panel;
panel.setAttribute("class", "scratchpad_propertyPanel");
panel.openPopup(null, "after_pointer", 0, 0, false, false);
panel.sizeTo(200, 400);
return propPanel;
},
// Menu Operations
/**
* Open a new Scratchpad window.
*/
openScratchpad: function SP_openScratchpad()
{
Services.ww.openWindow(null, SCRATCHPAD_WINDOW_URL, "_blank",
SCRATCHPAD_WINDOW_FEATURES, null);
},
/**
* Export the textbox content to a file.
*
* @param nsILocalFile aFile
* The file where you want to save the textbox content.
* @param boolean aNoConfirmation
* If the file already exists, ask for confirmation?
* @param boolean aSilentError
* True if you do not want to display an error when file save fails,
* false otherwise.
* @param function aCallback
* Optional function you want to call when file save completes. It will
* get the following arguments:
* 1) the nsresult status code for the export operation.
*/
exportToFile: function SP_exportToFile(aFile, aNoConfirmation, aSilentError,
aCallback)
{
if (!aNoConfirmation && aFile.exists() &&
!window.confirm(this.strings.
GetStringFromName("export.fileOverwriteConfirmation"))) {
return;
}
let fs = Cc["@mozilla.org/network/file-output-stream;1"].
createInstance(Ci.nsIFileOutputStream);
let modeFlags = 0x02 | 0x08 | 0x20;
fs.init(aFile, modeFlags, 0644, fs.DEFER_OPEN);
let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let input = converter.convertToInputStream(this.textbox.value);
let self = this;
NetUtil.asyncCopy(input, fs, function(aStatus) {
if (!aSilentError && !Components.isSuccessCode(aStatus)) {
window.alert(self.strings.GetStringFromName("saveFile.failed"));
}
if (aCallback) {
aCallback.call(self, aStatus);
}
});
},
/**
* Read the content of a file and put it into the textbox.
*
* @param nsILocalFile aFile
* The file you want to save the textbox content into.
* @param boolean aSilentError
* True if you do not want to display an error when file load fails,
* false otherwise.
* @param function aCallback
* Optional function you want to call when file load completes. It will
* get the following arguments:
* 1) the nsresult status code for the import operation.
* 2) the data that was read from the file, if any.
*/
importFromFile: function SP_importFromFile(aFile, aSilentError, aCallback)
{
// Prevent file type detection.
let channel = NetUtil.newChannel(aFile);
channel.contentType = "application/javascript";
let self = this;
NetUtil.asyncFetch(channel, function(aInputStream, aStatus) {
let content = null;
if (Components.isSuccessCode(aStatus)) {
content = NetUtil.readInputStreamToString(aInputStream,
aInputStream.available());
self.textbox.value = content;
}
else if (!aSilentError) {
window.alert(self.strings.GetStringFromName("openFile.failed"));
}
if (aCallback) {
aCallback.call(self, aStatus, content);
}
});
},
/**
* Open a file to edit in the Scratchpad.
*/
openFile: function SP_openFile()
{
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("openFile.title"),
Ci.nsIFilePicker.modeOpen);
fp.defaultString = "";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
document.title = this.filename = fp.file.path;
this.importFromFile(fp.file);
}
},
/**
* Save the textbox content to the currently open file.
*/
saveFile: function SP_saveFile()
{
if (!this.filename) {
return this.saveFileAs();
}
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
file.initWithPath(this.filename);
this.exportToFile(file, true);
},
/**
* Save the textbox content to a new file.
*/
saveFileAs: function SP_saveFileAs()
{
let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker);
fp.init(window, this.strings.GetStringFromName("saveFileAs"),
Ci.nsIFilePicker.modeSave);
fp.defaultString = "scratchpad.js";
if (fp.show() != Ci.nsIFilePicker.returnCancel) {
document.title = this.filename = fp.file.path;
this.exportToFile(fp.file, true);
}
},
/**
* Open the Error Console.
*/
openErrorConsole: function SP_openErrorConsole()
{
this.browserWindow.toJavaScriptConsole();
},
/**
* Open the Web Console.
*/
openWebConsole: function SP_openWebConsole()
{
if (!this.browserWindow.HUDConsoleUI.getOpenHUD()) {
this.browserWindow.HUDConsoleUI.toggleHUD();
}
this.browserWindow.focus();
},
/**
* Set the current execution context to be the active tab content window.
*/
setContentContext: function SP_setContentContext()
{
let content = document.getElementById("sp-menu-content");
document.getElementById("sp-menu-browser").removeAttribute("checked");
content.setAttribute("checked", true);
this.executionContext = SCRATCHPAD_CONTEXT_CONTENT;
this.statusbarStatus.label = content.getAttribute("label");
this.resetContext();
},
/**
* Set the current execution context to be the most recent chrome window.
*/
setBrowserContext: function SP_setBrowserContext()
{
let browser = document.getElementById("sp-menu-browser");
document.getElementById("sp-menu-content").removeAttribute("checked");
browser.setAttribute("checked", true);
this.executionContext = SCRATCHPAD_CONTEXT_BROWSER;
this.statusbarStatus.label = browser.getAttribute("label");
this.resetContext();
},
/**
* Reset the cached Cu.Sandbox object for the current context.
*/
resetContext: function SP_resetContext()
{
this._chromeSandbox = null;
this._contentSandbox = null;
this._previousWindow = null;
this._previousBrowser = null;
this._previousLocation = null;
},
/**
* Gets the ID of the outer window of the given DOM window object.
*
* @param nsIDOMWindow aWindow
* @return integer
* the outer window ID
*/
getWindowId: function SP_getWindowId(aWindow)
{
return aWindow.QueryInterface(Ci.nsIInterfaceRequestor).
getInterface(Ci.nsIDOMWindowUtils).outerWindowID;
},
/**
* The Scratchpad window DOMContentLoaded event handler.
*/
onLoad: function SP_onLoad()
{
let chromeContextMenu = document.getElementById("sp-menu-browser");
let errorConsoleMenu = document.getElementById("sp-menu-errorConsole");
let errorConsoleCommand = document.getElementById("sp-cmd-errorConsole");
let chromeContextCommand = document.getElementById("sp-cmd-browserContext");
let chrome = Services.prefs.getBoolPref(DEVTOOLS_CHROME_ENABLED, true);
if (chrome) {
chromeContextMenu.removeAttribute("hidden");
errorConsoleMenu.removeAttribute("hidden");
errorConsoleCommand.removeAttribute("disabled");
chromeContextCommand.removeAttribute("disabled");
}
let tabsize = Services.prefs.getIntPref(PREF_TABSIZE, 2);
if (tabsize < 1) {
// tabsize is invalid, clear back to the default value.
Services.prefs.clearUserPref(PREF_TABSIZE);
tabsize = Services.prefs.getIntPref(PREF_TABSIZE, 2);
}
let expandtab = Services.prefs.getBoolPref(PREF_EXPANDTAB, true);
this._tabCharacter = expandtab ? (new Array(tabsize + 1)).join(" ") : "\t";
this.textbox.style.MozTabSize = tabsize;
// Force LTR direction (otherwise the textbox inherits the locale direction)
this.textbox.style.direction = "ltr";
this.textbox.style.border = "none";
this.insertIntro();
// Make the Tab key work.
this.textbox.addEventListener("keypress", this.onKeypress.bind(this), false);
this.textbox.focus();
},
/**
* The textbox keypress event handler which allows users to indent code using
* the Tab key.
*
* @param nsIDOMEvent aEvent
*/
onKeypress: function SP_onKeypress(aEvent)
{
if (aEvent.keyCode == aEvent.DOM_VK_TAB) {
this.insertTextAtCaret(this._tabCharacter);
aEvent.preventDefault();
}
},
/**
* Insert text at the current caret location.
*
* @param string aText
*/
insertTextAtCaret: function SP_insertTextAtCaret(aText)
{
let firstPiece = this.textbox.value.substring(0, this.textbox.selectionStart);
let lastPiece = this.textbox.value.substring(this.textbox.selectionEnd);
this.textbox.value = firstPiece + aText + lastPiece;
let newCaretPosition = firstPiece.length + aText.length;
this.selectRange(newCaretPosition, newCaretPosition);
},
};
XPCOMUtils.defineLazyGetter(Scratchpad, "strings", function () {
return Services.strings.createBundle(SCRATCHPAD_L10N);
});
addEventListener("DOMContentLoaded", Scratchpad.onLoad.bind(Scratchpad), false);

352
communicator/components/devtools/content/scratchpad/scratchpad.xul

@ -0,0 +1,352 @@
<?xml version="1.0"?>
<!-- ***** BEGIN LICENSE BLOCK *****
- Version: MPL 1.1/GPL 2.0/LGPL 2.1
-
- The contents of this file are subject to the Mozilla Public License Version
- 1.1 (the "License"); you may not use this file except in compliance with
- the License. You may obtain a copy of the License at
- http://www.mozilla.org/MPL/
-
- Software distributed under the License is distributed on an "AS IS" basis,
- WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- for the specific language governing rights and limitations under the
- License.
-
- The Original Code is Scratchpad.
-
- The Initial Developer of the Original Code is
- The Mozilla Foundation.
- Portions created by the Initial Developer are Copyright (C) 2011
- the Initial Developer. All Rights Reserved.
-
- Contributor(s):
- Rob Campbell <robcee@mozilla.com> (original author)
- Mihai Sucan <mihai.sucan@gmail.com>
- Erik Vold <erikvvold@gmail.com>
-
- Alternatively, the contents of this file may be used under the terms of
- either the GNU General Public License Version 2 or later (the "GPL"), or
- the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- in which case the provisions of the GPL or the LGPL are applicable instead
- of those above. If you wish to allow use of your version of this file only
- under the terms of either the GPL or the LGPL, and not to allow others to
- use your version of this file under the terms of the MPL, indicate your
- decision by deleting the provisions above and replace them with the notice
- and other provisions required by the GPL or the LGPL. If you do not delete
- the provisions above, a recipient may use your version of this file under
- the terms of any one of the MPL, the GPL or the LGPL.
-
- ***** END LICENSE BLOCK ***** -->
<!DOCTYPE window [
<!ENTITY % scratchpadDTD SYSTEM "chrome://communicator/locale/devtools/scratchpad.dtd" >
%scratchpadDTD;
]>
<?xml-stylesheet href="chrome://communicator/skin/communicator.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<window id="main-window"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
title="&window.title;"
windowtype="devtools:scratchpad"
screenX="4" screenY="4"
width="640" height="480"
persist="screenX screenY width height sizemode">
<script type="application/javascript" src="chrome://global/content/globalOverlay.js"/>
<script type="application/javascript" src="chrome://communicator/content/devtools/scratchpad.js"/>
<commandset id="editMenuCommands"/>
<commandset id="sp-commandset">
<command id="sp-cmd-newWindow" oncommand="Scratchpad.openScratchpad();"/>
<command id="sp-cmd-openFile" oncommand="Scratchpad.openFile();"/>
<command id="sp-cmd-save" oncommand="Scratchpad.saveFile();"/>
<command id="sp-cmd-saveas" oncommand="Scratchpad.saveFileAs();"/>
<!-- TODO: bug 650340 - implement printFile()
<command id="sp-cmd-printFile" oncommand="Scratchpad.printFile();" disabled="true"/>
-->
<command id="sp-cmd-close" oncommand="window.close();"/>
<command id="sp-cmd-run" oncommand="Scratchpad.run();"/>
<command id="sp-cmd-inspect" oncommand="Scratchpad.inspect();"/>
<command id="sp-cmd-display" oncommand="Scratchpad.display();"/>
<command id="sp-cmd-contentContext" oncommand="Scratchpad.setContentContext();"/>
<command id="sp-cmd-browserContext" oncommand="Scratchpad.setBrowserContext();" disabled="true"/>
<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();"/>
</commandset>
<keyset id="sp-keyset">
<key id="sp-key-window"
key="&newWindowCmd.commandkey;"
command="sp-cmd-newWindow"
modifiers="accel"/>
<key id="sp-key-open"
key="&openFileCmd.commandkey;"
command="sp-cmd-openFile"
modifiers="accel"/>
<key id="sp-key-save"
key="&saveFileCmd.commandkey;"
command="sp-cmd-save"
modifiers="accel"/>
<key id="sp-key-close"
key="&closeCmd.key;"
command="sp-cmd-close"
modifiers="accel"/>
<!-- TODO: bug 650340 - implement printFile
<key id="sp-key-printFile"
key="&printCmd.commandkey;"
command="sp-cmd-printFile"
modifiers="accel"/>
-->
<key id="key_cut"
key="&cutCmd.key;"
modifiers="accel"/>
<key id="key_copy"
key="&copyCmd.key;"
modifiers="accel"/>
<key id="key_paste"
key="&pasteCmd.key;"
modifiers="accel"/>
<key id="key_selectAll" key="&selectAllCmd.key;" modifiers="accel"/>
<key id="key_undo" key="&undoCmd.key;" modifiers="accel"/>
<key id="key_redo" key="&undoCmd.key;" modifiers="accel,shift"/>
<key id="sp-key-run"
key="&run.key;"
command="sp-cmd-run"
modifiers="accel"/>
<!--
<key id="sp-key-inspect"
key="&inspect.key;"
command="sp-cmd-inspect"
modifiers="accel"/>
<key id="sp-key-display"
key="&display.key;"
command="sp-cmd-display"
modifiers="accel"/>
-->
<key id="sp-key-errorConsole"
key="&errorConsoleCmd.commandkey;"
command="sp-cmd-errorConsole"
modifiers="accel,shift"/>
<key id="sp-key-webConsole"
key="&webConsoleCmd.commandkey;"
command="sp-cmd-webConsole"
modifiers="accel,shift"/>
</keyset>
<menubar id="sp-menubar" xpfe="false">
<menu id="sp-file-menu" label="&fileMenu.label;"
accesskey="&fileMenu.accesskey;">
<menupopup id="sp-menu-filepopup">
<menuitem id="sp-menu-newscratchpad"
label="&newWindowCmd.label;"
accesskey="&newWindowCmd.accesskey;"
key="sp-key-window"
command="sp-cmd-newWindow"/>
<menuseparator/>
<menuitem id="sp-menu-open"
label="&openFileCmd.label;"
command="sp-cmd-openFile"
key="sp-key-open"
accesskey="&openFileCmd.accesskey;"/>
<menuitem id="sp-menu-save"
label="&saveFileCmd.label;"
accesskey="&saveFileCmd.accesskey;"
key="sp-key-save"
command="sp-cmd-save"/>
<menuitem id="sp-menu-saveas"
label="&saveFileAsCmd.label;"
accesskey="&saveFileAsCmd.accesskey;"
command="sp-cmd-saveas"/>
<menuseparator/>
<!-- TODO: bug 650340 - implement printFile
<menuitem id="sp-menu-print"
label="&printCmd.label;"
accesskey="&printCmd.accesskey;"
command="sp-cmd-printFile"/>
<menuseparator/>
-->
<menuitem id="sp-menu-close"
label="&closeCmd.label;"
key="sp-key-close"
accesskey="&closeCmd.accesskey;"
command="sp-cmd-close"/>
</menupopup>
</menu>
<menu id="sp-edit-menu" label="&editMenu.label;"
accesskey="&editMenu.accesskey;">
<menupopup id="sp-menu_editpopup">
<menuitem id="sp-menu-undo"
label="&undoCmd.label;"
key="key_undo"
accesskey="&undoCmd.accesskey;"
disabled="true"
command="cmd_undo"/>
<menuitem id="sp-menu-redo"
label="&redoCmd.label;"
key="key_redo"
disabled="true"
accesskey="&redoCmd.accesskey;"
command="cmd_redo"/>
<menuseparator/>
<menuitem id="sp-menu-cut"
label="&cutCmd.label;"
key="key_cut"
accesskey="&cutCmd.accesskey;"
command="cmd_cut"/>
<menuitem id="sp-menu-copy"
label="&copyCmd.label;"
key="key_copy"
accesskey="&copyCmd.accesskey;"
command="cmd_copy"/>
<menuitem id="sp-menu-paste"
label="&pasteCmd.label;"
key="key_paste"
accesskey="&pasteCmd.accesskey;"
command="cmd_paste"/>
<menuseparator/>
<menuitem id="sp-menu-selectAll"
label="&selectAllCmd.label;"
key="key_selectAll"
accesskey="&selectAllCmd.accesskey;"
command="cmd_selectAll"/>
<!-- TODO: bug 650345 - implement search and replace
<menuitem id="sp-menu-find"
label="&findOnCmd.label;"
accesskey="&findOnCmd.accesskey;"
key="key_find"
disabled="true"
command="cmd_find"/>
<menuitem id="sp-menu-findAgain"
label="&findAgainCmd.label;"
accesskey="&findAgainCmd.accesskey;"
key="key_findAgain"
disabled="true"
command="cmd_findAgain"/>
<menuseparator id="sp-execute-separator"/>
-->
</menupopup>
</menu>
<menu id="sp-execute-menu" label="&executeMenu.label;"
accesskey="&executeMenu.accesskey;">
<menupopup id="sp-menu_executepopup">
<menuitem id="sp-text-run"
label="&run.label;"
accesskey="&run.accesskey;"
key="sp-key-run"
command="sp-cmd-run"/>
<!--
<menuitem id="sp-text-inspect"
label="&inspect.label;"
accesskey="&inspect.accesskey;"
key="sp-key-inspect"
command="sp-cmd-inspect"/>
<menuitem id="sp-text-display"
label="&display.label;"
accesskey="&display.accesskey;"
key="sp-key-display"
command="sp-cmd-display"/>
-->
</menupopup>
</menu>
<menu id="sp-environment-menu"
label="&environmentMenu.label;"
accesskey="&environmentMenu.accesskey;">
<menupopup id="sp-menu-environment">
<menuitem id="sp-menu-content"
label="&contentContext.label;"
accesskey="&contentContext.accesskey;"
command="sp-cmd-contentContext"
checked="true"
type="radio"/>
<menuitem id="sp-menu-browser" hidden="true"
command="sp-cmd-browserContext"
label="&browserContext.label;"
accesskey="&browserContext.accesskey;"
type="radio"/>
<menuseparator/>
<menuitem id="sp-menu-resetContext"
command="sp-cmd-resetContext"
label="&resetContext.label;"
accesskey="&resetContext.accesskey;"/>
</menupopup>
</menu>
<menu id="sp-tools-menu"
label="&toolsMenu.label;"
accesskey="&toolsMenu.accesskey;">
<menupopup id="sp-menu-tools">
<menuitem id="sp-menu-errorConsole" hidden="true"
label="&errorConsoleCmd.label;"
accesskey="&errorConsoleCmd.accesskey;"
key="sp-key-errorConsole"
command="sp-cmd-errorConsole"/>
<!--
<menuitem id="sp-menu-webConsole"
label="&webConsoleCmd.label;"
accesskey="&webConsoleCmd.accesskey;"
key="sp-key-webConsole"
command="sp-cmd-webConsole"/>
-->
</menupopup>
</menu>
</menubar>
<popupset id="scratchpad-popups">
<menupopup id="scratchpad-text-popup">
<menuitem id="menu_cut"/>
<menuitem id="menu_copy"/>
<menuitem id="menu_paste"/>
<menuitem id="menu_delete"/>
<menuseparator/>
<menuitem id="menu_selectAll"/>
<menuseparator/>
<menuitem id="sp-text-run"
label="&run.label;"
accesskey="&run.accesskey;"
key="sp-key-run"
command="sp-cmd-run"/>
<!--
<menuitem id="sp-text-inspect"
label="&inspect.label;"
accesskey="&inspect.accesskey;"
key="sp-key-inspect"
command="sp-cmd-inspect"/>
<menuitem id="sp-text-display"
label="&display.label;"
accesskey="&display.accesskey;"
key="sp-key-display"
command="sp-cmd-display"/>
-->
</menupopup>
</popupset>
<textbox id="scratchpad-textbox"
class="monospace"
multiline="true"
flex="1"
context="scratchpad-text-popup"
placeholder="&textbox.placeholder1;" />
<statusbar id="scratchpad-statusbar" align="end">
<statusbarpanel id="scratchpad-status"
label="&contentContext.label;"
class="statusbarpanel-iconic-text"/>
<spacer flex="1"/>
</statusbar>
</window>

8
communicator/components/devtools/devtools-prefs.js

@ -0,0 +1,8 @@
/* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
pref("devtools.chrome.enabled", true);
pref("devtools.editor.tabsize", 2);
pref("devtools.editor.expandtab", true);

14
communicator/components/devtools/jar.mn

@ -0,0 +1,14 @@
# 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/.
comm.jar:
content/communicator/devtools/devtoolsOverlay.js (content/devtoolsOverlay.js)
content/communicator/devtools/devtoolsOverlay.xul (content/devtoolsOverlay.xul)
content/communicator/devtools/scratchpad.js (content/scratchpad/scratchpad.js)
content/communicator/devtools/scratchpad.xul (content/scratchpad/scratchpad.xul)
en-US.jar:
locale/en-US/communicator/devtools/devtoolsOverlay.dtd (locale/devtoolsOverlay.dtd)
locale/en-US/communicator/devtools/scratchpad.dtd (locale/scratchpad.dtd)
locale/en-US/communicator/devtools/scratchpad.properties (locale/scratchpad.properties)

6
communicator/components/devtools/locale/devtoolsOverlay.dtd

@ -0,0 +1,6 @@
<!-- 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/. -->
<!ENTITY scratchpad.label "Scratchpad">

123
communicator/components/devtools/locale/scratchpad.dtd

@ -0,0 +1,123 @@
<!-- LOCALIZATION NOTE : FILE This file contains the Scratchpad window strings -->
<!-- LOCALIZATION NOTE : FILE Do not translate commandkeys -->
<!-- LOCALIZATION NOTE (scratchpad.title):
- The Scratchpad is intended to provide a simple text editor for creating
- and evaluating bits of JavaScript code for the purposes of function
- prototyping, experimentation and convenient scripting.
-
- It's quite possible that you won't have a good analogue for the word
- "Scratchpad" in your locale. You should feel free to find a close
- approximation to it or choose a word (or words) that means
- "simple discardable text editor". -->
<!ENTITY window.title "Scratchpad">
<!ENTITY fileMenu.label "File">
<!ENTITY fileMenu.accesskey "F">
<!ENTITY newWindowCmd.label "New Window">
<!ENTITY newWindowCmd.accesskey "N">
<!ENTITY newWindowCmd.commandkey "n">
<!ENTITY openFileCmd.label "Open File…">
<!ENTITY openFileCmd.accesskey "O">
<!ENTITY openFileCmd.commandkey "o">
<!ENTITY saveFileCmd.label "Save">
<!ENTITY saveFileCmd.accesskey "S">
<!ENTITY saveFileCmd.commandkey "s">
<!ENTITY saveFileAsCmd.label "Save As…">
<!ENTITY saveFileAsCmd.accesskey "A">
<!ENTITY closeCmd.label "Close">
<!ENTITY closeCmd.key "W">
<!ENTITY closeCmd.accesskey "C">
<!ENTITY editMenu.label "Edit">
<!ENTITY editMenu.accesskey "E">
<!ENTITY undoCmd.label "Undo">
<!ENTITY undoCmd.key "Z">
<!ENTITY undoCmd.accesskey "U">
<!ENTITY redoCmd.label "Redo">
<!ENTITY redoCmd.key "Y">
<!ENTITY redoCmd.accesskey "R">
<!ENTITY cutCmd.label "Cut">
<!ENTITY cutCmd.key "X">
<!ENTITY cutCmd.accesskey "t">
<!ENTITY copyCmd.label "Copy">
<!ENTITY copyCmd.key "C">
<!ENTITY copyCmd.accesskey "C">
<!ENTITY pasteCmd.label "Paste">
<!ENTITY pasteCmd.key "V">
<!ENTITY pasteCmd.accesskey "P">
<!ENTITY selectAllCmd.label "Select All">
<!ENTITY selectAllCmd.key "A">
<!ENTITY selectAllCmd.accesskey "A">
<!ENTITY run.label "Run">
<!ENTITY run.accesskey "R">
<!ENTITY run.key "r">
<!ENTITY inspect.label "Inspect">
<!ENTITY inspect.accesskey "I">
<!ENTITY inspect.key "i">
<!ENTITY display.label "Display">
<!ENTITY display.accesskey "D">
<!ENTITY display.key "l">
<!-- LOCALIZATION NOTE (environmentMenu.label, accesskey): This menu item was
- renamed from "Context" to avoid confusion with the right-click context
- menu in the text area. It refers to the JavaScript Environment (or context)
- the user is evaluating against. I.e., Content (current tab) or Chrome
- (browser).
-->
<!ENTITY environmentMenu.label "Environment">
<!ENTITY environmentMenu.accesskey "N">
<!ENTITY contentContext.label "Content">
<!ENTITY contentContext.accesskey "C">
<!-- LOCALIZATION NOTE (browserContext.label, accesskey): This menu item is used
- to select an execution environment for the browser window itself as opposed
- to content. This is a feature for browser and addon developers and only
- enabled via the devtools.chrome.enabled preference. Formerly, this label
- was called "Chrome".
-->
<!ENTITY browserContext.label "Browser">
<!ENTITY browserContext.accesskey "B">
<!-- LOCALIZATION NOTE (resetContext.label): This command allows the developer
- to reset/clear the global object of the environment where the code executes.
-->
<!ENTITY resetContext.label "Reset">
<!ENTITY resetContext.accesskey "R">
<!ENTITY executeMenu.label "Execute">
<!ENTITY executeMenu.accesskey "X">
<!ENTITY toolsMenu.label "Tools">
<!ENTITY toolsMenu.accesskey "T">
<!ENTITY errorConsoleCmd.label "Error Console">
<!ENTITY errorConsoleCmd.accesskey "C">
<!ENTITY errorConsoleCmd.commandkey "j">
<!ENTITY webConsoleCmd.label "Web Console">
<!ENTITY webConsoleCmd.accesskey "W">
<!ENTITY webConsoleCmd.commandkey "k">
<!-- LOCALIZATION NOTE (textbox.placeholder1): This is some placeholder text
- that appears when the Scratchpad's text area is empty and unfocused.
- It should be a one-line JavaScript comment, i.e., preceded by '//'
-->
<!ENTITY textbox.placeholder1 "// Enter some JavaScript, select it, right click and select Run, Inspect or Display.">

35
communicator/components/devtools/locale/scratchpad.properties

@ -0,0 +1,35 @@
# LOCALIZATION NOTE (propertyPanel.updateButton.label): Used in the Property
# Panel that is opened by the Scratchpad window when inspecting an object. This
# is the Update button label.
propertyPanel.updateButton.label=Update
propertyPanel.updateButton.accesskey=U
# LOCALIZATION NOTE (export.fileOverwriteConfirmation): This is displayed when
# the user attempts to save to an already existing file.
export.fileOverwriteConfirmation=File exists. Overwrite?
# LOCALIZATION NOTE (browserWindow.unavailable): This error message is shown
# when Scratchpad does not find any recently active window of navigator:browser
# type.
browserWindow.unavailable=Scratchpad cannot find any browser window to execute the code in.
# LOCALIZATION NOTE (openFile.title): This is the file picker title, when you
# open a file from Scratchpad.
openFile.title=Open File
# LOCALIZATION NOTE (openFile.failed): This is the message displayed when file
# open fails.
openFile.failed=Failed to read the file.
# LOCALIZATION NOTE (saveFileAs): This is the file picker title, when you save
# a file in Scratchpad.
saveFileAs=Save File As
# LOCALIZATION NOTE (saveFile.failed): This is the message displayed when file
# save fails.
saveFile.failed=The file save operation failed.
# LOCALIZATION NOTE (scratchpadIntro): This is a multi-line comment explaining
# how to use the Scratchpad. Note that this should be a valid JavaScript
# comment inside /* and */.
scratchpadIntro=/*\n * This is a JavaScript Scratchpad.\n *\n * Enter some JavaScript, then Right Click or choose from the Execute Menu:\n * 1. Run to evaluate the selected text,\n * 2. Inspect to bring up an Object Inspector on the result, or,\n * 3. Display to insert the result in a comment after the selection.\n */\n\n

612
communicator/components/devtools/modules/PropertyPanel.jsm

@ -0,0 +1,612 @@
/* -*- Mode: js2; js2-basic-offset: 2; indent-tabs-mode: nil; -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is DevTools (HeadsUpDisplay) Console Code
*
* The Initial Developer of the Original Code is
* the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Rob Campbell <rcampbell@mozilla.com>
* Julian Viereck <jviereck@mozilla.com>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
var EXPORTED_SYMBOLS = ["PropertyPanel", "PropertyTreeView",
"namesAndValuesOf", "isNonNativeGetter"];
///////////////////////////////////////////////////////////////////////////
//// Helper for PropertyTreeView
const TYPE_OBJECT = 0, TYPE_FUNCTION = 1, TYPE_ARRAY = 2, TYPE_OTHER = 3;
/**
* Figures out the type of aObject and the string to display in the tree.
*
* @param object aObject
* The object to operate on.
* @returns object
* A object with the form:
* {
* type: TYPE_OBJECT || TYPE_FUNCTION || TYPE_ARRAY || TYPE_OTHER,
* display: string for displaying the object in the tree
* }
*/
function presentableValueFor(aObject)
{
if (aObject === null || aObject === undefined) {
return {
type: TYPE_OTHER,
display: aObject === undefined ? "undefined" : "null"
};
}
let presentable;
switch (aObject.constructor && aObject.constructor.name) {
case "Array":
return {
type: TYPE_ARRAY,
display: "Array"
};
case "String":
return {
type: TYPE_OTHER,
display: "\"" + aObject + "\""
};
case "Date":
case "RegExp":
case "Number":
case "Boolean":
return {
type: TYPE_OTHER,
display: aObject
};
case "Iterator":
return {
type: TYPE_OTHER,
display: "Iterator"
};
case "Function":
presentable = aObject.toString();
return {
type: TYPE_FUNCTION,
display: presentable.substring(0, presentable.indexOf(')') + 1)
};
default:
presentable = aObject.toString();
let m = /^\[object (\S+)\]/.exec(presentable);
try {
if (typeof aObject == "object" && typeof aObject.next == "function" &&
m && m[1] == "Generator") {
return {
type: TYPE_OTHER,
display: m[1]
};
}
}
catch (ex) {
// window.history.next throws in the typeof check above.
return {
type: TYPE_OBJECT,
display: m ? m[1] : "Object"
};