WordPress.org

Make WordPress Core

Changeset 20545


Ignore:
Timestamp:
04/20/2012 02:39:55 AM (8 years ago)
Author:
koopersmith
Message:

Theme Customizer: Improve image picker control. see #19910.

Overhauled image pickers:

  • Add support for drag and drop uploads to image controls.
  • Improve the 'uploaded' tab in image controls: automatically add images uploaded during the current session, hide the tab when no uploaded images exist.
  • Move the header image control to the WP_Customize_Header_Image_Control class. Remove wp_customize_print_uploaded_headers() and wp_customize_print_uploaded_headers() functions.
  • Abstract the dropdown functionality from the color picker to the .dropdown class.
  • In wp.Uploader, unset element keys if passed an empty jQuery collection.
Location:
trunk/wp-includes
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • trunk/wp-includes/class-wp-customize-control.php

    r20527 r20545  
    181181                <label>
    182182                    <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
    183                     <a href="#" class="color-picker-toggle">
    184                         <div class="color-picker-spot"></div>
    185                         <div class="color-picker-dropdown"></div>
    186                     </a>
     183                    <div class="dropdown color-picker-toggle">
     184                        <div class="dropdown-content color-picker-spot"></div>
     185                        <div class="dropdown-arrow"></div>
     186                    </div>
    187187                    <div class="color-picker-control color-picker-hex">
    188188                        <span>#</span>
     
    292292class WP_Customize_Image_Control extends WP_Customize_Upload_Control {
    293293    public $type = 'image';
    294     public $tabs = array();
    295294    public $get_url;
     295
     296    protected $tabs = array();
     297
     298    public function __construct( $manager, $id, $args ) {
     299        parent::__construct( $manager, $id, $args );
     300
     301        $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );
     302        $this->add_tab( 'uploaded',   __('Uploaded'),   array( $this, 'tab_uploaded' ) );
     303    }
    296304
    297305    public function render_content() {
     
    304312            <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
    305313
    306             <div class="thumbnail">
    307                 <?php if ( empty( $src ) ): ?>
    308                     <img style="display:none;" />
    309                 <?php else: ?>
    310                     <img src="<?php echo esc_url( $src ); ?>" />
    311                 <?php endif; ?>
    312             </div>
    313 
    314             <div class="actions">
    315                 <a href="#" class="upload"><?php _e( 'Upload New' ); ?></a>
    316                 <a href="#" class="change"><?php _e( 'Change Image' ); ?></a>
    317                 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
     314
     315            <div class="dropdown preview-thumbnail">
     316                <div class="dropdown-content">
     317                    <?php if ( empty( $src ) ): ?>
     318                        <img style="display:none;" />
     319                    <?php else: ?>
     320                        <img src="<?php echo esc_url( $src ); ?>" />
     321                    <?php endif; ?>
     322                </div>
     323                <div class="dropdown-arrow"></div>
    318324            </div>
    319325
    320326            <div class="library">
    321327                <ul>
    322                     <?php foreach ( $this->tabs as $tab ): ?>
    323                         <li data-customize-tab='<?php echo esc_attr( $tab[0] ); ?>'>
    324                             <?php echo esc_html( $tab[1] ); ?>
     328                    <?php foreach ( $this->tabs as $id => $tab ): ?>
     329                        <li data-customize-tab='<?php echo esc_attr( $id ); ?>'>
     330                            <?php echo esc_html( $tab['label'] ); ?>
    325331                        </li>
    326332                    <?php endforeach; ?>
    327333                </ul>
    328                 <?php foreach ( $this->tabs as $tab ): ?>
    329                     <div class="library-content" data-customize-tab='<?php echo esc_attr( $tab[0] ); ?>'>
    330                         <?php call_user_func( $tab[2] ); ?>
     334                <?php foreach ( $this->tabs as $id => $tab ): ?>
     335                    <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>
     336                        <?php call_user_func( $tab['callback'] ); ?>
    331337                    </div>
    332338                <?php endforeach; ?>
    333339            </div>
     340
     341            <div class="actions">
     342                <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>
     343            </div>
    334344        </label>
    335345        <?php
    336346    }
     347
     348    public function add_tab( $id, $label, $callback ) {
     349        $this->tabs[ $id ] = array(
     350            'label'    => $label,
     351            'callback' => $callback,
     352        );
     353    }
     354
     355    public function remove_tab( $id ) {
     356        unset( $this->tabs[ $id ] );
     357    }
     358
     359    public function tab_upload_new() {
     360        ?>
     361        <div class="upload-dropzone">
     362            <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?>
     363        </div>
     364        <?php
     365    }
     366
     367    public function tab_uploaded() {
     368        ?>
     369        <div class="uploaded-target"></div>
     370        <?php
     371    }
    337372}
     373
     374class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control {
     375    public function __construct( $manager ) {
     376        parent::__construct( $manager, 'header_image', array(
     377            'label'   => __( 'Header Image' ),
     378            'section' => 'header',
     379            'context' => 'custom-header',
     380            'removed' => 'remove-header',
     381            'get_url' => 'get_header_image',
     382        ) );
     383
     384        $this->add_tab( 'default',  __('Default'),  array( $this, 'tab_default_headers' ) );
     385    }
     386
     387    public function tab_uploaded() {
     388        $headers = get_uploaded_header_images();
     389
     390        ?><div class="uploaded-target"></div><?php
     391
     392        foreach ( $headers as $header ) : ?>
     393            <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $header['url'] ); ?>">
     394                <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
     395            </a>
     396        <?php endforeach;
     397    }
     398
     399    public function tab_default_headers() {
     400        global $custom_image_header;
     401        $custom_image_header->process_default_headers();
     402
     403        foreach ( $custom_image_header->default_headers as $header ) : ?>
     404            <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $header['url'] ); ?>">
     405                <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
     406            </a>
     407        <?php endforeach;
     408    }
     409}
  • trunk/wp-includes/class-wp-customize.php

    r20506 r20545  
    538538        ) );
    539539
    540         $this->add_control( new WP_Customize_Image_Control( $this, 'header_image', array(
    541             'label'          => 'Header Image',
    542             'section'        => 'header',
    543             'context'        => 'custom-header',
    544             'removed'        => 'remove-header',
    545             'get_url'        => 'get_header_image',
    546             'tabs'           => array(
    547                 array( 'uploaded', __('Uploaded'), 'wp_customize_print_uploaded_headers' ),
    548                 array( 'included', __('Included'), 'wp_customize_print_included_headers' ),
    549             ),
    550         ) ) );
     540        $this->add_control( new WP_Customize_Header_Image_Control( $this ) );
    551541
    552542        /* Custom Background */
     
    760750    return $color;
    761751}
    762 
    763 function wp_customize_print_uploaded_headers() {
    764     $headers = get_uploaded_header_images();
    765 
    766     foreach ( $headers as $header ) : ?>
    767         <a href="<?php echo esc_url( $header['url'] ); ?>">
    768             <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
    769         </a>
    770     <?php endforeach;
    771 }
    772 
    773 function wp_customize_print_included_headers() {
    774     global $custom_image_header;
    775     $custom_image_header->process_default_headers();
    776 
    777     foreach ( $custom_image_header->default_headers as $header ) : ?>
    778         <a href="<?php echo esc_url( $header['url'] ); ?>">
    779             <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" />
    780         </a>
    781     <?php endforeach;
    782 }
  • trunk/wp-includes/css/customize-controls.dev.css

    r20530 r20545  
    197197
    198198/*
    199  * Color Picker
     199 * Dropdowns
    200200 */
    201 .customize-section .color-picker-toggle {
    202     float: left;
    203     display: block;
     201.customize-section .dropdown {
     202    float: left;
     203    display: block;
     204    position: relative;
     205    cursor: pointer;
    204206
    205207    -webkit-border-radius: 3px;
     
    207209}
    208210
    209 .customize-section .color-picker-spot,
    210 .customize-section .color-picker-dropdown {
    211     float: left;
     211.customize-section .dropdown-content {
     212    overflow: hidden;
     213    float: left;
     214    min-width: 30px;
    212215    height: 24px;
    213216    line-height: 24px;
    214 }
    215 
    216 .customize-section .color-picker-spot {
    217     min-width: 30px;
     217    margin-right: 16px;
    218218    padding: 0 5px;
    219     background-color: #fff;
    220     border: 1px solid rgba( 0, 0, 0, 0.15 );
     219    background-color: #eee;
     220    border: 1px solid #ccc;
    221221    -webkit-border-radius: 3px 0 0 3px;
    222222    border-radius: 3px 0 0 3px;
    223223}
    224224
    225 .customize-section .color-picker-dropdown {
    226     position: relative;
     225.customize-control .dropdown-arrow {
     226    position: absolute;
     227    top: 0;
     228    bottom: 0;
     229    right: 0;
    227230    width: 15px;
    228231
     
    234237}
    235238
    236 .customize-section .color-picker-dropdown:after {
     239.customize-control .dropdown-arrow:after {
    237240    content: '';
    238241    width: 0;
    239242    height: 0;
    240     border-color: #ccc transparent transparent transparent;
     243    border-color: #ccc transparent;
    241244    border-style: solid;
    242     border-width: 4px;
     245    border-width: 4px 4px 0 4px;
    243246    position: absolute;
    244     top: 11px;
     247    top: 50%;
     248    margin-top: -1px;
    245249    right: 4px;
    246250    z-index: 1;
    247251}
    248252
    249 .customize-section .color-picker-toggle.open .color-picker-dropdown:after {
    250     border-color: transparent transparent #ccc transparent;
    251     top: 6px;
    252 }
    253 
    254 .customize-section .color-picker-toggle:hover .color-picker-spot {
     253.customize-control.open .dropdown-arrow:after {
     254    border-width: 0 4px 4px 4px;
     255    margin-top: -2px;
     256}
     257
     258.customize-section .dropdown:hover .dropdown-content,
     259.customize-control .dropdown:hover .dropdown-arrow {
     260    border-color: #aaa;
     261}
     262
     263.customize-section .dropdown:hover .dropdown-arrow:after {
     264    border-color: #aaa transparent;
     265}
     266
     267/*
     268 * Color Picker
     269 */
     270.customize-control .color-picker-control {
     271    display: none;
     272}
     273.customize-control.open .color-picker-control {
     274    display: block;
     275}
     276
     277.customize-control .dropdown .color-picker-spot {
     278    background-color: #fff;
     279    border: 1px solid rgba( 0, 0, 0, 0.15 );
     280}
     281
     282.customize-section .dropdown:hover .color-picker-spot {
    255283    border-color: rgba( 0, 0, 0, 0.25 );
    256 }
    257 
    258 .customize-section .color-picker-toggle:hover .color-picker-dropdown {
    259     border-color: #aaa;
    260 }
    261 
    262 .customize-section .color-picker-toggle:hover .color-picker-dropdown:after {
    263     border-color: #aaa transparent transparent transparent;
    264 }
    265 
    266 .customize-section .color-picker-toggle.open:hover .color-picker-dropdown:after {
    267     border-color: transparent transparent #aaa transparent;
    268 }
    269 
    270 .customize-section .color-picker-control {
    271     display: none;
    272284}
    273285
     
    318330 * Image Picker
    319331 */
    320 .customize-section .customize-control-image .thumbnail {
    321     float: right;
    322     width: 138px;
    323     min-height: 25px;
    324     border: 1px solid #ccc;
    325     margin-bottom: 5px;
    326     background: #eee;
    327 }
    328 
    329 .customize-section .customize-control-image .thumbnail img {
    330     display: block;
    331     max-width: 138px;
     332
     333.customize-control-image .library,
     334.customize-control-image .actions {
     335    display: none;
     336}
     337.customize-control-image.open .library,
     338.customize-control-image.open .actions {
     339    display: block;
     340}
     341
     342.customize-section .customize-control-image .dropdown-content {
     343    height: auto;
     344    min-height: 24px;
     345    min-width: 40px;
     346    padding: 0;
     347}
     348
     349.customize-section .customize-control-image .preview-thumbnail img {
     350    display: block;
     351    max-width: 122px;
    332352    max-height: 98px;
    333353    margin: 0 auto;
     
    335355
    336356.customize-section .customize-control-image .actions {
    337     width: 140px;
    338357    float: right;
    339358}
     
    342361    display: block;
    343362}
    344 
    345 .customize-section .customize-control-image .library {
    346     display: none;
    347 /*  float: left;*/
    348 }
    349 
    350 /*.customize-section .customize-control-image .library label {
    351     display: block;
    352     position: relative;
    353     float: left;
    354     padding: 0 0 5px 20px;
    355 }
    356 .customize-section .customize-control-image .library input {
    357     display: block;
    358     position: absolute;
    359     top: 50%;
    360     left: 0;
    361     margin-top: -7px;
    362 }*/
    363 /*.customize-section .customize-control-image .library .wp-tab-panel {
    364     padding: 10px 10px 5px 8px;
    365 }*/
    366363
    367364.customize-section .customize-control-image .library ul {
     
    369366    float: left;
    370367    width: 100%;
    371     margin: 5px 0;
     368    margin: 10px 0 0;
    372369}
    373370
     
    375372    color: #999;
    376373    float: left;
    377     padding: 4px 6px;
     374    padding: 3px 5px;
    378375    margin: 0;
    379376    border-style: solid;
     
    383380
    384381.customize-section .customize-control-image .library li.library-selected {
     382    margin-bottom: -1px;
     383    padding-bottom: 4px;
     384
    385385    color: #777;
     386    background: #f5f5f5;
    386387    border-color: #dfdfdf;
    387     background: #f5f5f5;
    388     margin-bottom: -1px;
    389     padding-bottom: 5px;
    390 }
    391 
    392 .customize-section .customize-control-image .library div {
     388    -webkit-border-radius: 3px 3px 0 0;
     389    border-radius: 3px 3px 0 0 ;
     390}
     391
     392.customize-section .customize-control-image .library-content {
     393    display: none;
     394    width: 260px;
     395    float: left;
     396    padding: 10px 0;
     397}
     398
     399.customize-section .customize-control-image .library-content.library-selected {
     400    display: block;
     401}
     402
     403.customize-section .customize-control-image .library .thumbnail {
     404    display: block;
    393405    width: 100%;
    394     float: left;
    395 }
    396 
    397 .customize-section .customize-control-image .library a {
     406}
     407
     408.customize-section .customize-control-image .library .thumbnail:hover img {
     409    border-color: #21759b;
     410}
     411
     412.customize-section .customize-control-image .library .thumbnail img {
    398413    display: block;
    399414    max-width: 220px;
    400415    max-height: 80px;
     416
    401417    margin: 5px auto;
    402418    padding: 4px;
     
    405421}
    406422
    407 .customize-section .customize-control-image .library a:hover {
    408     border-color: #21759b;
    409 }
    410 
    411 .customize-section .customize-control-image .library img {
    412     display: block;
    413     max-width: 220px;
    414     max-height: 80px;
    415 }
    416 
    417 .customize-section .customize-control-image .library-content {
    418     display: none;
    419 }
     423.customize-section .customize-control-upload .upload-dropzone,
     424.customize-section .customize-control-image .upload-dropzone {
     425    padding: 15px 10px;
     426    border: 3px dashed #dfdfdf;
     427    margin: 5px auto;
     428    text-align: center;
     429    color: #777;
     430    position: relative;
     431}
  • trunk/wp-includes/js/customize-controls.dev.js

    r20506 r20545  
    9191                });
    9292            });
     93
     94            // Support the .dropdown class to open/close complex elements
     95            this.container.on( 'click', '.dropdown', function( event ) {
     96                event.preventDefault();
     97                control.container.toggleClass('open');
     98            });
    9399        },
    94100        ready: function() {}
     
    98104        ready: function() {
    99105            var control = this,
    100                 toggle, spot, ui, text, update;
    101 
    102             toggle = this.container.find( '.color-picker-toggle' );
    103             spot   = toggle.find('.color-picker-spot');
    104             ui     = this.container.find( '.color-picker-control' );
     106                spot, text, update;
     107
     108            spot   = this.container.find('.color-picker-spot');
    105109            update = function( color ) {
    106110                color = '#' + color;
     
    109113            };
    110114
    111             toggle.on( 'click', function( event ) {
    112                 ui.toggle();
    113                 toggle.toggleClass( 'open' );
    114                 event.preventDefault();
    115             });
    116 
    117115            this.farbtastic = $.farbtastic( this.container.find('.farbtastic-placeholder'), function( color ) {
    118116                control.setting.set( color.replace( '#', '' ) );
     
    130128            this.params.removed = this.params.removed || '';
    131129
     130            this.success = $.proxy( this.success, this );
     131
    132132            this.uploader = new wp.Uploader({
    133                 browser: this.container.find('.upload'),
    134                 success: function( attachment ) {
    135                     control.setting.set( attachment.url );
    136                 }
     133                browser:  this.container.find('.upload'),
     134                dropzone: this.container.find('.upload-dropzone'),
     135                success:  this.success
    137136            });
    138137
     
    150149                control.uploader.param( 'post_data[context]', this.params.context );
    151150        },
     151        success: function( attachment ) {
     152            this.setting.set( attachment.url );
     153        },
    152154        removerVisibility: function( to ) {
    153155            this.remover.toggle( to != this.params.removed );
     
    157159    api.ImageControl = api.UploadControl.extend({
    158160        ready: function() {
    159             var control = this;
     161            var control = this,
     162                panels;
    160163
    161164            api.UploadControl.prototype.ready.call( this );
    162165
    163             this.thumbnail    = this.container.find('.thumbnail img');
     166            this.thumbnail    = this.container.find('.preview-thumbnail img');
    164167            this.thumbnailSrc = $.proxy( this.thumbnailSrc, this );
    165168            this.setting.bind( this.thumbnailSrc );
    166169
    167170            this.library = this.container.find('.library');
    168             this.changer = this.container.find('.change');
    169 
    170             this.changer.click( function( event ) {
    171                 control.library.toggle();
     171
     172            // Generate tab objects
     173            this.tabs = {};
     174            panels    = this.library.find('.library-content');
     175
     176            this.library.children('ul').children('li').each( function() {
     177                var link  = $(this),
     178                    id    = link.data('customizeTab'),
     179                    panel = panels.filter('[data-customize-tab="' + id + '"]');
     180
     181                control.tabs[ id ] = {
     182                    both:  link.add( panel ),
     183                    link:  link,
     184                    panel: panel
     185                };
     186            });
     187
     188            // Select a tab
     189            this.selected = this.tabs[ panels.first().data('customizeTab') ];
     190            this.selected.both.addClass('library-selected');
     191
     192            // Bind tab switch events
     193            this.library.children('ul').on( 'click', 'li', function( event ) {
     194                var id  = $(this).data('customizeTab'),
     195                    tab = control.tabs[ id ];
     196
    172197                event.preventDefault();
    173             });
    174 
    175             this.library.on( 'click', 'li', function( event ) {
    176                 var tab = $(this),
    177                     id = tab.data('customizeTab');
    178 
    179                 event.preventDefault();
    180 
    181                 if ( tab.hasClass('library-selected') )
     198
     199                if ( tab.link.hasClass('library-selected') )
    182200                    return;
    183201
    184                 tab.siblings('.library-selected').removeClass('library-selected');
    185                 tab.addClass('library-selected');
    186 
    187                 control.library.find('div').hide().filter( function() {
    188                     return $(this).data('customizeTab') === id;
    189                 }).show();
     202                control.selected.both.removeClass('library-selected');
     203                control.selected = tab;
     204                control.selected.both.addClass('library-selected');
    190205            });
    191206
    192207            this.library.on( 'click', 'a', function( event ) {
    193                 control.setting.set( $(this).attr('href') );
    194                 event.preventDefault();
    195             });
     208                var value = $(this).data('customizeImageValue');
     209
     210                if ( value ) {
     211                    control.setting.set( value );
     212                    event.preventDefault();
     213                }
     214            });
     215
     216            if ( this.tabs.uploaded ) {
     217                this.tabs.uploaded.target = this.library.find('.uploaded-target');
     218                if ( ! this.tabs.uploaded.panel.find('.thumbnail').length )
     219                    this.tabs.uploaded.both.addClass('hidden');
     220            }
     221        },
     222        success: function( attachment ) {
     223            api.UploadControl.prototype.success.call( this, attachment );
     224
     225            // Add the uploaded image to the uploaded tab.
     226            if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) {
     227                this.tabs.uploaded.both.removeClass('hidden');
     228
     229                $( '<a href="#" class="thumbnail"></a>' )
     230                    .data( 'customizeImageValue', attachment.url )
     231                    .append( '<img src="' +  attachment.url+ '" />' )
     232                    .appendTo( this.tabs.uploaded.target );
     233            }
    196234        },
    197235        thumbnailSrc: function( to ) {
  • trunk/wp-includes/js/plupload/wp-plupload.dev.js

    r20295 r20545  
    4848
    4949            this[ key ] = $( this[ key ] ).first();
     50
     51            if ( ! this[ key ].length ) {
     52                delete this[ key ];
     53                continue;
     54            }
     55
    5056            if ( ! this[ key ].prop('id') )
    5157                this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
Note: See TracChangeset for help on using the changeset viewer.