<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[1434] sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes: WP.org Themes: Consolidate JS handler.</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta" style="font-size: 105%">
<dt style="float: left; width: 6em; font-weight: bold">Revision</dt> <dd><a style="font-weight: bold" href="http://meta.trac.wordpress.org/changeset/1434">1434</a><script type="application/ld+json">{"@context":"http://schema.org","@type":"EmailMessage","description":"Review this Commit","action":{"@type":"ViewAction","url":"http://meta.trac.wordpress.org/changeset/1434","name":"Review Commit"}}</script></dd>
<dt style="float: left; width: 6em; font-weight: bold">Author</dt> <dd>obenland</dd>
<dt style="float: left; width: 6em; font-weight: bold">Date</dt> <dd>2015-03-20 00:10:03 +0000 (Fri, 20 Mar 2015)</dd>
</dl>

<pre style='padding-left: 1em; margin: 2em 0; border-left: 2px solid #ccc; line-height: 1.25; font-size: 105%; font-family: sans-serif'>WP.org Themes: Consolidate JS handler.

Removes the dependency on the theme-install JS, as well as 4 unnecessary
requests each pageload.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentthemespubwporgthemesfunctionsphp">sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/functions.php</a></li>
<li><a href="#sitestrunkwordpressorgpublic_htmlwpcontentthemespubwporgthemesjsthemejs">sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/js/theme.js</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentthemespubwporgthemesfunctionsphp"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/functions.php</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/functions.php    2015-03-19 23:59:17 UTC (rev 1433)
+++ sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/functions.php      2015-03-20 00:10:03 UTC (rev 1434)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -40,37 +40,36 @@
</span><span class="cx" style="display: block; padding: 0 10px">        wp_enqueue_style( 'wporg-themes', get_stylesheet_uri(), array(), filemtime( __DIR__ . '/style.css' ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">        if ( ! is_singular( 'page' ) ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                wp_enqueue_script( 'google-jsapi', '//www.google.com/jsapi', array( 'jquery' ), null );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wp_enqueue_script( 'google-jsapi', '//www.google.com/jsapi', array( 'jquery' ), null, true );
+               wp_enqueue_script( 'wporg-theme', get_template_directory_uri() . '/js/theme.js', array( 'wp-backbone' ), filemtime( __DIR__ . '/js/theme.js' ), true );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                wp_enqueue_script( 'theme', self_admin_url( 'js/theme.js' ), array( 'wp-backbone' ), false, true );
-               wp_enqueue_script( 'wporg-theme', get_template_directory_uri() . '/js/theme.js', array( 'theme' ), filemtime( __DIR__ . '/js/theme.js' ), true );
-
-               wp_localize_script( 'theme', '_wpThemeSettings', array(
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         wp_localize_script( 'wporg-theme', '_wpThemeSettings', array(
</ins><span class="cx" style="display: block; padding: 0 10px">                         'themes'   => false,
</span><span class="cx" style="display: block; padding: 0 10px">                        'query'    => wporg_themes_prepare_themes_for_js(),
</span><span class="cx" style="display: block; padding: 0 10px">                        'settings' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'title'      => __( 'WordPress &#8250; %s &laquo; Free WordPress Themes', 'wporg-themes' ),
-                               'isMobile'   => wp_is_mobile(),
-                               'isInstall'  => true,
-                               'canInstall' => false,
-                               'installURI' => null,
-                               'adminUrl'   => trailingslashit( parse_url( home_url(), PHP_URL_PATH ) ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'title'        => __( 'WordPress &#8250; %s &laquo; Free WordPress Themes', 'wporg-themes' ),
+                               'isMobile'     => wp_is_mobile(),
+                               'postsPerPage' => get_option( 'posts_per_page', 15 ),
+                               'path'         => trailingslashit( parse_url( home_url(), PHP_URL_PATH ) ),
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><span class="cx" style="display: block; padding: 0 10px">                        'l10n' => array(
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'addNew'            => __( 'Add New Theme' ),
-                               'search'            => __( 'Search Themes' ),
-                               'searchPlaceholder' => __( 'Search themes...' ), // placeholder (no ellipsis)
-                               'upload'            => __( 'Upload Theme' ),
-                               'back'              => __( 'Back' ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'search'            => __( 'Search Themes', 'wporg-themes' ),
+                               'searchPlaceholder' => __( 'Search themes...', 'wporg-themes' ), // placeholder (no ellipsis)
</ins><span class="cx" style="display: block; padding: 0 10px">                                 'error'             => __( 'An unexpected error occurred. Something may be wrong with WordPress.org or this server&#8217;s configuration. If you continue to have problems, please try the <a href="https://wordpress.org/support/">support forums</a>.' ),
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Downloads Graph
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                'date'      => __( 'Date' ),
-                               'downloads' => __( 'Downloads' ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         'date'      => __( 'Date', 'wporg-themes' ),
+                               'downloads' => __( 'Downloads', 'wporg-themes' ),
</ins><span class="cx" style="display: block; padding: 0 10px">                         ),
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        'installedThemes' => array(),
</del><span class="cx" style="display: block; padding: 0 10px">                 ) );
</span><span class="cx" style="display: block; padding: 0 10px">        }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+
+       // No emoji support needed.
+       remove_action( 'wp_print_styles','print_emoji_styles' );
+       wp_dequeue_script( 'emoji' );
+
+       // No Jetpack styles needed.
+       add_filter( 'jetpack_implode_frontend_css', '__return_false' );
</ins><span class="cx" style="display: block; padding: 0 10px"> }
</span><span class="cx" style="display: block; padding: 0 10px"> add_action( 'wp_enqueue_scripts', 'wporg_themes_scripts' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span></span></pre></div>
<a id="sitestrunkwordpressorgpublic_htmlwpcontentthemespubwporgthemesjsthemejs"></a>
<div class="modfile"><h4 style="background-color: #eee; color: inherit; margin: 1em 0; padding: 1.3em; font-size: 115%">Modified: sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/js/theme.js</h4>
<pre class="diff"><span>
<span class="info" style="display: block; padding: 0 10px; color: #888">--- sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/js/theme.js      2015-03-19 23:59:17 UTC (rev 1433)
+++ sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-themes/js/theme.js        2015-03-20 00:10:03 UTC (rev 1434)
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -1,165 +1,369 @@
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-( function ( $, wp ) {
-       google.load("visualization", "1", {packages:["corechart"]});
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+/* global _wpThemeSettings, confirm */
+window.wp = window.wp || {};
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        wp.themes.utils = {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+( function($) {
+
+       // Set up our namespace...
+       var themes = wp.themes = wp.themes || {},
+               l10n;
+
+       // Store the theme data and settings for organized and quick access
+       // themes.data.settings, themes.data.themes, themes.data.l10n
+       themes.data = _wpThemeSettings;
+       l10n = themes.data.l10n;
+
+       // Setup app structure
+       _.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template });
+
+       themes.utils = {
</ins><span class="cx" style="display: block; padding: 0 10px">                 title: function ( item ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        var title = $( 'title' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        title.html( wp.themes.data.settings.title.replace( '%s', item ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 title.html( themes.data.settings.title.replace( '%s', item ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        };
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Appearance.prototype, {
-               el: '#themes .theme-browser',
-               searchContainer: ''
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ themes.Model = Backbone.Model.extend({
+               // Adds attributes to the default data coming through the .org themes api
+               // Map `id` to `slug` for shared code
+               initialize: function() {
+                       var description;
+
+                       // Set the attributes
+                       this.set({
+                               // slug is for installation, id is for existing.
+                               id: this.get( 'slug' ) || this.get( 'id' )
+                       });
+
+                       // Map `section.description` to `description`
+                       // as the API sometimes returns it differently
+                       if ( this.has( 'sections' ) ) {
+                               description = this.get( 'sections' ).description;
+                               this.set({ description: description });
+                       }
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Themes.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Main view controller for themes.php
+       // Unifies and renders all available views
+       themes.view.Appearance = wp.Backbone.View.extend({
+               el: '#themes .theme-browser',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // The theme count element
-               count: $( '.wp-filter .theme-count' ),
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         window: $( window ),
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Renders the overlay with the ThemeDetails view.
-               // Uses the current model data.
-               expand: function( id ) {
-                       var self = this;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Pagination instance
+               page: 0,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Set the current theme model
-                       this.model = self.collection.get( id );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Sets up a throttler for binding to 'scroll'
+               initialize: function( options ) {
+                       // Scroller checks how far the scroll position is
+                       _.bindAll( this, 'scroller' );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Trigger a route update for the current model
-                       wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.themePath + this.model.id ) );
-                       wp.themes.utils.title( this.model.attributes.name );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 this.SearchView = options.SearchView ? options.SearchView : themes.view.Search;
+                       // Bind to the scroll event and throttle
+                       // the results from this.scroller
+                       this.window.bind( 'scroll', _.throttle( this.scroller, 300 ) );
+               },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Sets this.view to 'detail'
-                       this.setView( 'detail' );
-                       $( 'body' ).addClass( 'modal-open' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Main render control
+               render: function() {
+                       // Setup the main theme view
+                       // with the current theme collection
+                       this.view = new themes.view.Themes({
+                               collection: this.collection,
+                               parent: this
+                       });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Set up the theme details view
-                       this.overlay = new wp.themes.view.Details({
-                               model: self.model
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Render search form.
+                       this.search();
+
+                       // Render and append
+                       this.view.render();
+                       this.$el.find( '.themes' ).remove();
+                       this.$el.append( this.view.el ).addClass( 'rendered' );
+               },
+
+               // Defines search element container
+               searchContainer: '',
+
+               // Search input and view
+               // for current theme collection
+               search: function() {
+                       var view,
+                               self = this;
+
+                       view = new this.SearchView({
+                               collection: self.collection,
+                               parent: this
</ins><span class="cx" style="display: block; padding: 0 10px">                         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        this.overlay.render();
-                       this.$overlay.html( this.overlay.el );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Render and append after screen title
+                       view.render();
+                       this.searchContainer
+                               .append( $.parseHTML( '<label class="screen-reader-text" for="wp-filter-search-input">' + l10n.search + '</label>' ) )
+                               .append( view.el );
+               },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Bind to theme:next and theme:previous
-                       // triggered by the arrow keys
-                       //
-                       // Keep track of the current model so we
-                       // can infer an index position
-                       this.listenTo( this.overlay, 'theme:next', function() {
-                               // Renders the next theme on the overlay
-                               self.next( [ self.model.cid ] );
-                               $( '.theme-header' ).find( '.right' ).focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Checks when the user gets close to the bottom
+               // of the mage and triggers a theme:scroll event
+               scroller: function() {
+                       var self = this,
+                               bottom, threshold;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        })
-                       .listenTo( this.overlay, 'theme:previous', function() {
-                               // Renders the previous theme on the overlay
-                               self.previous( [ self.model.cid ] );
-                               $( '.theme-header' ).find( '.left' ).focus();
-                       });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 bottom = this.window.scrollTop() + self.window.height();
+                       threshold = self.$el.offset().top + self.$el.outerHeight( false ) - self.window.height();
+                       threshold = Math.round( threshold * 0.9 );
+
+                       if ( bottom > threshold ) {
+                               this.trigger( 'theme:scroll' );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Installer.prototype, {
-               el: '#themes',
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Set up the Collection for our theme data
+       // @has 'id' 'name' 'screenshot' 'author' 'authorURI' 'version' 'active' ...
+       themes.Collection = Backbone.Collection.extend({
+               model: themes.Model,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                sort: function( sort ) {
-                       var sorter = $( '.filter-links [data-sort="' + sort + '"]'),
-                               self = this;
-                       self.clearSearch();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Search terms
+               terms: '',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Clear filters.
-                       _.each( $( '.filter-group' ).find( ':checkbox' ).filter( ':checked' ), function( item ) {
-                               $( item ).prop( 'checked', false );
-                               return self.filtersChecked();
-                       });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Local cache array for API queries
+               queries: [],
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $( '.filter-links li > a, .theme-filter' ).removeClass( this.activeClass );
-                       sorter.addClass( this.activeClass );
-                       wp.themes.utils.title( sorter.text() );
-
-                       this.browse( sort );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Keep track of current query so we can handle pagination
+               currentQuery: {
+                       page: 1,
+                       request: {}
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Applying filters triggers a tag request.
-               applyFilters: function( event ) {
-                       var names = [],
-                               name,
-                               tags = this.filtersChecked(),
-                               request = { tag: tags },
-                               filteringBy = $( '.filtered-by .tags' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         count: false,
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( event ) {
-                               event.preventDefault();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Static status controller for when we are loading themes.
+               loadingThemes: false,
+
+               // Controls searching on the current theme collection
+               // and triggers an update event
+               doSearch: function( value ) {
+
+                       // Don't do anything if we've already done this search
+                       // Useful because the Search handler fires multiple times per keystroke
+                       if ( this.terms === value ) {
+                               return;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $( 'body' ).addClass( 'filters-applied' );
-                       $( '.filter-links li > a.current' ).removeClass( 'current' );
-                       filteringBy.empty();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Updates terms with the value passed
+                       this.terms = value;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        _.each( tags, function( tag ) {
-                               name = $( 'label[for="filter-id-' + tag + '"]' ).text();
-                               names.push( name );
-                               filteringBy.append( '<span class="tag">' + name + '</span>' );
-                       });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // If we have terms, run a search...
+                       if ( this.terms.length > 0 ) {
+                               this.search( this.terms );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.navigate( wp.themes.router.baseUrl( 'tags/' + tags.join( '+' ) ) );
-                       wp.themes.utils.title( names.join( ', ' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // If search is blank, show all themes
+                       // Useful for resetting the views when you clean the input
+                       if ( this.terms === '' ) {
+                               this.reset( themes.data.themes );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Get the themes by sending Ajax POST request to api.wordpress.org/themes
-                       // or searching the local cache
-                       this.collection.query( request );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Trigger an 'update' event
+                       this.trigger( 'update' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Toggle the full filters navigation.
-               moreFilters: function( event ) {
-                       event.preventDefault();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Performs a search within the collection
+               // @uses RegExp
+               search: function( term ) {
+                       var match, results, haystack, name, description, author;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( $( 'body' ).hasClass( 'filters-applied' ) ) {
-                               return this.backToFilters();
-                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Start with a full collection
+                       this.reset( themes.data.themes, { silent: true } );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // 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();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Escape the term string for RegExp meta characters
+                       term = term.replace( /[-\/\\^$*+?.()|[\]{}]/g, '\\$&' );
+
+                       // Consider spaces as word delimiters and match the whole string
+                       // so matching terms can be combined
+                       term = term.replace( / /g, ')(?=.*' );
+                       match = new RegExp( '^(?=.*' + term + ').+', 'i' );
+
+                       // Find results
+                       // _.filter and .test
+                       results = this.filter( function( data ) {
+                               name        = data.get( 'name' ).replace( /(<([^>]+)>)/ig, '' );
+                               description = data.get( 'description' ).replace( /(<([^>]+)>)/ig, '' );
+                               author      = data.get( 'author' ).replace( /(<([^>]+)>)/ig, '' );
+
+                               haystack = _.union( name, data.get( 'id' ), description, author, data.get( 'tags' ) );
+
+                               if ( match.test( data.get( 'author' ) ) && term.length > 2 ) {
+                                       data.set( 'displayAuthor', true );
+                               }
+
+                               return match.test( haystack );
+                       });
+
+                       if ( results.length === 0 ) {
+                               this.trigger( 'query:empty' );
+                       } else {
+                               $( 'body' ).removeClass( 'no-results' );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        this.clearSearch();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 this.reset( results );
+               },
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        $( 'body' ).toggleClass( 'show-filters' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Paginates the collection with a helper method
+               // that slices the collection
+               paginate: function( instance ) {
+                       var collection = this;
+                       instance = instance || 0;
+
+                       // Themes per instance are set at 15
+                       collection = _( collection.rest( themes.data.settings.postsPerPage * instance ) );
+                       collection = _( collection.first( themes.data.settings.postsPerPage ) );
+
+                       return collection;
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                // Get the checked filters.
-               // @return {array} of tags or false.
-               filtersChecked: function() {
-                       var items  = $( '.filter-group' ).find( ':checkbox' ).filter( ':checked' ),
-                               drawer = $( '.filter-drawer' ),
-                               tags   = [];
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Handles requests for more themes
+               // and caches results
+               //
+               // When we are missing a cache object we fire an apiCall()
+               // which triggers events of `query:success` or `query:fail`
+               query: function( request ) {
+                       /**
+                        * @static
+                        * @type Array
+                        */
+                       var queries = this.queries,
+                               self = this,
+                               query, isPaginated, count;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        _.each( items, function( item ) {
-                               tags.push( $( item ).prop( 'value' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Store current query request args
+                       // for later use with the event `theme:end`
+                       this.currentQuery.request = request;
+
+                       // Search the query cache for matches.
+                       query = _.find( queries, function( query ) {
+                               return _.isEqual( query.request, request );
</ins><span class="cx" style="display: block; padding: 0 10px">                         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // When no filters are checked, restore initial state and return.
-                       if ( 0 === tags.length ) {
-                               drawer.find( '.apply-filters' ).prop( 'disabled', true ).find( 'span' ).text( '' );
-                               drawer.find( '.clear-filters' ).hide();
-                               $( 'body' ).removeClass( 'filters-applied' );
-                               return false;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // If the request matches the stored currentQuery.request
+                       // it means we have a paginated request.
+                       isPaginated = _.has( request, 'page' );
+
+                       // Reset the internal api page counter for non paginated queries.
+                       if ( ! isPaginated ) {
+                               this.currentQuery.page = 1;
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        drawer.find( '.apply-filters' ).prop( 'disabled', false ).find( 'span' ).text( tags.length );
-                       drawer.find( '.clear-filters' ).css( 'display', 'inline-block' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Otherwise, send a new API call and add it to the cache.
+                       if ( ! query && ! isPaginated ) {
+                               query = this.apiCall( request ).done( function( data ) {
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        return tags;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 // Update the collection with the queried data.
+                                       if ( data.themes ) {
+                                               self.reset( data.themes );
+                                               count = data.info.results;
+                                               // Store the results and the query request
+                                               queries.push( { themes: data.themes, request: request, total: count } );
+                                       }
+
+                                       // Trigger a collection refresh event
+                                       // and a `query:success` event with a `count` argument.
+                                       self.trigger( 'update' );
+                                       self.trigger( 'query:success', count );
+
+                                       if ( data.themes && data.themes.length === 0 ) {
+                                               self.trigger( 'query:empty' );
+                                       }
+
+                               }).fail( function() {
+                                       self.trigger( 'query:fail' );
+                               });
+                       } else {
+                               // If it's a paginated request we need to fetch more themes...
+                               if ( isPaginated ) {
+                                       return this.apiCall( request, isPaginated ).done( function( data ) {
+                                               // Add the new themes to the current collection
+                                               // @todo update counter
+                                               self.add( data.themes );
+                                               self.trigger( 'query:success', data.info.results );
+
+                                               // We are done loading themes for now.
+                                               self.loadingThemes = false;
+
+                                       }).fail( function() {
+                                               self.trigger( 'query:fail' );
+                                       });
+                               }
+
+                               if ( query.themes.length === 0 ) {
+                                       self.trigger( 'query:empty' );
+                               } else {
+                                       $( 'body' ).removeClass( 'no-results' );
+                               }
+
+                               // Only trigger an update event since we already have the themes
+                               // on our cached object
+                               if ( _.isNumber( query.total ) ) {
+                                       this.count = query.total;
+                               }
+
+                               this.reset( query.themes );
+                               if ( ! query.total ) {
+                                       this.count = this.length;
+                               }
+
+                               this.trigger( 'update' );
+                               this.trigger( 'query:success', this.count );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Send request to api.wordpress.org/themes
+               apiCall: function( request, paginated ) {
+                       return wp.ajax.send( 'query-themes', {
+                               data: {
+                                       // Request data
+                                       request: _.extend({
+                                               per_page: themes.data.settings.postsPerPage,
+                                               fields: {
+                                                       description: true,
+                                                       tested: true,
+                                                       requires: true,
+                                                       rating: true,
+                                                       downloaded: true,
+                                                       downloadLink: true,
+                                                       last_updated: true,
+                                                       homepage: true,
+                                                       num_ratings: true
+                                               }
+                                       }, request)
+                               },
+
+                               beforeSend: function() {
+                                       if ( ! paginated ) {
+                                               // Spin it
+                                               $( 'body' ).addClass( 'loading-content' ).removeClass( 'no-results' );
+                                       }
+                               }
+                       });
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Theme.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // This is the view that controls each theme item
+       // that will be displayed on the screen
+       themes.view.Theme = wp.Backbone.View.extend({
+
+               // Wrap theme data on a div.theme element
+               className: 'theme',
+
+               // Reflects which theme view we have
+               // 'grid' (default) or 'detail'
+               state: 'grid',
+
+               // The HTML template for each element to be rendered
+               html: wp.themes.template( 'theme' ),
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 events: {
</span><span class="cx" style="display: block; padding: 0 10px">                        'click': 'expand',
</span><span class="cx" style="display: block; padding: 0 10px">                        'keydown': 'expand',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -168,10 +372,12 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'touchmove': 'preventExpand'
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                touchDrag: false,
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 render: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var data = this.model.toJSON();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        data.permalink = wp.themes.data.settings.adminUrl + wp.themes.router.baseUrl( data.slug );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 data.permalink = themes.data.settings.path + themes.router.baseUrl( data.slug );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Render themes using the html template
</span><span class="cx" style="display: block; padding: 0 10px">                        this.$el.html( this.html( data ) ).attr({
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -180,6 +386,22 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // Adds a class to the currently active theme
+               // and to the overlay in detailed view mode
+               activeTheme: function() {
+                       if ( this.model.get( 'active' ) ) {
+                               this.$el.addClass( 'active' );
+                       }
+               },
+
+               // Add class of focus to the theme we are focused on.
+               addFocus: function() {
+                       var $themeToFocus = ( $( ':focus' ).hasClass( 'theme' ) ) ? $( ':focus' ) : $(':focus').parents('.theme');
+
+                       $('.theme.focus').removeClass('focus');
+                       $themeToFocus.addClass('focus');
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Single theme overlay screen
</span><span class="cx" style="display: block; padding: 0 10px">                // It's shown when clicking a theme
</span><span class="cx" style="display: block; padding: 0 10px">                expand: function( event ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -209,16 +431,153 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Set focused theme to current element
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.focusedTheme = this.$el;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.focusedTheme = this.$el;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.trigger( 'theme:expand', self.model.cid );
</span><span class="cx" style="display: block; padding: 0 10px">                        event.preventDefault();
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                },
+
+               preventExpand: function() {
+                       this.touchDrag = true;
+               },
+
+               preview: function( event ) {
+                       var self = this,
+                               current, preview;
+
+                       // Bail if the user scrolled on a touch device
+                       if ( this.touchDrag === true ) {
+                               return this.touchDrag = false;
+                       }
+
+                       // Allow direct link path to installing a theme.
+                       if ( $( event.target ).hasClass( 'button-primary' ) ) {
+                               return;
+                       }
+
+                       // 'enter' and 'space' keys expand the details view when a theme is :focused
+                       if ( event.type === 'keydown' && ( event.which !== 13 && event.which !== 32 ) ) {
+                               return;
+                       }
+
+                       // pressing enter while focused on the buttons shouldn't open the preview
+                       if ( event.type === 'keydown' && event.which !== 13 && $( ':focus' ).hasClass( 'button' ) ) {
+                               return;
+                       }
+
+                       event.preventDefault();
+
+                       event = event || window.event;
+
+                       // Set focus to current theme.
+                       themes.focusedTheme = this.$el;
+
+                       // Construct a new Preview view.
+                       preview = new themes.view.Preview({
+                               model: this.model
+                       });
+
+                       // Render the view and append it.
+                       preview.render();
+                       this.setNavButtonsState();
+
+                       // Hide previous/next navigation if there is only one theme
+                       if ( this.model.collection.length === 1 ) {
+                               preview.$el.addClass( 'no-navigation' );
+                       } else {
+                               preview.$el.removeClass( 'no-navigation' );
+                       }
+
+                       // Append preview
+                       $( 'div.wrap' ).append( preview.el );
+
+                       // Listen to our preview object
+                       // for `theme:next` and `theme:previous` events.
+                       this.listenTo( preview, 'theme:next', function() {
+
+                               // Keep local track of current theme model.
+                               current = self.model;
+
+                               // If we have ventured away from current model update the current model position.
+                               if ( ! _.isUndefined( self.current ) ) {
+                                       current = self.current;
+                               }
+
+                               // Get next theme model.
+                               self.current = self.model.collection.at( self.model.collection.indexOf( current ) + 1 );
+
+                               // If we have no more themes, bail.
+                               if ( _.isUndefined( self.current ) ) {
+                                       self.options.parent.parent.trigger( 'theme:end' );
+                                       return self.current = current;
+                               }
+
+                               preview.model = self.current;
+
+                               // Render and append.
+                               preview.render();
+                               this.setNavButtonsState();
+                               $( '.next-theme' ).focus();
+                       })
+                               .listenTo( preview, 'theme:previous', function() {
+
+                                       // Keep track of current theme model.
+                                       current = self.model;
+
+                                       // Bail early if we are at the beginning of the collection
+                                       if ( self.model.collection.indexOf( self.current ) === 0 ) {
+                                               return;
+                                       }
+
+                                       // If we have ventured away from current model update the current model position.
+                                       if ( ! _.isUndefined( self.current ) ) {
+                                               current = self.current;
+                                       }
+
+                                       // Get previous theme model.
+                                       self.current = self.model.collection.at( self.model.collection.indexOf( current ) - 1 );
+
+                                       // If we have no more themes, bail.
+                                       if ( _.isUndefined( self.current ) ) {
+                                               return;
+                                       }
+
+                                       preview.model = self.current;
+
+                                       // Render and append.
+                                       preview.render();
+                                       this.setNavButtonsState();
+                                       $( '.previous-theme' ).focus();
+                               });
+
+                       this.listenTo( preview, 'preview:close', function() {
+                               self.current = self.model;
+                       });
+               },
+
+               // Handles .disabled classes for previous/next buttons in theme installer preview
+               setNavButtonsState: function() {
+                       var $themeInstaller = $( '.theme-install-overlay' ),
+                               current = _.isUndefined( this.current ) ? this.model : this.current;
+
+                       // Disable previous at the zero position
+                       if ( 0 === this.model.collection.indexOf( current ) ) {
+                               $themeInstaller.find( '.previous-theme' ).addClass( 'disabled' );
+                       }
+
+                       // Disable next if the next model is undefined
+                       if ( _.isUndefined( this.model.collection.at( this.model.collection.indexOf( current ) + 1 ) ) ) {
+                               $themeInstaller.find( '.next-theme' ).addClass( 'disabled' );
+                       }
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-//      wp.themes.view.Preview.prototype = wp.themes.view.Details.prototype;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+// Theme Details view
+// Set ups a modal overlay with the expanded theme data
+       themes.view.Details = wp.Backbone.View.extend({
+               // Wrap theme data on a div.theme element
+               className: 'theme-overlay',
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Details.prototype, {
</del><span class="cx" style="display: block; padding: 0 10px">                 events: {
</span><span class="cx" style="display: block; padding: 0 10px">                        'click': 'collapse',
</span><span class="cx" style="display: block; padding: 0 10px">                        'click .delete-theme': 'deleteTheme',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -229,6 +588,9 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        'touchend .theme-actions .button-secondary': 'preview'
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                // The HTML template for the theme overlay
+               html: themes.template( 'theme-single' ),
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 render: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var data = this.model.toJSON(),
</span><span class="cx" style="display: block; padding: 0 10px">                                updated = new Date(data.last_updated);
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -238,7 +600,7 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Make tags click-able and separated by a comma.
</span><span class="cx" style="display: block; padding: 0 10px">                        data.tags = _.map( data.tags, function( tag ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                return '<a href="' + wp.themes.data.settings.adminUrl + wp.themes.router.baseUrl( 'tags/' + tag.toLowerCase().replace( ' ', '-' ) ) + '">' + tag + '</a>';
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         return '<a href="' + themes.data.settings.path + themes.router.baseUrl( 'tags/' + tag.toLowerCase().replace( ' ', '-' ) ) + '">' + tag + '</a>';
</ins><span class="cx" style="display: block; padding: 0 10px">                         }).join( ', ' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.$el.html( this.html( data ) );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -277,15 +639,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                return;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        event = event || window.event;
</ins><span class="cx" style="display: block; padding: 0 10px">                         event.preventDefault();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        event = event || window.event;
-
</del><span class="cx" style="display: block; padding: 0 10px">                         // Set focus to current theme.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.focusedTheme = this.$el;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.focusedTheme = this.$el;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Construct a new Preview view.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        preview = new wp.themes.view.Preview({
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 preview = new themes.view.Preview({
</ins><span class="cx" style="display: block; padding: 0 10px">                                 model: this.model
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -300,7 +661,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                preview.$el.removeClass( 'no-navigation' );
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( wp.themes.data.settings.isMobile ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( themes.data.settings.isMobile ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 preview.$el.addClass( 'wp-full-overlay collapsed' );
</span><span class="cx" style="display: block; padding: 0 10px">                        } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                preview.$el.addClass( 'wp-full-overlay expanded' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -336,35 +697,35 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                this.setNavButtonsState();
</span><span class="cx" style="display: block; padding: 0 10px">                                $( '.next-theme' ).focus();
</span><span class="cx" style="display: block; padding: 0 10px">                        })
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                .listenTo( preview, 'theme:previous', function() {
-                                       // Keep track of current theme model.
-                                       current = self.model;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 .listenTo( preview, 'theme:previous', function() {
+                               // Keep track of current theme model.
+                               current = self.model;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        // Bail early if we are at the beginning of the collection
-                                       if ( self.model.collection.indexOf( self.current ) === 0 ) {
-                                               return;
-                                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // Bail early if we are at the beginning of the collection
+                               if ( self.model.collection.indexOf( self.current ) === 0 ) {
+                                       return;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        // If we have ventured away from current model update the current model position.
-                                       if ( ! _.isUndefined( self.current ) ) {
-                                               current = self.current;
-                                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // If we have ventured away from current model update the current model position.
+                               if ( ! _.isUndefined( self.current ) ) {
+                                       current = self.current;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        // Get previous theme model.
-                                       self.current = self.model.collection.at( self.model.collection.indexOf( current ) - 1 );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // Get previous theme model.
+                               self.current = self.model.collection.at( self.model.collection.indexOf( current ) - 1 );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        // If we have no more themes, bail.
-                                       if ( _.isUndefined( self.current ) ) {
-                                               return;
-                                       }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // If we have no more themes, bail.
+                               if ( _.isUndefined( self.current ) ) {
+                                       return;
+                               }
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        preview.model = self.current;
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         preview.model = self.current;
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        // Render and append.
-                                       preview.render();
-                                       this.setNavButtonsState();
-                                       $( '.previous-theme' ).focus();
-                               });
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         // Render and append.
+                               preview.render();
+                               this.setNavButtonsState();
+                               $( '.previous-theme' ).focus();
+                       });
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.listenTo( preview, 'preview:close', function() {
</span><span class="cx" style="display: block; padding: 0 10px">                                self.current = self.model;
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -387,57 +748,13 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                screenshotCheck: function( el ) {
-                       var image = new Image();
-                       image.src = el.find( '.screenshot img' ).attr( 'src' );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         // Adds a class to the currently active theme
+               // and to the overlay in detailed view mode
+               activeTheme: function() {
+                       // Check the model has the active property
+                       this.$el.toggleClass( 'active', this.model.get( 'active' ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                renderDownloadsGraph: function() {
-                       var self = this;
-
-                       $.getJSON( 'https://api.wordpress.org/stats/themes/1.0/downloads.php?slug=' + self.model.get( 'id' ) + '&limit=260&callback=?', function( downloads ) {
-                               var data = new google.visualization.DataTable(),
-                                       count = 0;
-
-                               data.addColumn('string', _wpThemeSettings.l10n.date);
-                               data.addColumn('number', _wpThemeSettings.l10n.downloads);
-
-                               $.each(downloads, function (key, value) {
-                                       data.addRow();
-                                       data.setValue(count, 0, new Date(key).toLocaleDateString() );
-                                       data.setValue(count, 1, Number(value));
-                                       count++;
-                               });
-
-                               new google.visualization.ColumnChart(document.getElementById('theme-download-stats-' + self.model.get( 'id' ) )).draw(data, {
-                                       colors: ['#253578'],
-                                       legend: {
-                                               position: 'none'
-                                       },
-                                       titlePosition: 'in',
-                                       axisTitlesPosition: 'in',
-                                       chartArea: {
-                                               height: 280,
-                                               left: 35,
-                                               width: '98%'
-                                       },
-                                       hAxis: {
-                                               textStyle: {color: 'black', fontSize: 9}
-                                       },
-                                       vAxis: {
-                                               format: '###,###',
-                                               textPosition: 'out',
-                                               viewWindowMode: 'explicit',
-                                               viewWindow: {min: 0}
-                                       },
-                                       bar: {
-                                               groupWidth: ( data.getNumberOfRows() > 100 ) ? "100%" : null
-                                       },
-                                       height: 350
-                               });
-                       });
-               },
-
</del><span class="cx" style="display: block; padding: 0 10px">                 // Keeps :focus within the theme details elements.
</span><span class="cx" style="display: block; padding: 0 10px">                containFocus: function( $el ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        var ev = window.event,
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -478,7 +795,7 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        event = event || window.event;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Prevent collapsing detailed view when there is only one theme available
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( wp.themes.data.themes.length === 1 ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( themes.data.themes.length === 1 ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                 return;
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -504,13 +821,71 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        document.body.scrollTop = scroll;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                        // Return focus to the theme div
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                        if ( wp.themes.focusedTheme ) {
-                                               wp.themes.focusedTheme.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                                 if ( themes.focusedTheme ) {
+                                               themes.focusedTheme.focus();
</ins><span class="cx" style="display: block; padding: 0 10px">                                         }
</span><span class="cx" style="display: block; padding: 0 10px">                                });
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                renderDownloadsGraph: function() {
+                       var self = this;
+
+                       $.getJSON( 'https://api.wordpress.org/stats/themes/1.0/downloads.php?slug=' + self.model.get( 'id' ) + '&limit=260&callback=?', function( downloads ) {
+                               var data = new google.visualization.DataTable(),
+                                       count = 0;
+
+                               data.addColumn('string', _wpThemeSettings.l10n.date);
+                               data.addColumn('number', _wpThemeSettings.l10n.downloads);
+
+                               $.each(downloads, function (key, value) {
+                                       data.addRow();
+                                       data.setValue(count, 0, new Date(key).toLocaleDateString() );
+                                       data.setValue(count, 1, Number(value));
+                                       count++;
+                               });
+
+                               new google.visualization.ColumnChart(document.getElementById('theme-download-stats-' + self.model.get( 'id' ) )).draw(data, {
+                                       colors: ['#253578'],
+                                       legend: {
+                                               position: 'none'
+                                       },
+                                       titlePosition: 'in',
+                                       axisTitlesPosition: 'in',
+                                       chartArea: {
+                                               height: 280,
+                                               left: 35,
+                                               width: '98%'
+                                       },
+                                       hAxis: {
+                                               textStyle: {color: 'black', fontSize: 9}
+                                       },
+                                       vAxis: {
+                                               format: '###,###',
+                                               textPosition: 'out',
+                                               viewWindowMode: 'explicit',
+                                               viewWindow: {min: 0}
+                                       },
+                                       bar: {
+                                               groupWidth: ( data.getNumberOfRows() > 100 ) ? "100%" : null
+                                       },
+                                       height: 350
+                               });
+                       });
+               },
+
+               // Handles .disabled classes for next/previous buttons
+               navigation: function() {
+
+                       // Disable Left/Right when at the start or end of the collection
+                       if ( this.model.cid === this.model.collection.at(0).cid ) {
+                               this.$el.find( '.left' ).addClass( 'disabled' );
+                       }
+                       if ( this.model.cid === this.model.collection.at( this.model.collection.length - 1 ).cid ) {
+                               this.$el.find( '.right' ).addClass( 'disabled' );
+                       }
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 // Performs the actions to effectively close
</span><span class="cx" style="display: block; padding: 0 10px">                // the theme details overlay
</span><span class="cx" style="display: block; padding: 0 10px">                closeOverlay: function() {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -523,17 +898,17 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        this.trigger( 'theme:collapse' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Clean the url structure
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        if ( author = wp.themes.Collection.prototype.currentQuery.request.author ) {
-                               wp.themes.router.navigate( wp.themes.router.baseUrl( 'author/' + author ) );
-                               wp.themes.utils.title( author );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 if ( author = themes.Collection.prototype.currentQuery.request.author ) {
+                               themes.router.navigate( themes.router.baseUrl( 'author/' + author ) );
+                               themes.utils.title( author );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        else if ( search = wp.themes.Collection.prototype.currentQuery.request.search ) {
-                               wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.searchPath + search ) );
-                               wp.themes.utils.title( search );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 else if ( search = themes.Collection.prototype.currentQuery.request.search ) {
+                               themes.router.navigate( themes.router.baseUrl( themes.router.searchPath + search ) );
+                               themes.utils.title( search );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        else if ( tags = wp.themes.view.Installer.prototype.filtersChecked() ) {
-                               wp.themes.router.navigate( wp.themes.router.baseUrl( 'tags/' + tags.join( '+' ) ) );
-                               wp.themes.utils.title( _.each( tags, function( tag, i ) {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 else if ( tags = themes.view.Installer.prototype.filtersChecked() ) {
+                               themes.router.navigate( themes.router.baseUrl( 'tags/' + tags.join( '+' ) ) );
+                               themes.utils.title( _.each( tags, function( tag, i ) {
</ins><span class="cx" style="display: block; padding: 0 10px">                                         tags[ i ] = $( 'label[for="filter-id-' + tag + '"]' ).text();
</span><span class="cx" style="display: block; padding: 0 10px">                                }).join( ', ' ) );
</span><span class="cx" style="display: block; padding: 0 10px">                        }
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -542,20 +917,59 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                        sorter = $( '.filter-links [data-sort="featured"]' );
</span><span class="cx" style="display: block; padding: 0 10px">                                        args   = { trigger: true };
</span><span class="cx" style="display: block; padding: 0 10px">                                }
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.browsePath + sorter.data( 'sort' ) ), args );
-                               wp.themes.utils.title( sorter.text() );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         themes.router.navigate( themes.router.baseUrl( themes.router.browsePath + sorter.data( 'sort' ) ), args );
+                               themes.utils.title( sorter.text() );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                },
+
+               // Confirmation dialog for deleting a theme
+               deleteTheme: function() {
+                       return confirm( themes.data.settings.confirmDelete );
+               },
+
+               nextTheme: function() {
+                       var self = this;
+                       self.trigger( 'theme:next', self.model.cid );
+                       return false;
+               },
+
+               previousTheme: function() {
+                       var self = this;
+                       self.trigger( 'theme:previous', self.model.cid );
+                       return false;
+               },
+
+               screenshotCheck: function( el ) {
+                       var image = new Image();
+                       image.src = el.find( '.screenshot img' ).attr( 'src' );
</ins><span class="cx" style="display: block; padding: 0 10px">                 }
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.Preview.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Theme Preview view
+       // Set ups a modal overlay with the expanded theme data
+       themes.view.Preview = themes.view.Details.extend({
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                className: 'wp-full-overlay expanded',
+               el: '.theme-install-overlay',
+
+               events: {
+                       'click .close-full-overlay': 'close',
+                       'click .collapse-sidebar': 'collapse',
+                       'click .previous-theme': 'previousTheme',
+                       'click .next-theme': 'nextTheme',
+                       'keyup': 'keyEvent'
+               },
+
+               // The HTML template for the theme preview
+               html: themes.template( 'theme-preview' ),
+
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 render: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var data = this.model.toJSON();
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.$el.html( this.html( data ) );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.themePath + this.model.get( 'id' ) + '/preview' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.navigate( themes.router.baseUrl( themes.router.themePath + this.model.get( 'id' ) + '/preview' ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.$el.fadeIn( 200, function() {
</span><span class="cx" style="display: block; padding: 0 10px">                                $( 'body' ).addClass( 'theme-installer-active full-overlay-active' );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -568,18 +982,24 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                $( 'body' ).removeClass( 'theme-installer-active full-overlay-active' );
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                // Return focus to the theme div
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                if ( wp.themes.focusedTheme ) {
-                                       wp.themes.focusedTheme.focus();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         if ( themes.focusedTheme ) {
+                                       themes.focusedTheme.focus();
</ins><span class="cx" style="display: block; padding: 0 10px">                                 }
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        this.trigger( 'preview:close' );
</span><span class="cx" style="display: block; padding: 0 10px">                        this.undelegateEvents();
</span><span class="cx" style="display: block; padding: 0 10px">                        this.unbind();
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.themePath + this.model.get( 'id' ) ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.navigate( themes.router.baseUrl( themes.router.themePath + this.model.get( 'id' ) ) );
</ins><span class="cx" style="display: block; padding: 0 10px">                         return false;
</span><span class="cx" style="display: block; padding: 0 10px">                },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                collapse: function() {
+
+                       this.$el.toggleClass( 'collapsed' ).toggleClass( 'expanded' );
+                       return false;
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 keyEvent: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        // The escape key closes the preview
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( event.keyCode === 27 ) {
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -601,16 +1021,408 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.view.InstallerSearch.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Controls the rendering of div.themes,
+       // a wrapper that will hold all the theme elements
+       themes.view.Themes = wp.Backbone.View.extend({
+
+               className: 'themes',
+               $overlay: $( 'div.theme-overlay' ),
+
+               // Number to keep track of scroll position
+               // while in theme-overlay mode
+               index: 0,
+
+               // The theme count element
+               count: $( '.wp-filter .theme-count' ),
+
+               initialize: function( options ) {
+                       var self = this;
+
+                       // Set up parent
+                       this.parent = options.parent;
+
+                       // Set current view to [grid]
+                       this.setView( 'grid' );
+
+                       // Move the active theme to the beginning of the collection
+                       self.currentTheme();
+
+                       // When the collection is updated by user input...
+                       this.listenTo( self.collection, 'update', function() {
+                               self.parent.page = 0;
+                               self.currentTheme();
+                               self.render( this );
+                       });
+
+                       // Update theme count to full result set when available.
+                       this.listenTo( self.collection, 'query:success', function( count ) {
+                               if ( _.isNumber( count ) ) {
+                                       self.count.text( count );
+                               } else {
+                                       self.count.text( self.collection.length );
+                               }
+                       });
+
+                       this.listenTo( self.collection, 'query:empty', function() {
+                               $( 'body' ).addClass( 'no-results' );
+                       });
+
+                       this.listenTo( this.parent, 'theme:scroll', function() {
+                               self.renderThemes( self.parent.page );
+                       });
+
+                       this.listenTo( this.parent, 'theme:close', function() {
+                               if ( self.overlay ) {
+                                       self.overlay.closeOverlay();
+                               }
+                       } );
+
+                       // Bind keyboard events.
+                       $( 'body' ).on( 'keyup', function( event ) {
+                               if ( ! self.overlay ) {
+                                       return;
+                               }
+
+                               // Pressing the right arrow key fires a theme:next event
+                               if ( event.keyCode === 39 ) {
+                                       self.overlay.nextTheme();
+                               }
+
+                               // Pressing the left arrow key fires a theme:previous event
+                               if ( event.keyCode === 37 ) {
+                                       self.overlay.previousTheme();
+                               }
+
+                               // Pressing the escape key fires a theme:collapse event
+                               if ( event.keyCode === 27 ) {
+                                       self.overlay.collapse( event );
+                               }
+                       });
+               },
+
+               // Manages rendering of theme pages
+               // and keeping theme count in sync
+               render: function() {
+                       // Clear the DOM, please
+                       this.$el.empty();
+
+                       // If the user doesn't have switch capabilities
+                       // or there is only one theme in the collection
+                       // render the detailed view of the active theme
+                       if ( themes.data.themes.length === 1 ) {
+
+                               // Constructs the view
+                               this.singleTheme = new themes.view.Details({
+                                       model: this.collection.models[0]
+                               });
+
+                               // Render and apply a 'single-theme' class to our container
+                               this.singleTheme.render();
+                               this.$el.addClass( 'single-theme' );
+                               this.$el.append( this.singleTheme.el );
+                       }
+
+                       // Generate the themes
+                       // Using page instance
+                       // While checking the collection has items
+                       if ( this.options.collection.size() > 0 ) {
+                               this.renderThemes( this.parent.page );
+                       }
+
+                       // Display a live theme count for the collection
+                       this.count.text( this.collection.count ? this.collection.count : this.collection.length );
+               },
+
+               // Iterates through each instance of the collection
+               // and renders each theme module
+               renderThemes: function( page ) {
+                       var self = this;
+
+                       self.instance = self.collection.paginate( page );
+
+                       // If we have no more themes bail
+                       if ( self.instance.size() === 0 ) {
+                               // Fire a no-more-themes event.
+                               this.parent.trigger( 'theme:end' );
+                               return;
+                       }
+
+                       // Make sure the add-new stays at the end
+                       if ( page >= 1 ) {
+                               $( '.add-new-theme' ).remove();
+                       }
+
+                       // Loop through the themes and setup each theme view
+                       self.instance.each( function( theme ) {
+                               self.theme = new themes.view.Theme({
+                                       model: theme,
+                                       parent: self
+                               });
+
+                               // Render the views...
+                               self.theme.render();
+                               // and append them to div.themes
+                               self.$el.append( self.theme.el );
+
+                               // Binds to theme:expand to show the modal box
+                               // with the theme details
+                               self.listenTo( self.theme, 'theme:expand', self.expand, self );
+                       });
+
+                       this.parent.page++;
+               },
+
+               // Grabs current theme and puts it at the beginning of the collection
+               currentTheme: function() {
+                       var self = this,
+                               current;
+
+                       current = self.collection.findWhere({ active: true });
+
+                       // Move the active theme to the beginning of the collection
+                       if ( current ) {
+                               self.collection.remove( current );
+                               self.collection.add( current, { at:0 } );
+                       }
+               },
+
+               // Sets current view
+               setView: function( view ) {
+                       return view;
+               },
+
+               // Renders the overlay with the ThemeDetails view.
+               // Uses the current model data.
+               expand: function( id ) {
+                       var self = this;
+
+                       // Set the current theme model
+                       this.model = self.collection.get( id );
+
+                       // Trigger a route update for the current model
+                       themes.router.navigate( themes.router.baseUrl( themes.router.themePath + this.model.id ) );
+                       themes.utils.title( this.model.attributes.name );
+
+                       // Sets this.view to 'detail'
+                       this.setView( 'detail' );
+                       $( 'body' ).addClass( 'modal-open' );
+
+                       // Set up the theme details view
+                       this.overlay = new themes.view.Details({
+                               model: self.model
+                       });
+
+                       this.overlay.render();
+                       this.$overlay.html( this.overlay.el );
+
+                       // Bind to theme:next and theme:previous
+                       // triggered by the arrow keys
+                       //
+                       // Keep track of the current model so we
+                       // can infer an index position
+                       this.listenTo( this.overlay, 'theme:next', function() {
+                               // Renders the next theme on the overlay
+                               self.next( [ self.model.cid ] );
+                               $( '.theme-header' ).find( '.right' ).focus();
+
+                       })
+                       .listenTo( this.overlay, 'theme:previous', function() {
+                               // Renders the previous theme on the overlay
+                               self.previous( [ self.model.cid ] );
+                               $( '.theme-header' ).find( '.left' ).focus();
+                       });
+               },
+
+               // This method renders the next theme on the overlay modal
+               // based on the current position in the collection
+               // @params [model cid]
+               next: function( args ) {
+                       var self = this,
+                               model, nextModel;
+
+                       // Get the current theme
+                       model = self.collection.get( args[0] );
+                       // Find the next model within the collection
+                       nextModel = self.collection.at( self.collection.indexOf( model ) + 1 );
+
+                       // Sanity check which also serves as a boundary test
+                       if ( nextModel !== undefined ) {
+
+                               // We have a new theme...
+                               // Close the overlay
+                               this.overlay.closeOverlay();
+
+                               // Trigger a route update for the current model
+                               self.theme.trigger( 'theme:expand', nextModel.cid );
+
+                       }
+               },
+
+               // This method renders the previous theme on the overlay modal
+               // based on the current position in the collection
+               // @params [model cid]
+               previous: function( args ) {
+                       var self = this,
+                               model, previousModel;
+
+                       // Get the current theme
+                       model = self.collection.get( args[0] );
+                       // Find the previous model within the collection
+                       previousModel = self.collection.at( self.collection.indexOf( model ) - 1 );
+
+                       if ( previousModel !== undefined ) {
+
+                               // We have a new theme...
+                               // Close the overlay
+                               this.overlay.closeOverlay();
+
+                               // Trigger a route update for the current model
+                               self.theme.trigger( 'theme:expand', previousModel.cid );
+
+                       }
+               }
+       });
+
+       // Search input view controller.
+       themes.view.Search = wp.Backbone.View.extend({
+
+               tagName: 'input',
+               className: 'wp-filter-search',
+               id: 'wp-filter-search-input',
+               searching: false,
+
+               attributes: {
+                       placeholder: l10n.searchPlaceholder,
+                       type: 'search'
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 events: {
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'input':  'search',
</ins><span class="cx" style="display: block; padding: 0 10px">                         'keyup':  'search',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'change': 'search',
</ins><span class="cx" style="display: block; padding: 0 10px">                         'search': 'search',
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                        'blur':   'pushState'
</ins><span class="cx" style="display: block; padding: 0 10px">                 },
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                initialize: function( options ) {
+
+                       this.parent = options.parent;
+
+                       this.listenTo( this.parent, 'theme:close', function() {
+                               this.searching = false;
+                       } );
+
+               },
+
+               // Runs a search on the theme collection.
+               search: function( event ) {
+                       var options = {};
+
+                       // Clear on escape.
+                       if ( event.type === 'keyup' && event.which === 27 ) {
+                               event.target.value = '';
+                       }
+
+                       // Lose input focus when pressing enter
+                       if ( event.which === 13 ) {
+                               this.$el.trigger( 'blur' );
+                       }
+
+                       this.collection.doSearch( event.target.value );
+
+                       // if search is initiated and key is not return
+                       if ( this.searching && event.which !== 13 ) {
+                               options.replace = true;
+                       } else {
+                               this.searching = true;
+                       }
+
+                       // Update the URL hash
+                       if ( event.target.value ) {
+                               themes.router.navigate( themes.router.baseUrl( themes.router.searchPath + event.target.value ), options );
+                       } else {
+                               themes.router.navigate( themes.router.baseUrl( '' ) );
+                       }
+               },
+
+               pushState: function( event ) {
+                       var url = themes.router.baseUrl( '' );
+
+                       if ( event.target.value ) {
+                               url = themes.router.baseUrl( themes.router.searchPath + event.target.value );
+                       }
+
+                       this.searching = false;
+                       themes.router.navigate( url );
+
+               }
+       });
+
+       // Sets up the routes events for relevant url queries
+       // Listens to [theme] and [search] params
+       themes.Router = Backbone.Router.extend({
+
+               routes: {
+                       'themes.php?theme=:slug': 'theme',
+                       'themes.php?search=:query': 'search',
+                       'themes.php?s=:query': 'search',
+                       'themes.php': 'themes',
+                       '': 'themes'
+               },
+
+               baseUrl: function( url ) {
+                       return 'themes.php' + url;
+               },
+
+               themePath: '?theme=',
+               searchPath: '?search=',
+
+               search: function( query ) {
+                       $( '.wp-filter-search' ).val( query );
+               },
+
+               themes: function() {
+                       $( '.wp-filter-search' ).val( '' );
+               },
+
+               navigate: function() {
+                       if ( Backbone.history._hasPushState ) {
+                               Backbone.Router.prototype.navigate.apply( this, arguments );
+                       }
+               }
+
+       });
+
+       // Extend the main Search view
+       themes.view.InstallerSearch =  themes.view.Search.extend({
+
+               events: {
+                       'keyup':  'search',
+                       'search': 'search'
+               },
+
+               // Handles Ajax request for searching through themes in public repo
+               search: function( event ) {
+
+                       // Tabbing or reverse tabbing into the search input shouldn't trigger a search
+                       if ( event.type === 'keyup' && ( event.which === 9 || event.which === 16 ) ) {
+                               return;
+                       }
+
+                       this.collection = this.options.parent.view.collection;
+
+                       // Clear on escape.
+                       if ( event.type === 'keyup' && event.which === 27 ) {
+                               event.target.value = '';
+                       }
+
+                       _.debounce( _.bind( this.doSearch, this ), 300 )( event.target.value );
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 doSearch: _.debounce( function( value ) {
</span><span class="cx" style="display: block; padding: 0 10px">                        var request = {};
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.view.Installer.prototype.clearFilters( new Event( 'click' ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.view.Installer.prototype.clearFilters( new Event( 'click' ) );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        request.search = value;
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -637,14 +1449,14 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Set route
</span><span class="cx" style="display: block; padding: 0 10px">                        if ( value ) {
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                wp.themes.utils.title( value );
-                               wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.searchPath + value ), { replace: true } );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         themes.utils.title( value );
+                               themes.router.navigate( themes.router.baseUrl( themes.router.searchPath + value ), { replace: true } );
</ins><span class="cx" style="display: block; padding: 0 10px">                         } else {
</span><span class="cx" style="display: block; padding: 0 10px">                                delete request.search;
</span><span class="cx" style="display: block; padding: 0 10px">                                request.browse = 'featured';
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                wp.themes.utils.title( $( '.filter-links [data-sort="featured"]' ).text() );
-                               wp.themes.router.navigate( wp.themes.router.baseUrl( wp.themes.router.browsePath + 'featured' ), { replace: true } );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         themes.utils.title( $( '.filter-links [data-sort="featured"]' ).text() );
+                               themes.router.navigate( themes.router.baseUrl( themes.router.browsePath + 'featured' ), { replace: true } );
</ins><span class="cx" style="display: block; padding: 0 10px">                         }
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Get the themes by sending Ajax POST request to api.wordpress.org/themes
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -653,7 +1465,261 @@
</span><span class="cx" style="display: block; padding: 0 10px">                }, 300 )
</span><span class="cx" style="display: block; padding: 0 10px">        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.InstallerRouter.prototype, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ themes.view.Installer = themes.view.Appearance.extend({
+               el: '#themes',
+
+               // Register events for sorting and filters in theme-navigation
+               events: {
+                       'click .filter-links li > a': 'onSort',
+                       'click .theme-filter': 'onFilter',
+                       'click .drawer-toggle': 'moreFilters',
+                       'click .filter-drawer .apply-filters': 'applyFilters',
+                       'click .filter-group [type="checkbox"]': 'addFilter',
+                       'click .filter-drawer .clear-filters': 'clearFilters',
+                       'click .filtered-by': 'backToFilters'
+               },
+
+               activeClass: 'current',
+
+               // Overwrite search container class to append search
+               // in new location
+               searchContainer: $( '.wp-filter .search-form' ),
+
+               // Initial render method
+               render: function() {
+                       var self = this;
+
+                       this.search();
+
+                       this.collection = new themes.Collection();
+
+                       // Bump `collection.currentQuery.page` and request more themes if we hit the end of the page.
+                       this.listenTo( this, 'theme:end', function() {
+
+                               // Make sure we are not already loading
+                               if ( self.collection.loadingThemes ) {
+                                       return;
+                               }
+
+                               // Set loadingThemes to true and bump page instance of currentQuery.
+                               self.collection.loadingThemes = true;
+                               self.collection.currentQuery.page++;
+
+                               // Use currentQuery.page to build the themes request.
+                               _.extend( self.collection.currentQuery.request, { page: self.collection.currentQuery.page } );
+                               self.collection.query( self.collection.currentQuery.request );
+                       });
+
+                       this.listenTo( this.collection, 'query:success', function() {
+                               $( 'body' ).removeClass( 'loading-content' );
+                               $( '.theme-browser' ).find( 'div.error' ).remove();
+                       });
+
+                       this.listenTo( this.collection, 'query:fail', function() {
+                               $( 'body' ).removeClass( 'loading-content' );
+                               $( '.theme-browser' ).find( 'div.error' ).remove();
+                               $( '.theme-browser' ).find( 'div.themes' ).before( '<div class="error"><p>' + l10n.error + '</p></div>' );
+                       });
+
+                       if ( this.view ) {
+                               this.view.remove();
+                       }
+
+                       // Set ups the view and passes the section argument
+                       this.view = new themes.view.Themes({
+                               collection: this.collection,
+                               parent: this
+                       });
+
+                       // Reset pagination every time the install view handler is run
+                       this.page = 0;
+
+                       // Render and append
+                       this.$el.find( '.themes' ).remove();
+                       this.view.render();
+                       this.$el.find( '.theme-browser' ).append( this.view.el ).addClass( 'rendered' );
+               },
+
+               // Handles all the rendering of the public theme directory
+               browse: function( section ) {
+                       // Create a new collection with the proper theme data
+                       // for each section
+                       this.collection.query( { browse: section } );
+               },
+
+               // Sorting navigation
+               onSort: function( event ) {
+                       var $el = $( event.target ),
+                               sort = $el.data( 'sort' );
+
+                       event.preventDefault();
+
+                       $( 'body' ).removeClass( 'filters-applied show-filters' );
+
+                       // Bail if this is already active
+                       if ( $el.hasClass( this.activeClass ) ) {
+                               return;
+                       }
+
+                       this.sort( sort );
+
+                       // Trigger a router.naviagte update
+                       themes.router.navigate( themes.router.baseUrl( themes.router.browsePath + sort ) );
+               },
+
+               sort: function( sort ) {
+                       var sorter = $( '.filter-links [data-sort="' + sort + '"]'),
+                               self = this;
+                       self.clearSearch();
+
+                       // Clear filters.
+                       _.each( $( '.filter-group' ).find( ':checkbox' ).filter( ':checked' ), function( item ) {
+                               $( item ).prop( 'checked', false );
+                               return self.filtersChecked();
+                       });
+
+                       $( '.filter-links li > a, .theme-filter' ).removeClass( this.activeClass );
+                       sorter.addClass( this.activeClass );
+                       themes.utils.title( sorter.text() );
+
+                       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 names = [],
+                               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();
+                               names.push( name );
+                               filteringBy.append( '<span class="tag">' + name + '</span>' );
+                       });
+
+                       themes.router.navigate( themes.router.baseUrl( 'tags/' + tags.join( '+' ) ) );
+                       themes.utils.title( names.join( ', ' ) );
+
+                       // 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' ).filter( ':checked' ),
+                               drawer = $( '.filter-drawer' ),
+                               tags   = [];
+
+                       _.each( items, function( item ) {
+                               tags.push( $( item ).prop( 'value' ) );
+                       });
+
+                       // When no filters are checked, restore initial state and return.
+                       if ( 0 === tags.length ) {
+                               drawer.find( '.apply-filters' ).prop( 'disabled', true ).find( 'span' ).text( '' );
+                               drawer.find( '.clear-filters' ).hide();
+                               $( 'body' ).removeClass( 'filters-applied' );
+                               return false;
+                       }
+
+                       drawer.find( '.apply-filters' ).prop( 'disabled', false ).find( 'span' ).text( tags.length );
+                       drawer.find( '.clear-filters' ).css( 'display', 'inline-block' );
+
+                       return tags;
+               },
+
+               // 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();
+
+                       $( '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({
</ins><span class="cx" style="display: block; padding: 0 10px">                 routes: {
</span><span class="cx" style="display: block; padding: 0 10px">                        'browse/:sort/'  : 'sort',
</span><span class="cx" style="display: block; padding: 0 10px">                        'tags/:tag/'     : 'tag',
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -673,22 +1739,57 @@
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                themePath: '',
</span><span class="cx" style="display: block; padding: 0 10px">                browsePath: 'browse/',
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                searchPath: 'search/'
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+         searchPath: 'search/',
+
+               search: function( query ) {
+                       $( '.wp-filter-search' ).val( query );
+               },
+
+               navigate: function() {
+                       if ( Backbone.history._hasPushState ) {
+                               Backbone.Router.prototype.navigate.apply( this, arguments );
+                       }
+               }
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-        _.extend( wp.themes.RunInstaller, {
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ 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.path,
+                               pushState: true,
+                               hashChange: false
+                       });
+               },
+
</ins><span class="cx" style="display: block; padding: 0 10px">                 routes: function() {
</span><span class="cx" style="display: block; padding: 0 10px">                        var self = this,
</span><span class="cx" style="display: block; padding: 0 10px">                                request = {};
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        // Bind to our global `wp.themes` object
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 // Bind to our global `themes` object
</ins><span class="cx" style="display: block; padding: 0 10px">                         // so that the router is available to sub-views
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router = new wp.themes.InstallerRouter();
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router = new themes.InstallerRouter();
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // Handles `theme` route event
</span><span class="cx" style="display: block; padding: 0 10px">                        // Queries the API for the passed theme slug
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.on( 'route:preview', function( slug ) {
-                               self.view.collection.queries.push( wp.themes.data.query );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.on( 'route:preview', function( slug ) {
+                               self.view.collection.queries.push( themes.data.query );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                request.theme = slug;
</span><span class="cx" style="display: block; padding: 0 10px">                                self.view.collection.query( request );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -700,8 +1801,8 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        // Handles sorting / browsing routes
</span><span class="cx" style="display: block; padding: 0 10px">                        // Also handles the root URL triggering a sort request
</span><span class="cx" style="display: block; padding: 0 10px">                        // for `featured`, the default view
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.on( 'route:sort', function( sort ) {
-                               self.view.collection.queries.push( wp.themes.data.query );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.on( 'route:sort', function( sort ) {
+                               self.view.collection.queries.push( themes.data.query );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                if ( ! sort ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        sort = 'featured';
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -711,14 +1812,14 @@
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                        // The `search` route event. The router populates the input field.
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.on( 'route:search', function() {
-                               self.view.collection.queries.push( wp.themes.data.query );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.on( 'route:search', function() {
+                               self.view.collection.queries.push( themes.data.query );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                $( '.wp-filter-search' ).focus().trigger( 'keyup' );
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.on( 'route:tag', function( tag ) {
-                               self.view.collection.queries.push( wp.themes.data.query );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.on( 'route:tag', function( tag ) {
+                               self.view.collection.queries.push( themes.data.query );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                _.each( tag.split( '+' ), function( tag ) {
</span><span class="cx" style="display: block; padding: 0 10px">                                        $( '#filter-id-' + tag ).prop( 'checked', true );
</span><span class="lines" style="display: block; padding: 0 10px; color: #888">@@ -727,16 +1828,23 @@
</span><span class="cx" style="display: block; padding: 0 10px">                                self.view.applyFilters();
</span><span class="cx" style="display: block; padding: 0 10px">                        });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        wp.themes.router.on( 'route:author', function( author ) {
-                               self.view.collection.queries.push( wp.themes.data.query );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                 themes.router.on( 'route:author', function( author ) {
+                               self.view.collection.queries.push( themes.data.query );
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><span class="cx" style="display: block; padding: 0 10px">                                request.author = author;
</span><span class="cx" style="display: block; padding: 0 10px">                                self.view.collection.query( request );
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                                wp.themes.utils.title( author );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                         themes.utils.title( author );
</ins><span class="cx" style="display: block; padding: 0 10px">                         });
</span><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+                }
+       };
</ins><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-                        this.extraRoutes();
-               }
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+ // Ready...
+       $( function() {
+               themes.RunInstaller.init();
</ins><span class="cx" style="display: block; padding: 0 10px">         });
</span><span class="cx" style="display: block; padding: 0 10px"> 
</span><del style="background-color: #fdd; text-decoration:none; display:block; padding: 0 10px">-}( jQuery, wp ) );
</del><ins style="background-color: #dfd; text-decoration:none; display:block; padding: 0 10px">+})( jQuery );
+
+( function( google ) {
+       google.load("visualization", "1", {packages:["corechart"]});
+})( google );
</ins></span></pre>
</div>
</div>

</body>
</html>