PageSourceSearch

https://www.mosaicnet.ca/wp-content/themes/jsbones/library/js/scripts.js

js mosaicnet.ca collected 2026-10-04 02:12:37 UTC 23,475 bytes, 675 lines download raw bytes

1/*
2 * Bones Scripts File
3 * Author: Eddie Machado
4 *
5 * This file is called automatically in the footer.
6*/
7
8
9/*
10 * Get Viewport Dimensions
11 * returns object with viewport dimensions to match css in width and height properties
12 * ( source: http://andylangton.co.uk/blog/development/get-viewport-size-width-and-height-javascript )
13*/
14function updateViewportDimensions() {
15	var w = window, d = document, e = d.documentElement, g = d.getElementsByTagName('body')[0], x = w.innerWidth || e.clientWidth || g.clientWidth, y = w.innerHeight || e.clientHeight || g.clientHeight;
16	return { width: x, height: y };
17}
18// setting the viewport width
19var viewport = updateViewportDimensions();
20
21
22/*
23 * Throttle Resize-triggered Events
24 * Wrap your actions in this function to throttle the frequency of firing them off, for better performance, esp. on mobile.
25 * ( source: http://stackoverflow.com/questions/2854407/javascript-jquery-window-resize-how-to-fire-after-the-resize-is-completed )
26*/
27var waitForFinalEvent = (function () {
28	var timers = {};
29	return function (callback, ms, uniqueId) {
30		if (!uniqueId) { uniqueId = "Don't call this twice without a uniqueId"; }
31		if (timers[uniqueId]) { clearTimeout(timers[uniqueId]); }
32		timers[uniqueId] = setTimeout(callback, ms);
33	};
34});
35
36// how long to wait before deciding the resize has stopped, in ms. Around 50-100 should work ok.
37var timeToWaitForLast = 100;
38
39
40/*
41 * Here's an example so you can see how we're using the above function
42 *
43 * If we want to only do it on a certain page, we can setup checks so we do it
44 * as efficient as possible.
45 *
46 * if( typeof is_home === "undefined" ) var is_home = $('body').hasClass('home');
47 *
48 * This once checks to see if you're on the home page based on the body class
49 * We can then use that check to perform actions on the home page only
50 *
51 * When the window is resized, we perform this function
52 * $(window).resize(function () {
53 *
54 *    // if we're on the home page, we wait the set amount (in function above) then fire the function
55 *    if( is_home ) { waitForFinalEvent( function() {
56 *
57 *	// update the viewport, in case the window size has changed
58 *	viewport = updateViewportDimensions();
59 *
60 *      // if we're above or equal to 768 fire this off
61 *      if( viewport.width >= 768 ) {
62 *        console.log('On home page and window sized to 768 width or more.');
63 *      } else {
64 *        // otherwise, let's do this instead
65 *        console.log('Not on home page, or window sized to less than 768.');
66 *      }
67 *
68 *    }, timeToWaitForLast, "your-function-identifier-string"); }
69 * });
70 *
71 *
72*/
73
74/*
75 Put all your regular jQuery in here.
76*/
77jQuery(document).ready(function ($) {
78	/* 
79	 * Apply parallax effect to header image
80	 */
81	$(window).scroll(function (e) {
82		var scrolled = $(window).scrollTop();
83		$('.header-image').css('top', -(scrolled * 0.1) + 'px');
84	});
85    
86 // We're going to swap out the gravatars.
87 // In the functions.php file, you can see we're not loading the gravatar
88 // images on mobile to save bandwidth. Once we hit an acceptable viewport
89 // then we can swap out those images since they are located in a data attribute.
90function loadGravatars() {
91// set the viewport using the function above
92	viewport = updateViewportDimensions();
93	// if the viewport is tablet or larger, we load in the gravatars
94	if (viewport.width >= 768) {
95		$('.comment img[data-gravatar]').each(function(){
96		  $(this).attr('src',$(this).attr('data-gravatar'));
97		});
98	}
99}; // end function
100
101  /*
102   * Let's fire off the gravatar function
103   * You can remove this if you don't need it
104  */
105  loadGravatars();
106    
107    
108
109    
110  // mobile support menu collapse and expand
111//  $('#support-nav-toggle').click(function(){
112//	$(this).toggleClass('open');
113//	$('.support-navigation').toggleClass('open');
114//	
115//  });
116    
117    
118    // Prevent cookies from blocking tabbing through main page content
119    const cookieDiv1s = document.querySelectorAll(".cky-consent-container");
120    const cookieDiv2s = document.querySelectorAll(".cky-modal");
121    const allOther = document.querySelector("#content");
122    function moveCookies() {
123        cookieDiv1s.forEach((cookieDiv1) => {
124            allOther.after(cookieDiv1);
125        });
126        cookieDiv2s.forEach((cookieDiv2) => {
127            allOther.after(cookieDiv2);
128        });
129
130    }
131    window.addEventListener("load", (event) => {
132       moveCookies();
133    });
134//  
135
136    // Menu script from https://www.a11y-collective.com/blog/mastering-web-accessibility-making-drop-down-menus-user-friendly/
137    const menuItems = document.querySelectorAll(".menu-wrapper");
138    const innerContent = document.querySelector("#inner-content");
139
140    let expandedItem = null;
141    
142    function collapseAll() {
143        const otherSubs = document.querySelectorAll("#site-navigation .sub-menu");
144        const otherButtons = document.querySelectorAll("#site-navigation .nav-button");
145        otherSubs.forEach((otherSub) => {
146            otherSub.setAttribute("aria-hidden","true");
147            otherSub.classList.remove("open");
148        });
149        otherButtons.forEach((otherButton) => {
150            otherButton.setAttribute("aria-expanded","false");
151            otherButton.classList.remove("open");
152        });
153    }
154
155    const expandSubMenu = (item) => {
156        const subMenu = item.querySelector(".sub-menu");
157        const button = item.querySelector(".nav-button");
158        expandedItem = item;
159        
160        // first close all other header menus
161        collapseAll();
162        subMenu.setAttribute("aria-hidden","false");
163        button.setAttribute("aria-expanded","true");
164        subMenu.classList.add("open");
165        button.classList.add("open");
166        item.classList.add("open");
167        item.setAttribute("aria-expanded","true");
168        item.dataset.expanded = "true";
169        let firstLink = subMenu.querySelector("a");
170        if (firstLink !== null){
171            firstLink.focus(); // Focus on the first link in the submenu
172        }
173        //subMenu.querySelector("#s").focus(); // Focus on the first link in the submenu
174        
175        
176    };
177
178    const collapseSubMenu = (item) => {
179        const subMenu = item.querySelector(".sub-menu");
180        const button = item.querySelector(".nav-button");
181        expandedItem = null;
182
183        subMenu.setAttribute("aria-hidden","true");
184        button.setAttribute("aria-expanded","false");
185        subMenu.classList.remove("open");
186        button.classList.remove("open");
187        item.classList.remove("open");
188        item.setAttribute("aria-expanded","false");
189        item.dataset.expanded = "false";
190        button.focus(); // Focus back on the button
191    };
192    
193
194    // trigger functions on button click
195    menuItems.forEach((item) => {
196        const button = item.querySelector(".nav-button");
197
198        button.addEventListener("click", (event) => {
199            if (button.ariaExpanded === "false") {
200                expandSubMenu(item);
201            } else {
202                collapseSubMenu(item);
203            }
204        });
205
206        // Handling keyboard navigation
207        button.addEventListener("keydown", (event) => {
208            if (event.key === "Enter" || event.key === " ") { // Space or Enter key
209                event.preventDefault(); // Prevent the default action to stop scrolling when pressing Space
210                if (button.ariaExpanded === "false") {
211                    expandSubMenu(item);
212                } else {
213                    collapseSubMenu(item);
214                }
215            }
216        });
217        
218         // Handling tab key inside submenu to loop back to the button
219    const subMenuLinks = item.querySelectorAll("ul a");
220    if (subMenuLinks.length) {
221        const lastLink = subMenuLinks[subMenuLinks.length - 1];
222        lastLink.addEventListener("keydown", (event) => {
223            if (event.key === "Tab" && !event.shiftKey) {
224                event.preventDefault();
225                button.focus(); // Move focus back to the button
226            }
227        });
228    }
229    });
230    allOther.addEventListener("click", (event) => {
231        collapseAll();
232    });
233    allOther.addEventListener("keydown", (event) => {
234        collapseAll();
235    });
236    
237 // Close all menus if user clicks on anything in main area
238
239//    innerContent.addEventListener("click", (event) => {
240//        collapseAll();
241//    });
242
243    // Handling keyboard navigation
244//    innerContent.addEventListener("keydown", (event) => {
245//        collapseAll();
246//    });
247
248
249   
250    
251    
252//    document.addEventListener("keydown", (event) => {
253//        if (event.key === "Tab") {
254//         if (!expandedItem) {
255//             return;
256//         }
257//
258//         const subMenu = expandedItem.querySelector(".sub-menu");
259//
260//         const focusedElement = expandedItem.querySelector(":focus");
261//         const firstFocusableElement = expandedItem.querySelector("a");
262//            firstFocusableElement.classList.add('first');
263//         const lastFocusableElement = subMenu.lastElementChild.querySelector("a");
264//            lastFocusableElement.classList.add('last');
265//
266//         if (!event.shiftKey && focusedElement === lastFocusableElement) {
267//             collapseSubMenu(expandedItem);
268//             return;
269//         }
270//
271//         if (event.shiftKey && focusedElement === firstFocusableElement) {
272//             collapseSubMenu(expandedItem);
273//             return;
274//         }
275//        }
276//
277//        if (event.key == "Escape") {
278//         collapseSubMenu(expandedItem);
279//        }
280//    });
281    
282    
283    
284    // make script aboave target .menu-wrapper > .widget:first-child .widgettitle and add .setAttribute("aria-expanded","fal
284se");
285    
286    const dynamicSidebarOpen = document.querySelectorAll(".menu-wrapper-special");
287    
288    // trigger functions on button click
289    dynamicSidebarOpen.forEach((sidebar) => {
290        sidebar.setAttribute("tabindex","-1");
291        const buttonSpecial = sidebar.querySelector(".menu-wrapper-special .widgettitle");
292        
293        buttonSpecial.setAttribute("aria-expanded","false");
294        buttonSpecial.setAttribute("tabIndex","0");
295        
296        const expandSidebar = (sidebar) => {
297            const subSidebar = buttonSpecial.nextElementSibling;
298            expandedSidebar = sidebar;
299
300            subSidebar.setAttribute("aria-hidden","false");
301            buttonSpecial.setAttribute("aria-expanded","true");
302            subSidebar.classList.add("open");
303            buttonSpecial.classList.add("open");
304            sidebar.classList.add("open");
305            sidebar.dataset.expanded = "true";
306            subSidebar.querySelectorAll("a")[0].focus(); // Focus on the first link in the submenu
307
308
309        };
310
311        const collapseSidebar = (sidebar) => {
312            const subSidebar = buttonSpecial.nextElementSibling;
313            expandedSidebar = null;
314
315            subSidebar.setAttribute("aria-hidden","true");
316            buttonSpecial.setAttribute("aria-expanded","false");
317            subSidebar.classList.remove("open");
318            buttonSpecial.classList.remove("open");
319            sidebar.classList.remove("open");
320            sidebar.dataset.expanded = "false";
321            buttonSpecial.focus(); // Focus back on the button
322        };
323
324
325        buttonSpecial.addEventListener("click", (event) => {
326            if (buttonSpecial.ariaExpanded === "false") {
327                expandSidebar(sidebar);
328            } else {
329                collapseSidebar(sidebar);
330            }
331        });
332
333        // Handling keyboard navigation
334        buttonSpecial.addEventListener("keydown", (event) => {
335            if (event.key === "Enter" || event.key === " ") { // Space or Enter key
336                event.preventDefault(); // Prevent the default action to stop scrolling when pressing Space
337                if (buttonSpecial.ariaExpanded === "false") {
338                    expandSidebar(sidebar);
339                } else {
340                    collapseSidebar(sidebar);
341                }
342            }
343        });
344    });
345    
346//    document.addEventListener("keydown2", (event) => {
347//        if (event.key === "Tab") {
348//            if (!expandedSidebar) {
349//                return;
350//            }
351//            const buttonSpecial = sidebar.querySelector(".menu-wrapper-special > .widget:first-child .widgettitle");
352//             const subSidebar = buttonSpecial.nextElementSibling;
353//
354//             const focusedElement2 = expandedSidebar.querySelector(":focus");
355//             const firstFocusableElement2 = expandedSidebar.querySelector("a");
356//             const lastFocusableElement2 = subSidebar.lastElementChild.querySelector("a");
357//
358//             if (!event.shiftKey && focusedElement2 === lastFocusableElement2) {
359//                 collapseSidebar(expandedSidebar);
360//                 return;
361//             }
362//
363//             if (event.shiftKey && focusedElement2 === firstFocusableElement2) {
364//                 collapseSidebar(expandedSidebar);
365//                 return;
366//             }
367//        }
368//
369//        if (event.key == "Escape") {
370//         collapseSidebar(expandedSidebar);
371//        }
372//    });
373    
374    
375    
376    
377    //Special case for upper header
378    const upperItems = document.querySelectorAll(".upper-menu-wrapper");
379    const homeTranslate = document.querySelector("#home-translate");
380
381    let expandedUpperItem = null;
382    
383    function collapseAllUpper() {
384        const otherUpperWraps = document.querySelectorAll(".upper-menu-wrapper");
385        const otherUpperSubs = document.querySelectorAll(".upper-sub-menu");
386        const otherUpperButtons = document.querySelectorAll(".upper-nav-button");
387        otherUpperWraps.forEach((otherUpperWrap) => {
388            //otherUpperWrap.setAttribute("aria-hidden","true");
389            otherUpperWrap.classList.remove("open");
390        });
391        otherUpperSubs.forEach((otherUpperSub) => {
392            otherUpperSub.setAttribute("aria-hidden","true");
393            otherUpperSub.classList.remove("open");
394        });
395        otherUpperButtons.forEach((otherUpperButton) => {
396            otherUpperButton.setAttribute("aria-expanded","false");
397            otherUpperButton.classList.remove("open");
398        });
399    }
400
401    const expandUpperSubMenu = (upperItem) => {
402        const upperSubMenu = upperItem.querySelector(".upper-sub-menu");
403        const upperButton = upperItem.querySelector(".upper-nav-button");
404        expandedUpperItem = upperItem;
405        
406        collapseAllUpper();
407        homeTranslate.classList.add("open");
408        upperButton.setAttribute("aria-expanded","true");
409        upperSubMenu.classList.add("open");
410        upperButton.classList.add("open");
411        upperItem.classList.add("open");
412        upperItem.dataset.expanded = "true";
413//        const searchFocus = document.getElementById("s");
414//            if (upperButton.classList.contains("search-toggle")) {
415//                    searchFocus.focus(); // Focus on the search field
416//                };
417        
418    };
419
420    const collapseUpperSubMenu = (upperItem) => {
421        const upperSubMenu = upperItem.querySelector(".upper-sub-menu");
422        const upperButton = upperItem.querySelector(".upper-nav-button");
423        expandedUpperItem = null;
424
425        homeTranslate.classList.remove("open");
426        upperSubMenu.setAttribute("aria-hidden","true");
427        upperButton.setAttribute("aria-expanded","false");
428        upperSubMenu.classList.remove("open");
429        upperButton.classList.remove("open");
430        upperItem.classList.remove("open");
431        upperItem.dataset.expanded = "false";
432        upperButton.focus(); // Focus back on the button
433    };
434    
435
436    // trigger functions on button click
437    upperItems.forEach((upperItem) => {
438        const upperButton = upperItem.querySelector(".upper-nav-button");
439
440        upperButton.addEventListener("click", (event) => {
441            
442            if (upperButton.ariaExpanded === "false") {
443                expandUpperSubMenu(upperItem);
444                
445            } else {
446                collapseUpperSubMenu(upperItem);
447            }
448        });
449
450        // Handling keyboard navigation
451        upperButton.addEventListener("keydown", (event) => {
452            if (event.key === "Enter" || event.key === " ") { // Space or Enter key
453                event.preventDefault(); // Prevent the default action to stop scrolling when pressing Space
454
455                if (upperButton.ariaExpanded === "false") {
456                    expandUpperSubMenu(upperItem);
457                
458                } else {
459                    collapseUpperSubMenu(upperItem);
460                }
461            }
462        });
463    });
464    
465//    document.addEventListener("keydown2", (event) => {
466//        if (event.key === "Tab") {
467//            if (!expandedUpperItem) {
468//                return;
469//            }
470//            if (event.key == "Escape") {
471//                collapseUpperSubMenu(upperItem);
472//            }
473//        }
474//    });
475    
476
477    
478    
479    // SKIP LINKS
480    if (window.location.pathname !== "/" && window.location.pathname !== "https://www.mosaicnet.ca/") {
481
482      var mainContent = document.getElementById('main-skip');
483      var skipMain = document.getElementById('skip-to-main');
484            skipMain.onclick = function(e) {
485            e.preventDefault();
486            mainContent.focus();
487        };
488      
489    }
490    var innerContentSkip = document.getElementById('inner-content-skip');
491    
492    var skipLink = document.getElementById('skip');
493    
494    skipLink.onclick = function(e) {
495        e.preventDefault();
496        innerContentSkip.focus();
497    }
498    
499    
500    // REPLACED BY ACCESSIBLE SCRIPT ABOVE
501//    function accordion() {
502//		$(".accordion-toggle, .accordion > .widget:first-child .widgettitle").click(function(){
503//			if ($(this).hasClass("open")){
504//				$(this).parents('.accordion').removeClass("open");
505//				$(this).parents('.accordion').children(".accordion-box").removeClass("open");
506//				$(this).removeClass("open");
507//                
508//			} else {
509//				$(this).parents('.accordion').addClass("open");
510//				$(this).parents('.accordion').children(".accordion-box").addClass("open");
511//				$(this).addClass("open");
512//			}
513//		});
514//	}
515//	$(".accordion").onload = accordion();
516  
517
518//     if(navigator.userAgent.match("CriOS")){
519//        let div = document.getElementById("google_translate_element");
520//        div.innerHTML = "<p style='margin-top: 0;'><small>If you don't see the language selector, please use the built-in browser translate function instead.</small></p>";
521//     };
522//    translateExists = document.querySelectorAll(".goog-te-gadget");
523//    if (translateExists === null) {
524//        translateReplace();
525//    }
526    
527//    if (navigator.cookieEnabled) {
528//      // Cookies are enabled
529//      console.log('Cookies are enabled');
530//    } else {
531//      // Cookies are disabled
532//      translateReplace();
533//    }
534    
535    if (window.getCkyConsent) {
536      const consent = window.getCkyConsent();
537      if (consent && consent.categories) {
538        // User has accepted cookies
539        console.log('Analytics cookies are accepted');
540      } else {
541        // User has not accepted cookies or cookies are disabled
542        translateReplace();
543      }
544    } else {
545        // CookieYes is not initialized or an error occurred
546        translateReplace();
547        console.log('CookieYes is not initialized');
548    }
549    
550    const translateContents = document.getElementById("google_translate_element").innerHTML;
551    document.addEventListener("cookieyes_consent_update", function (eventData) {
552      if (eventData && eventData.detail && eventData.detail.rejected.length > 0) {
553            // Cookies were rejected, execute your function here
554            translateReplace();
555      } else {
556            translateRefresh();
557      }
558    });
559
560    function translateReplace() {
561        let div = document.getElementById("google_translate_element");
562        div.innerHTML = "<p style='margin-top: 0;'><small>To translate, please accept cookies or use other browser translate options.
562</small></p>";
563    }
564    function translateRefresh() {
565        let div = document.getElementById("google_translate_element");
566        div.innerHTML = "<p style='margin-top: 0;'><small>Please refresh the page to access this translator.</small></p>";
567    }
568
569    
570	
571	// fixed sidebar for in-page nav from http://stackoverflow.com/questions/23081656/fixing-an-element-when-it-reaches-the-top-of-the-page
572		
573	if ($(".jsscrollfix").length > 0){
574		
575		viewport = updateViewportDimensions();
576		// if the viewport is tablet or larger, we use this sticky sidebar function
577		if (viewport.width >= 1140) {
578			var stickySidebar = $('.jsscrollfix').offset().top;
579			var footerSidebar = $('.site-footer').height() + $('.jsscrollfix').height();
580			var stickyHeight = footerSidebar + stickySidebar;
581			
582			var contentHeight = $('#inner-content').height();
583			
584			var elementHeights = $('.jsscrollfix').map(function() {
585				return $(this).height();
586			      }).get();
587			    
588			// Math.max takes a variable number of arguments
589			// `apply` is equivalent to passing each height as an argument
590			var maxHeight = Math.max.apply(null, elementHeights);
591			//if (viewport.width >= 1700) {
592			//	if (maxHeight < 680) {
593			//		maxHeight = 680;
594			//	}
595			//} else {
596				if (maxHeight < 600) {
597					maxHeight = 600;
598				}	
599			//}
600			
601			// Set each height to the max height
602			$('.jsscrollfix').height(maxHeight);
603			
604  
605			var docCalcunstick = contentHeight - maxHeight;
606			var docHeightunstick = docCalcunstick + stickySidebar;
607			
608			$(window).scroll(function(e) {
609                $("#inner-content").css("min-height", maxHeight);
610				
611				if (viewport.width < 1140) {
612					e.stopPropagation();
613                } else if (contentHeight < maxHeight) {
614                    e.stopPropagation();
615				} else {
616					$('.fixparent').css('height', contentHeight );
617				
618					if ($(window).scrollTop() > stickySidebar) {
619					    $('.jsscrollfix').addClass('fixed');
620					    
621					    
622					    if ( $(window).scrollTop() > docHeightunstick ) {
623						
624						$('.jsscrollfix').removeClass('fixed');
625						$('.jsscrollfix').addClass('unfixed');
626						
627					    } else {
628						$('.jsscrollfix').addClass('fixed');
629						$('.jsscrollfix').removeClass('unfixed');
630					    }
631					}
632					else {
633					    $('.jsscrollfix').removeClass('fixed');
634					}
635				}
636
637			});
638		} else {
639			$('.fixparent').css('height', '' );
640			//$('.jsscrollfix').css('height', '' );
641		}
642		
643		$(window).resize(function () {
644			viewport = updateViewportDimensions();
645			
646			$('.fixparent').css('height', '' );
647			$('.jsscrollfix').css('height', '' );
648		});
649	}
650	
651	
652  
653  // smooth scroll
654    $(function() {
655          $('a[href*="#"]:not([href="#"])').click(function() {
656            if (location.pathname.replace(/^\//,'') == this.pathname.replace(/^\//,'') && location.hostname == this.hostname) {
657              var target = $(this.hash);
658              target = target.length ? target : $('[name=' + this.hash.slice(1) +']');
659              if (target.length) {
660                $('html,body').animate({
661                  scrollTop: target.offset().top
662                }, 1000);
663                if( $(target).hasClass('accordion-toggle')) {
664                    target.addClass("open");
665                    target.siblings(".accordion-box").addClass("open");
666                }
667                return false;
668                  
669              }
670            }
671          });
672        });
673
674
675}); /* end of as page load scripts */

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.