Skip to content

Instantly share code, notes, and snippets.

@Enalmada
Last active May 21, 2020
Embed
What would you like to do?
custom version to support multiple (https://github.com/pklauzinski/jscroll/pull/119/files)
/*!
* jScroll - jQuery Plugin for Infinite Scrolling / Auto-Paging
* @see @link{https://jscroll.com}
*
* @copyright Philip Klauzinski
* @license Dual licensed under the MIT and GPL Version 2 licenses
* @author Philip Klauzinski (https://webtopian.com)
* @version 2.4.1
* @requires jQuery v1.8.0+
* @preserve
*/
(function($) {
'use strict';
// Define the jscroll namespace and default settings
$.jscroll = {
defaults: {
debug: false,
autoTrigger: true,
autoTriggerUntil: false,
loadingHtml: '<small>Loading...</small>',
loadingFunction: false,
padding: 0,
nextSelector: 'a:last',
contentSelector: '',
pagingSelector: '',
callback: false
},
instances: 0
};
// Constructor
var jScroll = function($e, options) {
// Private vars and methods
var _data = $e.data('jscroll'),
_userOptions = (typeof options === 'function') ? { callback: options } : options,
_options = $.extend({}, $.jscroll.defaults, _userOptions, _data || {}),
_isWindow = ($e.css('overflow-y') === 'visible'),
_$next = $e.find(_options.nextSelector).first(),
_$window = $(window),
_$body = $('body'),
_$scroll = _isWindow ? _$window : $e,
_nextHref = $.trim(_$next.prop('href') + ' ' + _options.contentSelector),
// Check if a loading image is defined and preload
_preloadImage = function() {
var src = $(_options.loadingHtml).filter('img').attr('src');
if (src) {
var image = new Image();
image.src = src;
}
},
// Wrap inner content, if it isn't already
_wrapInnerContent = function() {
if (!$e.find('.jscroll-inner').length) {
$e.contents().wrapAll('<div class="jscroll-inner" />');
}
},
// Find the next link's parent, or add one, and hide it
_nextWrap = function($next) {
var $parent;
if (_options.pagingSelector) {
$next.closest(_options.pagingSelector).hide();
} else {
$parent = $next.parent().not('.jscroll-inner,.jscroll-added').addClass('jscroll-next-parent').hide();
if (!$parent.length) {
$next.wrap('<div class="jscroll-next-parent" />').parent().hide();
}
}
},
// Remove the jscroll behavior and data from an element
_destroy = function() {
var data = $e.data('jscroll');
// don't do anything when called on an uninitialized element
if (!data) {
return;
}
$e.removeData('jscroll');
return _$scroll.unbind('.jscroll.instance_'+data.id)
.find('.jscroll-inner').children().unwrap()
.filter('.jscroll-added').children().unwrap();
},
// Observe the scroll event for when to trigger the next load
_observe = function() {
if ($e.is(':visible')) {
_wrapInnerContent();
var $inner = $e.find('div.jscroll-inner').first(),
data = $e.data('jscroll'),
borderTopWidth = parseInt($e.css('borderTopWidth'), 10),
borderTopWidthInt = isNaN(borderTopWidth) ? 0 : borderTopWidth,
iContainerTop = parseInt($e.css('paddingTop'), 10) + borderTopWidthInt,
iTopHeight = _isWindow ? _$scroll.scrollTop() : $e.offset().top,
innerTop = $inner.length ? $inner.offset().top : 0,
iTotalHeight = Math.ceil(iTopHeight - innerTop + _$scroll.height() + iContainerTop);
if (!data.waiting && iTotalHeight + _options.padding >= $inner.outerHeight()) {
_debug('info', 'jScroll['+data.id+']:', $inner.outerHeight() - iTotalHeight, 'from bottom. Loading next request...');
return _load();
}
}
},
// Check if the href for the next set of content has been set
_checkNextHref = function(data) {
data = data || $e.data('jscroll');
if (!data || !data.nextHref) {
_debug('warn', 'jScroll['+data.id+']: nextSelector not found - destroying');
_destroy();
return false;
} else {
_setBindings();
return true;
}
},
_setBindings = function() {
var $next = $e.find(_options.nextSelector).first(),
data = $e.data('jscroll');
if (!$next.length) {
return;
}
if (_options.autoTrigger && (_options.autoTriggerUntil === false || _options.autoTriggerUntil > 0)) {
_nextWrap($next);
var scrollingBodyHeight = _$body.height() - $e.offset().top,
scrollingHeight = ($e.height() < scrollingBodyHeight) ? $e.height() : scrollingBodyHeight,
windowHeight = ($e.offset().top - _$window.scrollTop() > 0) ? _$window.height() - ($e.offset().top - $(window).scrollTop()) : _$window.height();
if (scrollingHeight <= windowHeight) {
_observe();
}
_$scroll.unbind('.jscroll.instance_'+data.id).bind('scroll.jscroll.instance_'+data.id, function() {
return _observe();
});
if (_options.autoTriggerUntil > 0) {
_options.autoTriggerUntil--;
}
} else {
_$scroll.unbind('.jscroll.instance_'+data.id);
$next.bind('click.jscroll.instance_'+data.id, function() {
_nextWrap($next);
_load();
return false;
});
}
},
// Load the next set of content, if available
_load = function() {
var $inner = $e.find('div.jscroll-inner').first(),
data = $e.data('jscroll');
data.waiting = true;
$inner.append('<div class="jscroll-added" />')
.children('.jscroll-added').last()
.html('<div class="jscroll-loading jscroll-loading-'+data.id+'">' + _options.loadingHtml + '</div>')
.promise()
.done(function() {
if (_options.loadingFunction) {
_options.loadingFunction();
}
});
return $e.animate({scrollTop: $inner.outerHeight()}, 0, function() {
var nextHref = data.nextHref;
$inner.find('div.jscroll-added').last().load(nextHref, function(r, status) {
if (status === 'error') {
return _destroy();
}
var $next = $(this).find(_options.nextSelector).first();
data.waiting = false;
data.nextHref = $next.prop('href') ? $.trim($next.prop('href') + ' ' + _options.contentSelector) : false;
$('.jscroll-next-parent', $e).remove(); // Remove the previous next link now that we have a new one
_checkNextHref();
if (_options.callback) {
_options.callback.call(this, nextHref);
}
_debug('dir', data);
});
});
},
// Safe console debug - http://klauzinski.com/javascript/safe-firebug-console-in-javascript
_debug = function(m) {
if (_options.debug && typeof console === 'object' && (typeof m === 'object' || typeof console[m] === 'function')) {
if (typeof m === 'object') {
var args = [];
for (var sMethod in m) {
if (typeof console[sMethod] === 'function') {
args = (m[sMethod].length) ? m[sMethod] : [m[sMethod]];
console[sMethod].apply(console, args);
} else {
console.log.apply(console, args);
}
}
} else {
console[m].apply(console, Array.prototype.slice.call(arguments, 1));
}
}
};
// Initialization
$e.data('jscroll', $.extend({}, _data, {initialized: true, waiting: false, nextHref: _nextHref, id: ++$.jscroll.instances}));
_wrapInnerContent();
_preloadImage();
_setBindings();
// Expose API methods via the jQuery.jscroll namespace, e.g. $('sel').jscroll.method()
$.extend($e.jscroll, {
destroy: _destroy
});
return $e;
};
// Define the jscroll plugin method and loop
$.fn.jscroll = function(m) {
return this.each(function() {
var $this = $(this),
data = $this.data('jscroll');
// Instantiate jScroll on this element if it hasn't been already
if (data && data.initialized) {
return;
}
jScroll($this, m);
});
};
})(jQuery);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment