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