author | Ryan VanderMeulen <ryanvm@gmail.com> |
Mon, 02 Dec 2013 16:43:03 -0500 | |
changeset 158404 | c93cfe704487cf493fc4f289e015f068e49c4644 |
parent 158379 | 492fbc8095b807132f96446fcc6a8db62faf9ff8 (current diff) |
parent 158403 | 2d4fd5a493b172750da02e2ecf0e929576ed8a82 (diff) |
child 158405 | 612b104050ce2fe75aca45f1754a7740a6691ddb |
child 158465 | cf52d24c12b678104d08adec2b82c82a908e257f |
child 158468 | 4fda28f9e2597bb0df620e092ae2f6e19f132136 |
child 158493 | a06f7b3bb7f7b7def2806e641215bb2bb60b7ccf |
push id | 36978 |
push user | ryanvm@gmail.com |
push date | Mon, 02 Dec 2013 21:58:15 +0000 |
treeherder | mozilla-inbound@612b104050ce [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
milestone | 28.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
|
CLOBBER | file | annotate | diff | comparison | revisions | |
browser/devtools/debugger/DebuggerProcess.jsm | file | annotate | diff | comparison | revisions | |
toolkit/components/moz.build | file | annotate | diff | comparison | revisions |
--- a/CLOBBER +++ b/CLOBBER @@ -13,9 +13,9 @@ # | | # O <-- Clobber O <-- Clobber # # Note: The description below will be part of the error message shown to users. # # Modifying this file will now automatically clobber the buildbot machines \o/ # -More Windows webidl changes +More Windows webidl changes
--- a/browser/base/content/browser-menubar.inc +++ b/browser/base/content/browser-menubar.inc @@ -513,19 +513,19 @@ accesskey="&devToolboxMenuItem.accesskey;"/> <menuseparator id="menu_devtools_separator"/> <menuitem id="menu_devToolbar" observes="devtoolsMenuBroadcaster_DevToolbar" accesskey="&devToolbarMenu.accesskey;"/> <menuitem id="menu_devAppMgr" observes="devtoolsMenuBroadcaster_DevAppMgr" accesskey="&devAppMgrMenu.accesskey;"/> - <menuitem id="menu_chromeDebugger" - observes="devtoolsMenuBroadcaster_ChromeDebugger" - accesskey="&chromeDebuggerMenu.accesskey;"/> + <menuitem id="menu_browserToolbox" + observes="devtoolsMenuBroadcaster_BrowserToolbox" + accesskey="&browserToolboxMenu.accesskey;"/> <menuitem id="menu_browserConsole" observes="devtoolsMenuBroadcaster_BrowserConsole" accesskey="&browserConsoleCmd.accesskey;"/> <menuitem id="menu_responsiveUI" observes="devtoolsMenuBroadcaster_ResponsiveUI" accesskey="&responsiveDesignTool.accesskey;"/> <menuitem id="menu_scratchpad" observes="devtoolsMenuBroadcaster_Scratchpad"
--- a/browser/base/content/browser-sets.inc +++ b/browser/base/content/browser-sets.inc @@ -90,17 +90,17 @@ <command id="Browser:RestoreLastSession" oncommand="restoreLastSession();" disabled="true"/> <command id="Tools:Search" oncommand="BrowserSearch.webSearch();"/> <command id="Tools:Downloads" oncommand="BrowserDownloadsUI();"/> <command id="Tools:DevToolbox" oncommand="gDevToolsBrowser.toggleToolboxCommand(gBrowser);"/> <command id="Tools:DevToolbar" oncommand="DeveloperToolbar.toggle();" disabled="true" hidden="true"/> <command id="Tools:DevToolbarFocus" oncommand="DeveloperToolbar.focusToggle();" disabled="true"/> <command id="Tools:DevAppMgr" oncommand="gDevToolsBrowser.openAppManager(gBrowser);" disabled="true" hidden="true"/> - <command id="Tools:ChromeDebugger" oncommand="BrowserDebuggerProcess.init();" disabled="true" hidden="true"/> + <command id="Tools:BrowserToolbox" oncommand="BrowserToolboxProcess.init();" disabled="true" hidden="true"/> <command id="Tools:BrowserConsole" oncommand="HUDService.toggleBrowserConsole();"/> <command id="Tools:Scratchpad" oncommand="Scratchpad.openScratchpad();"/> <command id="Tools:ResponsiveUI" oncommand="ResponsiveUI.toggle();"/> <command id="Tools:Addons" oncommand="BrowserOpenAddonsMgr();"/> <command id="Tools:ErrorConsole" oncommand="toJavaScriptConsole()" disabled="true" hidden="true"/> <command id="Tools:DevToolsConnect" oncommand="gDevToolsBrowser.openConnectScreen(gBrowser)" disabled="true" hidden="true"/> <command id="Tools:Sanitize" oncommand="Cc['@mozilla.org/browser/browserglue;1'].getService(Ci.nsIBrowserGlue).sanitize(window);"/> @@ -180,19 +180,19 @@ <broadcaster id="devtoolsMenuBroadcaster_DevToolbar" label="&devToolbarMenu.label;" type="checkbox" autocheck="false" command="Tools:DevToolbar" key="key_devToolbar"/> <broadcaster id="devtoolsMenuBroadcaster_DevAppMgr" label="&devAppMgrMenu.label;" command="Tools:DevAppMgr"/> - <broadcaster id="devtoolsMenuBroadcaster_ChromeDebugger" - label="&chromeDebuggerMenu.label;" - command="Tools:ChromeDebugger"/> + <broadcaster id="devtoolsMenuBroadcaster_BrowserToolbox" + label="&browserToolboxMenu.label;" + command="Tools:BrowserToolbox"/> <broadcaster id="devtoolsMenuBroadcaster_BrowserConsole" label="&browserConsoleCmd.label;" key="key_browserConsole" command="Tools:BrowserConsole"/> <broadcaster id="devtoolsMenuBroadcaster_Scratchpad" label="&scratchpad.label;" command="Tools:Scratchpad" key="key_scratchpad"/>
--- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -112,20 +112,20 @@ XPCOMUtils.defineLazyGetter(this, "Popup }); 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, "BrowserDebuggerProcess", function() { +XPCOMUtils.defineLazyGetter(this, "BrowserToolboxProcess", function() { let tmp = {}; - Cu.import("resource:///modules/devtools/DebuggerProcess.jsm", tmp); - return tmp.BrowserDebuggerProcess; + Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", tmp); + return tmp.BrowserToolboxProcess; }); XPCOMUtils.defineLazyModuleGetter(this, "Social", "resource:///modules/Social.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PageThumbs", "resource://gre/modules/PageThumbs.jsm");
--- a/browser/base/content/test/social/browser_blocklist.js +++ b/browser/base/content/test/social/browser_blocklist.js @@ -129,27 +129,29 @@ var tests = { let listener = { _window: null, onOpenWindow: function(aXULWindow) { Services.wm.removeListener(this); this._window = aXULWindow; let domwindow = aXULWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDOMWindow); - domwindow.addEventListener("unload", function _unload() { - domwindow.removeEventListener("unload", _unload, false); - windowWasClosed = true; + domwindow.addEventListener("load", function _load() { + domwindow.removeEventListener("load", _load, false); + + domwindow.addEventListener("unload", function _unload() { + domwindow.removeEventListener("unload", _unload, false); + info("blocklist window was closed"); + windowWasClosed = true; + }, false); + + is(domwindow.document.location.href, URI_EXTENSION_BLOCKLIST_DIALOG, "dialog opened and focused"); + domwindow.close(); + }, false); - info("dialog opened, waiting for focus"); - waitForFocus(function() { - is(domwindow.document.location.href, URI_EXTENSION_BLOCKLIST_DIALOG, "dialog opened and focused"); - executeSoon(function() { - domwindow.close(); - }); - }, domwindow); }, onCloseWindow: function(aXULWindow) { }, onWindowTitleChange: function(aXULWindow, aNewTitle) { } }; Services.wm.addListener(listener); setManifestPref("social.manifest.blocked", manifest_bad);
--- a/browser/components/customizableui/src/CustomizableUI.jsm +++ b/browser/components/customizableui/src/CustomizableUI.jsm @@ -152,18 +152,17 @@ let CustomizableUIInternal = { // Windows 8 is version 6.2. let version = Cc["@mozilla.org/system-info;1"] .getService(Ci.nsIPropertyBag2) .getProperty("version"); isMetroCapable = (parseFloat(version) >= 6.2); } catch (ex) { } if (isMetroCapable) { - // TODO: Bug 942915 - Place 'Metro Mode' button as a default - // for Windows 8 in the customization panel. + panelPlacements.push("switch-to-metro-button"); } #endif #endif let showCharacterEncoding = Services.prefs.getComplexValue( "browser.menu.showCharacterEncoding", Ci.nsIPrefLocalizedString ).data;
--- a/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js +++ b/browser/components/customizableui/test/browser_876944_customize_mode_create_destroy.js @@ -23,25 +23,25 @@ let gTests = [ let item = document.getElementById(kTestWidget1); ok(!item, "There should no longer be an item"); }, }, { desc: "Creating and destroying a widget should correctly deal with panel placeholders", run: function() { let panel = document.getElementById(CustomizableUI.AREA_PANEL); - is(panel.querySelectorAll(".panel-customization-placeholder").length, 3, "The number of placeholders should be correct."); + is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 2 : 3, "The number of placeholders should be correct."); CustomizableUI.createWidget({id: kTestWidget2, label: 'Pretty label', tooltiptext: 'Pretty tooltip', defaultArea: CustomizableUI.AREA_PANEL}); let elem = document.getElementById(kTestWidget2); let wrapper = document.getElementById("wrapper-" + kTestWidget2); ok(elem, "There should be an item"); ok(wrapper, "There should be a wrapper"); is(wrapper.firstChild.id, kTestWidget2, "Wrapper should have test widget"); is(wrapper.parentNode, panel, "Wrapper should be in panel"); - is(panel.querySelectorAll(".panel-customization-placeholder").length, 2, "The number of placeholders should be correct."); + is(panel.querySelectorAll(".panel-customization-placeholder").length, isInWin8() ? 1 : 2, "The number of placeholders should be correct."); CustomizableUI.destroyWidget(kTestWidget2); wrapper = document.getElementById("wrapper-" + kTestWidget2); ok(!wrapper, "There should be a wrapper"); let item = document.getElementById(kTestWidget2); ok(!item, "There should no longer be an item"); }, teardown: endCustomizing },
--- a/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js +++ b/browser/components/customizableui/test/browser_880382_drag_wide_widgets_in_panel.js @@ -16,16 +16,17 @@ let gTests = [ "save-page-button", "zoom-controls", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(zoomControls, printButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); let newWindowButton = document.getElementById("new-window-button"); simulateItemDrag(zoomControls, newWindowButton); ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, @@ -42,16 +43,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(zoomControls, savePageButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(CustomizableUI.inDefaultState, "Should be in default state."); }, }, { desc: "Dragging the zoom controls to be before the new-window " + "button should not move any widgets.", @@ -65,16 +67,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(zoomControls, newWindowButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { desc: "Dragging the zoom controls to be before the history-panelmenu " + "should move the zoom-controls in to the row higher than the " + @@ -89,16 +92,17 @@ let gTests = [ "save-page-button", "zoom-controls", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(zoomControls, historyPanelMenu); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); let newWindowButton = document.getElementById("new-window-button"); simulateItemDrag(zoomControls, newWindowButton); ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, @@ -116,16 +120,17 @@ let gTests = [ "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "zoom-controls", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(zoomControls, preferencesButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); let newWindowButton = document.getElementById("new-window-button"); simulateItemDrag(zoomControls, newWindowButton); ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, @@ -143,16 +148,17 @@ let gTests = [ "zoom-controls", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterInsert); simulateItemDrag(developerButton, zoomControls); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); let palette = document.getElementById("customization-palette"); // Check that the palette items are re-wrapped correctly. let feedWrapper = document.getElementById("wrapper-feed-button"); let feedButton = document.getElementById("feed-button"); is(feedButton.parentNode, feedWrapper, @@ -181,16 +187,17 @@ let gTests = [ "zoom-controls", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterInsert); simulateItemDrag(developerButton, editControls); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterInsert); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); let palette = document.getElementById("customization-palette"); // Check that the palette items are re-wrapped correctly. let feedWrapper = document.getElementById("wrapper-feed-button"); let feedButton = document.getElementById("feed-button"); is(feedButton.parentNode, feedWrapper, @@ -216,16 +223,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, zoomControls); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { desc: "Dragging the edit-controls to be before the new-window-button should " + "move the zoom-controls before the edit-controls.", @@ -239,16 +247,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, newWindowButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(editControls, zoomControls); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { @@ -265,16 +274,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, privateBrowsingButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(editControls, zoomControls); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { @@ -291,16 +301,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, savePageButton); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(editControls, zoomControls); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { @@ -316,16 +327,17 @@ let gTests = [ "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button", "edit-controls"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, panel); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(editControls, zoomControls); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, { @@ -340,16 +352,17 @@ let gTests = [ "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); let paletteChildElementCount = palette.childElementCount; simulateItemDrag(editControls, palette); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); is(paletteChildElementCount + 1, palette.childElementCount, "The palette should have a new child, congratulations!"); is(editControls.parentNode.id, "wrapper-edit-controls", "The edit-controls should be properly wrapped."); is(editControls.parentNode.getAttribute("place"), "palette", @@ -363,31 +376,33 @@ let gTests = [ }, { desc: "Dragging the edit-controls to each of the panel placeholders " + "should append the edit-controls to the bottom of the panel.", setup: startCustomizing, run: function() { let editControls = document.getElementById("edit-controls"); let panel = document.getElementById(CustomizableUI.AREA_PANEL); - for (let i = 0; i < 3; i++) { + let numPlaceholders = isInWin8() ? 2 : 3; + for (let i = 0; i < numPlaceholders; i++) { // NB: We can't just iterate over all of the placeholders // because each drag-drop action recreates them. let placeholder = panel.getElementsByClassName("panel-customization-placeholder")[i]; let placementsAfterMove = ["zoom-controls", "new-window-button", "privatebrowsing-button", "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button", "edit-controls"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, placeholder); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(editControls, zoomControls); ok(CustomizableUI.inDefaultState, "Should still be in default state."); } }, }, @@ -420,21 +435,26 @@ let gTests = [ "save-page-button", "print-button", "history-panelmenu", "fullscreen-button", "find-button", "preferences-button", "add-ons-button", "edit-controls"]; + addSwitchToMetroButtonInWindows8(placementsAfterMove); simulateItemDrag(editControls, target); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); let itemToDrag = "sync-button"; let button = document.getElementById(itemToDrag); - placementsAfterMove.push(itemToDrag); + if (!isInWin8()) { + placementsAfterMove.push(itemToDrag); + } else { + placementsAfterMove.splice(11, 0, itemToDrag); + } simulateItemDrag(button, editControls); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterMove); // Put stuff back: let palette = document.getElementById("customization-palette"); let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(button, palette); simulateItemDrag(editControls, zoomControls);
--- a/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js +++ b/browser/components/customizableui/test/browser_890140_orphaned_placeholders.js @@ -6,116 +6,155 @@ let gTests = [ { desc: "One orphaned item should have two placeholders next to it.", setup: startCustomizing, run: function() { let btn = document.getElementById("developer-button"); let panel = document.getElementById(CustomizableUI.AREA_PANEL); let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); - let placementsAfterAppend = placements.concat(["developer-button"]); - simulateItemDrag(btn, panel); - assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); - ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + if (!isInWin8()) { + placements = placements.concat(["developer-button"]); + simulateItemDrag(btn, panel); + ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); + } else { + ok(CustomizableUI.inDefaultState, "Should be in default state."); + } + + assertAreaPlacements(CustomizableUI.AREA_PANEL, placements); is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders before exiting"); yield endCustomizing(); yield startCustomizing(); is(getVisiblePlaceholderCount(panel), 2, "Should only have 2 visible placeholders after re-entering"); - let palette = document.getElementById("customization-palette"); - simulateItemDrag(btn, palette); + if (!isInWin8()) { + let palette = document.getElementById("customization-palette"); + simulateItemDrag(btn, palette); + } ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, { desc: "Two orphaned items should have one placeholder next to them (case 1).", setup: startCustomizing, run: function() { let btn = document.getElementById("developer-button"); let panel = document.getElementById(CustomizableUI.AREA_PANEL); let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); - let placementsAfterAppend = placements.concat(["developer-button", "sync-button"]); + let placementsAfterAppend = placements.concat(["developer-button"]); simulateItemDrag(btn, panel); - btn = document.getElementById("sync-button"); - simulateItemDrag(btn, panel); + + if (!isInWin8()) { + placementsAfterAppend = placementsAfterAppend.concat(["sync-button"]); + btn = document.getElementById("sync-button"); + simulateItemDrag(btn, panel); + } + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting"); yield endCustomizing(); yield startCustomizing(); is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering"); let palette = document.getElementById("customization-palette"); simulateItemDrag(btn, palette); - btn = document.getElementById("developer-button"); - simulateItemDrag(btn, palette); + + if (!isInWin8()) { + btn = document.getElementById("developer-button"); + simulateItemDrag(btn, palette); + } ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, { desc: "Two orphaned items should have one placeholder next to them (case 2).", setup: startCustomizing, run: function() { let btn = document.getElementById("add-ons-button"); + let btn2 = document.getElementById("switch-to-metro-button"); let panel = document.getElementById(CustomizableUI.AREA_PANEL); let palette = document.getElementById("customization-palette"); let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); let placementsAfterAppend = placements.filter(p => p != btn.id); simulateItemDrag(btn, palette); + + if (isInWin8()) { + placementsAfterAppend = placementsAfterAppend.filter(p => p != btn2.id); + simulateItemDrag(btn2, palette); + } + assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders before exiting"); yield endCustomizing(); yield startCustomizing(); is(getVisiblePlaceholderCount(panel), 1, "Should only have 1 visible placeholders after re-entering"); simulateItemDrag(btn, panel); + + if (isInWin8()) { + simulateItemDrag(btn2, panel); + } + assertAreaPlacements(CustomizableUI.AREA_PANEL, placements); ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, { desc: "A wide widget at the bottom of the panel should have three placeholders after it.", setup: startCustomizing, run: function() { let btn = document.getElementById("edit-controls"); + let metroBtn = document.getElementById("switch-to-metro-button"); let panel = document.getElementById(CustomizableUI.AREA_PANEL); + let palette = document.getElementById("customization-palette"); let placements = getAreaWidgetIds(CustomizableUI.AREA_PANEL); + if (isInWin8()) { + // Remove switch-to-metro-button + placements.pop(); + simulateItemDrag(metroBtn, palette); + } + let placementsAfterAppend = placements.concat([placements.shift()]); simulateItemDrag(btn, panel); assertAreaPlacements(CustomizableUI.AREA_PANEL, placementsAfterAppend); ok(!CustomizableUI.inDefaultState, "Should no longer be in default state."); is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting"); yield endCustomizing(); yield startCustomizing(); is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering"); + if (isInWin8()) { + simulateItemDrag(metroBtn, panel); + } let zoomControls = document.getElementById("zoom-controls"); simulateItemDrag(btn, zoomControls); ok(CustomizableUI.inDefaultState, "Should be in default state again."); }, }, { - desc: "The default placements should have three placeholders at the bottom.", + desc: "The default placements should have three placeholders at the bottom (or 2 in win8).", setup: startCustomizing, run: function() { + let numPlaceholders = isInWin8() ? 2 : 3; let panel = document.getElementById(CustomizableUI.AREA_PANEL); ok(CustomizableUI.inDefaultState, "Should be in default state."); - is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders before exiting"); + is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders before exiting"); yield endCustomizing(); yield startCustomizing(); - is(getVisiblePlaceholderCount(panel), 3, "Should have 3 visible placeholders after re-entering"); + is(getVisiblePlaceholderCount(panel), numPlaceholders, "Should have " + numPlaceholders + " visible placeholders after re-entering"); ok(CustomizableUI.inDefaultState, "Should still be in default state."); }, }, ]; function asyncCleanup() { yield endCustomizing();
--- a/browser/components/customizableui/test/head.js +++ b/browser/components/customizableui/test/head.js @@ -49,16 +49,31 @@ function removeCustomToolbars() { } gAddedToolbars.clear(); } function resetCustomization() { return CustomizableUI.reset(); } +function isInWin8() { + let sysInfo = Services.sysinfo; + let osName = sysInfo.getProperty("name"); + let version = sysInfo.getProperty("version"); + + // Windows 8 is version >= 6.2 + return osName == "Windows_NT" && version >= 6.2; +} + +function addSwitchToMetroButtonInWindows8(areaPanelPlacements) { + if (isInWin8()) { + areaPanelPlacements.push("switch-to-metro-button"); + } +} + function assertAreaPlacements(areaId, expectedPlacements) { let actualPlacements = getAreaWidgetIds(areaId); is(actualPlacements.length, expectedPlacements.length, "Area " + areaId + " should have " + expectedPlacements.length + " items."); let minItems = Math.min(expectedPlacements.length, actualPlacements.length); for (let i = 0; i < minItems; i++) { if (typeof expectedPlacements[i] == "string") { is(actualPlacements[i], expectedPlacements[i],
--- a/browser/components/sessionstore/src/SessionStore.jsm +++ b/browser/components/sessionstore/src/SessionStore.jsm @@ -1449,18 +1449,22 @@ let SessionStoreInternal = { setBrowserState: function ssi_setBrowserState(aState) { this._handleClosedWindows(); try { var state = JSON.parse(aState); } catch (ex) { /* invalid state object - don't restore anything */ } - if (!state || !state.windows) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!state) { + throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG); + } + if (!state.windows) { + throw Components.Exception("No windows", Cr.NS_ERROR_INVALID_ARG); + } this._browserSetState = true; // Make sure the priority queue is emptied out this._resetRestoringState(); var window = this._getMostRecentBrowserWindow(); if (!window) { @@ -1496,77 +1500,83 @@ let SessionStoreInternal = { return this._toJSONString(this._getWindowState(aWindow)); } if (DyingWindowCache.has(aWindow)) { let data = DyingWindowCache.get(aWindow); return this._toJSONString({ windows: [data] }); } - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); }, setWindowState: function ssi_setWindowState(aWindow, aState, aOverwrite) { - if (!aWindow.__SSi) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!aWindow.__SSi) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); + } this.restoreWindow(aWindow, aState, {overwriteTabs: aOverwrite}); }, getTabState: function ssi_getTabState(aTab) { - if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!aTab.ownerDocument) { + throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG); + } + if (!aTab.ownerDocument.defaultView.__SSi) { + throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG); + } let tabState = TabState.collectSync(aTab); return this._toJSONString(tabState); }, setTabState: function ssi_setTabState(aTab, aState) { // Remove the tab state from the cache. // Note that we cannot simply replace the contents of the cache // as |aState| can be an incomplete state that will be completed // by |restoreTabs|. let tabState = JSON.parse(aState); if (!tabState) { - debug("Empty state argument"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Invalid state string: not JSON", Cr.NS_ERROR_INVALID_ARG); } if (typeof tabState != "object") { - debug("State argument does not represent an object"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Not an object", Cr.NS_ERROR_INVALID_ARG); } if (!("entries" in tabState)) { - debug("State argument must contain field 'entries'"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Invalid state object: no entries", Cr.NS_ERROR_INVALID_ARG); } if (!aTab.ownerDocument) { - debug("Tab argument must have an owner document"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG); } let window = aTab.ownerDocument.defaultView; if (!("__SSi" in window)) { - debug("Default view of ownerDocument must have a unique identifier"); - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); } if (aTab.linkedBrowser.__SS_restoreState) { this._resetTabRestoringState(aTab); } TabStateCache.delete(aTab); this._setWindowStateBusy(window); this.restoreTabs(window, [aTab], [tabState], 0); }, duplicateTab: function ssi_duplicateTab(aWindow, aTab, aDelta = 0) { - if (!aTab.ownerDocument || !aTab.ownerDocument.defaultView.__SSi || - !aWindow.getBrowser) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!aTab.ownerDocument) { + throw Components.Exception("Invalid tab object: no ownerDocument", Cr.NS_ERROR_INVALID_ARG); + } + if (!aTab.ownerDocument.defaultView.__SSi) { + throw Components.Exception("Default view is not tracked", Cr.NS_ERROR_INVALID_ARG); + } + if (!aWindow.getBrowser) { + throw Components.Exception("Invalid window object: no getBrowser", Cr.NS_ERROR_INVALID_ARG); + } // Flush all data queued in the content script because we will need that // state to properly duplicate the given tab. TabState.flush(aTab.linkedBrowser); // Duplicate the tab state let tabState = TabState.clone(aTab); @@ -1581,78 +1591,81 @@ let SessionStoreInternal = { this.restoreTabs(aWindow, [newTab], [tabState], 0, true /* Load this tab right away. */); return newTab; }, setNumberOfTabsClosedLast: function ssi_setNumberOfTabsClosedLast(aWindow, aNumber) { - if (this._disabledForMultiProcess) + if (this._disabledForMultiProcess) { return; - - if ("__SSi" in aWindow) { - return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber); } - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!("__SSi" in aWindow)) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); + } + + return NumberOfTabsClosedLastPerWindow.set(aWindow, aNumber); }, /* Used to undo batch tab-close operations. Defaults to 1. */ getNumberOfTabsClosedLast: function ssi_getNumberOfTabsClosedLast(aWindow) { - if (this._disabledForMultiProcess) + if (this._disabledForMultiProcess) { return 0; - - if ("__SSi" in aWindow) { - // Blank tabs cannot be undo-closed, so the number returned by - // the NumberOfTabsClosedLastPerWindow can be greater than the - // return value of getClosedTabCount. We won't restore blank - // tabs, so we return the minimum of these two values. - return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1, - this.getClosedTabCount(aWindow)); + } + + if (!("__SSi" in aWindow)) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); } - - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + // Blank tabs cannot be undo-closed, so the number returned by + // the NumberOfTabsClosedLastPerWindow can be greater than the + // return value of getClosedTabCount. We won't restore blank + // tabs, so we return the minimum of these two values. + return Math.min(NumberOfTabsClosedLastPerWindow.get(aWindow) || 1, + this.getClosedTabCount(aWindow)); }, getClosedTabCount: function ssi_getClosedTabCount(aWindow) { if ("__SSi" in aWindow) { return this._windows[aWindow.__SSi]._closedTabs.length; } - if (DyingWindowCache.has(aWindow)) { - return DyingWindowCache.get(aWindow)._closedTabs.length; + if (!DyingWindowCache.has(aWindow)) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); } - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + return DyingWindowCache.get(aWindow)._closedTabs.length; }, getClosedTabData: function ssi_getClosedTabDataAt(aWindow) { if ("__SSi" in aWindow) { return this._toJSONString(this._windows[aWindow.__SSi]._closedTabs); } - if (DyingWindowCache.has(aWindow)) { - let data = DyingWindowCache.get(aWindow); - return this._toJSONString(data._closedTabs); + if (!DyingWindowCache.has(aWindow)) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); } - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + let data = DyingWindowCache.get(aWindow); + return this._toJSONString(data._closedTabs); }, undoCloseTab: function ssi_undoCloseTab(aWindow, aIndex) { - if (!aWindow.__SSi) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!aWindow.__SSi) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); + } var closedTabs = this._windows[aWindow.__SSi]._closedTabs; // default to the most-recently closed tab aIndex = aIndex || 0; - if (!(aIndex in closedTabs)) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!(aIndex in closedTabs)) { + throw Components.Exception("Invalid index: not in the closed tabs", Cr.NS_ERROR_INVALID_ARG); + } // fetch the data of closed tab, while removing it from the array let closedTab = closedTabs.splice(aIndex, 1).shift(); let closedTabState = closedTab.state; this._setWindowStateBusy(aWindow); // create a new tab let tabbrowser = aWindow.gBrowser; @@ -1666,87 +1679,90 @@ let SessionStoreInternal = { // focus the tab's content area (bug 342432) tab.linkedBrowser.focus(); return tab; }, forgetClosedTab: function ssi_forgetClosedTab(aWindow, aIndex) { - if (!aWindow.__SSi) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!aWindow.__SSi) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); + } var closedTabs = this._windows[aWindow.__SSi]._closedTabs; // default to the most-recently closed tab aIndex = aIndex || 0; - if (!(aIndex in closedTabs)) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!(aIndex in closedTabs)) { + throw Components.Exception("Invalid index: not in the closed tabs", Cr.NS_ERROR_INVALID_ARG); + } // remove closed tab from the array closedTabs.splice(aIndex, 1); }, getClosedWindowCount: function ssi_getClosedWindowCount() { return this._closedWindows.length; }, getClosedWindowData: function ssi_getClosedWindowData() { return this._toJSONString(this._closedWindows); }, undoCloseWindow: function ssi_undoCloseWindow(aIndex) { - if (!(aIndex in this._closedWindows)) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!(aIndex in this._closedWindows)) { + throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG); + } // reopen the window let state = { windows: this._closedWindows.splice(aIndex, 1) }; let window = this._openWindowWithState(state); this.windowToFocus = window; return window; }, forgetClosedWindow: function ssi_forgetClosedWindow(aIndex) { // default to the most-recently closed window aIndex = aIndex || 0; - if (!(aIndex in this._closedWindows)) - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!(aIndex in this._closedWindows)) { + throw Components.Exception("Invalid index: not in the closed windows", Cr.NS_ERROR_INVALID_ARG); + } // remove closed window from the array this._closedWindows.splice(aIndex, 1); }, getWindowValue: function ssi_getWindowValue(aWindow, aKey) { - if (this._disabledForMultiProcess) + if (this._disabledForMultiProcess) { return ""; + } if ("__SSi" in aWindow) { var data = this._windows[aWindow.__SSi].extData || {}; return data[aKey] || ""; } if (DyingWindowCache.has(aWindow)) { let data = DyingWindowCache.get(aWindow).extData || {}; return data[aKey] || ""; } - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); }, setWindowValue: function ssi_setWindowValue(aWindow, aKey, aStringValue) { - if (aWindow.__SSi) { - if (!this._windows[aWindow.__SSi].extData) { - this._windows[aWindow.__SSi].extData = {}; - } - this._windows[aWindow.__SSi].extData[aKey] = aStringValue; - this.saveStateDelayed(aWindow); + if (!("__SSi" in aWindow)) { + throw Components.Exception("Window is not tracked", Cr.NS_ERROR_INVALID_ARG); } - else { - throw (Components.returnCode = Cr.NS_ERROR_INVALID_ARG); + if (!this._windows[aWindow.__SSi].extData) { + this._windows[aWindow.__SSi].extData = {}; } + this._windows[aWindow.__SSi].extData[aKey] = aStringValue; + this.saveStateDelayed(aWindow); }, deleteWindowValue: function ssi_deleteWindowValue(aWindow, aKey) { if (aWindow.__SSi && this._windows[aWindow.__SSi].extData && this._windows[aWindow.__SSi].extData[aKey]) delete this._windows[aWindow.__SSi].extData[aKey]; this.saveStateDelayed(aWindow); }, @@ -1835,31 +1851,33 @@ let SessionStoreInternal = { * Restores the session state stored in LastSession. This will attempt * to merge data into the current session. If a window was opened at startup * with pinned tab(s), then the remaining data from the previous session for * that window will be opened into that winddow. Otherwise new windows will * be opened. */ restoreLastSession: function ssi_restoreLastSession() { // Use the public getter since it also checks PB mode - if (!this.canRestoreLastSession) - throw (Components.returnCode = Cr.NS_ERROR_FAILURE); + if (!this.canRestoreLastSession) { + throw Components.Exception("Last session can not be restored"); + } // First collect each window with its id... let windows = {}; this._forEachBrowserWindow(function(aWindow) { if (aWindow.__SS_lastSessionWindowID) windows[aWindow.__SS_lastSessionWindowID] = aWindow; }); let lastSessionState = LastSession.getState(); // This shouldn't ever be the case... - if (!lastSessionState.windows.length) - throw (Components.returnCode = Cr.NS_ERROR_UNEXPECTED); + if (!lastSessionState.windows.length) { + throw Components.Exception("lastSessionState has no windows", Cr.NS_ERROR_UNEXPECTED); + } // We're technically doing a restore, so set things up so we send the // notification when we're done. We want to send "sessionstore-browser-state-restored". this._restoreCount = lastSessionState.windows.length; this._browserSetState = true; // We want to re-use the last opened window instead of opening a new one in // the case where it's "empty" and not associated with a window in the session.
--- a/browser/devtools/app-manager/content/index.js +++ b/browser/devtools/app-manager/content/index.js @@ -62,16 +62,19 @@ let UI = { this.selectTab("projects"); break; case "toolbox-raise": this.selectTab(json.uid); break; case "toolbox-close": this.closeToolboxTab(json.uid); break; + case "toolbox-title": + // Not implemented + break; default: Cu.reportError("Unknown message: " + json.name); } } catch(e) { Cu.reportError(e); } // Forward message let panels = document.querySelectorAll(".panel"); for (let frame of panels) {
--- a/browser/devtools/debugger/test/browser_dbg_globalactor.js +++ b/browser/devtools/debugger/test/browser_dbg_globalactor.js @@ -39,35 +39,24 @@ function test() { // Make sure that lazily-created actors are created only once. let conn = transport._serverConnection; // First we look for the pool of global actors. let extraPools = conn._extraPools; let globalPool; + let actorPrefix = conn._prefix + "test_one"; + let count = 0; for (let pool of extraPools) { - if (Object.keys(pool._actors).some(e => { - // Tab actors are in the global pool. - let re = new RegExp(conn._prefix + "tab", "g"); - return e.match(re) !== null; - })) { - globalPool = pool; - break; - } + count += Object.keys(pool._actors).filter(e => { + return e.startsWith(actorPrefix); + }).length; } - - // Then we look if the global pool contains only one test actor. - let actorPrefix = conn._prefix + "test_one"; - let actors = Object.keys(globalPool._actors).join(); - info("Global actors: " + actors); - - isnot(actors.indexOf(actorPrefix), -1, - "The test actor exists in the pool."); - is(actors.indexOf(actorPrefix), actors.lastIndexOf(actorPrefix), - "Only one actor exists in the pool."); + is(count, 2, + "Only two actor exists in all pools. One tab actor and one global."); gClient.close(finish); }); }); }); }); }
--- a/browser/devtools/debugger/test/head.js +++ b/browser/devtools/debugger/test/head.js @@ -12,17 +12,17 @@ let { Services } = Cu.import("resource:/ let gEnableLogging = Services.prefs.getBoolPref("devtools.debugger.log"); Services.prefs.setBoolPref("devtools.debugger.log", false); let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); let { Promise: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}); let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let { DevToolsUtils } = Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm", {}); -let { BrowserDebuggerProcess } = Cu.import("resource:///modules/devtools/DebuggerProcess.jsm", {}); +let { BrowserToolboxProcess } = Cu.import("resource:///modules/devtools/ToolboxProcess.jsm", {}); let { DebuggerServer } = Cu.import("resource://gre/modules/devtools/dbg-server.jsm", {}); let { DebuggerClient } = Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); let { AddonManager } = Cu.import("resource://gre/modules/AddonManager.jsm", {}); let TargetFactory = devtools.TargetFactory; let Toolbox = devtools.Toolbox; const EXAMPLE_URL = "http://example.com/browser/browser/devtools/debugger/test/"; @@ -468,19 +468,19 @@ function initDebugger(aTarget, aWindow) }); } function initChromeDebugger(aOnClose) { info("Initializing a chrome debugger process."); let deferred = promise.defer(); - // Wait for the debugger process to start... - BrowserDebuggerProcess.init(aOnClose, aProcess => { - info("Chrome debugger process started successfully."); + // Wait for the toolbox process to start... + BrowserToolboxProcess.init(aOnClose, aProcess => { + info("Browser toolbox process started successfully."); prepareDebugger(aProcess); deferred.resolve(aProcess); }); return deferred.promise; }
--- a/browser/devtools/devtools-clhandler.js +++ b/browser/devtools/devtools-clhandler.js @@ -47,31 +47,31 @@ devtoolsCommandlineHandler.prototype = { let remoteDebuggingEnabled = false; try { remoteDebuggingEnabled = kDebuggerPrefs.every((pref) => Services.prefs.getBoolPref(pref)); } catch (ex) { Cu.reportError(ex); return; } if (remoteDebuggingEnabled) { - Cu.import("resource:///modules/devtools/DebuggerProcess.jsm"); - BrowserDebuggerProcess.init(); + Cu.import("resource:///modules/devtools/ToolboxProcess.jsm"); + BrowserToolboxProcess.init(); } else { let errorMsg = "Could not run chrome debugger! You need the following prefs " + "to be set to true: " + kDebuggerPrefs.join(", "); Cu.reportError(errorMsg); // Dump as well, as we're doing this from a commandline, make sure people don't miss it: dump(errorMsg + "\n"); } if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) { cmdLine.preventDefault = true; } }, helpInfo : " -jsconsole Open the Browser Console.\n" + - " -jsdebugger Open the Browser Debugger.\n", + " -jsdebugger Open the Browser Toolbox.\n", classID: Components.ID("{9e9a9283-0ce9-4e4a-8f1c-ba129a032c32}"), QueryInterface: XPCOMUtils.generateQI([Ci.nsICommandLineHandler]), }; this.NSGetFactory = XPCOMUtils.generateNSGetFactory([devtoolsCommandlineHandler]);
rename from browser/devtools/debugger/DebuggerProcess.jsm rename to browser/devtools/framework/ToolboxProcess.jsm --- a/browser/devtools/debugger/DebuggerProcess.jsm +++ b/browser/devtools/framework/ToolboxProcess.jsm @@ -2,60 +2,60 @@ /* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components; -const DBG_XUL = "chrome://browser/content/devtools/debugger.xul"; +const DBG_XUL = "chrome://browser/content/devtools/framework/toolbox-process-window.xul"; const CHROME_DEBUGGER_PROFILE_NAME = "-chrome-debugger"; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); Cu.import("resource://gre/modules/devtools/Loader.jsm"); let require = devtools.require; let Telemetry = require("devtools/shared/telemetry"); -this.EXPORTED_SYMBOLS = ["BrowserDebuggerProcess"]; +this.EXPORTED_SYMBOLS = ["BrowserToolboxProcess"]; /** - * Constructor for creating a process that will hold a chrome debugger. + * Constructor for creating a process that will hold a chrome toolbox. * * @param function aOnClose [optional] * A function called when the process stops running. * @param function aOnRun [optional] * A function called when the process starts running. */ -this.BrowserDebuggerProcess = function BrowserDebuggerProcess(aOnClose, aOnRun) { +this.BrowserToolboxProcess = function BrowserToolboxProcess(aOnClose, aOnRun) { this._closeCallback = aOnClose; this._runCallback = aOnRun; this._telemetry = new Telemetry(); this._initServer(); this._initProfile(); this._create(); }; /** - * Initializes and starts a chrome debugger process. + * Initializes and starts a chrome toolbox process. * @return object */ -BrowserDebuggerProcess.init = function(aOnClose, aOnRun) { - return new BrowserDebuggerProcess(aOnClose, aOnRun); +BrowserToolboxProcess.init = function(aOnClose, aOnRun) { + return new BrowserToolboxProcess(aOnClose, aOnRun); }; -BrowserDebuggerProcess.prototype = { +BrowserToolboxProcess.prototype = { /** * Initializes the debugger server. */ _initServer: function() { - dumpn("Initializing the chrome debugger server."); + dumpn("Initializing the chrome toolbox server."); if (!this.loader) { // Create a separate loader instance, so that we can be sure to receive a // separate instance of the DebuggingServer from the rest of the devtools. // This allows us to safely use the tools against even the actors and // DebuggingServer itself. this.loader = new DevToolsLoader(); this.loader.main("devtools/server/main"); @@ -66,73 +66,73 @@ BrowserDebuggerProcess.prototype = { if (!this.debuggerServer.initialized) { this.debuggerServer.init(); this.debuggerServer.addBrowserActors(); dumpn("initialized and added the browser actors for the DebuggerServer."); } this.debuggerServer.openListener(Prefs.chromeDebuggingPort); - dumpn("Finished initializing the chrome debugger server."); + dumpn("Finished initializing the chrome toolbox server."); dumpn("Started listening on port: " + Prefs.chromeDebuggingPort); }, /** * Initializes a profile for the remote debugger process. */ _initProfile: function() { - dumpn("Initializing the chrome debugger user profile."); + dumpn("Initializing the chrome toolbox user profile."); let profileService = Cc["@mozilla.org/toolkit/profile-service;1"] .createInstance(Ci.nsIToolkitProfileService); let profileName; try { // Attempt to get the required chrome debugging profile name string. profileName = profileService.selectedProfile.name + CHROME_DEBUGGER_PROFILE_NAME; - dumpn("Using chrome debugger profile name: " + profileName); + dumpn("Using chrome toolbox profile name: " + profileName); } catch (e) { // Requested profile string could not be retrieved. profileName = CHROME_DEBUGGER_PROFILE_NAME; let msg = "Querying the current profile failed. " + e.name + ": " + e.message; dumpn(msg); Cu.reportError(msg); } let profileObject; try { // Attempt to get the required chrome debugging profile toolkit object. profileObject = profileService.getProfileByName(profileName); - dumpn("Using chrome debugger profile object: " + profileObject); + dumpn("Using chrome toolbox profile object: " + profileObject); // The profile exists but the corresponding folder may have been deleted. var enumerator = Services.dirsvc.get("ProfD", Ci.nsIFile).parent.directoryEntries; while (enumerator.hasMoreElements()) { let profileDir = enumerator.getNext().QueryInterface(Ci.nsIFile); if (profileDir.leafName.contains(profileName)) { // Requested profile was found and the folder exists. this._dbgProfile = profileObject; return; } } // Requested profile was found but the folder was deleted. Cleanup needed. profileObject.remove(true); - dumpn("The already existing chrome debugger profile was invalid."); + dumpn("The already existing chrome toolbox profile was invalid."); } catch (e) { // Requested profile object was not found. let msg = "Creating a profile failed. " + e.name + ": " + e.message; dumpn(msg); Cu.reportError(msg); } // Create a new chrome debugging profile. this._dbgProfile = profileService.createProfile(null, profileName); profileService.flush(); - dumpn("Finished creating the chrome debugger user profile."); + dumpn("Finished creating the chrome toolbox user profile."); dumpn("Flushed profile service with: " + profileName); }, /** * Creates and initializes the profile & process for the remote debugger. */ _create: function() { dumpn("Initializing chrome debugging process."); @@ -140,17 +140,17 @@ BrowserDebuggerProcess.prototype = { process.init(Services.dirsvc.get("XREExeF", Ci.nsIFile)); dumpn("Running chrome debugging process."); let args = ["-no-remote", "-foreground", "-P", this._dbgProfile.name, "-chrome", DBG_XUL]; process.runwAsync(args, args.length, { observe: () => this.close() }); this._telemetry.toolOpened("jsbrowserdebugger"); - dumpn("Chrome debugger is now running..."); + dumpn("Chrome toolbox is now running..."); if (typeof this._runCallback == "function") { this._runCallback.call({}, this); } }, /** * Closes the remote debugger, removing the profile and killing the process. */ @@ -159,17 +159,17 @@ BrowserDebuggerProcess.prototype = { if (this._dbgProcess.isRunning) { this._dbgProcess.kill(); } this._telemetry.toolClosed("jsbrowserdebugger"); this.debuggerServer.destroy(); - dumpn("Chrome debugger is now closed..."); + dumpn("Chrome toolbox is now closed..."); if (typeof this._closeCallback == "function") { this._closeCallback.call({}, this); } } }; /** * Shortcuts for accessing various debugger preferences.
--- a/browser/devtools/framework/gDevTools.jsm +++ b/browser/devtools/framework/gDevTools.jsm @@ -400,22 +400,22 @@ let gDevToolsBrowser = { if (devToolbarEnabled && Services.prefs.getBoolPref("devtools.toolbar.visible")) { win.DeveloperToolbar.show(false); } // Enable App Manager? let appMgrEnabled = Services.prefs.getBoolPref("devtools.appmanager.enabled"); toggleCmd("Tools:DevAppMgr", appMgrEnabled); - // Enable Chrome Debugger? + // Enable Browser Toolbox? let chromeEnabled = Services.prefs.getBoolPref("devtools.chrome.enabled"); let devtoolsRemoteEnabled = Services.prefs.getBoolPref("devtools.debugger.remote-enabled"); let remoteEnabled = chromeEnabled && devtoolsRemoteEnabled && Services.prefs.getBoolPref("devtools.debugger.chrome-enabled"); - toggleCmd("Tools:ChromeDebugger", remoteEnabled); + toggleCmd("Tools:BrowserToolbox", remoteEnabled); // Enable Error Console? let consoleEnabled = Services.prefs.getBoolPref("devtools.errorconsole.enabled"); toggleCmd("Tools:ErrorConsole", consoleEnabled); // Enable DevTools connection screen, if the preference allows this. toggleCmd("Tools:DevToolsConnect", devtoolsRemoteEnabled); },
--- a/browser/devtools/framework/test/browser_dynamic_tool_enabling.js +++ b/browser/devtools/framework/test/browser_dynamic_tool_enabling.js @@ -1,17 +1,17 @@ /* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ // Tests that toggling prefs immediately (de)activates the relevant menuitem let gItemsToTest = { "menu_devToolbar": "devtools.toolbar.enabled", "menu_devAppMgr": "devtools.appmanager.enabled", - "menu_chromeDebugger": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"], + "menu_browserToolbox": ["devtools.chrome.enabled", "devtools.debugger.remote-enabled", "devtools.debugger.chrome-enabled"], "javascriptConsole": "devtools.errorconsole.enabled", "menu_devtools_connect": "devtools.debugger.remote-enabled", }; function expectedAttributeValueFromPrefs(prefs) { return prefs.every((pref) => Services.prefs.getBoolPref(pref)) ? "" : "true"; }
--- a/browser/devtools/framework/toolbox-hosts.js +++ b/browser/devtools/framework/toolbox-hosts.js @@ -21,17 +21,17 @@ Cu.import("resource:///modules/devtools/ * destroy() - destroy the host's UI */ exports.Hosts = { "bottom": BottomHost, "side": SidebarHost, "window": WindowHost, "custom": CustomHost -} +}; /** * Host object for the dock on the bottom of the browser */ function BottomHost(hostTab) { this.hostTab = hostTab; EventEmitter.decorate(this); @@ -267,35 +267,38 @@ WindowHost.prototype = { this._destroyed = true; this._window.removeEventListener("unload", this._boundUnload); this._window.close(); } return promise.resolve(null); } -} +}; /** * Host object for the toolbox in its own tab */ function CustomHost(hostTab, options) { this.frame = options.customIframe; this.uid = options.uid; EventEmitter.decorate(this); } CustomHost.prototype = { type: "custom", - _sendMessageToTopWindow: function CH__sendMessageToTopWindow(msg) { + _sendMessageToTopWindow: function CH__sendMessageToTopWindow(msg, data) { // It's up to the custom frame owner (parent window) to honor // "close" or "raise" instructions. let topWindow = this.frame.ownerDocument.defaultView; - let json = {name:"toolbox-" + msg, uid: this.uid} + let json = {name:"toolbox-" + msg, uid: this.uid}; + if (data) { + json.data = data; + } topWindow.postMessage(JSON.stringify(json), "*"); }, /** * Create a new xul window to contain the toolbox. */ create: function CH_create() { return promise.resolve(this.frame); @@ -307,17 +310,17 @@ CustomHost.prototype = { raise: function CH_raise() { this._sendMessageToTopWindow("raise"); }, /** * Set the toolbox title. */ setTitle: function CH_setTitle(title) { - // Not supported + this._sendMessageToTopWindow("title", { value: title }); }, /** * Destroy the window. */ destroy: function WH_destroy() { if (!this._destroyed) { this._destroyed = true;
new file mode 100644 --- /dev/null +++ b/browser/devtools/framework/toolbox-process-window.js @@ -0,0 +1,103 @@ +/* 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 { classes: Cc, interfaces: Ci, utils: Cu } = Components; + +let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); +let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); +let { Services } = Cu.import("resource://gre/modules/Services.jsm", {}); +let { debuggerSocketConnect, DebuggerClient } = + Cu.import("resource://gre/modules/devtools/dbg-client.jsm", {}); +let { ViewHelpers } = + Cu.import("resource:///modules/devtools/ViewHelpers.jsm", {}); + +/** + * Shortcuts for accessing various debugger preferences. + */ +let Prefs = new ViewHelpers.Prefs("devtools.debugger", { + chromeDebuggingHost: ["Char", "chrome-debugging-host"], + chromeDebuggingPort: ["Int", "chrome-debugging-port"] +}); + +// Initiate the connection +let transport = debuggerSocketConnect( + Prefs.chromeDebuggingHost, + Prefs.chromeDebuggingPort +); +let client = new DebuggerClient(transport); +client.connect(() => { + client.listTabs(openToolbox); +}); + +let gToolbox; + +function openToolbox(form) { + let options = { + form: form, + client: client, + chrome: true + }; + devtools.TargetFactory.forRemoteTab(options).then(target => { + let frame = document.getElementById("toolbox-iframe"); + let options = { customIframe: frame }; + gDevTools.showToolbox(target, + "jsdebugger", + devtools.Toolbox.HostType.CUSTOM, + options) + .then(onNewToolbox); + }); +} + +function onNewToolbox(toolbox) { + gToolbox = toolbox; + bindToolboxHandlers(); + raise(); +} + +function bindToolboxHandlers() { + gToolbox.once("destroyed", quitApp); + window.addEventListener("unload", onUnload); +} + +function onUnload() { + window.removeEventListener("unload", onUnload); + window.removeEventListener("message", onMessage); + gToolbox.destroy(); +} + +function onMessage(event) { + try { + let json = JSON.parse(event.data); + switch (json.name) { + case "toolbox-raise": + raise(); + break; + case "toolbox-title": + setTitle(json.data.value); + break; + } + } catch(e) { Cu.reportError(e); } +} + +window.addEventListener("message", onMessage); + +function raise() { + window.focus(); +} + +function setTitle(title) { + document.title = title; +} + +function quitApp() { + let quit = Cc["@mozilla.org/supports-PRBool;1"] + .createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(quit, "quit-application-requested", null); + + let shouldProceed = !quit.data; + if (shouldProceed) { + Services.startup.quit(Ci.nsIAppStartup.eForceQuit); + } +}
new file mode 100644 --- /dev/null +++ b/browser/devtools/framework/toolbox-process-window.xul @@ -0,0 +1,41 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- This Source Code Form is subject to the terms of the Mozilla Public + - License, v. 2.0. If a copy of the MPL was not distributed with this + - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> +<!DOCTYPE window [ +<!ENTITY % toolboxDTD SYSTEM "chrome://browser/locale/devtools/toolbox.dtd" > + %toolboxDTD; +]> + +<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?> + +<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" + id="devtools-toolbox-window" + macanimationtype="document" + fullscreenbutton="true" + windowtype="devtools:toolbox" + width="900" height="600" + persist="screenX screenY width height sizemode"> + + <script type="text/javascript" src="chrome://global/content/globalOverlay.js"/> + <script type="text/javascript" src="toolbox-process-window.js"/> + <script type="text/javascript" src="chrome://global/content/viewSourceUtils.js"/> + <script type="text/javascript" src="chrome://browser/content/utilityOverlay.js"/> + + <commandset id="toolbox-commandset"> + <command id="toolbox-cmd-close" oncommand="window.close();"/> + </commandset> + + <keyset id="toolbox-keyset"> + <key id="toolbox-key-close" + key="&closeCmd.key;" + command="toolbox-cmd-close" + modifiers="accel"/> + </keyset> + + <!-- This will be used by the Web Console to hold any popups it may create, + for example when viewing network request details. --> + <popupset id="mainPopupSet"></popupset> + + <iframe id="toolbox-iframe" flex="1"></iframe> +</window>
--- a/browser/devtools/jar.mn +++ b/browser/devtools/jar.mn @@ -71,16 +71,18 @@ browser.jar: content/browser/devtools/commandline.css (commandline/commandline.css) content/browser/devtools/commandlineoutput.xhtml (commandline/commandlineoutput.xhtml) content/browser/devtools/commandlinetooltip.xhtml (commandline/commandlinetooltip.xhtml) content/browser/devtools/framework/toolbox-window.xul (framework/toolbox-window.xul) content/browser/devtools/framework/toolbox-options.xul (framework/toolbox-options.xul) content/browser/devtools/framework/toolbox-options.js (framework/toolbox-options.js) * content/browser/devtools/framework/toolbox.xul (framework/toolbox.xul) content/browser/devtools/framework/toolbox.css (framework/toolbox.css) + content/browser/devtools/framework/toolbox-process-window.xul (framework/toolbox-process-window.xul) + content/browser/devtools/framework/toolbox-process-window.js (framework/toolbox-process-window.js) content/browser/devtools/inspector/inspector.xul (inspector/inspector.xul) content/browser/devtools/inspector/inspector.css (inspector/inspector.css) content/browser/devtools/connect.xhtml (framework/connect/connect.xhtml) content/browser/devtools/connect.css (framework/connect/connect.css) content/browser/devtools/connect.js (framework/connect/connect.js) content/browser/devtools/app-manager/template.js (app-manager/content/template.js) content/browser/devtools/app-manager/utils.js (app-manager/content/utils.js) content/browser/devtools/app-manager/connection-footer.js (app-manager/content/connection-footer.js)
--- a/browser/devtools/netmonitor/netmonitor-controller.js +++ b/browser/devtools/netmonitor/netmonitor-controller.js @@ -50,27 +50,40 @@ const EVENTS = { STARTED_RECEIVING_RESPONSE: "NetMonitor:NetworkEventUpdating:ResponseStart", UPDATING_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdating:ResponseContent", RECEIVED_RESPONSE_CONTENT: "NetMonitor:NetworkEventUpdated:ResponseContent", // When the request post params are displayed in the UI. REQUEST_POST_PARAMS_DISPLAYED: "NetMonitor:RequestPostParamsAvailable", // When the response body is displayed in the UI. - RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable" -} + RESPONSE_BODY_DISPLAYED: "NetMonitor:ResponseBodyAvailable", + + // When `onTabSelect` is fired and subsequently rendered + TAB_UPDATED: "NetMonitor:TabUpdated", + + // Fired when Sidebar is finished being populated + SIDEBAR_POPULATED: "NetMonitor:SidebarPopulated", + + // Fired when NetworkDetailsView is finished being populated + NETWORKDETAILSVIEW_POPULATED: "NetMonitor:NetworkDetailsViewPopulated", + + // Fired when NetworkDetailsView is finished being populated + CUSTOMREQUESTVIEW_POPULATED: "NetMonitor:CustomRequestViewPopulated" +}; Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -let promise = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js").Promise; +Cu.import("resource://gre/modules/Task.jsm"); Cu.import("resource:///modules/devtools/shared/event-emitter.js"); Cu.import("resource:///modules/devtools/SideMenuWidget.jsm"); Cu.import("resource:///modules/devtools/VariablesView.jsm"); Cu.import("resource:///modules/devtools/VariablesViewController.jsm"); Cu.import("resource:///modules/devtools/ViewHelpers.jsm"); +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require; const Editor = require("devtools/sourceeditor/editor"); XPCOMUtils.defineLazyModuleGetter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "devtools",
--- a/browser/devtools/netmonitor/netmonitor-panel.js +++ b/browser/devtools/netmonitor/netmonitor-panel.js @@ -1,17 +1,17 @@ /* -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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 { Cc, Ci, Cu, Cr } = require("chrome"); -const promise = require("sdk/core/promise"); +const { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); const EventEmitter = require("devtools/shared/event-emitter"); function NetMonitorPanel(iframeWindow, toolbox) { this.panelWin = iframeWindow; this._toolbox = toolbox; this._destroyer = null; this._view = this.panelWin.NetMonitorView;
--- a/browser/devtools/netmonitor/netmonitor-view.js +++ b/browser/devtools/netmonitor/netmonitor-view.js @@ -1377,25 +1377,29 @@ SidebarView.prototype = { NetMonitorView.RequestsMenu._flushWaterfallViews(true); }, /** * Populates this view with the specified data. * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population of the subview. */ populate: function(aData) { - if (aData.isCustom) { - NetMonitorView.CustomRequest.populate(aData); - $("#details-pane").selectedIndex = 0; - } else { - NetMonitorView.NetworkDetails.populate(aData); - $("#details-pane").selectedIndex = 1; - } + let isCustom = aData.isCustom; + let view = isCustom ? + NetMonitorView.CustomRequest : + NetMonitorView.NetworkDetails; + + return view.populate(aData).then(() => { + $("#details-pane").selectedIndex = isCustom ? 0 : 1 + window.emit(EVENTS.SIDEBAR_POPULATED) + }); }, /** * Hides this container. */ reset: function() { this.toggle(false); } @@ -1409,32 +1413,41 @@ function CustomRequestView() { } CustomRequestView.prototype = { /** * Populates this view with the specified data. * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population the view. */ populate: function(aData) { $("#custom-url-value").value = aData.url; $("#custom-method-value").value = aData.method; $("#custom-headers-value").value = writeHeaderText(aData.requestHeaders.headers); + let view = this; + let postDataPromise = null; + if (aData.requestPostData) { let body = aData.requestPostData.postData.text; - gNetwork.getString(body).then(aString => { + postDataPromise = gNetwork.getString(body).then(aString => { $("#custom-postdata-value").value = aString; }); + } else { + postDataPromise = promise.resolve(); } - this.updateCustomQuery(aData.url); + return postDataPromise + .then(() => view.updateCustomQuery(aData.url)) + .then(() => window.emit(EVENTS.CUSTOMREQUESTVIEW_POPULATED)); }, /** * Handle user input in the custom request form. * * @param object aField * the field that the user updated. */ @@ -1579,16 +1592,18 @@ NetworkDetailsView.prototype = { this._dataSrc = null; }, /** * Populates this view with the specified data. * * @param object aData * The data source (this should be the attachment of a request item). + * @return object + * Returns a promise that resolves upon population the view. */ populate: function(aData) { $("#request-params-box").setAttribute("flex", "1"); $("#request-params-box").hidden = false; $("#request-post-data-textarea-box").hidden = true; $("#response-content-info-header").hidden = true; $("#response-content-json-box").hidden = true; $("#response-content-textarea-box").hidden = true; @@ -1596,53 +1611,59 @@ NetworkDetailsView.prototype = { this._headers.empty(); this._cookies.empty(); this._params.empty(); this._json.empty(); this._dataSrc = { src: aData, populated: [] }; this._onTabSelect(); + window.emit(EVENTS.NETWORKDETAILSVIEW_POPULATED); + + return promise.resolve(); }, /** * Listener handling the tab selection event. */ _onTabSelect: function() { let { src, populated } = this._dataSrc || {}; let tab = this.widget.selectedIndex; + let view = this; // Make sure the data source is valid and don't populate the same tab twice. if (!src || populated[tab]) { return; } - switch (tab) { - case 0: // "Headers" - this._setSummary(src); - this._setResponseHeaders(src.responseHeaders); - this._setRequestHeaders(src.requestHeaders); - break; - case 1: // "Cookies" - this._setResponseCookies(src.responseCookies); - this._setRequestCookies(src.requestCookies); - break; - case 2: // "Params" - this._setRequestGetParams(src.url); - this._setRequestPostParams(src.requestHeaders, src.requestPostData); - break; - case 3: // "Response" - this._setResponseBody(src.url, src.responseContent); - break; - case 4: // "Timings" - this._setTimingsInformation(src.eventTimings); - break; - } - - populated[tab] = true; + Task.spawn(function*() { + switch (tab) { + case 0: // "Headers" + yield view._setSummary(src); + yield view._setResponseHeaders(src.responseHeaders); + yield view._setRequestHeaders(src.requestHeaders); + break; + case 1: // "Cookies" + yield view._setResponseCookies(src.responseCookies); + yield view._setRequestCookies(src.requestCookies); + break; + case 2: // "Params" + yield view._setRequestGetParams(src.url); + yield view._setRequestPostParams(src.requestHeaders, src.requestPostData); + break; + case 3: // "Response" + yield view._setResponseBody(src.url, src.responseContent); + break; + case 4: // "Timings" + yield view._setTimingsInformation(src.eventTimings); + break; + } + populated[tab] = true; + window.emit(EVENTS.TAB_UPDATED); + }); }, /** * Sets the network request summary shown in this view. * * @param object aData * The data source (this should be the attachment of a request item). */ @@ -1679,116 +1700,135 @@ NetworkDetailsView.prototype = { } }, /** * Sets the network request headers shown in this view. * * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when request headers are set. */ _setRequestHeaders: function(aResponse) { if (aResponse && aResponse.headers.length) { - this._addHeaders(this._requestHeaders, aResponse); + return this._addHeaders(this._requestHeaders, aResponse); } + return promise.resolve(); }, /** * Sets the network response headers shown in this view. * * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when response headers are set. */ _setResponseHeaders: function(aResponse) { if (aResponse && aResponse.headers.length) { aResponse.headers.sort((a, b) => a.name > b.name); - this._addHeaders(this._responseHeaders, aResponse); + return this._addHeaders(this._responseHeaders, aResponse); } + return promise.resolve(); }, /** * Populates the headers container in this view with the specified data. * * @param string aName * The type of headers to populate (request or response). * @param object aResponse * The message received from the server. + * @return object + * A promise that resolves when headers are added. */ _addHeaders: function(aName, aResponse) { let kb = aResponse.headersSize / 1024; let size = L10N.numberWithDecimals(kb, HEADERS_SIZE_DECIMALS); let text = L10N.getFormatStr("networkMenu.sizeKB", size); let headersScope = this._headers.addScope(aName + " (" + text + ")"); headersScope.expanded = true; - for (let header of aResponse.headers) { + return promise.all(aResponse.headers.map(header => { let headerVar = headersScope.addItem(header.name, {}, true); - gNetwork.getString(header.value).then(aString => headerVar.setGrip(aString)); - } + return gNetwork.getString(header.value) + .then(aString => headerVar.setGrip(aString)); + })); }, /** * Sets the network request cookies shown in this view. * * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the request cookies are set. */ _setRequestCookies: function(aResponse) { if (aResponse && aResponse.cookies.length) { aResponse.cookies.sort((a, b) => a.name > b.name); - this._addCookies(this._requestCookies, aResponse); + return this._addCookies(this._requestCookies, aResponse); } + return promise.resolve(); }, /** * Sets the network response cookies shown in this view. * * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the response cookies are set. */ _setResponseCookies: function(aResponse) { if (aResponse && aResponse.cookies.length) { - this._addCookies(this._responseCookies, aResponse); + return this._addCookies(this._responseCookies, aResponse); } + return promise.resolve(); }, /** * Populates the cookies container in this view with the specified data. * * @param string aName * The type of cookies to populate (request or response). * @param object aResponse * The message received from the server. + * @return object + * Returns a promise that resolves upon the adding of cookies. */ _addCookies: function(aName, aResponse) { let cookiesScope = this._cookies.addScope(aName); cookiesScope.expanded = true; - for (let cookie of aResponse.cookies) { + return promise.all(aResponse.cookies.map(cookie => { let cookieVar = cookiesScope.addItem(cookie.name, {}, true); - gNetwork.getString(cookie.value).then(aString => cookieVar.setGrip(aString)); + return gNetwork.getString(cookie.value).then(aString => { + cookieVar.setGrip(aString); - // By default the cookie name and value are shown. If this is the only - // information available, then nothing else is to be displayed. - let cookieProps = Object.keys(cookie); - if (cookieProps.length == 2) { - continue; - } + // By default the cookie name and value are shown. If this is the only + // information available, then nothing else is to be displayed. + let cookieProps = Object.keys(cookie); + if (cookieProps.length == 2) { + return; + } - // Display any other information other than the cookie name and value - // which may be available. - let rawObject = Object.create(null); - let otherProps = cookieProps.filter(e => e != "name" && e != "value"); - for (let prop of otherProps) { - rawObject[prop] = cookie[prop]; - } - cookieVar.populate(rawObject); - cookieVar.twisty = true; - cookieVar.expanded = true; - } + // Display any other information other than the cookie name and value + // which may be available. + let rawObject = Object.create(null); + let otherProps = cookieProps.filter(e => e != "name" && e != "value"); + for (let prop of otherProps) { + rawObject[prop] = cookie[prop]; + } + cookieVar.populate(rawObject); + cookieVar.twisty = true; + cookieVar.expanded = true; + }); + })); }, /** * Sets the network request get params shown in this view. * * @param string aUrl * The request's url. */ @@ -1801,22 +1841,24 @@ NetworkDetailsView.prototype = { /** * Sets the network request post params shown in this view. * * @param object aHeadersResponse * The "requestHeaders" message received from the server. * @param object aPostDataResponse * The "requestPostData" message received from the server. + * @return object + * A promise that is resolved when the request post params are set. */ _setRequestPostParams: function(aHeadersResponse, aPostDataResponse) { if (!aHeadersResponse || !aPostDataResponse) { - return; + return promise.resolve(); } - gNetwork.getString(aPostDataResponse.postData.text).then(aString => { + return gNetwork.getString(aPostDataResponse.postData.text).then(aString => { // Handle query strings (poor man's forms, e.g. "?foo=bar&baz=42"). let cType = aHeadersResponse.headers.filter(({ name }) => name == "Content-Type")[0]; let cString = cType ? cType.value : ""; if (cString.contains("x-www-form-urlencoded") || aString.contains("x-www-form-urlencoded")) { let formDataGroups = aString.split(/\r\n|\n|\r/); for (let group of formDataGroups) { this._addParams(this._paramsFormData, group); @@ -1828,22 +1870,21 @@ NetworkDetailsView.prototype = { // scope in the params view and place the source editor containing // the raw post data directly underneath. $("#request-params-box").removeAttribute("flex"); let paramsScope = this._params.addScope(this._paramsPostPayload); paramsScope.expanded = true; paramsScope.locked = true; $("#request-post-data-textarea-box").hidden = false; - NetMonitorView.editor("#request-post-data-textarea").then(aEditor => { + return NetMonitorView.editor("#request-post-data-textarea").then(aEditor => { aEditor.setText(aString); }); } - window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED); - }); + }).then(() => window.emit(EVENTS.REQUEST_POST_PARAMS_DISPLAYED)); }, /** * Populates the params container in this view with the specified data. * * @param string aName * The type of params to populate (get or post). * @param string aQueryString @@ -1865,24 +1906,26 @@ NetworkDetailsView.prototype = { /** * Sets the network response body shown in this view. * * @param string aUrl * The request's url. * @param object aResponse * The message received from the server. + * @return object + * A promise that is resolved when the response body is set */ _setResponseBody: function(aUrl, aResponse) { if (!aResponse) { - return; + return promise.resolve(); } let { mimeType, text, encoding } = aResponse.content; - gNetwork.getString(text).then(aString => { + return gNetwork.getString(text).then(aString => { // Handle json, which we tentatively identify by checking the MIME type // for "json" after any word boundary. This works for the standard // "application/json", and also for custom types like "x-bigcorp-json". // This should be marginally more reliable than just looking for "json". if (/\bjson/.test(mimeType)) { let jsonpRegex = /^[a-zA-Z0-9_$]+\(|\)$/g; // JSONP with callback. let sanitizedJSON = aString.replace(jsonpRegex, ""); let callbackPadding = aString.match(jsonpRegex); @@ -1898,32 +1941,32 @@ NetworkDetailsView.prototype = { // Valid JSON. if (jsonObject) { $("#response-content-json-box").hidden = false; let jsonScopeName = callbackPadding ? L10N.getFormatStr("jsonpScopeName", callbackPadding[0].slice(0, -1)) : L10N.getStr("jsonScopeName"); - this._json.controller.setSingleVariable({ + return this._json.controller.setSingleVariable({ label: jsonScopeName, rawObject: jsonObject, - }); + }).expanded; } // Malformed JSON. else { $("#response-content-textarea-box").hidden = false; - NetMonitorView.editor("#response-content-textarea").then(aEditor => { - aEditor.setMode(Editor.modes.js); - aEditor.setText(aString); - }); let infoHeader = $("#response-content-info-header"); infoHeader.setAttribute("value", parsingError); infoHeader.setAttribute("tooltiptext", parsingError); infoHeader.hidden = false; + return NetMonitorView.editor("#response-content-textarea").then(aEditor => { + aEditor.setMode(Editor.modes.js); + aEditor.setText(aString); + }); } } // Handle images. else if (mimeType.contains("image/")) { $("#response-content-image-box").setAttribute("align", "center"); $("#response-content-image-box").setAttribute("pack", "center"); $("#response-content-image-box").hidden = false; $("#response-content-image").src = @@ -1943,34 +1986,33 @@ NetworkDetailsView.prototype = { let { width, height } = e.target.getBoundingClientRect(); let dimensions = (width - 2) + " x " + (height - 2); $("#response-content-image-dimensions-value").setAttribute("value", dimensions); }; } // Handle anything else. else { $("#response-content-textarea-box").hidden = false; - NetMonitorView.editor("#response-content-textarea").then(aEditor => { + return NetMonitorView.editor("#response-content-textarea").then(aEditor => { aEditor.setMode(Editor.modes.text); aEditor.setText(aString); // Maybe set a more appropriate mode in the Source Editor if possible, // but avoid doing this for very large files. if (aString.length < SOURCE_SYNTAX_HIGHLIGHT_MAX_FILE_SIZE) { for (let key in CONTENT_MIME_TYPE_MAPPINGS) { if (mimeType.contains(key)) { aEditor.setMode(CONTENT_MIME_TYPE_MAPPINGS[key]); break; } } } }); } - window.emit(EVENTS.RESPONSE_BODY_DISPLAYED); - }); + }).then(() => window.emit(EVENTS.RESPONSE_BODY_DISPLAYED)); }, /** * Sets the timings information shown in this view. * * @param object aResponse * The message received from the server. */
--- a/browser/devtools/netmonitor/test/browser_net_content-type.js +++ b/browser/devtools/netmonitor/test/browser_net_content-type.js @@ -70,41 +70,37 @@ function test() { time: true }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - testResponseTab("xml") - .then(() => { - RequestsMenu.selectedIndex = 1; - return testResponseTab("css"); - }) - .then(() => { - RequestsMenu.selectedIndex = 2; - return testResponseTab("js"); - }) - .then(() => { - RequestsMenu.selectedIndex = 3; - return testResponseTab("json"); - }) - .then(() => { - RequestsMenu.selectedIndex = 4; - return testResponseTab("html"); - }) - .then(() => { - RequestsMenu.selectedIndex = 5; - return testResponseTab("png"); - }) - .then(() => { - return teardown(aMonitor); - }) - .then(finish); + Task.spawn(function*() { + yield waitForResponseBodyDisplayed(); + yield testResponseTab("xml"); + RequestsMenu.selectedIndex = 1; + yield waitForTabUpdated(); + yield testResponseTab("css"); + RequestsMenu.selectedIndex = 2; + yield waitForTabUpdated(); + yield testResponseTab("js"); + RequestsMenu.selectedIndex = 3; + yield waitForTabUpdated(); + yield testResponseTab("json"); + RequestsMenu.selectedIndex = 4; + yield waitForTabUpdated(); + yield testResponseTab("html"); + RequestsMenu.selectedIndex = 5; + yield waitForTabUpdated(); + yield testResponseTab("png"); + yield teardown(aMonitor); + finish(); + }); function testResponseTab(aType) { let tab = document.querySelectorAll("#details-pane tab")[3]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; is(tab.getAttribute("selected"), "true", "The response tab in the network details pane should be selected."); @@ -216,13 +212,21 @@ function test() { deferred.resolve(); }); return deferred.promise; } } } + + function waitForTabUpdated () { + return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED); + } + + function waitForResponseBodyDisplayed () { + return waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED); + } }); aDebuggee.performRequests(); }); }
--- a/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js +++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-01.js @@ -21,17 +21,20 @@ function test() { statusText: "DA DA DA" }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => + NetMonitorView.editor("#response-content-textarea") + ).then((aEditor) => { is(aEditor.getText().indexOf("\u044F"), 26, // я "The text shown in the source editor is incorrect."); is(aEditor.getMode(), Editor.modes.text, "The mode active in the source editor is incorrect."); teardown(aMonitor).then(finish); }); });
--- a/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js +++ b/browser/devtools/netmonitor/test/browser_net_cyrillic-02.js @@ -22,17 +22,20 @@ function test() { statusText: "OK" }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => + NetMonitorView.editor("#response-content-textarea") + ).then((aEditor) => { is(aEditor.getText().indexOf("\u044F"), 302, // я "The text shown in the source editor is incorrect."); is(aEditor.getMode(), Editor.modes.html, "The mode active in the source editor is incorrect."); teardown(aMonitor).then(finish); }); });
--- a/browser/devtools/netmonitor/test/browser_net_json-malformed.js +++ b/browser/devtools/netmonitor/test/browser_net_json-malformed.js @@ -26,46 +26,49 @@ function test() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); let tab = document.querySelectorAll("#details-pane tab")[3]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; - is(tab.getAttribute("selected"), "true", - "The response tab in the network details pane should be selected."); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED).then(() => { + is(tab.getAttribute("selected"), "true", + "The response tab in the network details pane should be selected."); - is(tabpanel.querySelector("#response-content-info-header") - .hasAttribute("hidden"), false, - "The response info header doesn't have the intended visibility."); - is(tabpanel.querySelector("#response-content-info-header") - .getAttribute("value"), - "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data", - "The response info header doesn't have the intended value attribute."); - is(tabpanel.querySelector("#response-content-info-header") - .getAttribute("tooltiptext"), - "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data", - "The response info header doesn't have the intended tooltiptext attribute."); + is(tabpanel.querySelector("#response-content-info-header") + .hasAttribute("hidden"), false, + "The response info header doesn't have the intended visibility."); + is(tabpanel.querySelector("#response-content-info-header") + .getAttribute("value"), + "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data", + "The response info header doesn't have the intended value attribute."); + is(tabpanel.querySelector("#response-content-info-header") + .getAttribute("tooltiptext"), + "SyntaxError: JSON.parse: unexpected non-whitespace character after JSON data", + "The response info header doesn't have the intended tooltiptext attribute."); - is(tabpanel.querySelector("#response-content-json-box") - .hasAttribute("hidden"), true, - "The response content json box doesn't have the intended visibility."); - is(tabpanel.querySelector("#response-content-textarea-box") - .hasAttribute("hidden"), false, - "The response content textarea box doesn't have the intended visibility."); - is(tabpanel.querySelector("#response-content-image-box") - .hasAttribute("hidden"), true, - "The response content image box doesn't have the intended visibility."); + is(tabpanel.querySelector("#response-content-json-box") + .hasAttribute("hidden"), true, + "The response content json box doesn't have the intended visibility."); + is(tabpanel.querySelector("#response-content-textarea-box") + .hasAttribute("hidden"), false, + "The response content textarea box doesn't have the intended visibility."); + is(tabpanel.querySelector("#response-content-image-box") + .hasAttribute("hidden"), true, + "The response content image box doesn't have the intended visibility."); - NetMonitorView.editor("#response-content-textarea").then((aEditor) => { - is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },", - "The text shown in the source editor is incorrect."); - is(aEditor.getMode(), Editor.modes.js, - "The mode active in the source editor is incorrect."); + NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + is(aEditor.getText(), "{ \"greeting\": \"Hello malformed JSON!\" },", + "The text shown in the source editor is incorrect."); + is(aEditor.getMode(), Editor.modes.js, + "The mode active in the source editor is incorrect."); - teardown(aMonitor).then(finish); + teardown(aMonitor).then(finish); + }); }); }); aDebuggee.performRequests(); }); }
--- a/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js +++ b/browser/devtools/netmonitor/test/browser_net_json_custom_mime.js @@ -25,18 +25,21 @@ function test() { time: true }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - testResponseTab(); - teardown(aMonitor).then(finish); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED) + .then(testResponseTab) + .then(() => teardown(aMonitor)) + .then(finish); function testResponseTab() { let tab = document.querySelectorAll("#details-pane tab")[3]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; is(tab.getAttribute("selected"), "true", "The response tab in the network details pane should be selected.");
--- a/browser/devtools/netmonitor/test/browser_net_jsonp.js +++ b/browser/devtools/netmonitor/test/browser_net_jsonp.js @@ -25,18 +25,21 @@ function test() { time: true }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - testResponseTab(); - teardown(aMonitor).then(finish); + let RESPONSE_BODY_DISPLAYED = aMonitor.panelWin.EVENTS.RESPONSE_BODY_DISPLAYED; + waitFor(aMonitor.panelWin, RESPONSE_BODY_DISPLAYED) + .then(testResponseTab) + .then(() => teardown(aMonitor)) + .then(finish); function testResponseTab() { let tab = document.querySelectorAll("#details-pane tab")[3]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; is(tab.getAttribute("selected"), "true", "The response tab in the network details pane should be selected.");
--- a/browser/devtools/netmonitor/test/browser_net_post-data-01.js +++ b/browser/devtools/netmonitor/test/browser_net_post-data-01.js @@ -35,24 +35,24 @@ function test() { time: true }); EventUtils.sendMouseEvent({ type: "mousedown" }, document.getElementById("details-pane-toggle")); EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[2]); - testParamsTab("urlencoded") - .then(() => { - RequestsMenu.selectedIndex = 1; - return testParamsTab("multipart"); - }) - .then(() => { - return teardown(aMonitor); - }) + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => + testParamsTab("urlencoded") + ).then(() => { + RequestsMenu.selectedIndex = 1; + return waitFor(aMonitor.panelWin, TAB_UPDATED); + }).then(() => testParamsTab("multipart")) + .then(() => teardown(aMonitor)) .then(finish); function testParamsTab(aType) { let tab = document.querySelectorAll("#details-pane tab")[2]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[2]; is(tab.getAttribute("selected"), "true", "The params tab in the network details pane should be selected.");
--- a/browser/devtools/netmonitor/test/browser_net_post-data-02.js +++ b/browser/devtools/netmonitor/test/browser_net_post-data-02.js @@ -15,48 +15,50 @@ function test() { RequestsMenu.lazyUpdate = false; NetworkDetails._params.lazyEmpty = false; waitForNetworkEvents(aMonitor, 0, 1).then(() => { NetMonitorView.toggleDetailsPane({ visible: true }, 2) RequestsMenu.selectedIndex = 0; - let tab = document.querySelectorAll("#event-details-pane tab")[2]; - let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2]; - - is(tab.getAttribute("selected"), "true", - "The params tab in the network details pane should be selected."); + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => { + let tab = document.querySelectorAll("#event-details-pane tab")[2]; + let tabpanel = document.querySelectorAll("#event-details-pane tabpanel")[2]; - is(tabpanel.querySelector("#request-params-box") - .hasAttribute("hidden"), false, - "The request params box doesn't have the indended visibility."); - is(tabpanel.querySelector("#request-post-data-textarea-box") - .hasAttribute("hidden"), true, - "The request post data textarea box doesn't have the indended visibility."); + is(tab.getAttribute("selected"), "true", + "The params tab in the network details pane should be selected."); - is(tabpanel.querySelectorAll(".variables-view-scope").length, 1, - "There should be 1 param scopes displayed in this tabpanel."); - is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0, - "The empty notice should not be displayed in this tabpanel."); + is(tabpanel.querySelector("#request-params-box") + .hasAttribute("hidden"), false, + "The request params box doesn't have the indended visibility."); + is(tabpanel.querySelector("#request-post-data-textarea-box") + .hasAttribute("hidden"), true, + "The request post data textarea box doesn't have the indended visibility."); - let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0]; - is(postScope.querySelector(".name").getAttribute("value"), - L10N.getStr("paramsFormData"), - "The post scope doesn't have the correct title."); + is(tabpanel.querySelectorAll(".variables-view-scope").length, 1, + "There should be 1 param scopes displayed in this tabpanel."); + is(tabpanel.querySelectorAll(".variables-view-empty-notice").length, 0, + "The empty notice should not be displayed in this tabpanel."); + + let postScope = tabpanel.querySelectorAll(".variables-view-scope")[0]; + is(postScope.querySelector(".name").getAttribute("value"), + L10N.getStr("paramsFormData"), + "The post scope doesn't have the correct title."); - is(postScope.querySelectorAll(".variables-view-variable").length, 2, - "There should be 2 param values displayed in the post scope."); - is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"), - "foo", "The first query param name was incorrect."); - is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"), - "\"bar\"", "The first query param value was incorrect."); - is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"), - "baz", "The second query param name was incorrect."); - is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"), - "\"123\"", "The second query param value was incorrect."); - - teardown(aMonitor).then(finish); + is(postScope.querySelectorAll(".variables-view-variable").length, 2, + "There should be 2 param values displayed in the post scope."); + is(postScope.querySelectorAll(".variables-view-variable .name")[0].getAttribute("value"), + "foo", "The first query param name was incorrect."); + is(postScope.querySelectorAll(".variables-view-variable .value")[0].getAttribute("value"), + "\"bar\"", "The first query param value was incorrect."); + is(postScope.querySelectorAll(".variables-view-variable .name")[1].getAttribute("value"), + "baz", "The second query param name was incorrect."); + is(postScope.querySelectorAll(".variables-view-variable .value")[1].getAttribute("value"), + "\"123\"", "The second query param value was incorrect."); + teardown(aMonitor).then(finish); + }); }); aDebuggee.performRequests(); }); }
--- a/browser/devtools/netmonitor/test/browser_net_resend.js +++ b/browser/devtools/netmonitor/test/browser_net_resend.js @@ -16,41 +16,47 @@ function test() { initNetMonitor(POST_DATA_URL).then(([aTab, aDebuggee, aMonitor]) => { info("Starting test... "); gPanelWin = aMonitor.panelWin; gPanelDoc = gPanelWin.document; let { NetMonitorView } = gPanelWin; let { RequestsMenu } = NetMonitorView; + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; + let CUSTOMREQUESTVIEW_POPULATED = aMonitor.panelWin.EVENTS.CUSTOMREQUESTVIEW_POPULATED; RequestsMenu.lazyUpdate = false; waitForNetworkEvents(aMonitor, 0, 2).then(() => { let origItem = RequestsMenu.getItemAtIndex(0); RequestsMenu.selectedItem = origItem; - // add a new custom request cloned from selected request - RequestsMenu.cloneSelectedRequest(); - testCustomForm(origItem.attachment); + waitFor(aMonitor.panelWin, TAB_UPDATED).then(() => { + // add a new custom request cloned from selected request + RequestsMenu.cloneSelectedRequest(); + return waitFor(aMonitor.panelWin, CUSTOMREQUESTVIEW_POPULATED); + }).then(() => { + testCustomForm(origItem.attachment); - let customItem = RequestsMenu.selectedItem; - testCustomItem(customItem, origItem); + let customItem = RequestsMenu.selectedItem; + testCustomItem(customItem, origItem); - // edit the custom request - editCustomForm(() => { - testCustomItemChanged(customItem, origItem); + // edit the custom request + editCustomForm(() => { + testCustomItemChanged(customItem, origItem); - waitForNetworkEvents(aMonitor, 0, 1).then(() => { - let sentItem = RequestsMenu.selectedItem; - testSentRequest(sentItem.attachment, origItem.attachment); - finishUp(aMonitor); + waitForNetworkEvents(aMonitor, 0, 1).then(() => { + let sentItem = RequestsMenu.selectedItem; + testSentRequest(sentItem.attachment, origItem.attachment); + finishUp(aMonitor); + }); + // send the new request + RequestsMenu.sendCustomRequest(); }); - // send the new request - RequestsMenu.sendCustomRequest(); }); }); aDebuggee.performRequests(); }); } function testCustomItem(aItem, aOrigItem) {
--- a/browser/devtools/netmonitor/test/browser_net_simple-request-details.js +++ b/browser/devtools/netmonitor/test/browser_net_simple-request-details.js @@ -6,20 +6,21 @@ */ function test() { initNetMonitor(SIMPLE_SJS).then(([aTab, aDebuggee, aMonitor]) => { info("Starting test... "); let { document, L10N, Editor, NetMonitorView } = aMonitor.panelWin; let { RequestsMenu, NetworkDetails } = NetMonitorView; - + let TAB_UPDATED = aMonitor.panelWin.EVENTS.TAB_UPDATED; RequestsMenu.lazyUpdate = false; - waitForNetworkEvents(aMonitor, 1).then(() => { + Task.spawn(function () { + yield waitForNetworkEvents(aMonitor, 1); is(RequestsMenu.selectedItem, null, "There shouldn't be any selected item in the requests menu."); is(RequestsMenu.itemCount, 1, "The requests menu should not be empty after the first request."); is(NetMonitorView.detailsPaneHidden, true, "The details pane should still be hidden after the first request."); EventUtils.sendMouseEvent({ type: "mousedown" }, @@ -27,25 +28,24 @@ function test() { isnot(RequestsMenu.selectedItem, null, "There should be a selected item in the requests menu."); is(RequestsMenu.selectedIndex, 0, "The first item should be selected in the requests menu."); is(NetMonitorView.detailsPaneHidden, false, "The details pane should not be hidden after toggle button was pressed."); + yield waitFor(aMonitor.panelWin, TAB_UPDATED) testHeadersTab(); testCookiesTab(); testParamsTab(); - testResponseTab() - .then(() => { - testTimingsTab(); - return teardown(aMonitor); - }) - .then(finish); + yield testResponseTab(); + testTimingsTab(); + yield teardown(aMonitor); + finish(); }); function testHeadersTab() { let tab = document.querySelectorAll("#details-pane tab")[0]; let tabpanel = document.querySelectorAll("#details-pane tabpanel")[0]; is(tab.getAttribute("selected"), "true", "The headers tab in the network details pane should be selected."); @@ -167,36 +167,39 @@ function test() { .hasAttribute("hidden"), true, "The request post data textarea box should be hidden."); } function testResponseTab() { EventUtils.sendMouseEvent({ type: "mousedown" }, document.querySelectorAll("#details-pane tab")[3]); - let tab = document.querySelectorAll("#details-pane tab")[3]; - let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; + return Task.spawn(function () { + yield waitFor(aMonitor.panelWin, TAB_UPDATED); - is(tab.getAttribute("selected"), "true", - "The response tab in the network details pane should be selected."); + let tab = document.querySelectorAll("#details-pane tab")[3]; + let tabpanel = document.querySelectorAll("#details-pane tabpanel")[3]; + + is(tab.getAttribute("selected"), "true", + "The response tab in the network details pane should be selected."); - is(tabpanel.querySelector("#response-content-info-header") - .hasAttribute("hidden"), true, - "The response info header should be hidden."); - is(tabpanel.querySelector("#response-content-json-box") - .hasAttribute("hidden"), true, - "The response content json box should be hidden."); - is(tabpanel.querySelector("#response-content-textarea-box") - .hasAttribute("hidden"), false, - "The response content textarea box should not be hidden."); - is(tabpanel.querySelector("#response-content-image-box") - .hasAttribute("hidden"), true, - "The response content image box should be hidden."); + is(tabpanel.querySelector("#response-content-info-header") + .hasAttribute("hidden"), true, + "The response info header should be hidden."); + is(tabpanel.querySelector("#response-content-json-box") + .hasAttribute("hidden"), true, + "The response content json box should be hidden."); + is(tabpanel.querySelector("#response-content-textarea-box") + .hasAttribute("hidden"), false, + "The response content textarea box should not be hidden."); + is(tabpanel.querySelector("#response-content-image-box") + .hasAttribute("hidden"), true, + "The response content image box should be hidden."); - return NetMonitorView.editor("#response-content-textarea").then((aEditor) => { + let aEditor = yield NetMonitorView.editor("#response-content-textarea"); is(aEditor.getText(), "Hello world!", "The text shown in the source editor is incorrect."); is(aEditor.getMode(), Editor.modes.text, "The mode active in the source editor is incorrect."); }); } function testTimingsTab() {
--- a/browser/devtools/netmonitor/test/head.js +++ b/browser/devtools/netmonitor/test/head.js @@ -1,16 +1,17 @@ /* Any copyright is dedicated to the Public Domain. 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: promise } = Cu.import("resource://gre/modules/commonjs/sdk/core/promise.js", {}); +let { Task } = Cu.import("resource://gre/modules/Task.jsm", {}); +let { Promise: promise } = Cu.import("resource://gre/modules/Promise.jsm", {}); let { gDevTools } = Cu.import("resource:///modules/devtools/gDevTools.jsm", {}); let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); let TargetFactory = devtools.TargetFactory; let Toolbox = devtools.Toolbox; const EXAMPLE_URL = "http://example.com/browser/browser/devtools/netmonitor/test/"; const SIMPLE_URL = EXAMPLE_URL + "html_simple-test-page.html"; @@ -277,8 +278,25 @@ function verifyRequestItemTarget(aReques } else { ok(!aRequestItem.target.hasAttribute("even"), "Unexpected 'even' attribute for " + aRequestItem.value); ok(aRequestItem.target.hasAttribute("odd"), "Unexpected 'odd' attribute for " + aRequestItem.value); } } } + +/** + * Helper function for waiting for an event to fire before resolving a promise. + * Example: waitFor(aMonitor.panelWin, aMonitor.panelWin.EVENTS.TAB_UPDATED); + * + * @param object subject + * The event emitter object that is being listened to. + * @param string eventName + * The name of the event to listen to. + * @return object + * Returns a promise that resolves upon firing of the event. + */ +function waitFor (subject, eventName) { + let deferred = promise.defer(); + subject.once(eventName, deferred.resolve); + return deferred.promise; +}
--- a/browser/devtools/responsivedesign/responsivedesign.jsm +++ b/browser/devtools/responsivedesign/responsivedesign.jsm @@ -171,17 +171,17 @@ function ResponsiveUI(aWindow, aTab) this.bound_startResizing = this.startResizing.bind(this); this.bound_stopResizing = this.stopResizing.bind(this); this.bound_onDrag = this.onDrag.bind(this); this.bound_onKeypress = this.onKeypress.bind(this); // Events this.tab.addEventListener("TabClose", this); this.tabContainer.addEventListener("TabSelect", this); - this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, false); + this.mainWindow.document.addEventListener("keypress", this.bound_onKeypress, true); this.buildUI(); this.checkMenus(); this.docShell = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebNavigation) .QueryInterface(Ci.nsIDocShell); @@ -271,17 +271,17 @@ ResponsiveUI.prototype = { "max-height: none;" + "min-height: 0;"; this.stack.setAttribute("style", style); if (this.isResizing) this.stopResizing(); // Remove listeners. - this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, false); + this.mainWindow.document.removeEventListener("keypress", this.bound_onKeypress, true); this.menulist.removeEventListener("select", this.bound_presetSelected, true); this.tab.removeEventListener("TabClose", this); this.tabContainer.removeEventListener("TabSelect", this); this.rotatebutton.removeEventListener("command", this.bound_rotate, true); this.screenshotbutton.removeEventListener("command", this.bound_screenshot, true); this.touchbutton.removeEventListener("command", this.bound_touch, true); this.closebutton.removeEventListener("command", this.bound_close, true); this.addbutton.removeEventListener("command", this.bound_addPreset, true);
--- a/browser/devtools/webconsole/hudservice.js +++ b/browser/devtools/webconsole/hudservice.js @@ -331,34 +331,53 @@ WebConsole.prototype = { * by unit tests. The callback takes one argument: the HTTP activity object as * received from the remote Web Console. * * @type function */ get lastFinishedRequestCallback() HUDService.lastFinishedRequest.callback, /** + * Getter for the window that can provide various utilities that the web + * console makes use of, like opening links, managing popups, etc. In + * most cases, this will be |this.browserWindow|, but in some uses (such as + * the Browser Toolbox), there is no browser window, so an alternative window + * hosts the utilities there. + * @type nsIDOMWindow + */ + get chromeUtilsWindow() + { + if (this.browserWindow) { + return this.browserWindow; + } + return this.chromeWindow.top; + }, + + /** * Getter for the xul:popupset that holds any popups we open. * @type nsIDOMElement */ get mainPopupSet() { - return this.browserWindow.document.getElementById("mainPopupSet"); + return this.chromeUtilsWindow.document.getElementById("mainPopupSet"); }, /** * Getter for the output element that holds messages we display. * @type nsIDOMElement */ get outputNode() { return this.ui ? this.ui.outputNode : null; }, - get gViewSourceUtils() this.browserWindow.gViewSourceUtils, + get gViewSourceUtils() + { + return this.chromeUtilsWindow.gViewSourceUtils; + }, /** * Initialize the Web Console instance. * * @return object * A promise for the initialization. */ init: function WC_init() @@ -411,17 +430,17 @@ WebConsole.prototype = { /** * Open a link in a new tab. * * @param string aLink * The URL you want to open in a new tab. */ openLink: function WC_openLink(aLink) { - this.browserWindow.openUILinkIn(aLink, "tab"); + this.chromeUtilsWindow.openUILinkIn(aLink, "tab"); }, /** * Open a link in Firefox's view source. * * @param string aSourceURL * The URL of the file. * @param integer aSourceLine
--- a/browser/locales/en-US/chrome/browser/browser.dtd +++ b/browser/locales/en-US/chrome/browser/browser.dtd @@ -239,20 +239,20 @@ These should match what Safari and other - "Scratchpad" in your locale. You should feel free to find a close - approximation to it or choose a word (or words) that means - "simple discardable text editor". --> <!ENTITY scratchpad.label "Scratchpad"> <!ENTITY scratchpad.accesskey "s"> <!ENTITY scratchpad.keycode "VK_F4"> <!ENTITY scratchpad.keytext "F4"> -<!-- LOCALIZATION NOTE (chromeDebuggerMenu.label): This is the label for the - - application menu item that opens the browser debugger UI in the Tools menu. --> -<!ENTITY chromeDebuggerMenu.label "Browser Debugger"> -<!ENTITY chromeDebuggerMenu.accesskey "e"> +<!-- LOCALIZATION NOTE (browserToolboxMenu.label): This is the label for the + - application menu item that opens the browser toolbox UI in the Tools menu. --> +<!ENTITY browserToolboxMenu.label "Browser Toolbox"> +<!ENTITY browserToolboxMenu.accesskey "e"> <!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar"> <!ENTITY devToolbarMenu.label "Developer Toolbar"> <!ENTITY devToolbarMenu.accesskey "v"> <!ENTITY devAppMgrMenu.label "App Manager"> <!ENTITY devAppMgrMenu.accesskey "a"> <!ENTITY devToolbar.keycode "VK_F2"> <!ENTITY devToolbar.keytext "F2">
--- a/browser/locales/en-US/chrome/browser/places/places.properties +++ b/browser/locales/en-US/chrome/browser/places/places.properties @@ -65,16 +65,19 @@ detailsPane.noItems=No items # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals # #1 number of items # example: 111 items detailsPane.itemsCountLabel=One item;#1 items mostVisitedTitle=Most Visited recentlyBookmarkedTitle=Recently Bookmarked recentTagsTitle=Recent Tags +# LOCALIZATION NOTE (firefoxTouchTitle): this is the name of the folder used +# to store bookmarks created in Metro mode and share bookmarks between Metro +# and Desktop. firefoxTouchTitle=Firefox Touch OrganizerQueryHistory=History OrganizerQueryDownloads=Downloads OrganizerQueryAllBookmarks=All Bookmarks OrganizerQueryTags=Tags # LOCALIZATION NOTE (tagResultLabel) :
--- a/browser/themes/shared/devtools/responsivedesign.inc.css +++ b/browser/themes/shared/devtools/responsivedesign.inc.css @@ -12,16 +12,20 @@ } .browserStack[responsivemode] { box-shadow: 0 0 7px black; } .devtools-responsiveui-toolbar { background: transparent; + /* text color is textColor from dark theme, since no theme is applied to + * the responsive toolbar. + */ + color: hsl(210,30%,85%); margin: 10px 0; padding: 0; box-shadow: none; border-bottom-width: 0; } .devtools-responsiveui-toolbar > menulist, .devtools-responsiveui-toolbar > toolbarbutton {
--- a/mobile/android/base/tests/StringHelper.java +++ b/mobile/android/base/tests/StringHelper.java @@ -43,16 +43,23 @@ class StringHelper { "Open in New Tab", "Open in Private Tab", "Edit", "Remove", "Share", "Add to Home Screen" }; + public static final String[] CONTEXT_MENU_ITEMS_IN_URL_BAR = new String[] { + "Share", + "Copy Address", + "Edit Site Settings", + "Add to Home Screen" + }; + public static final String TITLE_PLACE_HOLDER = "Enter Search or Address"; // Robocop page urls // Note: please use getAbsoluteUrl(String url) on each robocop url to get the correct url public static final String ROBOCOP_BIG_LINK_URL = "/robocop/robocop_big_link.html"; public static final String ROBOCOP_BIG_MAILTO_URL = "/robocop/robocop_big_mailto.html"; public static final String ROBOCOP_BLANK_PAGE_01_URL = "/robocop/robocop_blank_01.html"; public static final String ROBOCOP_BLANK_PAGE_02_URL = "/robocop/robocop_blank_02.html";
--- a/mobile/android/base/tests/testClearPrivateData.java +++ b/mobile/android/base/tests/testClearPrivateData.java @@ -1,48 +1,117 @@ package org.mozilla.gecko.tests; - +import android.view.View; import org.mozilla.gecko.*; import java.util.ArrayList; +/** + * This patch tests the clear private data options: + * - clear history option by: adding and checking that clear private + * data option removes the history items but not the users bookmarks + * - clear site settings and clear saved password by: checking + * each option present in the doorhanger and clearing the settings from + * the URL bar context menu and settings menu + */ + public class testClearPrivateData extends PixelTest { private final int TEST_WAIT_MS = 10000; @Override protected int getTestType() { return TEST_MOCHITEST; } public void testClearPrivateData() { blockForGeckoReady(); clearHistory(); + clearSiteSettings(); + clearPassword(); } private void clearHistory() { + // Loading a page and adding a second one as bookmark to have user made bookmarks and history String blank1 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_01_URL); String blank2 = getAbsoluteUrl(StringHelper.ROBOCOP_BLANK_PAGE_02_URL); - - loadAndPaint(blank1); - waitForText(StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE); - + String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE; + inputAndLoadUrl(blank1); + verifyPageTitle(title); mDatabaseHelper.addOrUpdateMobileBookmark(StringHelper.ROBOCOP_BLANK_PAGE_02_TITLE, blank2); // Checking that the history list is not empty verifyHistoryCount(1); - clearPrivateData(); + + //clear and check for device + checkDevice(title); // Checking that history list is empty verifyHistoryCount(0); // Checking that the user made bookmark is not removed mAsserter.ok(mDatabaseHelper.isBookmark(blank2), "Checking that bookmarks have not been removed", "User made bookmarks were not removed with private data"); } private void verifyHistoryCount(final int expectedCount) { boolean match = waitForTest( new BooleanTest() { public boolean test() { return (mDatabaseHelper.getBrowserDBUrls(DatabaseHelper.BrowserDataType.HISTORY).size() == expectedCount); } }, TEST_WAIT_MS); mAsserter.ok(match, "Checking that the number of history items is correct", String.valueOf(expectedCount) + " history items present in the database"); } + + public void clearSiteSettings() { + String shareStrings[] = {"Share your location with", "Share", "Don't share", "There are no settings to clear"}; + String titleGeolocation = StringHelper.ROBOCOP_GEOLOCATION_TITLE; + String url = getAbsoluteUrl(StringHelper.ROBOCOP_GEOLOCATION_URL); + loadCheckDismiss(shareStrings[1], url, shareStrings[0]); + checkOption(shareStrings[1], "Clear"); + checkOption(shareStrings[3], "Cancel"); + loadCheckDismiss(shareStrings[2], url, shareStrings[0]); + checkOption(shareStrings[2], "Cancel"); + checkDevice(titleGeolocation); + } + + public void clearPassword(){ + String passwordStrings[] = {"Save password", "Save", "Don't save"}; + String title = StringHelper.ROBOCOP_BLANK_PAGE_01_TITLE; + String loginUrl = getAbsoluteUrl(StringHelper.ROBOCOP_LOGIN_URL); + loadCheckDismiss(passwordStrings[1], loginUrl, passwordStrings[0]); + checkOption(passwordStrings[1], "Clear"); + loadCheckDismiss(passwordStrings[2], loginUrl, passwordStrings[0]); + checkDevice(title); + } + + // clear private data and verify the device type because for phone there is an extra back action to exit the settings menu + public void checkDevice(String title) { + clearPrivateData(); + if (mDevice.type.equals("phone")) { + mActions.sendSpecialKey(Actions.SpecialKey.BACK); + mAsserter.ok(waitForText(StringHelper.PRIVACY_SECTION_LABEL), "waiting to perform one back", "one back"); + mActions.sendSpecialKey(Actions.SpecialKey.BACK); + verifyPageTitle(title); + } + else { + mActions.sendSpecialKey(Actions.SpecialKey.BACK); + verifyPageTitle(title); + } + } + + // Load a URL, verify that the doorhanger appears and dismiss it + public void loadCheckDismiss(String option, String url, String message) { + inputAndLoadUrl(url); + waitForText(message); + mAsserter.is(mSolo.searchText(message), true, "Doorhanger:" + message + " has been displayed"); + mSolo.clickOnButton(option); + mAsserter.is(mSolo.searchText(message), false, "Doorhanger:" + message + " has been hidden"); + } + + //Verify if there are settings to be clear if so clear them from the URL bar context menu + public void checkOption(String option, String button) { + final View toolbarView = mSolo.getView("browser_toolbar"); + mSolo.clickLongOnView(toolbarView); + mAsserter.ok(waitForText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]), "Waiting for the pop-up to open", "Pop up was openend"); + mSolo.clickOnText(StringHelper.CONTEXT_MENU_ITEMS_IN_URL_BAR[2]); + mAsserter.ok(waitForText(option), "Verify that the option: " + option + " is in the list", "The option is in the list. There are settings to clear"); + mSolo.clickOnButton(button); + } }
--- a/toolkit/components/places/Database.cpp +++ b/toolkit/components/places/Database.cpp @@ -34,22 +34,25 @@ // Filename of the database. #define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite") // Filename used to backup corrupt databases. #define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt") // Set when the database file was found corrupt by a previous maintenance. #define PREF_FORCE_DATABASE_REPLACEMENT "places.database.replaceOnStartup" +// Set to specify the size of the places database growth increments in kibibytes +#define PREF_GROWTH_INCREMENT_KIB "places.database.growthIncrementKiB" + // Maximum size for the WAL file. It should be small enough since in case of // crashes we could lose all the transactions in the file. But a too small // file could hurt performance. #define DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES 512 -#define BYTES_PER_MEBIBYTE 1048576 +#define BYTES_PER_KIBIBYTE 1024 // Old Sync GUID annotation. #define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid") // Places string bundle, contains internationalized bookmark root names. #define PLACES_BUNDLE "chrome://places/locale/places.properties" // Livemarks annotations. @@ -587,18 +590,23 @@ Database::InitSchema(bool* aDatabaseMigr // mobile devices, limit its size. // Since exceeding the limit will cause a truncate, allow a slightly // larger limit than DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES to reduce the number // of times it is needed. nsAutoCString journalSizePragma("PRAGMA journal_size_limit = "); journalSizePragma.AppendInt(DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES * 3); (void)mMainConn->ExecuteSimpleSQL(journalSizePragma); - // Grow places in 10MiB increments to limit fragmentation on disk. - (void)mMainConn->SetGrowthIncrement(10 * BYTES_PER_MEBIBYTE, EmptyCString()); + // Grow places in |growthIncrementKiB| increments to limit fragmentation on disk. + // By default, it's 10 MB. + int32_t growthIncrementKiB = + Preferences::GetInt(PREF_GROWTH_INCREMENT_KIB, 10 * BYTES_PER_KIBIBYTE * BYTES_PER_KIBIBYTE); + if (growthIncrementKiB > 0) { + (void)mMainConn->SetGrowthIncrement(growthIncrementKiB * BYTES_PER_KIBIBYTE, EmptyCString()); + } // We use our functions during migration, so initialize them now. rv = InitFunctions(); NS_ENSURE_SUCCESS(rv, rv); // Get the database schema version. int32_t currentSchemaVersion; rv = mMainConn->GetSchemaVersion(¤tSchemaVersion);
--- a/toolkit/devtools/Loader.jsm +++ b/toolkit/devtools/Loader.jsm @@ -30,16 +30,17 @@ this.EXPORTED_SYMBOLS = ["DevToolsLoader /** * Providers are different strategies for loading the devtools. */ let loaderGlobals = { btoa: btoa, console: console, _Iterator: Iterator, + ChromeWorker: ChromeWorker, loader: { lazyGetter: XPCOMUtils.defineLazyGetter.bind(XPCOMUtils), lazyImporter: XPCOMUtils.defineLazyModuleGetter.bind(XPCOMUtils), lazyServiceGetter: XPCOMUtils.defineLazyServiceGetter.bind(XPCOMUtils) } }; // Used when the tools should be loaded from the Firefox package itself (the default)
--- a/toolkit/devtools/server/actors/inspector.js +++ b/toolkit/devtools/server/actors/inspector.js @@ -76,20 +76,22 @@ HELPER_SHEET += ":-moz-devtools-highligh Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/devtools/LayoutHelpers.jsm"); loader.lazyGetter(this, "DOMParser", function() { return Cc["@mozilla.org/xmlextras/domparser;1"].createInstance(Ci.nsIDOMParser); }); exports.register = function(handle) { + handle.addGlobalActor(InspectorActor, "inspectorActor"); handle.addTabActor(InspectorActor, "inspectorActor"); }; exports.unregister = function(handle) { + handle.removeGlobalActor(InspectorActor); handle.removeTabActor(InspectorActor); }; // XXX: A poor man's makeInfallible until we move it out of transport.js // Which should be very soon. function makeInfallible(handler) { return function(...args) { try {
--- a/toolkit/devtools/server/actors/root.js +++ b/toolkit/devtools/server/actors/root.js @@ -187,16 +187,21 @@ RootActor.prototype = { get isRootActor() true, /** * The (chrome) window, for use by child actors */ get window() Services.wm.getMostRecentWindow(DebuggerServer.chromeWindowType), /** + * URL of the chrome window. + */ + get url() { return this.window ? this.window.document.location.href : null; }, + + /** * Getter for the best nsIWebProgress for to watching this window. */ get webProgress() { return this.window .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIDocShell) .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebProgress); @@ -248,17 +253,21 @@ RootActor.prototype = { selected = tabActorList.length; } tabActor.parentID = this.actorID; newActorPool.addActor(tabActor); tabActorList.push(tabActor); } /* DebuggerServer.addGlobalActor support: create actors. */ - this._createExtraActors(this._parameters.globalActorFactories, newActorPool); + if (!this._globalActorPool) { + this._globalActorPool = new ActorPool(this.conn); + this._createExtraActors(this._parameters.globalActorFactories, this._globalActorPool); + this.conn.addActorPool(this._globalActorPool); + } /* * Drop the old actorID -> actor map. Actors that still mattered were * added to the new map; others will go away. */ if (this._tabActorPool) { this.conn.removeActorPool(this._tabActorPool); } @@ -266,16 +275,21 @@ RootActor.prototype = { this.conn.addActorPool(this._tabActorPool); let reply = { "from": this.actorID, "selected": selected || 0, "tabs": [actor.form() for (actor of tabActorList)], }; + /* If a root window is accessible, include its URL. */ + if (this.url) { + reply.url = this.url; + } + /* DebuggerServer.addGlobalActor support: name actors in 'listTabs' reply. */ this._appendExtraActors(reply); /* * Now that we're actually going to report the contents of tabList to * the client, we're responsible for letting the client know if it * changes. */
--- a/toolkit/devtools/server/actors/styleeditor.js +++ b/toolkit/devtools/server/actors/styleeditor.js @@ -701,12 +701,13 @@ StyleSheetActor.prototype = { StyleSheetActor.prototype.requestTypes = { "toggleDisabled": StyleSheetActor.prototype.onToggleDisabled, "fetchSource": StyleSheetActor.prototype.onFetchSource, "update": StyleSheetActor.prototype.onUpdate }; DebuggerServer.addTabActor(StyleEditorActor, "styleEditorActor"); +DebuggerServer.addGlobalActor(StyleEditorActor, "styleEditorActor"); XPCOMUtils.defineLazyGetter(this, "DOMUtils", function () { return Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils); });
--- a/toolkit/devtools/server/dbg-server.jsm +++ b/toolkit/devtools/server/dbg-server.jsm @@ -10,36 +10,16 @@ * shield it from the debuggee. This way, when debugging chrome globals, * debugger and debuggee will be in separate compartments. */ const Ci = Components.interfaces; const Cc = Components.classes; const Cu = Components.utils; +const { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); + this.EXPORTED_SYMBOLS = ["DebuggerServer", "ActorPool"]; -var loadSubScript = - "function loadSubScript(aURL)\n" + - "{\n" + - "const Ci = Components.interfaces;\n" + - "const Cc = Components.classes;\n" + - " try {\n" + - " let loader = Cc[\"@mozilla.org/moz/jssubscript-loader;1\"]\n" + - " .getService(Ci.mozIJSSubScriptLoader);\n" + - " loader.loadSubScript(aURL, this);\n" + - " } catch(e) {\n" + - " dump(\"Error loading: \" + aURL + \": \" + e + \" - \" + e.stack + \"\\n\");\n" + - " throw e;\n" + - " }\n" + - "}"; +let server = devtools.require("devtools/server/main"); -// Load the debugging server in a sandbox with its own compartment. -var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"] - .createInstance(Ci.nsIPrincipal); - -var gGlobal = Cu.Sandbox(systemPrincipal); -gGlobal.ChromeWorker = ChromeWorker; -Cu.evalInSandbox(loadSubScript, gGlobal, "1.8"); -gGlobal.loadSubScript("resource://gre/modules/devtools/server/main.js"); - -this.DebuggerServer = gGlobal.DebuggerServer; -this.ActorPool = gGlobal.ActorPool; +this.DebuggerServer = server.DebuggerServer; +this.ActorPool = server.ActorPool;
--- a/toolkit/devtools/server/main.js +++ b/toolkit/devtools/server/main.js @@ -5,46 +5,32 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; /** * Toolkit glue for the remote debugging protocol, loaded into the * debugging global. */ -// |this.require| is used to test if this file was loaded via the devtools -// loader (as it is in DebuggerProcess.jsm) or via loadSubScript (as it is from -// dbg-server.jsm). Note that testing |require| is not safe in either -// situation, as it causes a ReferenceError. -var Ci, Cc, CC, Cu, Cr, Components; -if (this.require) { - ({ Ci, Cc, CC, Cu, Cr, components: Components }) = require("chrome"); -} else { - ({ - interfaces: Ci, - classes: Cc, - Constructor: CC, - utils: Cu, - results: Cr - }) = Components; -} - -// On B2G, if |this.require| is undefined at this point, it remains undefined -// later on when |DebuggerServer.registerModule| is called. On desktop (and -// perhaps other places), if |this.require| starts out undefined, it ends up -// being set to some native code by the time we get to |registerModule|. Here -// we perform a test early on, and then cache the correct require function for -// later use. -var localRequire; -if (this.require) { - localRequire = id => require(id); -} else { - let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}); - localRequire = id => devtools.require(id); -} +// Until all Debugger server code is converted to SDK modules, +// imports Components.* alias from chrome module. +var { Ci, Cc, CC, Cu, Cr } = require("chrome"); +// On B2G, `this` != Global scope, so `Ci` won't be binded on `this` +// (i.e. this.Ci is undefined) Then later, when using loadSubScript, +// Ci,... won't be defined for sub scripts. +this.Ci = Ci; +this.Cc = Cc; +this.CC = CC; +this.Cu = Cu; +this.Cr = Cr; +// Overload `Components` to prevent SDK loader exception on Components +// object usage +Object.defineProperty(this, "Components", { + get: function () require("chrome").components +}); const DBG_STRINGS_URI = "chrome://global/locale/devtools/debugger.properties"; const nsFile = CC("@mozilla.org/file/local;1", "nsIFile", "initWithPath"); Cu.import("resource://gre/modules/reflect.jsm"); Cu.import("resource://gre/modules/devtools/DevToolsUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); @@ -63,36 +49,40 @@ function loadSubScript(aURL) } catch(e) { let errorStr = "Error loading: " + aURL + ": " + e + " - " + e.stack + "\n"; dump(errorStr); Cu.reportError(errorStr); throw e; } } -let loaderRequire = this.require; -this.require = null; -loadSubScript.call(this, "resource://gre/modules/commonjs/sdk/core/promise.js"); -this.require = loaderRequire; +let {defer, resolve, reject, promised, all} = require("sdk/core/promise"); +this.defer = defer; +this.resolve = resolve; +this.reject = reject; +this.promised = promised; +this.all = all; Cu.import("resource://gre/modules/devtools/SourceMap.jsm"); loadSubScript.call(this, "resource://gre/modules/devtools/DevToolsUtils.js"); function dumpn(str) { if (wantLogging) { dump("DBG-SERVER: " + str + "\n"); } } +this.dumpn = dumpn; function dbg_assert(cond, e) { if (!cond) { return e; } } +this.dbg_assert = dbg_assert; loadSubScript.call(this, "resource://gre/modules/devtools/server/transport.js"); // XPCOM constructors const ServerSocket = CC("@mozilla.org/network/server-socket;1", "nsIServerSocket", "initSpecialConnection"); const UnixDomainServerSocket = CC("@mozilla.org/network/server-socket;1", @@ -319,17 +309,17 @@ var DebuggerServer = { * 'register' and 'unregister' functions. */ registerModule: function(id) { if (id in gRegisteredModules) { throw new Error("Tried to register a module twice: " + id + "\n"); } let moduleAPI = ModuleAPI(); - let mod = localRequire(id); + let mod = require(id); mod.register(moduleAPI); gRegisteredModules[id] = { module: mod, api: moduleAPI }; }, /** * Returns true if a module id has been registered. */ isModuleRegistered: function(id) { @@ -683,16 +673,18 @@ var DebuggerServer = { } } } }; if (this.exports) { exports.DebuggerServer = DebuggerServer; } +// Needed on B2G (See header note) +this.DebuggerServer = DebuggerServer; /** * Construct an ActorPool. * * ActorPools are actorID -> actor mapping and storage. These are * used to accumulate and quickly dispose of groups of actors that * share a lifetime. */ @@ -701,16 +693,18 @@ function ActorPool(aConnection) this.conn = aConnection; this._cleanups = {}; this._actors = {}; } if (this.exports) { exports.ActorPool = ActorPool; } +// Needed on B2G (See header note) +this.ActorPool = ActorPool; ActorPool.prototype = { /** * Add an actor to the actor pool. If the actor doesn't have an ID, * allocate one from the connection. * * @param aActor object * The actor implementation. If the object has a
--- a/toolkit/devtools/server/tests/unit/test_add_actors.js +++ b/toolkit/devtools/server/tests/unit/test_add_actors.js @@ -22,16 +22,17 @@ function run_test() DebuggerServer.addActors("resource://test/post_init_global_actors.js"); DebuggerServer.addActors("resource://test/post_init_tab_actors.js"); add_test(init); add_test(test_pre_init_global_actor); add_test(test_pre_init_tab_actor); add_test(test_post_init_global_actor); add_test(test_post_init_tab_actor); + add_test(test_stable_global_actor_instances); add_test(close_client); run_next_test(); } function init() { gClient = new DebuggerClient(DebuggerServer.connectPipe()); gClient.connect(function onConnect() { @@ -77,11 +78,30 @@ function test_post_init_tab_actor() gClient.request({ to: gActors.postInitTabActor, type: "ping" }, function onResponse(aResponse) { do_check_eq(aResponse.message, "pong"); run_next_test(); } ); } +// Get the object object, from the server side, for a given actor ID +function getActorInstance(connID, actorID) { + return DebuggerServer._connections[connID].getActor(actorID); +} + +function test_stable_global_actor_instances() +{ + // Consider that there is only one connection, + // and the first one is ours + let connID = Object.keys(DebuggerServer._connections)[0]; + let postInitGlobalActor = getActorInstance(connID, gActors.postInitGlobalActor); + let preInitGlobalActor = getActorInstance(connID, gActors.preInitGlobalActor); + gClient.listTabs(function onListTabs(aResponse) { + do_check_eq(postInitGlobalActor, getActorInstance(connID, aResponse.postInitGlobalActor)); + do_check_eq(preInitGlobalActor, getActorInstance(connID, aResponse.preInitGlobalActor)); + run_next_test(); + }); +} + function close_client() { gClient.close(() => run_next_test()); }
--- a/webapprt/prefs.js +++ b/webapprt/prefs.js @@ -78,8 +78,9 @@ pref("devtools.debugger.force-local", tr pref("dom.ipc.plugins.enabled.i386", false); pref("dom.ipc.plugins.enabled.i386.flash player.plugin", true); // x86_64 ipc preferences pref("dom.ipc.plugins.enabled.x86_64", true); #else pref("dom.ipc.plugins.enabled", true); #endif +pref("places.database.growthIncrementKiB", 0);