зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1245921 - Turn toolbox toolbar into a React component r+miker r=miker
MozReview-Commit-ID: 4UZbcfw2YI9 --HG-- extra : rebase_source : 9e9e8bfed8c8511ade6c7307a0201b88b0781fba
This commit is contained in:
Родитель
8eca822d58
Коммит
555caa01f2
|
@ -27,11 +27,13 @@ const test = function(unit) {
|
|||
return function*(assert) {
|
||||
assert.isRendered = (panel, toolbox) => {
|
||||
const doc = toolbox.doc;
|
||||
assert.ok(doc.querySelector("[value='" + panel.label + "']"),
|
||||
"panel.label is found in the developer toolbox DOM");
|
||||
assert.ok(doc.querySelector("[tooltiptext='" + panel.tooltip + "']"),
|
||||
"panel.tooltip is found in the developer toolbox DOM");
|
||||
|
||||
assert.ok(Array.from(doc.querySelectorAll(".devtools-tab"))
|
||||
.find(el => el.textContent === panel.label),
|
||||
"panel.label is found in the developer toolbox DOM " + panel.label);
|
||||
if (panel.tooltip) {
|
||||
assert.ok(doc.querySelector("[title='" + panel.tooltip + "']"),
|
||||
`panel.tooltip is found in the developer toolbox DOM "${panel.tooltip}"`);
|
||||
}
|
||||
assert.ok(doc.querySelector("#toolbox-panel-" + panel.id),
|
||||
"toolbar panel with a matching id is present");
|
||||
};
|
||||
|
|
|
@ -17,6 +17,7 @@ var PREFS = [
|
|||
["devtools.netmonitor.enabled", true],
|
||||
["devtools.scratchpad.enabled", true]
|
||||
];
|
||||
|
||||
function test() {
|
||||
Task.spawn(function* () {
|
||||
// Store and enable all optional dev tools panels
|
||||
|
@ -26,20 +27,19 @@ function test() {
|
|||
let addonDebugger = yield initAddonDebugger(ADDON_ID);
|
||||
|
||||
// Check only valid tabs are shown
|
||||
let tabs = addonDebugger.frame.contentDocument.getElementById("toolbox-tabs").children;
|
||||
let tabs = addonDebugger.frame.contentDocument.querySelectorAll(".toolbox-tabs button")
|
||||
|
||||
let expectedTabs = ["webconsole", "jsdebugger", "scratchpad"];
|
||||
|
||||
is(tabs.length, expectedTabs.length, "displaying only " + expectedTabs.length + " tabs in addon debugger");
|
||||
Array.forEach(tabs, (tab, i) => {
|
||||
let toolName = expectedTabs[i];
|
||||
is(tab.getAttribute("toolid"), toolName, "displaying " + toolName);
|
||||
is(tab.getAttribute("data-id"), toolName, "displaying " + toolName);
|
||||
});
|
||||
|
||||
// Check no toolbox buttons are shown
|
||||
let buttons = addonDebugger.frame.contentDocument.getElementById("toolbox-buttons").children;
|
||||
Array.forEach(buttons, (btn, i) => {
|
||||
is(btn.hidden, true, "no toolbox buttons for the addon debugger -- " + btn.className);
|
||||
});
|
||||
let buttons = addonDebugger.frame.contentDocument.querySelectorAll("#toolbox-buttons-end button");
|
||||
is(buttons.length, 0, "no toolbox buttons for the addon debugger");
|
||||
|
||||
yield addonDebugger.destroy();
|
||||
yield removeAddon(addon);
|
||||
|
|
|
@ -35,18 +35,14 @@ function testPause() {
|
|||
|
||||
gDebugger.gThreadClient.addOneTimeListener("paused", () => {
|
||||
gToolbox.selectTool("webconsole").then(() => {
|
||||
ok(gToolboxTab.hasAttribute("highlighted") &&
|
||||
gToolboxTab.getAttribute("highlighted") == "true",
|
||||
ok(gToolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is present");
|
||||
ok(!gToolboxTab.hasAttribute("selected") ||
|
||||
gToolboxTab.getAttribute("selected") != "true",
|
||||
ok(!gToolboxTab.classList.contains("selected"),
|
||||
"The tab is not selected");
|
||||
}).then(() => gToolbox.selectTool("jsdebugger")).then(() => {
|
||||
ok(gToolboxTab.hasAttribute("highlighted") &&
|
||||
gToolboxTab.getAttribute("highlighted") == "true",
|
||||
ok(gToolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is present");
|
||||
ok(gToolboxTab.hasAttribute("selected") &&
|
||||
gToolboxTab.getAttribute("selected") == "true",
|
||||
ok(gToolboxTab.classList.contains("selected"),
|
||||
"...and the tab is selected, so the glow will not be present.");
|
||||
}).then(testResume);
|
||||
});
|
||||
|
@ -66,8 +62,7 @@ function testResume() {
|
|||
gToolbox.selectTool("webconsole").then(() => {
|
||||
ok(!gToolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is not present now after the resume");
|
||||
ok(!gToolboxTab.hasAttribute("selected") ||
|
||||
gToolboxTab.getAttribute("selected") != "true",
|
||||
ok(!gToolboxTab.classList.contains("selected"),
|
||||
"The tab is not selected");
|
||||
}).then(() => closeDebuggerAndFinish(gPanel));
|
||||
});
|
||||
|
|
|
@ -79,18 +79,14 @@ add_task(function *() {
|
|||
}
|
||||
|
||||
yield toolbox.selectTool("webconsole");
|
||||
ok(toolboxTab.hasAttribute("highlighted") &&
|
||||
toolboxTab.getAttribute("highlighted") == "true",
|
||||
ok(toolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is present");
|
||||
ok(!toolboxTab.hasAttribute("selected") ||
|
||||
toolboxTab.getAttribute("selected") != "true",
|
||||
ok(!toolboxTab.classList.contains("selected"),
|
||||
"The tab is not selected");
|
||||
yield toolbox.selectTool("jsdebugger");
|
||||
ok(toolboxTab.hasAttribute("highlighted") &&
|
||||
toolboxTab.getAttribute("highlighted") == "true",
|
||||
ok(toolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is present");
|
||||
ok(toolboxTab.hasAttribute("selected") &&
|
||||
toolboxTab.getAttribute("selected") == "true",
|
||||
ok(toolboxTab.classList.contains("selected"),
|
||||
"...and the tab is selected, so the glow will not be present.");
|
||||
}
|
||||
|
||||
|
@ -104,11 +100,9 @@ add_task(function *() {
|
|||
yield onPaused;
|
||||
|
||||
yield toolbox.selectTool("webconsole");
|
||||
ok(!toolboxTab.hasAttribute("highlighted") ||
|
||||
toolboxTab.getAttribute("highlighted") != "true",
|
||||
ok(!toolboxTab.classList.contains("highlighted"),
|
||||
"The highlighted class is not present now after the resume");
|
||||
ok(!toolboxTab.hasAttribute("selected") ||
|
||||
toolboxTab.getAttribute("selected") != "true",
|
||||
ok(!toolboxTab.classList.contains("selected"),
|
||||
"The tab is not selected");
|
||||
}
|
||||
});
|
||||
|
|
|
@ -48,7 +48,7 @@ add_task(function* () {
|
|||
"worker URL in host title");
|
||||
|
||||
let toolTabs = toolbox.doc.querySelectorAll(".devtools-tab");
|
||||
let activeTools = [...toolTabs].map(tab=>tab.getAttribute("toolid"));
|
||||
let activeTools = [...toolTabs].map(tab=>tab.getAttribute("data-id"));
|
||||
|
||||
is(activeTools.join(","), "webconsole,jsdebugger,scratchpad,options",
|
||||
"Correct set of tools supported by worker");
|
||||
|
|
|
@ -470,6 +470,11 @@ exports.defaultThemes = [
|
|||
// addons that have manually inserted toolbarbuttons into DOM.
|
||||
// (By default, supported target is only local tab)
|
||||
exports.ToolboxButtons = [
|
||||
{ id: "command-button-pick",
|
||||
isTargetSupported: target => {
|
||||
return target.activeTab && target.activeTab.traits.frames;
|
||||
}
|
||||
},
|
||||
{ id: "command-button-frames",
|
||||
isTargetSupported: target => {
|
||||
return target.activeTab && target.activeTab.traits.frames;
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# 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/.
|
||||
|
||||
|
||||
DevToolsModules(
|
||||
'toolbox-controller.js',
|
||||
'toolbox-tab.js',
|
||||
'toolbox-toolbar.js',
|
||||
)
|
|
@ -0,0 +1,151 @@
|
|||
/* 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 {createClass, createFactory} = require("devtools/client/shared/vendor/react");
|
||||
const ToolboxToolbar = createFactory(require("devtools/client/framework/components/toolbox-toolbar"));
|
||||
const ELEMENT_PICKER_ID = "command-button-pick";
|
||||
|
||||
/**
|
||||
* This component serves as a state controller for the toolbox React component. It's a
|
||||
* thin layer for translating events and state of the outside world into the React update
|
||||
* cycle. This solution was used to keep the amount of code changes to a minimimum while
|
||||
* adapting the existing codebase to start using React.
|
||||
*/
|
||||
module.exports = createClass({
|
||||
displayName: "ToolboxController",
|
||||
|
||||
getInitialState() {
|
||||
// See the ToolboxToolbar propTypes for documentation on each of these items in state,
|
||||
// and for the defintions of the props that are expected to be passed in.
|
||||
return {
|
||||
focusedButton: ELEMENT_PICKER_ID,
|
||||
currentToolId: null,
|
||||
canRender: false,
|
||||
highlightedTool: "",
|
||||
areDockButtonsEnabled: true,
|
||||
panelDefinitions: [],
|
||||
hostTypes: [],
|
||||
canCloseToolbox: true,
|
||||
toolboxButtons: [],
|
||||
buttonIds: [],
|
||||
checkedButtonsUpdated: () => {
|
||||
this.forceUpdate();
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
this.state.toolboxButtons.forEach(button => {
|
||||
button.off("updatechecked", this.state.checkedButtonsUpdated);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* The button and tab ids must be known in order to be able to focus left and right
|
||||
* using the arrow keys.
|
||||
*/
|
||||
updateButtonIds() {
|
||||
const {panelDefinitions, toolboxButtons, optionsPanel, hostTypes,
|
||||
canCloseToolbox} = this.state;
|
||||
|
||||
// This is a little gnarly, but go through all of the state and extract the IDs.
|
||||
this.setState({
|
||||
buttonIds: [
|
||||
...toolboxButtons.filter(btn => btn.isInStartContainer).map(({id}) => id),
|
||||
...panelDefinitions.map(({id}) => id),
|
||||
...toolboxButtons.filter(btn => !btn.isInStartContainer).map(({id}) => id),
|
||||
optionsPanel ? optionsPanel.id : null,
|
||||
...hostTypes.map(({position}) => "toolbox-dock-" + position),
|
||||
canCloseToolbox ? "toolbox-close" : null
|
||||
].filter(id => id)
|
||||
});
|
||||
|
||||
this.updateFocusedButton();
|
||||
},
|
||||
|
||||
updateFocusedButton() {
|
||||
this.setFocusedButton(this.state.focusedButton);
|
||||
},
|
||||
|
||||
setFocusedButton(focusedButton) {
|
||||
const {buttonIds} = this.state;
|
||||
|
||||
this.setState({
|
||||
focusedButton: focusedButton && buttonIds.includes(focusedButton)
|
||||
? focusedButton
|
||||
: buttonIds[0]
|
||||
});
|
||||
},
|
||||
|
||||
setCurrentToolId(currentToolId) {
|
||||
this.setState({currentToolId});
|
||||
// Also set the currently focused button to this tool.
|
||||
this.setFocusedButton(currentToolId);
|
||||
},
|
||||
|
||||
setCanRender() {
|
||||
this.setState({ canRender: true });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setOptionsPanel(optionsPanel) {
|
||||
this.setState({ optionsPanel });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
highlightTool(highlightedTool) {
|
||||
this.setState({ highlightedTool });
|
||||
},
|
||||
|
||||
unhighlightTool(id) {
|
||||
if (this.state.highlightedTool === id) {
|
||||
this.setState({ highlightedTool: "" });
|
||||
}
|
||||
},
|
||||
|
||||
setDockButtonsEnabled(areDockButtonsEnabled) {
|
||||
this.setState({ areDockButtonsEnabled });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setHostTypes(hostTypes) {
|
||||
this.setState({ hostTypes });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setCanCloseToolbox(canCloseToolbox) {
|
||||
this.setState({ canCloseToolbox });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setPanelDefinitions(panelDefinitions) {
|
||||
this.setState({ panelDefinitions });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setToolboxButtons(toolboxButtons) {
|
||||
// Listen for updates of the checked attribute.
|
||||
this.state.toolboxButtons.forEach(button => {
|
||||
button.off("updatechecked", this.state.checkedButtonsUpdated);
|
||||
});
|
||||
toolboxButtons.forEach(button => {
|
||||
button.on("updatechecked", this.state.checkedButtonsUpdated);
|
||||
});
|
||||
|
||||
this.setState({ toolboxButtons });
|
||||
this.updateButtonIds();
|
||||
},
|
||||
|
||||
setCanMinimize(canMinimize) {
|
||||
/* Bug 1177463 - The minimize button is currently hidden until we agree on
|
||||
the UI for it, and until bug 1173849 is fixed too. */
|
||||
|
||||
// this.setState({ canMinimize });
|
||||
},
|
||||
|
||||
render() {
|
||||
return ToolboxToolbar(Object.assign({}, this.props, this.state));
|
||||
}
|
||||
});
|
|
@ -0,0 +1,62 @@
|
|||
/* 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 {DOM, createClass} = require("devtools/client/shared/vendor/react");
|
||||
const {img, button} = DOM;
|
||||
|
||||
module.exports = createClass({
|
||||
displayName: "ToolboxTab",
|
||||
|
||||
renderIcon(definition, isHighlighted) {
|
||||
const {icon, highlightedicon} = definition;
|
||||
if (!icon) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
img({
|
||||
className: "default-icon",
|
||||
src: icon
|
||||
}),
|
||||
img({
|
||||
className: "highlighted-icon",
|
||||
src: highlightedicon || icon
|
||||
})
|
||||
];
|
||||
},
|
||||
|
||||
render() {
|
||||
const {panelDefinition, currentToolId, highlightedTool, selectTool,
|
||||
focusedButton, focusButton} = this.props;
|
||||
const {id, tooltip, label, iconOnly} = panelDefinition;
|
||||
const isHighlighted = id === currentToolId;
|
||||
|
||||
const className = [
|
||||
"devtools-tab",
|
||||
panelDefinition.invertIconForLightTheme || panelDefinition.invertIconForDarkTheme
|
||||
? "icon-invertable"
|
||||
: "",
|
||||
panelDefinition.invertIconForLightTheme ? "icon-invertable-light-theme" : "",
|
||||
panelDefinition.invertIconForDarkTheme ? "icon-invertable-dark-theme" : "",
|
||||
currentToolId === id ? "selected" : "",
|
||||
highlightedTool === id ? "highlighted" : "",
|
||||
iconOnly ? "devtools-tab-icon-only" : ""
|
||||
].join(" ");
|
||||
|
||||
return button(
|
||||
{
|
||||
className,
|
||||
id: `toolbox-tab-${id}`,
|
||||
"data-id": id,
|
||||
title: tooltip,
|
||||
type: "button",
|
||||
tabIndex: focusedButton === id ? "0" : "-1",
|
||||
onFocus: () => focusButton(id),
|
||||
onClick: () => selectTool(id),
|
||||
},
|
||||
...this.renderIcon(panelDefinition, isHighlighted),
|
||||
iconOnly ? null : label
|
||||
);
|
||||
}
|
||||
});
|
|
@ -0,0 +1,250 @@
|
|||
/* 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 {DOM, createClass, createFactory, PropTypes} = require("devtools/client/shared/vendor/react");
|
||||
const {div, button} = DOM;
|
||||
const ToolboxTab = createFactory(require("devtools/client/framework/components/toolbox-tab"));
|
||||
|
||||
/**
|
||||
* This is the overall component for the toolbox toolbar. It is designed to not know how
|
||||
* the state is being managed, and attempts to be as pure as possible. The
|
||||
* ToolboxController component controls the changing state, and passes in everything as
|
||||
* props.
|
||||
*/
|
||||
module.exports = createClass({
|
||||
displayName: "ToolboxToolbar",
|
||||
|
||||
propTypes: {
|
||||
// The currently focused item (for arrow keyboard navigation)
|
||||
// This ID determines the tabindex being 0 or -1.
|
||||
focusedButton: PropTypes.string,
|
||||
// List of command button definitions.
|
||||
toolboxButtons: PropTypes.array,
|
||||
// The id of the currently selected tool, e.g. "inspector"
|
||||
currentToolId: PropTypes.string,
|
||||
// An optionally highlighted tool, e.g. "inspector"
|
||||
highlightedTool: PropTypes.string,
|
||||
// List of tool panel definitions.
|
||||
panelDefinitions: PropTypes.array,
|
||||
// Function to select a tool based on its id.
|
||||
selectTool: PropTypes.func,
|
||||
// Keep a record of what button is focused.
|
||||
focusButton: PropTypes.func,
|
||||
// The options button definition.
|
||||
optionsPanel: PropTypes.object,
|
||||
// Hold off displaying the toolbar until enough information is ready for it to render
|
||||
// nicely.
|
||||
canRender: PropTypes.bool,
|
||||
// Localization interface.
|
||||
L10N: PropTypes.object,
|
||||
},
|
||||
|
||||
/**
|
||||
* The render function is kept fairly short for maintainability. See the individual
|
||||
* render functions for how each of the sections is rendered.
|
||||
*/
|
||||
render() {
|
||||
const containerProps = {className: "devtools-tabbar"};
|
||||
return this.props.canRender
|
||||
? (
|
||||
div(
|
||||
containerProps,
|
||||
renderToolboxButtonsStart(this.props),
|
||||
renderTabs(this.props),
|
||||
renderToolboxButtonsEnd(this.props),
|
||||
renderOptions(this.props),
|
||||
renderSeparator(),
|
||||
renderDockButtons(this.props)
|
||||
)
|
||||
)
|
||||
: div(containerProps);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Render all of the tabs, this takes in the panel definitions and builds out
|
||||
* the buttons for each of them.
|
||||
*
|
||||
* @param {Array} panelDefinitions - Array of objects that define panels.
|
||||
* @param {String} currentToolId - The currently selected tool's id; e.g. "inspector".
|
||||
* @param {String} highlightedTool - If a tool is highlighted, this is it's id.
|
||||
* @param {Function} selectTool - Function to select a tool in the toolbox.
|
||||
* @param {String} focusedButton - The id of the focused button.
|
||||
* @param {Function} focusButton - Keep a record of the currently focused button.
|
||||
*/
|
||||
function renderTabs({panelDefinitions, currentToolId, highlightedTool, selectTool,
|
||||
focusedButton, focusButton}) {
|
||||
// A wrapper is needed to get flex sizing correct in XUL.
|
||||
return div({className: "toolbox-tabs-wrapper"},
|
||||
div({className: "toolbox-tabs"},
|
||||
...panelDefinitions.map(panelDefinition => ToolboxTab({
|
||||
panelDefinition,
|
||||
currentToolId,
|
||||
highlightedTool,
|
||||
selectTool,
|
||||
focusedButton,
|
||||
focusButton,
|
||||
}))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A little helper function to call renderToolboxButtons for buttons at the start
|
||||
* of the toolbox.
|
||||
*/
|
||||
function renderToolboxButtonsStart(props) {
|
||||
return renderToolboxButtons(props, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* A little helper function to call renderToolboxButtons for buttons at the end
|
||||
* of the toolbox.
|
||||
*/
|
||||
function renderToolboxButtonsEnd(props) {
|
||||
return renderToolboxButtons(props, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render all of the tabs, this takes in a list of toolbox button states. These are plain
|
||||
* objects that have all of the relevant information needed to render the button.
|
||||
* See Toolbox.prototype._createButtonState in devtools/client/framework/toolbox.js for
|
||||
* documentation on this object.
|
||||
*
|
||||
* @param {Array} toolboxButtons - Array of objects that define the command buttons.
|
||||
* @param {String} focusedButton - The id of the focused button.
|
||||
* @param {Function} focusButton - Keep a record of the currently focused button.
|
||||
* @param {boolean} isStart - Render either the starting buttons, or ending buttons.
|
||||
*/
|
||||
function renderToolboxButtons({toolboxButtons, focusedButton, focusButton}, isStart) {
|
||||
const visibleButtons = toolboxButtons.filter(command => {
|
||||
const {isVisible, isInStartContainer} = command;
|
||||
return isVisible && (isStart ? isInStartContainer : !isInStartContainer);
|
||||
});
|
||||
|
||||
if (visibleButtons.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return div({id: `toolbox-buttons-${isStart ? "start" : "end"}`},
|
||||
...visibleButtons.map(command => {
|
||||
const {id, description, onClick, isChecked, className: buttonClass} = command;
|
||||
return button({
|
||||
id,
|
||||
title: description,
|
||||
className: (
|
||||
"command-button command-button-invertable devtools-button "
|
||||
+ buttonClass + (isChecked ? " checked" : "")
|
||||
),
|
||||
onClick: (event) => {
|
||||
onClick(event);
|
||||
focusButton(id);
|
||||
},
|
||||
onFocus: () => focusButton(id),
|
||||
tabIndex: id === focusedButton ? "0" : "-1"
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The options button is a ToolboxTab just like in the renderTabs() function. However
|
||||
* it is separate from the normal tabs, so deal with it separately here.
|
||||
*
|
||||
* @param {Object} optionsPanel - A single panel definition for the options panel.
|
||||
* @param {String} currentToolId - The currently selected tool's id; e.g. "inspector".
|
||||
* @param {Function} selectTool - Function to select a tool in the toolbox.
|
||||
* @param {String} focusedButton - The id of the focused button.
|
||||
* @param {Function} focusButton - Keep a record of the currently focused button.
|
||||
*/
|
||||
function renderOptions({optionsPanel, currentToolId, selectTool, focusedButton,
|
||||
focusButton}) {
|
||||
return div({id: "toolbox-option-container"}, ToolboxTab({
|
||||
panelDefinition: optionsPanel,
|
||||
currentToolId,
|
||||
selectTool,
|
||||
focusedButton,
|
||||
focusButton,
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a separator.
|
||||
*/
|
||||
function renderSeparator() {
|
||||
return div({
|
||||
id: "toolbox-controls-separator",
|
||||
className: "devtools-separator"
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the dock buttons, and handle all the cases for what type of host the toolbox
|
||||
* is attached to. The following props are expected.
|
||||
*
|
||||
* @property {String} focusedButton - The id of the focused button.
|
||||
* @property {Function} closeToolbox - Completely close the toolbox.
|
||||
* @property {Array} hostTypes - Array of host type objects, containing:
|
||||
* @property {String} position - Position name
|
||||
* @property {Function} switchHost - Function to switch the host.
|
||||
* @property {Function} focusButton - Keep a record of the currently focused button.
|
||||
* @property {Object} L10N - Localization interface.
|
||||
* @property {Boolean} areDockButtonsEnabled - They are not enabled in certain situations
|
||||
* like when they are in the WebIDE.
|
||||
* @property {Boolean} canCloseToolbox - Are the tools in a context where they can be
|
||||
* closed? This is not always the case, e.g. in the
|
||||
* WebIDE.
|
||||
*/
|
||||
function renderDockButtons(props) {
|
||||
const {
|
||||
focusedButton,
|
||||
closeToolbox,
|
||||
hostTypes,
|
||||
focusButton,
|
||||
L10N,
|
||||
areDockButtonsEnabled,
|
||||
canCloseToolbox,
|
||||
} = props;
|
||||
|
||||
let buttons = [];
|
||||
|
||||
if (areDockButtonsEnabled) {
|
||||
hostTypes.forEach(hostType => {
|
||||
const id = "toolbox-dock-" + hostType.position;
|
||||
buttons.push(button({
|
||||
id,
|
||||
onFocus: () => focusButton(id),
|
||||
className: "toolbox-dock-button devtools-button",
|
||||
title: L10N.getStr(`toolboxDockButtons.${hostType.position}.tooltip`),
|
||||
onClick: e => {
|
||||
hostType.switchHost();
|
||||
focusButton(id);
|
||||
},
|
||||
tabIndex: focusedButton === id ? "0" : "-1",
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
const closeButtonId = "toolbox-close";
|
||||
|
||||
const closeButton = canCloseToolbox
|
||||
? button({
|
||||
id: closeButtonId,
|
||||
onFocus: () => focusButton(closeButtonId),
|
||||
className: "devtools-button",
|
||||
title: L10N.getStr("toolbox.closebutton.tooltip"),
|
||||
onClick: () => {
|
||||
closeToolbox();
|
||||
focusButton(closeButtonId);
|
||||
},
|
||||
tabIndex: focusedButton === "toolbox-close" ? "0" : "-1",
|
||||
})
|
||||
: null;
|
||||
|
||||
return div({id: "toolbox-controls"},
|
||||
div({id: "toolbox-dock-buttons"}, ...buttons),
|
||||
closeButton
|
||||
);
|
||||
}
|
|
@ -9,6 +9,10 @@ TEST_HARNESS_FILES.xpcshell.devtools.client.framework.test += [
|
|||
'test/shared-redux-head.js',
|
||||
]
|
||||
|
||||
DIRS += [
|
||||
'components',
|
||||
]
|
||||
|
||||
DevToolsModules(
|
||||
'about-devtools-toolbox.js',
|
||||
'attach-thread.js',
|
||||
|
|
|
@ -152,11 +152,13 @@ var continueTests = Task.async(function* (toolbox, panel) {
|
|||
ok(toolbox.getCurrentPanel(), "panel value is correct");
|
||||
is(toolbox.currentToolId, toolId2, "toolbox _currentToolId is correct");
|
||||
|
||||
ok(!toolbox.doc.getElementById("toolbox-tab-" + toolId2).hasAttribute("icon-invertable"),
|
||||
"The tool tab does not have the invertable attribute");
|
||||
ok(!toolbox.doc.getElementById("toolbox-tab-" + toolId2)
|
||||
.classList.contains("icon-invertable"),
|
||||
"The tool tab does not have the invertable class");
|
||||
|
||||
ok(toolbox.doc.getElementById("toolbox-tab-inspector").hasAttribute("icon-invertable"),
|
||||
"The builtin tool tabs do have the invertable attribute");
|
||||
ok(toolbox.doc.getElementById("toolbox-tab-inspector")
|
||||
.classList.contains("icon-invertable"),
|
||||
"The builtin tool tabs do have the invertable class");
|
||||
|
||||
let toolDefinitions = gDevTools.getToolDefinitionMap();
|
||||
ok(toolDefinitions.has(toolId2), "The tool is in gDevTools");
|
||||
|
|
|
@ -41,7 +41,7 @@ function checkToolLoading() {
|
|||
function selectAndCheckById(id) {
|
||||
return toolbox.selectTool(id).then(function () {
|
||||
let tab = toolbox.doc.getElementById("toolbox-tab-" + id);
|
||||
is(tab.hasAttribute("selected"), true, "The " + id + " tab is selected");
|
||||
is(tab.classList.contains("selected"), true, "The " + id + " tab is selected");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -97,8 +97,9 @@ function toolUnregistered(event, toolId)
|
|||
|
||||
function cleanup()
|
||||
{
|
||||
toolbox.destroy();
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
toolbox.destroy().then(() => {;
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
})
|
||||
}
|
||||
|
|
|
@ -8,74 +8,78 @@ var {Toolbox} = require("devtools/client/framework/toolbox");
|
|||
var toolbox = null;
|
||||
|
||||
function test() {
|
||||
const URL = "data:text/plain;charset=UTF-8,Nothing to see here, move along";
|
||||
Task.spawn(function* () {
|
||||
const URL = "data:text/plain;charset=UTF-8,Nothing to see here, move along";
|
||||
|
||||
const TOOL_ID_1 = "jsdebugger";
|
||||
const TOOL_ID_2 = "webconsole";
|
||||
const TOOL_ID_1 = "jsdebugger";
|
||||
const TOOL_ID_2 = "webconsole";
|
||||
yield addTab(URL);
|
||||
|
||||
addTab(URL).then(() => {
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, TOOL_ID_1, Toolbox.HostType.BOTTOM)
|
||||
.then(aToolbox => {
|
||||
toolbox = aToolbox;
|
||||
// select tool 2
|
||||
toolbox.selectTool(TOOL_ID_2)
|
||||
// and highlight the first one
|
||||
.then(highlightTab.bind(null, TOOL_ID_1))
|
||||
// to see if it has the proper class.
|
||||
.then(checkHighlighted.bind(null, TOOL_ID_1))
|
||||
// Now switch back to first tool
|
||||
.then(() => toolbox.selectTool(TOOL_ID_1))
|
||||
// to check again. But there is no easy way to test if
|
||||
// it is showing orange or not.
|
||||
.then(checkNoHighlightWhenSelected.bind(null, TOOL_ID_1))
|
||||
// Switch to tool 2 again
|
||||
.then(() => toolbox.selectTool(TOOL_ID_2))
|
||||
// and check again.
|
||||
.then(checkHighlighted.bind(null, TOOL_ID_1))
|
||||
// Now unhighlight the tool
|
||||
.then(unhighlightTab.bind(null, TOOL_ID_1))
|
||||
// to see the classes gone.
|
||||
.then(checkNoHighlight.bind(null, TOOL_ID_1))
|
||||
// Now close the toolbox and exit.
|
||||
.then(() => executeSoon(() => {
|
||||
toolbox.destroy()
|
||||
.then(() => {
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
}));
|
||||
});
|
||||
const target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
toolbox = yield gDevTools.showToolbox(target, TOOL_ID_1, Toolbox.HostType.BOTTOM)
|
||||
|
||||
// select tool 2
|
||||
yield toolbox.selectTool(TOOL_ID_2)
|
||||
// and highlight the first one
|
||||
yield highlightTab(TOOL_ID_1);
|
||||
// to see if it has the proper class.
|
||||
yield checkHighlighted(TOOL_ID_1);
|
||||
// Now switch back to first tool
|
||||
yield toolbox.selectTool(TOOL_ID_1);
|
||||
// to check again. But there is no easy way to test if
|
||||
// it is showing orange or not.
|
||||
yield checkNoHighlightWhenSelected(TOOL_ID_1);
|
||||
// Switch to tool 2 again
|
||||
yield toolbox.selectTool(TOOL_ID_2);
|
||||
// and check again.
|
||||
yield checkHighlighted(TOOL_ID_1);
|
||||
// Now unhighlight the tool
|
||||
yield unhighlightTab(TOOL_ID_1);
|
||||
// to see the classes gone.
|
||||
yield checkNoHighlight(TOOL_ID_1);
|
||||
|
||||
// Now close the toolbox and exit.
|
||||
executeSoon(() => {
|
||||
toolbox.destroy().then(() => {
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
ok(false, "There was an error running the test.");
|
||||
});
|
||||
}
|
||||
|
||||
function highlightTab(toolId) {
|
||||
info("Highlighting tool " + toolId + "'s tab.");
|
||||
toolbox.highlightTool(toolId);
|
||||
info(`Highlighting tool ${toolId}'s tab.`);
|
||||
return toolbox.highlightTool(toolId);
|
||||
}
|
||||
|
||||
function unhighlightTab(toolId) {
|
||||
info("Unhighlighting tool " + toolId + "'s tab.");
|
||||
toolbox.unhighlightTool(toolId);
|
||||
info(`Unhighlighting tool ${toolId}'s tab.`);
|
||||
return toolbox.unhighlightTool(toolId);
|
||||
}
|
||||
|
||||
function checkHighlighted(toolId) {
|
||||
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
|
||||
ok(tab.hasAttribute("highlighted"), "The highlighted attribute is present");
|
||||
ok(!tab.hasAttribute("selected") || tab.getAttribute("selected") != "true",
|
||||
"The tab is not selected");
|
||||
ok(tab.classList.contains("highlighted"),
|
||||
`The highlighted class is present in ${toolId}.`);
|
||||
ok(!tab.classList.contains("selected"),
|
||||
`The tab is not selected in ${toolId}`);
|
||||
}
|
||||
|
||||
function checkNoHighlightWhenSelected(toolId) {
|
||||
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
|
||||
ok(tab.hasAttribute("highlighted"), "The highlighted attribute is present");
|
||||
ok(tab.hasAttribute("selected") && tab.getAttribute("selected") == "true",
|
||||
"and the tab is selected, so the orange glow will not be present.");
|
||||
ok(tab.classList.contains("highlighted"),
|
||||
`The highlighted class is present in ${toolId}`);
|
||||
ok(tab.classList.contains("selected"),
|
||||
`And the tab is selected, so the orange glow will not be present. in ${toolId}`);
|
||||
}
|
||||
|
||||
function checkNoHighlight(toolId) {
|
||||
let tab = toolbox.doc.getElementById("toolbox-tab-" + toolId);
|
||||
ok(!tab.hasAttribute("highlighted"),
|
||||
"The highlighted attribute is not present");
|
||||
ok(!tab.classList.contains("highlighted"),
|
||||
`The highlighted class is not present in ${toolId}`);
|
||||
}
|
||||
|
|
|
@ -134,6 +134,6 @@ function* testPreviousHost() {
|
|||
}
|
||||
|
||||
function checkToolboxLoaded(iframe) {
|
||||
let tabs = iframe.contentDocument.getElementById("toolbox-tabs");
|
||||
let tabs = iframe.contentDocument.querySelector(".toolbox-tabs");
|
||||
ok(tabs, "toolbox UI has been loaded into iframe");
|
||||
}
|
||||
|
|
|
@ -293,22 +293,8 @@ function checkRegistered(toolId, deferred, event, data) {
|
|||
if (data == toolId) {
|
||||
ok(true, "Correct tool added back");
|
||||
// checking tab on the toolbox
|
||||
let radio = doc.getElementById("toolbox-tab-" + toolId);
|
||||
ok(radio, "Tab added back for " + toolId);
|
||||
if (radio.previousSibling) {
|
||||
ok(+radio.getAttribute("ordinal") >=
|
||||
+radio.previousSibling.getAttribute("ordinal"),
|
||||
"Inserted tab's ordinal is greater than equal to its previous tab." +
|
||||
"Expected " + radio.getAttribute("ordinal") + " >= " +
|
||||
radio.previousSibling.getAttribute("ordinal"));
|
||||
}
|
||||
if (radio.nextSibling) {
|
||||
ok(+radio.getAttribute("ordinal") <
|
||||
+radio.nextSibling.getAttribute("ordinal"),
|
||||
"Inserted tab's ordinal is less than its next tab. Expected " +
|
||||
radio.getAttribute("ordinal") + " < " +
|
||||
radio.nextSibling.getAttribute("ordinal"));
|
||||
}
|
||||
let button = doc.getElementById("toolbox-tab-" + toolId);
|
||||
ok(button, "Tab added back for " + toolId);
|
||||
} else {
|
||||
ok(false, "Something went wrong, " + toolId + " was not registered");
|
||||
}
|
||||
|
|
|
@ -60,19 +60,16 @@ function testPreferenceAndUIStateIsConsistent() {
|
|||
let checkNodes = [...panelWin.document.querySelectorAll(
|
||||
"#enabled-toolbox-buttons-box input[type=checkbox]")];
|
||||
let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
|
||||
toolboxButtonNodes.push(doc.getElementById("command-button-frames"));
|
||||
let toggleableTools = toolbox.toolboxButtons;
|
||||
|
||||
// The noautohide button is only displayed in the browser toolbox
|
||||
toggleableTools = toggleableTools.filter(
|
||||
let toolbarButtons = toolbox.toolbarButtons.filter(
|
||||
tool => tool.id != "command-button-noautohide");
|
||||
|
||||
for (let tool of toggleableTools) {
|
||||
for (let tool of toolbarButtons) {
|
||||
let isVisible = getBoolPref(tool.visibilityswitch);
|
||||
|
||||
let button = toolboxButtonNodes.filter(
|
||||
toolboxButton => toolboxButton.id === tool.id)[0];
|
||||
is(!button.hasAttribute("hidden"), isVisible,
|
||||
let button = toolboxButtonNodes.find(toolboxButton => toolboxButton.id === tool.id);
|
||||
is(!!button, isVisible,
|
||||
"Button visibility matches pref for " + tool.id);
|
||||
|
||||
let check = checkNodes.filter(node => node.id === tool.id)[0];
|
||||
|
@ -84,48 +81,52 @@ function testPreferenceAndUIStateIsConsistent() {
|
|||
function testToggleToolboxButtons() {
|
||||
let checkNodes = [...panelWin.document.querySelectorAll(
|
||||
"#enabled-toolbox-buttons-box input[type=checkbox]")];
|
||||
let toolboxButtonNodes = [...doc.querySelectorAll(".command-button")];
|
||||
let toggleableTools = toolbox.toolboxButtons;
|
||||
|
||||
// The noautohide button is only displayed in the browser toolbox, and the element
|
||||
// picker button is not toggleable.
|
||||
toggleableTools = toggleableTools.filter(
|
||||
tool => tool.id != "command-button-noautohide" && tool.id != "command-button-pick");
|
||||
toolboxButtonNodes = toolboxButtonNodes.filter(
|
||||
btn => btn.id != "command-button-noautohide" && btn.id != "command-button-pick");
|
||||
let toolbarButtons = toolbox.toolbarButtons.filter(
|
||||
tool => tool.id != "command-button-noautohide");
|
||||
|
||||
is(checkNodes.length, toggleableTools.length,
|
||||
let visibleToolbarButtons = toolbox.toolbarButtons.filter(tool => tool.isVisible);
|
||||
|
||||
let toolbarButtonNodes = [...doc.querySelectorAll(".command-button")].filter(
|
||||
btn => btn.id != "command-button-noautohide");
|
||||
|
||||
is(checkNodes.length, toolbarButtons.length,
|
||||
"All of the buttons are toggleable.");
|
||||
is(checkNodes.length, toolboxButtonNodes.length,
|
||||
is(visibleToolbarButtons.length, toolbarButtonNodes.length,
|
||||
"All of the DOM buttons are toggleable.");
|
||||
|
||||
for (let tool of toggleableTools) {
|
||||
for (let tool of toolbarButtons) {
|
||||
let id = tool.id;
|
||||
let matchedCheckboxes = checkNodes.filter(node => node.id === id);
|
||||
let matchedButtons = toolboxButtonNodes.filter(button => button.id === id);
|
||||
let matchedButtons = toolbarButtonNodes.filter(button => button.id === id);
|
||||
is(matchedCheckboxes.length, 1,
|
||||
"There should be a single toggle checkbox for: " + id);
|
||||
is(matchedButtons.length, 1,
|
||||
"There should be a DOM button for: " + id);
|
||||
is(matchedButtons[0], tool.button,
|
||||
"DOM buttons should match for: " + id);
|
||||
if (tool.isVisible) {
|
||||
is(matchedButtons.length, 1,
|
||||
"There should be a DOM button for the visible: " + id);
|
||||
is(matchedButtons[0].getAttribute("title"), tool.description,
|
||||
"The tooltip for button matches the tool definition.");
|
||||
} else {
|
||||
is(matchedButtons.length, 0,
|
||||
"There should not be a DOM button for the invisible: " + id);
|
||||
}
|
||||
|
||||
is(matchedCheckboxes[0].nextSibling.textContent, tool.label,
|
||||
is(matchedCheckboxes[0].nextSibling.textContent, tool.description,
|
||||
"The label for checkbox matches the tool definition.");
|
||||
is(matchedButtons[0].getAttribute("title"), tool.label,
|
||||
"The tooltip for button matches the tool definition.");
|
||||
}
|
||||
|
||||
// Store modified pref names so that they can be cleared on error.
|
||||
for (let tool of toggleableTools) {
|
||||
for (let tool of toolbarButtons) {
|
||||
let pref = tool.visibilityswitch;
|
||||
modifiedPrefs.push(pref);
|
||||
}
|
||||
|
||||
// Try checking each checkbox, making sure that it changes the preference
|
||||
for (let node of checkNodes) {
|
||||
let tool = toggleableTools.filter(
|
||||
toggleableTool => toggleableTool.id === node.id)[0];
|
||||
let tool = toolbarButtons.filter(
|
||||
commandButton => commandButton.id === node.id)[0];
|
||||
let isVisible = getBoolPref(tool.visibilityswitch);
|
||||
|
||||
testPreferenceAndUIStateIsConsistent();
|
||||
|
|
|
@ -132,8 +132,9 @@ function toolboxToolUnregistered() {
|
|||
}
|
||||
|
||||
function cleanup() {
|
||||
toolbox.destroy();
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
toolbox.destroy().then(() => {;
|
||||
toolbox = null;
|
||||
gBrowser.removeCurrentTab();
|
||||
finish();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -30,10 +30,12 @@ function cleanUp(toolbox) {
|
|||
off(DebuggerClient, "connect", onDebuggerClientConnect);
|
||||
|
||||
toolbox.destroy().then(function () {
|
||||
gBrowser.removeCurrentTab();
|
||||
executeSoon(function () {
|
||||
finish();
|
||||
});
|
||||
setTimeout(() => {
|
||||
gBrowser.removeCurrentTab();
|
||||
executeSoon(function () {
|
||||
finish();
|
||||
});
|
||||
}, 1000);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -44,11 +44,11 @@ add_task(function* () {
|
|||
// Open frame menu and wait till it's available on the screen.
|
||||
// Also check 'open' attribute on the command button.
|
||||
let btn = toolbox.doc.getElementById("command-button-frames");
|
||||
ok(!btn.getAttribute("open"), "The open attribute must not be present");
|
||||
ok(!btn.classList.contains("checked"), "The checked class must not be present");
|
||||
let menu = toolbox.showFramesMenu({target: btn});
|
||||
yield once(menu, "open");
|
||||
|
||||
is(btn.getAttribute("open"), "true", "The open attribute must be set");
|
||||
ok(btn.classList.contains("checked"), "The checked class must be set");
|
||||
|
||||
// Verify that the frame list menu is populated
|
||||
let frames = menu.items;
|
||||
|
|
|
@ -122,7 +122,7 @@ exports.getHighlighterUtils = function (toolbox) {
|
|||
}
|
||||
isPicking = true;
|
||||
|
||||
toolbox.pickerButtonChecked = true;
|
||||
toolbox.pickerButton.isChecked = true;
|
||||
yield toolbox.selectTool("inspector");
|
||||
toolbox.on("select", cancelPicker);
|
||||
|
||||
|
@ -156,7 +156,7 @@ exports.getHighlighterUtils = function (toolbox) {
|
|||
}
|
||||
isPicking = false;
|
||||
|
||||
toolbox.pickerButtonChecked = false;
|
||||
toolbox.pickerButton.isChecked = false;
|
||||
|
||||
if (isRemoteHighlightable()) {
|
||||
yield toolbox.highlighter.cancelPick();
|
||||
|
|
|
@ -135,30 +135,36 @@ OptionsPanel.prototype = {
|
|||
}
|
||||
},
|
||||
|
||||
setupToolbarButtonsList: function () {
|
||||
setupToolbarButtonsList: Task.async(function* () {
|
||||
// Ensure the toolbox is open, and the buttons are all set up.
|
||||
yield this.toolbox.isOpen;
|
||||
|
||||
let enabledToolbarButtonsBox = this.panelDoc.getElementById(
|
||||
"enabled-toolbox-buttons-box");
|
||||
|
||||
let toggleableButtons = this.toolbox.toolboxButtons;
|
||||
let setToolboxButtonsVisibility =
|
||||
this.toolbox.setToolboxButtonsVisibility.bind(this.toolbox);
|
||||
let toolbarButtons = this.toolbox.toolbarButtons;
|
||||
|
||||
if (!toolbarButtons) {
|
||||
console.warn("The command buttons weren't initiated yet.");
|
||||
return;
|
||||
}
|
||||
|
||||
let onCheckboxClick = (checkbox) => {
|
||||
let toolDefinition = toggleableButtons.filter(
|
||||
let commandButton = toolbarButtons.filter(
|
||||
toggleableButton => toggleableButton.id === checkbox.id)[0];
|
||||
Services.prefs.setBoolPref(
|
||||
toolDefinition.visibilityswitch, checkbox.checked);
|
||||
setToolboxButtonsVisibility();
|
||||
commandButton.visibilityswitch, checkbox.checked);
|
||||
this.toolbox.updateToolboxButtonsVisibility();
|
||||
};
|
||||
|
||||
let createCommandCheckbox = tool => {
|
||||
let createCommandCheckbox = button => {
|
||||
let checkboxLabel = this.panelDoc.createElement("label");
|
||||
let checkboxSpanLabel = this.panelDoc.createElement("span");
|
||||
checkboxSpanLabel.textContent = tool.label;
|
||||
checkboxSpanLabel.textContent = button.description;
|
||||
let checkboxInput = this.panelDoc.createElement("input");
|
||||
checkboxInput.setAttribute("type", "checkbox");
|
||||
checkboxInput.setAttribute("id", tool.id);
|
||||
if (InfallibleGetBoolPref(tool.visibilityswitch)) {
|
||||
checkboxInput.setAttribute("id", button.id);
|
||||
if (button.isVisible) {
|
||||
checkboxInput.setAttribute("checked", true);
|
||||
}
|
||||
checkboxInput.addEventListener("change",
|
||||
|
@ -169,14 +175,14 @@ OptionsPanel.prototype = {
|
|||
return checkboxLabel;
|
||||
};
|
||||
|
||||
for (let tool of toggleableButtons) {
|
||||
if (!tool.isTargetSupported(this.toolbox.target)) {
|
||||
for (let button of toolbarButtons) {
|
||||
if (!button.isTargetSupported(this.toolbox.target)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
enabledToolbarButtonsBox.appendChild(createCommandCheckbox(tool));
|
||||
enabledToolbarButtonsBox.appendChild(createCommandCheckbox(button));
|
||||
}
|
||||
},
|
||||
}),
|
||||
|
||||
setupToolsList: function () {
|
||||
let defaultToolsBox = this.panelDoc.getElementById("default-tools-box");
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -47,28 +47,7 @@
|
|||
|
||||
<vbox id="toolbox-container" flex="1">
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-notificationbox"/>
|
||||
<toolbar class="devtools-tabbar">
|
||||
<hbox id="toolbox-picker-container" />
|
||||
<hbox id="toolbox-tabs" flex="1" role="tablist" />
|
||||
<hbox id="toolbox-buttons" pack="end">
|
||||
<html:button id="command-button-frames"
|
||||
class="command-button command-button-invertable devtools-button"
|
||||
title="&toolboxFramesTooltip;"
|
||||
hidden="true" />
|
||||
<html:button id="command-button-noautohide"
|
||||
class="command-button command-button-invertable devtools-button"
|
||||
title="&toolboxNoAutoHideTooltip;"
|
||||
hidden="true" />
|
||||
</hbox>
|
||||
<vbox id="toolbox-controls-separator" class="devtools-separator"/>
|
||||
<hbox id="toolbox-option-container"/>
|
||||
<hbox id="toolbox-controls">
|
||||
<hbox id="toolbox-dock-buttons"/>
|
||||
<html:button id="toolbox-close"
|
||||
class="devtools-button"
|
||||
title="&toolboxCloseButton.tooltip;"/>
|
||||
</hbox>
|
||||
</toolbar>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml" id="toolbox-toolbar-mount" />
|
||||
<vbox flex="1" class="theme-body">
|
||||
<!-- Set large flex to allow the toolbox-panel-webconsole to have a
|
||||
height set to a small value without flexing to fill up extra
|
||||
|
|
|
@ -52,5 +52,5 @@ function* checkElementSelected(selector, inspector) {
|
|||
|
||||
function checkPickerMode(toolbox, isOn) {
|
||||
let pickerButton = toolbox.doc.querySelector("#command-button-pick");
|
||||
is(pickerButton.hasAttribute("checked"), isOn, "The picker mode is correct");
|
||||
is(pickerButton.classList.contains("checked"), isOn, "The picker mode is correct");
|
||||
}
|
||||
|
|
|
@ -57,9 +57,7 @@ function* testToolboxInitialization(testActor, tab) {
|
|||
yield testBreadcrumbs("span", inspector);
|
||||
|
||||
info("Destroying toolbox");
|
||||
let destroyed = toolbox.once("destroyed");
|
||||
toolbox.destroy();
|
||||
yield destroyed;
|
||||
yield toolbox.destroy();
|
||||
|
||||
ok("true", "'destroyed' notification received.");
|
||||
ok(!gDevTools.getToolbox(target), "Toolbox destroyed.");
|
||||
|
|
|
@ -10,19 +10,6 @@
|
|||
<!ENTITY toggleToolboxF12.keycode "VK_F12">
|
||||
<!ENTITY toggleToolboxF12.keytext "F12">
|
||||
|
||||
<!ENTITY toolboxCloseButton.tooltip "Close Developer Tools">
|
||||
|
||||
<!-- LOCALIZATION NOTE (toolboxFramesButton): This is the label for
|
||||
- the iframes menu list that appears only when the document has some.
|
||||
- It allows you to switch the context of the whole toolbox. -->
|
||||
<!ENTITY toolboxFramesTooltip "Select an iframe as the currently targeted document">
|
||||
|
||||
<!-- LOCALIZATION NOTE (toolboxNoAutoHideButton): This is the label for
|
||||
- the button to force the popups/panels to stay visible on blur.
|
||||
- This is only visible in the browser toolbox as it is meant for
|
||||
- addon developers and Firefox contributors. -->
|
||||
<!ENTITY toolboxNoAutoHideTooltip "Disable popup auto hide">
|
||||
|
||||
<!-- LOCALIZATION NOTE (browserToolboxErrorMessage): This is the label
|
||||
- shown next to error details when the Browser Toolbox is unable to open. -->
|
||||
<!ENTITY browserToolboxErrorMessage "Error opening Browser Toolbox:">
|
||||
|
|
|
@ -158,3 +158,18 @@ toolbox.minimize.key=CmdOrCtrl+Shift+U
|
|||
# LOCALIZATION NOTE (toolbox.toggleHost.key)
|
||||
# Key shortcut used to move the toolbox in bottom or side of the browser window
|
||||
toolbox.toggleHost.key=CmdOrCtrl+Shift+D
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.frames.tooltip): This is the label for
|
||||
# the iframes menu list that appears only when the document has some.
|
||||
# It allows you to switch the context of the whole toolbox.
|
||||
toolbox.frames.tooltip=Select an iframe as the currently targeted document
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.noautohide.tooltip): This is the label for
|
||||
# the button to force the popups/panels to stay visible on blur.
|
||||
# This is only visible in the browser toolbox as it is meant for
|
||||
# addon developers and Firefox contributors.
|
||||
toolbox.noautohide.tooltip=Disable popup auto hide
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.closebutton.tooltip): This is the tooltip for
|
||||
# the close button the developer tools toolbox.
|
||||
toolbox.closebutton.tooltip=Close Developer Tools
|
||||
|
|
|
@ -21,27 +21,27 @@ add_task(function* () {
|
|||
let tab = toolbox.doc.getElementById("toolbox-tab-performance");
|
||||
|
||||
yield console.profile("rust");
|
||||
yield waitUntil(() => tab.hasAttribute("highlighted"));
|
||||
yield waitUntil(() => tab.classList.contains("highlighted"));
|
||||
|
||||
ok(tab.hasAttribute("highlighted"), "Performance tab is highlighted during recording " +
|
||||
"from console.profile when unloaded.");
|
||||
ok(tab.classList.contains("highlighted"), "Performance tab is highlighted during " +
|
||||
"recording from console.profile when unloaded.");
|
||||
|
||||
yield console.profileEnd("rust");
|
||||
yield waitUntil(() => !tab.hasAttribute("highlighted"));
|
||||
yield waitUntil(() => !tab.classList.contains("highlighted"));
|
||||
|
||||
ok(!tab.hasAttribute("highlighted"),
|
||||
ok(!tab.classList.contains("highlighted"),
|
||||
"Performance tab is no longer highlighted when console.profile recording finishes.");
|
||||
|
||||
let { panel } = yield initPerformanceInTab({ tab: target.tab });
|
||||
|
||||
yield startRecording(panel);
|
||||
|
||||
ok(tab.hasAttribute("highlighted"),
|
||||
ok(tab.classList.contains("highlighted"),
|
||||
"Performance tab is highlighted during recording while in performance tool.");
|
||||
|
||||
yield stopRecording(panel);
|
||||
|
||||
ok(!tab.hasAttribute("highlighted"),
|
||||
ok(!tab.classList.contains("highlighted"),
|
||||
"Performance tab is no longer highlighted when recording finishes.");
|
||||
|
||||
yield teardownToolboxAndRemoveTab(panel);
|
||||
|
|
|
@ -37,6 +37,7 @@ pref("devtools.toolbox.splitconsoleEnabled", false);
|
|||
pref("devtools.toolbox.splitconsoleHeight", 100);
|
||||
|
||||
// Toolbox Button preferences
|
||||
pref("devtools.command-button-pick.enabled", true);
|
||||
pref("devtools.command-button-frames.enabled", true);
|
||||
pref("devtools.command-button-splitconsole.enabled", true);
|
||||
pref("devtools.command-button-paintflashing.enabled", false);
|
||||
|
|
|
@ -10,7 +10,6 @@ const defer = require("devtools/shared/defer");
|
|||
const Services = require("Services");
|
||||
const { TargetFactory } = require("devtools/client/framework/target");
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
const {ViewHelpers} = require("devtools/client/shared/widgets/view-helpers");
|
||||
const {LocalizationHelper} = require("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper("devtools/client/locales/toolbox.properties");
|
||||
const {Task} = require("devtools/shared/task");
|
||||
|
@ -67,71 +66,56 @@ var CommandUtils = {
|
|||
},
|
||||
|
||||
/**
|
||||
* A toolbarSpec is an array of strings each of which is a GCLI command.
|
||||
* Create a list of props for React components that manage the state of the buttons.
|
||||
*
|
||||
* @param {Array} toolbarSpec - An array of strings each of which is a GCLI command.
|
||||
* @param {Object} target
|
||||
* @param {Object} document - Used to listen to unload event of the window.
|
||||
* @param {Requisition} requisition
|
||||
* @param {Function} createButtonState - A function that provides a common interface
|
||||
* to create a button for the toolbox.
|
||||
*
|
||||
* @return {Array} List of ToolboxButton objects..
|
||||
*
|
||||
* Warning: this method uses the unload event of the window that owns the
|
||||
* buttons that are of type checkbox. this means that we don't properly
|
||||
* unregister event handlers until the window is destroyed.
|
||||
*/
|
||||
createButtons: function (toolbarSpec, target, document, requisition) {
|
||||
createCommandButtons: function (toolbarSpec, target, document, requisition,
|
||||
createButtonState) {
|
||||
return util.promiseEach(toolbarSpec, typed => {
|
||||
// Ask GCLI to parse the typed string (doesn't execute it)
|
||||
return requisition.update(typed).then(() => {
|
||||
let button = document.createElementNS(NS_XHTML, "button");
|
||||
|
||||
// Ignore invalid commands
|
||||
let command = requisition.commandAssignment.value;
|
||||
if (command == null) {
|
||||
throw new Error("No command '" + typed + "'");
|
||||
}
|
||||
|
||||
if (command.buttonId != null) {
|
||||
button.id = command.buttonId;
|
||||
if (command.buttonClass != null) {
|
||||
button.className = command.buttonClass;
|
||||
}
|
||||
} else {
|
||||
button.setAttribute("text-as-image", "true");
|
||||
button.setAttribute("label", command.name);
|
||||
if (!command.buttonId) {
|
||||
throw new Error("Attempting to add a button to the toolbar, and the command " +
|
||||
"did not have an id.");
|
||||
}
|
||||
// Create the ToolboxButton.
|
||||
let button = createButtonState({
|
||||
id: command.buttonId,
|
||||
className: command.buttonClass,
|
||||
description: command.tooltipText || command.description,
|
||||
onClick: requisition.updateExec.bind(requisition, typed)
|
||||
});
|
||||
|
||||
button.classList.add("devtools-button");
|
||||
|
||||
if (command.tooltipText != null) {
|
||||
button.setAttribute("title", command.tooltipText);
|
||||
} else if (command.description != null) {
|
||||
button.setAttribute("title", command.description);
|
||||
}
|
||||
|
||||
button.addEventListener("click",
|
||||
requisition.updateExec.bind(requisition, typed));
|
||||
|
||||
button.addEventListener("keypress", (event) => {
|
||||
if (ViewHelpers.isSpaceOrReturn(event)) {
|
||||
event.preventDefault();
|
||||
requisition.updateExec(typed);
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Allow the command button to be toggleable
|
||||
let onChange = null;
|
||||
// Allow the command button to be toggleable.
|
||||
if (command.state) {
|
||||
button.setAttribute("autocheck", false);
|
||||
|
||||
/**
|
||||
* The onChange event should be called with an event object that
|
||||
* contains a target property which specifies which target the event
|
||||
* applies to. For legacy reasons the event object can also contain
|
||||
* a tab property.
|
||||
*/
|
||||
onChange = (eventName, ev) => {
|
||||
const onChange = (eventName, ev) => {
|
||||
if (ev.target == target || ev.tab == target.tab) {
|
||||
let updateChecked = (checked) => {
|
||||
if (checked) {
|
||||
button.setAttribute("checked", true);
|
||||
} else if (button.hasAttribute("checked")) {
|
||||
button.removeAttribute("checked");
|
||||
}
|
||||
// This will emit a ToolboxButton update event.
|
||||
button.isChecked = checked;
|
||||
};
|
||||
|
||||
// isChecked would normally be synchronous. An annoying quirk
|
||||
|
@ -150,14 +134,13 @@ var CommandUtils = {
|
|||
|
||||
command.state.onChange(target, onChange);
|
||||
onChange("", { target: target });
|
||||
|
||||
document.defaultView.addEventListener("unload", function (event) {
|
||||
if (command.state.offChange) {
|
||||
command.state.offChange(target, onChange);
|
||||
}
|
||||
}, { once: true });
|
||||
}
|
||||
document.defaultView.addEventListener("unload", function (event) {
|
||||
if (onChange && command.state.offChange) {
|
||||
command.state.offChange(target, onChange);
|
||||
}
|
||||
button.remove();
|
||||
button = null;
|
||||
}, { once: true });
|
||||
|
||||
requisition.clear();
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ const TOOL_DELAY = 200;
|
|||
add_task(function* () {
|
||||
yield addTab(TEST_URI);
|
||||
let Telemetry = loadTelemetryAndRecordLogs();
|
||||
yield pushPref("devtools.command-button-paintflashing.enabled", true);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
|
|
|
@ -14,6 +14,8 @@ add_task(function* () {
|
|||
yield addTab(TEST_URI);
|
||||
let Telemetry = loadTelemetryAndRecordLogs();
|
||||
|
||||
yield pushPref("devtools.command-button-scratchpad.enabled", true);
|
||||
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
let toolbox = yield gDevTools.showToolbox(target, "inspector");
|
||||
info("inspector opened");
|
||||
|
|
|
@ -94,6 +94,22 @@
|
|||
.theme-firebug .devtools-sidebar-tabs tab {
|
||||
}
|
||||
|
||||
.theme-firebug .devtools-tab span {
|
||||
padding-inline-end: 0;
|
||||
}
|
||||
|
||||
/* Tweak the margin and padding values differently for sidebar and the main tab bar */
|
||||
.theme-firebug .devtools-tab,
|
||||
.theme-firebug .devtools-tab.selected {
|
||||
padding: 2px 4px 0 4px;
|
||||
margin: 3px 1px -1px;
|
||||
}
|
||||
|
||||
.theme-firebug .devtools-sidebar-tabs tab {
|
||||
margin: 3px 0 -1px 0;
|
||||
padding: 2px 0 0 0;
|
||||
}
|
||||
|
||||
/* In order to hide bottom-border of side panel tabs we need
|
||||
to make the parent element overflow visible, so child element
|
||||
can move one pixel down to hide the bottom border of the parent. */
|
||||
|
@ -107,7 +123,7 @@
|
|||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.theme-firebug .devtools-tab[selected],
|
||||
.theme-firebug .devtools-tab.selected,
|
||||
.theme-firebug .devtools-sidebar-tabs tab[selected] {
|
||||
background-color: rgb(247, 251, 254);
|
||||
border: 1px solid rgb(170, 188, 207) !important;
|
||||
|
@ -116,8 +132,8 @@
|
|||
color: inherit;
|
||||
}
|
||||
|
||||
.theme-firebug .devtools-tab spacer,
|
||||
.theme-firebug .devtools-tab image {
|
||||
.theme-firebug .devtools-tabbar .devtools-separator,
|
||||
.theme-firebug .devtools-tab img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
@ -135,7 +151,7 @@
|
|||
margin: 0 4px !important;
|
||||
}
|
||||
|
||||
.theme-firebug #panelSideBox .devtools-tab[selected],
|
||||
.theme-firebug #panelSideBox .devtools-tab.selected,
|
||||
.theme-firebug .devtools-sidebar-tabs tab[selected] {
|
||||
background-color: white;
|
||||
}
|
||||
|
@ -155,13 +171,21 @@
|
|||
.theme-firebug #toolbox-tab-options::before {
|
||||
content: url(chrome://devtools/skin/images/firebug/tool-options.svg);
|
||||
display: block;
|
||||
margin: 4px 7px 0;
|
||||
margin: 4px 4px 0;
|
||||
}
|
||||
|
||||
.theme-firebug #toolbox-tab-options:not([selected]):hover::before {
|
||||
filter: brightness(80%);
|
||||
}
|
||||
|
||||
/* Element picker */
|
||||
.theme-firebug #toolbox-buttons-start {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.theme-firebug #command-button-pick {
|
||||
top: 6px;
|
||||
}
|
||||
/* Toolbar */
|
||||
|
||||
.theme-firebug .theme-toolbar,
|
||||
|
@ -233,3 +257,9 @@
|
|||
.theme-firebug #element-picker {
|
||||
min-height: 21px;
|
||||
}
|
||||
|
||||
/* Make sure the toolbar buttons shrink nicely. */
|
||||
|
||||
#toolbox-buttons-end {
|
||||
background-image: linear-gradient(rgba(253, 253, 253, 0.2), rgba(253, 253, 253, 0));
|
||||
}
|
||||
|
|
|
@ -187,7 +187,7 @@
|
|||
/* Invert the colors of certain light theme images for displaying
|
||||
* inside of the dark theme.
|
||||
*/
|
||||
.devtools-tab[icon-invertable] > image,
|
||||
.devtools-tab.icon-invertable > img,
|
||||
.devtools-toolbarbutton > image,
|
||||
.devtools-button::before,
|
||||
#breadcrumb-separator-normal,
|
||||
|
|
|
@ -49,15 +49,32 @@
|
|||
padding: 0;
|
||||
background: var(--theme-tab-toolbar-background);
|
||||
border-bottom-color: var(--theme-splitter-color);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#toolbox-tabs {
|
||||
.toolbox-tabs {
|
||||
margin: 0;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toolbox-tabs-wrapper {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.toolbox-tabs {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
/* Set flex attribute to Toolbox buttons and Picker container so,
|
||||
they don't overlapp with the tab bar */
|
||||
#toolbox-buttons {
|
||||
they don't overlap with the tab bar */
|
||||
#toolbox-buttons-end {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
@ -65,22 +82,38 @@
|
|||
display: flex;
|
||||
}
|
||||
|
||||
/* Toolbox tabs */
|
||||
#toolbox-buttons-start {
|
||||
border: solid 0 var(--theme-splitter-color);
|
||||
border-inline-end-width: 1px;
|
||||
}
|
||||
|
||||
/* Toolbox tabs */
|
||||
.devtools-tab {
|
||||
-moz-appearance: none;
|
||||
-moz-binding: url("chrome://global/content/bindings/general.xml#control-item");
|
||||
-moz-box-align: center;
|
||||
min-width: 32px;
|
||||
min-height: 24px;
|
||||
max-width: 100px;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border-style: solid;
|
||||
border-width: 0;
|
||||
border-inline-start-width: 1px;
|
||||
-moz-box-align: center;
|
||||
-moz-box-flex: 1;
|
||||
padding-inline-end: 10px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.devtools-tab-icon-only {
|
||||
padding-inline-end: 2px;
|
||||
}
|
||||
|
||||
.devtools-tab span {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-inline-end: 13px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
|
||||
/* Save space on the tab-strip in Firebug theme */
|
||||
|
@ -114,17 +147,17 @@
|
|||
background-color: var(--toolbar-tab-hover-active);
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab:not([selected])[highlighted] {
|
||||
.theme-dark .devtools-tab:not(.selected).highlighted {
|
||||
background-color: hsla(99, 100%, 14%, .3);
|
||||
}
|
||||
|
||||
.theme-light .devtools-tab:not([selected])[highlighted] {
|
||||
.theme-light .devtools-tab:not(.selected).highlighted {
|
||||
background-color: rgba(44, 187, 15, .2);
|
||||
}
|
||||
|
||||
/* Display execution pointer in the Debugger tab to indicate
|
||||
that the debugger is paused. */
|
||||
.theme-firebug #toolbox-tab-jsdebugger.devtools-tab:not([selected])[highlighted] {
|
||||
.theme-firebug #toolbox-tab-jsdebugger.devtools-tab:not(.selected).highlighted {
|
||||
background-color: rgba(89, 178, 234, .2);
|
||||
background-image: url(chrome://devtools/skin/images/firebug/tool-debugger-paused.svg);
|
||||
background-repeat: no-repeat;
|
||||
|
@ -132,27 +165,29 @@
|
|||
background-position: 3px 6px;
|
||||
}
|
||||
|
||||
.devtools-tab > image {
|
||||
.devtools-tab > img {
|
||||
border: none;
|
||||
margin: 0;
|
||||
margin-inline-start: 4px;
|
||||
margin-inline-start: 10px;
|
||||
opacity: 0.6;
|
||||
max-height: 16px;
|
||||
width: 16px; /* Prevents collapse during theme switching */
|
||||
vertical-align: text-top;
|
||||
margin-inline-end: 6px;
|
||||
}
|
||||
|
||||
/* Support invertable icon flags and make icon white when it's on a blue background */
|
||||
.theme-light .devtools-tab[icon-invertable="light-theme"]:not([selected]) > image,
|
||||
.devtools-tab[icon-invertable="dark-theme"][selected] > image {
|
||||
.theme-light .devtools-tab.icon-invertable-light-theme:not(.selected) > img,
|
||||
.devtools-tab.icon-invertable-dark-theme.selected > img {
|
||||
filter: invert(1);
|
||||
}
|
||||
|
||||
/* Don't apply any filter to non-invertable command button icons */
|
||||
.command-button:not(.command-button-invertable),
|
||||
/* [icon-invertable="light-theme"] icons are white, so do not invert them for the dark theme */
|
||||
.theme-dark .devtools-tab[icon-invertable="light-theme"] > image,
|
||||
/* icon-invertable-light-theme icons are white, so do not invert them for the dark theme */
|
||||
.theme-dark .devtools-tab.icon-invertable-light-theme > img,
|
||||
/* Since "highlighted" icons are green, we should omit the filter */
|
||||
.devtools-tab[icon-invertable][highlighted]:not([selected]) > image {
|
||||
.devtools-tab.icon-invertable.highlighted:not(.selected) > img {
|
||||
filter: none;
|
||||
}
|
||||
|
||||
|
@ -161,55 +196,50 @@
|
|||
margin: 0 4px;
|
||||
}
|
||||
|
||||
.devtools-tab:hover > image {
|
||||
.devtools-tab:hover > img {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
.devtools-tab:active > image,
|
||||
.devtools-tab[selected] > image {
|
||||
.devtools-tab:active > img,
|
||||
.devtools-tab.selected > img {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.devtools-tabbar .devtools-tab[selected],
|
||||
.devtools-tabbar .devtools-tab[selected]:hover:active {
|
||||
.devtools-tabbar .devtools-tab.selected,
|
||||
.devtools-tabbar .devtools-tab.selected:hover:active {
|
||||
color: var(--theme-selection-color);
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
#toolbox-tabs .devtools-tab[selected],
|
||||
#toolbox-tabs .devtools-tab[highlighted] {
|
||||
.toolbox-tabs .devtools-tab.selected,
|
||||
.toolbox-tabs .devtools-tab.highlighted {
|
||||
border-width: 0;
|
||||
padding-inline-start: 1px;
|
||||
}
|
||||
|
||||
#toolbox-tabs .devtools-tab[selected]:last-child,
|
||||
#toolbox-tabs .devtools-tab[highlighted]:last-child {
|
||||
padding-inline-end: 1px;
|
||||
}
|
||||
|
||||
#toolbox-tabs .devtools-tab[selected] + .devtools-tab,
|
||||
#toolbox-tabs .devtools-tab[highlighted] + .devtools-tab {
|
||||
.toolbox-tabs .devtools-tab.selected + .devtools-tab,
|
||||
.toolbox-tabs .devtools-tab.highlighted + .devtools-tab {
|
||||
border-inline-start-width: 0;
|
||||
padding-inline-start: 1px;
|
||||
}
|
||||
|
||||
#toolbox-tabs .devtools-tab:first-child[selected] {
|
||||
.toolbox-tabs .devtools-tab:first-child {
|
||||
border-inline-start-width: 0;
|
||||
}
|
||||
|
||||
#toolbox-tabs .devtools-tab:last-child {
|
||||
.toolbox-tabs .devtools-tab:last-child {
|
||||
border-inline-end-width: 1px;
|
||||
}
|
||||
|
||||
.devtools-tab:not([highlighted]) > .highlighted-icon,
|
||||
.devtools-tab[selected] > .highlighted-icon,
|
||||
.devtools-tab:not([selected])[highlighted] > .default-icon {
|
||||
visibility: collapse;
|
||||
.devtools-tab:not(.highlighted) > .highlighted-icon,
|
||||
.devtools-tab.selected > .highlighted-icon,
|
||||
.devtools-tab:not(.selected).highlighted > .default-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The options tab is special - it doesn't have the same parent
|
||||
as the other tabs (toolbox-option-container vs toolbox-tabs) */
|
||||
#toolbox-option-container .devtools-tab:not([selected]) {
|
||||
#toolbox-option-container .devtools-tab:not(.selected) {
|
||||
background-color: transparent;
|
||||
}
|
||||
#toolbox-option-container .devtools-tab {
|
||||
|
@ -217,12 +247,16 @@
|
|||
border-width: 0;
|
||||
padding-inline-start: 1px;
|
||||
}
|
||||
#toolbox-tab-options > image {
|
||||
margin: 0 8px;
|
||||
#toolbox-option-container img {
|
||||
margin-inline-end: 6px;
|
||||
margin-inline-start: 6px;
|
||||
}
|
||||
|
||||
/* Toolbox controls */
|
||||
|
||||
#toolbox-controls, #toolbox-dock-buttons {
|
||||
display: flex;
|
||||
}
|
||||
#toolbox-controls > button,
|
||||
#toolbox-dock-buttons > button {
|
||||
-moz-appearance: none;
|
||||
|
@ -263,7 +297,16 @@
|
|||
background-image: url("chrome://devtools/skin/images/dock-bottom-maximize@2x.png");
|
||||
}
|
||||
|
||||
#toolbox-buttons:empty + .devtools-separator,
|
||||
/**
|
||||
* Ensure that when the toolbar collapses in on itself when there is not enough room
|
||||
* that it still looks reasonable.
|
||||
*/
|
||||
.devtools-tabbar > div {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
z-index: 0;
|
||||
}
|
||||
|
||||
#toolbox-buttons-end:empty + .devtools-separator,
|
||||
.devtools-separator[invisible] {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
@ -293,12 +336,12 @@
|
|||
}
|
||||
|
||||
.command-button:hover:active,
|
||||
.command-button[checked=true]:not(:hover) {
|
||||
.command-button.checked:not(:hover) {
|
||||
background-color: var(--toolbar-tab-hover-active)
|
||||
}
|
||||
|
||||
.theme-light .command-button:hover:active,
|
||||
.theme-light .command-button[checked=true]:not(:hover) {
|
||||
.theme-light .command-button.checked:not(:hover) {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
|
@ -307,8 +350,8 @@
|
|||
}
|
||||
|
||||
.command-button:hover:active::before,
|
||||
.command-button[checked=true]::before,
|
||||
.command-button[open=true]::before {
|
||||
.command-button.checked::before,
|
||||
.command-button.open::before {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -85,17 +85,15 @@ function runTest() {
|
|||
webconsoleHeight: webconsoleHeight,
|
||||
splitterVisibility: splitterVisibility,
|
||||
openedConsolePanel: openedConsolePanel,
|
||||
buttonSelected: cmdButton.hasAttribute("checked")
|
||||
buttonSelected: cmdButton.classList.contains("checked")
|
||||
};
|
||||
}
|
||||
|
||||
function checkWebconsolePanelOpened() {
|
||||
const checkWebconsolePanelOpened = Task.async(function* () {
|
||||
info("About to check special cases when webconsole panel is open.");
|
||||
|
||||
let deferred = promise.defer();
|
||||
|
||||
// Start with console split, so we can test for transition to main panel.
|
||||
toolbox.toggleSplitConsole();
|
||||
yield toolbox.toggleSplitConsole();
|
||||
|
||||
let currentUIState = getCurrentUIState();
|
||||
|
||||
|
@ -109,78 +107,54 @@ function runTest() {
|
|||
"The console panel is not the current tool");
|
||||
ok(currentUIState.buttonSelected, "The command button is selected");
|
||||
|
||||
openPanel("webconsole").then(() => {
|
||||
currentUIState = getCurrentUIState();
|
||||
yield openPanel("webconsole");
|
||||
currentUIState = getCurrentUIState();
|
||||
|
||||
ok(!currentUIState.splitterVisibility,
|
||||
"Splitter is hidden when console is opened.");
|
||||
is(currentUIState.deckHeight, 0,
|
||||
"Deck has a height == 0 when console is opened.");
|
||||
is(currentUIState.webconsoleHeight, currentUIState.containerHeight,
|
||||
"Web console is full height.");
|
||||
ok(currentUIState.openedConsolePanel,
|
||||
"The console panel is the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
ok(!currentUIState.splitterVisibility,
|
||||
"Splitter is hidden when console is opened.");
|
||||
is(currentUIState.deckHeight, 0,
|
||||
"Deck has a height == 0 when console is opened.");
|
||||
is(currentUIState.webconsoleHeight, currentUIState.containerHeight,
|
||||
"Web console is full height.");
|
||||
ok(currentUIState.openedConsolePanel,
|
||||
"The console panel is the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
|
||||
// Make sure splitting console does nothing while webconsole is opened
|
||||
toolbox.toggleSplitConsole();
|
||||
// Make sure splitting console does nothing while webconsole is opened
|
||||
yield toolbox.toggleSplitConsole();
|
||||
|
||||
currentUIState = getCurrentUIState();
|
||||
currentUIState = getCurrentUIState();
|
||||
|
||||
ok(!currentUIState.splitterVisibility,
|
||||
"Splitter is hidden when console is opened.");
|
||||
is(currentUIState.deckHeight, 0,
|
||||
"Deck has a height == 0 when console is opened.");
|
||||
is(currentUIState.webconsoleHeight, currentUIState.containerHeight,
|
||||
"Web console is full height.");
|
||||
ok(currentUIState.openedConsolePanel,
|
||||
"The console panel is the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
ok(!currentUIState.splitterVisibility,
|
||||
"Splitter is hidden when console is opened.");
|
||||
is(currentUIState.deckHeight, 0,
|
||||
"Deck has a height == 0 when console is opened.");
|
||||
is(currentUIState.webconsoleHeight, currentUIState.containerHeight,
|
||||
"Web console is full height.");
|
||||
ok(currentUIState.openedConsolePanel,
|
||||
"The console panel is the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
|
||||
// Make sure that split state is saved after opening another panel
|
||||
openPanel("inspector").then(() => {
|
||||
currentUIState = getCurrentUIState();
|
||||
ok(currentUIState.splitterVisibility,
|
||||
"Splitter is visible when console is split");
|
||||
ok(currentUIState.deckHeight > 0,
|
||||
"Deck has a height > 0 when console is split");
|
||||
ok(currentUIState.webconsoleHeight > 0,
|
||||
"Web console has a height > 0 when console is split");
|
||||
ok(!currentUIState.openedConsolePanel,
|
||||
"The console panel is not the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
// Make sure that split state is saved after opening another panel
|
||||
yield openPanel("inspector");
|
||||
currentUIState = getCurrentUIState();
|
||||
ok(currentUIState.splitterVisibility,
|
||||
"Splitter is visible when console is split");
|
||||
ok(currentUIState.deckHeight > 0,
|
||||
"Deck has a height > 0 when console is split");
|
||||
ok(currentUIState.webconsoleHeight > 0,
|
||||
"Web console has a height > 0 when console is split");
|
||||
ok(!currentUIState.openedConsolePanel,
|
||||
"The console panel is not the current tool");
|
||||
ok(currentUIState.buttonSelected,
|
||||
"The command button is still selected.");
|
||||
|
||||
toolbox.toggleSplitConsole();
|
||||
deferred.resolve();
|
||||
});
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
yield toolbox.toggleSplitConsole();
|
||||
});
|
||||
|
||||
function openPanel(toolId) {
|
||||
let deferred = promise.defer();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, toolId).then(function (box) {
|
||||
toolbox = box;
|
||||
deferred.resolve();
|
||||
}).then(null, console.error);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function openAndCheckPanel(toolId) {
|
||||
let deferred = promise.defer();
|
||||
openPanel(toolId).then(() => {
|
||||
info("Checking toolbox for " + toolId);
|
||||
checkToolboxUI(toolbox.getCurrentPanel());
|
||||
deferred.resolve();
|
||||
});
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function checkToolboxUI() {
|
||||
const checkToolboxUI = Task.async(function* () {
|
||||
let currentUIState = getCurrentUIState();
|
||||
|
||||
ok(!currentUIState.splitterVisibility, "Splitter is hidden by default");
|
||||
|
@ -192,7 +166,7 @@ function runTest() {
|
|||
"The console panel is not the current tool");
|
||||
ok(!currentUIState.buttonSelected, "The command button is not selected.");
|
||||
|
||||
toolbox.toggleSplitConsole();
|
||||
yield toolbox.toggleSplitConsole();
|
||||
|
||||
currentUIState = getCurrentUIState();
|
||||
|
||||
|
@ -209,7 +183,7 @@ function runTest() {
|
|||
"The console panel is not the current tool");
|
||||
ok(currentUIState.buttonSelected, "The command button is selected.");
|
||||
|
||||
toolbox.toggleSplitConsole();
|
||||
yield toolbox.toggleSplitConsole();
|
||||
|
||||
currentUIState = getCurrentUIState();
|
||||
|
||||
|
@ -221,6 +195,23 @@ function runTest() {
|
|||
ok(!currentUIState.openedConsolePanel,
|
||||
"The console panel is not the current tool");
|
||||
ok(!currentUIState.buttonSelected, "The command button is not selected.");
|
||||
});
|
||||
|
||||
function openPanel(toolId) {
|
||||
let deferred = promise.defer();
|
||||
let target = TargetFactory.forTab(gBrowser.selectedTab);
|
||||
gDevTools.showToolbox(target, toolId).then(function (box) {
|
||||
toolbox = box;
|
||||
deferred.resolve();
|
||||
}).then(null, console.error);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function openAndCheckPanel(toolId) {
|
||||
return openPanel(toolId).then(() => {
|
||||
info("Checking toolbox for " + toolId);
|
||||
return checkToolboxUI(toolbox.getCurrentPanel());
|
||||
});
|
||||
}
|
||||
|
||||
function testBottomHost() {
|
||||
|
|
|
@ -99,7 +99,7 @@
|
|||
|
||||
function isCommandButtonChecked() {
|
||||
return toolbox.doc.querySelector("#command-button-splitconsole")
|
||||
.hasAttribute("checked");
|
||||
.classList.contains("checked");
|
||||
}
|
||||
|
||||
function toggleSplitConsoleWithEscape() {
|
||||
|
|
Загрузка…
Ссылка в новой задаче