diff --git a/browser/base/content/browser-menubar.inc b/browser/base/content/browser-menubar.inc index 4947fae8a8c9..fbbabf288d2d 100644 --- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -522,7 +522,7 @@ - + diff --git a/browser/devtools/commandline/CmdDbg.jsm b/browser/devtools/commandline/CmdDbg.jsm index c74cbf9578e4..f30593598580 100644 --- a/browser/devtools/commandline/CmdDbg.jsm +++ b/browser/devtools/commandline/CmdDbg.jsm @@ -18,6 +18,47 @@ gcli.addCommand({ manual: gcli.lookup("dbgManual") }); +/** + * 'dbg open' command + */ +gcli.addCommand({ + name: "dbg open", + description: gcli.lookup("dbgOpen"), + params: [], + exec: function (args, context) { + let win = context.environment.chromeDocument.defaultView; + let tab = win.gBrowser.selectedTab; + let dbg = win.DebuggerUI.findDebugger(); + + if (dbg) { + if (dbg.ownerTab !== tab) { + win.DebuggerUI.toggleDebugger(); + } + + return; + } + + win.DebuggerUI.toggleDebugger(); + } +}); + +/** + * 'dbg close' command + */ +gcli.addCommand({ + name: "dbg close", + description: gcli.lookup("dbgClose"), + params: [], + exec: function (args, context) { + let win = context.environment.chromeDocument.defaultView; + let tab = win.gBrowser.selectedTab; + let dbg = win.DebuggerUI.findDebugger(); + + if (dbg) { + dbg.close(); + } + } +}); /** * 'dbg interrupt' command diff --git a/browser/devtools/commandline/test/browser_dbg_cmd.js b/browser/devtools/commandline/test/browser_dbg_cmd.js index eef119a5cb29..8011c8c9fa2f 100644 --- a/browser/devtools/commandline/test/browser_dbg_cmd.js +++ b/browser/devtools/commandline/test/browser_dbg_cmd.js @@ -8,8 +8,13 @@ function test() { } function testDbgCmd() { - let pane = DebuggerUI.toggleDebugger(); - ok(pane, "toggleDebugger() should return a pane."); + DeveloperToolbarTest.exec({ + typed: "dbg open", + blankOutput: true + }); + + let pane = DebuggerUI.findDebugger(); + ok(pane, "Debugger was opened."); let frame = pane._frame; frame.addEventListener("Debugger:Connecting", function dbgConnected(aEvent) { @@ -41,9 +46,14 @@ function testDbgCmd() { cmd("dbg continue", function() { cmd("dbg continue", function() { is(output.value, "dbg continue", "debugger continued"); - pane.contentWindow.gClient.close(function() { - finish(); + DeveloperToolbarTest.exec({ + typed: "dbg close", + blankOutput: true }); + + let dbg = DebuggerUI.findDebugger(); + ok(!dbg, "Debugger was closed."); + finish(); }); }); }); diff --git a/browser/devtools/debugger/debugger-controller.js b/browser/devtools/debugger/debugger-controller.js index f7e5a545bb42..57d770deb6ae 100644 --- a/browser/devtools/debugger/debugger-controller.js +++ b/browser/devtools/debugger/debugger-controller.js @@ -9,6 +9,7 @@ const Cc = Components.classes; const Ci = Components.interfaces; const Cu = Components.utils; +const NEW_SCRIPT_DISPLAY_DELAY = 100; // ms const FRAME_STEP_CACHE_DURATION = 100; // ms const DBG_STRINGS_URI = "chrome://browser/locale/devtools/debugger.properties"; const SCRIPTS_URL_MAX_LENGTH = 64; // chars @@ -929,7 +930,11 @@ SourceScripts.prototype = { return; } - this._addScript({ url: aPacket.url, startLine: aPacket.startLine }, true); + this._addScript({ + url: aPacket.url, + startLine: aPacket.startLine, + source: aPacket.source + }, true); let preferredScriptUrl = DebuggerView.Scripts.preferredScriptUrl; @@ -937,15 +942,21 @@ SourceScripts.prototype = { if (aPacket.url === DebuggerView.Scripts.preferredScriptUrl) { DebuggerView.Scripts.selectScript(aPacket.url); } - // ..or the first entry if there's not one selected yet. - else if (!DebuggerView.Scripts.selected) { - DebuggerView.Scripts.selectIndex(0); - // Selecting a script would make it "preferred", which is a lie here, - // because we're only displaying a script to make sure there's always - // something available in the SourceEditor and the scripts menulist. - // Hence the need revert back to the initial preferred script, just - // in case it will be available soon. - DebuggerView.Scripts.preferredScriptUrl = preferredScriptUrl; + // ..or the first entry if there's none selected yet after a while + else { + window.setTimeout(function() { + // If after a certain delay the preferred script still wasn't received, + // just give up on waiting and display the first entry. + if (!DebuggerView.Scripts.selected) { + DebuggerView.Scripts.selectIndex(0); + // Selecting a script would make it "preferred", which is a lie here, + // because we're only displaying a script to make sure there's always + // something available in the SourceEditor and the scripts menulist. + // Hence the need revert back to the initial preferred script, just + // in case it will be available soon. + DebuggerView.Scripts.preferredScriptUrl = preferredScriptUrl; + } + }, NEW_SCRIPT_DISPLAY_DELAY); } // If there are any stored breakpoints for this script, display them again, @@ -1206,7 +1217,11 @@ SourceScripts.prototype = { */ showScript: function SS_showScript(aScript, aOptions = {}) { if (aScript.loaded) { - this._onShowScript(aScript, aOptions); + // Scripts may take a longer time to load than expected, therefore the + // required one may change at any time after a previous request was made. + if (aScript.url === DebuggerView.Scripts.selected) { + this._onShowScript(aScript, aOptions); + } return; } @@ -1217,7 +1232,7 @@ SourceScripts.prototype = { // Notify that we need to load a script file. DebuggerController.dispatchEvent("Debugger:LoadSource", { - url: aScript.url, + script: aScript, options: aOptions }); }, @@ -1256,84 +1271,22 @@ SourceScripts.prototype = { }, /** - * 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 - * without relying on caching when we can (not for eval, etc.): - * http://www.softwareishard.com/blog/firebug/nsitraceablechannel-intercept-http-traffic/ + * Handles notifications to load a source script. */ _onLoadSource: function SS__onLoadSource(aEvent) { - let url = aEvent.detail.url; + let script = aEvent.detail.script; let options = aEvent.detail.options; - let self = this; - switch (Services.io.extractScheme(url)) { - case "file": - case "chrome": - case "resource": - try { - NetUtil.asyncFetch(url, function onFetch(aStream, aStatus) { - if (!Components.isSuccessCode(aStatus)) { - return self._logError(url, aStatus); - } - let source = NetUtil.readInputStreamToString(aStream, aStream.available()); - source = self._convertToUnicode(source); - self._onLoadSourceFinished(url, source, null, options); - aStream.close(); - }); - } catch (ex) { - return self._logError(url, ex.name); - } - break; + let sourceClient = this.activeThread.source(script.source); + sourceClient.source(function (aResponse) { + if (aResponse.error) { + return this._logError(script.url, -1); + } - default: - let channel = Services.io.newChannel(url, null, null); - let chunks = []; - let streamListener = { - onStartRequest: function(aRequest, aContext, aStatusCode) { - if (!Components.isSuccessCode(aStatusCode)) { - return self._logError(url, aStatusCode); - } - }, - onDataAvailable: function(aRequest, aContext, aStream, aOffset, aCount) { - chunks.push(NetUtil.readInputStreamToString(aStream, aCount)); - }, - onStopRequest: function(aRequest, aContext, aStatusCode) { - if (!Components.isSuccessCode(aStatusCode)) { - return self._logError(url, aStatusCode); - } - let source = self._convertToUnicode(chunks.join(""), channel.contentCharset); - self._onLoadSourceFinished(url, source, channel.contentType, options); - } - }; - - channel.loadFlags = channel.LOAD_FROM_CACHE; - channel.asyncOpen(streamListener, null); - break; - } - }, - - /** - * Convert a given string, encoded in a given character set, to unicode. - * @param string aString - * A string. - * @param string aCharset - * A character set. - * @return string - * A unicode string. - */ - _convertToUnicode: function SS__convertToUnicode(aString, aCharset) { - // Decoding primitives. - let converter = Cc["@mozilla.org/intl/scriptableunicodeconverter"] - .createInstance(Ci.nsIScriptableUnicodeConverter); - - try { - converter.charset = aCharset || "UTF-8"; - return converter.ConvertToUnicode(aString); - } catch(e) { - return aString; - } + this._onLoadSourceFinished(script.url, + aResponse.source, + options); + }.bind(this)); }, /** @@ -1344,14 +1297,12 @@ SourceScripts.prototype = { * The URL of the source script. * @param string aSourceText * The text of the source script. - * @param string aContentType - * The content type of the source script. * @param object aOptions [optional] * Additional options for showing the script. Supported options: * - targetLine: place the editor at the given line number. */ _onLoadSourceFinished: - function SS__onLoadSourceFinished(aScriptUrl, aSourceText, aContentType, aOptions) { + function SS__onLoadSourceFinished(aScriptUrl, aSourceText, aOptions) { let element = DebuggerView.Scripts.getScriptByLocation(aScriptUrl); // Tab navigated before we got a chance to finish loading and displaying @@ -1367,7 +1318,6 @@ SourceScripts.prototype = { script.loaded = true; script.text = aSourceText; - script.contentType = aContentType; element.setUserData("sourceScript", script, null); if (aOptions.silent) { diff --git a/browser/devtools/debugger/debugger-view.js b/browser/devtools/debugger/debugger-view.js index 79b254be1217..4e9a9613bb9e 100644 --- a/browser/devtools/debugger/debugger-view.js +++ b/browser/devtools/debugger/debugger-view.js @@ -468,7 +468,7 @@ GlobalSearchView.prototype = { continue; } DebuggerController.dispatchEvent("Debugger:LoadSource", { - url: url, + script: DebuggerView.Scripts.getScriptByLocation(url).getUserData("sourceScript"), options: { silent: true, callback: aFetchCallback diff --git a/browser/devtools/debugger/test/browser_dbg_location-changes-new.js b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js index 28040421b4b4..d5dbc9575aa0 100644 --- a/browser/devtools/debugger/test/browser_dbg_location-changes-new.js +++ b/browser/devtools/debugger/test/browser_dbg_location-changes-new.js @@ -59,7 +59,7 @@ function testLocationChange() ok(true, "tabNavigated event was fired."); info("Still attached to the tab."); - gDebugger.addEventListener("Debugger:AfterNewScript", function _onEvent(aEvent) { + gDebugger.addEventListener("Debugger:ScriptShown", function _onEvent(aEvent) { gDebugger.removeEventListener(aEvent.type, _onEvent); isnot(gDebugger.DebuggerView.Scripts.selected, null, diff --git a/browser/devtools/debugger/test/browser_dbg_reload-same-script.js b/browser/devtools/debugger/test/browser_dbg_reload-same-script.js index bc23e6ff0b15..5b4673d0b1d9 100644 --- a/browser/devtools/debugger/test/browser_dbg_reload-same-script.js +++ b/browser/devtools/debugger/test/browser_dbg_reload-same-script.js @@ -170,18 +170,24 @@ function test() { let scriptsView = gView.Scripts; let scriptLocations = scriptsView.scriptLocations; - info("Available scripts: " + scriptLocations); - if (scriptLocations.length === 2) { + // Poll every few milliseconds until the scripts are retrieved. + let count = 0; + let intervalID = window.setInterval(function() { + dump("count: " + count + " "); + if (++count > 50) { + ok(false, "Timed out while polling for the scripts."); + closeDebuggerAndFinish(); + } + if (scriptLocations.length !== 2) { + return; + } + info("Available scripts: " + scriptLocations); + // We got all the scripts, it's safe to switch. + window.clearInterval(intervalID); scriptsView.selectScript(scriptLocations[index]); - return; - } - - window.addEventListener("Debugger:AfterNewScript", function _onEvent(aEvent) { - window.removeEventListener(aEvent.type, _onEvent); - switchScript(index); - }); + }, 100); } function reloadPage() diff --git a/browser/devtools/markupview/markup-view.xhtml b/browser/devtools/markupview/markup-view.xhtml index 3d0893add337..191655ec4c70 100644 --- a/browser/devtools/markupview/markup-view.xhtml +++ b/browser/devtools/markupview/markup-view.xhtml @@ -11,7 +11,7 @@ - +