├── .gitignore ├── Gruntfile.js ├── composer.json ├── package.json ├── languages └── infinite-wp-list-tables.pot ├── README.md ├── infinite-wp-list-tables.php └── assets └── js └── vendor ├── jquery.infinitescroll.min.js └── jquery.infinitescroll.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | /*jshint node:true */ 2 | 3 | module.exports = function( grunt ) { 4 | 'use strict'; 5 | 6 | grunt.loadNpmTasks( 'grunt-wp-i18n' ); 7 | 8 | grunt.initConfig({ 9 | pkg: grunt.file.readJSON( 'package.json' ), 10 | 11 | makepot: { 12 | plugin: { 13 | options: { 14 | mainFile: 'infinite-wp-list-tables.php', 15 | potHeaders: { 16 | poedit: true, 17 | 'Report-Msgid-Bugs-To': '<%= pkg.bugs.url %>' 18 | }, 19 | type: 'wp-plugin', 20 | updateTimestamp: false 21 | } 22 | } 23 | } 24 | 25 | }); 26 | 27 | }; 28 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cedaro/infinite-wp-list-tables", 3 | "description": "A WordPress plugin to add infinite scroll support for WP List Tables in the admin panel.", 4 | "keywords": ["wordpress"], 5 | "type": "wordpress-plugin", 6 | "homepage": "https://github.com/cedaro/infinite-wp-list-tables", 7 | "license": "GPL-2.0+", 8 | "authors": [ 9 | { 10 | "name": "Brady Vercher", 11 | "email": "brady@blazersix.com", 12 | "homepage": "http://www.cedaro.com/" 13 | } 14 | ], 15 | "support": { 16 | "issues": "https://github.com/cedaro/infinite-wp-list-tables/issues", 17 | "source": "https://github.com/cedaro/infinite-wp-list-tables" 18 | }, 19 | "require": { 20 | "composer/installers": "~1.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infinite-wp-list-tables", 3 | "version": "4.2.1", 4 | "description": "A WordPress plugin to add infinite scroll support for WP List Tables in the admin panel.", 5 | "main": "Gruntfile.js", 6 | "repository": { 7 | "type": "git", 8 | "url": "https://github.com/cedaro/infinite-wp-list-tables.git" 9 | }, 10 | "author": { 11 | "name": "Brady Vercher", 12 | "email": "brady@blazersix.com", 13 | "url": "http://www.cedaro.com/" 14 | }, 15 | "license": "GPL-2.0+", 16 | "bugs": { 17 | "url": "https://github.com/cedaro/infinite-wp-list-tables/issues" 18 | }, 19 | "homepage": "https://github.com/cedaro/infinite-wp-list-tables", 20 | "devDependencies": { 21 | "grunt": "~0.4.5", 22 | "grunt-wp-i18n": "~0.5" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /languages/infinite-wp-list-tables.pot: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2015 Cedaro 2 | # This file is distributed under the GPL-2.0+. 3 | msgid "" 4 | msgstr "" 5 | "Project-Id-Version: Infinite WP List Tables 2.0.0\n" 6 | "Report-Msgid-Bugs-To: " 7 | "https://github.com/cedaro/infinite-wp-list-tables/issues\n" 8 | "POT-Creation-Date: 2015-02-20 06:33:37+00:00\n" 9 | "MIME-Version: 1.0\n" 10 | "Content-Type: text/plain; charset=utf-8\n" 11 | "Content-Transfer-Encoding: 8bit\n" 12 | "PO-Revision-Date: 2015-MO-DA HO:MI+ZONE\n" 13 | "Last-Translator: FULL NAME \n" 14 | "Language-Team: LANGUAGE \n" 15 | "X-Generator: grunt-wp-i18n 0.5.0\n" 16 | "X-Poedit-KeywordsList: " 17 | "__;_e;_x:1,2c;_ex:1,2c;_n:1,2;_nx:1,2,4c;_n_noop:1,2;_nx_noop:1,2,3c;esc_" 18 | "attr__;esc_html__;esc_attr_e;esc_html_e;esc_attr_x:1,2c;esc_html_x:1,2c;\n" 19 | "Language: en\n" 20 | "Plural-Forms: nplurals=2; plural=(n != 1);\n" 21 | "X-Poedit-Country: United States\n" 22 | "X-Poedit-SourceCharset: UTF-8\n" 23 | "X-Poedit-Basepath: ../\n" 24 | "X-Poedit-SearchPath-0: .\n" 25 | "X-Poedit-Bookmarks: \n" 26 | "X-Textdomain-Support: yes\n" 27 | 28 | #: infinite-wp-list-tables.php:81 29 | msgid "Loading…" 30 | msgstr "" 31 | 32 | #. Plugin Name of the plugin/theme 33 | msgid "Infinite WP List Tables" 34 | msgstr "" 35 | 36 | #. Plugin URI of the plugin/theme 37 | msgid "https://github.com/cedaro/infinite-wp-list-tables" 38 | msgstr "" 39 | 40 | #. Description of the plugin/theme 41 | msgid "Infinite scroll support for WP List Tables in the WordPress admin panel." 42 | msgstr "" 43 | 44 | #. Author of the plugin/theme 45 | msgid "Cedaro" 46 | msgstr "" 47 | 48 | #. Author URI of the plugin/theme 49 | msgid "http://www.cedaro.com/" 50 | msgstr "" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Infinite WP List Tables 2 | 3 | Infinite scroll support for WP List Tables in the WordPress admin panel. 4 | 5 | __Contributors:__ [Brady Vercher](https://twitter.com/bradyvercher) 6 | __Requires:__ 4.0 7 | __Tested up to:__ 4.1 8 | __License:__ [GPL-2.0+](http://www.gnu.org/licenses/gpl-2.0.html) 9 | 10 | Supports list tables for posts, pages, comments, users and most custom post types. Taxonomies (categories, tags, etc) should also be supported. 11 | 12 | ## Installation 13 | 14 | ### Upload 15 | 16 | 1. Download the [latest release](https://github.com/cedaro/infinite-wp-list-tables/archive/master.zip) from GitHub. 17 | 2. Go to the _Plugins → Add New_ screen in your WordPress admin panel and click the __Upload__ button at the top next to the "Add Plugins" title. 18 | 3. Upload the zipped archive. 19 | 4. Click the __Activate Plugin__ link after installation completes. 20 | 21 | ### Manual 22 | 23 | 1. Download the [latest release](https://github.com/cedaro/infinite-wp-list-tables/archive/master.zip) from GitHub. 24 | 2. Unzip the archive. 25 | 3. Copy the folder to `/wp-content/plugins/`. 26 | 4. Go to the _Plugins → Installed Plugins_ screen in your WordPress admin panel and click the __Activate__ link under the _Infinite WP List Tables_ item. 27 | 28 | Read the Codex for more information about [installing plugins manually](http://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation). 29 | 30 | ### Git 31 | 32 | Clone this repository in `/wp-content/plugins/`: 33 | 34 | `git clone git@github.com:cedaro/infinite-wp-list-tables.git` 35 | 36 | Then go to the _Plugins → Installed Plugins_ screen in your WordPress admin panel and click the __Activate__ link under the _Infinite WP List Tables_ item. 37 | 38 | ## Changelog 39 | 40 | ### 2.0.0 41 | 42 | * Rewrote the plugin to add support for the comment list table and BuddyPress. 43 | * Added a filter to make it easier for plugins with custom list tables to add integration. 44 | * Added support for loading translation files. 45 | * Bundled the unminified version of jquery.infinitescroll.js for use when `SCRIPT_DEBUG` is enabled. 46 | * Ensure the pagination links aren't hidden to more easily navigate many pages. 47 | 48 | ### 1.0.0 49 | 50 | * Initial release. 51 | -------------------------------------------------------------------------------- /infinite-wp-list-tables.php: -------------------------------------------------------------------------------- 1 | load_textdomain(); 39 | $this->register_hooks(); 40 | } 41 | 42 | /** 43 | * Localize the plugin's strings. 44 | * 45 | * @since 2.0.0 46 | */ 47 | public function load_textdomain() { 48 | $plugin_rel_path = dirname( plugin_basename( __FILE__ ) ) . '/languages'; 49 | load_plugin_textdomain( 'infinite-wp-list-tables', false, $plugin_rel_path ); 50 | } 51 | 52 | /** 53 | * Register hooks. 54 | * 55 | * @since 2.0.0 56 | */ 57 | public function register_hooks() { 58 | add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) ); 59 | add_action( 'admin_head', array( $this, 'print_css' ) ); 60 | add_action( 'admin_print_footer_scripts', array( $this, 'print_script' ) ); 61 | } 62 | 63 | /** 64 | * Enqueue and print assets to make WP List Tables support infinite scroll. 65 | * 66 | * @since 2.0.0 67 | */ 68 | public function enqueue_assets( $hook_suffix ) { 69 | $suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min'; 70 | 71 | wp_enqueue_script( 72 | 'jquery-infinite-scroll', 73 | plugin_dir_url( __FILE__ ) . 'assets/js/vendor/jquery.infinitescroll' . $suffix . '.js', 74 | array( 'jquery' ), 75 | '2.1.0', 76 | true 77 | ); 78 | 79 | wp_localize_script( 'jquery-infinite-scroll', '_iwpltSettings', array( 80 | 'l10n' => array( 81 | 'loadingMessage' => __( 'Loading…', 'infinite-wp-list-tables' ), 82 | ), 83 | 'selectors' => $this->get_selectors(), 84 | ) ); 85 | } 86 | 87 | /** 88 | * Print CSS to support the Infinite Scroll script. 89 | * 90 | * @since 2.0.0 91 | */ 92 | public function print_css() { 93 | ?> 94 | 107 | 117 | 147 | id; 159 | 160 | $selectors = array( 161 | 'content' => '#the-list', 162 | 'item' => '#the-list tr', 163 | 'table' => '.wp-list-table', 164 | ); 165 | 166 | // Comment List Table 167 | if ( 'edit-comments' == $screen_id ) { 168 | $selectors = array( 169 | 'content' => '#the-comment-list', 170 | 'item' => '#the-comment-list tr', 171 | 'table' => 'table.comments', 172 | ); 173 | } 174 | 175 | // BuddyPress Activity List Table 176 | if ( 'toplevel_page_bp-activity' == $screen_id ) { 177 | $selectors = array( 178 | 'content' => '#the-comment-list', 179 | 'item' => '#the-comment-list tr', 180 | 'table' => 'table.activities', 181 | ); 182 | } 183 | 184 | // BuddyPress Group List Table 185 | if ( 'toplevel_page_bp-groups' == $screen_id ) { 186 | $selectors = array( 187 | 'content' => '#the-comment-list', 188 | 'item' => '#the-comment-list tr', 189 | 'table' => 'table.groups', 190 | ); 191 | } 192 | 193 | return apply_filters( 'infinite_wp_list_tables_selectors', $selectors ); 194 | } 195 | } 196 | 197 | /** 198 | * Initialize the plugin. 199 | */ 200 | $infinite_wp_list_tables = new Cedaro_Infinite_WP_List_Tables(); 201 | add_action( 'plugins_loaded', array( $infinite_wp_list_tables, 'load' ) ); 202 | -------------------------------------------------------------------------------- /assets/js/vendor/jquery.infinitescroll.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | -------------------------------- 3 | Infinite Scroll 4 | -------------------------------- 5 | + https://github.com/paulirish/infinite-scroll 6 | + version 2.1.0 7 | + Copyright 2011/12 Paul Irish & Luke Shumard 8 | + Licensed under the MIT license 9 | 10 | + Documentation: http://infinite-scroll.com/ 11 | */ 12 | ;(function(e){if(typeof define==="function"&&define.amd){define(["jquery"],e)}else{e(jQuery)}})(function(e,t){"use strict";e.infinitescroll=function(n,r,i){this.element=e(i);if(!this._create(n,r)){this.failed=true}};e.infinitescroll.defaults={loading:{finished:t,finishedMsg:"Congratulations, you've reached the end of the internet.",img:"data:image/gif;base64,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",msg:null,msgText:"Loading the next set of posts...",selector:null,speed:"fast",start:t},state:{isDuringAjax:false,isInvalidPage:false,isDestroyed:false,isDone:false,isPaused:false,isBeyondMaxPage:false,currPage:1},debug:false,behavior:t,binder:e(window),nextSelector:"div.navigation a:first",navSelector:"div.navigation",contentSelector:null,extraScrollPx:150,itemSelector:"div.post",animate:false,pathParse:t,dataType:"html",appendCallback:true,bufferPx:40,errorCallback:function(){},infid:0,pixelsFromNavToBottom:t,path:t,prefill:false,maxPage:t};e.infinitescroll.prototype={_binding:function(n){var r=this,i=r.options;i.v="2.0b2.120520";if(!!i.behavior&&this["_binding_"+i.behavior]!==t){this["_binding_"+i.behavior].call(this);return}if(n!=="bind"&&n!=="unbind"){this._debug("Binding value "+n+" not valid");return false}if(n==="unbind"){this.options.binder.unbind("smartscroll.infscr."+r.options.infid)}else{this.options.binder[n]("smartscroll.infscr."+r.options.infid,function(){r.scroll()})}this._debug("Binding",n)},_create:function(r,i){var s=e.extend(true,{},e.infinitescroll.defaults,r);this.options=s;var o=e(window);var u=this;if(!u._validate(r)){return false}var a=e(s.nextSelector).attr("href");if(!a){this._debug("Navigation selector not found");return false}s.path=s.path||this._determinepath(a);s.contentSelector=s.contentSelector||this.element;s.loading.selector=s.loading.selector||s.contentSelector;s.loading.msg=s.loading.msg||e('
Loading...
'+s.loading.msgText+"
");(new Image).src=s.loading.img;if(s.pixelsFromNavToBottom===t){s.pixelsFromNavToBottom=e(document).height()-e(s.navSelector).offset().top;this._debug("pixelsFromNavToBottom: "+s.pixelsFromNavToBottom)}var f=this;s.loading.start=s.loading.start||function(){e(s.navSelector).hide();s.loading.msg.appendTo(s.loading.selector).show(s.loading.speed,e.proxy(function(){this.beginAjax(s)},f))};s.loading.finished=s.loading.finished||function(){if(!s.state.isBeyondMaxPage)s.loading.msg.fadeOut(s.loading.speed)};s.callback=function(n,r,u){if(!!s.behavior&&n["_callback_"+s.behavior]!==t){n["_callback_"+s.behavior].call(e(s.contentSelector)[0],r,u)}if(i){i.call(e(s.contentSelector)[0],r,s,u)}if(s.prefill){o.bind("resize.infinite-scroll",n._prefill)}};if(r.debug){if(Function.prototype.bind&&(typeof console==="object"||typeof console==="function")&&typeof console.log==="object"){["log","info","warn","error","assert","dir","clear","profile","profileEnd"].forEach(function(e){console[e]=this.call(console[e],console)},Function.prototype.bind)}}this._setup();if(s.prefill){this._prefill()}return true},_prefill:function(){function i(){return e(n.options.contentSelector).height()<=r.height()}var n=this;var r=e(window);this._prefill=function(){if(i()){n.scroll()}r.bind("resize.infinite-scroll",function(){if(i()){r.unbind("resize.infinite-scroll");n.scroll()}})};this._prefill()},_debug:function(){if(true!==this.options.debug){return}if(typeof console!=="undefined"&&typeof console.log==="function"){if(Array.prototype.slice.call(arguments).length===1&&typeof Array.prototype.slice.call(arguments)[0]==="string"){console.log(Array.prototype.slice.call(arguments).toString())}else{console.log(Array.prototype.slice.call(arguments))}}else if(!Function.prototype.bind&&typeof console!=="undefined"&&typeof console.log==="object"){Function.prototype.call.call(console.log,console,Array.prototype.slice.call(arguments))}},_determinepath:function(n){var r=this.options;if(!!r.behavior&&this["_determinepath_"+r.behavior]!==t){return this["_determinepath_"+r.behavior].call(this,n)}if(!!r.pathParse){this._debug("pathParse manual");return r.pathParse(n,this.options.state.currPage+1)}else if(n.match(/^(.*?)\b2\b(.*?$)/)){n=n.match(/^(.*?)\b2\b(.*?$)/).slice(1)}else if(n.match(/^(.*?)2(.*?$)/)){if(n.match(/^(.*?page=)2(\/.*|$)/)){n=n.match(/^(.*?page=)2(\/.*|$)/).slice(1);return n}n=n.match(/^(.*?)2(.*?$)/).slice(1)}else{if(n.match(/^(.*?page=)1(\/.*|$)/)){n=n.match(/^(.*?page=)1(\/.*|$)/).slice(1);return n}else{this._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.");r.state.isInvalidPage=true}}this._debug("determinePath",n);return n},_error:function(n){var r=this.options;if(!!r.behavior&&this["_error_"+r.behavior]!==t){this["_error_"+r.behavior].call(this,n);return}if(n!=="destroy"&&n!=="end"){n="unknown"}this._debug("Error",n);if(n==="end"||r.state.isBeyondMaxPage){this._showdonemsg()}r.state.isDone=true;r.state.currPage=1;r.state.isPaused=false;r.state.isBeyondMaxPage=false;this._binding("unbind")},_loadcallback:function(r,i,s){var o=this.options,u=this.options.callback,a=o.state.isDone?"done":!o.appendCallback?"no-append":"append",f;if(!!o.behavior&&this["_loadcallback_"+o.behavior]!==t){this["_loadcallback_"+o.behavior].call(this,r,i);return}switch(a){case"done":this._showdonemsg();return false;case"no-append":if(o.dataType==="html"){i="
"+i+"
";i=e(i).find(o.itemSelector)}if(i.length===0){return this._error("end")}break;case"append":var l=r.children();if(l.length===0){return this._error("end")}f=document.createDocumentFragment();while(r[0].firstChild){f.appendChild(r[0].firstChild)}this._debug("contentSelector",e(o.contentSelector)[0]);e(o.contentSelector)[0].appendChild(f);i=l.get();break}o.loading.finished.call(e(o.contentSelector)[0],o);if(o.animate){var c=e(window).scrollTop()+e(o.loading.msg).height()+o.extraScrollPx+"px";e("html,body").animate({scrollTop:c},800,function(){o.state.isDuringAjax=false})}if(!o.animate){o.state.isDuringAjax=false}u(this,i,s);if(o.prefill){this._prefill()}},_nearbottom:function(){var r=this.options,i=0+e(document).height()-r.binder.scrollTop()-e(window).height();if(!!r.behavior&&this["_nearbottom_"+r.behavior]!==t){return this["_nearbottom_"+r.behavior].call(this)}this._debug("math:",i,r.pixelsFromNavToBottom);return i-r.bufferPx-1&&e(n[r]).length===0){this._debug("Your "+r+" found no elements.");return false}}return true},bind:function(){this._binding("bind")},destroy:function(){this.options.state.isDestroyed=true;this.options.loading.finished();return this._error("destroy")},pause:function(){this._pausing("pause")},resume:function(){this._pausing("resume")},beginAjax:function(r){var i=this,s=r.path,o,u,a,f;r.state.currPage++;if(r.maxPage!==t&&r.state.currPage>r.maxPage){r.state.isBeyondMaxPage=true;this.destroy();return}o=e(r.contentSelector).is("table, tbody")?e(""):e("
");u=typeof s==="function"?s(r.state.currPage):s.join(r.state.currPage);i._debug("heading into ajax",u);a=r.dataType==="html"||r.dataType==="json"?r.dataType:"html+callback";if(r.appendCallback&&r.dataType==="html"){a+="+callback"}switch(a){case"html+callback":i._debug("Using HTML via .load() method");o.load(u+" "+r.itemSelector,t,function(t){i._loadcallback(o,t,u)});break;case"html":i._debug("Using "+a.toUpperCase()+" via $.ajax() method");e.ajax({url:u,dataType:r.dataType,complete:function(t,n){f=typeof t.isResolved!=="undefined"?t.isResolved():n==="success"||n==="notmodified";if(f){i._loadcallback(o,t.responseText,u)}else{i._error("end")}}});break;case"json":i._debug("Using "+a.toUpperCase()+" via $.ajax() method");e.ajax({dataType:"json",type:"GET",url:u,success:function(e,n,s){f=typeof s.isResolved!=="undefined"?s.isResolved():n==="success"||n==="notmodified";if(r.appendCallback){if(r.template!==t){var a=r.template(e);o.append(a);if(f){i._loadcallback(o,a)}else{i._error("end")}}else{i._debug("template must be defined.");i._error("end")}}else{if(f){i._loadcallback(o,e,u)}else{i._error("end")}}},error:function(){i._debug("JSON ajax request failed.");i._error("end")}});break}},retrieve:function(r){r=r||null;var i=this,s=i.options;if(!!s.behavior&&this["retrieve_"+s.behavior]!==t){this["retrieve_"+s.behavior].call(this,r);return}if(s.state.isDestroyed){this._debug("Instance is destroyed");return false}s.state.isDuringAjax=true;s.loading.start.call(e(s.contentSelector)[0],s)},scroll:function(){var n=this.options,r=n.state;if(!!n.behavior&&this["scroll_"+n.behavior]!==t){this["scroll_"+n.behavior].call(this);return}if(r.isDuringAjax||r.isInvalidPage||r.isDone||r.isDestroyed||r.isPaused){return}if(!this._nearbottom()){return}this.retrieve()},toggle:function(){this._pausing()},unbind:function(){this._binding("unbind")},update:function(n){if(e.isPlainObject(n)){this.options=e.extend(true,this.options,n)}}};e.fn.infinitescroll=function(n,r){var i=typeof n;switch(i){case"string":var s=Array.prototype.slice.call(arguments,1);this.each(function(){var t=e.data(this,"infinitescroll");if(!t){return false}if(!e.isFunction(t[n])||n.charAt(0)==="_"){return false}t[n].apply(t,s)});break;case"object":this.each(function(){var t=e.data(this,"infinitescroll");if(t){t.update(n)}else{t=new e.infinitescroll(n,r,this);if(!t.failed){e.data(this,"infinitescroll",t)}}});break}return this};var n=e.event,r;n.special.smartscroll={setup:function(){e(this).bind("scroll",n.special.smartscroll.handler)},teardown:function(){e(this).unbind("scroll",n.special.smartscroll.handler)},handler:function(t,n){var i=this,s=arguments;t.type="smartscroll";if(r){clearTimeout(r)}r=setTimeout(function(){e(i).trigger("smartscroll",s)},n==="execAsap"?0:100)}};e.fn.smartscroll=function(e){return e?this.bind("smartscroll",e):this.trigger("smartscroll",["execAsap"])}}); 13 | -------------------------------------------------------------------------------- /assets/js/vendor/jquery.infinitescroll.js: -------------------------------------------------------------------------------- 1 | /*global jQuery: true */ 2 | 3 | /*! 4 | -------------------------------- 5 | Infinite Scroll 6 | -------------------------------- 7 | + https://github.com/paulirish/infinite-scroll 8 | + version 2.1.0 9 | + Copyright 2011/12 Paul Irish & Luke Shumard 10 | + Licensed under the MIT license 11 | 12 | + Documentation: http://infinite-scroll.com/ 13 | */ 14 | 15 | // Uses AMD or browser globals to create a jQuery plugin. 16 | (function (factory) { 17 | if (typeof define === 'function' && define.amd) { 18 | // AMD. Register as an anonymous module. 19 | define(['jquery'], factory); 20 | } else { 21 | // Browser globals 22 | factory(jQuery); 23 | } 24 | }(function ($, undefined) { 25 | 'use strict'; 26 | 27 | $.infinitescroll = function infscr(options, callback, element) { 28 | this.element = $(element); 29 | 30 | // Flag the object in the event of a failed creation 31 | if (!this._create(options, callback)) { 32 | this.failed = true; 33 | } 34 | }; 35 | 36 | $.infinitescroll.defaults = { 37 | loading: { 38 | finished: undefined, 39 | finishedMsg: "Congratulations, you've reached the end of the internet.", 40 | img: 'data:image/gif;base64,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', 41 | msg: null, 42 | msgText: 'Loading the next set of posts...', 43 | selector: null, 44 | speed: 'fast', 45 | start: undefined 46 | }, 47 | state: { 48 | isDuringAjax: false, 49 | isInvalidPage: false, 50 | isDestroyed: false, 51 | isDone: false, // For when it goes all the way through the archive. 52 | isPaused: false, 53 | isBeyondMaxPage: false, 54 | currPage: 1 55 | }, 56 | debug: false, 57 | behavior: undefined, 58 | binder: $(window), // used to cache the selector 59 | nextSelector: 'div.navigation a:first', 60 | navSelector: 'div.navigation', 61 | contentSelector: null, // rename to pageFragment 62 | extraScrollPx: 150, 63 | itemSelector: 'div.post', 64 | animate: false, 65 | pathParse: undefined, 66 | dataType: 'html', 67 | appendCallback: true, 68 | bufferPx: 40, 69 | errorCallback: function () { }, 70 | infid: 0, //Instance ID 71 | pixelsFromNavToBottom: undefined, 72 | path: undefined, // Either parts of a URL as an array (e.g. ["/page/", "/"] or a function that takes in the page number and returns a URL 73 | prefill: false, // When the document is smaller than the window, load data until the document is larger or links are exhausted 74 | maxPage: undefined // to manually control maximum page (when maxPage is undefined, maximum page limitation is not work) 75 | }; 76 | 77 | $.infinitescroll.prototype = { 78 | 79 | /* 80 | ---------------------------- 81 | Private methods 82 | ---------------------------- 83 | */ 84 | 85 | // Bind or unbind from scroll 86 | _binding: function infscr_binding(binding) { 87 | 88 | var instance = this, 89 | opts = instance.options; 90 | 91 | opts.v = '2.0b2.120520'; 92 | 93 | // if behavior is defined and this function is extended, call that instead of default 94 | if (!!opts.behavior && this['_binding_'+opts.behavior] !== undefined) { 95 | this['_binding_'+opts.behavior].call(this); 96 | return; 97 | } 98 | 99 | if (binding !== 'bind' && binding !== 'unbind') { 100 | this._debug('Binding value ' + binding + ' not valid'); 101 | return false; 102 | } 103 | 104 | if (binding === 'unbind') { 105 | (this.options.binder).unbind('smartscroll.infscr.' + instance.options.infid); 106 | } else { 107 | (this.options.binder)[binding]('smartscroll.infscr.' + instance.options.infid, function () { 108 | instance.scroll(); 109 | }); 110 | } 111 | 112 | this._debug('Binding', binding); 113 | }, 114 | 115 | // Fundamental aspects of the plugin are initialized 116 | _create: function infscr_create(options, callback) { 117 | 118 | // Add custom options to defaults 119 | var opts = $.extend(true, {}, $.infinitescroll.defaults, options); 120 | this.options = opts; 121 | var $window = $(window); 122 | var instance = this; 123 | 124 | // Validate selectors 125 | if (!instance._validate(options)) { 126 | return false; 127 | } 128 | 129 | // Validate page fragment path 130 | var path = $(opts.nextSelector).attr('href'); 131 | if (!path) { 132 | this._debug('Navigation selector not found'); 133 | return false; 134 | } 135 | 136 | // Set the path to be a relative URL from root. 137 | opts.path = opts.path || this._determinepath(path); 138 | 139 | // contentSelector is 'page fragment' option for .load() / .ajax() calls 140 | opts.contentSelector = opts.contentSelector || this.element; 141 | 142 | // loading.selector - if we want to place the load message in a specific selector, defaulted to the contentSelector 143 | opts.loading.selector = opts.loading.selector || opts.contentSelector; 144 | 145 | // Define loading.msg 146 | opts.loading.msg = opts.loading.msg || $('
Loading...
' + opts.loading.msgText + '
'); 147 | 148 | // Preload loading.img 149 | (new Image()).src = opts.loading.img; 150 | 151 | // distance from nav links to bottom 152 | // computed as: height of the document + top offset of container - top offset of nav link 153 | if(opts.pixelsFromNavToBottom === undefined) { 154 | opts.pixelsFromNavToBottom = $(document).height() - $(opts.navSelector).offset().top; 155 | this._debug('pixelsFromNavToBottom: ' + opts.pixelsFromNavToBottom); 156 | } 157 | 158 | var self = this; 159 | 160 | // determine loading.start actions 161 | opts.loading.start = opts.loading.start || function() { 162 | $(opts.navSelector).hide(); 163 | opts.loading.msg 164 | .appendTo(opts.loading.selector) 165 | .show(opts.loading.speed, $.proxy(function() { 166 | this.beginAjax(opts); 167 | }, self)); 168 | }; 169 | 170 | // determine loading.finished actions 171 | opts.loading.finished = opts.loading.finished || function() { 172 | if (!opts.state.isBeyondMaxPage) 173 | opts.loading.msg.fadeOut(opts.loading.speed); 174 | }; 175 | 176 | // callback loading 177 | opts.callback = function(instance, data, url) { 178 | if (!!opts.behavior && instance['_callback_'+opts.behavior] !== undefined) { 179 | instance['_callback_'+opts.behavior].call($(opts.contentSelector)[0], data, url); 180 | } 181 | 182 | if (callback) { 183 | callback.call($(opts.contentSelector)[0], data, opts, url); 184 | } 185 | 186 | if (opts.prefill) { 187 | $window.bind('resize.infinite-scroll', instance._prefill); 188 | } 189 | }; 190 | 191 | if (options.debug) { 192 | // Tell IE9 to use its built-in console 193 | if (Function.prototype.bind && (typeof console === 'object' || typeof console === 'function') && typeof console.log === 'object') { 194 | ['log','info','warn','error','assert','dir','clear','profile','profileEnd'] 195 | .forEach(function (method) { 196 | console[method] = this.call(console[method], console); 197 | }, Function.prototype.bind); 198 | } 199 | } 200 | 201 | this._setup(); 202 | 203 | // Setups the prefill method for use 204 | if (opts.prefill) { 205 | this._prefill(); 206 | } 207 | 208 | // Return true to indicate successful creation 209 | return true; 210 | }, 211 | 212 | _prefill: function infscr_prefill() { 213 | var instance = this; 214 | var $window = $(window); 215 | 216 | function needsPrefill() { 217 | return ( $(instance.options.contentSelector).height() <= $window.height() ); 218 | } 219 | 220 | this._prefill = function() { 221 | if (needsPrefill()) { 222 | instance.scroll(); 223 | } 224 | 225 | $window.bind('resize.infinite-scroll', function() { 226 | if (needsPrefill()) { 227 | $window.unbind('resize.infinite-scroll'); 228 | instance.scroll(); 229 | } 230 | }); 231 | }; 232 | 233 | // Call self after setting up the new function 234 | this._prefill(); 235 | }, 236 | 237 | // Console log wrapper 238 | _debug: function infscr_debug() { 239 | if (true !== this.options.debug) { 240 | return; 241 | } 242 | 243 | if (typeof console !== 'undefined' && typeof console.log === 'function') { 244 | // Modern browsers 245 | // Single argument, which is a string 246 | if ((Array.prototype.slice.call(arguments)).length === 1 && typeof Array.prototype.slice.call(arguments)[0] === 'string') { 247 | console.log( (Array.prototype.slice.call(arguments)).toString() ); 248 | } else { 249 | console.log( Array.prototype.slice.call(arguments) ); 250 | } 251 | } else if (!Function.prototype.bind && typeof console !== 'undefined' && typeof console.log === 'object') { 252 | // IE8 253 | Function.prototype.call.call(console.log, console, Array.prototype.slice.call(arguments)); 254 | } 255 | }, 256 | 257 | // find the number to increment in the path. 258 | _determinepath: function infscr_determinepath(path) { 259 | 260 | var opts = this.options; 261 | 262 | // if behavior is defined and this function is extended, call that instead of default 263 | if (!!opts.behavior && this['_determinepath_'+opts.behavior] !== undefined) { 264 | return this['_determinepath_'+opts.behavior].call(this,path); 265 | } 266 | 267 | if (!!opts.pathParse) { 268 | 269 | this._debug('pathParse manual'); 270 | return opts.pathParse(path, this.options.state.currPage+1); 271 | 272 | } else if (path.match(/^(.*?)\b2\b(.*?$)/)) { 273 | path = path.match(/^(.*?)\b2\b(.*?$)/).slice(1); 274 | 275 | // if there is any 2 in the url at all. 276 | } else if (path.match(/^(.*?)2(.*?$)/)) { 277 | 278 | // page= is used in django: 279 | // http://www.infinite-scroll.com/changelog/comment-page-1/#comment-127 280 | if (path.match(/^(.*?page=)2(\/.*|$)/)) { 281 | path = path.match(/^(.*?page=)2(\/.*|$)/).slice(1); 282 | return path; 283 | } 284 | 285 | path = path.match(/^(.*?)2(.*?$)/).slice(1); 286 | 287 | } else { 288 | 289 | // page= is used in drupal too but second page is page=1 not page=2: 290 | // thx Jerod Fritz, vladikoff 291 | if (path.match(/^(.*?page=)1(\/.*|$)/)) { 292 | path = path.match(/^(.*?page=)1(\/.*|$)/).slice(1); 293 | return path; 294 | } else { 295 | this._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."); 296 | // Get rid of isInvalidPage to allow permalink to state 297 | opts.state.isInvalidPage = true; //prevent it from running on this page. 298 | } 299 | } 300 | this._debug('determinePath', path); 301 | return path; 302 | 303 | }, 304 | 305 | // Custom error 306 | _error: function infscr_error(xhr) { 307 | 308 | var opts = this.options; 309 | 310 | // if behavior is defined and this function is extended, call that instead of default 311 | if (!!opts.behavior && this['_error_'+opts.behavior] !== undefined) { 312 | this['_error_'+opts.behavior].call(this,xhr); 313 | return; 314 | } 315 | 316 | if (xhr !== 'destroy' && xhr !== 'end') { 317 | xhr = 'unknown'; 318 | } 319 | 320 | this._debug('Error', xhr); 321 | 322 | if (xhr === 'end' || opts.state.isBeyondMaxPage) { 323 | this._showdonemsg(); 324 | } 325 | 326 | opts.state.isDone = true; 327 | opts.state.currPage = 1; // if you need to go back to this instance 328 | opts.state.isPaused = false; 329 | opts.state.isBeyondMaxPage = false; 330 | this._binding('unbind'); 331 | 332 | }, 333 | 334 | // Load Callback 335 | _loadcallback: function infscr_loadcallback(box, data, url) { 336 | var opts = this.options, 337 | callback = this.options.callback, // GLOBAL OBJECT FOR CALLBACK 338 | result = (opts.state.isDone) ? 'done' : (!opts.appendCallback) ? 'no-append' : 'append', 339 | frag; 340 | 341 | // if behavior is defined and this function is extended, call that instead of default 342 | if (!!opts.behavior && this['_loadcallback_'+opts.behavior] !== undefined) { 343 | this['_loadcallback_'+opts.behavior].call(this,box,data,url); 344 | return; 345 | } 346 | 347 | switch (result) { 348 | case 'done': 349 | this._showdonemsg(); 350 | return false; 351 | 352 | case 'no-append': 353 | if (opts.dataType === 'html') { 354 | data = '
' + data + '
'; 355 | data = $(data).find(opts.itemSelector); 356 | } 357 | 358 | // if it didn't return anything 359 | if (data.length === 0) { 360 | return this._error('end'); 361 | } 362 | 363 | break; 364 | 365 | case 'append': 366 | var children = box.children(); 367 | // if it didn't return anything 368 | if (children.length === 0) { 369 | return this._error('end'); 370 | } 371 | 372 | // use a documentFragment because it works when content is going into a table or UL 373 | frag = document.createDocumentFragment(); 374 | while (box[0].firstChild) { 375 | frag.appendChild(box[0].firstChild); 376 | } 377 | 378 | this._debug('contentSelector', $(opts.contentSelector)[0]); 379 | $(opts.contentSelector)[0].appendChild(frag); 380 | // previously, we would pass in the new DOM element as context for the callback 381 | // however we're now using a documentfragment, which doesn't have parents or children, 382 | // so the context is the contentContainer guy, and we pass in an array 383 | // of the elements collected as the first argument. 384 | 385 | data = children.get(); 386 | break; 387 | } 388 | 389 | // loadingEnd function 390 | opts.loading.finished.call($(opts.contentSelector)[0],opts); 391 | 392 | // smooth scroll to ease in the new content 393 | if (opts.animate) { 394 | var scrollTo = $(window).scrollTop() + $(opts.loading.msg).height() + opts.extraScrollPx + 'px'; 395 | $('html,body').animate({ scrollTop: scrollTo }, 800, function () { opts.state.isDuringAjax = false; }); 396 | } 397 | 398 | if (!opts.animate) { 399 | // once the call is done, we can allow it again. 400 | opts.state.isDuringAjax = false; 401 | } 402 | 403 | callback(this, data, url); 404 | 405 | if (opts.prefill) { 406 | this._prefill(); 407 | } 408 | }, 409 | 410 | _nearbottom: function infscr_nearbottom() { 411 | 412 | var opts = this.options, 413 | pixelsFromWindowBottomToBottom = 0 + $(document).height() - (opts.binder.scrollTop()) - $(window).height(); 414 | 415 | // if behavior is defined and this function is extended, call that instead of default 416 | if (!!opts.behavior && this['_nearbottom_'+opts.behavior] !== undefined) { 417 | return this['_nearbottom_'+opts.behavior].call(this); 418 | } 419 | 420 | this._debug('math:', pixelsFromWindowBottomToBottom, opts.pixelsFromNavToBottom); 421 | 422 | // if distance remaining in the scroll (including buffer) is less than the orignal nav to bottom.... 423 | return (pixelsFromWindowBottomToBottom - opts.bufferPx < opts.pixelsFromNavToBottom); 424 | 425 | }, 426 | 427 | // Pause / temporarily disable plugin from firing 428 | _pausing: function infscr_pausing(pause) { 429 | 430 | var opts = this.options; 431 | 432 | // if behavior is defined and this function is extended, call that instead of default 433 | if (!!opts.behavior && this['_pausing_'+opts.behavior] !== undefined) { 434 | this['_pausing_'+opts.behavior].call(this,pause); 435 | return; 436 | } 437 | 438 | // If pause is not 'pause' or 'resume', toggle it's value 439 | if (pause !== 'pause' && pause !== 'resume' && pause !== null) { 440 | this._debug('Invalid argument. Toggling pause value instead'); 441 | } 442 | 443 | pause = (pause && (pause === 'pause' || pause === 'resume')) ? pause : 'toggle'; 444 | 445 | switch (pause) { 446 | case 'pause': 447 | opts.state.isPaused = true; 448 | break; 449 | 450 | case 'resume': 451 | opts.state.isPaused = false; 452 | break; 453 | 454 | case 'toggle': 455 | opts.state.isPaused = !opts.state.isPaused; 456 | break; 457 | } 458 | 459 | this._debug('Paused', opts.state.isPaused); 460 | return false; 461 | 462 | }, 463 | 464 | // Behavior is determined 465 | // If the behavior option is undefined, it will set to default and bind to scroll 466 | _setup: function infscr_setup() { 467 | 468 | var opts = this.options; 469 | 470 | // if behavior is defined and this function is extended, call that instead of default 471 | if (!!opts.behavior && this['_setup_'+opts.behavior] !== undefined) { 472 | this['_setup_'+opts.behavior].call(this); 473 | return; 474 | } 475 | 476 | this._binding('bind'); 477 | 478 | return false; 479 | 480 | }, 481 | 482 | // Show done message 483 | _showdonemsg: function infscr_showdonemsg() { 484 | 485 | var opts = this.options; 486 | 487 | // if behavior is defined and this function is extended, call that instead of default 488 | if (!!opts.behavior && this['_showdonemsg_'+opts.behavior] !== undefined) { 489 | this['_showdonemsg_'+opts.behavior].call(this); 490 | return; 491 | } 492 | 493 | opts.loading.msg 494 | .find('img') 495 | .hide() 496 | .parent() 497 | .find('div').html(opts.loading.finishedMsg).animate({ opacity: 1 }, 2000, function () { 498 | $(this).parent().fadeOut(opts.loading.speed); 499 | }); 500 | 501 | // user provided callback when done 502 | opts.errorCallback.call($(opts.contentSelector)[0],'done'); 503 | }, 504 | 505 | // grab each selector option and see if any fail 506 | _validate: function infscr_validate(opts) { 507 | for (var key in opts) { 508 | if (key.indexOf && key.indexOf('Selector') > -1 && $(opts[key]).length === 0) { 509 | this._debug('Your ' + key + ' found no elements.'); 510 | return false; 511 | } 512 | } 513 | 514 | return true; 515 | }, 516 | 517 | /* 518 | ---------------------------- 519 | Public methods 520 | ---------------------------- 521 | */ 522 | 523 | // Bind to scroll 524 | bind: function infscr_bind() { 525 | this._binding('bind'); 526 | }, 527 | 528 | // Destroy current instance of plugin 529 | destroy: function infscr_destroy() { 530 | this.options.state.isDestroyed = true; 531 | this.options.loading.finished(); 532 | return this._error('destroy'); 533 | }, 534 | 535 | // Set pause value to false 536 | pause: function infscr_pause() { 537 | this._pausing('pause'); 538 | }, 539 | 540 | // Set pause value to false 541 | resume: function infscr_resume() { 542 | this._pausing('resume'); 543 | }, 544 | 545 | beginAjax: function infscr_ajax(opts) { 546 | var instance = this, 547 | path = opts.path, 548 | box, desturl, method, condition; 549 | 550 | // increment the URL bit. e.g. /page/3/ 551 | opts.state.currPage++; 552 | 553 | // Manually control maximum page 554 | if ( opts.maxPage !== undefined && opts.state.currPage > opts.maxPage ){ 555 | opts.state.isBeyondMaxPage = true; 556 | this.destroy(); 557 | return; 558 | } 559 | 560 | // if we're dealing with a table we can't use DIVs 561 | box = $(opts.contentSelector).is('table, tbody') ? $('') : $('
'); 562 | 563 | desturl = (typeof path === 'function') ? path(opts.state.currPage) : path.join(opts.state.currPage); 564 | instance._debug('heading into ajax', desturl); 565 | 566 | method = (opts.dataType === 'html' || opts.dataType === 'json' ) ? opts.dataType : 'html+callback'; 567 | if (opts.appendCallback && opts.dataType === 'html') { 568 | method += '+callback'; 569 | } 570 | 571 | switch (method) { 572 | case 'html+callback': 573 | instance._debug('Using HTML via .load() method'); 574 | box.load(desturl + ' ' + opts.itemSelector, undefined, function infscr_ajax_callback(responseText) { 575 | instance._loadcallback(box, responseText, desturl); 576 | }); 577 | 578 | break; 579 | 580 | case 'html': 581 | instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 582 | $.ajax({ 583 | // params 584 | url: desturl, 585 | dataType: opts.dataType, 586 | complete: function infscr_ajax_callback(jqXHR, textStatus) { 587 | condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 588 | if (condition) { 589 | instance._loadcallback(box, jqXHR.responseText, desturl); 590 | } else { 591 | instance._error('end'); 592 | } 593 | } 594 | }); 595 | 596 | break; 597 | case 'json': 598 | instance._debug('Using ' + (method.toUpperCase()) + ' via $.ajax() method'); 599 | $.ajax({ 600 | dataType: 'json', 601 | type: 'GET', 602 | url: desturl, 603 | success: function (data, textStatus, jqXHR) { 604 | condition = (typeof (jqXHR.isResolved) !== 'undefined') ? (jqXHR.isResolved()) : (textStatus === 'success' || textStatus === 'notmodified'); 605 | if (opts.appendCallback) { 606 | // if appendCallback is true, you must defined template in options. 607 | // note that data passed into _loadcallback is already an html (after processed in opts.template(data)). 608 | if (opts.template !== undefined) { 609 | var theData = opts.template(data); 610 | box.append(theData); 611 | if (condition) { 612 | instance._loadcallback(box, theData); 613 | } else { 614 | instance._error('end'); 615 | } 616 | } else { 617 | instance._debug('template must be defined.'); 618 | instance._error('end'); 619 | } 620 | } else { 621 | // if appendCallback is false, we will pass in the JSON object. you should handle it yourself in your callback. 622 | if (condition) { 623 | instance._loadcallback(box, data, desturl); 624 | } else { 625 | instance._error('end'); 626 | } 627 | } 628 | }, 629 | error: function() { 630 | instance._debug('JSON ajax request failed.'); 631 | instance._error('end'); 632 | } 633 | }); 634 | 635 | break; 636 | } 637 | }, 638 | 639 | // Retrieve next set of content items 640 | retrieve: function infscr_retrieve(pageNum) { 641 | pageNum = pageNum || null; 642 | 643 | var instance = this, 644 | opts = instance.options; 645 | 646 | // if behavior is defined and this function is extended, call that instead of default 647 | if (!!opts.behavior && this['retrieve_'+opts.behavior] !== undefined) { 648 | this['retrieve_'+opts.behavior].call(this,pageNum); 649 | return; 650 | } 651 | 652 | // for manual triggers, if destroyed, get out of here 653 | if (opts.state.isDestroyed) { 654 | this._debug('Instance is destroyed'); 655 | return false; 656 | } 657 | 658 | // we dont want to fire the ajax multiple times 659 | opts.state.isDuringAjax = true; 660 | 661 | opts.loading.start.call($(opts.contentSelector)[0],opts); 662 | }, 663 | 664 | // Check to see next page is needed 665 | scroll: function infscr_scroll() { 666 | 667 | var opts = this.options, 668 | state = opts.state; 669 | 670 | // if behavior is defined and this function is extended, call that instead of default 671 | if (!!opts.behavior && this['scroll_'+opts.behavior] !== undefined) { 672 | this['scroll_'+opts.behavior].call(this); 673 | return; 674 | } 675 | 676 | if (state.isDuringAjax || state.isInvalidPage || state.isDone || state.isDestroyed || state.isPaused) { 677 | return; 678 | } 679 | 680 | if (!this._nearbottom()) { 681 | return; 682 | } 683 | 684 | this.retrieve(); 685 | 686 | }, 687 | 688 | // Toggle pause value 689 | toggle: function infscr_toggle() { 690 | this._pausing(); 691 | }, 692 | 693 | // Unbind from scroll 694 | unbind: function infscr_unbind() { 695 | this._binding('unbind'); 696 | }, 697 | 698 | // update options 699 | update: function infscr_options(key) { 700 | if ($.isPlainObject(key)) { 701 | this.options = $.extend(true,this.options,key); 702 | } 703 | } 704 | }; 705 | 706 | 707 | /* 708 | ---------------------------- 709 | Infinite Scroll function 710 | ---------------------------- 711 | 712 | Borrowed logic from the following... 713 | 714 | jQuery UI 715 | - https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.widget.js 716 | 717 | jCarousel 718 | - https://github.com/jsor/jcarousel/blob/master/lib/jquery.jcarousel.js 719 | 720 | Masonry 721 | - https://github.com/desandro/masonry/blob/master/jquery.masonry.js 722 | 723 | */ 724 | 725 | $.fn.infinitescroll = function infscr_init(options, callback) { 726 | 727 | 728 | var thisCall = typeof options; 729 | 730 | switch (thisCall) { 731 | 732 | // method 733 | case 'string': 734 | var args = Array.prototype.slice.call(arguments, 1); 735 | 736 | this.each(function () { 737 | var instance = $.data(this, 'infinitescroll'); 738 | 739 | if (!instance) { 740 | // not setup yet 741 | // return $.error('Method ' + options + ' cannot be called until Infinite Scroll is setup'); 742 | return false; 743 | } 744 | 745 | if (!$.isFunction(instance[options]) || options.charAt(0) === '_') { 746 | // return $.error('No such method ' + options + ' for Infinite Scroll'); 747 | return false; 748 | } 749 | 750 | // no errors! 751 | instance[options].apply(instance, args); 752 | }); 753 | 754 | break; 755 | 756 | // creation 757 | case 'object': 758 | 759 | this.each(function () { 760 | 761 | var instance = $.data(this, 'infinitescroll'); 762 | 763 | if (instance) { 764 | 765 | // update options of current instance 766 | instance.update(options); 767 | 768 | } else { 769 | 770 | // initialize new instance 771 | instance = new $.infinitescroll(options, callback, this); 772 | 773 | // don't attach if instantiation failed 774 | if (!instance.failed) { 775 | $.data(this, 'infinitescroll', instance); 776 | } 777 | 778 | } 779 | 780 | }); 781 | 782 | break; 783 | 784 | } 785 | 786 | return this; 787 | }; 788 | 789 | 790 | 791 | /* 792 | * smartscroll: debounced scroll event for jQuery * 793 | * https://github.com/lukeshumard/smartscroll 794 | * Based on smartresize by @louis_remi: https://github.com/lrbabe/jquery.smartresize.js * 795 | * Copyright 2011 Louis-Remi & Luke Shumard * Licensed under the MIT license. * 796 | */ 797 | 798 | var event = $.event, 799 | scrollTimeout; 800 | 801 | event.special.smartscroll = { 802 | setup: function () { 803 | $(this).bind('scroll', event.special.smartscroll.handler); 804 | }, 805 | teardown: function () { 806 | $(this).unbind('scroll', event.special.smartscroll.handler); 807 | }, 808 | handler: function (event, execAsap) { 809 | // Save the context 810 | var context = this, 811 | args = arguments; 812 | 813 | // set correct event type 814 | event.type = 'smartscroll'; 815 | 816 | if (scrollTimeout) { clearTimeout(scrollTimeout); } 817 | scrollTimeout = setTimeout(function () { 818 | $(context).trigger('smartscroll', args); 819 | }, execAsap === 'execAsap' ? 0 : 100); 820 | } 821 | }; 822 | 823 | $.fn.smartscroll = function (fn) { 824 | return fn ? this.bind('smartscroll', fn) : this.trigger('smartscroll', ['execAsap']); 825 | }; 826 | 827 | })); 828 | --------------------------------------------------------------------------------