1/* Source and licensing information for the line(s) below can be found at https://www.ntccthailand.org/core/misc/announce.js. */ 2/** 3 * @file 4 * Adds an HTML element and method to trigger audio UAs to read system messages. 5 * 6 * Use {@link Drupal.announce} to indicate to screen reader users that an 7 * element on the page has changed state. For instance, if clicking a link 8 * loads 10 more items into a list, one might announce the change like this. 9 * 10 * @example 11 * $('#search-list') 12 * .on('itemInsert', function (event, data) { 13 * // Insert the new items. 14 * $(data.container.el).append(data.items.el); 15 * // Announce the change to the page contents. 16 * Drupal.announce(Drupal.t('@count items added to @container', 17 * {'@count': data.items.length, '@container': data.container.title} 18 * )); 19 * }); 20 */ 21 22(function (Drupal, debounce) { 23 let liveElement; 24 const announcements = []; 25 26 /** 27 * Builds a div element with the aria-live attribute and add it to the DOM. 28 * 29 * @type {Drupal~behavior} 30 * 31 * @prop {Drupal~behaviorAttach} attach 32 * Attaches the behavior for drupalAnnounce. 33 */ 34 Drupal.behaviors.drupalAnnounce = { 35 attach(context) { 36 // Create only one aria-live element. 37 if (!liveElement) { 38 liveElement = document.createElement('div'); 39 liveElement.id = 'drupal-live-announce'; 40 liveElement.className = 'visually-hidden'; 41 liveElement.setAttribute('aria-live', 'polite'); 42 liveElement.setAttribute('aria-busy', 'false'); 43 document.body.appendChild(liveElement); 44 } 45 }, 46 }; 47 48 /** 49 * Concatenates announcements to a single string; appends to the live region. 50 */ 51 function announce() { 52 const text = []; 53 let priority = 'polite'; 54 let announcement; 55 56 // Create an array of announcement strings to be joined and appended to the 57 // aria live region. 58 const il = announcements.length; 59 for (let i = 0; i < il; i++) { 60 announcement = announcements.pop(); 61 text.unshift(announcement.text); 62 // If any of the announcements has a priority of assertive then the group 63 // of joined announcements will have this priority. 64 if (announcement.priority === 'assertive') { 65 priority = 'assertive'; 66 } 67 } 68 69 if (text.length) { 70 // Clear the liveElement so that repeated strings will be read. 71 liveElement.innerHTML = ''; 72 // Set the busy state to true until the node changes are complete. 73 liveElement.setAttribute('aria-busy', 'true'); 74 // Set the priority to assertive, or default to polite. 75 liveElement.setAttribute('aria-live', priority); 76 // Print the text to the live region. Text should be run through 77 // Drupal.t() before being passed to Drupal.announce(). 78 liveElement.innerHTML = text.join('\n'); 79 // The live text area is updated. Allow the AT to announce the text. 80 liveElement.setAttribute('aria-busy', 'false'); 81 } 82 } 83 84 /** 85 * Triggers audio UAs to read the supplied text. 86 * 87 * The aria-live region will only read the text that currently populates its 88 * text node. Replacing text quickly in rapid calls to announce results in 89 * only the text from the most recent call to {@link Drupal.announce} being 90 * read. By wrapping the call to announce in a debounce function, we allow for 91 * time for multiple calls to {@link Drupal.announce} to queue up their 92 * messages. These messages are then joined and append to the aria-live region 93 * as one text node. 94 * 95 * @param {string} text 96 * A string to be read by the UA. 97 * @param {string} [priority='polite'] 98 * A string to indicate the priority of the message. Can be either 99 * 'polite' or 'assertive'. 100 * 101 * @return {function} 102 * The return of the call to debounce. 103 * 104 * @see https://www.w3.org/WAI/PF/aria-practices/#liveprops 105 */ 106 Drupal.announce = function (text, priority) { 107 // Save the text and priority into a closure variable. Multiple simultaneous 108 // announcements will be concatenated and read in sequence. 109 announcements.push({ 110 text, 111 priority, 112 }); 113 // Immediately invoke the function that debounce returns. 200 ms is right at 114 // the cusp where humans notice a pause, so we will wait 115 // at most this much time before the set of queued announcements is read. 116 return debounce(announce, 200)(); 117 }; 118})(Drupal, Drupal.debounce); 119 120/* Source and licensing information for the above line(s) can be found at https://www.ntccthailand.org/core/misc/announce.js. */
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.