Ticket #28965: 28965.diff
File 28965.diff, 24.5 KB (added by , 10 years ago) |
---|
-
src/wp-includes/css/media-views.css
diff --git a/src/wp-includes/css/media-views.css b/src/wp-includes/css/media-views.css index 907f252..105a81b 100644
a b 912 912 } 913 913 914 914 .attachment.details, 915 .media- grid-view.selected.attachment {915 .media-frame.mode-grid .selected.attachment { 916 916 -webkit-box-shadow: 0 0 0 1px #fff, 917 917 0 0 0 5px #1e8cbe; 918 918 box-shadow: 0 0 0 1px #fff, … … 921 921 922 922 .attachment.details .check, 923 923 .attachment.selected .check:focus, 924 .media- grid-view.attachment.selected .check {924 .media-frame.mode-grid .attachment.selected .check { 925 925 background-color: #1e8cbe; 926 926 -webkit-box-shadow: 0 0 0 1px #fff, 927 927 0 0 0 2px #1e8cbe; … … 929 929 0 0 0 2px #1e8cbe; 930 930 } 931 931 932 .media- grid-view.attachment .check {932 .media-frame.mode-grid .attachment .check { 933 933 display: block; 934 934 } 935 935 936 .media- grid-view.attachment .check div {936 .media-frame.mode-grid .attachment .check div { 937 937 background-position: 21px 0; 938 938 } 939 939 940 940 .attachment.details .check div, 941 .media- grid-view.attachment.selected .check div {941 .media-frame.mode-grid .attachment.selected .check div { 942 942 background-position: -21px 0; 943 943 } 944 944 945 945 .attachment.details .check:hover div, 946 946 .attachment.selected .check:focus div, 947 .media- grid-view.attachment.selected .check:hover div {947 .media-frame.mode-grid .attachment.selected .check:hover div { 948 948 background-position: -60px 0; 949 949 } 950 950 … … video#inline-media-node { 2596 2596 /** 2597 2597 * Media Grid 2598 2598 */ 2599 .media- grid-view,2600 .media- grid-view.media-frame-content,2601 .media- grid-view.attachments-browser .attachments,2602 .media- grid-view.uploader-inline-content {2599 .media-frame.mode-grid, 2600 .media-frame.mode-grid .media-frame-content, 2601 .media-frame.mode-grid .attachments-browser .attachments, 2602 .media-frame.mode-grid .uploader-inline-content { 2603 2603 position: static; 2604 2604 } 2605 2605 2606 2606 /* Regions we don't use at all */ 2607 .media-grid-view .media-frame-title, 2608 .media-grid-view .media-frame-toolbar, 2609 .media-grid-view .media-frame-menu { 2607 .media-frame.mode-grid .media-frame-title, 2608 .media-frame.mode-grid .media-frame-toolbar, 2609 .media-frame.mode-grid .media-frame-router, 2610 .media-frame.mode-grid .media-frame-menu { 2610 2611 display: none; 2611 2612 } 2612 2613 2613 .media- grid-view.media-frame-content {2614 .media-frame.mode-grid .media-frame-content { 2614 2615 background-color: transparent; 2615 2616 border: none; 2616 2617 } 2617 2618 2618 .media- grid-view.uploader-inline {2619 .media-frame.mode-grid .uploader-inline { 2619 2620 position: relative; 2620 2621 top: auto; 2621 2622 right: auto; … … video#inline-media-node { 2625 2626 margin-top: 0; 2626 2627 } 2627 2628 2628 .media- grid-view.media-toolbar select {2629 .media-frame.mode-grid .media-toolbar select { 2629 2630 margin-top: 1px; 2630 2631 font-size: inherit; 2631 2632 } 2632 2633 2633 .media- grid-view.attachments-browser .bulk-select {2634 .media-frame.mode-grid .attachments-browser .bulk-select { 2634 2635 display: inline-block; 2635 2636 } 2636 2637 … … video#inline-media-node { 2639 2640 * 2640 2641 * This should be OOCSS'd so both use a shared selector. 2641 2642 */ 2642 .media- grid-view.attachments-browser .media-toolbar {2643 .media-frame.mode-grid .attachments-browser .media-toolbar { 2643 2644 background: #fff; 2644 2645 -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); 2645 2646 box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); … … video#inline-media-node { 2657 2658 border: none; 2658 2659 } 2659 2660 2660 .media- grid-viewinput[type="search"] {2661 .media-frame.mode-grid input[type="search"] { 2661 2662 margin: 1px; 2662 2663 padding: 3px 5px; 2663 2664 position: absolute; … … video#inline-media-node { 2669 2670 width: 280px; 2670 2671 } 2671 2672 2672 .media- grid-view.view-switch {2673 .media-frame.mode-grid .view-switch { 2673 2674 display: inline-block; 2674 2675 float: none; 2675 2676 vertical-align: middle; … … video#inline-media-node { 2677 2678 margin: 0 20px 0 0; 2678 2679 } 2679 2680 2680 .media- grid-viewselect {2681 .media-frame.mode-grid select { 2681 2682 margin: 0 10px 0 0; 2682 2683 } 2683 2684 2684 .media- grid-view.spinner {2685 .media-frame.mode-grid .spinner { 2685 2686 margin-top: 15px; 2686 2687 } 2687 2688 2688 .media- grid-view.attachments-browser {2689 .media-frame.mode-grid .attachments-browser { 2689 2690 padding: 0; 2690 2691 } 2691 2692 2692 .media- grid-view.attachments-browser .no-media {2693 .media-frame.mode-grid .attachments-browser .no-media { 2693 2694 color: #999; 2694 2695 font-size: 18px; 2695 2696 font-style: normal; … … video#inline-media-node { 2805 2806 top: 56px; 2806 2807 } 2807 2808 2808 /* Hiding this for the moment instead of removing it from the template. */2809 .edit-attachment-frame h3 {2810 display: none;2811 }2812 2813 2809 .edit-attachment-frame .attachment-details { 2814 2810 position: absolute; 2815 2811 overflow: auto; … … video#inline-media-node { 2950 2946 */ 2951 2947 2952 2948 @media only screen and (max-width: 1120px) { 2953 .media- grid-view.attachments-browser .media-toolbar-primary,2954 .media- grid-view.attachments-browser .media-toolbar-secondary {2949 .media-frame.mode-grid .attachments-browser .media-toolbar-primary, 2950 .media-frame.mode-grid .attachments-browser .media-toolbar-secondary { 2955 2951 float: none; 2956 2952 } 2957 2953 2958 .media- grid-viewinput[type="search"] {2954 .media-frame.mode-grid input[type="search"] { 2959 2955 margin: 20px 0; 2960 2956 position: static; 2961 2957 width: 100%; -
src/wp-includes/js/media-grid.js
diff --git a/src/wp-includes/js/media-grid.js b/src/wp-includes/js/media-grid.js index 67f4dc5..01ada52 100644
a b 1 1 /* global _wpMediaViewsL10n, MediaElementPlayer, _wpMediaGridSettings, confirm */ 2 2 (function($, _, Backbone, wp) { 3 // Local reference to the WordPress media namespace. 3 4 var media = wp.media, l10n; 4 5 5 // Link any localized strings.6 // Link localized strings and settings. 6 7 if ( media.view.l10n ) { 7 8 l10n = media.view.l10n; 8 9 } else { … … 11 12 } 12 13 13 14 /** 15 * wp.media.controller.EditAttachmentMetadata 16 * 14 17 * A state for editing an attachment's metadata. 15 18 * 16 19 * @constructor … … 20 23 media.controller.EditAttachmentMetadata = media.controller.State.extend({ 21 24 defaults: { 22 25 id: 'edit-attachment', 26 // Title string passed to the frame's title region view. 23 27 title: l10n.attachmentDetails, 24 28 // Region mode defaults. 25 menu: false,26 29 content: 'edit-metadata', 27 28 url: '' 29 }, 30 31 _ready: function() {}, 32 33 /** 34 * Override media.controller.State._postActivate, since this state doesn't 35 * include the regions expected there. 36 */ 37 _postActivate: function() { 38 this.frame.on( 'title:render:default', this._renderTitle, this ); 39 40 this._title(); 41 this._content(); 42 }, 43 44 /** 45 * @access private 46 */ 47 _title: function() { 48 this.frame.title.render( this.get('titleMode') || 'default' ); 49 }, 50 /** 51 * @access private 52 */ 53 _renderTitle: function( view ) { 54 view.$el.text( this.get('title') || '' ); 55 }, 56 57 _content: function() { 58 var mode = this.get( 'content' ); 59 if ( mode ) { 60 this.frame.content.render( mode ); 61 } 30 menu: false, 31 toolbar: false, 32 router: false 62 33 } 63 34 }); 64 35 … … 87 58 title: '', 88 59 modal: false, 89 60 selection: [], 90 library: {}, 61 library: {}, // Options hash for the query to the media library. 91 62 multiple: 'add', 92 63 state: 'library', 93 64 uploader: true, 94 mode: [ 'grid' , 'edit']65 mode: [ 'grid' ] 95 66 }); 96 67 97 68 $(document).on( 'click', '.add-new-h2', _.bind( this.addNewClickHandler, this ) ); 98 $(document).on( 'screen:options:open', _.bind( this.screenOptionsOpen, this ) );99 $(document).on( 'screen:options:close', _.bind( this.screenOptionsClose, this ) );100 69 101 70 // Ensure core and media grid view UI is enabled. 102 this.$el.addClass('wp-core-ui media-grid-view');71 this.$el.addClass('wp-core-ui'); 103 72 104 73 // Force the uploader off if the upload limit has been exceeded or 105 74 // if the browser isn't supported. … … 123 92 } 124 93 125 94 /** 126 * call 'initialize' directly on the parent class 95 * call 'initialize' directly on the parent class. 127 96 */ 128 97 media.view.MediaFrame.prototype.initialize.apply( this, arguments ); 129 98 130 // Since we're not using the default modal built into 131 // a media frame, append our $element to the supplied container. 99 // Append the frame view directly the supplied container. 132 100 this.$el.appendTo( this.options.container ); 133 101 134 this.createSelection();135 102 this.createStates(); 136 this.bind Handlers();103 this.bindRegionModeHandlers(); 137 104 this.render(); 138 105 139 106 // Update the URL when entering search string (at most once per second) … … 148 115 _.delay( _.bind( this.createRouter, this ), 1000 ); 149 116 }, 150 117 151 screenOptionsOpen: function() {152 this.$el.addClass( 'media-grid-view-options' );153 },154 155 screenOptionsClose: function() {156 this.$el.removeClass( 'media-grid-view-options' );157 },158 159 118 createRouter: function() { 160 119 this.gridRouter = new media.view.MediaFrame.Manage.Router(); 161 120 … … 168 127 } 169 128 }, 170 129 171 createSelection: function() { 172 var selection = this.options.selection; 173 174 if ( ! (selection instanceof media.model.Selection) ) { 175 this.options.selection = new media.model.Selection( selection, { 176 multiple: this.options.multiple 177 }); 178 } 179 180 this._selection = { 181 attachments: new media.model.Attachments(), 182 difference: [] 183 }; 184 }, 185 130 /** 131 * Create the default states for the frame. 132 */ 186 133 createStates: function() { 187 134 var options = this.options; 188 135 … … 196 143 library: media.query( options.library ), 197 144 multiple: options.multiple, 198 145 title: options.title, 199 priority: 20,200 201 router: false,202 146 content: 'browse', 203 147 204 148 filterable: 'mime-types' … … 206 150 ]); 207 151 }, 208 152 209 bindHandlers: function() { 210 this.on( 'content:create:browse', this.browseContent, this ); 211 this.on( 'content:render:edit-image', this.editImageContent, this ); 153 /** 154 * Bind region mode activation events to proper handlers. 155 */ 156 bindRegionModeHandlers: function() { 157 this.on( 'content:create:browse', this.createViewForContentRegionInBrowseMode, this ); 212 158 213 159 // Handle a frame-level event for editing an attachment. 214 this.on( 'edit:attachment', this. editAttachment, this );160 this.on( 'edit:attachment', this.openEditAttachmentModal, this ); 215 161 }, 216 162 163 /** 164 * Click handler for the `Add New` button. 165 */ 217 166 addNewClickHandler: function( event ) { 218 167 event.preventDefault(); 219 168 this.trigger( 'toggle:upload:attachment' ); … … 222 171 /** 223 172 * Open the Edit Attachment modal. 224 173 */ 225 editAttachment: function( model ) {174 openEditAttachmentModal: function( model ) { 226 175 // Create a new EditAttachment frame, passing along the library and the attachment model. 227 176 wp.media( { 228 177 frame: 'edit-attachments', … … 233 182 }, 234 183 235 184 /** 236 * C ontent185 * Create an attachments browser view within the content region. 237 186 * 238 * @param {Object} content 187 * @param {Object} contentRegion Basic object with a `view` property, which 188 * should be set with the proper region view. 239 189 * @this wp.media.controller.Region 240 190 */ 241 browseContent: function( content) {191 createViewForContentRegionInBrowseMode: function( contentRegion ) { 242 192 var state = this.state(); 243 193 244 194 // Browse our library of attachments. 245 content .view = new media.view.AttachmentsBrowser({195 contentRegion.view = new media.view.AttachmentsBrowser({ 246 196 controller: this, 247 197 collection: state.get('library'), 248 198 selection: state.get('selection'), … … 259 209 260 210 AttachmentView: state.get('AttachmentView') 261 211 }); 262 },263 264 editImageContent: function() {265 var image = this.state().get('image'),266 view = new media.view.EditImage( { model: image, controller: this } ).render();267 268 this.content.set( view );269 270 // after creating the wrapper view, load the actual editor via an ajax call271 view.loadEditor();272 273 212 } 274 213 }); 275 214 215 /** 216 * A similar view to media.view.Attachment.Details 217 * for use in the Edit Attachment modal. 218 */ 276 219 media.view.Attachment.Details.TwoColumn = media.view.Attachment.Details.extend({ 277 template: wp.template( 'attachment-details-two-column' ), 278 279 events: { 280 'change [data-setting]': 'updateSetting', 281 'change [data-setting] input': 'updateSetting', 282 'change [data-setting] select': 'updateSetting', 283 'change [data-setting] textarea': 'updateSetting', 284 'click .delete-attachment': 'deleteAttachment', 285 'click .trash-attachment': 'trashAttachment', 286 'click .edit-attachment': 'editAttachment', 287 'click .refresh-attachment': 'refreshAttachment', 288 'click .edit-image': 'handleEditImageClick' 289 }, 290 291 initialize: function() { 292 if ( ! this.model ) { 293 return; 294 } 295 296 this.$el.attr('aria-label', this.model.get( 'title' ) ).attr( 'aria-checked', false ); 297 298 this.model.on( 'change:title', this._syncTitle, this ); 299 this.model.on( 'change:caption', this._syncCaption, this ); 300 this.model.on( 'change:percent', this.progress, this ); 301 this.model.on( 'change:album', this._syncAlbum, this ); 302 this.model.on( 'change:artist', this._syncArtist, this ); 303 304 // Update the selection. 305 this.model.on( 'add', this.select, this ); 306 this.model.on( 'remove', this.deselect, this ); 307 this.model.on( 'sync', this.afterDelete, this ); 308 }, 220 template: media.template( 'attachment-details-two-column' ), 309 221 310 222 preDestroy: function( event ) { 311 223 event.preventDefault(); … … 324 236 media.view.Attachment.Details.prototype.deleteAttachment.apply( this, arguments ); 325 237 }, 326 238 327 handleEditImageClick: function() { 239 editAttachment: function( event ) { 240 event.preventDefault(); 328 241 this.controller.setState( 'edit-image' ); 329 242 }, 330 243 244 /** 245 * Noop this from parent class, doesn't apply here. 246 */ 247 toggleSelectionHandler: function() {}, 248 331 249 afterDelete: function( model ) { 332 250 if ( ! model.destroyed ) { 333 251 return; … … 444 362 this.createStates(); 445 363 446 364 this.on( 'content:render:edit-metadata', this.editMetadataContent, this ); 447 this.on( 'content:render:edit-image', this.editImageContentUgh, this ); 365 this.on( 'content:create:edit-image', this.createViewForContentRegionInEditImageMode, this ); 366 // this.on( 'content:render:edit-image', this.rendereditImageContentUgh, this ); 448 367 this.on( 'close', this.detach ); 449 368 450 369 // Bind default title creation. … … 512 431 }, 513 432 514 433 /** 515 * For some reason the view doesn't exist in the DOM yet, don't have the516 * patience to track this down right now.517 */518 editImageContentUgh: function() {519 _.defer( _.bind( this.editImageContent, this ) );520 },521 522 /**523 434 * Render the EditImage view into the frame's content region. 524 435 */ 525 editImageContent: function() { 526 var view = new media.view.EditImage( { model: this.model, controller: this } ).render(); 527 528 this.content.set( view ); 529 530 // after creating the wrapper view, load the actual editor via an ajax call 531 view.loadEditor(); 436 createViewForContentRegionInEditImageMode: function( contentRegion ) { 437 contentRegion.view = new media.view.EditImage( { model: this.model, controller: this } ); 438 // Defer a call to load the editor, which 439 // requires DOM elements to exist. 440 _.defer( _.bind( contentRegion.view.loadEditor, contentRegion.view ) ); 532 441 }, 533 442 534 443 resetContent: function() { -
src/wp-includes/js/media-views.js
diff --git a/src/wp-includes/js/media-views.js b/src/wp-includes/js/media-views.js index c57df05..ce8eadf 100644
a b 1685 1685 */ 1686 1686 media.view.Frame = media.View.extend({ 1687 1687 initialize: function() { 1688 _.defaults( this.options, { 1689 mode: [ 'select' ] 1690 }); 1688 1691 this._createRegions(); 1689 1692 this._createStates(); 1693 this._createModes(); 1690 1694 }, 1691 1695 1692 1696 _createRegions: function() { … … 1721 1725 this.states.add( this.options.states ); 1722 1726 } 1723 1727 }, 1728 _createModes: function() { 1729 // Store active "modes" that the frame is in. Unrelated to region modes. 1730 this.activeModes = new Backbone.Collection(); 1731 this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) ); 1732 1733 _.each( this.options.mode, function( mode ) { 1734 this.activateMode( mode ); 1735 }, this ); 1736 }, 1724 1737 /** 1725 1738 * @returns {wp.media.view.Frame} Returns itself to allow chaining 1726 1739 */ 1727 1740 reset: function() { 1728 1741 this.states.invoke( 'trigger', 'reset' ); 1729 1742 return this; 1743 }, 1744 /** 1745 * Map activeMode collection events to the frame. 1746 */ 1747 triggerModeEvents: function( model, collection, options ) { 1748 var collectionEvent, 1749 modeEventMap = { 1750 add: 'activate', 1751 remove: 'deactivate' 1752 }, 1753 eventToTrigger; 1754 // Probably a better way to do this. 1755 _.each( options, function( value, key ) { 1756 if ( value ) { 1757 collectionEvent = key; 1758 } 1759 } ); 1760 1761 if ( ! _.has( modeEventMap, collectionEvent ) ) { 1762 return; 1763 } 1764 1765 eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent]; 1766 this.trigger( eventToTrigger ); 1767 }, 1768 /** 1769 * Activate a mode on the frame. 1770 * 1771 * @param string mode Mode ID. 1772 * @returns {this} Returns itself to allow chaining. 1773 */ 1774 activateMode: function( mode ) { 1775 // Bail if the mode is already active. 1776 if ( this.isModeActive( mode ) ) { 1777 return; 1778 } 1779 this.activeModes.add( [ { id: mode } ] ); 1780 // Add a CSS class to the frame so elements can be styled for the mode. 1781 this.$el.addClass( 'mode-' + mode ); 1782 /** 1783 * Frame mode activation event. 1784 * 1785 * @event this#{mode}:activate 1786 */ 1787 this.trigger( mode + ':activate' ); 1788 1789 return this; 1790 }, 1791 /** 1792 * Deactivate a mode on the frame. 1793 * 1794 * @param string mode Mode ID. 1795 * @returns {this} Returns itself to allow chaining. 1796 */ 1797 deactivateMode: function( mode ) { 1798 // Bail if the mode isn't active. 1799 if ( ! this.isModeActive( mode ) ) { 1800 return; 1801 } 1802 this.activeModes.remove( this.activeModes.where( { id: mode } ) ); 1803 this.$el.removeClass( 'mode-' + mode ); 1804 /** 1805 * Frame mode deactivation event. 1806 * 1807 * @event this#{mode}:deactivate 1808 */ 1809 this.trigger( mode + ':deactivate' ); 1810 1811 return this; 1812 }, 1813 /** 1814 * Check if a mode is enabled on the frame. 1815 * 1816 * @param string mode Mode ID. 1817 * @return bool 1818 */ 1819 isModeActive: function( mode ) { 1820 return Boolean( this.activeModes.where( { id: mode } ).length ); 1730 1821 } 1731 1822 }); 1732 1823 … … 1759 1850 _.defaults( this.options, { 1760 1851 title: '', 1761 1852 modal: true, 1762 uploader: true, 1763 mode: [ 'select' ] 1853 uploader: true 1764 1854 }); 1765 1855 1766 1856 // Ensure core UI is enabled. … … 1776 1866 this.modal.content( this ); 1777 1867 } 1778 1868 1779 // Store active "modes" that the frame is in. Unrelated to region modes.1780 this.activeModes = new Backbone.Collection();1781 this.activeModes.on( 'add remove reset', _.bind( this.triggerModeEvents, this ) );1782 1783 _.each( this.options.mode, function( mode ) {1784 this.activateMode( mode );1785 }, this );1786 1787 1869 // Force the uploader off if the upload limit has been exceeded or 1788 1870 // if the browser isn't supported. 1789 1871 if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { … … 1948 2030 1949 2031 window.tb_remove = this._tb_remove; 1950 2032 delete this._tb_remove; 1951 },1952 1953 /**1954 * Map activeMode collection events to the frame.1955 */1956 triggerModeEvents: function( model, collection, options ) {1957 var collectionEvent,1958 modeEventMap = {1959 add: 'activate',1960 remove: 'deactivate'1961 },1962 eventToTrigger;1963 // Probably a better way to do this.1964 _.each( options, function( value, key ) {1965 if ( value ) {1966 collectionEvent = key;1967 }1968 } );1969 1970 if ( ! _.has( modeEventMap, collectionEvent ) )1971 return;1972 1973 eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent];1974 this.trigger( eventToTrigger );1975 },1976 /**1977 * Activate a mode on the frame.1978 *1979 * @param string mode Mode ID.1980 * @returns {this} Returns itself to allow chaining.1981 */1982 activateMode: function( mode ) {1983 // Bail if the mode is already active.1984 if ( this.isModeActive( mode ) ) {1985 return;1986 }1987 this.activeModes.add( [ { id: mode } ] );1988 // Add a css class to the frame for anything that needs to be styled1989 // for the mode.1990 this.$el.addClass( 'mode-' + mode );1991 /**1992 * Frame mode activation event.1993 *1994 * @event this#{mode}:activate1995 */1996 this.trigger( mode + ':activate' );1997 1998 return this;1999 },2000 /**2001 * Deactivate a mode on the frame.2002 *2003 * @param string mode Mode ID.2004 * @returns {this} Returns itself to allow chaining.2005 */2006 deactivateMode: function( mode ) {2007 // Bail if the mode isn't active.2008 if ( ! this.isModeActive( mode ) ) {2009 return;2010 }2011 this.activeModes.remove( this.activeModes.where( { id: mode } ) );2012 this.$el.removeClass( 'mode-' + mode );2013 /**2014 * Frame mode deactivation event.2015 *2016 * @event this#{mode}:deactivate2017 */2018 this.trigger( mode + ':deactivate' );2019 2020 return this;2021 },2022 /**2023 * Check if a mode is enabled on the frame.2024 *2025 * @param string mode Mode ID.2026 * @return bool2027 */2028 isModeActive: function( mode ) {2029 return Boolean( this.activeModes.where( { id: mode } ).length );2030 2033 } 2031 2034 }); 2032 2035 … … 4631 4634 buttons: {}, 4632 4635 4633 4636 initialize: function() { 4634 var selection = this.options.selection; 4637 var selection = this.options.selection, 4638 options = _.defaults( this.options, { 4639 rerenderOnModelChange: true 4640 } ); 4641 this.$el.attr( 'aria-label', this.model.get( 'title' ) ).attr( 'aria-checked', false ); 4635 4642 4636 this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false); 4637 this.model.on( 'change', this.render, this ); 4643 if ( options.rerenderOnModelChange ) { 4644 this.model.on( 'change', this.render, this ); 4645 } 4638 4646 this.model.on( 'change:title', this._syncTitle, this ); 4639 4647 this.model.on( 'change:caption', this._syncCaption, this ); 4640 4648 this.model.on( 'change:artist', this._syncArtist, this ); … … 4646 4654 this.model.on( 'remove', this.deselect, this ); 4647 4655 if ( selection ) { 4648 4656 selection.on( 'reset', this.updateSelect, this ); 4657 // Update the model's details view. 4658 this.model.on( 'selection:single selection:unsingle', this.details, this ); 4659 this.details( this.model, this.controller.state().get('selection') ); 4649 4660 } 4650 4651 // Update the model's details view.4652 this.model.on( 'selection:single selection:unsingle', this.details, this );4653 this.details( this.model, this.controller.state().get('selection') );4654 4661 }, 4655 4662 /** 4656 4663 * @returns {wp.media.view.Attachment} Returns itself to allow chaining … … 4752 4759 } 4753 4760 4754 4761 // In the grid view, bubble up an edit:attachment event to the controller. 4755 if ( this.controller. activeModes.where( { id: 'edit' } ).length) {4762 if ( this.controller.isModeActive( 'grid' ) ) { 4756 4763 this.controller.trigger( 'edit:attachment', this.model ); 4757 4764 return; 4758 4765 } … … 6318 6325 }, 6319 6326 6320 6327 initialize: function() { 6328 this.options = _.defaults( this.options, { 6329 rerenderOnModelChange: false 6330 }); 6321 6331 /** 6322 6332 * call 'initialize' directly on the parent class 6323 6333 */ 6324 6334 media.view.Attachment.prototype.initialize.apply( this, arguments ); 6325 6335 }, 6326 6336 /** 6327 * @returns {wp.media.view..Attachment.Details} Returns itself to allow chaining6328 */6329 render: function() {6330 /**6331 * call 'render' directly on the parent class6332 */6333 media.view.Attachment.prototype.render.apply( this, arguments );6334 return this;6335 },6336 /**6337 6337 * @param {Object} event 6338 6338 */ 6339 6339 deleteAttachment: function( event ) { … … 6379 6379 this.model.fetch(); 6380 6380 }, 6381 6381 /** 6382 * When reverse tabbing(shift+tab) out of the right details panel, deliver 6383 * the focus to the item in the list that was being edited. 6384 * 6382 6385 * @param {Object} event 6383 6386 */ 6384 6387 toggleSelectionHandler: function( event ) { 6385 // Reverse tabbing out of the right details panel6386 // should take me back to the item in the list that was being edited.6387 6388 if ( 'keydown' === event.type && 9 === event.keyCode && event.shiftKey && event.target === $( ':tabbable', this.$el ).filter( ':first' )[0] ) { 6388 6389 $('.attachments-browser .details').focus(); 6389 6390 return false; -
src/wp-includes/media-template.php
diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index c71086e..5ccc5ff 100644
a b function wp_print_media_templates() { 263 263 </script> 264 264 265 265 <script type="text/html" id="tmpl-attachment-details-two-column"> 266 <h3>267 <?php _e('Attachment Details'); ?>268 </h3>269 266 <div class="attachment-media-view"> 270 267 <div class="thumbnail thumbnail-{{ data.type }}"> 271 268 <# if ( data.uploading ) { #> … … function wp_print_media_templates() { 294 291 295 292 <div class="attachment-actions"> 296 293 <# if ( 'image' === data.type && ! data.uploading ) { #> 297 <a class="button edit- image" href="#"><?php _e( 'Edit Image' ); ?></a>294 <a class="button edit-attachment" href="#"><?php _e( 'Edit Image' ); ?></a> 298 295 <# } #> 299 296 300 297 <# if ( ! data.uploading && data.can.remove ) { #>