wp/wp-includes/js/plupload/wp-plupload.js
changeset 5 5e2f62d02dcd
parent 0 d970ebf37754
child 7 cf61fcea0001
--- a/wp/wp-includes/js/plupload/wp-plupload.js	Mon Jun 08 16:11:51 2015 +0000
+++ b/wp/wp-includes/js/plupload/wp-plupload.js	Tue Jun 09 03:35:32 2015 +0200
@@ -1,27 +1,32 @@
+/* global pluploadL10n, plupload, _wpPluploadSettings */
+
 window.wp = window.wp || {};
 
-(function( exports, $ ) {
+( function( exports, $ ) {
 	var Uploader;
 
-	if ( typeof _wpPluploadSettings === 'undefined' )
+	if ( typeof _wpPluploadSettings === 'undefined' ) {
 		return;
+	}
 
-	/*
-	 * An object that helps create a WordPress uploader using plupload.
+	/**
+	 * A WordPress uploader.
 	 *
-	 * @param options - object - The options passed to the new plupload instance.
-	 *    Accepts the following parameters:
-	 *    - container - The id of uploader container.
-	 *    - browser   - The id of button to trigger the file select.
-	 *    - dropzone  - The id of file drop target.
-	 *    - plupload  - An object of parameters to pass to the plupload instance.
-	 *    - params    - An object of parameters to pass to $_POST when uploading the file.
-	 *                  Extends this.plupload.multipart_params under the hood.
+	 * The Plupload library provides cross-browser uploader UI integration.
+	 * This object bridges the Plupload API to integrate uploads into the
+	 * WordPress back-end and the WordPress media experience.
 	 *
-	 * @param attributes - object - Attributes and methods for this specific instance.
+	 * @param {object} options           The options passed to the new plupload instance.
+	 * @param {object} options.container The id of uploader container.
+	 * @param {object} options.browser   The id of button to trigger the file select.
+	 * @param {object} options.dropzone  The id of file drop target.
+	 * @param {object} options.plupload  An object of parameters to pass to the plupload instance.
+	 * @param {object} options.params    An object of parameters to pass to $_POST when uploading the file.
+	 *                                   Extends this.plupload.multipart_params under the hood.
 	 */
 	Uploader = function( options ) {
 		var self = this,
+			isIE = navigator.userAgent.indexOf('Trident/') != -1 || navigator.userAgent.indexOf('MSIE ') != -1,
 			elements = {
 				container: 'container',
 				browser:   'browse_button',
@@ -35,14 +40,16 @@
 
 		this.supported = this.supports.upload;
 
-		if ( ! this.supported )
+		if ( ! this.supported ) {
 			return;
+		}
 
+		// Arguments to send to pluplad.Uploader().
 		// Use deep extend to ensure that multipart_params and other objects are cloned.
 		this.plupload = $.extend( true, { multipart_params: {} }, Uploader.defaults );
 		this.container = document.body; // Set default container.
 
-		// Extend the instance with options
+		// Extend the instance with options.
 		//
 		// Use deep extend to allow options.plupload to override individual
 		// default plupload keys.
@@ -50,15 +57,17 @@
 
 		// Proxy all methods so this always refers to the current instance.
 		for ( key in this ) {
-			if ( $.isFunction( this[ key ] ) )
+			if ( $.isFunction( this[ key ] ) ) {
 				this[ key ] = $.proxy( this[ key ], this );
+			}
 		}
 
-		// Ensure all elements are jQuery elements and have id attributes
-		// Then set the proper plupload arguments to the ids.
+		// Ensure all elements are jQuery elements and have id attributes,
+		// then set the proper plupload arguments to the ids.
 		for ( key in elements ) {
-			if ( ! this[ key ] )
+			if ( ! this[ key ] ) {
 				continue;
+			}
 
 			this[ key ] = $( this[ key ] ).first();
 
@@ -67,15 +76,27 @@
 				continue;
 			}
 
-			if ( ! this[ key ].prop('id') )
+			if ( ! this[ key ].prop('id') ) {
 				this[ key ].prop( 'id', '__wp-uploader-id-' + Uploader.uuid++ );
+			}
+
 			this.plupload[ elements[ key ] ] = this[ key ].prop('id');
 		}
 
 		// If the uploader has neither a browse button nor a dropzone, bail.
-		if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) )
+		if ( ! ( this.browser && this.browser.length ) && ! ( this.dropzone && this.dropzone.length ) ) {
 			return;
+		}
 
+		// Make sure flash sends cookies (seems in IE it does without switching to urlstream mode)
+		if ( ! isIE && 'flash' === plupload.predictRuntime( this.plupload ) &&
+			( ! this.plupload.required_features || ! this.plupload.required_features.hasOwnProperty( 'send_binary_string' ) ) ) {
+
+			this.plupload.required_features = this.plupload.required_features || {};
+			this.plupload.required_features.send_binary_string = true;
+		}
+
+		// Initialize the plupload instance.
 		this.uploader = new plupload.Uploader( this.plupload );
 		delete this.plupload;
 
@@ -83,9 +104,20 @@
 		this.param( this.params || {} );
 		delete this.params;
 
+		/**
+		 * Custom error callback.
+		 *
+		 * Add a new error to the errors collection, so other modules can track
+		 * and display errors. @see wp.Uploader.errors.
+		 *
+		 * @param  {string}        message
+		 * @param  {object}        data
+		 * @param  {plupload.File} file     File that was uploaded.
+		 */
 		error = function( message, data, file ) {
-			if ( file.attachment )
+			if ( file.attachment ) {
 				file.attachment.destroy();
+			}
 
 			Uploader.errors.unshift({
 				message: message || pluploadL10n.default_error,
@@ -96,47 +128,59 @@
 			self.error( message, data, file );
 		};
 
-		this.uploader.init();
-
-		this.supports.dragdrop = this.uploader.features.dragdrop && ! Uploader.browser.mobile;
+		/**
+		 * After the Uploader has been initialized, initialize some behaviors for the dropzone.
+		 *
+		 * @param {plupload.Uploader} uploader Uploader instance.
+		 */
+		this.uploader.bind( 'init', function( uploader ) {
+			var timer, active, dragdrop,
+				dropzone = self.dropzone;
 
-		// Generate drag/drop helper classes.
-		(function( dropzone, supported ) {
-			var timer, active;
+			dragdrop = self.supports.dragdrop = uploader.features.dragdrop && ! Uploader.browser.mobile;
 
-			if ( ! dropzone )
+			// Generate drag/drop helper classes.
+			if ( ! dropzone ) {
 				return;
+			}
 
-			dropzone.toggleClass( 'supports-drag-drop', !! supported );
+			dropzone.toggleClass( 'supports-drag-drop', !! dragdrop );
 
-			if ( ! supported )
+			if ( ! dragdrop ) {
 				return dropzone.unbind('.wp-uploader');
+			}
 
-			// 'dragenter' doesn't fire correctly,
-			// simulate it with a limited 'dragover'
-			dropzone.bind( 'dragover.wp-uploader', function(){
-				if ( timer )
+			// 'dragenter' doesn't fire correctly, simulate it with a limited 'dragover'.
+			dropzone.bind( 'dragover.wp-uploader', function() {
+				if ( timer ) {
 					clearTimeout( timer );
+				}
 
-				if ( active )
+				if ( active ) {
 					return;
+				}
 
 				dropzone.trigger('dropzone:enter').addClass('drag-over');
 				active = true;
 			});
 
-			dropzone.bind('dragleave.wp-uploader, drop.wp-uploader', function(){
+			dropzone.bind('dragleave.wp-uploader, drop.wp-uploader', function() {
 				// Using an instant timer prevents the drag-over class from
 				// being quickly removed and re-added when elements inside the
 				// dropzone are repositioned.
 				//
-				// See http://core.trac.wordpress.org/ticket/21705
+				// @see https://core.trac.wordpress.org/ticket/21705
 				timer = setTimeout( function() {
 					active = false;
 					dropzone.trigger('dropzone:leave').removeClass('drag-over');
 				}, 0 );
 			});
-		}( this.dropzone, this.supports.dragdrop ));
+
+			self.ready = true;
+			$(self).trigger( 'uploader:ready' );
+		});
+
+		this.uploader.init();
 
 		if ( this.browser ) {
 			this.browser.on( 'mouseenter', this.refresh );
@@ -146,13 +190,21 @@
 			$('#' + this.uploader.id + '_html5_container').hide();
 		}
 
+		/**
+		 * After files were filtered and added to the queue, create a model for each.
+		 *
+		 * @event FilesAdded
+		 * @param {plupload.Uploader} uploader Uploader instance.
+		 * @param {Array}             files    Array of file objects that were added to queue by the user.
+		 */
 		this.uploader.bind( 'FilesAdded', function( up, files ) {
 			_.each( files, function( file ) {
 				var attributes, image;
 
 				// Ignore failed uploads.
-				if ( plupload.FAILED === file.status )
+				if ( plupload.FAILED === file.status ) {
 					return;
+				}
 
 				// Generate attributes for a new `Attachment` model.
 				attributes = _.extend({
@@ -167,7 +219,7 @@
 				// Handle early mime type scanning for images.
 				image = /(?:jpe?g|png|gif)$/i.exec( file.name );
 
-				// Did we find an image?
+				// For images set the model's type and subtype attributes.
 				if ( image ) {
 					attributes.type = 'image';
 
@@ -176,9 +228,9 @@
 					attributes.subtype = ( 'jpg' === image[0] ) ? 'jpeg' : image[0];
 				}
 
-				// Create the `Attachment`.
+				// Create a model for the attachment, and add it to the Upload queue collection
+				// so listeners to the upload queue can track and display upload progress.
 				file.attachment = wp.media.model.Attachment.create( attributes );
-
 				Uploader.queue.add( file.attachment );
 
 				self.added( file.attachment );
@@ -193,6 +245,14 @@
 			self.progress( file.attachment );
 		});
 
+		/**
+		 * After a file is successfully uploaded, update its model.
+		 *
+		 * @param {plupload.Uploader} uploader Uploader instance.
+		 * @param {plupload.File}     file     File that was uploaded.
+		 * @param {Object}            response Object with response properties.
+		 * @return {mixed}
+		 */
 		this.uploader.bind( 'FileUploaded', function( up, file, response ) {
 			var complete;
 
@@ -224,6 +284,12 @@
 			self.success( file.attachment );
 		});
 
+		/**
+		 * When plupload surfaces an error, send it to the error handler.
+		 *
+		 * @param {plupload.Uploader} uploader Uploader instance.
+		 * @param {Object}            error    Contains code, message and sometimes file and other details.
+		 */
 		this.uploader.bind( 'Error', function( up, pluploadError ) {
 			var message = pluploadL10n.default_error,
 				key;
@@ -232,8 +298,11 @@
 			for ( key in Uploader.errorMap ) {
 				if ( pluploadError.code === plupload[ key ] ) {
 					message = Uploader.errorMap[ key ];
-					if ( _.isFunction( message ) )
+
+					if ( _.isFunction( message ) ) {
 						message = message( pluploadError.file, pluploadError );
+					}
+
 					break;
 				}
 			}
@@ -242,7 +311,9 @@
 			up.refresh();
 		});
 
-		this.init();
+		this.uploader.bind( 'PostInit', function() {
+			self.init();
+		});
 	};
 
 	// Adds the 'defaults' and 'browser' properties.
@@ -250,6 +321,7 @@
 
 	Uploader.uuid = 0;
 
+	// Map Plupload error codes to user friendly error messages.
 	Uploader.errorMap = {
 		'FAILED':                 pluploadL10n.upload_failed,
 		'FILE_EXTENSION_ERROR':   pluploadL10n.invalid_filetype,
@@ -280,8 +352,9 @@
 		 *    Sets values for a map of data.
 		 */
 		param: function( key, value ) {
-			if ( arguments.length === 1 && typeof key === 'string' )
+			if ( arguments.length === 1 && typeof key === 'string' ) {
 				return this.uploader.settings.multipart_params[ key ];
+			}
 
 			if ( arguments.length > 1 ) {
 				this.uploader.settings.multipart_params[ key ] = value;
@@ -290,6 +363,10 @@
 			}
 		},
 
+		/**
+		 * Make a few internal event callbacks available on the wp.Uploader object
+		 * to change the Uploader internals if absolutely necessary.
+		 */
 		init:     function() {},
 		error:    function() {},
 		success:  function() {},
@@ -336,7 +413,11 @@
 		}
 	});
 
+	// Create a collection of attachments in the upload queue,
+	// so that other modules can track and display upload progress.
 	Uploader.queue = new wp.media.model.Attachments( [], { query: false });
+
+	// Create a collection to collect errors incurred while attempting upload.
 	Uploader.errors = new Backbone.Collection();
 
 	exports.Uploader = Uploader;