Bartosz Dziewoński has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/232403

Change subject: mediawiki.api.uploadWithFormData: Implement in terms of 
existing mw.Api functionality
......................................................................

mediawiki.api.uploadWithFormData: Implement in terms of existing mw.Api 
functionality

* mw.Api#ajax can already handle FormData, if instructed to, since
  d19432a332c21935d42087db706e50c5259063ea (which seems to have been a
  part of mobile uploads experiments).
* MobileFrontend's api.js already had code to provide upload progress
  events while using mw.Api, lifted it from there.

With this change, we should be able to just use mw.ForeignApi (being
added in Ic20b9682d28633baa87d22e6e9fb71ce507da58d) to upload to a
different wiki. (Assuming that the browser supports FormData.)

Additionally:

* Improve detection of whether we can use FormData: if we are given a
  HTMLInputElement, try to get a File from it before we fall back to
  iframe form upload.
* mediawiki.api.edit: In #postWithEditToken, pass through the
  ajaxOptions parameter to #postWithToken.

Change-Id: Ib9abe32ee3320c67ac0a4544c942b844a5550562
---
M resources/src/mediawiki.api/mediawiki.api.edit.js
M resources/src/mediawiki.api/mediawiki.api.upload.js
2 files changed, 43 insertions(+), 77 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/core 
refs/changes/03/232403/1

diff --git a/resources/src/mediawiki.api/mediawiki.api.edit.js 
b/resources/src/mediawiki.api/mediawiki.api.edit.js
index dbe45bf..e6161e4 100644
--- a/resources/src/mediawiki.api/mediawiki.api.edit.js
+++ b/resources/src/mediawiki.api/mediawiki.api.edit.js
@@ -11,10 +11,11 @@
                 * cached token and start over.
                 *
                 * @param {Object} params API parameters
+                * @param {Object} [ajaxOptions]
                 * @return {jQuery.Promise} See #post
                 */
-               postWithEditToken: function ( params ) {
-                       return this.postWithToken( 'edit', params );
+               postWithEditToken: function ( params, ajaxOptions ) {
+                       return this.postWithToken( 'edit', params, ajaxOptions 
);
                },
 
                /**
diff --git a/resources/src/mediawiki.api/mediawiki.api.upload.js 
b/resources/src/mediawiki.api/mediawiki.api.upload.js
index cec352a..43764a4 100644
--- a/resources/src/mediawiki.api/mediawiki.api.upload.js
+++ b/resources/src/mediawiki.api/mediawiki.api.upload.js
@@ -48,29 +48,6 @@
        }
 
        /**
-        * Parse response from an XHR to the server.
-        * @private
-        * @param {Event} e
-        * @return {Object}
-        */
-       function parseXHRResponse( e ) {
-               var response;
-
-               try {
-                       response = $.parseJSON( e.target.responseText );
-               } catch ( error ) {
-                       response = {
-                               error: {
-                                       code: e.target.code,
-                                       info: e.target.responseText
-                               }
-                       };
-               }
-
-               return response;
-       }
-
-       /**
         * Process the result of the form submission, returned to an iframe.
         * This is the iframe's onload event.
         *
@@ -116,20 +93,25 @@
                 * @return {jQuery.Promise}
                 */
                upload: function ( file, data ) {
-                       var iframe, formData;
+                       var isFileInput, canUseFormData;
+
+                       isFileInput = file.nodeType === Node.ELEMENT_NODE;
+
+                       if ( formDataAvailable() && isFileInput && file.files ) 
{
+                               file = file.files[0];
+                       }
 
                        if ( !file ) {
                                return $.Deferred().reject( 'No file' );
                        }
 
-                       iframe = file.nodeType && file.nodeType === 
Node.ELEMENT_NODE;
-                       formData = formDataAvailable() && file instanceof 
window.File;
+                       canUseFormData = formDataAvailable() && file instanceof 
window.File;
 
-                       if ( !iframe && !formData ) {
+                       if ( !isFileInput && !canUseFormData ) {
                                return $.Deferred().reject( 'Unsupported 
argument type passed to mw.Api.upload' );
                        }
 
-                       if ( formData ) {
+                       if ( canUseFormData ) {
                                return this.uploadWithFormData( file, data );
                        }
 
@@ -242,11 +224,10 @@
                 * Uploads a file using the FormData API.
                 * @param {File} file
                 * @param {Object} data
+                * @return {jQuery.Promise}
                 */
                uploadWithFormData: function ( file, data ) {
-                       var key, xhr,
-                               api = this,
-                               formData = new FormData(),
+                       var key,
                                deferred = $.Deferred();
 
                        for ( key in data ) {
@@ -256,58 +237,42 @@
                        }
 
                        data = $.extend( {}, this.defaults.parameters, { 
action: 'upload' }, data );
-
-                       $.each( data, function ( key, val ) {
-                               formData.append( key, val );
-                       } );
+                       data.file = file;
 
                        if ( !data.filename && !data.stash ) {
                                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 ) {
-                               var result = parseXHRResponse( e );
-
-                               if ( result.error || result.warnings ) {
-                                       if ( result.error && result.error.code 
=== 'badtoken' ) {
-                                               api.badToken( 'edit' );
+                       // Use this.postWithEditToken() or this.post()
+                       this[ this.needToken() ? 'postWithEditToken' : 'post' 
]( data, {
+                               // Use FormData (if we got here, we know that 
it's available)
+                               contentType: 'multipart/form-data',
+                               // Provide upload progress notifications
+                               xhr: function () {
+                                       var xhr = $.ajaxSettings.xhr();
+                                       if ( xhr.upload ) {
+                                               // need to bind this event 
before we open the connection (see note at
+                                               // 
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress)
+                                               xhr.upload.addEventListener( 
'progress', function ( ev ) {
+                                                       if ( 
ev.lengthComputable ) {
+                                                               
deferred.notify( ev.loaded / ev.total );
+                                                       }
+                                               } );
                                        }
-
-                                       deferred.reject( result.error || 
result.warnings );
-                               } else {
-                                       deferred.notify( 1 );
-                                       deferred.resolve( result );
+                                       return xhr;
                                }
-                       }, false );
-
-                       xhr.addEventListener( 'error', function ( e ) {
-                               deferred.reject( parseXHRResponse( e ) );
-                       }, false );
-
-                       xhr.open( 'POST', this.defaults.ajax.url, true );
-
-                       if ( this.needToken() ) {
-                               this.getEditToken().then( function ( token ) {
-                                       formData.append( 'token', token );
-                                       xhr.send( formData );
+                       } )
+                               .done( function ( result ) {
+                                       if ( result.error || result.warnings ) {
+                                               deferred.reject( result.error 
|| result.warnings );
+                                       } else {
+                                               deferred.notify( 1 );
+                                               deferred.resolve( result );
+                                       }
+                               } )
+                               .fail( function ( result ) {
+                                       deferred.reject( result );
                                } );
-                       } else {
-                               xhr.send( formData );
-                       }
 
                        return deferred.promise();
                },

-- 
To view, visit https://gerrit.wikimedia.org/r/232403
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: Ib9abe32ee3320c67ac0a4544c942b844a5550562
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/core
Gerrit-Branch: master
Gerrit-Owner: Bartosz Dziewoński <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to