author | Ehsan Akhgari <ehsan@mozilla.com> |
Wed, 02 May 2012 16:20:02 -0400 | |
changeset 92775 | 24a6a53c714a06f4dd094d3a8a881c24a08c4cf5 |
parent 92606 | 0f8ea3826bf79f3b6c09b4da14abdd76200004ff |
child 92776 | 89346604e75958d2f63e0a9e4042edfa264b1964 |
push id | 22586 |
push user | eakhgari@mozilla.com |
push date | Wed, 02 May 2012 20:22:55 +0000 |
treeherder | mozilla-central@89346604e759 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 15.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/tests/mochitest/tree/test_dochierarchy.html +++ b/accessible/tests/mochitest/tree/test_dochierarchy.html @@ -26,17 +26,17 @@ getAccessible(window.parent.document, [nsIAccessibleDocument]) : getAccessible(document, [nsIAccessibleDocument]); var testDoc = getAccessible(document, [nsIAccessibleDocument]); var iframeDoc = getAccessible("iframe").firstChild. QueryInterface(nsIAccessibleDocument); is(root.parentDocument, null, "Wrong parent document of root accessible"); - is(root.childDocumentCount, SEAMONKEY ? 1 : 3, + is(root.childDocumentCount, 1, "Wrong child document count of root accessible"); is(root.getChildDocumentAt(0), tabDoc, "Wrong child document at index 0 of root accessible"); is(tabDoc.parentDocument, root, "Wrong parent document of tab document"); is(tabDoc.childDocumentCount, 1, "Wrong child document count of tab document");
--- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1040,40 +1040,32 @@ pref("services.sync.prefs.sync.security. pref("services.sync.prefs.sync.signon.rememberSignons", true); pref("services.sync.prefs.sync.spellchecker.dictionary", true); pref("services.sync.prefs.sync.xpinstall.whitelist.required", true); #endif // Disable the error console pref("devtools.errorconsole.enabled", false); -// Enable the developer toolbar -pref("devtools.toolbar.enabled", false); - // Enable the Inspector pref("devtools.inspector.enabled", true); pref("devtools.inspector.htmlHeight", 112); pref("devtools.inspector.htmlPanelOpen", false); pref("devtools.inspector.sidebarOpen", false); pref("devtools.inspector.activeSidebar", "ruleview"); // Enable the Layout View pref("devtools.layoutview.enabled", false); pref("devtools.layoutview.open", false); // Enable the Debugger pref("devtools.debugger.enabled", false); -pref("devtools.debugger.remote-enabled", false); -pref("devtools.debugger.remote-host", "localhost"); -pref("devtools.debugger.remote-port", 6000); // The default Debugger UI height pref("devtools.debugger.ui.height", 250); -pref("devtools.debugger.ui.remote-win.width", 900); -pref("devtools.debugger.ui.remote-win.height", 400); // Enable the style inspector pref("devtools.styleinspector.enabled", true); // Enable the Tilt inspector pref("devtools.tilt.enabled", true); pref("devtools.tilt.intro_transition", true); pref("devtools.tilt.outro_transition", true); @@ -1086,24 +1078,18 @@ pref("devtools.scratchpad.enabled", true // Enable the Style Editor. pref("devtools.styleeditor.enabled", true); pref("devtools.styleeditor.transitions", true); // Enable tools for Chrome development. pref("devtools.chrome.enabled", false); -// Display the introductory text -pref("devtools.gcli.hideIntro", false); - -// How eager are we to show help: never=1, sometimes=2, always=3 -pref("devtools.gcli.eagerHelper", 2); - -// Do we allow the 'pref set' command -pref("devtools.gcli.allowSet", false); +// Disable the GCLI enhanced command line. +pref("devtools.gcli.enable", false); // The last Web Console height. This is initially 0 which means that the Web // Console will use the default height next time it shows. // Change to -1 if you do not want the Web Console to remember its last height. pref("devtools.hud.height", 0); // Remember the Web Console position. Possible values: // above - above the web page,
--- a/browser/base/content/browser-appmenu.inc +++ b/browser/base/content/browser-appmenu.inc @@ -171,45 +171,34 @@ <menuitem id="appmenu_printSetup" label="&printSetupCmd.label;" command="cmd_pageSetup"/> </menupopup> </splitmenu> <menuseparator class="appmenu-menuseparator"/> <menu id="appmenu_webDeveloper" label="&appMenuWebDeveloper.label;"> - <menupopup id="appmenu_webDeveloper_popup"> - <menuitem id="appmenu_devToolbar" - type="checkbox" - autocheck="false" - hidden="true" - label="&devToolbarMenu.label;" - command="Tools:DevToolbar" - key="key_devToolbar"/> + <menupopup id="appmenu_webDeveloper_popup" + onpopupshowing="onWebDeveloperMenuShowing();"> <menuitem id="appmenu_webConsole" label="&webConsoleCmd.label;" type="checkbox" command="Tools:WebConsole" key="key_webConsole"/> <menuitem id="appmenu_pageInspect" hidden="true" label="&inspectMenu.label;" type="checkbox" command="Tools:Inspect" key="key_inspect"/> <menuitem id="appmenu_debugger" hidden="true" - type="checkbox" label="&debuggerMenu.label;" key="key_debugger" command="Tools:Debugger"/> - <menuitem id="appmenu_remoteDebugger" - hidden="true" - label="&remoteDebuggerMenu.label;" - command="Tools:RemoteDebugger"/> <menuitem id="appmenu_scratchpad" hidden="true" label="&scratchpad.label;" key="key_scratchpad" command="Tools:Scratchpad"/> <menuitem id="appmenu_styleeditor" hidden="true" label="&styleeditor.label;"
--- a/browser/base/content/browser-fullZoom.js +++ b/browser/base/content/browser-fullZoom.js @@ -220,17 +220,17 @@ var FullZoom = { * @param aBrowser * (optional) browser object displaying the document */ onLocationChange: function FullZoom_onLocationChange(aURI, aIsTabSwitch, aBrowser) { if (!aURI || (aIsTabSwitch && !this.siteSpecific)) return; // Avoid the cps roundtrip and apply the default/global pref. - if (aURI.spec == "about:blank") { + if (isBlankPageURL(aURI.spec)) { this._applyPrefToSetting(undefined, aBrowser); return; } let browser = aBrowser || gBrowser.selectedBrowser; // Media documents should always start at 1, and are not affected by prefs. if (!aIsTabSwitch && browser.contentDocument.mozSyntheticDocument) {
--- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -526,48 +526,36 @@ accesskey="&syncSyncNowItem.accesskey;" observes="sync-syncnow-state" oncommand="gSyncUI.doSync(event);"/> #endif <menuseparator id="devToolsSeparator"/> <menu id="webDeveloperMenu" label="&webDeveloperMenu.label;" accesskey="&webDeveloperMenu.accesskey;"> - <menupopup id="menuWebDeveloperPopup"> - <menuitem id="menu_devToolbar" - type="checkbox" - autocheck="false" - hidden="true" - label="&devToolbarMenu.label;" - accesskey="&devToolbarMenu.accesskey;" - key="key_devToolbar" - command="Tools:DevToolbar"/> + <menupopup id="menuWebDeveloperPopup" + onpopupshowing="onWebDeveloperMenuShowing();"> <menuitem id="webConsole" type="checkbox" label="&webConsoleCmd.label;" accesskey="&webConsoleCmd.accesskey;" key="key_webConsole" command="Tools:WebConsole"/> <menuitem id="menu_pageinspect" type="checkbox" hidden="true" label="&inspectMenu.label;" accesskey="&inspectMenu.accesskey;" key="key_inspect" command="Tools:Inspect"/> <menuitem id="menu_debugger" hidden="true" - type="checkbox" label="&debuggerMenu.label;" key="key_debugger" command="Tools:Debugger"/> - <menuitem id="menu_remoteDebugger" - hidden="true" - label="&remoteDebuggerMenu.label;" - command="Tools:RemoteDebugger"/> <menuitem id="menu_scratchpad" hidden="true" label="&scratchpad.label;" accesskey="&scratchpad.accesskey;" key="key_scratchpad" command="Tools:Scratchpad"/> <menuitem id="menu_styleeditor" hidden="true"
--- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -121,21 +121,19 @@ <command id="cmd_fullZoomReduce" oncommand="FullZoom.reduce()"/> <command id="cmd_fullZoomEnlarge" oncommand="FullZoom.enlarge()"/> <command id="cmd_fullZoomReset" oncommand="FullZoom.reset()"/> <command id="cmd_fullZoomToggle" oncommand="ZoomManager.toggleZoom();"/> <command id="Browser:OpenLocation" oncommand="openLocation();"/> <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/> <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/> - <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true"/> <command id="Tools:WebConsole" oncommand="HUDConsoleUI.toggleHUD();"/> <command id="Tools:Inspect" oncommand="InspectorUI.toggleInspectorUI();" disabled="true"/> <command id="Tools:Debugger" oncommand="DebuggerUI.toggleDebugger();" disabled="true"/> - <command id="Tools:RemoteDebugger" oncommand="DebuggerUI.toggleRemoteDebugger();" disabled="true"/> <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();" disabled="true"/> <command id="Tools:StyleEditor" oncommand="StyleEditor.openChrome();" disabled="true"/> <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/> <command id="Tools:Sanitize" oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/> <command id="Tools:PrivateBrowsing" oncommand="gPrivateBrowsingUI.toggleMode();"/> <command id="History:UndoCloseTab" oncommand="undoCloseTab();"/> <command id="History:UndoCloseWindow" oncommand="undoCloseWindow();"/> @@ -252,23 +250,16 @@ #ifdef XP_GNOME <key id="key_search2" key="&searchFocusUnix.commandkey;" command="Tools:Search" modifiers="accel"/> <key id="key_openDownloads" key="&downloadsUnix.commandkey;" command="Tools:Downloads" modifiers="accel,shift"/> #else <key id="key_openDownloads" key="&downloads.commandkey;" command="Tools:Downloads" modifiers="accel"/> #endif <key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/> <key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/> - <key id="key_devToolbar" key="&devToolbar.commandkey;" command="Tools:DevToolbar" -#ifdef XP_MACOSX - modifiers="accel,alt" -#else - modifiers="accel,shift" -#endif - /> <key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();" #ifdef XP_MACOSX modifiers="accel,alt" #else modifiers="accel,shift" #endif /> <key id="key_debugger" key="&debuggerMenu.commandkey;" command="Tools:Debugger"
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -174,22 +174,16 @@ XPCOMUtils.defineLazyGetter(this, "Popup return new tmp.PopupNotifications(gBrowser, document.getElementById("notification-popup"), document.getElementById("notification-popup-box")); } catch (ex) { Cu.reportError(ex); } }); -XPCOMUtils.defineLazyGetter(this, "DeveloperToolbar", function() { - let tmp = {}; - Cu.import("resource:///modules/devtools/DeveloperToolbar.jsm", tmp); - return new tmp.DeveloperToolbar(window, document.getElementById("developer-toolbar")); -}); - XPCOMUtils.defineLazyGetter(this, "InspectorUI", function() { let tmp = {}; Cu.import("resource:///modules/inspector.jsm", tmp); return new tmp.InspectorUI(window); }); XPCOMUtils.defineLazyGetter(this, "DebuggerUI", function() { let tmp = {}; @@ -1697,56 +1691,34 @@ function delayedStartup(isLoadingBlank, TabView.init(); setUrlAndSearchBarWidthForConditionalForwardButton(); window.addEventListener("resize", function resizeHandler(event) { if (event.target == window) setUrlAndSearchBarWidthForConditionalForwardButton(); }); - // Enable developer toolbar? - let devToolbarEnabled = gPrefService.getBoolPref("devtools.toolbar.enabled"); - if (devToolbarEnabled) { - document.getElementById("menu_devToolbar").hidden = false; - document.getElementById("Tools:DevToolbar").removeAttribute("disabled"); -#ifdef MENUBAR_CAN_AUTOHIDE - document.getElementById("appmenu_devToolbar").hidden = false; -#endif - } - // Enable Inspector? let enabled = gPrefService.getBoolPref("devtools.inspector.enabled"); if (enabled) { document.getElementById("menu_pageinspect").hidden = false; document.getElementById("Tools:Inspect").removeAttribute("disabled"); #ifdef MENUBAR_CAN_AUTOHIDE document.getElementById("appmenu_pageInspect").hidden = false; #endif - document.getElementById("developer-toolbar-inspector").hidden = false; } // Enable Debugger? let enabled = gPrefService.getBoolPref("devtools.debugger.enabled"); if (enabled) { document.getElementById("menu_debugger").hidden = false; document.getElementById("Tools:Debugger").removeAttribute("disabled"); #ifdef MENUBAR_CAN_AUTOHIDE document.getElementById("appmenu_debugger").hidden = false; #endif - document.getElementById("developer-toolbar-debugger").hidden = false; - } - - // Enable Remote Debugger? - let enabled = gPrefService.getBoolPref("devtools.debugger.remote-enabled"); - if (enabled) { - document.getElementById("menu_remoteDebugger").hidden = false; - document.getElementById("Tools:RemoteDebugger").removeAttribute("disabled"); -#ifdef MENUBAR_CAN_AUTOHIDE - document.getElementById("appmenu_remoteDebugger").hidden = false; -#endif } // Enable Error Console? // XXX Temporarily always-enabled, see bug 601201 let consoleEnabled = true || gPrefService.getBoolPref("devtools.errorconsole.enabled"); if (consoleEnabled) { document.getElementById("javascriptConsole").hidden = false; document.getElementById("key_errorConsole").removeAttribute("disabled"); @@ -9304,16 +9276,20 @@ var StyleEditor = { args.wrappedJSObject = args; let chromeWindow = Services.ww.openWindow(null, CHROME_URL, "_blank", CHROME_WINDOW_FLAGS, args); chromeWindow.focus(); return chromeWindow; } }; +function onWebDeveloperMenuShowing() { + document.getElementById("Tools:WebConsole").setAttribute("checked", HUDConsoleUI.getOpenHUD() != null); +} + XPCOMUtils.defineLazyGetter(window, "gShowPageResizers", function () { #ifdef XP_WIN // Only show resizers on Windows 2000 and XP let sysInfo = Components.classes["@mozilla.org/system-info;1"] .getService(Components.interfaces.nsIPropertyBag2); return parseFloat(sysInfo.getProperty("version")) < 6; #else
--- a/browser/base/content/browser.xul +++ b/browser/base/content/browser.xul @@ -1034,70 +1034,16 @@ <!-- registered tools go here --> </hbox> #ifndef XP_MACOSX <toolbarbutton id="highlighter-closebutton" oncommand="InspectorUI.closeInspectorUI(false);" tooltiptext="&inspectCloseButton.tooltiptext;"/> #endif </toolbar> - - <panel id="gcli-tooltip" - type="arrow" - noautofocus="true" - noautohide="true" - class="gcli-panel"> - <iframe id="gcli-tooltip-frame" - src="chrome://browser/content/devtools/gcliblank.xhtml" - flex="1"/> - </panel> - <panel id="gcli-output" - type="arrow" - noautofocus="true" - noautohide="true" - class="gcli-panel"> - <iframe id="gcli-output-frame" - src="chrome://browser/content/devtools/gcliblank.xhtml" - flex="1"/> - </panel> - - <toolbar id="developer-toolbar" - class="devtools-toolbar" - hidden="true"> -#ifdef XP_MACOSX - <toolbarbutton id="developer-toolbar-closebutton" - oncommand="DeveloperToolbar.hide();" - tooltiptext="&devToolbarCloseButton.tooltiptext;"/> -#endif - <stack class="gclitoolbar-stack-node" flex="1"> - <description class="gclitoolbar-prompt">»</description> - <description class="gclitoolbar-complete-node"/> - <textbox class="gclitoolbar-input-node" rows="1"/> - </stack> - <toolbarbutton id="developer-toolbar-webconsole" - label="&webConsoleButton.label;" - class="devtools-toolbarbutton" - command="Tools:WebConsole"/> - <toolbarbutton id="developer-toolbar-inspector" - label="&inspectorButton.label;" - class="devtools-toolbarbutton" - hidden="true" - command="Tools:Inspect"/> - <toolbarbutton id="developer-toolbar-debugger" - label="&scriptsButton.label;" - class="devtools-toolbarbutton" - hidden="true" - command="Tools:Debugger"/> -#ifndef XP_MACOSX - <toolbarbutton id="developer-toolbar-closebutton" - oncommand="DeveloperToolbar.hide();" - tooltiptext="&devToolbarCloseButton.tooltiptext;"/> -#endif - </toolbar> - <toolbar id="addon-bar" toolbarname="&addonBarCmd.label;" accesskey="&addonBarCmd.accesskey;" collapsed="true" class="toolbar-primary chromeclass-toolbar" context="toolbar-context-menu" toolboxid="navigator-toolbox" mode="icons" iconsize="small" defaulticonsize="small" lockiconsize="true" defaultset="addonbar-closebutton,spring,status-bar"
--- a/browser/devtools/debugger/DebuggerUI.jsm +++ b/browser/devtools/debugger/DebuggerUI.jsm @@ -40,137 +40,90 @@ * * ***** END LICENSE BLOCK ***** */ "use strict"; const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; -const DBG_XUL = "chrome://browser/content/debugger.xul"; -const REMOTE_PROFILE_NAME = "_remote-debug"; - -Cu.import("resource://gre/modules/devtools/dbg-server.jsm"); Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/FileUtils.jsm"); -Cu.import("resource://gre/modules/XPCOMUtils.jsm"); let EXPORTED_SYMBOLS = ["DebuggerUI"]; /** * Provides a simple mechanism of managing debugger instances per tab. * * @param nsIDOMWindow aWindow * The chrome window for which the DebuggerUI instance is created. */ function DebuggerUI(aWindow) { this.chromeWindow = aWindow; } DebuggerUI.prototype = { - /** - * Called by the DebuggerPane to update the Debugger toggle switches with the - * debugger state. - */ - refreshCommand: function DUI_refreshCommand() { - let selectedTab = this.chromeWindow.getBrowser().selectedTab; - let command = this.chromeWindow.document.getElementById("Tools:Debugger"); - - if (this.getDebugger(selectedTab) != null) { - command.setAttribute("checked", "true"); - } else { - command.removeAttribute("checked"); - } - }, /** * Starts a debugger for the current tab, or stops it if already started. * @return DebuggerPane if the debugger is started, null if it's stopped. */ toggleDebugger: function DUI_toggleDebugger() { let tab = this.chromeWindow.gBrowser.selectedTab; if (tab._scriptDebugger) { tab._scriptDebugger.close(); return null; } - return new DebuggerPane(this, tab); - }, - - /** - * Starts a remote debugger in a new process, or stops it if already started. - * @see DebuggerProcess.constructor - * @return DebuggerProcess if the debugger is started, null if it's stopped. - */ - toggleRemoteDebugger: function DUI_toggleRemoteDebugger(aOnClose, aOnRun) { - let win = this.chromeWindow; - - if (win._remoteDebugger) { - win._remoteDebugger.close(); - return null; - } - return new DebuggerProcess(win, aOnClose, aOnRun); + return new DebuggerPane(tab); }, /** * Get the debugger for a specified tab. * @return DebuggerPane if a debugger exists for the tab, null otherwise */ getDebugger: function DUI_getDebugger(aTab) { - return '_scriptDebugger' in aTab ? aTab._scriptDebugger : null; + return aTab._scriptDebugger; }, /** * Get the preferences associated with the debugger frontend. * @return object */ get preferences() { - return DebuggerPreferences; + return DebuggerUIPreferences; } }; /** * Creates a pane that will host the debugger. * * @param XULElement aTab * The tab in which to create the debugger. */ -function DebuggerPane(aDebuggerUI, aTab) { - this._globalUI = aDebuggerUI; +function DebuggerPane(aTab) { this._tab = aTab; - this._initServer(); this._create(); } DebuggerPane.prototype = { /** - * Initializes the debugger server. - */ - _initServer: function DP__initServer() { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - }, - - /** * Creates and initializes the widgets containing the debugger UI. */ _create: function DP__create() { this._tab._scriptDebugger = this; let gBrowser = this._tab.linkedBrowser.getTabBrowser(); let ownerDocument = gBrowser.parentNode.ownerDocument; this._splitter = ownerDocument.createElement("splitter"); this._splitter.setAttribute("class", "hud-splitter"); this._frame = ownerDocument.createElement("iframe"); - this._frame.height = DebuggerPreferences.height; + this._frame.height = DebuggerUIPreferences.height; this._nbox = gBrowser.getNotificationBox(this._tab.linkedBrowser); this._nbox.appendChild(this._splitter); this._nbox.appendChild(this._frame); this.close = this.close.bind(this); let self = this; @@ -181,43 +134,39 @@ DebuggerPane.prototype = { // Bind shortcuts for accessing the breakpoint methods in the debugger. let bkp = self.debuggerWindow.DebuggerController.Breakpoints; self.addBreakpoint = bkp.addBreakpoint; self.removeBreakpoint = bkp.removeBreakpoint; self.getBreakpoint = bkp.getBreakpoint; }, true); - this._frame.setAttribute("src", DBG_XUL); - - this._globalUI.refreshCommand(); + this._frame.setAttribute("src", "chrome://browser/content/debugger.xul"); }, /** * Closes the debugger, removing child nodes and event listeners. */ close: function DP_close() { if (!this._tab) { return; } - delete this._tab._scriptDebugger; + this._tab._scriptDebugger = null; this._tab = null; - DebuggerPreferences.height = this._frame.height; + DebuggerUIPreferences.height = this._frame.height; this._frame.removeEventListener("Debugger:Close", this.close, true); this._frame.removeEventListener("unload", this.close, true); this._nbox.removeChild(this._splitter); this._nbox.removeChild(this._frame); this._splitter = null; this._frame = null; this._nbox = null; - - this._globalUI.refreshCommand(); }, /** * Gets the debugger content window. * @return nsIDOMWindow if a debugger window exists, null otherwise */ get debuggerWindow() { return this._frame ? this._frame.contentWindow : null; @@ -232,122 +181,19 @@ DebuggerPane.prototype = { if (debuggerWindow) { return debuggerWindow.DebuggerController.Breakpoints.store; } return null; } }; /** - * Creates a process that will hold the remote debugger. - * - * @param function aOnClose - * Optional, a function called when the process exits. - * @param function aOnRun - * Optional, a function called when the process starts running. - * @param nsIDOMWindow aWindow - * The chrome window for which the remote debugger instance is created. + * Various debugger UI preferences (currently just the pane height). */ -function DebuggerProcess(aWindow, aOnClose, aOnRun) { - this._win = aWindow; - this._closeCallback = aOnClose; - this._runCallback = aOnRun; - this._initProfile(); - this._create(); -} - -DebuggerProcess.prototype = { - - /** - * Initializes the debugger server. - */ - _initServer: function RDP__initServer() { - if (!DebuggerServer.initialized) { - DebuggerServer.init(); - DebuggerServer.addBrowserActors(); - } - DebuggerServer.closeListener(); - DebuggerServer.openListener(DebuggerPreferences.remotePort, false); - }, - - /** - * Initializes a profile for the remote debugger process. - */ - _initProfile: function RDP__initProfile() { - let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] - .createInstance(Ci.nsIToolkitProfileService); - - let dbgProfileName; - try { - dbgProfileName = profileService.selectedProfile.name + REMOTE_PROFILE_NAME; - } catch(e) { - dbgProfileName = REMOTE_PROFILE_NAME; - Cu.reportError(e); - } - - this._dbgProfile = profileService.createProfile(null, null, dbgProfileName); - profileService.flush(); - }, - - /** - * Creates and initializes the profile & process for the remote debugger. - */ - _create: function RDP__create() { - this._win._remoteDebugger = this; - - let file = FileUtils.getFile("CurProcD", - [Services.appinfo.OS == "WINNT" ? "firefox.exe" - : "firefox-bin"]); - - let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess); - process.init(file); - - let args = [ - "-no-remote", "-P", this._dbgProfile.name, - "-chrome", DBG_XUL, - "-width", DebuggerPreferences.remoteWinWidth, - "-height", DebuggerPreferences.remoteWinHeight]; - - process.runwAsync(args, args.length, { observe: this.close.bind(this) }); - this._dbgProcess = process; - - if (typeof this._runCallback === "function") { - this._runCallback.call({}, this); - } - }, - - /** - * Closes the remote debugger, removing the profile and killing the process. - */ - close: function RDP_close() { - if (!this._win) { - return; - } - delete this._win._remoteDebugger; - this._win = null; - - if (this._dbgProcess.isRunning) { - this._dbgProcess.kill(); - } - if (this._dbgProfile) { - this._dbgProfile.remove(false); - } - if (typeof this._closeCallback === "function") { - this._closeCallback.call({}, this); - } - - this._dbgProcess = null; - this._dbgProfile = null; - } -}; - -/** - * Various debugger preferences. - */ -let DebuggerPreferences = { +let DebuggerUIPreferences = { /** * Gets the preferred height of the debugger pane. * @return number */ get height() { if (this._height === undefined) { this._height = Services.prefs.getIntPref("devtools.debugger.ui.height"); @@ -359,40 +205,8 @@ let DebuggerPreferences = { * Sets the preferred height of the debugger pane. * @param number value */ set height(value) { Services.prefs.setIntPref("devtools.debugger.ui.height", value); this._height = value; } }; - -/** - * Gets the preferred width of the remote debugger window. - * @return number - */ -XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteWinWidth", function() { - return Services.prefs.getIntPref("devtools.debugger.ui.remote-win.width"); -}); - -/** - * Gets the preferred height of the remote debugger window. - * @return number - */ -XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteWinHeight", function() { - return Services.prefs.getIntPref("devtools.debugger.ui.remote-win.height"); -}); - -/** - * Gets the preferred default remote debugging host. - * @return string - */ -XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remoteHost", function() { - return Services.prefs.getCharPref("devtools.debugger.remote-host"); -}); - -/** - * Gets the preferred default remote debugging port. - * @return number - */ -XPCOMUtils.defineLazyGetter(DebuggerPreferences, "remotePort", function() { - return Services.prefs.getIntPref("devtools.debugger.remote-port"); -});
--- a/browser/devtools/debugger/debugger-controller.js +++ b/browser/devtools/debugger/debugger-controller.js @@ -109,28 +109,29 @@ let DebuggerController = { DebuggerView.Properties.destroy(); DebuggerController.SourceScripts.disconnect(); DebuggerController.StackFrames.disconnect(); DebuggerController.ThreadState.disconnect(); this.dispatchEvent("Debugger:Unloaded"); this._disconnect(); - this._isRemote && this._quitApp(); }, /** * Initializes a debugger client and connects it to the debugger server, * wiring event handlers as necessary. */ _connect: function DC__connect() { - let transport = - this._isRemote ? debuggerSocketConnect(Prefs.remoteHost, Prefs.remotePort) - : DebuggerServer.connectPipe(); + if (!DebuggerServer.initialized) { + DebuggerServer.init(); + DebuggerServer.addBrowserActors(); + } + let transport = DebuggerServer.connectPipe(); let client = this.client = new DebuggerClient(transport); client.addListener("tabNavigated", this._onTabNavigated); client.addListener("tabDetached", this._onTabDetached); client.connect(function(aType, aTraits) { client.listTabs(function(aResponse) { let tab = aResponse.tabs[aResponse.selected]; @@ -215,41 +216,16 @@ let DebuggerController = { }); }); }.bind(this)); }.bind(this)); }, /** - * Returns true if this is a remote debugger instance. - * @return boolean - */ - get _isRemote() { - return !window.parent.content; - }, - - /** - * Attempts to quit the current process if allowed. - */ - _quitApp: function DC__quitApp() { - let canceled = Cc["@mozilla.org/supports-PRBool;1"] - .createInstance(Ci.nsISupportsPRBool); - - Services.obs.notifyObservers(canceled, "quit-application-requested", null); - - // Somebody canceled our quit request. - if (canceled.data) { - return; - } - - Services.startup.quit(Ci.nsIAppStartup.eAttemptQuit); - }, - - /** * Convenience method, dispatching a custom event. * * @param string aType * The name of the event. * @param string aDetail * The data passed when initializing the event. */ dispatchEvent: function DC_dispatchEvent(aType, aDetail) { @@ -489,71 +465,52 @@ StackFrames.prototype = { let thisVar = localScope.addVar("this"); thisVar.setGrip({ type: frame.this.type, class: frame.this.class }); this._addExpander(thisVar, frame.this); } - if (frame.environment) { - // Add nodes for every argument. - let variables = frame.environment.bindings.arguments; - for each (let variable in variables) { - let name = Object.getOwnPropertyNames(variable)[0]; - let paramVar = localScope.addVar(name); - let paramVal = variable[name].value; - paramVar.setGrip(paramVal); - this._addExpander(paramVar, paramVal); - } - - // Add nodes for every other variable in scope. - variables = frame.environment.bindings.variables; - for (let variable in variables) { - let paramVar = localScope.addVar(variable); - let paramVal = variables[variable].value; - paramVar.setGrip(paramVal); - this._addExpander(paramVar, paramVal); - } - - // If we already found 'arguments', we are done here. - if ("arguments" in frame.environment.bindings.variables) { - // Signal that variables have been fetched. - DebuggerController.dispatchEvent("Debugger:FetchedVariables"); - return; - } - } - - // Sometimes in call frames with arguments we don't get 'arguments' in the - // environment (bug 746601) and we have to construct it manually. Note, that - // in this case arguments.callee will be absent, even in the cases where it - // shouldn't be. if (frame.arguments && frame.arguments.length > 0) { // Add "arguments". let argsVar = localScope.addVar("arguments"); argsVar.setGrip({ type: "object", class: "Arguments" }); this._addExpander(argsVar, frame.arguments); - // Signal that variables have been fetched. - DebuggerController.dispatchEvent("Debugger:FetchedVariables"); + // Add variables for every argument. + let objClient = this.activeThread.pauseGrip(frame.callee); + objClient.getSignature(function SF_getSignature(aResponse) { + for (let i = 0, l = aResponse.parameters.length; i < l; i++) { + let param = aResponse.parameters[i]; + let paramVar = localScope.addVar(param); + let paramVal = frame.arguments[i]; + + paramVar.setGrip(paramVal); + this._addExpander(paramVar, paramVal); + } + + // Signal that call parameters have been fetched. + DebuggerController.dispatchEvent("Debugger:FetchedParameters"); + + }.bind(this)); } - }, /** - * Adds an 'onexpand' callback for a variable, lazily handling the addition of + * Adds a onexpand callback for a variable, lazily handling the addition of * new properties. */ _addExpander: function SF__addExpander(aVar, aObject) { // No need for expansion for null and undefined values, but we do need them // for frame.arguments which is a regular array. - if (!aVar || !aObject || typeof aObject !== "object" || + if (!aObject || typeof aObject !== "object" || (aObject.type !== "object" && !Array.isArray(aObject))) { return; } // Force the twisty to show up. aVar.forceShowArrow(); aVar.onexpand = this._addVarProperties.bind(this, aVar, aObject); }, @@ -724,27 +681,26 @@ SourceScripts.prototype = { this.activeThread.removeListener("scriptsadded", this._onScriptsAdded); this.activeThread.removeListener("scriptscleared", this._onScriptsCleared); }, /** * Handler for the debugger client's unsolicited newScript notification. */ _onNewScript: function SS__onNewScript(aNotification, aPacket) { - this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true); + this._addScript({ url: aPacket.url, startLine: aPacket.startLine }); }, /** * Handler for the thread client's scriptsadded notification. */ _onScriptsAdded: function SS__onScriptsAdded() { for each (let script in this.activeThread.cachedScripts) { - this._addScript(script, false); + this._addScript(script); } - DebuggerView.Scripts.commitScripts(); }, /** * Handler for the thread client's scriptscleared notification. */ _onScriptsCleared: function SS__onScriptsCleared() { DebuggerView.Scripts.empty(); }, @@ -787,70 +743,51 @@ SourceScripts.prototype = { let q = aUrl.indexOf('?'); if (q > -1) { return aUrl.slice(0, q); } return aUrl; }, /** - * Gets the prePath for a script URL. - * - * @param string aUrl - * The script url. - * @return string - * The script prePath if the url is valid, null otherwise. - */ - _getScriptPrePath: function SS__getScriptDomain(aUrl) { - try { - return Services.io.newURI(aUrl, null, null).prePath + "/"; - } catch (e) { - } - return null; - }, - - /** * Gets a unique, simplified label from a script url. * ex: a). ici://some.address.com/random/subrandom/ * b). ni://another.address.org/random/subrandom/page.html * c). san://interesting.address.gro/random/script.js * d). si://interesting.address.moc/random/another/script.js * => * a). subrandom/ * b). page.html * c). script.js * d). another/script.js * * @param string aUrl * The script url. * @param string aHref * The content location href to be used. If unspecified, it will - * default to the script url prepath. + * defalult to debugged panrent window location. * @return string * The simplified label. */ _getScriptLabel: function SS__getScriptLabel(aUrl, aHref) { let url = this._trimUrlQuery(aUrl); if (this._labelsCache[url]) { return this._labelsCache[url]; } - let content = window.parent.content; - let domain = content ? content.location.href : this._getScriptPrePath(aUrl); - - let href = aHref || domain; + let href = aHref || window.parent.content.location.href; let pathElements = url.split("/"); let label = pathElements.pop() || (pathElements.pop() + "/"); - // If the label as a leaf name is already present in the scripts list. + // if the label as a leaf name is alreay present in the scripts list if (DebuggerView.Scripts.containsLabel(label)) { label = url.replace(href.substring(0, href.lastIndexOf("/") + 1), ""); - // If the path/to/script is exactly the same, we're in different domains. + // if the path/to/script is exactly the same, we're in different domains if (DebuggerView.Scripts.containsLabel(label)) { label = url; } } return this._labelsCache[url] = label; }, @@ -858,26 +795,25 @@ SourceScripts.prototype = { * Clears the labels cache, populated by SS_getScriptLabel. * This should be done every time the content location changes. */ _clearLabelsCache: function SS__clearLabelsCache() { this._labelsCache = {}; }, /** - * Add the specified script to the list. - * - * @param object aScript - * The script object coming from the active thread. - * @param boolean aForceFlag - * True to force the script to be immediately added. + * Add the specified script to the list and display it in the editor if the + * editor is empty. */ - _addScript: function SS__addScript(aScript, aForceFlag) { - DebuggerView.Scripts.addScript( - this._getScriptLabel(aScript.url), aScript, aForceFlag); + _addScript: function SS__addScript(aScript) { + DebuggerView.Scripts.addScript(this._getScriptLabel(aScript.url), aScript); + + if (DebuggerView.editor.getCharCount() == 0) { + this.showScript(aScript); + } }, /** * Load the editor with the script text if available, otherwise fire an event * to load and display the script text. * * @param object aScript * The script object coming from the active thread. @@ -935,17 +871,17 @@ SourceScripts.prototype = { url: aScript.url }); }, /** * Handles notifications to load a source script from the cache or from a * local file. * - * XXX: It may be better to use nsITraceableChannel to get to the sources + * XXX: Tt may be better to use nsITraceableChannel to get to the sources * without relying on caching when we can (not for eval, etc.): * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ */ _onLoadSource: function SS__onLoadSource(aEvent) { let url = aEvent.detail.url; let options = aEvent.detail.options; let self = this; @@ -1026,17 +962,17 @@ SourceScripts.prototype = { * Log an error message in the error console when a script fails to load. * * @param string aUrl * The URL of the source script. * @param string aStatus * The failure status code. */ _logError: function SS__logError(aUrl, aStatus) { - Cu.reportError(L10N.getFormatStr("loadingError", [aUrl, aStatus])); + Components.utils.reportError(L10N.getFormatStr("loadingError", [aUrl, aStatus])); }, }; /** * Handles all the breakpoints in the current debugger. */ function Breakpoints() { this._onEditorBreakpointChange = this._onEditorBreakpointChange.bind(this); @@ -1318,37 +1254,16 @@ let L10N = { } }; XPCOMUtils.defineLazyGetter(L10N, "stringBundle", function() { return Services.strings.createBundle(DBG_STRINGS_URI); }); /** - * Shortcuts for accessing various debugger preferences. - */ -let Prefs = {}; - -/** - * Gets the preferred default remote debugging host. - * @return string - */ -XPCOMUtils.defineLazyGetter(Prefs, "remoteHost", function() { - return Services.prefs.getCharPref("devtools.debugger.remote-host"); -}); - -/** - * Gets the preferred default remote debugging port. - * @return number - */ -XPCOMUtils.defineLazyGetter(Prefs, "remotePort", function() { - return Services.prefs.getIntPref("devtools.debugger.remote-port"); -}); - -/** * Preliminary setup for the DebuggerController object. */ DebuggerController.init(); DebuggerController.ThreadState = new ThreadState(); DebuggerController.StackFrames = new StackFrames(); DebuggerController.SourceScripts = new SourceScripts(); DebuggerController.Breakpoints = new Breakpoints();
--- a/browser/devtools/debugger/debugger-view.js +++ b/browser/devtools/debugger/debugger-view.js @@ -85,72 +85,53 @@ let DebuggerView = { } }; /** * Functions handling the scripts UI. */ function ScriptsView() { this._onScriptsChange = this._onScriptsChange.bind(this); - this._onScriptsSearch = this._onScriptsSearch.bind(this); } ScriptsView.prototype = { /** * Removes all elements from the scripts container, leaving it empty. */ empty: function DVS_empty() { while (this._scripts.firstChild) { this._scripts.removeChild(this._scripts.firstChild); } }, /** - * Removes the input in the searchbox and unhides all the scripts. - */ - clearSearch: function DVS_clearSearch() { - this._searchbox.value = ""; - this._onScriptsSearch({}); - }, - - /** * Checks whether the script with the specified URL is among the scripts * known to the debugger and shown in the list. * * @param string aUrl * The script URL. * @return boolean */ contains: function DVS_contains(aUrl) { - if (this._tmpScripts.some(function(element) { - return element.script.url == aUrl; - })) { - return true; - } if (this._scripts.getElementsByAttribute("value", aUrl).length > 0) { return true; } return false; }, /** * Checks whether the script with the specified label is among the scripts * known to the debugger and shown in the list. * * @param string aLabel * The script label. * @return boolean */ containsLabel: function DVS_containsLabel(aLabel) { - if (this._tmpScripts.some(function(element) { - return element.label == aLabel; - })) { - return true; - } if (this._scripts.getElementsByAttribute("label", aLabel).length > 0) { return true; } return false; }, /** * Selects the script with the specified URL from the list. @@ -186,258 +167,80 @@ ScriptsView.prototype = { * @return string | null */ get selected() { return this._scripts.selectedItem ? this._scripts.selectedItem.value : null; }, /** - * Returns the list of labels in the scripts container. - * @return array - */ - get scriptLabels() { - let labels = []; - for (let i = 0, l = this._scripts.itemCount; i < l; i++) { - labels.push(this._scripts.getItemAtIndex(i).label); - } - return labels; - }, - - /** * Returns the list of URIs for scripts in the page. * @return array */ get scriptLocations() { let locations = []; for (let i = 0, l = this._scripts.itemCount; i < l; i++) { locations.push(this._scripts.getItemAtIndex(i).value); } return locations; }, /** - * Gets the number of visible (hidden=false) scripts in the container. - * @return number - */ - get visibleItemsCount() { - let count = 0; - for (let i = 0, l = this._scripts.itemCount; i < l; i++) { - count += this._scripts.getItemAtIndex(i).hidden ? 0 : 1; - } - return count; - }, - - /** - * Prepares a script to be added to the scripts container. This allows - * for a large number of scripts to be batched up before being - * alphabetically sorted and added in the container. - * @see ScriptsView.commitScripts - * - * If aForceFlag is true, the script will be immediately inserted at the - * necessary position in the container so that all the scripts remain sorted. - * This can be much slower than batching up multiple scripts. - * - * @param string aLabel - * The simplified script location to be shown. - * @param string aScript - * The source script. - * @param boolean aForceFlag - * True to force the script to be immediately added. - */ - addScript: function DVS_addScript(aLabel, aScript, aForceFlag) { - // Batch the script to be added later. - if (!aForceFlag) { - this._tmpScripts.push({ label: aLabel, script: aScript }); - return; - } - - // Find the target position in the menulist and insert the script there. - for (let i = 0, l = this._scripts.itemCount; i < l; i++) { - if (this._scripts.getItemAtIndex(i).label > aLabel) { - this._createScriptElement(aLabel, aScript, i); - return; - } - } - // The script is alphabetically the last one. - this._createScriptElement(aLabel, aScript, -1, true); - }, - - /** - * Adds all the prepared scripts to the scripts container. - * If a script already exists (was previously added), nothing happens. - */ - commitScripts: function DVS_commitScripts() { - let newScripts = this._tmpScripts; - this._tmpScripts = []; - - if (!newScripts || !newScripts.length) { - return; - } - newScripts.sort(function(a, b) { - return a.label.toLowerCase() > b.label.toLowerCase(); - }); - - for (let i = 0, l = newScripts.length; i < l; i++) { - let item = newScripts[i]; - this._createScriptElement(item.label, item.script, -1, true); - } - }, - - /** - * Creates a custom script element and adds it to the scripts container. - * If the script with the specified label already exists, nothing happens. + * Adds a script to the scripts container. + * If the script already exists (was previously added), null is returned. + * Otherwise, the newly created element is returned. * * @param string aLabel * The simplified script location to be shown. * @param string aScript * The source script. - * @param number aIndex - * The index where to insert to new script in the container. - * Pass -1 to append the script at the end. - * @param boolean aSelectIfEmptyFlag - * True to set the newly created script as the currently selected item - * if there are no other existing scripts in the container. + * @return object + * The newly created html node representing the added script. */ - _createScriptElement: function DVS__createScriptElement( - aLabel, aScript, aIndex, aSelectIfEmptyFlag) - { + addScript: function DVS_addScript(aLabel, aScript) { // Make sure we don't duplicate anything. - if (aLabel == "null" || this.containsLabel(aLabel)) { - return; + if (this.containsLabel(aLabel)) { + return null; } - let scriptItem = - aIndex == -1 ? this._scripts.appendItem(aLabel, aScript.url) - : this._scripts.insertItemAt(aIndex, aLabel, aScript.url); + let script = this._scripts.appendItem(aLabel, aScript.url); + script.setAttribute("tooltiptext", aScript.url); + script.setUserData("sourceScript", aScript, null); - scriptItem.setAttribute("tooltiptext", aScript.url); - scriptItem.setUserData("sourceScript", aScript, null); - - if (this._scripts.itemCount == 1 && aSelectIfEmptyFlag) { - this._scripts.selectedItem = scriptItem; - } + this._scripts.selectedItem = script; + return script; }, /** - * The click listener for the scripts container. + * The cached click listener for the scripts container. */ _onScriptsChange: function DVS__onScriptsChange() { let script = this._scripts.selectedItem.getUserData("sourceScript"); - this._preferredScript = script; DebuggerController.SourceScripts.showScript(script); }, /** - * The search listener for the scripts search box. - */ - _onScriptsSearch: function DVS__onScriptsSearch(e) { - let editor = DebuggerView.editor; - let scripts = this._scripts; - let rawValue = this._searchbox.value.toLowerCase(); - - let rawLength = rawValue.length; - let lastColon = rawValue.lastIndexOf(":"); - let lastAt = rawValue.lastIndexOf("@"); - - let fileEnd = lastColon != -1 ? lastColon : lastAt != -1 ? lastAt : rawLength; - let lineEnd = lastAt != -1 ? lastAt : rawLength; - - let file = rawValue.slice(0, fileEnd); - let line = window.parseInt(rawValue.slice(fileEnd + 1, lineEnd)) || -1; - let token = rawValue.slice(lineEnd + 1); - - // Presume we won't find anything. - scripts.selectedItem = this._preferredScript; - - // If we're not searching for a file anymore, unhide all the scripts. - if (!file) { - for (let i = 0, l = scripts.itemCount; i < l; i++) { - scripts.getItemAtIndex(i).hidden = false; - } - } else { - for (let i = 0, l = scripts.itemCount, found = false; i < l; i++) { - let item = scripts.getItemAtIndex(i); - let target = item.value.toLowerCase(); - - // Search is not case sensitive, and is tied to the url not the label. - if (target.match(file)) { - item.hidden = false; - - if (!found) { - found = true; - scripts.selectedItem = item; - } - } - // Hide what doesn't match our search. - else { - item.hidden = true; - } - } - } - if (line > -1) { - editor.setCaretPosition(line - 1); - } - if (token) { - let offset = editor.find(token, { ignoreCase: true }); - if (offset > -1) { - editor.setCaretPosition(0); - editor.setCaretOffset(offset); - } - } - }, - - /** - * The keyup listener for the scripts search box. - */ - _onScriptsKeyUp: function DVS__onScriptsKeyUp(e) { - if (e.keyCode === e.DOM_VK_ESCAPE) { - DebuggerView.editor.focus(); - return; - } - - if (e.keyCode === e.DOM_VK_RETURN || e.keyCode === e.DOM_VK_ENTER) { - let editor = DebuggerView.editor; - let offset = editor.findNext(true); - if (offset > -1) { - editor.setCaretPosition(0); - editor.setCaretOffset(offset); - } - } - }, - - /** - * The cached scripts container and search box. + * The cached scripts container. */ _scripts: null, - _searchbox: null, /** * Initialization function, called when the debugger is initialized. */ initialize: function DVS_initialize() { this._scripts = document.getElementById("scripts"); - this._searchbox = document.getElementById("scripts-search"); this._scripts.addEventListener("select", this._onScriptsChange, false); - this._searchbox.addEventListener("select", this._onScriptsSearch, false); - this._searchbox.addEventListener("input", this._onScriptsSearch, false); - this._searchbox.addEventListener("keyup", this._onScriptsKeyUp, false); - this.commitScripts(); }, /** * Destruction function, called when the debugger is shut down. */ destroy: function DVS_destroy() { this._scripts.removeEventListener("select", this._onScriptsChange, false); - this._searchbox.removeEventListener("select", this._onScriptsSearch, false); - this._searchbox.removeEventListener("input", this._onScriptsSearch, false); - this._searchbox.removeEventListener("keyup", this._onScriptsKeyUp, false); this._scripts = null; - this._searchbox = null; } }; /** * Functions handling the html stackframes UI. */ function StackFramesView() { this._onFramesScroll = this._onFramesScroll.bind(this); @@ -469,18 +272,16 @@ StackFramesView.prototype = { else if (aState == "attached") { status.textContent = L10N.getStr("runningState"); resume.label = L10N.getStr("pauseLabel"); } // No valid state parameter. else { status.textContent = ""; } - - DebuggerView.Scripts.clearSearch(); }, /** * Removes all elements from the stackframes container, leaving it empty. */ empty: function DVF_empty() { while (this._frames.firstChild) { this._frames.removeChild(this._frames.firstChild); @@ -494,17 +295,17 @@ StackFramesView.prototype = { emptyText: function DVF_emptyText() { // Make sure the container is empty first. this.empty(); let item = document.createElement("div"); // The empty node should look grayed out to avoid confusion. item.className = "empty list-item"; - item.appendChild(document.createTextNode(L10N.getStr("emptyStackText"))); + item.appendChild(document.createTextNode(L10N.getStr("emptyText"))); this._frames.appendChild(item); }, /** * Adds a frame to the stackframes container. * If the frame already exists (was previously added), null is returned. * Otherwise, the newly created element is returned. @@ -575,17 +376,17 @@ StackFramesView.prototype = { /** * Deselects a frame from the stackframe container. * * @param number aDepth * The frame depth specified by the debugger. */ unhighlightFrame: function DVF_unhighlightFrame(aDepth) { - this.highlightFrame(aDepth, true); + this.highlightFrame(aDepth, true) }, /** * Gets the current dirty state. * * @return boolean value * True if should load more frames. */
--- a/browser/devtools/debugger/debugger.xul +++ b/browser/devtools/debugger/debugger.xul @@ -76,18 +76,16 @@ <div id="body" class="vbox flex"> <xul:toolbar id="dbg-toolbar"> <xul:button id="close">&debuggerUI.closeButton;</xul:button> <xul:button id="resume"/> <xul:button id="step-over">&debuggerUI.stepOverButton;</xul:button> <xul:button id="step-in">&debuggerUI.stepInButton;</xul:button> <xul:button id="step-out">&debuggerUI.stepOutButton;</xul:button> <xul:menulist id="scripts"/> - <xul:textbox id="scripts-search" type="search" - emptytext="&debuggerUI.emptyFilterText;"/> </xul:toolbar> <div id="dbg-content" class="hbox flex"> <div id="stack" class="vbox"> <div class="title unselectable">&debuggerUI.stackTitle;</div> <div id="stackframes" class="vbox flex"></div> </div> <div id="script" class="vbox flex"> <div class="title unselectable">&debuggerUI.scriptTitle;</div>
--- a/browser/devtools/debugger/test/Makefile.in +++ b/browser/devtools/debugger/test/Makefile.in @@ -41,17 +41,16 @@ topsrcdir = @top_srcdir@ srcdir = @srcdir@ VPATH = @srcdir@ relativesrcdir = browser/devtools/debugger/test include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _BROWSER_TEST_FILES = \ - browser_dbg_createRemote.js \ browser_dbg_debuggerstatement.js \ browser_dbg_listtabs.js \ browser_dbg_tabactor-01.js \ browser_dbg_tabactor-02.js \ browser_dbg_contextactor-01.js \ browser_dbg_contextactor-02.js \ testactors.js \ browser_dbg_nav-01.js \ @@ -66,19 +65,16 @@ include $(topsrcdir)/config/rules.mk browser_dbg_panesize.js \ browser_dbg_stack-01.js \ browser_dbg_stack-02.js \ browser_dbg_stack-03.js \ browser_dbg_stack-04.js \ browser_dbg_stack-05.js \ browser_dbg_location-changes.js \ browser_dbg_script-switching.js \ - browser_dbg_scripts-sorting.js \ - browser_dbg_scripts-searching-01.js \ - browser_dbg_scripts-searching-02.js \ browser_dbg_pause-resume.js \ browser_dbg_update-editor-mode.js \ $(warning browser_dbg_select-line.js temporarily disabled due to oranges, see bug 726609) \ browser_dbg_clean-exit.js \ browser_dbg_bug723069_editor-breakpoints.js \ browser_dbg_bug731394_editor-contextmenu.js \ browser_dbg_displayName.js \ browser_dbg_iframes.js \
--- a/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js +++ b/browser/devtools/debugger/test/browser_dbg_bug723069_editor-breakpoints.js @@ -18,54 +18,47 @@ let gBreakpoints = null; function test() { let tempScope = {}; Cu.import("resource:///modules/source-editor.jsm", tempScope); let SourceEditor = tempScope.SourceEditor; let scriptShown = false; let framesAdded = false; - let resumed = false; - let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; gDebugger = gPane.debuggerWindow; - resumed = true; - gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; - executeSoon(startTest); + runTest(); }); - executeSoon(function() { - gDebuggee.firstCall(); - }); + gDebuggee.firstCall(); }); - function onScriptShown(aEvent) - { - scriptShown = aEvent.detail.url.indexOf("-02.js") != -1; - executeSoon(startTest); - } + window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { + let url = aEvent.detail.url; + if (url.indexOf("-02.js") != -1) { + scriptShown = true; + window.removeEventListener(aEvent.type, _onEvent); + runTest(); + } + }); - window.addEventListener("Debugger:ScriptShown", onScriptShown); - - function startTest() + function runTest() { - if (scriptShown && framesAdded && resumed && !testStarted) { - window.removeEventListener("Debugger:ScriptShown", onScriptShown); - testStarted = true; - Services.tm.currentThread.dispatch({ run: performTest }, 0); + if (scriptShown && framesAdded) { + Services.tm.currentThread.dispatch({ run: onScriptShown }, 0); } } - function performTest() + function onScriptShown() { gScripts = gDebugger.DebuggerView.Scripts; is(gDebugger.DebuggerController.activeThread.state, "paused", "Should only be getting stack frames while paused."); is(gScripts._scripts.itemCount, 2, "Found the expected number of scripts.");
--- a/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js +++ b/browser/devtools/debugger/test/browser_dbg_bug731394_editor-contextmenu.js @@ -16,53 +16,47 @@ function test() { let tempScope = {}; Cu.import("resource:///modules/source-editor.jsm", tempScope); let SourceEditor = tempScope.SourceEditor; let contextMenu = null; let scriptShown = false; let framesAdded = false; - let resumed = false; - let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; gDebugger = gPane.debuggerWindow; - resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; - executeSoon(startTest); + runTest(); }); - - executeSoon(function() { - gDebuggee.firstCall(); - }); + gDebuggee.firstCall(); }); - function onScriptShown(aEvent) { - scriptShown = aEvent.detail.url.indexOf("-02.js") != -1; - executeSoon(startTest); - } - - window.addEventListener("Debugger:ScriptShown", onScriptShown); + window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { + let url = aEvent.detail.url; + if (url.indexOf("-02.js") != -1) { + scriptShown = true; + window.removeEventListener(aEvent.type, _onEvent); + runTest(); + } + }); - function startTest() + function runTest() { - if (scriptShown && framesAdded && resumed && !testStarted) { - testStarted = true; - window.removeEventListener("Debugger:ScriptShown", onScriptShown); - Services.tm.currentThread.dispatch({ run: performTest }, 0); + if (scriptShown && framesAdded) { + Services.tm.currentThread.dispatch({ run: onScriptShown }, 0); } } - function performTest() + function onScriptShown() { let scripts = gDebugger.DebuggerView.Scripts._scripts; is(gDebugger.DebuggerController.activeThread.state, "paused", "Should only be getting stack frames while paused."); is(scripts.itemCount, 2, "Found the expected number of scripts.");
deleted file mode 100644 --- a/browser/devtools/debugger/test/browser_dbg_createRemote.js +++ /dev/null @@ -1,86 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -var gProcess = null; -var gTab = null; -var gDebuggee = null; - -function test() { - remote_debug_tab_pane(STACK_URL, aOnClosing, function(aTab, aDebuggee, aProcess) { - gTab = aTab; - gDebuggee = aDebuggee; - gProcess = aProcess; - - testSimpleCall(); - }); -} - -function testSimpleCall() { - Services.tm.currentThread.dispatch({ run: function() { - - ok(gProcess._dbgProcess, - "The remote debugger process wasn't created properly!"); - ok(gProcess._dbgProcess.isRunning, - "The remote debugger process isn't running!"); - is(typeof gProcess._dbgProcess.pid, "number", - "The remote debugger process doesn't have a pid (?!)"); - - info("process location: " + gProcess._dbgProcess.location); - info("process pid: " + gProcess._dbgProcess.pid); - info("process name: " + gProcess._dbgProcess.processName); - info("process sig: " + gProcess._dbgProcess.processSignature); - - ok(gProcess._dbgProfile, - "The remote debugger profile wasn't created properly!"); - ok(gProcess._dbgProfile.localDir, - "The remote debugger profile doesn't have a localDir..."); - ok(gProcess._dbgProfile.rootDir, - "The remote debugger profile doesn't have a rootDir..."); - ok(gProcess._dbgProfile.name, - "The remote debugger profile doesn't have a name..."); - - info("profile localDir: " + gProcess._dbgProfile.localDir); - info("profile rootDir: " + gProcess._dbgProfile.rootDir); - info("profile name: " + gProcess._dbgProfile.name); - - let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] - .createInstance(Ci.nsIToolkitProfileService); - - let profile = profileService.getProfileByName(gProcess._dbgProfile.name); - - ok(profile, - "The remote debugger profile wasn't *actually* created properly!"); - is(profile.localDir.path, gProcess._dbgProfile.localDir.path, - "The remote debugger profile doesn't have the correct localDir!"); - is(profile.rootDir.path, gProcess._dbgProfile.rootDir.path, - "The remote debugger profile doesn't have the correct rootDir!"); - - DebuggerUI.toggleRemoteDebugger(); - }}, 0); -} - -function aOnClosing() { - ok(!gProcess._dbgProcess.isRunning, - "The remote debugger process isn't closed as it should be!"); - is(gProcess._dbgProcess.exitValue, (Services.appinfo.OS == "WINNT" ? 0 : 256), - "The remote debugger process didn't die cleanly."); - - info("process exit value: " + gProcess._dbgProcess.exitValue); - - info("profile localDir: " + gProcess._dbgProfile.localDir.path); - info("profile rootDir: " + gProcess._dbgProfile.rootDir.path); - info("profile name: " + gProcess._dbgProfile.name); - - executeSoon(function() { - finish(); - }); -} - -registerCleanupFunction(function() { - removeTab(gTab); - gProcess = null; - gTab = null; - gDebuggee = null; -});
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-01.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-01.js @@ -80,38 +80,38 @@ function testSimpleCall() { gDebuggee.simpleCall(); } function resumeAndFinish() { gDebugger.DebuggerController.activeThread.resume(function() { let vs = gDebugger.DebuggerView.Scripts; let ss = gDebugger.DebuggerController.SourceScripts; - vs.empty(); - vs._scripts.removeEventListener("select", vs._onScriptsChange, false); + ss._onScriptsCleared(); is(ss._trimUrlQuery("a/b/c.d?test=1&random=4"), "a/b/c.d", "Trimming the url query isn't done properly."); let urls = [ { href: "ici://some.address.com/random/", leaf: "subrandom/" }, { href: "ni://another.address.org/random/subrandom/", leaf: "page.html" }, { href: "san://interesting.address.gro/random/", leaf: "script.js" }, { href: "si://interesting.address.moc/random/", leaf: "script.js" }, { href: "si://interesting.address.moc/random/", leaf: "x/script.js" }, { href: "si://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" }, { href: "si://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2" }, { href: "si://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3" } ]; + vs._scripts.removeEventListener("select", vs._onScriptsChange, false); + urls.forEach(function(url) { executeSoon(function() { let loc = url.href + url.leaf; vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }); - vs.commitScripts(); }); }); executeSoon(function() { for (let i = 0; i < vs._scripts.itemCount; i++) { let lab = vs._scripts.getItemAtIndex(i).getAttribute("label"); let loc = urls[i].href + urls[i].leaf;
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-07.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-07.js @@ -22,20 +22,20 @@ function test() testFrameParameters(); }); } function testFrameParameters() { dump("Started testFrameParameters!\n"); - gDebugger.addEventListener("Debugger:FetchedVariables", function test() { - dump("Entered Debugger:FetchedVariables!\n"); + gDebugger.addEventListener("Debugger:FetchedParameters", function test() { + dump("Entered Debugger:FetchedParameters!\n"); - gDebugger.removeEventListener("Debugger:FetchedVariables", test, false); + gDebugger.removeEventListener("Debugger:FetchedParameters", test, false); Services.tm.currentThread.dispatch({ run: function() { dump("After currentThread.dispatch!\n"); var frames = gDebugger.DebuggerView.StackFrames._frames, childNodes = frames.childNodes, localScope = gDebugger.DebuggerView.Properties.localScope, localNodes = localScope.querySelector(".details").childNodes; @@ -47,52 +47,43 @@ function testFrameParameters() dump("localNodes - " + localNodes.constructor + "\n"); is(gDebugger.DebuggerController.activeThread.state, "paused", "Should only be getting stack frames while paused."); is(frames.querySelectorAll(".dbg-stackframe").length, 3, "Should have three frames."); - is(localNodes.length, 11, + is(localNodes.length, 8, "The localScope should contain all the created variable elements."); is(localNodes[0].querySelector(".info").textContent, "[object Proxy]", "Should have the right property value for 'this'."); - is(localNodes[1].querySelector(".info").textContent, "[object Object]", + is(localNodes[1].querySelector(".info").textContent, "[object Arguments]", + "Should have the right property value for 'arguments'."); + + is(localNodes[2].querySelector(".info").textContent, "[object Object]", "Should have the right property value for 'aArg'."); - is(localNodes[2].querySelector(".info").textContent, '"beta"', + is(localNodes[3].querySelector(".info").textContent, '"beta"', "Should have the right property value for 'bArg'."); - is(localNodes[3].querySelector(".info").textContent, "3", + is(localNodes[4].querySelector(".info").textContent, "3", "Should have the right property value for 'cArg'."); - is(localNodes[4].querySelector(".info").textContent, "false", + is(localNodes[5].querySelector(".info").textContent, "false", "Should have the right property value for 'dArg'."); - is(localNodes[5].querySelector(".info").textContent, "null", + is(localNodes[6].querySelector(".info").textContent, "null", "Should have the right property value for 'eArg'."); - is(localNodes[6].querySelector(".info").textContent, "undefined", + is(localNodes[7].querySelector(".info").textContent, "undefined", "Should have the right property value for 'fArg'."); - is(localNodes[7].querySelector(".info").textContent, "1", - "Should have the right property value for 'a'."); - - is(localNodes[8].querySelector(".info").textContent, "[object Object]", - "Should have the right property value for 'b'."); - - is(localNodes[9].querySelector(".info").textContent, "[object Object]", - "Should have the right property value for 'c'."); - - is(localNodes[10].querySelector(".info").textContent, "[object Arguments]", - "Should have the right property value for 'arguments'."); - resumeAndFinish(); }}, 0); }, false); EventUtils.sendMouseEvent({ type: "click" }, content.document.querySelector("button"), content.window); }
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-08.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-08.js @@ -22,20 +22,20 @@ function test() testFrameParameters(); }); } function testFrameParameters() { dump("Started testFrameParameters!\n"); - gDebugger.addEventListener("Debugger:FetchedVariables", function test() { - dump("Entered Debugger:FetchedVariables!\n"); + gDebugger.addEventListener("Debugger:FetchedParameters", function test() { + dump("Entered Debugger:FetchedParameters!\n"); - gDebugger.removeEventListener("Debugger:FetchedVariables", test, false); + gDebugger.removeEventListener("Debugger:FetchedParameters", test, false); Services.tm.currentThread.dispatch({ run: function() { dump("After currentThread.dispatch!\n"); var frames = gDebugger.DebuggerView.StackFrames._frames, localScope = gDebugger.DebuggerView.Properties.localScope, localNodes = localScope.querySelector(".details").childNodes; @@ -45,98 +45,82 @@ function testFrameParameters() dump("localNodes - " + localNodes.constructor + "\n"); is(gDebugger.DebuggerController.activeThread.state, "paused", "Should only be getting stack frames while paused."); is(frames.querySelectorAll(".dbg-stackframe").length, 3, "Should have three frames."); - is(localNodes.length, 11, + is(localNodes.length, 8, "The localScope should contain all the created variable elements."); is(localNodes[0].querySelector(".info").textContent, "[object Proxy]", "Should have the right property value for 'this'."); - // Expand the '__proto__', 'arguments' and 'a' tree nodes. This causes - // their properties to be retrieved and displayed. + // Expand the __proto__ and arguments tree nodes. This causes their + // properties to be retrieved and displayed. localNodes[0].expand(); - localNodes[9].expand(); - localNodes[10].expand(); + localNodes[1].expand(); // Poll every few milliseconds until the properties are retrieved. // It's important to set the timer in the chrome window, because the // content window timers are disabled while the debuggee is paused. let count = 0; let intervalID = window.setInterval(function(){ if (++count > 50) { ok(false, "Timed out while polling for the properties."); resumeAndFinish(); } - if (!localNodes[0].fetched || - !localNodes[9].fetched || - !localNodes[10].fetched) { + if (!localNodes[0].fetched || !localNodes[1].fetched) { return; } window.clearInterval(intervalID); is(localNodes[0].querySelector(".property > .title > .key") .textContent, "__proto__ ", "Should have the right property name for __proto__."); ok(localNodes[0].querySelector(".property > .title > .value") .textContent.search(/object/) != -1, "__proto__ should be an object."); - is(localNodes[9].querySelector(".info").textContent, "[object Object]", - "Should have the right property value for 'c'."); - - is(localNodes[9].querySelectorAll(".property > .title > .key")[1] - .textContent, "a", - "Should have the right property name for 'a'."); - - is(localNodes[9].querySelectorAll(".property > .title > .value")[1] - .textContent, 1, - "Should have the right value for 'c.a'."); - - is(localNodes[10].querySelector(".info").textContent, - "[object Arguments]", + is(localNodes[1].querySelector(".info").textContent, "[object Arguments]", "Should have the right property value for 'arguments'."); - is(localNodes[10].querySelector(".property > .title > .key") + is(localNodes[1].querySelector(".property > .title > .key") .textContent, "length", - "Should have the right property name for 'length'."); + "Should have the right property name for length."); - is(localNodes[10].querySelector(".property > .title > .value") + is(localNodes[1].querySelector(".property > .title > .value") .textContent, 5, "Should have the right argument length."); resumeAndFinish(); }, 100); }}, 0); }, false); EventUtils.sendMouseEvent({ type: "click" }, content.document.querySelector("button"), content.window); } function resumeAndFinish() { - let thread = gDebugger.DebuggerController.activeThread; - thread.addOneTimeListener("framescleared", function() { + gDebugger.DebuggerController.activeThread.addOneTimeListener("framescleared", function() { Services.tm.currentThread.dispatch({ run: function() { var frames = gDebugger.DebuggerView.StackFrames._frames; is(frames.querySelectorAll(".dbg-stackframe").length, 0, "Should have no frames."); closeDebuggerAndFinish(gTab); }}, 0); }); - thread.resume(); + gDebugger.DebuggerController.activeThread.resume(); } registerCleanupFunction(function() { removeTab(gTab); gPane = null; gTab = null; gDebugger = null; });
--- a/browser/devtools/debugger/test/browser_dbg_script-switching.js +++ b/browser/devtools/debugger/test/browser_dbg_script-switching.js @@ -3,59 +3,57 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ /** * Make sure that switching the displayed script in the UI works as advertised. */ const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html"; +let tempScope = {}; +Cu.import("resource:///modules/source-editor.jsm", tempScope); +let SourceEditor = tempScope.SourceEditor; + var gPane = null; var gTab = null; var gDebuggee = null; var gDebugger = null; var gScripts = null; function test() { let scriptShown = false; let framesAdded = false; - let resumed = false; - let testStarted = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; gDebugger = gPane.debuggerWindow; - resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; - executeSoon(startTest); + runTest(); }); - executeSoon(function() { - gDebuggee.firstCall(); - }); + gDebuggee.firstCall(); }); - function onScriptShown(aEvent) - { - scriptShown = aEvent.detail.url.indexOf("-02.js") != -1; - executeSoon(startTest); - } + window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { + let url = aEvent.detail.url; + if (url.indexOf("-02.js") != -1) { + scriptShown = true; + window.removeEventListener(aEvent.type, _onEvent); + runTest(); + } + }); - window.addEventListener("Debugger:ScriptShown", onScriptShown); - - function startTest() + function runTest() { - if (scriptShown && framesAdded && resumed && !testStarted) { - window.removeEventListener("Debugger:ScriptShown", onScriptShown); - testStarted = true; + if (scriptShown && framesAdded) { Services.tm.currentThread.dispatch({ run: testScriptsDisplay }, 0); } } } function testScriptsDisplay() { gScripts = gDebugger.DebuggerView.Scripts._scripts; @@ -76,16 +74,18 @@ function testScriptsDisplay() { ok(gDebugger.DebuggerView.Scripts.contains(EXAMPLE_URL + label2), "Second script url is incorrect."); ok(gDebugger.DebuggerView.Scripts.containsLabel( label1), "First script label is incorrect."); ok(gDebugger.DebuggerView.Scripts.containsLabel( label2), "Second script label is incorrect."); + dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n"); + ok(gDebugger.editor.getText().search(/debugger/) != -1, "The correct script was loaded initially."); is(gDebugger.editor.getDebugLocation(), 5, "editor debugger location is correct."); window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { let url = aEvent.detail.url; @@ -95,16 +95,18 @@ function testScriptsDisplay() { } }); gDebugger.DebuggerView.Scripts.selectScript(EXAMPLE_URL + label1); } function testSwitchPaused() { + dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n"); + ok(gDebugger.editor.getText().search(/debugger/) == -1, "The second script is no longer displayed."); ok(gDebugger.editor.getText().search(/firstCall/) != -1, "The first script is displayed."); is(gDebugger.editor.getDebugLocation(), -1, "editor debugger location has been cleared."); @@ -120,18 +122,16 @@ function testSwitchPaused() gDebugger.DebuggerView.Scripts.selectScript(EXAMPLE_URL + "test-script-switching-02.js"); }); } function testSwitchRunning() { - dump("Debugger editor text:\n" + gDebugger.editor.getText() + "\n"); - ok(gDebugger.editor.getText().search(/debugger/) != -1, "The second script is displayed again."); ok(gDebugger.editor.getText().search(/firstCall/) == -1, "The first script is no longer displayed."); is(gDebugger.editor.getDebugLocation(), -1, "editor debugger location is still -1.");
deleted file mode 100644 --- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-01.js +++ /dev/null @@ -1,188 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -var gPane = null; -var gTab = null; -var gDebuggee = null; -var gDebugger = null; -var gEditor = null; -var gScripts = null; -var gSearchBox = null; -var gMenulist = null; - -function test() -{ - let scriptShown = false; - let framesAdded = false; - - debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { - gTab = aTab; - gDebuggee = aDebuggee; - gPane = aPane; - gDebugger = gPane.debuggerWindow; - - gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { - framesAdded = true; - runTest(); - }); - - gDebuggee.simpleCall(); - }); - - window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { - window.removeEventListener(aEvent.type, _onEvent); - scriptShown = true; - runTest(); - }); - - function runTest() - { - if (scriptShown && framesAdded) { - Services.tm.currentThread.dispatch({ run: testScriptSearching }, 0); - } - } -} - -function testScriptSearching() { - gDebugger.DebuggerController.activeThread.resume(function() { - gEditor = gDebugger.DebuggerView.editor; - gScripts = gDebugger.DebuggerView.Scripts; - gSearchBox = gScripts._searchbox; - gMenulist = gScripts._scripts; - - write(":12"); - ok(gEditor.getCaretPosition().line == 11 && - gEditor.getCaretPosition().col == 0, - "The editor didn't jump to the correct line."); - - write("@debugger"); - ok(gEditor.getCaretPosition().line == 2 && - gEditor.getCaretPosition().col == 44, - "The editor didn't jump to the correct token. (1)"); - - EventUtils.sendKey("RETURN"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (2)"); - - EventUtils.sendKey("ENTER"); - ok(gEditor.getCaretPosition().line == 12 && - gEditor.getCaretPosition().col == 8, - "The editor didn't jump to the correct token. (3)"); - - EventUtils.sendKey("ENTER"); - ok(gEditor.getCaretPosition().line == 19 && - gEditor.getCaretPosition().col == 4, - "The editor didn't jump to the correct token. (4)"); - - EventUtils.sendKey("RETURN"); - ok(gEditor.getCaretPosition().line == 2 && - gEditor.getCaretPosition().col == 44, - "The editor didn't jump to the correct token. (5)"); - - - write(":bogus@debugger;"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (7)"); - - write(":13@debugger;"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (7)"); - - write(":@debugger;"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (8)"); - - write("::@debugger;"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (9)"); - - write(":::@debugger;"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (10)"); - - - write(":i am not a number"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't remain at the correct token. (11)"); - - write("@__i do not exist__"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't remain at the correct token. (12)"); - - - write(":1:2:3:a:b:c:::12"); - ok(gEditor.getCaretPosition().line == 11 && - gEditor.getCaretPosition().col == 0, - "The editor didn't jump to the correct line. (13)"); - - write("@don't@find@me@instead@find@debugger"); - ok(gEditor.getCaretPosition().line == 2 && - gEditor.getCaretPosition().col == 44, - "The editor didn't jump to the correct token. (14)"); - - EventUtils.sendKey("RETURN"); - ok(gEditor.getCaretPosition().line == 8 && - gEditor.getCaretPosition().col == 2, - "The editor didn't jump to the correct token. (15)"); - - EventUtils.sendKey("ENTER"); - ok(gEditor.getCaretPosition().line == 12 && - gEditor.getCaretPosition().col == 8, - "The editor didn't jump to the correct token. (16)"); - - EventUtils.sendKey("RETURN"); - ok(gEditor.getCaretPosition().line == 19 && - gEditor.getCaretPosition().col == 4, - "The editor didn't jump to the correct token. (17)"); - - EventUtils.sendKey("ENTER"); - ok(gEditor.getCaretPosition().line == 2 && - gEditor.getCaretPosition().col == 44, - "The editor didn't jump to the correct token. (18)"); - - - clear(); - ok(gEditor.getCaretPosition().line == 2 && - gEditor.getCaretPosition().col == 44, - "The editor didn't remain at the correct token. (19)"); - is(gScripts.visibleItemsCount, 1, - "Not all the scripts are shown after the search. (20)"); - - closeDebuggerAndFinish(gTab); - }); -} - -function clear() { - gSearchBox.focus(); - gSearchBox.value = ""; -} - -function write(text) { - clear(); - - for (let i = 0; i < text.length; i++) { - EventUtils.sendChar(text[i]); - } - dump("editor caret position: " + gEditor.getCaretPosition().toSource() + "\n"); -} - -registerCleanupFunction(function() { - removeTab(gTab); - gPane = null; - gTab = null; - gDebuggee = null; - gDebugger = null; - gEditor = null; - gScripts = null; - gSearchBox = null; - gMenulist = null; -});
deleted file mode 100644 --- a/browser/devtools/debugger/test/browser_dbg_scripts-searching-02.js +++ /dev/null @@ -1,146 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -const TAB_URL = EXAMPLE_URL + "browser_dbg_script-switching.html"; - -var gPane = null; -var gTab = null; -var gDebuggee = null; -var gDebugger = null; -var gEditor = null; -var gScripts = null; -var gSearchBox = null; -var gMenulist = null; - -function test() -{ - let scriptShown = false; - let framesAdded = false; - - debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { - gTab = aTab; - gDebuggee = aDebuggee; - gPane = aPane; - gDebugger = gPane.debuggerWindow; - - gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { - framesAdded = true; - runTest(); - }); - - gDebuggee.firstCall(); - }); - - window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { - let url = aEvent.detail.url; - if (url.indexOf("-02.js") != -1) { - scriptShown = true; - window.removeEventListener(aEvent.type, _onEvent); - runTest(); - } - }); - - function runTest() - { - if (scriptShown && framesAdded) { - Services.tm.currentThread.dispatch({ run: testScriptSearching }, 0); - } - } -} - -function testScriptSearching() { - gDebugger.DebuggerController.activeThread.resume(function() { - gEditor = gDebugger.DebuggerView.editor; - gScripts = gDebugger.DebuggerView.Scripts; - gSearchBox = gScripts._searchbox; - gMenulist = gScripts._scripts; - - firstSearch(); - }); -} - -function firstSearch() { - window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { - dump("Current script url:\n" + aEvent.detail.url + "\n"); - dump("Debugger editor text:\n" + gEditor.getText() + "\n"); - - let url = aEvent.detail.url; - if (url.indexOf("-01.js") != -1) { - window.removeEventListener(aEvent.type, _onEvent); - - executeSoon(function() { - dump("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n"); - ok(gEditor.getCaretPosition().line == 4 && - gEditor.getCaretPosition().col == 0, - "The editor didn't jump to the correct line. (1)"); - is(gScripts.visibleItemsCount, 1, - "Not all the correct scripts are shown after the search. (1)"); - - secondSearch(); - }); - } - }); - write(".*-01\.js:5"); -} - -function secondSearch() { - window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { - dump("Current script url:\n" + aEvent.detail.url + "\n"); - dump("Debugger editor text:\n" + gEditor.getText() + "\n"); - - let url = aEvent.detail.url; - if (url.indexOf("-02.js") != -1) { - window.removeEventListener(aEvent.type, _onEvent); - - executeSoon(function() { - dump("Editor caret position: " + gEditor.getCaretPosition().toSource() + "\n"); - ok(gEditor.getCaretPosition().line == 5 && - gEditor.getCaretPosition().col == 8, - "The editor didn't jump to the correct line. (2)"); - is(gScripts.visibleItemsCount, 1, - "Not all the correct scripts are shown after the search. (2)"); - - finalCheck(); - }); - } - }); - write(".*-02\.js@debugger;"); -} - -function finalCheck() { - clear(); - ok(gEditor.getCaretPosition().line == 5 && - gEditor.getCaretPosition().col == 8, - "The editor didn't remain at the correct token. (3)"); - is(gScripts.visibleItemsCount, 2, - "Not all the scripts are shown after the search. (3)"); - - closeDebuggerAndFinish(gTab); -} - -function clear() { - gSearchBox.focus(); - gSearchBox.value = ""; -} - -function write(text) { - clear(); - - for (let i = 0; i < text.length; i++) { - EventUtils.sendChar(text[i]); - } - dump("editor caret position: " + gEditor.getCaretPosition().toSource() + "\n"); -} - -registerCleanupFunction(function() { - removeTab(gTab); - gPane = null; - gTab = null; - gDebuggee = null; - gDebugger = null; - gEditor = null; - gScripts = null; - gSearchBox = null; - gMenulist = null; -});
deleted file mode 100644 --- a/browser/devtools/debugger/test/browser_dbg_scripts-sorting.js +++ /dev/null @@ -1,124 +0,0 @@ -/* vim:set ts=2 sw=2 sts=2 et: */ -/* - * Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ - */ -var gPane = null; -var gTab = null; -var gDebuggee = null; -var gDebugger = null; - -function test() { - debug_tab_pane(STACK_URL, function(aTab, aDebuggee, aPane) { - gTab = aTab; - gDebuggee = aDebuggee; - gPane = aPane; - gDebugger = gPane.debuggerWindow; - - testSimpleCall(); - }); -} - -function testSimpleCall() { - gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { - Services.tm.currentThread.dispatch({ run: function() { - resumeAndFinish(); - }}, 0); - }); - - gDebuggee.simpleCall(); -} - -function resumeAndFinish() { - gDebugger.DebuggerController.activeThread.resume(function() { - checkScriptsOrder(); - addScriptsAndCheckOrder(1, function() { - addScriptsAndCheckOrder(2, function() { - addScriptsAndCheckOrder(3, function() { - closeDebuggerAndFinish(gTab); - }); - }); - }); - }); -} - -function addScriptsAndCheckOrder(method, callback) { - let vs = gDebugger.DebuggerView.Scripts; - let ss = gDebugger.DebuggerController.SourceScripts; - vs.empty(); - vs._scripts.removeEventListener("select", vs._onScriptsChange, false); - - let urls = [ - { href: "ici://some.address.com/random/", leaf: "subrandom/" }, - { href: "ni://another.address.org/random/subrandom/", leaf: "page.html" }, - { href: "san://interesting.address.gro/random/", leaf: "script.js" }, - { href: "si://interesting.address.moc/random/", leaf: "script.js" }, - { href: "si://interesting.address.moc/random/", leaf: "x/script.js" }, - { href: "si://interesting.address.moc/random/", leaf: "x/y/script.js?a=1" }, - { href: "si://interesting.address.moc/random/x/", leaf: "y/script.js?a=1&b=2" }, - { href: "si://interesting.address.moc/random/x/y/", leaf: "script.js?a=1&b=2&c=3" } - ]; - - urls.sort(function(a, b) { - return Math.random() - 0.5; - }); - - switch (method) { - case 1: - urls.forEach(function(url) { - let loc = url.href + url.leaf; - vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }); - }); - vs.commitScripts(); - break; - - case 2: - urls.forEach(function(url) { - let loc = url.href + url.leaf; - vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true); - }); - break; - - case 3: - let i = 0 - for (; i < urls.length / 2; i++) { - let url = urls[i]; - let loc = url.href + url.leaf; - vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }); - } - vs.commitScripts(); - - for (; i < urls.length; i++) { - let url = urls[i]; - let loc = url.href + url.leaf; - vs.addScript(ss._getScriptLabel(loc, url.href), { url: loc }, true); - } - break; - } - - executeSoon(function() { - checkScriptsOrder(method); - callback(); - }); -} - -function checkScriptsOrder(method) { - let labels = gDebugger.DebuggerView.Scripts.scriptLabels; - let sorted = labels.reduce(function(prev, curr, index, array) { - return array[index - 1] < array[index]; - }); - - ok(sorted, - "Using method " + method + ", " + - "the scripts weren't in the correct order: " + labels.toSource()); - - return sorted; -} - -registerCleanupFunction(function() { - removeTab(gTab); - gPane = null; - gTab = null; - gDebuggee = null; - gDebugger = null; -});
--- a/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js +++ b/browser/devtools/debugger/test/browser_dbg_update-editor-mode.js @@ -17,48 +17,42 @@ var gTab = null; var gDebuggee = null; var gDebugger = null; var gScripts = null; function test() { let scriptShown = false; let framesAdded = false; - let testStarted = false; - let resumed = false; debug_tab_pane(TAB_URL, function(aTab, aDebuggee, aPane) { gTab = aTab; gDebuggee = aDebuggee; gPane = aPane; gDebugger = gPane.debuggerWindow; - resumed = true; gDebugger.DebuggerController.activeThread.addOneTimeListener("framesadded", function() { framesAdded = true; - executeSoon(startTest); + runTest(); }); - - executeSoon(function() { - gDebuggee.firstCall(); - }); + gDebuggee.firstCall(); }); - function onScriptShown(aEvent) { - scriptShown = aEvent.detail.url.indexOf("test-editor-mode") != -1; - executeSoon(startTest); - } + window.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { + let url = aEvent.detail.url; + if (url.indexOf("editor-mode") != -1) { + scriptShown = true; + window.removeEventListener(aEvent.type, _onEvent); + runTest(); + } + }); - window.addEventListener("Debugger:ScriptShown", onScriptShown); - - function startTest() + function runTest() { - if (scriptShown && framesAdded && resumed && !testStarted) { - window.removeEventListener("Debugger:ScriptShown", onScriptShown); - testStarted = true; + if (scriptShown && framesAdded) { Services.tm.currentThread.dispatch({ run: testScriptsDisplay }, 0); } } } function testScriptsDisplay() { gScripts = gDebugger.DebuggerView.Scripts._scripts;
--- a/browser/devtools/debugger/test/head.js +++ b/browser/devtools/debugger/test/head.js @@ -87,35 +87,22 @@ function attach_thread_actor_for_url(aCl }); }); } function debug_tab_pane(aURL, aOnDebugging) { let tab = addTab(aURL, function() { gBrowser.selectedTab = gTab; + let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject; let pane = DebuggerUI.toggleDebugger(); pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() { pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true); // Wait for the initial resume... pane.debuggerWindow.gClient.addOneTimeListener("resumed", function() { aOnDebugging(tab, debuggee, pane); }); }, true); }); } - -function remote_debug_tab_pane(aURL, aOnClosing, aOnDebugging) -{ - let tab = addTab(aURL, function() { - gBrowser.selectedTab = gTab; - let debuggee = tab.linkedBrowser.contentWindow.wrappedJSObject; - - DebuggerUI.toggleRemoteDebugger(aOnClosing, function dbgRan(process) { - - // Wait for the remote debugging process to start... - aOnDebugging(tab, debuggee, process); - }); - }); -}
--- a/browser/devtools/highlighter/inspector.jsm +++ b/browser/devtools/highlighter/inspector.jsm @@ -393,17 +393,17 @@ InspectorUI.prototype = { /** * Is the inspector UI open? Simply check if the toolbar is visible or not. * * @returns boolean */ get isInspectorOpen() { - return !!(this.toolbar && !this.toolbar.hidden && this.highlighter); + return this.toolbar && !this.toolbar.hidden && this.highlighter; }, /** * Return the default selection element for the inspected document. */ get defaultSelection() { let doc = this.win.document; @@ -642,17 +642,17 @@ InspectorUI.prototype = { this.breadcrumbs.destroy(); this.breadcrumbs = null; } delete this._currentInspector; if (!aKeepInspector) this.store.deleteInspector(this.winID); - this.inspectMenuitem.removeAttribute("checked"); + this.inspectMenuitem.setAttribute("checked", false); this.browser = this.win = null; // null out references to browser and window this.winID = null; this.selection = null; this.closing = false; this.isDirty = false; delete this.treePanel; delete this.stylePanel;
--- a/browser/devtools/jar.mn +++ b/browser/devtools/jar.mn @@ -12,10 +12,8 @@ browser.jar: * content/browser/devtools/layoutview/view.xhtml (layoutview/view.xhtml) content/browser/devtools/layoutview/view.css (layoutview/view.css) content/browser/orion.js (sourceeditor/orion/orion.js) * content/browser/source-editor-overlay.xul (sourceeditor/source-editor-overlay.xul) * content/browser/debugger.xul (debugger/debugger.xul) content/browser/debugger.css (debugger/debugger.css) content/browser/debugger-controller.js (debugger/debugger-controller.js) content/browser/debugger-view.js (debugger/debugger-view.js) - content/browser/devtools/gcli.css (webconsole/gcli.css) - content/browser/devtools/gcliblank.xhtml (webconsole/gcliblank.xhtml)
deleted file mode 100644 --- a/browser/devtools/shared/DeveloperToolbar.jsm +++ /dev/null @@ -1,476 +0,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 the Firefox Developer Toolbar. - * - * The Initial Developer of the Original Code is - * The Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2012 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Dave Camp <dcamp@mozilla.com> (Original Author) - * Joe Walker <jwalker@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 ***** */ - -"use strict"; - -Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); -Components.utils.import("resource://gre/modules/Services.jsm"); - -let EXPORTED_SYMBOLS = [ "DeveloperToolbar", "loadCommands" ]; - -XPCOMUtils.defineLazyGetter(this, "gcli", function () { - let obj = {}; - Components.utils.import("resource:///modules/gcli.jsm", obj); - return obj.gcli; -}); - -let console = gcli._internal.console; - -/** - * Load the various Command JSMs. - * Should be called when the developer toolbar first opens. - */ -function loadCommands() -{ - Components.utils.import("resource:///modules/GcliCommands.jsm", {}); - Components.utils.import("resource:///modules/GcliTiltCommands.jsm", {}); -} - - - -let commandsLoaded = false; - -/** - * A component to manage the global developer toolbar, which contains a GCLI - * and buttons for various developer tools. - * @param aChromeWindow The browser window to which this toolbar is attached - * @param aToolbarElement See browser.xul:<toolbar id="developer-toolbar"> - */ -function DeveloperToolbar(aChromeWindow, aToolbarElement) -{ - if (!commandsLoaded) { - loadCommands(); - commandsLoaded = true; - } - - this._chromeWindow = aChromeWindow; - - this._element = aToolbarElement; - this._element.hidden = true; - this._doc = this._element.ownerDocument; - - this._command = this._doc.getElementById("Tools:DevToolbar"); - - aChromeWindow.getBrowser().tabContainer.addEventListener("TabSelect", this, false); -} - -/** - * Inspector notifications dispatched through the nsIObserverService - */ -const NOTIFICATIONS = { - /** DeveloperToolbar.show() has been called */ - SHOW: "developer-toolbar-show", - - /** DeveloperToolbar.hide() has been called */ - HIDE: "developer-toolbar-hide" -}; - -/** - * Attach notification constants to the object prototype so tests etc can - * use them without needing to import anything - */ -DeveloperToolbar.prototype.NOTIFICATIONS = NOTIFICATIONS; - -/** - * Is the toolbar open? - */ -Object.defineProperty(DeveloperToolbar.prototype, 'visible', { - get: function DT_visible() { - return !this._element.hidden; - }, - enumerable: true -}); - -/** - * Called from browser.xul in response to menu-click or keyboard shortcut to - * toggle the toolbar - */ -DeveloperToolbar.prototype.toggle = function DT_toggle() -{ - if (this.visible) { - this.hide(); - } else { - this.show(); - this._input.focus(); - } -}; - -/** - * Even if the user has not clicked on 'Got it' in the intro, we only show it - * once per session. - * Warning this is slightly messed up because this.DeveloperToolbar is not the - * same as this.DeveloperToolbar when in browser.js context. - */ -DeveloperToolbar.introShownThisSession = false; - -/** - * Show the developer toolbar - */ -DeveloperToolbar.prototype.show = function DT_show() -{ - this._command.setAttribute("checked", "true"); - - this._input = this._doc.querySelector(".gclitoolbar-input-node"); - - this.tooltipPanel = new TooltipPanel(this._doc, this._input); - this.outputPanel = new OutputPanel(this._doc, this._input); - - let contentDocument = this._chromeWindow.getBrowser().contentDocument; - - this.display = gcli._internal.createDisplay({ - contentDocument: contentDocument, - chromeDocument: this._doc, - chromeWindow: this._chromeWindow, - - hintElement: this.tooltipPanel.hintElement, - inputElement: this._input, - completeElement: this._doc.querySelector(".gclitoolbar-complete-node"), - backgroundElement: this._doc.querySelector(".gclitoolbar-stack-node"), - outputDocument: this.outputPanel.document, - - environment: { - chromeDocument: this._doc, - contentDocument: contentDocument - }, - - tooltipClass: 'gcliterm-tooltip', - eval: null, - scratchpad: null - }); - - this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel); - this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel); - this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel); - - this._element.hidden = false; - this._notify(NOTIFICATIONS.SHOW); - - if (!DeveloperToolbar.introShownThisSession) { - this.display.maybeShowIntro(); - DeveloperToolbar.introShownThisSession = true; - } -}; - -/** - * Hide the developer toolbar - */ -DeveloperToolbar.prototype.hide = function DT_hide() -{ - this._command.setAttribute("checked", "false"); - - this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel); - this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel); - this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel); - this.display.destroy(); - - // We could "delete this.display" etc if we have hard-to-track-down memory - // leaks as a belt-and-braces approach, however this prevents our DOM node - // hunter from looking in all the nooks and crannies, so it's better if we - // can be leak-free without - - this.outputPanel.remove(); - delete this.outputPanel; - - this.tooltipPanel.remove(); - delete this.tooltipPanel; - - this._element.hidden = true; - this._notify(NOTIFICATIONS.HIDE); -}; - -/** - * Utility for sending notifications - * @param aTopic a NOTIFICATION constant - */ -DeveloperToolbar.prototype._notify = function DT_notify(aTopic) -{ - let data = { toolbar: this }; - data.wrappedJSObject = data; - Services.obs.notifyObservers(data, aTopic, null); -}; - -/** - * Update various parts of the UI when the current tab changes - * @param aEvent - */ -DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent) -{ - if (aEvent.type == "TabSelect") { - this._chromeWindow.HUDConsoleUI.refreshCommand(); - this._chromeWindow.DebuggerUI.refreshCommand(); - - if (this.visible) { - let contentDocument = this._chromeWindow.getBrowser().contentDocument; - - this.display.reattach({ - contentDocument: contentDocument, - chromeWindow: this._chromeWindow, - environment: { - chromeDocument: this._doc, - contentDocument: contentDocument - }, - }); - } - } -}; - -/** - * Add class="gcli-panel-inner-arrowcontent" to a panel's - * |<xul:box class="panel-inner-arrowcontent">| so we can alter the styling - * without complex CSS expressions. - * @param aPanel The panel to affect - */ -function getContentBox(aPanel) -{ - let container = aPanel.ownerDocument.getAnonymousElementByAttribute( - aPanel, "anonid", "container"); - return container.querySelector(".panel-inner-arrowcontent"); -} - -/** - * Helper function to calculate the sum of the vertical padding and margins - * between a nested node |aNode| and an ancestor |aRoot|. Iff all of the - * children of aRoot are 'only-childs' until you get to aNode then to avoid - * scroll-bars, the 'correct' height of aRoot is verticalSpacing + aNode.height. - * @param aNode The child node whose height is known. - * @param aRoot The parent height whose height we can affect. - * @return The sum of the vertical padding/margins in between aNode and aRoot. - */ -function getVerticalSpacing(aNode, aRoot) -{ - let win = aNode.ownerDocument.defaultView; - - function pxToNum(styles, property) { - return parseInt(styles.getPropertyValue(property).replace(/px$/, ''), 10); - } - - let vertSpacing = 0; - do { - let styles = win.getComputedStyle(aNode); - vertSpacing += pxToNum(styles, "padding-top"); - vertSpacing += pxToNum(styles, "padding-bottom"); - vertSpacing += pxToNum(styles, "margin-top"); - vertSpacing += pxToNum(styles, "margin-bottom"); - vertSpacing += pxToNum(styles, "border-top-width"); - vertSpacing += pxToNum(styles, "border-bottom-width"); - - let prev = aNode.previousSibling; - while (prev != null) { - vertSpacing += prev.clientHeight; - prev = prev.previousSibling; - } - - let next = aNode.nextSibling; - while (next != null) { - vertSpacing += next.clientHeight; - next = next.nextSibling; - } - - aNode = aNode.parentNode; - } while (aNode !== aRoot); - - return vertSpacing + 9; -} - -/** - * Panel to handle command line output. - * @param aChromeDoc document from which we can pull the parts we need. - * @param aInput the input element that should get focus. - */ -function OutputPanel(aChromeDoc, aInput) -{ - this._input = aInput; - this._panel = aChromeDoc.getElementById("gcli-output"); - this._frame = aChromeDoc.getElementById("gcli-output-frame"); - this._anchor = aChromeDoc.getElementById("developer-toolbar"); - - this._content = getContentBox(this._panel); - this._content.classList.add("gcli-panel-inner-arrowcontent"); - - this.document = this._frame.contentDocument; - this.document.body.classList.add("gclichrome-output"); - - this._div = this.document.querySelector("div"); - this._div.classList.add('gcli-row-out'); - this._div.setAttribute('aria-live', 'assertive'); - - this.displayedOutput = undefined; -} - -/** - * Display the OutputPanel. - */ -OutputPanel.prototype.show = function OP_show() -{ - this._panel.ownerDocument.defaultView.setTimeout(function() { - this._resize(); - }.bind(this), 0); - - this._resize(); - this._panel.openPopup(this._anchor, "before_end", -300, 0, false, false, null); - - this._input.focus(); -}; - -/** - * Internal helper to set the height of the output panel to fit the available - * content; - */ -OutputPanel.prototype._resize = function CLP_resize() -{ - let vertSpacing = getVerticalSpacing(this._content, this._panel); - let idealHeight = this.document.body.scrollHeight + vertSpacing; - this._panel.sizeTo(400, Math.min(idealHeight, 500)); -}; - -/** - * Called by GCLI when a command is executed. - */ -OutputPanel.prototype._outputChanged = function OP_outputChanged(aEvent) -{ - if (aEvent.output.hidden) { - return; - } - - this.remove(); - - this.displayedOutput = aEvent.output; - this.update(); - - this.displayedOutput.onChange.add(this.update, this); - this.displayedOutput.onClose.add(this.remove, this); -}; - -/** - * Called when displayed Output says it's changed or from outputChanged, which - * happens when there is a new displayed Output. - */ -OutputPanel.prototype.update = function OP_update() -{ - if (this.displayedOutput.data == null) { - while (this._div.hasChildNodes()) { - this._div.removeChild(this._div.firstChild); - } - } else { - this.displayedOutput.toDom(this._div); - this.show(); - } -}; - -/** - * Detach listeners from the currently displayed Output. - */ -OutputPanel.prototype.remove = function OP_remove() -{ - this._panel.hidePopup(); - - if (this.displayedOutput) { - this.displayedOutput.onChange.remove(this.update, this); - this.displayedOutput.onClose.remove(this.remove, this); - delete this.displayedOutput; - } -}; - -/** - * Called by GCLI to indicate that we should show or hide one either the - * tooltip panel or the output panel. - */ -OutputPanel.prototype._visibilityChanged = function OP_visibilityChanged(aEvent) -{ - if (aEvent.outputVisible === true) { - // this.show is called by _outputChanged - } else { - this._panel.hidePopup(); - } -}; - - -/** - * Panel to handle tooltips. - * @param aChromeDoc document from which we can pull the parts we need. - * @param aInput the input element that should get focus. - */ -function TooltipPanel(aChromeDoc, aInput) -{ - this._input = aInput; - this._panel = aChromeDoc.getElementById("gcli-tooltip"); - this._frame = aChromeDoc.getElementById("gcli-tooltip-frame"); - this._anchor = aChromeDoc.getElementById("developer-toolbar"); - - this._content = getContentBox(this._panel); - this._content.classList.add("gcli-panel-inner-arrowcontent"); - - this.document = this._frame.contentDocument; - this.document.body.classList.add("gclichrome-tooltip"); - - this.hintElement = this.document.querySelector("div"); -} - -/** - * Display the TooltipPanel. - */ -TooltipPanel.prototype.show = function TP_show() -{ - let vertSpacing = getVerticalSpacing(this._content, this._panel); - let idealHeight = this.document.body.scrollHeight + vertSpacing; - this._panel.sizeTo(350, Math.min(idealHeight, 500)); - this._panel.openPopup(this._anchor, "before_start", 0, 0, false, false, null); - - this._input.focus(); -}; - -/** - * Hide the TooltipPanel. - */ -TooltipPanel.prototype.remove = function TP_remove() -{ - this._panel.hidePopup(); -}; - -/** - * Called by GCLI to indicate that we should show or hide one either the - * tooltip panel or the output panel. - */ -TooltipPanel.prototype._visibilityChanged = function TP_visibilityChanged(aEvent) -{ - if (aEvent.tooltipVisible === true) { - this.show(); - } else { - this._panel.hidePopup(); - } -};
--- a/browser/devtools/shared/Templater.jsm +++ b/browser/devtools/shared/Templater.jsm @@ -37,64 +37,43 @@ * ***** END LICENSE BLOCK ***** */ var EXPORTED_SYMBOLS = [ "Templater", "template" ]; Components.utils.import("resource://gre/modules/Services.jsm"); const Node = Components.interfaces.nsIDOMNode; -/** - * For full documentation, see: - * https://github.com/mozilla/domtemplate/blob/master/README.md - */ - // WARNING: do not 'use_strict' without reading the notes in _envEval(); /** * Begin a new templating process. * @param node A DOM element or string referring to an element's id * @param data Data to use in filling out the template * @param options Options to customize the template processing. One of: * - allowEval: boolean (default false) Basic template interpolations are - * either property paths (e.g. ${a.b.c.d}), or if allowEval=true then we - * allow arbitrary JavaScript - * - stack: string or array of strings (default empty array) The template - * engine maintains a stack of tasks to help debug where it is. This allows - * this stack to be prefixed with a template name - * - blankNullUndefined: By default DOMTemplate exports null and undefined - * values using the strings 'null' and 'undefined', which can be helpful for - * debugging, but can introduce unnecessary extra logic in a template to - * convert null/undefined to ''. By setting blankNullUndefined:true, this - * conversion is handled by DOMTemplate + * either property paths (e.g. ${a.b.c.d}), however if allowEval=true then we + * allow arbitrary JavaScript */ function template(node, data, options) { var template = new Templater(options || {}); template.processNode(node, data); return template; } /** * Construct a Templater object. Use template() in preference to this ctor. * @deprecated Use template(node, data, options); */ function Templater(options) { if (options == null) { options = { allowEval: true }; } this.options = options; - if (options.stack && Array.isArray(options.stack)) { - this.stack = options.stack; - } - else if (typeof options.stack === 'string') { - this.stack = [ options.stack ]; - } - else { - this.stack = []; - } + this.stack = []; } /** * Cached regex used to find ${...} sections in some text. * Performance note: This regex uses ( and ) to capture the 'script' for * further processing. Not all of the uses of this regex use this feature so * if use of the capturing group is a performance drain then we should split * this regex in two. @@ -106,17 +85,17 @@ Templater.prototype._templateRegion = /\ * See Templater._processTextNode() for details. */ Templater.prototype._splitSpecial = /\uF001|\uF002/; /** * Cached regex used to detect if a script is capable of being interpreted * using Template._property() or if we need to use Template._envEval() */ -Templater.prototype._isPropertyScript = /^[_a-zA-Z0-9.]*$/; +Templater.prototype._isPropertyScript = /^[a-zA-Z0-9.]*$/; /** * Recursive function to walk the tree processing the attributes as it goes. * @param node the node to process. If you pass a string in instead of a DOM * element, it is assumed to be an id for use with document.getElementById() * @param data the data to use for node processing. */ Templater.prototype.processNode = function(node, data) { @@ -169,21 +148,17 @@ Templater.prototype.processNode = functi var capture = node.hasAttribute('capture' + name.substring(2)); node.addEventListener(name.substring(2), func, capture); if (capture) { node.removeAttribute('capture' + name.substring(2)); } } else { // Replace references in all other attributes var newValue = value.replace(this._templateRegion, function(path) { - var insert = this._envEval(path.slice(2, -1), data, value); - if (this.options.blankNullUndefined && insert == null) { - insert = ''; - } - return insert; + return this._envEval(path.slice(2, -1), data, value); }.bind(this)); // Remove '_' prefix of attribute names so the DOM won't try // to use them before we've processed the template if (name.charAt(0) === '_') { node.removeAttribute(name); node.setAttribute(name.substring(1), newValue); } else if (value !== newValue) { attrs[i].value = newValue; @@ -197,17 +172,17 @@ Templater.prototype.processNode = functi // Loop through our children calling processNode. First clone them, so the // set of nodes that we visit will be unaffected by additions or removals. var childNodes = Array.prototype.slice.call(node.childNodes); for (var j = 0; j < childNodes.length; j++) { this.processNode(childNodes[j], data); } - if (node.nodeType === 3 /*Node.TEXT_NODE*/) { + if (node.nodeType === Node.TEXT_NODE) { this._processTextNode(node, data); } } finally { delete data.__element; this.stack.pop(); } }; @@ -367,51 +342,40 @@ Templater.prototype._processTextNode = f parts.forEach(function(part) { if (part === null || part === undefined || part === '') { return; } if (part.charAt(0) === '$') { part = this._envEval(part.slice(1), data, node.data); } this._handleAsync(part, node, function(reply, siblingNode) { - var doc = siblingNode.ownerDocument; - if (reply == null) { - reply = this.options.blankNullUndefined ? '' : '' + reply; - } - if (typeof reply.cloneNode === 'function') { - // i.e. if (reply instanceof Element) { ... - reply = this._maybeImportNode(reply, doc); - siblingNode.parentNode.insertBefore(reply, siblingNode); - } else if (typeof reply.item === 'function' && reply.length) { - // if thing is a NodeList, then import the children - for (var i = 0; i < reply.length; i++) { - var child = this._maybeImportNode(reply.item(i), doc); - siblingNode.parentNode.insertBefore(child, siblingNode); - } - } - else { - // if thing isn't a DOM element then wrap its string value in one - reply = doc.createTextNode(reply.toString()); - siblingNode.parentNode.insertBefore(reply, siblingNode); - } - + reply = this._toNode(reply, siblingNode.ownerDocument); + siblingNode.parentNode.insertBefore(reply, siblingNode); }.bind(this)); }, this); node.parentNode.removeChild(node); } }; /** - * Return node or a import of node, if it's not in the given document - * @param node The node that we want to be properly owned - * @param doc The document that the given node should belong to - * @return A node that belongs to the given document + * Helper to convert a 'thing' to a DOM Node. + * This is (obviously) a no-op for DOM Elements (which are detected using + * 'typeof thing.cloneNode !== "function"' (is there a better way that will + * work in all environments, including a .jsm?) + * Non DOM elements are converted to a string and wrapped in a TextNode. */ -Templater.prototype._maybeImportNode = function(node, doc) { - return node.ownerDocument === doc ? node : doc.importNode(node, true); +Templater.prototype._toNode = function(thing, document) { + if (thing == null) { + thing = '' + thing; + } + // if thing isn't a DOM element then wrap its string value in one + if (typeof thing.cloneNode !== 'function') { + thing = document.createTextNode(thing.toString()); + } + return thing; }; /** * A function to handle the fact that some nodes can be promises, so we check * and resolve if needed using a marker node to keep our place before calling * an inserter function. * @param thing The object which could be real data or a promise of real data * we use it directly if it's not a promise, or resolve it if it is. @@ -460,38 +424,38 @@ Templater.prototype._stripBraces = funct * a string to be cut into an array using <tt>split('.')</tt> * @param data the data to use for node processing * @param newValue (optional) If defined, this value will replace the * original value for the data at the path specified. * @return The value pointed to by <tt>path</tt> before any * <tt>newValue</tt> is applied. */ Templater.prototype._property = function(path, data, newValue) { + this.stack.push(path); try { if (typeof path === 'string') { path = path.split('.'); } var value = data[path[0]]; if (path.length === 1) { if (newValue !== undefined) { data[path[0]] = newValue; } if (typeof value === 'function') { return value.bind(data); } return value; } if (!value) { - this._handleError('"' + path[0] + '" is undefined'); + this._handleError('Can\'t find path=' + path); return null; } return this._property(path.slice(1), value, newValue); - } catch (ex) { - this._handleError('Path error with \'' + path + '\'', ex); - return '${' + path + '}'; + } finally { + this.stack.pop(); } }; /** * Like eval, but that creates a context of the variables in <tt>env</tt> in * which the script is evaluated. * WARNING: This script uses 'with' which is generally regarded to be evil. * The alternative is to create a Function at runtime that takes X parameters @@ -500,45 +464,47 @@ Templater.prototype._property = function * @param script The string to be evaluated. * @param data The environment in which to eval the script. * @param frame Optional debugging string in case of failure. * @return The return value of the script, or the error message if the script * execution failed. */ Templater.prototype._envEval = function(script, data, frame) { try { - this.stack.push(frame.replace(/\s+/g, ' ')); + this.stack.push(frame); if (this._isPropertyScript.test(script)) { return this._property(script, data); } else { if (!this.options.allowEval) { this._handleError('allowEval is not set, however \'' + script + '\'' + ' can not be resolved using a simple property path.'); return '${' + script + '}'; } with (data) { return eval(script); } } } catch (ex) { - this._handleError('Template error evaluating \'' + script + '\'', ex); + this._handleError('Template error evaluating \'' + script + '\'' + + ' environment=' + Object.keys(data).join(', '), ex); return '${' + script + '}'; } finally { this.stack.pop(); } }; /** * A generic way of reporting errors, for easy overloading in different * environments. * @param message the error message to report. * @param ex optional associated exception. */ Templater.prototype._handleError = function(message, ex) { - this._logError(message + ' (In: ' + this.stack.join(' > ') + ')'); + this._logError(message); + this._logError('In: ' + this.stack.join(' > ')); if (ex) { this._logError(ex); } }; /** * A generic way of reporting errors, for easy overloading in different
--- a/browser/devtools/shared/test/Makefile.in +++ b/browser/devtools/shared/test/Makefile.in @@ -44,30 +44,20 @@ VPATH = @srcdir@ relativesrcdir = browser/devtools/shared/test include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _BROWSER_TEST_FILES = \ browser_promise_basic.js \ browser_templater_basic.js \ - browser_toolbar_basic.js \ - browser_gcli_commands.js \ - browser_gcli_inspect.js \ - browser_gcli_integrate.js \ - browser_gcli_require.js \ - browser_gcli_web.js \ - browser_gcli_break.js \ head.js \ $(NULL) _BROWSER_TEST_PAGES = \ browser_templater_basic.html \ - browser_toolbar_basic.html \ - browser_gcli_inspect.html \ - browser_gcli_break.html \ $(NULL) libs:: $(_BROWSER_TEST_FILES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir) libs:: $(_BROWSER_TEST_PAGES) $(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/browser/$(relativesrcdir)
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_break.html +++ /dev/null @@ -1,19 +0,0 @@ -<!DOCTYPE HTML> -<html> - <head> - <meta charset="utf-8"> - <title>Browser GCLI break command test</title> - <!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> - <script type="text/javascript"> - function firstCall() { - eval("window.line0 = Error().lineNumber; secondCall();"); - } - function secondCall() { - eval("debugger;"); - } - </script> - </head> - <body> - </body> -</html>
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_break.js +++ /dev/null @@ -1,82 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that the break command works as it should - -const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_break.html"; - -function test() { - DeveloperToolbarTest.test(TEST_URI, function(browser, tab) { - testBreakCommands(); - }); -} - -function testBreakCommands() { - DeveloperToolbarTest.checkInputStatus({ - typed: "brea", - directTabText: "k", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "break", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "break add", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "break add line", - emptyParameters: [ " <file>", " <line>" ], - status: "ERROR" - }); - - let pane = DebuggerUI.toggleDebugger(); - pane._frame.addEventListener("Debugger:Connecting", function dbgConnected() { - pane._frame.removeEventListener("Debugger:Connecting", dbgConnected, true); - - // Wait for the initial resume. - let client = pane.debuggerWindow.gClient; - client.addOneTimeListener("resumed", function() { - client.activeThread.addOneTimeListener("framesadded", function() { - DeveloperToolbarTest.checkInputStatus({ - typed: "break add line " + TEST_URI + " " + content.wrappedJSObject.line0, - status: "VALID" - }); - DeveloperToolbarTest.exec({ - args: { - type: 'line', - file: TEST_URI, - line: content.wrappedJSObject.line0 - }, - completed: false - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "break list", - status: "VALID" - }); - DeveloperToolbarTest.exec(); - - client.activeThread.resume(function() { - DeveloperToolbarTest.checkInputStatus({ - typed: "break del 0", - status: "VALID" - }); - DeveloperToolbarTest.exec({ - args: { breakid: 0 }, - completed: false - }); - - finish(); - }); - }); - - // Trigger newScript notifications using eval. - content.wrappedJSObject.firstCall(); - }); - }, true); -}
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_commands.js +++ /dev/null @@ -1,55 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Test various GCLI commands - -let imported = {}; -Components.utils.import("resource:///modules/HUDService.jsm", imported); - -const TEST_URI = "data:text/html;charset=utf-8,gcli-commands"; - -function test() { - DeveloperToolbarTest.test(TEST_URI, function(browser, tab) { - testEcho(); - testConsoleClear(); - testConsoleOpenClose(tab); - - imported = undefined; - finish(); - }); -} - -function testEcho() { - DeveloperToolbarTest.exec({ - typed: "echo message", - args: { message: "message" }, - outputMatch: /^message$/, - }); -} - -function testConsoleClear() { - DeveloperToolbarTest.exec({ - typed: "console clear", - args: {}, - blankOutput: true, - }); -} - -function testConsoleOpenClose(tab) { - DeveloperToolbarTest.exec({ - typed: "console open", - args: {}, - blankOutput: true, - }); - - let hud = imported.HUDService.getHudByWindow(content); - ok(hud.hudId in imported.HUDService.hudReferences, "console open"); - - DeveloperToolbarTest.exec({ - typed: "console close", - args: {}, - blankOutput: true, - }); - - ok(!(hud.hudId in imported.HUDService.hudReferences), "console closed"); -}
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_inspect.html +++ /dev/null @@ -1,25 +0,0 @@ -<!doctype html> -<html lang="en"> -<head> - <meta charset="utf-8"> - <title>GCLI inspect command test</title> -</head> -<body> - - <!-- This is a list of 0 h1 elements --> - - <!-- This is a list of 1 div elements --> - <div>Hello, I'm a div</div> - - <!-- This is a list of 2 span elements --> - <span>Hello, I'm a span</span> - <span>And me</span> - - <!-- This is a collection of various things that match only once --> - <p class="someclass">.someclass</p> - <p id="someid">#someid</p> - <button disabled>button[disabled]</button> - <p><strong>p>strong</strong></p> - -</body> -</html>
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_inspect.js +++ /dev/null @@ -1,68 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that the inspect command works as it should - -const TEST_URI = "http://example.com/browser/browser/devtools/shared/test/browser_gcli_inspect.html"; - -function test() { - DeveloperToolbarTest.test(TEST_URI, function(browser, tab) { - testInspect(); - - finish(); - }); -} - -function testInspect() { - DeveloperToolbarTest.checkInputStatus({ - typed: "inspec", - directTabText: "t", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect", - emptyParameters: [ " <node>" ], - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect h1", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect span", - status: "ERROR" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect div", - status: "VALID" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect .someclass", - status: "VALID" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect #someid", - status: "VALID" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect button[disabled]", - status: "VALID" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect p>strong", - status: "VALID" - }); - - DeveloperToolbarTest.checkInputStatus({ - typed: "inspect :root", - status: "VALID" - }); -}
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_integrate.js +++ /dev/null @@ -1,40 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that source URLs in the Web Console can be clicked to display the -// standard View Source window. - -function test() { - testCreateCommands(); - testRemoveCommands(); -} - -let tselarr = { - name: 'tselarr', - params: [ - { name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } }, - { name: 'arr', type: { name: 'array', subtype: 'string' } }, - ], - exec: function(args, env) { - return "flu " + args.num + "-" + args.arr.join("_"); - } -}; - -function testCreateCommands() { - let gcliIndex = require("gcli/index"); - gcliIndex.addCommand(tselarr); - - let canon = require("gcli/canon"); - let tselcmd = canon.getCommand("tselarr"); - ok(tselcmd != null, "tselarr exists in the canon"); - ok(tselcmd instanceof canon.Command, "canon storing commands"); -} - -function testRemoveCommands() { - let gcliIndex = require("gcli/index"); - gcliIndex.removeCommand(tselarr); - - let canon = require("gcli/canon"); - let tselcmd = canon.getCommand("tselarr"); - ok(tselcmd == null, "tselcmd removed from the canon"); -}
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_require.js +++ /dev/null @@ -1,105 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - * http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that source URLs in the Web Console can be clicked to display the -// standard View Source window. - -function test() { - define('gclitest/requirable', [], function(require, exports, module) { - exports.thing1 = 'thing1'; - exports.thing2 = 2; - - let status = 'initial'; - exports.setStatus = function(aStatus) { status = aStatus; }; - exports.getStatus = function() { return status; }; - }); - - define('gclitest/unrequirable', [], function(require, exports, module) { - null.throwNPE(); - }); - - define('gclitest/recurse', [], function(require, exports, module) { - require('gclitest/recurse'); - }); - - testWorking(); - testLeakage(); - testMultiImport(); - testRecursive(); - testUncompilable(); - - delete define.modules['gclitest/requirable']; - delete define.globalDomain.modules['gclitest/requirable']; - delete define.modules['gclitest/unrequirable']; - delete define.globalDomain.modules['gclitest/unrequirable']; - delete define.modules['gclitest/recurse']; - delete define.globalDomain.modules['gclitest/recurse']; - - finish(); -} - -function testWorking() { - // There are lots of requirement tests that we could be doing here - // The fact that we can get anything at all working is a testament to - // require doing what it should - we don't need to test the - let requireable = require('gclitest/requirable'); - ok('thing1' == requireable.thing1, 'thing1 was required'); - ok(2 == requireable.thing2, 'thing2 was required'); - ok(requireable.thing3 === undefined, 'thing3 was not required'); -} - -function testDomains() { - let requireable = require('gclitest/requirable'); - ok(requireable.status === undefined, 'requirable has no status'); - requireable.setStatus(null); - ok(null === requireable.getStatus(), 'requirable.getStatus changed to null'); - ok(requireable.status === undefined, 'requirable still has no status'); - requireable.setStatus('42'); - ok('42' == requireable.getStatus(), 'requirable.getStatus changed to 42'); - ok(requireable.status === undefined, 'requirable *still* has no status'); - - let domain = new define.Domain(); - let requireable2 = domain.require('gclitest/requirable'); - ok(requireable2.status === undefined, 'requirable2 has no status'); - ok('initial' === requireable2.getStatus(), 'requirable2.getStatus is initial'); - requireable2.setStatus(999); - ok(999 === requireable2.getStatus(), 'requirable2.getStatus changed to 999'); - ok(requireable2.status === undefined, 'requirable2 still has no status'); - - t.verifyEqual('42', requireable.getStatus()); - ok(requireable.status === undefined, 'requirable has no status (as expected)'); - - delete domain.modules['gclitest/requirable']; -} - -function testLeakage() { - let requireable = require('gclitest/requirable'); - ok(requireable.setup == null, 'leakage of setup'); - ok(requireable.shutdown == null, 'leakage of shutdown'); - ok(requireable.testWorking == null, 'leakage of testWorking'); -} - -function testMultiImport() { - let r1 = require('gclitest/requirable'); - let r2 = require('gclitest/requirable'); - ok(r1 === r2, 'double require was strict equal'); -} - -function testUncompilable() { - // It's not totally clear how a module loader should perform with unusable - // modules, however at least it should go into a flat spin ... - // GCLI mini_require reports an error as it should - try { - let unrequireable = require('gclitest/unrequirable'); - fail(); - } - catch (ex) { - // an exception is expected - } -} - -function testRecursive() { - // See Bug 658583 - // require('gclitest/recurse'); - // Also see the comments in the testRecursive() function -}
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_gcli_web.js +++ /dev/null @@ -1,2939 +0,0 @@ -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -/* - * - * - * - * - * - * - * - *********************************** WARNING *********************************** - * - * Do not edit this file without understanding where it comes from, - * Your changes are likely to be overwritten without warning. - * - * This test file is generated using a level 25 wizard spell cast on the - * test files that run in the browser as part of GCLI's test suite. - * For details of how to cast the spell, see GCLI's gcli.js - * - * For more information on GCLI see: - * - https://github.com/mozilla/gcli/blob/master/docs/index.md - * - https://wiki.mozilla.org/DevTools/Features/GCLI - * - * The original source for this file is: - * https://github.com/mozilla/gcli/ - * - ******************************************************************************* - * - * - * - * - * - * - * - * - * - */ - -/////////////////////////////////////////////////////////////////////////////// -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/index', ['require', 'exports', 'module' , 'gclitest/suite'], function(require, exports, module) { - - var examiner = require('gclitest/suite').examiner; - - // A minimum fake dom to get us through the JS tests - var fakeWindow = { - isFake: true, - document: { title: 'Fake DOM' } - }; - fakeWindow.window = fakeWindow; - examiner.defaultOptions = { - window: fakeWindow, - hideExec: true - }; - - /** - * A simple proxy to examiner.run, for convenience - this is run from the - * top level. - * @param options Lookup of options that customize test running. Includes: - * - window (default=undefined) A reference to the DOM window. If left - * undefined then a reduced set of tests will run. - * - isNode (default=false) Are we running under NodeJS, specifically, are we - * using JSDom, which isn't a 100% complete DOM implementation. - * Some tests are skipped when using NodeJS. - * - display (default=undefined) A reference to a Display implementation. - * A reduced set of tests will run if left undefined - * - detailedResultLog (default=false) do we output a test summary to - * |console.log| on test completion. - * - hideExec (default=false) Set the |hidden| property in calls to - * |requisition.exec()| which prevents the display from becoming messed up, - * however use of hideExec restricts the set of tests that are run - */ - exports.run = function(options) { - examiner.run(options || {}); - - // A better set of default than those specified above, come from the set - // that are passed to run(). - examiner.defaultOptions = { - window: options.window, - display: options.display, - hideExec: options.hideExec - }; - }; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/suite', ['require', 'exports', 'module' , 'gcli/index', 'test/examiner', 'gclitest/testCli', 'gclitest/testCompletion', 'gclitest/testExec', 'gclitest/testHistory', 'gclitest/testJs', 'gclitest/testKeyboard', 'gclitest/testRequire', 'gclitest/testResource', 'gclitest/testScratchpad', 'gclitest/testSpell', 'gclitest/testSplit', 'gclitest/testTokenize', 'gclitest/testTooltip', 'gclitest/testTypes', 'gclitest/testUtil'], function(require, exports, module) { - - // We need to make sure GCLI is initialized before we begin testing it - require('gcli/index'); - - var examiner = require('test/examiner'); - - // It's tempting to want to unify these strings and make addSuite() do the - // call to require(), however that breaks the build system which looks for - // the strings passed to require - examiner.addSuite('gclitest/testCli', require('gclitest/testCli')); - examiner.addSuite('gclitest/testCompletion', require('gclitest/testCompletion')); - examiner.addSuite('gclitest/testExec', require('gclitest/testExec')); - examiner.addSuite('gclitest/testHistory', require('gclitest/testHistory')); - examiner.addSuite('gclitest/testJs', require('gclitest/testJs')); - examiner.addSuite('gclitest/testKeyboard', require('gclitest/testKeyboard')); - examiner.addSuite('gclitest/testRequire', require('gclitest/testRequire')); - examiner.addSuite('gclitest/testResource', require('gclitest/testResource')); - examiner.addSuite('gclitest/testScratchpad', require('gclitest/testScratchpad')); - examiner.addSuite('gclitest/testSpell', require('gclitest/testSpell')); - examiner.addSuite('gclitest/testSplit', require('gclitest/testSplit')); - examiner.addSuite('gclitest/testTokenize', require('gclitest/testTokenize')); - examiner.addSuite('gclitest/testTooltip', require('gclitest/testTooltip')); - examiner.addSuite('gclitest/testTypes', require('gclitest/testTypes')); - examiner.addSuite('gclitest/testUtil', require('gclitest/testUtil')); - - exports.examiner = examiner; -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('test/examiner', ['require', 'exports', 'module' ], function(require, exports, module) { -var examiner = exports; - - -/** - * Test harness data - */ -examiner.suites = {}; - -/** - * The gap between tests when running async - */ -var delay = 10; - -var currentTest = null; - -var stati = { - notrun: { index: 0, name: 'Skipped' }, - executing: { index: 1, name: 'Executing' }, - asynchronous: { index: 2, name: 'Waiting' }, - pass: { index: 3, name: 'Pass' }, - fail: { index: 4, name: 'Fail' } -}; - -/** - * Add a test suite. Generally used like: - * test.addSuite('foo', require('path/to/foo')); - */ -examiner.addSuite = function(name, suite) { - examiner.suites[name] = new Suite(name, suite); -}; - -/** - * When run from an command, there are some options that we can't (and - * shouldn't) specify, so we allow a set of default options, which are merged - * with the specified options in |run()|. - */ -examiner.defaultOptions = {}; - -/** - * Add properties to |options| from |examiner.defaultOptions| when |options| - * does not have a value for a given name. - */ -function mergeDefaultOptions(options) { - Object.keys(examiner.defaultOptions).forEach(function(name) { - if (options[name] == null) { - options[name] = examiner.defaultOptions[name]; - } - }); -} - -/** - * Run the tests defined in the test suite synchronously - */ -examiner.run = function(options) { - mergeDefaultOptions(options); - - Object.keys(examiner.suites).forEach(function(suiteName) { - var suite = examiner.suites[suiteName]; - suite.run(options); - }.bind(this)); - - if (options.detailedResultLog) { - examiner.detailedResultLog(); - } - else { - console.log('Completed test suite'); - } - - return examiner.suites; -}; - -/** - * Run all the tests asynchronously - */ -examiner.runAsync = function(options, callback) { - mergeDefaultOptions(options); - this._runAsyncInternal(0, options, callback); -}; - -/** - * Run all the test suits asynchronously - */ -examiner._runAsyncInternal = function(i, options, callback) { - if (i >= Object.keys(examiner.suites).length) { - if (typeof callback === 'function') { - callback(); - } - return; - } - - var suiteName = Object.keys(examiner.suites)[i]; - examiner.suites[suiteName].runAsync(options, function() { - setTimeout(function() { - examiner._runAsyncInternal(i + 1, options, callback); - }.bind(this), delay); - }.bind(this)); -}; - -/** - * Create a JSON object suitable for serialization - */ -examiner.toRemote = function() { - return { - suites: Object.keys(examiner.suites).map(function(suiteName) { - return examiner.suites[suiteName].toRemote(); - }.bind(this)), - summary: { - checks: this.checks, - status: this.status - } - }; -}; - -/** - * The number of checks in this set of test suites is the sum of the checks in - * the test suites. - */ -Object.defineProperty(examiner, 'checks', { - get: function() { - return Object.keys(examiner.suites).reduce(function(current, suiteName) { - return current + examiner.suites[suiteName].checks; - }.bind(this), 0); - }, - enumerable: true -}); - -/** - * The status of this set of test suites is the worst of the statuses of the - * contained test suites. - */ -Object.defineProperty(examiner, 'status', { - get: function() { - return Object.keys(examiner.suites).reduce(function(status, suiteName) { - var suiteStatus = examiner.suites[suiteName].status; - return status.index > suiteStatus.index ? status : suiteStatus; - }.bind(this), stati.notrun); - }, - enumerable: true -}); - -/** - * Output a test summary to console.log - */ -examiner.detailedResultLog = function() { - Object.keys(this.suites).forEach(function(suiteName) { - var suite = examiner.suites[suiteName]; - - console.log(suite.name + ': ' + suite.status.name + ' (funcs=' + - Object.keys(suite.tests).length + - ', checks=' + suite.checks + ')'); - - Object.keys(suite.tests).forEach(function(testName) { - var test = suite.tests[testName]; - if (test.status !== stati.pass || test.failures.length !== 0) { - console.log('- ' + test.name + ': ' + test.status.name); - test.failures.forEach(function(failure) { - console.log(' - ' + failure.message); - if (failure.expected) { - console.log(' - Expected: ' + failure.expected); - console.log(' - Actual: ' + failure.actual); - } - }.bind(this)); - } - }.bind(this)); - }.bind(this)); - - console.log(); - console.log('Summary: ' + this.status.name + ' (' + this.checks + ' checks)'); -}; - -/** - * Used by assert to record a failure against the current test - * @param failure A set of properties describing the failure. Properties include: - * - message (string, required) A message describing the test - * - expected (optional) The expected data - * - actual (optional) The actual data - */ -examiner.recordFailure = function(failure) { - if (!currentTest) { - console.error('No currentTest for ' + failure.message); - return; - } - - currentTest.status = stati.fail; - currentTest.failures.push(failure); -}; - -/** - * Used by assert to record a check pass - */ -examiner.recordPass = function() { - if (!currentTest) { - console.error('No currentTest'); - return; - } - - currentTest.checks++; -}; - -/** - * When we want to note something alongside a test - */ -examiner.log = function(message) { - currentTest.failures.push({ message: message }); -}; - -/** - * A suite is a group of tests - */ -function Suite(suiteName, suite) { - this.name = suiteName.replace(/gclitest\//, ''); - this.suite = suite; - - this.tests = {}; - Object.keys(suite).forEach(function(testName) { - if (testName !== 'setup' && testName !== 'shutdown') { - var test = new Test(this, testName, suite[testName]); - this.tests[testName] = test; - } - }.bind(this)); -} - -/** - * Run all the tests in this suite synchronously - */ -Suite.prototype.run = function(options) { - if (!this._setup(options)) { - return; - } - - Object.keys(this.tests).forEach(function(testName) { - var test = this.tests[testName]; - test.run(options); - }.bind(this)); - - this._shutdown(options); -}; - -/** - * Run all the tests in this suite asynchronously - */ -Suite.prototype.runAsync = function(options, callback) { - if (!this._setup(options)) { - if (typeof callback === 'function') { - callback(); - } - return; - } - - this._runAsyncInternal(0, options, function() { - this._shutdown(options); - - if (typeof callback === 'function') { - callback(); - } - }.bind(this)); -}; - -/** - * Function used by the async runners that can handle async recursion. - */ -Suite.prototype._runAsyncInternal = function(i, options, callback) { - if (i >= Object.keys(this.tests).length) { - if (typeof callback === 'function') { - callback(); - } - return; - } - - var testName = Object.keys(this.tests)[i]; - this.tests[testName].runAsync(options, function() { - setTimeout(function() { - this._runAsyncInternal(i + 1, options, callback); - }.bind(this), delay); - }.bind(this)); -}; - -/** - * Create a JSON object suitable for serialization - */ -Suite.prototype.toRemote = function() { - return { - name: this.name, - tests: Object.keys(this.tests).map(function(testName) { - return this.tests[testName].toRemote(); - }.bind(this)) - }; -}; - -/** - * The number of checks in this suite is the sum of the checks in the contained - * tests. - */ -Object.defineProperty(Suite.prototype, 'checks', { - get: function() { - return Object.keys(this.tests).reduce(function(prevChecks, testName) { - return prevChecks + this.tests[testName].checks; - }.bind(this), 0); - }, - enumerable: true -}); - -/** - * The status of a test suite is the worst of the statuses of the contained - * tests. - */ -Object.defineProperty(Suite.prototype, 'status', { - get: function() { - return Object.keys(this.tests).reduce(function(prevStatus, testName) { - var suiteStatus = this.tests[testName].status; - return prevStatus.index > suiteStatus.index ? prevStatus : suiteStatus; - }.bind(this), stati.notrun); - }, - enumerable: true -}); - -/** - * Defensively setup the test suite - */ -Suite.prototype._setup = function(options) { - if (typeof this.suite.setup !== 'function') { - return true; - } - - try { - this.suite.setup(options); - return true; - } - catch (ex) { - this._logToAllTests(stati.notrun, '' + ex); - console.error(ex); - if (ex.stack) { - console.error(ex.stack); - } - return false; - } -}; - -/** - * Defensively shutdown the test suite - */ -Suite.prototype._shutdown = function(options) { - if (typeof this.suite.shutdown !== 'function') { - return true; - } - - try { - this.suite.shutdown(options); - return true; - } - catch (ex) { - this._logToAllTests(stati.fail, '' + ex); - console.error(ex); - if (ex.stack) { - console.error(ex.stack); - } - return false; - } -}; - -/** - * Something has gone wrong that affects all tests in this Suite - */ -Suite.prototype._logToAllTests = function(status, message) { - Object.keys(this.tests).forEach(function(testName) { - var test = this.tests[testName]; - test.status = status; - test.failures.push({ message: message }); - }.bind(this)); -}; - - -/** - * A test represents data about a single test function - */ -function Test(suite, name, func) { - this.suite = suite; - this.name = name; - this.func = func; - this.title = name.replace(/^test/, '').replace(/([A-Z])/g, ' $1'); - - this.failures = []; - this.status = stati.notrun; - this.checks = 0; -} - -/** - * Run just a single test - */ -Test.prototype.run = function(options) { - currentTest = this; - this.status = stati.executing; - this.failures = []; - this.checks = 0; - - try { - this.func.apply(this.suite, [ options ]); - } - catch (ex) { - this.status = stati.fail; - this.failures.push({ message: '' + ex }); - console.error(ex); - if (ex.stack) { - console.error(ex.stack); - } - } - - if (this.status === stati.executing) { - this.status = stati.pass; - } - - currentTest = null; -}; - -/** - * Run all the tests in this suite asynchronously - */ -Test.prototype.runAsync = function(options, callback) { - setTimeout(function() { - this.run(options); - if (typeof callback === 'function') { - callback(); - } - }.bind(this), delay); -}; - -/** - * Create a JSON object suitable for serialization - */ -Test.prototype.toRemote = function() { - return { - name: this.name, - title: this.title, - status: this.status, - failures: this.failures, - checks: this.checks - }; -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testCli', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gclitest/commands', 'test/assert'], function(require, exports, module) { - - -var Requisition = require('gcli/cli').Requisition; -var Status = require('gcli/types').Status; -var commands = require('gclitest/commands'); - -var test = require('test/assert'); - -exports.setup = function() { - commands.setup(); -}; - -exports.shutdown = function() { - commands.shutdown(); -}; - - -var assign1; -var assign2; -var assignC; -var requ; -var debug = false; -var status; -var statuses; - -function update(input) { - if (!requ) { - requ = new Requisition(); - } - requ.update(input.typed); - - if (debug) { - console.log('####### TEST: typed="' + input.typed + - '" cur=' + input.cursor.start + - ' cli=', requ); - } - - status = requ.getStatus(); - assignC = requ.getAssignmentAt(input.cursor.start); - statuses = requ.getInputStatusMarkup(input.cursor.start).map(function(s) { - return Array(s.string.length + 1).join(s.status.toString()[0]); - }).join(''); - - if (requ.commandAssignment.value) { - assign1 = requ.getAssignment(0); - assign2 = requ.getAssignment(1); - } - else { - assign1 = undefined; - assign2 = undefined; - } -} - -function verifyPredictionsContains(name, predictions) { - return predictions.every(function(prediction) { - return name === prediction.name; - }, this); -} - - -exports.testBlank = function() { - update({ typed: '', cursor: { start: 0, end: 0 } }); - test.is( '', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is(undefined, requ.commandAssignment.value); - - update({ typed: ' ', cursor: { start: 1, end: 1 } }); - test.is( 'V', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is(undefined, requ.commandAssignment.value); - - update({ typed: ' ', cursor: { start: 0, end: 0 } }); - test.is( 'V', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is(undefined, requ.commandAssignment.value); -}; - -exports.testIncompleteMultiMatch = function() { - update({ typed: 't', cursor: { start: 1, end: 1 } }); - test.is( 'I', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.ok(assignC.getPredictions().length > 0); - verifyPredictionsContains('tsv', assignC.getPredictions()); - verifyPredictionsContains('tsr', assignC.getPredictions()); - test.is(undefined, requ.commandAssignment.value); -}; - -exports.testIncompleteSingleMatch = function() { - update({ typed: 'tselar', cursor: { start: 6, end: 6 } }); - test.is( 'IIIIII', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is(1, assignC.getPredictions().length); - test.is('tselarr', assignC.getPredictions()[0].name); - test.is(undefined, requ.commandAssignment.value); -}; - -exports.testTsv = function() { - update({ typed: 'tsv', cursor: { start: 3, end: 3 } }); - test.is( 'VVV', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is('tsv', requ.commandAssignment.value.name); - - update({ typed: 'tsv ', cursor: { start: 4, end: 4 } }); - test.is( 'VVVV', statuses); - test.is(Status.ERROR, status); - test.is(0, assignC.paramIndex); - test.is('tsv', requ.commandAssignment.value.name); - - update({ typed: 'tsv ', cursor: { start: 2, end: 2 } }); - test.is( 'VVVV', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is('tsv', requ.commandAssignment.value.name); - - update({ typed: 'tsv o', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVI', statuses); - test.is(Status.ERROR, status); - test.is(0, assignC.paramIndex); - test.ok(assignC.getPredictions().length >= 2); - test.is(commands.option1, assignC.getPredictions()[0].value); - test.is(commands.option2, assignC.getPredictions()[1].value); - test.is('tsv', requ.commandAssignment.value.name); - test.is('o', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsv option', cursor: { start: 10, end: 10 } }); - test.is( 'VVVVIIIIII', statuses); - test.is(Status.ERROR, status); - test.is(0, assignC.paramIndex); - test.ok(assignC.getPredictions().length >= 2); - test.is(commands.option1, assignC.getPredictions()[0].value); - test.is(commands.option2, assignC.getPredictions()[1].value); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsv option', cursor: { start: 1, end: 1 } }); - test.is( 'VVVVEEEEEE', statuses); - test.is(Status.ERROR, status); - test.is(-1, assignC.paramIndex); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsv option ', cursor: { start: 11, end: 11 } }); - test.is( 'VVVVEEEEEEV', statuses); - test.is(Status.ERROR, status); - test.is(1, assignC.paramIndex); - test.is(0, assignC.getPredictions().length); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsv option1', cursor: { start: 11, end: 11 } }); - test.is( 'VVVVVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option1', assign1.arg.text); - test.is(commands.option1, assign1.value); - test.is(0, assignC.paramIndex); - - update({ typed: 'tsv option1 ', cursor: { start: 12, end: 12 } }); - test.is( 'VVVVVVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option1', assign1.arg.text); - test.is(commands.option1, assign1.value); - test.is(1, assignC.paramIndex); - - update({ typed: 'tsv option1 6', cursor: { start: 13, end: 13 } }); - test.is( 'VVVVVVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option1', assign1.arg.text); - test.is(commands.option1, assign1.value); - test.is('6', assign2.arg.text); - test.is('6', assign2.value); - test.is('string', typeof assign2.value); - test.is(1, assignC.paramIndex); - - update({ typed: 'tsv option2 6', cursor: { start: 13, end: 13 } }); - test.is( 'VVVVVVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsv', requ.commandAssignment.value.name); - test.is('option2', assign1.arg.text); - test.is(commands.option2, assign1.value); - test.is('6', assign2.arg.text); - test.is(6, assign2.value); - test.is('number', typeof assign2.value); - test.is(1, assignC.paramIndex); -}; - -exports.testInvalid = function() { - update({ typed: 'zxjq', cursor: { start: 4, end: 4 } }); - test.is( 'EEEE', statuses); - test.is('zxjq', requ.commandAssignment.arg.text); - test.is('', requ._unassigned.arg.text); - test.is(-1, assignC.paramIndex); - - update({ typed: 'zxjq ', cursor: { start: 5, end: 5 } }); - test.is( 'EEEEV', statuses); - test.is('zxjq', requ.commandAssignment.arg.text); - test.is('', requ._unassigned.arg.text); - test.is(-1, assignC.paramIndex); - - update({ typed: 'zxjq one', cursor: { start: 8, end: 8 } }); - test.is( 'EEEEVEEE', statuses); - test.is('zxjq', requ.commandAssignment.arg.text); - test.is('one', requ._unassigned.arg.text); -}; - -exports.testSingleString = function() { - update({ typed: 'tsr', cursor: { start: 3, end: 3 } }); - test.is( 'VVV', statuses); - test.is(Status.ERROR, status); - test.is('tsr', requ.commandAssignment.value.name); - test.ok(assign1.arg.isBlank()); - test.is(undefined, assign1.value); - test.is(undefined, assign2); - - update({ typed: 'tsr ', cursor: { start: 4, end: 4 } }); - test.is( 'VVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsr', requ.commandAssignment.value.name); - test.ok(assign1.arg.isBlank()); - test.is(undefined, assign1.value); - test.is(undefined, assign2); - - update({ typed: 'tsr h', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsr', requ.commandAssignment.value.name); - test.is('h', assign1.arg.text); - test.is('h', assign1.value); - - update({ typed: 'tsr "h h"', cursor: { start: 9, end: 9 } }); - test.is( 'VVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsr', requ.commandAssignment.value.name); - test.is('h h', assign1.arg.text); - test.is('h h', assign1.value); - - update({ typed: 'tsr h h h', cursor: { start: 9, end: 9 } }); - test.is( 'VVVVVVVVV', statuses); - test.is('tsr', requ.commandAssignment.value.name); - test.is('h h h', assign1.arg.text); - test.is('h h h', assign1.value); -}; - -exports.testSingleNumber = function() { - update({ typed: 'tsu', cursor: { start: 3, end: 3 } }); - test.is( 'VVV', statuses); - test.is(Status.ERROR, status); - test.is('tsu', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsu ', cursor: { start: 4, end: 4 } }); - test.is( 'VVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsu', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsu 1', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsu', requ.commandAssignment.value.name); - test.is('1', assign1.arg.text); - test.is(1, assign1.value); - test.is('number', typeof assign1.value); - - update({ typed: 'tsu x', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVE', statuses); - test.is(Status.ERROR, status); - test.is('tsu', requ.commandAssignment.value.name); - test.is('x', assign1.arg.text); - test.is(undefined, assign1.value); -}; - -exports.testElement = function(options) { - update({ typed: 'tse', cursor: { start: 3, end: 3 } }); - test.is( 'VVV', statuses); - test.is(Status.ERROR, status); - test.is('tse', requ.commandAssignment.value.name); - test.ok(assign1.arg.isBlank()); - test.is(undefined, assign1.value); - - update({ typed: 'tse :root', cursor: { start: 9, end: 9 } }); - test.is( 'VVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tse', requ.commandAssignment.value.name); - test.is(':root', assign1.arg.text); - if (!options.window.isFake) { - test.is(options.window.document.documentElement, assign1.value); - } - - if (!options.window.isFake) { - var inputElement = options.window.document.getElementById('gcli-input'); - if (inputElement) { - update({ typed: 'tse #gcli-input', cursor: { start: 15, end: 15 } }); - test.is( 'VVVVVVVVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tse', requ.commandAssignment.value.name); - test.is('#gcli-input', assign1.arg.text); - test.is(inputElement, assign1.value); - } - else { - test.log('Skipping test that assumes gcli on the web'); - } - } - - update({ typed: 'tse #gcli-nomatch', cursor: { start: 17, end: 17 } }); - // This is somewhat debatable because this input can't be corrected simply - // by typing so it's and error rather than incomplete, however without - // digging into the CSS engine we can't tell that so we default to incomplete - test.is( 'VVVVIIIIIIIIIIIII', statuses); - test.is(Status.ERROR, status); - test.is('tse', requ.commandAssignment.value.name); - test.is('#gcli-nomatch', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tse #', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVE', statuses); - test.is(Status.ERROR, status); - test.is('tse', requ.commandAssignment.value.name); - test.is('#', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tse .', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVE', statuses); - test.is(Status.ERROR, status); - test.is('tse', requ.commandAssignment.value.name); - test.is('.', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tse *', cursor: { start: 5, end: 5 } }); - test.is( 'VVVVE', statuses); - test.is(Status.ERROR, status); - test.is('tse', requ.commandAssignment.value.name); - test.is('*', assign1.arg.text); - test.is(undefined, assign1.value); -}; - -exports.testNestedCommand = function() { - update({ typed: 'tsn', cursor: { start: 3, end: 3 } }); - test.is( 'III', statuses); - test.is(Status.ERROR, status); - test.is('tsn', requ.commandAssignment.arg.text); - test.is(undefined, assign1); - - update({ typed: 'tsn ', cursor: { start: 4, end: 4 } }); - test.is( 'IIIV', statuses); - test.is(Status.ERROR, status); - test.is('tsn', requ.commandAssignment.arg.text); - test.is(undefined, assign1); - - update({ typed: 'tsn x', cursor: { start: 5, end: 5 } }); - // Commented out while we try out fuzzy matching - // test.is( 'EEEVE', statuses); - test.is(Status.ERROR, status); - test.is('tsn x', requ.commandAssignment.arg.text); - test.is(undefined, assign1); - - update({ typed: 'tsn dif', cursor: { start: 7, end: 7 } }); - test.is( 'VVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn dif', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsn dif ', cursor: { start: 8, end: 8 } }); - test.is( 'VVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn dif', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsn dif x', cursor: { start: 9, end: 9 } }); - test.is( 'VVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsn dif', requ.commandAssignment.value.name); - test.is('x', assign1.arg.text); - test.is('x', assign1.value); - - update({ typed: 'tsn ext', cursor: { start: 7, end: 7 } }); - test.is( 'VVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn ext', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsn exte', cursor: { start: 8, end: 8 } }); - test.is( 'VVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn exte', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsn exten', cursor: { start: 9, end: 9 } }); - test.is( 'VVVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn exten', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'tsn extend', cursor: { start: 10, end: 10 } }); - test.is( 'VVVVVVVVVV', statuses); - test.is(Status.ERROR, status); - test.is('tsn extend', requ.commandAssignment.value.name); - test.is('', assign1.arg.text); - test.is(undefined, assign1.value); - - update({ typed: 'ts ', cursor: { start: 3, end: 3 } }); - test.is( 'EEV', statuses); - test.is(Status.ERROR, status); - test.is('ts', requ.commandAssignment.arg.text); - test.is(undefined, assign1); -}; - -// From Bug 664203 -exports.testDeeplyNested = function() { - update({ typed: 'tsn deep down nested cmd', cursor: { start: 24, end: 24 } }); - test.is( 'VVVVVVVVVVVVVVVVVVVVVVVV', statuses); - test.is(Status.VALID, status); - test.is('tsn deep down nested cmd', requ.commandAssignment.value.name); - test.is(undefined, assign1); - - update({ typed: 'tsn deep down nested', cursor: { start: 20, end: 20 } }); - test.is( 'IIIVIIIIVIIIIVIIIIII', statuses); - test.is(Status.ERROR, status); - test.is('tsn deep down nested', requ.commandAssignment.value.name); - test.is(undefined, assign1); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/commands', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/util', 'gcli/types/selection', 'gcli/types/basic', 'gcli/types'], function(require, exports, module) { -var commands = exports; - - -var canon = require('gcli/canon'); -var util = require('gcli/util'); - -var SelectionType = require('gcli/types/selection').SelectionType; -var DeferredType = require('gcli/types/basic').DeferredType; -var types = require('gcli/types'); - -/** - * Registration and de-registration. - */ -commands.setup = function() { - // setup/shutdown need to register/unregister types, however that means we - // need to re-initialize commands.option1 and commands.option2 with the - // actual types - commands.option1.type = types.getType('string'); - commands.option2.type = types.getType('number'); - - types.registerType(commands.optionType); - types.registerType(commands.optionValue); - - canon.addCommand(commands.tsv); - canon.addCommand(commands.tsr); - canon.addCommand(commands.tse); - canon.addCommand(commands.tsj); - canon.addCommand(commands.tsb); - canon.addCommand(commands.tss); - canon.addCommand(commands.tsu); - canon.addCommand(commands.tsn); - canon.addCommand(commands.tsnDif); - canon.addCommand(commands.tsnExt); - canon.addCommand(commands.tsnExte); - canon.addCommand(commands.tsnExten); - canon.addCommand(commands.tsnExtend); - canon.addCommand(commands.tsnDeep); - canon.addCommand(commands.tsnDeepDown); - canon.addCommand(commands.tsnDeepDownNested); - canon.addCommand(commands.tsnDeepDownNestedCmd); - canon.addCommand(commands.tselarr); - canon.addCommand(commands.tsm); - canon.addCommand(commands.tsg); -}; - -commands.shutdown = function() { - canon.removeCommand(commands.tsv); - canon.removeCommand(commands.tsr); - canon.removeCommand(commands.tse); - canon.removeCommand(commands.tsj); - canon.removeCommand(commands.tsb); - canon.removeCommand(commands.tss); - canon.removeCommand(commands.tsu); - canon.removeCommand(commands.tsn); - canon.removeCommand(commands.tsnDif); - canon.removeCommand(commands.tsnExt); - canon.removeCommand(commands.tsnExte); - canon.removeCommand(commands.tsnExten); - canon.removeCommand(commands.tsnExtend); - canon.removeCommand(commands.tsnDeep); - canon.removeCommand(commands.tsnDeepDown); - canon.removeCommand(commands.tsnDeepDownNested); - canon.removeCommand(commands.tsnDeepDownNestedCmd); - canon.removeCommand(commands.tselarr); - canon.removeCommand(commands.tsm); - canon.removeCommand(commands.tsg); - - types.deregisterType(commands.optionType); - types.deregisterType(commands.optionValue); -}; - - -commands.option1 = { type: types.getType('string') }; -commands.option2 = { type: types.getType('number') }; - -var lastOption = undefined; - -commands.optionType = new SelectionType({ - name: 'optionType', - lookup: [ - { name: 'option1', value: commands.option1 }, - { name: 'option2', value: commands.option2 } - ], - noMatch: function() { - lastOption = undefined; - }, - stringify: function(option) { - lastOption = option; - return SelectionType.prototype.stringify.call(this, option); - }, - parse: function(arg) { - var conversion = SelectionType.prototype.parse.call(this, arg); - lastOption = conversion.value; - return conversion; - } -}); - -commands.optionValue = new DeferredType({ - name: 'optionValue', - defer: function() { - if (lastOption && lastOption.type) { - return lastOption.type; - } - else { - return types.getType('blank'); - } - } -}); - -commands.onCommandExec = util.createEvent('commands.onCommandExec'); - -function createExec(name) { - return function(args, context) { - var data = { - command: commands[name], - args: args, - context: context - }; - commands.onCommandExec(data); - return data; - }; -} - -commands.tsv = { - name: 'tsv', - params: [ - { name: 'optionType', type: 'optionType' }, - { name: 'optionValue', type: 'optionValue' } - ], - exec: createExec('tsv') -}; - -commands.tsr = { - name: 'tsr', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('tsr') -}; - -commands.tse = { - name: 'tse', - params: [ { name: 'node', type: 'node' } ], - exec: createExec('tse') -}; - -commands.tsj = { - name: 'tsj', - params: [ { name: 'javascript', type: 'javascript' } ], - exec: createExec('tsj') -}; - -commands.tsb = { - name: 'tsb', - params: [ { name: 'toggle', type: 'boolean' } ], - exec: createExec('tsb') -}; - -commands.tss = { - name: 'tss', - exec: createExec('tss') -}; - -commands.tsu = { - name: 'tsu', - params: [ { name: 'num', type: { name: 'number', max: 10, min: -5, step: 3 } } ], - exec: createExec('tsu') -}; - -commands.tsn = { - name: 'tsn' -}; - -commands.tsnDif = { - name: 'tsn dif', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('tsnDif') -}; - -commands.tsnExt = { - name: 'tsn ext', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('tsnExt') -}; - -commands.tsnExte = { - name: 'tsn exte', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('') -}; - -commands.tsnExten = { - name: 'tsn exten', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('tsnExte') -}; - -commands.tsnExtend = { - name: 'tsn extend', - params: [ { name: 'text', type: 'string' } ], - exec: createExec('tsnExtend') -}; - -commands.tsnDeep = { - name: 'tsn deep', -}; - -commands.tsnDeepDown = { - name: 'tsn deep down', -}; - -commands.tsnDeepDownNested = { - name: 'tsn deep down nested', -}; - -commands.tsnDeepDownNestedCmd = { - name: 'tsn deep down nested cmd', - exec: createExec('tsnDeepDownNestedCmd') -}; - -commands.tselarr = { - name: 'tselarr', - params: [ - { name: 'num', type: { name: 'selection', data: [ '1', '2', '3' ] } }, - { name: 'arr', type: { name: 'array', subtype: 'string' } }, - ], - exec: createExec('tselarr') -}; - -commands.tsm = { - name: 'tsm', - description: 'a 3-param test selection|string|number', - params: [ - { name: 'abc', type: { name: 'selection', data: [ 'a', 'b', 'c' ] } }, - { name: 'txt', type: 'string' }, - { name: 'num', type: { name: 'number', max: 42, min: 0 } }, - ], - exec: createExec('tsm') -}; - -commands.tsg = { - name: 'tsg', - description: 'a param group test', - params: [ - { name: 'solo', type: { name: 'selection', data: [ 'aaa', 'bbb', 'ccc' ] } }, - { - group: 'First', - params: [ - { name: 'txt1', type: 'string', defaultValue: null }, - { name: 'bool', type: 'boolean' } - ] - }, - { - group: 'Second', - params: [ - { name: 'txt2', type: 'string', defaultValue: 'd' }, - { name: 'num', type: { name: 'number', min: 40 }, defaultValue: 42 } - ] - } - ], - exec: createExec('tsg') -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('test/assert', ['require', 'exports', 'module' ], function(require, exports, module) { - - exports.ok = ok; - exports.is = is; - exports.log = info; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testCompletion', ['require', 'exports', 'module' , 'test/assert', 'gclitest/commands'], function(require, exports, module) { - - -var test = require('test/assert'); -var commands = require('gclitest/commands'); - - -exports.setup = function() { - commands.setup(); -}; - -exports.shutdown = function() { - commands.shutdown(); -}; - - -function type(typed, tests, options) { - var inputter = options.display.inputter; - var completer = options.display.completer; - - inputter.setInput(typed); - - if (tests.cursor) { - inputter.setCursor({ start: tests.cursor, end: tests.cursor }); - } - - if (tests.emptyParameters == null) { - tests.emptyParameters = []; - } - - var realParams = completer.emptyParameters; - test.is(tests.emptyParameters.length, realParams.length, - 'emptyParameters.length for \'' + typed + '\''); - - if (realParams.length === tests.emptyParameters.length) { - for (var i = 0; i < realParams.length; i++) { - test.is(tests.emptyParameters[i], realParams[i].replace(/\u00a0/g, ' '), - 'emptyParameters[' + i + '] for \'' + typed + '\''); - } - } - - if (tests.directTabText) { - test.is(tests.directTabText, completer.directTabText, - 'directTabText for \'' + typed + '\''); - } - else { - test.is('', completer.directTabText, - 'directTabText for \'' + typed + '\''); - } - - if (tests.arrowTabText) { - test.is(' \u00a0\u21E5 ' + tests.arrowTabText, - completer.arrowTabText, - 'arrowTabText for \'' + typed + '\''); - } - else { - test.is('', completer.arrowTabText, - 'arrowTabText for \'' + typed + '\''); - } -} - -exports.testActivate = function(options) { - if (!options.display) { - test.log('No display. Skipping activate tests'); - return; - } - - type('', { }, options); - - type(' ', { }, options); - - type('tsr', { - emptyParameters: [ ' <text>' ] - }, options); - - type('tsr ', { - emptyParameters: [ '<text>' ] - }, options); - - type('tsr b', { }, options); - - type('tsb', { - emptyParameters: [ ' [toggle]' ] - }, options); - - type('tsm', { - emptyParameters: [ ' <abc>', ' <txt>', ' <num>' ] - }, options); - - type('tsm ', { - emptyParameters: [ ' <txt>', ' <num>' ], - directTabText: 'a' - }, options); - - type('tsm a', { - emptyParameters: [ ' <txt>', ' <num>' ] - }, options); - - type('tsm a ', { - emptyParameters: [ '<txt>', ' <num>' ] - }, options); - - type('tsm a ', { - emptyParameters: [ '<txt>', ' <num>' ] - }, options); - - type('tsm a d', { - emptyParameters: [ ' <num>' ] - }, options); - - type('tsm a "d d"', { - emptyParameters: [ ' <num>' ] - }, options); - - type('tsm a "d ', { - emptyParameters: [ ' <num>' ] - }, options); - - type('tsm a "d d" ', { - emptyParameters: [ '<num>' ] - }, options); - - type('tsm a "d d ', { - emptyParameters: [ ' <num>' ] - }, options); - - type('tsm d r', { - emptyParameters: [ ' <num>' ] - }, options); - - type('tsm a d ', { - emptyParameters: [ '<num>' ] - }, options); - - type('tsm a d 4', { }, options); - - type('tsg', { - emptyParameters: [ ' <solo>' ] - }, options); - - type('tsg ', { - directTabText: 'aaa' - }, options); - - type('tsg a', { - directTabText: 'aa' - }, options); - - type('tsg b', { - directTabText: 'bb' - }, options); - - type('tsg d', { }, options); - - type('tsg aa', { - directTabText: 'a' - }, options); - - type('tsg aaa', { }, options); - - type('tsg aaa ', { }, options); - - type('tsg aaa d', { }, options); - - type('tsg aaa dddddd', { }, options); - - type('tsg aaa dddddd ', { }, options); - - type('tsg aaa "d', { }, options); - - type('tsg aaa "d d', { }, options); - - type('tsg aaa "d d"', { }, options); - - type('tsn ex ', { }, options); - - type('selarr', { - arrowTabText: 'tselarr' - }, options); - - type('tselar 1', { }, options); - - type('tselar 1', { - cursor: 7 - }, options); - - type('tselar 1', { - cursor: 6, - arrowTabText: 'tselarr' - }, options); - - type('tselar 1', { - cursor: 5, - arrowTabText: 'tselarr' - }, options); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testExec', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/canon', 'gclitest/commands', 'gcli/types/node', 'test/assert'], function(require, exports, module) { - - -var Requisition = require('gcli/cli').Requisition; -var canon = require('gcli/canon'); -var commands = require('gclitest/commands'); -var nodetype = require('gcli/types/node'); - -var test = require('test/assert'); - -var actualExec; -var actualOutput; -var hideExec = false; - -exports.setup = function() { - commands.setup(); - commands.onCommandExec.add(commandExeced); - canon.commandOutputManager.onOutput.add(commandOutputed); -}; - -exports.shutdown = function() { - commands.shutdown(); - commands.onCommandExec.remove(commandExeced); - canon.commandOutputManager.onOutput.remove(commandOutputed); -}; - -function commandExeced(ev) { - actualExec = ev; -} - -function commandOutputed(ev) { - actualOutput = ev.output; -} - -function exec(command, expectedArgs) { - var environment = {}; - - var requisition = new Requisition(environment); - var outputObject = requisition.exec({ typed: command, hidden: hideExec }); - - test.is(command.indexOf(actualExec.command.name), 0, 'Command name: ' + command); - - test.is(command, outputObject.typed, 'outputObject.command for: ' + command); - test.ok(outputObject.completed, 'outputObject.completed false for: ' + command); - - if (expectedArgs == null) { - test.ok(false, 'expectedArgs == null for ' + command); - return; - } - if (actualExec.args == null) { - test.ok(false, 'actualExec.args == null for ' + command); - return; - } - - test.is(Object.keys(expectedArgs).length, Object.keys(actualExec.args).length, - 'Arg count: ' + command); - Object.keys(expectedArgs).forEach(function(arg) { - var expectedArg = expectedArgs[arg]; - var actualArg = actualExec.args[arg]; - - if (Array.isArray(expectedArg)) { - if (!Array.isArray(actualArg)) { - test.ok(false, 'actual is not an array. ' + command + '/' + arg); - return; - } - - test.is(expectedArg.length, actualArg.length, - 'Array length: ' + command + '/' + arg); - for (var i = 0; i < expectedArg.length; i++) { - test.is(expectedArg[i], actualArg[i], - 'Member: "' + command + '/' + arg + '/' + i); - } - } - else { - test.is(expectedArg, actualArg, 'Command: "' + command + '" arg: ' + arg); - } - }); - - test.is(environment, actualExec.context.environment, 'Environment'); - - if (!hideExec) { - test.is(false, actualOutput.error, 'output error is false'); - test.is(command, actualOutput.typed, 'command is typed'); - test.ok(typeof actualOutput.canonical === 'string', 'canonical exists'); - - test.is(actualExec.args, actualOutput.args, 'actualExec.args is actualOutput.args'); - } -} - - -exports.testExec = function(options) { - hideExec = options.hideExec; - - exec('tss', {}); - - // Bug 707008 - GCLI deferred types don't work properly - exec('tsv option1 10', { optionType: commands.option1, optionValue: '10' }); - exec('tsv option2 10', { optionType: commands.option2, optionValue: 10 }); - - exec('tsr fred', { text: 'fred' }); - exec('tsr fred bloggs', { text: 'fred bloggs' }); - exec('tsr "fred bloggs"', { text: 'fred bloggs' }); - - exec('tsb', { toggle: false }); - exec('tsb --toggle', { toggle: true }); - - exec('tsu 10', { num: 10 }); - exec('tsu --num 10', { num: 10 }); - - // Bug 704829 - Enable GCLI Javascript parameters - // The answer to this should be 2 - exec('tsj { 1 + 1 }', { javascript: '1 + 1' }); - - var origDoc = nodetype.getDocument(); - nodetype.setDocument(mockDoc); - exec('tse :root', { node: mockBody }); - nodetype.setDocument(origDoc); - - exec('tsn dif fred', { text: 'fred' }); - exec('tsn exten fred', { text: 'fred' }); - exec('tsn extend fred', { text: 'fred' }); - - exec('tselarr 1', { num: '1', arr: [ ] }); - exec('tselarr 1 a', { num: '1', arr: [ 'a' ] }); - exec('tselarr 1 a b', { num: '1', arr: [ 'a', 'b' ] }); - - exec('tsm a 10 10', { abc: 'a', txt: '10', num: 10 }); - - // Bug 707009 - GCLI doesn't always fill in default parameters properly - exec('tsg aaa', { solo: 'aaa', txt1: null, bool: false, txt2: 'd', num: 42 }); -}; - -var mockBody = { - style: {} -}; - -var mockDoc = { - querySelectorAll: function(css) { - if (css === ':root') { - return { - length: 1, - item: function(i) { - return mockBody; - } - }; - } - throw new Error('mockDoc.querySelectorAll(\'' + css + '\') error'); - } -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testHistory', ['require', 'exports', 'module' , 'test/assert', 'gcli/history'], function(require, exports, module) { - -var test = require('test/assert'); -var History = require('gcli/history').History; - -exports.setup = function() { -}; - -exports.shutdown = function() { -}; - -exports.testSimpleHistory = function () { - var history = new History({}); - history.add('foo'); - history.add('bar'); - test.is('bar', history.backward()); - test.is('foo', history.backward()); - - // Adding to the history again moves us back to the start of the history. - history.add('quux'); - test.is('quux', history.backward()); - test.is('bar', history.backward()); - test.is('foo', history.backward()); -}; - -exports.testBackwardsPastIndex = function () { - var history = new History({}); - history.add('foo'); - history.add('bar'); - test.is('bar', history.backward()); - test.is('foo', history.backward()); - - // Moving backwards past recorded history just keeps giving you the last - // item. - test.is('foo', history.backward()); -}; - -exports.testForwardsPastIndex = function () { - var history = new History({}); - history.add('foo'); - history.add('bar'); - test.is('bar', history.backward()); - test.is('foo', history.backward()); - - // Going forward through the history again. - test.is('bar', history.forward()); - - // 'Present' time. - test.is('', history.forward()); - - // Going to the 'future' just keeps giving us the empty string. - test.is('', history.forward()); -}; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testJs', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/types', 'gcli/types/javascript', 'gcli/canon', 'test/assert'], function(require, exports, module) { - - -var Requisition = require('gcli/cli').Requisition; -var Status = require('gcli/types').Status; -var javascript = require('gcli/types/javascript'); -var canon = require('gcli/canon'); - -var test = require('test/assert'); - -var debug = false; -var requ; - -var assign; -var status; -var statuses; -var tempWindow; - - -exports.setup = function(options) { - tempWindow = javascript.getGlobalObject(); - javascript.setGlobalObject(options.window); - - Object.defineProperty(options.window, 'donteval', { - get: function() { - test.ok(false, 'donteval should not be used'); - return { cant: '', touch: '', 'this': '' }; - }, - enumerable: true, - configurable : true - }); -}; - -exports.shutdown = function(options) { - delete options.window.donteval; - - javascript.setGlobalObject(tempWindow); - tempWindow = undefined; -}; - -function input(typed) { - if (!requ) { - requ = new Requisition(); - } - var cursor = { start: typed.length, end: typed.length }; - requ.update(typed); - - if (debug) { - console.log('####### TEST: typed="' + typed + - '" cur=' + cursor.start + - ' cli=', requ); - } - - status = requ.getStatus(); - statuses = requ.getInputStatusMarkup(cursor.start).map(function(s) { - return Array(s.string.length + 1).join(s.status.toString()[0]); - }).join(''); - - if (requ.commandAssignment.value) { - assign = requ.getAssignment(0); - } - else { - assign = undefined; - } -} - -function predictionsHas(name) { - return assign.getPredictions().some(function(prediction) { - return name === prediction.name; - }, this); -} - -function check(expStatuses, expStatus, expAssign, expPredict) { - test.is('{', requ.commandAssignment.value.name, 'is exec'); - - test.is(expStatuses, statuses, 'unexpected status markup'); - test.is(expStatus.toString(), status.toString(), 'unexpected status'); - test.is(expAssign, assign.value, 'unexpected assignment'); - - if (expPredict != null) { - var contains; - if (Array.isArray(expPredict)) { - expPredict.forEach(function(p) { - contains = predictionsHas(p); - test.ok(contains, 'missing prediction ' + p); - }); - } - else if (typeof expPredict === 'number') { - contains = true; - test.is(assign.getPredictions().length, expPredict, 'prediction count'); - if (assign.getPredictions().length !== expPredict) { - assign.getPredictions().forEach(function(prediction) { - test.log('actual prediction: ', prediction); - }); - } - } - else { - contains = predictionsHas(expPredict); - test.ok(contains, 'missing prediction ' + expPredict); - } - - if (!contains) { - test.log('Predictions: ' + assign.getPredictions().map(function(p) { - return p.name; - }).join(', ')); - } - } -} - -exports.testBasic = function(options) { - if (!canon.getCommand('{')) { - test.log('Skipping exec tests because { is not registered'); - return; - } - - input('{'); - check('V', Status.ERROR, undefined); - - input('{ '); - check('VV', Status.ERROR, undefined); - - input('{ w'); - check('VVI', Status.ERROR, 'w', 'window'); - - input('{ windo'); - check('VVIIIII', Status.ERROR, 'windo', 'window'); - - input('{ window'); - check('VVVVVVVV', Status.VALID, 'window'); - - input('{ window.d'); - check('VVIIIIIIII', Status.ERROR, 'window.d', 'window.document'); - - input('{ window.document.title'); - check('VVVVVVVVVVVVVVVVVVVVVVV', Status.VALID, 'window.document.title', 0); - - input('{ d'); - check('VVI', Status.ERROR, 'd', 'document'); - - input('{ document.title'); - check('VVVVVVVVVVVVVVVV', Status.VALID, 'document.title', 0); - - test.ok('donteval' in options.window, 'donteval exists'); - - input('{ don'); - check('VVIII', Status.ERROR, 'don', 'donteval'); - - input('{ donteval'); - check('VVVVVVVVVV', Status.VALID, 'donteval', 0); - - /* - // This is a controversial test - technically we can tell that it's an error - // because 'donteval.' is a syntax error, however donteval is unsafe so we - // are playing safe by bailing out early. It's enough of a corner case that - // I don't think it warrants fixing - input('{ donteval.'); - check('VVIIIIIIIII', Status.ERROR, 'donteval.', 0); - */ - - input('{ donteval.cant'); - check('VVVVVVVVVVVVVVV', Status.VALID, 'donteval.cant', 0); - - input('{ donteval.xxx'); - check('VVVVVVVVVVVVVV', Status.VALID, 'donteval.xxx', 0); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testKeyboard', ['require', 'exports', 'module' , 'gcli/cli', 'gcli/canon', 'gclitest/commands', 'gcli/types/javascript', 'test/assert'], function(require, exports, module) { - - -var Requisition = require('gcli/cli').Requisition; -var canon = require('gcli/canon'); -var commands = require('gclitest/commands'); -var javascript = require('gcli/types/javascript'); - -var test = require('test/assert'); - -var tempWindow; -var inputter; - -exports.setup = function(options) { - tempWindow = javascript.getGlobalObject(); - javascript.setGlobalObject(options.window); - - if (options.display) { - inputter = options.display.inputter; - } - - commands.setup(); -}; - -exports.shutdown = function(options) { - commands.shutdown(); - - inputter = undefined; - javascript.setGlobalObject(tempWindow); - tempWindow = undefined; -}; - -var COMPLETES_TO = 'complete'; -var KEY_UPS_TO = 'keyup'; -var KEY_DOWNS_TO = 'keydown'; - -function check(initial, action, after, choice, cursor, expectedCursor) { - var requisition; - if (inputter) { - requisition = inputter.requisition; - inputter.setInput(initial); - } - else { - requisition = new Requisition(); - requisition.update(initial); - } - - if (cursor == null) { - cursor = initial.length; - } - var assignment = requisition.getAssignmentAt(cursor); - switch (action) { - case COMPLETES_TO: - requisition.complete({ start: cursor, end: cursor }, choice); - break; - - case KEY_UPS_TO: - assignment.increment(); - break; - - case KEY_DOWNS_TO: - assignment.decrement(); - break; - } - - test.is(after, requisition.toString(), - initial + ' + ' + action + ' -> ' + after); - - if (expectedCursor != null) { - if (inputter) { - test.is(expectedCursor, inputter.getInputState().cursor.start, - 'Ending cursor position for \'' + initial + '\''); - } - } -} - -exports.testComplete = function(options) { - if (!inputter) { - test.log('Missing display, reduced checks'); - } - - check('tsela', COMPLETES_TO, 'tselarr ', 0); - check('tsn di', COMPLETES_TO, 'tsn dif ', 0); - check('tsg a', COMPLETES_TO, 'tsg aaa ', 0); - - check('tsn e', COMPLETES_TO, 'tsn extend ', -5); - check('tsn e', COMPLETES_TO, 'tsn ext ', -4); - check('tsn e', COMPLETES_TO, 'tsn exte ', -3); - check('tsn e', COMPLETES_TO, 'tsn exten ', -2); - check('tsn e', COMPLETES_TO, 'tsn extend ', -1); - check('tsn e', COMPLETES_TO, 'tsn ext ', 0); - check('tsn e', COMPLETES_TO, 'tsn exte ', 1); - check('tsn e', COMPLETES_TO, 'tsn exten ', 2); - check('tsn e', COMPLETES_TO, 'tsn extend ', 3); - check('tsn e', COMPLETES_TO, 'tsn ext ', 4); - check('tsn e', COMPLETES_TO, 'tsn exte ', 5); - check('tsn e', COMPLETES_TO, 'tsn exten ', 6); - check('tsn e', COMPLETES_TO, 'tsn extend ', 7); - check('tsn e', COMPLETES_TO, 'tsn ext ', 8); - - if (!canon.getCommand('{')) { - test.log('Skipping exec tests because { is not registered'); - } - else { - check('{ wind', COMPLETES_TO, '{ window', 0); - check('{ window.docum', COMPLETES_TO, '{ window.document', 0); - - // Bug 717228: This fails under node - if (!options.isNode) { - check('{ window.document.titl', COMPLETES_TO, '{ window.document.title ', 0); - } - else { - test.log('Running under Node. Skipping tests due to bug 717228.'); - } - } -}; - -exports.testInternalComplete = function(options) { - // Bug 664377 - // check('tsela 1', COMPLETES_TO, 'tselarr 1', 0, 3, 8); -}; - -exports.testIncrDecr = function() { - check('tsu -70', KEY_UPS_TO, 'tsu -5'); - check('tsu -7', KEY_UPS_TO, 'tsu -5'); - check('tsu -6', KEY_UPS_TO, 'tsu -5'); - check('tsu -5', KEY_UPS_TO, 'tsu -3'); - check('tsu -4', KEY_UPS_TO, 'tsu -3'); - check('tsu -3', KEY_UPS_TO, 'tsu 0'); - check('tsu -2', KEY_UPS_TO, 'tsu 0'); - check('tsu -1', KEY_UPS_TO, 'tsu 0'); - check('tsu 0', KEY_UPS_TO, 'tsu 3'); - check('tsu 1', KEY_UPS_TO, 'tsu 3'); - check('tsu 2', KEY_UPS_TO, 'tsu 3'); - check('tsu 3', KEY_UPS_TO, 'tsu 6'); - check('tsu 4', KEY_UPS_TO, 'tsu 6'); - check('tsu 5', KEY_UPS_TO, 'tsu 6'); - check('tsu 6', KEY_UPS_TO, 'tsu 9'); - check('tsu 7', KEY_UPS_TO, 'tsu 9'); - check('tsu 8', KEY_UPS_TO, 'tsu 9'); - check('tsu 9', KEY_UPS_TO, 'tsu 10'); - check('tsu 10', KEY_UPS_TO, 'tsu 10'); - check('tsu 100', KEY_UPS_TO, 'tsu -5'); - - check('tsu -70', KEY_DOWNS_TO, 'tsu 10'); - check('tsu -7', KEY_DOWNS_TO, 'tsu 10'); - check('tsu -6', KEY_DOWNS_TO, 'tsu 10'); - check('tsu -5', KEY_DOWNS_TO, 'tsu -5'); - check('tsu -4', KEY_DOWNS_TO, 'tsu -5'); - check('tsu -3', KEY_DOWNS_TO, 'tsu -5'); - check('tsu -2', KEY_DOWNS_TO, 'tsu -3'); - check('tsu -1', KEY_DOWNS_TO, 'tsu -3'); - check('tsu 0', KEY_DOWNS_TO, 'tsu -3'); - check('tsu 1', KEY_DOWNS_TO, 'tsu 0'); - check('tsu 2', KEY_DOWNS_TO, 'tsu 0'); - check('tsu 3', KEY_DOWNS_TO, 'tsu 0'); - check('tsu 4', KEY_DOWNS_TO, 'tsu 3'); - check('tsu 5', KEY_DOWNS_TO, 'tsu 3'); - check('tsu 6', KEY_DOWNS_TO, 'tsu 3'); - check('tsu 7', KEY_DOWNS_TO, 'tsu 6'); - check('tsu 8', KEY_DOWNS_TO, 'tsu 6'); - check('tsu 9', KEY_DOWNS_TO, 'tsu 6'); - check('tsu 10', KEY_DOWNS_TO, 'tsu 9'); - check('tsu 100', KEY_DOWNS_TO, 'tsu 10'); - - // Bug 707007 - GCLI increment and decrement operations cycle through - // selection options in the wrong order - check('tselarr 1', KEY_DOWNS_TO, 'tselarr 2'); - check('tselarr 2', KEY_DOWNS_TO, 'tselarr 3'); - check('tselarr 3', KEY_DOWNS_TO, 'tselarr 1'); - - check('tselarr 3', KEY_UPS_TO, 'tselarr 2'); -}; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testRequire', ['require', 'exports', 'module' , 'test/assert', 'gclitest/requirable'], function(require, exports, module) { - -var test = require('test/assert'); - - -exports.testWorking = function() { - // There are lots of requirement tests that we could be doing here - // The fact that we can get anything at all working is a testament to - // require doing what it should - we don't need to test the - var requireable = require('gclitest/requirable'); - test.is('thing1', requireable.thing1); - test.is(2, requireable.thing2); - test.ok(requireable.thing3 === undefined); -}; - -exports.testDomains = function() { - var requireable = require('gclitest/requirable'); - test.ok(requireable.status === undefined); - requireable.setStatus(null); - test.is(null, requireable.getStatus()); - test.ok(requireable.status === undefined); - requireable.setStatus('42'); - test.is('42', requireable.getStatus()); - test.ok(requireable.status === undefined); - - if (define.Domain) { - var domain = new define.Domain(); - var requireable2 = domain.require('gclitest/requirable'); - test.is(undefined, requireable2.status); - test.is('initial', requireable2.getStatus()); - requireable2.setStatus(999); - test.is(999, requireable2.getStatus()); - test.is(undefined, requireable2.status); - - test.is('42', requireable.getStatus()); - test.is(undefined, requireable.status); - } -}; - -exports.testLeakage = function() { - var requireable = require('gclitest/requirable'); - test.ok(requireable.setup === undefined); - test.ok(requireable.shutdown === undefined); - test.ok(requireable.testWorking === undefined); -}; - -exports.testMultiImport = function() { - var r1 = require('gclitest/requirable'); - var r2 = require('gclitest/requirable'); - test.is(r1, r2); -}; - -exports.testUncompilable = function() { - // This test is commented out because it breaks the RequireJS module - // loader and because it causes console output and because testing failure - // cases such as this is something of a luxury - // It's not totally clear how a module loader should perform with unusable - // modules, however at least it should go into a flat spin ... - // GCLI mini_require reports an error as it should - /* - if (define.Domain) { - try { - var unrequireable = require('gclitest/unrequirable'); - t.fail(); - } - catch (ex) { - console.error(ex); - } - } - */ -}; - -exports.testRecursive = function() { - // See Bug 658583 - /* - var recurse = require('gclitest/recurse'); - */ -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/requirable', ['require', 'exports', 'module' ], function(require, exports, module) { - - exports.thing1 = 'thing1'; - exports.thing2 = 2; - - var status = 'initial'; - exports.setStatus = function(aStatus) { status = aStatus; }; - exports.getStatus = function() { return status; }; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testResource', ['require', 'exports', 'module' , 'gcli/types/resource', 'gcli/types', 'test/assert'], function(require, exports, module) { - - -var resource = require('gcli/types/resource'); -var types = require('gcli/types'); -var Status = require('gcli/types').Status; - -var test = require('test/assert'); - -var tempDocument; - -exports.setup = function(options) { - tempDocument = resource.getDocument(); - resource.setDocument(options.window.document); -}; - -exports.shutdown = function(options) { - resource.setDocument(tempDocument); - tempDocument = undefined; -}; - -exports.testPredictions = function(options) { - if (options.window.isFake) { - test.log('Skipping resource tests: options.window.isFake = true'); - return; - } - - var resource1 = types.getType('resource'); - var predictions1 = resource1.parseString('').getPredictions(); - test.ok(predictions1.length > 1, 'have resources'); - predictions1.forEach(function(prediction) { - checkPrediction(resource1, prediction); - }); - - var resource2 = types.getType({ name: 'resource', include: 'text/javascript' }); - var predictions2 = resource2.parseString('').getPredictions(); - test.ok(predictions2.length > 1, 'have resources'); - predictions2.forEach(function(prediction) { - checkPrediction(resource2, prediction); - }); - - var resource3 = types.getType({ name: 'resource', include: 'text/css' }); - var predictions3 = resource3.parseString('').getPredictions(); - // jsdom fails to support digging into stylesheets - if (!options.isNode) { - test.ok(predictions3.length >= 1, 'have resources'); - } - else { - test.log('Running under Node. ' + - 'Skipping checks due to jsdom document.stylsheets support.'); - } - predictions3.forEach(function(prediction) { - checkPrediction(resource3, prediction); - }); - - var resource4 = types.getType({ name: 'resource' }); - var predictions4 = resource4.parseString('').getPredictions(); - - test.is(predictions1.length, predictions4.length, 'type spec'); - // Bug 734045 - // test.is(predictions2.length + predictions3.length, predictions4.length, 'split'); -}; - -function checkPrediction(res, prediction) { - var name = prediction.name; - var value = prediction.value; - - var conversion = res.parseString(name); - test.is(conversion.getStatus(), Status.VALID, 'status VALID for ' + name); - test.is(conversion.value, value, 'value for ' + name); - - var strung = res.stringify(value); - test.is(strung, name, 'stringify for ' + name); - - test.is(typeof value.loadContents, 'function', 'resource for ' + name); - test.is(typeof value.element, 'object', 'resource for ' + name); -} - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testScratchpad', ['require', 'exports', 'module' , 'test/assert'], function(require, exports, module) { - - -var test = require('test/assert'); - -var origScratchpad; - -exports.setup = function(options) { - if (options.display) { - origScratchpad = options.display.inputter.scratchpad; - options.display.inputter.scratchpad = stubScratchpad; - } -}; - -exports.shutdown = function(options) { - if (options.display) { - options.display.inputter.scratchpad = origScratchpad; - } -}; - -var stubScratchpad = { - shouldActivate: function(ev) { - return true; - }, - activatedCount: 0, - linkText: 'scratchpad.linkText' -}; -stubScratchpad.activate = function(value) { - stubScratchpad.activatedCount++; - return true; -}; - - -exports.testActivate = function(options) { - if (!options.display) { - test.log('No display. Skipping scratchpad tests'); - return; - } - - var ev = {}; - stubScratchpad.activatedCount = 0; - options.display.inputter.onKeyUp(ev); - test.is(1, stubScratchpad.activatedCount, 'scratchpad is activated'); -}; - - -}); -/* - * Copyright (c) 2009 Panagiotis Astithas - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION - * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN - * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -define('gclitest/testSpell', ['require', 'exports', 'module' , 'test/assert', 'gcli/types/spell'], function(require, exports, module) { - -var test = require('test/assert'); -var Speller = require('gcli/types/spell').Speller; - -exports.setup = function() { -}; - -exports.shutdown = function() { -}; - -exports.testSimple = function(options) { - var speller = new Speller(); - speller.train(Object.keys(options.window)); - - test.is(speller.correct('document'), 'document'); - test.is(speller.correct('documen'), 'document'); - test.is(speller.correct('ocument'), 'document'); - test.is(speller.correct('odcument'), 'document'); - - test.is(speller.correct('========='), null); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testSplit', ['require', 'exports', 'module' , 'test/assert', 'gclitest/commands', 'gcli/cli'], function(require, exports, module) { - -var test = require('test/assert'); - -var commands = require('gclitest/commands'); -var Requisition = require('gcli/cli').Requisition; - -exports.setup = function() { - commands.setup(); -}; - -exports.shutdown = function() { - commands.shutdown(); -}; - -exports.testSimple = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('s'); - requ._split(args); - test.is(0, args.length); - test.is('s', requ.commandAssignment.arg.text); -}; - -exports.testFlatCommand = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('tsv'); - requ._split(args); - test.is(0, args.length); - test.is('tsv', requ.commandAssignment.value.name); - - args = requ._tokenize('tsv a b'); - requ._split(args); - test.is('tsv', requ.commandAssignment.value.name); - test.is(2, args.length); - test.is('a', args[0].text); - test.is('b', args[1].text); -}; - -exports.testJavascript = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('{'); - requ._split(args); - test.is(1, args.length); - test.is('', args[0].text); - test.is('', requ.commandAssignment.arg.text); - test.is('{', requ.commandAssignment.value.name); -}; - -// BUG 663081 - add tests for sub commands - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testTokenize', ['require', 'exports', 'module' , 'test/assert', 'gcli/cli', 'gcli/argument'], function(require, exports, module) { - - -var test = require('test/assert'); -var Requisition = require('gcli/cli').Requisition; -var Argument = require('gcli/argument').Argument; -var ScriptArgument = require('gcli/argument').ScriptArgument; - -exports.testBlanks = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize(''); - test.is(1, args.length); - test.is('', args[0].text); - test.is('', args[0].prefix); - test.is('', args[0].suffix); - - args = requ._tokenize(' '); - test.is(1, args.length); - test.is('', args[0].text); - test.is(' ', args[0].prefix); - test.is('', args[0].suffix); -}; - -exports.testSimple = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('s'); - test.is(1, args.length); - test.is('s', args[0].text); - test.is('', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof Argument); - - args = requ._tokenize('s s'); - test.is(2, args.length); - test.is('s', args[0].text); - test.is('', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof Argument); - test.is('s', args[1].text); - test.is(' ', args[1].prefix); - test.is('', args[1].suffix); - test.ok(args[1] instanceof Argument); -}; - -exports.testJavascript = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('{x}'); - test.is(1, args.length); - test.is('x', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{ x }'); - test.is(1, args.length); - test.is('x', args[0].text); - test.is('{ ', args[0].prefix); - test.is(' }', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{x} {y}'); - test.is(2, args.length); - test.is('x', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - test.is('y', args[1].text); - test.is(' {', args[1].prefix); - test.is('}', args[1].suffix); - test.ok(args[1] instanceof ScriptArgument); - - args = requ._tokenize('{x}{y}'); - test.is(2, args.length); - test.is('x', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - test.is('y', args[1].text); - test.is('{', args[1].prefix); - test.is('}', args[1].suffix); - test.ok(args[1] instanceof ScriptArgument); - - args = requ._tokenize('{'); - test.is(1, args.length); - test.is('', args[0].text); - test.is('{', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{ '); - test.is(1, args.length); - test.is('', args[0].text); - test.is('{ ', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{x'); - test.is(1, args.length); - test.is('x', args[0].text); - test.is('{', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); -}; - -exports.testRegularNesting = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('{"x"}'); - test.is(1, args.length); - test.is('"x"', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{\'x\'}'); - test.is(1, args.length); - test.is('\'x\'', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('"{x}"'); - test.is(1, args.length); - test.is('{x}', args[0].text); - test.is('"', args[0].prefix); - test.is('"', args[0].suffix); - test.ok(args[0] instanceof Argument); - - args = requ._tokenize('\'{x}\''); - test.is(1, args.length); - test.is('{x}', args[0].text); - test.is('\'', args[0].prefix); - test.is('\'', args[0].suffix); - test.ok(args[0] instanceof Argument); -}; - -exports.testDeepNesting = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('{{}}'); - test.is(1, args.length); - test.is('{}', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{{x} {y}}'); - test.is(1, args.length); - test.is('{x} {y}', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - args = requ._tokenize('{{w} {{{x}}}} {y} {{{z}}}'); - - test.is(3, args.length); - - test.is('{w} {{{x}}}', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - test.is('y', args[1].text); - test.is(' {', args[1].prefix); - test.is('}', args[1].suffix); - test.ok(args[1] instanceof ScriptArgument); - - test.is('{{z}}', args[2].text); - test.is(' {', args[2].prefix); - test.is('}', args[2].suffix); - test.ok(args[2] instanceof ScriptArgument); - - args = requ._tokenize('{{w} {{{x}}} {y} {{{z}}}'); - - test.is(1, args.length); - - test.is('{w} {{{x}}} {y} {{{z}}}', args[0].text); - test.is('{', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); -}; - -exports.testStrangeNesting = function() { - var args; - var requ = new Requisition(); - - // Note: When we get real JS parsing this should break - args = requ._tokenize('{"x}"}'); - - test.is(2, args.length); - - test.is('"x', args[0].text); - test.is('{', args[0].prefix); - test.is('}', args[0].suffix); - test.ok(args[0] instanceof ScriptArgument); - - test.is('}', args[1].text); - test.is('"', args[1].prefix); - test.is('', args[1].suffix); - test.ok(args[1] instanceof Argument); -}; - -exports.testComplex = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize(' 1234 \'12 34\''); - - test.is(2, args.length); - - test.is('1234', args[0].text); - test.is(' ', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof Argument); - - test.is('12 34', args[1].text); - test.is(' \'', args[1].prefix); - test.is('\'', args[1].suffix); - test.ok(args[1] instanceof Argument); - - args = requ._tokenize('12\'34 "12 34" \\'); // 12'34 "12 34" \ - - test.is(3, args.length); - - test.is('12\'34', args[0].text); - test.is('', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof Argument); - - test.is('12 34', args[1].text); - test.is(' "', args[1].prefix); - test.is('"', args[1].suffix); - test.ok(args[1] instanceof Argument); - - test.is('\\', args[2].text); - test.is(' ', args[2].prefix); - test.is('', args[2].suffix); - test.ok(args[2] instanceof Argument); -}; - -exports.testPathological = function() { - var args; - var requ = new Requisition(); - - args = requ._tokenize('a\\ b \\t\\n\\r \\\'x\\\" \'d'); // a_b \t\n\r \'x\" 'd - - test.is(4, args.length); - - test.is('a b', args[0].text); - test.is('', args[0].prefix); - test.is('', args[0].suffix); - test.ok(args[0] instanceof Argument); - - test.is('\t\n\r', args[1].text); - test.is(' ', args[1].prefix); - test.is('', args[1].suffix); - test.ok(args[1] instanceof Argument); - - test.is('\'x"', args[2].text); - test.is(' ', args[2].prefix); - test.is('', args[2].suffix); - test.ok(args[2] instanceof Argument); - - test.is('d', args[3].text); - test.is(' \'', args[3].prefix); - test.is('', args[3].suffix); - test.ok(args[3] instanceof Argument); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testTooltip', ['require', 'exports', 'module' , 'test/assert', 'gclitest/commands'], function(require, exports, module) { - - -var test = require('test/assert'); -var commands = require('gclitest/commands'); - - -exports.setup = function() { - commands.setup(); -}; - -exports.shutdown = function() { - commands.shutdown(); -}; - - -function type(typed, tests, options) { - var inputter = options.display.inputter; - var tooltip = options.display.tooltip; - - inputter.setInput(typed); - if (tests.cursor) { - inputter.setCursor({ start: tests.cursor, end: tests.cursor }); - } - - if (!options.isNode) { - if (tests.important) { - test.ok(tooltip.field.isImportant, 'Important for ' + typed); - } - else { - test.ok(!tooltip.field.isImportant, 'Not important for ' + typed); - } - - if (tests.options) { - var names = tooltip.field.menu.items.map(function(item) { - return item.name.textContent ? item.name.textContent : item.name; - }); - test.is(tests.options.join('|'), names.join('|'), 'Options for ' + typed); - } - - if (tests.error) { - test.is(tests.error, tooltip.errorEle.textContent, 'Error for ' + typed); - } - else { - test.is('', tooltip.errorEle.textContent, 'No error for ' + typed); - } - } -} - -exports.testActivate = function(options) { - if (!options.display) { - test.log('No display. Skipping activate tests'); - return; - } - - if (options.isNode) { - test.log('Running under Node. Reduced checks due to JSDom.textContent'); - } - - type(' ', { }, options); - - type('tsb ', { - important: true, - options: [ 'false', 'true' ] - }, options); - - type('tsb t', { - important: true, - options: [ 'true' ] - }, options); - - type('tsb tt', { - important: true, - options: [ ], - error: 'Can\'t use \'tt\'.' - }, options); - - - type('asdf', { - important: false, - options: [ ], - error: 'Can\'t use \'asdf\'.' - }, options); - - type('', { }, options); -}; - - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testTypes', ['require', 'exports', 'module' , 'test/assert', 'gcli/types'], function(require, exports, module) { - -var test = require('test/assert'); -var types = require('gcli/types'); - -exports.setup = function() { -}; - -exports.shutdown = function() { -}; - -exports.testDefault = function(options) { - if (options.isNode) { - test.log('Running under Node. ' + - 'Skipping tests due to issues with resource type.'); - return; - } - - types.getTypeNames().forEach(function(name) { - if (name === 'selection') { - name = { name: 'selection', data: [ 'a', 'b' ] }; - } - if (name === 'deferred') { - name = { - name: 'deferred', - defer: function() { return types.getType('string'); } - }; - } - if (name === 'array') { - name = { name: 'array', subtype: 'string' }; - } - var type = types.getType(name); - if (type.name !== 'boolean' && type.name !== 'array') { - test.ok(type.getBlank().value === undefined, - 'default defined for ' + type.name); - } - }); -}; - -}); -/* - * Copyright 2009-2011 Mozilla Foundation and contributors - * Licensed under the New BSD license. See LICENSE.txt or: - * http://opensource.org/licenses/BSD-3-Clause - */ - -define('gclitest/testUtil', ['require', 'exports', 'module' , 'gcli/util', 'test/assert'], function(require, exports, module) { - -var util = require('gcli/util'); -var test = require('test/assert'); - -exports.testFindCssSelector = function(options) { - if (options.window.isFake) { - test.log('Skipping dom.findCssSelector tests due to window.isFake'); - return; - } - - var nodes = options.window.document.querySelectorAll('*'); - for (var i = 0; i < nodes.length; i++) { - var selector = util.findCssSelector(nodes[i]); - var matches = options.window.document.querySelectorAll(selector); - - test.is(matches.length, 1, 'multiple matches for ' + selector); - test.is(matches[0], nodes[i], 'non-matching selector: ' + selector); - } -}; - - -}); - -let testModuleNames = [ - 'gclitest/index', - 'gclitest/suite', - 'test/examiner', - 'gclitest/testCli', - 'gclitest/commands', - 'test/assert', - 'gclitest/testCompletion', - 'gclitest/testExec', - 'gclitest/testHistory', - 'gclitest/testJs', - 'gclitest/testKeyboard', - 'gclitest/testRequire', - 'gclitest/requirable', - 'gclitest/testResource', - 'gclitest/testScratchpad', - 'gclitest/testSpell', - 'gclitest/testSplit', - 'gclitest/testTokenize', - 'gclitest/testTooltip', - 'gclitest/testTypes', - 'gclitest/testUtil', -]; - -// Cached so it still exists during cleanup until we need it to -let localDefine; - -const TEST_URI = "data:text/html;charset=utf-8,gcli-web"; - -function test() { - localDefine = define; - - DeveloperToolbarTest.test(TEST_URI, function(browser, tab) { - var gclitest = define.globalDomain.require("gclitest/index"); - gclitest.run({ - display: DeveloperToolbar.display, - // window: browser.getBrowser().contentWindow - }); - - finish(); - }); -} - -registerCleanupFunction(function() { - testModuleNames.forEach(function(moduleName) { - delete localDefine.modules[moduleName]; - delete localDefine.globalDomain.modules[moduleName]; - }); - - localDefine = undefined; -});
--- a/browser/devtools/shared/test/browser_templater_basic.js +++ b/browser/devtools/shared/test/browser_templater_basic.js @@ -1,22 +1,18 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests that the DOM Template engine works properly -/* - * These tests run both in Mozilla/Mochitest and plain browsers (as does - * domtemplate) - * We should endevour to keep the source in sync. - */ - -var imports = {}; -Cu.import("resource:///modules/devtools/Templater.jsm", imports); -Cu.import("resource:///modules/devtools/Promise.jsm", imports); +let tempScope = {}; +Cu.import("resource:///modules/devtools/Templater.jsm", tempScope); +Cu.import("resource:///modules/devtools/Promise.jsm", tempScope); +let template = tempScope.template; +let Promise = tempScope.Promise; function test() { addTab("http://example.com/browser/browser/devtools/shared/test/browser_templater_basic.html", function() { info("Starting DOM Templater Tests"); runTest(0); }); } @@ -24,17 +20,17 @@ function runTest(index) { var options = tests[index] = tests[index](); var holder = content.document.createElement('div'); holder.id = options.name; var body = content.document.body; body.appendChild(holder); holder.innerHTML = options.template; info('Running ' + options.name); - imports.template(holder, options.data, options.options); + template(holder, options.data, options.options); if (typeof options.result == 'string') { is(holder.innerHTML, options.result, options.name); } else { ok(holder.innerHTML.match(options.result), options.name); } @@ -237,50 +233,18 @@ var tests = [ options: { allowEval: true }, result: '<p>2</p>' };}, function() { return { name: 'propertyFail', template: '<p>${Math.max(1, 2)}</p>', result: '<p>${Math.max(1, 2)}</p>' - };}, - - // Bug 723431: DOMTemplate should allow customisation of display of - // null/undefined values - function() { return { - name: 'propertyUndefAttrFull', - template: '<p>${nullvar}|${undefinedvar1}|${undefinedvar2}</p>', - data: { nullvar: null, undefinedvar1: undefined }, - result: '<p>null|undefined|undefined</p>' - };}, - - function() { return { - name: 'propertyUndefAttrBlank', - template: '<p>${nullvar}|${undefinedvar1}|${undefinedvar2}</p>', - data: { nullvar: null, undefinedvar1: undefined }, - options: { blankNullUndefined: true }, - result: '<p>||</p>' - };}, - - function() { return { - name: 'propertyUndefAttrFull', - template: '<div><p value="${nullvar}"></p><p value="${undefinedvar1}"></p><p value="${undefinedvar2}"></p></div>', - data: { nullvar: null, undefinedvar1: undefined }, - result: '<div><p value="null"></p><p value="undefined"></p><p value="undefined"></p></div>' - };}, - - function() { return { - name: 'propertyUndefAttrBlank', - template: '<div><p value="${nullvar}"></p><p value="${undefinedvar1}"></p><p value="${undefinedvar2}"></p></div>', - data: { nullvar: null, undefinedvar1: undefined }, - options: { blankNullUndefined: true }, - result: '<div><p value=""></p><p value=""></p><p value=""></p></div>' };} ]; function delayReply(data) { - var p = new imports.Promise(); + var p = new Promise(); executeSoon(function() { p.resolve(data); }); return p; }
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_toolbar_basic.html +++ /dev/null @@ -1,35 +0,0 @@ -<!doctype html> -<!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> - -<html> -<head> - <meta charset="UTF-8"> - <title>Developer Toolbar Tests</title> - <style type="text/css"> - #single { color: red; } - </style> - <script type="text/javascript">var a=1;</script> -</head> -<body> - -<p id=single> -1 -</p> - -<p class=twin> -2a -</p> - -<p class=twin> -2b -</p> - -<style> -.twin { color: blue; } -</style> -<script>var b=2;</script> - -</body> -</html> -
deleted file mode 100644 --- a/browser/devtools/shared/test/browser_toolbar_basic.js +++ /dev/null @@ -1,36 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -// Tests that the developer toolbar works properly - -const URL = "http://example.com/browser/browser/devtools/shared/test/browser_toolbar_basic.html"; - -function test() { - addTab(URL, function(browser, tab) { - info("Starting browser_toolbar_basic.js"); - runTest(); - }); -} - -function runTest() { - Services.obs.addObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false); - // TODO: reopen the window so the pref has a chance to take effect - // EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true }); - DeveloperToolbarTest.show(); -} - -function checkOpen() { - Services.obs.removeObserver(checkOpen, DeveloperToolbar.NOTIFICATIONS.SHOW, false); - ok(DeveloperToolbar.visible, "DeveloperToolbar is visible"); - - Services.obs.addObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false); - // EventUtils.synthesizeKey("v", { ctrlKey: true, shiftKey: true }); - DeveloperToolbarTest.hide(); -} - -function checkClosed() { - Services.obs.removeObserver(checkClosed, DeveloperToolbar.NOTIFICATIONS.HIDE, false); - ok(!DeveloperToolbar.visible, "DeveloperToolbar is not visible"); - - finish(); -}
--- a/browser/devtools/shared/test/head.js +++ b/browser/devtools/shared/test/head.js @@ -31,282 +31,37 @@ * 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 ***** */ -let gcli; -let console; -let require; -let define; - -(function() { - let tempScope = {}; - Components.utils.import("resource:///modules/gcli.jsm", tempScope); +let tab; +let browser; - gcli = tempScope.gcli; - console = gcli._internal.console; - define = gcli._internal.define; - require = gcli._internal.require; -})(); - -/** - * Open a new tab at a URL and call a callback on load - */ function addTab(aURL, aCallback) { waitForExplicitFinish(); + function onTabLoad() { + browser.removeEventListener("load", onTabLoad, true); + aCallback(); + } + gBrowser.selectedTab = gBrowser.addTab(); content.location = aURL; - let tab = gBrowser.selectedTab; - let browser = gBrowser.getBrowserForTab(tab); - - function onTabLoad() { - browser.removeEventListener("load", onTabLoad, true); - aCallback(browser, tab); - } + tab = gBrowser.selectedTab; + browser = gBrowser.getBrowserForTab(tab); browser.addEventListener("load", onTabLoad, true); } registerCleanupFunction(function tearDown() { while (gBrowser.tabs.length > 1) { gBrowser.removeCurrentTab(); } - console = undefined; - define = undefined; - require = undefined; - gcli = undefined; + tab = undefined; + browser = undefined; }); - -/** - * Various functions for testing DeveloperToolbar - */ -let DeveloperToolbarTest = { - /** - * Paranoid DeveloperToolbar.show(); - */ - show: function DTT_show() { - if (DeveloperToolbar.visible) { - ok(false, "DeveloperToolbar.visible at start of openDeveloperToolbar"); - } - else { - DeveloperToolbar.show(); - } - }, - - /** - * Paranoid DeveloperToolbar.hide(); - */ - hide: function DTT_hide() { - if (!DeveloperToolbar.visible) { - ok(false, "!DeveloperToolbar.visible at start of closeDeveloperToolbar"); - } - else { - DeveloperToolbar.display.inputter.setInput(""); - DeveloperToolbar.hide(); - } - }, - - /** - * Check that we can parse command input. - * Doesn't execute the command, just checks that we grok the input properly: - * - * DeveloperToolbarTest.checkInputStatus({ - * // Test inputs - * typed: "ech", // Required - * cursor: 3, // Optional cursor position - * - * // Thing to check - * status: "INCOMPLETE", // One of "VALID", "ERROR", "INCOMPLETE" - * emptyParameters: [ "<message>" ], // Still to type - * directTabText: "o", // Simple completion text - * arrowTabText: "", // When the completion is not an extension - * }); - */ - checkInputStatus: function DTT_checkInputStatus(test) { - if (test.typed) { - DeveloperToolbar.display.inputter.setInput(test.typed); - } - else { - ok(false, "Missing typed for " + JSON.stringify(test)); - return; - } - - if (test.cursor) { - DeveloperToolbar.display.inputter.setCursor(test.cursor) - } - - if (test.status) { - is(DeveloperToolbar.display.requisition.getStatus().toString(), - test.status, - "status for " + test.typed); - } - - if (test.emptyParameters == null) { - test.emptyParameters = []; - } - - let completer = DeveloperToolbar.display.completer; - let realParams = completer.emptyParameters; - is(realParams.length, test.emptyParameters.length, - 'emptyParameters.length for \'' + test.typed + '\''); - - if (realParams.length === test.emptyParameters.length) { - for (let i = 0; i < realParams.length; i++) { - is(realParams[i].replace(/\u00a0/g, ' '), test.emptyParameters[i], - 'emptyParameters[' + i + '] for \'' + test.typed + '\''); - } - } - - if (test.directTabText) { - is(completer.directTabText, test.directTabText, - 'directTabText for \'' + test.typed + '\''); - } - else { - is(completer.directTabText, '', 'directTabText for \'' + test.typed + '\''); - } - - if (test.arrowTabText) { - is(completer.arrowTabText, ' \u00a0\u21E5 ' + test.arrowTabText, - 'arrowTabText for \'' + test.typed + '\''); - } - else { - is(completer.arrowTabText, '', 'arrowTabText for \'' + test.typed + '\''); - } - }, - - /** - * Execute a command: - * - * DeveloperToolbarTest.exec({ - * // Test inputs - * typed: "echo hi", // Optional, uses existing if undefined - * - * // Thing to check - * args: { message: "hi" }, // Check that the args were understood properly - * outputMatch: /^hi$/, // Regex to test against textContent of output - * blankOutput: true, // Special checks when there is no output - * }); - */ - exec: function DTT_exec(test) { - test = test || {}; - - if (test.typed) { - DeveloperToolbar.display.inputter.setInput(test.typed); - } - - let typed = DeveloperToolbar.display.inputter.getInputState().typed; - let output = DeveloperToolbar.display.requisition.exec(); - - is(typed, output.typed, 'output.command for: ' + typed); - - if (test.completed !== false) { - ok(output.completed, 'output.completed false for: ' + typed); - } - else { - // It is actually an error if we say something is async and it turns - // out not to be? For now we're saying 'no' - // ok(!output.completed, 'output.completed true for: ' + typed); - } - - if (test.args != null) { - is(Object.keys(test.args).length, Object.keys(output.args).length, - 'arg count for ' + typed); - - Object.keys(output.args).forEach(function(arg) { - let expectedArg = test.args[arg]; - let actualArg = output.args[arg]; - - if (Array.isArray(expectedArg)) { - if (!Array.isArray(actualArg)) { - ok(false, 'actual is not an array. ' + typed + '/' + arg); - return; - } - - is(expectedArg.length, actualArg.length, - 'array length: ' + typed + '/' + arg); - for (let i = 0; i < expectedArg.length; i++) { - is(expectedArg[i], actualArg[i], - 'member: "' + typed + '/' + arg + '/' + i); - } - } - else { - is(expectedArg, actualArg, 'typed: "' + typed + '" arg: ' + arg); - } - }); - } - - let displayed = DeveloperToolbar.outputPanel._div.textContent; - - if (test.outputMatch) { - if (!test.outputMatch.test(displayed)) { - ok(false, "html output for " + typed + " (textContent sent to info)"); - info("Actual textContent"); - info(displayed); - } - } - - if (test.blankOutput != null) { - if (!/^$/.test(displayed)) { - ok(false, "html output for " + typed + " (textContent sent to info)"); - info("Actual textContent"); - info(displayed); - } - } - }, - - /** - * Quick wrapper around the things you need to do to run DeveloperToolbar - * command tests: - * - Set the pref 'devtools.toolbar.enabled' to true - * - Add a tab pointing at |uri| - * - Open the DeveloperToolbar - * - Register a cleanup function to undo the above - * - Run the tests - * - * @param uri The uri of a page to load. Can be 'about:blank' or 'data:...' - * @param testFunc A function containing the tests to run. This should - * arrange for 'finish()' to be called on completion. - */ - test: function DTT_test(uri, testFunc) { - let menuItem = document.getElementById("menu_devToolbar"); - let command = document.getElementById("Tools:DevToolbar"); - let appMenuItem = document.getElementById("appmenu_devToolbar"); - - registerCleanupFunction(function() { - DeveloperToolbarTest.hide(); - - // a.k.a Services.prefs.clearUserPref("devtools.toolbar.enabled"); - if (menuItem) { - menuItem.hidden = true; - } - if (command) { - command.setAttribute("disabled", "true"); - } - if (appMenuItem) { - appMenuItem.hidden = true; - } - }); - - // a.k.a: Services.prefs.setBoolPref("devtools.toolbar.enabled", true); - if (menuItem) { - menuItem.hidden = false; - } - if (command) { - command.removeAttribute("disabled"); - } - if (appMenuItem) { - appMenuItem.hidden = false; - } - - addTab(uri, function(browser, tab) { - DeveloperToolbarTest.show(); - testFunc(browser, tab); - }); - }, -};
--- a/browser/devtools/webconsole/GcliCommands.jsm +++ b/browser/devtools/webconsole/GcliCommands.jsm @@ -96,34 +96,22 @@ gcli.addCommand({ /** * 'console close' command */ gcli.addCommand({ name: "console close", description: gcli.lookup("consolecloseDesc"), exec: function Command_consoleClose(args, context) { - let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab + let tab = HUDService.getHudReferenceById(context.environment.hudId).tab; HUDService.deactivateHUDForContext(tab); } }); /** - * 'console open' command - */ -gcli.addCommand({ - name: "console open", - description: gcli.lookup("consoleopenDesc"), - exec: function Command_consoleOpen(args, context) { - let tab = context.environment.chromeDocument.defaultView.gBrowser.selectedTab - HUDService.activateHUDForContext(tab); - } -}); - -/** * 'inspect' command */ gcli.addCommand({ name: "inspect", description: gcli.lookup("inspectDesc"), manual: gcli.lookup("inspectManual"), params: [ {
--- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -146,16 +146,34 @@ function LogFactory(aMessagePrefix) { function log(aMessage) { var _msg = aMessagePrefix + " " + aMessage + "\n"; dump(_msg); } return log; } +/** + * Load the various Command JSMs. + * Should be called when the console first opens. + * + * @return an object containing the EXPORTED_SYMBOLS from all the command + * modules. In general there is no reason when JSMs need to export symbols + * except when they need the host environment to inform them of things like the + * current window/document/etc. + */ +function loadCommands() { + let commandExports = {}; + + Cu.import("resource:///modules/GcliCommands.jsm", commandExports); + Cu.import("resource:///modules/GcliTiltCommands.jsm", commandExports); + + return commandExports; +} + let log = LogFactory("*** HUDService:"); const HUD_STRINGS_URI = "chrome://browser/locale/devtools/webconsole.properties"; XPCOMUtils.defineLazyGetter(this, "stringBundle", function () { return Services.strings.createBundle(HUD_STRINGS_URI); }); @@ -1547,17 +1565,16 @@ HUD_SERVICE.prototype = let root = aContext.ownerDocument.getElementsByTagName('window')[0]; root.parentNode.insertBefore(procInstr, root); aContext.ownerDocument.gcliCssProcInstr = procInstr; } if (procInstr.contexts.indexOf(hudId) == -1) { procInstr.contexts.push(hudId); } - HeadsUpDisplayUICommands.refreshCommand(); }, /** * Deactivate a HeadsUpDisplay for the given tab context. * * @param nsIDOMWindow aContext * @param aAnimated animate closing the web console? * @returns void @@ -1578,17 +1595,16 @@ HUD_SERVICE.prototype = let hud = this.hudReferences[hudId]; browser.webProgress.removeProgressListener(hud.progressListener); delete hud.progressListener; this.unregisterDisplay(hudId); window.focus(); - HeadsUpDisplayUICommands.refreshCommand(); } // Remove this context from the list of contexts that need the GCLI CSS // processing instruction and then remove the processing instruction if it // isn't needed any more. let procInstr = aContext.ownerDocument.gcliCssProcInstr; if (procInstr) { procInstr.contexts = procInstr.contexts.filter(function(id) { @@ -3593,17 +3609,17 @@ HeadsUpDisplay.prototype = { * @param nsIDOMWindow aWindow * @returns void */ createConsoleInput: function HUD_createConsoleInput(aWindow, aParentNode, aExistingConsole) { let usegcli = false; try { - // usegcli = Services.prefs.getBoolPref("devtools.gcli.enable"); + usegcli = Services.prefs.getBoolPref("devtools.gcli.enable"); } catch (ex) {} if (appName() == "FIREFOX") { if (!usegcli) { let context = Cu.getWeakReference(aWindow); let mixin = new JSTermFirefoxMixin(context, aParentNode, aExistingConsole); @@ -6314,26 +6330,16 @@ ConsoleUtils = { } }; ////////////////////////////////////////////////////////////////////////// // HeadsUpDisplayUICommands ////////////////////////////////////////////////////////////////////////// HeadsUpDisplayUICommands = { - refreshCommand: function UIC_refreshCommand() { - var window = HUDService.currentContext(); - let command = window.document.getElementById("Tools:WebConsole"); - if (this.getOpenHUD() != null) { - command.setAttribute("checked", true); - } else { - command.removeAttribute("checked"); - } - }, - toggleHUD: function UIC_toggleHUD() { var window = HUDService.currentContext(); var gBrowser = window.gBrowser; var linkedBrowser = gBrowser.selectedTab.linkedBrowser; var tabId = gBrowser.getNotificationBox(linkedBrowser).getAttribute("id"); var hudId = "hud_" + tabId; var ownerDocument = gBrowser.selectedTab.ownerDocument; var hud = ownerDocument.getElementById(hudId); @@ -6824,121 +6830,136 @@ function GcliTerm(aContentWindow, aHudId this.document = aDocument; this.console = aConsole; this.hintNode = aHintNode; this._window = this.context.get().QueryInterface(Ci.nsIDOMWindow); this.createUI(); this.createSandbox(); - this.gcliConsole = gcli._internal.createDisplay({ - contentDocument: aContentWindow.document, - chromeDocument: this.document, - outputDocument: this.document, - chromeWindow: this.document.defaultView, - - hintElement: this.hintNode, - inputElement: this.inputNode, - completeElement: this.completeNode, - backgroundElement: this.inputStack, - consoleWrap: aConsoleWrap, - - eval: this.evalInSandbox.bind(this), - + this.show = this.show.bind(this); + this.hide = this.hide.bind(this); + + // Allow GCLI:Inputter to decide how and when to open a scratchpad window + let scratchpad = { + shouldActivate: function Scratchpad_shouldActivate(aEvent) { + return aEvent.shiftKey && + aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN; + }, + activate: function Scratchpad_activate(aValue) { + aValue = aValue.replace(/^\s*{\s*/, ''); + ScratchpadManager.openScratchpad({ text: aValue }); + return true; + }, + linkText: stringBundle.GetStringFromName('scratchpad.linkText') + }; + + this.opts = { environment: { + hudId: this.hudId, chromeDocument: this.document, contentDocument: aContentWindow.document }, - - tooltipClass: 'gcliterm-tooltip', - - // Allow GCLI:Inputter to decide how and when to open a scratchpad window - scratchpad: { - shouldActivate: function Scratchpad_shouldActivate(aEvent) { - return aEvent.shiftKey && - aEvent.keyCode === Ci.nsIDOMKeyEvent.DOM_VK_RETURN; - }, - activate: function Scratchpad_activate(aValue) { - aValue = aValue.replace(/^\s*{\s*/, ''); - ScratchpadManager.openScratchpad({ text: aValue }); - return true; - }, - linkText: stringBundle.GetStringFromName('scratchpad.linkText') + chromeDocument: this.document, + contentDocument: aContentWindow.document, + jsEnvironment: { + globalObject: unwrap(aContentWindow), + evalFunction: this.evalInSandbox.bind(this) }, - }); - - this.gcliConsole.onVisibilityChange.add(this.onVisibilityChange, this); - this.gcliConsole.onOutput.add(this.onOutput, this); + inputElement: this.inputNode, + completeElement: this.completeNode, + inputBackgroundElement: this.inputStack, + hintElement: this.hintNode, + consoleWrap: aConsoleWrap, + scratchpad: scratchpad, + gcliTerm: this + }; + + gcli._internal.commandOutputManager.addListener(this.onCommandOutput, this); + gcli._internal.createView(this.opts); + + if (!commandExports) { + commandExports = loadCommands(); + } } GcliTerm.prototype = { /** - * Show or remove the hint column from the display. - */ - onVisibilityChange: function GcliTerm_onVisibilityChange(ev) - { - if (ev.visible) { - this.hintNode.parentNode.hidden = false; - } - else { - let permaHint = false; - try { - permaHint = Services.prefs.getBoolPref("devtools.gcli.permaHint"); - } - catch (ex) {} - - if (!permaHint) { - this.hintNode.parentNode.hidden = true; - } - } + * Remove the hint column from the display. + */ + hide: function GcliTerm_hide() + { + let permaHint = false; + try { + permaHint = Services.prefs.getBoolPref("devtools.gcli.permaHint"); + } + catch (ex) {} + + if (!permaHint) { + this.hintNode.parentNode.hidden = true; + } + }, + + /** + * Undo the effects of calling hide(). + */ + show: function GcliTerm_show() + { + this.hintNode.parentNode.hidden = false; }, /** * Destroy the GcliTerm object. Call this method to avoid memory leaks. */ destroy: function Gcli_destroy() { - this.gcliConsole.onVisibilityChange.remove(this.onVisibilityChange, this); - this.gcliConsole.onOutput.remove(this.onOutput, this); - this.gcliConsole.destroy(); + gcli._internal.removeView(this.opts); + gcli._internal.commandOutputManager.removeListener(this.onCommandOutput, this); + + delete this.opts.chromeDocument; + delete this.opts.inputElement; + delete this.opts.completeElement; + delete this.opts.inputBackgroundElement; + delete this.opts.hintElement; + delete this.opts.contentDocument; + delete this.opts.jsEnvironment; + delete this.opts.gcliTerm; delete this.context; delete this.document; delete this.console; delete this.hintNode; delete this._window; delete this.sandbox; - delete this.element; - delete this.inputStack; - delete this.completeNode; - delete this.inputNode; + delete this.element + delete this.inputStack + delete this.completeNode + delete this.inputNode }, /** * Re-attaches a console when the contentWindow is recreated. * * @param nsIDOMWindow aContentWindow * The content window that we're providing as the context to commands * @param object aConsole * Console object to use within the GcliTerm. */ reattachConsole: function Gcli_reattachConsole(aContentWindow, aConsole) { this.context = Cu.getWeakReference(aContentWindow); this.console = aConsole; this.createSandbox(); - this.gcliConsole.reattach({ - contentDocument: aContentWindow.document, - environment: { - chromeDocument: this.document, - contentDocument: aContentWindow.document - }, - }); + this.opts.environment.contentDocument = aContentWindow.document; + this.opts.contentDocument = aContentWindow.document; + this.opts.jsEnvironment.globalObject = unwrap(aContentWindow); + + gcli._internal.reattachConsole(this.opts); }, /** * Generates and attaches the GCLI Terminal part of the Web Console, which * essentially consists of the interactive JavaScript input facility. */ createUI: function Gcli_createUI() { @@ -6959,17 +6980,17 @@ GcliTerm.prototype = { this.inputNode.setAttribute("class", "gcliterm-input-node"); this.inputNode.setAttribute("rows", "1"); this.inputStack.appendChild(this.inputNode); }, /** * Called by GCLI/canon when command line output changes. */ - onOutput: function Gcli_onOutput(aEvent) + onCommandOutput: function Gcli_onCommandOutput(aEvent) { // When we can update the history of the console, then we should stop // filtering incomplete reports. if (!aEvent.output.completed) { return; } this.writeOutput(aEvent.output.typed, CATEGORY_INPUT);
deleted file mode 100644 --- a/browser/devtools/webconsole/gcli.css +++ /dev/null @@ -1,74 +0,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 the GCLI. - * - * 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): - * Joe Walker <jwalker@mozilla.com> (original author) - * - * 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 ***** */ - -.gclichrome-output { - max-width: 350px; -} - -.gclichrome-tooltip { - max-width: 350px; -} - -.gcli-help-name { - text-align: end; -} - -.gcli-help-synopsis { - cursor: pointer; - display: inline-block; -} - -.gcli-help-synopsis:before { - content: '\bb'; -} - -.gcli-menu-option { - overflow: hidden; - white-space: nowrap; - cursor: pointer; -} - -.gcli-menu-template { - border-collapse: collapse; - width: 100%; -} - -.gcli-menu-error { - overflow: hidden; - white-space: nowrap; -} -
--- a/browser/devtools/webconsole/gcli.jsm +++ b/browser/devtools/webconsole/gcli.jsm @@ -31,17 +31,17 @@ * - mini_require: A very basic commonjs AMD (Asynchronous Modules Definition) * 'require' implementation (which is just good enough to load GCLI). For * more, see http://wiki.commonjs.org/wiki/Modules/AsynchronousDefinition. * This alleviates the need for requirejs (http://requirejs.org/) which is * used when running in the browser. This code is provided by dryice. * - A build of GCLI itself, packaged using dryice * - suffix-gcli.jsm - code to require the gcli object for EXPORTED_SYMBOLS. * - * See gcli.js for more details of this build. + * See Makefile.dryice.js for more details of this build. * For more details on dryice, see the https://github.com/mozilla/dryice * ******************************************************************************* * * * * * @@ -52,21 +52,20 @@ */ /////////////////////////////////////////////////////////////////////////////// var EXPORTED_SYMBOLS = [ "gcli" ]; /** - * Expose Node/HTMLElement objects. This allows us to use the Node constants - * without resorting to hardcoded numbers + * Expose a Node object. This allows us to use the Node constants without + * resorting to hardcoded numbers */ var Node = Components.interfaces.nsIDOMNode; -var HTMLElement = Components.interfaces.nsIDOMHTMLElement; Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); /** * Define setTimeout and clearTimeout to match the browser functions */ var setTimeout; @@ -224,17 +223,17 @@ var console = {}; } if (aThing === null) { return "null"; } if (typeof aThing == "object") { var type = getCtorName(aThing); - if (aThing instanceof Node && aThing.tagName) { + if (type == "XULElement") { return debugElement(aThing); } type = (type == "Object" ? "" : type + " "); var json; try { json = JSON.stringify(aThing); } catch (ex) { @@ -288,18 +287,18 @@ var console = {}; if (typeof aThing == "object") { var reply = ""; var type = getCtorName(aThing); if (type == "Error") { reply += " " + aThing.message + "\n"; reply += logProperty("stack", aThing.stack); } - else if (aThing instanceof Node && aThing.tagName) { - reply += " " + debugElement(aThing) + "\n"; + else if (type == "XULElement") { + reply += " " + debugElement(aThing) + " (XUL)\n"; } else { var keys = Object.getOwnPropertyNames(aThing); if (keys.length > 0) { reply += type + "\n"; keys.forEach(function(aProp) { reply += logProperty(aProp, aThing[aProp]); }, this); @@ -687,47 +686,39 @@ var mozl10n = {}; } catch (ex) { throw new Error("Failure in lookupFormat('" + name + "')"); } }; })(mozl10n); -define('gcli/index', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/types/basic', 'gcli/types/command', 'gcli/types/javascript', 'gcli/types/node', 'gcli/types/resource', 'gcli/types/setting', 'gcli/types/selection', 'gcli/settings', 'gcli/ui/intro', 'gcli/ui/focus', 'gcli/ui/fields/basic', 'gcli/ui/fields/javascript', 'gcli/ui/fields/selection', 'gcli/commands/help', 'gcli/ui/ffdisplay'], function(require, exports, module) { +define('gcli/index', ['require', 'exports', 'module' , 'gcli/canon', 'gcli/types/basic', 'gcli/types/javascript', 'gcli/types/node', 'gcli/types/resource', 'gcli/cli', 'gcli/commands/help', 'gcli/ui/console'], function(require, exports, module) { // The API for use by command authors exports.addCommand = require('gcli/canon').addCommand; exports.removeCommand = require('gcli/canon').removeCommand; exports.lookup = mozl10n.lookup; exports.lookupFormat = mozl10n.lookupFormat; // Internal startup process. Not exported require('gcli/types/basic').startup(); - require('gcli/types/command').startup(); require('gcli/types/javascript').startup(); require('gcli/types/node').startup(); require('gcli/types/resource').startup(); - require('gcli/types/setting').startup(); - require('gcli/types/selection').startup(); - - require('gcli/settings').startup(); - require('gcli/ui/intro').startup(); - require('gcli/ui/focus').startup(); - require('gcli/ui/fields/basic').startup(); - require('gcli/ui/fields/javascript').startup(); - require('gcli/ui/fields/selection').startup(); - + require('gcli/cli').startup(); require('gcli/commands/help').startup(); - // Some commands require customizing for Firefox before we include them - // require('gcli/cli').startup(); - // require('gcli/commands/pref').startup(); - - var FFDisplay = require('gcli/ui/ffdisplay').FFDisplay; + var Requisition = require('gcli/cli').Requisition; + var Console = require('gcli/ui/console').Console; + + var cli = require('gcli/cli'); + var jstype = require('gcli/types/javascript'); + var nodetype = require('gcli/types/node'); + var resource = require('gcli/types/resource'); /** * API for use by HUDService only. * This code is internal and subject to change without notice. */ exports._internal = { require: require, define: define, @@ -738,22 +729,65 @@ define('gcli/index', ['require', 'export * members: * - contentDocument: From the window of the attached tab * - chromeDocument: GCLITerm.document * - environment.hudId: GCLITerm.hudId * - jsEnvironment.globalObject: 'window' * - jsEnvironment.evalFunction: 'eval' in a sandbox * - inputElement: GCLITerm.inputNode * - completeElement: GCLITerm.completeNode + * - gcliTerm: GCLITerm * - hintElement: GCLITerm.hintNode * - inputBackgroundElement: GCLITerm.inputStack */ - createDisplay: function(opts) { - return new FFDisplay(opts); - } + createView: function(opts) { + jstype.setGlobalObject(opts.jsEnvironment.globalObject); + nodetype.setDocument(opts.contentDocument); + cli.setEvalFunction(opts.jsEnvironment.evalFunction); + resource.setDocument(opts.contentDocument); + + if (opts.requisition == null) { + opts.requisition = new Requisition(opts.environment, opts.chromeDocument); + } + + opts.console = new Console(opts); + }, + + /** + * Called when the page to which we're attached changes + */ + reattachConsole: function(opts) { + jstype.setGlobalObject(opts.jsEnvironment.globalObject); + nodetype.setDocument(opts.contentDocument); + cli.setEvalFunction(opts.jsEnvironment.evalFunction); + + opts.requisition.environment = opts.environment; + opts.requisition.document = opts.chromeDocument; + + opts.console.reattachConsole(opts); + }, + + /** + * Undo the effects of createView() to prevent memory leaks + */ + removeView: function(opts) { + opts.console.destroy(); + delete opts.console; + + opts.requisition.destroy(); + delete opts.requisition; + + cli.unsetEvalFunction(); + nodetype.unsetDocument(); + jstype.unsetGlobalObject(); + resource.unsetDocument(); + resource.clearResourceCache(); + }, + + commandOutputManager: require('gcli/canon').commandOutputManager }; }); /* * Copyright 2009-2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ @@ -894,21 +928,26 @@ canon.Command = Command; /** * A wrapper for a paramSpec so we can sort out shortened versions names for * option switches */ function Parameter(paramSpec, command, groupName) { this.command = command || { name: 'unnamed' }; - this.paramSpec = paramSpec; - this.name = this.paramSpec.name; - this.type = this.paramSpec.type; + + Object.keys(paramSpec).forEach(function(key) { + this[key] = paramSpec[key]; + }, this); + + this.description = 'description' in this ? this.description : undefined; + this.description = lookup(this.description, 'canonDescNone'); + this.manual = 'manual' in this ? this.manual : undefined; + this.manual = lookup(this.manual); this.groupName = groupName; - this.defaultValue = this.paramSpec.defaultValue; if (!this.name) { throw new Error('In ' + this.command.name + ': all params must have a name'); } var typeSpec = this.type; this.type = types.getType(typeSpec); @@ -916,17 +955,17 @@ function Parameter(paramSpec, command, g console.error('Known types: ' + types.getTypeNames().join(', ')); throw new Error('In ' + this.command.name + '/' + this.name + ': can\'t find type for: ' + JSON.stringify(typeSpec)); } // boolean parameters have an implicit defaultValue:false, which should // not be changed. See the docs. if (this.type instanceof BooleanType) { - if (this.defaultValue !== undefined) { + if ('defaultValue' in this) { console.error('In ' + this.command.name + '/' + this.name + ': boolean parameters can not have a defaultValue.' + ' Ignoring'); } this.defaultValue = false; } // Check the defaultValue for validity. @@ -943,94 +982,45 @@ function Parameter(paramSpec, command, g defaultConversion.getStatus()); } } catch (ex) { console.error('In ' + this.command.name + '/' + this.name + ': ' + ex); } } - - // Some typed (boolean, array) have a non 'undefined' blank value. Give the - // type a chance to override the default defaultValue of undefined - if (this.defaultValue === undefined) { - this.defaultValue = this.type.getBlank().value; - } } /** * Does the given name uniquely identify this param (among the other params * in this command) * @param name The name to check */ Parameter.prototype.isKnownAs = function(name) { if (name === '--' + this.name) { return true; } return false; }; /** - * Read the default value for this parameter either from the parameter itself - * (if this function has been over-ridden) or from the type, or from calling - * parseString on an empty string - */ -Parameter.prototype.getBlank = function() { - var conversion; - - if (this.type.getBlank) { - return this.type.getBlank(); - } - - return this.type.parseString(''); -}; - -/** - * Resolve the manual for this parameter, by looking in the paramSpec - * and doing a l10n lookup - */ -Object.defineProperty(Parameter.prototype, 'manual', { - get: function() { - return lookup(this.paramSpec.manual || undefined); - }, - enumerable: true -}); - -/** - * Resolve the description for this parameter, by looking in the paramSpec - * and doing a l10n lookup - */ -Object.defineProperty(Parameter.prototype, 'description', { - get: function() { - return lookup(this.paramSpec.description || undefined, 'canonDescNone'); - }, - enumerable: true -}); - -/** * Is the user required to enter data for this parameter? (i.e. has * defaultValue been set to something other than undefined) */ -Object.defineProperty(Parameter.prototype, 'isDataRequired', { - get: function() { - return this.defaultValue === undefined; - }, - enumerable: true -}); +Parameter.prototype.isDataRequired = function() { + return this.defaultValue === undefined; +}; /** * Are we allowed to assign data to this parameter using positional * parameters? */ -Object.defineProperty(Parameter.prototype, 'isPositionalAllowed', { - get: function() { - return this.groupName == null; - }, - enumerable: true -}); +Parameter.prototype.isPositionalAllowed = function() { + return this.groupName == null; +}; canon.Parameter = Parameter; /** * Add a command to the canon of known commands. * This function is exposed to the outside world (via gcli/index). It is * documented in docs/index.md for all the world to see. @@ -1038,34 +1028,34 @@ canon.Parameter = Parameter; * @return The new command */ canon.addCommand = function addCommand(commandSpec) { var command = new Command(commandSpec); commands[commandSpec.name] = command; commandNames.push(commandSpec.name); commandNames.sort(); - canon.onCanonChange(); + canon.canonChange(); return command; }; /** * Remove an individual command. The opposite of #addCommand(). * @param commandOrName Either a command name or the command itself. */ canon.removeCommand = function removeCommand(commandOrName) { var name = typeof commandOrName === 'string' ? commandOrName : commandOrName.name; delete commands[name]; commandNames = commandNames.filter(function(test) { return test !== name; }); - canon.onCanonChange(); + canon.canonChange(); }; /** * Retrieve a command by name * @param name The name of the command to retrieve */ canon.getCommand = function getCommand(name) { // '|| undefined' is to silence 'reference to undefined property' warnings @@ -1087,32 +1077,56 @@ canon.getCommands = function getCommands */ canon.getCommandNames = function getCommandNames() { return commandNames.slice(0); }; /** * Enable people to be notified of changes to the list of commands */ -canon.onCanonChange = util.createEvent('canon.onCanonChange'); +canon.canonChange = util.createEvent('canon.canonChange'); /** * CommandOutputManager stores the output objects generated by executed * commands. * * CommandOutputManager is exposed (via canon.commandOutputManager) to the the * outside world and could (but shouldn't) be used before gcli.startup() has * been called. This could should be defensive to that where possible, and we * should certainly document if the use of it or similar will fail if used too * soon. */ function CommandOutputManager() { - this.onOutput = util.createEvent('CommandOutputManager.onOutput'); + this._event = util.createEvent('CommandOutputManager'); } +/** + * Call this method to notify the manager (and therefore all listeners) of a + * new or updated command output. + * @param output The command output object that has been created or updated. + */ +CommandOutputManager.prototype.sendCommandOutput = function(output) { + this._event({ output: output }); +}; + +/** + * Register a function to be called whenever there is a new command output + * object. + */ +CommandOutputManager.prototype.addListener = function(fn, ctx) { + this._event.add(fn, ctx); +}; + +/** + * Undo the effects of CommandOutputManager.addListener() + */ +CommandOutputManager.prototype.removeListener = function(fn, ctx) { + this._event.remove(fn, ctx); +}; + canon.CommandOutputManager = CommandOutputManager; /** * We maintain a global command output manager for the majority case where * there is only one important set of outputs. */ canon.commandOutputManager = new CommandOutputManager(); @@ -1128,91 +1142,50 @@ define('gcli/util', ['require', 'exports /* * A number of DOM manipulation and event handling utilities. */ //------------------------------------------------------------------------------ -var eventDebug = false; - -/** - * Useful way to create a name for a handler, used in createEvent() - */ -function nameFunction(handler) { - var scope = handler.scope ? handler.scope.constructor.name + '.' : ''; - var name = handler.func.name; - if (name) { - return scope + name; - } - for (var prop in handler.scope) { - if (handler.scope[prop] === handler.func) { - return scope + prop; - } - } - return scope + handler.func; -} - /** * Create an event. * For use as follows: * * function Hat() { - * this.putOn = createEvent('Hat.putOn'); + * this.putOn = createEvent(); * ... * } * Hat.prototype.adorn = function(person) { * this.putOn({ hat: hat, person: person }); * ... * } * * var hat = new Hat(); * hat.putOn.add(function(ev) { * console.log('The hat ', ev.hat, ' has is worn by ', ev.person); * }, scope); * * @param name Optional name to help with debugging */ exports.createEvent = function(name) { var handlers = []; - var holdFire = false; - var heldEvents = []; - var eventCombiner = undefined; /** * This is how the event is triggered. * @param ev The event object to be passed to the event listeners */ var event = function(ev) { - if (holdFire) { - heldEvents.push(ev); - if (eventDebug) { - console.log('Held fire: ' + name, ev); - } - return; - } - - if (eventDebug) { - console.group('Fire: ' + name + ' to ' + handlers.length + ' listeners', ev); - } - // Use for rather than forEach because it step debugs better, which is // important for debugging events for (var i = 0; i < handlers.length; i++) { var handler = handlers[i]; - if (eventDebug) { - console.log(nameFunction(handler)); - } handler.func.call(handler.scope, ev); } - - if (eventDebug) { - console.groupEnd(); - } }; /** * Add a new handler function * @param func The function to call when this event is triggered * @param scope Optional 'this' object for the function call */ event.add = function(func, scope) { @@ -1234,284 +1207,158 @@ exports.createEvent = function(name) { /** * Remove all handlers. * Reset the state of this event back to it's post create state */ event.removeAll = function() { handlers = []; }; - /** - * Temporarily prevent this event from firing. - * @see resumeFire(ev) - */ - event.holdFire = function() { - if (eventDebug) { - console.group('Holding fire: ' + name); - } - - holdFire = true; - }; - - /** - * Resume firing events. - * If there are heldEvents, then we fire one event to cover them all. If an - * event combining function has been provided then we use that to combine the - * events. Otherwise the last held event is used. - * @see holdFire() - */ - event.resumeFire = function() { - if (eventDebug) { - console.groupEnd('Resume fire: ' + name); - } - - if (holdFire !== true) { - throw new Error('Event not held: ' + name); - } - - holdFire = false; - if (heldEvents.length === 0) { - return; - } - - if (heldEvents.length === 1) { - event(heldEvents[0]); - } - else { - var first = heldEvents[0]; - var last = heldEvents[heldEvents.length - 1]; - if (eventCombiner) { - event(eventCombiner(first, last, heldEvents)); - } - else { - event(last); - } - } - - heldEvents = []; - }; - - /** - * When resumeFire has a number of events to combine, by default it just - * picks the last, however you can provide an eventCombiner which returns a - * combined event. - * eventCombiners will be passed 3 parameters: - * - first The first event to be held - * - last The last event to be held - * - all An array containing all the held events - * The return value from an eventCombiner is expected to be an event object - */ - Object.defineProperty(event, 'eventCombiner', { - set: function(newEventCombiner) { - if (typeof newEventCombiner !== 'function') { - throw new Error('eventCombiner is not a function'); - } - eventCombiner = newEventCombiner; - }, - - enumerable: true - }); - return event; }; //------------------------------------------------------------------------------ +var dom = {}; + /** * XHTML namespace */ -exports.NS_XHTML = 'http://www.w3.org/1999/xhtml'; +dom.NS_XHTML = 'http://www.w3.org/1999/xhtml'; /** * XUL namespace */ -exports.NS_XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; +dom.NS_XUL = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul'; /** * Create an HTML or XHTML element depending on whether the document is HTML * or XML based. Where HTML/XHTML elements are distinguished by whether they * are created using doc.createElementNS('http://www.w3.org/1999/xhtml', tag) * or doc.createElement(tag) * If you want to create a XUL element then you don't have a problem knowing * what namespace you want. * @param doc The document in which to create the element * @param tag The name of the tag to create * @returns The created element */ -exports.createElement = function(doc, tag) { - if (exports.isXmlDocument(doc)) { - return doc.createElementNS(exports.NS_XHTML, tag); +dom.createElement = function(doc, tag) { + if (dom.isXmlDocument(doc)) { + return doc.createElementNS(dom.NS_XHTML, tag); } else { return doc.createElement(tag); } }; /** * Remove all the child nodes from this node * @param elem The element that should have it's children removed */ -exports.clearElement = function(elem) { +dom.clearElement = function(elem) { while (elem.hasChildNodes()) { elem.removeChild(elem.firstChild); } }; var isAllWhitespace = /^\s*$/; /** * Iterate over the children of a node looking for TextNodes that have only * whitespace content and remove them. * This utility is helpful when you have a template which contains whitespace * so it looks nice, but where the whitespace interferes with the rendering of * the page * @param elem The element which should have blank whitespace trimmed * @param deep Should this node removal include child elements */ -exports.removeWhitespace = function(elem, deep) { +dom.removeWhitespace = function(elem, deep) { var i = 0; while (i < elem.childNodes.length) { var child = elem.childNodes.item(i); - if (child.nodeType === 3 /*Node.TEXT_NODE*/ && + if (child.nodeType === Node.TEXT_NODE && isAllWhitespace.test(child.textContent)) { elem.removeChild(child); } else { - if (deep && child.nodeType === 1 /*Node.ELEMENT_NODE*/) { - exports.removeWhitespace(child, deep); + if (deep && child.nodeType === Node.ELEMENT_NODE) { + dom.removeWhitespace(child, deep); } i++; } } }; /** * Create a style element in the document head, and add the given CSS text to * it. * @param cssText The CSS declarations to append * @param doc The document element to work from - * @param id Optional id to assign to the created style tag. If the id already - * exists on the document, we do not add the CSS again. - */ -exports.importCss = function(cssText, doc, id) { - if (!cssText) { - return undefined; - } - + */ +dom.importCss = function(cssText, doc) { doc = doc || document; - if (!id) { - id = 'hash-' + hash(cssText); - } - - var found = doc.getElementById(id); - if (found) { - if (found.tagName.toLowerCase() !== 'style') { - console.error('Warning: importCss passed id=' + id + - ', but that pre-exists (and isn\'t a style tag)'); - } - return found; - } - - var style = exports.createElement(doc, 'style'); - style.id = id; + var style = dom.createElement(doc, 'style'); style.appendChild(doc.createTextNode(cssText)); var head = doc.getElementsByTagName('head')[0] || doc.documentElement; head.appendChild(style); return style; }; /** - * Simple hash function which happens to match Java's |String.hashCode()| - * Done like this because I we don't need crypto-security, but do need speed, - * and I don't want to spend a long time working on it. - * @see http://werxltd.com/wp/2010/05/13/javascript-implementation-of-javas-string-hashcode-method/ - */ -function hash(str) { - var hash = 0; - if (str.length == 0) { - return hash; - } - for (var i = 0; i < str.length; i++) { - var char = str.charCodeAt(i); - hash = ((hash << 5) - hash) + char; - hash = hash & hash; // Convert to 32bit integer - } - return hash; -} - -/** * There are problems with innerHTML on XML documents, so we need to do a dance * using document.createRange().createContextualFragment() when in XML mode */ -exports.setContents = function(elem, contents) { - if (typeof HTMLElement !== 'undefined' && contents instanceof HTMLElement) { - exports.clearElement(elem); - elem.appendChild(contents); - return; - } - - if (exports.isXmlDocument(elem.ownerDocument)) { +dom.setInnerHtml = function(elem, html) { + if (dom.isXmlDocument(elem.ownerDocument)) { try { - var ns = elem.ownerDocument.documentElement.namespaceURI; - if (!ns) { - ns = exports.NS_XHTML; - } - exports.clearElement(elem); - contents = '<div xmlns="' + ns + '">' + contents + '</div>'; + dom.clearElement(elem); + html = '<div xmlns="' + dom.NS_XHTML + '">' + html + '</div>'; var range = elem.ownerDocument.createRange(); - var child = range.createContextualFragment(contents).firstChild; + var child = range.createContextualFragment(html).firstChild; while (child.hasChildNodes()) { elem.appendChild(child.firstChild); } } catch (ex) { console.error('Bad XHTML', ex); console.trace(); throw ex; } } else { - elem.innerHTML = contents; - } -}; - -/** - * Load some HTML into the given document and return a DOM element. - * This utility assumes that the html has a single root (other than whitespace) - */ -exports.toDom = function(document, html) { - var div = exports.createElement(document, 'div'); - exports.setContents(div, html); - return div.children[0]; + elem.innerHTML = html; + } }; /** * How to detect if we're in an XML document. * In a Mozilla we check that document.xmlVersion = null, however in Chrome * we use document.contentType = undefined. * @param doc The document element to work from (defaulted to the global * 'document' if missing */ -exports.isXmlDocument = function(doc) { +dom.isXmlDocument = function(doc) { doc = doc || document; // Best test for Firefox if (doc.contentType && doc.contentType != 'text/html') { return true; } // Best test for Chrome if (doc.xmlVersion != null) { return true; } return false; }; +exports.dom = dom; + /** * Find the position of [element] in [nodeList]. * @returns an index of the match, or -1 if there is no match */ function positionInNodeList(element, nodeList) { for (var i = 0; i < nodeList.length; i++) { if (element === nodeList[i]) { return i; @@ -1520,17 +1367,17 @@ function positionInNodeList(element, nod return -1; } /** * Find a unique CSS selector for a given element * @returns a string such that ele.ownerDocument.querySelector(reply) === ele * and ele.ownerDocument.querySelectorAll(reply).length === 1 */ -exports.findCssSelector = function(ele) { +dom.findCssSelector = function(ele) { var document = ele.ownerDocument; if (ele.id && document.getElementById(ele.id) === ele) { return '#' + ele.id; } // Inherently unique by tag name var tagName = ele.tagName.toLowerCase(); if (tagName === 'html') { @@ -1570,68 +1417,46 @@ exports.findCssSelector = function(ele) if (matches.length === 1) { return selector; } } } // So we can be unique w.r.t. our parent, and use recursion index = positionInNodeList(ele, ele.parentNode.children) + 1; - selector = exports.findCssSelector(ele.parentNode) + ' > ' + + selector = dom.findCssSelector(ele.parentNode) + ' > ' + tagName + ':nth-child(' + index + ')'; return selector; }; -/** - * Work out the path for images. - */ -exports.createUrlLookup = function(callingModule) { - return function imageUrl(path) { - try { - return require('text!gcli/ui/' + path); - } - catch (ex) { - var filename = callingModule.id.split('/').pop() + '.js'; - - if (callingModule.uri.substr(-filename.length) !== filename) { - console.error('Can\'t work out path from module.uri/module.id'); - return path; - } - - if (callingModule.uri) { - var end = callingModule.uri.length - filename.length - 1; - return callingModule.uri.substr(0, end) + '/' + path; - } - - return filename + '/' + path; - } - }; -}; - - //------------------------------------------------------------------------------ /** + * Various event utilities + */ +var event = {}; + +/** * Keyboard handling is a mess. http://unixpapa.com/js/key.html * It would be good to use DOM L3 Keyboard events, * http://www.w3.org/TR/2010/WD-DOM-Level-3-Events-20100907/#events-keyboardevents * however only Webkit supports them, and there isn't a shim on Monernizr: * https://github.com/Modernizr/Modernizr/wiki/HTML5-Cross-browser-Polyfills * and when the code that uses this KeyEvent was written, nothing was clear, * so instead, we're using this unmodern shim: * http://stackoverflow.com/questions/5681146/chrome-10-keyevent-or-something-similar-to-firefoxs-keyevent * See BUG 664991: GCLI's keyboard handling should be updated to use DOM-L3 * https://bugzilla.mozilla.org/show_bug.cgi?id=664991 */ if ('KeyEvent' in this) { - exports.KeyEvent = this.KeyEvent; + event.KeyEvent = this.KeyEvent; } else { - exports.KeyEvent = { + event.KeyEvent = { DOM_VK_CANCEL: 3, DOM_VK_HELP: 6, DOM_VK_BACK_SPACE: 8, DOM_VK_TAB: 9, DOM_VK_CLEAR: 12, DOM_VK_RETURN: 13, DOM_VK_ENTER: 14, DOM_VK_SHIFT: 16, @@ -1740,16 +1565,18 @@ else { DOM_VK_OPEN_BRACKET: 219, DOM_VK_BACK_SLASH: 220, DOM_VK_CLOSE_BRACKET: 221, DOM_VK_QUOTE: 222, DOM_VK_META: 224 }; } +exports.event = event; + }); /* * Copyright 2009-2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ @@ -1784,25 +1611,16 @@ exports.lookupPlural = function(key, ord exports.getPreferredLocales = function() { return [ 'root' ]; }; /** @see lookup() in lib/gcli/l10n.js */ exports.lookup = function(key) { try { - // Our memory leak hunter walks reachable objects trying to work out what - // type of thing they are using object.constructor.name. If that causes - // problems then we can avoid the unknown-key-exception with the following: - /* - if (key === 'constructor') { - return { name: 'l10n-mem-leak-defeat' }; - } - */ - return stringBundle.GetStringFromName(key); } catch (ex) { console.error('Failed to lookup ', key, ex); return key; } }; @@ -1955,17 +1773,18 @@ types.Conversion = Conversion; Conversion.prototype.assign = function(assignment) { this.arg.assign(assignment); }; /** * Work out if there is information provided in the contained argument. */ Conversion.prototype.isDataProvided = function() { - return !this.arg.isBlank(); + var argProvided = this.arg.text !== ''; + return this.value !== undefined || argProvided; }; /** * 2 conversions are equal if and only if their args are equal (argEquals) and * their values are equal (valueEquals). * @param that The conversion object to compare against. */ Conversion.prototype.equals = function(that) { @@ -1988,17 +1807,17 @@ Conversion.prototype.valueEquals = funct }; /** * Check that the argument in this conversion is equal to the value in the * provided conversion as defined by the argument (i.e. arg.equals). * @param that The conversion to compare arguments with */ Conversion.prototype.argEquals = function(that) { - return that == null ? false : this.arg.equals(that.arg); + return this.arg.equals(that.arg); }; /** * Accessor for the status of this conversion */ Conversion.prototype.getStatus = function(arg) { return this._status; }; @@ -2027,66 +1846,16 @@ Conversion.prototype.toString = function Conversion.prototype.getPredictions = function() { if (typeof this.predictions === 'function') { return this.predictions(); } return this.predictions || []; }; /** - * Accessor for a prediction by index. - * This is useful above <tt>getPredictions()[index]</tt> because it normalizes - * index to be within the bounds of the predictions, which means that the UI - * can maintain an index of which prediction to choose without caring how many - * predictions there are. - * @param index The index of the prediction to choose - */ -Conversion.prototype.getPredictionAt = function(index) { - if (index == null) { - return undefined; - } - - var predictions = this.getPredictions(); - if (predictions.length === 0) { - return undefined; - } - - index = index % predictions.length; - if (index < 0) { - index = predictions.length + index; - } - return predictions[index]; -}; - -/** - * Accessor for a prediction by index. - * This is useful above <tt>getPredictions()[index]</tt> because it normalizes - * index to be within the bounds of the predictions, which means that the UI - * can maintain an index of which prediction to choose without caring how many - * predictions there are. - * @param index The index of the prediction to choose - */ -Conversion.prototype.constrainPredictionIndex = function(index) { - if (index == null) { - return undefined; - } - - var predictions = this.getPredictions(); - if (predictions.length === 0) { - return undefined; - } - - index = index % predictions.length; - if (index < 0) { - index = predictions.length + index; - } - return index; -}; - -/** * ArrayConversion is a special Conversion, needed because arrays are converted * member by member rather then as a whole, which means we can track the * conversion if individual array elements. So an ArrayConversion acts like a * normal Conversion (which is needed as Assignment requires a Conversion) but * it can also be devolved into a set of Conversions for each array member. */ function ArrayConversion(conversions, arg) { this.arg = arg; @@ -2216,33 +1985,21 @@ Type.prototype.increment = function(valu * If there is some concept of a lower value, return it, * otherwise return undefined. */ Type.prototype.decrement = function(value) { return undefined; }; /** - * The 'blank value' of most types is 'undefined', but there are exceptions; - * This allows types to specify a better conversion from empty string than - * 'undefined'. - * 2 known examples of this are boolean -> false and array -> [] - */ -Type.prototype.getBlank = function() { - return this.parse(new Argument()); -}; - -/** - * This is something of a hack for the benefit of DeferredType which needs to - * be able to lie about it's type for fields to accept it as one of their own. - * Sub-types can ignore this unless they're DeferredType. - */ -Type.prototype.getType = function() { - return this; -}; + * There is interesting information (like predictions) in a conversion of + * nothing, the output of this can sometimes be customized. + * @return Conversion + */ +Type.prototype.getDefault = undefined; types.Type = Type; /** * Private registry of types * Invariant: types[name] = type.name */ var registeredTypes = {}; @@ -2379,17 +2136,16 @@ Argument.prototype.merge = function(foll * Returns a new Argument like this one but with the text set to * <tt>replText</tt> and the end adjusted to fit. * @param replText Text to replace the old text value */ Argument.prototype.beget = function(replText, options) { var prefix = this.prefix; var suffix = this.suffix; - // We need to add quotes when the replacement string has spaces or is empty var quote = (replText.indexOf(' ') >= 0 || replText.length == 0) ? '\'' : ''; if (options) { prefix = (options.prefixSpace ? ' ' : '') + quote; suffix = quote; } @@ -2471,22 +2227,20 @@ Argument.merge = function(argArray, star }; argument.Argument = Argument; /** * ScriptArgument is a marker that the argument is designed to be Javascript. * It also implements the special rules that spaces after the { or before the - * } are part of the pre/suffix rather than the content, and that they are - * never 'blank' so they can be used by Requisition._split() and not raise an - * ERROR status due to being blank. + * } are part of the pre/suffix rather than the content. */ function ScriptArgument(text, prefix, suffix) { - this.text = text !== undefined ? text : ''; + this.text = text; this.prefix = prefix !== undefined ? prefix : ''; this.suffix = suffix !== undefined ? suffix : ''; while (this.text.charAt(0) === ' ') { this.prefix = this.prefix + ' '; this.text = this.text.substring(1); } @@ -2502,33 +2256,27 @@ ScriptArgument.prototype = Object.create * Returns a new Argument like this one but with the text set to * <tt>replText</tt> and the end adjusted to fit. * @param replText Text to replace the old text value */ ScriptArgument.prototype.beget = function(replText, options) { var prefix = this.prefix; var suffix = this.suffix; + var quote = (replText.indexOf(' ') >= 0 || replText.length == 0) ? + '\'' : ''; + if (options && options.normalize) { prefix = '{ '; suffix = ' }'; } return new ScriptArgument(replText, prefix, suffix); }; -/** - * ScriptArguments are never blank due to the '{' and '}' and their special use - * for the command argument requires them not to be blank even when there is - * no text. - */ -ScriptArgument.prototype.isBlank = function() { - return false; -}; - argument.ScriptArgument = ScriptArgument; /** * Commands like 'echo' with a single string argument, and used with the * special format like: 'echo a b c' effectively have a number of arguments * merged together. */ @@ -2790,51 +2538,51 @@ argument.ArrayArgument = ArrayArgument; }); /* * Copyright 2009-2011 Mozilla Foundation and contributors * Licensed under the New BSD license. See LICENSE.txt or: * http://opensource.org/licenses/BSD-3-Clause */ -define('gcli/types/basic', ['require', 'exports', 'module' , 'gcli/l10n', 'gcli/types', 'gcli/types/spell', 'gcli/types/selection', 'gcli/argument'], function(require, exports, module) { +define('gcli/types/basic', ['require', 'exports', 'module' , 'gcli/l10n', 'gcli/types', 'gcli/argument'], function(require, exports, module) { var l10n = require('gcli/l10n'); var types = require('gcli/types'); var Type = require('gcli/types').Type; var Status = require('gcli/types').Status; var Conversion = require('gcli/types').Conversion; var ArrayConversion = require('gcli/types').ArrayConversion; -var Speller = require('gcli/types/spell').Speller; -var SelectionType = require('gcli/types/selection').SelectionType; var Argument = require('gcli/argument').Argument; var TrueNamedArgument = require('gcli/argument').TrueNamedArgument; var FalseNamedArgument = require('gcli/argument').FalseNamedArgument; var ArrayArgument = require('gcli/argument').ArrayArgument; /** * Registration and de-registration. */ exports.startup = function() { types.registerType(StringType); types.registerType(NumberType); types.registerType(BooleanType); types.registerType(BlankType); + types.registerType(SelectionType); types.registerType(DeferredType); types.registerType(ArrayType); }; exports.shutdown = function() { types.unregisterType(StringType); types.unregisterType(NumberType); types.unregisterType(BooleanType); types.unregisterType(BlankType); + types.unregisterType(SelectionType); types.unregisterType(DeferredType); types.unregisterType(ArrayType); }; /** * 'string' the most basic string type that doesn't need to convert */ @@ -2850,17 +2598,17 @@ StringType.prototype.stringify = functio if (value == null) { return ''; } return value.toString(); }; StringType.prototype.parse = function(arg) { if (arg.text == null || arg.text === '') { - return new Conversion(undefined, arg, Status.INCOMPLETE, ''); + return new Conversion(null, arg, Status.INCOMPLETE, ''); } return new Conversion(arg.text, arg); }; StringType.prototype.name = 'string'; exports.StringType = StringType; @@ -2892,52 +2640,50 @@ NumberType.prototype.getMin = function() if (this._min) { if (typeof this._min === 'function') { return this._min(); } if (typeof this._min === 'number') { return this._min; } } - return undefined; + return 0; }; NumberType.prototype.getMax = function() { if (this._max) { if (typeof this._max === 'function') { return this._max(); } if (typeof this._max === 'number') { return this._max; } } return undefined; }; NumberType.prototype.parse = function(arg) { if (arg.text.replace(/\s/g, '').length === 0) { - return new Conversion(undefined, arg, Status.INCOMPLETE, ''); + return new Conversion(null, arg, Status.INCOMPLETE, ''); } var value = parseInt(arg.text, 10); if (isNaN(value)) { - return new Conversion(undefined, arg, Status.ERROR, + return new Conversion(null, arg, Status.ERROR, l10n.lookupFormat('typesNumberNan', [ arg.text ])); } - var max = this.getMax(); - if (max != null && value > max) { - return new Conversion(undefined, arg, Status.ERROR, - l10n.lookupFormat('typesNumberMax', [ value, max ])); - } - - var min = this.getMin(); - if (min != null && value < min) { - return new Conversion(undefined, arg, Status.ERROR, - l10n.lookupFormat('typesNumberMin', [ value, min ])); + if (this.getMax() != null && value > this.getMax()) { + return new Conversion(null, arg, Status.ERROR, + l10n.lookupFormat('typesNumberMax', [ value, this.getMax() ])); + } + + if (value < this.getMin()) { + return new Conversion(null, arg, Status.ERROR, + l10n.lookupFormat('typesNumberMin', [ value, this.getMin() ])); } return new Conversion(value, arg); }; NumberType.prototype.decrement = function(value) { if (typeof value !== 'number' || isNaN(value)) { return this.getMax() || 1; @@ -2945,18 +2691,17 @@ NumberType.prototype.decrement = functio var newValue = value - this._step; // Snap to the nearest incremental of the step newValue = Math.ceil(newValue / this._step) * this._step; return this._boundsCheck(newValue); };