WordPress.org

Make WordPress Core

Changeset 19971


Ignore:
Timestamp:
02/21/2012 07:44:10 PM (9 years ago)
Author:
koopersmith
Message:

Second pass at infinite scroll for themes, including polling, fixed paging, and fewer ajax calls. props DH-Shredder, helenyhou, garyc40. see #19815.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-admin/js/theme.dev.js

    r19893 r19971  
    4646        };
    4747
    48     return api;
     48    return api;
    4949    }
    5050})(jQuery);
     
    5555});
    5656
    57 var wpThemes;
     57var ThemeScroller;
    5858
    5959(function($){
    60     var inputs = {}, Query;
     60    ThemeScroller = {
     61        // Inputs
     62        nonce: '',
     63        search: '',
     64        tab: '',
     65        type: '',
     66        nextPage: 2,
     67        features: {},
    6168
    62     wpThemes = {
    63         timeToTriggerQuery: 150,
    64         minQueryAJAXDuration: 200,
    65         outListBottomThreshold: 200,
    66         noMoreResults: false,
    67        
    68         init : function() {
     69        // Preferences
     70        scrollPollingDelay: 500,
     71        failedRetryDelay: 4000,
     72        outListBottomThreshold: 300,
     73
     74        // Flags
     75        scrolling: false,
     76        querying: false,
     77
     78        init: function() {
     79            var self = this,
     80                startPage,
     81                queryArray = {},
     82                queryString = window.location.search;
     83
     84            // We're using infinite scrolling, so hide all pagination.
    6985            $('.pagination-links').hide();
    7086
    71             inputs.nonce = $('#_ajax_fetch_list_nonce').val();
    72    
    73             // Parse Query
    74             inputs.queryString = window.location.search;           
    75             inputs.queryArray = wpThemes.parseQuery( inputs.queryString.substring( 1 ) );
     87            // Parse GET query string
     88            queryArray = this.parseQuery( queryString.substring( 1 ) );
    7689
    77             // Handle Inputs from Query
    78             inputs.search = inputs.queryArray['s'];
    79             inputs.features = inputs.queryArray['features'];
    80             inputs.startPage = parseInt( inputs.queryArray['paged'] ); 
    81             inputs.tab = inputs.queryArray['tab'];
    82             inputs.type = inputs.queryArray['type'];
     90            // Handle inputs
     91            this.nonce = $('#_ajax_fetch_list_nonce').val();
     92            this.search = queryArray['s'];
     93            this.features = queryArray['features'];
     94            this.tab = queryArray['tab'];
     95            this.type = queryArray['type'];
    8396
    84             if ( isNaN( inputs.startPage ) )
    85                 inputs.startPage = 2;
    86             else
    87                 inputs.startPage++;
     97            startPage = parseInt( queryArray['paged'], 10 );
     98            if ( ! isNaN( startPage ) )
     99                this.nextPage = ( startPage + 1 );
    88100
    89             // Cache jQuery objects
    90             inputs.outList = $('#availablethemes');
    91             inputs.waiting = $('div.tablenav.bottom').children( 'img.ajax-loading' );
    92             inputs.window = $(window);
     101            // Cache jQuery selectors
     102            this.$outList = $('#availablethemes');
     103            this.$spinner = $('div.tablenav.bottom').children( 'img.ajax-loading' );
     104            this.$window = $(window);
     105            this.$document = $(document);
    93106
    94             // Generate Query
    95             wpThemes.query = new Query();
     107            if ( $('.tablenav-pages').length )
     108                this.pollInterval =
     109                    setInterval( function() {
     110                        return self.poll();
     111                    }, this.scrollPollingDelay );
     112        },
     113        poll: function() {
     114            var bottom = this.$document.scrollTop() + this.$window.innerHeight();
    96115
    97             // Start Polling
    98             inputs.window.scroll( function(){ wpThemes.maybeLoad(); } );
    99         },
    100         delayedCallback : function( func, delay ) {
    101             var timeoutTriggered, funcTriggered, funcArgs, funcContext;
    102 
    103             if ( ! delay )
    104                 return func;
    105 
    106             setTimeout( function() {
    107                 if ( funcTriggered )
    108                     return func.apply( funcContext, funcArgs );
    109                 // Otherwise, wait.
    110                 timeoutTriggered = true;
    111             }, delay);
    112 
    113             return function() {
    114                 if ( timeoutTriggered )
    115                     return func.apply( this, arguments );
    116                 // Otherwise, wait.
    117                 funcArgs = arguments;
    118                 funcContext = this;
    119                 funcTriggered = true;
    120             };
    121         },
    122         ajax: function( callback ) {
    123             var self = this,
    124                 response = wpThemes.delayedCallback( function( results, params ) {
    125                     self.process( results, params );
    126                     if ( callback )
    127                         callback( results, params );
    128                 }, wpThemes.minQueryAJAXDuration );
    129 
    130             this.query.ajax( response );
    131         },
    132         process: function( results, params ) {
    133             // If no Results, for now, mark as no Matches, and bail.
    134             // Alternately: inputs.outList.append(wpThemesL10n.noMatchesFound);
    135             if ( ( results === undefined ) ||
    136                  ( results.rows.indexOf( "no-items" ) != -1 ) ) {
    137                 this.noMoreResults = true;
    138             } else {
    139                 inputs.outList.append( results.rows );
    140             }
    141         },
    142         maybeLoad: function() {
    143             var self = this,
    144                 el = $(document),
    145                 bottom = el.scrollTop() + inputs.window.innerHeight();
    146                
    147             if ( this.noMoreResults ||
    148                  !this.query.ready() ||
    149                  ( bottom < inputs.outList.height() - wpThemes.outListBottomThreshold ) )
     116            if ( this.querying ||
     117                ( bottom < this.$outList.height() - this.outListBottomThreshold ) )
    150118                return;
    151119
    152             setTimeout( function() {
    153                 var newTop = el.scrollTop(),
    154                     newBottom = newTop + inputs.window.innerHeight();
     120            this.ajax();
     121        },
     122        process: function( results ) {
     123            if ( ( results === undefined ) ||
     124                ( results.rows.indexOf( 'no-items' ) != -1 ) ) {
     125                clearInterval( this.pollInterval );
     126                return;
     127            }
    155128
    156                 if ( !self.query.ready() ||
    157                      ( newBottom < inputs.outList.height() - wpThemes.outListBottomThreshold ) )
    158                     return;
     129            var totalPages = parseInt( results.total_pages, 10 );
     130            if ( this.nextPage > totalPages )
     131                clearInterval( this.pollInterval );
    159132
    160                 inputs.waiting.css( 'visibility', 'visible' ); // Show Spinner
    161                 self.ajax( function() { inputs.waiting.css( 'visibility', 'hidden' ) } ); // Hide Spinner
    162                
    163             }, wpThemes.timeToTriggerQuery );
     133            if ( this.nextPage <= ( totalPages + 1 ) )
     134                this.$outList.append( results.rows );
     135        },
     136        ajax: function() {
     137            var self = this;
     138            this.querying = true;
     139
     140            var query = {
     141                action: 'fetch-list',
     142                tab: this.tab,
     143                paged: this.nextPage,
     144                s: this.search,
     145                type: this.type,
     146                _ajax_fetch_list_nonce: this.nonce,
     147                'features[]': this.features,
     148                'list_args': list_args
     149            };
     150
     151            this.$spinner.css( 'visibility', 'visible' );
     152            $.getJSON( ajaxurl, query )
     153                .done( function( response ) {
     154                    self.nextPage++;
     155                    self.process( response );
     156                    self.$spinner.css( 'visibility', 'hidden' );
     157                    self.querying = false;
     158                })
     159                .fail( function() {
     160                    self.$spinner.css( 'visibility', 'hidden' );
     161                    self.querying = false;
     162                    setTimeout( function() { self.ajax(); }, self.failedRetryDelay )
     163                });
    164164        },
    165165        parseQuery: function( query ) {
    166             var Params = {};
    167             if ( ! query ) {return Params;}// return empty object
    168             var Pairs = query.split(/[;&]/);
    169             for ( var i = 0; i < Pairs.length; i++ ) {
    170                 var KeyVal = Pairs[i].split('=');
    171                 if ( ! KeyVal || KeyVal.length != 2 ) {continue;}
    172                 var key = unescape( KeyVal[0] );
    173                 var val = unescape( KeyVal[1] );
    174                 val = val.replace(/\+/g, ' ');
    175                 key = key.replace(/\[.*\]$/g, '');
    176    
    177                 if ( Params[key] === undefined ) {
    178                     Params[key] = val;
     166            var params = {};
     167            if ( ! query )
     168                return params;
     169
     170            var pairs = query.split( /[;&]/ );
     171            for ( var i = 0; i < pairs.length; i++ ) {
     172                var keyVal = pairs[i].split( '=' );
     173
     174                if ( ! keyVal || keyVal.length != 2 )
     175                    continue;
     176
     177                var key = unescape( keyVal[0] );
     178                var val = unescape( keyVal[1] );
     179                val = val.replace( /\+/g, ' ' );
     180                key = key.replace( /\[.*\]$/g, '' );
     181
     182                if ( params[key] === undefined ) {
     183                    params[key] = val;
    179184                } else {
    180                     var oldVal = Params[key];
    181                     if ( ! jQuery.isArray( Params[key] ) )
    182                         Params[key] = new Array( oldVal, val );
     185                    var oldVal = params[key];
     186                    if ( ! $.isArray( params[key] ) )
     187                        params[key] = new Array( oldVal, val );
    183188                    else
    184                         Params[key].push( val );
     189                        params[key].push( val );
    185190                }
    186191            }
    187             return Params;
     192            return params;
    188193        }
    189194    }
    190195
    191     Query = function() {
    192         this.failedRequest = false;
    193         this.querying = false;
    194         this.page = inputs.startPage;
    195     }
    196    
    197     $.extend( Query.prototype, {
    198         ready: function() {
    199             return !( this.querying || this.failedRequest );
    200         },
    201         ajax: function( callback ) {
    202             var self = this,
    203             query = {
    204                 action: 'fetch-list',
    205                 tab: inputs.tab,
    206                 paged: this.page,
    207                 s: inputs.search,
    208                 type: inputs.type,
    209                 _ajax_fetch_list_nonce: inputs.nonce,
    210                 'features[]': inputs.features,
    211                 'list_args': list_args
    212             };
    213 
    214             this.querying = true;
    215             $.get( ajaxurl, query, function(r) {
    216                 self.page++;
    217                 self.querying = false;
    218                 self.failedRequest = !r;
    219                 callback( r, query );
    220             }, "json" );
    221         }
    222     });
    223 
    224     $(document).ready( wpThemes.init );
     196    $(document).ready( function( $ ) { ThemeScroller.init(); });
    225197
    226198})(jQuery);
Note: See TracChangeset for help on using the changeset viewer.