author | Tim Taubert <ttaubert@mozilla.com> |
Tue, 23 Apr 2013 18:56:19 +0200 | |
changeset 140518 | 591caa6e37af1ad075bb2dbcc2101cbbfbb380c0 |
parent 140508 | aa620f3fc2f7116e6fad91915cb273160a2f5f0a (current diff) |
parent 140517 | 45829ebfd8f4d74e9275a33e2b60499334c53f85 (diff) |
child 140527 | 424ddd76303b4d2fb7a5faf972d6714323c9e86c |
push id | 2579 |
push user | akeybl@mozilla.com |
push date | Mon, 24 Jun 2013 18:52:47 +0000 |
treeherder | mozilla-beta@b69b7de8a05a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 23.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/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1077,16 +1077,17 @@ pref("devtools.debugger.ui.variables-sea // Enable the Profiler pref("devtools.profiler.enabled", true); // Enable the Network Monitor pref("devtools.netmonitor.enabled", true); // The default Network Monitor UI settings pref("devtools.netmonitor.panes-network-details-width", 450); +pref("devtools.netmonitor.panes-network-details-height", 450); // Enable the Tilt inspector pref("devtools.tilt.enabled", true); pref("devtools.tilt.intro_transition", true); pref("devtools.tilt.outro_transition", true); // Enable the Scratchpad tool. pref("devtools.scratchpad.enabled", true);
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -6761,18 +6761,20 @@ let gPrivateBrowsingUI = { newWindow.label = newPrivateWindow.label; newWindow.accessKey = newPrivateWindow.accessKey; newWindow.command = newPrivateWindow.command; } }); } } - if (gURLBar) { - // Disable switch to tab autocompletion for private windows + if (gURLBar && + !PrivateBrowsingUtils.permanentPrivateBrowsing) { + // Disable switch to tab autocompletion for private windows + // (not for "Always use private browsing" mode) gURLBar.setAttribute("autocompletesearchparam", ""); } } }; /** * Switch to a tab that has a given URI, and focusses its browser window. @@ -6785,19 +6787,20 @@ let gPrivateBrowsingUI = { * True to open a new tab and switch to it, if no existing tab is found. * If no suitable window is found, a new one will be opened. * @return True if an existing tab was found, false otherwise */ function switchToTabHavingURI(aURI, aOpenNew) { // This will switch to the tab in aWindow having aURI, if present. function switchIfURIInWindow(aWindow) { // Only switch to the tab if neither the source and desination window are - // private. - if (PrivateBrowsingUtils.isWindowPrivate(window) || - PrivateBrowsingUtils.isWindowPrivate(aWindow)) { + // private and they are not in permanent private borwsing mode + if ((PrivateBrowsingUtils.isWindowPrivate(window) || + PrivateBrowsingUtils.isWindowPrivate(aWindow)) && + !PrivateBrowsingUtils.permanentPrivateBrowsing) { return false; } let browsers = aWindow.gBrowser.browsers; for (let i = 0; i < browsers.length; i++) { let browser = browsers[i]; if (browser.currentURI.equals(aURI)) { // Focus the matching window & tab
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -645,17 +645,18 @@ let autocomplete = this.mTabBrowser._placesAutocomplete; if (this.mBrowser.registeredOpenURI) { autocomplete.unregisterOpenPage(this.mBrowser.registeredOpenURI); delete this.mBrowser.registeredOpenURI; } // Tabs in private windows aren't registered as "Open" so // that they don't appear as switch-to-tab candidates. if (!isBlankPageURL(aLocation.spec) && - !PrivateBrowsingUtils.isWindowPrivate(window)) { + (!PrivateBrowsingUtils.isWindowPrivate(window) || + PrivateBrowsingUtils.permanentPrivateBrowsing)) { autocomplete.registerOpenPage(aLocation); this.mBrowser.registeredOpenURI = aLocation; } } if (!this.mBlank) { this._callProgressListeners("onLocationChange", [aWebProgress, aRequest, aLocation,
--- a/browser/devtools/commandline/gcli.jsm +++ b/browser/devtools/commandline/gcli.jsm @@ -7303,22 +7303,20 @@ Output.prototype.complete = function(dat }; exports.Output = Output; /** * Functions and data related to the execution of a command */ exports.createExecutionContext = function(requisition) { - return { + var context = { exec: requisition.exec.bind(requisition), update: requisition.update.bind(requisition), updateExec: requisition.updateExec.bind(requisition), - document: requisition.document, - environment: requisition.environment, createView: view.createView, typedData: function(data, type) { return { isTypedData: true, data: data, type: type }; }, @@ -7329,16 +7327,28 @@ exports.createExecutionContext = functio /** * @deprecated Use defer() instead, which does the same thing, but is not * confusingly named */ createPromise: function() { return Promise.defer(); } }; + + Object.defineProperty(context, 'environment', { + get: function() { return requisition.environment; }, + enumerable : true + }); + + Object.defineProperty(context, 'document', { + get: function() { return requisition.document; }, + enumerable : true + }); + + return context; }; }); define("text!gcli/ui/intro.html", [], "\n" + "<div>\n" + " <p>${l10n.introTextOpening2}</p>\n" + "\n" +
--- a/browser/devtools/debugger/test/browser_dbg_propertyview-data.js +++ b/browser/devtools/debugger/test/browser_dbg_propertyview-data.js @@ -648,51 +648,51 @@ function testKeyboardAccessibility(callb is(gVariablesView.getFocusedItem().name, "someProp5", "The someProp5 item should be focused now."); EventUtils.sendKey("DOWN", gDebugger); is(gVariablesView.getFocusedItem().name, "0", "The 0 item should be focused now."); EventUtils.sendKey("END", gDebugger); - is(gVariablesView.getFocusedItem().name, "foo", - "The foo item should be focused now."); + is(gVariablesView.getFocusedItem().name, "bar", + "The bar item should be focused now."); EventUtils.sendKey("DOWN", gDebugger); is(gVariablesView.getFocusedItem().name, "bar", - "The bar item should be focused now."); + "The bar item should still be focused now."); EventUtils.sendKey("UP", gDebugger); is(gVariablesView.getFocusedItem().name, "foo", "The foo item should be focused now."); EventUtils.sendKey("RIGHT", gDebugger); is(gVariablesView.getFocusedItem().name, "foo", "The foo item should still be focused now."); EventUtils.sendKey("PAGE_DOWN", gDebugger); - is(gVariablesView.getFocusedItem().name, "foo", - "The foo item should still be focused now."); + is(gVariablesView.getFocusedItem().name, "bar", + "The bar item should be focused now."); EventUtils.sendKey("PAGE_UP", gDebugger); + is(gVariablesView.getFocusedItem().name, "someProp7", + "The someProp7 item should be focused now."); + + EventUtils.sendKey("UP", gDebugger); is(gVariablesView.getFocusedItem().name, "__proto__", "The __proto__ item should be focused now."); EventUtils.sendKey("UP", gDebugger); is(gVariablesView.getFocusedItem().name, "set", "The set item should be focused now."); EventUtils.sendKey("UP", gDebugger); is(gVariablesView.getFocusedItem().name, "get", "The get item should be focused now."); - EventUtils.sendKey("UP", gDebugger); - is(gVariablesView.getFocusedItem().name, "p8", - "The p8 item should be focused now."); - EventUtils.sendKey("HOME", gDebugger); is(gVariablesView.getFocusedItem().name, "someProp0", "The someProp0 item should be focused now."); EventUtils.sendKey("UP", gDebugger); is(gVariablesView.getFocusedItem().name, "someProp0", "The someProp0 item should still be focused now."); @@ -823,16 +823,28 @@ function testKeyboardAccessibility(callb "The top-level __proto__ item should be expanded."); EventUtils.sendKey("LEFT", gDebugger); is(gVariablesView.getFocusedItem().name, "__proto__", "The top-level __proto__ item should still be focused."); is(gVariablesView.getFocusedItem().expanded, false, "The top-level __proto__ item should not be expanded."); + EventUtils.sendKey("END", gDebugger); + is(gVariablesView.getFocusedItem().name, "foo", + "The foo scope should be focused."); + + EventUtils.sendKey("PAGE_UP", gDebugger); + is(gVariablesView.getFocusedItem().name, "__proto__", + "The __proto__ property should be focused."); + + EventUtils.sendKey("PAGE_DOWN", gDebugger); + is(gVariablesView.getFocusedItem().name, "foo", + "The foo scope should be focused."); + executeSoon(callback); }); }); }); }); }); }); }
--- a/browser/devtools/framework/Target.jsm +++ b/browser/devtools/framework/Target.jsm @@ -270,35 +270,41 @@ TabTarget.prototype = { this._client = new DebuggerClient(DebuggerServer.connectPipe()); // A local TabTarget will never perform chrome debugging. this._chrome = false; } this._setupRemoteListeners(); - if (this.isRemote) { - // In the remote debugging case, the protocol connection will have been - // already initialized in the connection screen code. - this._remote.resolve(null); - } else { + let attachTab = () => { + this._client.attachTab(this._form.actor, (aResponse, aTabClient) => { + if (!aTabClient) { + this._remote.reject("Unable to attach to the tab"); + return; + } + this.threadActor = aResponse.threadActor; + this._remote.resolve(null); + }); + }; + + if (this.isLocalTab) { this._client.connect((aType, aTraits) => { this._client.listTabs(aResponse => { this._form = aResponse.tabs[aResponse.selected]; - - this._client.attachTab(this._form.actor, (aResponse, aTabClient) => { - if (!aTabClient) { - this._remote.reject("Unable to attach to the tab"); - return; - } - this.threadActor = aResponse.threadActor; - this._remote.resolve(null); - }); + attachTab(); }); }); + } else if (!this.chrome) { + // In the remote debugging case, the protocol connection will have been + // already initialized in the connection screen code. + attachTab(); + } else { + // Remote chrome debugging doesn't need anything at this point. + this._remote.resolve(null); } return this._remote.promise; }, /** * Listen to the different events. */
--- a/browser/devtools/netmonitor/netmonitor-controller.js +++ b/browser/devtools/netmonitor/netmonitor-controller.js @@ -510,17 +510,18 @@ NetworkEventsHandler.prototype = { * Localization convenience methods. */ let L10N = new ViewHelpers.L10N(NET_STRINGS_URI); /** * Shortcuts for accessing various network monitor preferences. */ let Prefs = new ViewHelpers.Prefs("devtools.netmonitor", { - networkDetailsWidth: ["Int", "panes-network-details-width"] + networkDetailsWidth: ["Int", "panes-network-details-width"], + networkDetailsHeight: ["Int", "panes-network-details-height"] }); /** * Convenient way of emitting events from the panel window. */ EventEmitter.decorate(this); /**
--- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -2,16 +2,17 @@ /* vim: set ft=javascript ts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; const EPSILON = 0.001; const REQUESTS_REFRESH_RATE = 50; // ms +const REQUESTS_HEADERS_SAFE_BOUNDS = 30; // px const REQUESTS_WATERFALL_SAFE_BOUNDS = 100; // px const REQUESTS_WATERFALL_BACKGROUND_PATTERN = [5, 250, 1000, 2000]; // ms const DEFAULT_HTTP_VERSION = "HTTP/1.1"; const HEADERS_SIZE_DECIMALS = 3; const CONTENT_SIZE_DECIMALS = 2; const CONTENT_MIME_TYPE_ABBREVIATIONS = { "ecmascript": "js", "javascript": "js", @@ -97,26 +98,28 @@ let NetMonitorView = { this._detailsPane = $("#details-pane"); this._detailsPaneToggleButton = $("#details-pane-toggle"); this._collapsePaneString = L10N.getStr("collapseDetailsPane"); this._expandPaneString = L10N.getStr("expandDetailsPane"); this._detailsPane.setAttribute("width", Prefs.networkDetailsWidth); + this._detailsPane.setAttribute("height", Prefs.networkDetailsHeight); this.toggleDetailsPane({ visible: false }); }, /** * Destroys the UI for all the displayed panes. */ _destroyPanes: function DV__destroyPanes() { dumpn("Destroying the NetMonitorView panes"); Prefs.networkDetailsWidth = this._detailsPane.getAttribute("width"); + Prefs.networkDetailsHeight = this._detailsPane.getAttribute("height"); this._detailsPane = null; this._detailsPaneToggleButton = null; }, /** * Gets the visibility state of the network details pane. * @return boolean @@ -587,16 +590,37 @@ create({ constructor: RequestsMenuView, * True if this container's width was changed. */ _flushWaterfallViews: function NVRM__flushWaterfallViews(aReset) { // To avoid expensive operations like getBoundingClientRect(), the // waterfalls width is cached. However, in certain scenarios like when // the window is resized, this needs to be invalidated. if (aReset) { this._cachedWaterfallWidth = 0; + + let table = $("#network-table"); + let toolbar = $("#requests-menu-toolbar"); + let columns = [ + [".requests-menu-waterfall", "waterfall-overflows"], + [".requests-menu-size", "size-overflows"], + [".requests-menu-type", "type-overflows"], + [".requests-menu-domain", "domain-overflows"] + ]; + + // Flush headers. + columns.forEach(([, attribute]) => table.removeAttribute(attribute)); + let availableWidth = toolbar.getBoundingClientRect().width; + + // Hide overflowing columns. + columns.forEach(([className, attribute]) => { + let bounds = $(".requests-menu-header" + className).getBoundingClientRect(); + if (bounds.right > availableWidth - REQUESTS_HEADERS_SAFE_BOUNDS) { + table.setAttribute(attribute, ""); + } + }); } // Determine the scaling to be applied to all the waterfalls so that // everything is visible at once. One millisecond == one unscaled pixel. let availableWidth = this._waterfallWidth - REQUESTS_WATERFALL_SAFE_BOUNDS; let longestWidth = this._lastRequestEndedMillis - this._firstRequestStartedMillis; let scale = Math.min(Math.max(availableWidth / longestWidth, EPSILON), 1);
--- a/browser/devtools/netmonitor/netmonitor.css +++ b/browser/devtools/netmonitor/netmonitor.css @@ -8,13 +8,41 @@ } #timings-summary-blocked { display: none; /* This doesn't work yet. */ } /* Responsive sidebar */ @media (max-width: 700px) { + #toolbar-spacer, #details-pane-toggle, + #details-pane[pane-collapsed], .requests-menu-waterfall { display: none; } } + +@media (min-width: 701px) { + #network-table[waterfall-overflows] .requests-menu-waterfall { + display: none; + } + + #network-table[size-overflows] .requests-menu-size { + display: none; + } + + #network-table[type-overflows] .requests-menu-type { + display: none; + } + + #network-table[domain-overflows] .requests-menu-domain { + display: none; + } + + #network-table[type-overflows] .requests-menu-domain { + -moz-box-flex: 1; + } + + #network-table[domain-overflows] .requests-menu-file { + -moz-box-flex: 1; + } +}
--- a/browser/devtools/netmonitor/netmonitor.xul +++ b/browser/devtools/netmonitor/netmonitor.xul @@ -41,17 +41,17 @@ <label id="requests-menu-size-label" class="plain requests-menu-header requests-menu-size" value="&netmonitorUI.toolbar.size;" crop="end"/> <label id="requests-menu-waterfall-label" class="plain requests-menu-header requests-menu-waterfall" value="&netmonitorUI.toolbar.waterfall;" crop="end"/> - <spacer flex="1"/> + <spacer id="toolbar-spacer" flex="1"/> <toolbarbutton id="details-pane-toggle" class="devtools-toolbarbutton" tooltiptext="&netmonitorUI.panesButton.tooltip;" tabindex="0"/> </toolbar> <label class="plain requests-menu-empty-notice" value="&netmonitorUI.emptyNotice;"/> <vbox id="requests-menu-contents" flex="1">
--- a/browser/devtools/netmonitor/test/browser_net_prefs-reload.js +++ b/browser/devtools/netmonitor/test/browser_net_prefs-reload.js @@ -4,23 +4,30 @@ /** * Tests if the prefs that should survive across tool reloads work. */ function test() { initNetMonitor(SIMPLE_URL).then(([aTab, aDebuggee, aMonitor]) => { info("Starting test... "); + // This test reopens the network monitor a bunch of times, for different + // hosts (bottom, side, window). This seems to be slow on debug builds. + requestLongerTimeout(2); + let prefsToCheck = { networkDetailsWidth: { newValue: ~~(Math.random() * 200 + 100), - validate: () => - ~~aMonitor._view._detailsPane.getAttribute("width"), - modifyFrontend: (aValue) => - aMonitor._view._detailsPane.setAttribute("width", aValue) + validate: ($) => ~~$("#details-pane").getAttribute("width"), + modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("width", aValue) + }, + networkDetailsHeight: { + newValue: ~~(Math.random() * 300 + 100), + validate: ($) => ~~$("#details-pane").getAttribute("height"), + modifyFrontend: ($, aValue) => $("#details-pane").setAttribute("height", aValue) }, /* add more prefs here... */ }; function storeFirstPrefValues() { info("Caching initial pref values."); for (let name in prefsToCheck) { @@ -34,97 +41,177 @@ function test() { for (let name in prefsToCheck) { let currentValue = aMonitor.panelWin.Prefs[name]; let firstValue = prefsToCheck[name].firstValue; let validate = prefsToCheck[name].validate; is(currentValue, firstValue, "Pref " + name + " should be equal to first value: " + firstValue); - is(currentValue, validate(), + is(currentValue, validate(aMonitor.panelWin.$), "Pref " + name + " should validate: " + currentValue); } } function modifyFrontend() { info("Modifying UI elements to the specified new values."); for (let name in prefsToCheck) { let currentValue = aMonitor.panelWin.Prefs[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validate = prefsToCheck[name].validate; let modifyFrontend = prefsToCheck[name].modifyFrontend; - modifyFrontend(newValue); + modifyFrontend(aMonitor.panelWin.$, newValue); info("Modified UI element affecting " + name + " to: " + newValue); is(currentValue, firstValue, "Pref " + name + " should still be equal to first value: " + firstValue); isnot(currentValue, newValue, "Pref " + name + " should't yet be equal to second value: " + newValue); - is(newValue, validate(), + is(newValue, validate(aMonitor.panelWin.$), "The UI element affecting " + name + " should validate: " + newValue); } } function validateNewPrefValues() { info("Invalidating old pref values to the modified UI elements."); for (let name in prefsToCheck) { let currentValue = aMonitor.panelWin.Prefs[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validate = prefsToCheck[name].validate; - let modifyFrontend = prefsToCheck[name].modifyFrontend; isnot(currentValue, firstValue, "Pref " + name + " should't be equal to first value: " + firstValue); is(currentValue, newValue, "Pref " + name + " should now be equal to second value: " + newValue); - is(newValue, validate(), + is(newValue, validate(aMonitor.panelWin.$), "The UI element affecting " + name + " should validate: " + newValue); } } function resetFrontend() { info("Resetting UI elements to the cached initial pref values."); for (let name in prefsToCheck) { let currentValue = aMonitor.panelWin.Prefs[name]; let firstValue = prefsToCheck[name].firstValue; let newValue = prefsToCheck[name].newValue; let validate = prefsToCheck[name].validate; let modifyFrontend = prefsToCheck[name].modifyFrontend; - modifyFrontend(firstValue); + modifyFrontend(aMonitor.panelWin.$, firstValue); info("Modified UI element affecting " + name + " to: " + firstValue); isnot(currentValue, firstValue, "Pref " + name + " should't yet be equal to first value: " + firstValue); is(currentValue, newValue, "Pref " + name + " should still be equal to second value: " + newValue); - is(firstValue, validate(), + is(firstValue, validate(aMonitor.panelWin.$), "The UI element affecting " + name + " should validate: " + firstValue); } } - storeFirstPrefValues(); + function testBottom() { + info("Testing prefs reload for a bottom host."); + storeFirstPrefValues(); + + // Validate and modify while toolbox is on the bottom. + validateFirstPrefValues(); + modifyFrontend(); + + return restartNetMonitor(aMonitor) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; + + // Revalidate and reset frontend while toolbox is on the bottom. + validateNewPrefValues(); + resetFrontend(); + + return restartNetMonitor(aMonitor); + }) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; - // Validate and modify. - validateFirstPrefValues(); - modifyFrontend(); - restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => { - aMonitor = aNewMonitor; + // Revalidate. + validateFirstPrefValues(); + }); + } + + function testSide() { + info("Moving toolbox to the side..."); + + return aMonitor._toolbox.switchHost(Toolbox.HostType.SIDE) + .then(() => { + info("Testing prefs reload for a side host."); + storeFirstPrefValues(); + + // Validate and modify frontend while toolbox is on the side. + validateFirstPrefValues(); + modifyFrontend(); + + return restartNetMonitor(aMonitor); + }) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; + + // Revalidate and reset frontend while toolbox is on the side. + validateNewPrefValues(); + resetFrontend(); - // Revalidate and reset. - validateNewPrefValues(); - resetFrontend(); - restartNetMonitor(aMonitor).then(([,, aNewMonitor]) => { - aMonitor = aNewMonitor; + return restartNetMonitor(aMonitor); + }) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; + + // Revalidate. + validateFirstPrefValues(); + }); + } + + function testWindow() { + info("Moving toolbox into a window..."); + + return aMonitor._toolbox.switchHost(Toolbox.HostType.WINDOW) + .then(() => { + info("Testing prefs reload for a window host."); + storeFirstPrefValues(); + + // Validate and modify frontend while toolbox is in a window. + validateFirstPrefValues(); + modifyFrontend(); + + return restartNetMonitor(aMonitor); + }) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; - // Revalidate and finish. - validateFirstPrefValues(); - teardown(aMonitor).then(finish); - }); - }); + // Revalidate and reset frontend while toolbox is in a window. + validateNewPrefValues(); + resetFrontend(); + + return restartNetMonitor(aMonitor); + }) + .then(([,, aNewMonitor]) => { + aMonitor = aNewMonitor; + + // Revalidate. + validateFirstPrefValues(); + }); + } + + function cleanupAndFinish() { + info("Moving toolbox back to the bottom..."); + + aMonitor._toolbox.switchHost(Toolbox.HostType.BOTTOM) + .then(() => teardown(aMonitor)) + .then(finish); + } + + testBottom() + .then(testSide) + .then(testWindow) + .then(cleanupAndFinish); }); }
--- a/browser/devtools/netmonitor/test/head.js +++ b/browser/devtools/netmonitor/test/head.js @@ -2,16 +2,17 @@ http://creativecommons.org/publicdomain/zero/1.0/ */ "use strict"; const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components; let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); let { Promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}); let { TargetFactory } = Cu.import("resource:///modules/devtools/Target.jsm", {}); +let { Toolbox } = Cu.import("resource:///modules/devtools/Toolbox.jsm", {}); let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/"; const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html"; const NAVIGATE_URL = EXAMPLE_URL + "html_navigate-test-page.html"; const CONTENT_TYPE_URL = EXAMPLE_URL + "html_content-type-test-page.html"; const STATUS_CODES_URL = EXAMPLE_URL + "html_status-codes-test-page.html";
--- a/browser/devtools/shared/DeveloperToolbar.jsm +++ b/browser/devtools/shared/DeveloperToolbar.jsm @@ -501,17 +501,17 @@ DeveloperToolbar.prototype.destroy = fun { if (this._lastState == NOTIFICATIONS.HIDE) { return; } let tabbrowser = this._chromeWindow.getBrowser(); tabbrowser.tabContainer.removeEventListener("TabSelect", this, false); tabbrowser.tabContainer.removeEventListener("TabClose", this, false); - tabbrowser.removeEventListener("load", this, true); + tabbrowser.removeEventListener("load", this, true); tabbrowser.removeEventListener("beforeunload", this, true); Array.prototype.forEach.call(tabbrowser.tabs, this._stopErrorsCount, this); this.display.focusManager.removeMonitoredElement(this.outputPanel._frame); this.display.focusManager.removeMonitoredElement(this._element); this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
--- a/browser/devtools/shared/widgets/VariablesView.jsm +++ b/browser/devtools/shared/widgets/VariablesView.jsm @@ -47,16 +47,17 @@ const STR = Services.strings.createBundl * @param nsIDOMNode aParentNode * The parent node to hold this view. * @param object aFlags [optional] * An object contaning initialization options for this view. * e.g. { lazyEmpty: true, searchEnabled: true ... } */ this.VariablesView = function VariablesView(aParentNode, aFlags = {}) { this._store = new Map(); + this._items = []; this._itemsByElement = new WeakMap(); this._prevHierarchy = new Map(); this._currHierarchy = new Map(); this._parent = aParentNode; this._parent.classList.add("variables-view-container"); this._appendEmptyNotice(); @@ -98,16 +99,17 @@ VariablesView.prototype = { * The newly created Scope instance. */ addScope: function VV_addScope(aName = "") { this._removeEmptyNotice(); this._toggleSearchVisibility(true); let scope = new Scope(this, aName); this._store.set(scope.id, scope); + this._items.push(scope); this._currHierarchy.set(aName, scope); this._itemsByElement.set(scope._target, scope); scope.header = !!aName; return scope; }, /** * Removes all items from this container. @@ -130,16 +132,17 @@ VariablesView.prototype = { let list = this._list; let firstChild; while (firstChild = list.firstChild) { list.removeChild(firstChild); } this._store.clear(); + this._items.length = 0; this._itemsByElement.clear(); this._appendEmptyNotice(); this._toggleSearchVisibility(false); }, /** * Emptying this container and rebuilding it immediately afterwards would @@ -156,16 +159,17 @@ VariablesView.prototype = { * @see VariablesView.empty * @see VariablesView.commitHierarchy */ _emptySoon: function VV__emptySoon(aTimeout) { let prevList = this._list; let currList = this._list = this.document.createElement("scrollbox"); this._store.clear(); + this._items.length = 0; this._itemsByElement.clear(); this._emptyTimeout = this.window.setTimeout(function() { this._emptyTimeout = null; prevList.removeEventListener("keypress", this._onViewKeyPress, false); currList.addEventListener("keypress", this._onViewKeyPress, false); currList.setAttribute("orient", "vertical"); @@ -524,74 +528,83 @@ VariablesView.prototype = { let match = scope._firstMatch; if (match) { match.expand(); } } }, /** - * Focuses the first visible variable or property in this container. + * Find the first item in the tree of visible items in this container that + * matches the predicate. Searches in visual order (the order seen by the + * user). Descends into each scope to check the scope and its children. + * + * @param function aPredicate + * A function that returns true when a match is found. + * @return Scope | Variable | Property + * The first visible scope, variable or property, or null if nothing + * is found. + */ + _findInVisibleItems: function VV__findInVisibleItems(aPredicate) { + for (let scope of this._items) { + let result = scope._findInVisibleItems(aPredicate); + if (result) { + return result; + } + } + return null; + }, + + /** + * Find the last item in the tree of visible items in this container that + * matches the predicate. Searches in reverse visual order (opposite of the + * order seen by the user). Descends into each scope to check the scope and + * its children. + * + * @param function aPredicate + * A function that returns true when a match is found. + * @return Scope | Variable | Property + * The last visible scope, variable or property, or null if nothing + * is found. + */ + _findInVisibleItemsReverse: function VV__findInVisibleItemsReverse(aPredicate) { + for (let i = this._items.length - 1; i >= 0; i--) { + let scope = this._items[i]; + let result = scope._findInVisibleItemsReverse(aPredicate); + if (result) { + return result; + } + } + return null; + }, + + /** + * Focuses the first visible scope, variable, or property in this container. */ focusFirstVisibleNode: function VV_focusFirstVisibleNode() { - let property, variable, scope; - - for (let [, item] of this._currHierarchy) { - if (!item.focusable) { - continue; - } - if (item instanceof Property) { - property = item; - break; - } else if (item instanceof Variable) { - variable = item; - break; - } else if (item instanceof Scope) { - scope = item; - break; - } - } - if (scope) { - this._focusItem(scope); - } else if (variable) { - this._focusItem(variable); - } else if (property) { - this._focusItem(property); + let focusableItem = this._findInVisibleItems(item => item.focusable); + + if (focusableItem) { + this._focusItem(focusableItem); } this._parent.scrollTop = 0; this._parent.scrollLeft = 0; }, /** - * Focuses the last visible variable or property in this container. + * Focuses the last visible scope, variable, or property in this container. */ focusLastVisibleNode: function VV_focusLastVisibleNode() { - let property, variable, scope; - - for (let [, item] of this._currHierarchy) { - if (!item.focusable) { - continue; - } - if (item instanceof Property) { - property = item; - } else if (item instanceof Variable) { - variable = item; - } else if (item instanceof Scope) { - scope = item; - } + let focusableItem = this._findInVisibleItemsReverse(item => item.focusable); + + if (focusableItem) { + this._focusItem(focusableItem); } - if (property && (!variable || property.isDescendantOf(variable))) { - this._focusItem(property); - } else if (variable && (!scope || variable.isDescendantOf(scope))) { - this._focusItem(variable); - } else if (scope) { - this._focusItem(scope); - this._parent.scrollTop = this._parent.scrollHeight; - this._parent.scrollLeft = 0; - } + this._parent.scrollTop = this._parent.scrollHeight; + this._parent.scrollLeft = 0; }, /** * Searches for the scope in this container displayed by the specified node. * * @param nsIDOMNode aNode * The node to search for. * @return Scope @@ -883,16 +896,17 @@ VariablesView.prototype = { * @return nsIDOMWindow */ get window() this._window || (this._window = this.document.defaultView), _document: null, _window: null, _store: null, + _items: null, _prevHierarchy: null, _currHierarchy: null, _enumVisible: true, _nonEnumVisible: true, _emptyTimeout: null, _searchTimeout: null, _searchFunction: null, _parent: null, @@ -1077,16 +1091,18 @@ function Scope(aView, aName, aFlags = {} this.editableNameTooltip = aView.editableNameTooltip; this.editButtonTooltip = aView.editButtonTooltip; this.deleteButtonTooltip = aView.deleteButtonTooltip; this.descriptorTooltip = aView.descriptorTooltip; this.contextMenuId = aView.contextMenuId; this.separatorStr = aView.separatorStr; this._store = new Map(); + this._enumItems = []; + this._nonEnumItems = []; this._init(aName.trim(), aFlags); } Scope.prototype = { /** * Adds a variable to contain any inspected properties. * * @param string aName @@ -1781,16 +1797,99 @@ Scope.prototype = { if (match) { return match; } } return null; }, /** + * Find the first item in the tree of visible items in this item that matches + * the predicate. Searches in visual order (the order seen by the user). + * Tests itself, then descends into first the enumerable children and then + * the non-enumerable children (since they are presented in separate groups). + * + * @param function aPredicate + * A function that returns true when a match is found. + * @return Scope | Variable | Property + * The first visible scope, variable or property, or null if nothing + * is found. + */ + _findInVisibleItems: function S__findInVisibleItems(aPredicate) { + if (aPredicate(this)) { + return this; + } + + if (this._isExpanded) { + if (this._variablesView._enumVisible) { + for (let item of this._enumItems) { + let result = item._findInVisibleItems(aPredicate); + if (result) { + return result; + } + } + } + + if (this._variablesView._nonEnumVisible) { + for (let item of this._nonEnumItems) { + let result = item._findInVisibleItems(aPredicate); + if (result) { + return result; + } + } + } + } + + return null; + }, + + /** + * Find the last item in the tree of visible items in this item that matches + * the predicate. Searches in reverse visual order (opposite of the order + * seen by the user). Descends into first the non-enumerable children, then + * the enumerable children (since they are presented in separate groups), and + * finally tests itself. + * + * @param function aPredicate + * A function that returns true when a match is found. + * @return Scope | Variable | Property + * The last visible scope, variable or property, or null if nothing + * is found. + */ + _findInVisibleItemsReverse: function S__findInVisibleItemsReverse(aPredicate) { + if (this._isExpanded) { + if (this._variablesView._nonEnumVisible) { + for (let i = this._nonEnumItems.length - 1; i >= 0; i--) { + let item = this._nonEnumItems[i]; + let result = item._findInVisibleItemsReverse(aPredicate); + if (result) { + return result; + } + } + } + + if (this._variablesView._enumVisible) { + for (let i = this._enumItems.length - 1; i >= 0; i--) { + let item = this._enumItems[i]; + let result = item._findInVisibleItemsReverse(aPredicate); + if (result) { + return result; + } + } + } + } + + if (aPredicate(this)) { + return this; + } + + return null; + }, + + /** * Gets top level variables view instance. * @return VariablesView */ get _variablesView() this._topView || (this._topView = (function(self) { let parentView = self.ownerView; let topView; while (topView = parentView.ownerView) { @@ -1849,17 +1948,19 @@ Scope.prototype = { _isMatch: true, _idString: "", _nameString: "", _target: null, _arrow: null, _name: null, _title: null, _enum: null, + _enumItems: null, _nonenum: null, + _nonEnumItems: null, _throbber: null }; /** * A Variable is a Scope holding Property instances. * Iterable via "for (let [name, property] in instance) { }". * * @param Scope aScope @@ -2162,18 +2263,20 @@ ViewHelpers.create({ constructor: Variab * @param boolean aImmediateFlag * @see Scope.prototype._lazyAppend */ _onInit: function V__onInit(aImmediateFlag) { if (this._initialDescriptor.enumerable || this._nameString == "this" || this._nameString == "<exception>") { this.ownerView._lazyAppend(aImmediateFlag, true, this._target); + this.ownerView._enumItems.push(this); } else { this.ownerView._lazyAppend(aImmediateFlag, false, this._target); + this.ownerView._nonEnumItems.push(this); } }, /** * Creates the necessary nodes for this variable. */ _displayVariable: function V__createVariable() { let document = this.document; @@ -2669,18 +2772,20 @@ ViewHelpers.create({ constructor: Proper * be attached to the owner view. * * @param boolean aImmediateFlag * @see Scope.prototype._lazyAppend */ _onInit: function P__onInit(aImmediateFlag) { if (this._initialDescriptor.enumerable) { this.ownerView._lazyAppend(aImmediateFlag, true, this._target); + this.ownerView._enumItems.push(this); } else { this.ownerView._lazyAppend(aImmediateFlag, false, this._target); + this.ownerView._nonEnumItems.push(this); } } }); /** * A generator-iterator over the VariablesView, Scopes, Variables and Properties. */ VariablesView.prototype.__iterator__ =
--- a/browser/devtools/webconsole/HUDService.jsm +++ b/browser/devtools/webconsole/HUDService.jsm @@ -658,19 +658,29 @@ var HeadsUpDisplayUICommands = { if (!DebuggerServer.initialized) { DebuggerServer.init(); DebuggerServer.addBrowserActors(); } let client = new DebuggerClient(DebuggerServer.connectPipe()); client.connect(() => - client.listTabs((aResponse) => - deferred.resolve({ form: aResponse, client: client }) - )); + client.listTabs((aResponse) => { + // Add Global Process debugging... + let globals = JSON.parse(JSON.stringify(aResponse)); + delete globals.tabs; + delete globals.selected; + // ...only if there are appropriate actors (a 'from' property will + // always be there). + if (Object.keys(globals).length > 1) { + deferred.resolve({ form: globals, client: client, chrome: true }); + } else { + deferred.reject("Global console not found!"); + } + })); return deferred.promise; } let target; function getTarget(aConnection) { let options = {
--- a/browser/devtools/webconsole/webconsole.xul +++ b/browser/devtools/webconsole/webconsole.xul @@ -57,18 +57,18 @@ <menuitem id="saveBodiesContextMenu" type="checkbox" label="&saveBodies.label;" accesskey="&saveBodies.accesskey;"/> <menuitem id="menu_openURL" label="&openURL.label;" accesskey="&openURL.accesskey;" command="consoleCmd_openURL" selection="network" selectionType="single"/> <menuitem id="menu_copyURL" label="©URLCmd.label;" accesskey="©URLCmd.accesskey;" command="consoleCmd_copyURL" selection="network" selectionType="single"/> - <menuitem id="menu_copy"/> - <menuitem id="menu_selectAll"/> + <menuitem id="cMenu_copy"/> + <menuitem id="cMenu_selectAll"/> </menupopup> </popupset> <box class="hud-outer-wrapper devtools-responsive-container" flex="1"> <vbox class="hud-console-wrapper" flex="1"> <toolbar class="hud-console-filter-toolbar devtools-toolbar" mode="full"> <toolbarbutton label="&btnPageNet.label;" type="menu-button" category="net" class="devtools-toolbarbutton webconsole-filter-button"
--- a/browser/themes/linux/devtools/netmonitor.css +++ b/browser/themes/linux/devtools/netmonitor.css @@ -88,21 +88,23 @@ } .requests-menu-method { text-align: center; font-weight: 600; } .requests-menu-file { - width: 14em; + width: 20vw; + min-width: 4em; } .requests-menu-domain { - width: 14em; + width: 14vw; + min-width: 10em; } .requests-menu-type { text-align: center; width: 4em; } .requests-menu-size { @@ -298,18 +300,49 @@ transition: transform 0.2s ease-out; } /* Responsive sidebar */ @media (max-width: 700px) { #details-pane { max-width: none; margin: 0 !important; - /* To prevent all the margin hacks to hide the sidebar */ + /* To prevent all the margin hacks to hide the sidebar. */ + } + + .requests-menu-status-and-method { + width: 14vw; + } + + .requests-menu-file, + .requests-menu-domain { + width: 30vw; + min-width: 10em; + } + + .requests-menu-type { + width: 8vw; } .requests-menu-size { - border-width: 0px !important; + width: 16vw; + border-width: 0 !important; box-shadow: none !important; - /* !important are required here because Timeline is not visible and thus - the right border and box-shadow of Size column should be hidden */ + /* The "Timeline" header is not visible anymore, and thus the + right border and box-shadow of "Size" column should be hidden. */ } } + +@media (min-width: 701px) { + #network-table[type-overflows] .requests-menu-domain { + border-width: 0 !important; + box-shadow: none !important; + /* The "Type" header is not visible anymore, and thus the + right border and box-shadow of "Domain" column should be hidden. */ + } + + #network-table[domain-overflows] .requests-menu-file { + border-width: 0 !important; + box-shadow: none !important; + /* The "Domain" header is not visible anymore, and thus the + right border and box-shadow of "File" column should be hidden. */ + } +}
--- a/browser/themes/osx/devtools/netmonitor.css +++ b/browser/themes/osx/devtools/netmonitor.css @@ -88,21 +88,23 @@ } .requests-menu-method { text-align: center; font-weight: 600; } .requests-menu-file { - width: 16em; + width: 20vw; + min-width: 4em; } .requests-menu-domain { - width: 16em; + width: 14vw; + min-width: 10em; } .requests-menu-type { text-align: center; width: 4em; } .requests-menu-size { @@ -298,18 +300,49 @@ transition: transform 0.2s ease-out; } /* Responsive sidebar */ @media (max-width: 700px) { #details-pane { max-width: none; margin: 0 !important; - /* To prevent all the margin hacks to hide the sidebar */ + /* To prevent all the margin hacks to hide the sidebar. */ + } + + .requests-menu-status-and-method { + width: 14vw; + } + + .requests-menu-file, + .requests-menu-domain { + width: 30vw; + min-width: 10em; + } + + .requests-menu-type { + width: 8vw; } .requests-menu-size { - border-width: 0px !important; + width: 16vw; + border-width: 0 !important; box-shadow: none !important; - /* !important are required here because Timeline is not visible and thus - the right border and box-shadow of Size column should be hidden */ + /* The "Timeline" header is not visible anymore, and thus the + right border and box-shadow of "Size" column should be hidden. */ } } + +@media (min-width: 701px) { + #network-table[type-overflows] .requests-menu-domain { + border-width: 0 !important; + box-shadow: none !important; + /* The "Type" header is not visible anymore, and thus the + right border and box-shadow of "Domain" column should be hidden. */ + } + + #network-table[domain-overflows] .requests-menu-file { + border-width: 0 !important; + box-shadow: none !important; + /* The "Domain" header is not visible anymore, and thus the + right border and box-shadow of "File" column should be hidden. */ + } +}
--- a/browser/themes/windows/devtools/netmonitor.css +++ b/browser/themes/windows/devtools/netmonitor.css @@ -88,21 +88,23 @@ } .requests-menu-method { text-align: center; font-weight: 600; } .requests-menu-file { - width: 16em; + width: 20vw; + min-width: 4em; } .requests-menu-domain { - width: 16em; + width: 14vw; + min-width: 10em; } .requests-menu-type { text-align: center; width: 4em; } .requests-menu-size { @@ -298,18 +300,49 @@ transition: transform 0.2s ease-out; } /* Responsive sidebar */ @media (max-width: 700px) { #details-pane { max-width: none; margin: 0 !important; - /* To prevent all the margin hacks to hide the sidebar */ + /* To prevent all the margin hacks to hide the sidebar. */ + } + + .requests-menu-status-and-method { + width: 14vw; + } + + .requests-menu-file, + .requests-menu-domain { + width: 30vw; + min-width: 10em; + } + + .requests-menu-type { + width: 8vw; } .requests-menu-size { - border-width: 0px !important; + width: 16vw; + border-width: 0 !important; box-shadow: none !important; - /* !important are required here because Timeline is not visible and thus - the right border and box-shadow of Size column should be hidden */ + /* The "Timeline" header is not visible anymore, and thus the + right border and box-shadow of "Size" column should be hidden. */ } } + +@media (min-width: 701px) { + #network-table[type-overflows] .requests-menu-domain { + border-width: 0 !important; + box-shadow: none !important; + /* The "Type" header is not visible anymore, and thus the + right border and box-shadow of "Domain" column should be hidden. */ + } + + #network-table[domain-overflows] .requests-menu-file { + border-width: 0 !important; + box-shadow: none !important; + /* The "Domain" header is not visible anymore, and thus the + right border and box-shadow of "File" column should be hidden. */ + } +}
--- a/toolkit/devtools/debugger/server/dbg-script-actors.js +++ b/toolkit/devtools/debugger/server/dbg-script-actors.js @@ -592,35 +592,41 @@ ThreadActor.prototype = { * take that into account. * * @param object aLocation * The location of the breakpoint as specified in the protocol. */ _setBreakpoint: function TA__setBreakpoint(aLocation) { let breakpoints = this._breakpointStore[aLocation.url]; + // Get or create the breakpoint actor for the given location let actor; if (breakpoints[aLocation.line].actor) { actor = breakpoints[aLocation.line].actor; } else { actor = breakpoints[aLocation.line].actor = new BreakpointActor(this, { url: aLocation.url, line: aLocation.line }); this._hooks.addToParentPool(actor); } + // Find all scripts matching the given location let scripts = this.dbg.findScripts(aLocation); if (scripts.length == 0) { return { error: "noScript", actor: actor.actorID }; } + /** + * For each script, if the given line has at least one entry point, set + * breakpoint on the bytecode offet for each of them. + */ let found = false; for (let script of scripts) { let offsets = script.getLineOffsets(aLocation.line); if (offsets.length > 0) { for (let offset of offsets) { script.setBreakpoint(offset, actor); } actor.addScript(script, this); @@ -628,65 +634,93 @@ ThreadActor.prototype = { } } if (found) { return { actor: actor.actorID }; } + /** + * If we get here, no breakpoint was set. This is because the given line + * has no entry points, for example because it is empty. As a fallback + * strategy, we try to set the breakpoint on the smallest line greater + * than or equal to the given line that as at least one entry point. + */ + + // Find all innermost scripts matching the given location let scripts = this.dbg.findScripts({ url: aLocation.url, line: aLocation.line, innermost: true }); + /** + * For each innermost script, look for the smallest line greater than or + * equal to the given line that has one or more entry points. If found, set + * a breakpoint on the bytecode offset for each of its entry points. + */ let actualLocation; let found = false; for (let script of scripts) { let offsets = script.getAllOffsets(); for (let line = aLocation.line; line < offsets.length; ++line) { if (offsets[line]) { for (let offset of offsets[line]) { script.setBreakpoint(offset, actor); } actor.addScript(script, this); if (!actualLocation) { actualLocation = { url: aLocation.url, line: line, - column: aLocation.column + column: 0 }; } found = true; break; } } } if (found) { if (breakpoints[actualLocation.line] && breakpoints[actualLocation.line].actor) { + /** + * We already have a breakpoint actor for the actual location, so + * actor we created earlier is now redundant. Delete it, update the + * breakpoint store, and return the actor for the actual location. + */ actor.onDelete(); delete breakpoints[aLocation.line]; return { actor: breakpoints[actualLocation.line].actor.actorID, actualLocation: actualLocation }; } else { + /** + * We don't have a breakpoint actor for the actual location yet. + * Instead or creating a new actor, reuse the actor we created earlier, + * and update the breakpoint store. + */ actor.location = actualLocation; breakpoints[actualLocation.line] = breakpoints[aLocation.line]; + delete breakpoints[aLocation.line]; + // WARNING: This overwrites aLocation.line breakpoints[actualLocation.line].line = actualLocation.line; - delete breakpoints[aLocation.line]; return { actor: actor.actorID, actualLocation: actualLocation }; } } + /** + * If we get here, no line matching the given line was found, so just + * epically. + */ return { error: "noCodeAtLineColumn", actor: actor.actorID }; }, /** * Get the script and source lists from the debugger.
--- a/toolkit/mozapps/extensions/content/extensions.js +++ b/toolkit/mozapps/extensions/content/extensions.js @@ -97,17 +97,17 @@ function initialize(event) { return; } // Default to the last selected category var view = gCategories.node.value; // Allow passing in a view through the window arguments if ("arguments" in window && window.arguments.length > 0 && - "view" in window.arguments[0]) { + window.arguments[0] !== null && "view" in window.arguments[0]) { view = window.arguments[0].view; } gViewController.loadInitialView(view); } function notifyInitialized() { if (!gIsInitializing)