WordPress.org

Make WordPress Core

Changeset 27499


Ignore:
Timestamp:
03/11/14 07:46:27 (3 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.