/* 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";
// Make this available to both AMD and CJS environments
define(function (require, exports, module) { const {
Component,
createFactory,
createRef,
} = require("resource://devtools/client/shared/vendor/react.js"); const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js"); const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); const {
findDOMNode,
} = require("resource://devtools/client/shared/vendor/react-dom.js"); const { tr } = dom;
// Child components might add/remove new focusable elements, watch for the // additions/removals of descendant nodes and update focusable state. const win = this.treeRowRef.current.ownerDocument.defaultView; const { MutationObserver } = win; this.observer = new MutationObserver(() => { this._setTabbableState();
}); this.observer.observe(this.treeRowRef.current, {
childList: true,
subtree: true,
});
}
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillReceiveProps(nextProps) { // I don't like accessing the underlying DOM elements directly, // but this optimization makes the filtering so damn fast! // The row doesn't have to be re-rendered, all we really need // to do is toggling a class name. // The important part is that DOM elements don't need to be // re-created when they should appear again. if (nextProps.member.hidden != this.props.member.hidden) { const row = findDOMNode(this);
row.classList.toggle("hidden");
}
}
/** * Optimize row rendering. If props are the same do not render. * This makes the rendering a lot faster!
*/
shouldComponentUpdate(nextProps) { for (const prop of UPDATE_ON_PROPS) { if (nextProps.member[prop] !== this.props.member[prop]) { returntrue;
}
}
/** * Makes sure that none of the focusable elements inside the row container * are tabbable if the row is not active. If the row is active and focus * is outside its container, focus on the first focusable element inside.
*/
_setTabbableState() { const elms = getFocusableElements(this.treeRowRef.current); if (elms.length === 0) { return;
}
const { active } = this.props.member; if (!active) {
elms.forEach(elm => elm.setAttribute("tabindex", "-1")); return;
}
if (!elms.includes(document.activeElement)) {
elms[0].focus();
}
}
const focusMoved = !!wrapMoveFocus(
getFocusableElements(this.treeRowRef.current),
target,
shiftKey
); if (focusMoved) { // Focus was moved to the begining/end of the list, so we need to // prevent the default focus change that would happen here.
e.preventDefault();
}
// Compute class name list for the <tr> element. const classNames = this.getRowClass(member.object) || [];
classNames.push("treeRow");
classNames.push(member.type + "Row");
if (member.hasChildren) {
classNames.push("hasChildren");
// There are 2 situations where hasChildren is true: // 1. it is an object with children. Only set aria-expanded in this situation // 2. It is a long string (> 50 chars) that can be expanded to fully display it if (member.type !== "string") {
props["aria-expanded"] = member.open;
}
}
if (member.open) {
classNames.push("opened");
}
if (member.loading) {
classNames.push("loading");
}
if (member.selected) {
classNames.push("selected");
}
if (member.hidden) {
classNames.push("hidden");
}
props.className = classNames.join(" ");
// The label column (with toggle buttons) is usually // the first one, but there might be cases (like in // the Memory panel) where the toggling is done // in the last column. const cells = [];
// Get components for rendering cells.
let renderCell = this.props.renderCell || RenderCell;
let renderLabelCell = this.props.renderLabelCell || RenderLabelCell; if (decorator?.renderLabelCell) {
renderLabelCell =
decorator.renderLabelCell(member.object) || renderLabelCell;
}
// Render a cell for every column. this.props.columns.forEach(col => { const cellProps = Object.assign({}, this.props, {
key: col.id,
id: col.id,
value: this.props.provider.getValue(member.object, col.id),
});
if (decorator?.renderCell) {
renderCell = decorator.renderCell(member.object, col.id);
}
// Some cells don't have to be rendered. This happens when some // other cells span more columns. Note that the label cells contains // toggle buttons and should be usually there unless we are rendering // a simple non-expandable table. if (render) {
cells.push(render(cellProps));
}
});
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.