PageSourceSearch

https://nystransportationmasterplan.com/Scripts/focusTrap.js

js nystransportationmasterplan.com collected 2026-09-29 15:06:38 UTC 1,985 bytes, 68 lines download raw bytes

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.