PageSourceSearch

https://www.givewell.org/themes/gw_basic/scripts/lib/main.js?v=1.x

js givewell.org collected 2026-10-01 08:36:47 UTC 29,992 bytes, 707 lines download raw bytes

1(function($) {
2
3    $(document).ready(function() {
4
5        // Check TOC is a block.
6        if($("#block-gw-basic-tableofcontents").length > 0) {
7          // Add an ID for back-to-top, whih is lost if placing the TOC in a block.
8            var top = $('<div style="display:block;"></div>');
9            $('h1.title').append(top);
10            top.attr('id', 'top');
11
12          // This kicks in when the window is scrolled enough to hide the header.
13          // It is useful for setting fixed on the table of contents.
14          // Check width as it is desktop only.
15          $(window).scroll(function(){
16
17            if ($(this).scrollTop() > 210) {
18              $('body').addClass('scrolled');
19            } else {
20              $('body').removeClass('scrolled');
21            }
22            // Deal with overlapping the footer.
23            var tocHeight = document.getElementById('block-gw-basic-tableofcontents').offsetHeight; 
24            var overScrolled = document.body.offsetHeight - (window.innerHeight + Math.round(window.scrollY));
25            if (overScrolled <= 370) {
26              var overscrollCorrection = (368-overScrolled);
27              $('body').addClass('overscrolled');
28              $('#block-gw-basic-tableofcontents').css('margin-top', '-' + overscrollCorrection + 'px');
29            } else {
30              $('body').removeClass('overscrolled');
31              $('#block-gw-basic-tableofcontents').css('margin-top', 'unset');
32            }
33          });
34
35          var tocHash = window.location.hash;
36          if(tocHash.length > 0) {$('.toc-accordion li a[href="' + tocHash + '"]').addClass("black");}
37          if(tocHash.length > 0) {$(tocHash).addClass("black");}
38           $(window).on('hashchange', function() {
39             tocHash = window.location.hash; 
40             $('.toc-accordion li a').removeClass("black");
41             $('.toc-accordion li a[href="' + tocHash + '"]').addClass("black");
42             $('h2, h3, h4, h5, h6').removeClass("black"); 
43             $(tocHash).addClass("black");
44          });
45 
46          $("#block-gw-basic-tableofcontents li").on("click", function (e) {
47              if ($(this).parent().has("ul")) {
48                  e.stopPropagation();
49              }
50          });
51          $("li.has-children").on("click", function() {
52            $(this).siblings().removeClass("expanded");
53            if($(this).hasClass("expanded")) {
54              $(this).removeClass("expanded");
55              $(this).children('ul').children().removeClass("expanded");
56            } else {
57            $(this).addClass("expanded");
58            }
59            $(this)
60             .children('ul')
61             .toggleClass("show")
62            $(this)
63             .siblings()
64             .children('ul')
65             .hide();
66            $(this)
67             .children('ul')
68             .slideToggle(300);
69          });
70        }
71        var breakpoints = {
72            'mobile': '720',
73            'tablet': '720',
74        };
75        var isMobile = breakpoints.mobile >= $(window).width() ? 1 : 0;
76        var isTablet = breakpoints.tablet >= $(window).width() && $(window).width()>breakpoints.mobile ? 1 : 0;
77
78        // SCROLL-TO-TOP
79
80        $("#up-link").click(function() {
81            $('html, body').animate({
82                scrollTop: $("#header").offset().top
83            }, 1000);
84        });
85
86
87        // FOOTER EMAIL SUBSCRIBER FORM
88
89        $('#footer .email-subscribe').validate({
90            rules: {
91                EMAIL: {
92                    required: true,
93                    email: true
94                }
95            },
96            showErrors: function(map, list) {},
97            invalidHandler: function(e, validator) {
98                if (validator.numberOfInvalids()) {
99                    var el = $('input[name=EMAIL]');
100                    el.addClass('validator-field-error').attr('placeholder', 'Please enter a valid email.').val('');
101                    setTimeout(function() {
102                        el.removeClass('validator-field-error');
103                    }, 1500);
104                }
105            }
106        });
107
108        // DONATE ONLINE FORM
109
110        // Placeholder Text
111        var formDonate = $('#webform-client-form-2350');
112        formDonate.find('#webform-component-card-information .webform-component').each(function(){
113            var placeholder = $(this).find('label').text();
114            $(this).find('input').attr('placeholder', placeholder);
115        });
116
117        // Calculate totals
118        var formDonateDonations = $('#webform-client-form-2350').find('input[type="number"]');
119        formDonateDonations.on('change', function(){
120            var total = 0;
121            formDonateDonations.each(function(){
122                total += Math.abs($(this).val()*1);
123            });
124            formDonate.find('input[name="submitted[totals][total]"]').val(total);
125        });
126
127
128        // ACCORDION
129        accordions = $('.accordion');
130        accordions.accordion({
131            collapsible: true,
132            active: true,
133            heightStyle: 'content',
134            header: 'h3',
135            activate: function(e) {
136                // Scroll the page so the clicked accordion element is at the top of the page.
137                var viewportHt = $(window).height();
138                var viewportTop = $(window).scrollTop();
139                with($(this)) {
140                    if (find('.ui-state-active').length) {
141                        var elementTop = find('.ui-state-active').offset().top;
142                        if (elementTop - viewportTop > viewportHt / 2 || 1) {
143                            $('html, body').animate({
144                                scrollTop: elementTop - 20
145                            }, 500);
146                        }
147                    }
148                }
149            }
150        });
151        with(accordions) {
152            if (length) {
153                find('.accordion-container').hide();
154                find('.accordion-wrapper').first().find('.accordion-container').show();
155                find('.accordion-title').click(function() {
156                    if ($(this).hasClass('open')) {
157                        $(this).removeClass('open');
158                        $(this).parent().find('.accordion-container').slideUp();
159                    } else {
160                        $(this).addClass('open');
161                        $(this).parent().find('.accordion-container').slideDown();
162                    }
163                    return false;
164                });
165            }
166        }
167
168        // LEGACY FIELDSET ACCORDION (See: gq-legacy.css for styling)
169        accordionsFieldset = $('.collapsible');
170        accordionsFieldset.accordion({
171            collapsible: true,
172            active: true,
173            heightStyle: 'content',
174            header: 'legend',
175            activate: function(e) {
176                // Scroll the page so the clicked accordion element is at the top of the page.
177                var viewportHt = $(window).height();
178                var viewportTop = $(window).scrollTop();
179                with($(this)) {
180                    if (find('.ui-state-active').length) {
181                        var elementTop = find('.ui-state-active').offset().top;
182                        if (elementTop - viewportTop > viewportHt / 2 || 1) {
183                            $('html, body').animate({
184                                scrollTop: elementTop - 20
185                            }, 500);
186                        }
187                    }
188                }
189            }
190        });
191        with(accordionsFieldset) {
192            if (length) {
193                find('.accordion-container').hide();
194                find('.accordion-wrapper').first().find('.accordion-container').show();
195                find('.accordion-title').click(function() {
196                    if ($(this).hasClass('open')) {
197                        $(this).removeClass('open');
198                        $(this).parent().find('.accordion-container').slideUp();
199                    } else {
200                        $(this).addClass('open');
201                        $(this).parent().find('.accordion-container').slideDown();
202                    }
203                    return false;
204                });
205            }
206        }
207
208        // FOOTNOTES
209        // Note: The footnotes module implements it's own accordion, not related to Drupal's native jQuery accordion.
210        if ($('.footnotes').length) {
211
212            // Wrap the whole footnotes block in a div so it opens as a single block.
213            $('.footnotes').wrap('<div class="footnote-block"></div>');
214            $('.footnotes > ul').wrap('<div class="footnote-content"/>');
215            $('.footnote-block').prepend('<div style="clear:both"></div><div class="show-hide"><span class="expand">Expand</span><span class="collapse">Collapse</span> Footnotes</div>');
216
217            $('.footnote-block').accordion({
218                collapsible: true,
219                autoHeight: true,
220                active: false,
221                header: '.show-hide',
222                heightStyle: 'content',
223                activate: function(e) {
224                    // If the top of the accordion element header is further than halfway down the page,
225                    // scroll the page to the top of the element.
226                    var viewportHt = $(window).height();
227                    var viewportTop = $(window).scrollTop();
228                    with($(this)) {
229                        if (find('.ui-state-active').length) {
230                            var elementTop = find('.ui-state-active').offset().top;
231                            if (elementTop - viewportTop > viewportHt / 2) {
232                                $('html, body').animate({
233                                    scrollTop: elementTop - 20
234                                }, 500);
235                            }
236                        }
237                    }
238                }
239            });
240
241            // If the footnote index is clicked and the footnotes blocka t the bottom of the page is collapsed,
242            // open it, wait until it has expanded, then to jump to it.
243            $('a.see-footnote').click( function(){
244                var hash = $(this).attr('href').split('#')[1];
245                with($('.footnote-block .show-hide')){
246                    if(!$('.footnote-block .show-hide.ui-state-active').length) {
247                        document.location='#top';
248                        $('.footnote-block .show-hide').click();
249                        window.setTimeout(function(){document.location='#'+hash;},750);
250                    }
251                }
252            });
253
254            // This one works in reverse. If the footnote at the bottom of the page is clicked and the corresponding footnote
255            // index is inside a collapsed accordion, this expands the accordion so we can scroll to it.
256            $('.footnote-label').on('click',function(i,u){
257                var hash = $(this).attr('href').split('#')[1];
258                var currAccordion = $('#'+hash).parents('.ui-accordion-content').prev('h3');
259                if(!currAccordion.hasClass('ui-state-active')) currAccordion.click();
260                window.setTimeout(function(){$('html, body').animate({ scrollTop: $('#'+hash).offset().top - 20 }, 1);},750);
261            });
262          //  if (window.location.href.indexOf("#footnote") > -1) {
263          //  $('a[href^="#"]').on('ready',function() {
264          //    var target = $(this.getAttribute('href'));
265          //    if( target.length ) {
266          //      event.preventDefault();
267          //      $('html,body').stop().animate({
268          //        scrollTop: target.offset().top
269          //      }, 1000);
270          //    }
271          // }); 
272
273           function goToByScroll(id){
274             if ($(id).offset() !== undefined) {
275               $('html,body').animate({scrollTop: $(id).offset().top},'slow');
276             }
277           }
278           var hash = window.location.hash;
279           if (hash.includes("#footnote")) {
280             setTimeout(function(){
281               goToByScroll(hash);
282             },1000);
283           }
284        }
285
286        // Open details element if an ID in it is clicked.
287        function openTarget() {
288            const hash = location.hash.substring(1);
289            if (hash) {
290              if (hash === 'top') {
291                const allDetails = document.getElementsByTagName('details');
292                for (detail of allDetails) {
293                  detail.open = false;
294                }
295              } else {
296                const target = document.getElementById(hash);
297                if (target) {
298                    const details = target.closest('details');
299                    if (details)
300                        details.open = true;
301               
302                }
303              } 
304            }
305        }
306        openTarget(); // onload
307        window.addEventListener('hashchange', openTarget);
308
309        // INITIALIZE MENUS AND SEARCH
310
311        /* Initializes Mobile and Desktop menu functions as needed. */
312        function toggleMenu() {
313
314            var isMobile = breakpoints.mobile >= $(window).width() ? 1 : 0;
315
316            // Load the responsive menu only once, but reinstate our custom
317            // menu click actions any time the page changes size
318            // (because MeanMenu doesn't offer a callback to tell us when it has reloaded).
319            if (isMobile) {
320                if (!this.hasMobileMenu) {
321                    initMobileMenu();
322                    this.hasMobileMenu = 1;
323                }
324                setMobileMenuActions();
325            } else {
326                $('#block-search-form .btn-close').click();
327                if (!this.hasSrch) {
328                    initDesktopSearch();
329                    this.hasSrch = 1;
330                }
331            }
332
333        }
334        window.resizeTimer = setTimeout(toggleMenu, 250);
335        $(window).resize(function() {
336          //  clearTimeout(window.resizeTimer ? resizeTimer : 0);
337          //  window.resizeTimer = setTimeout(toggleMenu, 250);
338        });
339
340        //if(Modernizr.touch){
341        if(isTablet){
342            $('#block-system-main-menu ul li').not('#block-system-main-menu ul ul li').each(function(i,u){
343                var li = $(this);
344                li.data('clicks',0);
345                li.find('a').click(function(e){
346                    li.data('clicks',li.data('clicks')+1)
347                    if(li.data('clicks')==1) {
348                        e.preventDefault();
349                        return false;
350                    }
351                });
352            });
353        }
354
355        // Search form - abort submit if no search term
356        $('#search360-block-form').on('submit', function(e){
357            let searchTerms =  $(this).find('.form-text').val();
358            if(!searchTerms){
359                e.preventDefault;
360                return false;
361            }
362            else  {
363              $(this).attr('action', '/search/ss360?keys=' + searchTerms);
364            }
365        });
366        $('#search360-block-form input[type="text"]').css('background:none')
367        // Same for mobile
368        $(document).on('submit', '#mobile-search360-block-form', function(e){
369            let searchTerms =  $('#mobile-edit-search-block-form--2').val();
370         
371            if(!searchTerms){
372                e.preventDefault;
373                return false;
374            }
375            else  {
376              $(this).attr('action', '/search/ss360?keys=' + searchTerms);
377            }
378        });
379        $('#mobile-search360-block-form input[type="text"]').css('background:none')
380
381
382
383        // FORMS
384
385        $('#user-login #edit-name').attr('placeholder','Please enter your username.');
386
387
388        /* Initialize Mean Menu plugin */
389        function initMobileMenu() {
390
391            // Note: This selector has to be a container that includes both the menu UL block and
392            // the header search block in order for the MeanMenu plugin to toggle them both together.
393            $('#header .region-header').meanmenu({
394                meanScreenWidth: breakpoints.mobile,
395                meanMenuOpen: '<span/>',
396                meanMenuClose: '<span/>'
397            });
398            $('meanmenu-btn-donate').addClass('visible');
399            $('#main,#logo').click(function() {
400                $('.meanclose').click();
401            });
402
403        }
404
405        /* Initialize Mean Menu click actions. */
406        function setMobileMenuActions() {
407
408            $('.mean-nav ul li > a').on('click', function() {
409                $(this).siblings('a').toggleClass('open');
410            });
411
412            $('.meanmenu-reveal').on('click', function() {
413                with($('.mean-bar')) {
414                    if (!find('.meanmenu-reveal').hasClass('meanclose')) {
415                        removeClass('opened');
416                    } else {
417                        addClass('opened');
418                    }
419                }
420            });
421
422        }
423
424
425        /* Desktop search box open/close button toggles */
426        function initDesktopSearch() {
427
428            var
429                mainMenu = $('#header .menu'),
430                srchBtnOpen = $('.search-btn-open'),
431                /* this is coded directly in page.tpl */
432                srchBox = $('#block-search-form'),
433                srchForm = srchBox.find('form'),
434                srchText = srchBox.find('input:text');
435
436            $('a.header-btn-donate').addClass('visible');
437
438            // open the search box.
439            srchBtnOpen.on('click', function(e) {
440                e.preventDefault();
441                if (!srchForm.hasClass('visible')) {
442                    srchForm.addClass('visible');
443                    mainMenu.addClass('hidden');
444                    srchText.focus();
445                } else {
446                    srchForm.removeClass('visible');
447                    mainMenu.removeClass('hidden');
448                }
449            });
450
451            // Close the search box.
452            srchForm.on('mouseout', function(e) {
453                var
454                    e = e ? e : window.event;
455                var tg = (window.event) ? e.srcElement : e.target,
456                    reltg = (e.relatedTarget) ? e.relatedTarget : e.toElement;
457                if (typeof tg === 'undefined' || tg.nodeName != 'DIV') return;
458                while (reltg != tg && reltg.nodeName != 'BODY') reltg = reltg.parentNode;
459                if (reltg == tg || $(tg).hasClass('form-wrapper')) return;
460                e.preventDefault();
461                srchForm.removeClass('visible');
462                mainMenu.removeClass('hidden');
463            });
464
465            // Close the search box.
466            srchBox.find('.btn-close').on('click', function(e) {
467                e.preventDefault();
468                //srchBox.removeClass('visible');
469                srchForm.removeClass('visible');
470                mainMenu.removeClass('hidden');
471            });
472
473            // Set dropdown menu left position for desktop.
474            $('#header ul.menu:first-child > li').each(function(index, value) {
475
476                var menu_width = $(this).find('ul').width();
477                if (menu_width) {
478                    if (index == 0) {
479                        $(this).find('.menu').css({
480                            'left': '0'
481                        });
482                    } else if (index == $('#header ul.menu:first-child > li').length - 1) {
483                        $(this).find('.menu').css({
484                            'right': '0'
485                        });
486                    } else {
487                        var left = -menu_width / 2 + $(this).innerWidth() / 2;
488                        $(this).find('.menu').css({
489                            'left': left + 'px'
490                        });
491                    }
492                }
493            });
494
495        }
496
497        // IMAGE OVERLAY
498
499        // A simple overlay for viewing large images.
500        imgTypes = ['jpg', 'jpeg', 'png', 'gif'];
501        $('body').append('<div id="op-overlay"><div class="img"/><div class="close"/></div>');
502        $overlay = $('#op-overlay');
503
504        $overlay.find('.close').click(function() {
505            $overlay.fadeOut(200)
506        });
507        $overlay.find('.img').click(function() {
508            $overlay.fadeOut(200)
509        });
510
511
512        $('a img').each(function(i, e) {
513            with($(this).parent('a')) {
514                if (length) {
515                    for (n = 0; n < imgTypes.length; n++) {
516                        if (attr('href').indexOf('.' + imgTypes[n]) > 1) {
517                            $(this).parent('a').click(function(e) {
518                                $overlay.find('.img').html('<img src="' + $(this).attr('href') + '">');
519                                $overlay.fadeIn(400);
520                                e.preventDefault();
521                                return false;
522                            });
523                            n = imgTypes.length;
524                        }
525                    }
526                }
527            }
528        });
529
530        // TABLE OF CONTENTS
531        var elements = document.getElementsByClassName("toc-back-to-top");
532        if (elements.length > 0) { document.getElementsByClassName("toc-back-to-top")[0].style.display="none"; }
533        // Add a class to parent element to allow items containing a back-to-top to be realigned.
534        for(var i = 0; i < elements.length; i++) {
535            elements[i].parentNode.classList.add('back-to-top-realign');
536        }
537        var tocScrollSpeed = 800;
538
539
540        // MULTI-SELECT DROP-DOWN MENUS
541        // Converstions page multi-select
542        var convForm = $('.view-conversations form');
543        var convSelect = convForm.find('.form-select');
544        convForm.data('changed',0);
545        convSelect.multiselect({
546            selectedList: 1,
547            checkAllText: 'All Conversations',
548            noneSelectedText: 'All Conversations',
549            height: 'auto',
550            minWidth: 'auto'
551        });
552        convSelect.change(function(){
553            convForm.data('changed',1);
554        });
555        convForm.find('button').on('mouseup',function(){
556            if($(this).hasClass('ui-state-active') && convForm.data('changed')) convForm.submit();
557        });
558        convForm.focusout(function(){
559            if(convForm.data('changed')) convForm.submit();
560        });
561
562        var multiSelect = $('.ui-multiselect-menu');
563        if(multiSelect.length) {
564            $(window).resize(function(){ multiSelect.hide(); });
565        }
566
567        // TABLE OVERFLOW SLIDER (SCROLLBOX)
568        scrollBoxLabel = (isMobile?'Drag':'Click and drag') +' to scroll the table.';
569        pageWd = $('#content').width();
570        aside = $('#sidebar-second');
571
572        // Set footnotes display to block and make them invisible so we can get measurements from them.
573        $('.footnotes').css('visibility','hidden').css('display','block');
574        table = $('#content-area table').each(function(i,u){
575            with($(this)){
576                var scrollWd = width();
577                var parentWd = parent().width();
578                if(width() > parentWd) {
579                    // expand table container to full available width if the sidebar is not in the way.
580                    parentWd = pageWd<scrollWd? pageWd:scrollWd;
581                    // adjust for the footnotes left margin as needed.
582                    parentWd = parents('.footnotes').length? parentWd-40:parentWd;
583                    wrap('<div class="scroll-box scroll-box-'+i+'"/>');
584                    scrollBox = $('.scroll-box-'+i);
585                    // DEV NOTE: undefined aside.offset was causing an error so we test for it, not sure if not setting the css width creates another issue.
586                    if (aside.offset()) {
587                        if(scrollBox.offset().top > (aside.offset().top+aside.height())){
588                            scrollBox.css({ width:parentWd });
589                        }
590                    }
591                }
592            }
593        });
594        // Set footnotes display to none and set to visible again.
595        $('.footnotes').css('display','none').css('visibility','visible');
596
597        // Make collapsed divs open when table of content link is clicked.
598        // Only works if collapsed divs are using ui-accordion.
599        if(document.querySelectorAll(".ui-accordion-content").length > 0) {
600            // Create event listener for all link clicks
601            document.querySelectorAll('#content-area a').forEach(link => {
602                link.addEventListener('click', (e) => {
603                    // Retrieve href and store in targetUrl variable
604                    let targetUrl = e.target.href;
605                    let hash = targetUrl.substring(targetUrl.indexOf('#')+1);
606	            if (hash === "top") {
607                        let elems = document.querySelectorAll(".ui-accordion-content");
608                        var index = 0, length = elems.length;
609                        for ( ; index < length; index++) {
610                            elems[index].style.display = "none";
611                        }
612	            } else {
613                        let target = document.getElementById(hash);
614                        if (target !== null && target.closest(".ui-accordion-content") !== null) {
615                          target.closest(".ui-accordion-content").style.display="block";
616                        }
617                    }
618               });
619            });
620        }
621        // Create event listener for all link clicks
622        document.querySelectorAll('#content-area a').forEach(link => {
623            link.addEventListener('click', (e) => {
624                // Retrieve href and store in targetUrl variable
625                let targetUrl = e.target.href;
626                let hash = targetUrl.substring(targetUrl.indexOf('#')+1);
627                if (hash === "Database_of_all_GiveWell_grants") {
628                       e.preventDefault();
629                       location.href = "https://airtable.com/appaVhon0jdLt1rVs/shrixNMUWCSC5v1lh/tblykYPizxzYj3U1L/viwJ3DyqAUsL654Rm";
630                }
631          });
632        });
633        if (document.location.hash == "#Database_of_all_GiveWell_grants") {
634             location.href = "https://airtable.com/appaVhon0jdLt1rVs/shrixNMUWCSC5v1lh/tblykYPizxzYj3U1L/viwJ3DyqAUsL654Rm";
635        }
636 // Make collapsed divs open when hashed link link is clicked.
637        // Only works if collapsed divs are using ui-accordion.
638        if(location.hash.length > 0) {
639            // Retrieve href and store in targetUrl variable
640            let targetUrl = location.hash;
641            let hash = targetUrl.substring(targetUrl.indexOf('#')+1);
642            let target=document.getElementById(hash);
643            if(target !== null && target !== '' && target.closest(".ui-accordion-content") !== null) {
644                target.closest(".ui-accordion-content").style.display="block";
645                location.hash = hash;
646            }
647        }
648        // Toggle open class on three ways to donate (homepage section)..
649        if(document.getElementsByClassName('way').length > 0) {
650            // Get elements as array.
651            const ways = Object.values(document.getElementsByClassName('way'));
652            // When each is clicked, toggle 'open' class.
653            ways.forEach(row => {
654              row.addEventListener('click', (e) => {
655                if(e.target.className.indexOf('button') != -1) { return false; }
656                row.classList.toggle('open');
657                // Repeated clicks can toggle the class 'open' outer-grid the wrong way.
658                // If any item in the "three ways" section is open, we need the "open" class on the overall grid to hide the left-hand line.
659                let openWays = document.querySelectorAll('.way .open');
660                if (openWays.length > 0) {document.getElementsByClassName('outer-grid')[0].classList.add('open');}
661              });
662            });
663        }
664        // Toggle visibility on all grants charity card on click..
665        if(document.getElementsByClassName('purpose').length > 0) {
666            // Get elements as array.
667            const purposes = Object.values(document.getElementsByClassName('purpose'));
668            // When each is clicked, toggle 'open' class.
669            purposes.forEach(row => {
670              row.addEventListener('click', (e) => {
671                if(e.target.className.indexOf('button') != -1) { return false; }
672                row.classList.toggle('open');
673              });
674            });
675        }
676//        if(document.getElementsByClassName('purpose').length > 0 && document.getElementsByClassName('purpose-read-more').length > 0) {
677//            // Get elements.
678//            const purposes = Object.values(document.getElementsByClassName('purpose'));
679//            const readmores = Object.values(document.getElementsByClassName('purpose-read-more'));
680//            // Check whether the item is truncated with an elipses in CSS, and if no, hide the read more link.
681//            window.addEventListener('load', function() {
682//              Object.keys(purposes).forEach(key => {
683//                const e = purposes[key];
684//                const f = readmores[key];
685//                if (e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth)  {
686//                  f.classList.remove('hide');
687//                } else { 
688//                  f.classList.add('hide');
689//                }
690//              });
691//            });
692//            window.addEventListener('resize', function() {
693//              Object.keys(purposes).forEach(key => {
694//                const e = purposes[key];
695//                const f = readmores[key];
696//                if (e.scrollHeight > e.clientHeight || e.scrollWidth > e.clientWidth)  {
697//                  f.classList.remove('hide');
698//                } else { 
699//                  f.classList.add('hide');
700//                }
701//              });
702//            });
703//       }
704
705  });
706
707})(jQuery); // .noConflict()

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.