Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/devtools/client/shared/components/tree/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 8 kB image not shown  

Quelle  TreeRow.js   Sprache: JAVA

 
/* 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;

  // Tree
  const TreeCell = createFactory(
    require("resource://devtools/client/shared/components/tree/TreeCell.js")
  );
  const LabelCell = createFactory(
    require("resource://devtools/client/shared/components/tree/LabelCell.js")
  );

  const {
    wrapMoveFocus,
    getFocusableElements,
  } = require("resource://devtools/client/shared/focus.js");

  const UPDATE_ON_PROPS = [
    "name",
    "open",
    "value",
    "loading",
    "level",
    "selected",
    "active",
    "hasChildren",
  ];

  /**
   * This template represents a node in TreeView component. It's rendered
   * using <tr> element (the entire tree is one big <table>).
   */

  class TreeRow extends Component {
    // See TreeView component for more details about the props and
    // the 'member' object.
    static get propTypes() {
      return {
        member: PropTypes.shape({
          object: PropTypes.object,
          name: PropTypes.string,
          type: PropTypes.string.isRequired,
          rowClass: PropTypes.string.isRequired,
          level: PropTypes.number.isRequired,
          hasChildren: PropTypes.bool,
          value: PropTypes.any,
          open: PropTypes.bool.isRequired,
          path: PropTypes.string.isRequired,
          hidden: PropTypes.bool,
          selected: PropTypes.bool,
          active: PropTypes.bool,
          loading: PropTypes.bool,
        }),
        decorator: PropTypes.object,
        renderCell: PropTypes.func,
        renderLabelCell: PropTypes.func,
        columns: PropTypes.array.isRequired,
        id: PropTypes.string.isRequired,
        provider: PropTypes.object.isRequired,
        onClick: PropTypes.func.isRequired,
        onContextMenu: PropTypes.func,
        onMouseOver: PropTypes.func,
        onMouseOut: PropTypes.func,
      };
    }

    constructor(props) {
      super(props);

      this.treeRowRef = createRef();

      this.getRowClass = this.getRowClass.bind(this);
      this._onKeyDown = this._onKeyDown.bind(this);
    }

    componentDidMount() {
      this._setTabbableState();

      // 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]) {
          return true;
        }
      }

      return false;
    }

    componentWillUnmount() {
      this.observer.disconnect();
      this.observer = null;
    }

    /**
     * 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();
      }
    }

    _onKeyDown(e) {
      const { target, key, shiftKey } = e;

      if (key !== "Tab") {
        return;
      }

      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();
      }

      e.stopPropagation();
    }

    getRowClass(object) {
      const decorator = this.props.decorator;
      if (!decorator || !decorator.getRowClass) {
        return [];
      }

      // Decorator can return a simple string or array of strings.
      let classNames = decorator.getRowClass(object);
      if (!classNames) {
        return [];
      }

      if (typeof classNames == "string") {
        classNames = [classNames];
      }

      return classNames;
    }

    render() {
      const member = this.props.member;
      const decorator = this.props.decorator;

      const props = {
        id: this.props.id,
        ref: this.treeRowRef,
        role: "treeitem",
        "aria-level": member.level + 1,
        "aria-selected": !!member.selected,
        onClick: this.props.onClick,
        onContextMenu: this.props.onContextMenu,
        onKeyDownCapture: member.active ? this._onKeyDown : undefined,
        onMouseOver: this.props.onMouseOver,
        onMouseOut: this.props.onMouseOut,
      };

      // 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);
        }

        const render = col.id == "default" ? renderLabelCell : renderCell;

        // 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));
        }
      });

      // Render tree row
      return tr(props, cells);
    }
  }

  // Helpers

  const RenderCell = props => {
    return TreeCell(props);
  };

  const RenderLabelCell = props => {
    return LabelCell(props);
  };

  // Exports from this module
  module.exports = TreeRow;
});

99%


¤ Dauer der Verarbeitung: 0.6 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

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.