PageSourceSearch

https://www.scholarshare529.com/scripts/master.js?v=10735

js scholarshare529.com collected 2026-10-03 22:51:53 UTC 22,541 bytes, 687 lines download raw bytes

1// Begin Search JS
2
3var result_m = document.getElementById("mobilesearchvalidation");
4var result_d = document.getElementById("desktopsearchvalidation");
5var resultsBase = "/resources/search";
6var searchErrMsg = "⚠ Please enter a search term";
7
8$("#findmobile").on('input', function () {
9    ClearSearchValidation(result_m);
10});
11
12$("#finddesktop").on('input', function () {
13    ClearSearchValidation(result_d);
14});
15
16function ClearSearchValidation(el) {
17    el.classList.remove("search-error");
18    el.removeAttribute("role");
19    el.innerHTML = "";
20}
21
22$("#searchboxformmobile").on('submit', function (event) {
23    event.preventDefault();
24    var query = $("#findmobile").val();
25    ClearSearchValidation(result_m);
26    var value = document.getElementById('findmobile').value;
27    if (value === '') {
28        result_m.classList.add("search-error");
29        result_m.setAttribute("role", "alert");
30        result_m.innerHTML = searchErrMsg;
31    } else {
32        window.location = resultsBase + "#stq=" + query + "&stp=1";
33    }
34});
35
36$("#searchboxformmodal").on('submit', function (event) {
37    event.preventDefault();
38    var query = $("#finddesktop").val();
39    ClearSearchValidation(result_d);
40    var value = document.getElementById('finddesktop').value;
41    if (value === '') {
42        result_d.classList.add("search-error");
43        result_d.setAttribute("role", "alert");
44        result_d.innerHTML = searchErrMsg;
45    } else {
46        //close the modal window
47        $('#desktopSearchModal').modal('hide');
48        window.location = resultsBase + "#stq=" + query + "&stp=1";
49    }
50});
51
52window.addEventListener('resize', function () {
53    var rw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
54
55    if (rw >= 992) {
56        if (result_m !== undefined && result_m !== null && result_m.innerHTML.trim() !== "") {
57            ClearSearchValidation(result_m);
58        }
59    } else {
60        if (result_d !== undefined && result_d !== null && result_d.innerHTML.trim() !== "") {
61            ClearSearchValidation(result_d);
62        }
63        if ($('#desktopSearchModal').is(':visible')) {
64            $('#desktopSearchModal').modal('hide');
65        }
66    }
67});
68
69var searchModal = document.getElementById('desktopSearchModal');
70
71if (searchModal != null) {
72    searchModal.addEventListener('hidden.bs.modal', function () {
73        ClearSearchValidation(result_d);
74        document.getElementById('finddesktop').value = "";
75    });
76}
77
78$('#desktopSearchModal').on('shown.bs.modal', function () {
79    //set focus on input in modal	
80    $('#finddesktop').trigger("focus");
81
82})
83
84$(document).on('mouseenter', 'li.result.seeall', function () {
85    $('li.result').removeClass('active');
86    $(this).addClass('active');
87});
88
89$(document).on('mouseleave', 'li.result.seeall', function () {
90    $(this).removeClass('active');
91});
92
93$(document).on('click', 'li.result.seeall', function () {
94    let link = $("li.result.seeall > p > a").attr("href");
95    if (link) {
96        window.location.href = link;
97    }
98});
99// End Search JS
100
101// Begin Modal JS
102//Prevent Keyboard Users from Focusing on Elements Outside of the Modal Dialogs While Open - .first-focusable-element/.first-focusable-element-graph and .last-focusable-element/.last-focusable-element-graph have been added to the respective elements inside the modal dialogs.
103$('.modal:not([role])').attr('role', 'dialog');
104
105const modals = document.querySelectorAll('[role="dialog"]');
106modals.forEach(modal => {
107    let firstFocusableElement = modal.querySelector('[class*="first-focusable-element"]');
108    let lastFocusableElement = modal.querySelector('[class*="last-focusable-element"]');
109
110    if (firstFocusableElement == null) {
111        firstFocusableElement = getFirstFocusableElement(modal);
112    }
113
114    if (lastFocusableElement == null) {
115        lastFocusableElement = getLastFocusableElement(modal);
116
117        if (lastFocusableElement == null && firstFocusableElement != null) {
118            lastFocusableElement = firstFocusableElement;
119        }
120    }
121
122    modal.addEventListener('keydown', function (e) {
123        if (e.target == firstFocusableElement && e.key == 'Tab' && e.shiftKey) {
124            e.preventDefault();
125            lastFocusableElement.focus();
126        } else if (e.target == lastFocusableElement && e.key == 'Tab' && !e.shiftKey) {
127            e.preventDefault();
128            firstFocusableElement.focus();
129        }
130    });
131});
132
133function getFirstFocusableElement(container = document) {
134    const focusableElements = container.querySelectorAll(
135        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
136    );
137
138    if (focusableElements.length > 0) {
139        return focusableElements[0];
140    } else {
141        return null; // No focusable elements found
142    }
143}
144
145function getLastFocusableElement(container = document) {
146    const focusableElements = container.querySelectorAll(
147        'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
148    );
149
150    if (focusableElements.length > 0) {
151        return focusableElements[focusableElements.length - 1];
152    } else {
153        return null; // No focusable elements found
154    }
155}
156// End Modal JS
157
158
159// Begin Back To Top Button
160//Get the button
161let mybutton = document.getElementById("btn-back-to-top");
162
163// When the user scrolls down 20px from the top of the document, show the button
164window.onscroll = function () {
165    scrollFunction();
166};
167
168function scrollFunction() {
169    if (
170        document.body.scrollTop > 20 ||
171        document.documentElement.scrollTop > 20
172    ) {
173        mybutton.style.display = "block";
174    } else {
175        mybutton.style.display = "none";
176    }
177}
178// When the user clicks on the button, scroll to the top of the document
179mybutton.addEventListener("click", backToTop);
180
181function backToTop() {
182    var bw = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;
183    var skip = $("#" + (bw >= 992 ? "skipbutton" : "main-logo"));
184    $(skip)[0].scrollIntoView();
185    skip.trigger("focus");
186}
187// End Back To Top Button
188
189
190// Begin Email Signup
191var frm = $('#subscribeForm');
192var frm_input = document.getElementById('emailsignup');
193var result_p = document.getElementById('emailsignup-result');
194var icon_span = document.getElementById('email-result-icon');
195
196frm.on('submit', function (e) {
197    //reinitialize variables if needed
198    if (frm.attr('id').indexOf('campaign') > -1) {
199        frm = $('#subscribeForm');
200        frm_input = document.getElementById('emailsignup');
201        result_p = document.getElementById('emailsignup-result');
202        icon_span = document.getElementById('email-result-icon');
203    }
204
205    e.preventDefault();
206    clearEmailMessage();
207    validateForm();
208});
209
210function clearEmailMessage() {
211    result_p.classList.remove('error');
212    result_p.classList.remove('success');
213    result_p.removeAttribute("role");
214    result_p.innerHTML = "";
215    icon_span.classList.remove('email-error-icon');
216    icon_span.classList.remove('email-success-icon');
217    icon_span.innerHTML = "";
218    $("#" + frm_input.id).attr('aria-invalid', 'false').removeAttr('aria-describedby');
219}
220
221function validateForm() {
222    var value = frm_input.value;
223    if (value === '') {
224        setEmailError('Please enter your email in the format:<br/>[email protected]');
225        return false;
226    }
227
228    if (!validateEmail(value)) {
229        setEmailError('Please enter your email in the format:<br/>[email protected]');
230        return false;
231    }
232    SubmitForm(value);
233}
234
235function setEmailError(msg) {
236    result_p.classList.remove('success');
237    result_p.classList.add('error');
238    result_p.setAttribute("role", "alert");
239    result_p.innerHTML = DOMPurify.sanitize(msg);
240
241    icon_span.classList.remove('email-success-icon');
242    icon_span.classList.add('email-error-icon');
243    icon_span.innerHTML = "&#9888;";
244
245    $("#" + frm_input.id).attr('aria-invalid', 'true').attr('aria-describedby', result_p.id);
246    $("#" + frm_input.id).trigger("focus");
247}
248
249function setEmailSuccess(msg) {
250    result_p.classList.add('success');
251    result_p.classList.remove('error');
252    result_p.setAttribute("role", "alert");
253    result_p.innerHTML = DOMPurify.sanitize(msg);
254
255    icon_span.classList.add('email-success-icon');
256    icon_span.classList.remove('email-error-icon');
257    icon_span.innerHTML = "&#10003;";
258
259    $("#" + frm_input.id).attr('aria-invalid', 'false').attr('aria-describedby', result_p.id);
260}
261
262function validateEmail(emailAddress) {
263    var filter = /^([A-Za-z0-9_\-\.])+\@([A-Za-z0-9_\-\.])+\.([A-Za-z]{2,4})$/;
264    return String(emailAddress)
265        .toLowerCase()
266        .match(filter);
267}
268
269function SubmitForm() {
270    disableSubscribeBtn();
271    var formData = frm.serialize();
272    result_p.innerHTML = "";
273
274    var url = "/api/subscribe/Submit";
275    if (frm.attr('id').indexOf('campaign') > -1) {
276        url = "/api/subscribe/SubmitCampaign";
277    }
278
279    $.ajax({
280        url: url,
281        type: "POST",
282        contentType: "application/x-www-form-urlencoded; charset=UTF-8",
283        data: formData,
284        success: function (result) {
285            if (result.valid) {
286                frm_input.value = "";
287                setEmailSuccess(result.message);
288            } else {
289                frm_input.focus();
290                setEmailError(result.errors[0].message);
291            }
292            enableSubscribeBtn();
293        },
294        error: function (xhr) {
295            frm_input.focus();
296            setEmailError('Email signup failed');
297            enableSubscribeBtn();
298        }
299    });
300}
301
302function disableSubscribeBtn() {
303    var button = frm.find('button');
304    button.prop("disabled", true);
305}
306
307function enableSubscribeBtn() {
308    var button = frm.find('button');
309    button.prop("disabled", false);
310}
311// End Email Signup
312
313
314//Mobile NavBar Toggler Listeners
315
316$('#navbarSupportedContent').on('show.bs.collapse', function () {
317    // Actions to perform when the navbar is about to show (expand)
318    MobileNavLinkNameToggle('Menu');
319});
320
321$('#navbarSupportedContent').on('hide.bs.collapse', function () {
322    // Actions to perform when the navbar is about to hide (collapse)
323    MobileNavLinkNameToggle('Close Menu');
324});
325
326function MobileNavLinkNameToggle(newState) {
327    const $el = $('.navbar-toggler');
328    if (!$el.length || !newState) return;
329
330    $el.attr('data-analytics-linkname', newState);
331}
332
333//End Mobile NavBar Toggler Functions
334
335
336//Accordion Functions
337var doAccordionScroll = true;
338
339//When Accordion Item opens
340$(document).on('shown.bs.collapse', '.collapse', function () {
341    const $collapse = $(this);
342
343    // Cache key elements
344    const $card = $collapse.closest('.accordion-item');
345    if (!$card.length) return;
346
347    const $button = $card.find('button').first();
348    if ($button.length) {
349        AccordionLinkNameToggle($button, '-Collapse');
350    }
351
352    // Find other open panels within same parent
353    const parentSelector = $collapse.data('parent');
354    const $open = parentSelector ? $(parentSelector).find('.collapse.show') : $();
355
356    let additionalOffset = 0;
357
358    if ($open.length) {
359        const $openCard = $open.closest('.accordion-item');
360        if ($card.prevAll().filter($openCard).length) {
361            additionalOffset = $open.outerHeight() || 0;
362        }
363    }
364
365    const id = getParameterByName("id");
366    const windowWidth = window.innerWidth;
367    const hash = DOMPurify.sanitize(window.location.hash);
368
369    // Handle ID-based adjustment
370    if (id && this.id === id) {
371        if (windowWidth >= 992) {
372            const isSpecial = id.includes("popular") || id.includes("common");
373            additionalOffset = isSpecial ? 100 : 185;
374        } else {
375            additionalOffset = 0;
376        }
377
378        const uri = window.location.href;
379        window.history.replaceState({}, document.title, removeURLParameter(uri, "id"));
380    }
381
382    if (!doAccordionScroll) return;
383
384    // Scroll to accordion
385    const cardOffset = $card.offset();
386    if (cardOffset) {
387        $('html, body').animate({
388            scrollTop: cardOffset.top - additionalOffset
389        }, 100);
390    }
391
392    // Optional: scroll to inner anchor
393    if (id && hash && $(hash).length) {
394        const isSpecial = id.includes("popular") || id.includes("common");
395        const offset = windowWidth >= 992
396            ? (isSpecial ? 110 : 275)
397            : 75;
398
399        const targetOffset = $(hash).offset();
400        if (targetOffset) {
401            $('html, body').animate({
402                scrollTop: targetOffset.top - offset
403            }, 100);
404        }
405    }
406
407    doAccordionScroll = true;
408});
409
410//When Accordion Item closes
411$(document).on('hidden.bs.collapse', '.collapse', function () {
412    const $collapse = $(this);
413
414    // Find the nearest accordion item once
415    const $card = $collapse.closest('.accordion-item');
416    if (!$card.length) return;
417
418    // Limit search to direct toggle button(s) if possible
419    const $button = $card.find('button').first();
420    if (!$button.length) return;
421
422    AccordionLinkNameToggle($button, '-Expand');
423});
424
425function AccordionLinkNameToggle($element, newState) {
426    const attr = $element.attr('data-analytics-linkname');
427    if (!attr) return; // handles undefined, null, empty string
428
429    // Replace either -Expand or -Collapse with the new state
430    const updated = attr.replace(/-(Expand|Collapse)$/, newState);
431
432    // Only write if something actually changed
433    if (updated !== attr) {
434        $element.attr('data-analytics-linkname', updated);
435    }
436}
437
438// End Accordion Functions
439
440
441// Begin URL querystring parameter functions
442function getParameterByName(name, url = window.location.href) {
443    name = name.replace(/[\[\]]/g, '\\$&');
444    var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
445        results = regex.exec(url);
446    if (!results) return null;
447    if (!results[2]) return '';
448    return decodeURIComponent(results[2].replace(/\+/g, ' '));
449}
450
451function removeURLParameter(url, parameter) {
452    //prefer to use l.search if you have a location/link object
453    var urlparts = url.split('?');
454    if (urlparts.length >= 2) {
455
456        var prefix = encodeURIComponent(parameter) + '=';
457        var pars = urlparts[1].split(/[&;]/g);
458
459        //reverse iteration as may be destructive
460        for (var i = pars.length; i-- > 0;) {
461            //idiom for string.startsWith
462            if (pars[i].lastIndexOf(prefix, 0) !== -1) {
463                pars.splice(i, 1);
464            }
465        }
466
467        return urlparts[0] + (pars.length > 0 ? '?' + pars.join('&') : '');
468    }
469    return url;
470}
471// End URL querystring parameter functions
472
473
474//Allow for multiple references on page to same footnote
475//example footnote reference:  <sup><a id="footnotes-ref1-1" href="#footnotes_1" aria-label="footnote 1">1</a></sup>
476//example footnote w/ back link: <li id="footnotes_1"><sup>1</sup>Footnote Content<a id="footnotes_1_back" href="#footnotes-ref1-1" class="back-to-content" aria-label="Back to content">↩</a></li>
477
478//in body footnote reference
479$(document).on('click', "a[href^='#footnotes_']", function () {
480    const $this = $(this);
481
482    // Remove existing highlight only if present
483    const $current = $(".footnoteTarget");
484    if ($current.length) {
485        $current.removeClass("footnoteTarget");
486    }
487
488    // Use hash and strip the #
489    const targetId = this.hash.slice(1);
490
491    const $footnote = $("#" + targetId);
492    if (!$footnote.length) return; // guard clause
493
494    // Set backlink
495    $("#" + targetId + "_back").attr("href", "#" + this.id);
496
497    // Add highlight + tabindex in one pass
498    $footnote
499        .addClass("footnoteTarget")
500        .attr("tabindex", "-1");
501});
502
503//back to content
504$(document).on('click', "a[href^='#footnotes-ref']", function () {
505    // Remove existing highlight only if present
506    const $current = $(".footnoteTarget");
507    if ($current.length) {
508        $current.removeClass("footnoteTarget");
509    }
510});
511
512//End Allow for multiple references on page to same footnote
513
514function syncNavDropdownAccessibility(dropdownMenu, isOpen) {
515    if (!dropdownMenu) {
516        return;
517    }
518
519    var $menu = $(dropdownMenu);
520    var $links = $menu.find('a.primary-sub-nav-links.dropdown-item');
521
522    $links.each(function () {
523        $(this).attr('tabindex', isOpen ? '0' : '-1');
524    });
525
526    if (isOpen) {
527        $menu.removeAttr('aria-hidden');
528        $menu.removeAttr('inert');
529    } else {
530        $menu.attr('aria-hidden', 'true');
531        $menu.attr('inert', '');
532    }
533} 
534
535$(function () {
536    //remove empty aria-label attributes from a tags, buttons and images
537    $('a,button,img').each(function () {
538        const $el = $(this);
539        const label = $el.attr('aria-label');
540
541        if (label === '') {
542            $el.removeAttr('aria-label');
543        }
544    });
545
546    // Keep hidden dropdown links out of the interactive target set.
547    $('.dropdown-menu').each(function () {
548        syncNavDropdownAccessibility(this, false);
549    });
550
551    $('[data-bs-toggle="dropdown"]').each(function () {
552        $(this).on('shown.bs.dropdown', function () {
553            var menu = $(this).parent().find('.dropdown-menu').first();
554            syncNavDropdownAccessibility(menu, true);
555        });
556
557        $(this).on('hidden.bs.dropdown', function () {
558            var menu = $(this).parent().find('.dropdown-menu').first();
559            syncNavDropdownAccessibility(menu, false);
560        });
561    });
562
563    //open all accordions based on querystring
564    const openall = getParameterByName("openall");
565    const $collapses = $('.collapse');
566    if (openall && $collapses.length) {
567        $collapses
568            .addClass('show')
569            .each(function () {
570                const $button = $(this).closest('.accordion-item').find('button').first();
571                if ($button.length) {
572                    $button.attr('aria-expanded', 'true');
573                    AccordionLinkNameToggle($button, '-Collapse');
574                }
575            });
576    }
577
578    //add role to element
579    const $roles = $('.addRole');
580    if ($roles.length) {
581        // Set role and remove the data attribute in one pass
582        $roles.attr('role', function () {
583            return this.getAttribute('data-role');
584        }).removeAttr('data-role');
585
586        // Remove the marker class in bulk
587        $roles.removeClass('addRole');
588
589        // Only loop for the rare cleanup case
590        $roles.each(function () {
591            if (!this.className) {
592                this.removeAttribute('class');
593            }
594        });
595    }
596
597    //add presentation role to UL element if only one line item present
598    const $ultargets = $('main ul:not([role])').filter(function () {
599        return !this.hasAttribute('role') &&
600            this.querySelectorAll('li').length === 1;
601    });
602
603    if ($ultargets.length) {
604        $ultargets.attr('role', 'presentation');
605    }
606
607    //only query the DOM once for these classes
608    var $targets = $('.hideUntil, .showUntil, .showBetween');
609
610    //exit early if none of the classes exist on the page
611    if ($targets.length === 0) {
612        return;
613    }
614
615    getCurrentDate().done(function (data) {
616        //standardize the API string to ISO format and parse it
617        var isoDateString = data.replace(" ", "T").replace("_", ":") + getTZOffsetbyDate(data);
618        var dateNowTS = Date.parse(isoDateString) / 1000;
619
620        //helper function to convert data attributes to Unix timestamps
621        function getAttrTimestamp($el, attrName) {
622            var val = $el.attr(attrName);
623            if (!val) return null;
624            return Date.parse(val.replace(" ", "T").replace("_", ":")) / 1000;
625        }
626
627        //loop through the pre-selected elements exactly once
628        $targets.each(function () {
629            var $this = $(this);
630
631            //date-based content (elements should have data attributes with date in format: yyyy-MM-ddTHH:mm:ss-0#:00) - hides content until date, should be date with appropriate time zone offset (ex.-08:00 for PST/-07:00 for PDT)
632            if ($this.hasClass('hideUntil')) {
633                var checkTS = getAttrTimestamp($this, 'data-date');
634                if (dateNowTS >= checkTS) {
635                    $this.removeClass("hide");
636                } else {
637                    $this.remove();
638                }
639            }
640
641            else if ($this.hasClass('showUntil')) {
642                var checkTS = getAttrTimestamp($this, 'data-date');
643                if (dateNowTS > checkTS) {
644                    $this.remove();
645                }
646            }
647
648            else if ($this.hasClass('showBetween')) {
649                var checkStartTS = getAttrTimestamp($this, 'data-start-date');
650                var checkEndTS = getAttrTimestamp($this, 'data-end-date');
651                if (dateNowTS >= checkStartTS && dateNowTS <= checkEndTS) {
652                    $this.removeClass("hide");
653                } else {
654                    $this.remove();
655                }
656            }
657        });
658    });
659});          
660
661function isProd() {
662    var host = window.location.hostname;
663    if (host.indexOf("localhost") !== -1 || host.indexOf("dev.") !== -1 || host.indexOf("qa.") !== -1 || host.indexOf("azurewebsites.net") !== -1) {
664        return false;
665    }
666
667    return true;
668}
669
670function getCurrentDate() {
671    return $.ajax({
672        type: "GET",
673        url: "/api/internal/GetDateNow",
674        cache: false,
675        data: { today_dt: getParameterByName("today_dt"), env: getParameterByName("env") }
676    });
677}
678
679function getTZOffset() {
680    const date = new Date();
681    return new Intl.DateTimeFormat('en', { timeZone: 'America/Los_Angeles', timeZoneName: 'longOffset' }).format(date).match(/[\d+:-]+$/)?.[0];
682}
683
684function getTZOffsetbyDate(dt) {
685    const date = new Date(dt);
686    return new Intl.DateTimeFormat('en', { timeZone: 'America/Los_Angeles', timeZoneName: 'longOffset' }).format(date).match(/[\d+:-]+$/)?.[0];
687}

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.