Ticket #21785: 21785-customizer-header.diff
File 21785-customizer-header.diff, 68.7 KB (added by , 11 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 c76a6e5..3bd297f 100644
body { 455 455 -webkit-overflow-scrolling: touch; 456 456 } 457 457 458 /** Header control **/ 459 460 #customize-control-header_image .current { 461 margin-bottom: 8px; 462 } 463 464 #customize-control-header_image .uploaded { 465 margin-bottom: 18px; 466 } 467 468 /* Header control: current image container */ 469 470 #customize-control-header_image .current .container { 471 overflow: hidden; 472 border-radius: 2px; 473 } 474 475 #customize-control-header_image .placeholder { 476 width: 100%; 477 position: relative; 478 background: #262626; 479 text-align: center; 480 cursor: default; 481 } 482 483 #customize-control-header_image .inner { 484 display: none; 485 position: absolute; 486 width: 100%; 487 height: 18px; 488 margin-top: -9px; 489 top: 50%; 490 } 491 492 body:not(.blue) #customize-control-header_image .inner { 493 color: #eee; 494 } 495 496 /* Header control: overlay "close" button */ 497 498 #customize-control-header_image .header-view { 499 position: relative; 500 } 501 502 #customize-control-header_image .uploaded .header-view .close { 503 visibility: hidden; 504 position: absolute; 505 top: 10px; 506 right: 10px; 507 z-index: 1; 508 width: 20px; 509 height: 20px; 510 background: url('../images/close-button.light.png'); 511 background-size: 20px 20px; 512 text-indent: -999px; 513 } 514 515 #customize-control-header_image .header-view:hover .close { 516 visibility: visible; 517 } 518 519 /* Header control: randomiz(s)er */ 520 521 #customize-control-header_image .random.placeholder { 522 cursor: pointer; 523 border-radius: 2px; 524 height: 40px; 525 } 526 527 #customize-control-header_image .random .inner { 528 display: block; 529 } 530 531 #customize-control-header_image .dice { 532 font-size: 16px; 533 vertical-align: -1px; 534 } 535 536 #customize-control-header_image .placeholder:hover .dice { 537 -webkit-animation: dice-color-change 3s infinite; 538 -moz-animation: dice-color-change 3s infinite; 539 -ms-animation: dice-color-change 3s infinite; 540 animation: dice-color-change 3s infinite; 541 } 542 543 @-webkit-keyframes dice-color-change { 544 0% { color: #d4b146; } 545 50% { color: #ef54b0; } 546 75% { color: #7190d3; } 547 100% { color: #d4b146; } 548 } 549 550 @-moz-keyframes dice-color-change { 551 0% { color: #d4b146; } 552 50% { color: #ef54b0; } 553 75% { color: #7190d3; } 554 100% { color: #d4b146; } 555 } 556 557 @-ms-keyframes dice-color-change { 558 0% { color: #d4b146; } 559 50% { color: #ef54b0; } 560 75% { color: #7190d3; } 561 100% { color: #d4b146; } 562 } 563 564 @keyframes dice-color-change { 565 0% { color: #d4b146; } 566 50% { color: #ef54b0; } 567 75% { color: #7190d3; } 568 100% { color: #d4b146; } 569 } 570 571 /* Header control: actions and choices */ 572 573 #customize-control-header_image .actions { 574 margin-bottom: 32px; 575 } 576 577 #customize-control-header_image .choice { 578 position: relative; 579 display: block; 580 margin-bottom: 9px; 581 } 582 583 #customize-control-header_image .choice.random:before { 584 position: absolute; 585 content: attr(data-label); 586 left: 0; 587 top: 0; 588 } 589 590 #customize-control-header_image .uploaded div:last-child > .choice { 591 margin-bottom: 0; 592 } 593 594 #customize-control-header_image .choices hr { 595 visibility: hidden; 596 } 597 598 #customize-control-header_image img { 599 width: 100%; 600 border-radius: 2px; 601 } 602 603 #customize-control-header_image .remove { 604 float: left; 605 margin-right: 3px; 606 } 607 608 #customize-control-header_image .new { 609 float: right; 610 } 611 612 458 613 /** Handle cheaters. */ 459 614 body.cheatin { 460 615 min-width: 0; -
src/wp-admin/custom-header.php
diff --git src/wp-admin/custom-header.php src/wp-admin/custom-header.php index 633dc65..1c6ee7e 100644
class Custom_Image_Header { 43 43 var $default_headers = array(); 44 44 45 45 /** 46 * Holds custom headers uploaded by the user 46 * Holds custom headers uploaded by the user. 47 47 * 48 48 * @var array 49 49 * @since 3.2.0 … … class Custom_Image_Header { 61 61 var $page = ''; 62 62 63 63 /** 64 * ID of the attachment image from which we are cropping a new one. 65 * 66 * @var int 67 * @since 3.9.0 68 */ 69 public $parent_attachment_id; 70 71 /** 64 72 * Constructor - Register administration header callback. 65 73 * 66 74 * @since 2.1.0 … … class Custom_Image_Header { 72 80 $this->admin_header_callback = $admin_header_callback; 73 81 $this->admin_image_div_callback = $admin_image_div_callback; 74 82 83 if ( current_theme_supports( 'custom-header' ) ) { 84 add_action( 'customize_save_after', array( $this, 'set_last_used' ) ); 85 add_action( 'wp_ajax_header_crop', array( $this, 'ajax_header_crop' ) ); 86 add_action( 'wp_ajax_header_add', array( $this, 'ajax_header_add' ) ); 87 add_action( 'wp_ajax_header_remove', array( __CLASS__, 'ajax_header_remove' ) ); 88 add_filter( 'wp_prepare_attachment_for_js', array( $this, 'add_parent_attachment_js' ) , 11, 3); 89 add_filter( 'wp_header_image_attachment_metadata', array( $this, 'add_parent_attachment_id' ) , 11, 1); 90 } 91 75 92 add_action( 'admin_menu', array( $this, 'init' ) ); 76 93 } 77 94 … … class Custom_Image_Header { 93 110 add_action("admin_head-$page", array($this, 'js'), 50); 94 111 if ( $this->admin_header_callback ) 95 112 add_action("admin_head-$page", $this->admin_header_callback, 51); 113 96 114 } 97 115 98 116 /** … … wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?> 819 837 $attachment_id = absint( $_POST['attachment_id'] ); 820 838 $original = get_attached_file($attachment_id); 821 839 822 823 $max_width = 0; 824 // For flex, limit size of image displayed to 1500px unless theme says otherwise 825 if ( current_theme_supports( 'custom-header', 'flex-width' ) ) 826 $max_width = 1500; 827 828 if ( current_theme_supports( 'custom-header', 'max-width' ) ) 829 $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) ); 830 $max_width = max( $max_width, get_theme_support( 'custom-header', 'width' ) ); 831 832 if ( ( current_theme_supports( 'custom-header', 'flex-height' ) && ! current_theme_supports( 'custom-header', 'flex-width' ) ) || $_POST['width'] > $max_width ) 833 $dst_height = absint( $_POST['height'] * ( $max_width / $_POST['width'] ) ); 834 elseif ( current_theme_supports( 'custom-header', 'flex-height' ) && current_theme_supports( 'custom-header', 'flex-width' ) ) 835 $dst_height = absint( $_POST['height'] ); 836 else 837 $dst_height = get_theme_support( 'custom-header', 'height' ); 838 839 if ( ( current_theme_supports( 'custom-header', 'flex-width' ) && ! current_theme_supports( 'custom-header', 'flex-height' ) ) || $_POST['width'] > $max_width ) 840 $dst_width = absint( $_POST['width'] * ( $max_width / $_POST['width'] ) ); 841 elseif ( current_theme_supports( 'custom-header', 'flex-width' ) && current_theme_supports( 'custom-header', 'flex-height' ) ) 842 $dst_width = absint( $_POST['width'] ); 843 else 844 $dst_width = get_theme_support( 'custom-header', 'width' ); 840 extract( $this->get_header_dimensions( array( 841 'width' => $_POST['width'], 842 'height' => $_POST['height'], 843 ) ) ); 845 844 846 845 if ( empty( $_POST['skip-cropping'] ) ) 847 846 $cropped = wp_crop_image( $attachment_id, (int) $_POST['x1'], (int) $_POST['y1'], (int) $_POST['width'], (int) $_POST['height'], $dst_width, $dst_height ); … … wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?> 856 855 /** This filter is documented in wp-admin/custom-header.php */ 857 856 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication 858 857 859 $parent = get_post($attachment_id); 860 $parent_url = $parent->guid; 861 $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url ); 862 863 $size = @getimagesize( $cropped ); 864 $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; 858 $object = $this->create_attachment_object( $cropped, $attachment_id ); 865 859 866 // Construct the object array867 $object = array(868 'ID' => $attachment_id,869 'post_title' => basename($cropped),870 'post_content' => $url,871 'post_mime_type' => $image_type,872 'guid' => $url,873 'context' => 'custom-header'874 );875 860 if ( ! empty( $_POST['create-new-attachment'] ) ) 876 861 unset( $object['ID'] ); 877 862 878 863 // Update the attachment 879 $attachment_id = wp_insert_attachment( $object, $cropped ); 880 wp_update_attachment_metadata( $attachment_id, wp_generate_attachment_metadata( $attachment_id, $cropped ) ); 864 $attachment_id = $this->insert_attachment( $object, $cropped ); 881 865 882 866 $width = $dst_width; 883 867 $height = $dst_height; 868 $url = $object['guid']; 884 869 $this->set_header_image( compact( 'url', 'attachment_id', 'width', 'height' ) ); 885 870 886 871 // cleanup … … wp_nonce_field( 'custom-header-options', '_wpnonce-custom-header-options' ); ?> 1041 1026 set_theme_mod( 'header_image', $default ); 1042 1027 set_theme_mod( 'header_image_data', (object) $default_data ); 1043 1028 } 1029 1030 /** 1031 * Calculate dst_width and dst_height based on what the currently selected theme supports. 1032 * 1033 * @return array dst_height and dst_width of header image. 1034 */ 1035 final public function get_header_dimensions( $dimensions ) { 1036 $max_width = 0; 1037 $width = absint( $dimensions['width'] ); 1038 $height = absint( $dimensions['height'] ); 1039 $theme_height = get_theme_support( 'custom-header', 'height' ); 1040 $theme_width = get_theme_support( 'custom-header', 'width' ); 1041 $has_flex_width = current_theme_supports( 'custom-header', 'flex-width' ); 1042 $has_flex_height = current_theme_supports( 'custom-header', 'flex-height' ); 1043 $has_max_width = current_theme_supports( 'custom-header', 'max-width' ) ; 1044 $dst = array(); 1045 1046 // For flex, limit size of image displayed to 1500px unless theme says otherwise 1047 if ( $has_flex_width ) 1048 $max_width = 1500; 1049 1050 if ( $has_max_width ) 1051 $max_width = max( $max_width, get_theme_support( 'custom-header', 'max-width' ) ); 1052 $max_width = max( $max_width, $theme_width ); 1053 1054 if ( $has_flex_height && ( ! $has_flex_width || $width > $max_width ) ) 1055 $dst['dst_height'] = absint( $height * ( $max_width / $width ) ); 1056 elseif ( $has_flex_height && $has_flex_width ) 1057 $dst['dst_height'] = $height; 1058 else 1059 $dst['dst_height'] = $theme_height; 1060 1061 if ( $has_flex_width && ( ! $has_flex_height || $width > $max_width ) ) 1062 $dst['dst_width'] = absint( $width * ( $max_width / $width ) ); 1063 elseif ( $has_flex_width && $has_flex_height ) 1064 $dst['dst_width'] = $width; 1065 else 1066 $dst['dst_width'] = $theme_width; 1067 1068 return $dst; 1069 } 1070 1071 /** 1072 * Create an attachment 'object'. 1073 * 1074 * @param string $cropped Cropped image URL. 1075 * @param int $parent_attachment_id Attachment ID of parent image. 1076 * 1077 * @return array Attachment object. 1078 */ 1079 final public function create_attachment_object( $cropped, $parent_attachment_id ) { 1080 $parent = get_post( $parent_attachment_id ); 1081 $parent_url = $parent->guid; 1082 $url = str_replace( basename( $parent_url ), basename( $cropped ), $parent_url ); 1083 1084 $size = @getimagesize( $cropped ); 1085 $image_type = ( $size ) ? $size['mime'] : 'image/jpeg'; 1086 1087 $object = array( 1088 'ID' => $parent_attachment_id, 1089 'post_title' => basename($cropped), 1090 'post_content' => $url, 1091 'post_mime_type' => $image_type, 1092 'guid' => $url, 1093 'context' => 'custom-header' 1094 ); 1095 1096 return $object; 1097 } 1098 1099 /** 1100 * Insert an attachment & its metadata. 1101 * 1102 * @param array $object Attachment object. 1103 * @param string $cropped Cropped image URL. 1104 * 1105 * @return int Attachment ID. 1106 */ 1107 final public function insert_attachment( $object, $cropped ) { 1108 $attachment_id = wp_insert_attachment( $object, $cropped ); 1109 $metadata = wp_generate_attachment_metadata( $attachment_id, $cropped ); 1110 /** 1111 * Allows us to insert custom meta data for an attachment. 1112 * 1113 */ 1114 $metadata = apply_filters( 'wp_header_image_attachment_metadata', $metadata ); 1115 wp_update_attachment_metadata( $attachment_id, $metadata ); 1116 return $attachment_id; 1117 } 1118 1119 function ajax_check_nonce( $nonce, $attachment_id = null ) { 1120 if ( ! isset( $nonce ) || ! wp_verify_nonce( $nonce, 'crop-image_' . $attachment_id ) ) { 1121 wp_die( __( 'Cheatin’ uh?' ) ); 1122 } 1123 } 1124 1125 /** 1126 * Gets attachment uploaded by Media Manager, crops it, then saves it as a 1127 * new object. Returns JSON-encoded object details. 1128 */ 1129 function ajax_header_crop() { 1130 $data = $_POST['data']; 1131 $this->ajax_check_nonce( $data['nonces']['crop'], $data['id'] ); 1132 if ( ! current_theme_supports( 'custom-header', 'uploads' ) ) 1133 wp_die( __( 'Cheatin’ uh?' ) ); 1134 1135 if ( ! empty( $data['skip-cropping'] ) && ! ( current_theme_supports( 'custom-header', 'flex-height' ) || current_theme_supports( 'custom-header', 'flex-width' ) ) ) 1136 wp_die( __( 'Cheatin’ uh?' ) ); 1137 1138 $crop_details = $data['cropDetails']; 1139 1140 $dimensions = $this->get_header_dimensions( array( 1141 'width' => $crop_details['width'], 1142 'height' => $crop_details['height'], 1143 ) ); 1144 1145 $attachment_id = absint( $data['id'] ); 1146 1147 $cropped = wp_crop_image( $attachment_id, (int) $crop_details['x1'], (int) $crop_details['y1'], (int) $crop_details['width'], (int) $crop_details['height'], (int) $dimensions['dst_width'], (int) $dimensions['dst_height'] ); 1148 1149 if ( ! $cropped || is_wp_error( $cropped ) ) 1150 wp_die( __( 'Image could not be processed. Please go back and try again.' ), __( 'Image Processing Error' ) ); 1151 1152 $cropped = apply_filters( 'wp_create_file_in_uploads', $cropped, $attachment_id ); // For replication 1153 1154 $object = $this->create_attachment_object( $cropped, $attachment_id ); 1155 1156 unset( $object['ID'] ); 1157 1158 $this->parent_attachment_id = $attachment_id; 1159 $new_attachment_id = $this->insert_attachment( $object, $cropped ); 1160 1161 $object['attachment_id'] = $new_attachment_id; 1162 $object['width'] = $dimensions['dst_width']; 1163 $object['height'] = $dimensions['dst_height']; 1164 1165 echo json_encode($object); 1166 die(); 1167 } 1168 1169 /** 1170 * Given an attachment ID for a header image, updates its "last used" 1171 * timestamp to now. 1172 * 1173 * Triggered when the user tries adds a new header image from the 1174 * Media Manager, even if s/he doesn't save that change. 1175 */ 1176 function ajax_header_add() { 1177 $data = $_POST['data']; 1178 check_ajax_referer( 'header-add', 'nonce' ); 1179 1180 $attachment_id = absint( $data['attachment_id'] ); 1181 if ( $attachment_id < 1 ) 1182 return; 1183 1184 $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); 1185 update_post_meta( $attachment_id, $key, time() ); 1186 update_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() ); 1187 1188 die(); 1189 } 1190 1191 /** 1192 * Given an attachment ID for a header image, unsets it as a user-uploaded 1193 * header image for the current theme. 1194 * 1195 * Triggered when the user clicks the overlay "X" button next to each image 1196 * choice in the Customizer's Header tool. 1197 */ 1198 function ajax_header_remove() { 1199 $data = $_POST['data']; 1200 check_ajax_referer( 'header-remove', 'nonce' ); 1201 1202 $attachment_id = absint( $data['attachment_id'] ); 1203 if ( $attachment_id < 1 ) 1204 return; 1205 1206 $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); 1207 delete_post_meta( $attachment_id, $key ); 1208 delete_post_meta( $attachment_id, '_wp_attachment_is_custom_header', get_stylesheet() ); 1209 1210 die(); 1211 } 1212 1213 function set_last_used( $manager ) { 1214 $data = $manager->get_setting( 'header_image_data' )->post_value(); 1215 1216 if ( !isset( $data['attachment_id'] ) ) 1217 return; 1218 1219 $attachment_id = $data['attachment_id']; 1220 $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); 1221 update_post_meta( $attachment_id, $key, time() ); 1222 } 1223 1224 function add_parent_attachment_id( $metadata ) { 1225 $metadata['parent_attachment_id'] = $this->parent_attachment_id; 1226 return $metadata; 1227 } 1228 1229 function add_parent_attachment_js($response, $attachment, $meta ){ 1230 $response['parentAttachmentId'] = isset( $meta['parent_attachment_id'] ) ? $meta['parent_attachment_id'] : 0; 1231 return $response; 1232 } 1044 1233 } -
src/wp-admin/js/customize-controls.js
diff --git src/wp-admin/images/close-button.light.png src/wp-admin/images/close-button.light.png new file mode 100644 index 0000000..5da989b Binary files /dev/null and src/wp-admin/images/close-button.light.png differ diff --git src/wp-admin/js/customize-controls.js src/wp-admin/js/customize-controls.js index 3a05ad4..d16a94b 100644
306 306 } 307 307 }); 308 308 309 api.HeaderControl = api.Control.extend({ 310 ready: function() { 311 this.btnRemove = $('.actions .remove'); 312 this.btnNew = $('.actions .new'); 313 314 _.bindAll(this, 'openMM', 'removeImage'); 315 316 this.btnNew.on( 'click', this.openMM ); 317 this.btnRemove.on( 'click', this.removeImage ); 318 319 api.HeaderTool.currentHeader = new api.HeaderTool.ImageModel(); 320 321 new api.HeaderTool.CurrentView({ 322 model: api.HeaderTool.currentHeader, 323 el: '.current .container' 324 }); 325 326 new api.HeaderTool.ChoiceListView({ 327 collection: api.HeaderTool.UploadsList = new api.HeaderTool.ChoiceList(), 328 el: '.choices .uploaded .list' 329 }); 330 331 new api.HeaderTool.ChoiceListView({ 332 collection: api.HeaderTool.DefaultsList = new api.HeaderTool.DefaultsList(), 333 el: '.choices .default .list' 334 }); 335 336 api.HeaderTool.combinedList = api.HeaderTool.CombinedList = new api.HeaderTool.CombinedList([ 337 api.HeaderTool.UploadsList, 338 api.HeaderTool.DefaultsList 339 ]); 340 }, 341 342 /** 343 * Returns a set of options, computed from the attached image data and 344 * theme-specific data, to be fed to the imgAreaSelect plugin in 345 * wp.media.view.Cropper. 346 * 347 * @param {wp.media.model.Attachment} attachment 348 * @param {wp.media.controller.Cropper} controller 349 * @returns {Object} Options 350 */ 351 calculateImageSelectOptions: function(attachment, controller) { 352 var xInit = parseInt(_wpCustomizeHeader.data.width, 10), 353 yInit = parseInt(_wpCustomizeHeader.data.height, 10), 354 flexWidth = !! parseInt(_wpCustomizeHeader.data['flex-width'], 10), 355 flexHeight = !! parseInt(_wpCustomizeHeader.data['flex-height'], 10), 356 ratio, xImg, yImg, realHeight, realWidth, 357 imgSelectOptions; 358 359 realWidth = attachment.get('width'); 360 realHeight = attachment.get('height'); 361 362 this.headerImage = new api.HeaderTool.ImageModel(); 363 this.headerImage.set({ 364 themeWidth: xInit, 365 themeHeight: yInit, 366 themeFlexWidth: flexWidth, 367 themeFlexHeight: flexHeight, 368 imageWidth: realWidth, 369 imageHeight: realHeight 370 }); 371 372 controller.set( 'canSkipCrop', ! this.headerImage.shouldBeCropped() ); 373 374 ratio = xInit / yInit; 375 xImg = realWidth; 376 yImg = realHeight; 377 378 if ( xImg / yImg > ratio ) { 379 yInit = yImg; 380 xInit = yInit * ratio; 381 } else { 382 xInit = xImg; 383 yInit = xInit / ratio; 384 } 385 386 imgSelectOptions = { 387 handles: true, 388 keys: true, 389 instance: true, 390 persistent: true, 391 parent: this.$el, 392 imageWidth: realWidth, 393 imageHeight: realHeight, 394 x1: 0, 395 y1: 0, 396 x2: xInit, 397 y2: yInit 398 }; 399 400 if (flexHeight === false && flexWidth === false) { 401 imgSelectOptions.aspectRatio = xInit + ':' + yInit; 402 } 403 if (flexHeight === false ) { 404 imgSelectOptions.maxHeight = yInit; 405 } 406 if (flexWidth === false ) { 407 imgSelectOptions.maxWidth = xInit; 408 } 409 410 return imgSelectOptions; 411 }, 412 413 /** 414 * Sets up and opens the Media Manager in order to select an image. 415 * Depending on both the size of the image and the properties of the 416 * current theme, a cropping step after selection may be required or 417 * skippable. 418 * 419 * @param {event} event 420 */ 421 openMM: function(event) { 422 var title, suggestedWidth, suggestedHeight, 423 l10n = _wpMediaViewsL10n; 424 425 event.preventDefault(); 426 427 suggestedWidth = l10n.suggestedWidth.replace('%d', _wpCustomizeHeader.data.width); 428 suggestedHeight = l10n.suggestedHeight.replace('%d', _wpCustomizeHeader.data.height); 429 430 title = { 431 html: l10n.chooseImage + ' <span class="suggested-dimensions">' + 432 suggestedWidth + ' ' + suggestedHeight +'</span>', 433 text: l10n.chooseImage 434 }; 435 436 frame = wp.media({ 437 title: title, 438 library: { 439 type: 'image' 440 }, 441 button: { 442 text: l10n.selectAndCrop, 443 close: false 444 }, 445 multiple: false, 446 imgSelectOptions: this.calculateImageSelectOptions 447 }); 448 449 frame.states.add([new wp.media.controller.Cropper()]); 450 451 frame.on('select', function() { 452 frame.setState('cropper'); 453 }); 454 455 frame.on('cropped', function(croppedImage) { 456 var url = croppedImage.post_content, 457 attachmentId = croppedImage.attachment_id, 458 w = croppedImage.width, 459 h = croppedImage.height; 460 this.setImageFromURL(url, attachmentId, w, h); 461 }, this); 462 463 frame.on('skippedcrop', function(selection) { 464 var url = selection.get('url'), 465 w = selection.get('width'), 466 h = selection.get('height'); 467 this.setImageFromURL(url, selection.id, w, h); 468 }, this); 469 470 frame.open(); 471 }, 472 473 /** 474 * Creates a new wp.customize.HeaderTool.ImageModel from provided 475 * header image data and inserts it into the user-uploaded headers 476 * collection. 477 * 478 * @param {String} url 479 * @param {Number} attachmentId 480 * @param {Number} width 481 * @param {Number} height 482 */ 483 setImageFromURL: function(url, attachmentId, width, height) { 484 var choice, data = {}; 485 486 data.url = url; 487 data.thumbnail_url = url; 488 489 if (attachmentId) 490 data.attachment_id = attachmentId; 491 492 if (width) 493 data.width = width; 494 495 if (height) 496 data.height = height; 497 498 choice = new api.HeaderTool.ImageModel({ 499 header: data, 500 choice: url.split('/').pop() 501 }); 502 api.HeaderTool.UploadsList.add(choice); 503 api.HeaderTool.currentHeader.set(choice.toJSON()); 504 choice.save(); 505 choice.importImage(); 506 }, 507 508 /** 509 * Triggers the necessary events to deselect an image which was set as 510 * the currently selected one. 511 */ 512 removeImage: function() { 513 api.HeaderTool.currentHeader.trigger('hide'); 514 api.HeaderTool.CombinedList.trigger('control:removeImage'); 515 } 516 517 }); 518 309 519 // Change objects contained within the main customize object to Settings. 310 520 api.defaultConstructor = api.Setting; 311 521 … … 686 896 api.controlConstructor = { 687 897 color: api.ColorControl, 688 898 upload: api.UploadControl, 689 image: api.ImageControl 899 image: api.ImageControl, 900 header: api.HeaderControl 690 901 }; 691 902 692 903 $( function() { … … 961 1172 }); 962 1173 }); 963 1174 964 // Handle header image data965 api.control( 'header_image', function( control ) {966 control.setting.bind( function( to ) {967 if ( to === control.params.removed )968 control.settings.data.set( false );969 });970 971 control.library.on( 'click', 'a', function() {972 control.settings.data.set( $(this).data('customizeHeaderImageData') );973 });974 975 control.uploader.success = function( attachment ) {976 var data;977 978 api.ImageControl.prototype.success.call( control, attachment );979 980 data = {981 attachment_id: attachment.get('id'),982 url: attachment.get('url'),983 thumbnail_url: attachment.get('url'),984 height: attachment.get('height'),985 width: attachment.get('width')986 };987 988 attachment.element.data( 'customizeHeaderImageData', data );989 control.settings.data.set( data );990 };991 });992 993 1175 api.trigger( 'ready' ); 994 1176 995 1177 // Make sure left column gets focus -
new file src/wp-admin/js/header-models.js
diff --git src/wp-admin/js/header-models.js src/wp-admin/js/header-models.js new file mode 100644 index 0000000..945bc23
- + 1 /* globals jQuery, _wpCustomizeHeader */ 2 ;( function( $, wp ) { 3 var api = wp.customize; 4 api.HeaderTool = {}; 5 6 7 /** 8 * wp.customize.HeaderTool.ImageModel 9 * 10 * A header image. This is where saves via the Customizer API are 11 * abstracted away, plus our own AJAX calls to add images to and remove 12 * images from the user's recently uploaded images setting on the server. 13 * These calls are made regardless of whether the user actually saves new 14 * Customizer settings. 15 * 16 * @constructor 17 * @augments Backbone.Model 18 */ 19 api.HeaderTool.ImageModel = Backbone.Model.extend({ 20 defaults: function() { 21 return { 22 header: { 23 attachment_id: 0, 24 url: '', 25 timestamp: Date.now(), 26 thumbnail_url: '' 27 }, 28 choice: '', 29 hidden: false, 30 random: false 31 }; 32 }, 33 34 initialize: function() { 35 this.on('hide', this.hide, this); 36 }, 37 38 hide: function() { 39 this.set('choice', ''); 40 api('header_image').set('remove-header'); 41 api('header_image_data').set('remove-header'); 42 }, 43 44 destroy: function() { 45 var data = this.get('header'), 46 curr = api.HeaderTool.currentHeader.get('header').attachment_id; 47 48 // If the image we're removing is also the current header, unset 49 // the latter 50 if (curr && data.attachment_id == curr) 51 api.HeaderTool.currentHeader.trigger('hide'); 52 53 $.post(_wpCustomizeSettings.url.ajax, { 54 wp_customize: 'on', 55 theme: api.settings.theme.stylesheet, 56 dataType: 'json', 57 action: 'header_remove', 58 nonce: _wpCustomizeHeader.nonces.remove, 59 data: data 60 }); 61 62 this.trigger('destroy', this, this.collection); 63 }, 64 65 save: function() { 66 if (this.get('random')) { 67 api('header_image').set(this.get('header').random); 68 api('header_image_data').set(this.get('header').random); 69 } else { 70 if (this.get('header').defaultName) { 71 api('header_image').set(this.get('header').url); 72 api('header_image_data').set(this.get('header').defaultName); 73 } else { 74 api('header_image').set(this.get('header').url); 75 api('header_image_data').set(this.get('header')); 76 } 77 } 78 79 api.HeaderTool.combinedList.trigger('control:setImage', this); 80 }, 81 82 importImage: function() { 83 var data = this.get('header'); 84 if (data.attachment_id === undefined) 85 return; 86 87 $.post(_wpCustomizeSettings.url.ajax, { 88 wp_customize: 'on', 89 theme: api.settings.theme.stylesheet, 90 dataType: 'json', 91 action: 'header_add', 92 nonce: _wpCustomizeHeader.nonces.add, 93 data: data 94 }); 95 }, 96 97 shouldBeCropped: function() { 98 if (this.get('themeFlexWidth') === true && 99 this.get('themeFlexHeight') === true) { 100 return false; 101 } 102 103 if (this.get('themeFlexWidth') === true && 104 this.get('themeHeight') === this.get('imageHeight')) { 105 return false; 106 } 107 108 if (this.get('themeFlexHeight') === true && 109 this.get('themeWidth') === this.get('imageWidth')) { 110 return false; 111 } 112 113 if (this.get('themeWidth') === this.get('imageWidth') && 114 this.get('themeHeight') === this.get('imageHeight')) { 115 return false; 116 } 117 118 return true; 119 } 120 }); 121 122 123 /** 124 * wp.customize.HeaderTool.ChoiceList 125 * 126 * @constructor 127 * @augments Backbone.Collection 128 */ 129 api.HeaderTool.ChoiceList = Backbone.Collection.extend({ 130 model: api.HeaderTool.ImageModel, 131 132 // Ordered from most recently used to least 133 comparator: function(model) { 134 return -model.get('header').timestamp; 135 }, 136 137 initialize: function() { 138 var current = api.HeaderTool.currentHeader.get('choice').replace(/^https?:\/\//, ''), 139 isRandom = this.isRandomChoice(api.get().header_image); 140 141 // Overridable by an extending class 142 if (!this.type) 143 this.type = 'uploaded'; 144 145 // Overridable by an extending class 146 if (!this.data) 147 this.data = _wpCustomizeHeader.uploads; 148 149 if (isRandom) { 150 // So that when adding data we don't hide regular images 151 current = api.get().header_image; 152 } 153 154 this.on('control:setImage', this.setImage, this); 155 this.on('control:removeImage', this.removeImage, this); 156 this.on('add', this.maybeAddRandomChoice, this); 157 158 _.each(this.data, function(elt, index) { 159 if (!elt.attachment_id) 160 elt.defaultName = index; 161 162 this.add({ 163 header: elt, 164 choice: elt.url.split('/').pop(), 165 hidden: current == elt.url.replace(/^https?:\/\//, '') 166 }, { silent: true }); 167 }, this); 168 169 if (this.size() > 0) 170 this.addRandomChoice(current); 171 }, 172 173 maybeAddRandomChoice: function() { 174 if (this.size() === 1) 175 this.addRandomChoice(); 176 }, 177 178 addRandomChoice: function(initialChoice) { 179 var isRandomSameType = RegExp(this.type).test(initialChoice), 180 randomChoice = 'random-' + this.type + '-image'; 181 182 this.add({ 183 header: { 184 timestamp: 0, 185 random: randomChoice, 186 width: 245, 187 height: 41 188 }, 189 choice: randomChoice, 190 random: true, 191 hidden: isRandomSameType 192 }); 193 }, 194 195 isRandomChoice: function(choice) { 196 return /^random-(uploaded|default)-image$/.test(choice); 197 }, 198 199 shouldHideTitle: function() { 200 return _.every(this.pluck('hidden')); 201 }, 202 203 setImage: function(model) { 204 this.each(function(m) { 205 m.set('hidden', false); 206 }); 207 208 if (model) { 209 model.set('hidden', true); 210 // Bump images to top except for special "Randomize" images 211 if (!model.get('random')) { 212 model.get('header').timestamp = Date.now(); 213 this.sort(); 214 } 215 } 216 }, 217 218 removeImage: function() { 219 this.each(function(m) { 220 m.set('hidden', false); 221 }); 222 }, 223 224 shown: function() { 225 var filtered = this.where({ hidden: false }); 226 return new api.HeaderTool.ChoiceList( filtered ); 227 } 228 }); 229 230 231 /** 232 * wp.customize.HeaderTool.DefaultsList 233 * 234 * @constructor 235 * @augments wp.customize.HeaderTool.ChoiceList 236 * @augments Backbone.Collection 237 */ 238 api.HeaderTool.DefaultsList = api.HeaderTool.ChoiceList.extend({ 239 initialize: function() { 240 this.type = 'default'; 241 this.data = _wpCustomizeHeader.defaults; 242 api.HeaderTool.ChoiceList.prototype.initialize.apply(this); 243 } 244 }); 245 246 })( jQuery, this.wp ); -
new file src/wp-admin/js/header-views.js
diff --git src/wp-admin/js/header-views.js src/wp-admin/js/header-views.js new file mode 100644 index 0000000..a9957b5
- + 1 /* globals jQuery, _, Backbone, _wpMediaViewsL10n, _wpCustomizeHeader */ 2 ;( function( $, wp, _ ) { 3 if ( ! wp || ! wp.customize ) { return; } 4 var api = wp.customize, frame, CombinedList, UploadsList, DefaultsList; 5 6 7 /** 8 * wp.customize.HeaderTool.CurrentView 9 * 10 * Displays the currently selected header image, or a placeholder in lack 11 * thereof. 12 * 13 * Instantiate with model wp.customize.HeaderTool.currentHeader. 14 * 15 * @constructor 16 * @augments Backbone.View 17 */ 18 api.HeaderTool.CurrentView = Backbone.View.extend({ 19 template: _.template($('#tmpl-header-current').html()), 20 21 initialize: function() { 22 this.listenTo(this.model, 'change', this.render); 23 this.render(); 24 }, 25 26 render: function() { 27 this.$el.html(this.template(this.model.toJSON())); 28 this.setPlaceholder(); 29 this.setButtons(); 30 return this; 31 }, 32 33 getHeight: function() { 34 var image = this.$el.find('img'), 35 saved = this.model.get('savedHeight'), 36 height = image.height() || saved; 37 38 if (image.length) { 39 this.$el.find('.inner').hide(); 40 } else { 41 this.$el.find('.inner').show(); 42 } 43 44 // happens at ready 45 if (!height) { 46 var d = api.get().header_image_data; 47 48 if (d && d.width && d.height) { 49 var w = d.width, 50 h = d.height; 51 // hardcoded container width 52 height = 260 / w * h; 53 } 54 // fallback for when no image is set 55 else height = 40; 56 } 57 58 return height; 59 }, 60 61 setPlaceholder: function(_height) { 62 var height = _height || this.getHeight(); 63 this.model.set('savedHeight', height); 64 this.$el 65 .add(this.$el.find('.placeholder')) 66 .height(height); 67 }, 68 69 setButtons: function() { 70 var elements = $('.actions .remove'); 71 if (this.model.get('choice')) 72 elements.show(); 73 else 74 elements.hide(); 75 } 76 }); 77 78 79 /** 80 * wp.customize.HeaderTool.ChoiceView 81 * 82 * Represents a choosable header image, be it user-uploaded, 83 * theme-suggested or a special Randomize choice. 84 * 85 * Takes a wp.customize.HeaderTool.ImageModel. 86 * 87 * Manually changes model wp.customize.HeaderTool.currentHeader via the 88 * `select` method. 89 * 90 * @constructor 91 * @augments Backbone.View 92 */ 93 (function () { // closures FTW 94 var lastHeight = 0; 95 api.HeaderTool.ChoiceView = Backbone.View.extend({ 96 template: _.template($('#tmpl-header-choice').html()), 97 98 className: 'header-view', 99 100 events: { 101 'click .choice,.random': 'select', 102 'click .close': 'removeImage' 103 }, 104 105 initialize: function() { 106 var properties = [ 107 this.model.get('header').url, 108 this.model.get('choice') 109 ]; 110 111 this.listenTo(this.model, 'change', this.render); 112 if (_.contains(properties, api.get().header_image)) 113 api.HeaderTool.currentHeader.set(this.extendedModel()); 114 }, 115 116 render: function() { 117 var model = this.model; 118 119 this.$el.html(this.template(this.extendedModel())); 120 121 if (model.get('random')) 122 this.setPlaceholder(40); 123 else 124 lastHeight = this.getHeight(); 125 126 this.$el.toggleClass('hidden', model.get('hidden')); 127 return this; 128 }, 129 130 extendedModel: function() { 131 var c = this.model.get('collection'), 132 t = _wpCustomizeHeader.l10n[c.type] || ''; 133 134 return _.extend(this.model.toJSON(), { 135 // -1 to exclude the randomize button 136 nImages: c.size() - 1, 137 type: t 138 }); 139 }, 140 141 getHeight: api.HeaderTool.CurrentView.prototype.getHeight, 142 143 setPlaceholder: api.HeaderTool.CurrentView.prototype.setPlaceholder, 144 145 select: function() { 146 this.model.save(); 147 api.HeaderTool.currentHeader.set(this.extendedModel()); 148 }, 149 150 removeImage: function(e) { 151 e.stopPropagation(); 152 this.model.destroy(); 153 this.remove(); 154 } 155 }); 156 })(); 157 158 159 /** 160 * wp.customize.HeaderTool.ChoiceListView 161 * 162 * A container for ChoiceViews. These choices should be of one same type: 163 * user-uploaded headers or theme-defined ones. 164 * 165 * Takes a wp.customize.HeaderTool.ChoiceList. 166 * 167 * @constructor 168 * @augments Backbone.View 169 */ 170 api.HeaderTool.ChoiceListView = Backbone.View.extend({ 171 slimScrollOptions: { 172 disableFadeOut: true, 173 allowPageScroll: true, 174 height: 'auto' 175 }, 176 177 initialize: function() { 178 this.listenTo(this.collection, 'add', this.addOne); 179 this.listenTo(this.collection, 'remove', this.render); 180 this.listenTo(this.collection, 'sort', this.render); 181 this.listenTo(this.collection, 'change:hidden', this.toggleTitle); 182 this.listenTo(this.collection, 'change:hidden', this.setMaxListHeight); 183 this.render(); 184 }, 185 186 render: function() { 187 this.$el.empty(); 188 this.collection.each(this.addOne, this); 189 this.toggleTitle(); 190 if (this.$el.parents().hasClass('uploaded')) { 191 this.setMaxListHeight(); 192 } 193 }, 194 195 setMaxListHeight: function() { 196 if (this.$el.parents().hasClass('uploaded')) { 197 var uploaded = this.$el.parents('.uploaded'), 198 height = this.maxListHeight(); 199 200 uploaded.height(height); 201 this.$el.slimScroll(this.slimScrollOptions); 202 } 203 }, 204 205 maxListHeight: function() { 206 var shown = this.collection.shown(), 207 imgsHeight = shown.reduce( function(memo, img, index) { 208 var imgMargin = (shown.length - 1) === index ? 0 : 9, 209 height = (260 / img.get('header').width) * img.get('header').height; 210 211 return memo + height + 5 + imgMargin; 212 }, 0); 213 return Math.min( Math.ceil(imgsHeight), 180 ); 214 }, 215 216 addOne: function(choice) { 217 var view; 218 choice.set({ collection: this.collection }); 219 view = new api.HeaderTool.ChoiceView({ model: choice }); 220 this.$el.append(view.render().el); 221 }, 222 223 toggleTitle: function() { 224 var title = this.$el.parents().prev('.customize-control-title'); 225 if (this.collection.shouldHideTitle()) 226 title.hide(); 227 else 228 title.show(); 229 } 230 }); 231 232 233 /** 234 * wp.customize.HeaderTool.CombinedList 235 * 236 * Aggregates wp.customize.HeaderTool.ChoiceList collections (or any 237 * Backbone object, really) and acts as a bus to feed them events. 238 * 239 * @constructor 240 * @augments Backbone.View 241 */ 242 api.HeaderTool.CombinedList = Backbone.View.extend({ 243 initialize: function(collections) { 244 this.collections = collections; 245 this.on('all', this.propagate, this); 246 }, 247 propagate: function(event, arg) { 248 _.each(this.collections, function(collection) { 249 collection.trigger(event, arg); 250 }); 251 }, 252 }); 253 254 })( jQuery, this.wp, _ ); -
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 fde8561..5529513 100644
class WP_Customize_Background_Image_Control extends WP_Customize_Image_Control { 691 691 } 692 692 } 693 693 694 /** 695 * Customize Header Image Control Class 696 * 697 * @package WordPress 698 * @subpackage Customize 699 * @since 3.4.0 700 */ 701 class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control { 702 /** 703 * The processed default headers. 704 * @since 3.4.2 705 * @var array 706 */ 707 protected $default_headers; 708 709 /** 710 * The uploaded headers. 711 * @since 3.4.2 712 * @var array 713 */ 714 protected $uploaded_headers; 694 class WP_Customize_Header_Image_Control extends WP_Customize_Control { 695 public $type = 'header'; 715 696 716 /**717 * Constructor.718 *719 * @since 3.4.0720 * @uses WP_Customize_Image_Control::__construct()721 * @uses WP_Customize_Image_Control::add_tab()722 *723 * @param WP_Customize_Manager $manager724 */725 697 public function __construct( $manager ) { 726 698 parent::__construct( $manager, 'header_image', array( 727 699 'label' => __( 'Header Image' ), … … class WP_Customize_Header_Image_Control extends WP_Customize_Image_Control { 733 705 'context' => 'custom-header', 734 706 'removed' => 'remove-header', 735 707 'get_url' => 'get_header_image', 736 'statuses' => array( 737 '' => __('Default'), 738 'remove-header' => __('No Image'), 739 'random-default-image' => __('Random Default Image'), 740 'random-uploaded-image' => __('Random Uploaded Image'), 708 ) ); 709 710 } 711 712 public function to_json() { 713 parent::to_json(); 714 } 715 716 public function enqueue() { 717 wp_enqueue_media(); 718 wp_enqueue_script( 'customize-header-views' ); 719 720 $this->prepare_control(); 721 722 wp_localize_script( 'customize-header-views', '_wpCustomizeHeader', array( 723 'data' => array( 724 'width' => absint( get_theme_support( 'custom-header', 'width' ) ), 725 'height' => absint( get_theme_support( 'custom-header', 'height' ) ), 726 'flex-width' => absint( get_theme_support( 'custom-header', 'flex-width' ) ), 727 'flex-height' => absint( get_theme_support( 'custom-header', 'flex-height' ) ), 728 'currentImgSrc' => $this->get_current_image_src(), 729 ), 730 'nonces' => array( 731 'add' => wp_create_nonce( 'header-add' ), 732 'remove' => wp_create_nonce( 'header-remove' ), 733 ), 734 'l10n' => array( 735 /* translators: header images uploaded by user */ 736 'uploaded' => __( 'uploaded' ), 737 /* translators: header images suggested by the current theme */ 738 'default' => __( 'suggested' ) 739 ), 740 'uploads' => $this->uploaded_headers, 741 'defaults' => $this->default_headers 742 ) ); 743 744 parent::enqueue(); 745 } 746 747 public function get_default_header_images() { 748 global $custom_image_header; 749 750 // Get *the* default image if there is one 751 $default = get_theme_support( 'custom-header', 'default-image' ); 752 753 if ( ! $default ) // If not, 754 return $custom_image_header->default_headers; // easy peasy. 755 756 $default = sprintf( $default, 757 get_template_directory_uri(), 758 get_stylesheet_directory_uri() ); 759 760 $header_images = array(); 761 $already_has_default = false; 762 763 // Get the whole set of default images 764 $default_header_images = $custom_image_header->default_headers; 765 foreach ( $default_header_images as $k => $h ) { 766 if ( $h['url'] == $default ) { 767 $already_has_default = true; 768 break; 769 } 770 } 771 772 // If *the one true image* isn't included in the default set, add it in 773 // first position 774 if ( ! $already_has_default ) { 775 $header_images['default'] = array( 776 'url' => $default, 777 'thumbnail_url' => $default, 778 'description' => 'Default' 779 ); 780 } 781 782 // The rest of the set comes after 783 $header_images = array_merge( $header_images, $default_header_images ); 784 785 return $header_images; 786 } 787 788 public function get_uploaded_header_images() { 789 $key = '_wp_attachment_custom_header_last_used_' . get_stylesheet(); 790 $header_images = array(); 791 792 $headers_not_dated = get_posts( array( 793 'post_type' => 'attachment', 794 'meta_key' => '_wp_attachment_is_custom_header', 795 'meta_value' => get_option('stylesheet'), 796 'orderby' => 'none', 797 'nopaging' => true, 798 'meta_query' => array( 799 array( 800 'key' => '_wp_attachment_is_custom_header', 801 'value' => get_option( 'stylesheet' ), 802 'compare' => 'LIKE' 803 ), 804 array( 805 'key' => $key, 806 'value' => 'this string must not be empty', 807 'compare' => 'NOT EXISTS' 808 ), 741 809 ) 742 810 ) ); 743 811 744 // Remove the upload tab. 745 $this->remove_tab( 'upload-new' ); 812 $headers_dated = get_posts( array( 813 'post_type' => 'attachment', 814 'meta_key' => $key, 815 'orderby' => 'meta_value_num', 816 'order' => 'DESC', 817 'nopaging' => true, 818 'meta_query' => array( 819 array( 820 'key' => '_wp_attachment_is_custom_header', 821 'value' => get_option( 'stylesheet' ), 822 'compare' => 'LIKE' 823 ), 824 ), 825 ) ); 826 827 $limit = apply_filters( 'custom_header_uploaded_limit', 15 ); 828 $headers = array_merge( $headers_dated, $headers_not_dated ); 829 $headers = array_slice( $headers, 0, $limit ); 830 831 foreach ( (array) $headers as $header ) { 832 $url = esc_url_raw( $header->guid ); 833 $header_data = wp_get_attachment_metadata( $header->ID ); 834 $timestamp = get_post_meta( $header->ID, 835 '_wp_attachment_custom_header_last_used_' . get_stylesheet(), 836 true ); 837 838 $h = array( 839 'attachment_id' => $header->ID, 840 'url' => $url, 841 'thumbnail_url' => $url, 842 'timestamp' => $timestamp ? $timestamp : 0, 843 ); 844 845 if ( isset( $header_data['width'] ) ) 846 $h['width'] = $header_data['width']; 847 if ( isset( $header_data['height'] ) ) 848 $h['height'] = $header_data['height']; 849 850 $header_images[] = $h; 851 } 852 853 return $header_images; 746 854 } 747 855 748 /**749 * Prepares the control.750 *751 * If no tabs exist, removes the control from the manager.752 *753 * @since 3.4.2754 */755 856 public function prepare_control() { 756 857 global $custom_image_header; 757 858 if ( empty( $custom_image_header ) ) 758 return parent::prepare_control();859 return; 759 860 760 861 // Process default headers and uploaded headers. 761 862 $custom_image_header->process_default_headers(); 762 $this->default_headers = $custom_image_header->default_headers; 763 $this->uploaded_headers = get_uploaded_header_images(); 863 $this->default_headers = $this->get_default_header_images(); 864 $this->uploaded_headers = $this->get_uploaded_header_images(); 865 } 764 866 765 if ( $this->default_headers ) 766 $this->add_tab( 'default', __('Default'), array( $this, 'tab_default_headers' ) ); 867 function print_header_image_template() { 868 ?> 869 <script type="text/template" id="tmpl-header-choice"> 870 <% if (random) { %> 871 872 <div class="placeholder random"> 873 <div class="inner"> 874 <span><span class="dice">⚄</span> 875 <?php /* translators: "nImages" is a number, "type" is either "uploaded" or "suggested" */ ?> 876 <?php _e( 'Randomize <%- nImages %> <%- type %> headers' ); ?> 877 </span> 878 </div> 879 </div> 767 880 768 if ( ! $this->uploaded_headers ) 769 $this->remove_tab( 'uploaded' ); 881 <% } else { %> 770 882 771 return parent::prepare_control(); 772 } 883 <% if (type == 'uploaded') { %> 884 <a href="#" class="close">X</a> 885 <% } %> 773 886 774 /** 775 * @since 3.4.0 776 * 777 * @param mixed $choice Which header image to select. (@see Custom_Image_Header::get_header_image() ) 778 * @param array $header 779 */ 780 public function print_header_image( $choice, $header ) { 781 $header['url'] = set_url_scheme( $header['url'] ); 782 $header['thumbnail_url'] = set_url_scheme( $header['thumbnail_url'] ); 887 <a href="#" class="choice thumbnail %>" 888 data-customize-image-value="<%- header.url %>" 889 data-customize-header-image-data="<%- JSON.stringify(header) %>"> 890 <img src="<%- header.thumbnail_url %>"> 891 </a> 783 892 784 $header_image_data = array( 'choice' => $choice ); 785 foreach ( array( 'attachment_id', 'width', 'height', 'url', 'thumbnail_url' ) as $key ) { 786 if ( isset( $header[ $key ] ) ) 787 $header_image_data[ $key ] = $header[ $key ]; 788 } 893 <% } %> 894 </script> 789 895 896 <script type="text/template" id="tmpl-header-current"> 897 <% if (choice) { %> 898 <% if (random) { %> 790 899 791 ?> 792 <a href="#" class="thumbnail" 793 data-customize-image-value="<?php echo esc_url( $header['url'] ); ?>" 794 data-customize-header-image-data="<?php echo esc_attr( json_encode( $header_image_data ) ); ?>"> 795 <img src="<?php echo esc_url( $header['thumbnail_url'] ); ?>" /> 796 </a> 900 <div class="placeholder"> 901 <div class="inner"> 902 <span><span class="dice">⚄</span> 903 <?php /* translators: "nImages" is a number, "type" is either "uploaded" or "suggested" */ ?> 904 <?php _e( 'Randomizing <%- nImages %> <%- type %> headers' ); ?> 905 </span> 906 </div> 907 </div> 908 909 <% } else { %> 910 911 <img src="<%- header.thumbnail_url %>" /> 912 913 <% } %> 914 <% } else { %> 915 916 <div class="placeholder"> 917 <div class="inner"> 918 <span> 919 No image set. 920 </span> 921 </div> 922 </div> 923 924 <% } %> 925 </script> 797 926 <?php 798 927 } 799 928 800 /** 801 * @since 3.4.0 802 */ 803 public function tab_uploaded() { 804 ?><div class="uploaded-target"></div><?php 805 806 foreach ( $this->uploaded_headers as $choice => $header ) 807 $this->print_header_image( $choice, $header ); 929 public function get_current_image_src() { 930 $src = $this->value(); 931 if ( isset( $this->get_url ) ) { 932 $src = call_user_func( $this->get_url, $src ); 933 return $src; 934 } 935 return null; 808 936 } 809 937 810 /** 811 * @since 3.4.0 812 */ 813 public function tab_default_headers() { 814 foreach ( $this->default_headers as $choice => $header ) 815 $this->print_header_image( $choice, $header ); 938 public function render_content() { 939 $this->print_header_image_template(); 940 $visibility = $this->get_current_image_src() ? '' : ' style="display:none" '; 941 $width = absint( get_theme_support( 'custom-header', 'width' ) ); 942 $height = absint( get_theme_support( 'custom-header', 'height' ) ); 943 ?> 944 945 946 <div class="customize-control-content"> 947 <p class="customizer-section-intro"> 948 <?php _e( 'Personalize your blog with your own header image.' ); ?> 949 <?php 950 if ( $width && $height ) { 951 printf( __( 'While you can crop images to your liking after clicking <strong>%s</strong>, your theme recommends a header size of <strong>%dx%d</strong> pixels.' ), 952 _x( 'Add new', 'new image', 'custom-header' ), $width, $height ); 953 } else { 954 if ( $width ) 955 printf( __( 'While you can crop images to your liking after clicking <strong>%s</strong>, your theme recommends a header width of <strong>%d</strong> pixels.' ), 956 _x( 'Add new', 'new image', 'custom-header' ), $width ); 957 if ( $height ) 958 printf( __( 'While you can crop images to your liking after clicking <strong>%s</strong>, your theme recommends a header height of <strong>%d</strong> pixels.' ), 959 _x( 'Add new', 'new image', 'custom-header' ), $height ); 960 } 961 ?> 962 </p> 963 <div class="current"> 964 <span class="customize-control-title"> 965 <?php _e( 'Current header', 'custom-header' ); ?> 966 </span> 967 <div class="container"> 968 </div> 969 </div> 970 <div class="actions"> 971 <?php /* translators: Hide as in hide header image via the Customizer */ ?> 972 <a href="#" <?php echo $visibility ?> class="button remove"><?php _e( 'Hide', 'custom-header' ); ?></a> 973 <?php /* translators: New as in add new header image via the Customizer */ ?> 974 <a href="#" class="button new"><?php _ex( 'Add new', 'new image', 'custom-header' ); ?></a> 975 <div style="clear:both"></div> 976 </div> 977 <div class="choices"> 978 <span class="customize-control-title header-previously-uploaded"> 979 <?php _e( 'Previously uploaded', 'custom-header' ); ?> 980 </span> 981 <div class="uploaded"> 982 <div class="list"> 983 </div> 984 </div> 985 <span class="customize-control-title header-default"> 986 <?php _e( 'Suggested', 'custom-header' ); ?> 987 </span> 988 <div class="default"> 989 <div class="list"> 990 </div> 991 </div> 992 </div> 993 </div> 994 <?php 816 995 } 817 } 818 No newline at end of file 996 997 } -
new file src/wp-includes/js/jquery/jquery.slimscroll.js
diff --git src/wp-includes/js/jquery/jquery.slimscroll.js src/wp-includes/js/jquery/jquery.slimscroll.js new file mode 100644 index 0000000..8f813ee
- + 1 /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) 2 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 * 5 * Version: 1.3.2 6 * 7 */ 8 (function($) { 9 10 jQuery.fn.extend({ 11 slimScroll: function(options) { 12 13 var defaults = { 14 15 // width in pixels of the visible scroll area 16 width : 'auto', 17 18 // height in pixels of the visible scroll area 19 height : '250px', 20 21 // width in pixels of the scrollbar and rail 22 size : '7px', 23 24 // scrollbar color, accepts any hex/color value 25 color: '#000', 26 27 // scrollbar position - left/right 28 position : 'right', 29 30 // distance in pixels between the side edge and the scrollbar 31 distance : '1px', 32 33 // default scroll position on load - top / bottom / $('selector') 34 start : 'top', 35 36 // sets scrollbar opacity 37 opacity : .4, 38 39 // enables always-on mode for the scrollbar 40 alwaysVisible : false, 41 42 // check if we should hide the scrollbar when user is hovering over 43 disableFadeOut : false, 44 45 // sets visibility of the rail 46 railVisible : false, 47 48 // sets rail color 49 railColor : '#333', 50 51 // sets rail opacity 52 railOpacity : .2, 53 54 // whether we should use jQuery UI Draggable to enable bar dragging 55 railDraggable : true, 56 57 // defautlt CSS class of the slimscroll rail 58 railClass : 'slimScrollRail', 59 60 // defautlt CSS class of the slimscroll bar 61 barClass : 'slimScrollBar', 62 63 // defautlt CSS class of the slimscroll wrapper 64 wrapperClass : 'slimScrollDiv', 65 66 // check if mousewheel should scroll the window if we reach top/bottom 67 allowPageScroll : false, 68 69 // scroll amount applied to each mouse wheel step 70 wheelStep : 20, 71 72 // scroll amount applied when user is using gestures 73 touchScrollStep : 200, 74 75 // sets border radius 76 borderRadius: '7px', 77 78 // sets border radius of the rail 79 railBorderRadius : '7px' 80 }; 81 82 var o = $.extend(defaults, options); 83 84 // do it for every element that matches selector 85 this.each(function(){ 86 87 var isOverPanel, isOverBar, isDragg, queueHide, touchDif, 88 barHeight, percentScroll, lastScroll, 89 divS = '<div></div>', 90 minBarHeight = 30, 91 releaseScroll = false; 92 93 // used in event handlers and for better minification 94 var me = $(this); 95 96 // ensure we are not binding it again 97 if (me.parent().hasClass(o.wrapperClass)) 98 { 99 // start from last bar position 100 var offset = me.scrollTop(); 101 102 // find bar and rail 103 bar = me.parent().find('.' + o.barClass); 104 rail = me.parent().find('.' + o.railClass); 105 106 getBarHeight(); 107 108 // check if we should scroll existing instance 109 if ($.isPlainObject(options)) 110 { 111 // Pass height: auto to an existing slimscroll object to force a resize after contents have changed 112 if ( 'height' in options && options.height == 'auto' ) { 113 me.parent().css('height', 'auto'); 114 me.css('height', 'auto'); 115 var height = me.parent().parent().height(); 116 me.parent().css('height', height); 117 me.css('height', height); 118 } 119 120 if ('scrollTo' in options) 121 { 122 // jump to a static point 123 offset = parseInt(o.scrollTo); 124 } 125 else if ('scrollBy' in options) 126 { 127 // jump by value pixels 128 offset += parseInt(o.scrollBy); 129 } 130 else if ('destroy' in options) 131 { 132 // remove slimscroll elements 133 bar.remove(); 134 rail.remove(); 135 me.unwrap(); 136 return; 137 } 138 139 // scroll content by the given offset 140 scrollContent(offset, false, true); 141 } 142 143 return; 144 } 145 146 // optionally set height to the parent's height 147 o.height = (options.height == 'auto') ? me.parent().height() : options.height; 148 149 // wrap content 150 var wrapper = $(divS) 151 .addClass(o.wrapperClass) 152 .css({ 153 position: 'relative', 154 overflow: 'hidden', 155 width: o.width, 156 height: o.height 157 }); 158 159 // update style for the div 160 me.css({ 161 overflow: 'hidden', 162 width: o.width, 163 height: o.height 164 }); 165 166 // create scrollbar rail 167 var rail = $(divS) 168 .addClass(o.railClass) 169 .css({ 170 width: o.size, 171 height: '100%', 172 position: 'absolute', 173 top: 0, 174 display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none', 175 'border-radius': o.railBorderRadius, 176 background: o.railColor, 177 opacity: o.railOpacity, 178 zIndex: 90 179 }); 180 181 // create scrollbar 182 var bar = $(divS) 183 .addClass(o.barClass) 184 .css({ 185 background: o.color, 186 width: o.size, 187 position: 'absolute', 188 top: 0, 189 opacity: o.opacity, 190 display: o.alwaysVisible ? 'block' : 'none', 191 'border-radius' : o.borderRadius, 192 BorderRadius: o.borderRadius, 193 MozBorderRadius: o.borderRadius, 194 WebkitBorderRadius: o.borderRadius, 195 zIndex: 99 196 }); 197 198 // set position 199 var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance }; 200 rail.css(posCss); 201 bar.css(posCss); 202 203 // wrap it 204 me.wrap(wrapper); 205 206 // append to parent div 207 me.parent().append(bar); 208 me.parent().append(rail); 209 210 // make it draggable and no longer dependent on the jqueryUI 211 if (o.railDraggable){ 212 bar.bind("mousedown", function(e) { 213 var $doc = $(document); 214 isDragg = true; 215 t = parseFloat(bar.css('top')); 216 pageY = e.pageY; 217 218 $doc.bind("mousemove.slimscroll", function(e){ 219 currTop = t + e.pageY - pageY; 220 bar.css('top', currTop); 221 scrollContent(0, bar.position().top, false);// scroll content 222 }); 223 224 $doc.bind("mouseup.slimscroll", function(e) { 225 isDragg = false;hideBar(); 226 $doc.unbind('.slimscroll'); 227 }); 228 return false; 229 }).bind("selectstart.slimscroll", function(e){ 230 e.stopPropagation(); 231 e.preventDefault(); 232 return false; 233 }); 234 } 235 236 // on rail over 237 rail.hover(function(){ 238 showBar(); 239 }, function(){ 240 hideBar(); 241 }); 242 243 // on bar over 244 bar.hover(function(){ 245 isOverBar = true; 246 }, function(){ 247 isOverBar = false; 248 }); 249 250 // show on parent mouseover 251 me.hover(function(){ 252 isOverPanel = true; 253 showBar(); 254 hideBar(); 255 }, function(){ 256 isOverPanel = false; 257 hideBar(); 258 }); 259 260 // support for mobile 261 me.bind('touchstart', function(e,b){ 262 if (e.originalEvent.touches.length) 263 { 264 // record where touch started 265 touchDif = e.originalEvent.touches[0].pageY; 266 } 267 }); 268 269 me.bind('touchmove', function(e){ 270 // prevent scrolling the page if necessary 271 if(!releaseScroll) 272 { 273 e.originalEvent.preventDefault(); 274 } 275 if (e.originalEvent.touches.length) 276 { 277 // see how far user swiped 278 var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep; 279 // scroll content 280 scrollContent(diff, true); 281 touchDif = e.originalEvent.touches[0].pageY; 282 } 283 }); 284 285 // set up initial height 286 getBarHeight(); 287 288 // check start position 289 if (o.start === 'bottom') 290 { 291 // scroll content to bottom 292 bar.css({ top: me.outerHeight() - bar.outerHeight() }); 293 scrollContent(0, true); 294 } 295 else if (o.start !== 'top') 296 { 297 // assume jQuery selector 298 scrollContent($(o.start).position().top, null, true); 299 300 // make sure bar stays hidden 301 if (!o.alwaysVisible) { bar.hide(); } 302 } 303 304 // attach scroll events 305 attachWheel(); 306 307 function _onWheel(e) 308 { 309 // use mouse wheel only when mouse is over 310 if (!isOverPanel) { return; } 311 312 var e = e || window.event; 313 314 var delta = 0; 315 if (e.wheelDelta) { delta = -e.wheelDelta/120; } 316 if (e.detail) { delta = e.detail / 3; } 317 318 var target = e.target || e.srcTarget || e.srcElement; 319 if ($(target).closest('.' + o.wrapperClass).is(me.parent())) { 320 // scroll content 321 scrollContent(delta, true); 322 } 323 324 // stop window scroll 325 if (e.preventDefault && !releaseScroll) { e.preventDefault(); } 326 if (!releaseScroll) { e.returnValue = false; } 327 } 328 329 function scrollContent(y, isWheel, isJump) 330 { 331 releaseScroll = false; 332 var delta = y; 333 var maxTop = me.outerHeight() - bar.outerHeight(); 334 335 if (isWheel) 336 { 337 // move bar with mouse wheel 338 delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight(); 339 340 // move bar, make sure it doesn't go out 341 delta = Math.min(Math.max(delta, 0), maxTop); 342 343 // if scrolling down, make sure a fractional change to the 344 // scroll position isn't rounded away when the scrollbar's CSS is set 345 // this flooring of delta would happened automatically when 346 // bar.css is set below, but we floor here for clarity 347 delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta); 348 349 // scroll the scrollbar 350 bar.css({ top: delta + 'px' }); 351 } 352 353 // calculate actual scroll amount 354 percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight()); 355 delta = percentScroll * (me[0].scrollHeight - me.outerHeight()); 356 357 if (isJump) 358 { 359 delta = y; 360 var offsetTop = delta / me[0].scrollHeight * me.outerHeight(); 361 offsetTop = Math.min(Math.max(offsetTop, 0), maxTop); 362 bar.css({ top: offsetTop + 'px' }); 363 } 364 365 // scroll content 366 me.scrollTop(delta); 367 368 // fire scrolling event 369 me.trigger('slimscrolling', ~~delta); 370 371 // ensure bar is visible 372 showBar(); 373 374 // trigger hide when scroll is stopped 375 hideBar(); 376 } 377 378 function attachWheel() 379 { 380 if (window.addEventListener) 381 { 382 this.addEventListener('DOMMouseScroll', _onWheel, false ); 383 this.addEventListener('mousewheel', _onWheel, false ); 384 } 385 else 386 { 387 document.attachEvent("onmousewheel", _onWheel) 388 } 389 } 390 391 function getBarHeight() 392 { 393 // calculate scrollbar height and make sure it is not too small 394 barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight); 395 bar.css({ height: barHeight + 'px' }); 396 397 // hide scrollbar if content is not long enough 398 var display = barHeight == me.outerHeight() ? 'none' : 'block'; 399 bar.css({ display: display }); 400 } 401 402 function showBar() 403 { 404 // recalculate bar height 405 getBarHeight(); 406 clearTimeout(queueHide); 407 408 // when bar reached top or bottom 409 if (percentScroll == ~~percentScroll) 410 { 411 //release wheel 412 releaseScroll = o.allowPageScroll; 413 414 // publish approporiate event 415 if (lastScroll != percentScroll) 416 { 417 var msg = (~~percentScroll == 0) ? 'top' : 'bottom'; 418 me.trigger('slimscroll', msg); 419 } 420 } 421 else 422 { 423 releaseScroll = false; 424 } 425 lastScroll = percentScroll; 426 427 // show only when required 428 if(barHeight >= me.outerHeight()) { 429 //allow window scroll 430 releaseScroll = true; 431 return; 432 } 433 bar.stop(true,true).fadeIn('fast'); 434 if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); } 435 } 436 437 function hideBar() 438 { 439 // only hide when options allow it 440 if (!o.alwaysVisible) 441 { 442 queueHide = setTimeout(function(){ 443 if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg) 444 { 445 bar.fadeOut('slow'); 446 rail.fadeOut('slow'); 447 } 448 }, 1000); 449 } 450 } 451 452 }); 453 454 // maintain chainability 455 return this; 456 } 457 }); 458 459 jQuery.fn.extend({ 460 slimscroll: jQuery.fn.slimScroll 461 }); 462 463 })(jQuery); -
new file src/wp-includes/js/jquery/jquery.slimscroll.min.js
diff --git src/wp-includes/js/jquery/jquery.slimscroll.min.js src/wp-includes/js/jquery/jquery.slimscroll.min.js new file mode 100644 index 0000000..09785e7
- + 1 /*! Copyright (c) 2011 Piotr Rochala (http://rocha.la) 2 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) 3 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. 4 * 5 * Version: 1.3.2 6 * 7 */ 8 (function(f){jQuery.fn.extend({slimScroll:function(g){var a=f.extend({width:"auto",height:"250px",size:"7px",color:"#000",position:"right",distance:"1px",start:"top",opacity:0.4,alwaysVisible:!1,disableFadeOut:!1,railVisible:!1,railColor:"#333",railOpacity:0.2,railDraggable:!0,railClass:"slimScrollRail",barClass:"slimScrollBar",wrapperClass:"slimScrollDiv",allowPageScroll:!1,wheelStep:20,touchScrollStep:200,borderRadius:"7px",railBorderRadius:"7px"},g);this.each(function(){function u(d){if(r){d=d|| 9 window.event;var c=0;d.wheelDelta&&(c=-d.wheelDelta/120);d.detail&&(c=d.detail/3);f(d.target||d.srcTarget||d.srcElement).closest("."+a.wrapperClass).is(b.parent())&&m(c,!0);d.preventDefault&&!k&&d.preventDefault();k||(d.returnValue=!1)}}function m(d,f,g){k=!1;var e=d,h=b.outerHeight()-c.outerHeight();f&&(e=parseInt(c.css("top"))+d*parseInt(a.wheelStep)/100*c.outerHeight(),e=Math.min(Math.max(e,0),h),e=0<d?Math.ceil(e):Math.floor(e),c.css({top:e+"px"}));l=parseInt(c.css("top"))/(b.outerHeight()-c.outerHeight()); 10 e=l*(b[0].scrollHeight-b.outerHeight());g&&(e=d,d=e/b[0].scrollHeight*b.outerHeight(),d=Math.min(Math.max(d,0),h),c.css({top:d+"px"}));b.scrollTop(e);b.trigger("slimscrolling",~~e);v();p()}function C(){window.addEventListener?(this.addEventListener("DOMMouseScroll",u,!1),this.addEventListener("mousewheel",u,!1)):document.attachEvent("onmousewheel",u)}function w(){s=Math.max(b.outerHeight()/b[0].scrollHeight*b.outerHeight(),D);c.css({height:s+"px"});var a=s==b.outerHeight()?"none":"block";c.css({display:a})} 11 function v(){w();clearTimeout(A);l==~~l?(k=a.allowPageScroll,B!=l&&b.trigger("slimscroll",0==~~l?"top":"bottom")):k=!1;B=l;s>=b.outerHeight()?k=!0:(c.stop(!0,!0).fadeIn("fast"),a.railVisible&&h.stop(!0,!0).fadeIn("fast"))}function p(){a.alwaysVisible||(A=setTimeout(function(){a.disableFadeOut&&r||x||y||(c.fadeOut("slow"),h.fadeOut("slow"))},1E3))}var r,x,y,A,z,s,l,B,D=30,k=!1,b=f(this);if(b.parent().hasClass(a.wrapperClass)){var n=b.scrollTop(),c=b.parent().find("."+a.barClass),h=b.parent().find("."+ 12 a.railClass);w();if(f.isPlainObject(g)){if("height"in g&&"auto"==g.height){b.parent().css("height","auto");b.css("height","auto");var q=b.parent().parent().height();b.parent().css("height",q);b.css("height",q)}if("scrollTo"in g)n=parseInt(a.scrollTo);else if("scrollBy"in g)n+=parseInt(a.scrollBy);else if("destroy"in g){c.remove();h.remove();b.unwrap();return}m(n,!1,!0)}}else{a.height="auto"==g.height?b.parent().height():g.height;n=f("<div></div>").addClass(a.wrapperClass).css({position:"relative", 13 overflow:"hidden",width:a.width,height:a.height});b.css({overflow:"hidden",width:a.width,height:a.height});var h=f("<div></div>").addClass(a.railClass).css({width:a.size,height:"100%",position:"absolute",top:0,display:a.alwaysVisible&&a.railVisible?"block":"none","border-radius":a.railBorderRadius,background:a.railColor,opacity:a.railOpacity,zIndex:90}),c=f("<div></div>").addClass(a.barClass).css({background:a.color,width:a.size,position:"absolute",top:0,opacity:a.opacity,display:a.alwaysVisible? 14 "block":"none","border-radius":a.borderRadius,BorderRadius:a.borderRadius,MozBorderRadius:a.borderRadius,WebkitBorderRadius:a.borderRadius,zIndex:99}),q="right"==a.position?{right:a.distance}:{left:a.distance};h.css(q);c.css(q);b.wrap(n);b.parent().append(c);b.parent().append(h);a.railDraggable&&c.bind("mousedown",function(a){var b=f(document);y=!0;t=parseFloat(c.css("top"));pageY=a.pageY;b.bind("mousemove.slimscroll",function(a){currTop=t+a.pageY-pageY;c.css("top",currTop);m(0,c.position().top,!1)}); 15 b.bind("mouseup.slimscroll",function(a){y=!1;p();b.unbind(".slimscroll")});return!1}).bind("selectstart.slimscroll",function(a){a.stopPropagation();a.preventDefault();return!1});h.hover(function(){v()},function(){p()});c.hover(function(){x=!0},function(){x=!1});b.hover(function(){r=!0;v();p()},function(){r=!1;p()});b.bind("touchstart",function(a,b){a.originalEvent.touches.length&&(z=a.originalEvent.touches[0].pageY)});b.bind("touchmove",function(b){k||b.originalEvent.preventDefault();b.originalEvent.touches.length&& 16 (m((z-b.originalEvent.touches[0].pageY)/a.touchScrollStep,!0),z=b.originalEvent.touches[0].pageY)});w();"bottom"===a.start?(c.css({top:b.outerHeight()-c.outerHeight()}),m(0,!0)):"top"!==a.start&&(m(f(a.start).position().top,null,!0),a.alwaysVisible||c.hide());C()}});return this}});jQuery.fn.extend({slimscroll:jQuery.fn.slimScroll})})(jQuery); -
src/wp-includes/script-loader.php
diff --git src/wp-includes/script-loader.php src/wp-includes/script-loader.php index 98e4a87..945f192 100644
function wp_default_scripts( &$scripts ) { 198 198 $scripts->add( 'jquery-table-hotkeys', "/wp-includes/js/jquery/jquery.table-hotkeys$suffix.js", array('jquery', 'jquery-hotkeys'), false, 1 ); 199 199 $scripts->add( 'jquery-touch-punch', "/wp-includes/js/jquery/jquery.ui.touch-punch.js", array('jquery-ui-widget', 'jquery-ui-mouse'), '0.2.2', 1 ); 200 200 $scripts->add( 'jquery-masonry', "/wp-includes/js/jquery/jquery.masonry.min.js", array('jquery'), '2.1.05', 1 ); 201 $scripts->add( 'jquery-slimscroll', "/wp-includes/js/jquery/jquery.slimscroll$suffix.js", array( 'jquery' ), '1.3.2', 1 ); 201 202 202 203 $scripts->add( 'thickbox', "/wp-includes/js/thickbox/thickbox.js", array('jquery'), '3.1-20121105', 1 ); 203 204 did_action( 'init' ) && $scripts->localize( 'thickbox', 'thickboxL10n', array( … … function wp_default_scripts( &$scripts ) { 375 376 'allowedFiles' => __( 'Allowed Files' ), 376 377 ) ); 377 378 379 $scripts->add( 'customize-header-models', "/wp-admin/js/header-models.js", array( 'underscore', 'backbone' ), false, 1 ); 380 $scripts->add( 'customize-header-views', "/wp-admin/js/header-views.js", array( 'jquery', 'underscore', 'jquery-slimscroll', 'imgareaselect', 'customize-header-models' ), false, 1 ); 381 378 382 $scripts->add( 'accordion', "/wp-admin/js/accordion$suffix.js", array( 'jquery' ), false, 1 ); 379 383 380 384 $scripts->add( 'shortcode', "/wp-includes/js/shortcode$suffix.js", array( 'underscore' ), false, 1 ); … … function wp_default_styles( &$styles ) { 594 598 $styles->add( 'login', "/wp-admin/css/login$suffix.css", array( 'buttons', 'open-sans', 'dashicons' ) ); 595 599 $styles->add( 'install', "/wp-admin/css/install$suffix.css", array( 'buttons', 'open-sans' ) ); 596 600 $styles->add( 'wp-color-picker', "/wp-admin/css/color-picker$suffix.css" ); 597 $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie' ) );601 $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie', 'imgareaselect' ) ); 598 602 $styles->add( 'ie', "/wp-admin/css/ie$suffix.css" ); 599 603 600 604 $styles->add_data( 'ie', 'conditional', 'lte IE 7' );