Ticket #24409: 24409-01.patch
File 24409-01.patch, 19.4 KB (added by , 11 years ago) |
---|
-
src/wp-includes/js/media-models.js
diff --git src/wp-includes/js/media-models.js src/wp-includes/js/media-models.js index 569beec..e51e4d7 100644
2 2 window.wp = window.wp || {}; 3 3 4 4 (function($){ 5 var Attachment, Attachments, Query, compare, l10n, media;5 var Attachment, Attachments, Query, PostImage, compare, l10n, media; 6 6 7 7 /** 8 8 * wp.media( attributes ) … … window.wp = window.wp || {}; 30 30 frame = new MediaFrame.Select( attributes ); 31 31 } else if ( 'post' === attributes.frame && MediaFrame.Post ) { 32 32 frame = new MediaFrame.Post( attributes ); 33 } else if ( 'image' === attributes.frame && MediaFrame.ImageDetails ) { 34 frame = new MediaFrame.ImageDetails( attributes ); 33 35 } 34 36 35 37 delete attributes.frame; … … window.wp = window.wp || {}; 326 328 }); 327 329 328 330 /** 331 * wp.media.model.Attachment 332 * 333 * @constructor 334 * @augments Backbone.Model 335 * 336 **/ 337 PostImage = media.model.PostImage = Backbone.Model.extend({ 338 339 initialize: function( attributes ) { 340 this.attachment = false; 341 342 if ( attributes.attachment_id ) { 343 this.attachment = media.model.Attachment.get( attributes.attachment_id ); 344 this.dfd = this.attachment.fetch(); 345 this.listenTo( this.attachment, 'sync', this.setLinkTypeFromUrl ); 346 } 347 348 // keep url in sync with changes to the type of link 349 this.on( 'change:link', this.updateLinkUrl, this ); 350 this.on( 'change:size', this.updateSize, this ); 351 352 }, 353 354 setLinkTypeFromUrl: function() { 355 var linkUrl = this.get( 'linkUrl' ), 356 type; 357 358 if ( ! linkUrl ) { 359 this.set( 'link', 'none' ); 360 return; 361 } 362 363 // default to custom if there is a linkUrl 364 type = 'custom'; 365 366 if ( this.attachment ) { 367 if ( this.attachment.get( 'url' ) === linkUrl ) { 368 type = 'file'; 369 } else if ( this.attachment.get( 'link' ) === linkUrl ) { 370 type = 'post'; 371 } 372 } else { 373 if ( this.get( 'url' ) === linkUrl ) { 374 type = 'file'; 375 } 376 } 377 378 this.set( 'link', type ); 379 380 }, 381 382 383 updateLinkUrl: function() { 384 var link = this.get( 'link' ), 385 url; 386 387 switch( link ) { 388 case 'file': 389 if ( this.attachment ) { 390 url = this.attachment.get( 'url' ); 391 } else { 392 url = this.get( 'url' ); 393 } 394 this.set( 'linkUrl', url ); 395 break; 396 case 'post': 397 this.set( 'linkUrl', this.attachment.get( 'link' ) ); 398 break; 399 case 'none': 400 this.set( 'linkUrl', '' ); 401 break; 402 403 } 404 405 }, 406 407 updateSize: function() { 408 var size; 409 410 if ( ! this.attachment ) { 411 return; 412 } 413 414 size = this.attachment.get( 'sizes' )[ this.get( 'size' ) ]; 415 this.set( 'url', size.url ); 416 this.set( 'width', size.width ); 417 this.set( 'height', size.height ); 418 419 } 420 421 422 }); 423 424 /** 329 425 * wp.media.model.Attachments 330 426 * 331 427 * @constructor … … window.wp = window.wp || {}; 1111 1207 window.wp = null; 1112 1208 }); 1113 1209 1114 }(jQuery)); 1115 No newline at end of file 1210 }(jQuery)); -
src/wp-includes/js/media-views.js
diff --git src/wp-includes/js/media-views.js src/wp-includes/js/media-views.js index 07b49c9..fea8114 100644
980 980 } 981 981 }); 982 982 983 984 media.controller.ImageDetails = media.controller.State.extend({ 985 986 defaults: _.defaults({ 987 id: 'image-details', 988 filterable: 'uploaded', 989 multiple: false, 990 toolbar: 'image-details', 991 title: l10n.imageDetailsTitle, 992 content: 'image-details', 993 menu: 'image-details', 994 router: false, 995 attachment: false, 996 priority: 60, 997 editing: false, 998 syncSelection: false 999 }, media.controller.Library.prototype.defaults ), 1000 1001 // probably should have some notion of an embed model 1002 initialize: function( options ) { 1003 var attachment = false; 1004 this.props = new media.model.PostImage( options.metadata ); 1005 1006 media.controller.State.prototype.initialize.apply( this, arguments ); 1007 }, 1008 1009 activate: function() { 1010 media.controller.State.prototype.activate.apply( this, arguments ); 1011 }, 1012 1013 deactivate: function() { 1014 /** 1015 * call 'deactivate' directly on the parent class 1016 */ 1017 media.controller.State.prototype.deactivate.apply( this, arguments ); 1018 } 1019 1020 }); 1021 1022 /** 1023 * wp.media.controller.ReplaceImage 1024 * 1025 * Replace a selected single image 1026 * 1027 **/ 1028 media.controller.ReplaceImage = media.controller.Library.extend({ 1029 1030 1031 1032 }); 1033 983 1034 /** 984 1035 * wp.media.controller.Embed 985 1036 * … … 1923 1974 } 1924 1975 } 1925 1976 }) ); 1977 }, 1978 1979 }); 1980 1981 media.view.MediaFrame.ImageDetails = media.view.MediaFrame.Select.extend({ 1982 defaults: { 1983 id: 'image', 1984 url: '', 1985 menu: 'image-details', 1986 content: 'image-details', 1987 toolbar: 'image-details', 1988 type: 'link', 1989 title: l10n.imageDetailsTitle, 1990 priority: 120 1991 }, 1992 1993 bindHandlers: function() { 1994 media.view.MediaFrame.Select.prototype.bindHandlers.apply( this, arguments ); 1995 this.on( 'menu:create:image-details', this.createMenu, this ); 1996 this.on( 'content:render:image-details', this.renderImageDetailsContent, this ); 1997 this.on( 'menu:render:image-details', this.renderMenu, this ); 1998 this.on( 'toolbar:render:image-details', this.renderToolbar, this ); 1999 }, 2000 2001 createStates: function() { 2002 var options = this.options; 2003 this.states.add([ 2004 new media.controller.ImageDetails({ 2005 metadata: options.metadata, 2006 editable: false, 2007 menu: 'image-details' 2008 }), 2009 new media.controller.Library({ 2010 id: 'replace-image', 2011 library: media.query(), 2012 multiple: false, 2013 title: l10n.imageReplaceTitle, 2014 menu: 'image-details', 2015 priority: 80 2016 }) 2017 ]); 2018 }, 2019 2020 renderImageDetailsContent: function() { 2021 var view = new media.view.ImageDetails({ 2022 controller: this, 2023 model: this.state().props, 2024 attachment: this.state().props.attachment 2025 }).render(); 2026 2027 this.content.set( view ); 2028 2029 }, 2030 2031 renderMenu: function( view ) { 2032 var lastState = this.lastState(), 2033 previous = lastState && lastState.id, 2034 frame = this; 2035 2036 view.set({ 2037 cancel: { 2038 text: l10n.imageDetailsCancel, 2039 priority: 20, 2040 click: function() { 2041 if ( previous ) { 2042 frame.setState( previous ); 2043 } else { 2044 frame.close(); 2045 } 2046 } 2047 }, 2048 separateCancel: new media.View({ 2049 className: 'separator', 2050 priority: 40 2051 }) 2052 }); 2053 2054 }, 2055 2056 renderToolbar: function() { 2057 this.toolbar.set( new media.view.Toolbar({ 2058 controller: this, 2059 items: { 2060 update: { 2061 style: 'primary', 2062 text: l10n.update, 2063 priority: 80, 2064 2065 click: function() { 2066 var controller = this.controller, 2067 state = controller.state(); 2068 2069 controller.close(); 2070 2071 // not sure if we want to use wp.media.string.image which will create a shortcode or 2072 // perhaps wp.html.string to at least to build the <img /> 2073 2074 state.trigger( 'update', state.props.toJSON() ); 2075 2076 // Restore and reset the default state. 2077 controller.setState( controller.options.state ); 2078 controller.reset(); 2079 } 2080 } 2081 } 2082 }) ); 1926 2083 } 2084 2085 2086 1927 2087 }); 1928 2088 2089 1929 2090 /** 1930 2091 * wp.media.view.Modal 1931 2092 * … … 4932 5093 this.$('img').attr( 'src', this.model.get('url') ); 4933 5094 } 4934 5095 }); 4935 }(jQuery)); 4936 No newline at end of file 5096 5097 // maybe I should just avoid the inheritance 5098 media.view.ImageDetails = media.view.Settings.AttachmentDisplay.extend({ 5099 className: 'image-details', 5100 template: media.template('image-details'), 5101 5102 prepare: function() { 5103 var attachment = false; 5104 5105 if ( this.model.attachment ) { 5106 attachment = this.model.attachment.toJSON(); 5107 } 5108 return _.defaults({ 5109 model: this.model.toJSON(), 5110 attachment: attachment 5111 }, this.options ); 5112 }, 5113 5114 5115 render: function() { 5116 var self = this, 5117 args = arguments; 5118 if ( this.model.attachment && 'pending' === this.model.dfd.state() ) { 5119 // should instead show a spinner when the attachment is new and then add a listener that updates on change 5120 this.model.dfd.done( function() { 5121 media.view.Settings.AttachmentDisplay.prototype.render.apply( self, args ); 5122 } ); 5123 } else { 5124 media.view.Settings.AttachmentDisplay.prototype.render.apply( this, arguments ); 5125 } 5126 5127 5128 return this; 5129 } 5130 }); 5131 }(jQuery)); -
src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js
diff --git src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js src/wp-includes/js/tinymce/plugins/wpeditimage/plugin.js index 3f4ca10..e34e7e7 100644
tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 101 101 }); 102 102 } 103 103 104 function extractImageData( imageNode ) { 105 var classes, metadata, captionBlock, caption; 106 107 // default attributes 108 metadata = { 109 attachment_id: false, 110 url: false, 111 height: '', 112 width: '', 113 size: 'none', 114 caption: '', 115 alt: '', 116 align: 'none', 117 link: 'none', 118 linkUrl: '' 119 }; 120 121 metadata.url = editor.dom.getAttrib( imageNode, 'src' ); 122 metadata.alt = editor.dom.getAttrib( imageNode, 'alt' ); 123 metadata.width = parseInt( editor.dom.getAttrib( imageNode, 'width' ), 10 ); 124 metadata.height = parseInt( editor.dom.getAttrib( imageNode, 'height' ), 10 ); 125 126 //TODO: probably should capture attributes on both the <img /> and the <a /> so that they can be restored when the image and/or caption are updated 127 // maybe use getAttribs() 128 129 // extract meta data from classes (candidate for turning into a method) 130 classes = imageNode.className.split( ' ' ); 131 tinymce.each( classes, function( name ) { 132 133 if ( /^wp-image/.test( name ) ) { 134 metadata.attachment_id = parseInt( name.replace( 'wp-image-', '' ), 10 ); 135 } 136 137 if ( /^align/.test( name ) ) { 138 metadata.align = name.replace( 'align', '' ); 139 } 140 141 if ( /^size/.test( name ) ) { 142 metadata.size = name.replace( 'size-', '' ); 143 } 144 } ); 145 146 147 // extract caption 148 captionBlock = editor.dom.getParents( imageNode, '.wp-caption' ); 149 150 if ( captionBlock.length ) { 151 captionBlock = captionBlock[0]; 152 153 classes = captionBlock.className.split( ' ' ); 154 tinymce.each( classes, function( name ) { 155 if ( /^align/.test( name ) ) { 156 metadata.align = name.replace( 'align', '' ); 157 } 158 } ); 159 caption = editor.dom.select( 'dd.wp-caption-dd', captionBlock ); 160 if ( caption.length ) { 161 caption = caption[0]; 162 // need to do some more thinking about this 163 metadata.caption = editor.serializer.serialize( caption ) 164 .replace( /<br[^>]*>/g, '$&\n' ).replace( /^<p>/, '' ).replace( /<\/p>$/, '' ); 165 166 } 167 } 168 169 // extract linkTo 170 if ( imageNode.parentNode.nodeName === 'A' ) { 171 metadata.linkUrl = editor.dom.getAttrib( imageNode.parentNode, 'href' ); 172 } 173 174 return metadata; 175 176 } 177 178 function updateImage( imageNode, imageData ) { 179 var className, width, node, html, captionNode, nodeToReplace, uid; 180 181 if ( imageData.caption ) { 182 183 html = createImageAndLink( imageData, 'html' ); 184 185 width = imageData.width + 10; 186 className = 'align' + imageData.align; 187 188 //TODO: shouldn't add the id attribute if it isn't an attachment 189 190 // should create a new function for genrating the caption markup 191 html = '<dl id="'+ imageData.attachment_id +'" class="wp-caption '+ className +'" style="width: '+ width +'px">' + 192 '<dt class="wp-caption-dt">'+ html + '</dt><dd class="wp-caption-dd">'+ imageData.caption +'</dd></dl>'; 193 194 node = editor.dom.create( 'div', { 'class': 'mceTemp', draggable: 'true' }, html ); 195 } else { 196 node = createImageAndLink( imageData, 'node' ); 197 } 198 199 nodeToReplace = imageNode; 200 201 captionNode = editor.dom.getParent( imageNode, '.mceTemp' ); 202 203 if ( captionNode ) { 204 nodeToReplace = captionNode; 205 } else { 206 if ( imageNode.parentNode.nodeName === 'A' ) { 207 nodeToReplace = imageNode.parentNode; 208 } 209 } 210 // uniqueId isn't super exciting, so maybe we want to use something else 211 uid = editor.dom.uniqueId( 'wp_' ); 212 editor.dom.setAttrib( node, 'data-wp-replace-id', uid ); 213 editor.dom.replace( node, nodeToReplace ); 214 215 // find the updated node 216 node = editor.dom.select( '[data-wp-replace-id="' + uid + '"]' )[0]; 217 218 editor.dom.setAttrib( node, 'data-wp-replace-id', '' ); 219 220 if ( node.nodeName === 'IMG' ) { 221 editor.selection.select( node ); 222 } else { 223 editor.selection.select( editor.dom.select( 'img', node )[0] ); 224 } 225 editor.nodeChanged(); 226 227 } 228 229 function createImageAndLink( imageData, mode ) { 230 var classes = [], 231 props; 232 233 mode = mode ? mode : 'node'; 234 235 236 if ( ! imageData.caption ) { 237 classes.push( 'align' + imageData.align ); 238 } 239 240 if ( imageData.attachment_id ) { 241 classes.push( 'wp-image-' + imageData.attachment_id ); 242 if ( imageData.size ) { 243 classes.push( 'size-' + imageData.size ); 244 } 245 } 246 247 props = { 248 src: imageData.url, 249 width: imageData.width, 250 height: imageData.height, 251 alt: imageData.alt 252 }; 253 254 if ( classes.length ) { 255 props['class'] = classes.join( ' ' ); 256 } 257 258 if ( imageData.linkUrl ) { 259 if ( mode === 'node' ) { 260 return editor.dom.create( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) ); 261 } else if ( mode === 'html' ) { 262 return editor.dom.createHTML( 'a', { href: imageData.linkUrl }, editor.dom.createHTML( 'img', props ) ); 263 } 264 } else { 265 if ( mode === 'node' ) { 266 return editor.dom.create( 'img', props ); 267 } else if ( mode === 'html' ) { 268 return editor.dom.createHTML( 'img', props ); 269 } 270 271 } 272 } 273 104 274 editor.on( 'init', function() { 105 275 var dom = editor.dom; 106 276 … … tinymce.PluginManager.add( 'wpeditimage', function( editor ) { 452 622 } 453 623 }); 454 624 625 editor.on( 'mouseup', function( e ) { 626 var imageNode, frame; 627 if ( e.target.nodeName === 'IMG' && editor.dom.getAttrib( e.target, 'data-mce-selected' ) === '1' ) { 628 // Don't trigger on right-click 629 if ( e.button !== 2 ) { 630 631 if ( editor.dom.hasClass( e.target, 'mceItem' ) || '1' === editor.dom.getAttrib( e.target, 'data-mce-placeholder' ) ) { 632 return; 633 } 634 635 636 imageNode = e.target; 637 638 // file, post, custom, none 639 frame = wp.media({ 640 frame: 'image', 641 state: 'image-details', 642 multiple: false, 643 editing: true, 644 metadata: extractImageData( imageNode ) 645 } ); 646 647 // update the image when update is clicked in the media frame 648 frame.state('image-details').on( 'update', function( imageData ) { 649 editor.focus(); 650 updateImage( imageNode, imageData ); 651 } ); 652 653 frame.open(); 654 655 656 } 657 } 658 } ); 659 455 660 editor.wpSetImgCaption = function( content ) { 456 661 return parseShortcode( content ); 457 662 }; -
src/wp-includes/media-template.php
diff --git src/wp-includes/media-template.php src/wp-includes/media-template.php index 57d1c00..3e251b8 100644
function wp_print_media_templates() { 500 500 } 501 501 </style> 502 502 </script> 503 504 <script type="text/html" id="tmpl-image-details"> 505 <?php // reusing .media-embed to pick up the styles for now ?> 506 <div class="media-embed"> 507 <div class="embed-image-settings"> 508 <div class="thumbnail"> 509 <img src="{{ data.model.url }}" draggable="false" /> 510 </div> 511 512 <div class="url"> 513 <?php // might want to make the url editable if it isn't an attachment ?> 514 <input type="text" disabled="disabled" value="{{ data.model.url }}" /> 515 </div> 516 517 <?php 518 /** This filter is documented in wp-admin/includes/media.php */ 519 if ( ! apply_filters( 'disable_captions', '' ) ) : ?> 520 <label class="setting caption"> 521 <span><?php _e('Caption'); ?></span> 522 <textarea data-setting="caption">{{ data.model.caption }}</textarea> 523 </label> 524 <?php endif; ?> 525 526 <label class="setting alt-text"> 527 <span><?php _e('Alt Text'); ?></span> 528 <input type="text" data-setting="alt" value="{{ data.model.alt }}" /> 529 </label> 530 531 <div class="setting align"> 532 <span><?php _e('Align'); ?></span> 533 <div class="button-group button-large" data-setting="align"> 534 <button class="button" value="left"> 535 <?php esc_attr_e('Left'); ?> 536 </button> 537 <button class="button" value="center"> 538 <?php esc_attr_e('Center'); ?> 539 </button> 540 <button class="button" value="right"> 541 <?php esc_attr_e('Right'); ?> 542 </button> 543 <button class="button active" value="none"> 544 <?php esc_attr_e('None'); ?> 545 </button> 546 </div> 547 </div> 548 <div class="setting link-to"> 549 <span><?php _e('Link To'); ?></span> 550 551 <# if ( data.attachment ) { #> 552 <div class="button-group button-large" data-setting="link"> 553 <button class="button" value="file"> 554 <?php esc_attr_e('Media File'); ?> 555 </button> 556 <button class="button" value="post"> 557 <?php esc_attr_e('Attachment Page'); ?> 558 </button> 559 <button class="button" value="custom"> 560 <?php esc_attr_e('Custom URL'); ?> 561 </button> 562 <button class="button active" value="none"> 563 <?php esc_attr_e('None'); ?> 564 </button> 565 </div> 566 <input type="text" class="link-to-custom" data-setting="linkUrl" /> 567 568 <# } else { #> 569 <div class="button-group button-large" data-setting="link"> 570 <button class="button" value="file"> 571 <?php esc_attr_e('Image URL'); ?> 572 </button> 573 <button class="button" value="custom"> 574 <?php esc_attr_e('Custom URL'); ?> 575 </button> 576 <button class="button active" value="none"> 577 <?php esc_attr_e('None'); ?> 578 </button> 579 </div> 580 <input type="text" class="link-to-custom" data-setting="linkUrl" /> 581 582 <# } #> 583 584 585 <# if ( data.attachment ) { #> 586 <div class="setting size"> 587 <span><?php _e('Size'); ?></span> 588 <div class="button-group button-large" data-setting="size"> 589 <?php 590 /** This filter is documented in wp-admin/includes/media.php */ 591 $sizes = apply_filters( 'image_size_names_choose', array( 592 'thumbnail' => __('Thumbnail'), 593 'medium' => __('Medium'), 594 'large' => __('Large'), 595 'full' => __('Full Size'), 596 ) ); 597 598 foreach ( $sizes as $value => $name ) : ?> 599 <# 600 var size = data.attachment.sizes['<?php echo esc_js( $value ); ?>']; 601 if ( size ) { #> 602 <button class="button" value="<?php echo esc_attr( $value ); ?>"> 603 <?php echo esc_html( $name ); ?> 604 </button> 605 <# } #> 606 <?php endforeach; ?> 607 </div> 608 </div> 609 <# } #> 610 </div> 611 </div> 612 </div> 613 </script> 503 614 <?php 504 615 505 616 /** -
src/wp-includes/media.php
diff --git src/wp-includes/media.php src/wp-includes/media.php index 4ce006e..70bba6d 100644
function wp_enqueue_media( $args = array() ) { 1967 1967 'search' => __( 'Search' ), 1968 1968 'select' => __( 'Select' ), 1969 1969 'cancel' => __( 'Cancel' ), 1970 'update' => __( 'Update' ), 1970 1971 /* translators: This is a would-be plural string used in the media manager. 1971 1972 If there is not a word you can use in your language to avoid issues with the 1972 1973 lack of plural support here, turn it into "selected: %d" then translate it. … … function wp_enqueue_media( $args = array() ) { 2005 2006 'addToGallery' => __( 'Add to gallery' ), 2006 2007 'addToGalleryTitle' => __( 'Add to Gallery' ), 2007 2008 'reverseOrder' => __( 'Reverse order' ), 2009 2010 2011 // Edit Image 2012 'imageDetailsTitle' => __( 'Image Details' ), 2013 'imageReplaceTitle' => __( 'Replace Image' ), 2014 'imageDetailsCancel' => __( 'Cancel Edit' ) 2008 2015 ); 2009 2016 2010 2017 $settings = apply_filters( 'media_view_settings', $settings, $post );