Make WordPress Core

Changeset 27499


Ignore:
Timestamp:
03/11/2014 07:46:27 AM (12 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.