WordPress.org

Make WordPress Core

Ticket #27055: 27055.16.diff

File 27055.16.diff, 9.3 KB (added by matveb, 5 years ago)

Adds API pagination support

  • wp-admin/js/theme.js

     
    213213                collection = _( collection.first( 20 ) );
    214214
    215215                return collection;
     216        },
     217
     218        // Handles requests for more themes
     219        // and caches results
     220        //
     221        // When we are missing a cache object we fire an apiCall()
     222        // which triggers events of `query:success` or `query:fail`
     223        query: function( request ) {
     224                /**
     225                 * @static
     226                 * @type Array
     227                 */
     228                var queries = this.queries,
     229                        self = this,
     230                        query, paginatedQuery, combined;
     231
     232                // Search the query cache for matches.
     233                query = _.find( queries, function( query ) {
     234                        return _.isEqual( query.request, request );
     235                });
     236
     237                // If the request matches the stored currentQuery.request
     238                // it means we have a paginated request.
     239                isPaginated = _.isEqual( self.currentQuery.request, request );
     240
     241                // Reset the internal api page counter for non paginated queries.
     242                if ( ! isPaginated ) {
     243                        this.currentQuery.page = 1;
     244                }
     245
     246                // Otherwise, send a new API call and add it to the cache.
     247                if ( ! query ) {
     248                        query = this.apiCall( request ).done( function( data ) {
     249                                // Update the collection with the queried data.
     250                                self.reset( data.themes );
     251
     252                                // Trigger a `query:success` event
     253                                // and a collection refresh event so the views are aware of changes.
     254                                self.trigger( 'query:success' );
     255                                self.trigger( 'update' );
     256
     257                                // Store the results and the query request
     258                                queries.push( { themes: data.themes, request: request } );
     259                        }).fail( function() {
     260                                self.trigger( 'query:fail' );
     261                        });
     262                } else {
     263                        // If it's a paginated request we need to fetch more themes...
     264                        if ( isPaginated ) {
     265                                return this.apiCall( request, isPaginated ).done( function( data ) {
     266                                        // Add the new themes to the current collection
     267                                        // @todo update counter
     268                                        self.add( data.themes );
     269                                        self.trigger( 'query:success' );
     270
     271                                }).fail( function() {
     272                                        self.trigger( 'query:fail' );
     273                                });
     274                        }
     275
     276                        // Only trigger an update event since we already have the themes
     277                        // on our cached object
     278                        this.reset( query.themes );
     279                        this.trigger( 'update' );
     280                }
     281        },
     282
     283        // Local cache array for API queries
     284        queries: [],
     285
     286        // Keep track of current query so we can handle pagination
     287        currentQuery: {
     288                page: 1,
     289                request: {}
     290        },
     291
     292        // Send Ajax POST request to api.wordpress.org/themes
     293        apiCall: function( request, paginated ) {
     294                // Store current query request args
     295                // for later use with the event `theme:end`
     296                this.currentQuery.request = request;
     297
     298                // Ajax request to .org API
     299                return $.ajax({
     300                        url: 'https://api.wordpress.org/themes/info/1.1/?action=query_themes',
     301
     302                        // We want JSON data
     303                        dataType: 'json',
     304                        type: 'POST',
     305                        crossDomain: true,
     306
     307                        // Request data
     308                        data: {
     309                                action: 'query_themes',
     310                                request: _.extend({
     311                                        per_page: 72,
     312                                        page: this.currentQuery.page,
     313                                        fields: {
     314                                                description: true,
     315                                                tested: true,
     316                                                requires: true,
     317                                                rating: true,
     318                                                downloaded: true,
     319                                                downloadLink: true,
     320                                                last_updated: true,
     321                                                homepage: true,
     322                                                num_ratings: true
     323                                        }
     324                                }, request)
     325                        },
     326
     327                        beforeSend: function() {
     328                                if ( ! paginated ) {
     329                                        // Spin it
     330                                        $( 'body' ).addClass( 'loading-themes' );
     331                                }
     332                        }
     333                });
    216334        }
    217335});
    218336
     
    628746
    629747                // Generate the themes
    630748                // Using page instance
    631                 this.renderThemes( this.parent.page );
     749                // While checking the collection has items
     750                if ( this.options.collection.size() > 1 ) {
     751                        this.renderThemes( this.parent.page );
     752                }
    632753
    633754                // Display a live theme count for the collection
    634755                this.count.text( this.collection.length );
     
    642763                self.instance = self.collection.paginate( page );
    643764
    644765                // If we have no more themes bail
    645                 if ( self.instance.length === 0 ) {
     766                if ( self.instance.size() === 0 ) {
     767                        // Fire a no-more-themes event.
     768                        this.parent.trigger( 'theme:end' );
    646769                        return;
    647770                }
    648771
     
    9671090                _.debounce( _.bind( this.doSearch, this ), 300 )( event.target.value );
    9681091        },
    9691092
    970         doSearch: function( value ) {
     1093        doSearch: _.debounce( function( value ) {
    9711094                var request = {},
    9721095                        self = this;
    9731096
     
    9911114                        request.tag = [ value.slice( 4 ) ];
    9921115                }
    9931116
    994                 // Send Ajax POST request to api.wordpress.org/themes
    995                 themes.view.Installer.prototype.apiCall( request ).done( function( data ) {
    996                                 // Update the collection with the queried data
    997                                 self.collection.reset( data.themes );
    998                                 // Trigger a collection refresh event to render the views
    999                                 self.collection.trigger( 'update' );
    1000 
    1001                                 // Un-spin it
    1002                                 $( 'body' ).removeClass( 'loading-themes' );
    1003                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1004                 }).fail( function() {
    1005                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1006                                 $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
    1007                 });
    1008 
    1009                 return false;
    1010         }
     1117                // Get the themes by sending Ajax POST request to api.wordpress.org/themes
     1118                // or searching the local cache
     1119                this.collection.query( request );
     1120        }, 300 ),
    10111121});
    10121122
    10131123themes.view.Installer = themes.view.Appearance.extend({
     
    10221132                'click [type="checkbox"]': 'addFilter'
    10231133        },
    10241134
    1025         // Send Ajax POST request to api.wordpress.org/themes
    1026         apiCall: function( request ) {
    1027                 return $.ajax({
    1028                         url: 'https://api.wordpress.org/themes/info/1.1/?action=query_themes',
    1029 
    1030                         // We want JSON data
    1031                         dataType: 'json',
    1032                         type: 'POST',
    1033                         crossDomain: true,
    1034 
    1035                         // Request data
    1036                         data: {
    1037                                 action: 'query_themes',
    1038                                 request: _.extend({
    1039                                         per_page: 36,
    1040                                         fields: {
    1041                                                 description: true,
    1042                                                 tested: true,
    1043                                                 requires: true,
    1044                                                 rating: true,
    1045                                                 downloaded: true,
    1046                                                 downloadLink: true,
    1047                                                 last_updated: true,
    1048                                                 homepage: true,
    1049                                                 num_ratings: true
    1050                                         }
    1051                                 }, request)
    1052                         },
    1053 
    1054                         beforeSend: function() {
    1055                                 // Spin it
    1056                                 $( 'body' ).addClass( 'loading-themes' );
    1057                         }
    1058                 });
    1059         },
    1060 
    10611135        // Handles all the rendering of the public theme directory
    10621136        browse: function( section ) {
    10631137                var self = this;
    10641138
    1065                 // @todo Cache the collection after fetching based on the section
    10661139                this.collection = new themes.Collection();
    10671140
    1068                 // Create a new collection with the proper theme data
    1069                 // for each section
    1070                 this.apiCall({ browse: section }).done( function( data ) {
    1071                         // Update the collection with the queried data
    1072                         self.collection.reset( data.themes );
    1073                         // Trigger a collection refresh event to render the views
    1074                         self.collection.trigger( 'update' );
     1141                // Bump `collection.currentQuery.page` and request more themes if we hit the end of the page.
     1142                this.listenTo( this, 'theme:end', function() {
     1143                        self.collection.currentQuery.page++;
     1144                        self.collection.query( self.collection.currentQuery.request );
     1145                });
    10751146
    1076                         // Un-spin it
     1147                this.listenTo( this.collection, 'query:success', function() {
    10771148                        $( 'body' ).removeClass( 'loading-themes' );
    10781149                        $( '.theme-browser' ).find( 'div.error' ).remove();
    10791150                });
    10801151
     1152                this.listenTo( this.collection, 'query:fail', function() {
     1153                        $( '.theme-browser' ).find( 'div.error' ).remove();
     1154                        $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
     1155                });
     1156
     1157                // Create a new collection with the proper theme data
     1158                // for each section
     1159                this.collection.query( { browse: section } );
     1160
    10811161                if ( this.view ) {
    10821162                        this.view.remove();
    10831163                }
     
    11531233
    11541234                // Construct the filter request
    11551235                // using the default values
    1156 
    1157                 // @todo Cache the collection after fetching based on the filter
    11581236                filter = _.union( filter, this.filtersChecked() );
    11591237                request = { tag: [ filter ] };
    11601238
    1161                 // Send Ajax POST request to api.wordpress.org/themes
    1162                 this.apiCall( request ).done( function( data ) {
    1163                                 // Update the collection with the queried data
    1164                                 self.collection.reset( data.themes );
    1165                                 // Trigger a collection refresh event to render the views
    1166                                 self.collection.trigger( 'update' );
    1167 
    1168                                 // Un-spin it
    1169                                 $( 'body' ).removeClass( 'loading-themes' );
    1170                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1171                 }).fail( function() {
    1172                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1173                                 $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
    1174                 });
    1175 
    1176                 return false;
     1239                // Get the themes by sending Ajax POST request to api.wordpress.org/themes
     1240                // or searching the local cache
     1241                this.collection.query( request );
    11771242        },
    11781243
    11791244        // Clicking on a checkbox triggers a tag request
     
    11821247                        tags = this.filtersChecked(),
    11831248                        request = { tag: tags };
    11841249
    1185                 // Send Ajax POST request to api.wordpress.org/themes
    1186                 this.apiCall( request ).done( function( data ) {
    1187                                 // Update the collection with the queried data
    1188                                 self.collection.reset( data.themes );
    1189                                 // Trigger a collection refresh event to render the views
    1190                                 self.collection.trigger( 'update' );
    1191 
    1192                                 // Un-spin it
    1193                                 $( 'body' ).removeClass( 'loading-themes' );
    1194                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1195                 }).fail( function() {
    1196                                 $( '.theme-browser' ).find( 'div.error' ).remove();
    1197                                 $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
    1198                 });
     1250                // Get the themes by sending Ajax POST request to api.wordpress.org/themes
     1251                // or searching the local cache
     1252                this.collection.query( request );
    11991253        },
    12001254
    12011255        // Get the checked filters and return an array