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(); |