/* 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/. */
// To render a sidebar toggle button before the tab menu provide a function that // returns a React component for the button.
renderSidebarToggle: PropTypes.func, // Set true will only render selected panel on DOM. It's complete // opposite of the created array, and it's useful if panels content // is unpredictable and update frequently.
renderOnlySelected: PropTypes.bool,
};
}
// This array is used to store an object containing information on whether a tab // at a specified index has already been created (e.g. selected at least once) and // the tab id. An example of the object structure is the following: // [{ isCreated: true, tabId: "ruleview" }, { isCreated: false, tabId: "foo" }]. // If the tab at the specified index has already been created, it's rendered even // if not currently selected. This is because in some cases we don't want // to re-create tab content when it's being unselected/selected. // E.g. in case of an iframe being used as a tab-content we want the iframe to // stay in the DOM.
created: [],
// True if tabs can't fit into available horizontal space.
overflow: false,
};
// Register overflow listeners to manage visibility // of all-tabs-menu. This menu is displayed when there // is not enough h-space to render all tabs. // It allows the user to select a tab even if it's hidden. if (this.props.showAllTabsMenu) {
node.addEventListener("overflow", this.onOverflow);
node.addEventListener("underflow", this.onUnderflow);
}
const index = this.state.activeTab; if (this.props.onMount) { this.props.onMount(index);
}
}
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillReceiveProps(nextProps) {
let { children, activeTab } = nextProps; const panels = children.filter(panel => panel);
let created = [...this.state.created];
// If the children props has changed due to an addition or removal of a tab, // update the state's created array with the latest tab ids and whether or not // the tab is already created. if (this.state.created.length != panels.length) {
created = panels.map(panel => { // Get whether or not the tab has already been created from the previous state. const createdEntry = this.state.created.find(entry => { return entry && entry.tabId === panel.props.id;
}); const isCreated = !!createdEntry && createdEntry.isCreated; const tabId = panel.props.id;
return {
isCreated,
tabId,
};
});
}
// Check type of 'activeTab' props to see if it's valid (it's 0-based index). if (typeof activeTab === "number") { // Reset to index 0 if index overflows the range of panel array
activeTab = activeTab < panels.length && activeTab >= 0 ? activeTab : 0;
onMouseDown(event) { // Prevents click-dragging the tab headers if (event) {
event.preventDefault();
}
}
// API
/** * Set the active tab from its index * * @param {Integer} index * Index of the tab that we want to set as the active one * @param {Object} options * @param {Boolean} options.fromMouseEvent * Set to true if this is called from a click on the tab
*/
setActive(index, options = {}) { const onAfterChange = this.props.onAfterChange; const onBeforeChange = this.props.onBeforeChange;
if (onBeforeChange) { const cancel = onBeforeChange(index); if (cancel) { return;
}
}
this.setState(newState, () => { // Properly set focus on selected tab. const selectedTab = this.tabsEl.current.querySelector(
`a[data-tab-index="${index}"]`
);
selectedTab.focus({ // When focus is coming from a mouse event, // prevent :focus-visible to be applied to the element
focusVisible: !options.fromMouseEvent,
});
if (onAfterChange) {
onAfterChange(index);
}
});
}
// Rendering
renderMenuItems() { if (!this.props.children) { thrownew Error("There must be at least one Tab");
}
if (!Array.isArray(this.props.children)) { this.props.children = [this.props.children];
}
// Set tabindex to -1 (except the selected tab) so, it's focusable, // but not reachable via sequential tab-key navigation. // Changing selected tab (and so, moving focus) is done through // left and right arrow keys. // See also `onKeyDown()` event handler. return dom.li(
{
className,
key: index,
ref,
role: "presentation",
},
dom.span({ className: "devtools-tab-line" }),
dom.a(
{
id: id ? id + "-tab" : "tab-" + index,
tabIndex: isTabSelected ? 0 : -1,
title, "aria-controls": id ? id + "-panel" : "panel-" + index, "aria-selected": isTabSelected,
role: "tab",
onClick: this.onClickTab.bind(this, index),
onMouseDown: this.onMouseDown.bind(this), "data-tab-index": index,
},
title,
badge && !isTabSelected && showBadge()
? dom.span({ className: "tab-badge" }, badge)
: null
)
);
});
// Display the menu only if there is not enough horizontal // space for all tabs (and overflow happened). const allTabsMenu = this.state.overflow
? dom.button({
className: "all-tabs-menu",
title: this.props.allTabsMenuButtonTooltip,
onClick: this.props.onAllTabsMenuClick,
})
: null;
// Get the sidebar toggle button if a renderSidebarToggle function is provided. const sidebarToggle = this.props.renderSidebarToggle
? this.props.renderSidebarToggle()
: null;
const id = tab.props.id; const isCreated = this.state.created[index] && this.state.created[index].isCreated;
// Use 'visibility:hidden' + 'height:0' for hiding content of non-selected // tab. It's faster than 'display:none' because it avoids triggering frame // destruction and reconstruction. 'width' is not changed to avoid relayout. const style = {
visibility: selected ? "visible" : "hidden",
height: selected ? "100%" : "0",
};
// Allows lazy loading panels by creating them only if they are selected, // then store a copy of the lazy created panel in `tab.panel`. if (typeof tab.panel == "function" && selected) {
tab.panel = tab.panel(tab);
} const panel = tab.panel || tab;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.