PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.3.2
Responsive Lightbox & Gallery v2.3.2
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / assets / infinitescroll / infinite-scroll.pkgd.js
responsive-lightbox / assets / infinitescroll Last commit date
infinite-scroll.pkgd.js 5 years ago infinite-scroll.pkgd.min.js 5 years ago
infinite-scroll.pkgd.js
2223 lines
1 /*!
2 * Infinite Scroll PACKAGED v3.0.6
3 * Automatically add next page
4 *
5 * Licensed GPLv3 for open source use
6 * or Infinite Scroll Commercial License for commercial use
7 *
8 * https://infinite-scroll.com
9 * Copyright 2018 Metafizzy
10 */
11
12 /**
13 * Bridget makes jQuery widgets
14 * v2.0.1
15 * MIT license
16 */
17
18 /* jshint browser: true, strict: true, undef: true, unused: true */
19
20 ( function( window, factory ) {
21 // universal module definition
22 /*jshint strict: false */ /* globals define, module, require */
23 if ( typeof define == 'function' && define.amd ) {
24 // AMD
25 define( 'jquery-bridget/jquery-bridget',[ 'jquery' ], function( jQuery ) {
26 return factory( window, jQuery );
27 });
28 } else if ( typeof module == 'object' && module.exports ) {
29 // CommonJS
30 module.exports = factory(
31 window,
32 require('jquery')
33 );
34 } else {
35 // browser global
36 window.jQueryBridget = factory(
37 window,
38 window.jQuery
39 );
40 }
41
42 }( window, function factory( window, jQuery ) {
43 'use strict';
44
45 // ----- utils ----- //
46
47 var arraySlice = Array.prototype.slice;
48
49 // helper function for logging errors
50 // $.error breaks jQuery chaining
51 var console = window.console;
52 var logError = typeof console == 'undefined' ? function() {} :
53 function( message ) {
54 console.error( message );
55 };
56
57 // ----- jQueryBridget ----- //
58
59 function jQueryBridget( namespace, PluginClass, $ ) {
60 $ = $ || jQuery || window.jQuery;
61 if ( !$ ) {
62 return;
63 }
64
65 // add option method -> $().plugin('option', {...})
66 if ( !PluginClass.prototype.option ) {
67 // option setter
68 PluginClass.prototype.option = function( opts ) {
69 // bail out if not an object
70 if ( !$.isPlainObject( opts ) ){
71 return;
72 }
73 this.options = $.extend( true, this.options, opts );
74 };
75 }
76
77 // make jQuery plugin
78 $.fn[ namespace ] = function( arg0 /*, arg1 */ ) {
79 if ( typeof arg0 == 'string' ) {
80 // method call $().plugin( 'methodName', { options } )
81 // shift arguments by 1
82 var args = arraySlice.call( arguments, 1 );
83 return methodCall( this, arg0, args );
84 }
85 // just $().plugin({ options })
86 plainCall( this, arg0 );
87 return this;
88 };
89
90 // $().plugin('methodName')
91 function methodCall( $elems, methodName, args ) {
92 var returnValue;
93 var pluginMethodStr = '$().' + namespace + '("' + methodName + '")';
94
95 $elems.each( function( i, elem ) {
96 // get instance
97 var instance = $.data( elem, namespace );
98 if ( !instance ) {
99 logError( namespace + ' not initialized. Cannot call methods, i.e. ' +
100 pluginMethodStr );
101 return;
102 }
103
104 var method = instance[ methodName ];
105 if ( !method || methodName.charAt(0) == '_' ) {
106 logError( pluginMethodStr + ' is not a valid method' );
107 return;
108 }
109
110 // apply method, get return value
111 var value = method.apply( instance, args );
112 // set return value if value is returned, use only first value
113 returnValue = returnValue === undefined ? value : returnValue;
114 });
115
116 return returnValue !== undefined ? returnValue : $elems;
117 }
118
119 function plainCall( $elems, options ) {
120 $elems.each( function( i, elem ) {
121 var instance = $.data( elem, namespace );
122 if ( instance ) {
123 // set options & init
124 instance.option( options );
125 instance._init();
126 } else {
127 // initialize new instance
128 instance = new PluginClass( elem, options );
129 $.data( elem, namespace, instance );
130 }
131 });
132 }
133
134 updateJQuery( $ );
135
136 }
137
138 // ----- updateJQuery ----- //
139
140 // set $.bridget for v1 backwards compatibility
141 function updateJQuery( $ ) {
142 if ( !$ || ( $ && $.bridget ) ) {
143 return;
144 }
145 $.bridget = jQueryBridget;
146 }
147
148 updateJQuery( jQuery || window.jQuery );
149
150 // ----- ----- //
151
152 return jQueryBridget;
153
154 }));
155
156 /**
157 * EvEmitter v1.1.0
158 * Lil' event emitter
159 * MIT License
160 */
161
162 /* jshint unused: true, undef: true, strict: true */
163
164 ( function( global, factory ) {
165 // universal module definition
166 /* jshint strict: false */ /* globals define, module, window */
167 if ( typeof define == 'function' && define.amd ) {
168 // AMD - RequireJS
169 define( 'ev-emitter/ev-emitter',factory );
170 } else if ( typeof module == 'object' && module.exports ) {
171 // CommonJS - Browserify, Webpack
172 module.exports = factory();
173 } else {
174 // Browser globals
175 global.EvEmitter = factory();
176 }
177
178 }( typeof window != 'undefined' ? window : this, function() {
179
180
181
182 function EvEmitter() {}
183
184 var proto = EvEmitter.prototype;
185
186 proto.on = function( eventName, listener ) {
187 if ( !eventName || !listener ) {
188 return;
189 }
190 // set events hash
191 var events = this._events = this._events || {};
192 // set listeners array
193 var listeners = events[ eventName ] = events[ eventName ] || [];
194 // only add once
195 if ( listeners.indexOf( listener ) == -1 ) {
196 listeners.push( listener );
197 }
198
199 return this;
200 };
201
202 proto.once = function( eventName, listener ) {
203 if ( !eventName || !listener ) {
204 return;
205 }
206 // add event
207 this.on( eventName, listener );
208 // set once flag
209 // set onceEvents hash
210 var onceEvents = this._onceEvents = this._onceEvents || {};
211 // set onceListeners object
212 var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};
213 // set flag
214 onceListeners[ listener ] = true;
215
216 return this;
217 };
218
219 proto.off = function( eventName, listener ) {
220 var listeners = this._events && this._events[ eventName ];
221 if ( !listeners || !listeners.length ) {
222 return;
223 }
224 var index = listeners.indexOf( listener );
225 if ( index != -1 ) {
226 listeners.splice( index, 1 );
227 }
228
229 return this;
230 };
231
232 proto.emitEvent = function( eventName, args ) {
233 var listeners = this._events && this._events[ eventName ];
234 if ( !listeners || !listeners.length ) {
235 return;
236 }
237 // copy over to avoid interference if .off() in listener
238 listeners = listeners.slice(0);
239 args = args || [];
240 // once stuff
241 var onceListeners = this._onceEvents && this._onceEvents[ eventName ];
242
243 for ( var i=0; i < listeners.length; i++ ) {
244 var listener = listeners[i]
245 var isOnce = onceListeners && onceListeners[ listener ];
246 if ( isOnce ) {
247 // remove listener
248 // remove before trigger to prevent recursion
249 this.off( eventName, listener );
250 // unset once flag
251 delete onceListeners[ listener ];
252 }
253 // trigger listener
254 listener.apply( this, args );
255 }
256
257 return this;
258 };
259
260 proto.allOff = function() {
261 delete this._events;
262 delete this._onceEvents;
263 };
264
265 return EvEmitter;
266
267 }));
268
269 /**
270 * matchesSelector v2.0.2
271 * matchesSelector( element, '.selector' )
272 * MIT license
273 */
274
275 /*jshint browser: true, strict: true, undef: true, unused: true */
276
277 ( function( window, factory ) {
278 /*global define: false, module: false */
279 'use strict';
280 // universal module definition
281 if ( typeof define == 'function' && define.amd ) {
282 // AMD
283 define( 'desandro-matches-selector/matches-selector',factory );
284 } else if ( typeof module == 'object' && module.exports ) {
285 // CommonJS
286 module.exports = factory();
287 } else {
288 // browser global
289 window.matchesSelector = factory();
290 }
291
292 }( window, function factory() {
293 'use strict';
294
295 var matchesMethod = ( function() {
296 var ElemProto = window.Element.prototype;
297 // check for the standard method name first
298 if ( ElemProto.matches ) {
299 return 'matches';
300 }
301 // check un-prefixed
302 if ( ElemProto.matchesSelector ) {
303 return 'matchesSelector';
304 }
305 // check vendor prefixes
306 var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];
307
308 for ( var i=0; i < prefixes.length; i++ ) {
309 var prefix = prefixes[i];
310 var method = prefix + 'MatchesSelector';
311 if ( ElemProto[ method ] ) {
312 return method;
313 }
314 }
315 })();
316
317 return function matchesSelector( elem, selector ) {
318 return elem[ matchesMethod ]( selector );
319 };
320
321 }));
322
323 /**
324 * Fizzy UI utils v2.0.7
325 * MIT license
326 */
327
328 /*jshint browser: true, undef: true, unused: true, strict: true */
329
330 ( function( window, factory ) {
331 // universal module definition
332 /*jshint strict: false */ /*globals define, module, require */
333
334 if ( typeof define == 'function' && define.amd ) {
335 // AMD
336 define( 'fizzy-ui-utils/utils',[
337 'desandro-matches-selector/matches-selector'
338 ], function( matchesSelector ) {
339 return factory( window, matchesSelector );
340 });
341 } else if ( typeof module == 'object' && module.exports ) {
342 // CommonJS
343 module.exports = factory(
344 window,
345 require('desandro-matches-selector')
346 );
347 } else {
348 // browser global
349 window.fizzyUIUtils = factory(
350 window,
351 window.matchesSelector
352 );
353 }
354
355 }( window, function factory( window, matchesSelector ) {
356
357
358
359 var utils = {};
360
361 // ----- extend ----- //
362
363 // extends objects
364 utils.extend = function( a, b ) {
365 for ( var prop in b ) {
366 a[ prop ] = b[ prop ];
367 }
368 return a;
369 };
370
371 // ----- modulo ----- //
372
373 utils.modulo = function( num, div ) {
374 return ( ( num % div ) + div ) % div;
375 };
376
377 // ----- makeArray ----- //
378
379 var arraySlice = Array.prototype.slice;
380
381 // turn element or nodeList into an array
382 utils.makeArray = function( obj ) {
383 if ( Array.isArray( obj ) ) {
384 // use object if already an array
385 return obj;
386 }
387 // return empty array if undefined or null. #6
388 if ( obj === null || obj === undefined ) {
389 return [];
390 }
391
392 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
393 if ( isArrayLike ) {
394 // convert nodeList to array
395 return arraySlice.call( obj );
396 }
397
398 // array of single index
399 return [ obj ];
400 };
401
402 // ----- removeFrom ----- //
403
404 utils.removeFrom = function( ary, obj ) {
405 var index = ary.indexOf( obj );
406 if ( index != -1 ) {
407 ary.splice( index, 1 );
408 }
409 };
410
411 // ----- getParent ----- //
412
413 utils.getParent = function( elem, selector ) {
414 while ( elem.parentNode && elem != document.body ) {
415 elem = elem.parentNode;
416 if ( matchesSelector( elem, selector ) ) {
417 return elem;
418 }
419 }
420 };
421
422 // ----- getQueryElement ----- //
423
424 // use element as selector string
425 utils.getQueryElement = function( elem ) {
426 if ( typeof elem == 'string' ) {
427 return document.querySelector( elem );
428 }
429 return elem;
430 };
431
432 // ----- handleEvent ----- //
433
434 // enable .ontype to trigger from .addEventListener( elem, 'type' )
435 utils.handleEvent = function( event ) {
436 var method = 'on' + event.type;
437 if ( this[ method ] ) {
438 this[ method ]( event );
439 }
440 };
441
442 // ----- filterFindElements ----- //
443
444 utils.filterFindElements = function( elems, selector ) {
445 // make array of elems
446 elems = utils.makeArray( elems );
447 var ffElems = [];
448
449 elems.forEach( function( elem ) {
450 // check that elem is an actual element
451 if ( !( elem instanceof HTMLElement ) ) {
452 return;
453 }
454 // add elem if no selector
455 if ( !selector ) {
456 ffElems.push( elem );
457 return;
458 }
459 // filter & find items if we have a selector
460 // filter
461 if ( matchesSelector( elem, selector ) ) {
462 ffElems.push( elem );
463 }
464 // find children
465 var childElems = elem.querySelectorAll( selector );
466 // concat childElems to filterFound array
467 for ( var i=0; i < childElems.length; i++ ) {
468 ffElems.push( childElems[i] );
469 }
470 });
471
472 return ffElems;
473 };
474
475 // ----- debounceMethod ----- //
476
477 utils.debounceMethod = function( _class, methodName, threshold ) {
478 threshold = threshold || 100;
479 // original method
480 var method = _class.prototype[ methodName ];
481 var timeoutName = methodName + 'Timeout';
482
483 _class.prototype[ methodName ] = function() {
484 var timeout = this[ timeoutName ];
485 clearTimeout( timeout );
486
487 var args = arguments;
488 var _this = this;
489 this[ timeoutName ] = setTimeout( function() {
490 method.apply( _this, args );
491 delete _this[ timeoutName ];
492 }, threshold );
493 };
494 };
495
496 // ----- docReady ----- //
497
498 utils.docReady = function( callback ) {
499 var readyState = document.readyState;
500 if ( readyState == 'complete' || readyState == 'interactive' ) {
501 // do async to allow for other scripts to run. metafizzy/flickity#441
502 setTimeout( callback );
503 } else {
504 document.addEventListener( 'DOMContentLoaded', callback );
505 }
506 };
507
508 // ----- htmlInit ----- //
509
510 // http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/
511 utils.toDashed = function( str ) {
512 return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {
513 return $1 + '-' + $2;
514 }).toLowerCase();
515 };
516
517 var console = window.console;
518 /**
519 * allow user to initialize classes via [data-namespace] or .js-namespace class
520 * htmlInit( Widget, 'widgetName' )
521 * options are parsed from data-namespace-options
522 */
523 utils.htmlInit = function( WidgetClass, namespace ) {
524 utils.docReady( function() {
525 var dashedNamespace = utils.toDashed( namespace );
526 var dataAttr = 'data-' + dashedNamespace;
527 var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );
528 var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );
529 var elems = utils.makeArray( dataAttrElems )
530 .concat( utils.makeArray( jsDashElems ) );
531 var dataOptionsAttr = dataAttr + '-options';
532 var jQuery = window.jQuery;
533
534 elems.forEach( function( elem ) {
535 var attr = elem.getAttribute( dataAttr ) ||
536 elem.getAttribute( dataOptionsAttr );
537 var options;
538 try {
539 options = attr && JSON.parse( attr );
540 } catch ( error ) {
541 // log error, do not initialize
542 if ( console ) {
543 console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +
544 ': ' + error );
545 }
546 return;
547 }
548 // initialize
549 var instance = new WidgetClass( elem, options );
550 // make available via $().data('namespace')
551 if ( jQuery ) {
552 jQuery.data( elem, namespace, instance );
553 }
554 });
555
556 });
557 };
558
559 // ----- ----- //
560
561 return utils;
562
563 }));
564
565 // core
566 ( function( window, factory ) {
567 // universal module definition
568 /* globals define, module, require */
569 if ( typeof define == 'function' && define.amd ) {
570 // AMD
571 define( 'infinite-scroll/js/core',[
572 'ev-emitter/ev-emitter',
573 'fizzy-ui-utils/utils',
574 ], function( EvEmitter, utils) {
575 return factory( window, EvEmitter, utils );
576 });
577 } else if ( typeof module == 'object' && module.exports ) {
578 // CommonJS
579 module.exports = factory(
580 window,
581 require('ev-emitter'),
582 require('fizzy-ui-utils')
583 );
584 } else {
585 // browser global
586 window.InfiniteScroll = factory(
587 window,
588 window.EvEmitter,
589 window.fizzyUIUtils
590 );
591 }
592
593 }( window, function factory( window, EvEmitter, utils ) {
594
595 var jQuery = window.jQuery;
596 // internal store of all InfiniteScroll intances
597 var instances = {};
598
599 function InfiniteScroll( element, options ) {
600 var queryElem = utils.getQueryElement( element );
601
602 if ( !queryElem ) {
603 console.error( 'Bad element for InfiniteScroll: ' + ( queryElem || element ) );
604 return;
605 }
606 element = queryElem;
607 // do not initialize twice on same element
608 if ( element.infiniteScrollGUID ) {
609 var instance = instances[ element.infiniteScrollGUID ];
610 instance.option( options );
611 return instance;
612 }
613
614 this.element = element;
615 // options
616 this.options = utils.extend( {}, InfiniteScroll.defaults );
617 this.option( options );
618 // add jQuery
619 if ( jQuery ) {
620 this.$element = jQuery( this.element );
621 }
622
623 this.create();
624 }
625
626 // defaults
627 InfiniteScroll.defaults = {
628 // path: null,
629 // hideNav: null,
630 // debug: false,
631 };
632
633 // create & destroy methods
634 InfiniteScroll.create = {};
635 InfiniteScroll.destroy = {};
636
637 var proto = InfiniteScroll.prototype;
638 // inherit EvEmitter
639 utils.extend( proto, EvEmitter.prototype );
640
641 // -------------------------- -------------------------- //
642
643 // globally unique identifiers
644 var GUID = 0;
645
646 proto.create = function() {
647 // create core
648 // add id for InfiniteScroll.data
649 var id = this.guid = ++GUID;
650 this.element.infiniteScrollGUID = id; // expando
651 instances[ id ] = this; // associate via id
652 // properties
653 this.pageIndex = 1; // default to first page
654 this.loadCount = 0;
655 this.updateGetPath();
656 // bail if getPath not set, or returns falsey #776
657 var hasPath = this.getPath && this.getPath();
658 if ( !hasPath ) {
659 console.error('Disabling InfiniteScroll');
660 return;
661 }
662 this.updateGetAbsolutePath();
663 this.log( 'initialized', [ this.element.className ] );
664 this.callOnInit();
665 // create features
666 for ( var method in InfiniteScroll.create ) {
667 InfiniteScroll.create[ method ].call( this );
668 }
669 };
670
671 proto.option = function( opts ) {
672 utils.extend( this.options, opts );
673 };
674
675 // call onInit option, used for binding events on init
676 proto.callOnInit = function() {
677 var onInit = this.options.onInit;
678 if ( onInit ) {
679 onInit.call( this, this );
680 }
681 };
682
683 // ----- events ----- //
684
685 proto.dispatchEvent = function( type, event, args ) {
686 this.log( type, args );
687 var emitArgs = event ? [ event ].concat( args ) : args;
688 this.emitEvent( type, emitArgs );
689 // trigger jQuery event
690 if ( !jQuery || !this.$element ) {
691 return;
692 }
693 // namespace jQuery event
694 type += '.infiniteScroll';
695 var $event = type;
696 if ( event ) {
697 // create jQuery event
698 var jQEvent = jQuery.Event( event );
699 jQEvent.type = type;
700 $event = jQEvent;
701 }
702 this.$element.trigger( $event, args );
703 };
704
705 var loggers = {
706 initialized: function( className ) {
707 return 'on ' + className;
708 },
709 request: function( path ) {
710 return 'URL: ' + path;
711 },
712 load: function( response, path ) {
713 return ( response.title || '' ) + '. URL: ' + path;
714 },
715 error: function( error, path ) {
716 return error + '. URL: ' + path;
717 },
718 append: function( response, path, items ) {
719 return items.length + ' items. URL: ' + path;
720 },
721 last: function( response, path ) {
722 return 'URL: ' + path;
723 },
724 history: function( title, path ) {
725 return 'URL: ' + path;
726 },
727 pageIndex: function( index, origin ) {
728 return 'current page determined to be: ' + index + ' from ' + origin;
729 },
730 };
731
732 // log events
733 proto.log = function( type, args ) {
734 if ( !this.options.debug ) {
735 return;
736 }
737 var message = '[InfiniteScroll] ' + type;
738 var logger = loggers[ type ];
739 if ( logger ) {
740 message += '. ' + logger.apply( this, args );
741 }
742 console.log( message );
743 };
744
745 // -------------------------- methods used amoung features -------------------------- //
746
747 proto.updateMeasurements = function() {
748 this.windowHeight = window.innerHeight;
749 var rect = this.element.getBoundingClientRect();
750 this.top = rect.top + window.pageYOffset;
751 };
752
753 proto.updateScroller = function() {
754 var elementScroll = this.options.elementScroll;
755 if ( !elementScroll ) {
756 // default, use window
757 this.scroller = window;
758 return;
759 }
760 // if true, set to element, otherwise use option
761 this.scroller = elementScroll === true ? this.element :
762 utils.getQueryElement( elementScroll );
763 if ( !this.scroller ) {
764 throw 'Unable to find elementScroll: ' + elementScroll;
765 }
766 };
767
768 // -------------------------- page path -------------------------- //
769
770 proto.updateGetPath = function() {
771 var optPath = this.options.path;
772 if ( !optPath ) {
773 console.error( 'InfiniteScroll path option required. Set as: ' + optPath );
774 return;
775 }
776 // function
777 var type = typeof optPath;
778 if ( type == 'function' ) {
779 this.getPath = optPath;
780 return;
781 }
782 // template string: '/pages/{{#}}.html'
783 var templateMatch = type == 'string' && optPath.match('{{#}}');
784 if ( templateMatch ) {
785 this.updateGetPathTemplate( optPath );
786 return;
787 }
788 // selector: '.next-page-selector'
789 this.updateGetPathSelector( optPath );
790 };
791
792 proto.updateGetPathTemplate = function( optPath ) {
793 // set getPath with template string
794 this.getPath = function() {
795 var nextIndex = this.pageIndex + 1;
796 return optPath.replace( '{{#}}', nextIndex );
797 }.bind( this );
798 // get pageIndex from location
799 // convert path option into regex to look for pattern in location
800 // escape query (?) in url, allows for parsing GET parameters
801 var regexString = optPath
802 .replace( /(\\\?|\?)/, '\\?' )
803 .replace( '{{#}}', '(\\d\\d?\\d?)' );
804 var templateRe = new RegExp( regexString );
805 var match = location.href.match( templateRe );
806
807 if ( match ) {
808 this.pageIndex = parseInt( match[1], 10 );
809 this.log( 'pageIndex', [ this.pageIndex, 'template string' ] );
810 }
811 };
812
813 var pathRegexes = [
814 // WordPress & Tumblr - example.com/page/2
815 // Jekyll - example.com/page2
816 /^(.*?\/?page\/?)(\d\d?\d?)(.*?$)/,
817 // Drupal - example.com/?page=1
818 /^(.*?\/?\?page=)(\d\d?\d?)(.*?$)/,
819 // catch all, last occurence of a number
820 /(.*?)(\d\d?\d?)(?!.*\d)(.*?$)/,
821 ];
822
823 proto.updateGetPathSelector = function( optPath ) {
824 // parse href of link: '.next-page-link'
825 var hrefElem = document.querySelector( optPath );
826 if ( !hrefElem ) {
827 console.error( 'Bad InfiniteScroll path option. Next link not found: ' +
828 optPath );
829 return;
830 }
831 var href = hrefElem.getAttribute('href');
832 // try matching href to pathRegexes patterns
833 var pathParts, regex;
834 for ( var i=0; href && i < pathRegexes.length; i++ ) {
835 regex = pathRegexes[i];
836 var match = href.match( regex );
837 if ( match ) {
838 pathParts = match.slice(1); // remove first part
839 break;
840 }
841 }
842 if ( !pathParts ) {
843 console.error( 'InfiniteScroll unable to parse next link href: ' + href );
844 return;
845 }
846 this.isPathSelector = true; // flag for checkLastPage()
847 this.getPath = function() {
848 var nextIndex = this.pageIndex + 1;
849 return pathParts[0] + nextIndex + pathParts[2];
850 }.bind( this );
851 // get pageIndex from href
852 this.pageIndex = parseInt( pathParts[1], 10 ) - 1;
853 this.log( 'pageIndex', [ this.pageIndex, 'next link' ] );
854 };
855
856 proto.updateGetAbsolutePath = function() {
857 var path = this.getPath();
858 // path doesn't start with http or /
859 var isAbsolute = path.match( /^http/ ) || path.match( /^\// );
860 if ( isAbsolute ) {
861 this.getAbsolutePath = this.getPath;
862 return;
863 }
864
865 var pathname = location.pathname;
866 // query parameter #829. example.com/?pg=2
867 var isQuery = path.match( /^\?/ );
868 if ( isQuery ) {
869 this.getAbsolutePath = function() {
870 return pathname + this.getPath();
871 };
872 return;
873 }
874
875 // /foo/bar/index.html => /foo/bar
876 var directory = pathname.substring( 0, pathname.lastIndexOf('/') );
877 this.getAbsolutePath = function() {
878 return directory + '/' + this.getPath();
879 };
880 };
881
882 // -------------------------- nav -------------------------- //
883
884 // hide navigation
885 InfiniteScroll.create.hideNav = function() {
886 var nav = utils.getQueryElement( this.options.hideNav );
887 if ( !nav ) {
888 return;
889 }
890 nav.style.display = 'none';
891 this.nav = nav;
892 };
893
894 InfiniteScroll.destroy.hideNav = function() {
895 if ( this.nav ) {
896 this.nav.style.display = '';
897 }
898 };
899
900 // -------------------------- destroy -------------------------- //
901
902 proto.destroy = function() {
903 this.allOff(); // remove all event listeners
904 // call destroy methods
905 for ( var method in InfiniteScroll.destroy ) {
906 InfiniteScroll.destroy[ method ].call( this );
907 }
908
909 delete this.element.infiniteScrollGUID;
910 delete instances[ this.guid ];
911 // remove jQuery data. #807
912 if ( jQuery && this.$element ) {
913 jQuery.removeData( this.element, 'infiniteScroll' );
914 }
915 };
916
917 // -------------------------- utilities -------------------------- //
918
919 // https://remysharp.com/2010/07/21/throttling-function-calls
920 InfiniteScroll.throttle = function( fn, threshold ) {
921 threshold = threshold || 200;
922 var last, timeout;
923
924 return function() {
925 var now = +new Date();
926 var args = arguments;
927 var trigger = function() {
928 last = now;
929 fn.apply( this, args );
930 }.bind( this );
931 if ( last && now < last + threshold ) {
932 // hold on to it
933 clearTimeout( timeout );
934 timeout = setTimeout( trigger, threshold );
935 } else {
936 trigger();
937 }
938 };
939 };
940
941 InfiniteScroll.data = function( elem ) {
942 elem = utils.getQueryElement( elem );
943 var id = elem && elem.infiniteScrollGUID;
944 return id && instances[ id ];
945 };
946
947 // set internal jQuery, for Webpack + jQuery v3
948 InfiniteScroll.setJQuery = function( $ ) {
949 jQuery = $;
950 };
951
952 // -------------------------- setup -------------------------- //
953
954 utils.htmlInit( InfiniteScroll, 'infinite-scroll' );
955
956 // add noop _init method for jQuery Bridget. #768
957 proto._init = function() {};
958
959 if ( jQuery && jQuery.bridget ) {
960 jQuery.bridget( 'infiniteScroll', InfiniteScroll );
961 }
962
963 // -------------------------- -------------------------- //
964
965 return InfiniteScroll;
966
967 }));
968
969 // page-load
970 ( function( window, factory ) {
971 // universal module definition
972 /* globals define, module, require */
973 if ( typeof define == 'function' && define.amd ) {
974 // AMD
975 define( 'infinite-scroll/js/page-load',[
976 './core',
977 ], function( InfiniteScroll ) {
978 return factory( window, InfiniteScroll );
979 });
980 } else if ( typeof module == 'object' && module.exports ) {
981 // CommonJS
982 module.exports = factory(
983 window,
984 require('./core')
985 );
986 } else {
987 // browser global
988 factory(
989 window,
990 window.InfiniteScroll
991 );
992 }
993
994 }( window, function factory( window, InfiniteScroll ) {
995
996 var proto = InfiniteScroll.prototype;
997
998 // InfiniteScroll.defaults.append = false;
999 InfiniteScroll.defaults.loadOnScroll = true;
1000 InfiniteScroll.defaults.checkLastPage = true;
1001 InfiniteScroll.defaults.responseType = 'document';
1002 // InfiniteScroll.defaults.prefill = false;
1003 // InfiniteScroll.defaults.outlayer = null;
1004
1005 InfiniteScroll.create.pageLoad = function() {
1006 this.canLoad = true;
1007 this.on( 'scrollThreshold', this.onScrollThresholdLoad );
1008 this.on( 'load', this.checkLastPage );
1009 if ( this.options.outlayer ) {
1010 this.on( 'append', this.onAppendOutlayer );
1011 }
1012 };
1013
1014 proto.onScrollThresholdLoad = function() {
1015 if ( this.options.loadOnScroll ) {
1016 this.loadNextPage();
1017 }
1018 };
1019
1020 proto.loadNextPage = function() {
1021 if ( this.isLoading || !this.canLoad ) {
1022 return;
1023 }
1024
1025 var path = this.getAbsolutePath();
1026 this.isLoading = true;
1027
1028 var onLoad = function( response ) {
1029 this.onPageLoad( response, path );
1030 }.bind( this );
1031
1032 var onError = function( error ) {
1033 this.onPageError( error, path );
1034 }.bind( this );
1035
1036 var onLast = function( response ) {
1037 this.lastPageReached( response, path );
1038 }.bind( this );
1039
1040 request( path, this.options.responseType, onLoad, onError, onLast );
1041 this.dispatchEvent( 'request', null, [ path ] );
1042 };
1043
1044 proto.onPageLoad = function( response, path ) {
1045 // done loading if not appending
1046 if ( !this.options.append ) {
1047 this.isLoading = false;
1048 }
1049 this.pageIndex++;
1050 this.loadCount++;
1051 this.dispatchEvent( 'load', null, [ response, path ] );
1052 this.appendNextPage( response, path );
1053 return response;
1054 };
1055
1056 proto.appendNextPage = function( response, path ) {
1057 var optAppend = this.options.append;
1058 // do not append json
1059 var isDocument = this.options.responseType == 'document';
1060 if ( !isDocument || !optAppend ) {
1061 return;
1062 }
1063
1064 var items = response.querySelectorAll( optAppend );
1065 var fragment = getItemsFragment( items );
1066 var appendReady = function () {
1067 this.appendItems( items, fragment );
1068 this.isLoading = false;
1069 this.dispatchEvent( 'append', null, [ response, path, items ] );
1070 }.bind( this );
1071
1072 // TODO add hook for option to trigger appendReady
1073 if ( this.options.outlayer ) {
1074 this.appendOutlayerItems( fragment, appendReady );
1075 } else {
1076 appendReady();
1077 }
1078 };
1079
1080 proto.appendItems = function( items, fragment ) {
1081 if ( !items || !items.length ) {
1082 return;
1083 }
1084 // get fragment if not provided
1085 fragment = fragment || getItemsFragment( items );
1086 refreshScripts( fragment );
1087 this.element.appendChild( fragment );
1088 };
1089
1090 function getItemsFragment( items ) {
1091 // add items to fragment
1092 var fragment = document.createDocumentFragment();
1093 for ( var i=0; items && i < items.length; i++ ) {
1094 fragment.appendChild( items[i] );
1095 }
1096 return fragment;
1097 }
1098
1099 // replace <script>s with copies so they load
1100 // <script>s added by InfiniteScroll will not load
1101 // similar to https://stackoverflow.com/questions/610995
1102 function refreshScripts( fragment ) {
1103 var scripts = fragment.querySelectorAll('script');
1104 for ( var i=0; i < scripts.length; i++ ) {
1105 var script = scripts[i];
1106 var freshScript = document.createElement('script');
1107 copyAttributes( script, freshScript );
1108 // copy inner script code. #718, #782
1109 freshScript.innerHTML = script.innerHTML;
1110 script.parentNode.replaceChild( freshScript, script );
1111 }
1112 }
1113
1114 function copyAttributes( fromNode, toNode ) {
1115 var attrs = fromNode.attributes;
1116 for ( var i=0; i < attrs.length; i++ ) {
1117 var attr = attrs[i];
1118 toNode.setAttribute( attr.name, attr.value );
1119 }
1120 }
1121
1122 // ----- outlayer ----- //
1123
1124 proto.appendOutlayerItems = function( fragment, appendReady ) {
1125 var imagesLoaded = InfiniteScroll.imagesLoaded || window.imagesLoaded;
1126 if ( !imagesLoaded ) {
1127 console.error('[InfiniteScroll] imagesLoaded required for outlayer option');
1128 this.isLoading = false;
1129 return;
1130 }
1131 // append once images loaded
1132 imagesLoaded( fragment, appendReady );
1133 };
1134
1135 proto.onAppendOutlayer = function( response, path, items ) {
1136 this.options.outlayer.appended( items );
1137 };
1138
1139 // ----- checkLastPage ----- //
1140
1141 // check response for next element
1142 proto.checkLastPage = function( response, path ) {
1143 var checkLastPage = this.options.checkLastPage;
1144 if ( !checkLastPage ) {
1145 return;
1146 }
1147
1148 var pathOpt = this.options.path;
1149 // if path is function, check if next path is truthy
1150 if ( typeof pathOpt == 'function' ) {
1151 var nextPath = this.getPath();
1152 if ( !nextPath ) {
1153 this.lastPageReached( response, path );
1154 return;
1155 }
1156 }
1157 // get selector from checkLastPage or path option
1158 var selector;
1159 if ( typeof checkLastPage == 'string' ) {
1160 selector = checkLastPage;
1161 } else if ( this.isPathSelector ) {
1162 // path option is selector string
1163 selector = pathOpt;
1164 }
1165 // check last page for selector
1166 // bail if no selector or not document response
1167 if ( !selector || !response.querySelector ) {
1168 return;
1169 }
1170 // check if response has selector
1171 var nextElem = response.querySelector( selector );
1172 if ( !nextElem ) {
1173 this.lastPageReached( response, path );
1174 }
1175 };
1176
1177 proto.lastPageReached = function( response, path ) {
1178 this.canLoad = false;
1179 this.dispatchEvent( 'last', null, [ response, path ] );
1180 };
1181
1182 // ----- error ----- //
1183
1184 proto.onPageError = function( error, path ) {
1185 this.isLoading = false;
1186 this.canLoad = false;
1187 this.dispatchEvent( 'error', null, [ error, path ] );
1188 return error;
1189 };
1190
1191 // -------------------------- prefill -------------------------- //
1192
1193 InfiniteScroll.create.prefill = function() {
1194 if ( !this.options.prefill ) {
1195 return;
1196 }
1197 var append = this.options.append;
1198 if ( !append ) {
1199 console.error( 'append option required for prefill. Set as :' + append );
1200 return;
1201 }
1202 this.updateMeasurements();
1203 this.updateScroller();
1204 this.isPrefilling = true;
1205 this.on( 'append', this.prefill );
1206 this.once( 'error', this.stopPrefill );
1207 this.once( 'last', this.stopPrefill );
1208 this.prefill();
1209 };
1210
1211 proto.prefill = function() {
1212 var distance = this.getPrefillDistance();
1213 this.isPrefilling = distance >= 0;
1214 if ( this.isPrefilling ) {
1215 this.log('prefill');
1216 this.loadNextPage();
1217 } else {
1218 this.stopPrefill();
1219 }
1220 };
1221
1222 proto.getPrefillDistance = function() {
1223 // element scroll
1224 if ( this.options.elementScroll ) {
1225 return this.scroller.clientHeight - this.scroller.scrollHeight;
1226 }
1227 // window
1228 return this.windowHeight - this.element.clientHeight;
1229 };
1230
1231 proto.stopPrefill = function() {
1232 this.log('stopPrefill');
1233 this.off( 'append', this.prefill );
1234 };
1235
1236 // -------------------------- request -------------------------- //
1237
1238 function request( url, responseType, onLoad, onError, onLast ) {
1239 var req = new XMLHttpRequest();
1240 req.open( 'GET', url, true );
1241 // set responseType document to return DOM
1242 req.responseType = responseType || '';
1243
1244 // set X-Requested-With header to check that is ajax request
1245 req.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
1246
1247 req.onload = function() {
1248 if ( req.status == 200 ) {
1249 onLoad( req.response );
1250 } else if ( req.status == 204 ) {
1251 onLast( req.response );
1252 } else {
1253 // not 200 OK, error
1254 var error = new Error( req.statusText );
1255 onError( error );
1256 }
1257 };
1258
1259 // Handle network errors
1260 req.onerror = function() {
1261 var error = new Error( 'Network error requesting ' + url );
1262 onError( error );
1263 };
1264
1265 req.send();
1266 }
1267
1268 // -------------------------- -------------------------- //
1269
1270 return InfiniteScroll;
1271
1272 }));
1273
1274 // scroll-watch
1275 ( function( window, factory ) {
1276 // universal module definition
1277 /* globals define, module, require */
1278 if ( typeof define == 'function' && define.amd ) {
1279 // AMD
1280 define( 'infinite-scroll/js/scroll-watch',[
1281 './core',
1282 'fizzy-ui-utils/utils',
1283 ], function( InfiniteScroll, utils ) {
1284 return factory( window, InfiniteScroll, utils );
1285 });
1286 } else if ( typeof module == 'object' && module.exports ) {
1287 // CommonJS
1288 module.exports = factory(
1289 window,
1290 require('./core'),
1291 require('fizzy-ui-utils')
1292 );
1293 } else {
1294 // browser global
1295 factory(
1296 window,
1297 window.InfiniteScroll,
1298 window.fizzyUIUtils
1299 );
1300 }
1301
1302 }( window, function factory( window, InfiniteScroll, utils ) {
1303
1304 var proto = InfiniteScroll.prototype;
1305
1306 // default options
1307 InfiniteScroll.defaults.scrollThreshold = 400;
1308 // InfiniteScroll.defaults.elementScroll = null;
1309
1310 InfiniteScroll.create.scrollWatch = function() {
1311 // events
1312 this.pageScrollHandler = this.onPageScroll.bind( this );
1313 this.resizeHandler = this.onResize.bind( this );
1314
1315 var scrollThreshold = this.options.scrollThreshold;
1316 var isEnable = scrollThreshold || scrollThreshold === 0;
1317 if ( isEnable ) {
1318 this.enableScrollWatch();
1319 }
1320 };
1321
1322 InfiniteScroll.destroy.scrollWatch = function() {
1323 this.disableScrollWatch();
1324 };
1325
1326 proto.enableScrollWatch = function() {
1327 if ( this.isScrollWatching ) {
1328 return;
1329 }
1330 this.isScrollWatching = true;
1331 this.updateMeasurements();
1332 this.updateScroller();
1333 // TODO disable after error?
1334 this.on( 'last', this.disableScrollWatch );
1335 this.bindScrollWatchEvents( true );
1336 };
1337
1338 proto.disableScrollWatch = function() {
1339 if ( !this.isScrollWatching ) {
1340 return;
1341 }
1342 this.bindScrollWatchEvents( false );
1343 delete this.isScrollWatching;
1344 };
1345
1346 proto.bindScrollWatchEvents = function( isBind ) {
1347 var addRemove = isBind ? 'addEventListener' : 'removeEventListener';
1348 this.scroller[ addRemove ]( 'scroll', this.pageScrollHandler );
1349 window[ addRemove ]( 'resize', this.resizeHandler );
1350 };
1351
1352 proto.onPageScroll = InfiniteScroll.throttle( function() {
1353 var distance = this.getBottomDistance();
1354 if ( distance <= this.options.scrollThreshold ) {
1355 this.dispatchEvent('scrollThreshold');
1356 }
1357 });
1358
1359 proto.getBottomDistance = function() {
1360 if ( this.options.elementScroll ) {
1361 return this.getElementBottomDistance();
1362 } else {
1363 return this.getWindowBottomDistance();
1364 }
1365 };
1366
1367 proto.getWindowBottomDistance = function() {
1368 var bottom = this.top + this.element.clientHeight;
1369 var scrollY = window.pageYOffset + this.windowHeight;
1370 return bottom - scrollY;
1371 };
1372
1373 proto.getElementBottomDistance = function() {
1374 var bottom = this.scroller.scrollHeight;
1375 var scrollY = this.scroller.scrollTop + this.scroller.clientHeight;
1376 return bottom - scrollY;
1377 };
1378
1379 proto.onResize = function() {
1380 this.updateMeasurements();
1381 };
1382
1383 utils.debounceMethod( InfiniteScroll, 'onResize', 150 );
1384
1385 // -------------------------- -------------------------- //
1386
1387 return InfiniteScroll;
1388
1389 }));
1390
1391 // history
1392 ( function( window, factory ) {
1393 // universal module definition
1394 /* globals define, module, require */
1395 if ( typeof define == 'function' && define.amd ) {
1396 // AMD
1397 define( 'infinite-scroll/js/history',[
1398 './core',
1399 'fizzy-ui-utils/utils',
1400 ], function( InfiniteScroll, utils ) {
1401 return factory( window, InfiniteScroll, utils );
1402 });
1403 } else if ( typeof module == 'object' && module.exports ) {
1404 // CommonJS
1405 module.exports = factory(
1406 window,
1407 require('./core'),
1408 require('fizzy-ui-utils')
1409 );
1410 } else {
1411 // browser global
1412 factory(
1413 window,
1414 window.InfiniteScroll,
1415 window.fizzyUIUtils
1416 );
1417 }
1418
1419 }( window, function factory( window, InfiniteScroll, utils ) {
1420
1421 var proto = InfiniteScroll.prototype;
1422
1423 InfiniteScroll.defaults.history = 'replace';
1424 // InfiniteScroll.defaults.historyTitle = false;
1425
1426 var link = document.createElement('a');
1427
1428 // ----- create/destroy ----- //
1429
1430 InfiniteScroll.create.history = function() {
1431 if ( !this.options.history ) {
1432 return;
1433 }
1434 // check for same origin
1435 link.href = this.getAbsolutePath();
1436 // MS Edge does not have origin on link https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12236493/
1437 var linkOrigin = link.origin || link.protocol + '//' + link.host;
1438 var isSameOrigin = linkOrigin == location.origin;
1439 if ( !isSameOrigin ) {
1440 console.error( '[InfiniteScroll] cannot set history with different origin: ' +
1441 link.origin + ' on ' + location.origin +
1442 ' . History behavior disabled.' );
1443 return;
1444 }
1445
1446 // two ways to handle changing history
1447 if ( this.options.append ) {
1448 this.createHistoryAppend();
1449 } else {
1450 this.createHistoryPageLoad();
1451 }
1452 };
1453
1454 proto.createHistoryAppend = function() {
1455 this.updateMeasurements();
1456 this.updateScroller();
1457 // array of scroll positions of appended pages
1458 this.scrollPages = [
1459 {
1460 // first page
1461 top: 0,
1462 path: location.href,
1463 title: document.title,
1464 }
1465 ];
1466 this.scrollPageIndex = 0;
1467 // events
1468 this.scrollHistoryHandler = this.onScrollHistory.bind( this );
1469 this.unloadHandler = this.onUnload.bind( this );
1470 this.scroller.addEventListener( 'scroll', this.scrollHistoryHandler );
1471 this.on( 'append', this.onAppendHistory );
1472 this.bindHistoryAppendEvents( true );
1473 };
1474
1475 proto.bindHistoryAppendEvents = function( isBind ) {
1476 var addRemove = isBind ? 'addEventListener' : 'removeEventListener';
1477 this.scroller[ addRemove ]( 'scroll', this.scrollHistoryHandler );
1478 window[ addRemove ]( 'unload', this.unloadHandler );
1479 };
1480
1481 proto.createHistoryPageLoad = function() {
1482 this.on( 'load', this.onPageLoadHistory );
1483 };
1484
1485 InfiniteScroll.destroy.history =
1486 proto.destroyHistory = function() {
1487 var isHistoryAppend = this.options.history && this.options.append;
1488 if ( isHistoryAppend ) {
1489 this.bindHistoryAppendEvents( false );
1490 }
1491 };
1492
1493 // ----- append history ----- //
1494
1495 proto.onAppendHistory = function( response, path, items ) {
1496 // do not proceed if no items. #779
1497 if ( !items || !items.length ) {
1498 return;
1499 }
1500 var firstItem = items[0];
1501 var elemScrollY = this.getElementScrollY( firstItem );
1502 // resolve path
1503 link.href = path;
1504 // add page data to hash
1505 this.scrollPages.push({
1506 top: elemScrollY,
1507 path: link.href,
1508 title: response.title,
1509 });
1510 };
1511
1512 proto.getElementScrollY = function( elem ) {
1513 if ( this.options.elementScroll ) {
1514 return this.getElementElementScrollY( elem );
1515 } else {
1516 return this.getElementWindowScrollY( elem );
1517 }
1518 };
1519
1520 proto.getElementWindowScrollY = function( elem ) {
1521 var rect = elem.getBoundingClientRect();
1522 return rect.top + window.pageYOffset;
1523 };
1524
1525 // wow, stupid name
1526 proto.getElementElementScrollY = function( elem ) {
1527 return elem.offsetTop - this.top;
1528 };
1529
1530 proto.onScrollHistory = function() {
1531 // cycle through positions, find biggest without going over
1532 var scrollViewY = this.getScrollViewY();
1533 var pageIndex, page;
1534 for ( var i=0; i < this.scrollPages.length; i++ ) {
1535 var scrollPage = this.scrollPages[i];
1536 if ( scrollPage.top >= scrollViewY ) {
1537 break;
1538 }
1539 pageIndex = i;
1540 page = scrollPage;
1541 }
1542 // set history if changed
1543 if ( pageIndex != this.scrollPageIndex ) {
1544 this.scrollPageIndex = pageIndex;
1545 this.setHistory( page.title, page.path );
1546 }
1547 };
1548
1549 utils.debounceMethod( InfiniteScroll, 'onScrollHistory', 150 );
1550
1551 proto.getScrollViewY = function() {
1552 if ( this.options.elementScroll ) {
1553 return this.scroller.scrollTop + this.scroller.clientHeight/2;
1554 } else {
1555 return window.pageYOffset + this.windowHeight/2;
1556 }
1557 };
1558
1559 proto.setHistory = function( title, path ) {
1560 var optHistory = this.options.history;
1561 var historyMethod = optHistory && history[ optHistory + 'State' ];
1562 if ( !historyMethod ) {
1563 return;
1564 }
1565
1566 history[ optHistory + 'State' ]( null, title, path );
1567
1568 if ( this.options.historyTitle ) {
1569 document.title = title;
1570 }
1571
1572 this.dispatchEvent( 'history', null, [ title, path ] );
1573 };
1574
1575 // scroll to top to prevent initial scroll-reset after page refresh
1576 // https://stackoverflow.com/a/18633915/182183
1577 proto.onUnload = function() {
1578 var pageIndex = this.scrollPageIndex;
1579 if ( pageIndex === 0 ) {
1580 return;
1581 }
1582 // calculate where scroll position would be on refresh
1583 var scrollPage = this.scrollPages[ pageIndex ];
1584 var scrollY = window.pageYOffset - scrollPage.top + this.top;
1585 // disable scroll event before setting scroll #679
1586 this.destroyHistory();
1587 scrollTo( 0, scrollY );
1588 };
1589
1590 // ----- load history ----- //
1591
1592 // update URL
1593 proto.onPageLoadHistory = function( response, path ) {
1594 this.setHistory( response.title, path );
1595 };
1596
1597 // -------------------------- -------------------------- //
1598
1599 return InfiniteScroll;
1600
1601 }));
1602
1603 // button
1604 ( function( window, factory ) {
1605 // universal module definition
1606 /* globals define, module, require */
1607 if ( typeof define == 'function' && define.amd ) {
1608 // AMD
1609 define( 'infinite-scroll/js/button',[
1610 './core',
1611 'fizzy-ui-utils/utils',
1612 ], function( InfiniteScroll, utils ) {
1613 return factory( window, InfiniteScroll, utils );
1614 });
1615 } else if ( typeof module == 'object' && module.exports ) {
1616 // CommonJS
1617 module.exports = factory(
1618 window,
1619 require('./core'),
1620 require('fizzy-ui-utils')
1621 );
1622 } else {
1623 // browser global
1624 factory(
1625 window,
1626 window.InfiniteScroll,
1627 window.fizzyUIUtils
1628 );
1629 }
1630
1631 }( window, function factory( window, InfiniteScroll, utils ) {
1632
1633 // InfiniteScroll.defaults.button = null;
1634
1635 InfiniteScroll.create.button = function() {
1636 var buttonElem = utils.getQueryElement( this.options.button );
1637 if ( buttonElem ) {
1638 this.button = new InfiniteScrollButton( buttonElem, this );
1639 return;
1640 }
1641 };
1642
1643 InfiniteScroll.destroy.button = function() {
1644 if ( this.button ) {
1645 this.button.destroy();
1646 }
1647 };
1648
1649 // -------------------------- InfiniteScrollButton -------------------------- //
1650
1651 function InfiniteScrollButton( element, infScroll ) {
1652 this.element = element;
1653 this.infScroll = infScroll;
1654 // events
1655 this.clickHandler = this.onClick.bind( this );
1656 this.element.addEventListener( 'click', this.clickHandler );
1657 infScroll.on( 'request', this.disable.bind( this ) );
1658 infScroll.on( 'load', this.enable.bind( this ) );
1659 infScroll.on( 'error', this.hide.bind( this ) );
1660 infScroll.on( 'last', this.hide.bind( this ) );
1661 }
1662
1663 InfiniteScrollButton.prototype.onClick = function( event ) {
1664 event.preventDefault();
1665 this.infScroll.loadNextPage();
1666 };
1667
1668 InfiniteScrollButton.prototype.enable = function() {
1669 this.element.removeAttribute('disabled');
1670 };
1671
1672 InfiniteScrollButton.prototype.disable = function() {
1673 this.element.disabled = 'disabled';
1674 };
1675
1676 InfiniteScrollButton.prototype.hide = function() {
1677 this.element.style.display = 'none';
1678 };
1679
1680 InfiniteScrollButton.prototype.destroy = function() {
1681 this.element.removeEventListener( 'click', this.clickHandler );
1682 };
1683
1684 // -------------------------- -------------------------- //
1685
1686 InfiniteScroll.Button = InfiniteScrollButton;
1687
1688 return InfiniteScroll;
1689
1690 }));
1691
1692 // status
1693 ( function( window, factory ) {
1694 // universal module definition
1695 /* globals define, module, require */
1696 if ( typeof define == 'function' && define.amd ) {
1697 // AMD
1698 define( 'infinite-scroll/js/status',[
1699 './core',
1700 'fizzy-ui-utils/utils',
1701 ], function( InfiniteScroll, utils ) {
1702 return factory( window, InfiniteScroll, utils );
1703 });
1704 } else if ( typeof module == 'object' && module.exports ) {
1705 // CommonJS
1706 module.exports = factory(
1707 window,
1708 require('./core'),
1709 require('fizzy-ui-utils')
1710 );
1711 } else {
1712 // browser global
1713 factory(
1714 window,
1715 window.InfiniteScroll,
1716 window.fizzyUIUtils
1717 );
1718 }
1719
1720 }( window, function factory( window, InfiniteScroll, utils ) {
1721
1722 var proto = InfiniteScroll.prototype;
1723
1724 // InfiniteScroll.defaults.status = null;
1725
1726 InfiniteScroll.create.status = function() {
1727 var statusElem = utils.getQueryElement( this.options.status );
1728 if ( !statusElem ) {
1729 return;
1730 }
1731 // elements
1732 this.statusElement = statusElem;
1733 this.statusEventElements = {
1734 request: statusElem.querySelector('.infinite-scroll-request'),
1735 error: statusElem.querySelector('.infinite-scroll-error'),
1736 last: statusElem.querySelector('.infinite-scroll-last'),
1737 };
1738 // events
1739 this.on( 'request', this.showRequestStatus );
1740 this.on( 'error', this.showErrorStatus );
1741 this.on( 'last', this.showLastStatus );
1742 this.bindHideStatus('on');
1743 };
1744
1745 proto.bindHideStatus = function( bindMethod ) {
1746 var hideEvent = this.options.append ? 'append' : 'load';
1747 this[ bindMethod ]( hideEvent, this.hideAllStatus );
1748 };
1749
1750 proto.showRequestStatus = function() {
1751 this.showStatus('request');
1752 };
1753
1754 proto.showErrorStatus = function() {
1755 this.showStatus('error');
1756 };
1757
1758 proto.showLastStatus = function() {
1759 this.showStatus('last');
1760 // prevent last then append event race condition from showing last status #706
1761 this.bindHideStatus('off');
1762 };
1763
1764 proto.showStatus = function( eventName ) {
1765 show( this.statusElement );
1766 this.hideStatusEventElements();
1767 var eventElem = this.statusEventElements[ eventName ];
1768 show( eventElem );
1769 };
1770
1771 proto.hideAllStatus = function() {
1772 hide( this.statusElement );
1773 this.hideStatusEventElements();
1774 };
1775
1776 proto.hideStatusEventElements = function() {
1777 for ( var type in this.statusEventElements ) {
1778 var eventElem = this.statusEventElements[ type ];
1779 hide( eventElem );
1780 }
1781 };
1782
1783 // -------------------------- -------------------------- //
1784
1785 function hide( elem ) {
1786 setDisplay( elem, 'none' );
1787 }
1788
1789 function show( elem ) {
1790 setDisplay( elem, 'block' );
1791 }
1792
1793 function setDisplay( elem, value ) {
1794 if ( elem ) {
1795 elem.style.display = value;
1796 }
1797 }
1798
1799 // -------------------------- -------------------------- //
1800
1801 return InfiniteScroll;
1802
1803 }));
1804
1805 /*!
1806 * Infinite Scroll v3.0.6
1807 * Automatically add next page
1808 *
1809 * Licensed GPLv3 for open source use
1810 * or Infinite Scroll Commercial License for commercial use
1811 *
1812 * https://infinite-scroll.com
1813 * Copyright 2018 Metafizzy
1814 */
1815
1816 ( function( window, factory ) {
1817 // universal module definition
1818 /* globals define, module, require */
1819 if ( typeof define == 'function' && define.amd ) {
1820 // AMD
1821 define( [
1822 'infinite-scroll/js/core',
1823 'infinite-scroll/js/page-load',
1824 'infinite-scroll/js/scroll-watch',
1825 'infinite-scroll/js/history',
1826 'infinite-scroll/js/button',
1827 'infinite-scroll/js/status',
1828 ], factory );
1829 } else if ( typeof module == 'object' && module.exports ) {
1830 // CommonJS
1831 module.exports = factory(
1832 require('./core'),
1833 require('./page-load'),
1834 require('./scroll-watch'),
1835 require('./history'),
1836 require('./button'),
1837 require('./status')
1838 );
1839 }
1840
1841 })( window, function factory( InfiniteScroll ) {
1842 return InfiniteScroll;
1843 });
1844
1845 /*!
1846 * imagesLoaded v4.1.4
1847 * JavaScript is all like "You images are done yet or what?"
1848 * MIT License
1849 */
1850
1851 ( function( window, factory ) { 'use strict';
1852 // universal module definition
1853
1854 /*global define: false, module: false, require: false */
1855
1856 if ( typeof define == 'function' && define.amd ) {
1857 // AMD
1858 define( 'imagesloaded/imagesloaded',[
1859 'ev-emitter/ev-emitter'
1860 ], function( EvEmitter ) {
1861 return factory( window, EvEmitter );
1862 });
1863 } else if ( typeof module == 'object' && module.exports ) {
1864 // CommonJS
1865 module.exports = factory(
1866 window,
1867 require('ev-emitter')
1868 );
1869 } else {
1870 // browser global
1871 window.imagesLoaded = factory(
1872 window,
1873 window.EvEmitter
1874 );
1875 }
1876
1877 })( typeof window !== 'undefined' ? window : this,
1878
1879 // -------------------------- factory -------------------------- //
1880
1881 function factory( window, EvEmitter ) {
1882
1883
1884
1885 var $ = window.jQuery;
1886 var console = window.console;
1887
1888 // -------------------------- helpers -------------------------- //
1889
1890 // extend objects
1891 function extend( a, b ) {
1892 for ( var prop in b ) {
1893 a[ prop ] = b[ prop ];
1894 }
1895 return a;
1896 }
1897
1898 var arraySlice = Array.prototype.slice;
1899
1900 // turn element or nodeList into an array
1901 function makeArray( obj ) {
1902 if ( Array.isArray( obj ) ) {
1903 // use object if already an array
1904 return obj;
1905 }
1906
1907 var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';
1908 if ( isArrayLike ) {
1909 // convert nodeList to array
1910 return arraySlice.call( obj );
1911 }
1912
1913 // array of single index
1914 return [ obj ];
1915 }
1916
1917 // -------------------------- imagesLoaded -------------------------- //
1918
1919 /**
1920 * @param {Array, Element, NodeList, String} elem
1921 * @param {Object or Function} options - if function, use as callback
1922 * @param {Function} onAlways - callback function
1923 */
1924 function ImagesLoaded( elem, options, onAlways ) {
1925 // coerce ImagesLoaded() without new, to be new ImagesLoaded()
1926 if ( !( this instanceof ImagesLoaded ) ) {
1927 return new ImagesLoaded( elem, options, onAlways );
1928 }
1929 // use elem as selector string
1930 var queryElem = elem;
1931 if ( typeof elem == 'string' ) {
1932 queryElem = document.querySelectorAll( elem );
1933 }
1934 // bail if bad element
1935 if ( !queryElem ) {
1936 console.error( 'Bad element for imagesLoaded ' + ( queryElem || elem ) );
1937 return;
1938 }
1939
1940 this.elements = makeArray( queryElem );
1941 this.options = extend( {}, this.options );
1942 // shift arguments if no options set
1943 if ( typeof options == 'function' ) {
1944 onAlways = options;
1945 } else {
1946 extend( this.options, options );
1947 }
1948
1949 if ( onAlways ) {
1950 this.on( 'always', onAlways );
1951 }
1952
1953 this.getImages();
1954
1955 if ( $ ) {
1956 // add jQuery Deferred object
1957 this.jqDeferred = new $.Deferred();
1958 }
1959
1960 // HACK check async to allow time to bind listeners
1961 setTimeout( this.check.bind( this ) );
1962 }
1963
1964 ImagesLoaded.prototype = Object.create( EvEmitter.prototype );
1965
1966 ImagesLoaded.prototype.options = {};
1967
1968 ImagesLoaded.prototype.getImages = function() {
1969 this.images = [];
1970
1971 // filter & find items if we have an item selector
1972 this.elements.forEach( this.addElementImages, this );
1973 };
1974
1975 /**
1976 * @param {Node} element
1977 */
1978 ImagesLoaded.prototype.addElementImages = function( elem ) {
1979 // filter siblings
1980 if ( elem.nodeName == 'IMG' ) {
1981 this.addImage( elem );
1982 }
1983 // get background image on element
1984 if ( this.options.background === true ) {
1985 this.addElementBackgroundImages( elem );
1986 }
1987
1988 // find children
1989 // no non-element nodes, #143
1990 var nodeType = elem.nodeType;
1991 if ( !nodeType || !elementNodeTypes[ nodeType ] ) {
1992 return;
1993 }
1994 var childImgs = elem.querySelectorAll('img');
1995 // concat childElems to filterFound array
1996 for ( var i=0; i < childImgs.length; i++ ) {
1997 var img = childImgs[i];
1998 this.addImage( img );
1999 }
2000
2001 // get child background images
2002 if ( typeof this.options.background == 'string' ) {
2003 var children = elem.querySelectorAll( this.options.background );
2004 for ( i=0; i < children.length; i++ ) {
2005 var child = children[i];
2006 this.addElementBackgroundImages( child );
2007 }
2008 }
2009 };
2010
2011 var elementNodeTypes = {
2012 1: true,
2013 9: true,
2014 11: true
2015 };
2016
2017 ImagesLoaded.prototype.addElementBackgroundImages = function( elem ) {
2018 var style = getComputedStyle( elem );
2019 if ( !style ) {
2020 // Firefox returns null if in a hidden iframe https://bugzil.la/548397
2021 return;
2022 }
2023 // get url inside url("...")
2024 var reURL = /url\((['"])?(.*?)\1\)/gi;
2025 var matches = reURL.exec( style.backgroundImage );
2026 while ( matches !== null ) {
2027 var url = matches && matches[2];
2028 if ( url ) {
2029 this.addBackground( url, elem );
2030 }
2031 matches = reURL.exec( style.backgroundImage );
2032 }
2033 };
2034
2035 /**
2036 * @param {Image} img
2037 */
2038 ImagesLoaded.prototype.addImage = function( img ) {
2039 var loadingImage = new LoadingImage( img );
2040 this.images.push( loadingImage );
2041 };
2042
2043 ImagesLoaded.prototype.addBackground = function( url, elem ) {
2044 var background = new Background( url, elem );
2045 this.images.push( background );
2046 };
2047
2048 ImagesLoaded.prototype.check = function() {
2049 var _this = this;
2050 this.progressedCount = 0;
2051 this.hasAnyBroken = false;
2052 // complete if no images
2053 if ( !this.images.length ) {
2054 this.complete();
2055 return;
2056 }
2057
2058 function onProgress( image, elem, message ) {
2059 // HACK - Chrome triggers event before object properties have changed. #83
2060 setTimeout( function() {
2061 _this.progress( image, elem, message );
2062 });
2063 }
2064
2065 this.images.forEach( function( loadingImage ) {
2066 loadingImage.once( 'progress', onProgress );
2067 loadingImage.check();
2068 });
2069 };
2070
2071 ImagesLoaded.prototype.progress = function( image, elem, message ) {
2072 this.progressedCount++;
2073 this.hasAnyBroken = this.hasAnyBroken || !image.isLoaded;
2074 // progress event
2075 this.emitEvent( 'progress', [ this, image, elem ] );
2076 if ( this.jqDeferred && this.jqDeferred.notify ) {
2077 this.jqDeferred.notify( this, image );
2078 }
2079 // check if completed
2080 if ( this.progressedCount == this.images.length ) {
2081 this.complete();
2082 }
2083
2084 if ( this.options.debug && console ) {
2085 console.log( 'progress: ' + message, image, elem );
2086 }
2087 };
2088
2089 ImagesLoaded.prototype.complete = function() {
2090 var eventName = this.hasAnyBroken ? 'fail' : 'done';
2091 this.isComplete = true;
2092 this.emitEvent( eventName, [ this ] );
2093 this.emitEvent( 'always', [ this ] );
2094 if ( this.jqDeferred ) {
2095 var jqMethod = this.hasAnyBroken ? 'reject' : 'resolve';
2096 this.jqDeferred[ jqMethod ]( this );
2097 }
2098 };
2099
2100 // -------------------------- -------------------------- //
2101
2102 function LoadingImage( img ) {
2103 this.img = img;
2104 }
2105
2106 LoadingImage.prototype = Object.create( EvEmitter.prototype );
2107
2108 LoadingImage.prototype.check = function() {
2109 // If complete is true and browser supports natural sizes,
2110 // try to check for image status manually.
2111 var isComplete = this.getIsImageComplete();
2112 if ( isComplete ) {
2113 // report based on naturalWidth
2114 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
2115 return;
2116 }
2117
2118 // If none of the checks above matched, simulate loading on detached element.
2119 this.proxyImage = new Image();
2120 this.proxyImage.addEventListener( 'load', this );
2121 this.proxyImage.addEventListener( 'error', this );
2122 // bind to image as well for Firefox. #191
2123 this.img.addEventListener( 'load', this );
2124 this.img.addEventListener( 'error', this );
2125 this.proxyImage.src = this.img.src;
2126 };
2127
2128 LoadingImage.prototype.getIsImageComplete = function() {
2129 // check for non-zero, non-undefined naturalWidth
2130 // fixes Safari+InfiniteScroll+Masonry bug infinite-scroll#671
2131 return this.img.complete && this.img.naturalWidth;
2132 };
2133
2134 LoadingImage.prototype.confirm = function( isLoaded, message ) {
2135 this.isLoaded = isLoaded;
2136 this.emitEvent( 'progress', [ this, this.img, message ] );
2137 };
2138
2139 // ----- events ----- //
2140
2141 // trigger specified handler for event type
2142 LoadingImage.prototype.handleEvent = function( event ) {
2143 var method = 'on' + event.type;
2144 if ( this[ method ] ) {
2145 this[ method ]( event );
2146 }
2147 };
2148
2149 LoadingImage.prototype.onload = function() {
2150 this.confirm( true, 'onload' );
2151 this.unbindEvents();
2152 };
2153
2154 LoadingImage.prototype.onerror = function() {
2155 this.confirm( false, 'onerror' );
2156 this.unbindEvents();
2157 };
2158
2159 LoadingImage.prototype.unbindEvents = function() {
2160 this.proxyImage.removeEventListener( 'load', this );
2161 this.proxyImage.removeEventListener( 'error', this );
2162 this.img.removeEventListener( 'load', this );
2163 this.img.removeEventListener( 'error', this );
2164 };
2165
2166 // -------------------------- Background -------------------------- //
2167
2168 function Background( url, element ) {
2169 this.url = url;
2170 this.element = element;
2171 this.img = new Image();
2172 }
2173
2174 // inherit LoadingImage prototype
2175 Background.prototype = Object.create( LoadingImage.prototype );
2176
2177 Background.prototype.check = function() {
2178 this.img.addEventListener( 'load', this );
2179 this.img.addEventListener( 'error', this );
2180 this.img.src = this.url;
2181 // check if image is already complete
2182 var isComplete = this.getIsImageComplete();
2183 if ( isComplete ) {
2184 this.confirm( this.img.naturalWidth !== 0, 'naturalWidth' );
2185 this.unbindEvents();
2186 }
2187 };
2188
2189 Background.prototype.unbindEvents = function() {
2190 this.img.removeEventListener( 'load', this );
2191 this.img.removeEventListener( 'error', this );
2192 };
2193
2194 Background.prototype.confirm = function( isLoaded, message ) {
2195 this.isLoaded = isLoaded;
2196 this.emitEvent( 'progress', [ this, this.element, message ] );
2197 };
2198
2199 // -------------------------- jQuery -------------------------- //
2200
2201 ImagesLoaded.makeJQueryPlugin = function( jQuery ) {
2202 jQuery = jQuery || window.jQuery;
2203 if ( !jQuery ) {
2204 return;
2205 }
2206 // set local variable
2207 $ = jQuery;
2208 // $().imagesLoaded()
2209 $.fn.imagesLoaded = function( options, callback ) {
2210 var instance = new ImagesLoaded( this, options, callback );
2211 return instance.jqDeferred.promise( $(this) );
2212 };
2213 };
2214 // try making plugin
2215 ImagesLoaded.makeJQueryPlugin();
2216
2217 // -------------------------- -------------------------- //
2218
2219 return ImagesLoaded;
2220
2221 });
2222
2223