Ticket #21483: 21483.6.diff
File 21483.6.diff, 28.6 KB (added by , 10 years ago) |
---|
-
src/wp-admin/css/customize-controls.css
diff --git src/wp-admin/css/customize-controls.css src/wp-admin/css/customize-controls.css index 5503cfd..88cc6c4 100644
body { 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 } … … p.customize-section-description { 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 443 .customize-control .placeholder-text { 444 font-size: 18px; 445 font-weight: 300; 446 text-align: center; 447 color: #aaa; 448 cursor: default; 449 } 450 451 .customize-control .thumbnail-image img { 452 cursor: pointer; 453 } 454 417 455 #customize-preview iframe { 418 456 width: 100%; 419 457 height: 100%; -
src/wp-admin/js/customize-controls.js
diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js index 66d63bd..5bfabe2 100644
5 5 // @todo Move private helper functions to wp.customize.utils so they can be unit tested 6 6 7 7 /** 8 * @c onstructor8 * @class 9 9 * @augments wp.customize.Value 10 10 * @augments wp.customize.Class 11 11 * … … 127 127 /** 128 128 * Base class for Panel and Section 129 129 * 130 * @c onstructor130 * @class 131 131 * @augments wp.customize.Class 132 132 */ 133 133 Container = api.Class.extend({ … … 312 312 }); 313 313 314 314 /** 315 * @c onstructor315 * @class 316 316 * @augments wp.customize.Class 317 317 */ 318 318 api.Section = Container.extend({ … … 467 467 }); 468 468 469 469 /** 470 * @c onstructor470 * @class 471 471 * @augments wp.customize.Class 472 472 */ 473 473 api.Panel = Container.extend({ … … 636 636 }); 637 637 638 638 /** 639 * @constructor 639 * A Customizer Control. 640 * 641 * A control provides a UI element that allows a user to modify a Customizer Setting. 642 * 643 * @see PHP class WP_Customize_Control. 644 * 645 * @class 640 646 * @augments wp.customize.Class 647 * 648 * @param {string} id Unique identifier for the control instance. 649 * @param {object} options Options hash for the control instance. 650 * @param {object} options.params 651 * @param {object} options.params.type Type of control (e.g. text, radio, dropdown-pages, etc.) 652 * @param {string} options.params.content The HTML content for the control. 653 * @param {string} options.params.priority Order of priority to show the control within the section. 654 * @param {string} options.params.active 655 * @param {string} options.params.section 656 * @param {string} options.params.label 657 * @param {string} options.params.description 658 * @param {string} options.params.instanceNumber Order in which this instance was created in relation to other instances. 641 659 */ 642 660 api.Control = api.Class.extend({ 643 661 defaultActiveArguments: { duration: 'fast' }, … … 648 666 649 667 control.params = {}; 650 668 $.extend( control, options || {} ); 651 652 669 control.id = id; 653 670 control.selector = '#customize-control-' + id.replace( /\]/g, '' ).replace( /\[/g, '-' ); 654 671 control.templateSelector = 'customize-control-' + control.params.type + '-content'; … … 724 741 }, 725 742 726 743 /** 727 * 744 * Embed the control into the page. 728 745 */ 729 746 embed: function () { 730 747 var control = this, … … 754 771 }, 755 772 756 773 /** 774 * Triggered when the control's markup has been injected into the DOM. 775 * 757 776 * @abstract 758 777 */ 759 778 ready: function() {}, … … 867 886 }); 868 887 869 888 /** 870 * @constructor 889 * A colorpicker control. 890 * 891 * @class 871 892 * @augments wp.customize.Control 872 893 * @augments wp.customize.Class 873 894 */ … … 893 914 }); 894 915 895 916 /** 896 * @constructor 917 * An upload control, which utilizes the media modal. 918 * 919 * @class 897 920 * @augments wp.customize.Control 898 921 * @augments wp.customize.Class 899 922 */ 900 923 api.UploadControl = api.Control.extend({ 901 ready: function() {902 var control = this;903 904 this.params.removed = this.params.removed || '';905 924 906 this.success = $.proxy( this.success, this ); 907 908 this.uploader = $.extend({ 909 container: this.container, 910 browser: this.container.find('.upload'), 911 dropzone: this.container.find('.upload-dropzone'), 912 success: this.success, 913 plupload: {}, 914 params: {} 915 }, this.uploader || {} ); 916 917 if ( control.params.extensions ) { 918 control.uploader.plupload.filters = [{ 919 title: api.l10n.allowedFiles, 920 extensions: control.params.extensions 921 }]; 922 } 923 924 if ( control.params.context ) 925 control.uploader.params['post_data[context]'] = this.params.context; 926 927 if ( api.settings.theme.stylesheet ) 928 control.uploader.params['post_data[theme]'] = api.settings.theme.stylesheet; 929 930 this.uploader = new wp.Uploader( this.uploader ); 931 932 this.remover = this.container.find('.remove'); 933 this.remover.on( 'click keydown', function( event ) { 934 if ( isKeydownButNotEnterEvent( event ) ) { 935 return; 936 } 937 938 control.setting.set( control.params.removed ); 939 event.preventDefault(); 940 }); 925 /** 926 * When the control's DOM structure is ready, 927 * set up internal event bindings. 928 */ 929 ready: function() { 930 var control = this; 941 931 942 this.removerVisibility = $.proxy( this.removerVisibility, this ); 943 this.setting.bind( this.removerVisibility ); 944 this.removerVisibility( this.setting.get() ); 945 }, 946 success: function( attachment ) { 947 this.setting.set( attachment.get('url') ); 932 control.setupEvents(); 933 control.setting.bind( function () { control.reRender(); } ); 948 934 }, 949 removerVisibility: function( to ) {950 this.remover.toggle( to != this.params.removed );951 }952 });953 954 /**955 * @constructor956 * @augments wp.customize.UploadControl957 * @augments wp.customize.Control958 * @augments wp.customize.Class959 */960 api.ImageControl = api.UploadControl.extend({961 ready: function() {962 var control = this,963 panels;964 965 this.uploader = {966 init: function() {967 var fallback, button;968 969 if ( this.supports.dragdrop )970 return;971 972 // Maintain references while wrapping the fallback button.973 fallback = control.container.find( '.upload-fallback' );974 button = fallback.children().detach();975 935 976 this.browser.detach().empty().append( button ); 977 fallback.append( this.browser ).show(); 978 } 979 }; 936 /** 937 * Set up event bindings. 938 */ 939 setupEvents: function() { 940 // Cache buttons for re-use. 941 this.$button = this.container.find( '.upload-button' ); 942 this.$img = this.container.find( '.thumbnail-image img' ); 943 this.$defaultButton = this.container.find( '.default-button' ); 944 this.$removeButton = this.container.find( '.remove-button' ); 945 946 // Shortcut so that we don't have to use _.bind every time we add a callback. 947 _.bindAll( this, 'removeFile', 'reRender', 'openFrame', 'select' ); 948 949 this.$defaultButton.on( 'click keydown', this.restoreDefault ); 950 this.$removeButton.on( 'click keydown', this.removeFile ); 951 this.$button.on( 'click keydown', this.openFrame ); 952 this.$img.on( 'click keydown', this.openFrame ); 953 }, 980 954 981 api.UploadControl.prototype.ready.call( this ); 955 /** 956 * Open the media modal. 957 */ 958 openFrame: function( event ) { 959 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 960 return; 961 } 982 962 983 this.thumbnail = this.container.find('.preview-thumbnail img'); 984 this.thumbnailSrc = $.proxy( this.thumbnailSrc, this ); 985 this.setting.bind( this.thumbnailSrc ); 963 event.preventDefault(); 986 964 987 this.library = this.container.find('.library'); 965 if ( ! this.frame ) { 966 this.initFrame(); 967 } 988 968 989 // Generate tab objects 990 this.tabs = {}; 991 panels = this.library.find('.library-content'); 969 this.frame.open(); 970 }, 992 971 993 this.library.children('ul').children('li').each( function() { 994 var link = $(this), 995 id = link.data('customizeTab'), 996 panel = panels.filter('[data-customize-tab="' + id + '"]'); 972 /** 973 * Create a media modal select frame, and store it so the instance can be reused when needed. 974 */ 975 initFrame: function() { 976 this.frame = wp.media({ 977 // The title of the media modal. 978 title: this.params.button_labels.frame_title, 997 979 998 control.tabs[ id ] = { 999 both: link.add( panel ), 1000 link: link, 1001 panel: panel 1002 }; 1003 }); 980 // Restrict the library to specified mime type. 981 library: { 982 type: this.params.mime_type 983 }, 984 button: { 985 // Change the submit button label. 986 text: this.params.button_labels.frame_button 987 }, 988 multiple: false 989 }); 1004 990 1005 // Bind tab switch events 1006 this.library.children('ul').on( 'click keydown', 'li', function( event ) { 1007 if ( isKeydownButNotEnterEvent( event ) ) { 1008 return; 1009 } 991 // When a file is selected, run a callback. 992 this.frame.on( 'select', this.select ); 993 }, 1010 994 1011 var id = $(this).data('customizeTab'), 1012 tab = control.tabs[ id ]; 995 /** 996 * Callback handler for when an attachment is selected in the media modal. 997 * Gets the selected image information, and sets it within the control. 998 */ 999 select: function() { 1000 // Get the attachment from the modal frame. 1001 var attachment = this.frame.state().get( 'selection' ).first().toJSON(); 1013 1002 1014 event.preventDefault();1003 this.params.attachment = attachment; 1015 1004 1016 if ( tab.link.hasClass('library-selected') ) 1017 return; 1005 // Set the Customizer setting; the callback takes care of rendering. 1006 this.setting( attachment.url ); 1007 }, 1018 1008 1019 control.selected.both.removeClass('library-selected'); 1020 control.selected = tab; 1021 control.selected.both.addClass('library-selected'); 1022 }); 1009 /** 1010 * Called on whenever a setting is changed. 1011 */ 1012 reRender: function() { 1013 this.container.html(''); 1014 this.renderContent(); 1015 this.setupEvents(); 1016 // @todo: something else is needed to preview audio/video files 1017 }, 1023 1018 1024 // Bind events to switch image urls. 1025 this.library.on( 'click keydown', 'a', function( event ) { 1026 if ( isKeydownButNotEnterEvent( event ) ) { 1027 return; 1028 } 1019 /** 1020 * Reset the setting to the default value. 1021 * 1022 * @todo default button instead of remove that calls this. 1023 */ 1024 restoreDefault: function( event ) { 1025 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 1026 return; 1027 } 1029 1028 1030 var value = $(this).data('customizeImageValue'); 1029 event.preventDefault(); 1030 this.setting( this.params.defaultAttachment.url ); 1031 this.params.attachment = this.params.defaultAttachment; 1032 }, 1031 1033 1032 if ( value ) { 1033 control.setting.set( value ); 1034 event.preventDefault(); 1035 } 1036 }); 1034 /** 1035 * Called when the "Remove" link is clicked. Empties the setting. 1036 * 1037 * @param {object} event jQuery Event object 1038 */ 1039 removeFile: function( event ) { 1040 if ( event.type === 'keydown' && 13 !== event.which ) { // enter 1041 return; 1042 } 1037 1043 1038 if ( this.tabs.uploaded ) { 1039 this.tabs.uploaded.target = this.library.find('.uploaded-target'); 1040 if ( ! this.tabs.uploaded.panel.find('.thumbnail').length ) 1041 this.tabs.uploaded.both.addClass('hidden'); 1042 } 1044 event.preventDefault(); 1045 this.params.attachment = {}; 1046 this.setting( '' ); 1047 }, 1043 1048 1044 // Select a tab 1045 panels.each( function() { 1046 var tab = control.tabs[ $(this).data('customizeTab') ]; 1049 // @deprecated 1050 success: function( attachment ) {}, 1047 1051 1048 // Select the first visible tab. 1049 if ( ! tab.link.hasClass('hidden') ) { 1050 control.selected = tab; 1051 tab.both.addClass('library-selected'); 1052 return false; 1053 } 1054 }); 1052 // @deprecated 1053 removerVisibility: function( to ) {} 1054 }); 1055 1055 1056 this.dropdownInit(); 1057 }, 1058 success: function( attachment ) { 1059 api.UploadControl.prototype.success.call( this, attachment ); 1060 1061 // Add the uploaded image to the uploaded tab. 1062 if ( this.tabs.uploaded && this.tabs.uploaded.target.length ) { 1063 this.tabs.uploaded.both.removeClass('hidden'); 1064 1065 // @todo: Do NOT store this on the attachment model. That is bad. 1066 attachment.element = $( '<a href="#" class="thumbnail"></a>' ) 1067 .data( 'customizeImageValue', attachment.get('url') ) 1068 .append( '<img src="' + attachment.get('url')+ '" />' ) 1069 .appendTo( this.tabs.uploaded.target ); 1070 } 1071 }, 1072 thumbnailSrc: function( to ) { 1073 if ( /^(https?:)?\/\//.test( to ) ) 1074 this.thumbnail.prop( 'src', to ).show(); 1075 else 1076 this.thumbnail.hide(); 1077 } 1056 /** 1057 * A control for uploading images. 1058 * 1059 * @class 1060 * @augments wp.customize.UploadControl 1061 * @augments wp.customize.Control 1062 * @augments wp.customize.Class 1063 */ 1064 api.ImageControl = api.UploadControl.extend({ 1065 // @deprecated 1066 thumbnailSrc: function( to ) {} 1078 1067 }); 1079 1068 1080 1069 /** 1081 * @c onstructor1070 * @class 1082 1071 * @augments wp.customize.Control 1083 1072 * @augments wp.customize.Class 1084 1073 */ … … 1225 1214 this.frame.open(); 1226 1215 }, 1227 1216 1217 /** 1218 * After an image is selected in the media modal, 1219 * switch to the cropper state. 1220 */ 1228 1221 onSelect: function() { 1229 1222 this.frame.setState('cropper'); 1230 1223 }, 1224 1225 /** 1226 * After the image has been cropped, apply the cropped image data to the setting. 1227 * 1228 * @param {object} croppedImage Cropped attachment data. 1229 */ 1231 1230 onCropped: function(croppedImage) { 1232 1231 var url = croppedImage.post_content, 1233 1232 attachmentId = croppedImage.attachment_id, … … 1235 1234 h = croppedImage.height; 1236 1235 this.setImageFromURL(url, attachmentId, w, h); 1237 1236 }, 1237 1238 /** 1239 * If cropping was skipped, apply the image data directly to the setting. 1240 * 1241 * @param {object} selection 1242 */ 1238 1243 onSkippedCrop: function(selection) { 1239 1244 var url = selection.get('url'), 1240 1245 w = selection.get('width'), … … 1301 1306 api.panel = new api.Values({ defaultConstructor: api.Panel }); 1302 1307 1303 1308 /** 1304 * @c onstructor1309 * @class 1305 1310 * @augments wp.customize.Messenger 1306 1311 * @augments wp.customize.Class 1307 1312 * @mixes wp.customize.Events … … 1500 1505 }()); 1501 1506 1502 1507 /** 1503 * @c onstructor1508 * @class 1504 1509 * @augments wp.customize.Messenger 1505 1510 * @augments wp.customize.Class 1506 1511 * @mixes wp.customize.Events -
src/wp-includes/class-wp-customize-control.php
diff --git src/wp-includes/class-wp-customize-control.php src/wp-includes/class-wp-customize-control.php index 7fe3c0f..1286c3a 100644
class WP_Customize_Color_Control extends WP_Customize_Control { 637 637 * @since 3.4.0 638 638 */ 639 639 class WP_Customize_Upload_Control extends WP_Customize_Control { 640 public $type = 'upload'; 641 public $removed = ''; 642 public $context; 643 public $extensions = array(); 640 public $type = 'upload'; 641 public $mime_type = ''; 642 public $button_labels = array(); 643 public $removed = ''; // unused 644 public $context; // unused 645 public $extensions = array(); // unused 646 647 /** 648 * Constructor. 649 * 650 * @since 4.1.0 651 * @uses WP_Customize_Control::__construct() 652 * 653 * @param WP_Customize_Manager $manager 654 */ 655 public function __construct( $manager, $id, $args = array() ) { 656 parent::__construct( $manager, $id, $args ); 657 658 $this->button_labels = array( 659 'select' => __( 'Select File' ), 660 'change' => __( 'Change File' ), 661 'default' => __( 'Default' ), 662 'remove' => __( 'Remove' ), 663 'placeholder' => __( 'No file selected' ), 664 'frame_title' => __( 'Select File' ), 665 'frame_button' => __( 'Choose File' ), 666 ); 667 } 644 668 645 669 /** 646 670 * Enqueue control related scripts/styles. … … class WP_Customize_Upload_Control extends WP_Customize_Control { 648 672 * @since 3.4.0 649 673 */ 650 674 public function enqueue() { 651 wp_enqueue_ script( 'wp-plupload');675 wp_enqueue_media(); 652 676 } 653 677 654 678 /** … … class WP_Customize_Upload_Control extends WP_Customize_Control { 659 683 */ 660 684 public function to_json() { 661 685 parent::to_json(); 686 $this->json['mime_type'] = $this->mime_type; 687 $this->json['button_labels'] = $this->button_labels; 688 689 if ( is_object( $this->setting ) ) { 690 if ( $this->setting->default ) { 691 // @todo: fake an attachment model - needs all fields used by template 692 $default_attachment = array( 693 'id' => -1, 694 'url' => $this->setting->default, 695 'type' => ( in_array( substr( $this->setting->default, -3), array( 'jpg', 'png', 'gif', 'bmp' ) ) ) ? 'image' : 'document', 696 'sizes' => array( 697 'full' => $this->setting->default, 698 ), 699 'icon' => 'http://localhost/develop/src/wp-includes/images/media/default.png',//@todo 700 'title' => '', //@todo filename 662 701 663 $this->json['removed'] = $this->removed; 702 ); 703 $this->json['defaultAttachment'] = $default_attachment; 704 } 664 705 665 if ( $this->context ) 666 $this->json['context'] = $this->context; 706 // Get the attachment model for the existing file, or make one. 707 if ( $this->value() ) { 708 $attachment_id = attachment_url_to_postid( $this->value() ); 709 if ( $attachment_id ) { 710 $this->json['attachment'] = wp_prepare_attachment_for_js( $attachment_id); 711 } 712 } elseif ( $this->setting->default ) { 667 713 668 if ( $this->extensions )669 $this->json['extensions'] = implode( ',', $this->extensions );714 } 715 } 670 716 } 671 717 672 718 /** 673 * Render the control's content.719 * Don't render any content for this control from PHP. 674 720 * 721 * @see WP_Customize_Upload_Control::content_template() 675 722 * @since 3.4.0 676 723 */ 677 public function render_content() { 724 public function render_content() {} 725 726 /** 727 * Render a JS template for the content of the upload control. 728 * 729 * @since 4.1.0 730 */ 731 public function content_template() { 678 732 ?> 679 <label> 680 <?php if ( ! empty( $this->label ) ) : ?> 681 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span> 682 <?php endif; 683 if ( ! empty( $this->description ) ) : ?> 684 <span class="description customize-control-description"><?php echo $this->description; ?></span> 685 <?php endif; ?> 686 <div> 687 <a href="#" class="button-secondary upload"><?php _e( 'Upload' ); ?></a> 688 <a href="#" class="remove"><?php _e( 'Remove' ); ?></a> 689 </div> 733 <label for="{{ data.settings.default }}-button"> 734 <# if ( data.label ) { #> 735 <span class="customize-control-title">{{ data.label }}</span> 736 <# } #> 737 <# if ( data.description ) { #> 738 <span class="description customize-control-description">{{ data.description }}</span> 739 <# } #> 690 740 </label> 741 742 <# if ( data.attachment && data.attachment.id ) { #> 743 <div class="attachment-media-view {{ data.attachment.orientation }}"> 744 <div class="thumbnail thumbnail-{{ data.attachment.type }}"> 745 <# if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.medium ) { #> 746 <img class="attachment-thumb" src="{{ data.attachment.sizes.medium.url }}" draggable="false" /> 747 <# } else if ( 'image' === data.attachment.type && data.attachment.sizes && data.attachment.sizes.full ) { #> 748 <img class="attachment-thumb" src="{{ data.attachment.sizes.full.url }}" draggable="false" /> 749 <# } else if ( -1 === jQuery.inArray( data.attachment.type, [ 'audio', 'video' ] ) ) { #> 750 <img class="attachment-thumb type-icon" src="{{ data.attachment.icon }}" class="icon" draggable="false" /> 751 <p class="attachment-title">{{ data.attachment.title }}</p> 752 <# } #> 753 754 <# if ( 'audio' === data.attachment.type ) { #> 755 <div class="wp-media-wrapper"> 756 <p class="attachment-title">{{ data.attachment.title }}</p> 757 <audio style="visibility: hidden" controls class="wp-audio-shortcode" width="100%" preload="none"> 758 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 759 </audio> 760 </div> 761 <# } else if ( 'video' === data.attachment.type ) { 762 var w_rule = h_rule = ''; 763 if ( data.attachment.width ) { 764 w_rule = 'width: ' + data.attachment.width + 'px;'; 765 } else if ( wp.media.view.settings.contentWidth ) { 766 w_rule = 'width: ' + wp.media.view.settings.contentWidth + 'px;'; 767 } 768 if ( data.attachment.height ) { 769 h_rule = 'height: ' + data.attachment.height + 'px;'; 770 } 771 #> 772 <div style="{{ w_rule }}{{ h_rule }}" class="wp-media-wrapper wp-video"> 773 <video controls="controls" class="wp-video-shortcode" preload="metadata" 774 <# if ( data.attachment.width ) { #>width="{{ data.attachment.width }}"<# } #> 775 <# if ( data.attachment.height ) { #>height="{{ data.attachment.height }}"<# } #> 776 <# if ( data.attachment.image && data.attachment.image.src !== data.attachment.icon ) { #>poster="{{ data.attachment.image.src }}"<# } #>> 777 <source type="{{ data.attachment.mime }}" src="{{ data.attachment.url }}"/> 778 </video> 779 </div> 780 <# } #> 781 </div> 782 </div> 783 <a class="button upload-button" id="{{ data.settings.default }}-button" href="#"><?php echo $this->button_labels['change']; ?></a> 784 <# if ( data.defaultAttachmet && data.defaultAttachment.id !== data.attachment.id ) { #> 785 <a class="default-button remove-button" href="#"><?php echo $this->button_labels['default']; ?></a> 786 <p>{{ data.defaultAttachment.src }}</p> 787 <# } else { #> 788 <a class="remove-button" href="#"><?php echo $this->button_labels['remove']; ?></a> 789 <# } #> 790 <# } else { #> 791 <p class="placeholder-text"><?php echo $this->button_labels['placeholder']; ?></p> 792 <a class="button upload-button" id="{{ data.settings.default }}-button" href="#"><?php echo $this->button_labels['select']; ?></a> 793 <# } #> 691 794 <?php 692 795 } 693 796 } … … class WP_Customize_Upload_Control extends WP_Customize_Control { 701 804 */ 702 805 class WP_Customize_Image_Control extends WP_Customize_Upload_Control { 703 806 public $type = 'image'; 704 public $get_url; 705 public $statuses; 706 public $extensions = array( 'jpg', 'jpeg', 'gif', 'png' ); 707 708 protected $tabs = array(); 807 public $mime_type = 'image'; 709 808 710 809 /** 711 810 * Constructor. 712 811 * 713 * @since 3.4.0812 * @since 4.1.0 714 813 * @uses WP_Customize_Upload_Control::__construct() 715 814 * 716 815 * @param WP_Customize_Manager $manager 717 * @param string $id718 * @param array $args719 816 */ 720 public function __construct( $manager, $id, $args ) { 721 $this->statuses = array( '' => __('No Image') ); 722 817 public function __construct( $manager, $id, $args = array() ) { 723 818 parent::__construct( $manager, $id, $args ); 724 819 725 $this->add_tab( 'upload-new', __('Upload New'), array( $this, 'tab_upload_new' ) ); 726 $this->add_tab( 'uploaded', __('Uploaded'), array( $this, 'tab_uploaded' ) ); 727 728 // Early priority to occur before $this->manager->prepare_controls(); 729 add_action( 'customize_controls_init', array( $this, 'prepare_control' ), 5 ); 820 $this->button_labels = array( 821 'select' => __( 'Select Image' ), 822 'change' => __( 'Change Image' ), 823 'remove' => __( 'Remove' ), 824 'default' => __( 'Default' ), 825 'placeholder' => __( 'No image selected' ), 826 'frame_title' => __( 'Select Image' ), 827 'frame_button' => __( 'Choose Image' ), 828 ); 730 829 } 731 830 732 831 /** 733 * Prepares the control.734 *735 * If no tabs exist, removes the control from the manager.736 *737 832 * @since 3.4.2 833 * @deprecated 4.1.0 738 834 */ 739 public function prepare_control() { 740 if ( ! $this->tabs ) 741 $this->manager->remove_control( $this->id ); 742 } 835 public function prepare_control() {} 743 836 744 837 /** 745 * Refresh the parameters passed to the JavaScript via JSON.746 *747 * @since 3.4.0748 * @uses WP_Customize_Upload_Control::to_json()749 */750 public function to_json() {751 parent::to_json();752 $this->json['statuses'] = $this->statuses;753 }754 755 /**756 * Render the control's content.757 *758 * @since 3.4.0759 */760 public function render_content() {761 $src = $this->value();762 if ( isset( $this->get_url ) )763 $src = call_user_func( $this->get_url, $src );764 765 ?>766 <div class="customize-image-picker">767 <?php if ( ! empty( $this->label ) ) : ?>768 <span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>769 <?php endif;770 if ( ! empty( $this->description ) ) : ?>771 <span class="description customize-control-description"><?php echo $this->description; ?></span>772 <?php endif; ?>773 774 <div class="customize-control-content">775 <div class="dropdown preview-thumbnail" tabindex="0">776 <div class="dropdown-content">777 <?php if ( empty( $src ) ): ?>778 <img style="display:none;" />779 <?php else: ?>780 <img src="<?php echo esc_url( set_url_scheme( $src ) ); ?>" />781 <?php endif; ?>782 <div class="dropdown-status"></div>783 </div>784 <div class="dropdown-arrow"></div>785 </div>786 </div>787 788 <div class="library">789 <ul>790 <?php foreach ( $this->tabs as $id => $tab ): ?>791 <li data-customize-tab='<?php echo esc_attr( $id ); ?>' tabindex='0'>792 <?php echo esc_html( $tab['label'] ); ?>793 </li>794 <?php endforeach; ?>795 </ul>796 <?php foreach ( $this->tabs as $id => $tab ): ?>797 <div class="library-content" data-customize-tab='<?php echo esc_attr( $id ); ?>'>798 <?php call_user_func( $tab['callback'] ); ?>799 </div>800 <?php endforeach; ?>801 </div>802 803 <div class="actions">804 <a href="#" class="remove"><?php _e( 'Remove Image' ); ?></a>805 </div>806 </div>807 <?php808 }809 810 /**811 * Add a tab to the control.812 *813 838 * @since 3.4.0 839 * @deprecated 4.1.0 814 840 * 815 841 * @param string $id 816 842 * @param string $label 817 843 * @param mixed $callback 818 844 */ 819 public function add_tab( $id, $label, $callback ) { 820 $this->tabs[ $id ] = array( 821 'label' => $label, 822 'callback' => $callback, 823 ); 824 } 845 public function add_tab( $id, $label, $callback ) {} 825 846 826 847 /** 827 * Remove a tab from the control.828 *829 848 * @since 3.4.0 849 * @deprecated 4.1.0 830 850 * 831 851 * @param string $id 832 852 */ 833 public function remove_tab( $id ) { 834 unset( $this->tabs[ $id ] ); 835 } 836 837 /** 838 * @since 3.4.0 839 */ 840 public function tab_upload_new() { 841 if ( ! _device_can_upload() ) { 842 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>'; 843 } else { 844 ?> 845 <div class="upload-dropzone"> 846 <?php _e('Drop a file here or <a href="#" class="upload">select a file</a>.'); ?> 847 </div> 848 <div class="upload-fallback"> 849 <span class="button-secondary"><?php _e('Select File'); ?></span> 850 </div> 851 <?php 852 } 853 } 854 855 /** 856 * @since 3.4.0 857 */ 858 public function tab_uploaded() { 859 ?> 860 <div class="uploaded-target"></div> 861 <?php 862 } 853 public function remove_tab( $id ) {} 863 854 864 855 /** 865 856 * @since 3.4.0 857 * @deprecated 4.1.0 866 858 * 867 859 * @param string $url 868 860 * @param string $thumbnail_url 869 861 */ 870 public function print_tab_image( $url, $thumbnail_url = null ) { 871 $url = set_url_scheme( $url ); 872 $thumbnail_url = ( $thumbnail_url ) ? set_url_scheme( $thumbnail_url ) : $url; 873 ?> 874 <a href="#" class="thumbnail" data-customize-image-value="<?php echo esc_url( $url ); ?>"> 875 <img src="<?php echo esc_url( $thumbnail_url ); ?>" /> 876 </a> 877 <?php 878 } 862 public function print_tab_image( $url, $thumbnail_url = null ) {} 879 863 } 880 864 881 865 /** … … class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control { 899 883 parent::__construct( $manager, 'background_image', array( 900 884 'label' => __( 'Background Image' ), 901 885 'section' => 'background_image', 902 'context' => 'custom-background',903 'get_url' => 'get_background_image',904 886 ) ); 905 906 if ( $this->setting->default )907 $this->add_tab( 'default', __('Default'), array( $this, 'tab_default_background' ) );908 }909 910 /**911 * @since 3.4.0912 */913 public function tab_uploaded() {914 $backgrounds = get_posts( array(915 'post_type' => 'attachment',916 'meta_key' => '_wp_attachment_is_custom_background',917 'meta_value' => $this->manager->get_stylesheet(),918 'orderby' => 'none',919 'nopaging' => true,920 ) );921 922 ?><div class="uploaded-target"></div><?php923 924 if ( empty( $backgrounds ) )925 return;926 927 foreach ( (array) $backgrounds as $background )928 $this->print_tab_image( esc_url_raw( $background->guid ) );929 }930 931 /**932 * @since 3.4.0933 * @uses WP_Customize_Image_Control::print_tab_image()934 */935 public function tab_default_background() {936 $this->print_tab_image( $this->setting->default );937 887 } 938 888 } 939 889 -
src/wp-includes/class-wp-customize-manager.php
diff --git src/wp-includes/class-wp-customize-manager.php src/wp-includes/class-wp-customize-manager.php index 987edc6..45ad34f 100644
final class WP_Customize_Manager { 965 965 966 966 /* Control Types (custom control classes) */ 967 967 $this->register_control_type( 'WP_Customize_Color_Control' ); 968 $this->register_control_type( 'WP_Customize_Upload_Control' ); 969 $this->register_control_type( 'WP_Customize_Image_Control' ); 968 970 969 971 /* Site Title & Tagline */ 970 972