PageSourceSearch

https://studentpool.nl/wp-content/themes/bz-studentpool/assets/essentials/essentials.js

js studentpool.nl collected 2026-10-08 08:26:15 UTC 41,948 bytes, 1,263 lines download raw bytes

1/**
2 * Plugin Name: jQuery Essentials Main
3 * Version: 1.3
4 * Date: 07-02-2019
5 * License: CC0 1.0 (https://creativecommons.org/publicdomain/zero/1.0/deed)
6 * 
7 */
8
9function isMobile(){
10	if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
11		return true;
12	} else {
13		return false;
14	}
15}
16
17function isIE(){
18	var ua = window.navigator.userAgent;
19    var msie = ua.indexOf("MSIE ");
20
21    if (msie > 0){
22    	return true;
23    } else {
24    	return false;
25    }
26}
27
28function openPopup(popupId){
29    var popupContent = jQuery('.popup-essential-').find('.popup-essential-content-video');
30    
31    jQuery('.popup-essential-'+popupId).show();
32    
33    jQuery('.popup-essential-'+popupId).on('click',function(){
34        closePopup(popupId);
35    });
36
37    jQuery('.popup-essential-'+popupId+' .popup-essential-content-in-content').on('click',function(e){
38        e.preventDefault();
39        e.stopPropagation();
40    });
41    
42    jQuery('.popup-essential-'+popupId+' .popup-essential-close').on('click',function(){
43        closePopup(popupId);
44    });
45    
46    jQuery('body').addClass('popup-essential-open');
47    jQuery('body,html').css('overflow','');
48}
49function closePopup(popupId){
50    jQuery('.popup-essential-'+popupId).hide();
51    jQuery('body').removeClass('popup-essential-open');
52    jQuery('body,html').css('overflow','');
53}
54
55
56
57
58
59
60function isInViewport(el) {
61  var rect = el.getBoundingClientRect()
62  return (
63    (rect.height > 0 || rect.width > 0) &&
64    rect.bottom >= 0 &&
65    rect.right >= 0 &&
66    rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
67    rect.left <= (window.innerWidth || document.documentElement.clientWidth)
68  )
69}
70
71function animationElementInViewport(el,extraPercentageHeight) {
72    var top = el.offsetTop;
73    var left = el.offsetLeft;
74    var width = el.offsetWidth;
75    var height = el.offsetHeight;
76    var extraPercentageHeight = extraPercentageHeight;
77    var container = jQuery(window);
78    var extraHeightInPixels = (container.innerHeight()/100)*extraPercentageHeight;
79    
80    while (el.offsetParent) {
81        el = el.offsetParent;
82        top += el.offsetTop;
83        left += el.offsetLeft;
84    }
85
86    return (
87        top < (container.scrollTop() + extraHeightInPixels + container.innerHeight()) &&
88        left < (container.scrollLeft() + container.innerWidth()) &&
89        (top + height) > (container.scrollTop() - extraHeightInPixels) &&
90        (left + width) > container.scrollLeft()
91    );
92}
93
94/*
95 * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
96 *
97 * Uses the built in easing capabilities added In jQuery 1.1
98 * to offer multiple easing options
99 *
100 * TERMS OF USE - jQuery Easing
101 * 
102 * Open source under the BSD License. 
103 * 
104 * Copyright © 2008 George McGinley Smith
105 * All rights reserved.
106 * 
107 * Redistribution and use in source and binary forms, with or without modification, 
108 * are permitted provided that the following conditions are met:
109 * 
110 * Redistributions of source code must retain the above copyright notice, this list of 
111 * conditions and the following disclaimer.
112 * Redistributions in binary form must reproduce the above copyright notice, this list 
113 * of conditions and the following disclaimer in the documentation and/or other materials 
114 * provided with the distribution.
115 * 
116 * Neither the name of the author nor the names of contributors may be used to endorse 
117 * or promote products derived from this software without specific prior written permission.
118 * 
119 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
120 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
121 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
122 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
123 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
124 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
125 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
126 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
127 * OF THE POSSIBILITY OF SUCH DAMAGE. 
128 *
129 */
130
131// t: current time, b: begInnIng value, c: change In value, d: duration
132jQuery.easing['jswing'] = jQuery.easing['swing'];
133
134jQuery.extend( jQuery.easing,
135    {
136        def: 'easeOutQuad',
137        swing: function (x, t, b, c, d) {
138            //alert(jQuery.easing.default);
139            return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
140        },
141        easeInQuad: function (x, t, b, c, d) {
142            return c*(t/=d)*t + b;
143        },
144        easeOutQuad: function (x, t, b, c, d) {
145            return -c *(t/=d)*(t-2) + b;
146        },
147        easeInOutQuad: function (x, t, b, c, d) {
148            if ((t/=d/2) < 1) return c/2*t*t + b;
149            return -c/2 * ((--t)*(t-2) - 1) + b;
150        },
151        easeInCubic: function (x, t, b, c, d) {
vendor: 5,027 bytes, lines 152-268
152            return c*(t/=d)*t*t + b;
153        },
154        easeOutCubic: function (x, t, b, c, d) {
155            return c*((t=t/d-1)*t*t + 1) + b;
156        },
157        easeInOutCubic: function (x, t, b, c, d) {
158            if ((t/=d/2) < 1) return c/2*t*t*t + b;
159            return c/2*((t-=2)*t*t + 2) + b;
160        },
161        easeInQuart: function (x, t, b, c, d) {
162            return c*(t/=d)*t*t*t + b;
163        },
164        easeOutQuart: function (x, t, b, c, d) {
165            return -c * ((t=t/d-1)*t*t*t - 1) + b;
166        },
167        easeInOutQuart: function (x, t, b, c, d) {
168            if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
169            return -c/2 * ((t-=2)*t*t*t - 2) + b;
170        },
171        easeInQuint: function (x, t, b, c, d) {
172            return c*(t/=d)*t*t*t*t + b;
173        },
174        easeOutQuint: function (x, t, b, c, d) {
175            return c*((t=t/d-1)*t*t*t*t + 1) + b;
176        },
177        easeInOutQuint: function (x, t, b, c, d) {
178            if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
179            return c/2*((t-=2)*t*t*t*t + 2) + b;
180        },
181        easeInSine: function (x, t, b, c, d) {
182            return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
183        },
184        easeOutSine: function (x, t, b, c, d) {
185            return c * Math.sin(t/d * (Math.PI/2)) + b;
186        },
187        easeInOutSine: function (x, t, b, c, d) {
188            return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
189        },
190        easeInExpo: function (x, t, b, c, d) {
191            return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
192        },
193        easeOutExpo: function (x, t, b, c, d) {
194            return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
195        },
196        easeInOutExpo: function (x, t, b, c, d) {
197            if (t==0) return b;
198            if (t==d) return b+c;
199            if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
200            return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
201        },
202        easeInCirc: function (x, t, b, c, d) {
203            return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
204        },
205        easeOutCirc: function (x, t, b, c, d) {
206            return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
207        },
208        easeInOutCirc: function (x, t, b, c, d) {
209            if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
210            return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
211        },
212        easeInElastic: function (x, t, b, c, d) {
213            var s=1.70158;var p=0;var a=c;
214            if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
215            if (a < Math.abs(c)) { a=c; var s=p/4; }
216            else var s = p/(2*Math.PI) * Math.asin (c/a);
217            return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
218        },
219        easeOutElastic: function (x, t, b, c, d) {
220            var s=1.70158;var p=0;var a=c;
221            if (t==0) return b;  if ((t/=d)==1) return b+c;  if (!p) p=d*.3;
222            if (a < Math.abs(c)) { a=c; var s=p/4; }
223            else var s = p/(2*Math.PI) * Math.asin (c/a);
224            return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
225        },
226        easeInOutElastic: function (x, t, b, c, d) {
227            var s=1.70158;var p=0;var a=c;
228            if (t==0) return b;  if ((t/=d/2)==2) return b+c;  if (!p) p=d*(.3*1.5);
229            if (a < Math.abs(c)) { a=c; var s=p/4; }
230            else var s = p/(2*Math.PI) * Math.asin (c/a);
231            if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
232            return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
233        },
234        easeInBack: function (x, t, b, c, d, s) {
235            if (s == undefined) s = 1.70158;
236            return c*(t/=d)*t*((s+1)*t - s) + b;
237        },
238        easeOutBack: function (x, t, b, c, d, s) {
239            if (s == undefined) s = 1.70158;
240            return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
241        },
242        easeInOutBack: function (x, t, b, c, d, s) {
243            if (s == undefined) s = 1.70158;
244            if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
245            return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
246        },
247        easeInBounce: function (x, t, b, c, d) {
248            return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
249        },
250        easeOutBounce: function (x, t, b, c, d) {
251            if ((t/=d) < (1/2.75)) {
252                return c*(7.5625*t*t) + b;
253            } else if (t < (2/2.75)) {
254                return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
255            } else if (t < (2.5/2.75)) {
256                return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
257            } else {
258                return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
259            }
260        },
261        easeInOutBounce: function (x, t, b, c, d) {
262            if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
263            return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
264        }
265    });
266
267/*
268 *
269 * TERMS OF USE - EASING EQUATIONS
270 * 
271 * Open source under the BSD License. 
272 * 
273 * Copyright © 2001 Robert Penner
274 * All rights reserved.
275 * 
276 * Redistribution and use in source and binary forms, with or without modification, 
277 * are permitted provided that the following conditions are met:
278 * 
279 * Redistributions of source code must retain the above copyright notice, this list of 
280 * conditions and the following disclaimer.
281 * Redistributions in binary form must reproduce the above copyright notice, this list 
282 * of conditions and the following disclaimer in the documentation and/or other materials 
283 * provided with the distribution.
284 * 
285 * Neither the name of the author nor the names of contributors may be used to endorse 
286 * or promote products derived from this software without specific prior written permission.
287 * 
288 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
289 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
290 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
291 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
292 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
293 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 
294 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
295 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 
296 * OF THE POSSIBILITY OF SUCH DAMAGE. 
297 *
298 */
299
300/*! waitForImages jQuery Plugin - v2.4.0 - 2018-02-13
301* https://github.com/alexanderdickson/waitForImages
302* Copyright (c) 2018 Alex Dickson; Licensed MIT */
303;(function (factory) {
304    if (typeof define === 'function' && define.amd) {
305        // AMD. Register as an anonymous module.
306        define(['jquery'], factory);
307    } else if (typeof exports === 'object') {
308        // CommonJS / nodejs module
309        module.exports = factory(require('jquery'));
310    } else {
311        // Browser globals
312        factory(jQuery);
313    }
314}(function ($) {
315    // Namespace all events.
316    var eventNamespace = 'onImagesLoaded';
317
318    // Is srcset supported by this browser?
319    var hasSrcset = (function(img) {
320        return img.srcset && img.sizes;
321    })(new Image());
322
323    // CSS properties which contain references to images.
324    $.onImagesLoaded = {
325        hasImageProperties: [
326            'backgroundImage',
327            'listStyleImage',
328            'borderImage',
329            'borderCornerImage',
330            'cursor'
331        ],
332        hasImageAttributes: ['srcset']
333    };
334
335    // Custom selector to find all `img` elements with a valid `src` attribute.
336    $.expr.pseudos['has-src'] = function (obj) {
337        // Ensure we are dealing with an `img` element with a valid
338        // `src` attribute.
339        return $(obj).is('img[src][src!=""]');
340    };
341
342    // Custom selector to find images which are not already cached by the
343    // browser.
344    $.expr.pseudos.uncached = function (obj) {
345        // Ensure we are dealing with an `img` element with a valid
346        // `src` attribute.
347        if (!$(obj).is(':has-src')) {
348            return false;
349        }
350
351        return !obj.complete;
352    };
353
354    $.fn.onImagesLoaded = function () {
355
356        var allImgsLength = 0;
357        var allImgsLoaded = 0;
358        var deferred = $.Deferred();
359        var originalCollection = this;
360        var allImgs = [];
361
362        // CSS properties which may contain an image.
363        var hasImgProperties = $.onImagesLoaded.hasImageProperties || [];
364        // Element attributes which may contain an image.
365        var hasImageAttributes = $.onImagesLoaded
vendor: 5,767 bytes, lines 365-528
365.hasImageAttributes || [];
366        // To match `url()` references.
367        // Spec: http://www.w3.org/TR/CSS2/syndata.html#value-def-uri
368        var matchUrl = /url\(\s*(['"]?)(.*?)\1\s*\)/g;
369
370        var finishedCallback;
371        var eachCallback;
372        var waitForAll;
373
374        // Handle options object (if passed).
375        if ($.isPlainObject(arguments[0])) {
376
377            waitForAll = arguments[0].waitForAll;
378            eachCallback = arguments[0].each;
379            finishedCallback = arguments[0].finished;
380
381        } else {
382
383            // Handle if using deferred object and only one param was passed in.
384            if (arguments.length === 1 && $.type(arguments[0]) === 'boolean') {
385                waitForAll = arguments[0];
386            } else {
387                finishedCallback = arguments[0];
388                eachCallback = arguments[1];
389                waitForAll = arguments[2];
390            }
391
392        }
393
394        // Handle missing callbacks.
395        finishedCallback = finishedCallback || $.noop;
396        eachCallback = eachCallback || $.noop;
397
398        // Convert waitForAll to Boolean.
399        waitForAll = !! waitForAll;
400
401        // Ensure callbacks are functions.
402        if (!$.isFunction(finishedCallback) || !$.isFunction(eachCallback)) {
403            throw new TypeError('An invalid callback was supplied.');
404        }
405
406        this.each(function () {
407            // Build a list of all imgs, dependent on what images will
408            // be considered.
409            var obj = $(this);
410
411            if (waitForAll) {
412
413                // Get all elements (including the original), as any one of
414                // them could have a background image.
415                obj.find('*').addBack().each(function () {
416                    var element = $(this);
417
418                    // If an `img` element, add it. But keep iterating in
419                    // case it has a background image too.
420                    if (element.is('img:has-src') &&
421                        !element.is('[srcset]')) {
422                        allImgs.push({
423                            src: element.attr('src'),
424                            element: element[0]
425                        });
426                    }
427
428                    $.each(hasImgProperties, function (i, property) {
429                        var propertyValue = element.css(property);
430                        var match;
431
432                        // If it doesn't contain this property, skip.
433                        if (!propertyValue) {
434                            return true;
435                        }
436
437                        // Get all url() of this element.
438                        while (match = matchUrl.exec(propertyValue)) {
439                            allImgs.push({
440                                src: match[2],
441                                element: element[0]
442                            });
443                        }
444                    });
445
446                    $.each(hasImageAttributes, function (i, attribute) {
447                        var attributeValue = element.attr(attribute);
448                        var attributeValues;
449
450                        // If it doesn't contain this property, skip.
451                        if (!attributeValue) {
452                            return true;
453                        }
454
455                        allImgs.push({
456                            src: element.attr('src'),
457                            srcset: element.attr('srcset'),
458                            element: element[0]
459                        });
460                    });
461                });
462            } else {
463                // For images only, the task is simpler.
464                obj.find('img:has-src')
465                    .each(function () {
466                    allImgs.push({
467                        src: this.src,
468                        element: this
469                    });
470                });
471            }
472        });
473
474        allImgsLength = allImgs.length;
475        allImgsLoaded = 0;
476
477        // If no images found, don't bother.
478        if (allImgsLength === 0) {
479            finishedCallback.call(originalCollection);
480            deferred.resolveWith(originalCollection);
481        }
482
483        // Now that we've found all imgs in all elements in this,
484        // load them and attach callbacks.
485        $.each(allImgs, function (i, img) {
486
487            var image = new Image();
488            var events =
489              'load.' + eventNamespace + ' error.' + eventNamespace;
490
491            // Handle the image loading and error with the same callback.
492            $(image).one(events, function me (event) {
493                // If an error occurred with loading the image, set the
494                // third argument accordingly.
495                var eachArguments = [
496                    allImgsLoaded,
497                    allImgsLength,
498                    event.type == 'load'
499                ];
500                allImgsLoaded++;
501
502                eachCallback.apply(img.element, eachArguments);
503                deferred.notifyWith(img.element, eachArguments);
504
505                // Unbind the event listeners. I use this in addition to
506                // `one` as one of those events won't be called (either
507                // 'load' or 'error' will be called).
508                $(this).off(events, me);
509
510                if (allImgsLoaded == allImgsLength) {
511                    finishedCallback.call(originalCollection[0]);
512                    deferred.resolveWith(originalCollection[0]);
513                    return false;
514                }
515
516            });
517
518            if (hasSrcset && img.srcset) {
519                image.srcset = img.srcset;
520                image.sizes = img.sizes;
521            }
522            image.src = img.src;
523        });
524
525        return deferred.promise();
526
527    };
528}));
529
530
531
532/**
533 * Copyright 2016 Google Inc. All Rights Reserved.
534 *
535 * Licensed under the W3C SOFTWARE AND DOCUMENT NOTICE AND LICENSE.
536 *
537 *  https://www.w3.org/Consortium/Legal/2015/copyright-software-and-document
538 *
539 */
540
541(function(window, document) {
542'use strict';
543
544
545// Exits early if all IntersectionObserver and IntersectionObserverEntry
546// features are natively supported.
547if ('IntersectionObserver' in window &&
548    'IntersectionObserverEntry' in window &&
549    'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
550
551  // Minimal polyfill for Edge 15's lack of `isIntersecting`
552  // See: https://github.com/w3c/IntersectionObserver/issues/211
553  if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) {
554    Object.defineProperty(window.IntersectionObserverEntry.prototype,
555      'isIntersecting', {
556      get: function () {
557        return this.intersectionRatio > 0;
558      }
559    });
560  }
561  return;
562}
563
564
565/**
566 * An IntersectionObserver registry. This registry exists to hold a strong
567 * reference to IntersectionObserver instances currently observing a target
568 * element. Without this registry, instances without another reference may be
569 * garbage collected.
570 */
571var registry = [];
572
573
574/**
575 * Creates the global IntersectionObserverEntry constructor.
576 * https://w3c.github.io/IntersectionObserver/#intersection-observer-entry
577 * @param {Object} entry A dictionary of instance properties.
578 * @constructor
579 */
580function IntersectionObserverEntry(entry) {
581  this.time = entry.time;
582  this.target = entry.target;
583  this.rootBounds = entry.rootBounds;
584  this.boundingClientRect = entry.boundingClientRect;
585  this.intersectionRect = entry.intersectionRect || getEmptyRect();
586  this.isIntersecting = !!entry.intersectionRect;
587
588  // Calculates the intersection ratio.
589  var targetRect = this.boundingClientRect;
590  var targetArea = targetRect.width * targetRect.height;
591  var intersectionRect = this.intersectionRect;
592  var intersectionArea = intersectionRect.width * intersectionRect.height;
593
594  // Sets intersection ratio.
595  if (targetArea) {
596    // Round the intersection ratio to avoid floating point math issues:
597    // https://github.com/w3c/IntersectionObserver/issues/324
598    this.intersectionRatio = Number((intersectionArea / targetArea).toFixed(4));
599  } else {
600    // If area is zero and is intersecting, sets to 1, otherwise to 0
601    this.intersectionRatio = this.isIntersecting ? 1 : 0;
602  }
603}
604
605
606/**
607 * Creates the global IntersectionObserver constructor.
608 * https://w3c.github.io/IntersectionObserver/#intersection-observer-interface
609 * @param {Function} callback The function to be invoked after intersection
610 *     changes have queued. The function is not invoked if the queue has
611 *     been emptied by calling the `takeRecords` method.
612 * @param {Object=} opt_options Optional configuration options.
613 * @constructor
614 */
615function IntersectionObserver(callback, opt_options) {
616
617  var options = opt_options || {};
618
619  if (typeof callback != 'function') {
620    throw new Error('callback must be a function');
621  }
622
623  if (options.root && options.root.nodeType != 1) {
624    throw new Error('root must be an Element');
625  }
626
627  // Binds and throttles `this._checkForIntersections`.
628  this._checkForIntersections = throttle(
629      this._checkForIntersections.bind(this), this.THROTTLE_TIMEOUT);
630
631  // Private properties.
632  this._callback = callback;
633  this._observationTargets = [];
634  this._queuedEntries = [];
635  this._rootMarginValues = this._parseRootMargin(options.rootMargin);
636
637  // Public properties.
638  this.thresholds = this._initThresholds(options.threshold);
639  this.root = options.root || null;
640  this.rootMargin = this._rootMarginValues.map(function(margin) {
641    return margin.value + margin.unit;
642  }).join(' ');
643}
644
645
646/**
647 * The minimum interval within which the document will be checked for
648 * intersection changes.
649 */
650IntersectionObserver.prototype.THROTTLE_TIMEOUT = 100;
651
652
653/**
654 * The frequency in which the polyfill polls for intersection changes.
655 * this can be updated on a per instance basis and must be set prior to
656 * calling `observe` on the first target.
657 */
658IntersectionObserver.prototype.POLL_INTERVAL = null;
659
660/**
661 * Use a mutation observer on the root element
662 * to detect intersection changes.
663 */
664IntersectionObserver.prototype.USE_MUTATION_OBSERVER = true;
665
666
667/**
668 * Starts observing a target element for intersection changes based on
669 * the thresholds values.
670 * @param {Element} target The DOM element to observe.
671 */
672IntersectionObserver.prototype.observe = function(target) {
673  var isTargetAlreadyObserved = this._observationTargets.some(function(item) {
674    return item.element == target;
675  });
676
677  if (isTargetAlreadyObserved) {
678    return;
679  }
680
vendor: 2,303 bytes, lines 681-756
681  if (!(target && target.nodeType == 1)) {
682    throw new Error('target must be an Element');
683  }
684
685  this._registerInstance();
686  this._observationTargets.push({element: target, entry: null});
687  this._monitorIntersections();
688  this._checkForIntersections();
689};
690
691
692/**
693 * Stops observing a target element for intersection changes.
694 * @param {Element} target The DOM element to observe.
695 */
696IntersectionObserver.prototype.unobserve = function(target) {
697  this._observationTargets =
698      this._observationTargets.filter(function(item) {
699
700    return item.element != target;
701  });
702  if (!this._observationTargets.length) {
703    this._unmonitorIntersections();
704    this._unregisterInstance();
705  }
706};
707
708
709/**
710 * Stops observing all target elements for intersection changes.
711 */
712IntersectionObserver.prototype.disconnect = function() {
713  this._observationTargets = [];
714  this._unmonitorIntersections();
715  this._unregisterInstance();
716};
717
718
719/**
720 * Returns any queue entries that have not yet been reported to the
721 * callback and clears the queue. This can be used in conjunction with the
722 * callback to obtain the absolute most up-to-date intersection information.
723 * @return {Array} The currently queued entries.
724 */
725IntersectionObserver.prototype.takeRecords = function() {
726  var records = this._queuedEntries.slice();
727  this._queuedEntries = [];
728  return records;
729};
730
731
732/**
733 * Accepts the threshold value from the user configuration object and
734 * returns a sorted array of unique threshold values. If a value is not
735 * between 0 and 1 and error is thrown.
736 * @private
737 * @param {Array|number=} opt_threshold An optional threshold value or
738 *     a list of threshold values, defaulting to [0].
739 * @return {Array} A sorted list of unique and valid threshold values.
740 */
741IntersectionObserver.prototype._initThresholds = function(opt_threshold) {
742  var threshold = opt_threshold || [0];
743  if (!Array.isArray(threshold)) threshold = [threshold];
744
745  return threshold.sort().filter(function(t, i, a) {
746    if (typeof t != 'number' || isNaN(t) || t < 0 || t > 1) {
747      throw new Error('threshold must be a number between 0 and 1 inclusively');
748    }
749    return t !== a[i - 1];
750  });
751};
752
753
754/**
755 * Accepts the rootMargin value from the user configuration object
756 * and returns an array of the four margin values as an object c
756ontaining
757 * the value and unit properties. If any of the values are not properly
758 * formatted or use a unit other than px or %, and error is thrown.
759 * @private
760 * @param {string=} opt_rootMargin An optional rootMargin value,
761 *     defaulting to '0px'.
762 * @return {Array<Object>} An array of margin objects with the keys
763 *     value and unit.
764 */
765IntersectionObserver.prototype._parseRootMargin = function(opt_rootMargin) {
766  var marginString = opt_rootMargin || '0px';
767  var margins = marginString.split(/\s+/).map(function(margin) {
768    var parts = /^(-?\d*\.?\d+)(px|%)$/.exec(margin);
769    if (!parts) {
770      throw new Error('rootMargin must be specified in pixels or percent');
771    }
772    return {value: parseFloat(parts[1]), unit: parts[2]};
773  });
774
775  // Handles shorthand.
776  margins[1] = margins[1] || margins[0];
777  margins[2] = margins[2] || margins[0];
778  margins[3] = margins[3] || margins[1];
779
780  return margins;
781};
782
783
784/**
785 * Starts polling for intersection changes if the polling is not already
786 * happening, and if the page's visibility state is visible.
787 * @private
788 */
789IntersectionObserver.prototype._monitorIntersections = function() {
790  if (!this._monitoringIntersections) {
791    this._monitoringIntersections = true;
792
793    // If a poll interval is set, use polling instead of listening to
794    // resize and scroll events or DOM mutations.
795    if (this.POLL_INTERVAL) {
796      this._monitoringInterval = setInterval(
797          this._checkForIntersections, this.POLL_INTERVAL);
798    }
799    else {
800      addEvent(window, 'resize', this._checkForIntersections, true);
801      addEvent(document, 'scroll', this._checkForIntersections, true);
802
803      if (this.USE_MUTATION_OBSERVER && 'MutationObserver' in window) {
804        this._domObserver = new MutationObserver(this._checkForIntersections);
805        this._domObserver.observe(document, {
806          attributes: true,
807          childList: true,
808          characterData: true,
809          subtree: true
810        });
811      }
812    }
813  }
814};
815
816
817/**
818 * Stops polling for intersection changes.
819 * @private
820 */
821IntersectionObserver.prototype._unmonitorIntersections = function() {
822  if (this._monitoringIntersections) {
823    this._monitoringIntersections = false;
824
825    clearInterval(this._monitoringInterval);
826    this._monitoringInterval = null;
827
828    removeEvent(window, 'resize', this._checkForIntersections, true);
829    removeEvent(document, 'scroll', this._checkForIntersections, true);
830
831    if (this._domObserver) {
832      this._domObserver.disconnect();
833      this._domObserver = null;
834    }
835  }
836};
837
838
839/**
840 * Scans each observation target for intersection changes and adds them
841 * to the internal entries queue. If new entries are found, it
842 * schedules the callback to be invoked.
843 * @private
844 */
845IntersectionObserver.prototype._checkForIntersections = function() {
846  var rootIsInDom = this._rootIsInDom();
847  var rootRect = rootIsInDom ? this._getRootRect() : getEmptyRect();
848
849  this._observationTargets.forEach(function(item) {
850    var target = item.element;
851    var targetRect = getBoundingClientRect(target);
852    var rootContainsTarget = this._rootContainsTarget(target);
853    var oldEntry = item.entry;
854    var intersectionRect = rootIsInDom && rootContainsTarget &&
855        this._computeTargetAndRootIntersection(target, rootRect);
856
857    var newEntry = item.entry = new IntersectionObserverEntry({
858      time: now(),
859      target: target,
860      boundingClientRect: targetRect,
861      rootBounds: rootRect,
862      intersectionRect: intersectionRect
863    });
864
865    if (!oldEntry) {
866      this._queuedEntries.push(newEntry);
867    } else if (rootIsInDom && rootContainsTarget) {
868      // If the new entry intersection ratio has crossed any of the
869      // thresholds, add a new entry.
870      if (this._hasCrossedThreshold(oldEntry, newEntry)) {
871        this._queuedEntries.push(newEntry);
872      }
873    } else {
874      // If the root is not in the DOM or target is not contained within
875      // root but the previous entry for this target had an intersection,
876      // add a new record indicating removal.
877      if (oldEntry && oldEntry.isIntersecting) {
878        this._queuedEntries.push(newEntry);
879      }
880    }
881  }, this);
882
883  if (this._queuedEntries.length) {
884    this._callback(this.takeRecords(), this);
885  }
886};
887
888
889/**
890 * Accepts a target and root rect computes the intersection between then
891 * following the algorithm in the spec.
892 * TODO(philipwalton): at this time clip-path is not considered.
893 * https://w3c.github.io/IntersectionObserver/#calculate-intersection-rect-algo
894 * @param {Element} target The target DOM element
895 * @param {Object} rootRect The bounding rect of the root after being
896 *     expanded by the rootMargin value.
897 * @return {?Object} The final intersection rect object or undefined if no
898 *     intersection is found.
899 * @private
900 */
901IntersectionObserver.prototype._computeTargetAndRootIntersection =
902    function(target, rootRect) {
903
904  // If the element isn't displayed, an intersection can't happen.
905  if (window.getComputedStyle(target).display == 'none') return;
906
907  var targetRect = getBoundingClientRect(target);
908  var intersectionRect = targetRect;
909  var parent = getParentNode(target);
910  var atRoot = false;
vendor: 8,268 bytes, lines 911-1181
911
912  while (!atRoot) {
913    var parentRect = null;
914    var parentComputedStyle = parent.nodeType == 1 ?
915        window.getComputedStyle(parent) : {};
916
917    // If the parent isn't displayed, an intersection can't happen.
918    if (parentComputedStyle.display == 'none') return;
919
920    if (parent == this.root || parent == document) {
921      atRoot = true;
922      parentRect = rootRect;
923    } else {
924      // If the element has a non-visible overflow, and it's not the <body>
925      // or <html> element, update the intersection rect.
926      // Note: <body> and <html> cannot be clipped to a rect that's not also
927      // the document rect, so no need to compute a new intersection.
928      if (parent != document.body &&
929          parent != document.documentElement &&
930          parentComputedStyle.overflow != 'visible') {
931        parentRect = getBoundingClientRect(parent);
932      }
933    }
934
935    // If either of the above conditionals set a new parentRect,
936    // calculate new intersection data.
937    if (parentRect) {
938      intersectionRect = computeRectIntersection(parentRect, intersectionRect);
939
940      if (!intersectionRect) break;
941    }
942    parent = getParentNode(parent);
943  }
944  return intersectionRect;
945};
946
947
948/**
949 * Returns the root rect after being expanded by the rootMargin value.
950 * @return {Object} The expanded root rect.
951 * @private
952 */
953IntersectionObserver.prototype._getRootRect = function() {
954  var rootRect;
955  if (this.root) {
956    rootRect = getBoundingClientRect(this.root);
957  } else {
958    // Use <html>/<body> instead of window since scroll bars affect size.
959    var html = document.documentElement;
960    var body = document.body;
961    rootRect = {
962      top: 0,
963      left: 0,
964      right: html.clientWidth || body.clientWidth,
965      width: html.clientWidth || body.clientWidth,
966      bottom: html.clientHeight || body.clientHeight,
967      height: html.clientHeight || body.clientHeight
968    };
969  }
970  return this._expandRectByRootMargin(rootRect);
971};
972
973
974/**
975 * Accepts a rect and expands it by the rootMargin value.
976 * @param {Object} rect The rect object to expand.
977 * @return {Object} The expanded rect.
978 * @private
979 */
980IntersectionObserver.prototype._expandRectByRootMargin = function(rect) {
981  var margins = this._rootMarginValues.map(function(margin, i) {
982    return margin.unit == 'px' ? margin.value :
983        margin.value * (i % 2 ? rect.width : rect.height) / 100;
984  });
985  var newRect = {
986    top: rect.top - margins[0],
987    right: rect.right + margins[1],
988    bottom: rect.bottom + margins[2],
989    left: rect.left - margins[3]
990  };
991  newRect.width = newRect.right - newRect.left;
992  newRect.height = newRect.bottom - newRect.top;
993
994  return newRect;
995};
996
997
998/**
999 * Accepts an old and new entry and returns true if at least one of the
1000 * threshold values has been crossed.
1001 * @param {?IntersectionObserverEntry} oldEntry The previous entry for a
1002 *    particular target element or null if no previous entry exists.
1003 * @param {IntersectionObserverEntry} newEntry The current entry for a
1004 *    particular target element.
1005 * @return {boolean} Returns true if a any threshold has been crossed.
1006 * @private
1007 */
1008IntersectionObserver.prototype._hasCrossedThreshold =
1009    function(oldEntry, newEntry) {
1010
1011  // To make comparing easier, an entry that has a ratio of 0
1012  // but does not actually intersect is given a value of -1
1013  var oldRatio = oldEntry && oldEntry.isIntersecting ?
1014      oldEntry.intersectionRatio || 0 : -1;
1015  var newRatio = newEntry.isIntersecting ?
1016      newEntry.intersectionRatio || 0 : -1;
1017
1018  // Ignore unchanged ratios
1019  if (oldRatio === newRatio) return;
1020
1021  for (var i = 0; i < this.thresholds.length; i++) {
1022    var threshold = this.thresholds[i];
1023
1024    // Return true if an entry matches a threshold or if the new ratio
1025    // and the old ratio are on the opposite sides of a threshold.
1026    if (threshold == oldRatio || threshold == newRatio ||
1027        threshold < oldRatio !== threshold < newRatio) {
1028      return true;
1029    }
1030  }
1031};
1032
1033
1034/**
1035 * Returns whether or not the root element is an element and is in the DOM.
1036 * @return {boolean} True if the root element is an element and is in the DOM.
1037 * @private
1038 */
1039IntersectionObserver.prototype._rootIsInDom = function() {
1040  return !this.root || containsDeep(document, this.root);
1041};
1042
1043
1044/**
1045 * Returns whether or not the target element is a child of root.
1046 * @param {Element} target The target element to check.
1047 * @return {boolean} True if the target element is a child of root.
1048 * @private
1049 */
1050IntersectionObserver.prototype._rootContainsTarget = function(target) {
1051  return containsDeep(this.root || document, target);
1052};
1053
1054
1055/**
1056 * Adds the instance to the global IntersectionObserver registry if it isn't
1057 * already present.
1058 * @private
1059 */
1060IntersectionObserver.prototype._registerInstance = function() {
1061  if (registry.indexOf(this) < 0) {
1062    registry.push(this);
1063  }
1064};
1065
1066
1067/**
1068 * Removes the instance from the global IntersectionObserver registry.
1069 * @private
1070 */
1071IntersectionObserver.prototype._unregisterInstance = function() {
1072  var index = registry.indexOf(this);
1073  if (index != -1) registry.splice(index, 1);
1074};
1075
1076
1077/**
1078 * Returns the result of the performance.now() method or null in browsers
1079 * that don't support the API.
1080 * @return {number} The elapsed time since the page was requested.
1081 */
1082function now() {
1083  return window.performance && performance.now && performance.now();
1084}
1085
1086
1087/**
1088 * Throttles a function and delays its execution, so it's only called at most
1089 * once within a given time period.
1090 * @param {Function} fn The function to throttle.
1091 * @param {number} timeout The amount of time that must pass before the
1092 *     function can be called again.
1093 * @return {Function} The throttled function.
1094 */
1095function throttle(fn, timeout) {
1096  var timer = null;
1097  return function () {
1098    if (!timer) {
1099      timer = setTimeout(function() {
1100        fn();
1101        timer = null;
1102      }, timeout);
1103    }
1104  };
1105}
1106
1107
1108/**
1109 * Adds an event handler to a DOM node ensuring cross-browser compatibility.
1110 * @param {Node} node The DOM node to add the event handler to.
1111 * @param {string} event The event name.
1112 * @param {Function} fn The event handler to add.
1113 * @param {boolean} opt_useCapture Optionally adds the even to the capture
1114 *     phase. Note: this only works in modern browsers.
1115 */
1116function addEvent(node, event, fn, opt_useCapture) {
1117  if (typeof node.addEventListener == 'function') {
1118    node.addEventListener(event, fn, opt_useCapture || false);
1119  }
1120  else if (typeof node.attachEvent == 'function') {
1121    node.attachEvent('on' + event, fn);
1122  }
1123}
1124
1125
1126/**
1127 * Removes a previously added event handler from a DOM node.
1128 * @param {Node} node The DOM node to remove the event handler from.
1129 * @param {string} event The event name.
1130 * @param {Function} fn The event handler to remove.
1131 * @param {boolean} opt_useCapture If the event handler was added with this
1132 *     flag set to true, it should be set to true here in order to remove it.
1133 */
1134function removeEvent(node, event, fn, opt_useCapture) {
1135  if (typeof node.removeEventListener == 'function') {
1136    node.removeEventListener(event, fn, opt_useCapture || false);
1137  }
1138  else if (typeof node.detatchEvent == 'function') {
1139    node.detatchEvent('on' + event, fn);
1140  }
1141}
1142
1143
1144/**
1145 * Returns the intersection between two rect objects.
1146 * @param {Object} rect1 The first rect.
1147 * @param {Object} rect2 The second rect.
1148 * @return {?Object} The intersection rect or undefined if no intersection
1149 *     is found.
1150 */
1151function computeRectIntersection(rect1, rect2) {
1152  var top = Math.max(rect1.top, rect2.top);
1153  var bottom = Math.min(rect1.bottom, rect2.bottom);
1154  var left = Math.max(rect1.left, rect2.left);
1155  var right = Math.min(rect1.right, rect2.right);
1156  var width = right - left;
1157  var height = bottom - top;
1158
1159  return (width >= 0 && height >= 0) && {
1160    top: top,
1161    bottom: bottom,
1162    left: left,
1163    right: right,
1164    width: width,
1165    height: height
1166  };
1167}
1168
1169
1170/**
1171 * Shims the native getBoundingClientRect for compatibility with older IE.
1172 * @param {Element} el The element whose bounding rect to get.
1173 * @return {Object} The (possibly shimmed) rect of the element.
1174 */
1175function getBoundingClientRect(el) {
1176  var rect;
1177
1178  try {
1179    rect = el.getBoundingClientRect();
1180  } catch (err) {
1181    // Ignore Windows 7 IE11 "Unspecified error"
1182    // https://github.com/w3c/IntersectionObserver/pull/205
1183  }
1184
1185  if (!rect) return getEmptyRect();
1186
1187  // Older IE
1188  if (!(rect.width && rect.height)) {
1189    rect = {
1190      top: rect.top,
1191      right: rect.right,
1192      bottom: rect.bottom,
1193      left: rect.left,
1194      width: rect.right - rect.left,
1195      height: rect.bottom - rect.top
1196    };
1197  }
1198  return rect;
1199}
1200
1201
1202/**
1203 * Returns an empty rect object. An empty rect is returned when an element
1204 * is not in the DOM.
1205 * @return {Object} The empty rect.
1206 */
1207function getEmptyRect() {
1208  return {
1209    top: 0,
1210    bottom: 0,
1211    left: 0,
1212    right: 0,
1213    width: 0,
1214    height: 0
1215  };
1216}
1217
1218/**
1219 * Checks to see if a parent element contains a child element (including inside
1220 * shadow DOM).
1221 * @param {Node} parent The parent element.
1222 * @param {Node} child The child element.
1223 * @return {boolean} True if the parent node contains the child node.
1224 */
1225function containsDeep(parent, child) {
1226  var node = child;
1227  while (node) {
1228    if (node == parent) return true;
1229
1230    node = getParentNode(node);
1231  }
1232  return false;
1233}
1234
1235
1236/**
1237 * Gets the parent node of an element or its host element if the parent node
1238 * is a shadow root.
1239 * @param {Node} node The node whose parent to get.
1240 * @return {Node|null} The parent node or null if no parent exists.
1241 */
1242function getParentNode(node) {
1243  var parent = node.parentNode;
1244
1245  if (parent && parent.nodeType == 11 && parent.host) {
1246    // If the parent is a shadow root, return the host element.
1247    return parent.host;
1248  }
1249
1250  if (parent && parent.assignedSlot) {
1251    // If the parent is distributed in a <slot>, return the parent of a slot.
1252    return parent.assignedSlot.parentNode;
1253  }
1254
1255  return parent;
1256}
1257
1258
1259// Exposes the constructors globally.
1260window.IntersectionObserver = IntersectionObserver;
1261window.IntersectionObserverEntry = IntersectionObserverEntry;
1262
1263}(window, document));

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.