PageSourceSearch

https://www.wallingfordadulted.org/includes/pageLoad.js?v=7.5

js wallingfordadulted.org collected 2026-10-05 03:00:10 UTC 13,609 bytes, 437 lines download raw bytes

1function inMobileMode() {
2  return $("#mobilenav").is(":visible");
3}
4
5$(document).ready(function () {
6
7
8  let navContainer = document.getElementById( 'navContainer' );
9
10  // Event listener for nav buttons
11  document.querySelectorAll( '#mainnav>ul>li>button' ).forEach( el => {
12    el.addEventListener( 'click', (e) => {
13      e.preventDefault();
14
15      let parent    = el.parentNode;
16      let dropdown  = el.nextElementSibling;
17      let is_mobile = inMobileMode();
18
19      // Toggle open/expand based on mode
20      if ( is_mobile ) {
21        parent.classList.toggle( 'open' );
22      } else {
23        parent.classList.toggle( 'expand' );
24      }
25
26      // Update aria-expanded
27      const expanded = parent.classList.contains('open') || parent.classList.contains('expand');
28      el.setAttribute( 'aria-expanded', expanded );
29
30      // Handle dropdown behavior (only in mobile mode)
31      if ( is_mobile && dropdown ) {
32        if ( !parent.classList.contains( 'open' ) ) {
33          // Closing
34          dropdown.inert = true;
35        } else {
36          // Opening
37          dropdown.inert = false;
38        }
39      }
40
41    });
42  });
43
44
45  // Close dropdown when it loses focus
46  document.querySelectorAll( '#mainnav>ul>li.menu-item-has-children' ).forEach( el => {
47    el.querySelector( 'a' ).addEventListener( 'focus', e => {
48      if ( !inMobileMode() ) {
49        el.classList.remove( 'expand' );
50        el.querySelector( 'button' ).setAttribute( 'aria-expanded', false );
51      }
52    });
53
54    el.querySelector( 'div' ).addEventListener( 'focusout', function (e) {
55      if ( !this.contains(e.relatedTarget) && !inMobileMode() ) {
56        el.classList.remove( 'expand' );
57        el.querySelector( 'button' ).setAttribute( 'aria-expanded', false );
58      }
59    });
60  });
61
62
63
64  // Event listener for slideNav toggles (mobile only)
65  document.querySelectorAll( '.toggleNav' ).forEach( menu => {
66    menu.addEventListener( 'click', () => {
67      ws_toggleNav();
68    });
69  });
70
71
72
73  // Toggle open/close the slideNav and set accessibility properties
74  function ws_toggleNav() {
75    document.body.classList.toggle( 'slideNav' );
76    let expanded = document.body.classList.contains( 'slideNav' );
77
78    let main    = document.querySelector( 'main' );
79    let footer  = document.querySelector( 'body>footer' );
80    let skipnav = document.getElementById( 'skipNavigation' );
81
82    if ( expanded ) {
83      main.inert = true;
84      footer.inert = true;
85      skipnav.inert = true;
86      navContainer.inert = false;
87      navContainer.setAttribute( 'aria-modal', true );
88    } else {
89      main.inert = false;
90      footer.inert = false;
91      skipnav.inert = false;
92      navContainer.inert = true;
93      navContainer.setAttribute( 'aria-modal', false );
94    }
95
96    document.querySelectorAll( '.toggleNav' ).forEach( button => {
97      button.setAttribute( 'aria-expanded', expanded ? 'true' : 'false' );
98    });
99
100    // Focus management with 250ms delay
101    setTimeout( () => {
102      if ( expanded ) {
103        navContainer.querySelector( 'button.toggleNav' ).focus();
104      } else {
105        document.querySelector( '#mobilenav button.toggleNav' ).focus();
106      }
107    }, 250);
108  }
109
110
111
112  // Close slidenav with ESC key
113  navContainer.addEventListener( 'keydown', function(event) {
114    if ( event.key === 'Escape' || event.key === 'Esc' && inMobileMode() ) {
115      ws_toggleNav();
116    }
117  });
118
119
120
121  // Close slideNav when clicked outside navContainer
122  document.addEventListener( 'click', check_target, false );
123  document.addEventListener( 'touchstart', check_target, { passive: true, capture: false } );
124  function check_target(event) {
125    if ( document.body.classList.contains( 'slideNav' ) &&
126    !document.querySelector( '#navContainer' ).contains( event.target ) &&
127    !document.querySelector( '#mobilenav .toggleNav' ).contains( event.target ) ) {
128      ws_toggleNav();
129    }
130  }
131
132
133
134  // Trap focus within navContainer
135  navContainer.addEventListener( 'focusout', e => {
136    if ( inMobileMode() && !navContainer.contains( e.relatedTarget ) ) {
137      navContainer.querySelector( 'button.toggleNav' ).focus();
138    }
139  });
140
141
142
143  // Expand current page / current page ancestor T1 items in mobile nav
144  document.querySelectorAll( '#navContainer li.on' ).forEach( open_nav => {
145    open_nav.classList.add( 'open' );
146    var dropdown = open_nav.querySelector( 'div' );
147    if ( dropdown ) {
148      dropdown.style.height = 'auto';
149      dropdown.inert = false;
150      dropdown.previousElementSibling.setAttribute( 'aria-expanded', true );
151    }
152  });
153
154
155
156  // Set accessibility properties (on pageLoad and after window resize)
157  function ws_set_navigation_attributes() {
158    if ( inMobileMode() ) {
159      navContainer.role = 'dialog';
160      navContainer.inert = true;
161      navContainer.querySelectorAll( 'li.menu-item-has-children:not(.open)>div' ).forEach( item => {
162        item.inert = true;
163      });
164    } else {
165      navContainer.inert = false;
166      navContainer.querySelectorAll( 'li.menu-item-has-children>div' ).forEach( item => {
167        item.inert = false;
168      });
169    }
170  }
171
172  ws_set_navigation_attributes(); // on pageLoad
173
174
175
176  // Stop animations during window resize event / maybe update navigation attributes
177  var timer;
178  var was_mobile_mode = inMobileMode(); // Mobile state on page load
179
180  window.addEventListener( 'resize', () => {
181    document.body.classList.add( 'stop-animations' );
182    clearTimeout(timer);
183    timer = setTimeout(() => {
184      document.body.classList.remove( 'stop-animations' );
185
186      // Reset navigation attributes if the mode changed (mobile <-> desktop)
187      let is_mobile_mode = inMobileMode();
188      if ( is_mobile_mode !== was_mobile_mode ) {
189        was_mobile_mode = is_mobile_mode;
190        ws_set_navigation_attributes();
191      }
192
193    }, 250);
194  }, true);
195
196
197
198  // Toggle 'scroll' class on body when page is scrolled down
199  window.addEventListener( 'scroll', () => {
200    if (window.scrollY > 0) {
201      document.body.classList.add( 'scroll' );
202    } else {
203      document.body.classList.remove( 'scroll' );
204    }
205  }, { passive: true } );
206
207
208
209  // Determine if using a touch device
210  function is_touch_device() {
211    var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
212    var mq = function (query) {
213      return window.matchMedia(query).matches;
214    }
215    if (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints > 0) || window.DocumentTouch && document instanceof DocumentTouch) {
216      return true;
217    }
218    var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
219    return mq(query);
220  }
221
222
223  // On touch devices, expand dropdowns on first tap
224  // Make sure selector is added in stylesheet
225  if ( is_touch_device() ) {
226    document.querySelectorAll( '#mainnav>ul>li>a' ).forEach( elem => {
227      elem.addEventListener('click', (e) => {
228        if ( !inMobileMode() ) {
229          var parent = elem.parentElement;
230          if ( parent.contains( parent.querySelector( 'ul' ) ) ) {
231            if ( !parent.classList.contains( 'tapped' ) ) {
232              e.preventDefault();
233              document.querySelector( '#mainnav>ul>li.tapped' )?.classList.remove( 'tapped' );
234              parent.classList.add( 'tapped' );
235            }
236          }
237        }
238      });
239    });
240  }
241
242
243
244
245  $('a[href*="#"]:not([href="#"])').click(function (e) {
246    if (location.pathname.replace(/^\//, '') == this.pathname.replace(/^\//, '') && location.hostname == this.hostname) {
247      var target = $(this.hash);
248      target = target.length ? target : $('[name=' + this.hash.slice(1) + ']');
249      if (target.length) {
250        e.preventDefault();
251        $('html,body').animate({
252          scrollTop: target.offset().top - $("body>header").height()
253        }, 1000, function () {
254          // Callback after animation, Must change focus!
255          var $target = $(target);
256          $target.focus();
257          if ($target.is(":focus")) { // Checking if the target was focused
258            return false;
259          } else {
260            $target.attr('tabindex', '-1'); // Adding tabindex for elements not focusable
261            $target.focus(); // Set focus again
262          }
263        });
264      }
265    }
266  });
267
268
269
270  //
271  // SEARCH BUTTON
272  //
273
274  document.querySelectorAll( '.search-toggle' ).forEach( toggle => {
275    toggle.addEventListener( 'click', (e) => {
276      e.preventDefault();
277      var search_form = document.getElementById( 'search-form' );
278      var main_nav    = document.getElementById( 'mainnav' );
279
280      if( !search_form.classList.contains( 'show' ) ) {
281        search_form.classList.add('show');
282        main_nav.classList.add('hide');
283        setTimeout( () => { document.getElementById( 'search-terms' ).focus(); }, 150);
284      } else {
285        search_form.classList.remove( 'show' );
286        main_nav.classList.remove( 'hide' );
287        setTimeout( () => { document.getElementById( 'search-button' ).focus(); }, 150);
288      }
289    });
290  });
291
292
293
294  //
295  // STICKY HEADER
296  //
297  var buffer = 100, alertBarHeight, body, delta, distanceFromTop, firstScroll, header, headerHeight, headerTopOffset, initialHeaderOffset, partialScrollDown, partialScrollUp, prevScrollPosition, scrollPosition, topPosition, wpAdminBarHeight, wsMgmtBarHeight;
298
299  alertBarHeight = wpAdminBarHeight = wsMgmtBarHeight = 0;
300  firstScroll = partialScrollDown = partialScrollUp = false;
301
302  body = $('body');
303  header = $('body>header:first');
304
305  prevScrollPosition = window.pageYOffset;
306
307  if ($(window).scrollTop() == 0)
308  firstScroll = true;
309
310  $(window).scroll(function() {
311    if($(document).outerHeight() > 1500 && !inMobileMode()) {
312
313      scrollPosition = $(this).scrollTop();
314
315      if ($('#alertApp').length)
316      alertBarHeight = $('#alertApp').outerHeight();
317      if ($('#wpadminbar').length)
318      wpAdminBarHeight = $('#wpadminbar').outerHeight();
319      if ($('#wsManagementBar').length)
320      wsMgmtBarHeight = $('#wsManagementBar').outerHeight();
321
322      headerHeight = header.outerHeight();
323      delta = headerHeight + alertBarHeight;
324      initialHeaderOffset = alertBarHeight;
325      topPosition = 0 + wpAdminBarHeight + wsMgmtBarHeight;
326
327      if (prevScrollPosition > scrollPosition) {
328        partialScrollUp = true;
329        if (!partialScrollDown)
330        header.addClass("sticky-header").css({"top": headerTopOffset});
331
332        var headerPosition = header.offset().top - $(this).scrollTop();
333        if (headerPosition >= topPosition) {
334          header.css({"position": "fixed", "top": topPosition + "px"});
335          firstScroll = partialScrollUp = partialScrollDown = false;
336          distanceFromTop = window.pageYOffset;
337        }
338      }
339
340      else if (firstScroll && scrollPosition > delta + buffer) {
341        headerTopOffset = scrollPosition - (delta + buffer);
342        header.css({"position": "absolute", "top": headerTopOffset});
343        body.css({"padding-top": header.outerHeight()});
344        firstScroll = false;
345        partialScrollDown = true;
346      }
347
348      else if (!firstScroll && !partialScrollUp) {
349        partialScrollDown = "true";
350        header.css({"position": "absolute", "top": distanceFromTop + wpAdminBarHeight + wsMgmtBarHeight});
351        body.css({"padding-top": header.outerHeight()});
352
353        if ((header.offset().top + headerHeight + buffer) < scrollPosition) {
354          headerTopOffset = scrollPosition - (delta + buffer);
355          header.removeClass("sticky-header");
356          partialScrollDown = false;
357        }
358      }
359
360      if (scrollPosition <= initialHeaderOffset) {
361        header.css({"position": "relative", "top": ""}).removeClass("sticky-header");
362        body.css({"padding-top": 0});
363        firstScroll = partialScrollDown = true;
364        partialScrollUp = false;
365      }
366      prevScrollPosition = scrollPosition;
367    }
368  });
369
370
371  //
372  // PAGE SCROLL ANIMATIONS
373  //
374  $(function() {
375    var elements = $(".fade-in, .translate-left, .translate-right, .translate-up, .translate-down, .flip-in");
376    var theWindow = $(window), offset;
377
378    function animate() {
379      offset = $("#mobilenav").is(":visible") ? 25 : 75; // different offsets for mobile/desktop
380      elements.each(function(i, elem) {
381        if ($(this).hasClass('animated'))
382        return;
383        animateMe($(this), offset);
384      });
385    }
386
387    function animateMe(elem, offset) {
388      var winTop = theWindow.scrollTop() - offset;
389      var winBottom = winTop + theWindow.height();
390      var elemTop = $(elem).offset().top + offset;
391      if ((elemTop <= winBottom) && (elemTop >= winTop)) {
392        $(elem).addClass('animated');
393      }
394    }
395
396    theWindow.on('resize scroll', function(e) {
397      animate();
398    });
399
400    animate();
401
402  });
403
404
405
406
407  //
408  // Detect short interior pages and add a class to remove the bottom left/right
409  // square embellishments so they don't overlap the ones on the top left/right
410  //
411  $(window).on('load resize', function() {
412    setInteriorPageClass();
413  });
414
415  setInteriorPageClass();
416
417  function setInteriorPageClass() {
418    var interior_page = $("main.interior");
419    if(interior_page.outerHeight() < 800) {
420      interior_page.addClass('short-page');
421    } else {
422      interior_page.removeClass('short-page');
423    }
424  }
425
426    // Add <span class="sr-only">(Opens in new window)</span> to any link with target="_blank"
427  const links = document.querySelectorAll( 'a[target="_blank"]' );
428  links.forEach( link => {
429    if ( !link.querySelector( '.sr-only' ) ) {
430      const sr_span = document.createElement( 'span' );
431      sr_span.className   = 'sr-only';
432      sr_span.textContent = ' (Opens in new window)';
433      link.appendChild( sr_span );
434    }
435  });
436
437});

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.