WordPress.org

Make WordPress Core

Changeset 27499


Ignore:
Timestamp:
03/11/2014 07:46:27 AM (4 years ago)
Author:
nacin
Message:

Bring the theme browsing experience from 3.8 to the theme installer. First pass.

props matveb with assists from me and gcorne.
see #27055.

Location:
trunk/src
Files:
2 deleted
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/css/themes.css

    r27289 r27499  
    2626}
    2727
    28 .themes-php .wrap .theme-count {
     28.themes-php .wrap .theme-count,
     29.theme-navigation .theme-count {
    2930    color: #fff;
    3031    -webkit-border-radius: 30px;
     
    10651066------------------------------------------------------------------------------*/
    10661067
    1067 .theme-install-php h4 {
    1068     margin: 2.5em 0 8px;
    1069 }
    1070 
    1071 .theme-install-php .tablenav {
    1072     height: auto;
    1073 }
    1074 
    1075 .theme-install-php .spinner {
    1076     margin-top: 9px;
    1077 }
    1078 
    1079 .available-theme {
     1068.theme-install-php h2 .upload {
     1069    margin-left: 10px;
     1070}
     1071.theme-navigation {
     1072    background: #fff;
     1073    box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);
     1074    -moz-box-sizing: border-box;
     1075    box-sizing: border-box;
     1076    color: #555;
    10801077    display: inline-block;
    1081     margin-right: 10px;
     1078    font-size: 13px;
     1079    margin: 20px 0 30px;
     1080    padding: 0 20px;
     1081    position: relative;
     1082    width: 100%;
     1083}
     1084.upload-theme {
     1085    -moz-box-sizing: border-box;
     1086    box-sizing: border-box;
     1087    display: none;
     1088    margin: 0px 0 0;
     1089    padding: 0;
     1090    width: 100%;
    10821091    overflow: hidden;
    1083     padding: 20px 20px 20px 0;
     1092    position: relative;
     1093        top: 10px;
     1094}
     1095.upload-theme.opened {
     1096    display: block;
     1097}
     1098.upload-theme .wp-upload-form {
     1099    background: #fafafa;
     1100    border: 1px solid #e5e5e5;
     1101    padding: 30px;
     1102    margin: 30px auto;
     1103    max-width: 380px;
     1104}
     1105.upload-theme .install-help {
     1106    color: #999;
     1107    font-size: 18px;
     1108    font-style: normal;
     1109    margin: 0;
     1110    padding: 40px 0 0;
     1111    text-align: center;
     1112}
     1113.upload-theme.opened + .theme-navigation,
     1114.upload-theme.opened + .theme-navigation + .theme-browser {
     1115    display: none;
     1116}
     1117.theme-navigation .theme-count {
     1118    top: 3px;
     1119    margin-left: 0;
     1120}
     1121.theme-section,
     1122.theme-filter {
     1123    border-bottom: 4px solid #fff;
     1124    color: #666;
     1125    cursor: pointer;
     1126    display: inline-block;
     1127    margin: 0 10px;
     1128    padding: 15px 0;
     1129    -moz-transition: border-color .1s ease-in;
     1130    -webkit-transition: border-color .1s ease-in;
     1131}
     1132.theme-section.current,
     1133.theme-filter.current {
     1134    border-bottom: 4px solid #666;
     1135    color: #222;
     1136}
     1137.theme-top-filters {
     1138    display: inline-block;
     1139}
     1140.theme-navigation .more-filters {
     1141    color: #666;
     1142    cursor: pointer;
     1143    display: inline-block;
     1144    margin: 0 10px;
     1145    padding: 4px 5px;
     1146    -moz-transition: color .1s ease-in, background .1s ease-in;
     1147    -webkit-transition: color .1s ease-in, background .1s ease-in;
     1148    transition: color .1s ease-in, background .1s ease-in;
     1149}
     1150body.more-filters-opened .more-filters,
     1151.theme-navigation .more-filters.current {
     1152    background: rgb(46, 162, 204);
     1153    border-radius: 2px;
     1154    border: none;
     1155    color: #fff;
     1156}
     1157.theme-install-php .theme-search {
     1158    position: absolute;
     1159        right: 10px;
     1160        top: 9px;
     1161    font-size: 16px;
     1162    font-weight: 300;
     1163    line-height: 1.5;
     1164    width: 280px;
     1165}
     1166.more-filters:before {
     1167    color: #777;
     1168    text-align: center;
     1169    margin: 0 5px 0 0;
     1170    content: "\f111";
     1171    display: inline-block;
     1172    width: 16px;
     1173    height: 16px;
     1174    -webkit-font-smoothing: antialiased;
     1175    font-size: 16px;
     1176    line-height: 1;
     1177    font-family: "dashicons";
     1178    text-decoration: inherit;
     1179    font-weight: normal;
     1180    font-style: normal;
    10841181    vertical-align: top;
    1085     width: 300px;
    1086 }
    1087 
    1088 .available-theme .screenshot {
    1089     width: 300px;
    1090     height: 225px;
    1091     display: block;
    1092     border: 1px solid #ccc;
    1093     margin-bottom: 10px;
    1094     overflow: hidden;
    1095     background-color: #fff;
    1096 }
    1097 
    1098 .available-theme img {
    1099     width: 300px;
    1100 }
    1101 
    1102 .available-theme h3 {
    1103     margin: 15px 0 0;
    1104 }
    1105 
    1106 .available-theme .theme-author {
    1107     line-height: 18px;
    1108 }
    1109 
    1110 .available-theme .action-links {
    1111     margin-top: 10px;
    1112     overflow: hidden;
    1113 }
    1114 
    1115 .available-theme a.screenshot:focus {
    1116     border-color: #777;
    1117 }
    1118 
    1119 .available-theme .action-links li {
    1120     float: left;
    1121     padding-right: 10px;
    1122     margin-right: 10px;
    1123     border-right: 1px solid #dfdfdf;
    1124 }
    1125 
    1126 .available-theme .action-links li {
    1127     padding-right: 8px;
    1128     margin-right: 8px;
    1129 }
    1130 
    1131 .ie8 .available-theme .action-links li {
    1132     padding-right: 7px;
    1133     margin-right: 7px;
    1134 }
    1135 
    1136 .available-theme .action-links li:last-child {
    1137     padding-right: 0;
    1138     margin-right: 0;
    1139     border-right: 0;
    1140 }
    1141 
    1142 .available-theme .action-links .delete-theme {
    1143     float: right;
    1144     margin-left: 8px;
    1145     margin-right: 0;
    1146 }
    1147 
    1148 .available-theme .action-links .delete-theme a {
    1149     color: red;
    1150     padding: 2px;
    1151 }
    1152 
    1153 .available-theme .action-links .delete-theme a:hover {
    1154     background: red;
     1182    -moz-transition: color .1s ease-in 0;
     1183    -webkit-transition: color .1s ease-in 0;
     1184    transition: color .1s ease-in 0;
     1185    text-align: center;
     1186}
     1187.more-filters.current:before {
    11551188    color: #fff;
    1156     text-decoration: none;
    1157 }
    1158 
    1159 .available-theme .action-links p {
    1160     float: left;
    1161 }
    1162 
    1163 /* Allow for three-up in small windows when sidebar is collapsed */
    1164 @media only screen and (max-width: 1200px) {
    1165     .folded .available-theme,
    1166     .folded .available-theme .screenshot {
    1167         width: 300px;
    1168     }
    1169 
    1170     .folded .available-theme .screenshot {
    1171         height: 225px;
    1172     }
    1173 }
    1174 
    1175 /* Adjust three-up display in smaller windows when sidebar is collapsed */
    1176 @media only screen and (max-width: 1079px) {
    1177     .folded .available-theme,
    1178     .folded .available-theme .screenshot {
    1179         width: 270px;
    1180     }
    1181 
    1182     .folded .available-theme .screenshot {
    1183         height: 203px;
    1184     }
    1185 }
    1186 
    1187 /* Allow for three-up on 1024px wide screens, e.g. tablets */
    1188 @media only screen and (max-width: 1200px) {
    1189     .available-theme,
    1190     .available-theme .screenshot {
    1191         width: 240px;
    1192     }
    1193 
    1194     .available-theme .screenshot {
    1195         height: 180px;
    1196     }
    1197 
    1198     .available-theme img {
    1199         width: 100%;
    1200     }
    1201 }
    1202 
    1203 .feature-filter {
    1204     padding: 8px 12px 0;
    1205 }
    1206 
    1207 .feature-filter .feature-group {
    1208     float: left;
    1209     margin: 5px 10px 10px;
    1210 }
    1211 
    1212 .feature-filter .feature-group li {
     1189}
     1190.more-filters-container {
     1191    display: none;
     1192    padding: 30px;
     1193    border-top: 1px solid #eee;
     1194    margin: 0 -20px;
     1195    background: #fafafa;
     1196}
     1197body.more-filters-opened .more-filters-container {
     1198    display: block;
     1199}
     1200.theme-install-php .add-new-theme {
     1201    display: none !important;
     1202}
     1203
     1204.rating {
     1205    margin: 30px 0;
     1206}
     1207.rating span:before {
     1208    color: #e6b800;
     1209    content: "\f154";
    12131210    display: inline-block;
     1211    -webkit-font-smoothing: antialiased;
     1212    font: normal 20px/1 'dashicons';
    12141213    vertical-align: top;
    1215     list-style-type: none;
    1216     padding-right: 25px;
    1217     width: 150px;
     1214}
     1215/* Half stars */
     1216.rating-10 span.one:before,
     1217.rating-30 span.two:before,
     1218.rating-50 span.three:before,
     1219.rating-70 span.four:before,
     1220.rating-90 span.five:before {
     1221    content: "\f459";
     1222}
     1223/* Full stars */
     1224.rating-20 span.one:before {
     1225    content: "\f155";
     1226}
     1227.rating-30 span.one:before,
     1228.rating-40 span.one:before,
     1229.rating-40 span.two:before {
     1230    content: "\f155";
     1231}
     1232.rating-50 span.one:before,
     1233.rating-50 span.two:before,
     1234.rating-60 span.one:before,
     1235.rating-60 span.two:before,
     1236.rating-60 span.three:before {
     1237    content: "\f155";
     1238}
     1239.rating-70 span.one:before,
     1240.rating-70 span.two:before,
     1241.rating-70 span.three:before,
     1242.rating-80 span.one:before,
     1243.rating-80 span.two:before,
     1244.rating-80 span.three:before,
     1245.rating-80 span.four:before {
     1246    content: "\f155";
     1247}
     1248.rating-90 span.one:before,
     1249.rating-90 span.two:before,
     1250.rating-90 span.three:before,
     1251.rating-90 span.four:before,
     1252.rating-100 span.one:before,
     1253.rating-100 span.two:before,
     1254.rating-100 span.three:before,
     1255.rating-100 span.four:before,
     1256.rating-100 span.five:before {
     1257    content: "\f155";
     1258}
     1259.rating .votes {
     1260    display: inline;
     1261    margin-left: 10px;
     1262    line-height: 20px;
     1263}
     1264.loading-themes .theme-browser,
     1265.error .theme-browser {
     1266    display: none;
     1267}
     1268.loading-themes .spinner {
     1269    display: block;
     1270    margin: 40px auto 0;
     1271    float: none;
    12181272}
    12191273
  • trunk/src/wp-admin/includes/theme-install.php

    r24189 r27499  
    133133<?php
    134134}
    135 add_action('install_themes_dashboard', 'install_themes_dashboard');
    136 
    137 function install_themes_upload($page = 1) {
     135// add_action('install_themes_dashboard', 'install_themes_dashboard');
     136
     137function install_themes_upload() {
    138138?>
    139 <h4><?php _e('Install a theme in .zip format'); ?></h4>
    140139<p class="install-help"><?php _e('If you have a theme in a .zip format, you may install it by uploading it here.'); ?></p>
    141140<form method="post" enctype="multipart/form-data" class="wp-upload-form" action="<?php echo self_admin_url('update.php?action=upload-theme'); ?>">
     
    146145    <?php
    147146}
    148 add_action('install_themes_upload', 'install_themes_upload', 10, 1);
     147// add_action('install_themes_upload', 'install_themes_upload', 10, 0);
    149148
    150149/**
     
    156155    _deprecated_function( __FUNCTION__, '3.4' );
    157156    global $wp_list_table;
     157    if ( ! isset( $wp_list_table ) ) {
     158        $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
     159    }
     160    $wp_list_table->prepare_items();
    158161    $wp_list_table->single_row( $theme );
    159162}
     
    167170    global $wp_list_table;
    168171
     172    if ( ! isset( $wp_list_table ) ) {
     173        $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
     174    }
     175    $wp_list_table->prepare_items();
    169176    $wp_list_table->display();
    170 }
    171 add_action('install_themes_search', 'display_themes');
    172 add_action('install_themes_featured', 'display_themes');
    173 add_action('install_themes_new', 'display_themes');
    174 add_action('install_themes_updated', 'display_themes');
     177
     178}
     179// add_action('install_themes_search', 'display_themes');
     180// add_action('install_themes_featured', 'display_themes');
     181// add_action('install_themes_new', 'display_themes');
     182// add_action('install_themes_updated', 'display_themes');
    175183
    176184/**
     
    180188 */
    181189function install_theme_information() {
    182     global $tab, $themes_allowedtags, $wp_list_table;
     190    global $wp_list_table;
    183191
    184192    $theme = themes_api( 'theme_information', array( 'slug' => wp_unslash( $_REQUEST['theme'] ) ) );
     
    188196
    189197    iframe_header( __('Theme Install') );
     198    if ( ! isset( $wp_list_table ) ) {
     199        $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
     200    }
    190201    $wp_list_table->theme_installer_single( $theme );
    191202    iframe_footer();
  • trunk/src/wp-admin/js/theme.js

    r27306 r27499  
    1313l10n = themes.data.l10n;
    1414
     15// Shortcut for isInstall check
     16themes.isInstall = !! themes.data.settings.isInstall;
     17
    1518// Setup app structure
    1619_.extend( themes, { model: {}, view: {}, routes: {}, router: {}, template: wp.template });
    1720
    18 themes.model = Backbone.Model.extend({});
     21themes.Model = Backbone.Model.extend({
     22    // Adds attributes to the default data coming through the .org themes api
     23    // Map `id` to `slug` for shared code
     24    initialize: function() {
     25        var install, preview;
     26
     27        // Install url for the theme
     28        // using the install nonce
     29        install = {
     30            action: 'install-theme',
     31            theme: this.get( 'slug' ),
     32            _wpnonce: themes.data.settings._nonceInstall
     33        };
     34
     35        // Build the url query
     36        install = themes.data.settings.updateURI + '?' + $.param( install );
     37
     38        // Preview url for the theme
     39        preview = {
     40            tab: 'theme-information',
     41            theme: this.get( 'slug' )
     42        };
     43
     44        preview = themes.data.settings.installURI + '?' + $.param( preview );
     45
     46        // Set the attributes
     47        this.set({
     48            installURI: install,
     49            previewURI: preview,
     50            id: this.get( 'slug' )
     51        });
     52    }
     53});
    1954
    2055// Main view controller for themes.php
     
    2964
    3065    // Sets up a throttler for binding to 'scroll'
    31     initialize: function() {
     66    initialize: function( options ) {
    3267        // Scroller checks how far the scroll position is
    3368        _.bindAll( this, 'scroller' );
    3469
     70        this.SearchView = options.SearchView ? options.SearchView : themes.view.Search;
    3571        // Bind to the scroll event and throttle
    3672        // the results from this.scroller
     
    5692    },
    5793
     94    // Defines search element container
     95    searchContainer: $( '#wpbody h2:first' ),
     96
    5897    // Search input and view
    5998    // for current theme collection
     
    67106        }
    68107
    69         view = new themes.view.Search({ collection: self.collection, parent: this });
     108        view = new this.SearchView({
     109            collection: self.collection,
     110            parent: this
     111        });
    70112
    71113        // Render and append after screen title
    72114        view.render();
    73         $('#wpbody h2:first')
     115        this.searchContainer
    74116            .append( $.parseHTML( '<label class="screen-reader-text" for="theme-search-input">' + l10n.search + '</label>' ) )
    75117            .append( view.el );
     
    96138themes.Collection = Backbone.Collection.extend({
    97139
    98     model: themes.model,
     140    model: themes.Model,
    99141
    100142    // Search terms
     
    188230
    189231    events: {
    190         'click': 'expand',
    191         'keydown': 'expand',
    192         'touchend': 'expand',
     232        'click': themes.isInstall ? 'preview': 'expand',
     233        'click .preview': 'preview',
     234        'keydown': themes.isInstall ? 'preview': 'expand',
     235        'touchend': themes.isInstall ? 'preview': 'expand',
    193236        'touchmove': 'preventExpand'
    194237    },
     
    251294    preventExpand: function() {
    252295        this.touchDrag = true;
     296    },
     297
     298    preview: function( event ) {
     299        // Bail if the user scrolled on a touch device
     300        if ( this.touchDrag === true ) {
     301            return this.touchDrag = false;
     302        }
     303
     304        event.preventDefault();
     305
     306        event = event || window.event;
     307
     308        var preview = new themes.view.Preview({
     309            model: this.model
     310        });
     311
     312        preview.render();
     313        $( 'div.wrap' ).append( preview.el );
    253314    }
    254315});
     
    416477});
    417478
     479// Theme Preview view
     480// Set ups a modal overlay with the expanded theme data
     481themes.view.Preview = wp.Backbone.View.extend({
     482
     483    className: 'wp-full-overlay expanded',
     484    el: '#theme-installer',
     485
     486    events: {
     487        'click .close-full-overlay': 'close',
     488        'click .collapse-sidebar': 'collapse'
     489    },
     490
     491    // The HTML template for the theme preview
     492    html: themes.template( 'theme-preview' ),
     493
     494    render: function() {
     495        var data = this.model.toJSON();
     496        this.$el.html( this.html( data ) );
     497
     498        themes.router.navigate( themes.router.baseUrl( '?theme=' + this.model.get( 'id' ) ), { replace: true } );
     499
     500        this.$el.fadeIn( 200, function() {
     501            $( 'body' ).addClass( 'theme-installer-active full-overlay-active' );
     502        });
     503    },
     504
     505    close: function() {
     506        this.$el.fadeOut( 200, function() {
     507            $( 'body' ).removeClass( 'theme-installer-active full-overlay-active' );
     508        });
     509
     510        themes.router.navigate( themes.router.baseUrl( '' ) );
     511        return false;
     512    },
     513
     514    collapse: function() {
     515        this.$el.toggleClass( 'collapsed' ).toggleClass( 'expanded' );
     516        return false;
     517    }
     518});
     519
    418520// Controls the rendering of div.themes,
    419521// a wrapper that will hold all the theme elements
     
    733835// Sets up the routes events for relevant url queries
    734836// Listens to [theme] and [search] params
    735 themes.routes = Backbone.Router.extend({
     837themes.Router = Backbone.Router.extend({
    736838
    737839    routes: {
     
    789891        // Bind to our global thx object
    790892        // so that the object is available to sub-views
    791         themes.router = new themes.routes();
     893        themes.router = new themes.Router();
    792894
    793895        // Handles theme details route event
     
    806908            self.themes.doSearch( query );
    807909        });
     910
     911        this.extraRoutes();
     912    },
     913
     914    extraRoutes: function() {
     915        return false;
    808916    }
    809917};
    810918
     919// Extend the main Search view
     920themes.view.InstallerSearch =  themes.view.Search.extend({
     921
     922    events: {
     923        'keyup': 'search'
     924    },
     925
     926    // Handles Ajax request for searching through themes in public repo
     927    search: function( event ) {
     928        this.collection = this.options.parent.view.collection;
     929
     930        // Clear on escape.
     931        if ( event.type === 'keyup' && event.which === 27 ) {
     932            event.target.value = '';
     933        }
     934
     935        _.debounce( _.bind( this.doSearch, this ), 300 )( event.target.value );
     936    },
     937
     938    doSearch: function( value ) {
     939        var request = {},
     940            self = this;
     941
     942        request.search = value;
     943
     944        // Intercept an [author] search.
     945        //
     946        // If input value starts with `author:` send a request
     947        // for `author` instead of a regular `search`
     948        if ( value.substring( 0, 7 ) === 'author:' ) {
     949            request.search = '';
     950            request.author = value.slice( 7 );
     951        }
     952
     953        // Intercept a [tag] search.
     954        //
     955        // If input value starts with `tag:` send a request
     956        // for `tag` instead of a regular `search`
     957        if ( value.substring( 0, 4 ) === 'tag:' ) {
     958            request.search = '';
     959            request.tag = [ value.slice( 4 ) ];
     960        }
     961
     962        // Send Ajax POST request to api.wordpress.org/themes
     963        themes.view.Installer.prototype.apiCall( request ).done( function( data ) {
     964                // Update the collection with the queried data
     965                self.collection.reset( data.themes );
     966                // Trigger a collection refresh event to render the views
     967                self.collection.trigger( 'update' );
     968
     969                // Un-spin it
     970                $( 'body' ).removeClass( 'loading-themes' );
     971                $( '.theme-browser' ).find( 'div.error' ).remove();
     972        }).fail( function() {
     973                $( '.theme-browser' ).find( 'div.error' ).remove();
     974                $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
     975        });
     976
     977        return false;
     978    }
     979});
     980
     981themes.view.Installer = themes.view.Appearance.extend({
     982
     983    el: '#wpbody-content .wrap',
     984
     985    // Register events for sorting and filters in theme-navigation
     986    events: {
     987        'click .theme-section': 'onSort',
     988        'click .theme-filter': 'onFilter',
     989        'click .more-filters': 'moreFilters'
     990    },
     991
     992    // Send Ajax POST request to api.wordpress.org/themes
     993    apiCall: function( request ) {
     994        return $.ajax({
     995            url: 'https://api.wordpress.org/themes/info/1.1/?action=query_themes',
     996
     997            // We want JSON data
     998            dataType: 'json',
     999            type: 'POST',
     1000            crossDomain: true,
     1001
     1002            // Request data
     1003            data: {
     1004                action: 'query_themes',
     1005                request: _.extend({
     1006                    per_page: 36,
     1007                    fields: {
     1008                        description: true,
     1009                        tested: true,
     1010                        requires: true,
     1011                        rating: true,
     1012                        downloaded: true,
     1013                        downloadLink: true,
     1014                        last_updated: true,
     1015                        homepage: true,
     1016                        num_ratings: true
     1017                    }
     1018                }, request)
     1019            },
     1020
     1021            beforeSend: function() {
     1022                // Spin it
     1023                $( 'body' ).addClass( 'loading-themes' );
     1024            }
     1025        });
     1026    },
     1027
     1028    // Handles all the rendering of the public theme directory
     1029    browse: function( section ) {
     1030        var self = this;
     1031
     1032        // @todo Cache the collection after fetching based on the section
     1033        this.collection = new themes.Collection();
     1034
     1035        // Create a new collection with the proper theme data
     1036        // for each section
     1037        this.apiCall({ browse: section }).done( function( data ) {
     1038            // Update the collection with the queried data
     1039            self.collection.reset( data.themes );
     1040            // Trigger a collection refresh event to render the views
     1041            self.collection.trigger( 'update' );
     1042
     1043            // Un-spin it
     1044            $( 'body' ).removeClass( 'loading-themes' );
     1045            $( '.theme-browser' ).find( 'div.error' ).remove();
     1046        });
     1047
     1048        if ( this.view ) {
     1049            this.view.remove();
     1050        }
     1051
     1052        // Set ups the view and passes the section argument
     1053        this.view = new themes.view.Themes({
     1054            collection: this.collection,
     1055            section: section,
     1056            parent: this
     1057        });
     1058
     1059        // Reset pagination every time the install view handler is run
     1060        this.page = 0;
     1061
     1062        // Render and append
     1063        this.$el.find( '.themes' ).remove();
     1064        this.view.render();
     1065        this.$el.find( '.theme-browser' ).append( this.view.el ).addClass( 'rendered' );
     1066    },
     1067
     1068    // Initial render method
     1069    render: function() {
     1070        this.search();
     1071        this.uploader();
     1072        return this.browse( this.options.section );
     1073    },
     1074
     1075    // Sorting navigation
     1076    onSort: function( event ) {
     1077        var $el = $( event.target ),
     1078            sort = $el.data( 'sort' );
     1079
     1080        // Bail if this is already active
     1081        if ( $el.hasClass( this.activeClass ) ) {
     1082            return;
     1083        }
     1084
     1085        this.sort( sort );
     1086
     1087        // Trigger a router.naviagte update
     1088        themes.router.navigate( themes.router.baseUrl( '?sort=' + sort ) );
     1089    },
     1090
     1091    sort: function( sort ) {
     1092        $( '#theme-search-input' ).val( '' );
     1093
     1094        $( '.theme-section, .theme-filter' ).removeClass( this.activeClass );
     1095        $( '[data-sort="' + sort + '"]' ).addClass( this.activeClass );
     1096
     1097        this.browse( sort );
     1098    },
     1099
     1100    // Filters and Tags
     1101    onFilter: function( event ) {
     1102        var request,
     1103            $el = $( event.target ),
     1104            filter = $el.data( 'filter' ),
     1105            self = this;
     1106
     1107        // Bail if this is already active
     1108        if ( $el.hasClass( this.activeClass ) ) {
     1109            return;
     1110        }
     1111
     1112        $( '.theme-filter, .theme-section' ).removeClass( this.activeClass );
     1113        $el.addClass( this.activeClass );
     1114
     1115        if ( ! filter ) {
     1116            return;
     1117        }
     1118
     1119        // Construct the filter request
     1120        // using the default values
     1121
     1122        // @todo Cache the collection after fetching based on the filter
     1123        request = { tag: [ filter ] };
     1124
     1125        // Send Ajax POST request to api.wordpress.org/themes
     1126        this.apiCall( request ).done( function( data ) {
     1127                // Update the collection with the queried data
     1128                self.collection.reset( data.themes );
     1129                // Trigger a collection refresh event to render the views
     1130                self.collection.trigger( 'update' );
     1131
     1132                // Un-spin it
     1133                $( 'body' ).removeClass( 'loading-themes' );
     1134                $( '.theme-browser' ).find( 'div.error' ).remove();
     1135        }).fail( function() {
     1136                $( '.theme-browser' ).find( 'div.error' ).remove();
     1137                $( '.theme-browser' ).append( '<div class="error"><p>' + l10n.error + '</p></div>' );
     1138        });
     1139
     1140        return false;
     1141    },
     1142
     1143    activeClass: 'current',
     1144
     1145    // Overwrite search container class to append search
     1146    // in new location
     1147    searchContainer: $( '.theme-navigation' ),
     1148
     1149    uploader: function() {
     1150        $( 'a.upload.button' ).on( 'click', function() {
     1151            $( '.upload-theme' )
     1152                .toggleClass( 'opened' )
     1153                .hasClass( 'opened' ) ? $( this ).text( l10n.back ) : $( this ).text( l10n.upload );
     1154        });
     1155    },
     1156
     1157    moreFilters: function() {
     1158        $( 'body' ).toggleClass( 'more-filters-opened' );
     1159    }
     1160});
     1161
     1162themes.InstallerRouter = Backbone.Router.extend({
     1163    routes: {
     1164        'theme-install.php?theme=:slug': 'preview',
     1165        'theme-install.php(?sort=:sort)': 'sort',
     1166        '': 'sort'
     1167    },
     1168
     1169    baseUrl: function( url ) {
     1170        return 'theme-install.php' + url;
     1171    }
     1172});
     1173
     1174
     1175themes.RunInstaller = {
     1176
     1177    init: function() {
     1178        // Set up the view
     1179        // Passes the default 'section' as an option
     1180        this.view = new themes.view.Installer({
     1181            section: 'featured',
     1182            SearchView: themes.view.InstallerSearch
     1183        });
     1184
     1185        // Render results
     1186        this.render();
     1187
     1188    },
     1189
     1190    render: function() {
     1191
     1192        // Render results
     1193        this.view.render();
     1194        this.routes();
     1195
     1196        Backbone.history.start({
     1197            root: themes.data.settings.adminUrl,
     1198            pushState: true,
     1199            hashChange: false
     1200        });
     1201    },
     1202
     1203    routes: function() {
     1204        var self = this;
     1205        // Bind to our global thx object
     1206        // so that the object is available to sub-views
     1207        themes.router = new themes.InstallerRouter();
     1208
     1209        // Handles theme details route event
     1210        themes.router.on( 'route:theme', function( slug ) {
     1211            self.view.view.expand( slug );
     1212        });
     1213
     1214        themes.router.on( 'route:sort', function( sort ) {
     1215            if ( ! sort ) {
     1216                sort = 'featured';
     1217            }
     1218            self.view.sort( sort );
     1219            self.view.trigger( 'theme:close' );
     1220        });
     1221
     1222        this.extraRoutes();
     1223    },
     1224
     1225    extraRoutes: function() {
     1226        return false;
     1227    }
     1228};
     1229
    8111230// Ready...
    812 jQuery( document ).ready(
    813 
    814     // Bring on the themes
    815     _.bind( themes.Run.init, themes.Run )
    816 
    817 );
     1231$( document ).ready(function() {
     1232    if ( themes.isInstall ) {
     1233        themes.RunInstaller.init();
     1234    } else {
     1235        themes.Run.init();
     1236    }
     1237});
    8181238
    8191239})( jQuery );
  • trunk/src/wp-admin/theme-install.php

    r27469 r27499  
    77 */
    88
    9 if ( !defined( 'IFRAME_REQUEST' ) && isset( $_GET['tab'] ) && ( 'theme-information' == $_GET['tab'] ) )
    10     define( 'IFRAME_REQUEST', true );
    11 
    129/** WordPress Administration Bootstrap */
    1310require_once( dirname( __FILE__ ) . '/admin.php' );
     11require( ABSPATH . 'wp-admin/includes/theme-install.php' );
     12
     13wp_reset_vars( array( 'tab' ) );
    1414
    1515if ( ! current_user_can('install_themes') )
     
    2121}
    2222
    23 $wp_list_table = _get_list_table('WP_Theme_Install_List_Table');
    24 $pagenum = $wp_list_table->get_pagenum();
    25 $wp_list_table->prepare_items();
    26 
    27 $title = __('Install Themes');
     23$title = __( 'Add Themes' );
    2824$parent_file = 'themes.php';
    29 if ( !is_network_admin() )
     25
     26if ( ! is_network_admin() ) {
    3027    $submenu_file = 'themes.php';
    31 
    32 wp_enqueue_script( 'theme-install' );
    33 wp_enqueue_script( 'theme-preview' );
    34 
    35 $body_id = $tab;
     28}
     29
     30$sections = array(
     31    'featured' => __( 'Featured Themes' ),
     32    'popular'  => __( 'Popular Themes' ),
     33    'new'      => __( 'Newest Themes' ),
     34);
     35
     36wp_localize_script( 'theme', '_wpThemeSettings', array(
     37    'themes'   => false,
     38    'settings' => array(
     39        'isInstall'     => true,
     40        'canInstall'    => current_user_can( 'install_themes' ),
     41        'installURI'    => current_user_can( 'install_themes' ) ? self_admin_url( 'theme-install.php' ) : null,
     42        'adminUrl'      => parse_url( self_admin_url(), PHP_URL_PATH ),
     43        'updateURI'     => self_admin_url( 'update.php' ),
     44        '_nonceInstall' => wp_create_nonce( 'install-theme' )
     45    ),
     46    'l10n' => array(
     47        'addNew' => __( 'Add New Theme' ),
     48        'search'  => __( 'Search Themes' ),
     49        'searchPlaceholder' => __( 'Search themes...' ),
     50        'upload' => __( 'Upload Theme' ),
     51        'back'   => __( 'Back' ),
     52        'error'  => __( 'There was a problem trying to load the themes. Please, try again.' ),
     53    ),
     54    'browse' => array(
     55        'sections' => $sections,
     56    ),
     57) );
     58
     59wp_enqueue_script( 'theme' );
    3660
    3761/**
     
    4468 * @since 2.8.0
    4569 */
    46 do_action( "install_themes_pre_{$tab}" );
     70if ( $tab ) {
     71    do_action( "install_themes_pre_{$tab}" );
     72}
    4773
    4874$help_overview =
     
    74100
    75101include(ABSPATH . 'wp-admin/admin-header.php');
     102
    76103?>
    77104<div class="wrap">
    78 <h2><?php echo esc_html( $title ); ?></h2>
    79 <?php
    80 
    81 $wp_list_table->views(); ?>
    82 
    83 <br class="clear" />
     105    <h2>
     106        <?php echo esc_html( $title ); ?>
     107        <a class="upload button button-secondary"><?php esc_html_e( 'Upload Theme' ); ?></a>
     108    </h2>
     109
     110    <div class="upload-theme">
     111    <?php install_themes_upload(); ?>
     112    </div>
     113
     114    <div class="theme-navigation">
     115        <span class="theme-count"></span>
     116        <span class="theme-section current" data-sort="featured"><?php esc_html_e( 'Featured' ); ?></span>
     117        <span class="theme-section" data-sort="popular"><?php esc_html_e( 'Popular' ); ?></span>
     118        <span class="theme-section" data-sort="new"><?php esc_html_e( 'Latest' ); ?></span>
     119        <div class="theme-top-filters">
     120            <span class="theme-filter" data-filter="photoblogging">Photography</span>
     121            <span class="theme-filter" data-filter="responsive-layout">Responsive</span>
     122            <span class="theme-filter more-filters">More</span>
     123        </div>
     124        <div class="more-filters-container">
     125            Display more filters.
     126        </div>
     127    </div>
     128    <div class="theme-browser"></div>
     129    <div class="theme-overlay"></div>
     130    <div id="theme-installer" class="wp-full-overlay expanded"></div>
     131
     132    <span class="spinner"></span>
     133
     134    <br class="clear" />
    84135<?php
    85136/**
     
    94145 * @param int $paged Number of the current page of results being viewed.
    95146 */
    96 do_action( "install_themes_{$tab}", $paged );
     147if ( $tab ) {
     148    do_action( "install_themes_{$tab}", $paged );
     149}
    97150?>
    98151</div>
     152
     153<script id="tmpl-theme" type="text/template">
     154    <# if ( data.screenshot_url ) { #>
     155        <div class="theme-screenshot">
     156            <img src="{{ data.screenshot_url }}" alt="" />
     157        </div>
     158    <# } else { #>
     159        <div class="theme-screenshot blank"></div>
     160    <# } #>
     161    <span class="more-details"><?php _ex( 'Details &amp; Preview', 'theme' ); ?></span>
     162    <div class="theme-author"><?php printf( __( 'By %s' ), '{{ data.author }}' ); ?></div>
     163    <h3 class="theme-name">{{ data.name }}</h3>
     164
     165    <div class="theme-actions">
     166        <a class="button button-primary" href="{{ data.installURI }}"><?php esc_html_e( 'Install' ); ?></a>
     167        <a class="button button-secondary preview install-theme-preview" href="#"><?php esc_html_e( 'Preview' ); ?></a>
     168    </div>
     169</script>
     170
     171<script id="tmpl-theme-preview" type="text/template">
     172    <div class="wp-full-overlay-sidebar">
     173        <div class="wp-full-overlay-header">
     174            <a href="" class="close-full-overlay button-secondary"><?php _e( 'Close' ); ?></a>
     175            <a href="{{ data.installURI }}" class="button button-primary theme-install"><?php _e( 'Install' ); ?></a>
     176        </div>
     177        <div class="wp-full-overlay-sidebar-content">
     178            <div class="install-theme-info">
     179                <h3 class="theme-name">{{ data.name }}</h3>
     180                <span class="theme-by"><?php printf( __( 'By %s' ), '{{ data.author }}' ); ?></span>
     181
     182                <img class="theme-screenshot" src="{{ data.screenshot_url }}" alt="" />
     183
     184                <div class="theme-details">
     185                    <div class="rating rating-{{ Math.round( data.rating / 10 ) * 10 }}">
     186                        <span class="one"></span>
     187                        <span class="two"></span>
     188                        <span class="three"></span>
     189                        <span class="four"></span>
     190                        <span class="five"></span>
     191                        <p class="votes"><?php printf( __( 'Based on %s ratings.' ), '{{ data.num_ratings }}' ); ?></p>
     192                    </div>
     193                    <div class="theme-version"><?php printf( __( 'Version: %s' ), '{{ data.version }}' ); ?></div>
     194                    <div class="theme-description">{{ data.description }}</div>
     195                </div>
     196            </div>
     197        </div>
     198        <div class="wp-full-overlay-footer">
     199            <a href="" class="collapse-sidebar" title="<?php esc_attr_e( 'Collapse Sidebar' ); ?>">
     200                <span class="collapse-sidebar-label"><?php _e( 'Collapse' ); ?></span>
     201                <span class="collapse-sidebar-arrow"></span>
     202            </a>
     203        </div>
     204    </div>
     205    <div class="wp-full-overlay-main">
     206        <iframe src="{{ data.preview_url }}" />
     207    </div>
     208</script>
     209
    99210<?php
    100211include(ABSPATH . 'wp-admin/admin-footer.php');
  • trunk/src/wp-admin/update.php

    r27280 r27499  
    203203        include_once ABSPATH . 'wp-admin/includes/theme-install.php'; //for themes_api..
    204204
    205         check_admin_referer('install-theme_' . $theme);
     205        check_admin_referer( 'install-theme' );
    206206        $api = themes_api('theme_information', array('slug' => $theme, 'fields' => array('sections' => false, 'tags' => false) ) ); //Save on a bit of bandwidth.
    207207
  • trunk/src/wp-includes/script-loader.php

    r27497 r27499  
    455455
    456456        $scripts->add( 'theme', "/wp-admin/js/theme$suffix.js", array( 'wp-backbone' ), false, 1 );
    457         $scripts->add( 'theme-install', "/wp-admin/js/theme-install$suffix.js", array( 'jquery' ), false, 1 );
    458 
    459         // @todo: Core no longer uses theme-preview.js. Remove?
    460         $scripts->add( 'theme-preview', "/wp-admin/js/theme-preview$suffix.js", array( 'thickbox', 'jquery' ), false, 1 );
    461457
    462458        $scripts->add( 'inline-edit-post', "/wp-admin/js/inline-edit-post$suffix.js", array( 'jquery', 'suggest', 'heartbeat' ), false, 1 );
Note: See TracChangeset for help on using the changeset viewer.