+ return deferred.promise();
+ },
+
+ /**
+ * Uploads a file using the FormData API.
+ * @param {File} file
+ * @param {Object} data
+ */
+ uploadWithFormData: function ( file, data ) {
+ var xhr, tokenPromise,
+ api = this,
+ formData = new FormData(),
+ deferred = $.Deferred(),
+ filenameFound = false;
+
+ formData.append( 'action', 'upload' );
+ formData.append( 'format', 'json' );
+
+ $.each( data, function ( key, val ) {
+ if ( key === 'filename' ) {
+ filenameFound = true;
+ }
+
+ if ( fieldsAllowed[key] === true ) {
+ formData.append( key, val );
+ }
+ } );
+
+ if ( !filenameFound ) {
+ return $.Deferred().reject( 'Filename not included in file data.' );
+ }
+
+ formData.append( 'file', file );
+
+ xhr = new XMLHttpRequest();
+
+ xhr.upload.addEventListener( 'progress', function ( e ) {
+ if ( e.lengthComputable ) {
+ deferred.notify( e.loaded / e.total );
+ }
+ }, false );
+
+ xhr.addEventListener( 'abort', function ( e ) {
+ deferred.reject( parseXHRResponse( e ) );
+ }, false );
+
+ xhr.addEventListener( 'load', function ( e ) {
+ deferred.resolve( parseXHRResponse( e ) );
+ }, false );
+
+ xhr.addEventListener( 'error', function ( e ) {
+ deferred.reject( parseXHRResponse( e ) );
+ }, false );
+
+ xhr.open( 'POST', this.defaults.ajax.url, true );
+
+ tokenPromise = this.getEditToken().then( function ( token ) {
+ formData.append( 'token', token );
+ xhr.send( formData );
+ }, function () {
+ // Mark the edit token as bad, it's been used.
+ api.badToken( 'edit' );
+ } );
+