diff --git src/wp-includes/js/media/views/attachments.js src/wp-includes/js/media/views/attachments.js
index 73edcec8f4..2098b01ffc 100644
|
|
|
var View = wp.media.View, |
| 5 | 5 | /** |
| 6 | 6 | * wp.media.view.Attachments |
| 7 | 7 | * |
| | 8 | * Represents the overview of attachments in the Media Library. |
| | 9 | * |
| | 10 | * @since 4.2.0 |
| | 11 | * |
| 8 | 12 | * @memberOf wp.media.view |
| 9 | 13 | * |
| 10 | 14 | * @class |
| 11 | 15 | * @augments wp.media.View |
| 12 | 16 | * @augments wp.Backbone.View |
| 13 | 17 | * @augments Backbone.View |
| | 18 | * |
| | 19 | * @access private |
| 14 | 20 | */ |
| 15 | 21 | Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 16 | 22 | tagName: 'ul', |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 20 | 26 | tabIndex: -1 |
| 21 | 27 | }, |
| 22 | 28 | |
| | 29 | /** |
| | 30 | * Binds events to scrolling to trigger the scroll function. |
| | 31 | * |
| | 32 | * Binds events to the collection this view represents when adding or removing attachments |
| | 33 | * or resetting the entire collection. |
| | 34 | * |
| | 35 | * @since 4.2.0 |
| | 36 | * |
| | 37 | * @constructs |
| | 38 | * @memberof wp.media.view |
| | 39 | * |
| | 40 | * @augments wp.media.View |
| | 41 | * @augments wp.Backbone.View |
| | 42 | * @augments Backbone.View |
| | 43 | * |
| | 44 | * @listens collection:add |
| | 45 | * @listens collection:remove |
| | 46 | * @listens collection:reset |
| | 47 | * @listens controller:library:selection:add |
| | 48 | * @listens scrollElement:scroll |
| | 49 | * @listens this:ready |
| | 50 | * @listens controller:open |
| | 51 | */ |
| 23 | 52 | initialize: function() { |
| 24 | 53 | this.el.id = _.uniqueId('__attachments-view-'); |
| 25 | 54 | |
| | 55 | /** |
| | 56 | * @param refreshSensitivity The time in milliseconds to throttle the scroll handler. |
| | 57 | * @param refreshThreshold The amount of pixels that should be scrolled before loading more attachments |
| | 58 | * from the server. |
| | 59 | * @param AttachmentView The view class to be used for models in the collection. |
| | 60 | * @param sortable A jQuery sortable options object ( http://api.jqueryui.com/sortable/ ). |
| | 61 | * @param resize A boolean indicating whether or not to listen to resize events. |
| | 62 | * @param idealColumnWidth The width in pixels which a column should have when calculating the |
| | 63 | * total number of columns. |
| | 64 | */ |
| 26 | 65 | _.defaults( this.options, { |
| 27 | 66 | refreshSensitivity: wp.media.isTouchDevice ? 300 : 200, |
| 28 | 67 | refreshThreshold: 3, |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 42 | 81 | }); |
| 43 | 82 | }, this ); |
| 44 | 83 | |
| | 84 | /* |
| | 85 | * Find the view to be removed, delete it and call the remove function to clear |
| | 86 | * any set event handlers. |
| | 87 | */ |
| 45 | 88 | this.collection.on( 'remove', function( attachment ) { |
| 46 | 89 | var view = this._viewsByCid[ attachment.cid ]; |
| 47 | 90 | delete this._viewsByCid[ attachment.cid ]; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 69 | 112 | this.on( 'ready', this.bindEvents ); |
| 70 | 113 | this.controller.on( 'open', this.setColumns ); |
| 71 | 114 | |
| 72 | | // Call this.setColumns() after this view has been rendered in the DOM so |
| 73 | | // attachments get proper width applied. |
| | 115 | /* |
| | 116 | * Call this.setColumns() after this view has been rendered in the |
| | 117 | * DOM so attachments get proper width applied. |
| | 118 | */ |
| 74 | 119 | _.defer( this.setColumns, this ); |
| 75 | 120 | } |
| 76 | 121 | }, |
| 77 | 122 | |
| | 123 | /** |
| | 124 | * Listens to the resizeEvent on the window. |
| | 125 | * |
| | 126 | * Listens to the resizeEvent on the window and adjusts the amount of columns accordingly. |
| | 127 | * First removes any existing event handlers to prevent duplicate listeners. |
| | 128 | * |
| | 129 | * @since 4.2.0 |
| | 130 | * |
| | 131 | * @listens window:resize |
| | 132 | * |
| | 133 | * @returns {void} |
| | 134 | */ |
| 78 | 135 | bindEvents: function() { |
| 79 | 136 | this.$window.off( this.resizeEvent ).on( this.resizeEvent, _.debounce( this.setColumns, 50 ) ); |
| 80 | 137 | }, |
| 81 | 138 | |
| | 139 | /** |
| | 140 | * Focuses the first item in the collection. |
| | 141 | * |
| | 142 | * @since 4.2.0 |
| | 143 | * |
| | 144 | * @returns {void} |
| | 145 | */ |
| 82 | 146 | attachmentFocus: function() { |
| 83 | 147 | this.$( 'li:first' ).focus(); |
| 84 | 148 | }, |
| 85 | 149 | |
| | 150 | /** |
| | 151 | * Restores focus to the selected item in the collection. |
| | 152 | * |
| | 153 | * @since 4.2.0 |
| | 154 | * |
| | 155 | * @returns {void} |
| | 156 | */ |
| 86 | 157 | restoreFocus: function() { |
| 87 | 158 | this.$( 'li.selected:first' ).focus(); |
| 88 | 159 | }, |
| 89 | 160 | |
| | 161 | /** |
| | 162 | * Event handler for arrow key presses. |
| | 163 | * Focuses the attachment in the direction of the used arrow key if it exists. |
| | 164 | * |
| | 165 | * @since 4.2.0 |
| | 166 | * |
| | 167 | * @param {KeyboardEvent} event The keyboard event that triggered this function. |
| | 168 | * |
| | 169 | * @returns {void} |
| | 170 | */ |
| 90 | 171 | arrowEvent: function( event ) { |
| 91 | 172 | var attachments = this.$el.children( 'li' ), |
| 92 | 173 | perRow = this.columns, |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 97 | 178 | return; |
| 98 | 179 | } |
| 99 | 180 | |
| 100 | | // Left arrow |
| | 181 | // Left arrow = 37. |
| 101 | 182 | if ( 37 === event.keyCode ) { |
| 102 | 183 | if ( 0 === index ) { |
| 103 | 184 | return; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 105 | 186 | attachments.eq( index - 1 ).focus(); |
| 106 | 187 | } |
| 107 | 188 | |
| 108 | | // Up arrow |
| | 189 | // Up arrow = 38. |
| 109 | 190 | if ( 38 === event.keyCode ) { |
| 110 | 191 | if ( 1 === row ) { |
| 111 | 192 | return; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 113 | 194 | attachments.eq( index - perRow ).focus(); |
| 114 | 195 | } |
| 115 | 196 | |
| 116 | | // Right arrow |
| | 197 | // Right arrow = 39. |
| 117 | 198 | if ( 39 === event.keyCode ) { |
| 118 | 199 | if ( attachments.length === index ) { |
| 119 | 200 | return; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 121 | 202 | attachments.eq( index + 1 ).focus(); |
| 122 | 203 | } |
| 123 | 204 | |
| 124 | | // Down arrow |
| | 205 | // Down arrow = 40. |
| 125 | 206 | if ( 40 === event.keyCode ) { |
| 126 | 207 | if ( Math.ceil( attachments.length / perRow ) === row ) { |
| 127 | 208 | return; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 130 | 211 | } |
| 131 | 212 | }, |
| 132 | 213 | |
| | 214 | /** |
| | 215 | * Clears any set event handlers. |
| | 216 | * |
| | 217 | * @since 4.2.0 |
| | 218 | * |
| | 219 | * @returns {void} |
| | 220 | */ |
| 133 | 221 | dispose: function() { |
| 134 | 222 | this.collection.props.off( null, null, this ); |
| 135 | 223 | if ( this.options.resize ) { |
| 136 | 224 | this.$window.off( this.resizeEvent ); |
| 137 | 225 | } |
| 138 | 226 | |
| 139 | | /** |
| 140 | | * call 'dispose' directly on the parent class |
| 141 | | */ |
| | 227 | // Call 'dispose' directly on the parent class. |
| 142 | 228 | View.prototype.dispose.apply( this, arguments ); |
| 143 | 229 | }, |
| 144 | 230 | |
| | 231 | /** |
| | 232 | * Calculates the amount of columns. |
| | 233 | * |
| | 234 | * Calculates the amount of columns and sets it on the data-columns attribute |
| | 235 | * of .media-frame-content. |
| | 236 | * |
| | 237 | * @since 4.2.0 |
| | 238 | * |
| | 239 | * @returns {void} |
| | 240 | */ |
| 145 | 241 | setColumns: function() { |
| 146 | 242 | var prev = this.columns, |
| 147 | 243 | width = this.$el.width(); |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 155 | 251 | } |
| 156 | 252 | }, |
| 157 | 253 | |
| | 254 | /** |
| | 255 | * Initializes jQuery sortable on the list. |
| | 256 | * |
| | 257 | * Initializes jQuery sortable on the list if jQuery sortable exists and sortable has |
| | 258 | * been passed to the options. |
| | 259 | * |
| | 260 | * @since 4.2.0 |
| | 261 | * |
| | 262 | * @fires collection:reset |
| | 263 | * |
| | 264 | * @returns {void} |
| | 265 | */ |
| 158 | 266 | initSortable: function() { |
| 159 | 267 | var collection = this.collection; |
| 160 | 268 | |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 166 | 274 | // If the `collection` has a `comparator`, disable sorting. |
| 167 | 275 | disabled: !! collection.comparator, |
| 168 | 276 | |
| 169 | | // Change the position of the attachment as soon as the |
| 170 | | // mouse pointer overlaps a thumbnail. |
| | 277 | // Change the position of the attachment as soon as the mouse pointer overlaps a thumbnail. |
| 171 | 278 | tolerance: 'pointer', |
| 172 | 279 | |
| 173 | 280 | // Record the initial `index` of the dragged model. |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 175 | 282 | ui.item.data('sortableIndexStart', ui.item.index()); |
| 176 | 283 | }, |
| 177 | 284 | |
| 178 | | // Update the model's index in the collection. |
| 179 | | // Do so silently, as the view is already accurate. |
| | 285 | /* |
| | 286 | * Update the model's index in the collection. |
| | 287 | * Do so silently, as the view is already accurate. |
| | 288 | */ |
| 180 | 289 | update: function( event, ui ) { |
| 181 | 290 | var model = collection.at( ui.item.data('sortableIndexStart') ), |
| 182 | 291 | comparator = collection.comparator; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 200 | 309 | // Fire the `reset` event to ensure other collections sync. |
| 201 | 310 | collection.trigger( 'reset', collection ); |
| 202 | 311 | |
| 203 | | // If the collection is sorted by menu order, |
| 204 | | // update the menu order. |
| | 312 | // If the collection is sorted by menu order, update the menu order. |
| 205 | 313 | collection.saveMenuOrder(); |
| 206 | 314 | } |
| 207 | 315 | }, this.options.sortable ) ); |
| 208 | 316 | |
| 209 | | // If the `orderby` property is changed on the `collection`, |
| 210 | | // check to see if we have a `comparator`. If so, disable sorting. |
| | 317 | /* |
| | 318 | * If the `orderby` property is changed on the `collection`, |
| | 319 | * check to see if we have a `comparator`. If so, disable sorting. |
| | 320 | */ |
| 211 | 321 | collection.props.on( 'change:orderby', function() { |
| 212 | 322 | this.$el.sortable( 'option', 'disabled', !! collection.comparator ); |
| 213 | 323 | }, this ); |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 216 | 326 | this.refreshSortable(); |
| 217 | 327 | }, |
| 218 | 328 | |
| | 329 | /** |
| | 330 | * Disables jQuery sortable if collection has a comparator or collection.orderby equals menuOrder. |
| | 331 | * |
| | 332 | * @since 4.2.0 |
| | 333 | * |
| | 334 | * @returns {void} |
| | 335 | */ |
| 219 | 336 | refreshSortable: function() { |
| 220 | 337 | if ( ! this.options.sortable || ! $.fn.sortable ) { |
| 221 | 338 | return; |
| 222 | 339 | } |
| 223 | 340 | |
| 224 | | // If the `collection` has a `comparator`, disable sorting. |
| 225 | 341 | var collection = this.collection, |
| 226 | 342 | orderby = collection.props.get('orderby'), |
| 227 | 343 | enabled = 'menuOrder' === orderby || ! collection.comparator; |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 230 | 346 | }, |
| 231 | 347 | |
| 232 | 348 | /** |
| | 349 | * Creates a new view for an attachment and adds it to _viewsByCid. |
| | 350 | * |
| | 351 | * @since 4.2.0 |
| | 352 | * |
| 233 | 353 | * @param {wp.media.model.Attachment} attachment |
| 234 | | * @returns {wp.media.View} |
| | 354 | * |
| | 355 | * @returns {wp.media.View} The created view. |
| 235 | 356 | */ |
| 236 | 357 | createAttachmentView: function( attachment ) { |
| 237 | 358 | var view = new this.options.AttachmentView({ |
| … |
… |
Attachments = View.extend(/** @lends wp.media.view.Attachments.prototype */{ |
| 244 | 365 | return this._viewsByCid[ attachment.cid ] = view; |
| 245 | 366 | }, |
| 246 | 367 | |
| | 368 | /** |
| | 369 | * Creates views for every attachment in collection. |
| | 370 | * |
| | 371 | * Creates views for every attachment in collection if the collection is not empty, |
| | 372 | * otherwise clears all views and loads more attachments. |
| | 373 | * |
| | 374 | * @since 4.2.0 |
| | 375 | * |
| | 376 | * @returns {void} |
| | 377 | */ |
| 247 | 378 | prepare: function() { |
| 248 | | // Create all of the Attachment views, and replace |
| 249 | | // the list in a single DOM operation. |
| 250 | 379 | if ( this.collection.length ) { |
| 251 | 380 | this.views.set( this.collection.map( this.createAttachmentView, this ) ); |
| 252 | | |
| 253 | | // If there are no elements, clear the views and load some. |
| 254 | 381 | } else { |
| 255 | 382 | this.views.unset(); |
| 256 | 383 | this.collection.more().done( this.scroll ); |
| 257 | 384 | } |
| 258 | 385 | }, |
| 259 | 386 | |
| | 387 | /** |
| | 388 | * Triggers the scroll function to check if we should query for additional attachments right away. |
| | 389 | * |
| | 390 | * @since 4.2.0 |
| | 391 | * |
| | 392 | * @returns {void} |
| | 393 | */ |
| 260 | 394 | ready: function() { |
| 261 | | // Trigger the scroll event to check if we're within the |
| 262 | | // threshold to query for additional attachments. |
| 263 | 395 | this.scroll(); |
| 264 | 396 | }, |
| 265 | 397 | |
| | 398 | /** |
| | 399 | * Event handler for scroll events. |
| | 400 | * |
| | 401 | * Shows the spinner if we're close to the bottom. Loads more attachments from |
| | 402 | * server if we're {refreshThreshold} times away from the bottom. |
| | 403 | * |
| | 404 | * @since 4.2.0 |
| | 405 | * |
| | 406 | * @returns {void} |
| | 407 | */ |
| 266 | 408 | scroll: function() { |
| 267 | 409 | var view = this, |
| 268 | 410 | el = this.options.scrollElement, |
| 269 | 411 | scrollTop = el.scrollTop, |
| 270 | 412 | toolbar; |
| 271 | 413 | |
| 272 | | // The scroll event occurs on the document, but the element |
| 273 | | // that should be checked is the document body. |
| | 414 | /* |
| | 415 | * The scroll event occurs on the document, but the element |
| | 416 | * that should be checked is the document body. |
| | 417 | */ |
| 274 | 418 | if ( el === document ) { |
| 275 | 419 | el = document.body; |
| 276 | 420 | scrollTop = $(document).scrollTop(); |