Ticket #21483: 21483.2.diff
File 21483.2.diff, 21.4 KB (added by , 10 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
10 10 font-size: 14px; 11 11 } 12 12 13 #customize-controls img { 14 max-width: 100%; 15 } 16 13 17 #customize-controls .submit { 14 18 text-align: center; 15 19 } … … 414 418 margin-right: 5px; 415 419 } 416 420 421 .customize-control .attachment-thumb.type-icon { 422 float: left; 423 margin-right: 12px; 424 } 425 426 .customize-control .attachment-title { 427 font-weight: bold; 428 margin: 0 0 12px 0; 429 } 430 431 .customize-control .remove-button { 432 margin-left: 8px; 433 vertical-align: middle; 434 } 435 436 .customize-control .thumbnail-audio .attachment-title, 437 .customize-control .thumbnail.thumbnail-audio, 438 .customize-control .thumbnail.thumbnail-video, 439 .customize-control .thumbnail.thumbnail-image { 440 margin-bottom: 8px; 441 } 442 417 443 #customize-preview iframe { 418 444 width: 100%; 419 445 height: 100%; -
src/wp-admin/js/customize-controls.js
201 201 * @augments wp.customize.Class 202 202 */ 203 203 api.UploadControl = api.Control.extend({ 204 205 /** 206 * Set up control and do event bindings. 207 */ 204 208 ready: function() { 205 var control = this; 209 210 // Cache buttons for re-use. 211 this.$button = this.container.find( '.upload-button' ); 212 this.$img = this.container.find( '.thumbnail-image img' ); 213 this.$removeButton = this.container.find( '.remove-button' ); 206 214 207 this.params.removed = this.params.removed || ''; 215 // Shortcut so that we don't have to use _.bind every time we add a callback. 216 _.bindAll( this, 'removeFile', 'reRender', 'openFrame', 'select' ); 208 217 209 this.success = $.proxy( this.success, this ); 218 this.$removeButton.on( 'click keydown', this.removeFile ); 219 this.$button.on( 'click keydown', this.openFrame ); 220 this.$img.on( 'click keydown', this.openFrame ); 221 }, 210 222 211 this.uploader = $.extend({ 212 container: this.container, 213 browser: this.container.find('.upload'), 214 dropzone: this.container.find('.upload-dropzone'), 215 success: this.success, 216 plupload: {}, 217 params: {} 218 }, this.uploader || {} ); 219 220 if ( control.params.extensions ) { 221 control.uploader.plupload.filters = [{ 222 title: api.l10n.allowedFiles, 223 extensions: control.params.extensions 224 }]; 223 /** 224 * Open the media modal. 225 */ 226 openFrame: function( event ) { 227 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 228 return; 225 229 } 226 230 227 if ( control.params.context ) 228 control.uploader.params['post_data[context]'] = this.params.context; 231 event.preventDefault(); 229 232 230 if ( api.settings.theme.stylesheet ) 231 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; 233 if ( ! this.frame ) { 234 this.initFrame(); 235 } 232 236 233 this.uploader = new wp.Uploader( this.uploader ); 237 this.frame.open(); 238 }, 234 239 235 this.remover = this.container.find('.remove'); 236 this.remover.on( 'click keydown', function( event ) { 237 if ( event.type === 'keydown' && 13 !== event.which ) // enter 238 return; 240 /** 241 * Set up the media modal so that it can be reused and accessed when needed. 242 */ 243 initFrame: function() { 244 this.frame = wp.media({ 245 // The title of the media modal 246 title: this.params.button_labels.frame_title, 239 247 240 control.setting.set( control.params.removed ); 241 event.preventDefault(); 248 // Restrict to specified mime type. 249 // @todo try to map $extensions to this in PHP. 250 library: { 251 type: this.params.mime_type 252 }, 253 button: { 254 // Change the submit button label. 255 text: this.params.button_labels.frame_button 256 }, 257 multiple: false 242 258 }); 243 259 244 this.removerVisibility = $.proxy( this.removerVisibility, this ); 245 this.setting.bind( this.removerVisibility ); 246 this.removerVisibility( this.setting.get() ); 260 // When a file is selected, run a callback. 261 this.frame.on( 'select', this.select ); 247 262 }, 248 success: function( attachment ) {249 this.setting.set( attachment.get('url') );250 },251 removerVisibility: function( to ) {252 this.remover.toggle( to != this.params.removed );253 }254 });255 263 256 /** 257 * @constructor 258 * @augments wp.customize.UploadControl 259 * @augments wp.customize.Control 260 * @augments wp.customize.Class 261 */ 262 api.ImageControl = api.UploadControl.extend({ 263 ready: function() { 264 var control = this, 265 panels; 264 /** 265 * Fired when an attachment is selected in the media modal. Gets the selected 266 * image information, and sets it within the control. 267 */ 268 select: function() { 269 // Get the attachment from the modal frame. 270 var attachment = this.frame.state().get( 'selection' ).first().toJSON(); 266 271 267 this.uploader = { 268 init: function() { 269 var fallback, button; 272 this.params.attachment = attachment; 270 273 271 if ( this.supports.dragdrop ) 272 return; 274 // Set the Customizer setting; the callback takes care of rendering. 275 this.setting( attachment.url ); 276 this.reRender(); 277 }, 273 278 274 // Maintain references while wrapping the fallback button. 275 fallback = control.container.find( '.upload-fallback' ); 276 button = fallback.children().detach(); 279 /** 280 * Called on whenever a setting is changed. 281 * 282 */ 283 reRender: function() { 284 // @todo: something else is needed to preview audio/video files 285 var self = this; 286 self.container.html(''); 287 self.renderContent( function() { 288 // Don't call ready() until the content has rendered. 289 self.ready(); 290 } ); 291 }, 277 292 278 this.browser.detach().empty().append( button ); 279 fallback.append( this.browser ).show(); 280 } 281 }; 293 /** 294 * Reset the setting to the default value. @todo default button instead of remove that calls this. 295 */ 296 restoreDefault: function( event ) { 297 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 298 return; 299 } 282 300 283 api.UploadControl.prototype.ready.call( this ); 301 event.preventDefault(); 302 // this.setting( this.setting.default ); @todo 303 this.params.attachment = {}; 304 this.reRender(); 305 }, 284 306 285 this.thumbnail = this.container.find('.preview-thumbnail img'); 286 this.thumbnailSrc = $.proxy( this.thumbnailSrc, this ); 287 this.setting.bind( this.thumbnailSrc ); 288 289 this.library = this.container.find('.library'); 290 291 // Generate tab objects 292 this.tabs = {}; 293 panels = this.library.find('.library-content'); 294 295 this.library.children('ul').children('li').each( function() { 296 var link = $(this), 297 id = link.data('customizeTab'), 298 panel = panels.filter('[data-customize-tab="' + id + '"]'); 299 300 control.tabs[ id ] = { 301 both: link.add( panel ), 302 link: link, 303 panel: panel 304 }; 305 }); 306 307 // Bind tab switch events 308 this.library.children('ul').on( 'click keydown', 'li', function( event ) { 309 if ( event.type === 'keydown' && 13 !== event.which ) // enter 310 return; 311 312 var id = $(this).data('customizeTab'), 313 tab = control.tabs[ id ]; 314 315 event.preventDefault(); 316 317 if ( tab.link.hasClass('library-selected') ) 318 return; 319 320 control.selected.both.removeClass('library-selected'); 321 control.selected = tab; 322 control.selected.both.addClass('library-selected'); 323 }); 324 325 // Bind events to switch image urls. 326 this.library.on( 'click keydown', 'a', function( event ) { 327 if ( event.type === 'keydown' && 13 !== event.which ) // enter 328 return; 329 330 var value = $(this).data('customizeImageValue'); 331 332 if ( value ) { 333 control.setting.set( value ); 334 event.preventDefault(); 335 } 336 }); 337 338 if ( this.tabs.uploaded ) { 339 this.tabs.uploaded.target = this.library.find('.uploaded-target'); 340 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length ) 341 this.tabs.uploaded.both.addClass('hidden'); 307 /** 308 * Called when the "Remove" link is clicked. Empties the setting. 309 * @param {object} event jQuery Event object from click event 310 */ 311 removeFile: function( event ) { 312 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 313 return; 342 314 } 343 315 344 // Select a tab 345 panels.each( function() { 346 var tab = control.tabs[ $(this).data('customizeTab') ]; 347 348 // Select the first visible tab. 349 if ( ! tab.link.hasClass('hidden') ) { 350 control.selected = tab; 351 tab.both.addClass('library-selected'); 352 return false; 353 } 354 }); 355 356 this.dropdownInit(); 357 }, 358 success: function( attachment ) { 359 api.UploadControl.prototype.success.call( this, attachment ); 360 361 // Add the uploaded image to the uploaded tab. 362 if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { 363 this.tabs.uploaded.both.removeClass('hidden'); 364 365 // @todo: Do NOT store this on the attachment model. That is bad. 366 attachment.element = $( '<a href="#" class="thumbnail"></a>' ) 367 .data( 'customizeImageValue', attachment.get('url') ) 368 .append( '<img src="' + attachment.get('url')+ '" />' ) 369 .appendTo( this.tabs.uploaded.target ); 370 } 371 }, 372 thumbnailSrc: function( to ) { 373 if ( /^(https?:)?\/\//.test( to ) ) 374 this.thumbnail.prop( 'src', to ).show(); 375 else 376 this.thumbnail.hide(); 377 } 316 event.preventDefault(); 317 this.setting( '' ); 318 this.params.attachment = {}; 319 this.reRender(); 320 } 378 321 }); 379 322 380 323 /** 324 * We just need to declare that this is a subclass of UploadControl. 325 * 381 326 * @constructor 327 * @augments wp.customize.UploadControl 382 328 * @augments wp.customize.Control 383 329 * @augments wp.customize.Class 384 330 */ 331 api.ImageControl = api.UploadControl.extend({}); 332 333 /** 334 * @constructor 335 * @augments wp.customize.Control 336 * @augments wp.customize.Class 337 */ 385 338 api.HeaderControl = api.Control.extend({ 386 339 ready: function() { 387 340 this.btnRemove = $('#customize-control-header_image .actions .remove'); -
src/wp-includes/class-wp-customize-control.php
580 580 * @since 3.4.0 581 581 */ 582 582 class WP_Customize_Upload_Control extends WP_Customize_Control { 583 public $type = 'upload'; 584 public $removed = ''; 585 public $context; 586 public $extensions = array(); 583 public $type = 'upload'; 584 public $mime_type = ''; 585 public $button_labels = array( 586 'select' => 'Select File', // @todo PHP doesn't like letting us translate these 587 'change' => 'Change File', 588 'remove' => 'Remove', 589 'frame_title' => 'Select File', 590 'frame_button' => 'Choose File', 591 ); 592 public $removed = ''; // unused 593 public $context; // unused 594 public $extensions = array(); // unused 587 595 588 596 /** 589 597 * Enqueue control related scripts/styles. … … 591 599 * @since 3.4.0 592 600 */ 593 601 public function enqueue() { 594 wp_enqueue_ script( 'wp-plupload');602 wp_enqueue_media(); 595 603 } 596 604 597 605 /** … … 602 610 */ 603 611 public function to_json() { 604 612 parent::to_json(); 613 $this->json['mime_type'] = $this->mime_type; 614 $this->json['button_labels'] = $this->button_labels; 605 615 606 $this->json['removed'] = $this->removed; 616 if ( $this->setting ) { 617 // if ( $this->setting->default ) { 618 // $this->json['default_url'] = $this->setting->default; @todo 619 // } 607 620 608 if ( $this->context ) 609 $this->json['context'] = $this->context; 610 611 if ( $this->extensions ) 612 $this->json['extensions'] = implode( ',', $this->extensions ); 621 // Get the attachment model for the existing file, or make one. 622 if ( $this->value() ) { 623 $attachment_id = attachment_url_to_postid( $this->value() ); 624 if ( $attachment_id ) { 625 $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id); 626 } 627 } 628 } 613 629 } 614 630 615 631 /** 616 * Render the control's content.632 * Don't render any content for this control from PHP. 617 633 * 634 * @see WP_Customize_Upload_Control::content_template() 618 635 * @since 3.4.0 619 636 */ 620 public function render_content() { 637 public function render_content() {} 638 639 /** 640 * Render a JS template for the content of the upload control. 641 * 642 * @since 4.1.0 643 */ 644 public function content_template() { 621 645 ?> 622 646 <label> 623 <?php if ( ! empty( $this->label ) ) : ?> 624 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span> 625 <?php endif; 626 if ( ! empty( $this->description ) ) : ?> 627 <span class="description customize-control-description"><?php echo $this->description; ?></span> 628 <?php endif; ?> 629 <div> 630 <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a> 631 <a href="#" class="remove"><?php _e( 'Remove' ); ?></a> 632 </div> 647 <# if ( data.label ) { #> 648 <span class="customize-control-title">{{ data.label }}</span> 649 <# } #> 650 <# if ( data.description ) { #> 651 <span class="description customize-control-description">{{ data.description }}</span> 652 <# } #> 653 654 <# if ( data.attachment && data.attachment.id ) { #> 655 <div class="attachment-media-view {{ data.attachment.orientation }}"> 656 <div class="thumbnail thumbnail-{{ data.attachment.type }}"> 657 <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #> 658 <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" /> 659 <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #> 660 <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" /> 661 <# } else if ( -1 === jQuery.inArray( data.attachment.type, [ 'audio', 'video' ] ) ) { #> 662 <img class="attachment-thumb type-icon" src="{{ data.attachment.icon }}" class="icon" draggable="false" /> 663 <p class="attachment-title">{{ data.attachment.title }}</p> 664 <# } #> 665 666 <# if ( 'audio' === data.attachment.type ) { #> 667 <div class="wp-media-wrapper"> 668 <p class="attachment-title">{{ data.attachment.title }}</p> 669 <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none"> 670 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 671 </audio> 672 </div> 673 <# } else if ( 'video' === data.attachment.type ) { 674 var w_rule = h_rule = ''; 675 if ( data.attachment.width ) { 676 w_rule = 'width: ' + data.attachment.width + 'px;'; 677 } else if ( wp.media.view.settings.contentWidth ) { 678 w_rule = 'width: ' + wp.media.view.settings.contentWidth + 'px;'; 679 } 680 if ( data.attachment.height ) { 681 h_rule = 'height: ' + data.attachment.height + 'px;'; 682 } 683 #> 684 <div style="{{ w_rule }}{{ h_rule }}" class="wp-media-wrapper wp-video"> 685 <video controls="controls" class="wp-video-shortcode" preload="metadata" 686 <# if ( data.attachment.width ) { #>width="{{ data.attachment.width }}"<# } #> 687 <# if ( data.attachment.height ) { #>height="{{ data.attachment.height }}"<# } #> 688 <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>> 689 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 690 </video> 691 </div> 692 <# } #> 693 </div> 694 </div> 695 <a class="button upload-button" href="#"><?php echo $this->button_labels['change']; ?></a> 696 <a class="remove-button" href="#"><?php echo $this->button_labels['remove']; ?></a> 697 <# } else { #> 698 <a class="button upload-button" href="#"><?php echo $this->button_labels['select']; ?></a> 699 <# } #> 633 700 </label> 634 701 <?php 635 702 } … … 644 711 */ 645 712 class WP_Customize_Image_Control extends WP_Customize_Upload_Control { 646 713 public $type = 'image'; 647 public $get_url; 648 public $statuses; 649 public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' ); 714 public $mime_type = 'image'; 715 public $button_labels = array( 716 'select' => 'Select Image', // @todo PHP doesn't like letting us translate these 717 'change' => 'Change Image', 718 'remove' => 'Remove', 719 'frame_title' => 'Select Image', 720 'frame_button' => 'Choose Image', 721 ); 650 722 651 protected $tabs = array();652 653 723 /** 654 * Constructor.655 *656 * @since 3.4.0657 * @uses WP_Customize_Upload_Control::__construct()658 *659 * @param WP_Customize_Manager $manager660 * @param string $id661 * @param array $args662 */663 public function __construct( $manager, $id, $args ) {664 $this->statuses = array( '' => __('No Image') );665 666 parent::__construct( $manager, $id, $args );667 668 $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) );669 $this->add_tab( 'uploaded', __('Uploaded'), array( $this, 'tab_uploaded' ) );670 671 // Early priority to occur before $this->manager->prepare_controls();672 add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 );673 }674 675 /**676 * Prepares the control.677 *678 * If no tabs exist, removes the control from the manager.679 *680 724 * @since 3.4.2 725 * @deprecated 4.1.0 681 726 */ 682 public function prepare_control() { 683 if ( ! $this->tabs ) 684 $this->manager->remove_control( $this->id ); 685 } 727 public function prepare_control() {} 686 728 687 729 /** 688 * Refresh the parameters passed to the JavaScript via JSON.689 *690 730 * @since 3.4.0 691 * @uses WP_Customize_Upload_Control::to_json() 692 */ 693 public function to_json() { 694 parent::to_json(); 695 $this->json['statuses'] = $this->statuses; 696 } 697 698 /** 699 * Render the control's content. 731 * @deprecated 4.1.0 700 732 * 701 * @since 3.4.0702 */703 public function render_content() {704 $src = $this->value();705 if ( isset( $this->get_url ) )706 $src = call_user_func( $this->get_url, $src );707 708 ?>709 <div class="customize-image-picker">710 <?php if ( ! empty( $this->label ) ) : ?>711 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>712 <?php endif;713 if ( ! empty( $this->description ) ) : ?>714 <span class="description customize-control-description"><?php echo $this->description; ?></span>715 <?php endif; ?>716 717 <div class="customize-control-content">718 <div class="dropdown preview-thumbnail" tabindex="0">719 <div class="dropdown-content">720 <?php if ( empty( $src ) ): ?>721 <img style="display:none;" />722 <?php else: ?>723 <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />724 <?php endif; ?>725 <div class="dropdown-status"></div>726 </div>727 <div class="dropdown-arrow"></div>728 </div>729 </div>730 731 <div class="library">732 <ul>733 <?php foreach ( $this->tabs as $id => $tab ): ?>734 <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>735 <?php echo esc_html( $tab['label'] ); ?>736 </li>737 <?php endforeach; ?>738 </ul>739 <?php foreach ( $this->tabs as $id => $tab ): ?>740 <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>741 <?php call_user_func( $tab['callback'] ); ?>742 </div>743 <?php endforeach; ?>744 </div>745 746 <div class="actions">747 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>748 </div>749 </div>750 <?php751 }752 753 /**754 * Add a tab to the control.755 *756 * @since 3.4.0757 *758 733 * @param string $id 759 734 * @param string $label 760 735 * @param mixed $callback 761 736 */ 762 public function add_tab( $id, $label, $callback ) { 763 $this->tabs[ $id ] = array( 764 'label' => $label, 765 'callback' => $callback, 766 ); 767 } 737 public function add_tab( $id, $label, $callback ) {} 768 738 769 739 /** 770 * Remove a tab from the control.771 *772 740 * @since 3.4.0 741 * @deprecated 4.1.0 773 742 * 774 743 * @param string $id 775 744 */ 776 public function remove_tab( $id ) { 777 unset( $this->tabs[ $id ] ); 778 } 745 public function remove_tab( $id ) {} 779 746 780 747 /** 781 748 * @since 3.4.0 782 */ 783 public function tab_upload_new() { 784 if ( ! _device_can_upload() ) { 785 echo '<p>' . sprintf( __('The web browser on your device cannot be used to upload files. You may be able to use the <a href="%s">native app for your device</a> instead.'), 'https://apps.wordpress.org/' ) . '</p>'; 786 } else { 787 ?> 788 <div class="upload-dropzone"> 789 <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?> 790 </div> 791 <div class="upload-fallback"> 792 <span class="button-secondary"><?php _e('Select File'); ?></span> 793 </div> 794 <?php 795 } 796 } 797 798 /** 799 * @since 3.4.0 800 */ 801 public function tab_uploaded() { 802 ?> 803 <div class="uploaded-target"></div> 804 <?php 805 } 806 807 /** 808 * @since 3.4.0 749 * @deprecated 4.1.0 809 750 * 810 751 * @param string $url 811 752 * @param string $thumbnail_url 812 753 */ 813 public function print_tab_image( $url, $thumbnail_url = null ) { 814 $url = set_url_scheme( $url ); 815 $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url; 816 ?> 817 <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>"> 818 <img src="<?php echo esc_url( $thumbnail_url ); ?>" /> 819 </a> 820 <?php 821 } 754 public function print_tab_image( $url, $thumbnail_url = null ) {} 822 755 } 823 756 824 757 /** -
src/wp-includes/class-wp-customize-manager.php
962 962 963 963 /* Control Types (custom control classes) */ 964 964 $this->register_control_type( 'WP_Customize_Color_Control' ); 965 $this->register_control_type( 'WP_Customize_Upload_Control' ); 966 $this->register_control_type( 'WP_Customize_Image_Control' ); 965 967 966 968 /* Site Title & Tagline */ 967 969