PageSourceSearch

https://friendsprovidentfoundation.org/wp-content/themes/fpf-main/js/main.js?ver=1.79028479678E%2B12

js friendsprovidentfoundation.org collected 2026-09-24 21:20:16 UTC 22,542 bytes, 605 lines download raw bytes

1/* Init object fit polyfill */
2/* To make it work, add 'font-family: 'object-fit: cover;';' to image */
3if (window.objectFitImages) {
4    window.objectFitImages();
5}
6
7(function () {
8
9    let resizeId; // for resize timer
10    let wWidth = window.innerWidth; // for resize
11    let isObserver = true; //for scroll reveal
12    let observer; //for scroll reveal
13    let root = document.documentElement; //for css variables update
14    let scrollPosition = 0;
15    const $body = document.body;
16    const $html = document.documentElement;
17    let $landingScreenInterval;
18
19    /// /* Setup helper functions */
20
21    // https://www.afasterweb.com/2017/09/26/performance-basics-throttling/
22    function throttle(callback, limit) {
23        let tick = false;
24        return function () {
25            if (!tick) {
26                callback.call();
27                tick = true;
28                setTimeout(function () {
29                    tick = false;
30                }, limit);
31            }
32        }
33    }
34
35    // window.addEventListener("scroll", throttle(customFunction, 16));
36
37    function disableScrolling() {
38        if (document.documentElement.scrollHeight > window.innerHeight) {
39            const scrollTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop; // Works for Chrome, Firefox, IE...
40            document.documentElement.classList.add('disable-scrolling');
41            document.documentElement.style.top = -scrollTop + 'px';
42
43            setTimeout(() => {
44                document.documentElement.classList.add('scroll-default');
45            }, 0)
46        }
47    }
48
49    function enableScrolling() {
50        const scrollTop = parseInt(document.documentElement.style.top);
51        document.documentElement.classList.remove('disable-scrolling');
52        document.documentElement.scrollTop = -scrollTop;
53        document.body.scrollTop = -scrollTop;
54        setTimeout(() => {
55            document.documentElement.classList.remove('scroll-default');
56        }, 0)
57    }
58
59    function isMobile() {
60        if (document.querySelector('.is-mobile').style.display === 'block') {
61            return true;
62        } else {
63            return false;
64        }
65    }
66
67    //Scroll revealing animation
68    if (
69        !('IntersectionObserver' in window)
70        || !('IntersectionObserverEntry' in window)
71        || !('isIntersecting' in window.IntersectionObserverEntry.prototype)
72    ) {
73        isObserver = false;
74        document.documentElement.classList.remove('is-observer');
75    }
76
77    if (isObserver) {
78        observer = new IntersectionObserver(
79            entries => {
80                entries.forEach(entry => {
81                    if (entry.isIntersecting) {
82                        entry.target.classList.add('is-visible');
83                        observer.unobserve(entry.target);
84                    }
85                });
86            },
87            { rootMargin: '0px 0px -15% 0px' }
88        );
89    }
90
91    if (isObserver) {
92        document.querySelectorAll('.js-visibility').forEach((el, i) => {
93            observer.observe(el);
94        })
95    }
96
97    document.querySelectorAll('.scroll-link').forEach((el, i) => {
98        el.addEventListener('click', (e) => {
99            const $target = e.currentTarget.getAttribute('href');
100            const $targetFormatted = document.querySelector($target.substring(1)).offsetTop;
101            // document.documentElement.scrollTop = $targetFormatted.offsetTop;
102            // document.body.scrollTop = $targetFormatted.offsetTop;
103            window.scrollTo(
104                0,
105                $targetFormatted - document.querySelector('.site-header').getBoundingClientRect().height);
106        })
107    })
108
109    document.querySelectorAll('.btn-scroll-top--js').forEach((el, i) => {
110        el.addEventListener('click', (e) => {
111            e.preventDefault();
112            window.scrollTo(0, 0);
113        })
114    })
115
116
117    // Mac and IOS devices require different nav styling
118    let isMacLike = /(Mac|iPhone|iPod|iPad)/i.test(navigator.platform);
119    let isIOS = /(iPhone|iPod|iPad)/i.test(navigator.platform);
120
121    if (isIOS || isMacLike) {
122        // $('.section-404').addClass('is-ios');
123        // $('.homepage-hero__item-inner').addClass('is-ios');
124    }
125
126    //
127
128    let isTouch;
129
130    function isTouchDevice() {
131        const prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
132        const mq = (query) => {
133            return window.matchMedia(query).matches;
134        };
135
136        if (
137            'ontouchstart' in window ||
138            // eslint-disable-next-line no-undef
139            (window.DocumentTouch && document instanceof DocumentTouch)
140        ) {
141            return true;
142        }
143
144        // include the 'heartz' as a way to have a non matching MQ to help terminate the join
145        // https://git.io/vznFH
146        const query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(
147            ''
148        );
149        return mq(query);
150    }
151
152    if (isTouchDevice()) {
153        isTouch = true;
154        document.documentElement.classList.add('is-touch');
155    }
156
157    const getNextSibling = function (elem, selector) {
158
159        // Get the next sibling element
160        let sibling = elem.nextElementSibling;
161
162        // If there's no selector, return the first sibling
163        if (!selector) return sibling;
164
165        // If the sibling matches our selector, use it
166        // If not, jump to the next sibling and continue the loop
167        while (sibling) {
168            if (sibling.matches(selector)) return sibling;
169            sibling = sibling.nextElementSibling
170        }
171
172    };
173    /// /* End of Setup helper functions */
174
175    function mobileMenuActionHandler() {
176        const mobileMenu = document.querySelector('.mobile-menu');
177        const mobileMenuOpen = document.querySelector('.js-menu--open');
178        const mobileMenuClose = document.querySelector('.js-menu--close');
179        const menuItems = mobileMenu.querySelectorAll('.menu-item a');
180
181        mobileMenuOpen.addEventListener('click', function (e) {
182            mobileMenu.classList.add('is--visible');
183        });
184        mobileMenuClose.addEventListener('click', function (e) {
185            mobileMenu.classList.remove('is--visible');
186        });
187        menuItems.forEach(menuItem => {
188            menuItem.addEventListener('click', function () {
189                mobileMenu.classList.remove('is--visible');
190            });
191        })
192    }
193    function carouselsHandler() {
194        const libraryCarousel = new Swiper(".js-cards-carousel", {
195            slidesPerView: 1.3,
196            spaceBetween: 25,
197            scrollbar: {
198                el: ".swiper-scrollbar",
199                hide: false,
200                draggable: true,
201            },
202            breakpoints: {
203                767: {
204                    slidesPerView: 2.3,
205                    spaceBetween: 30,
206                },
207                1280: {
208                    slidesPerView: 3.7,
209                },
210            }
211        });
212        const libraryPickCarousel = new Swiper(".library-pick-carousel", {
213            slidesPerView: 1,
214            effect: 'fade',
215            autoplay: {
216                delay: 5000,
217            },
218            fadeEffect: {           // added
219                crossFade: true     // added(resolve the overlapping of the slides)
220            },
221            pagination: {
222                el: ".swiper-pagination",
223                clickable: true
224            },
225        });
226
227        const homeHeroCarousel = new Swiper(".js-hero-carousel", {
228            slidesPerView: 1,
229            spaceBetween: 17,
230            slidesPerView: 1.3,
231            autoplay: {
232                delay: 5000,
233            },
234            pagination: {
235                el: ".swiper-pagination",
236                clickable: true
237            },
238            breakpoints: {
239                767: {
240                    spaceBetween: 40,
241                },
242                1280: {
243                    slidesPerView: 1.4,
244                    spaceBetween: 50,
245                },
246            }
247        });
248
249        const singleImagesCarousel = new Swiper(".js-images-carousel", {
250            slidesPerView: 1,
251            spaceBetween: 25,
252            slidesPerView: 1.3,
253            scrollbar: {
254                el: ".swiper-scrollbar",
255                hide: false,
256                draggable: true,
257            },
258            breakpoints: {
259                767: {
260                    spaceBetween: 40,
261                },
262                1280: {
263                    slidesPerView: 2,
264                },
265            }
266        });
267
268
269        const genCarousels = document.querySelectorAll('.gen-carousel');
270        genCarousels.forEach(carousel => {
271            let genCarousel = new Swiper(carousel, {
272                slidesPerView: 1.2,
273                spaceBetween: 21,
274                scrollbar: {
275                    el: ".swiper-scrollbar",
276                    hide: false,
277                    draggable: true,
278                },
279                breakpoints: {
280                    767: {
281                        slidesPerView: 1.3,
282                        spaceBetween: 38,
283                    },
284                    1280: {
285                        slidesPerView: 1.7,
286                        spaceBetween: 40,
287                    },
288                }
289            });
290        });
291
292
293    }
294
295    function headerSearchHandler() {
296        const searchOpen = document.querySelector('.search--open');
297        const searchClose = document.querySelector('.search--close');
298        const search = document.querySelector('.header__search .search-form');
299        const menu = document.querySelector('.header__nav');
300        searchOpen.addEventListener('click', function () {
301            menu.classList.add('is--hidden');
302            searchOpen.classList.remove('is--visible');
303            setTimeout(() => {
304                search.classList.add('is--visible');
305                searchClose.classList.add('is--visible');
306            }, 500)
307        });
308        searchClose.addEventListener('click', function () {
309            search.classList.remove('is--visible');
310            searchClose.classList.remove('is--visible');
311            setTimeout(() => {
312                menu.classList.remove('is--hidden');
313                searchOpen.classList.add('is--visible');
314            }, 500)
315        });
316        document.addEventListener('click', function (e) {
317            let closestSearch = e.target.closest('.header__search .search-form');
318            let closestBtn = e.target.closest('.search--open');
319            if (!closestSearch && !closestBtn && search.classList.contains('is--visible')) {
320                search.classList.remove('is--visible');
321                searchClose.classList.remove('is--visible');
322                setTimeout(() => {
323                    menu.classList.remove('is--hidden');
324                    searchOpen.classList.add('is--visible');
325                }, 500)
326            }
327        });
328
329    }
330    function anchorDropdownHandler() {
331        const dropdown = document.querySelector('.anchor-nav__dropdown');
332        if (dropdown) {
333            dropdown.addEventListener('click', function () {
334                dropdown.classList.toggle('is--expanded');
335                if (dropdown.classList.contains('is--expanded')) {
336                    dropdown.style.height = `${dropdown.scrollHeight}px`;
337                } else {
338                    dropdown.style.height = '46px';
339                }
340            });
341        }
342
343    }
344    function lazyLoadHandler() {
345        // Get a reference to the animated element
346        const animatedEls = document.querySelectorAll('.js-animated-el');
347        animatedEls.forEach(el => {
348            // Create a GSAP animation for the element
349            const animation = gsap.fromTo(el, {
350                duration: 0.7,
351                yPercent: 50,
352                opacity: 0,
353            }, {
354                opacity: 1,
355                duration: 0.7,
356                yPercent: 0,
357                paused: true, // Initially, the animation is paused
358                // Additional animation properties if needed
359            });
360            ScrollTrigger.create({
361                trigger: el,
362                start: 'top 80%', // When to start the animation (80% from the top of the viewport)
363                end: 'bottom 20%', // When to end the animation (20% from the bottom of the viewport)
364                animation: animation,
365                toggleActions: 'play none none', // Play animation on enter and reverse it on leave
366            });
367        });
368    };
369    function popupHandler() {
370        const people = document.querySelectorAll('.js-popup--open');
371        const popupBody = document.querySelector('.person-popup');
372        const popupClose = document.querySelector('.js-popup--close');
373        if (popupBody && people) {
374            const popup = {
375                img: popupBody.querySelector('.js-popup-image'),
376                pronouns: popupBody.querySelector('.js-popup-pronouns'),
377                name: popupBody.querySelector('.js-popup-name'),
378                role: popupBody.querySelector('.js-popup-role'),
379                copy: popupBody.querySelector('.js-popup-copy'),
380                twitter: popupBody.querySelector('.js-popup-twitter'),
381                facebook: popupBody.querySelector('.js-popup-facebook'),
382                linkedin: popupBody.querySelector('.js-popup-linkedin'),
383                email: popupBody.querySelector('.js-popup-email'),
384            }
385            people.forEach(popupTrigger => {
386                popupTrigger.addEventListener('click', function () {
387                    console.log('click');
388                    let img = this.getAttribute('data-image');
389                    let pronouns = this.getAttribute('data-pronouns');
390                    let name = this.getAttribute('data-name');
391                    let role = this.getAttribute('data-role');
392                    let copy = this.getAttribute('data-copy');
393                    let twitter = this.getAttribute('data-twitter');
394                    let facebook = this.getAttribute('data-facebook');
395                    let linkedin = this.getAttribute('data-linkedin');
396                    let email = this.getAttribute('data-email');
397
398                    popup.img.setAttribute('src', img);
399                    popup.pronouns.textContent = pronouns;
400                    popup.name.textContent = name;
401                    popup.role.textContent = role;
402                    popup.copy.textContent = copy;
403
404                    if (twitter) {
405                        popup.twitter.setAttribute('href', twitter);
406                    } else {
407                        popup.twitter.parentElement.style = "display:none";
408                    }
409                    if (facebook) {
410                        popup.facebook.setAttribute('href', facebook);
411                    } else {
412                        popup.facebook.parentElement.style = "display:none";
413                    }
414                    if (linkedin) {
415                        popup.linkedin.setAttribute('href', linkedin);
416                    } else {
417                        popup.linkedin.parentElement.style = "display:none";
418                    }
419                    if (email) {
420                        popup.email.setAttribute('href', 'mailto:' + email);
421                    } else {
422                        popup.email.parentElement.style = "display:none";
423                    }
424
425                    popupBody.classList.add('is--visible');
426                });
427
428                popupClose.addEventListener('click', function () {
429                    popupBody.classList.remove('is--visible');
430                });
431
432                document.addEventListener('click', function (e) {
433                    let closestPopup = e.target.closest('.person-popup');
434                    let closestPerson = e.target.closest('.js-popup--open');
435                    if (!closestPopup && !closestPerson && popupBody.classList.contains('is--visible')) {
436                        popupBody.classList.remove('is--visible');
437                    }
438                });
439            });
440        }
441    }
442    function accordionHandler() {
443        const accordionBtns = document.querySelectorAll('.js-accordion-heading');
444        if (accordionBtns) {
445           
446            accordionBtns.forEach(el => {
447                const accordionTrigger = el.querySelector('.accordion-item__btn');
448                accordionInteraction(accordionTrigger);
449                    accordionInteraction(el);
450            });
451
452            function accordionInteraction(trigger){
453                trigger.addEventListener('click', function () {
454                    const accordionContent = this.parentElement.querySelector('.accordion-item__copy');
455                    const accordionBtn = this.querySelector('.accordion-item__btn-name');
456                    this.parentElement.classList.toggle('is--active');
457
458                    if (this.parentElement.getAttribute('aria-label') === 'expanded') {
459                        this.parentElement.setAttribute(
460                            'aria-label',
461                            'collapsed'
462                        );
463                    } else {
464                        this.parentElement.setAttribute('aria-label', 'expanded');
465                    }
466
467                    accordionContent.classList.toggle('is--visible');
468
469                    accordionBtns.forEach(sibling => {
470                        if (sibling !== trigger) {
471                            sibling.parentElement.classList.remove('is--active');
472                            let accordionContent = sibling.nextElementSibling;
473                            sibling.parentElement.setAttribute(
474                                'aria-label',
475                                'collapsed'
476                            );
477                            accordionContent.classList.remove('is--visible');
478                            accordionContent.style.height = '0';
479                            sibling.querySelector('.accordion-item__btn-name').textContent = "Open";
480                        }
481                    });
482
483                    if (accordionContent.classList.contains('is--visible')) {
484                        accordionContent.style.height = `${accordionContent.scrollHeight}px`;
485                        accordionBtn.textContent = "Close";
486                    } else {
487                        accordionContent.style.height = '0';
488                        accordionBtn.textContent = "Open";
489                    }
490                });
491            }
492        }
493    }
494    function customSelectHandler() {
495        const select = document.querySelector('.js-custom-select');
496        if (select) {
497            const options = select.querySelectorAll('.js-select-option');
498            const pickedVal = select.querySelectorAll('.js-select-picked');
499            select.addEventListener('click', function () {
500                select.classList.toggle('is--expanded');
501                if (select.classList.contains('is--expanded')) {
502                    select.style.height = `${select.scrollHeight}px`;
503                } else {
504                    select.style.height = '46px';
505                }
506            });
507            options.forEach(option => {
508                option.addEventListener('change', function () {
509                    pickedVal.innerText = this.value;
510                    select.classList.remove('is--expanded');
511                    select.style.height = '46px';
512                });
513            });
514        }
515    }
516
517    function customSelectCF7() {
518        const select = document.querySelector('.form-select');
519        const picked = document.querySelector('.form-select__picked');
520        if (select) {
521            select.addEventListener('click', function () {
522                this.classList.toggle('is--active');
523
524                if (this.getAttribute('aria-label') === 'expanded') {
525                    this.setAttribute('aria-label', 'collapsed');
526                } else {
527                    this.setAttribute('aria-label', 'expanded');
528                }
529                if (this.classList.contains('is--active')) {
530                    this.style.height = `${this.scrollHeight}px`;
531                } else {
532                    if (window.innerWidth < 767){
533                        this.style.height = '82px';
534                    } else {
535                        this.style.height = '68px';
536                    }
537                }
538            });
539            const inputs = select.querySelectorAll('input');
540            inputs.forEach(input => {
541                input.addEventListener('change', function () {
542                    console.log(true);
543                    select.classList.remove('is--active');
544                    select.setAttribute('aria-label', 'collapsed');
545                    if (window.innerWidth < 767){
546                        select.style.height = '82px';
547                    } else {
548                        select.style.height = '68px';
549                    }
550                    picked.innerText = this.nextElementSibling.innerText;
551                });
552            });
553        }
554    }
555
556
557
558    function copyArticleLinkInit() {
559        const link = document.querySelector('.share-list-link--copy');
560        if (link) {
561          const copy = link.nextElementSibling;
562          const tooltip = link.querySelector('.tooltip');
563          link.addEventListener('click', function(e) {
564            e.preventDefault();
565            let url = this.getAttribute('href');
566            navigator.clipboard.writeText(url);
567            tooltip.classList.add('is--visible');
568            setTimeout(() => {
569              tooltip.classList.remove('is--visible');
570            }, 500);
571          });
572        }
573      }
574
575      function anchorLinksInteraction(){
576        const items = document.querySelectorAll('.legal__nav-item a');
577        items.forEach(item => {
578            item.addEventListener('click', function(e){
579                this.classList.add('is--active');
580                items.forEach(sibling => {
581                    if (sibling !== item) {
582                        sibling.classList.remove('is--active');
583                    }
584                });
585            });
586
587
588        });
589      }
590
591    mobileMenuActionHandler();
592    carouselsHandler();
593    headerSearchHandler();
594    anchorDropdownHandler();
595 //   lazyLoadHandler();
596    accordionHandler();
597    customSelectHandler();
598    popupHandler();
599    copyArticleLinkInit();
600    customSelectCF7();
601    anchorLinksInteraction();
602}
603
604
605)();

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.