Changeset 29266
- Timestamp:
- 07/22/2014 04:20:59 PM (11 years ago)
- Location:
- trunk/src/wp-includes
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/css/media-views.css
r29265 r29266 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; … … 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, … … 930 930 } 931 931 932 .media- grid-view.attachment .check {933 display: block; 934 } 935 936 .media- grid-view.attachment .check div {932 .media-frame.mode-grid .attachment .check { 933 display: block; 934 } 935 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 } … … 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 } … … 1069 1069 } 1070 1070 1071 .attachment-preview:hover ~ .inline-toolbar { 1071 .attachment-preview:hover + .inline-toolbar, 1072 .inline-toolbar:hover { 1072 1073 display: block; 1073 1074 } … … 2597 2598 * Media Grid 2598 2599 */ 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 {2600 .media-frame.mode-grid, 2601 .media-frame.mode-grid .media-frame-content, 2602 .media-frame.mode-grid .attachments-browser .attachments, 2603 .media-frame.mode-grid .uploader-inline-content { 2603 2604 position: static; 2604 2605 } 2605 2606 2606 2607 /* 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 { 2610 display: none; 2611 } 2612 2613 .media-grid-view .media-frame-content { 2608 .media-frame.mode-grid .media-frame-title, 2609 .media-frame.mode-grid .media-frame-toolbar, 2610 .media-frame.mode-grid .media-frame-router, 2611 .media-frame.mode-grid .media-frame-menu { 2612 display: none; 2613 } 2614 2615 .media-frame.mode-grid .media-frame-content { 2614 2616 background-color: transparent; 2615 2617 border: none; 2616 2618 } 2617 2619 2618 .media- grid-view.uploader-inline {2620 .media-frame.mode-grid .uploader-inline { 2619 2621 position: relative; 2620 2622 top: auto; … … 2626 2628 } 2627 2629 2628 .media- grid-view.media-toolbar select {2630 .media-frame.mode-grid .media-toolbar select { 2629 2631 margin-top: 1px; 2630 2632 font-size: inherit; 2631 2633 } 2632 2634 2633 .media- grid-view.attachments-browser .bulk-select {2635 .media-frame.mode-grid .attachments-browser .bulk-select { 2634 2636 display: inline-block; 2635 2637 } … … 2640 2642 * This should be OOCSS'd so both use a shared selector. 2641 2643 */ 2642 .media- grid-view.attachments-browser .media-toolbar {2644 .media-frame.mode-grid .attachments-browser .media-toolbar { 2643 2645 background: #fff; 2644 2646 -webkit-box-shadow: 0 1px 1px 0 rgba(0,0,0,.1); … … 2658 2660 } 2659 2661 2660 .media- grid-viewinput[type="search"] {2662 .media-frame.mode-grid input[type="search"] { 2661 2663 margin: 1px; 2662 2664 padding: 3px 5px; … … 2670 2672 } 2671 2673 2672 .media- grid-view.view-switch {2674 .media-frame.mode-grid .view-switch { 2673 2675 display: inline-block; 2674 2676 float: none; … … 2678 2680 } 2679 2681 2680 .media- grid-viewselect {2682 .media-frame.mode-grid select { 2681 2683 margin: 0 10px 0 0; 2682 2684 } 2683 2685 2684 .media- grid-view.spinner {2686 .media-frame.mode-grid .spinner { 2685 2687 margin-top: 15px; 2686 2688 } 2687 2689 2688 .media- grid-view.attachments-browser {2690 .media-frame.mode-grid .attachments-browser { 2689 2691 padding: 0; 2690 2692 } 2691 2693 2692 .media- grid-view.attachments-browser .no-media {2694 .media-frame.mode-grid .attachments-browser .no-media { 2693 2695 color: #999; 2694 2696 font-size: 18px; … … 2806 2808 bottom: 0; 2807 2809 top: 56px; 2808 }2809 2810 /* Hiding this for the moment instead of removing it from the template. */2811 .edit-attachment-frame h3 {2812 display: none;2813 2810 } 2814 2811 … … 2954 2951 2955 2952 @media only screen and (max-width: 1120px) { 2956 .media- grid-view.attachments-browser .media-toolbar-primary,2957 .media- grid-view.attachments-browser .media-toolbar-secondary {2953 .media-frame.mode-grid .attachments-browser .media-toolbar-primary, 2954 .media-frame.mode-grid .attachments-browser .media-toolbar-secondary { 2958 2955 float: none; 2959 2956 } 2960 2957 2961 .media- grid-viewinput[type="search"] {2958 .media-frame.mode-grid input[type="search"] { 2962 2959 margin: 20px 0; 2963 2960 position: static; -
trunk/src/wp-includes/js/media-grid.js
r29263 r29266 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; … … 12 13 13 14 /** 15 * wp.media.controller.EditAttachmentMetadata 16 * 14 17 * A state for editing an attachment's metadata. 15 18 * … … 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. 29 content: 'edit-metadata', 25 30 menu: false, 26 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 } 31 toolbar: false, 32 router: false 62 33 } 63 34 }); … … 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 … … 123 92 } 124 93 125 /** 126 * call 'initialize' directly on the parent class 127 */ 94 // Call 'initialize' directly on the parent class. 128 95 media.view.MediaFrame.prototype.initialize.apply( this, arguments ); 129 96 130 // Since we're not using the default modal built into 131 // a media frame, append our $element to the supplied container. 97 // Append the frame view directly the supplied container. 132 98 this.$el.appendTo( this.options.container ); 133 99 134 this.createSelection();135 100 this.createStates(); 136 this.bind Handlers();101 this.bindRegionModeHandlers(); 137 102 this.render(); 138 103 … … 146 111 }, 1000 ) ); 147 112 113 // This is problematic. 148 114 _.delay( _.bind( this.createRouter, this ), 1000 ); 149 },150 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 115 }, 158 116 … … 169 127 }, 170 128 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 129 /** 130 * Create the default states for the frame. 131 */ 186 132 createStates: function() { 187 133 var options = this.options; … … 197 143 multiple: options.multiple, 198 144 title: options.title, 199 priority: 20,200 201 router: false,202 145 content: 'browse', 203 146 … … 207 150 }, 208 151 209 bindHandlers: function() { 152 /** 153 * Bind region mode activation events to proper handlers. 154 */ 155 bindRegionModeHandlers: function() { 210 156 this.on( 'content:create:browse', this.browseContent, this ); 211 this.on( 'content:render:edit-image', this.editImageContent, this );212 157 213 158 // Handle a frame-level event for editing an attachment. 214 this.on( 'edit:attachment', this.editAttachment, this ); 215 }, 216 159 this.on( 'edit:attachment', this.openEditAttachmentModal, this ); 160 }, 161 162 /** 163 * Click handler for the `Add New` button. 164 */ 217 165 addNewClickHandler: function( event ) { 218 166 event.preventDefault(); … … 223 171 * Open the Edit Attachment modal. 224 172 */ 225 editAttachment: function( model ) {173 openEditAttachmentModal: function( model ) { 226 174 // Create a new EditAttachment frame, passing along the library and the attachment model. 227 175 wp.media( { … … 234 182 235 183 /** 236 * C ontent184 * Create an attachments browser view within the content region. 237 185 * 238 * @param {Object} content 186 * @param {Object} contentRegion Basic object with a `view` property, which 187 * should be set with the proper region view. 239 188 * @this wp.media.controller.Region 240 189 */ 241 browseContent: function( content ) {190 browseContent: function( contentRegion ) { 242 191 var state = this.state(); 243 192 244 193 // Browse our library of attachments. 245 content .view = new media.view.AttachmentsBrowser({194 contentRegion.view = new media.view.AttachmentsBrowser({ 246 195 controller: this, 247 196 collection: state.get('library'), … … 260 209 AttachmentView: state.get('AttachmentView') 261 210 }); 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 }274 });275 211 } 212 }); 213 214 /** 215 * A similar view to media.view.Attachment.Details 216 * for use in the Edit Attachment modal. 217 * 218 * @constructor 219 * @augments wp.media.view.Attachment.Details 220 * @augments wp.media.view.Attachment 221 * @augments wp.media.View 222 * @augments wp.Backbone.View 223 * @augments Backbone.View 224 */ 276 225 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 }, 226 template: media.template( 'attachment-details-two-column' ), 309 227 310 228 preDestroy: function( event ) { … … 325 243 }, 326 244 327 handleEditImageClick: function() { 245 editAttachment: function( event ) { 246 event.preventDefault(); 328 247 this.controller.setState( 'edit-image' ); 329 248 }, 249 250 /** 251 * Noop this from parent class, doesn't apply here. 252 */ 253 toggleSelectionHandler: function() {}, 330 254 331 255 afterDelete: function( model ) { … … 352 276 353 277 media.mixin.removeAllPlayers(); 354 $( 'audio, video', this.$el).each( function (i, elem) {278 this.$( 'audio, video' ).each( function (i, elem) { 355 279 var el = media.view.MediaDetails.prepareSrc( elem ); 356 280 new MediaElementPlayer( el, media.mixin.mejsSettings ); … … 360 284 361 285 /** 362 * A router for handling the browser history and application state 286 * A router for handling the browser history and application state. 287 * 288 * @constructor 289 * @augments Backbone.Router 363 290 */ 364 291 media.view.MediaFrame.Manage.Router = Backbone.Router.extend({ 365 292 routes: { 366 'upload.php?item=:slug': 'show item',293 'upload.php?item=:slug': 'showItem', 367 294 'upload.php?search=:query': 'search', 368 295 ':default': 'defaultRoute' … … 382 309 383 310 // Show the modal with a specific item 384 show item: function( query ) {311 showItem: function( query ) { 385 312 var library = media.frame.state().get('library'); 386 313 … … 411 338 * 412 339 * Requires an attachment model to be passed in the options hash under `model`. 340 * 341 * @constructor 342 * @augments wp.media.view.Frame 343 * @augments wp.media.View 344 * @augments wp.Backbone.View 345 * @augments Backbone.View 346 * @mixes wp.media.controller.StateMachine 413 347 */ 414 348 media.view.MediaFrame.EditAttachments = media.view.MediaFrame.extend({ … … 444 378 this.createStates(); 445 379 446 this.on( 'content: render:edit-metadata', this.editMetadataContent, this );447 this.on( 'content: render:edit-image', this.editImageContentUgh, this );380 this.on( 'content:create:edit-metadata', this.editMetadataMode, this ); 381 this.on( 'content:create:edit-image', this.editImageMode, this ); 448 382 this.on( 'close', this.detach ); 449 383 … … 474 408 } ); 475 409 410 // Set this frame as the modal's content. 476 411 this.modal.content( this ); 477 412 this.modal.open(); … … 497 432 /** 498 433 * Content region rendering callback for the `edit-metadata` mode. 499 */ 500 editMetadataContent: function() { 501 var view = new media.view.Attachment.Details.TwoColumn({ 434 * 435 * @param {Object} contentRegion Basic object with a `view` property, which 436 * should be set with the proper region view. 437 */ 438 editMetadataMode: function( contentRegion ) { 439 contentRegion.view = new media.view.Attachment.Details.TwoColumn({ 502 440 controller: this, 503 441 model: this.model 504 442 }); 505 this.content.set( view );506 443 // Update browser url when navigating media details 507 444 if ( this.model ) { 508 445 this.gridRouter.navigate( this.gridRouter.baseUrl( '?item=' + this.model.id ) ); 509 } else { 510 this.resetRoute(); 511 } 512 }, 513 514 /** 515 * For some reason the view doesn't exist in the DOM yet, don't have the 516 * patience to track this down right now. 517 */ 518 editImageContentUgh: function() { 519 _.defer( _.bind( this.editImageContent, this ) ); 446 } 520 447 }, 521 448 522 449 /** 523 450 * Render the EditImage view into the frame's content region. 524 */ 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(); 532 }, 533 451 * 452 * @param {Object} contentRegion Basic object with a `view` property, which 453 * should be set with the proper region view. 454 */ 455 editImageMode: function( contentRegion ) { 456 contentRegion.view = new media.view.EditImage( { model: this.model, controller: this } ); 457 // Defer a call to load the editor, which 458 // requires DOM elements to exist. 459 _.defer( _.bind( contentRegion.view.loadEditor, contentRegion.view ) ); 460 }, 461 462 /** 463 * Close this modal and immediately open another one. 464 * 465 * Allows for quickly swapping out the attachment being edited. 466 */ 534 467 resetContent: function() { 535 468 this.modal.close(); … … 604 537 }); 605 538 539 /** 540 * Controller for bulk selection. 541 */ 606 542 media.view.BulkSelection = media.View.extend({ 607 543 className: 'bulk-select', … … 629 565 }); 630 566 567 /** 568 * Bulk Selection dropdown view. 569 * 570 * @constructor 571 * @augments wp.media.View 572 * @augments wp.Backbone.View 573 * @augments Backbone.View 574 */ 631 575 media.view.BulkSelectionActionDropdown = media.View.extend({ 632 576 tagName: 'select', … … 638 582 .append( $('<option></option>').val( 'delete' ).html( l10n.deletePermanently ) ); 639 583 this.$el.prop( 'disabled', true ); 640 this.$el.on( 'change', _.bind( this.toggleChange, this ) ); 641 }, 642 643 toggleChange: function() { 584 this.$el.on( 'change', _.bind( this.changeHandler, this ) ); 585 }, 586 587 /** 588 * Change handler for the dropdown. 589 * 590 * Sets the bulk selection controller's currentAction. 591 */ 592 changeHandler: function() { 644 593 this.controller.model.set( { 'currentAction': this.$el.val() } ); 645 594 }, 595 596 /** 597 * Enable or disable the dropdown if attachments have been selected. 598 */ 646 599 enabled: function() { 647 600 var disabled = ! this.controller.controller.state().get('selection').length; … … 650 603 }); 651 604 605 /** 606 * Bulk Selection dropdown view. 607 * 608 * @constructor 609 * 610 * @augments wp.media.view.Button 611 * @augments wp.media.View 612 * @augments wp.Backbone.View 613 * @augments Backbone.View 614 */ 652 615 media.view.BulkSelectionActionButton = media.view.Button.extend({ 653 616 tagName: 'button', … … 659 622 this.listenTo( this.controller.controller.state().get( 'selection' ), 'add remove reset', _.bind( this.enabled, this ) ); 660 623 }, 661 624 /** 625 * Button click handler. 626 */ 662 627 click: function() { 663 628 var selection = this.controller.controller.state().get('selection'); … … 673 638 this.enabled(); 674 639 }, 675 640 /** 641 * Enable or disable the button depending if a bulk action is selected 642 * in the bulk select dropdown, and if attachments have been selected. 643 */ 676 644 enabled: function() { 677 645 var currentAction = this.controller.model.get( 'currentAction' ), -
trunk/src/wp-includes/js/media-views.js
r29220 r29266 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 … … 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 … … 1728 1741 this.states.invoke( 'trigger', 'reset' ); 1729 1742 return this; 1730 } 1731 }); 1732 1733 // Make the `Frame` a `StateMachine`. 1734 _.extend( media.view.Frame.prototype, media.controller.StateMachine.prototype ); 1735 1736 /** 1737 * wp.media.view.MediaFrame 1738 * 1739 * Type of frame used to create the media modal. 1740 * 1741 * @constructor 1742 * @augments wp.media.view.Frame 1743 * @augments wp.media.View 1744 * @augments wp.Backbone.View 1745 * @augments Backbone.View 1746 * @mixes wp.media.controller.StateMachine 1747 */ 1748 media.view.MediaFrame = media.view.Frame.extend({ 1749 className: 'media-frame', 1750 template: media.template('media-frame'), 1751 regions: ['menu','title','content','toolbar','router'], 1752 1753 /** 1754 * @global wp.Uploader 1755 */ 1756 initialize: function() { 1757 media.view.Frame.prototype.initialize.apply( this, arguments ); 1758 1759 _.defaults( this.options, { 1760 title: '', 1761 modal: true, 1762 uploader: true, 1763 mode: [ 'select' ] 1764 }); 1765 1766 // Ensure core UI is enabled. 1767 this.$el.addClass('wp-core-ui'); 1768 1769 // Initialize modal container view. 1770 if ( this.options.modal ) { 1771 this.modal = new media.view.Modal({ 1772 controller: this, 1773 title: this.options.title 1774 }); 1775 1776 this.modal.content( this ); 1777 } 1778 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 // Force the uploader off if the upload limit has been exceeded or 1788 // if the browser isn't supported. 1789 if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 1790 this.options.uploader = false; 1791 } 1792 1793 // Initialize window-wide uploader. 1794 if ( this.options.uploader ) { 1795 this.uploader = new media.view.UploaderWindow({ 1796 controller: this, 1797 uploader: { 1798 dropzone: this.modal ? this.modal.$el : this.$el, 1799 container: this.$el 1800 } 1801 }); 1802 this.views.set( '.media-frame-uploader', this.uploader ); 1803 } 1804 1805 this.on( 'attach', _.bind( this.views.ready, this.views ), this ); 1806 1807 // Bind default title creation. 1808 this.on( 'title:create:default', this.createTitle, this ); 1809 this.title.mode('default'); 1810 1811 // Bind default menu. 1812 this.on( 'menu:create:default', this.createMenu, this ); 1813 }, 1814 /** 1815 * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining 1816 */ 1817 render: function() { 1818 // Activate the default state if no active state exists. 1819 if ( ! this.state() && this.options.state ) { 1820 this.setState( this.options.state ); 1821 } 1822 /** 1823 * call 'render' directly on the parent class 1824 */ 1825 return media.view.Frame.prototype.render.apply( this, arguments ); 1826 }, 1827 /** 1828 * @param {Object} title 1829 * @this wp.media.controller.Region 1830 */ 1831 createTitle: function( title ) { 1832 title.view = new media.View({ 1833 controller: this, 1834 tagName: 'h1' 1835 }); 1836 }, 1837 /** 1838 * @param {Object} menu 1839 * @this wp.media.controller.Region 1840 */ 1841 createMenu: function( menu ) { 1842 menu.view = new media.view.Menu({ 1843 controller: this 1844 }); 1845 }, 1846 /** 1847 * @param {Object} toolbar 1848 * @this wp.media.controller.Region 1849 */ 1850 createToolbar: function( toolbar ) { 1851 toolbar.view = new media.view.Toolbar({ 1852 controller: this 1853 }); 1854 }, 1855 /** 1856 * @param {Object} router 1857 * @this wp.media.controller.Region 1858 */ 1859 createRouter: function( router ) { 1860 router.view = new media.view.Router({ 1861 controller: this 1862 }); 1863 }, 1864 /** 1865 * @param {Object} options 1866 */ 1867 createIframeStates: function( options ) { 1868 var settings = media.view.settings, 1869 tabs = settings.tabs, 1870 tabUrl = settings.tabUrl, 1871 $postId; 1872 1873 if ( ! tabs || ! tabUrl ) { 1874 return; 1875 } 1876 1877 // Add the post ID to the tab URL if it exists. 1878 $postId = $('#post_ID'); 1879 if ( $postId.length ) { 1880 tabUrl += '&post_id=' + $postId.val(); 1881 } 1882 1883 // Generate the tab states. 1884 _.each( tabs, function( title, id ) { 1885 this.state( 'iframe:' + id ).set( _.defaults({ 1886 tab: id, 1887 src: tabUrl + '&tab=' + id, 1888 title: title, 1889 content: 'iframe', 1890 menu: 'default' 1891 }, options ) ); 1892 }, this ); 1893 1894 this.on( 'content:create:iframe', this.iframeContent, this ); 1895 this.on( 'menu:render:default', this.iframeMenu, this ); 1896 this.on( 'open', this.hijackThickbox, this ); 1897 this.on( 'close', this.restoreThickbox, this ); 1898 }, 1899 1900 /** 1901 * @param {Object} content 1902 * @this wp.media.controller.Region 1903 */ 1904 iframeContent: function( content ) { 1905 this.$el.addClass('hide-toolbar'); 1906 content.view = new media.view.Iframe({ 1907 controller: this 1908 }); 1909 }, 1910 1911 iframeMenu: function( view ) { 1912 var views = {}; 1913 1914 if ( ! view ) { 1915 return; 1916 } 1917 1918 _.each( media.view.settings.tabs, function( title, id ) { 1919 views[ 'iframe:' + id ] = { 1920 text: this.state( 'iframe:' + id ).get('title'), 1921 priority: 200 1922 }; 1923 }, this ); 1924 1925 view.set( views ); 1926 }, 1927 1928 hijackThickbox: function() { 1929 var frame = this; 1930 1931 if ( ! window.tb_remove || this._tb_remove ) { 1932 return; 1933 } 1934 1935 this._tb_remove = window.tb_remove; 1936 window.tb_remove = function() { 1937 frame.close(); 1938 frame.reset(); 1939 frame.setState( frame.options.state ); 1940 frame._tb_remove.call( window ); 1941 }; 1942 }, 1943 1944 restoreThickbox: function() { 1945 if ( ! this._tb_remove ) { 1946 return; 1947 } 1948 1949 window.tb_remove = this._tb_remove; 1950 delete this._tb_remove; 1951 }, 1952 1743 }, 1953 1744 /** 1954 1745 * Map activeMode collection events to the frame. … … 1968 1759 } ); 1969 1760 1970 if ( ! _.has( modeEventMap, collectionEvent ) ) 1761 if ( ! _.has( modeEventMap, collectionEvent ) ) { 1971 1762 return; 1763 } 1972 1764 1973 1765 eventToTrigger = model.get('id') + ':' + modeEventMap[collectionEvent]; … … 1986 1778 } 1987 1779 this.activeModes.add( [ { id: mode } ] ); 1988 // Add a css class to the frame for anything that needs to be styled 1989 // for the mode. 1780 // Add a CSS class to the frame so elements can be styled for the mode. 1990 1781 this.$el.addClass( 'mode-' + mode ); 1991 1782 /** … … 2028 1819 isModeActive: function( mode ) { 2029 1820 return Boolean( this.activeModes.where( { id: mode } ).length ); 1821 } 1822 }); 1823 1824 // Make the `Frame` a `StateMachine`. 1825 _.extend( media.view.Frame.prototype, media.controller.StateMachine.prototype ); 1826 1827 /** 1828 * wp.media.view.MediaFrame 1829 * 1830 * Type of frame used to create the media modal. 1831 * 1832 * @constructor 1833 * @augments wp.media.view.Frame 1834 * @augments wp.media.View 1835 * @augments wp.Backbone.View 1836 * @augments Backbone.View 1837 * @mixes wp.media.controller.StateMachine 1838 */ 1839 media.view.MediaFrame = media.view.Frame.extend({ 1840 className: 'media-frame', 1841 template: media.template('media-frame'), 1842 regions: ['menu','title','content','toolbar','router'], 1843 1844 /** 1845 * @global wp.Uploader 1846 */ 1847 initialize: function() { 1848 media.view.Frame.prototype.initialize.apply( this, arguments ); 1849 1850 _.defaults( this.options, { 1851 title: '', 1852 modal: true, 1853 uploader: true 1854 }); 1855 1856 // Ensure core UI is enabled. 1857 this.$el.addClass('wp-core-ui'); 1858 1859 // Initialize modal container view. 1860 if ( this.options.modal ) { 1861 this.modal = new media.view.Modal({ 1862 controller: this, 1863 title: this.options.title 1864 }); 1865 1866 this.modal.content( this ); 1867 } 1868 1869 // Force the uploader off if the upload limit has been exceeded or 1870 // if the browser isn't supported. 1871 if ( wp.Uploader.limitExceeded || ! wp.Uploader.browser.supported ) { 1872 this.options.uploader = false; 1873 } 1874 1875 // Initialize window-wide uploader. 1876 if ( this.options.uploader ) { 1877 this.uploader = new media.view.UploaderWindow({ 1878 controller: this, 1879 uploader: { 1880 dropzone: this.modal ? this.modal.$el : this.$el, 1881 container: this.$el 1882 } 1883 }); 1884 this.views.set( '.media-frame-uploader', this.uploader ); 1885 } 1886 1887 this.on( 'attach', _.bind( this.views.ready, this.views ), this ); 1888 1889 // Bind default title creation. 1890 this.on( 'title:create:default', this.createTitle, this ); 1891 this.title.mode('default'); 1892 1893 // Bind default menu. 1894 this.on( 'menu:create:default', this.createMenu, this ); 1895 }, 1896 /** 1897 * @returns {wp.media.view.MediaFrame} Returns itself to allow chaining 1898 */ 1899 render: function() { 1900 // Activate the default state if no active state exists. 1901 if ( ! this.state() && this.options.state ) { 1902 this.setState( this.options.state ); 1903 } 1904 /** 1905 * call 'render' directly on the parent class 1906 */ 1907 return media.view.Frame.prototype.render.apply( this, arguments ); 1908 }, 1909 /** 1910 * @param {Object} title 1911 * @this wp.media.controller.Region 1912 */ 1913 createTitle: function( title ) { 1914 title.view = new media.View({ 1915 controller: this, 1916 tagName: 'h1' 1917 }); 1918 }, 1919 /** 1920 * @param {Object} menu 1921 * @this wp.media.controller.Region 1922 */ 1923 createMenu: function( menu ) { 1924 menu.view = new media.view.Menu({ 1925 controller: this 1926 }); 1927 }, 1928 /** 1929 * @param {Object} toolbar 1930 * @this wp.media.controller.Region 1931 */ 1932 createToolbar: function( toolbar ) { 1933 toolbar.view = new media.view.Toolbar({ 1934 controller: this 1935 }); 1936 }, 1937 /** 1938 * @param {Object} router 1939 * @this wp.media.controller.Region 1940 */ 1941 createRouter: function( router ) { 1942 router.view = new media.view.Router({ 1943 controller: this 1944 }); 1945 }, 1946 /** 1947 * @param {Object} options 1948 */ 1949 createIframeStates: function( options ) { 1950 var settings = media.view.settings, 1951 tabs = settings.tabs, 1952 tabUrl = settings.tabUrl, 1953 $postId; 1954 1955 if ( ! tabs || ! tabUrl ) { 1956 return; 1957 } 1958 1959 // Add the post ID to the tab URL if it exists. 1960 $postId = $('#post_ID'); 1961 if ( $postId.length ) { 1962 tabUrl += '&post_id=' + $postId.val(); 1963 } 1964 1965 // Generate the tab states. 1966 _.each( tabs, function( title, id ) { 1967 this.state( 'iframe:' + id ).set( _.defaults({ 1968 tab: id, 1969 src: tabUrl + '&tab=' + id, 1970 title: title, 1971 content: 'iframe', 1972 menu: 'default' 1973 }, options ) ); 1974 }, this ); 1975 1976 this.on( 'content:create:iframe', this.iframeContent, this ); 1977 this.on( 'menu:render:default', this.iframeMenu, this ); 1978 this.on( 'open', this.hijackThickbox, this ); 1979 this.on( 'close', this.restoreThickbox, this ); 1980 }, 1981 1982 /** 1983 * @param {Object} content 1984 * @this wp.media.controller.Region 1985 */ 1986 iframeContent: function( content ) { 1987 this.$el.addClass('hide-toolbar'); 1988 content.view = new media.view.Iframe({ 1989 controller: this 1990 }); 1991 }, 1992 1993 iframeMenu: function( view ) { 1994 var views = {}; 1995 1996 if ( ! view ) { 1997 return; 1998 } 1999 2000 _.each( media.view.settings.tabs, function( title, id ) { 2001 views[ 'iframe:' + id ] = { 2002 text: this.state( 'iframe:' + id ).get('title'), 2003 priority: 200 2004 }; 2005 }, this ); 2006 2007 view.set( views ); 2008 }, 2009 2010 hijackThickbox: function() { 2011 var frame = this; 2012 2013 if ( ! window.tb_remove || this._tb_remove ) { 2014 return; 2015 } 2016 2017 this._tb_remove = window.tb_remove; 2018 window.tb_remove = function() { 2019 frame.close(); 2020 frame.reset(); 2021 frame.setState( frame.options.state ); 2022 frame._tb_remove.call( window ); 2023 }; 2024 }, 2025 2026 restoreThickbox: function() { 2027 if ( ! this._tb_remove ) { 2028 return; 2029 } 2030 2031 window.tb_remove = this._tb_remove; 2032 delete this._tb_remove; 2030 2033 } 2031 2034 }); … … 4632 4635 4633 4636 initialize: function() { 4634 var selection = this.options.selection; 4635 4636 this.$el.attr('aria-label', this.model.attributes.title).attr('aria-checked', false); 4637 this.model.on( 'change', this.render, this ); 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 ); 4642 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 ); … … 4647 4655 if ( selection ) { 4648 4656 selection.on( 'reset', this.updateSelect, this ); 4649 } 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') ); 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') ); 4660 } 4654 4661 }, 4655 4662 /** … … 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; … … 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 },6326 /**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 6335 }, 6336 6336 /** … … 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(); -
trunk/src/wp-includes/media-template.php
r29263 r29266 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 }}"> … … 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
Note: See TracChangeset
for help on using the changeset viewer.