54 // Arguments to send to pluplad.Uploader(). |
58 // Arguments to send to pluplad.Uploader(). |
55 // Use deep extend to ensure that multipart_params and other objects are cloned. |
59 // Use deep extend to ensure that multipart_params and other objects are cloned. |
56 this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults ); |
60 this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults ); |
57 this.container = document.body; // Set default container. |
61 this.container = document.body; // Set default container. |
58 |
62 |
59 // Extend the instance with options. |
63 /* |
60 // |
64 * Extend the instance with options. |
61 // Use deep extend to allow options.plupload to override individual |
65 * |
62 // default plupload keys. |
66 * Use deep extend to allow options.plupload to override individual |
|
67 * default plupload keys. |
|
68 */ |
63 $.extend( true, this, options ); |
69 $.extend( true, this, options ); |
64 |
70 |
65 // Proxy all methods so this always refers to the current instance. |
71 // Proxy all methods so this always refers to the current instance. |
66 for ( key in this ) { |
72 for ( key in this ) { |
67 if ( $.isFunction( this[ key ] ) ) { |
73 if ( $.isFunction( this[ key ] ) ) { |
93 // If the uploader has neither a browse button nor a dropzone, bail. |
99 // If the uploader has neither a browse button nor a dropzone, bail. |
94 if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) ) { |
100 if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) ) { |
95 return; |
101 return; |
96 } |
102 } |
97 |
103 |
98 // Make sure flash sends cookies (seems in IE it does without switching to urlstream mode) |
|
99 if ( ! isIE && 'flash' === plupload.predictRuntime( this.plupload ) && |
|
100 ( ! this.plupload.required_features || ! this.plupload.required_features.hasOwnProperty( 'send_binary_string' ) ) ) { |
|
101 |
|
102 this.plupload.required_features = this.plupload.required_features || {}; |
|
103 this.plupload.required_features.send_binary_string = true; |
|
104 } |
|
105 |
|
106 // Initialize the plupload instance. |
104 // Initialize the plupload instance. |
107 this.uploader = new plupload.Uploader( this.plupload ); |
105 this.uploader = new plupload.Uploader( this.plupload ); |
108 delete this.plupload; |
106 delete this.plupload; |
109 |
107 |
110 // Set default params and remove this.params alias. |
108 // Set default params and remove this.params alias. |
111 this.param( this.params || {} ); |
109 this.param( this.params || {} ); |
112 delete this.params; |
110 delete this.params; |
113 |
111 |
114 /** |
112 /** |
|
113 * Attempt to create image sub-sizes when an image was uploaded successfully |
|
114 * but the server responded with HTTP 5xx error. |
|
115 * |
|
116 * @since 5.3.0 |
|
117 * |
|
118 * @param {string} message Error message. |
|
119 * @param {object} data Error data from Plupload. |
|
120 * @param {plupload.File} file File that was uploaded. |
|
121 */ |
|
122 tryAgain = function( message, data, file ) { |
|
123 var times, id; |
|
124 |
|
125 if ( ! data || ! data.responseHeaders ) { |
|
126 error( pluploadL10n.http_error_image, data, file, 'no-retry' ); |
|
127 return; |
|
128 } |
|
129 |
|
130 id = data.responseHeaders.match( /x-wp-upload-attachment-id:\s*(\d+)/i ); |
|
131 |
|
132 if ( id && id[1] ) { |
|
133 id = id[1]; |
|
134 } else { |
|
135 error( pluploadL10n.http_error_image, data, file, 'no-retry' ); |
|
136 return; |
|
137 } |
|
138 |
|
139 times = tryAgainCount[ file.id ]; |
|
140 |
|
141 if ( times && times > 4 ) { |
|
142 /* |
|
143 * The file may have been uploaded and attachment post created, |
|
144 * but post-processing and resizing failed... |
|
145 * Do a cleanup then tell the user to scale down the image and upload it again. |
|
146 */ |
|
147 $.ajax({ |
|
148 type: 'post', |
|
149 url: ajaxurl, |
|
150 dataType: 'json', |
|
151 data: { |
|
152 action: 'media-create-image-subsizes', |
|
153 _wpnonce: _wpPluploadSettings.defaults.multipart_params._wpnonce, |
|
154 attachment_id: id, |
|
155 _wp_upload_failed_cleanup: true, |
|
156 } |
|
157 }); |
|
158 |
|
159 error( message, data, file, 'no-retry' ); |
|
160 return; |
|
161 } |
|
162 |
|
163 if ( ! times ) { |
|
164 tryAgainCount[ file.id ] = 1; |
|
165 } else { |
|
166 tryAgainCount[ file.id ] = ++times; |
|
167 } |
|
168 |
|
169 // Another request to try to create the missing image sub-sizes. |
|
170 $.ajax({ |
|
171 type: 'post', |
|
172 url: ajaxurl, |
|
173 dataType: 'json', |
|
174 data: { |
|
175 action: 'media-create-image-subsizes', |
|
176 _wpnonce: _wpPluploadSettings.defaults.multipart_params._wpnonce, |
|
177 attachment_id: id, |
|
178 } |
|
179 }).done( function( response ) { |
|
180 if ( response.success ) { |
|
181 fileUploaded( self.uploader, file, response ); |
|
182 } else { |
|
183 if ( response.data && response.data.message ) { |
|
184 message = response.data.message; |
|
185 } |
|
186 |
|
187 error( message, data, file, 'no-retry' ); |
|
188 } |
|
189 }).fail( function( jqXHR ) { |
|
190 // If another HTTP 5xx error, try try again... |
|
191 if ( jqXHR.status >= 500 && jqXHR.status < 600 ) { |
|
192 tryAgain( message, data, file ); |
|
193 return; |
|
194 } |
|
195 |
|
196 error( message, data, file, 'no-retry' ); |
|
197 }); |
|
198 } |
|
199 |
|
200 /** |
115 * Custom error callback. |
201 * Custom error callback. |
116 * |
202 * |
117 * Add a new error to the errors collection, so other modules can track |
203 * Add a new error to the errors collection, so other modules can track |
118 * and display errors. @see wp.Uploader.errors. |
204 * and display errors. @see wp.Uploader.errors. |
119 * |
205 * |
120 * @param {string} message |
206 * @param {string} message Error message. |
121 * @param {object} data |
207 * @param {object} data Error data from Plupload. |
122 * @param {plupload.File} file File that was uploaded. |
208 * @param {plupload.File} file File that was uploaded. |
123 */ |
209 * @param {string} retry Whether to try again to create image sub-sizes. Passing 'no-retry' will prevent it. |
124 error = function( message, data, file ) { |
210 */ |
|
211 error = function( message, data, file, retry ) { |
|
212 var isImage = file.type && file.type.indexOf( 'image/' ) === 0, |
|
213 status = data && data.status; |
|
214 |
|
215 // If the file is an image and the error is HTTP 5xx try to create sub-sizes again. |
|
216 if ( retry !== 'no-retry' && isImage && status >= 500 && status < 600 ) { |
|
217 tryAgain( message, data, file ); |
|
218 return; |
|
219 } |
|
220 |
125 if ( file.attachment ) { |
221 if ( file.attachment ) { |
126 file.attachment.destroy(); |
222 file.attachment.destroy(); |
127 } |
223 } |
128 |
224 |
129 Uploader.errors.unshift({ |
225 Uploader.errors.unshift({ |
134 |
230 |
135 self.error( message, data, file ); |
231 self.error( message, data, file ); |
136 }; |
232 }; |
137 |
233 |
138 /** |
234 /** |
|
235 * After a file is successfully uploaded, update its model. |
|
236 * |
|
237 * @param {plupload.Uploader} up Uploader instance. |
|
238 * @param {plupload.File} file File that was uploaded. |
|
239 * @param {Object} response Object with response properties. |
|
240 */ |
|
241 fileUploaded = function( up, file, response ) { |
|
242 var complete; |
|
243 |
|
244 // Remove the "uploading" UI elements. |
|
245 _.each( ['file','loaded','size','percent'], function( key ) { |
|
246 file.attachment.unset( key ); |
|
247 } ); |
|
248 |
|
249 file.attachment.set( _.extend( response.data, { uploading: false } ) ); |
|
250 |
|
251 wp.media.model.Attachment.get( response.data.id, file.attachment ); |
|
252 |
|
253 complete = Uploader.queue.all( function( attachment ) { |
|
254 return ! attachment.get( 'uploading' ); |
|
255 }); |
|
256 |
|
257 if ( complete ) { |
|
258 Uploader.queue.reset(); |
|
259 } |
|
260 |
|
261 self.success( file.attachment ); |
|
262 } |
|
263 |
|
264 /** |
139 * After the Uploader has been initialized, initialize some behaviors for the dropzone. |
265 * After the Uploader has been initialized, initialize some behaviors for the dropzone. |
140 * |
266 * |
141 * @param {plupload.Uploader} uploader Uploader instance. |
267 * @param {plupload.Uploader} uploader Uploader instance. |
142 */ |
268 */ |
143 this.uploader.bind( 'init', function( uploader ) { |
269 this.uploader.bind( 'init', function( uploader ) { |
196 |
324 |
197 if ( this.browser ) { |
325 if ( this.browser ) { |
198 this.browser.on( 'mouseenter', this.refresh ); |
326 this.browser.on( 'mouseenter', this.refresh ); |
199 } else { |
327 } else { |
200 this.uploader.disableBrowse( true ); |
328 this.uploader.disableBrowse( true ); |
201 // If HTML5 mode, hide the auto-created file container. |
329 } |
202 $('#' + this.uploader.id + '_html5_container').hide(); |
330 |
203 } |
331 $( self ).on( 'uploader:ready', function() { |
|
332 $( '.moxie-shim-html5 input[type="file"]' ) |
|
333 .attr( { |
|
334 tabIndex: '-1', |
|
335 'aria-hidden': 'true' |
|
336 } ); |
|
337 } ); |
204 |
338 |
205 /** |
339 /** |
206 * After files were filtered and added to the queue, create a model for each. |
340 * After files were filtered and added to the queue, create a model for each. |
207 * |
341 * |
208 * @param {plupload.Uploader} uploader Uploader instance. |
342 * @param {plupload.Uploader} up Uploader instance. |
209 * @param {Array} files Array of file objects that were added to queue by the user. |
343 * @param {Array} files Array of file objects that were added to queue by the user. |
210 */ |
344 */ |
211 this.uploader.bind( 'FilesAdded', function( up, files ) { |
345 this.uploader.bind( 'FilesAdded', function( up, files ) { |
212 _.each( files, function( file ) { |
346 _.each( files, function( file ) { |
213 var attributes, image; |
347 var attributes, image; |
214 |
348 |
215 // Ignore failed uploads. |
349 // Ignore failed uploads. |
216 if ( plupload.FAILED === file.status ) { |
350 if ( plupload.FAILED === file.status ) { |
217 return; |
351 return; |
|
352 } |
|
353 |
|
354 if ( file.type === 'image/heic' && up.settings.heic_upload_error ) { |
|
355 // Show error but do not block uploading. |
|
356 Uploader.errors.unshift({ |
|
357 message: pluploadL10n.unsupported_image, |
|
358 data: {}, |
|
359 file: file |
|
360 }); |
218 } |
361 } |
219 |
362 |
220 // Generate attributes for a new `Attachment` model. |
363 // Generate attributes for a new `Attachment` model. |
221 attributes = _.extend({ |
364 attributes = _.extend({ |
222 file: file, |
365 file: file, |
257 }); |
400 }); |
258 |
401 |
259 /** |
402 /** |
260 * After a file is successfully uploaded, update its model. |
403 * After a file is successfully uploaded, update its model. |
261 * |
404 * |
262 * @param {plupload.Uploader} uploader Uploader instance. |
405 * @param {plupload.Uploader} up Uploader instance. |
263 * @param {plupload.File} file File that was uploaded. |
406 * @param {plupload.File} file File that was uploaded. |
264 * @param {Object} response Object with response properties. |
407 * @param {Object} response Object with response properties. |
265 * @return {mixed} |
408 * @return {mixed} |
266 */ |
409 */ |
267 this.uploader.bind( 'FileUploaded', function( up, file, response ) { |
410 this.uploader.bind( 'FileUploaded', function( up, file, response ) { |
268 var complete; |
|
269 |
411 |
270 try { |
412 try { |
271 response = JSON.parse( response.response ); |
413 response = JSON.parse( response.response ); |
272 } catch ( e ) { |
414 } catch ( e ) { |
273 return error( pluploadL10n.default_error, e, file ); |
415 return error( pluploadL10n.default_error, e, file ); |
274 } |
416 } |
275 |
417 |
276 if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) |
418 if ( ! _.isObject( response ) || _.isUndefined( response.success ) ) { |
277 return error( pluploadL10n.default_error, null, file ); |
419 return error( pluploadL10n.default_error, null, file ); |
278 else if ( ! response.success ) |
420 } else if ( ! response.success ) { |
279 return error( response.data && response.data.message, response.data, file ); |
421 return error( response.data && response.data.message, response.data, file ); |
280 |
422 } |
281 _.each(['file','loaded','size','percent'], function( key ) { |
423 |
282 file.attachment.unset( key ); |
424 // Success. Update the UI with the new attachment. |
283 }); |
425 fileUploaded( up, file, response ); |
284 |
|
285 file.attachment.set( _.extend( response.data, { uploading: false }) ); |
|
286 wp.media.model.Attachment.get( response.data.id, file.attachment ); |
|
287 |
|
288 complete = Uploader.queue.all( function( attachment ) { |
|
289 return ! attachment.get('uploading'); |
|
290 }); |
|
291 |
|
292 if ( complete ) |
|
293 Uploader.queue.reset(); |
|
294 |
|
295 self.success( file.attachment ); |
|
296 }); |
426 }); |
297 |
427 |
298 /** |
428 /** |
299 * When plupload surfaces an error, send it to the error handler. |
429 * When plupload surfaces an error, send it to the error handler. |
300 * |
430 * |
301 * @param {plupload.Uploader} uploader Uploader instance. |
431 * @param {plupload.Uploader} up Uploader instance. |
302 * @param {Object} error Contains code, message and sometimes file and other details. |
432 * @param {Object} pluploadError Contains code, message and sometimes file and other details. |
303 */ |
433 */ |
304 this.uploader.bind( 'Error', function( up, pluploadError ) { |
434 this.uploader.bind( 'Error', function( up, pluploadError ) { |
305 var message = pluploadL10n.default_error, |
435 var message = pluploadL10n.default_error, |
306 key; |
436 key; |
307 |
437 |
336 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image, |
466 'IMAGE_FORMAT_ERROR': pluploadL10n.not_an_image, |
337 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded, |
467 'IMAGE_MEMORY_ERROR': pluploadL10n.image_memory_exceeded, |
338 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded, |
468 'IMAGE_DIMENSIONS_ERROR': pluploadL10n.image_dimensions_exceeded, |
339 'GENERIC_ERROR': pluploadL10n.upload_failed, |
469 'GENERIC_ERROR': pluploadL10n.upload_failed, |
340 'IO_ERROR': pluploadL10n.io_error, |
470 'IO_ERROR': pluploadL10n.io_error, |
341 'HTTP_ERROR': pluploadL10n.http_error, |
|
342 'SECURITY_ERROR': pluploadL10n.security_error, |
471 'SECURITY_ERROR': pluploadL10n.security_error, |
343 |
472 |
344 'FILE_SIZE_ERROR': function( file ) { |
473 'FILE_SIZE_ERROR': function( file ) { |
345 return pluploadL10n.file_exceeds_size_limit.replace('%s', file.name); |
474 return pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name ); |
346 } |
475 }, |
|
476 |
|
477 'HTTP_ERROR': function( file ) { |
|
478 if ( file.type && file.type.indexOf( 'image/' ) === 0 ) { |
|
479 return pluploadL10n.http_error_image; |
|
480 } |
|
481 |
|
482 return pluploadL10n.http_error; |
|
483 }, |
347 }; |
484 }; |
348 |
485 |
349 $.extend( Uploader.prototype, /** @lends wp.Uploader.prototype */{ |
486 $.extend( Uploader.prototype, /** @lends wp.Uploader.prototype */{ |
350 /** |
487 /** |
351 * Acts as a shortcut to extending the uploader's multipart_params object. |
488 * Acts as a shortcut to extending the uploader's multipart_params object. |