tor-browser

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

browser-a11yUtils.js (2994B)


      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 /**
      6 * Utility functions for UI accessibility.
      7 */
      8 
      9 var A11yUtils = {
     10  /**
     11   * Announce a message to the user.
     12   * This should only be used when something happens that is important to the
     13   * user and will be noticed visually, but is not related to the focused
     14   * control and is not a pop-up such as a doorhanger.
     15   * For example, this could be used to indicate that Reader View is available
     16   * or that Firefox is making a recommendation via the toolbar.
     17   * This must be used with caution, as it can create unwanted verbosity and
     18   * can thus hinder rather than help users if used incorrectly.
     19   * Please only use this after consultation with the Mozilla accessibility
     20   * team.
     21   *
     22   * @param {object} [options]
     23   * @param {string} [options.id] The Fluent id of the message to announce. The
     24   *        ftl file must already be included in browser.xhtml. This must be
     25   *        specified unless a raw message is specified instead.
     26   * @param {object} [options.args] Arguments for the Fluent message.
     27   * @param {string} [options.raw] The raw, already localized message to
     28   *        announce. You should generally prefer a Fluent id instead, but in
     29   *        rare cases, this might not be feasible.
     30   */
     31  async announce({ id = null, args = {}, raw = null } = {}) {
     32    if ((!id && !raw) || (id && raw)) {
     33      throw new Error("One of raw or id must be specified.");
     34    }
     35 
     36    // Cancel a previous pending call if any.
     37    if (this._cancelAnnounce) {
     38      this._cancelAnnounce();
     39      this._cancelAnnounce = null;
     40    }
     41 
     42    let message;
     43    if (id) {
     44      let cancel = false;
     45      this._cancelAnnounce = () => (cancel = true);
     46      message = await document.l10n.formatValue(id, args);
     47      if (cancel) {
     48        // announce() was called again while we were waiting for translation.
     49        return;
     50      }
     51      // No more async operations from this point.
     52      this._cancelAnnounce = null;
     53    } else {
     54      // We run fully synchronously if a raw message is provided.
     55      message = raw;
     56    }
     57 
     58    // For now, we don't use source, but it might be useful in future.
     59    // For example, we might use it when we support announcement events on
     60    // more platforms or it could be used to have a keyboard shortcut which
     61    // focuses the last element to announce a message.
     62    let live = document.getElementById("a11y-announcement");
     63    // We use role="alert" because JAWS doesn't support aria-live in browser
     64    // chrome.
     65    // Gecko a11y needs an insertion to trigger an alert event. This is why
     66    // we can't just use aria-label on the alert.
     67    if (live.firstChild) {
     68      live.firstChild.remove();
     69    }
     70    let label = document.createElement("label");
     71    label.setAttribute("aria-label", message);
     72    live.appendChild(label);
     73  },
     74 };