tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TreeCell.mjs (3635B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import { Component } from "resource://devtools/client/shared/vendor/react.mjs";
      6 import PropTypes from "resource://devtools/client/shared/vendor/react-prop-types.mjs";
      7 import * as dom from "resource://devtools/client/shared/vendor/react-dom-factories.mjs";
      8 
      9 const { input, span, td } = dom;
     10 
     11 /**
     12 * This template represents a cell in TreeView row. It's rendered
     13 * using <td> element (the row is <tr> and the entire tree is <table>).
     14 */
     15 class TreeCell extends Component {
     16  // See TreeView component for detailed property explanation.
     17  static get propTypes() {
     18    return {
     19      value: PropTypes.any,
     20      decorator: PropTypes.object,
     21      id: PropTypes.string.isRequired,
     22      member: PropTypes.object.isRequired,
     23      renderValue: PropTypes.func.isRequired,
     24      enableInput: PropTypes.bool,
     25    };
     26  }
     27 
     28  constructor(props) {
     29    super(props);
     30 
     31    this.state = {
     32      inputEnabled: false,
     33    };
     34 
     35    this.getCellClass = this.getCellClass.bind(this);
     36    this.updateInputEnabled = this.updateInputEnabled.bind(this);
     37  }
     38 
     39  /**
     40   * Optimize cell rendering. Rerender cell content only if
     41   * the value or expanded state changes.
     42   */
     43  shouldComponentUpdate(nextProps, nextState) {
     44    return (
     45      this.props.value !== nextProps.value ||
     46      this.state !== nextState ||
     47      this.props.member.open !== nextProps.member.open
     48    );
     49  }
     50 
     51  getCellClass(object, id) {
     52    const decorator = this.props.decorator;
     53    if (!decorator || !decorator.getCellClass) {
     54      return [];
     55    }
     56 
     57    // Decorator can return a simple string or array of strings.
     58    let classNames = decorator.getCellClass(object, id);
     59    if (!classNames) {
     60      return [];
     61    }
     62 
     63    if (typeof classNames == "string") {
     64      classNames = [classNames];
     65    }
     66 
     67    return classNames;
     68  }
     69 
     70  updateInputEnabled(evt) {
     71    this.setState(
     72      Object.assign({}, this.state, {
     73        inputEnabled: evt.target.nodeName.toLowerCase() !== "input",
     74      })
     75    );
     76  }
     77 
     78  render() {
     79    let { member, id, value, decorator, renderValue, enableInput } = this.props;
     80    const type = member.type || "";
     81 
     82    // Compute class name list for the <td> element.
     83    const classNames = this.getCellClass(member.object, id) || [];
     84    classNames.push("treeValueCell");
     85    classNames.push(type + "Cell");
     86 
     87    // Render value using a default render function or custom
     88    // provided function from props or a decorator.
     89    renderValue = renderValue || defaultRenderValue;
     90    if (decorator?.renderValue) {
     91      renderValue = decorator.renderValue(member.object, id) || renderValue;
     92    }
     93 
     94    const props = Object.assign({}, this.props, {
     95      object: value,
     96    });
     97 
     98    let cellElement;
     99    if (enableInput && this.state.inputEnabled && type !== "object") {
    100      classNames.push("inputEnabled");
    101      cellElement = input({
    102        autoFocus: true,
    103        onBlur: this.updateInputEnabled,
    104        readOnly: true,
    105        value,
    106        "aria-labelledby": id,
    107      });
    108    } else {
    109      cellElement = span(
    110        {
    111          onClick: type !== "object" ? this.updateInputEnabled : null,
    112        },
    113        renderValue(props)
    114      );
    115    }
    116 
    117    // Render me!
    118    return td(
    119      {
    120        className: classNames.join(" "),
    121        role: "presentation",
    122      },
    123      cellElement
    124    );
    125  }
    126 }
    127 
    128 // Default value rendering.
    129 const defaultRenderValue = props => {
    130  return props.object + "";
    131 };
    132 
    133 // Exports from this module
    134 export default TreeCell;