author | Gabriel Luong <gabriel.luong@gmail.com> |
Thu, 05 Apr 2018 14:21:13 -0400 | |
changeset 411943 | 8b549261f40d26868f8f26d7960fe3a79cbc5aea |
parent 411942 | 620a4eba9389d4cfebb8b45c913d7a13921dd49a |
child 411944 | 8cbc541afed7c033595841b0e61811507c66d4c4 |
push id | 101788 |
push user | gabriel.luong@gmail.com |
push date | Thu, 05 Apr 2018 18:21:41 +0000 |
treeherder | mozilla-inbound@8cbc541afed7 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | pbro |
bugs | 1433611 |
milestone | 61.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/devtools/client/inspector/grids/grid-inspector.js +++ b/devtools/client/inspector/grids/grid-inspector.js @@ -78,17 +78,23 @@ class GridInspector { * Initializes the grid inspector by fetching the LayoutFront from the walker, loading * the highlighter settings and initalizing the SwatchColorPicker instance. */ async init() { if (!this.inspector) { return; } - this.layoutInspector = await this.inspector.walker.getLayoutInspector(); + try { + this.layoutInspector = await this.inspector.walker.getLayoutInspector(); + } catch (e) { + // This call might fail if called asynchrously after the toolbox is finished + // closing. + return; + } this.loadHighlighterSettings(); // Create a shared SwatchColorPicker instance to be reused by all GridItem components. this.swatchColorPickerTooltip = new SwatchColorPickerTooltip( this.inspector.toolbox.doc, this.inspector, {
--- a/devtools/client/inspector/inspector.js +++ b/devtools/client/inspector/inspector.js @@ -7,16 +7,17 @@ /* global window, BrowserLoader */ "use strict"; const Services = require("Services"); const promise = require("promise"); const EventEmitter = require("devtools/shared/event-emitter"); const {executeSoon} = require("devtools/shared/DevToolsUtils"); +const {Toolbox} = require("devtools/client/framework/toolbox"); const {PrefObserver} = require("devtools/client/shared/prefs"); const Telemetry = require("devtools/client/shared/telemetry"); const HighlightersOverlay = require("devtools/client/inspector/shared/highlighters-overlay"); const ReflowTracker = require("devtools/client/inspector/shared/reflow-tracker"); const Store = require("devtools/client/inspector/store"); const InspectorStyleChangeTracker = require("devtools/client/inspector/shared/style-change-tracker"); // Use privileged promise in panel documents to prevent having them to freeze @@ -33,30 +34,34 @@ loader.lazyRequireGetter(this, "nodeCons loader.lazyRequireGetter(this, "Menu", "devtools/client/framework/menu"); loader.lazyRequireGetter(this, "MenuItem", "devtools/client/framework/menu-item"); loader.lazyRequireGetter(this, "ExtensionSidebar", "devtools/client/inspector/extensions/extension-sidebar"); loader.lazyRequireGetter(this, "CommandUtils", "devtools/client/shared/developer-toolbar", true); loader.lazyRequireGetter(this, "clipboardHelper", "devtools/shared/platform/clipboard"); const {LocalizationHelper, localizeMarkup} = require("devtools/shared/l10n"); const INSPECTOR_L10N = - new LocalizationHelper("devtools/client/locales/inspector.properties"); + new LocalizationHelper("devtools/client/locales/inspector.properties"); loader.lazyGetter(this, "TOOLBOX_L10N", function() { return new LocalizationHelper("devtools/client/locales/toolbox.properties"); }); // Sidebar dimensions const INITIAL_SIDEBAR_SIZE = 350; -// If the toolbox width is smaller than given amount of pixels, -// the sidebar automatically switches from 'landscape' to 'portrait' mode. -const PORTRAIT_MODE_WIDTH = 700; +// If the toolbox's width is smaller than the given amount of pixels, the sidebar +// automatically switches from 'landscape/horizontal' to 'portrait/vertical' mode. +const PORTRAIT_MODE_WIDTH_THRESHOLD = 700; +// If the toolbox's width docked to the side is smaller than the given amount of pixels, +// the sidebar automatically switches from 'landscape/horizontal' to 'portrait/vertical' +// mode. +const SIDE_PORTAIT_MODE_WIDTH_THRESHOLD = 1000; -const SHOW_SPLIT_SIDEBAR_TOGGLE_PREF = "devtools.inspector.split-sidebar-toggle"; -const SPLIT_RULE_VIEW_PREF = "devtools.inspector.split-rule-enabled"; +const SHOW_THREE_PANE_TOGGLE_PREF = "devtools.inspector.three-pane-toggle"; +const THREE_PANE_ENABLED_PREF = "devtools.inspector.three-pane-enabled"; /** * Represents an open instance of the Inspector for a tab. * The inspector controls the breadcrumbs, the markup view, and the sidebar * (computed view, rule view, font view and animation inspector). * * Events: * - ready @@ -108,19 +113,18 @@ function Inspector(toolbox) { this.styleChangeTracker = new InspectorStyleChangeTracker(this); this.store = Store(); this.telemetry = new Telemetry(); // Store the URL of the target page prior to navigation in order to ensure // telemetry counts in the Grid Inspector are not double counted on reload. this.previousURL = this.target.url; - this.showSplitSidebarToggle = Services.prefs.getBoolPref( - SHOW_SPLIT_SIDEBAR_TOGGLE_PREF); - this.isSplitRuleViewEnabled = Services.prefs.getBoolPref(SPLIT_RULE_VIEW_PREF); + this.show3PaneToggle = Services.prefs.getBoolPref(SHOW_THREE_PANE_TOGGLE_PREF); + this.is3PaneModeEnabled = Services.prefs.getBoolPref(THREE_PANE_ENABLED_PREF); this.nodeMenuTriggerInfo = null; this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(this); this._onContextMenu = this._onContextMenu.bind(this); this._onBeforeNavigate = this._onBeforeNavigate.bind(this); this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this); this._updateSearchResultsLabel = this._updateSearchResultsLabel.bind(this); @@ -450,17 +454,19 @@ Inspector.prototype = { /** * Check if the inspector should use the landscape mode. * * @return {Boolean} true if the inspector should be in landscape mode. */ useLandscapeMode: function() { let { clientWidth } = this.panelDoc.getElementById("inspector-splitter-box"); - return clientWidth > PORTRAIT_MODE_WIDTH; + return this.is3PaneModeEnabled && this.toolbox.hostType == Toolbox.HostType.SIDE ? + clientWidth > SIDE_PORTAIT_MODE_WIDTH_THRESHOLD : + clientWidth > PORTRAIT_MODE_WIDTH_THRESHOLD; }, /** * Build Splitter located between the main and side area of * the Inspector panel. */ setupSplitter: function() { let SplitBox = this.React.createFactory(this.browserRequire( @@ -477,18 +483,18 @@ Inspector.prototype = { endPanelControl: true, startPanel: this.InspectorTabPanel({ id: "inspector-main-content" }), endPanel: SplitBox({ initialWidth: splitSidebarWidth, minSize: 10, maxSize: "80%", - splitterSize: this.isSplitRuleViewEnabled ? 1 : 0, - endPanelControl: false, + splitterSize: this.is3PaneModeEnabled ? 1 : 0, + endPanelControl: this.is3PaneModeEnabled, startPanel: this.InspectorTabPanel({ id: "inspector-rules-container" }), endPanel: this.InspectorTabPanel({ id: "inspector-sidebar-container" }), ref: splitbox => { this.sidebarSplitBox = splitbox; @@ -536,17 +542,17 @@ Inspector.prototype = { height = Services.prefs.getIntPref("devtools.toolsidebar-height.inspector"); splitSidebarWidth = Services.prefs.getIntPref( "devtools.toolsidebar-width.inspector.splitsidebar"); } catch (e) { // Set width and height of the splitter. Only one // value is really useful at a time depending on the current // orientation (vertical/horizontal). // Having both is supported by the splitter component. - width = this.isSplitRuleViewEnabled ? + width = this.is3PaneModeEnabled ? INITIAL_SIDEBAR_SIZE * 2 : INITIAL_SIDEBAR_SIZE; height = INITIAL_SIDEBAR_SIZE; splitSidebarWidth = INITIAL_SIDEBAR_SIZE; } return { width, height, splitSidebarWidth }; }, @@ -576,72 +582,131 @@ Inspector.prototype = { onSidebarShown: function() { let { width, height, splitSidebarWidth } = this.getSidebarSize(); this.splitBox.setState({ width, height }); this.sidebarSplitBox.setState({ width: splitSidebarWidth }); }, async onSidebarToggle() { - this.isSplitRuleViewEnabled = !this.isSplitRuleViewEnabled; - Services.prefs.setBoolPref(SPLIT_RULE_VIEW_PREF, this.isSplitRuleViewEnabled); + this.is3PaneModeEnabled = !this.is3PaneModeEnabled; + Services.prefs.setBoolPref(THREE_PANE_ENABLED_PREF, this.is3PaneModeEnabled); await this.setupToolbar(); await this.addRuleView(); }, /** - * Adds the rule view to the main or split sidebar depending on whether or not it is - * split view mode. The default tab specifies whether or not the rule view should be - * selected. The defaultTab defaults to the rule view when the rule view is being merged - * back into the sidebar from the split sidebar. Otherwise, we specify the default tab - * when handling the sidebar setup. + * Adds the rule view to the middle (in landscape/horizontal mode) or bottom-left panel + * (in portrait/vertical mode) or inspector sidebar depending on whether or not it is 3 + * pane mode. The default tab specifies whether or not the rule view should be selected. + * The defaultTab defaults to the rule view when reverting to the 2 pane mode and the + * rule view is being merged back into the inspector sidebar from middle/bottom-left + * panel. Otherwise, we specify the default tab when handling the sidebar setup. * * @params {String} defaultTab * Thie id of the default tab for the sidebar. */ async addRuleView(defaultTab = "ruleview") { - let ruleViewSidebar = this.sidebarSplitBox.startPanelContainer; + const ruleViewSidebar = this.sidebarSplitBox.startPanelContainer; + const toolboxWidth = + this.panelDoc.getElementById("inspector-splitter-box").clientWidth; - if (this.isSplitRuleViewEnabled) { - // Removes the rule view from the main sidebar and adds the rule view to the split - // sidebar. + if (this.is3PaneModeEnabled) { + // Convert to 3 pane mode by removing the rule view from the inspector sidebar + // and adding the rule view to the middle (in landscape/horizontal mode) or + // bottom-left (in portrait/vertical mode) panel. + ruleViewSidebar.style.display = "block"; - // Show the splitter inside the sidebar split box. - this.sidebarSplitBox.setState({ splitterSize: 1 }); + // Get the inspector sidebar's (right panel in horizontal mode or bottom panel in + // vertical mode) width. + const sidebarWidth = this.splitBox.state.width; + // This variable represents the width of the right panel in horizontal mode or + // bottom-right panel in vertical mode width in 3 pane mode. + let sidebarSplitboxWidth; + + if (this.useLandscapeMode()) { + // Whether or not doubling the inspector sidebar's (right panel in horizontal mode + // or bottom panel in vertical mode) width will be bigger than half of the + // toolbox's width. + const canDoubleSidebarWidth = (sidebarWidth * 2) < (toolboxWidth / 2); + + // Resize the main split box's end panel that contains the middle and right panel. + // Attempts to resize the main split box's end panel to be double the size of the + // existing sidebar's width when switching to 3 pane mode. However, if the middle + // and right panel's width together is greater than half of the toolbox's width, + // split all 3 panels to be equally sized by resizing the end panel to be 2/3 of + // the current toolbox's width. + this.splitBox.setState({ + width: canDoubleSidebarWidth ? sidebarWidth * 2 : toolboxWidth * 2 / 3, + }); + + // In landscape/horizontal mode, set the right panel back to its original + // inspector sidebar width if we can double the sidebar width. Otherwise, set + // the width of the right panel to be 1/3 of the toolbox's width since all 3 + // panels will be equally sized. + sidebarSplitboxWidth = canDoubleSidebarWidth ? sidebarWidth : toolboxWidth / 3; + } else { + // In portrait/vertical mode, set the bottom-right panel to be 1/2 of the + // toolbox's width. + sidebarSplitboxWidth = toolboxWidth / 2; + } + + // Show the splitter inside the sidebar split box. Sets the width of the inspector + // sidebar and specify that the end (right in horizontal or bottom-right in + // vertical) panel of the sidebar split box should be controlled when resizing. + this.sidebarSplitBox.setState({ + endPanelControl: true, + splitterSize: 1, + width: sidebarSplitboxWidth, + }); // Force the rule view panel creation by calling getPanel this.getPanel("ruleview"); await this.sidebar.removeTab("ruleview"); this.ruleViewSideBar.addExistingTab( "ruleview", INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"), true); this.ruleViewSideBar.show("ruleview"); } else { - // Removes the rule view from the split sidebar and adds the rule view to the main - // sidebar. + // Removes the rule view from the 3 pane mode and adds the rule view to the main + // inspector sidebar. + ruleViewSidebar.style.display = "none"; - // Hide the splitter to prevent any drag events in the sidebar split box. - this.sidebarSplitBox.setState({ splitterSize: 0 }); + // Set the width of the split box (right panel in horziontal mode and bottom panel + // in vertical mode) to be the width of the inspector sidebar. + this.splitBox.setState({ + width: this.useLandscapeMode() ? this.sidebarSplitBox.state.width : toolboxWidth, + }); + + // Hide the splitter to prevent any drag events in the sidebar split box and + // specify that the end (right panel in horziontal mode or bottom panel in vertical + // mode) panel should be uncontrolled when resizing. + this.sidebarSplitBox.setState({ + endPanelControl: false, + splitterSize: 0, + }); this.ruleViewSideBar.hide(); await this.ruleViewSideBar.removeTab("ruleview"); this.sidebar.addExistingTab( "ruleview", INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"), defaultTab == "ruleview", 0); } + + this.emit("ruleview-added"); }, /** * Lazily get and create panel instances displayed in the sidebar */ getPanel: function(id) { if (this._panels.has(id)) { return this._panels.get(id); @@ -673,19 +738,19 @@ Inspector.prototype = { /** * Build the sidebar. */ async setupSidebar() { let sidebar = this.panelDoc.getElementById("inspector-sidebar"); let options = { showAllTabsMenu: true }; - if (this.showSplitSidebarToggle) { + if (this.show3PaneToggle) { options.sidebarToggleButton = { - collapsed: !this.isSplitRuleViewEnabled, + collapsed: !this.is3PaneModeEnabled, collapsePaneTitle: INSPECTOR_L10N.getStr("inspector.hideSplitRulesView"), expandPaneTitle: INSPECTOR_L10N.getStr("inspector.showSplitRulesView"), onClick: this.onSidebarToggle, }; } this.sidebar = new ToolSidebar(sidebar, this, "inspector", options); @@ -693,27 +758,27 @@ Inspector.prototype = { this.ruleViewSideBar = new ToolSidebar(ruleSideBar, this, "inspector", { hideTabstripe: true }); this.sidebar.on("select", this.onSidebarSelect); let defaultTab = Services.prefs.getCharPref("devtools.inspector.activeSidebar"); - if (this.isSplitRuleViewEnabled && defaultTab === "ruleview") { + if (this.is3PaneModeEnabled && defaultTab === "ruleview") { defaultTab = "computedview"; } // Append all side panels await this.addRuleView(defaultTab); // If the 3 Pane Inspector feature is disabled, use the old order: // Rules, Computed, Layout, etc. - if (!this.showSplitSidebarToggle) { + if (!this.show3PaneToggle) { this.sidebar.addExistingTab( "computedview", INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"), defaultTab == "computedview"); } // Inject a lazy loaded react tab by exposing a fake React object // with a lazy defined Tab thanks to `panel` being a function @@ -736,17 +801,17 @@ Inspector.prototype = { return this.layoutview.provider; } }, defaultTab == layoutId); // If the 3 Pane Inspector feature is enabled, use the new order: // Rules, Layout, Computed, etc. - if (this.showSplitSidebarToggle) { + if (this.show3PaneToggle) { this.sidebar.addExistingTab( "computedview", INSPECTOR_L10N.getStr("inspector.sidebar.computedViewTitle"), defaultTab == "computedview"); } if (Services.prefs.getBoolPref("devtools.changesview.enabled")) { // Inject a lazy loaded react tab by exposing a fake React object @@ -1300,24 +1365,25 @@ Inspector.prototype = { this.prefsObserver.destroy(); this.reflowTracker.destroy(); this.styleChangeTracker.destroy(); this.search.destroy(); this._toolbox = null; this.breadcrumbs = null; this.highlighters = null; - this.isSplitRuleViewEnabled = null; + this.is3PaneModeEnabled = null; this.panelDoc = null; this.panelWin.inspector = null; this.panelWin = null; this.prefsObserver = null; this.resultsLength = null; this.search = null; this.searchBox = null; + this.show3PaneToggle = null; this.sidebar = null; this.store = null; this.target = null; this._panelDestroyer = promise.all([ cssPropertiesDestroyer, markupDestroyer, sidebarDestroyer,
--- a/devtools/client/inspector/test/browser.ini +++ b/devtools/client/inspector/test/browser.ini @@ -156,16 +156,20 @@ skip-if = (os == 'linux' && bits == 32 & subsuite = clipboard skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32 debug devtools for timeouts [browser_inspector_menu-04-use-in-console.js] [browser_inspector_menu-05-attribute-items.js] [browser_inspector_menu-06-other.js] [browser_inspector_navigation.js] [browser_inspector_navigate_to_errors.js] [browser_inspector_open_on_neterror.js] +[browser_inspector_pane-toggle-01.js] +[browser_inspector_pane-toggle-02.js] +[browser_inspector_pane-toggle-03.js] +[browser_inspector_pane-toggle-04.js] [browser_inspector_picker-stop-on-destroy.js] [browser_inspector_picker-stop-on-tool-change.js] [browser_inspector_portrait_mode.js] [browser_inspector_pseudoclass-lock.js] [browser_inspector_pseudoclass-menu.js] [browser_inspector_reload-01.js] [browser_inspector_reload-02.js] [browser_inspector_remove-iframe-during-load.js]
new file mode 100644 --- /dev/null +++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-01.js @@ -0,0 +1,28 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the inspector panel has a 3 pane toggle button, and that +// this button is visible both in BOTTOM and SIDE hosts. + +add_task(async function() { + await pushPref("devtools.inspector.three-pane-toggle", true); + + info("Open the inspector in a bottom toolbox host"); + const { inspector, toolbox } = await openInspectorForURL("about:blank", "bottom"); + + const button = inspector.panelDoc.querySelector(".sidebar-toggle"); + ok(button, "The toggle button exists in the DOM"); + ok(button.getAttribute("title"), "The title tooltip has initial state"); + ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state"); + ok(!!button.getClientRects().length, "The button is visible"); + + info("Switch the host to side type"); + await toolbox.switchHost("side"); + + ok(!!button.getClientRects().length, "The button is still visible"); + ok(button.classList.contains("pane-collapsed"), + "The button is still in collapsed state"); +});
new file mode 100644 --- /dev/null +++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-02.js @@ -0,0 +1,49 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the 3 pane toggle button can toggle on and off the inspector's 3 pane mode, +// and the 3 panes rendered are all of equal widths in the BOTTOM host. + +add_task(async function() { + await pushPref("devtools.inspector.three-pane-toggle", true); + + const { inspector } = await openInspectorForURL("about:blank"); + const { panelDoc: doc } = inspector; + const button = doc.querySelector(".sidebar-toggle"); + const ruleViewSidebar = inspector.sidebarSplitBox.startPanelContainer; + const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth; + + ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state"); + + info("Click on the toggle button to toggle ON 3 pane inspector"); + let onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the state of the 3 pane inspector"); + let sidebarWidth = inspector.splitBox.state.width; + let sidebarSplitBoxWidth = inspector.sidebarSplitBox.state.width; + ok(!button.classList.contains("pane-collapsed"), "The button is in expanded state"); + ok(doc.getElementById("ruleview-panel"), "The rule view panel exist"); + is(inspector.sidebar.getCurrentTabID(), "layoutview", + "Layout view is shown in the sidebar"); + is(ruleViewSidebar.style.display, "block", "The split rule view sidebar is displayed"); + is(sidebarWidth, toolboxWidth * 2 / 3, "Got correct main split box width"); + is(sidebarSplitBoxWidth, toolboxWidth / 3, "Got correct sidebar split box width"); + + info("Click on the toggle button to toggle OFF the 3 pane inspector"); + onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the state of the 2 pane inspector"); + sidebarWidth = inspector.splitBox.state.width; + ok(button.classList.contains("pane-collapsed"), "The button is in collapsed state"); + is(inspector.sidebar.getCurrentTabID(), "ruleview", + "Rule view is shown in the sidebar"); + is(ruleViewSidebar.style.display, "none", "The split rule view sidebar is hidden"); + is(sidebarWidth, sidebarSplitBoxWidth, "Got correct sidebar width"); +});
new file mode 100644 --- /dev/null +++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-03.js @@ -0,0 +1,47 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the 3 pane inspector toggle can render the middle and right panels of equal +// sizes when the original sidebar can be doubled in width and be smaller than half the +// toolbox's width in the BOTTOM host. + +const SIDEBAR_WIDTH = 200; + +add_task(async function() { + await pushPref("devtools.inspector.three-pane-toggle", true); + + const { inspector } = await openInspectorForURL("about:blank"); + const { panelDoc: doc } = inspector; + const button = doc.querySelector(".sidebar-toggle"); + const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth; + + if (toolboxWidth < 600) { + ok(true, "Can't run the full test because the toolbox width is too small."); + } else { + info("Set the sidebar width to 200px"); + inspector.splitBox.setState({ width: SIDEBAR_WIDTH }); + + info("Click on the toggle button to toggle ON 3 pane inspector"); + let onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the sizes of the 3 pane inspector"); + let sidebarWidth = inspector.splitBox.state.width; + let sidebarSplitBoxWidth = inspector.sidebarSplitBox.state.width; + is(sidebarWidth, SIDEBAR_WIDTH * 2, "Got correct main split box width"); + is(sidebarSplitBoxWidth, SIDEBAR_WIDTH, "Got correct sidebar split box width"); + + info("Click on the toggle button to toggle OFF the 3 pane inspector"); + onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the sidebar size of the 2 pane inspector"); + sidebarWidth = inspector.splitBox.state.width; + is(sidebarWidth, SIDEBAR_WIDTH, "Got correct sidebar width"); + } +});
new file mode 100644 --- /dev/null +++ b/devtools/client/inspector/test/browser_inspector_pane-toggle-04.js @@ -0,0 +1,39 @@ +/* vim: set ft=javascript ts=2 et sw=2 tw=80: */ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +// Tests that the 3 pane inspector toggle button can render the bottom-left and +// bottom-right panels of equal sizes in the SIDE host. + +add_task(async function() { + await pushPref("devtools.inspector.three-pane-toggle", true); + + const { inspector, toolbox } = await openInspectorForURL("about:blank"); + const { panelDoc: doc } = inspector; + + info("Switch the host to side type"); + await toolbox.switchHost("side"); + + const button = doc.querySelector(".sidebar-toggle"); + const toolboxWidth = doc.getElementById("inspector-splitter-box").clientWidth; + + info("Click on the toggle button to toggle ON 3 pane inspector"); + let onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the sizes of the 3 pane inspector"); + let sidebarSplitBoxWidth = inspector.sidebarSplitBox.state.width; + is(sidebarSplitBoxWidth, toolboxWidth / 2, "Got correct sidebar split box width"); + + info("Click on the toggle button to toggle OFF the 3 pane inspector"); + onRuleViewAdded = inspector.once("ruleview-added"); + EventUtils.synthesizeMouseAtCenter(button, {}, inspector.panelDoc.defaultView); + await onRuleViewAdded; + + info("Checking the sidebar size of the 2 pane inspector"); + let sidebarWidth = inspector.splitBox.state.width; + is(sidebarWidth, toolboxWidth, "Got correct sidebar width"); +});
--- a/devtools/client/preferences/devtools.js +++ b/devtools/client/preferences/devtools.js @@ -43,20 +43,20 @@ pref("devtools.command-button-measure.en pref("devtools.command-button-noautohide.enabled", false); // Inspector preferences // Enable the Inspector pref("devtools.inspector.enabled", true); // What was the last active sidebar in the inspector pref("devtools.inspector.activeSidebar", "ruleview"); pref("devtools.inspector.remote", false); -// Enable the split rule view sidebar toggle in the inspector -pref("devtools.inspector.split-sidebar-toggle", false); -// Enable the split rule view in the inspector -pref("devtools.inspector.split-rule-enabled", false); +// Enable the 3 pane mode toggle in the inspector +pref("devtools.inspector.three-pane-toggle", false); +// Enable the 3 pane mode in the inspector +pref("devtools.inspector.three-pane-enabled", false); // Collapse pseudo-elements by default in the rule-view pref("devtools.inspector.show_pseudo_elements", false); // The default size for image preview tooltips in the rule-view/computed-view/markup-view pref("devtools.inspector.imagePreviewTooltipSize", 300); // Enable user agent style inspection in rule-view pref("devtools.inspector.showUserAgentStyles", false); // Show all native anonymous content (like controls in <video> tags) pref("devtools.inspector.showAllAnonymousContent", false);
--- a/devtools/client/shared/components/splitter/SplitBox.js +++ b/devtools/client/shared/components/splitter/SplitBox.js @@ -65,52 +65,66 @@ class SplitBox extends Component { endPanelControl: false }; } constructor(props) { super(props); /** - * The state stores the current orientation (vertical or horizontal) - * and the current size (width/height). All these values can change - * during the component's life time. + * The state stores whether or not the end panel should be controlled, the current + * orientation (vertical or horizontal), the splitter size, and the current size + * (width/height). All these values can change during the component's life time. */ this.state = { + // True if the right/bottom panel should be controlled. + endPanelControl: props.endPanelControl, + // True if the splitter bar is vertical (default is vertical). vert: props.vert, + // Size of the splitter handle bar. splitterSize: props.splitterSize, + // Width of controlled panel. width: props.initialWidth || props.initialSize, + // Height of controlled panel. height: props.initialHeight || props.initialSize }; this.onStartMove = this.onStartMove.bind(this); this.onStopMove = this.onStopMove.bind(this); this.onMove = this.onMove.bind(this); } componentWillReceiveProps(nextProps) { - let { splitterSize, vert } = nextProps; + let { + endPanelControl, + splitterSize, + vert, + } = nextProps; + + if (endPanelControl != this.props.endPanelControl) { + this.setState({ endPanelControl }); + } if (splitterSize != this.props.splitterSize) { this.setState({ splitterSize }); } if (vert !== this.props.vert) { this.setState({ vert }); } } shouldComponentUpdate(nextProps, nextState) { return nextState.width != this.state.width || + nextState.endPanelControl != this.props.endPanelControl || nextState.height != this.state.height || nextState.vert != this.state.vert || nextState.splitterSize != this.state.splitterSize || nextProps.startPanel != this.props.startPanel || nextProps.endPanel != this.props.endPanel || - nextProps.endPanelControl != this.props.endPanelControl || nextProps.minSize != this.props.minSize || nextProps.maxSize != this.props.maxSize; } componentDidUpdate(prevProps, prevState) { if (this.props.onControlledPanelResized && (prevState.width !== this.state.width || prevState.height !== this.state.height)) { this.props.onControlledPanelResized(this.state.width, this.state.height); @@ -149,19 +163,19 @@ class SplitBox extends Component { * Adjust size of the controlled panel. Depending on the current * orientation we either remember the width or height of * the splitter box. */ onMove(x, y) { const node = ReactDOM.findDOMNode(this); let size; - let { endPanelControl } = this.props; + let { endPanelControl, vert } = this.state; - if (this.state.vert) { + if (vert) { // Switch the control flag in case of RTL. Note that RTL // has impact on vertical splitter only. if (document.dir === "rtl") { endPanelControl = !endPanelControl; } size = endPanelControl ? (node.offsetLeft + node.offsetWidth) - x : @@ -179,18 +193,18 @@ class SplitBox extends Component { height: size }); } } // Rendering render() { - const { splitterSize, vert } = this.state; - const { startPanel, endPanel, endPanelControl, minSize, maxSize } = this.props; + const { endPanelControl, splitterSize, vert } = this.state; + const { startPanel, endPanel, minSize, maxSize } = this.props; let style = Object.assign({}, this.props.style); // Calculate class names list. let classNames = ["split-box"]; classNames.push(vert ? "vert" : "horz"); if (this.props.className) { classNames = classNames.concat(this.props.className.split(" "));
--- a/devtools/client/themes/inspector.css +++ b/devtools/client/themes/inspector.css @@ -58,16 +58,20 @@ window { .inspector-tabpanel { min-width: 200px; } #inspector-splitter-box .controlled.pane-collapsed { visibility: collapse; } +#inspector-splitter-box .sidebar-toggle::before { + transform: unset; +} + /* Use flex layout for the Inspector toolbar. For now, it's done specifically for the Inspector toolbar since general rule applied on .devtools-toolbar breaks breadcrumbs and also toolbars in other panels (e.g. webconsole, debugger), these are not ready for HTML layout yet. */ #inspector-toolbar.devtools-toolbar { display: flex; }