1/* 2 * Copyright 2024 Anyware Services 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16AmetysFront.Accessibility = { 17 18 _FOCUSABLE_ELEMENTS_SELECTOR: 'a[href]:not([disabled]), summary, button:not([disabled]), textarea:not([disabled]), input[type="text"]:not([disabled]), input[type="radio"]:not([disabled]), input[type="checkbox"]:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"]), iframe:not([disabled])', 19 20 _KEYCODE_TAB: 9, 21 22 _firstFocusableEl: null, 23 _lastFocusableEl: null, 24 25 _handleTabKeyPress: function(event) 26 { 27 var isTabPressed = (event.key === 'Tab' || event.keyCode === AmetysFront.Accessibility._KEYCODE_TAB); 28 if (!isTabPressed) { 29 return; 30 } 31 32 if (event.shiftKey && document.activeElement === AmetysFront.Accessibility._firstFocusableEl) 33 { 34 event.preventDefault();
35 AmetysFront.Accessibility._lastFocusableEl.focus(); 36 } 37 else if (!event.shiftKey && document.activeElement === AmetysFront.Accessibility._lastFocusableEl) 38 { 39 event.preventDefault(); 40 AmetysFront.Accessibility._firstFocusableEl.focus(); 41 } 42 }, 43 44 /** 45 * Trap focus into the given modal. Assume that this modal and any other modals into this modal have a "role='dialog"" attribute 46 * @param modal the modal with role='dialog' attribute 47 * @param focusFirstElmt set to true to focus the first focusable element 48 */ 49 trapFocus: function(modalEl, focusFirstElmt) 50 { 51 // Reinit event 52 AmetysFront.Accessibility.untrapFocus(modalEl); 53 54 var focusableEls = modalEl.querySelectorAll(AmetysFront.Accessibility._FOCUSABLE_ELEMENTS_SELECTOR); 55 56 // Remove not visible elements and elements from sub-modal 57 var $focusableEls = $j(focusableEls).filter(":visible").filter(function (i, elmt){ 58 let $elmt = $j(elmt); 59 return $elmt.css('visibility') != 'hidden' 60 && ($elmt.closest("[role='dialog']").length === 0 || $elmt.closest("[role='dialog']").get(0) == modalEl); 61 }); 62 63 if ($focusableEls.length) 64 { 65 AmetysFront.Accessibility._firstFocusableEl = $focusableEls.get(0); 66 AmetysFront.Accessibility._lastFocusableEl = $focusableEls.get($focusableEls.length - 1); 67 68 if (focusFirstElmt) 69 { 70 // Put focus on first focusable element 71 $j(AmetysFront.Accessibility._firstFocusableEl).trigger('focus'); 72 } 73 74 modalEl.addEventListener('keydown', AmetysFront.Accessibility._handleTabKeyPress); 75 } 76 }, 77 78 untrapFocus: function(modalEl) 79 { 80 modalEl.removeEventListener('keydown', AmetysFront.Accessibility._handleTabKeyPress); 81 AmetysFront.Accessibility._firstFocusableEl = null; 82 AmetysFront.Accessibility._lastFocusableEl = null; 83 } 84}
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.