tor-browser

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

AccessibilityTreeFilter.js (5168B)


      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 "use strict";
      5 
      6 // React
      7 const {
      8  createFactory,
      9  Component,
     10 } = require("resource://devtools/client/shared/vendor/react.mjs");
     11 const {
     12  div,
     13  hr,
     14  span,
     15 } = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     16 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     17 const {
     18  L10N,
     19 } = require("resource://devtools/client/accessibility/utils/l10n.js");
     20 
     21 loader.lazyGetter(this, "MenuButton", function () {
     22  return createFactory(
     23    require("resource://devtools/client/shared/components/menu/MenuButton.js")
     24  );
     25 });
     26 loader.lazyGetter(this, "MenuItem", function () {
     27  return createFactory(
     28    require("resource://devtools/client/shared/components/menu/MenuItem.js")
     29  );
     30 });
     31 loader.lazyGetter(this, "MenuList", function () {
     32  return createFactory(
     33    require("resource://devtools/client/shared/components/menu/MenuList.js")
     34  );
     35 });
     36 
     37 const actions = require("resource://devtools/client/accessibility/actions/audit.js");
     38 
     39 const {
     40  connect,
     41 } = require("resource://devtools/client/shared/vendor/react-redux.js");
     42 const {
     43  FILTERS,
     44 } = require("resource://devtools/client/accessibility/constants.js");
     45 
     46 const FILTER_LABELS = {
     47  [FILTERS.NONE]: "accessibility.filter.none",
     48  [FILTERS.ALL]: "accessibility.filter.all2",
     49  [FILTERS.CONTRAST]: "accessibility.filter.contrast",
     50  [FILTERS.KEYBOARD]: "accessibility.filter.keyboard",
     51  [FILTERS.TEXT_LABEL]: "accessibility.filter.textLabel",
     52 };
     53 
     54 class AccessibilityTreeFilter extends Component {
     55  static get propTypes() {
     56    return {
     57      auditing: PropTypes.array.isRequired,
     58      filters: PropTypes.object.isRequired,
     59      dispatch: PropTypes.func.isRequired,
     60      describedby: PropTypes.string,
     61      toolboxDoc: PropTypes.object.isRequired,
     62      audit: PropTypes.func.isRequired,
     63    };
     64  }
     65 
     66  async toggleFilter(filterKey) {
     67    const { audit: auditFunc, dispatch, filters } = this.props;
     68 
     69    if (filterKey !== FILTERS.NONE && !filters[filterKey]) {
     70      Glean.devtoolsAccessibility.auditActivated[filterKey].add(1);
     71 
     72      dispatch(actions.auditing(filterKey));
     73      await dispatch(actions.audit(auditFunc, filterKey));
     74    }
     75 
     76    // We wait to dispatch filter toggle until the tree is ready to be filtered
     77    // right after the audit. This is to make sure that we render an empty tree
     78    // (filtered) while the audit is running.
     79    dispatch(actions.filterToggle(filterKey));
     80  }
     81 
     82  onClick(filterKey) {
     83    this.toggleFilter(filterKey);
     84  }
     85 
     86  render() {
     87    const { auditing, filters, describedby, toolboxDoc } = this.props;
     88    const toolbarLabelID = "accessibility-tree-filters-label";
     89    const filterNoneChecked = !Object.values(filters).includes(true);
     90    const items = [
     91      MenuItem({
     92        key: FILTERS.NONE,
     93        checked: filterNoneChecked,
     94        className: `filter ${FILTERS.NONE}`,
     95        label: L10N.getStr(FILTER_LABELS[FILTERS.NONE]),
     96        onClick: this.onClick.bind(this, FILTERS.NONE),
     97        disabled: !!auditing.length,
     98      }),
     99      hr({ key: "hr-1" }),
    100    ];
    101 
    102    const { [FILTERS.ALL]: filterAllChecked, ...filtersWithoutAll } = filters;
    103    items.push(
    104      MenuItem({
    105        key: FILTERS.ALL,
    106        checked: filterAllChecked,
    107        className: `filter ${FILTERS.ALL}`,
    108        label: L10N.getStr(FILTER_LABELS[FILTERS.ALL]),
    109        onClick: this.onClick.bind(this, FILTERS.ALL),
    110        disabled: !!auditing.length,
    111      }),
    112      hr({ key: "hr-2" }),
    113      Object.entries(filtersWithoutAll).map(([filterKey, active]) =>
    114        MenuItem({
    115          key: filterKey,
    116          checked: active,
    117          className: `filter ${filterKey}`,
    118          label: L10N.getStr(FILTER_LABELS[filterKey]),
    119          onClick: this.onClick.bind(this, filterKey),
    120          disabled: !!auditing.length,
    121        })
    122      )
    123    );
    124 
    125    let label;
    126    if (filterNoneChecked) {
    127      label = L10N.getStr(FILTER_LABELS[FILTERS.NONE]);
    128    } else if (filterAllChecked) {
    129      label = L10N.getStr(FILTER_LABELS[FILTERS.ALL]);
    130    } else {
    131      label = Object.keys(filtersWithoutAll)
    132        .filter(filterKey => filtersWithoutAll[filterKey])
    133        .map(filterKey => L10N.getStr(FILTER_LABELS[filterKey]))
    134        .join(", ");
    135    }
    136 
    137    return div(
    138      {
    139        role: "group",
    140        className: "accessibility-tree-filters",
    141        "aria-labelledby": toolbarLabelID,
    142        "aria-describedby": describedby,
    143      },
    144      span(
    145        { id: toolbarLabelID, role: "presentation" },
    146        L10N.getStr("accessibility.tree.filters")
    147      ),
    148      MenuButton(
    149        {
    150          menuId: "accessibility-tree-filters-menu",
    151          toolboxDoc,
    152          className: `devtools-button badge toolbar-menu-button filters`,
    153          label,
    154        },
    155        MenuList({}, items)
    156      )
    157    );
    158  }
    159 }
    160 
    161 const mapStateToProps = ({ audit: { filters, auditing } }) => {
    162  return { filters, auditing };
    163 };
    164 
    165 // Exports from this module
    166 module.exports = connect(mapStateToProps)(AccessibilityTreeFilter);