diff --git a/devtools/client/framework/components/toolbox-tabs.js b/devtools/client/framework/components/toolbox-tabs.js index 32a9026db20b..cebc7c5ab533 100644 --- a/devtools/client/framework/components/toolbox-tabs.js +++ b/devtools/client/framework/components/toolbox-tabs.js @@ -12,7 +12,7 @@ const {button, div} = dom; const Menu = require("devtools/client/framework/menu"); const MenuItem = require("devtools/client/framework/menu-item"); const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab")); -const ToolboxTabsOrderManager = require("devtools/client/framework/toolbox-tabs-order-manager"); +const { ToolboxTabsOrderManager } = require("devtools/client/framework/toolbox-tabs-order-manager"); // 26px is chevron devtools button width.(i.e. tools-chevronmenu) const CHEVRON_BUTTON_WIDTH = 26; @@ -29,6 +29,7 @@ class ToolboxTabs extends Component { selectTool: PropTypes.func, toolbox: PropTypes.object, L10N: PropTypes.object, + onTabsOrderUpdated: PropTypes.func.isRequired, }; } @@ -48,7 +49,7 @@ class ToolboxTabs extends Component { this._resizeTimerId = null; this.resizeHandler = this.resizeHandler.bind(this); - this._tabsOrderManager = new ToolboxTabsOrderManager(); + this._tabsOrderManager = new ToolboxTabsOrderManager(props.onTabsOrderUpdated); } componentDidMount() { diff --git a/devtools/client/framework/components/toolbox-toolbar.js b/devtools/client/framework/components/toolbox-toolbar.js index 5193ac1f6900..268170b43113 100644 --- a/devtools/client/framework/components/toolbox-toolbar.js +++ b/devtools/client/framework/components/toolbox-toolbar.js @@ -72,6 +72,8 @@ class ToolboxToolbar extends Component { L10N: PropTypes.object, // The devtools toolbox toolbox: PropTypes.object, + // Call back function to detect tabs order updated. + onTabsOrderUpdated: PropTypes.func.isRequired, }; } diff --git a/devtools/client/framework/toolbox-tabs-order-manager.js b/devtools/client/framework/toolbox-tabs-order-manager.js index 86144bfac5bc..97f65db23790 100644 --- a/devtools/client/framework/toolbox-tabs-order-manager.js +++ b/devtools/client/framework/toolbox-tabs-order-manager.js @@ -4,18 +4,26 @@ "use strict"; +const Services = require("Services"); +const PREFERENCE_NAME = "devtools.toolbox.tabsOrder"; + /** * Manage the order of devtools tabs. */ class ToolboxTabsOrderManager { - constructor() { + constructor(onOrderUpdated) { + this.onOrderUpdated = onOrderUpdated; + this.onMouseDown = this.onMouseDown.bind(this); this.onMouseMove = this.onMouseMove.bind(this); this.onMouseOut = this.onMouseOut.bind(this); this.onMouseUp = this.onMouseUp.bind(this); + + Services.prefs.addObserver(PREFERENCE_NAME, this.onOrderUpdated); } destroy() { + Services.prefs.removeObserver(PREFERENCE_NAME, this.onOrderUpdated); this.onMouseUp(); } @@ -29,6 +37,7 @@ class ToolboxTabsOrderManager { this.previousPageX = e.pageX; this.toolboxContainerElement = this.dragTarget.closest("#toolbox-container"); this.toolboxTabsElement = this.dragTarget.closest(".toolbox-tabs"); + this.isOrderUpdated = false; this.dragTarget.ownerDocument.addEventListener("mousemove", this.onMouseMove); this.dragTarget.ownerDocument.addEventListener("mouseout", this.onMouseOut); @@ -65,6 +74,8 @@ class ToolboxTabsOrderManager { const xAfter = this.dragTarget.offsetLeft; this.dragStartX += xAfter - xBefore; + + this.isOrderUpdated = true; break; } } @@ -97,6 +108,14 @@ class ToolboxTabsOrderManager { return; } + if (this.isOrderUpdated) { + const ids = + [...this.toolboxTabsElement.querySelectorAll(".devtools-tab")] + .map(tabElement => tabElement.dataset.id); + const pref = ids.join(","); + Services.prefs.setCharPref(PREFERENCE_NAME, pref); + } + this.dragTarget.ownerDocument.removeEventListener("mousemove", this.onMouseMove); this.dragTarget.ownerDocument.removeEventListener("mouseout", this.onMouseOut); this.dragTarget.ownerDocument.removeEventListener("mouseup", this.onMouseUp); @@ -109,4 +128,28 @@ class ToolboxTabsOrderManager { } } -module.exports = ToolboxTabsOrderManager; +function sortPanelDefinitions(definitions) { + const pref = Services.prefs.getCharPref(PREFERENCE_NAME, ""); + + if (!pref) { + definitions.sort(definition => { + return -1 * (definition.ordinal == undefined || definition.ordinal < 0 + ? Number.MAX_VALUE + : definition.ordinal + ); + }); + } + + const toolIds = pref.split(","); + + return definitions.sort((a, b) => { + let orderA = toolIds.indexOf(a.id); + let orderB = toolIds.indexOf(b.id); + orderA = orderA < 0 ? Number.MAX_VALUE : orderA; + orderB = orderB < 0 ? Number.MAX_VALUE : orderB; + return orderA - orderB; + }); +} + +module.exports.ToolboxTabsOrderManager = ToolboxTabsOrderManager; +module.exports.sortPanelDefinitions = sortPanelDefinitions; diff --git a/devtools/client/framework/toolbox.js b/devtools/client/framework/toolbox.js index 7338c4518af0..3f5e9af4eaa6 100644 --- a/devtools/client/framework/toolbox.js +++ b/devtools/client/framework/toolbox.js @@ -76,6 +76,8 @@ loader.lazyRequireGetter(this, "getKnownDeviceFront", "devtools/shared/fronts/device", true); loader.lazyRequireGetter(this, "NetMonitorAPI", "devtools/client/netmonitor/src/api", true); +loader.lazyRequireGetter(this, "sortPanelDefinitions", + "devtools/client/framework/toolbox-tabs-order-manager", true); loader.lazyGetter(this, "domNodeConstants", () => { return require("devtools/shared/dom-node-constants"); @@ -147,6 +149,7 @@ function Toolbox(target, selectedTool, hostType, contentWindow, frameId) { this._showDevEditionPromo = this._showDevEditionPromo.bind(this); this._updateTextBoxMenuItems = this._updateTextBoxMenuItems.bind(this); this._onPerformanceFrontEvent = this._onPerformanceFrontEvent.bind(this); + this._onTabsOrderUpdated = this._onTabsOrderUpdated.bind(this); this._onToolbarFocus = this._onToolbarFocus.bind(this); this._onToolbarArrowKeypress = this._onToolbarArrowKeypress.bind(this); this._onPickerClick = this._onPickerClick.bind(this); @@ -263,13 +266,8 @@ Toolbox.prototype = { * can be set by add-ons. */ _combineAndSortPanelDefinitions() { - const definitions = [...this._panelDefinitions, ...this.getVisibleAdditionalTools()]; - definitions.sort(definition => { - return -1 * (definition.ordinal == undefined || definition.ordinal < 0 - ? MAX_ORDINAL - : definition.ordinal - ); - }); + let definitions = [...this._panelDefinitions, ...this.getVisibleAdditionalTools()]; + definitions = sortPanelDefinitions(definitions); this.component.setPanelDefinitions(definitions); }, @@ -1150,7 +1148,8 @@ Toolbox.prototype = { toggleNoAutohide: this.toggleNoAutohide, closeToolbox: this.destroy, focusButton: this._onToolbarFocus, - toolbox: this + toolbox: this, + onTabsOrderUpdated: this._onTabsOrderUpdated, }); this.component = this.ReactDOM.render(element, this._componentMount); @@ -1916,6 +1915,10 @@ Toolbox.prototype = { this._lastFocusedElement = originalTarget; }, + _onTabsOrderUpdated: function() { + this._combineAndSortPanelDefinitions(); + }, + /** * Opens the split console. * diff --git a/devtools/client/preferences/devtools-client.js b/devtools/client/preferences/devtools-client.js index 11855c4a6496..db9a11e35f51 100644 --- a/devtools/client/preferences/devtools-client.js +++ b/devtools/client/preferences/devtools-client.js @@ -29,6 +29,7 @@ pref("devtools.toolbox.sideEnabled", true); pref("devtools.toolbox.zoomValue", "1"); pref("devtools.toolbox.splitconsoleEnabled", false); pref("devtools.toolbox.splitconsoleHeight", 100); +pref("devtools.toolbox.tabsOrder", ""); // Toolbox Button preferences pref("devtools.command-button-pick.enabled", true);