123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262 |
- /*!
- // Infinite Scroll jQuery plugin
- // copyright Paul Irish, licensed GPL & MIT
- // version 1.2.090804
- // home and docs: http://www.infinite-scroll.com
- */
- // todo: add preloading option.
-
- ;(function($){
-
- $.fn.infinitescroll = function(options,callback){
-
- // console log wrapper.
- function debug(){
- if (opts.debug) { window.console && console.log.call(console,arguments)}
- }
-
- // grab each selector option and see if any fail.
- function areSelectorsValid(opts){
- for (var key in opts){
- if (key.indexOf && (key.indexOf('Selector') != -1) && $(opts[key]).length === 0){
- debug('Your ' + key + ' found no elements.');
- return false;
- }
- return true;
- }
- }
- // find the number to increment in the path.
- function determinePath(path){
-
- path.match(relurl) ? path.match(relurl)[2] : path;
- // there is a 2 in the url surrounded by slashes, e.g. /page/2/
- if ( path.match(/^(.*?)\b2\b(.*?$)/) ){
- path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1);
- } else
- // if there is any 2 in the url at all.
- if (path.match(/^(.*?)2(.*?$)/)){
- debug('Trying backup next selector parse technique. Treacherous waters here, matey.');
- path = path.match(/^(.*?)2(.*?$)/).slice(1);
- } else {
- debug('Sorry, we couldn\'t parse your Next (Previous Posts) URL. Verify your the css selector points to the correct A tag. If you still get this error: yell, scream, and kindly ask for help at infinite-scroll.com.');
- props.isInvalidPage = true; //prevent it from running on this page.
- }
-
- return path;
- }
- // 'document' means the full document usually, but sometimes the content of the overflow'd div in local mode
- function getDocumentHeight(){
- // weird doubletouch of scrollheight because http://soulpass.com/2006/07/24/ie-and-scrollheight/
- return opts.localMode ? ($(props.container)[0].scrollHeight && $(props.container)[0].scrollHeight)
- // needs to be document's height. (not props.container's) html's height is wrong in IE.
- : $(document).height()
- }
-
-
-
- function isNearBottom(opts,props){
-
- // distance remaining in the scroll
- // computed as: document height - distance already scroll - viewport height - buffer
- var pixelsFromWindowBottomToBottom = getDocumentHeight() -
- (opts.localMode ? $(props.container).scrollTop() :
- // have to do this bs because safari doesnt report a scrollTop on the html element
- ($(props.container).scrollTop() || $(props.container.ownerDocument.body).scrollTop())) -
- $(opts.localMode ? props.container : window).height();
-
- debug('math:',pixelsFromWindowBottomToBottom, props.pixelsFromNavToBottom);
-
- // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom....
- return (pixelsFromWindowBottomToBottom - opts.bufferPx < props.pixelsFromNavToBottom);
- }
-
- function showDoneMsg(){
- props.loadingMsg
- .find('img').hide()
- .parent()
- .find('div').html(opts.donetext).animate({opacity: 1},2000).fadeOut('normal');
-
- // user provided callback when done
- opts.errorCallback();
- }
-
- function infscrSetup(path,opts,props,callback){
-
- if (props.isDuringAjax || props.isInvalidPage || props.isDone) return;
-
- if ( opts.infiniteScroll && !isNearBottom(opts,props) ) return;
-
- // we dont want to fire the ajax multiple times
- props.isDuringAjax = true;
-
- // show the loading message and hide the previous/next links
- props.loadingMsg.appendTo( opts.contentSelector ).show();
- if(opts.infiniteScroll) $( opts.navSelector ).hide();
-
- // increment the URL bit. e.g. /page/3/
- props.currPage++;
-
- debug('heading into ajax',path);
-
- // if we're dealing with a table we can't use DIVs
- var box = $(opts.contentSelector).is('table') ? $('<tbody/>') : $('<div/>');
-
- box
- .attr('id','infscr-page-'+props.currPage)
- .addClass('infscr-pages')
- .appendTo( opts.contentSelector )
- .load( path.join( props.currPage ) + ' ' + opts.itemSelector,null,function(){
-
- // if we've hit the last page...
- if (props.isDone){
- showDoneMsg();
- return false;
-
- } else {
-
- // if it didn't return anything
- if (box.children().length == 0){
- // fake an ajaxError so we can quit.
- $.event.trigger( "ajaxError", [{status:404}] );
- }
-
- // fadeout currently makes the <em>'d text ugly in IE6
- props.loadingMsg.fadeOut('normal' );
-
- // smooth scroll to ease in the new content
- if (opts.animate){
- var scrollTo = $(window).scrollTop() + $('#infscr-loading').height() + opts.extraScrollPx + 'px';
- $('html,body').animate({scrollTop: scrollTo}, 800,function(){ props.isDuringAjax = false; });
- }
-
- // pass in the new DOM element as context for the callback
- callback.call( box[0] );
-
- if (!opts.animate) props.isDuringAjax = false; // once the call is done, we can allow it again.
- }
- }); // end of load()
-
-
- } // end of infscrSetup()
-
-
-
-
- // lets get started.
-
- var opts = $.extend({}, $.infinitescroll.defaults, options);
- var props = $.infinitescroll; // shorthand
- callback = callback || function(){};
-
- if (!areSelectorsValid(opts)){ return false; }
-
- // we doing this on an overflow:auto div?
- props.container = opts.localMode ? this : document.documentElement;
-
- // contentSelector we'll use for our .load()
- opts.contentSelector = opts.contentSelector || this;
-
-
- // get the relative URL - everything past the domain name.
- var relurl = /(.*?\/\/).*?(\/.*)/;
- var path = $(opts.nextSelector).attr('href');
-
-
- if (!path) { debug('Navigation selector not found'); return; }
-
- // set the path to be a relative URL from root.
- path = determinePath(path);
-
- // reset scrollTop in case of page refresh:
- if (opts.localMode) $(props.container)[0].scrollTop = 0;
- // distance from nav links to bottom
- // computed as: height of the document + top offset of container - top offset of nav link
- props.pixelsFromNavToBottom = getDocumentHeight() +
- $(props.container).offset().top -
- $(opts.navSelector).offset().top;
-
- // define loading msg
- props.loadingMsg = $('<div id="infscr-loading" style="text-align: center;"><img alt="Loading..." src="'+
- opts.loadingImg+'" /><div>'+opts.loadingText+'</div></div>');
- // preload the image
- (new Image()).src = opts.loadingImg;
-
-
- // set up our bindings
- $(document).ajaxError(function(e,xhr,opt){
- debug('Page not found. Self-destructing...');
-
- // die if we're out of pages.
- if (xhr.status == 404){
- showDoneMsg();
- props.isDone = true;
- $(opts.localMode ? this : window).unbind('scroll.infscr');
- }
- });
-
- if(opts.infiniteScroll){
- // bind scroll handler to element (if its a local scroll) or window
- $(opts.localMode ? this : window)
- .bind('scroll.infscr', function(){ infscrSetup(path,opts,props,callback); } )
- .trigger('scroll.infscr'); // trigger the event, in case it's a short page
- }else{
- $(opts.nextSelector).click(
- function(){
- infscrSetup(path,opts,props,callback);
- return false;
- }
- );
- }
-
-
- return this;
-
- } // end of $.fn.infinitescroll()
-
-
- // options and read-only properties object
-
- $.infinitescroll = {
- defaults : {
- debug : false,
- infiniteScroll : true,
- preload : false,
- nextSelector : "div.navigation a:first",
- loadingImg : "http://www.infinite-scroll.com/loading.gif",
- loadingText : "<em>Loading the next set of posts...</em>",
- donetext : "<em>Congratulations, you've reached the end of the internet.</em>",
- navSelector : "div.navigation",
- contentSelector : null, // not really a selector. :) it's whatever the method was called on..
- extraScrollPx : 150,
- itemSelector : "div.post",
- animate : false,
- localMode : false,
- bufferPx : 40,
- errorCallback : function(){}
- },
- loadingImg : undefined,
- loadingMsg : undefined,
- container : undefined,
- currPage : 1,
- currDOMChunk : null, // defined in setup()'s load()
- isDuringAjax : false,
- isInvalidPage : false,
- isDone : false // for when it goes all the way through the archive.
- };
-
- })(jQuery);
|