PluginProbe ʕ •ᴥ•ʔ
Jetpack – WP Security, Backup, Speed, & Growth / 15.9-a.7
Jetpack – WP Security, Backup, Speed, & Growth v15.9-a.7
16.0-a.5 15.9.1 16.0-a.3 16.0-a.1 15.9 15.9-beta 15.9-a.7 15.9-a.5 15.9-a.3 15.9-a.1 15.8 15.8-beta 15.8-a.7 15.8-a.5 5.2.5 5.3.4 5.4.4 5.5.5 5.6.5 5.7.5 5.8.4 5.9.4 6.0.4 6.1 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.2 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.3 6.3.1 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.4 6.4.1 6.4.2 6.4.3 6.4.4 6.4.5 6.4.6 6.5 6.5.1 6.5.2 6.5.3 6.5.4 6.6 6.6.1 6.6.2 6.6.3 6.6.4 6.6.5 6.7 6.7.1 6.7.2 6.7.3 6.7.4 6.8 6.8.1 6.8.2 6.8.3 6.8.4 6.8.5 6.9 6.9.1 6.9.2 6.9.3 6.9.4 7.0 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1 7.1.1 7.1.2 7.1.3 7.1.4 7.1.5 7.2 7.2.1 7.2.1.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3 7.3.0.1 7.3.1 7.3.1.1 7.3.2 7.3.3 7.3.4 7.3.5 7.4 7.4.1 7.4.2 7.4.3 7.4.4 7.4.5 7.5 7.5.0.1 7.5.1 7.5.2 7.5.3 7.5.4 7.5.5 7.5.6 7.5.7 7.6 7.6.1 7.6.2 7.6.3 7.6.4 7.7 7.7.1 7.7.2 7.7.3 7.7.4 7.7.5 7.7.6 7.8 7.8.1 7.8.2 7.8.3 7.8.4 7.9 7.9.1 7.9.2 7.9.3 7.9.4 8.0 8.0.1 8.0.2 8.0.3 8.1 8.1.1 8.1.2 8.1.3 8.1.4 8.2 8.2.0.1 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.2.6 8.3 8.3.1 8.3.2 8.3.3 8.4 8.4.1 8.4.2 8.4.3 8.4.4 8.4.5 8.5 8.5.1 8.5.2 8.5.3 8.6 8.6.1 8.6.2 8.6.3 8.6.4 8.7 8.7.0.1 8.7.1 8.7.2 8.7.3 8.7.4 8.8 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.9 8.9.1 8.9.2 8.9.3 8.9.4 9.0 9.0.1 9.0.2 9.0.3 9.0.4 9.0.5 9.1 9.1.1 9.1.2 9.1.3 9.2 9.2.1 9.2.2 9.2.3 9.2.4 9.3 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.4 9.4.1 9.4.2 9.4.3 9.4.4 9.5 9.5.1 9.5.2 9.5.3 9.5.4 9.5.5 9.6 9.6.1 9.6.2 9.6.3 9.6.4 9.7 9.7.1 9.7.2 15.7-beta.2 9.7.3 15.7.1 9.8 15.8-a.1 9.8.1 15.8-a.3 9.8.2 2.0.9 9.8.3 2.1.7 9.9 2.2.10 9.9.1 2.3.10 9.9.2 2.4.7 9.9.3 2.5.5 2.6.6 2.7.5 2.8.5 2.9.6 3.0.6 3.1.5 3.2.5 3.3.6 3.4.6 3.5.6 3.6.4 3.7.5 3.8.5 3.9.10 4.0.7 4.1.4 4.2.5 4.3.5 4.4.5 4.5.3 4.6.3 4.7.4 4.8.5 4.9.3 5.0.3 5.1.4 trunk 10.0 10.0.1 10.0.2 10.1 10.1.1 10.1.2 10.2 10.2.1 10.2.2 10.2.3 10.3 10.3.1 10.3.2 10.4 10.4.1 10.4.2 10.5 10.5.1 10.5.2 10.5.3 10.6 10.6.1 10.6.2 10.7 10.7.1 10.7.2 10.8 10.8.1 10.8.2 10.9 10.9.1 10.9.2 10.9.3 11.0 11.0.1 11.0.2 11.1 11.1.1 11.1.2 11.1.3 11.1.4 11.2 11.2.1 11.2.2 11.3 11.3.1 11.3.2 11.3.3 11.3.4 11.4 11.4.1 11.4.2 11.5 11.5.1 11.5.2 11.5.3 11.6 11.6.1 11.6.2 11.7 11.7.1 11.7.2 11.7.3 11.8 11.8.3 11.8.4 11.8.5 11.8.6 11.9 11.9.1 11.9.2 11.9.3 12.0 12.0.1 12.0.2 12.1 12.1.1 12.1.2 12.2 12.2.1 12.2.2 12.3 12.3.1 12.4 12.4.1 12.5 12.5.1 12.6 12.6.1 12.6.2 12.6.3 12.7 12.7.1 12.7.2 12.8 12.8.1 12.8.2 12.9 12.9.1 12.9.2 12.9.3 12.9.4 13.0 13.0.1 13.1 13.1.1 13.1.2 13.1.3 13.1.4 13.2 13.2.1 13.2.2 13.2.3 13.3 13.3.1 13.3.2 13.4 13.4.1 13.4.2 13.4.3 13.4.4 13.5 13.5.1 13.6 13.6.1 13.7 13.7.1 13.8 13.8.1 13.8.2 13.9 13.9.1 14.0 14.1 14.2 14.2.1 14.3 14.4 14.4.1 14.5 14.6 14.7 14.8 14.9 14.9.1 15.0 15.0.1 15.0.2 15.1 15.1.1 15.2 15.3 15.3.1 15.4 15.5 15.6 15.7 15.7-a.1 15.7-a.3 15.7-a.5 15.7-a.7 15.7-beta
jetpack / modules / videopress / js / videopress-plupload.js
jetpack / modules / videopress / js Last commit date
editor-view.js 7 months ago gutenberg-video-upload.js 4 months ago media-video-widget-extensions.js 5 years ago videopress-add-resumable-upload-support.js 4 years ago videopress-plupload.js 6 months ago videopress-uploader.js 7 months ago
videopress-plupload.js
521 lines
1 /* global pluploadL10n, plupload, _wpPluploadSettings */
2
3 window.wp = window.wp || {};
4
5 ( function ( exports, $ ) {
6 var Uploader, vp;
7
8 if ( typeof _wpPluploadSettings === 'undefined' ) {
9 return;
10 }
11
12 /**
13 * A WordPress uploader.
14 *
15 * The Plupload library provides cross-browser uploader UI integration.
16 * This object bridges the Plupload API to integrate uploads into the
17 * WordPress back end and the WordPress media experience.
18 *
19 * @param {object} options The options passed to the new plupload instance.
20 * @param {object} options.container The id of uploader container.
21 * @param {object} options.browser The id of button to trigger the file select.
22 * @param {object} options.dropzone The id of file drop target.
23 * @param {object} options.plupload An object of parameters to pass to the plupload instance.
24 * @param {object} options.params An object of parameters to pass to $_POST when uploading the file.
25 * Extends this.plupload.multipart_params under the hood.
26 */
27 Uploader = function ( options ) {
28 var self = this,
29 isIE =
30 navigator.userAgent.indexOf( 'Trident/' ) !== -1 ||
31 navigator.userAgent.indexOf( 'MSIE ' ) !== -1,
32 elements = {
33 container: 'container',
34 browser: 'browse_button',
35 dropzone: 'drop_element',
36 },
37 key,
38 error;
39
40 this.supports = {
41 upload: Uploader.browser.supported,
42 };
43
44 this.supported = this.supports.upload;
45
46 if ( ! this.supported ) {
47 return;
48 }
49
50 // Arguments to send to pluplad.Uploader().
51 // Use deep extend to ensure that multipart_params and other objects are cloned.
52 this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults );
53 this.container = document.body; // Set default container.
54
55 // Extend the instance with options.
56 //
57 // Use deep extend to allow options.plupload to override individual
58 // default plupload keys.
59 $.extend( true, this, options );
60
61 // Proxy all methods so this always refers to the current instance.
62 for ( key in this ) {
63 if ( $.isFunction( this[ key ] ) ) {
64 this[ key ] = $.proxy( this[ key ], this );
65 }
66 }
67
68 // Ensure all elements are jQuery elements and have id attributes,
69 // then set the proper plupload arguments to the ids.
70 for ( key in elements ) {
71 if ( ! this[ key ] ) {
72 continue;
73 }
74
75 this[ key ] = $( this[ key ] ).first();
76
77 if ( ! this[ key ].length ) {
78 delete this[ key ];
79 continue;
80 }
81
82 if ( ! this[ key ].prop( 'id' ) ) {
83 this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
84 }
85
86 this.plupload[ elements[ key ] ] = this[ key ].prop( 'id' );
87 }
88
89 // If the uploader has neither a browse button nor a dropzone, bail.
90 if (
91 ! ( this.browser && this.browser.length ) &&
92 ! ( this.dropzone && this.dropzone.length )
93 ) {
94 return;
95 }
96
97 // Make sure flash sends cookies (seems in IE it does without switching to urlstream mode)
98 if (
99 ! isIE &&
100 'flash' === plupload.predictRuntime( this.plupload ) &&
101 ( ! this.plupload.required_features ||
102 ! Object.hasOwn( this.plupload.required_features, 'send_binary_string' ) )
103 ) {
104 this.plupload.required_features = this.plupload.required_features || {};
105 this.plupload.required_features.send_binary_string = true;
106 }
107
108 // Initialize the plupload instance.
109 this.uploader = new plupload.Uploader( this.plupload );
110 delete this.plupload;
111
112 // Set default params and remove this.params alias.
113 this.param( this.params || {} );
114 delete this.params;
115
116 // Make sure that the VideoPress object is available
117 if ( typeof exports.VideoPress !== 'undefined' ) {
118 vp = exports.VideoPress;
119 } else {
120 window.console &&
121 window.console.error( 'The VideoPress object was not loaded. Errors may occur.' );
122 }
123
124 /**
125 * Custom error callback.
126 *
127 * Add a new error to the errors collection, so other modules can track
128 * and display errors. {@see wp.Uploader.errors}.
129 *
130 * @param {string} message
131 * @param {object} data
132 * @param {plupload.File} file File that was uploaded.
133 */
134 error = function ( message, data, file ) {
135 if ( file.attachment ) {
136 file.attachment.destroy();
137 }
138
139 Uploader.errors.unshift( {
140 message: message || pluploadL10n.default_error,
141 data: data,
142 file: file,
143 } );
144
145 self.error( message, data, file );
146 };
147
148 /**
149 * After the Uploader has been initialized, initialize some behaviors for the dropzone.
150 *
151 * @param {plupload.Uploader} uploader Uploader instance.
152 */
153 this.uploader.bind( 'init', function ( uploader ) {
154 var timer,
155 active,
156 dragdrop,
157 dropzone = self.dropzone;
158
159 dragdrop = self.supports.dragdrop = uploader.features.dragdrop && ! Uploader.browser.mobile;
160
161 // Generate drag/drop helper classes.
162 if ( ! dropzone ) {
163 return;
164 }
165
166 dropzone.toggleClass( 'supports-drag-drop', !! dragdrop );
167
168 if ( ! dragdrop ) {
169 return dropzone.unbind( '.wp-uploader' );
170 }
171
172 // 'dragenter' doesn't fire correctly, simulate it with a limited 'dragover'.
173 dropzone.bind( 'dragover.wp-uploader', function () {
174 if ( timer ) {
175 clearTimeout( timer );
176 }
177
178 if ( active ) {
179 return;
180 }
181
182 dropzone.trigger( 'dropzone:enter' ).addClass( 'drag-over' );
183 active = true;
184 } );
185
186 dropzone.bind( 'dragleave.wp-uploader, drop.wp-uploader', function () {
187 // Using an instant timer prevents the drag-over class from
188 // being quickly removed and re-added when elements inside the
189 // dropzone are repositioned.
190 //
191 // @see https://core.trac.wordpress.org/ticket/21705
192 timer = setTimeout( function () {
193 active = false;
194 dropzone.trigger( 'dropzone:leave' ).removeClass( 'drag-over' );
195 }, 0 );
196 } );
197
198 self.ready = true;
199 $( self ).trigger( 'uploader:ready' );
200 } );
201
202 this.uploader.bind( 'postinit', function ( up ) {
203 up.refresh();
204 self.init();
205 } );
206
207 this.uploader.init();
208
209 if ( this.browser ) {
210 this.browser.on( 'mouseenter', this.refresh );
211 } else {
212 this.uploader.disableBrowse( true );
213 // If HTML5 mode, hide the auto-created file container.
214 $( '#' + this.uploader.id + '_html5_container' ).hide();
215 }
216
217 /**
218 * After files were filtered and added to the queue, create a model for each.
219 *
220 * @event FilesAdded
221 * @param {plupload.Uploader} uploader Uploader instance.
222 * @param {Array} files Array of file objects that were added to queue by the user.
223 */
224 this.uploader.bind( 'FilesAdded', function ( up, files ) {
225 for ( const file of files ) {
226 var attributes, image;
227
228 // Ignore failed uploads.
229 if ( plupload.FAILED === file.status ) {
230 return;
231 }
232
233 // Generate attributes for a new `Attachment` model.
234 attributes = {
235 file: file,
236 uploading: true,
237 date: new Date(),
238 filename: file.name,
239 menuOrder: 0,
240 uploadedTo: wp.media.model.settings.post.id,
241 ...Object.fromEntries(
242 Object.entries( file ).filter(
243 ( [ k ] ) => k === 'loaded' || k === 'size' || k === 'percent'
244 )
245 ),
246 };
247
248 // Handle early mime type scanning for images.
249 image = /(?:jpe?g|png|gif|webp)$/i.exec( file.name );
250
251 // For images set the model's type and subtype attributes.
252 if ( image ) {
253 attributes.type = 'image';
254
255 // `jpeg`, `png` and `gif` are valid subtypes.
256 // `jpg` is not, so map it to `jpeg`.
257 attributes.subtype = 'jpg' === image[ 0 ] ? 'jpeg' : image[ 0 ];
258 }
259
260 // Create a model for the attachment, and add it to the Upload queue collection
261 // so listeners to the upload queue can track and display upload progress.
262 file.attachment = wp.media.model.Attachment.create( attributes );
263 Uploader.queue.add( file.attachment );
264
265 self.added( file.attachment );
266 }
267
268 up.refresh();
269 up.start();
270 } );
271
272 this.uploader.bind( 'UploadProgress', function ( up, file ) {
273 file.attachment.set(
274 Object.fromEntries(
275 Object.entries( file ).filter( ( [ k ] ) => k === 'loaded' || k === 'percent' )
276 )
277 );
278 self.progress( file.attachment );
279 } );
280
281 /**
282 * After a file is successfully uploaded, update its model.
283 *
284 * @param {plupload.Uploader} uploader Uploader instance.
285 * @param {plupload.File} file File that was uploaded.
286 * @param {Object} response Object with response properties.
287 * @return {mixed}
288 */
289 this.uploader.bind( 'FileUploaded', function ( up, file, response ) {
290 var complete;
291
292 try {
293 response = JSON.parse( response.response );
294 } catch ( e ) {
295 return error( pluploadL10n.default_error, e, file );
296 }
297
298 if ( typeof response.media !== 'undefined' ) {
299 response = vp.handleRestApiResponse( response, file );
300 } else {
301 response = vp.handleStandardResponse( response, file );
302 }
303
304 for ( const k of [ 'file', 'loaded', 'size', 'percent' ] ) {
305 file.attachment.unset( k );
306 }
307
308 file.attachment.set( { ...response.data, uploading: false } );
309 var att = wp.media.model.Attachment.get( response.data.id, file.attachment );
310
311 /* Once the new "empty" attachment is added to the collection above, check if it exists on the server, then set the new data.
312 * If it happens to not exist on the server yet (xmlrpc delayed or not working), then the empty media item will still be on the page,
313 * so no need to do any special error handling here on the sync.
314 *
315 * This is only necessary if `vp.handleRestApiResponse` was used above, as it is what returns the "empty" media item.
316 */
317 if ( typeof response.media !== 'undefined' ) {
318 att.sync( 'read' ).then( function ( data ) {
319 wp.media.model.Attachment.get( att.id ).set( data );
320 } );
321 }
322
323 complete = Uploader.queue.all( function ( attachment ) {
324 return ! attachment.get( 'uploading' );
325 } );
326
327 if ( complete ) {
328 vp && vp.resetToOriginalOptions( up );
329 Uploader.queue.reset();
330 }
331
332 self.success( file.attachment );
333 } );
334
335 /**
336 * When plupload surfaces an error, send it to the error handler.
337 *
338 * @param {plupload.Uploader} uploader Uploader instance.
339 * @param {Object} error Contains code, message and sometimes file and other details.
340 */
341 this.uploader.bind( 'Error', function ( up, pluploadError ) {
342 var message = pluploadL10n.default_error;
343
344 // Check for plupload errors.
345 for ( var k in Uploader.errorMap ) {
346 if ( pluploadError.code === plupload[ k ] ) {
347 message = Uploader.errorMap[ k ];
348
349 if ( typeof message === 'function' ) {
350 message = message( pluploadError.file, pluploadError );
351 }
352
353 break;
354 }
355 }
356
357 if ( 'response' in pluploadError ) {
358 try {
359 var pluploadResponseObject = JSON.parse( pluploadError.response );
360 if ( typeof pluploadResponseObject === 'object' ) {
361 if (
362 'errors' in pluploadResponseObject &&
363 typeof pluploadResponseObject.errors === 'object'
364 ) {
365 pluploadResponseObject = pluploadResponseObject.errors.shift();
366 }
367
368 if ( 'message' in pluploadResponseObject ) {
369 message = pluploadResponseObject.message;
370 }
371 }
372 } catch {
373 // Do nothing ...
374 }
375 }
376
377 error( message, pluploadError, pluploadError.file );
378 vp && vp.resetToOriginalOptions( up );
379 up.refresh();
380 } );
381
382 /**
383 * Add in a way for the uploader to reset itself when uploads are complete.
384 */
385 this.uploader.bind( 'UploadComplete', function ( up ) {
386 vp && vp.resetToOriginalOptions( up );
387 } );
388
389 /**
390 * Before we upload, check to see if this file is a videopress upload, if so, set new options and save the old ones.
391 */
392 this.uploader.bind( 'BeforeUpload', function ( up, file ) {
393 if ( typeof file.videopress !== 'undefined' ) {
394 vp.originalOptions.url = up.getOption( 'url' );
395 vp.originalOptions.multipart_params = up.getOption( 'multipart_params' );
396 vp.originalOptions.file_data_name = up.getOption( 'file_data_name' );
397
398 up.setOption( 'file_data_name', 'media[]' );
399 up.setOption( 'url', file.videopress.upload_action_url );
400 up.setOption( 'headers', {
401 Authorization:
402 'X_UPLOAD_TOKEN token="' +
403 file.videopress.upload_token +
404 '" blog_id="' +
405 file.videopress.upload_blog_id +
406 '"',
407 } );
408 }
409 } );
410 };
411
412 // Adds the 'defaults' and 'browser' properties.
413 $.extend( Uploader, _wpPluploadSettings );
414
415 Uploader.uuid = 0;
416
417 // Map Plupload error codes to user friendly error messages.
418 Uploader.errorMap = {
419 FAILED: pluploadL10n.upload_failed,
420 FILE_EXTENSION_ERROR: pluploadL10n.invalid_filetype,
421 IMAGE_FORMAT_ERROR: pluploadL10n.not_an_image,
422 IMAGE_MEMORY_ERROR: pluploadL10n.image_memory_exceeded,
423 IMAGE_DIMENSIONS_ERROR: pluploadL10n.image_dimensions_exceeded,
424 GENERIC_ERROR: pluploadL10n.upload_failed,
425 IO_ERROR: pluploadL10n.io_error,
426 HTTP_ERROR: pluploadL10n.http_error,
427 SECURITY_ERROR: pluploadL10n.security_error,
428
429 FILE_SIZE_ERROR: function ( file ) {
430 return pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name );
431 },
432 };
433
434 $.extend( Uploader.prototype, {
435 /**
436 * Acts as a shortcut to extending the uploader's multipart_params object.
437 *
438 * param( key )
439 * Returns the value of the key.
440 *
441 * param( key, value )
442 * Sets the value of a key.
443 *
444 * param( map )
445 * Sets values for a map of data.
446 */
447 param: function ( key, value ) {
448 if ( arguments.length === 1 && typeof key === 'string' ) {
449 return this.uploader.settings.multipart_params[ key ];
450 }
451
452 if ( arguments.length > 1 ) {
453 this.uploader.settings.multipart_params[ key ] = value;
454 } else {
455 $.extend( this.uploader.settings.multipart_params, key );
456 }
457 },
458
459 /**
460 * Make a few internal event callbacks available on the wp.Uploader object
461 * to change the Uploader internals if absolutely necessary.
462 */
463 init: function () {},
464 error: function () {},
465 success: function () {},
466 added: function () {},
467 progress: function () {},
468 complete: function () {},
469 refresh: function () {
470 var node, attached, container, id;
471
472 if ( this.browser ) {
473 node = this.browser[ 0 ];
474
475 // Check if the browser node is in the DOM.
476 while ( node ) {
477 if ( node === document.body ) {
478 attached = true;
479 break;
480 }
481 node = node.parentNode;
482 }
483
484 // If the browser node is not attached to the DOM, use a
485 // temporary container to house it, as the browser button
486 // shims require the button to exist in the DOM at all times.
487 if ( ! attached ) {
488 id = 'wp-uploader-browser-' + this.uploader.id;
489
490 container = $( '#' + id );
491 if ( ! container.length ) {
492 container = $( '<div class="wp-uploader-browser" />' )
493 .css( {
494 position: 'fixed',
495 top: '-1000px',
496 left: '-1000px',
497 height: 0,
498 width: 0,
499 } )
500 .attr( 'id', 'wp-uploader-browser-' + this.uploader.id )
501 .appendTo( 'body' );
502 }
503
504 container.append( this.browser );
505 }
506 }
507
508 this.uploader.refresh();
509 },
510 } );
511
512 // Create a collection of attachments in the upload queue,
513 // so that other modules can track and display upload progress.
514 Uploader.queue = new wp.media.model.Attachments( [], { query: false } );
515
516 // Create a collection to collect errors incurred while attempting upload.
517 Uploader.errors = new Backbone.Collection();
518
519 exports.Uploader = Uploader;
520 } )( wp, jQuery );
521