Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jscroll.js - Multiple Links lazy-loading #139

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
231 changes: 231 additions & 0 deletions jquery.jscroll.multi-links.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*!
* jScroll - jQuery Plugin for Infinite Scrolling / Auto-Paging
* @see @link{http://jscroll.com}
*
* @copyright 2011-2017, Philip Klauzinski
* @license Dual licensed under the MIT and GPL Version 2 licenses.
* @author Philip Klauzinski (http://webtopian.com)
* @version 2.3.9
* @requires jQuery v1.4.3+
* @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
}
};

// 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.attr('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() {
return _$scroll.unbind('.jscroll')
.removeData('jscroll')
.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()) {
//data.nextHref = $.trim(data.nextHref + ' ' + _options.contentSelector);
_debug('info', 'jScroll:', $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: nextSelector not found - destroying');
_destroy();
return false;
} else {
_setBindings();
return true;
}
},

_setBindings = function() {
var $next = $e.find(_options.nextSelector).first();
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').bind('scroll.jscroll', function() {
return _observe();
});
if (_options.autoTriggerUntil > 0) {
_options.autoTriggerUntil--;
}
} else {
_$scroll.unbind('.jscroll');
$next.bind('click.jscroll', 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;

//////////// ====== Load the ajax response .before '.jscroll-next-parent' / so it's positioned above the other <a> elements
var $bnx = $e.find('.jscroll-next-parent').first();
$bnx.before('<div class="jscroll-added" />');

$inner.children('.jscroll-added').last()
.html('<div class="jscroll-loading" id="jscroll-loading">' + _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();
}
$('.jscroll-next-parent', $e).remove(); //////////// ====== Remove the previous next link BEFORE looking for the new one
var $next = $inner.find(_options.nextSelector).first(); //////////// ====== Look for a new next inside 'div.jscroll-inner'
data.waiting = false;
data.nextHref = $next.attr('href') ? $.trim($next.attr('href') + ' ' + _options.contentSelector) : false;
_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}));
_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);