PageSourceSearch

https://www.pbk.org/pbk-250/js/main.js

js pbk.org collected 2026-09-24 09:04:12 UTC 6,118 bytes, 213 lines download raw bytes

1jQuery(function ($) {
2  console.log('JS initialized.'); 
3
4  function mainNav() {
5    let trigger, siteNav; 
6    trigger = $('#nav-trigger'); 
7    siteNav = $('#site-navigation'); 
8    $(trigger).on( 'click', function() {
9      let condition = $(this).attr('aria-expanded'); 
10      if ( condition == 'true' ) {
11        $(this).attr('aria-expanded', 'false'); 
12        $(siteNav).removeClass('expanded'); 
13      } else {
14        $(this).attr('aria-expanded', 'true'); 
15        $(siteNav).addClass('expanded'); 
16      }
17    });
18  }
19
20  function subNavs() {
21    let trigger; 
22    trigger = $('#secondary-navigation button.menu-item'); 
23    $(trigger).on('click', function() {
24      let condition, allNavs, thisNav; 
25      condition = $(this).attr('aria-expanded'); 
26      allNavs = $('#secondary-navigation ul.sub-menu'); 
27      thisNav = $(this).siblings('ul.sub-menu');
28      
29      if (condition == 'true') {
30        $(trigger).attr('aria-expanded', 'false'); 
31        $(allNavs).removeClass('expanded');
32      } else {
33        $(trigger).attr('aria-expanded', 'false'); 
34        $(allNavs).removeClass('expanded');
35        $(this).attr('aria-expanded', 'true'); 
36        $(thisNav).addClass('expanded'); 
37        // listenForClick(thisNav);
38      }
39    });
40  }
41  
42  function videoDialog() {
43    if (typeof HTMLDialogElement === "undefined") {
44      // Optional: load a <dialog> polyfill or fall back to a non-dialog modal.
45      return;
46    }
47
48    var $dialog = $("#video-modal");
49    if (!$dialog.length) return;
50
51    /** @type {HTMLDialogElement} */
52    var dialogEl = $dialog.get(0);
53
54    var lastActiveElement = null;
55
56    var focusableSelector = [
57      "a[href]",
58      "area[href]",
59      "button:not([disabled])",
60      "input:not([disabled]):not([type='hidden'])",
61      "select:not([disabled])",
62      "textarea:not([disabled])",
63      "[tabindex]:not([tabindex='-1'])",
64    ].join(",");
65
66    function getFocusable() {
67      // Filter out elements that are not actually visible (rough-but-practical)
68      return $dialog
69        .find(focusableSelector)
70        .filter(function () {
71          var $el = $(this);
72          return $el.is(":visible") && !$el.is("[inert]");
73        })
74        .toArray();
75    }
76
77    function setInitialFocus() {
78      var $autofocus = $dialog.find("[autofocus]").first();
79      if ($autofocus.length) {
80        $autofocus.trigger("focus");
81        return;
82      }
83
84      var focusable = getFocusable();
85      if (focusable.length) {
86        focusable[0].focus();
87        return;
88      }
89
90      // Last resort
91      dialogEl.focus();
92    }
93
94    function lockScroll(lock) {
95      $("html").css("overflow", lock ? "hidden" : "");
96    }
97
98    function openDialog() {
99      lastActiveElement = document.activeElement;
100
101      // showModal() is key for proper modality + top-layer behavior
102      dialogEl.showModal();
103
104      lockScroll(true);
105      setInitialFocus();
106    }
107
108    function closeDialog() {
109      if (dialogEl.open) dialogEl.close("dismissed");
110    }
111
112    // Open triggers: <button data-dialog-open="video-modal">
113    $(document).on("click", "[data-dialog-open]", function (e) {
114      var targetId = $(this).attr("data-dialog-open");
115      if (targetId !== dialogEl.id) return;
116      openDialog();
117    });
118
119    // Optional: close on backdrop click
120    $dialog.on("click", function (e) {
121      // If click is outside the dialog box (on the backdrop area), close
122      var rect = dialogEl.getBoundingClientRect();
123      var x = e.clientX;
124      var y = e.clientY;
125
126      var clickInside =
127        x >= rect.left && x <= rect.right && y >= rect.top && y <= rect.bottom;
128
129      if (!clickInside) closeDialog();
130    });
131
132    // Focus trap: keep Tab/Shift+Tab inside
133    $dialog.on("keydown", function (e) {
134      if (e.key !== "Tab" && e.keyCode !== 9) return;
135
136      var focusable = getFocusable();
137      if (!focusable.length) return;
138
139      var first = focusable[0];
140      var last = focusable[focusable.length - 1];
141
142      if (e.shiftKey && document.activeElement === first) {
143        e.preventDefault();
144        last.focus();
145      } else if (!e.shiftKey && document.activeElement === last) {
146        e.preventDefault();
147        first.focus();
148      }
149    });
150
151    // Escape key: <dialog> handles it; we just ensure cleanup happens in "close"
152    $dialog.on("cancel", function () {
153      // Don’t preventDefault(); allow Esc to close.
154    });
155
156    // Cleanup + restore focus
157    $dialog.on("close", function () {
158      lockScroll(false);
159
160      if (lastActiveElement && typeof lastActiveElement.focus === "function") {
161        lastActiveElement.focus();
162      }
163    });
164
165
166    $(document).on("click", "#video-modal .dialog-close", function (e) {
167      e.preventDefault();
168      var dialogEl = $("#video-modal").get(0);
169      if (dialogEl && dialogEl.open) dialogEl.close("dismissed");
170    });
171  }
172
173  function splideInit() {
174    const splide = new Splide( '.splide', {
175      type   : 'loop',
176      perPage: 1,
177      arrows : false,
178    } );
179
180    splide.on( 'pagination:mounted', function ( data ) {
181      // You can add your class to the UL element
182      data.list.classList.add( 'splide__pagination--spotlight' );
183
184      // `items` contains all dot items
185      data.items.forEach( function ( item ) {
186        var slideNum, slideString, slideID, slideH3, slideTitle; 
187        slideNum = item.page + 1; 
188        if (slideNum < 10) { 
189          slideString = slideNum.toString();
190          slideNum = slideString.padStart(2, "0"); 
191        }
192        slideID = "#splide01-slide"+slideNum;
193        slideH3 = slideID + " h3"; 
194        slideTitle = $(slideH3).text(); 
195        item.button.textContent = String( slideTitle ); 
196      } );
197    } );
198
199    splide.mount();
200  }
201
202  function main() { 
203    mainNav(); 
204    subNavs(); 
205    videoDialog(); 
206    splideInit(); 
207  }
208
209  $(document).ready(function(){
210    console.log('main function running.'); 
211    main(); 
212  });
213});

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.