Changeset 22320
- Timestamp:
- 10/28/2012 11:29:17 PM (12 years ago)
- Location:
- trunk
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/wp-admin/includes/meta-boxes.php
r22044 r22320 1019 1019 $thumbnailId = $element.find('input[name="thumbnail_id"]'), 1020 1020 title = '<?php _e( "Choose a Featured Image" ); ?>', 1021 workflow, se tFeaturedImage;1021 workflow, selection, setFeaturedImage; 1022 1022 1023 1023 setFeaturedImage = function( thumbnailId ) { … … 1038 1038 }); 1039 1039 1040 workflow.selection.on( 'add', function( model ) { 1040 selection = workflow.state().get('selection'); 1041 1042 selection.on( 'add', function( model ) { 1041 1043 var sizes = model.get('sizes'), 1042 1044 size; … … 1052 1054 size = size || model.toJSON(); 1053 1055 1054 workflow. modal.close();1055 workflow.selection.clear();1056 workflow.close(); 1057 selection.clear(); 1056 1058 1057 1059 $( '<img />', { … … 1062 1064 } 1063 1065 1064 workflow. modal.open();1066 workflow.open(); 1065 1067 }); 1066 1068 -
trunk/wp-admin/js/media-upload.js
r22220 r22320 105 105 workflow = workflows[ id ] = wp.media( _.defaults( options || {}, { 106 106 title: wp.media.view.l10n.insertMedia, 107 multiple: true, 108 describe: true 107 multiple: true 109 108 } ) ); 110 109 111 workflow. on( 'update:insert', function( selection ) {110 workflow.get('library').on( 'insert', function( selection ) { 112 111 this.insert( selection.map( function( attachment ) { 113 112 if ( 'image' === attachment.get('type') ) … … 118 117 }, this ); 119 118 120 workflow. on( 'update:gallery', function( selection ) {119 workflow.get('gallery').on( 'update', function( selection ) { 121 120 var view = wp.mce.view.get('gallery'), 122 121 shortcode; -
trunk/wp-includes/css/media-views.css
r22247 r22320 76 76 z-index: 50; 77 77 height: 60px; 78 padding: 0 10px; 78 79 border-bottom: 1px solid #dfdfdf; 79 80 } … … 102 103 103 104 /** 104 * Workspace 105 */ 106 .media-workspace { 107 position: relative; 108 width: 100%; 109 height: 100%; 110 } 111 112 .upload-attachments { 113 position: absolute; 114 top: 0; 115 left: 0; 116 bottom: 0; 117 width: 180px; 118 margin: 10px; 119 text-align: center; 120 border: 3px dashed #dfdfdf; 121 background: #fff; 122 z-index: 100; 123 } 124 125 .upload-attachments h3 { 126 font-size: 18px; 127 font-weight: 200; 128 color: #777; 129 padding: 40px 0 0; 130 margin: 0; 131 } 132 133 .upload-attachments span { 134 display: block; 135 color: #777; 136 margin: 10px 0; 137 } 138 139 .upload-attachments a { 140 display: inline-block; 141 margin: 0 auto; 142 } 143 144 .drag-over .upload-attachments { 145 width: auto; 146 right: 0; 147 border-color: #83B4D8; 148 box-shadow: 0 0 0 10px #fff; 149 } 150 151 .existing-attachments { 152 position: absolute; 153 top: 0; 154 left: 200px; 155 right: 0; 156 bottom: 0; 157 margin: 0 20px; 158 } 159 160 .media-workspace .attachments, 161 .media-workspace .media-toolbar { 105 * Frame 106 */ 107 108 .media-frame .attachments, 109 .media-frame .media-toolbar { 162 110 -webkit-transition-property: left, right, top, bottom, margin; 163 111 -moz-transition-property: left, right, top, bottom, margin; … … 173 121 } 174 122 175 .media- workspace .attachments {176 position: absolute; 177 top: 0;123 .media-frame .attachments { 124 position: absolute; 125 top: 61px; 178 126 left: 0; 179 127 right: 0; … … 183 131 } 184 132 185 .media-workspace.with-toolbar .attachments { 186 top: 61px; 187 } 188 189 .media-workspace .media-toolbar { 133 .media-frame.hide-toolbar .attachments { 134 top: 0; 135 } 136 137 .media-frame .media-toolbar { 138 margin-top: 0; 139 } 140 141 .media-frame.hide-toolbar .media-toolbar { 190 142 margin-top: -61px; 191 143 } 192 144 193 .media-workspace.with-toolbar .media-toolbar { 194 margin-top: 0; 195 } 196 197 .media-workspace .media-toolbar .add-to-gallery { 145 .media-frame .media-toolbar .add-to-gallery { 198 146 display: none; 199 147 } 200 201 148 /** 202 149 * Attachments … … 214 161 right: 0; 215 162 height: 50px; 163 padding: 0 10px; 216 164 background: #fff; 217 165 } … … 243 191 bottom: 0; 244 192 overflow: auto; 245 margin: 0 -10px20px;193 margin: 0 0 20px; 246 194 } 247 195 … … 446 394 } 447 395 448 .upload-attachments .media-progress-bar { 449 margin-top: 80px; 396 .uploader-window { 397 position: fixed; 398 top: 0; 399 left: 0; 400 right: 0; 401 bottom: 0; 402 background: rgba( 0, 86, 132, 0.9 ); 403 404 /*z-index: -200;*/ 405 z-index: 250000; 450 406 display: none; 451 } 452 453 .uploading .upload-attachments .media-progress-bar { 407 text-align: center; 408 opacity: 0; 409 410 -webkit-transition: opacity 250ms; 411 -moz-transition: opacity 250ms; 412 -ms-transition: opacity 250ms; 413 -o-transition: opacity 250ms; 414 transition: opacity 250ms; 415 } 416 417 /*.drag-over .uploader-window { 418 z-index: 250000; 419 }*/ 420 421 .uploader-window-content { 422 position: absolute; 423 top: 30px; 424 left: 30px; 425 right: 30px; 426 bottom: 30px; 427 border: 1px dashed #fff; 428 } 429 430 .uploader-window h3 { 431 position: absolute; 432 top: 50%; 433 left: 0; 434 right: 0; 435 -webkit-transform: translateY( -50% ); 436 -moz-transform: translateY( -50% ); 437 -ms-transform: translateY( -50% ); 438 -o-transform: translateY( -50% ); 439 transform: translateY( -50% ); 440 441 font-size: 18px; 442 font-weight: 200; 443 color: #fff; 444 padding: 0; 445 } 446 447 .uploader-window .media-progress-bar { 448 margin-top: 20px; 449 max-width: 300px; 450 background: transparent; 451 border-color: #fff; 452 /*display: none;*/ 453 } 454 455 .uploader-window .media-progress-bar div { 456 background: #fff; 457 } 458 459 .uploading .uploader-window .media-progress-bar { 454 460 display: block; 455 461 } -
trunk/wp-includes/js/mce-view.js
r22220 r22320 693 693 694 694 this.workflow = wp.media({ 695 view:'gallery',695 state: 'gallery', 696 696 selection: this.attachments.models, 697 697 title: mceview.l10n.editGallery, 698 698 editing: true, 699 multiple: true, 700 describe: true 699 multiple: true 701 700 }); 702 701 -
trunk/wp-includes/js/media-models.js
r22212 r22320 15 15 */ 16 16 media = wp.media = function( attributes ) { 17 if ( media. controller.Workflow)18 return new media. controller.Workflow( attributes ).attach().render();17 if ( media.view.Frame ) 18 return new media.view.Frame( attributes ).render().attach().open(); 19 19 }; 20 20 -
trunk/wp-includes/js/media-views.js
r22267 r22320 9 9 l10n = media.view.l10n = _.isUndefined( _wpMediaViewsL10n ) ? {} : _wpMediaViewsL10n; 10 10 11 // Check if the browser supports CSS 3.0 transitions 12 $.support.transition = (function(){ 13 var style = document.documentElement.style, 14 transitions = { 15 WebkitTransition: 'webkitTransitionEnd', 16 MozTransition: 'transitionend', 17 OTransition: 'oTransitionEnd otransitionend', 18 transition: 'transitionend' 19 }, transition; 20 21 transition = _.find( _.keys( transitions ), function( transition ) { 22 return ! _.isUndefined( style[ transition ] ); 23 }); 24 25 return transition && { 26 end: transitions[ transition ] 27 }; 28 }()); 29 30 // Makes it easier to bind events using transitions. 31 media.transition = function( selector ) { 32 var deferred = $.Deferred(); 33 34 if ( $.support.transition ) { 35 if ( ! (selector instanceof $) ) 36 selector = $( selector ); 37 38 // Resolve the deferred when the first element finishes animating. 39 selector.first().one( $.support.transition.end, deferred.resolve ); 40 41 // Otherwise, execute on the spot. 42 } else { 43 deferred.resolve(); 44 } 45 46 return deferred.promise(); 47 }; 48 11 49 /** 12 50 * ======================================================================== … … 16 54 17 55 /** 18 * wp.media.controller. Workflow56 * wp.media.controller.StateMachine 19 57 */ 20 media.controller.Workflow = Backbone.Model.extend({ 58 media.controller.StateMachine = function( states ) { 59 this.states = new Backbone.Collection( states ); 60 }; 61 62 // Use Backbone's self-propagating `extend` inheritance method. 63 media.controller.StateMachine.extend = Backbone.Model.extend; 64 65 _.extend( media.controller.StateMachine.prototype, { 66 // Fetch a state model. 67 // 68 // Implicitly creates states. 69 get: function( id ) { 70 // Ensure that the `states` collection exists so the `StateMachine` 71 // can be used as a mixin. 72 this.states = this.states || new Backbone.Collection(); 73 74 if ( ! this.states.get( id ) ) 75 this.states.add({ id: id }); 76 return this.states.get( id ); 77 }, 78 79 // Selects or returns the active state. 80 // 81 // If a `id` is provided, sets that as the current state. 82 // If no parameters are provided, returns the current state object. 83 state: function( id ) { 84 var previous; 85 86 if ( id ) { 87 if ( previous = this.state() ) 88 previous.trigger('deactivate'); 89 this._state = id; 90 return this.state().trigger('activate'); 91 } 92 93 if ( this._state ) 94 return this.get( this._state ); 95 } 96 }); 97 98 // Map methods from the `states` collection to the `StateMachine` itself. 99 _.each([ 'on', 'off', 'trigger' ], function( method ) { 100 media.controller.StateMachine.prototype[ method ] = function() { 101 // Ensure that the `states` collection exists so the `StateMachine` 102 // can be used as a mixin. 103 this.states = this.states || new Backbone.Collection(); 104 // Forward the method to the `states` collection. 105 this.states[ method ].apply( this.states, arguments ); 106 return this; 107 }; 108 }); 109 110 // wp.media.controller.Library 111 // --------------------------- 112 media.controller.Library = Backbone.Model.extend({ 21 113 defaults: { 22 title: '', 23 multiple: false, 24 view: 'library', 25 library: {}, 26 selection: [] 114 id: 'library', 115 multiple: false, 116 describe: false 27 117 }, 28 118 29 119 initialize: function() { 120 if ( ! this.get('selection') ) 121 this.set( 'selection', new Attachments() ); 122 123 if ( ! this.get('library') ) 124 this.set( 'library', media.query() ); 125 126 this.on( 'activate', this.activate, this ); 127 }, 128 129 activate: function() { 130 var frame = this.frame, 131 toolbar; 132 133 toolbar = this._postLibraryToolbar = new media.view.Toolbar.PostLibrary({ 134 controller: frame, 135 selection: this.get('selection') 136 }); 137 138 frame.toolbar( toolbar ); 139 this.get('selection').on( 'add remove', toolbar.visibility, toolbar ); 140 141 frame.content( new media.view.Attachments({ 142 directions: this.get('multiple') ? l10n.selectMediaMultiple : l10n.selectMediaSingular, 143 controller: frame, 144 collection: this.get('library'), 145 // The single `Attachment` view to be used in the `Attachments` view. 146 AttachmentView: media.view.Attachment.Library 147 }).render() ); 148 149 if ( ! this.get('selection').length ) 150 frame.$el.addClass('hide-toolbar'); 151 152 // If we're in a workflow that supports multiple attachments, 153 // automatically select any uploading attachments. 154 if ( this.get('multiple') ) 155 wp.Uploader.queue.on( 'add', this.selectUpload, this ); 156 }, 157 158 deactivate: function() { 159 var toolbar = this._postLibraryToolbar; 160 161 wp.Uploader.queue.off( 'add', this.selectUpload, this ); 162 this.get('selection').off( 'add remove', toolbar.visibility, toolbar ); 163 }, 164 165 selectUpload: function( attachment ) { 166 this.get('selection').add( attachment ); 167 } 168 }); 169 170 // wp.media.controller.Gallery 171 // --------------------------- 172 media.controller.Gallery = Backbone.Model.extend({ 173 defaults: { 174 id: 'gallery', 175 multiple: true, 176 describe: true 177 }, 178 179 initialize: function() { 180 if ( ! this.get('selection') ) 181 this.set( 'selection', new Attachments() ); 182 183 this.on( 'activate', this.activate, this ); 184 }, 185 186 activate: function() { 187 var frame = this.frame; 188 189 frame.toolbar( new media.view.Toolbar.Gallery({ 190 controller: frame, 191 editing: this.get('editing'), 192 selection: this.get('selection') 193 }) ); 194 195 frame.content( new media.view.Attachments({ 196 directions: 'Gallery time!', 197 controller: frame, 198 collection: this.get('selection'), 199 sortable: true, 200 // The single `Attachment` view to be used in the `Attachments` view. 201 AttachmentView: media.view.Attachment.Gallery 202 }).render() ); 203 204 // Automatically select any uploading attachments. 205 wp.Uploader.queue.on( 'add', this.selectUpload, this ); 206 }, 207 208 deactivate: function() { 209 wp.Uploader.queue.off( 'add', this.selectUpload, this ); 210 }, 211 212 selectUpload: function( attachment ) { 213 this.get('selection').add( attachment ); 214 } 215 }); 216 217 /** 218 * ======================================================================== 219 * VIEWS 220 * ======================================================================== 221 */ 222 223 /** 224 * wp.media.view.Frame 225 */ 226 media.view.Frame = Backbone.View.extend({ 227 tagName: 'div', 228 className: 'media-frame', 229 template: media.template('media-frame'), 230 231 initialize: function() { 232 _.defaults( this.options, { 233 state: 'library', 234 title: '', 235 selection: [], 236 library: {}, 237 modal: true, 238 multiple: false, 239 uploader: true 240 }); 241 30 242 this.createSelection(); 31 32 // Initialize view storage. 33 this._views = {}; 34 this._pendingViews = {}; 35 36 // Initialize modal container view. 37 this.modal = new media.view.Modal({ controller: this }); 38 39 // Add default views. 40 // 41 // Use the `library` property to initialize the corresponding view, 42 // then unset the property. 43 this.add( 'library', media.view.Workspace.Library, { 44 collection: media.query( this.get('library') ) 45 }); 46 this.unset('library'); 47 48 // Add the gallery view. 49 this.add( 'gallery', media.view.Workspace.Gallery, { 50 collection: this.selection 51 }); 52 this.add( 'gallery-library', media.view.Workspace.Library.Gallery, { 53 collection: media.query({ type: 'image' }) 54 }); 55 }, 56 57 58 // Registers a view. 59 // 60 // `id` is a unique ID for the view relative to the workflow instance. 61 // `constructor` is a `Backbone.View` constructor. `options` are the 62 // options to be passed when the view is initialized. 63 // 64 // Triggers the `add` and `add:VIEW_ID` events. 65 add: function( id, constructor, options ) { 66 this.remove( id ); 67 this._pendingViews[ id ] = { 68 view: constructor, 69 options: options 70 }; 71 this.trigger( 'add add:' + id, constructor, options ); 72 return this; 73 }, 74 75 // Returns a registered view instance. If an `id` is not provided, 76 // it will return the active view. 77 // 78 // Lazily instantiates a registered view. 79 // 80 // Triggers the `init` and `init:VIEW_ID` events. 81 view: function( id ) { 82 var pending; 83 84 id = id || this.get('view'); 85 pending = this._pendingViews[ id ]; 86 87 if ( ! this._views[ id ] && pending ) { 88 this._views[ id ] = new pending.view( _.extend({ controller: this }, pending.options || {} ) ); 89 delete this._pendingViews[ id ]; 90 this.trigger( 'init init:' + id, this._views[ id ] ); 91 } 92 93 return this._views[ id ]; 94 }, 95 96 // Unregisters a view from the workflow. 97 // 98 // Triggers the `remove` and `remove:VIEW_ID` events. 99 remove: function( id ) { 100 delete this._views[ id ]; 101 delete this._pendingViews[ id ]; 102 this.trigger( 'remove remove:' + id ); 103 return this; 104 }, 105 106 // Renders a view and places it within the modal window. 107 // Automatically adds a view if `constructor` is provided. 108 render: function( id, constructor, options ) { 109 var view; 110 id = id || this.get('view'); 111 112 if ( constructor ) 113 this.add( id, constructor, options ); 114 115 view = this.view( id ); 116 117 if ( ! view ) 118 return this; 119 120 view.render(); 121 this.modal.content( view ); 122 return this; 123 }, 124 125 update: function( event ) { 126 this.close(); 127 this.trigger( 'update', this.selection, this ); 128 this.trigger( 'update:' + event, this.selection, this ); 129 this.selection.clear(); 243 this.createSubviews(); 244 this.createStates(); 245 }, 246 247 render: function() { 248 var els = [ this.sidebar().el, this.toolbar().el, this.content().el ]; 249 250 if ( this.modal ) 251 this.modal.render(); 252 253 // Detach any views that will be rebound to maintain event bidnings. 254 this.$el.children().filter( els ).detach(); 255 this.$el.empty().append( els ); 256 257 // Render the window uploader if it exists. 258 if ( this.uploader ) 259 this.uploader.render().$el.appendTo( this.$el ); 260 261 return this; 130 262 }, 131 263 132 264 createSelection: function() { 133 var controller = this; 134 135 // Initialize workflow-specific models. 136 // Use the `selection` property to initialize the Attachments 137 // collection, then unset the property. 138 this.selection = new Attachments( this.get('selection') ); 139 this.unset('selection'); 140 141 _.extend( this.selection, { 265 var controller = this, 266 selection = this.options.selection; 267 268 if ( ! (selection instanceof Attachments) ) 269 selection = this.options.selection = new Attachments( selection ); 270 271 _.extend( selection, { 142 272 // Override the selection's add method. 143 273 // If the workflow does not support multiple 144 274 // selected attachments, reset the selection. 145 275 add: function( models, options ) { 146 if ( ! controller. get('multiple') ) {276 if ( ! controller.state().get('multiple') ) { 147 277 models = _.isArray( models ) ? _.first( models ) : models; 148 278 this.clear( options ); … … 171 301 } 172 302 }); 173 } 174 }); 175 176 // Map modal methods to the workflow. 177 _.each(['attach','detach','open','close'], function( method ) { 178 media.controller.Workflow.prototype[ method ] = function() { 179 this.modal[ method ].apply( this.modal, arguments ); 180 return this; 303 }, 304 305 createStates: function() { 306 var options = this.options; 307 308 // Create the default `states` collection. 309 this.states = new Backbone.Collection(); 310 311 // Ensure states have a reference to the frame. 312 this.states.on( 'add', function( model ) { 313 model.frame = this; 314 }, this ); 315 316 // Add the default states. 317 this.states.add([ 318 new media.controller.Library({ 319 selection: options.selection, 320 collection: media.query( options.library ), 321 multiple: this.options.multiple 322 }), 323 new media.controller.Gallery({ 324 selection: options.selection 325 }) 326 ]); 327 328 // Set the default state. 329 this.state( options.state ); 330 }, 331 332 createSubviews: function() { 333 // Initialize a stub view for each subview region. 334 _.each(['toolbar','sidebar','content'], function( subview ) { 335 this[ '_' + subview ] = new Backbone.View({ 336 tagName: 'div', 337 className: 'media-' + subview 338 }); 339 }, this ); 340 341 // Initialize modal container view. 342 if ( this.options.modal ) { 343 this.modal = new media.view.Modal({ 344 controller: this, 345 $content: this.$el, 346 title: this.options.title 347 }); 348 } 349 350 // Initialize window-wide uploader. 351 if ( this.options.uploader ) { 352 this.uploader = new media.view.UploaderWindow({ 353 uploader: { 354 dropzone: this.modal ? this.modal.$el : this.$el 355 } 356 }); 357 } 358 } 359 }); 360 361 // Make the `Frame` a `StateMachine`. 362 _.extend( media.view.Frame.prototype, media.controller.StateMachine.prototype ); 363 364 // Create methods to fetch and replace individual subviews. 365 _.each(['toolbar','sidebar','content'], function( subview ) { 366 media.view.Frame.prototype[ subview ] = function( view ) { 367 var previous = this[ '_' + subview ]; 368 369 if ( ! view ) 370 return previous; 371 372 view.$el.addClass( 'media-' + subview ); 373 374 if ( previous.destroy ) 375 previous.destroy(); 376 previous.undelegateEvents(); 377 previous.$el.replaceWith( view.$el ); 378 this[ '_' + subview ] = view; 181 379 }; 182 380 }); 183 381 184 /** 185 * ======================================================================== 186 * VIEWS 187 * ======================================================================== 188 */ 382 // Map some of the modal's methods to the frame. 383 _.each(['open','close','attach','detach'], function( method ) { 384 media.view.Frame.prototype[ method ] = function( view ) { 385 if ( this.modal ) 386 this.modal[ method ].apply( this.modal, arguments ); 387 return this; 388 }; 389 }); 189 390 190 391 /** … … 201 402 initialize: function() { 202 403 this.controller = this.options.controller; 203 this.controller.on( 'change:title', this.render, this );204 404 205 405 _.defaults( this.options, { 206 container: document.body 406 container: document.body, 407 title: '' 207 408 }); 208 409 }, … … 216 417 this.options.$content.detach(); 217 418 218 this.$el.html( this.template( this.controller.toJSON() ) ); 219 this.$('.media-modal-content').append( this.options.$content ); 419 this.$el.html( this.template({ 420 title: this.options.title 421 }) ); 422 423 this.options.$content.addClass('media-modal-content'); 424 this.$('.media-modal').append( this.options.$content ); 220 425 return this; 221 426 }, … … 224 429 this.$el.appendTo( this.options.container ); 225 430 this.controller.trigger( 'attach', this.controller ); 431 return this; 226 432 }, 227 433 … … 229 435 this.$el.detach(); 230 436 this.controller.trigger( 'detach', this.controller ); 437 return this; 231 438 }, 232 439 … … 234 441 this.$el.show(); 235 442 this.controller.trigger( 'open', this.controller ); 443 return this; 236 444 }, 237 445 … … 239 447 this.$el.hide(); 240 448 this.controller.trigger( 'close', this.controller ); 449 return this; 241 450 }, 242 451 … … 256 465 } 257 466 }); 467 468 // wp.media.view.UploaderWindow 469 // ---------------------------- 470 media.view.UploaderWindow = Backbone.View.extend({ 471 tagName: 'div', 472 className: 'uploader-window', 473 template: media.template('uploader-window'), 474 475 initialize: function() { 476 var uploader; 477 478 this.controller = this.options.controller; 479 480 uploader = this.options.uploader = _.defaults( this.options.uploader || {}, { 481 container: this.$el, 482 dropzone: this.$el, 483 browser: this.$('.upload-attachments a'), 484 params: {} 485 }); 486 487 // Track uploading attachments. 488 wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this ); 489 490 if ( uploader.dropzone ) { 491 // Ensure the dropzone is a jQuery collection. 492 if ( ! (uploader.dropzone instanceof $) ) 493 uploader.dropzone = $( uploader.dropzone ); 494 495 // Attempt to initialize the uploader whenever the dropzone is hovered. 496 uploader.dropzone.one( 'mouseenter dragenter', _.bind( this.maybeInitUploader, this ) ); 497 } 498 }, 499 500 render: function() { 501 this.maybeInitUploader(); 502 this.renderUploadProgress(); 503 this.$el.html( this.template( this.options ) ); 504 this.$bar = this.$('.upload-attachments .media-progress-bar div'); 505 return this; 506 }, 507 508 maybeInitUploader: function() { 509 var $id, dropzone; 510 511 // If the uploader already exists or the body isn't in the DOM, bail. 512 if ( this.uploader || ! this.$el.closest('body').length ) 513 return; 514 515 $id = $('#post_ID'); 516 if ( $id.length ) 517 this.options.uploader.params.post_id = $id.val(); 518 519 this.uploader = new wp.Uploader( this.options.uploader ); 520 521 dropzone = this.uploader.dropzone; 522 dropzone.on( 'dropzone:enter', _.bind( this.show, this ) ); 523 dropzone.on( 'dropzone:leave', _.bind( this.hide, this ) ); 524 }, 525 526 show: function() { 527 var $el = this.$el.show(); 528 529 // Ensure that the animation is triggered by waiting until 530 // the transparent element is painted into the DOM. 531 _.defer( function() { 532 $el.css({ opacity: 1 }); 533 }); 534 }, 535 536 hide: function() { 537 var $el = this.$el.css({ opacity: 0 }); 538 539 media.transition( $el ).done( function() { 540 // Transition end events are subject to race conditions. 541 // Make sure that the value is set as intended. 542 if ( '0' === $el.css('opacity') ) 543 $el.hide(); 544 }); 545 }, 546 547 renderUploadProgress: function() { 548 var queue = wp.Uploader.queue; 549 550 this.$el.toggleClass( 'uploading', !! queue.length ); 551 552 if ( ! this.$bar || ! queue.length ) 553 return; 554 555 this.$bar.width( ( queue.reduce( function( memo, attachment ) { 556 if ( attachment.get('uploading') ) 557 return memo + ( attachment.get('percent') || 0 ); 558 else 559 return memo + 100; 560 }, 0 ) / queue.length ) + '%' ); 561 } 562 }); 563 258 564 259 565 /** … … 265 571 266 572 initialize: function() { 267 this._views = {}; 573 this.controller = this.options.controller; 574 575 this._views = {}; 268 576 this.$primary = $('<div class="media-toolbar-primary" />').prependTo( this.$el ); 269 577 this.$secondary = $('<div class="media-toolbar-secondary" />').prependTo( this.$el ); 270 578 271 if ( this.options.items ) { 272 _.each( this.options.items, function( view, id ) { 273 this.add( id, view, { silent: true } ); 274 }, this ); 275 this.render(); 276 } 579 if ( this.options.items ) 580 this.add( this.options.items, { silent: true }).render(); 277 581 }, 278 582 … … 294 598 295 599 add: function( id, view, options ) { 600 // Accept an object with an `id` : `view` mapping. 601 if ( _.isObject( id ) ) { 602 _.each( id, function( view, id ) { 603 this.add( id, view, options ); 604 }, this ); 605 return this; 606 } 607 296 608 if ( ! ( view instanceof Backbone.View ) ) { 297 609 view.classes = [ id ].concat( view.classes || [] ); … … 299 611 } 300 612 613 view.controller = view.controller || this.controller; 614 301 615 this._views[ id ] = view; 302 616 if ( ! options || ! options.silent ) … … 317 631 }); 318 632 633 // wp.media.view.Toolbar.PostLibrary 634 // --------------------------------- 635 media.view.Toolbar.PostLibrary = media.view.Toolbar.extend({ 636 initialize: function() { 637 var selection = this.options.selection, 638 controller = this.options.controller; 639 640 this.options.items = { 641 'selection-preview': new media.view.SelectionPreview({ 642 controller: controller, 643 collection: selection, 644 priority: -40 645 }), 646 647 'create-new-gallery': { 648 style: 'primary', 649 text: l10n.createNewGallery, 650 priority: 40, 651 652 click: function() { 653 this.controller.state('gallery'); 654 } 655 }, 656 657 'insert-into-post': new media.view.ButtonGroup({ 658 priority: 30, 659 classes: 'dropdown-flip-x', 660 buttons: [ 661 { 662 text: l10n.insertIntoPost, 663 click: function() { 664 controller.close(); 665 controller.state().trigger( 'insert', selection ); 666 selection.clear(); 667 } 668 }, 669 { 670 classes: ['down-arrow'], 671 dropdown: new media.view.AttachmentDisplaySettings().render().$el, 672 673 click: function( event ) { 674 var $el = this.$el; 675 676 if ( ! $( event.target ).closest('.dropdown').length ) 677 $el.toggleClass('active'); 678 679 // Stop the event from propagating further so we can bind 680 // a one-time event to the body (and ensure that a click 681 // on the dropdown won't trigger said event). 682 event.stopPropagation(); 683 684 if ( $el.is(':visible') ) { 685 $(document.body).one( 'click', function() { 686 $el.removeClass('active'); 687 }); 688 } 689 } 690 } 691 ] 692 }).render(), 693 694 'add-to-gallery': { 695 text: l10n.addToGallery, 696 priority: 20 697 } 698 }; 699 700 media.view.Toolbar.prototype.initialize.apply( this, arguments ); 701 }, 702 703 visibility: function() { 704 var selection = this.options.selection, 705 controller = this.options.controller, 706 count = selection.length, 707 showGallery; 708 709 controller.$el.toggleClass( 'hide-toolbar', ! count ); 710 711 // Check if every attachment in the selection is an image. 712 showGallery = count > 1 && selection.all( function( attachment ) { 713 return 'image' === attachment.get('type'); 714 }); 715 716 this.get('create-new-gallery').$el.toggle( showGallery ); 717 insert = this.get('insert-into-post'); 718 _.each( insert.buttons, function( button ) { 719 button.model.set( 'style', showGallery ? '' : 'primary' ); 720 }); 721 } 722 }); 723 724 // wp.media.view.Toolbar.Gallery 725 // ----------------------------- 726 media.view.Toolbar.Gallery = media.view.Toolbar.extend({ 727 initialize: function() { 728 var editing = this.options.editing, 729 selection = this.options.selection, 730 controller = this.options.controller; 731 732 this.options.items = { 733 'update-gallery': { 734 style: 'primary', 735 text: editing ? l10n.updateGallery : l10n.insertGalleryIntoPost, 736 priority: 40, 737 click: function() { 738 controller.close(); 739 controller.state().trigger( 'update', selection ); 740 selection.clear(); 741 controller.state('library'); 742 } 743 }, 744 745 'return-to-library': { 746 text: editing ? l10n.addImagesFromLibrary : l10n.returnToLibrary, 747 priority: -40, 748 749 click: function() { 750 this.controller.state('library'); 751 } 752 } 753 }; 754 755 media.view.Toolbar.prototype.initialize.apply( this, arguments ); 756 } 757 }); 319 758 320 759 /** … … 460 899 461 900 options.buttons = this.buttons; 462 options.describe = this.controller. get('describe');901 options.describe = this.controller.state().get('describe'); 463 902 464 903 if ( 'image' === options.type ) … … 473 912 474 913 // Check if the model is selected. 475 if ( this. controller.selection.has( this.model) )914 if ( this.selected() ) 476 915 this.select(); 477 916 … … 485 924 486 925 toggleSelection: function( event ) { 487 var selection = this.controller.selection; 926 var selection = this.controller.state().get('selection'); 927 928 if ( ! selection ) 929 return; 930 488 931 selection[ selection.has( this.model ) ? 'remove' : 'add' ]( this.model ); 489 932 }, 490 933 934 selected: function() { 935 var selection = this.controller.state().get('selection'); 936 if ( selection ) 937 return selection.has( this.model ); 938 }, 939 491 940 select: function( model, collection ) { 492 // If a collection is provided, check if it's the selection. 493 // If it's not, bail; we're in another selection's event loop. 494 if ( collection && collection !== this.controller.selection ) 941 var selection = this.controller.state().get('selection'); 942 943 // Check if a selection exists and if it's the collection provided. 944 // If they're not the same collection, bail; we're in another 945 // selection's event loop. 946 if ( ! selection || ( collection && collection !== selection ) ) 495 947 return; 496 948 … … 499 951 500 952 deselect: function( model, collection ) { 501 // If a collection is provided, check if it's the selection. 502 // If it's not, bail; we're in another selection's event loop. 503 if ( collection && collection !== this.controller.selection ) 953 var selection = this.controller.state().get('selection'); 954 955 // Check if a selection exists and if it's the collection provided. 956 // If they're not the same collection, bail; we're in another 957 // selection's event loop. 958 if ( ! selection || ( collection && collection !== selection ) ) 504 959 return; 505 960 … … 609 1064 }()) 610 1065 }); 611 612 /**613 * wp.media.view.Workspace614 */615 media.view.Workspace = Backbone.View.extend({616 tagName: 'div',617 className: 'media-workspace',618 template: media.template('media-workspace'),619 620 // The `options` to be passed to `Attachments` view.621 attachmentsView: {},622 623 events: {624 'dragenter': 'maybeInitUploader',625 'mouseenter': 'maybeInitUploader'626 },627 628 initialize: function() {629 this.controller = this.options.controller;630 631 _.defaults( this.options, {632 selectOne: false,633 uploader: {},634 attachmentsView: {}635 });636 637 this.$content = $('<div class="existing-attachments" />');638 639 // Generate the `options` passed to the `Attachments` view.640 // Order of priority from lowest to highest: the provided defaults,641 // the prototypal `attachmentsView` property, the `attachmentsView`642 // option for the current instance, and then the `controller` and643 // `collection` keys, to ensure they're correctly set.644 this.attachmentsView = _.extend( {645 directions: this.controller.get('multiple') ? l10n.selectMediaMultiple : l10n.selectMediaSingular646 }, this.attachmentsView, this.options.attachmentsView, {647 controller: this.controller,648 collection: this.collection649 });650 651 // Initialize the `Attachments` view.652 this.attachmentsView = new media.view.Attachments( this.attachmentsView );653 this.$content.append( this.attachmentsView.$el );654 655 // Track uploading attachments.656 wp.Uploader.queue.on( 'add remove reset change:percent', this.renderUploadProgress, this );657 658 // If we're in a workflow that supports multiple attachments,659 // automatically select any uploading attachments.660 if ( this.controller.get('multiple') )661 wp.Uploader.queue.on( 'add', this.selectUpload, this );662 },663 664 render: function() {665 this.$content.detach();666 667 this.attachmentsView.render();668 this.renderUploadProgress();669 this.$el.html( this.template( this.options ) ).append( this.$content );670 this.$bar = this.$('.upload-attachments .media-progress-bar div');671 return this;672 },673 674 maybeInitUploader: function() {675 var workspace = this,676 params = {},677 $id;678 679 // If the uploader already exists or the body isn't in the DOM, bail.680 if ( this.uploader || ! this.$el.closest('body').length )681 return;682 683 $id = $('#post_ID');684 if ( $id.length )685 params.post_id = $id.val();686 687 this.uploader = new wp.Uploader( _.extend({688 container: this.$el,689 dropzone: this.$el,690 browser: this.$('.upload-attachments a'),691 params: params692 }, this.options.uploader ) );693 },694 695 selectUpload: function( attachment ) {696 this.controller.selection.add( attachment );697 },698 699 renderUploadProgress: function() {700 var queue = wp.Uploader.queue;701 702 this.$el.toggleClass( 'uploading', !! queue.length );703 704 if ( ! this.$bar || ! queue.length )705 return;706 707 this.$bar.width( ( queue.reduce( function( memo, attachment ) {708 if ( attachment.get('uploading') )709 return memo + ( attachment.get('percent') || 0 );710 else711 return memo + 100;712 }, 0 ) / queue.length ) + '%' );713 }714 });715 716 /**717 * wp.media.view.Workspace.Library718 */719 media.view.Workspace.Library = media.view.Workspace.extend({720 721 attachmentsView: {722 // The single `Attachment` view to be used in the `Attachments` view.723 AttachmentView: media.view.Attachment.Library724 },725 726 initialize: function() {727 media.view.Workspace.prototype.initialize.apply( this, arguments );728 729 // If this supports multiple attachments, initialize the sample toolbar view.730 if ( this.controller.get('multiple') )731 this.initToolbarView();732 },733 734 // Initializes the toolbar view. Currently uses defaults set for735 // inserting media into a post. This should be pulled out into the736 // appropriate workflow when the time comes, but is currently here737 // to test multiple selections.738 initToolbarView: function() {739 var controller = this.controller;740 741 this.toolbarView = new media.view.Toolbar({742 items: {743 'selection-preview': new media.view.SelectionPreview({744 controller: this.controller,745 collection: this.controller.selection,746 priority: -40747 }),748 749 'create-new-gallery': {750 style: 'primary',751 text: l10n.createNewGallery,752 priority: 40,753 754 click: function() {755 controller.render('gallery');756 }757 },758 759 'insert-into-post': new media.view.ButtonGroup({760 priority: 30,761 classes: 'dropdown-flip-x',762 buttons: [763 {764 text: l10n.insertIntoPost,765 click: _.bind( controller.update, controller, 'insert' )766 },767 {768 classes: ['down-arrow'],769 dropdown: new media.view.AttachmentDisplaySettings().render().$el,770 771 click: function( event ) {772 var $el = this.$el;773 774 if ( ! $( event.target ).closest('.dropdown').length )775 $el.toggleClass('active');776 777 // Stop the event from propagating further so we can bind778 // a one-time event to the body (and ensure that a click779 // on the dropdown won't trigger said event).780 event.stopPropagation();781 782 if ( $el.is(':visible') ) {783 $(document.body).one( 'click', function() {784 $el.removeClass('active');785 });786 }787 }788 }789 ]790 }).render(),791 792 'add-to-gallery': {793 text: l10n.addToGallery,794 priority: 20795 }796 }797 });798 799 this.controller.selection.on( 'add remove', function() {800 var count = this.controller.selection.length,801 showGallery;802 803 this.$el.toggleClass( 'with-toolbar', !! count );804 805 // Check if every attachment in the selection is an image.806 showGallery = count > 1 && this.controller.selection.all( function( attachment ) {807 return 'image' === attachment.get('type');808 });809 810 this.toolbarView.get('create-new-gallery').$el.toggle( showGallery );811 insert = this.toolbarView.get('insert-into-post');812 _.each( insert.buttons, function( button ) {813 button.model.set( 'style', showGallery ? '' : 'primary' );814 });815 }, this );816 817 this.$content.append( this.toolbarView.$el );818 }819 });820 821 media.view.Workspace.Library.Gallery = media.view.Workspace.Library.extend({822 initToolbarView: function() {823 var controller = this.controller,824 editing = controller.get('editing'),825 items = {826 'selection-preview': new media.view.SelectionPreview({827 controller: this.controller,828 collection: this.controller.selection,829 priority: -40,830 clearable: false831 }),832 833 'continue-editing-gallery': {834 style: 'primary',835 text: l10n.continueEditingGallery,836 priority: 40,837 838 click: function() {839 controller.render( 'gallery' );840 }841 }842 };843 844 this.toolbarView = new media.view.Toolbar({845 items: items846 });847 848 this.$el.addClass('with-toolbar');849 this.$content.append( this.toolbarView.$el );850 }851 });852 853 /**854 * wp.media.view.Workspace.Gallery855 */856 media.view.Workspace.Gallery = media.view.Workspace.extend({857 858 attachmentsView: {859 // The single `Attachment` view to be used in the `Attachments` view.860 AttachmentView: media.view.Attachment.Gallery,861 sortable: true862 },863 864 initialize: function() {865 media.view.Workspace.prototype.initialize.apply( this, arguments );866 this.initToolbarView();867 },868 869 // Initializes the toolbar view. Currently uses defaults set for870 // inserting media into a post. This should be pulled out into the871 // appropriate workflow when the time comes, but is currently here872 // to test multiple selections.873 initToolbarView: function() {874 var controller = this.controller,875 editing = controller.get('editing'),876 items = {877 'update-gallery': {878 style: 'primary',879 text: editing ? l10n.updateGallery : l10n.insertGalleryIntoPost,880 priority: 40,881 click: _.bind( controller.update, controller, 'gallery' )882 },883 884 'return-to-library': {885 text: editing ? l10n.addImagesFromLibrary : l10n.returnToLibrary,886 priority: -40,887 888 click: function() {889 controller.render( editing ? 'gallery-library' : 'library' );890 }891 }892 };893 894 this.toolbarView = new media.view.Toolbar({895 items: items896 });897 898 this.$el.addClass('with-toolbar');899 this.$content.append( this.toolbarView.$el );900 }901 });902 903 1066 904 1067 /** -
trunk/wp-includes/js/plupload/wp-plupload.js
r22126 r22320 115 115 return; 116 116 117 dropzone. addClass('drag-over');117 dropzone.trigger('dropzone:enter').addClass('drag-over'); 118 118 active = true; 119 119 }); … … 127 127 timer = setTimeout( function() { 128 128 active = false; 129 dropzone. removeClass('drag-over');129 dropzone.trigger('dropzone:leave').removeClass('drag-over'); 130 130 }, 0 ); 131 131 }); -
trunk/wp-includes/media.php
r22247 r22320 1300 1300 <h3 class="media-modal-title"><%- title %></h3> 1301 1301 <a class="media-modal-close" href="" title="<?php esc_attr_e('Close'); ?>">×</a> 1302 <div class="media-modal-content"></div>1303 1302 </div> 1304 1303 <div class="media-modal-backdrop"></div> 1305 1304 </script> 1306 1305 1307 <script type="text/html" id="tmpl-media-workspace"> 1308 <div class="upload-attachments"> 1309 <% if ( selectOne ) { %> 1310 <h3><?php _e( 'Drop a file here' ); ?></h3> 1311 <span><?php _ex( 'or', 'Uploader: Drop a file here - or - Select a File' ); ?></span> 1312 <a href="#" class="button-secondary"><?php _e( 'Select a File' ); ?></a> 1313 <% } else { %> 1314 <h3><?php _e( 'Drop files here' ); ?></h3> 1315 <span><?php _ex( 'or', 'Uploader: Drop files here - or - Select Files' ); ?></span> 1316 <a href="#" class="button-secondary"><?php _e( 'Select Files' ); ?></a> 1317 <% } %> 1318 1319 <div class="media-progress-bar"><div></div></div> 1306 <script type="text/html" id="tmpl-uploader-window"> 1307 <div class="uploader-window-content"> 1308 <h3><?php _e( 'Drop files here to upload' ); ?></h3> 1320 1309 </div> 1321 1310 </script>
Note: See TracChangeset
for help on using the changeset viewer.