+
+ this.sort( sort );
+
+ // Trigger a router.naviagte update
+ themes.router.navigate( themes.router.baseUrl( themes.router.browsePath + sort ) );
+ },
+
+ sort: function( sort ) {
+ this.clearSearch();
+
+ $( '.filter-links li > a, .theme-filter' ).removeClass( this.activeClass );
+ $( '[data-sort="' + sort + '"]' ).addClass( this.activeClass );
+
+ this.browse( sort );
+ },
+
+ // Filters and Tags
+ onFilter: function( event ) {
+ var request,
+ $el = $( event.target ),
+ filter = $el.data( 'filter' );
+
+ // Bail if this is already active
+ if ( $el.hasClass( this.activeClass ) ) {
+ return;
+ }
+
+ $( '.filter-links li > a, .theme-section' ).removeClass( this.activeClass );
+ $el.addClass( this.activeClass );
+
+ if ( ! filter ) {
+ return;
+ }
+
+ // Construct the filter request
+ // using the default values
+ filter = _.union( filter, this.filtersChecked() );
+ request = { tag: [ filter ] };
+
+ // Get the themes by sending Ajax POST request to api.wordpress.org/themes
+ // or searching the local cache
+ this.collection.query( request );
+ },
+
+ // Clicking on a checkbox to add another filter to the request
+ addFilter: function() {
+ this.filtersChecked();
+ },
+
+ // Applying filters triggers a tag request
+ applyFilters: function( event ) {
+ var name,
+ tags = this.filtersChecked(),
+ request = { tag: tags },
+ filteringBy = $( '.filtered-by .tags' );
+
+ if ( event ) {
+ event.preventDefault();
+ }
+
+ $( 'body' ).addClass( 'filters-applied' );
+ $( '.filter-links li > a.current' ).removeClass( 'current' );
+ filteringBy.empty();
+
+ _.each( tags, function( tag ) {
+ name = $( 'label[for="filter-id-' + tag + '"]' ).text();
+ filteringBy.append( '<span class="tag">' + name + '</span>' );
+ });
+
+ // Get the themes by sending Ajax POST request to api.wordpress.org/themes
+ // or searching the local cache
+ this.collection.query( request );
+ },
+
+ // Get the checked filters
+ // @return {array} of tags or false
+ filtersChecked: function() {
+ var items = $( '.filter-group' ).find( ':checkbox' ),
+ tags = [];
+
+ _.each( items.filter( ':checked' ), function( item ) {
+ tags.push( $( item ).prop( 'value' ) );
+ });
+
+ // When no filters are checked, restore initial state and return
+ if ( tags.length === 0 ) {
+ $( '.filter-drawer .apply-filters' ).find( 'span' ).text( '' );
+ $( '.filter-drawer .clear-filters' ).hide();
+ $( 'body' ).removeClass( 'filters-applied' );
+ return false;
+ }
+
+ $( '.filter-drawer .apply-filters' ).find( 'span' ).text( tags.length );
+ $( '.filter-drawer .clear-filters' ).css( 'display', 'inline-block' );
+
+ return tags;
+ },
+
+ activeClass: 'current',
+
+ // Overwrite search container class to append search
+ // in new location
+ searchContainer: $( '.wp-filter .search-form' ),
+
+ uploader: function() {
+ $( 'a.upload' ).on( 'click', function( event ) {
+ event.preventDefault();
+ $( 'body' ).addClass( 'show-upload-theme' );
+ themes.router.navigate( themes.router.baseUrl( '?upload' ), { replace: true } );
+ });
+ $( 'a.browse-themes' ).on( 'click', function( event ) {
+ event.preventDefault();
+ $( 'body' ).removeClass( 'show-upload-theme' );
+ themes.router.navigate( themes.router.baseUrl( '' ), { replace: true } );
+ });
+ },
+
+ // Toggle the full filters navigation
+ moreFilters: function( event ) {
+ event.preventDefault();
+
+ if ( $( 'body' ).hasClass( 'filters-applied' ) ) {
+ return this.backToFilters();
+ }
+
+ // If the filters section is opened and filters are checked
+ // run the relevant query collapsing to filtered-by state
+ if ( $( 'body' ).hasClass( 'show-filters' ) && this.filtersChecked() ) {
+ return this.addFilter();
+ }
+
+ this.clearSearch();
+
+ themes.router.navigate( themes.router.baseUrl( '' ) );
+ $( 'body' ).toggleClass( 'show-filters' );
+ },
+
+ // Clears all the checked filters
+ // @uses filtersChecked()
+ clearFilters: function( event ) {
+ var items = $( '.filter-group' ).find( ':checkbox' ),
+ self = this;
+
+ event.preventDefault();
+
+ _.each( items.filter( ':checked' ), function( item ) {
+ $( item ).prop( 'checked', false );
+ return self.filtersChecked();
+ });
+ },
+
+ backToFilters: function( event ) {
+ if ( event ) {
+ event.preventDefault();
+ }
+
+ $( 'body' ).removeClass( 'filters-applied' );
+ },
+
+ clearSearch: function() {
+ $( '#wp-filter-search-input').val( '' );
+ }
+});
+
+themes.InstallerRouter = Backbone.Router.extend({
+ routes: {
+ 'theme-install.php?theme=:slug': 'preview',
+ 'theme-install.php?browse=:sort': 'sort',
+ 'theme-install.php?upload': 'upload',
+ 'theme-install.php?search=:query': 'search',
+ 'theme-install.php': 'sort'
+ },
+
+ baseUrl: function( url ) {
+ return 'theme-install.php' + url;
+ },
+
+ themePath: '?theme=',
+ browsePath: '?browse=',
+ searchPath: '?search=',
+
+ search: function( query ) {
+ $( '.wp-filter-search' ).val( query );
+ },
+
+ navigate: function() {
+ if ( Backbone.history._hasPushState ) {
+ Backbone.Router.prototype.navigate.apply( this, arguments );
+ }
+ }
+});
+
+
+themes.RunInstaller = {
+
+ init: function() {
+ // Set up the view
+ // Passes the default 'section' as an option
+ this.view = new themes.view.Installer({
+ section: 'featured',
+ SearchView: themes.view.InstallerSearch
+ });
+
+ // Render results
+ this.render();
+
+ },
+
+ render: function() {
+
+ // Render results
+ this.view.render();
+ this.routes();
+
+ Backbone.history.start({
+ root: themes.data.settings.adminUrl,
+ pushState: true,
+ hashChange: false
+ });
+ },
+
+ routes: function() {
+ var self = this,
+ request = {};
+
+ // Bind to our global `wp.themes` object
+ // so that the router is available to sub-views
+ themes.router = new themes.InstallerRouter();
+
+ // Handles `theme` route event
+ // Queries the API for the passed theme slug
+ themes.router.on( 'route:preview', function( slug ) {
+ request.theme = slug;
+ self.view.collection.query( request );
+ });
+
+ // Handles sorting / browsing routes
+ // Also handles the root URL triggering a sort request
+ // for `featured`, the default view
+ themes.router.on( 'route:sort', function( sort ) {
+ if ( ! sort ) {
+ sort = 'featured';
+ }
+ self.view.sort( sort );
+ self.view.trigger( 'theme:close' );
+ });
+
+ // Support the `upload` route by going straight to upload section
+ themes.router.on( 'route:upload', function() {
+ $( 'a.upload' ).trigger( 'click' );
+ });
+
+ // The `search` route event. The router populates the input field.
+ themes.router.on( 'route:search', function() {
+ $( '.wp-filter-search' ).focus().trigger( 'keyup' );
+ });
+
+ this.extraRoutes();
+ },
+
+ extraRoutes: function() {
+ return false;