PageSourceSearch

https://www.thinkusadairy.org/assets/Documents/Prebuilt/js/scripts.js

js thinkusadairy.org collected 2026-09-26 03:21:06 UTC 34,686 bytes, 1,069 lines download raw bytes

1'use strict';
2
3/*
4    Buoy v1.2
5    A simple vanilla JS micro-library by Chris Ferdinandi.
6    http://gomakethings.com
7
8    Class handlers by Todd Motto.
9    https://github.com/toddmotto/apollo
10
11    Module pattern by Keith Rousseau.
12    https://twitter.com/keithtri
13
14    Free to use under the MIT License.
15    http://gomakethings.com/mit/
16*/
17
18window.$$ = (function(){
19
20    // Check for classList support
21    var classList = document.documentElement.classList;
22
23    // Check if an element has a class
24    var hasClass = function (elem, className) {
25        if (classList && elem) {
26            return elem.classList.contains(className);
27        } else {
28            return new RegExp('(^|\\s)' + className + '(\\s|$)').test(elem.className);
29        }
30    };
31
32    // Add a class to an element
33    var addClass = function (elem, className) {
34        if (classList && elem) {
35            elem.classList.add(className);
36        } else if ( elem && !hasClass(elem, className) ) {
37            elem.className += (elem.className ? ' ' : '') + className;
38        }
39    };
40
41    // Remove a class from an element
42    var removeClass = function (elem, className) {
43        if (classList && elem) {
44            elem.classList.remove(className);
45        } else if (elem && hasClass(elem, className)) {
46            elem.className = elem.className.replace(new RegExp('(^|\\s)*' + className + '(\\s|$)*', 'g'), '');
47        }
48    };
49
50    // Toggle a class on an element
51    var toggleClass = function (elem, className) {
52        if (classList && elem) {
53            elem.classList.toggle(className);
54        } else if (elem) {
55            if ( hasClass(elem, className ) ) {
56                removeClass(elem, className);
57            }
58            else {
59                addClass(elem, className);
60            }
61        }
62    };
63
64    // Get siblings of an element
65    var getSiblings = function (elem) {
66        var siblings = [];
67        var sibling = elem.parentNode.firstChild;
68        var skipMe = elem;
69        for ( ; sibling; sibling = sibling.nextSibling ) {
70            if ( sibling.nodeType == 1 && sibling != elem ) {
71                siblings.push( sibling );
72            }
73        }
74        return siblings;
75    };
76
77    var xhr = function() {
78        if (typeof XMLHttpRequest !== 'undefined') {
79            return new XMLHttpRequest();
80        }
81
82        var versions = [
83            "MSXML2.XmlHttp.5.0",
84            "MSXML2.XmlHttp.4.0",
85            "MSXML2.XmlHttp.3.0",
86            "MSXML2.XmlHttp.2.0",
87            "Microsoft.XmlHttp"
88        ];
89
90        var x;
91        for (var i = 0; i < versions.length; i++) {
92            try {
93                x = new ActiveXObject(versions[i]);
94                break;
95            } catch (e) {
96            }
97        }
98        return x;
99    };
100
101    var ajax = function(url, callback, method, data, sync) {
102        var x = xhr();
103        x.open(method, url, sync);
104        x.onreadystatechange = function() {
105            if (x.readyState == 4) {
106                callback(x.responseText);
107            }
108        };
109        if (method == 'POST') {
110            x.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
111        }
112        x.send(data);
113    };
114
115    // submit ajax GET request
116    var get = function(url, data, callback, sync) {
117        var query = [];
118        for (var key in data) {
119            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
120        }
121        ajax(url + '?' + query.join('&'), callback, 'GET', null, sync);
122    };
123
124    // submit ajax POST request
125    var post = function(url, data, callback, sync) {
126        var query = [];
127        for (var key in data) {
128            query.push(encodeURIComponent(key) + '=' + encodeURIComponent(data[key]));
129        }
130        ajax(url, callback, 'POST', query.join('&'), sync);
131    };
132
133    // Return functions
134    return {
135        toggleClass: toggleClass,
136        removeClass: removeClass,
137        addClass: addClass,
138        hasClass: hasClass,
139        getSiblings: getSiblings,
140        get: get,
141        post: post
142    };
143})();
144
145
146// 'for' loop shortcut
147function forEach(items, action) {
148    for (var itemsIndex = 0; itemsIndex < items.length; itemsIndex++) {
149        action(items[itemsIndex], itemsIndex);
150    }
151}
152
153
154// helper functions: element parents
155Element.prototype.getParents = function() {
156    var parents = [],
157        obj = this;
158    while ( obj !== document.documentElement ) {
159        parents.push(obj);
160        obj = obj.parentNode;
161    }
162    return parents;
163};
164Element.prototype.getParentsByTagName = function(tag) {
165    tag = tag.toLowerCase();
166    return this.getParents().filter(function(el) {
167        return el.tagName.toLowerCase() === tag;
168    });
169};
170Element.prototype.getParentsByClassName = function(cl) {
171    return this.getParents().filter(function(el) {
172        return el.classList.contains(cl);
173    });
174};
175
176
177// get index of element within its parent
178function elementIndex(el) {
179    var result = 0;
180    while ( (el = el.previousSibling) != null) {
181        if (el.nodeType === 1) {
182            result++;
183        }
184    }
185    return result;
186}
187
188
189// attach a click event with ie8 support
190Element.prototype.clickEvent = function(action) {
191    var thisEl = this;
192    if(window.addEventListener) {
193        thisEl.addEventListener('click', function(ev) {
194            ev.preventDefault();
195            action(thisEl);
196        });
197    } else { // ie8
198        thisEl.attachEvent('onclick', function() {
199            action(thisEl);
200        });
201    }
202};
203// attach a hover event with ie8 support
204Element.prototype.hoverEvent = function(onAction, offAction) {
205    var thisEl = this;
206    if(window.addEventListener) {
207        thisEl.addEventListener('mouseenter', function() {
208            onAction(thisEl);
209        });
210        thisEl.addEventListener('mouseleave', function() {
211            offAction(thisEl);
212        });
213    } else { // ie8
214        thisEl.attachEvent('onmouseenter', function() {
215            onAction(thisEl);
216        });
217        thisEl.attachEvent('onmouseleave', function() {
218            offAction(thisEl);
219        });
220    }
221};
222
223
224// debounced window resize event
225// https://github.com/porada/resizeend
226(function(window) {
227    var currentOrientation, debounce, dispatchResizeEndEvent, document, events, getCurrentOrientation, initialOrientation, resizeDebounceTimeout;
228    document = window.document;
229    if (!(window.addEventListener && document.createEvent)) {
230        return;
231    }
232    events = ['resize:end', 'resizeend'].map(function(name) {
233        var event;
234        event = document.createEvent('Event');
235        event.initEvent(name, false, false);
236        return event;
237    });
238    dispatchResizeEndEvent = function() {
239        return events.forEach(window.dispatchEvent.bind(window));
240    };
241    getCurrentOrientation = function() {
242        return Math.abs(+window.orientation || 0) % 180;
243    };
244    initialOrientation = getCurrentOrientation();
245    currentOrientation = null;
246    resizeDebounceTimeout = null;
247    debounce = function() {
248        currentOrientation = getCurrentOrientation();
249        if (currentOrientation !== initialOrientation) {
250            dispatchResizeEndEvent();
251            initialOrientation = currentOrientation;
252        } else {
253            clearTimeout(resizeDebounceTimeout);
254            resizeDebounceTimeout = setTimeout(dispatchResizeEndEvent, 100);
255        }
256    };
257    return window.addEventListener('resize', debounce, false);
258})(window);
259
260
261// array.prototype.indexOf polyfill (ie8)
262if (!Array.prototype.indexOf) {
263    Array.prototype.indexOf = function (searchElement, fromIndex) {
264        if ( this === undefined || this === null ) {
265            throw new TypeError( '"this" is null or not defined' );
266        }
267
268        var length = this.length >>> 0; // Hack to convert object.length to a UInt32
269
270        fromIndex = +fromIndex || 0;
271
272        if (Math.abs(fromIndex) === Infinity) {
273            fromIndex = 0;
274        }
275
276        if (fromIndex < 0) {
277            fromIndex += length;
278            if (fromIndex < 0) {
279                fromIndex = 0;
280            }
281        }
282
283        for (;fromIndex < length; fromIndex++) {
284            if (this[fromIndex] === searchElement) {
285                return fromIndex;
286            }
287        }
288
289        return -1;
290    };
291}
292
293
294// array.prototype.filter polyfill (ie8)
295if (!Array.prototype.filter) {
296    Array.prototype.filter = function(fun /*, thisArg */) {
297        if (this === void 0 || this === null) {
298            throw new TypeError();
299        }
300
301        var t = Object(this);
302        var len = t.length >>> 0;
303        if (typeof fun != "function") {
304            throw new TypeError();
305        }
306
307        var res = [];
308        var thisArg = arguments.length >= 2 ? arguments[1] : void 0;
309        for (var i = 0; i < len; i++) {
310            if (i in t) {
311                var val = t[i];
312                if (fun.call(thisArg, val, i, t)) {
313                    res.push(val);
314                }
315            }
316        }
317
318        return res;
319    };
320}
321
322
323// helper function: nodelist to array
324function toArray(obj) {
325    var array = [];
326    for (var i = obj.length >>> 0; i--;) {
327        array[i] = obj[i];
328    }
329    return array;
330}
331
332
333// generic toggles
334// <el class="toggle" data-toggle-target="[next|parentnext|css-selector]" />
335function toggles(el) {
336    var toggleTarget = el.getAttribute('data-toggle-target'),
337        targetObject = null,
338        onText = el.getAttribute('data-on-text'),
339        offText = el.getAttribute('data-off-text'),
340        behavior = null;
341
342    function doToggle(target, action) {
343        var action = action || null;
344        if (!action) {
345            $$.toggleClass(target, 'active');
346        } else if (action === 'on') {
347            $$.addClass(target, 'active');
348        } else if (action === 'off') {
349            $$.removeClass(target, 'active');
350        }
351    }
352
353    if ( toggleTarget == 'next' ) {
354        targetObject = el.nextElementSibling;
355    } else if ( toggleTarget == 'parent' ) {
356        targetObject = el.parentNode;
357    } else if ( toggleTarget == 'parentnext' ) {
358        targetObject = el.parentNode.nextElementSibling;
359    } else if ( toggleTarget == 'parentparent' ) {
360        targetObject = el.parentNode.parentNode;
361    } else if ( toggleTarget == 'parentparentnext' ) {
362        targetObject = el.parentNode.parentNode.nextElementSibling;
363    } else if (toggleTarget === 'self') {
364        targetObject = el;
365    }
366
367    // this is dirty. Clean up when able to edit markup
368    if (el.innerHTML === 'Expand All') {
369        behavior = 'on';
370    } else if (el.innerHTML === 'Collapse All') {
371        behavior = 'off';
372    }
373
374
375    if (targetObject) {
376        doToggle(targetObject, behavior);
377    } else if ( toggleTarget !== null ) {
378        var targetObjects = document.querySelectorAll(toggleTarget);
379        for ( var j = 0; j < targetObjects.length; j++ ) {
380            doToggle(targetObjects[j], behavior);
381        }
382    }
383
384    if (toggleTarget !== 'self') {
385        $$.toggleClass(el, 'active');
386
387        if ($$.hasClass(el, 'active') && onText) {
388            el.innerHTML = onText;
389        } else if (!$$.hasClass(el, 'active') && offText) {
390            el.innerHTML = offText;
391        }
392    }
393}
394forEach(document.querySelectorAll('.toggle'), function(el) {
395    el.clickEvent(function(el) {
396        toggles(el);
397    });
398});
399var escapeCloseItems = document.querySelectorAll('.escape-close');
400if (escapeCloseItems) {
401    document.addEventListener('keyup', function (ev) {
402        if (ev.keyCode === 27) {
403            forEach(escapeCloseItems, function (el) {
404                $$.removeClass(el, 'active');
405            });
406        }
407    });
408}
409
410
411// tabs + automation
412function tabs(tabGroup) {
413    var tabEls = tabGroup.querySelectorAll('.tab'),
414        paneEls = tabGroup.querySelectorAll('.pane'),
415        nextEls = tabGroup.querySelectorAll('.tabs-next'),
416        prevEls = tabGroup.querySelectorAll('.tabs-prev'),
417        panesCount = Math.max(tabEls.length, paneEls.length),
418        slideSpeed = 6000,
419        currentSlide = 0,
420        slideInterval;
421
422    function changeTo(index) {
423        // changes tabs/panes in current context to specified index
424
425        // reset state
426        forEach(tabEls, function(tabEl) {
427            $$.removeClass(tabEl, 'active');
428            $$.removeClass(tabEl, 'next');
429            $$.removeClass(tabEl, 'prev');
430        });
431        forEach(paneEls, function(paneEl) {
432            $$.removeClass(paneEl, 'active');
433            $$.removeClass(paneEl, 'next');
434            $$.removeClass(paneEl, 'prev');
435        });
436        // current active set
437        if ( tabEls[index] ) {
438            $$.addClass(tabEls[index], 'active');
439        }
440        if ( paneEls[index] ) {
441            $$.addClass(paneEls[index], 'active');
442        }
443        // set at current index + 1
444        if ( index < (panesCount - 1) ) {
445            $$.addClass(tabEls[index + 1], 'next');
446            $$.addClass(paneEls[index + 1], 'next');
447        } else {
448            $$.addClass(tabEls[0], 'next');
449            $$.addClass(paneEls[0], 'next');
450        }
451        // set at current index - 1
452        if ( index == 0 ) {
453            $$.addClass(tabEls[panesCount - 1], 'prev');
454            $$.addClass(paneEls[panesCount - 1], 'prev');
455        } else {
456            $$.addClass(tabEls[index - 1], 'prev');
457            $$.addClass(paneEls[index - 1], 'prev');
458        }
459
460        // trigger window resize
461        window.dispatchEvent(new Event('resize'));
462
463        // carry on
464        currentSlide = index;
465    }
466
467    function bindTabClick(el, action) {
468        var index = parseInt(el.getAttribute('data-tabs-index')) || 0;
469
470        function handleClick() {
471            if ( $$.hasClass(tabGroup, 'playing') ) {
472                pauseSlideshow();
473            }
474            if (action == 'next') {
475                if (currentSlide < panesCount - 1) {
476                    changeTo(currentSlide + 1);
477                } else {
478                    changeTo(0);
479                }
480            } else if (action == 'prev') {
481                if (currentSlide <= 0) {
482                    changeTo(panesCount - 1);
483                } else {
484                    changeTo(currentSlide - 1);
485                }
486            } else {
487                changeTo(index);
488            }
489            if ( $$.hasClass(tabGroup, 'slideshow') ) {
490                startSlideshow();
491            }
492        }
493
494        el.clickEvent(function() {
495            handleClick();
496        });
497    }
498
499    function startSlideshow() {
500        slideInterval = setInterval(switchForward, slideSpeed);
501        $$.addClass(tabGroup, 'playing');
502    }
503    function pauseSlideshow() {
504        window.clearInterval(slideInterval);
505        $$.removeClass(tabGroup, 'playing');
506    }
507    function switchForward() {
508        if ( currentSlide < (panesCount - 1) ) {
509            changeTo((currentSlide + 1));
510        } else {
511            changeTo(0);
512        }
513    }
514
515    // initialize
516    forEach(tabEls, function(el, i) {
517        el.setAttribute('data-tabs-index', i);
518        bindTabClick(el);
519    });
520    forEach(paneEls, function(el, i) {
521        el.setAttribute('data-tabs-index', i);
522    });
523    changeTo(0);
524
525    // 'next' clicks
526    forEach(nextEls, function(el) {
527        bindTabClick(el, 'next');
528    });
529    // 'prev' clicks
530    forEach(prevEls, function(el) {
531        bindTabClick(el, 'prev');
532    });
533
534    // automation
535    if ( $$.hasClass(tabGroup, 'slideshow') ) {
536        startSlideshow();
537    }
538}
539forEach(document.querySelectorAll('.tabs'), function(tabGroup) {
540    tabs(tabGroup);
541});
542
543
544// column class recognition
545function isAColumn(el) {
546    var classes = ['pagePresentationLayoutColumn',
547                   'col-sm-12', 'col-sm-6', 'col-sm-4', 'col-sm-3', 'col-sm-2',
548                   'col-md-12', 'col-md-6', 'col-md-4', 'col-md-3', 'col-md-2',
549                   'col-lg-12', 'col-lg-6', 'col-lg-4', 'col-lg-3', 'col-lg-2'],
550        candidate;
551    while (classes.length > 0) {
552        candidate = classes.pop();
553        if ($$.hasClass(el, candidate)) {
554            return true;
555        }
556    }
557    return false;
558}
559
560// automatically set up shared-height groups for similar items
561function autoHeightGroups(groupSelector) {
562    var boxes = document.querySelectorAll(groupSelector);
563    forEach(boxes, function (box, boxId) {
564        var parentColumn = box.parentNode,
565            groupId = 'auto-group-' + boxId.toString(),
566            boxIndex,
567            adjacentColumns = [];
568
569        // TODO: discard this box if it already is in a height group
570
571        // if is a direct child of a column
572        if (isAColumn(parentColumn)) {
573            // if column is not first in row, discard
574            if (elementIndex(parentColumn) === 0) {
575                $$.addClass(box, 'shared-height');
576                box.setAttribute('data-height-group', groupId);
577
578                // store this element's index within column
579                boxIndex = elementIndex(box);
580
581                // find adjacent columns
582                while ( (parentColumn = parentColumn.nextSibling) != null) {
583                    if (parentColumn.nodeType === 1 && isAColumn(parentColumn)) {
584                        adjacentColumns.push(parentColumn);
585                    }
586                }
587
588                forEach(adjacentColumns, function (column) {
589                    // apply same height group to similar index
590                    var columnBoxes = column.querySelectorAll(groupSelector),
591                        relevantBox = columnBoxes[boxIndex];
592                    if (relevantBox) {
593                        $$.addClass(relevantBox, 'shared-height');
594                        relevantBox.setAttribute('data-height-group', groupId);
595                    }
596                });
597            }
598        }
599    });
600}
601// auto-heights for all content boxes
602autoHeightGroups('.content-box');
603
604
605
606// shared height elements
607// <el class="shared-height" data-height-group="[string]">
608(function() {
609    var heightEls = document.querySelectorAll('.shared-height'),
610        heightGroups = [], uniqueHeightGroups = [];
611
612    // get height groups together
613    for ( var i = 0; i < heightEls.length; i++ ) {
614        heightGroups.push(heightEls[i].getAttribute('data-height-group'));
615    }
616    uniqueHeightGroups = heightGroups.filter(function(val, pos) {
617        return heightGroups.indexOf(val) == pos;
618    })
619
620    function evenHeights() {
621        // blank slate
622        for ( var i = 0; i < heightEls.length; i++ ) {
623            heightEls[i].style.minHeight = 'auto';
624        }
625        // iterate over groups
626        for ( var i = 0; i < uniqueHeightGroups.length; i++ ) {
627            var thisHeight, maxHeight = 1,
628                groupEls = document.querySelectorAll('.shared-height[data-height-group="' + uniqueHeightGroups[i] + '"]');
629            for ( var j = 0; j < groupEls.length; j++ ) {
630                var el = groupEls[j];
631                thisHeight = parseInt(el.clientHeight);
632                if (thisHeight > maxHeight) {
633                    maxHeight = thisHeight;
634                }
635            }
636            for ( var j = 0; j < groupEls.length; j++ ) {
637                var el = groupEls[j];
638                el.style.minHeight = maxHeight + 'px';
639            }
640        }
641    }
642
643    if(window.addEventListener) {
644        window.addEventListener('load', function () {
645            // shove this to the bottom of the stack so autoHeightGroups can run first
646            window.setTimeout(evenHeights, 1);
647        });
648        window.addEventListener('resize', function () {
649            window.setTimeout(evenHeights, 1);
650        });
651    } else { // ie8
652        window.attachEvent('onload', function () {
653            window.setTimeout(evenHeights, 1);
654        });
655        window.attachEvent('onresize', function () {
656            window.setTimeout(evenHeights, 1);
657        });
658    }
659})();
660
661
662// mobile drilldown menu
663Element.prototype.getPreviousAnchor = function() {
664    var prevSibling = this.previousSibling;
665    while (prevSibling) {
666        if (prevSibling.nodeType == 1 && (prevSibling.tagName == 'a' || prevSibling.tagName == 'A')) {
667            return prevSibling;
668        }
669        prevSibling = prevSibling.previousSibling;
670    }
671    return null;
672};
673forEach(document.querySelectorAll('.page-nav'), function(navContainer) {
674    var originalList = navContainer.querySelector('ul'),
675        list = navContainer.insertBefore(originalList.cloneNode(true), originalList);
676    $$.addClass(originalList, 'list-large');
677    $$.addClass(list, 'list-small');
678    list.setAttribute('aria-hidden', 'true');
679
680    forEach(list.getElementsByTagName('ul'), function(ul) {
681        var a = ul.getPreviousAnchor();
682
683        // add drilldown clicks
684        $$.addClass(a, 'drilldown');
685        a.clickEvent(function(el) {
686            $$.addClass(el, 'active');
687            $$.addClass(ul, 'active');
688        });
689
690        // include overview link if the top-level page actually exists.
691        if(a.className.indexOf("emptyLink") < 0) {
692            // add 'overview' links
693            var overviewLi = document.createElement('li');
694            $$.addClass(overviewLi, 'overview');
695            var overviewA = overviewLi.appendChild(a.cloneNode(true));
696            $$.removeClass(overviewA, 'drilldown');
697            overviewA.innerHTML += ' Overview';
698            ul.insertBefore(overviewLi, ul.querySelector('li'));
699        }
700
701        // add 'back' links
702        var backLi = document.createElement('li'),
703            backA = document.createElement('a'),
704            prevA = a.getParentsByTagName('ul')[0].getPreviousAnchor(),
705            prevName = prevA ? prevA.innerHTML : 'Main Navigation';
706        backLi.appendChild(backA);
707        $$.addClass(backLi, 'back');
708        backA.setAttribute('href', '#');
709        backA.innerHTML = 'Back to ' + prevName;
710        ul.insertBefore(backLi, ul.querySelector('li'));
711        backA.clickEvent(function(el) {
712            $$.removeClass(a, 'active');
713            $$.removeClass(ul, 'active');
714        });
715    });
716
717    // add disclosure arrows to desktop nav
718    var disclosureNode = document.createElement('span');
719    $$.addClass(disclosureNode, 'disclose');
720    forEach(navContainer.querySelectorAll('.list-large > li > ul > li > a'), function(link) {
721        link.appendChild(disclosureNode.cloneNode(true));
722    });
723});
724
725
726// add odd hover behavior on certain boxes
727forEach(document.querySelectorAll('.no-touch .hover-box'), function(box) {
728    forEach(box.querySelectorAll('.item-title a, .disclose, .market-data-indicator-image'), function(a) {
729        a.hoverEvent(function() {
730            $$.addClass(box, 'hovered');
731        }, function() {
732            $$.removeClass(box, 'hovered');
733        });
734    });
735});
736
737
738// netflix-style item sliders
739function itemSlider(container, rows) {
740    var items = toArray(container.querySelectorAll('.item')),
741        rows = rows || 1,
742        itemWidth = 0,
743        containerWidth, moveAmount, maxPos, curPos, navItems, itemGroups;
744
745    // quick helper function to make elements
746    function createElementWithClass(el, cl) {
747        var element = document.createElement(el);
748        if (el === 'a') {
749            element.setAttribute('href', '#');
750        }
751        element.setAttribute('class', cl);
752        return element;
753    }
754
755    // wrap items in sliding container
756    var wrapper = createElementWithClass('div', 'item-slider-wrapper group');
757    forEach(items, function(item) {
758        wrapper.appendChild(item);
759    });
760    container.appendChild(wrapper);
761
762    // create nav container and arrows
763    var navWrapper = createElementWithClass('div', 'item-slider-nav'),
764        navDotsWrapper = createElementWithClass('div', 'item-slider-dots'),
765        prevButton = createElementWithClass('a', 'item-slider-prev'),
766        nextButton = createElementWithClass('a', 'item-slider-next');
767    navWrapper.appendChild(prevButton);
768    navWrapper.appendChild(navDotsWrapper);
769    navWrapper.appendChild(nextButton);
770
771    // moves the wrapper. Starting position at 0
772    function setPosition(n) {
773        curPos = n;
774        if (window.getComputedStyle(wrapper).getPropertyValue('direction') === 'rtl') {
775            wrapper.style.right = (n * moveAmount * -1) + 'px';
776        } else {
777            wrapper.style.left = (n * moveAmount * -1) + 'px';
778        }
779        forEach(navItems, function(navItem) {
780            $$.removeClass(navItem, 'current');
781        });
782        $$.addClass(navItems[n], 'current');
783    }
784
785    // calculates frame movement amount, number of frames, etc
786    function setup() {
787
788        containerWidth = container.clientWidth;
789        // taking average item width
790        itemWidth = 0;
791        forEach(items, function (item) {
792            itemWidth += item.offsetWidth;
793            $$.removeClass(item, 'right');
794        });
795        itemWidth /= items.length;
796        maxPos = Math.floor(itemWidth * items.length / containerWidth);
797        moveAmount = Math.floor(containerWidth / itemWidth) * itemWidth;
798
799        wrapper.style.width = (itemWidth * items.length) + 'px';
800
801        // add class for switching the hover info side
802        forEach(items, function (item, i) {
803            if ((i + 1) * itemWidth % moveAmount === 0) {
804                $$.addClass(item, 'right');
805            }
806        });
807
808        // row splitting, if relevant
809        if (rows > 1) {
810            // in case this has already been generated, reset groups
811            forEach(items, function(item) {
812                wrapper.appendChild(item);
813                item.style.clear = '';
814            });
815            if (itemGroups) {
816                forEach(itemGroups, function(itemGroup) {
817                    wrapper.removeChild(itemGroup);
818                });
819            }
820
821            var itemsPerGroup = Math.floor(containerWidth / itemWidth) * rows,
822                numGroups = Math.ceil(items.length / itemsPerGroup),
823                itemGroups = [];
824            moveAmount = itemsPerGroup / rows * itemWidth;
825
826            for (var i = 0; i < numGroups; i++) {
827                itemGroups.unshift(createElementWithClass('div', 'item-group'));
828                for (var j = 0; j < itemsPerGroup; j++) {
829                    var item = items[i * itemsPerGroup + j];
830                    if (j % (itemsPerGroup / rows) === 0) {
831                        item.style.clear = 'left';
832                    }
833                    if (item) itemGroups[0].appendChild(item);
834                }
835                wrapper.appendChild(itemGroups[0]);
836                itemGroups[0].style.width = moveAmount + 'px';
837            }
838            maxPos = numGroups;
839            maxPos = numGroups - 1;
840        }
841
842        // navigation
843        container.appendChild(navWrapper);
844        navDotsWrapper.innerHTML = '';
845        navItems = [];
846        for (var i = 0; i <= maxPos; i++) {
847            navItems.push(createElementWithClass('a', 'item-slider-dot'));
848            navDotsWrapper.appendChild(navItems[i]);
849        }
850        forEach(navItems, function(navItem, i) {
851            navItem.clickEvent(function() {
852                setPosition(i);
853            });
854        });
855        navWrapper.style.display = maxPos > 0 ? '' : 'none';
856
857        // reset position to 0
858        setPosition(0);
859    }
860    setup();
861
862    // next and prev buttons
863    prevButton.clickEvent(function(button) {
864        setPosition(curPos == 0 ? maxPos : curPos - 1);
865    });
866    nextButton.clickEvent(function(button) {
867        setPosition(curPos == maxPos ? 0 : curPos + 1);
868    });
869
870    // resize
871    window.addEventListener('resize:end', setup);
872
873    $$.addClass(container, 'enabled');
874}
875forEach(document.querySelectorAll('.item-slider'), function(el) {
876    if ($$.hasClass(el, 'stack-2')) {
877        itemSlider(el, 2);
878    } else {
879        itemSlider(el);
880    }
881});
882
883
884// resize tableau iframe to ancestor
885function resizeTableau(ancestor) {
886    var target = ancestor.querySelector('.tableauPlaceholder'),
887        supportedTransform = detectTransform(),
888        ancestorWidth, targetWidth, ratio;
889
890    if (!supportedTransform || !target)
891        return;
892
893    // detect transform support
894    function detectTransform() {
895        var tmpDiv = document.createElement('div'),
896            props = ['transform', 'webkitTransform', 'MozTransform', 'msTransform', 'OTransform'];
897        for (var i = 0; i < props.length; i++) {
898            if (typeof tmpDiv.style[props[i]] != 'undefined') {
899                return props[i];
900            }
901        }
902        return false;
903    }
904
905    // function to resize the iframe
906    function doResize() {
907        target.style[supportedTransform] = '';
908        ancestorWidth = ancestor.clientWidth;
909        targetWidth = target.offsetWidth;
910        ratio = ancestorWidth / targetWidth;
911        target.style[supportedTransform] = 'scale(' + ratio + ')';
912        ancestor.style.height = target.offsetHeight * ratio + 'px';
913    }
914
915    // init and watch
916    doResize();
917    window.addEventListener('load', doResize);
918    window.addEventListener('resize:end', doResize);
919}
920window.addEventListener('load', function() {
921    forEach(document.querySelectorAll('.resize-tableau'), function(el) {
922        resizeTableau(el);
923    });
924});
925
926
927// hover groups
928[].forEach.call(document.querySelectorAll('[data-hover-group]'), function (el) {
929    el.setAttribute('data-hover-group', el.getAttribute('data-hover-group').replace(/&amp;|[\s&;]+/g, ''));
930    el.hoverEvent(function (el) {
931        [].forEach.call(document.querySelectorAll('[data-hover-group=' + el.getAttribute('data-hover-group') + ']'), function (el) {
932            $$.addClass(el, 'hovered');
933        });
934    }, function (el) {
935        [].forEach.call(document.querySelectorAll('[data-hover-group=' + el.getAttribute('data-hover-group') + ']'), function (el) {
936            $$.removeClass(el, 'hovered');
937        });
938    });
939});
940
941
942// fix: remove .page-contents-nav if useless
943(function () {
944    var navs = document.querySelectorAll('.page-contents-nav'),
945        i, anchors;
946    for (i = navs.length - 1; i >= 0; i--) {
947        anchors = navs[i].querySelectorAll('a');
948        if (anchors.length <= 1) {
949            navs[i].style.display = 'none';
950        }
951    }
952}());
953
954// align bottom of homepage boxes to bottom of twitter widget
955/* function homeHeights() {
956    var boxes = Array.prototype.slice.call(document.querySelectorAll('.home-match-height'), 0),
957        ref = document.querySelector('.home-match-height-ref');
958    if (!ref)
959        return;
960    forEach(boxes, function (box) {
961        box.style.minHeight = 0;
962        var offset = box.getBoundingClientRect().top + (window.pageYOffset || document.scrollTop || 0),
963            height = box.offsetHeight,
964            refOffset = ref.getBoundingClientRect().top + (window.pageYOffset || document.scrollTop || 0),
965            refHeight = ref.offsetHeight,
966            difference = (refOffset + refHeight) - (offset + height);
967
968        if (difference > 0) {
969            box.style.minHeight = (height + difference) + 'px';
970        }
971    });
972}
973window.addEventListener('resize:end', homeHeights);
974
975*/
976
977// consume rss feed async
978forEach(document.querySelectorAll('.rss-content'), function(el) {
979    var url = el.getAttribute('data-url');
980    var feedData = {
981        url: el.getAttribute('data-feedurl'),
982        itemsToSkip: el.getAttribute('data-skip'),
983        itemsToDisplay: el.getAttribute('data-take'),
984        itemTemplate: el.getAttribute('data-template'),
985        blogUrl: el.getAttribute('data-blog'),
986        blogName: el.getAttribute('data-blogName'),
987        itemCss: el.getAttribute('data-css')
988    };
989    $$.post(url, feedData, function(result) {
990        el.innerHTML = result;
991        //el.style.overflow = 'hidden';
992        forEach(el.querySelectorAll('span[style]'), function(span) {
993            span.removeAttribute('style');
994        });
995        // homeHeights();
996        stButtons.locateElements();
997    }, true);
998});
999
1000// shareable links
1001(function () {
1002    var links = document.getElementsByClassName('shareable-link'),
1003        shareList = [
1004            ['Facebook', 'https://www.facebook.com/sharer/sharer.php?u={0}&t={1}'],
1005            ['Twitter', 'https://twitter.com/intent/tweet?url={0}&text={1}'],
1006            ['LinkedIn', 'https://www.linkedin.com/shareArticle?mini=true&url={0}&title={1}'],
1007            ['Email', 'mailto:?body={0}&subject={1}']
1008        ],
1009        trigger, container, item, url;
1010
1011    // closer function
1012    function closeShares() {
1013        forEach(document.getElementsByClassName('share-inline'), function (trigger) {
1014            $$.removeClass(trigger, 'is-active');
1015        });
1016    }
1017
1018    if (links.length > 0) {
1019        // create our base button
1020        trigger = document.createElement('div');
1021        trigger.className = 'share-inline';
1022        trigger.textContent = 'Share';
1023
1024        // create our base popup and prototype item
1025        container = document.createElement('div');
1026        container.className = 'share-inline__container';
1027        item = document.createElement('a');
1028        item.setAttribute('target', '_blank');
1029
1030        // add buttons and popups to each relevant link
1031        forEach(links, function (link) {
1032            var thisTrigger = trigger.cloneNode(true),
1033                thisContainer = container.cloneNode(true);
1034            forEach(shareList, function (shareItem) {
1035                var thisItem = item.cloneNode(true),
1036                    thisURL = encodeURIComponent(link.href),
1037                    thisTitle = encodeURIComponent(link.getAttribute('data-share-title') || ' ');
1038                thisItem.className = 'share-inline__item share-inline__item--' + shareItem[0].toLowerCase();
1039                thisItem.href = shareItem[1].replace(/\{0\}/, thisURL).replace(/\{1\}/, thisTitle);
1040                thisItem.textContent = shareItem[0];
1041                thisContainer.appendChild(thisItem);
1042            });
1043            thisTrigger.appendChild(thisContainer);
1044            link.parentNode.insertBefore(thisTrigger, link.nextSibling);
1045
1046            thisTrigger.addEventListener('click', function (ev) {
1047                if (ev.target === thisTrigger) {
1048                    ev.preventDefault();
1049                }
1050                // throw to event loop to make way for closer
1051                setTimeout(function () {
1052                    $$.addClass(thisTrigger, 'is-active');
1053                }, 1);
1054            });
1055        });
1056
1057        // close by clicking anywhere
1058        document.body.addEventListener('click', closeShares);
1059        // close via esc
1060        document.addEventListener('keyup', function (ev) {
1061            if (ev.keyCode === 27) {
1062                closeShares();
1063            }
1064        });
1065    }
1066})();
1067
1068$$.removeClass(document.documentElement, 'no-js');
1069$$.addClass(document.documentElement, 'js');

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.