Created
November 26, 2013 09:53
-
-
Save mcspring/7655861 to your computer and use it in GitHub Desktop.
Infinite scroll support for Backbone.js' collection
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
_.extend Backbone.Collection.prototype, | |
options: | |
infinitescroll: | |
success: $.noop | |
error: $.noop | |
bufferPx: 40 | |
scrollPx: 150 | |
page: | |
current: 0 | |
per: null | |
state: | |
isDuringAjax: false | |
isDone: false | |
isInvalid: false | |
loading: | |
wrapper: 'backbone-infinitescroll-wrapper' | |
loadingId: 'backbone-infinitescroll-loading' | |
loadingImg: 'loading.gif' | |
loadingMsg: '<em>Loading ...</em>' | |
finishedMsg: '<em>No more</em>' | |
msg: null | |
speed: 'fast' | |
infinitescroll: (options={})-> | |
# NOTE: coffeescript cannot deal with nested scope! | |
that = @ | |
_.extend(@options.infinitescroll, options.infinitescroll) if options.infinitescroll | |
infinitescroll_options = @options.infinitescroll | |
# where we want to place the load message in? | |
infinitescroll_options.loading.wrapper = $(infinitescroll_options.loading.wrapper) | |
if !infinitescroll_options.loading.msg and infinitescroll_options.loading.wrapper.size() > 0 | |
infinitescroll_options.loading.msg = $('<div/>', { | |
id: infinitescroll_options.loading.loadingId | |
}).html('<img alt="'+$(infinitescroll_options.loading.loadingMsg).text()+'" src="' + infinitescroll_options.loading.loadingImg + '" /><div>' + infinitescroll_options.loading.loadingMsg + '</div>') | |
infinitescroll_options.loading.msg.appendTo(infinitescroll_options.loading.wrapper).hide() | |
else | |
infinitescroll_options.loading.msg = null | |
fetch_options = _.omit(options, 'infinitescroll') | |
infinitescroll_fetch = ()=> | |
# mark the XHR request | |
infinitescroll_options.state.isDuringAjax = true | |
# increase page count | |
infinitescroll_options.page.current++ | |
payload = { | |
page: infinitescroll_options.page.current | |
} | |
payload['limit'] = infinitescroll_options.page.per if infinitescroll_options.page.per isnt null | |
_.extend(fetch_options, { | |
remove: false | |
data: payload | |
}) | |
if infinitescroll_options.loading.msg | |
# preload loading.loadingImg | |
(new Image()).src = infinitescroll_options.loading.loadingImg if infinitescroll_options.loading.loadingImg | |
infinitescroll_options.loading.msg.fadeIn infinitescroll_options.loading.speed, ()-> | |
that.fetch(fetch_options) | |
.success (data, state, jqXHR)=> | |
infinitescroll_options.state.isDuringAjax = false | |
infinitescroll_options.state.isDone = true if _.size(data) is 0 | |
infinitescroll_options.loading.msg.fadeOut infinitescroll_options.loading.speed, ()-> | |
infinitescroll_options.success.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.success) | |
return | |
return | |
.error (data, state, jqXHR)=> | |
infinitescroll_options.state.isDuringAjax = false | |
infinitescroll_options.state.isInvalid = true | |
infinitescroll_options.loading.msg.fadeOut infinitescroll_options.loading.speed, ()-> | |
infinitescroll_options.error.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.error) | |
return | |
return | |
return | |
else | |
that.fetch(fetch_options) | |
.success (data, state, jqXHR)=> | |
infinitescroll_options.state.isDuringAjax = false | |
infinitescroll_options.state.isDone = true if _.size(data) is 0 | |
infinitescroll_options.success.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.success) | |
return | |
.error (data, state, jqXHR)=> | |
infinitescroll_options.state.isDuringAjax = false | |
infinitescroll_options.state.isInvalid = true | |
infinitescroll_options.error.call(data, state, jqXHR) if _.isFunction(infinitescroll_options.error) | |
return | |
return | |
$(document).scroll ()-> | |
$doc = $(document) | |
isNearBottom = ()-> | |
bottomPx = 0 + $doc.height() - $doc.scrollTop() - $(window).height() | |
# if distance remaining in the scroll (including buffer) is less than expected? | |
(bottomPx - infinitescroll_options.bufferPx) < infinitescroll_options.scrollPx | |
return if infinitescroll_options.state.isDuringAjax || infinitescroll_options.state.isDone || infinitescroll_options.state.isInvalid || !isNearBottom() | |
infinitescroll_fetch() | |
return | |
infinitescroll_fetch() | |
return |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Usage