PageSourceSearch

https://www.msu.edu.my/theme-2023/assets/themes/msu-apply/script.js?ver=6.0

js msu.edu.my collected 2026-10-02 11:16:15 UTC 50,683 bytes, 1,459 lines download raw bytes

1/**
2 * Below is a document-ready function that allows for standard jQuery syntax in WordPress by mapping jQuery() to '$'.
3 *
4 * If jQuery is not being used in this project, remove the function below and remove the jQuery dependency from the
5 * load_scripts_styles() function in inc/enqueue.php
6 *
7 * * */
8
9 jQuery(document).ready(function ($) {
10
11    /**
12     * Helper Functions
13     * */
14
15    /*Compensate for :hover states on touch devices*/
16    function isTouchDevice() {
17        return (('ontouchstart' in window) ||
18            (navigator.maxTouchPoints > 0) ||
19            (navigator.msMaxTouchPoints > 0));
20    }
21
22    /*Check if element is in viewport*/
23    function isElementVisible($element) {
24        if ($element.length) {
25            let top_of_element = $element.offset().top,
26                bottom_of_element = $element.offset().top + $element.outerHeight(),
27                bottom_of_screen = $(window).scrollTop() + $(window).innerHeight(),
28                top_of_screen = $(window).scrollTop();
29            if ((bottom_of_screen > top_of_element) && (top_of_screen < bottom_of_element)) {
30                // the element is visible
31                return true;
32            } else {
33                // the element is not visible
34                return false;
35            }
36        } else {
37            return false;
38        }
39    }
40
41    /* doubletaptogo.js: by Osvaldas Valutis, www.osvaldas.info */
42    $.fn.doubleTapToGo = function (params) {
43        if (!('ontouchstart' in window) &&
44            !navigator.msMaxTouchPoints &&
45            !navigator.userAgent.toLowerCase().match(/windows phone os 7/i)) return false;
46        this.each(function () {
47            var curItem = false;
48            $(this).on('click', function (e) {
49                var item = $(this);
50                if (item[0] != curItem[0]) {
51                    e.preventDefault();
52                    curItem = item;
53                }
54            });
55            $(document).on('click touchstart MSPointerDown', function (e) {
56                var resetItem = true,
57                    parents = $(e.target).parents();
58                for (var i = 0; i < parents.length; i++)
59                    if (parents[i] == curItem[0])
60                        resetItem = false;
61                if (resetItem)
62                    curItem = false;
63            });
64        });
65        return this;
66    };
67
68    /* Keyboard Character Code Reverse compatibility: use the legacy properties if they're available */
69    function getCharacterCode(e) {
70        if (e.which || e.charCode || e.keyCode) {
71            return e.which || e.charCode || e.keyCode;
72            //otherwise use new properties
73        } else if (e.key != undefined) {
74            return charCodeArr[e.key] || e.key.charCodeAt(0);
75        } else {
76            return 0;
77        }
78    }
79
80
81    /**
82     * Scroll Events
83     * */
84
85    var didScroll;
86    $(window).scroll(function (event) {
87        // on scroll, let the interval function know the user has scrolled
88        didScroll = true;
89
90        /*NOT Throttled Scroll Event*/
91        toggleStickyNav();
92    });
93    setInterval(function () {
94        if (didScroll) {
95            // run hasScrolled() and reset didScroll status
96            hasScrolled();
97            didScroll = false;
98        }
99    }, 250);
100
101    /*Throttled Scroll Event*/
102    function hasScrolled() {
103
104    }
105
106    /**
107     * On Resize and On Load
108     * */
109    $(window).on("resize", function () {
110        //wait for resize to end
111        if (this.resizeTO) clearTimeout(this.resizeTO);
112        this.resizeTO = setTimeout(function () {
113            $(this).trigger('resizeEnd');
114        }, 500);
115        // Invoke the resize event immediately on load
116    }).resize();
117
118    //After resize
119    $(window).bind('resizeEnd', function () {
120        //fix accordion tabs for desktop/mobile
121        if ($('.accordion-tabs').length) {
122            fixAccordionTabs();
123        }
124
125        //fix slider content height for desktop/mobile
126        if ($('.fixed-height-slider').length) {
127            fixSliderHeight();
128        }
129
130        //fix filters for desktop/mobile
131        if ($('.mobile-filters-wrapper').length) {
132            fixMobileFiltersVisibility();
133        }
134    });
135
136
137    /**
138     * Prevent page from scrolling behind modals/overlays
139     * */
140
141    function freezeScroll() {
142        let $body = $('body'),
143            scrollY = $(window).scrollTop(),
144            offsetTop = scrollY * -1;
145        $body.addClass('no-body-scroll').css('top', offsetTop + 'px');
146        if (scrollY > 0) {
147            $body.addClass('has-sticky-header');
148        }
149    }
150
151    function unfreezeScroll() {
152        let $body = $('body'),
153            scrollY = $body.css('top');
154        if ($body.hasClass('no-body-scroll')) {
155            $body.removeClass('no-body-scroll').css('top', '');
156            $(window).scrollTop(parseInt(scrollY || '0') * -1);
157        }
158    }
159
160    /**
161     * Smooth Scroll to Anchors
162     * */
163
164    $(document).on('click', 'a[href^="#"]', function (e) {
165        if ($(this).hasClass('smooth-scroll')) {
166            e.preventDefault();
167            let $header = $('#masthead');
168            $('html, body').animate({
169                scrollTop: $($.attr(this, 'href')).offset().top - $header.height()
170            }, 2500);
171        }
172    });
173
174    /**
175     * Desktop Header & Navigation
176     * */
177
178    /*Sticky Nav*/
179
180    //toggle sticky nav
181    function toggleStickyNav() {
182        let $header = $('#masthead'),
183            headerHeight = 150,
184            offset = $('html').css('margin-top'),
185            st = $(this).scrollTop();
186        //Show sticky header
187        if ((st > (headerHeight))) {
188            $('body').addClass('has-sticky-header');
189            $header.css('top', offset);
190        } else {
191            if (!$('body').hasClass('no-body-scroll')) {
192                $('body').removeClass('has-sticky-header');
193                $header.css('top', offset);
194            }
195        }
196    }
197
198    /*Mega Menu*/
199
200    //test for mobile menu
201    function isMobileMenu() {
202        return $('.header-mobile-btns').css('display') != 'none';
203    }
204
205    //fade in menu
206    $.fn.menuFadeIn = function () {
207        if (!isMobileMenu()) {
208            $('body').addClass('desktop-nav-active').removeClass('search-modal-active');
209            freezeScroll();
210        }
211        this.activateMenu();
212    }
213
214    //fade out menu
215    $.fn.menuFadeOut = function (fullFadeOut = false) {
216        //only fade out overlay if mouse has left the nav completely
217        if (($('#menu-primary-navigation').is(":hover") && !fullFadeOut) || isMobileMenu()) {
218            this.deactivateMenu();
219        } else {
220            $('body').removeClass('desktop-nav-active');
221            unfreezeScroll();
222            this.deactivateMenu();
223        }
224    }
225
226    //activate sub-menu
227    $.fn.activateMenu = function () {
228        if (isMobileMenu()) {
229            let $menu = this.children('.dropdown-panel').first();
230            $menu.height($menu.get(0).scrollHeight).parent('.menu-item').addClass('active'); // get height and open
231            $menu.one('transitionend', function () { // after transition complete
232                $menu.height(''); // revert to CSS-set height
233            });
234        } else {
235            this.addClass('active');
236        }
237        this.find('[aria-expanded]').attr('aria-expanded', 'true');
238    }
239
240    //deactivate sub-menu
241    $.fn.deactivateMenu = function () {
242        if (isMobileMenu()) {
243            let $menu = this.children('.dropdown-panel').first();
244            $menu.height('').parent('.menu-item').removeClass('active'); // remove height and close
245        } else {
246            this.removeClass('active');
247        }
248        this.find('[aria-expanded]').attr('aria-expanded', 'false');
249    }
250
251    //toggle menu dropdown on hover
252    $('#menu-primary-navigation > .menu-item-has-children').hoverIntent({
253        over: function () {
254            if (!isMobileMenu()) {
255                $(this).menuFadeIn();
256            }
257        },
258        out: function () {
259            if (!isMobileMenu()) {
260                $(this).menuFadeOut();
261            }
262        },
263        timeout: 500
264    });
265
266    //fade out menu by clicking "Close Dropdown Menu" button
267    $('.primary-navigation .dropdown-close').on('click keypress', function (e) {
268        e.preventDefault();
269        $(this).closest('.menu-item.active').menuFadeOut(true);
270    });
271
272    /*Desktop Menu Keyboard Navigation*/
273
274    // dropdown-trigger button utility menu
275    $('#menu-utility-menu > .menu-item-has-children .dropdown-trigger').on('click keypress', function (e) {
276        e.preventDefault();
277        let $li = $(this).closest('.menu-item-has-children'),
278            $alreadyActive = $li.siblings('.menu-item-has-children.active');
279
280        if ($li.hasClass('active')) {
281            $li.removeClass('active');
282        } else {
283            if ($alreadyActive.length) {
284                $alreadyActive.removeClass('active');
285            }
286            $li.addClass('active');
287        }
288    });
289
290    //fade out menu on focus of top level menu items
291    $('#menu-utility-menu .nav-link').on("focus", function () {
292        let $li = $(this).closest('.menu-item');
293        if (!isMobileMenu()) {
294            $li.siblings('.menu-item-has-children').removeClass('active');
295        }
296    });
297
298    // first click on utility mobile link opens the submenu
299    $('#menu-utility-menu .nav-link').on("click", function (e) {
300        let $parent = $(this).closest('.menu-item'),
301            $trigger = $(this).next('.dropdown-trigger');
302        if (isMobileMenu() && !$parent.hasClass('active') && $parent.hasClass('menu-item-has-children')) {
303            e.preventDefault();
304            $trigger.click();
305        }
306    });
307
308    //toggle menu with .dropdown-trigger button
309    $('#menu-primary-navigation > .menu-item-has-children .dropdown-trigger').on('click keypress', function (e) {
310        e.preventDefault();
311        let $li = $(this).closest('.menu-item-has-children'),
312            $alreadyActive = $li.siblings('.menu-item-has-children.active');
313
314        if ($li.hasClass('active')) {
315            $li.menuFadeOut();
316        } else {
317            if ($alreadyActive.length) {
318                $alreadyActive.menuFadeOut();
319            }
320            $li.menuFadeIn();
321        }
322    });
323
324    // close utility submenu on mouseleave
325    $('#menu-utility-menu .nav-item').on("mouseout", function () {
326        if (!isMobileMenu()) {
327            $(this).removeClass('active');
328        }
329    });
330
331    //fade out menu on focus of top level menu items
332    $('#menu-primary-navigation .menu-item-top a').on("focus", function () {
333        let $li = $(this).closest('.menu-item');
334        if (!isMobileMenu()) {
335            $li.siblings('.menu-item-has-children').menuFadeOut();
336        }
337    });
338
339    $('#menu-primary-navigation .menu-item-top a').on("click", function (e) {
340        let $parent = $(this).closest('.menu-item'),
341            $trigger = $(this).next('.dropdown-trigger');
342        if (isMobileMenu() && !$parent.hasClass('active')) {
343            e.preventDefault();
344            $trigger.click();
345        }
346        ;
347    });
348
349    /**
350     * Mobile Header & Navigation
351     * */
352
353    $('.mobile-nav-trigger').on('click', function () {
354        let expanded = $(this).attr('aria-expanded');
355        if (expanded === 'true') {
356            unfreezeScroll();
357            $(this).attr('aria-expanded', 'false');
358            $('body').removeClass('mobile-nav-active');
359        } else {
360            freezeScroll();
361            $(this).attr('aria-expanded', 'true');
362            $('body').addClass('mobile-nav-active');
363        }
364    });
365
366
367    /**
368     * Page Templates
369     * */
370    //Random Dots in corner
371    function randomDots() {
372        let rando = Math.floor((Math.random() * 2) + 1),
373            classAttr = 'has-bkgd-dots' + rando,
374            $body = $('body'),
375            templatesWithBackground = '.single-event_group, .page-template-tours-events-listing, .page-template-majors-and-minors';
376        if ($body.is(templatesWithBackground)) {
377            $body.find('.site-main').first().addClass(classAttr);
378        }
379    }
380
381    randomDots();
382
383    //Add arrow SVG to preset buttons
384    function insertArrowIcon() {
385        if ($('.btn-arrow--preset').length) {
386            let icon = '<svg class="icon-arrow-long" role="img" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="-2 -2 46 22" stroke-width="2" fill="none">\n' +
387                '  <path class="line" d="M 42 9 L 0 9" />\n' +
388                '  <path class="arrow" d="M 32 0 L 42 9 L 32 18" />\n' +
389                '</svg>';
390            $('.btn-arrow--preset').each(function () {
391                let wrappedContent = '<span>' + $(this).text() + '</span>';
392                $(this).html(icon + wrappedContent);
393            });
394        }
395    }
396
397    insertArrowIcon();
398
399    /**
400     * Video/Slider Controls
401     * */
402
403    //Toggle Play/Pause Button
404    $.fn.togglePlayPause = function ($target, label = 'Video') {
405        let $button = $(this),
406            isPaused = $button.attr('data-paused') === 'true',
407            newLabel = isPaused ? 'Pause' + ' ' + label : 'Play' + ' ' + label,
408            newState = isPaused ? 'false' : 'true';
409        if (typeof $target !== 'undefined') {
410
411            if ($target.is('video')) {
412                let $videos = $target;
413                //loop through videos
414                $videos.each(function () {
415                    if (isPaused) {
416                        $(this).get(0).play();
417                    } else {
418                        $(this).get(0).pause();
419                    }
420                });
421            } else if ($target.hasClass('slick-initialized')) {
422                let $slider = $target;
423                if (isPaused) {
424                    $slider.slick('slickPlay');
425                } else {
426                    $slider.slick('slickPause');
427                }
428            }
429        }
430        //update button
431        $button.toggleClass('playing').attr({
432            'aria-label': newLabel,
433            'data-paused': newState
434        }).find('.screen-reader-text').text(newLabel);
435    }
436
437    //Home Hero	Play/Pause
438    $('.home-hero .play-pause-button').click(function () {
439        let $video = $('.home-hero .video-background');
440        $(this).togglePlayPause($video, 'Background Video');
441    });
442
443    //L1 Hero Play/Pause
444    $('.l1-header .play-pause-button').click(function () {
445        let $video = $('.l1-header .video-background');
446        $(this).togglePlayPause($video, 'Background Video');
447    });
448
449    //Life in Baltimore Play/Pause
450    $('.life-baltimore-header .play-pause-button').click(function () {
451        let $video = $('.life-baltimore-header .video-background');
452        $(this).togglePlayPause($video, 'Background Video');
453    });
454
455    //Hopkins Insider
456    $('.insider-landing-column-header-video .play-pause-button').click(function () {
457        let $video = $('.insider-landing-column-header-video .video-background');
458        $(this).togglePlayPause($video, 'Background Videos');
459    });
460    $('#slider_studentVideo .play-pause-button').click(function () {
461        let $video = $('#slider_studentVideo .video-background');
462        $(this).togglePlayPause($video, 'Preview Videos');
463    });
464    $('#slider_advisorAdviceVideo .play-pause-button').click(function () {
465        let $video = $('#slider_advisorAdviceVideo .video-background');
466        $(this).togglePlayPause($video, 'Preview Videos');
467    });
468
469
470    //Insert Play/Pause Button into slick slider
471    $.fn.insertPlayPause = function (label = 'Slider', selector) {
472        let slideCount = $(this).slick("getSlick").slideCount;
473        if (slideCount > 1) {
474            let button = '<button type="button" class="play-pause-button playing" data-paused="false" aria-label="Pause ' + label + '"><span class="screen-reader-text">Pause ' + label + '</span></button>',
475                $target = $(this),
476                $sliderControls;
477            if (typeof selector !== 'undefined') {
478                $sliderControls = $(selector);
479            } else {
480                $sliderControls = $target;
481            }
482            $sliderControls.append(button).on('click', '.play-pause-button', function () {
483                $(this).togglePlayPause($target, label);
484            });
485        }
486    }
487
488    function findSlider($element) {
489        let sliderID = $element.closest('.slider-controls').attr('aria-controls');
490        return $('#' + sliderID);
491    }
492
493    $('.slider-prev').on('click', function () {
494        let $slider = findSlider($(this));
495        $slider.slick('slickPrev');
496    });
497
498    $('.slider-next').on('click', function () {
499        let $slider = findSlider($(this));
500        $slider.slick('slickNext');
501    });
502
503    $('.slider-controls .play-pause-button').click(function () {
504        let $slider = findSlider($(this));
505        $(this).togglePlayPause($slider, 'Slider');
506    });
507
508    //Fix "jumping" between first and last slides
509    $.fn.fixSlickJump =  function (){
510        this.on('beforeChange', function (event, slick, currentSlide, nextSlide) {
511            let direction,
512                slideCountZeroBased = slick.slideCount - 1,
513                extraSlidesShown = slick.options.slidesToShow - 1;
514            if (nextSlide == currentSlide) {
515                direction = "same";
516            } else if (Math.abs(nextSlide - currentSlide) == 1) {
517                direction = (nextSlide - currentSlide > 0) ? "right" : "left";
518            } else {
519                direction = (nextSlide - currentSlide > 0) ? "left" : "right";
520            }
521
522            // Add a temp CSS class for the slide animation (.slick-current-clone-animate)
523            if (direction == 'right') {
524                $(this).find('.slick-cloned[data-slick-index="' + (nextSlide + slideCountZeroBased + 1) + '"]').addClass('slick-current-clone-animate').nextAll().slice(0,extraSlidesShown).addClass('slick-current-clone-animate');
525            }
526            if (direction == 'left') {
527                $(this).find('.slick-cloned[data-slick-index="' + (nextSlide - slideCountZeroBased - 1) + '"]').addClass('slick-current-clone-animate').nextAll().slice(0,extraSlidesShown).addClass('slick-current-clone-animate');
528            }
529
530        });
531        this.on('afterChange', function (event, slick, currentSlide, nextSlide) {
532            $(this).find('.slick-current-clone-animate').removeClass('slick-current-clone-animate');
533        });
534    }
535
536
537    /**
538     * Sliders
539     * */
540
541    //Home Slider
542    $('#homeSlider').slick({
543        infinite: true,
544        autoplay: true,
545        arrows: false,
546        dots: true,
547        appendDots: $('#homeSliderControls'),
548    }).insertPlayPause('Slider', '#homeSliderControls');
549
550    //50-50 Carousel
551    if($('.carousel-50-50-section').length){
552        $('.carousel-50-50-section').each(function(){
553            let sectionID = '#' + $(this).attr('id'),
554                imageSliderID = sectionID + '-slider-images',
555                contentSliderID = sectionID + '-slider';
556
557            $(contentSliderID).slick({
558                infinite: true,
559                autoplay: true,
560                autoplaySpeed: 10000,
561                arrows: false,
562                dots: false,
563                speed: 500,
564                fade: true,
565                cssEase: 'linear',
566                asNavFor: imageSliderID,
567            });
568            $(imageSliderID).slick({
569                infinite: true,
570                arrows: false,
571                dots: false,
572                speed: 500,
573                fade: true,
574                cssEase: 'linear',
575                asNavFor: contentSliderID,
576            });
577
578        });
579    }
580
581
582    //Full-Width Slider
583    $('.full-width-slider').slick({
584        infinite: true,
585        autoplay: true,
586        autoplaySpeed: 7000,
587        arrows: false,
588        dots: false,
589        speed: 500,
590        fade: true,
591        cssEase: 'linear'
592    });
593
594    let full_width_slider_count = $('.full-width-slider').find('.slick-slide').length;
595    if (full_width_slider_count <= 1) {
596      $('.full-width-slider .slider-controls').hide();
597    }
598
599    //Featured Events Slider
600    $('#featuredEventsSlider').slick({
601        infinite: true,
602        autoplay: true,
603        autoplaySpeed: 7000,
604        arrows: false,
605        dots: true,
606        fade: true,
607        appendDots: $('#featuredEventsSliderControls'),
608    }).insertPlayPause('Featured Events Carousel', '#featuredEventsSliderControls');
609
610    //Listing A Slider
611    $('.listing-a-slider').slick({
612        infinite: true,
613        autoplay: true,
614        autoplaySpeed: 7000,
615        arrows: false,
616        dots: false,
617        speed: 500,
618        fade: true,
619        cssEase: 'linear'
620    });
621
622    //Interests Slider (Life in Baltimore)
623    var interstsSliderOptions = {
624        infinite: true,
625        arrows: false,
626        dots: false,
627        speed: 500,
628        variableWidth: true,
629    }
630    //only initialize visible Interests Slider on initial pageload
631    $('.tabs-panel.is-open .interests-slider').slick(interstsSliderOptions);
632
633    //initialize new Interests Slider when new tab opens
634    $('.interests-section .tabs-panel').on('tab:open', function () {
635        let $slider = $(this).find('.interests-slider');
636        if (!$slider.hasClass('slick-initialized')) {
637            $slider.slick(interstsSliderOptions);
638        }
639    });
640
641    //Hopkins Insider Categories Slider
642    $('#slider_otherCategories').slick({
643        infinite: true,
644        arrows: false,
645        dots: false,
646        speed: 500,
647        variableWidth: true,
648        responsive: [
649            {
650                breakpoint: 640,
651                settings: {
652                    infinite: true,
653                    arrows: false,
654                    dots: false,
655                    speed: 500,
656                    variableWidth: true,
657                    centerMode: true,
658                    slidesToShow: 1
659                }
660            },
661        ]
662    }).fixSlickJump();
663
664    //Hopkins Insider Video Sliders
665    if($('.hi-video-slider-video').length) {
666
667        let unslicked;
668
669        //remove loaders when responsive slider is initialized
670        $('#slider_studentVideo').on('init.slick', function (event, slick) {
671            $('.hi-block-video-slider--student').removeClass('loading');
672        });
673        $('#slider_advisorAdviceVideo').on('init.slick', function (event, slick) {
674            $('.hi-block-video-slider--admin').removeClass('loading');
675        });
676
677        //default slider options
678        function hi_videoSliderVideoOptions(navSlider) {
679            let centermode = false;
680            if(isMobileMenu()){
681                centermode = true;
682            }
683            return {
684                infinite: true,
685                arrows: false,
686                dots: false,
687                speed: 500,
688                variableWidth: true,
689                asNavFor: navSlider,
690                centerMode: centermode,
691                slidesToShow: 1,
692            };
693        }
694        function hi_videoSliderTextOptions(navSlider) {
695            return {
696                infinite: true,
697                arrows: false,
698                dots: false,
699                speed: 500,
700                slidesToShow: 1,
701                slidesToScroll: 1,
702                fade: true,
703                asNavFor: navSlider,
704                slidesToShow: 1,
705            };
706        }
707
708        //Initialize video sliders
709        function buildVideoSliders() {
710
711            //Hopkins Insider Student Video Sliders
712            $('#slider_studentVideo').slick(hi_videoSliderVideoOptions('#slider_studentText')).fixSlickJump();
713            $('#slider_studentText').slick(hi_videoSliderTextOptions('#slider_studentVideo'));
714
715            //Hopkins Insider Admin Video Sliders
716            $('#slider_advisorAdviceVideo').slick(hi_videoSliderVideoOptions('#slider_advisorAdviceText')).fixSlickJump();
717            $('#slider_advisorAdviceText').slick(hi_videoSliderTextOptions('#slider_advisorAdviceVideo'));
718
719
720            unslicked = false;
721        }
722
723        function destroyVideoSliders() {
724
725            if ($('#slider_studentVideo').hasClass('slick-initialized')) {
726                $('#slider_studentVideo').slick('unslick');
727            }
728            if ($('#slider_studentText').hasClass('slick-initialized')) {
729                $('#slider_studentText').slick('unslick');
730            }
731            if ($('#slider_advisorAdviceVideo').hasClass('slick-initialized')) {
732                $('#slider_advisorAdviceVideo').slick('unslick');
733            }
734            if ($('#slider_advisorAdviceText').hasClass('slick-initialized')) {
735                $('#slider_advisorAdviceText').slick('unslick');
736            }
737        }
738
739        //Build on initial page load
740        buildVideoSliders();
741
742        //Rebuild home header sliders on resize
743        let videoSliderResizeTimer,
744            windowWidth = $(window).width(),
745            windowHeight = $(window).height();
746        $(window).on('resize', function () {
747
748            if ($(this).width() !== windowWidth || $(this).height() !== windowHeight) {
749
750                //reset windowWidth to new width
751                windowWidth = $(this).width();
752                windowHeight = $(window).height();
753
754                if (unslicked === false) {
755                    unslicked = true;
756                    //"destroy" sliders and display loader on initial resize
757                    $('.hi-block-video-slider').addClass('loading');
758                    destroyVideoSliders();
759                }
760
761                clearTimeout(videoSliderResizeTimer);
762                videoSliderResizeTimer = setTimeout(function () {
763                    // Run code here, resizing has "stopped"
764                    buildVideoSliders();
765                    $('.hi-block-video-slider').removeClass('loading');
766                }, 250);
767            }
768        });
769
770    }
771
772
773    //Fixed Height Slider
774    function fixSliderHeight() {
775        $('.fixed-height-slider').each(function () {
776            let slideContents = $(this).find('.slide-content-inner'),
777                minHeight = 0;
778            slideContents.css('min-height', 0);
779            slideContents.each(function () {
780                if ($(this).outerHeight() > minHeight) {
781                    minHeight = $(this).outerHeight();
782                }
783            });
784            if (minHeight > 0) {
785                slideContents.css('min-height', minHeight + 'px');
786            }
787        });
788    }
789
790    /**
791     * Accordions & Tabs
792     * */
793
794    //open accordion
795    $.fn.openAccordion = function () {
796        let $accordion = $(this),
797            $trigger = $accordion.find('.accordion-trigger').first(),
798            $content = $accordion.find('.accordion-content').first(),
799            isAccordionTabs = $(this).closest('.accordion-tabs').length;
800
801        $accordion.addClass('is-open');
802        $trigger.attr('aria-expanded', 'true');
803
804        if ($trigger.css('display') != 'none') {
805            //animate accordion content unless its desktop accordion tabs
806            $content.height($content.get(0).scrollHeight).attr('aria-hidden', 'false').addClass('is-open'); // get height and open
807            $content.one('transitionend', function () { // after transition complete
808                $content.height(''); // revert to CSS-set height
809            });
810        } else {
811            $content.attr('aria-hidden', 'false').addClass('is-open');
812        }
813    }
814
815    //close accordion
816    $.fn.closeAccordion = function () {
817        let $accordion = $(this),
818            $trigger = $accordion.find('.accordion-trigger').first(),
819            $content = $accordion.find('.accordion-content').first();
820
821        $accordion.removeClass('is-open');
822        $trigger.attr('aria-expanded', 'false').blur();
823
824        if ($trigger.css('display') != 'none') {
825            //animate accordion content unless its desktop accordion tabs
826            $content.height($content.get(0).scrollHeight).height('').attr('aria-hidden', 'true').removeClass('is-open'); // get height and close
827        } else {
828            $content.attr('aria-hidden', 'true').removeClass('is-open');
829        }
830    }
831
832    //toggle accordion
833    $('.accordion-trigger').on('click', function (e) {
834        if(!$(e.target).is('a, a *')){ //allow links inside accordion titles to work
835            e.preventDefault();
836            let isOpen = $(this).attr('aria-expanded') === 'true',
837                target = $(this).attr('aria-controls'),
838                $accordion = $('#' + target),
839                $accordionTabs = $(this).closest('.accordion-tabs');
840            if (isOpen) {
841                //close accordion
842                $accordion.closeAccordion();
843
844                //open tab if this is also a tab panel
845                if ($accordionTabs.length) {
846                    $accordionTabs.find('.tabs-list a').each(function () {
847                        if ($(this).attr('aria-controls') === target) {
848                            $(this).closeTab();
849                        }
850                    });
851                }
852            } else {
853                $accordion.siblings('.accordion.is-open').each(function () {
854                    $(this).closeAccordion();
855                });
856                //open accordion
857                $accordion.openAccordion();
858
859                //open/close appropriate tabs if this is also a tab panel
860                if ($accordionTabs.length) {
861                    $accordionTabs.find('.tabs-list a').each(function () {
862                        if ($(this).attr('aria-controls') === target) {
863                            $(this).openTab();
864                        } else {
865                            $(this).closeTab();
866                        }
867                    });
868                }
869            }
870        }
871    });
872
873    //accordion keyboard accessibility
874    $('.accordion-trigger').keydown(function (e) {
875        if (e.code === 'Enter' || e.code === 'Space') {
876            e.preventDefault();
877            $(this).click();
878        }
879    });
880
881    //open tab
882    $.fn.openTab = function (withAccordion = false) {
883        let target = $(this).attr('aria-controls'),
884            $panel = $('#' + target);
885        $panel.trigger('tab:open');
886        $(this).attr('aria-selected', 'true').addClass('is-selected').removeAttr('tabindex');
887        $panel.addClass('is-open').attr('tabindex', '0');
888
889        //open accordion if this is also an accordion
890        if ($panel.hasClass('accordion') && withAccordion) {
891            $panel.openAccordion();
892        }
893    }
894
895    //close tab
896    $.fn.closeTab = function (withAccordion = false) {
897        let target = $(this).attr('aria-controls'),
898            $panel = $('#' + target);
899        $panel.trigger('tab:close');
900        $(this).attr('aria-selected', 'false').removeClass('is-selected').attr('tabindex', '-1');
901        $panel.removeClass('is-open').attr('tabindex', '-1');
902
903        //close accordion if this is also an accordion
904        if ($panel.hasClass('accordion') && withAccordion) {
905            $panel.closeAccordion();
906        }
907    }
908
909    //tab trigger click
910    $('.tabs-list .tabs-trigger').on('click', function (e) {
911        e.preventDefault();
912        let isSelected = $(this).hasClass('is-selected');
913        if (!isSelected) {
914            //close other tab
915            $(this).closest('li').siblings().find('.is-selected').each(function () {
916                $(this).closeTab(true);
917            });
918            //open this tab
919            $(this).openTab(true);
920        }
921    })
922
923    //accordion keyboard accessibility
924    $('.tabs-trigger').keyup(function (e) {
925        let keyCode = getCharacterCode(e),
926            keys = {
927                end: 35,
928                home: 36,
929                left: 37,
930                up: 38,
931                right: 39,
932                down: 40,
933                tab: 9,
934            };
935        if (keyCode != keys.tab) {
936            e.preventDefault();
937
938            let $tablist = $(this).closest('.tabs-list'),
939                $tablistItem = $(this).closest('li'),
940                $firstTab = $tablist.find('.tabs-trigger').first(),
941                $lastTab = $tablist.find('.tabs-trigger').last(),
942                $nextTab = $tablistItem.next().find('.tabs-trigger'),
943                $prevTab = $tablistItem.prev().find('.tabs-trigger');
944            if (keyCode === keys.left || keyCode === keys.up) {
945                if ($tablistItem.is(':first-child')) {
946                    $lastTab.click().focus();
947                } else {
948                    $prevTab.click().focus();
949                }
950            } else if (keyCode === keys.right || keyCode === keys.down) {
951                if ($tablistItem.is(':last-child')) {
952                    $firstTab.click().focus();
953                } else {
954                    $nextTab.click().focus();
955                }
956            } else if (keyCode === keys.home) {
957                $firstTab.click().focus();
958            } else if (keyCode === keys.end) {
959                $lastTab.click().focus();
960            }
961        }
962    });
963
964
965    //start with first tab open on desktop
966    function fixAccordionTabs() {
967        if ($('.tabs-list').css('display') != 'none') {
968            $('.accordion-tabs').each(function () {
969                if (!$(this).find('.tabs-trigger.is-selected').length) {
970                    $(this).find('.tabs-trigger').first().openTab(true);
971                }
972            });
973        }
974    }
975
976    /**
977     * Filter Functions
978     * */
979
980    //filters accordion on mobile. Add aria-hidden for mobile only.
981    function fixMobileFiltersVisibility() {
982        let $wrapper = $('.mobile-filters-wrapper'),
983            $filterList = $wrapper.find('.filter-list').first();
984        if (!isMobileMenu()) {
985            $filterList.removeAttr('aria-hidden');
986        } else {
987            if ($wrapper.hasClass('is-open')) {
988                $filterList.attr('aria-hidden', 'false');
989            } else {
990                $filterList.attr('aria-hidden', 'true');
991            }
992        }
993    }
994
995    $('.filter-box--select select').on('change', function () {
996        $(this).closest('.filter-box--select').addClass('has-option-selected');
997    });
998
999    /**
1000     * Modal Functions
1001     * */
1002
1003    //Trap Focus
1004    $.fn.trapFocus = function ($trigger, autoFocus = false) {
1005        let $this = $(this),
1006            hasTabbed = false,
1007            tabbable = $this.find('select, input, textarea, button, a, [tabindex]:not([tabindex^="-"]), iframe').filter(':visible'),
1008            firstTabbable = tabbable.first(),
1009            lastTabbable = tabbable.last();
1010
1011        if (autoFocus) {
1012            firstTabbable.focus();
1013            hasTabbed = true;
1014        } else {
1015            /*set focus on first tab press*/
1016            $(document).on('keydown', function (e) {
1017                let keyCode = getCharacterCode(e);
1018                if ((keyCode === 9 && !hasTabbed) && $this.hasClass('active')) {
1019                    e.preventDefault();
1020                    firstTabbable.focus();
1021                    hasTabbed = true;
1022                }
1023            });
1024        }
1025
1026        /*redirect last tab to first focus item*/
1027        lastTabbable.on('keydown', function (e) {
1028            let keyCode = getCharacterCode(e);
1029            if ((keyCode === 9 && !e.shiftKey)) {
1030                e.preventDefault();
1031                firstTabbable.focus();
1032            }
1033        });
1034
1035        /*redirect first shift+tab to last focus item*/
1036        firstTabbable.on('keydown', function (e) {
1037            let keyCode = getCharacterCode(e);
1038            if ((keyCode === 9 && e.shiftKey)) {
1039                e.preventDefault();
1040                lastTabbable.focus();
1041            }
1042        });
1043
1044        /*
1045        * Escape the Trap
1046        * */
1047
1048        /* escape key pressed */
1049        $(document).on('keyup', function (e) {
1050            let keyCode = getCharacterCode(e);
1051            if (keyCode === 27) {
1052                closeModal();
1053                if ($trigger) {
1054                    //focus on link that opened modal
1055                    $trigger.focus();
1056                }
1057            }
1058            ;
1059        });
1060
1061        /* close button pressed */
1062        $('.popup-modal-close').on('keypress', function (e) {
1063            e.preventDefault();
1064            closeModal();
1065            if ($trigger) {
1066                //focus on link that opened modal
1067                $trigger.focus();
1068            }
1069        });
1070    }
1071
1072    //Close Modals
1073    function closeModal() {
1074        unfreezeScroll();
1075        //Close dynamic popup
1076        $('.popup-modal').removeClass('active').fadeOut();
1077
1078        //stop video and remove aspect ratio class
1079        $('.popup-modal .video-wrapper').html('').closest('.wp-has-aspect-ratio').removeClass (function (index, className) {
1080            return (className.match (/\bwp-embed-aspect-\S+/g) || []).join(' ');
1081        });
1082    }
1083
1084    //Open Modals
1085    function openModal($target, $trigger = false) {
1086        freezeScroll();
1087        //Open dynamic popup
1088        $target.addClass('active').fadeIn().scrollTop(0).trapFocus($trigger);
1089    }
1090
1091    /**
1092     * Popup Modal Click Events
1093     * */
1094
1095    $('.popup-modal-close').on('click', function (e) {
1096        e.preventDefault();
1097        closeModal();
1098    });
1099
1100    //Youtube Modal
1101    $('.youtube-lightbox').on('click keypress', function (e) {
1102        e.preventDefault();
1103        let $trigger = $(this),
1104            href = $trigger.attr('href'),
1105            jsonEndpoint = 'https://www.youtube.com/oembed?url=' + href + '&format=json',
1106            embedHtml = '',
1107            aspectRatioClass = 'wp-embed-aspect-';
1108            aspectRatio = $trigger.attr('data-aspect-ratio');
1109
1110        //use 16:9 aspect ratio if not specified otherwise
1111        if (typeof aspectRatio !== 'undefined' && aspectRatio !== false) {
1112            aspectRatioClass += aspectRatio
1113        }else{
1114            aspectRatioClass += '16-9'
1115        }
1116        $.getJSON(jsonEndpoint, function (data) {
1117            // JSON result in `data` variable
1118            embedHtml = data.html;
1119            if (embedHtml != '') {
1120
1121                //make autoplay with no related videos
1122                embedHtml = embedHtml.replace('?feature=oembed', '?feature=oembed&rel=0&autoplay=1');
1123
1124                let $modal = $('#overlayVideo');
1125
1126                //add aspect ratio class
1127                $modal.find('.wp-has-aspect-ratio').addClass(aspectRatioClass);
1128
1129                //append the video
1130                $modal.find('.video-wrapper').html(embedHtml);
1131
1132                //Fade In Modal
1133                openModal($modal, $trigger);
1134            }
1135        });
1136    });
1137
1138    //Search Modal
1139    $('.search-trigger').on('click keypress', function (e) {
1140        e.preventDefault();
1141        let $trigger = $(this),
1142            $modal = $('#overlaySearch');
1143
1144        //Fade In Modal
1145        openModal($modal, $trigger);
1146
1147        //focus searchbar after fade-in
1148        setTimeout(function () {
1149            $modal.find('.searchform-input').first().focus();
1150        }, 600);
1151    });
1152
1153    /**
1154     * Parallax
1155     * */
1156
1157    //Parallax movement
1158    $.fn.parallaxOffset = function (maxOffset = 0, $viewport = $(window)) {
1159        let $wrapper = this.closest('.parallax-container'),
1160            totalHeight = $wrapper.height() + $viewport.height(),
1161            wrapperTop = $wrapper.offset().top,
1162            offset = (wrapperTop - $viewport.scrollTop()) + $wrapper.height(),
1163            percentage = (totalHeight - offset) / totalHeight;
1164        if (maxOffset === 0) {
1165            maxOffset = $wrapper.height() - this.outerHeight(true);
1166        }
1167        let parallaxPosition = maxOffset * percentage;
1168        this.css('transform', 'translateY(-' + parallaxPosition + 'px)');
1169    }
1170
1171    //Virtual Tour Block Background Parallax
1172    if ($('.virtual-tour-block').length) {
1173        let $viewport = $(window);
1174        $viewport.on({
1175            scroll: function () {
1176                //Move the Parallax Item
1177                $('.virtual-tour-block-bkgd.parallax').each(function () {
1178                    if (isElementVisible($(this))) {
1179                        //Move element if visible
1180                        $(this).parallaxOffset(200);
1181                    }
1182                });
1183            },
1184        });
1185    }
1186
1187
1188    /**
1189     * Homepage
1190     * */
1191
1192    //Disable Profile Panel part of Link on Mobile
1193    $('.home-profile-grid-item').on('click', function (e) {
1194        if (isMobileMenu()) {
1195            if ($('.profile-panel').find(e.target).length) {
1196                e.preventDefault();
1197            }
1198        }
1199    });
1200
1201    /**
1202     * Life in Baltimore
1203     * */
1204
1205    $.fn.isHoverColumn = function () {
1206        let $link = $(this).find('.hover-column-link').first()
1207        if ($link.css('position') === 'absolute') {
1208            return true;
1209        } else {
1210            return false;
1211        }
1212    }
1213
1214    $.fn.activateHoverColumnLeftAlign = function () {
1215        if ($(this).isHoverColumn()) {
1216            let $top = $(this).find('.hover-column-top').first(),
1217                $bottom = $(this).find('.hover-column-bottom').first(),
1218                offset = $bottom.height();
1219            $top.css('transform', 'translateY(-' + offset + 'px)');
1220        }
1221    }
1222
1223    $.fn.deactivateHoverColumnLeftAlign = function () {
1224        if ($(this).isHoverColumn() && !$(this).is(':focus-within')) {
1225            let $top = $(this).find('.hover-column-top').first();
1226            $top.removeAttr('style');
1227        }
1228    }
1229
1230    $('.hover-column--left-align').hover(
1231        function () {
1232            $(this).activateHoverColumnLeftAlign();
1233        }, function () {
1234            $(this).deactivateHoverColumnLeftAlign();
1235        }
1236    );
1237
1238    $('.hover-column--left-align .hover-column-link').focus(function () {
1239        let $column = $(this).closest('.hover-column--left-align');
1240        $column.activateHoverColumnLeftAlign();
1241    }).blur(function () {
1242        let $column = $(this).closest('.hover-column--left-align');
1243        $column.deactivateHoverColumnLeftAlign();
1244    });
1245
1246
1247    $('.tabs-list-wrapper').on('click', function (e) {
1248        if (isMobileMenu() && !$(this).hasClass('is-open')) {
1249            e.preventDefault();
1250            $(this).addClass('is-open');
1251        } else if (isMobileMenu()) {
1252            $(this).removeClass('is-open');
1253        }
1254    });
1255
1256    function closeTabsListWrapperDropdown() {
1257        $('.tabs-list-wrapper.is-open').removeClass('is-open');
1258    }
1259
1260    $(document).on('click', function (e) {
1261        let $list = $('.tabs-list-wrapper.is-open');
1262        if ($list !== e.target && !$list.has(e.target).length) {
1263            closeTabsListWrapperDropdown();
1264        }
1265    });
1266
1267    $('.tabs-list-wrapper').on('focusin', function (e) {
1268        if (isMobileMenu() && !$(this).hasClass('is-open')) {
1269            $(this).addClass('is-open');
1270        }
1271    });
1272
1273
1274    /**
1275     * Hopkins Insider
1276     * */
1277
1278    //HI Landing Page Prevent automatic browser scroll on page refresh
1279    $(window).on('beforeunload', function() {
1280        fixInsiderWindowScroll();
1281    });
1282    function fixInsiderWindowScroll(){
1283        if($('body').hasClass('page-template-hopkins-insider-landing') && !isMobileMenu()){
1284            history.scrollRestoration = "manual";
1285        }else{
1286            history.scrollRestoration = "auto";
1287        }
1288    }
1289
1290    //HI Landing Page Header (push up header content on column/page scroll)
1291    setHITitlePosition(); //onload
1292    $('.insider-landing-column').on('scroll', setHITitlePosition); //column scroll
1293    $(document).on('scroll', setHITitlePosition); //page scroll
1294
1295    function setHITitlePosition(){
1296        if($('body').hasClass('page-template-hopkins-insider-landing') && !isMobileMenu()) {
1297            let documentScrollY = document.documentElement.scrollTop,
1298                offsetLeft = $('#splitLayoutLeft').scrollTop(),
1299                offsetRight = $('#splitLayoutRight').scrollTop(),
1300                offset = (Math.max(offsetLeft, offsetRight) + documentScrollY) * -1;
1301            $('#splitLayoutHeader').css("transform", "translateY(" + offset + "px)");
1302        }
1303    }
1304
1305    //HI Landing Page faux scrollbar on scroll
1306    $('.insider-landing-column').scroll(function (event) {
1307        let scrollTop = $(this).scrollTop(),
1308            scrollBottom = $(this).prop("scrollHeight") - $(this).height(),
1309            scrollPercent = scrollTop / scrollBottom * 100 + "%";
1310
1311        //move scrollbar gradient
1312        $(this).find('.insider-landing-column-progress').css("--scroll", scrollPercent);
1313    });
1314
1315    //Allow the faux scrollbar to be clickable
1316    $('.insider-landing-column-progress-placeholder').on('mouseup', function(e) {
1317        let $parent = $(this).closest('.insider-landing-column'),
1318            height = $parent.height(),
1319            posY = $('#cols-container').offset().top,
1320            percent = (e.pageY) / height,
1321            parentHeight = $parent.prop("scrollHeight") - $parent.height(),
1322            newScrollPos = parentHeight * percent;
1323        //scroll to new position
1324        $parent.scrollTop(newScrollPos);
1325    });
1326
1327    //Expand faux scrollbar on hover
1328    $('.insider-landing-column-progress-placeholder').hover(function(){
1329        //hover in
1330        $(this).closest('.insider-landing-column').addClass('has-scrollbar-active');
1331    },function(){
1332        //hover out
1333        $(this).closest('.insider-landing-column').removeClass('has-scrollbar-active');
1334    });
1335
1336    //Move a scrollbar position indicator on hover
1337    $('.insider-landing-column-progress-placeholder').on('mousemove touchstart touchmove', function(e){
1338        let points = [],
1339            $target = $(this).closest('.insider-landing-column').find('.insider-landing-column-progress-inner').first();
1340        if ((e.clientX)&&(e.clientY)) {
1341            points[0] = e;
1342        } else if (e.targetTouches) {
1343            points = e.targetTouches;
1344            e.preventDefault();
1345        }
1346        for (let i = 0; i<points.length; i++) {
1347            $target.css('transform','translateY(' + points[i].clientY + 'px)');
1348        }
1349    });
1350
1351    //HI category selection form
1352    $('.hi-block-category-search-form').on('submit', function (e) {
1353        e.preventDefault();
1354
1355        // redirect to selected category
1356        let selectedCategory = $(this).find('[name="category"]').val();
1357        if (selectedCategory) {
1358            location.href = selectedCategory;
1359        }
1360    });
1361
1362
1363    /**
1364     * Datepicker Accessibility
1365     * */
1366
1367    //Send message to Datepicker Reader
1368    function readDatepicker(message) {
1369        let $datepickerReader = $('#datepicker-reader'),
1370            oldMessage = $datepickerReader.html();
1371        if (oldMessage != message) {
1372            $datepickerReader.html(message);
1373        }
1374    }
1375
1376    //Read Floating Datepicker
1377    function readFloatingDatepicker() {
1378        let $datepicker = $('#ui-datepicker-div');
1379        if ($datepicker.css('display') === 'block') {
1380            $('body').addClass('keyboard-in-use');
1381            let day = $datepicker.find('.ui-state-hover'),
1382                month = $datepicker.find('.ui-datepicker-month'),
1383                year = $datepicker.find('.ui-datepicker-year'),
1384                message =
1385                    ' ' + day.html() +
1386                    ' ' + month.html() +
1387                    ' ' + year.html();
1388            readDatepicker(message);
1389        }
1390    }
1391
1392    $(document).bind('keyup', function (e) {
1393        readFloatingDatepicker();
1394    });
1395
1396    //Read Inline Datepicker
1397    $.fn.readInlineDatepicker = function () {
1398        let $datepicker = $(this).closest('.ui-datepicker-inline'),
1399            day = $(this).attr('data-date'),
1400            month = $datepicker.find('.ui-datepicker-month').html(),
1401            year = $datepicker.find('.ui-datepicker-year').html(),
1402            message =
1403                ' ' + day +
1404                ' ' + month +
1405                ' ' + year;
1406        readDatepicker(message);
1407    }
1408
1409    $(document).on('focus', '.ui-datepicker-inline td a', function () {
1410        $(this).readInlineDatepicker();
1411    });
1412
1413
1414    /**
1415     * Weglot Accessibility
1416     * */
1417
1418    //Make weglot dropdown keyboard accessible
1419    $('.weglot-dropdown .wg-li').each(function () {
1420        $(this).attr('tabindex', '0');
1421    }).on('keypress', function (e) {
1422        e.preventDefault();
1423        let code = e.keyCode || e.which,
1424            $link = $(this).find('a').first();
1425        if (code == 13) {
1426            if ($link.length) {
1427                $link.get(0).click();
1428            } else {
1429                $(this).trigger('click');
1430            }
1431        }
1432    });
1433
1434    //close weglot dropdown on focusout
1435    $('.weglot-dropdown').on('focusout', function (e) {
1436        if (!$(this).is(':focus-within')) {
1437            $(this).find('input[type="checkbox"]').first().prop("checked", false);
1438        }
1439    });
1440
1441    /**
1442     * Keypress Events
1443     * */
1444
1445    $(document).bind('keydown', function (e) {
1446        //console.log(document.activeElement);
1447        let code = getCharacterCode(e);
1448        if (code == 27) {
1449            //ESC Pressed
1450            $('#menu-primary-navigation > .active').menuFadeOut(); //close nav dropdown
1451            closeModal(); //close popup modal
1452        }
1453        if (code == 9) {
1454            //Tab Pressed
1455            $('body').addClass('keyboard-in-use'); //add a11y buttons to nav
1456        }
1457    });
1458
1459});

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.