Ticket #16434: 16434.15.diff
File 16434.15.diff, 19.2 KB (added by , 9 years ago) |
---|
-
src/wp-admin/admin-ajax.php
62 62 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', 'get-revision-diffs', 63 63 'save-user-color-scheme', 'update-widget', 'query-themes', 'parse-embed', 'set-attachment-thumbnail', 64 64 'parse-media-shortcode', 'destroy-sessions', 'install-plugin', 'update-plugin', 'press-this-save-post', 65 'press-this-add-category', 65 'press-this-add-category', 'crop-image', 66 66 ); 67 67 68 68 // Deprecated -
src/wp-admin/css/customize-controls.css
771 771 .customize-control-upload .current, 772 772 .customize-control-image .current, 773 773 .customize-control-background .current, 774 .customize-control-cropped_image .current, 775 .customize-control-site_icon .current, 774 776 .customize-control-header .current { 775 777 margin-bottom: 8px; 776 778 } … … 806 808 .customize-control-background .remove-button, 807 809 .customize-control-background .default-button, 808 810 .customize-control-background .upload-button, 811 .customize-control-cropped_image .remove-button, 812 .customize-control-cropped_image .default-button, 813 .customize-control-cropped_image .upload-button, 814 .customize-control-site_icon .remove-button, 815 .customize-control-site_icon .default-button, 816 .customize-control-site_icon .upload-button, 809 817 .customize-control-header button.new, 810 818 .customize-control-header button.remove { 811 819 white-space: normal; … … 817 825 .customize-control-upload .current .container, 818 826 .customize-control-image .current .container, 819 827 .customize-control-background .current .container, 828 .customize-control-cropped_image .current .container, 829 .customize-control-site_icon .current .container, 820 830 .customize-control-header .current .container { 821 831 overflow: hidden; 822 832 -webkit-border-radius: 2px; … … 828 838 .customize-control-media .current .container, 829 839 .customize-control-upload .current .container, 830 840 .customize-control-background .current .container, 841 .customize-control-cropped_image .current .container, 842 .customize-control-site_icon .current .container, 831 843 .customize-control-image .current .container { 832 844 min-height: 40px; 833 845 } … … 836 848 .customize-control-upload .placeholder, 837 849 .customize-control-image .placeholder, 838 850 .customize-control-background .placeholder, 851 .customize-control-cropped_image .placeholder, 852 .customize-control-site_icon .placeholder, 839 853 .customize-control-header .placeholder { 840 854 width: 100%; 841 855 position: relative; … … 847 861 .customize-control-upload .inner, 848 862 .customize-control-image .inner, 849 863 .customize-control-background .inner, 864 .customize-control-cropped_image .inner, 865 .customize-control-site_icon .inner, 850 866 .customize-control-header .inner { 851 867 display: none; 852 868 position: absolute; … … 860 876 .customize-control-media .inner, 861 877 .customize-control-upload .inner, 862 878 .customize-control-background .inner, 879 .customize-control-cropped_image .inner, 880 .customize-control-site_icon .inner, 863 881 .customize-control-image .inner { 864 882 display: block; 865 883 min-height: 40px; … … 869 887 .customize-control-upload .inner, 870 888 .customize-control-image .inner, 871 889 .customize-control-background .inner, 890 .customize-control-cropped_image .inner, 891 .customize-control-site_icon .inner, 872 892 .customize-control-header .inner, 873 893 .customize-control-header .inner .dashicons { 874 894 line-height: 20px; … … 972 992 .customize-control-upload .actions, 973 993 .customize-control-image .actions, 974 994 .customize-control-background .actions, 995 .customize-control-cropped_image .actions, 996 .customize-control-site_icon .actions, 975 997 .customize-control-header .actions { 976 998 margin-bottom: 32px; 977 999 } … … 990 1012 .customize-control-upload img, 991 1013 .customize-control-image img, 992 1014 .customize-control-background img, 1015 .customize-control-cropped_image img, 1016 .customize-control-site_icon img, 993 1017 .customize-control-header img { 994 1018 width: 100%; 995 1019 -webkit-border-radius: 2px; … … 1004 1028 .customize-control-image .default-button, 1005 1029 .customize-control-background .remove-button, 1006 1030 .customize-control-background .default-button, 1031 .customize-control-cropped_image .remove-button, 1032 .customize-control-cropped_image .default-button, 1033 .customize-control-site_icon .remove-button, 1034 .customize-control-site_icon .default-button, 1007 1035 .customize-control-header .remove { 1008 1036 float: left; 1009 1037 margin-right: 3px; … … 1013 1041 .customize-control-upload .upload-button, 1014 1042 .customize-control-image .upload-button, 1015 1043 .customize-control-background .upload-button, 1044 .customize-control-cropped_image .upload-button, 1045 .customize-control-site_icon .upload-button, 1016 1046 .customize-control-header .new { 1017 1047 float: right; 1018 1048 } -
src/wp-admin/includes/ajax-actions.php
3052 3052 3053 3053 $GLOBALS['wp_press_this']->add_category(); 3054 3054 } 3055 3056 /** 3057 * AJAX handler for cropping an image. 3058 * 3059 * @since 4.3.0 3060 * 3061 * @global WP_Site_Icon $wp_site_icon 3062 */ 3063 function wp_ajax_crop_image() { 3064 $attachment_id = absint( $_POST['id'] ); 3065 3066 check_ajax_referer( 'image_editor-' . $attachment_id, 'nonce' ); 3067 if ( ! current_user_can( 'customize' ) ) { 3068 wp_send_json_error(); 3069 } 3070 3071 $context = $_POST['context']; 3072 $data = array_map( 'absint', $_POST['cropDetails'] ); 3073 $cropped = wp_crop_image( $attachment_id, $data['x1'], $data['y1'], $data['width'], $data['height'], $data['dst_width'], $data['dst_height'] ); 3074 3075 if ( ! $cropped || is_wp_error( $cropped ) ) { 3076 wp_send_json_error( array( 'message' => __( 'Image could not be processed. Please go back and try again.' ) ) ); 3077 } 3078 3079 switch ( $context ) { 3080 case 'site_icon': 3081 require_once ABSPATH . '/wp-admin/includes/class-wp-site-icon.php'; 3082 global $wp_site_icon; 3083 3084 /** This filter is documented in wp-admin/custom-header.php */ 3085 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication. 3086 $object = $wp_site_icon->create_attachment_object( $cropped, $attachment_id ); 3087 unset( $object['ID'] ); 3088 3089 // Update the attachment. 3090 add_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) ); 3091 $attachment_id = $wp_site_icon->insert_attachment( $object, $cropped ); 3092 remove_filter( 'intermediate_image_sizes_advanced', array( $wp_site_icon, 'additional_sizes' ) ); 3093 break; 3094 3095 default: 3096 3097 /** 3098 * Filters the attachment id for a cropped image. 3099 * 3100 * @since 4.3.0 3101 * 3102 * @param int $attachment_id The ID of the cropped image. 3103 * @param string $context The feature requesting the cropped image. 3104 */ 3105 $attachment_id = apply_filters( 'wp_ajax_cropped_attachment_id', 0, $context ); 3106 } 3107 3108 if ( ! $attachment_id ) { 3109 wp_send_json_error(); 3110 } 3111 3112 wp_send_json_success( wp_prepare_attachment_for_js( $attachment_id ) ); 3113 } 3114 No newline at end of file -
src/wp-admin/js/customize-controls.js
1836 1836 }); 1837 1837 1838 1838 /** 1839 * A control for selecting and cropping an image. 1840 * 1841 * @class 1842 * @augments wp.customize.MediaControl 1843 * @augments wp.customize.Control 1844 * @augments wp.customize.Class 1845 */ 1846 api.CroppedImageControl = api.MediaControl.extend({ 1847 /** 1848 * Open the media modal to the library state. 1849 */ 1850 openFrame: function( event ) { 1851 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 1852 return; 1853 } 1854 1855 if ( this.frame ) { 1856 this.frame.setState( 'library' ); 1857 } 1858 1859 api.MediaControl.prototype.openFrame.call( this, event ); 1860 }, 1861 1862 /** 1863 * Create a media modal select frame, and store it so the instance can be reused when needed. 1864 */ 1865 initFrame: function() { 1866 var l10n = _wpMediaViewsL10n; 1867 1868 this.frame = wp.media({ 1869 button: { 1870 text: l10n.selectAndCrop, 1871 close: false 1872 }, 1873 states: [ 1874 new wp.media.controller.Library({ 1875 title: this.params.button_labels.frame_title, 1876 library: wp.media.query({ type: 'image' }), 1877 multiple: false, 1878 date: false, 1879 priority: 20, 1880 suggestedWidth: this.params.width, 1881 suggestedHeight: this.params.height 1882 }), 1883 new wp.media.controller.customizeImageCropper({ 1884 imgSelectOptions: this.calculateImageSelectOptions, 1885 control: this 1886 }) 1887 ] 1888 }); 1889 1890 this.frame.on( 'select', this.onSelect, this ); 1891 this.frame.on( 'cropped', this.onCropped, this ); 1892 this.frame.on( 'skippedcrop', this.onSkippedCrop, this ); 1893 }, 1894 1895 /** 1896 * After an image is selected in the media modal, 1897 * switch to the cropper state. 1898 */ 1899 onSelect: function() { 1900 this.frame.setState( 'cropper' ); 1901 }, 1902 1903 /** 1904 * After the image has been cropped, apply the cropped image data to the setting. 1905 * 1906 * @param {object} croppedImage Cropped attachment data. 1907 */ 1908 onCropped: function( croppedImage ) { 1909 this.setImageFromAttachment( croppedImage ); 1910 }, 1911 1912 /** 1913 * Returns a set of options, computed from the attached image data and 1914 * control-specific data, to be fed to the imgAreaSelect plugin in 1915 * wp.media.view.Cropper. 1916 * 1917 * @param {wp.media.model.Attachment} attachment 1918 * @param {wp.media.controller.Cropper} controller 1919 * @returns {Object} Options 1920 */ 1921 calculateImageSelectOptions: function( attachment, controller ) { 1922 var control = controller.get( 'control' ), 1923 xInit = parseInt( control.params.width, 10 ), 1924 yInit = parseInt( control.params.height, 10 ), 1925 flexWidth = !! parseInt( control.params.flex_width, 10 ), 1926 flexHeight = !! parseInt( control.params.flex_height, 10 ), 1927 realWidth = attachment.get( 'width' ), 1928 realHeight = attachment.get( 'height' ), 1929 ratio = xInit / yInit, 1930 xImg = realWidth, 1931 yImg = realHeight, 1932 imgSelectOptions; 1933 1934 controller.set( 'canSkipCrop', ! control.mustBeCropped( flexWidth, flexHeight, xInit, yInit, realWidth, realHeight ) ); 1935 1936 if ( xImg / yImg > ratio ) { 1937 yInit = yImg; 1938 xInit = yInit * ratio; 1939 } else { 1940 xInit = xImg; 1941 yInit = xInit / ratio; 1942 } 1943 1944 imgSelectOptions = { 1945 handles: true, 1946 keys: true, 1947 instance: true, 1948 persistent: true, 1949 imageWidth: realWidth, 1950 imageHeight: realHeight, 1951 x1: 0, 1952 y1: 0, 1953 x2: xInit, 1954 y2: yInit 1955 }; 1956 1957 if ( flexHeight === false && flexWidth === false ) { 1958 imgSelectOptions.aspectRatio = xInit + ':' + yInit; 1959 } 1960 if ( flexHeight === false ) { 1961 imgSelectOptions.maxHeight = yInit; 1962 } 1963 if ( flexWidth === false ) { 1964 imgSelectOptions.maxWidth = xInit; 1965 } 1966 1967 return imgSelectOptions; 1968 }, 1969 1970 /** 1971 * Return whether the image must be cropped, based on required dimensions. 1972 */ 1973 mustBeCropped: function( flexW, flexH, dstW, dstH, imgW, imgH ) { 1974 if ( flexW === true && flexH === true ) { 1975 return false; 1976 } 1977 1978 if ( flexW === true && dstH === imgH ) { 1979 return false; 1980 } 1981 1982 if ( flexH === true && dstW === imgW ) { 1983 return false; 1984 } 1985 1986 if ( dstW === imgW && dstH === imgH ) { 1987 return false; 1988 } 1989 1990 if ( imgW <= dstW ) { 1991 return false; 1992 } 1993 1994 return true; 1995 }, 1996 1997 /** 1998 * If cropping was skipped, apply the image data directly to the setting. 1999 */ 2000 onSkippedCrop: function() { 2001 var attachment = this.frame.state().get( 'selection' ).first().toJSON(); 2002 this.setImageFromAttachment( attachment ); 2003 }, 2004 2005 /** 2006 * Updates the setting and re-renders the control UI. 2007 * 2008 * @param {object} attachment 2009 */ 2010 setImageFromAttachment: function( attachment ) { 2011 this.params.attachment = attachment; 2012 2013 // Set the Customizer setting; the callback takes care of rendering. 2014 this.setting( attachment.id ); 2015 } 2016 }); 2017 2018 /** 2019 * A control for selecting and cropping Site Icons. 2020 * 2021 * @class 2022 * @augments wp.customize.CroppedImageControl 2023 * @augments wp.customize.MediaControl 2024 * @augments wp.customize.Control 2025 * @augments wp.customize.Class 2026 */ 2027 api.SiteIconControl = api.CroppedImageControl.extend({ 2028 /** 2029 * Updates the setting and re-renders the control UI. 2030 * 2031 * @param {object} attachment 2032 */ 2033 setImageFromAttachment: function( attachment ) { 2034 this.params.attachment = attachment; 2035 2036 // Set the Customizer setting; the callback takes care of rendering. 2037 this.setting( attachment.id ); 2038 2039 // Update the icon in-browser. 2040 $( 'link[rel="icon"]' ).attr( 'href', attachment.sizes.thumbnail.url ); 2041 }, 2042 2043 /** 2044 * Called when the "Remove" link is clicked. Empties the setting. 2045 * 2046 * @param {object} event jQuery Event object 2047 */ 2048 removeFile: function( event ) { 2049 if ( api.utils.isKeydownButNotEnterEvent( event ) ) { 2050 return; 2051 } 2052 event.preventDefault(); 2053 2054 this.params.attachment = {}; 2055 this.setting( '' ); 2056 this.renderContent(); // Not bound to setting change when emptying. 2057 $( 'link[rel="icon"]' ).attr( 'href', '' ); 2058 } 2059 }); 2060 2061 /** 1839 2062 * @class 1840 2063 * @augments wp.customize.Control 1841 2064 * @augments wp.customize.Class … … 2695 2918 }); 2696 2919 2697 2920 api.controlConstructor = { 2698 color: api.ColorControl, 2699 media: api.MediaControl, 2700 upload: api.UploadControl, 2701 image: api.ImageControl, 2702 header: api.HeaderControl, 2703 background: api.BackgroundControl, 2704 theme: api.ThemeControl 2921 color: api.ColorControl, 2922 media: api.MediaControl, 2923 upload: api.UploadControl, 2924 image: api.ImageControl, 2925 cropped_image: api.CroppedImageControl, 2926 site_icon: api.SiteIconControl, 2927 header: api.HeaderControl, 2928 background: api.BackgroundControl, 2929 theme: api.ThemeControl 2705 2930 }; 2706 2931 api.panelConstructor = {}; 2707 2932 api.sectionConstructor = { -
src/wp-includes/class-wp-customize-control.php
1001 1001 } 1002 1002 1003 1003 /** 1004 * Customize Cropped Image Control class. 1005 * 1006 * @since 4.3.0 1007 * 1008 * @see WP_Customize_Image_Control 1009 */ 1010 class WP_Customize_Cropped_Image_Control extends WP_Customize_Image_Control { 1011 1012 /** 1013 * @access public 1014 * @var string 1015 */ 1016 public $type = 'cropped_image'; 1017 1018 /** 1019 * @access public 1020 * @var int 1021 */ 1022 public $width = 150; 1023 1024 /** 1025 * @access public 1026 * @var int 1027 */ 1028 public $height = 150; 1029 1030 /** 1031 * @access public 1032 * @var bool 1033 */ 1034 public $flex_width = false; 1035 1036 /** 1037 * @access public 1038 * @var bool 1039 */ 1040 public $flex_height = false; 1041 1042 /** 1043 * Enqueue control related scripts/styles. 1044 * 1045 * @access public 1046 */ 1047 public function enqueue() { 1048 wp_enqueue_script( 'customize-views' ); 1049 1050 parent::enqueue(); 1051 } 1052 1053 /** 1054 * Refresh the parameters passed to the JavaScript via JSON. 1055 * 1056 * @since 4.3.0 1057 * @access public 1058 * @uses WP_Customize_Image_Control::to_json() 1059 * 1060 * @see WP_Customize_Control::to_json() 1061 */ 1062 public function to_json() { 1063 parent::to_json(); 1064 1065 $this->json['width'] = absint( $this->width ); 1066 $this->json['height'] = absint( $this->height ); 1067 $this->json['flex_width'] = absint( $this->flex_width ); 1068 $this->json['flex_height'] = absint( $this->flex_height ); 1069 } 1070 1071 } 1072 1073 /** 1074 * Customize Site Icon control class. 1075 * 1076 * Used only for custom functionality in JavaScript. 1077 * 1078 * @since 4.3.0 1079 * 1080 * @see WP_Customize_Cropped_Image_Control 1081 */ 1082 class WP_Customize_Site_Icon_Control extends WP_Customize_Cropped_Image_Control { 1083 1084 /** 1085 * @access public 1086 * @var string 1087 */ 1088 public $type = 'site_icon'; 1089 1090 /** 1091 * Constructor. 1092 * 1093 * @since 4.3.0 1094 * 1095 * @param WP_Customize_Manager $manager 1096 * @param string $id 1097 * @param array $args 1098 */ 1099 public function __construct( $manager, $id, $args = array() ) { 1100 parent::__construct( $manager, $id, $args ); 1101 add_action( 'customize_controls_print_styles', 'wp_site_icon', 99 ); 1102 } 1103 } 1104 1105 /** 1004 1106 * Customize Header Image Control class. 1005 1107 * 1006 1108 * @since 3.4.0 -
src/wp-includes/class-wp-customize-manager.php
1278 1278 $this->register_control_type( 'WP_Customize_Upload_Control' ); 1279 1279 $this->register_control_type( 'WP_Customize_Image_Control' ); 1280 1280 $this->register_control_type( 'WP_Customize_Background_Image_Control' ); 1281 $this->register_control_type( 'WP_Customize_Cropped_Image_Control' ); 1282 $this->register_control_type( 'WP_Customize_Site_Icon_Control' ); 1281 1283 $this->register_control_type( 'WP_Customize_Theme_Control' ); 1282 1284 1283 1285 /* Themes */ … … 1324 1326 ) ) ); 1325 1327 } 1326 1328 1327 /* Site Title & Tagline*/1329 /* Site Identity */ 1328 1330 1329 1331 $this->add_section( 'title_tagline', array( 1330 'title' => __( 'Site Title & Tagline' ),1332 'title' => __( 'Site Identity' ), 1331 1333 'priority' => 20, 1332 1334 ) ); 1333 1335 … … 1353 1355 'section' => 'title_tagline', 1354 1356 ) ); 1355 1357 1358 $icon = wp_get_attachment_image_src( absint( get_option( 'site_icon' ) ), 'medium' ); 1359 $this->add_setting( 'site_icon', array( 1360 'default' => $icon[0] ? $icon[0] : '', 1361 'type' => 'option', 1362 'capability' => 'manage_options', 1363 'transport' => 'postMessage', // Previewed with JS in the Customizer controls window. 1364 ) ); 1365 1366 $this->add_control( new WP_Customize_Site_Icon_Control( $this, 'site_icon', array( 1367 'label' => __( 'Site Icon' ), 1368 'description' => __( 'The site icon is used as the browser and device icon for your site. Your theme may also display the site icon. Icons must be square, and at least 512px wide and tall.' ), 1369 'section' => 'title_tagline', 1370 'priority' => 60, 1371 'height' => 512, 1372 'width' => 512, 1373 ) ) ); 1374 1356 1375 /* Colors */ 1357 1376 1358 1377 $this->add_section( 'colors', array( … … 1375 1394 'label' => __( 'Display Header Text' ), 1376 1395 'section' => 'title_tagline', 1377 1396 'type' => 'checkbox', 1397 'priority' => 40, 1378 1398 ) ); 1379 1399 1380 1400 $this->add_control( new WP_Customize_Color_Control( $this, 'header_textcolor', array( -
src/wp-includes/js/customize-views.js
3 3 if ( ! wp || ! wp.customize ) { return; } 4 4 var api = wp.customize; 5 5 6 /** 7 * Use a custom ajax action for cropped image controls. 8 */ 9 wp.media.controller.customizeImageCropper = wp.media.controller.Cropper.extend( { 10 doCrop: function( attachment ) { 11 var cropDetails = attachment.get( 'cropDetails' ), 12 control = this.get( 'control' ); 13 14 cropDetails.dst_width = control.params.width; 15 cropDetails.dst_height = control.params.height; 16 17 return wp.ajax.post( 'crop-image', { 18 wp_customize: 'on', 19 nonce: attachment.get( 'nonces' ).edit, 20 id: attachment.get( 'id' ), 21 context: control.params.type, 22 cropDetails: cropDetails 23 } ); 24 } 25 } ); 6 26 7 27 /** 8 28 * wp.customize.HeaderTool.CurrentView