1/* exported trapFocus */ 2/** 3 * Puts focus inside modal; prevents focus from leaving 4 * until modal is closed; upon closing returns focus to 5 * element that triggered modal 6 * @param {jQuery} modal modal that will trap focus 7 * @param {jQuery} button button that opened modal 8 */ 9function trapFocus(modal, button) { 10 if (!modal.length) { 11 return; 12 } 13 14 var notModal = $(":not(" + modal[0].id + ")"); 15 var attrDict = {}; 16 /* 17 * record original aria-hidden values 18 * hide all elements outside modal from screen readers 19 */ 20 notModal.each(function (i) { 21 attrDict[i] = $(this).attr("aria-hidden"); 22 $(this).attr("aria-hidden", true); 23 }); 24 25 // focus first tabbable element inside modal 26 var modalFocusable = modal.find(":tabbable"); 27 var firstFocusable = modalFocusable[0]; 28 firstFocusable && firstFocusable.focus(); 29 30 var lastFocusable = modalFocusable[modalFocusable.length - 1]; 31 var tabKey = 9; 32 33 /* 34 * prevent URL bar from getting focus by looping 35 * between first and last elements 36 */ 37 modal.on("keydown", loopFocus); 38 39 // courtesy of https://gist.github.com/r3lk3r/0030bab99347a2326334e00b23188cab#file-focusloopingutil-js 40 function loopFocus(e) { 41 if (e.keyCode === tabKey) { 42 if (e.shiftKey && document.activeElement === firstFocusable) { 43 e.preventDefault(); 44 lastFocusable.focus(); 45 } else if (!e.shiftKey && document.activeElement === lastFocusable) { 46 e.preventDefault(); 47 firstFocusable.focus(); 48 } 49 } 50 } 51 52 /* 53 * on modal close: 54 * focus button that opened modal 55 * remove keydown listener from modal 56 * reset original aria-hidden values 57 */ 58 modal.on("hide.bs.modal", function () { 59 modal.off("keydown", loopFocus); 60 button.focus(); 61 notModal.each(function (i) { 62 $(this).attr( 63 "aria-hidden", 64 typeof attrDict[i] === "undefined" ? "" : attrDict[i] 65 ); 66 }); 67 }); 68}
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.