Bug 1369945 - Display a split rule view panel in the inspector. r=bgrins

MozReview-Commit-ID: If55vBPfU3W
This commit is contained in:
Gabriel Luong 2017-11-27 15:54:18 -05:00
Родитель e2cb498414
Коммит f353991f53
12 изменённых файлов: 252 добавлений и 69 удалений

Просмотреть файл

@ -117,6 +117,6 @@ const selectNodeAndWaitForAnimations = async function (data, inspector, reason =
*/
const setSidebarWidth = async function (width, inspector) {
const onUpdated = inspector.toolbox.once("inspector-sidebar-resized");
inspector._splitter.setState({ width });
inspector.splitBox.setState({ width });
await onUpdated;
};

Просмотреть файл

@ -166,7 +166,9 @@ class FontInspector {
if (!fonts || !fonts.length) {
// No fonts to display. Clear the previously shown fonts.
this.store.dispatch(updateFonts(fonts));
if (this.store) {
this.store.dispatch(updateFonts(fonts));
}
return;
}

Просмотреть файл

@ -13,24 +13,22 @@ const promise = require("promise");
const EventEmitter = require("devtools/shared/old-event-emitter");
const {executeSoon} = require("devtools/shared/DevToolsUtils");
const {Task} = require("devtools/shared/task");
// Use privileged promise in panel documents to prevent having them to freeze
// during toolbox destruction. See bug 1402779.
const Promise = require("Promise");
// constructor
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");
// Use privileged promise in panel documents to prevent having them to freeze
// during toolbox destruction. See bug 1402779.
const Promise = require("Promise");
loader.lazyRequireGetter(this, "initCssProperties", "devtools/shared/fronts/css-properties", true);
loader.lazyRequireGetter(this, "HTMLBreadcrumbs", "devtools/client/inspector/breadcrumbs", true);
loader.lazyRequireGetter(this, "KeyShortcuts", "devtools/client/shared/key-shortcuts");
loader.lazyRequireGetter(this, "InspectorSearch", "devtools/client/inspector/inspector-search", true);
loader.lazyRequireGetter(this, "ToolSidebar", "devtools/client/inspector/toolsidebar", true);
loader.lazyRequireGetter(this, "MarkupView", "devtools/client/inspector/markup/markup");
loader.lazyRequireGetter(this, "nodeConstants", "devtools/shared/dom-node-constants");
loader.lazyRequireGetter(this, "Menu", "devtools/client/framework/menu");
loader.lazyRequireGetter(this, "MenuItem", "devtools/client/framework/menu-item");
@ -50,7 +48,10 @@ 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;
const PORTRAIT_MODE_WIDTH = 800;
const SHOW_SPLIT_SIDEBAR_TOGGLE_PREF = "devtools.inspector.split-sidebar-toggle";
const SPLIT_RULE_VIEW_PREF = "devtools.inspector.split-rule-enabled";
/**
* Represents an open instance of the Inspector for a tab.
@ -102,6 +103,7 @@ function Inspector(toolbox) {
this._panels = new Map();
this.highlighters = new HighlightersOverlay(this);
this.prefsObserver = new PrefObserver("devtools.");
this.reflowTracker = new ReflowTracker(this._target);
this.store = Store();
this.telemetry = new Telemetry();
@ -110,6 +112,10 @@ function Inspector(toolbox) {
// 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.nodeMenuTriggerInfo = null;
this._handleRejectionIfNotDestroyed = this._handleRejectionIfNotDestroyed.bind(this);
@ -129,8 +135,11 @@ function Inspector(toolbox) {
this.onSidebarResized = this.onSidebarResized.bind(this);
this.onSidebarSelect = this.onSidebarSelect.bind(this);
this.onSidebarShown = this.onSidebarShown.bind(this);
this.onSidebarToggle = this.onSidebarToggle.bind(this);
this.onSplitRuleViewPrefChanged = this.onSplitRuleViewPrefChanged.bind(this);
this._target.on("will-navigate", this._onBeforeNavigate);
this.prefsObserver.on(SPLIT_RULE_VIEW_PREF, this.onSplitRuleViewPrefChanged);
}
Inspector.prototype = {
@ -453,25 +462,40 @@ Inspector.prototype = {
setupSplitter: function () {
let SplitBox = this.React.createFactory(this.browserRequire(
"devtools/client/shared/components/splitter/SplitBox"));
let { width, height, splitSidebarWidth } = this.getSidebarSize();
let { width, height } = this.getSidebarSize();
let splitter = SplitBox({
className: "inspector-sidebar-splitter",
initialWidth: width,
initialHeight: height,
minSize: "10%",
maxSize: "80%",
splitterSize: 1,
endPanelControl: true,
startPanel: this.InspectorTabPanel({
id: "inspector-main-content"
}),
endPanel: this.InspectorTabPanel({
id: "inspector-sidebar-container"
endPanel: SplitBox({
initialWidth: splitSidebarWidth,
minSize: 10,
maxSize: "80%",
splitterSize: this.isSplitRuleViewEnabled ? 1 : 0,
endPanelControl: false,
startPanel: this.InspectorTabPanel({
id: "inspector-rules-container"
}),
endPanel: this.InspectorTabPanel({
id: "inspector-sidebar-container"
}),
ref: splitbox => {
this.sidebarSplitBox = splitbox;
},
}),
vert: this.useLandscapeMode(),
onControlledPanelResized: this.onSidebarResized,
});
this._splitter = this.ReactDOM.render(splitter,
this.splitBox = this.ReactDOM.render(splitter,
this.panelDoc.getElementById("inspector-splitter-box"));
this.panelWin.addEventListener("resize", this.onPanelWindowResize, true);
@ -493,7 +517,7 @@ Inspector.prototype = {
* to `horizontal` to support portrait view.
*/
onPanelWindowResize: function () {
this._splitter.setState({
this.splitBox.setState({
vert: this.useLandscapeMode(),
});
},
@ -501,31 +525,42 @@ Inspector.prototype = {
getSidebarSize: function () {
let width;
let height;
let splitSidebarWidth;
// Initialize splitter size from preferences.
try {
width = Services.prefs.getIntPref("devtools.toolsidebar-width.inspector");
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 = INITIAL_SIDEBAR_SIZE;
width = this.isSplitRuleViewEnabled ?
INITIAL_SIDEBAR_SIZE * 2 : INITIAL_SIDEBAR_SIZE;
height = INITIAL_SIDEBAR_SIZE;
splitSidebarWidth = INITIAL_SIDEBAR_SIZE;
}
return { width, height };
},
onSidebarShown: function () {
this._splitter.setState(this.getSidebarSize());
return { width, height, splitSidebarWidth };
},
onSidebarHidden: function () {
// Store the current splitter size to preferences.
let state = this._splitter.state;
let state = this.splitBox.state;
Services.prefs.setIntPref("devtools.toolsidebar-width.inspector", state.width);
Services.prefs.setIntPref("devtools.toolsidebar-height.inspector", state.height);
if (this.isSplitRuleViewEnabled) {
Services.prefs.setIntPref("devtools.toolsidebar-width.inspector.splitsidebar",
this.sidebarSplitBox.state.width);
}
},
onSidebarResized: function (width, height) {
this.toolbox.emit("inspector-sidebar-resized", { width, height });
},
onSidebarSelect: function (event, toolId) {
@ -539,8 +574,83 @@ Inspector.prototype = {
this.toolbox.emit("inspector-sidebar-select", toolId);
},
onSidebarResized: function (width, height) {
this.toolbox.emit("inspector-sidebar-resized", { width, height });
onSidebarShown: function () {
let { width, height, splitSidebarWidth } = this.getSidebarSize();
this.splitBox.setState({ width, height });
this.sidebarSplitBox.setState({ width: splitSidebarWidth });
},
onSidebarToggle: function () {
Services.prefs.setBoolPref(SPLIT_RULE_VIEW_PREF, !this.isSplitRuleViewEnabled);
},
async onSplitRuleViewPrefChanged() {
// Update the stored value of the split rule view preference since it changed.
this.isSplitRuleViewEnabled = Services.prefs.getBoolPref(SPLIT_RULE_VIEW_PREF);
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.
*
* @params {String} defaultTab
* Thie id of the default tab for the sidebar.
*/
async addRuleView(defaultTab = "ruleview") {
let ruleViewSidebar = this.sidebarSplitBox.startPanelContainer;
if (this.isSplitRuleViewEnabled) {
// Removes the rule view from the main sidebar and adds the rule view to the split
// sidebar.
ruleViewSidebar.style.display = "block";
// The sidebar toggle might not be setup yet on the initial setup.
if (this.sidebarToggle) {
this.sidebarToggle.setState({ collapsed: false });
}
// Show the splitter inside the sidebar split box.
this.sidebarSplitBox.setState({ splitterSize: 1 });
// 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.
ruleViewSidebar.style.display = "none";
// The sidebar toggle might not be setup yet on the initial setup.
if (this.sidebarToggle) {
this.sidebarToggle.setState({ collapsed: true });
}
// Hide the splitter to prevent any drag events in the sidebar split box.
this.sidebarSplitBox.setState({ splitterSize: 0 });
this.ruleViewSideBar.hide();
await this.ruleViewSideBar.removeTab("ruleview");
this.sidebar.addExistingTab(
"ruleview",
INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"),
defaultTab == "ruleview",
0);
}
},
/**
@ -578,20 +688,28 @@ Inspector.prototype = {
/**
* Build the sidebar.
*/
setupSidebar: function () {
let tabbox = this.panelDoc.querySelector("#inspector-sidebar");
this.sidebar = new ToolSidebar(tabbox, this, "inspector", {
async setupSidebar() {
let sidebar = this.panelDoc.getElementById("inspector-sidebar");
this.sidebar = new ToolSidebar(sidebar, this, "inspector", {
showAllTabsMenu: true
});
let ruleSideBar = this.panelDoc.getElementById("inspector-rules-sidebar");
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") {
defaultTab = "computedview";
}
// Append all side panels
this.sidebar.addExistingTab(
"ruleview",
INSPECTOR_L10N.getStr("inspector.sidebar.ruleViewTitle"),
defaultTab == "ruleview");
await this.addRuleView(defaultTab);
this.sidebar.addExistingTab(
"computedview",
@ -876,6 +994,22 @@ Inspector.prototype = {
eyeDropperButton.disabled = true;
eyeDropperButton.title = INSPECTOR_L10N.getStr("eyedropper.disabled.title");
}
// Setup the sidebar toggle button if the split rule view is enabled.
if (this.showSplitSidebarToggle && !this.sidebarToggle) {
let SidebarToggle = this.React.createFactory(this.browserRequire(
"devtools/client/shared/components/SidebarToggle"));
let sidebarToggle = SidebarToggle({
collapsed: !this.isSplitRuleViewEnabled,
collapsePaneTitle: INSPECTOR_L10N.getStr("inspector.hideSplitRulesView"),
expandPaneTitle: INSPECTOR_L10N.getStr("inspector.showSplitRulesView"),
onClick: this.onSidebarToggle
});
let parentBox = this.panelDoc.getElementById("inspector-sidebar-toggle-box");
this.sidebarToggle = this.ReactDOM.render(sidebarToggle, parentBox);
}
}),
teardownToolbar: function () {
@ -1130,6 +1264,7 @@ Inspector.prototype = {
this.cancelUpdate();
this.prefsObserver.off(SPLIT_RULE_VIEW_PREF, this.onSplitRuleViewPrefChanged);
this.target.off("will-navigate", this._onBeforeNavigate);
this.target.off("thread-paused", this.updateDebuggerPausedWarning);
this.target.off("thread-resumed", this.updateDebuggerPausedWarning);
@ -1161,6 +1296,9 @@ Inspector.prototype = {
this.sidebar.off("select", this.onSidebarSelect);
let sidebarDestroyer = this.sidebar.destroy();
let ruleViewSideBarDestroyer = this.ruleViewSideBar ?
this.ruleViewSideBar.destroy() : null;
this.teardownSplitter();
this.teardownToolbar();
@ -1171,25 +1309,29 @@ Inspector.prototype = {
let markupDestroyer = this._destroyMarkup();
this.highlighters.destroy();
this.prefsObserver.destroy();
this.reflowTracker.destroy();
this.search.destroy();
this._toolbox = null;
this.breadcrumbs = null;
this.highlighters = null;
this.panelDoc = null;
this.panelWin.inspector = null;
this.panelWin = null;
this.prefsObserver = null;
this.resultsLength = null;
this.search = null;
this.searchBox = null;
this.sidebar = null;
this.store = null;
this.target = null;
this.highlighters = null;
this.search = null;
this.searchBox = null;
this._panelDestroyer = promise.all([
sidebarDestroyer,
cssPropertiesDestroyer,
markupDestroyer,
cssPropertiesDestroyer
sidebarDestroyer,
ruleViewSideBarDestroyer
]);
return this._panelDestroyer;

Просмотреть файл

@ -18,6 +18,7 @@
<link rel="stylesheet" href="chrome://devtools/skin/animation.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/Tabs.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/tabs/TabBar.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/SidebarToggle.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/components/InspectorTabPanel.css"/>
<link rel="stylesheet" href="resource://devtools/client/shared/components/splitter/SplitBox.css"/>
<link rel="stylesheet" href="resource://devtools/client/inspector/layout/components/Accordion.css"/>
@ -37,7 +38,7 @@
}
</script>
<!-- in content, inspector.js is mapped to the dynamically generated webpack bundle -->
<!-- In content, inspector.js is mapped to the dynamically generated webpack bundle -->
<script type="application/javascript" src="inspector.js" defer="true"></script>
</head>
<body class="theme-body" role="application">
@ -45,6 +46,7 @@
<!-- Main Panel Content -->
<div id="inspector-main-content" class="devtools-main-content" style="visibility: hidden;">
<!-- Toolbar -->
<div id="inspector-toolbar" class="devtools-toolbar" nowindowdrag="true"
data-localization-bundle="devtools/client/locales/inspector.properties">
<button id="inspector-element-add-button" class="devtools-button"
@ -58,7 +60,10 @@
<button id="inspector-searchinput-clear" class="devtools-searchinput-clear" tabindex="-1"></button>
</div>
<button id="inspector-eyedropper-toggle" class="devtools-button"></button>
<div id="inspector-sidebar-toggle-box"></div>
</div>
<!-- Markup Container -->
<div id="markup-box"></div>
<div id="inspector-breadcrumbs-toolbar" class="devtools-toolbar">
<div id="inspector-breadcrumbs" class="breadcrumbs-widget-container"
@ -67,16 +72,20 @@
</div>
<!-- Splitter -->
<div xmlns="http://www.w3.org/1999/xhtml" id="inspector-splitter-box">
<div id="inspector-splitter-box"></div>
<!-- Split Sidebar Container -->
<div id="inspector-rules-container">
<div id="inspector-rules-sidebar" hidden="true"></div>
</div>
<!-- Sidebar Container -->
<div id="inspector-sidebar-container">
<div xmlns="http://www.w3.org/1999/xhtml" id="inspector-sidebar" hidden="true"></div>
<div id="inspector-sidebar" hidden="true"></div>
</div>
<!-- Sidebar panel definitions -->
<div id="tabpanels" style="visibility:collapse">
<!-- Sidebar Panel Definitions -->
<div id="tabpanels" style="visibility: collapse">
<div id="sidebar-panel-ruleview" class="theme-sidebar inspector-tabpanel"
data-localization-bundle="devtools/client/locales/inspector.properties">
<div id="ruleview-toolbar-container" class="devtools-toolbar">

Просмотреть файл

@ -1607,11 +1607,11 @@ function RuleViewTool(inspector, window) {
this.onViewRefreshed = this.onViewRefreshed.bind(this);
this.view.on("ruleview-refreshed", this.onViewRefreshed);
this.inspector.selection.on("detached-front", this.onSelected);
this.inspector.selection.on("new-node-front", this.onSelected);
this.inspector.selection.on("pseudoclass", this.refresh);
this.inspector.target.on("navigate", this.clearUserProperties);
this.inspector.ruleViewSideBar.on("ruleview-selected", this.onPanelSelected);
this.inspector.sidebar.on("ruleview-selected", this.onPanelSelected);
this.inspector.pageStyle.on("stylesheet-updated", this.refresh);
this.inspector.walker.on("mutations", this.onMutations);
@ -1625,7 +1625,9 @@ RuleViewTool.prototype = {
if (!this.view) {
return false;
}
return this.inspector.sidebar.getCurrentTabID() == "ruleview";
return this.inspector.isSplitRuleViewEnabled ?
true : this.inspector.sidebar.getCurrentTabID() == "ruleview";
},
onSelected: function (event) {

Просмотреть файл

@ -32,10 +32,6 @@ const NODES = [
];
add_task(function* () {
// This test needs specific initial size of the sidebar.
yield pushPref("devtools.toolsidebar-width.inspector", 350);
yield pushPref("devtools.toolsidebar-height.inspector", 150);
let { inspector, toolbox } = yield openInspectorForURL(TEST_URI);
// No way to wait for scrolling to end (Bug 1172171)

Просмотреть файл

@ -65,6 +65,14 @@ eventsTooltip.Bubbling=Bubbling
#LOCALIZATION NOTE: Used in the tooltip for Capturing
eventsTooltip.Capturing=Capturing
# LOCALIZATION NOTE (inspector.displaySplitRulesView): This is the tooltip for the button
# that toggles on the display of a split rule view sidebar in the inspector.
inspector.showSplitRulesView=Show the split Rules panel
# LOCALIZATION NOTE (inspector.hideSplitRulesView): This is the tooltip for the button
# that toggles off the display of a split rule view sidebar in the inspector.
inspector.hideSplitRulesView=Hide the split Rules panel
# LOCALIZATION NOTE (inspector.searchResultsCount): This is the label that
# will show up next to the inspector search box. %1$S is the current result
# index and %2$S is the total number of search results. For example: "3 of 9".

Просмотреть файл

@ -48,6 +48,10 @@ 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);
// 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
@ -68,7 +72,6 @@ pref("devtools.changesview.enabled", false);
pref("devtools.eventsview.enabled", false);
// Enable the Flexbox Inspector panel
pref("devtools.flexboxinspector.enabled", false);
// Enable the new Animation Inspector
pref("devtools.new-animationinspector.enabled", false);

Просмотреть файл

@ -64,6 +64,7 @@ class SplitBox extends Component {
*/
this.state = {
vert: props.vert,
splitterSize: props.splitterSize,
width: props.initialWidth || props.initialSize,
height: props.initialHeight || props.initialSize
};
@ -74,7 +75,11 @@ class SplitBox extends Component {
}
componentWillReceiveProps(nextProps) {
let { vert } = nextProps;
let { splitterSize, vert } = nextProps;
if (splitterSize != this.props.splitterSize) {
this.setState({ splitterSize });
}
if (vert !== this.props.vert) {
this.setState({ vert });
@ -85,12 +90,12 @@ class SplitBox extends Component {
return nextState.width != this.state.width ||
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 ||
nextProps.splitterSize != this.props.splitterSize;
nextProps.maxSize != this.props.maxSize;
}
componentDidUpdate(prevProps, prevState) {
@ -170,9 +175,8 @@ class SplitBox extends Component {
// Rendering
render() {
const vert = this.state.vert;
const { startPanel, endPanel, endPanelControl, minSize,
maxSize, splitterSize } = this.props;
const { splitterSize, vert } = this.state;
const { startPanel, endPanel, endPanelControl, minSize, maxSize } = this.props;
let style = Object.assign({}, this.props.style);
@ -223,20 +227,27 @@ class SplitBox extends Component {
startPanel ?
dom.div({
className: endPanelControl ? "uncontrolled" : "controlled",
style: leftPanelStyle},
style: leftPanelStyle,
ref: div => {
this.startPanelContainer = div;
}},
startPanel
) : null,
Draggable({
className: "splitter",
style: splitterStyle,
onStart: this.onStartMove,
onStop: this.onStopMove,
onMove: this.onMove
}),
splitterSize > 0 ?
Draggable({
className: "splitter",
style: splitterStyle,
onStart: this.onStartMove,
onStop: this.onStopMove,
onMove: this.onMove
}) : null,
endPanel ?
dom.div({
className: endPanelControl ? "controlled" : "uncontrolled",
style: rightPanelStyle},
style: rightPanelStyle,
ref: div => {
this.endPanelContainer = div;
}},
endPanel
) : null
)

Просмотреть файл

@ -3,6 +3,11 @@
* 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/. */
/* Hides the tab strip in the TabBar */
div[hidetabs=true] .tabs .tabs-navigation {
display: none;
}
.tabs .tabs-navigation {
line-height: 15px;
}

Просмотреть файл

@ -142,16 +142,19 @@ class Tabbar extends Component {
let tabs = this.state.tabs.slice();
tabs.splice(index, 1);
let activeTab = this.state.activeTab;
if (activeTab >= tabs.length) {
activeTab = tabs.length - 1;
}
let activeTab = this.state.activeTab - 1;
activeTab = activeTab === -1 ? 0 : activeTab;
this.setState(Object.assign({}, this.state, {
tabs,
activeTab,
}));
tabs,
}), () => {
// Select the next active tab and force the select event handler to initialize
// the panel if needed.
if (tabs.length > 0 && this.props.onSelect) {
this.props.onSelect(this.getTabId(activeTab));
}
});
}
select(tabId) {

Просмотреть файл

@ -157,12 +157,14 @@ window {
font: message-box;
}
#inspector-rules-container,
#inspector-sidebar-container {
overflow: hidden;
position: relative;
height: 100%;
}
#inspector-rules-sidebar,
#inspector-sidebar {
position: absolute;
top: 0;