MarkTraceur has uploaded a new change for review.

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

Change subject: Remove upload handling from UploadWizard object
......................................................................

Remove upload handling from UploadWizard object

Implements a sort of linked-list setup for the uploads,
but only partly, because it was needed for the copyMetadata
refactor, but not really necessary outside of it. Maybe
useful in the future.

Change-Id: I5b2c0231cadbb7db3e5f38eb244efa090249592a
---
M resources/controller/uw.controller.Deed.js
M resources/controller/uw.controller.Details.js
M resources/controller/uw.controller.Step.js
M resources/controller/uw.controller.Thanks.js
M resources/controller/uw.controller.Upload.js
M resources/mw.UploadWizard.js
M resources/mw.UploadWizardDetails.js
M resources/mw.UploadWizardUpload.js
8 files changed, 309 insertions(+), 291 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/UploadWizard 
refs/changes/13/254913/1

diff --git a/resources/controller/uw.controller.Deed.js 
b/resources/controller/uw.controller.Deed.js
index b162c57..b2bfab8 100644
--- a/resources/controller/uw.controller.Deed.js
+++ b/resources/controller/uw.controller.Deed.js
@@ -155,6 +155,8 @@
                if ( this.deedChooser !== undefined ) {
                        this.deedChooser.remove();
                }
+
+               uw.controller.Step.prototype.empty.call( this );
        };
 
 }( mediaWiki, mediaWiki.uploadWizard, jQuery, OO ) );
diff --git a/resources/controller/uw.controller.Details.js 
b/resources/controller/uw.controller.Details.js
index adf4f0c..9c2d443 100644
--- a/resources/controller/uw.controller.Details.js
+++ b/resources/controller/uw.controller.Details.js
@@ -29,7 +29,7 @@
                        new uw.ui.Details()
                                .connect( this, {
                                        'start-details': 'startDetails',
-                                       'finalize-details-after-removal': [ 
'emit', 'finalize-details-after-removal' ]
+                                       'finalize-details-after-removal': 
'moveFrom'
                                } ),
                        config
                );
@@ -79,8 +79,9 @@
                uw.controller.Step.prototype.moveTo.call( this, uploads );
        };
 
-       uw.controller.Details.prototype.empty = function () {
-               this.ui.empty();
+       uw.controller.Details.prototype.moveFrom = function () {
+               this.removeErrorUploads();
+               uw.controller.Step.prototype.moveFrom.call( this );
        };
 
        /**
@@ -95,7 +96,7 @@
                        details.submit();
                        details.emit( 'start-details' );
                } ).fail( function () {
-                       details.emit( 'details-error' );
+                       details.showErrors();
                } );
        };
 
diff --git a/resources/controller/uw.controller.Step.js 
b/resources/controller/uw.controller.Step.js
index 10084e4..9b99daf 100644
--- a/resources/controller/uw.controller.Step.js
+++ b/resources/controller/uw.controller.Step.js
@@ -107,7 +107,7 @@
                uw.eventFlowLogger.logStep( this.stepName );
                this.emit( 'load' );
 
-               this.updateFileCounts( this.uploads );
+               this.updateFileCounts();
        };
 
        /**
@@ -152,14 +152,8 @@
         * @param {mw.UploadWizardUpload[]} uploads
         * @return {boolean} Whether there are uploads present in the list
         */
-       uw.controller.Step.prototype.updateFileCounts = function ( uploads ) {
-               if ( uploads ) {
-                       this.uploads = uploads;
-               } else {
-                       this.uploads = [];
-               }
-
-               if ( uploads.length - this.countEmpties() <= 0 ) {
+       uw.controller.Step.prototype.updateFileCounts = function () {
+               if ( this.uploads.length - this.countEmpties() <= 0 ) {
                        this.uploads = [];
                        this.emit( 'no-uploads' );
                        return false;
@@ -311,4 +305,116 @@
                return this.uploads === undefined || this.uploads.length === 0 
|| this.movedFrom;
        };
 
+       /**
+        * If there are no uploads, make a new one
+        */
+       uw.controller.Step.prototype.resetUploads = function () {
+               this.uploads = [];
+
+               if ( this.uploads.length === 0 ) {
+                       // Add one upload field to start
+                       // (this is the big one that asks you to upload 
something)
+                       this.newUpload();
+                       // Hide Flickr upload button if user doesn't have 
permissions
+                       if ( !mw.UploadWizard.config.UploadFromUrl || 
mw.UploadWizard.config.flickrApiKey === '' ) {
+                               $( '#mwe-upwiz-upload-ctrl-flickr-container, 
#mwe-upwiz-flickr-select-list-container' ).hide();
+                       }
+               }
+       };
+
+       /**
+        * Remove an upload from our array of uploads, and the HTML UI
+        * We can remove the HTML UI directly, as jquery will just get the 
parent.
+        * We need to grep through the array of uploads, since we don't know 
the current index.
+        * We need to update file counts for obvious reasons.
+        *
+        * @param {UploadWizardUpload} upload
+        */
+       uw.controller.Step.prototype.removeUpload = function ( upload ) {
+               // remove the div that passed along the trigger
+               var someupload, $div = $( upload.ui.div ),
+                       index;
+
+               if ( !this.uploads ) {
+                       // Not sure how this would happen, but let's be safe
+                       return;
+               }
+
+               $div.unbind(); // everything
+               $div.remove();
+
+               // and do what we in the wizard need to do after an upload is 
removed
+               // Remove the upload from the uploads array (modify in-place, 
as this is
+               // shared among various things that rely on having current 
information).
+               index = this.uploads.indexOf( upload );
+               if ( index !== -1 ) {
+                       this.uploads.splice( index, 1 );
+               }
+
+               this.updateFileCounts( this.uploads );
+
+               if ( this.uploads && this.uploads.length !== 0 ) {
+                       // check all uploads, if they're complete, show the 
next button
+                       this.showNext();
+               }
+
+               this.resetUploads();
+
+               someUpload = this.uploads[0];
+
+               while ( someUpload.nextUpload !== null ) {
+                       if ( someUpload.nextUpload === upload ) {
+                               someUpload.setNextUpload( upload.nextUpload );
+                               break;
+                       }
+
+                       someUpload = someUpload.nextUpload;
+               }
+       };
+
+       /**
+        * Remove uploads matching some criterion.
+        * @param {Function} test Function to test the upload
+        * @param {mw.UploadWizardUpload} test.upload Upload to test.
+        * @param {boolean} test.return Should be true if the upload is to be 
removed.
+        */
+       uw.controller.Step.prototype.removeMatchingUploads = function ( test ) {
+               var toRemove = [], step = this;
+
+               $.each( this.uploads, function ( i, upload ) {
+                       if ( upload === undefined ) {
+                               return;
+                       }
+                       if ( test( upload ) ) {
+                               toRemove.push( upload );
+                       }
+               } );
+
+               $.each( toRemove, function ( i, upload ) {
+                       if ( upload === undefined ) {
+                               return;
+                       }
+                       upload.remove();
+                       step.removeUpload( upload );
+               } );
+       };
+
+       /**
+        * Clear out uploads that are in error mode
+        */
+       uw.controller.Step.prototype.removeErrorUploads = function () {
+               this.removeMatchingUploads( function ( upload ) {
+                       return upload.state === 'error';
+               } );
+       };
+
+       /**
+        * Clear out uploads that are empty
+        */
+       uw.controller.Step.prototype.removeEmptyUploads = function () {
+               this.removeMatchingUploads( function ( upload ) {
+                       return !upload || ( !upload.file && !upload.fromURL );
+               } );
+       };
+
 }( mediaWiki, mediaWiki.uploadWizard, OO, jQuery ) );
diff --git a/resources/controller/uw.controller.Thanks.js 
b/resources/controller/uw.controller.Thanks.js
index 50931c8..ba66a74 100644
--- a/resources/controller/uw.controller.Thanks.js
+++ b/resources/controller/uw.controller.Thanks.js
@@ -26,9 +26,6 @@
                uw.controller.Step.call(
                        this,
                        new uw.ui.Thanks( config )
-                               .connect( this, {
-                                       'reset-wizard': [ 'emit', 
'reset-wizard' ]
-                               } )
                );
 
                this.stepName = 'thanks';
diff --git a/resources/controller/uw.controller.Upload.js 
b/resources/controller/uw.controller.Upload.js
index 0bc4592..2bc0713 100644
--- a/resources/controller/uw.controller.Upload.js
+++ b/resources/controller/uw.controller.Upload.js
@@ -23,9 +23,10 @@
         * @class uw.controller.Upload
         * @extends uw.controller.Step
         * @constructor
+        * @param {mw.Api} api
         * @param {Object} config UploadWizard config object.
         */
-       uw.controller.Upload = function UWControllerUpload( config ) {
+       uw.controller.Upload = function UWControllerUpload( api, config ) {
                uw.controller.Step.call(
                        this,
                        new uw.ui.Upload( config )
@@ -36,6 +37,8 @@
                        config
                );
 
+               this.uploads = [];
+               this.api = api;
                this.stepName = 'file';
                this.finishState = 'stashed';
        };
@@ -45,21 +48,17 @@
        /**
         * Updates the upload step data when a file is added or removed.
         */
-       uw.controller.Upload.prototype.updateFileCounts = function ( uploads ) {
+       uw.controller.Upload.prototype.updateFileCounts = function () {
                var fewerThanMax, haveUploads,
                        max = this.config.maxUploads;
 
                this.ui.hideEndButtons();
 
-               haveUploads = 
uw.controller.Step.prototype.updateFileCounts.call( this, uploads );
+               haveUploads = 
uw.controller.Step.prototype.updateFileCounts.call( this );
 
                fewerThanMax = this.uploads.length < max;
 
                this.ui.updateFileCounts( haveUploads, fewerThanMax );
-
-               if ( !haveUploads ) {
-                       this.emit( 'no-uploads' );
-               }
        };
 
        /**
@@ -72,14 +71,25 @@
                this.ui.showTooManyFilesWarning( filesUploaded );
        };
 
-       uw.controller.Upload.prototype.empty = function () {
-               this.ui.empty();
-       };
-
        uw.controller.Upload.prototype.moveTo = function () {
-               this.updateFileCounts( [] );
+               if ( this.hasLoadedBefore ) {
+                       // this is counterintuitive, but the count needs to 
start at -1 to allow for the empty upload created on the first step.
+                       mw.UploadWizardUpload.prototype.count = -1;
+               }
+
+               this.hasLoadedBefore = true;
+
+               this.updateFileCounts();
                uw.controller.Step.prototype.moveTo.call( this );
                this.progressBar = undefined;
+               this.resetUploads();
+       };
+
+       uw.controller.Upload.prototype.moveFrom = function () {
+               // Error uploads are forfeit, all ye who leave the upload step
+               this.removeErrorUploads();
+               this.removeEmptyUploads();
+               uw.controller.Step.prototype.moveFrom.call( this );
        };
 
        /**
@@ -185,4 +195,120 @@
                this.startUploads();
        };
 
+       /**
+        * Add an Upload: Create the upload interface, a handler to transport it
+        * to the server, and UI for the upload itself and the "details" at the
+        * second step of the wizard.
+        *
+        * We don't yet add it to the list of uploads; that only happens when it
+        * gets a real file.
+        *
+        * Returns false if there's no room for the upload (because of the 
global
+        * uploads-per-session limits)
+        *
+        * @return {UploadWizardUpload|false} the new upload
+        */
+       uw.controller.Upload.prototype.newUpload = function () {
+               var upload,
+                       step = this;
+
+               if ( this.uploads.length >= this.config.maxUploads ) {
+                       return false;
+               }
+
+               upload = new mw.UploadWizardUpload( this.api, 
'#mwe-upwiz-filelist' )
+                       .on( 'file-changed', function ( upload, files ) {
+                               var duplicate = false,
+                                       totalFiles = files.length + 
step.uploads.length,
+                                       tooManyFiles = totalFiles > 
step.config.maxUploads;
+
+                               if ( tooManyFiles ) {
+                                       step.showTooManyFilesWarning( 
totalFiles );
+                                       upload.resetFileInput();
+                                       return;
+                               }
+
+                               // check to see if the file has already been 
selected for upload.
+                               $.each( step.uploads, function ( i, thisupload 
) {
+                                       if ( thisupload !== undefined && upload 
!== thisupload && filename === thisupload.filename ) {
+                                               duplicate = true;
+                                               return false;
+                                       }
+                               } );
+
+                               upload.checkFile(
+                                       upload.ui.getFilename(),
+                                       files,
+                                       duplicate,
+                                       function () { upload.fileChangedOk(); }
+                               );
+
+                               uw.eventFlowLogger.logUploadEvent( 
'uploads-added', { quantity: files.length } );
+                       } )
+
+                       .on( 'filled', function () {
+                               step.setUploadFilled( upload );
+                       } )
+
+                       .on( 'extra-files', function ( files, toobig ) {
+                               var lastUpload = upload;
+
+                               $.each( files, function ( i, file ) {
+                                       // NOTE: By running newUpload we will 
end up calling checkfile() again.
+                                       var newUpload = step.newUpload();
+
+                                       lastUpload.setNextUpload( newUpload );
+
+                                       if ( toobig ) {
+                                               newUpload.disablePreview();
+                                       }
+
+                                       newUpload.fill( file );
+
+                                       lastUpload = newUpload;
+                               } );
+
+                               // Add a new upload to cover the button
+                               lastUpload.setNextUpload( step.newUpload() );
+
+                               step.updateFileCounts();
+                       } )
+
+                       .on( 'filename-accepted', function () {
+                               step.updateFileCounts();
+                       } )
+
+                       .on( 'error', function ( code, message ) {
+                               uw.eventFlowLogger.logError( 'file', { code: 
code, message: message } );
+                       } )
+                       
+                       .on( 'success', function () {
+                               // Upload finished, check all of them, maybe 
move to the next
+                               // step.
+                               step.showNext();
+                       } );
+
+               // we explicitly move the file input to cover the upload button
+               upload.ui.moveFileInputToCover( '#mwe-upwiz-add-file', 'poll' );
+
+               upload.connect( this, {
+                       'remove-upload': [ 'removeUpload', upload ]
+               } );
+
+               return upload;
+       };
+
+       /**
+        * When an upload is filled with a real file, accept it in the wizard's 
list of uploads
+        * and set up some other interfaces
+        *
+        * @param {UploadWizardUpload} upload
+        */
+       uw.controller.Upload.prototype.setUploadFilled = function ( upload ) {
+               this.uploads.push( upload );
+               this.updateFileCounts();
+               // Start uploads now, no reason to wait--leave the remove 
button alone
+               this.startUploads();
+       };
+
 }( mediaWiki, mediaWiki.uploadWizard, jQuery, OO ) );
diff --git a/resources/mw.UploadWizard.js b/resources/mw.UploadWizard.js
index 588e774..ce69fbd 100644
--- a/resources/mw.UploadWizard.js
+++ b/resources/mw.UploadWizard.js
@@ -7,7 +7,6 @@
        mw.UploadWizard = function ( config ) {
                var maxSimPref, wizard;
 
-               this.uploads = [];
                this.api = new mw.Api( { ajax: { timeout: 0 } } );
 
                // making a sort of global for now, should be done by passing 
in config or fragments of config
@@ -31,37 +30,14 @@
 
                this.steps = {
                        tutorial: new uw.controller.Tutorial( this.api ),
-
-                       file: new uw.controller.Upload( config )
+                       file: new uw.controller.Upload( this.api, config )
                                .on( 'flickr-ui-init', function () {
                                        wizard.flickrInterfaceInit();
                                        uw.eventFlowLogger.logEvent( 
'flickr-upload-button-clicked' );
-                               } )
-
-                               .on( 'load', function () {
-                                       wizard.reset();
-                                       wizard.resetFileStepUploads();
                                } ),
-
-                       deeds: new uw.controller.Deed( this.api, config )
-                               .on( 'load', function () {
-                                       wizard.removeErrorUploads();
-                               } ),
-
-                       details: new uw.controller.Details( config )
-                               .on( 'details-error', function () {
-                                       wizard.steps.details.showErrors();
-                               } )
-
-                               .on( 'finalize-details-after-removal', function 
() {
-                                       wizard.removeErrorUploads();
-                                       wizard.steps.details.moveFrom();
-                               } ),
-
+                       deeds: new uw.controller.Deed( this.api, config ),
+                       details: new uw.controller.Details( config ),
                        thanks: new uw.controller.Thanks( config )
-                               .on( 'reset-wizard', function () {
-                                       wizard.reset();
-                               } )
                };
 
                $.each( this.steps, function ( name, step ) {
@@ -102,22 +78,6 @@
 
        mw.UploadWizard.prototype = {
                stepNames: [ 'tutorial', 'file', 'deeds', 'details', 'thanks' ],
-
-               /**
-                * Reset the entire interface so we can upload more stuff
-                * (depends on updateFileCounts to reset the interface when 
uploads go down to 0)
-                * Depending on whether we split uploading / detailing, it may 
actually always be as simple as loading a URL
-                */
-               reset: function () {
-                       if ( this.hasLoadedBefore ) {
-                               // this is counterintuitive, but the count 
needs to start at -1 to allow for the empty upload created on the first step.
-                               mw.UploadWizardUpload.prototype.count = -1;
-                       }
-
-                       this.showDeed = false;
-                       this.removeMatchingUploads( function () { return true; 
} );
-                       this.hasLoadedBefore = true;
-               },
 
                /**
                 * Resets wizard state and moves to the file step.
@@ -224,194 +184,6 @@
                        $( '#mwe-upwiz-flickr-select-list-container' ).hide();
                        $( '#mwe-upwiz-upload-add-flickr-container' ).hide();
                        $( '#mwe-upwiz-upload-add-flickr' ).prop( 'disabled', 
true );
-               },
-
-               /**
-                * If there are no uploads, make a new one
-                */
-               resetFileStepUploads: function () {
-                       if ( this.uploads.length === 0 ) {
-                               // add one upload field to start (this is the 
big one that asks you to upload something)
-                               this.newUpload();
-                               // hide flickr uploading button if user doesn't 
have permissions
-                               if ( !mw.UploadWizard.config.UploadFromUrl || 
mw.UploadWizard.config.flickrApiKey === '' ) {
-                                       $( 
'#mwe-upwiz-upload-ctrl-flickr-container, 
#mwe-upwiz-flickr-select-list-container' ).hide();
-                               }
-                       }
-               },
-
-               /**
-                * Add an Upload
-                *   we create the upload interface, a handler to transport it 
to the server,
-                *   and UI for the upload itself and the "details" at the 
second step of the wizard.
-                *   we don't yet add it to the list of uploads; that only 
happens when it gets a real file.
-                *
-                * @return {UploadWizardUpload|false} the new upload
-                */
-               newUpload: function () {
-                       var upload,
-                               wizard = this;
-
-                       if ( this.uploads.length >= this.config.maxUploads ) {
-                               return false;
-                       }
-
-                       upload = new mw.UploadWizardUpload( this, 
'#mwe-upwiz-filelist' )
-                               .on( 'file-changed', function ( upload, files ) 
{
-                                       var totalFiles = files.length + 
wizard.uploads.length,
-                                               tooManyFiles = totalFiles > 
wizard.config.maxUploads;
-
-                                       if ( tooManyFiles ) {
-                                               
wizard.steps.file.showTooManyFilesWarning( totalFiles );
-                                               upload.resetFileInput();
-                                               return;
-                                       }
-
-                                       upload.checkFile(
-                                               upload.ui.getFilename(),
-                                               files,
-                                               function () { 
upload.fileChangedOk(); }
-                                       );
-
-                                       uw.eventFlowLogger.logUploadEvent( 
'uploads-added', { quantity: files.length } );
-                               } )
-
-                               .on( 'filled', function () {
-                                       wizard.setUploadFilled( upload );
-                               } )
-
-                               .on( 'extra-files', function ( files, toobig ) {
-                                       $.each( files, function ( i, file ) {
-                                               // NOTE: By running newUpload 
we will end up calling checkfile() again.
-                                               var newUpload = 
wizard.newUpload();
-
-                                               if ( toobig ) {
-                                                       
newUpload.disablePreview();
-                                               }
-
-                                               newUpload.fill( file );
-                                       } );
-
-                                       // Add a new upload to cover the button
-                                       wizard.newUpload();
-
-                                       wizard.steps.file.updateFileCounts( 
wizard.uploads );
-                               } )
-
-                               .on( 'filename-accepted', function () {
-                                       wizard.steps.file.updateFileCounts( 
wizard.uploads );
-                               } )
-
-                               .on( 'error', function ( code, message ) {
-                                       uw.eventFlowLogger.logError( 'file', { 
code: code, message: message } );
-                               } );
-
-                       // we explicitly move the file input to cover the 
upload button
-                       upload.ui.moveFileInputToCover( '#mwe-upwiz-add-file', 
'poll' );
-
-                       upload.connect( this, {
-                               'remove-upload': [ 'removeUpload', upload ]
-                       } );
-
-                       return upload;
-               },
-
-               /**
-                * When an upload is filled with a real file, accept it in the 
wizard's list of uploads
-                * and set up some other interfaces
-                *
-                * @param {UploadWizardUpload} upload
-                */
-               setUploadFilled: function ( upload ) {
-                       this.uploads.push( upload );
-                       this.steps.file.updateFileCounts( this.uploads );
-                       // Start uploads now, no reason to wait--leave the 
remove button alone
-                       this.steps.file.startUploads();
-               },
-
-               /**
-                * Remove an upload from our array of uploads, and the HTML UI
-                * We can remove the HTML UI directly, as jquery will just get 
the parent.
-                * We need to grep through the array of uploads, since we don't 
know the current index.
-                * We need to update file counts for obvious reasons.
-                *
-                * @param {UploadWizardUpload} upload
-                */
-               removeUpload: function ( upload ) {
-                       // remove the div that passed along the trigger
-                       var $div = $( upload.ui.div ),
-                               index;
-
-                       $div.unbind(); // everything
-                       $div.remove();
-                       // and do what we in the wizard need to do after an 
upload is removed
-                       // Remove the upload from the uploads array (modify 
in-place, as this is shared among various
-                       // things that rely on having current information).
-                       index = this.uploads.indexOf( upload );
-                       if ( index !== -1 ) {
-                               this.uploads.splice( index, 1 );
-                       }
-
-                       this.steps.file.updateFileCounts( this.uploads );
-
-                       if ( this.uploads && this.uploads.length !== 0 ) {
-                               // check all uploads, if they're complete, show 
the next button
-                               this.steps.file.showNext();
-                       }
-
-                       this.resetFileStepUploads();
-               },
-
-               /**
-                * This is useful to clean out unused upload file inputs if the 
user hits GO.
-                * We are using a second array to iterate, because we will be 
splicing the main one, _this.uploads
-                */
-               removeEmptyUploads: function () {
-
-                       // First remove array keys that don't have an assigned 
upload object
-                       this.uploads = $.grep( this.uploads,
-                               function ( v ) { return v !== undefined; }
-                       );
-
-                       // Now remove upload objects that exist but are empty
-                       this.removeMatchingUploads( function ( upload ) {
-                               return mw.isEmpty( upload.filename );
-                       } );
-               },
-
-               /**
-                * Clear out uploads that are in error mode, perhaps before 
proceeding to the next step
-                */
-               removeErrorUploads: function () {
-                       this.removeMatchingUploads( function ( upload ) {
-                               return upload.state === 'error';
-                       } );
-               },
-
-               /**
-                * This is useful to clean out file inputs that we don't want 
for some reason (error, empty...)
-                * We are using a second array to iterate, because we will be 
splicing the main one, _this.uploads
-                *
-                * @param {Function} criterion Function to test the upload, 
returns boolean; true if should be removed
-                */
-               removeMatchingUploads: function ( criterion ) {
-                       var toRemove = [];
-
-                       $.each( this.uploads, function ( i, upload ) {
-                               if ( upload === undefined ) {
-                                       return;
-                               }
-                               if ( criterion( upload ) ) {
-                                       toRemove.push( upload );
-                               }
-                       } );
-
-                       $.each( toRemove, function ( i, upload ) {
-                               if ( upload === undefined ) {
-                                       return;
-                               }
-                               upload.remove();
-                       } );
                },
 
                /**
diff --git a/resources/mw.UploadWizardDetails.js 
b/resources/mw.UploadWizardDetails.js
index 5fe4fd7..50a357e 100644
--- a/resources/mw.UploadWizardDetails.js
+++ b/resources/mw.UploadWizardDetails.js
@@ -282,17 +282,21 @@
                 */
                copyMetadata: function ( metadataType ) {
                        var titleZero, matches, i, j, currentTitle,
-                               uploads = this.upload.wizard.uploads,
                                moreInfo,
-                               sourceValue,
-                               sourceUpload = uploads[ 0 ];
+                               sourceValue, currentUpload,
+                               sourceUpload = this.upload;
 
                        function oouiCopy( property ) {
-                               var i;
+                               var upload = sourceUpload.nextUpload;
 
                                sourceValue = sourceUpload.details[ property 
].getSerialized();
-                               for ( i = 1; i < uploads.length; i++ ) {
-                                       uploads[ i ].details[ property 
].setSerialized( sourceValue );
+
+                               while ( upload !== null ) {
+                                       if ( upload && upload.details ) {
+                                               upload.details[ property 
].setSerialized( sourceValue );
+                                       }
+
+                                       upload = upload.nextUpload;
                                }
                        }
 
@@ -311,16 +315,23 @@
                                // numbers.
 
                                // This loop starts from 0 and not 1 - we want 
to overwrite the source upload too!
-                               for ( i = 0; i < uploads.length; i++ ) {
+                               currentUpload = sourceUpload;
+                               i = 0;
+                               while ( currentUpload !== null ) {
                                        /*jshint loopfunc:true */
                                        currentTitle = titleZero.replace( 
/(\D+)(\d{1,3})(\D*)$/,
                                                function ( str, m1, m2, m3 ) {
-                                                       var newstr = String( 
+m2 + i );
+                                                       var newstr = String( 
+m2 + i++ );
                                                        return m1 + new Array( 
m2.length + 1 - newstr.length )
                                                                .join( '0' ) + 
newstr + m3;
                                                }
                                        );
-                                       uploads[ i 
].details.titleDetails.setSerialized( { title: currentTitle } );
+
+                                       if ( currentUpload && 
currentUpload.details ) {
+                                               
currentUpload.details.titleDetails.setSerialized( { title: currentTitle } );
+                                       }
+
+                                       currentUpload = 
currentUpload.nextUpload;
                                }
 
                        } else if ( metadataType === 'description' ) {
@@ -346,8 +357,13 @@
                                // Copy fields added though campaigns
                                for ( j = 0; j < 
sourceUpload.details.campaignDetailsFields.length; j++ ) {
                                        sourceValue = 
sourceUpload.details.campaignDetailsFields[ j ].fieldWidget.getSerialized();
-                                       for ( i = 1; i < uploads.length; i++ ) {
-                                               uploads[ i 
].details.campaignDetailsFields[ j ].fieldWidget.setSerialized( sourceValue );
+                                       currentUpload = sourceUpload.nextUpload;
+                                       while ( currentUpload !== null ) {
+                                               if ( currentUpload && 
currentUpload.details ) {
+                                                       
currentUpload.details.campaignDetailsFields[ j ].fieldWidget.setSerialized( 
sourceValue );
+                                               }
+
+                                               currentUpload = 
currentUpload.nextUpload;
                                        }
                                }
 
@@ -357,11 +373,16 @@
 
                        if ( metadataType === 'location' || metadataType === 
'other' ) {
                                // Expand collapsed sections if we changed the 
fields within
-                               for ( i = 1; i < uploads.length; i++ ) {
-                                       moreInfo = uploads[ i 
].details.$form.find( '.mwe-upwiz-details-more-options a' );
-                                       if ( !moreInfo.hasClass( 
'mwe-upwiz-toggler-open' ) ) {
-                                               moreInfo.click();
+                               currentUpload = sourceUpload.nextUpload;
+                               while ( currentUpload !== null ) {
+                                       if ( currentUpload && 
currentUpload.details ) {
+                                               moreInfo = 
currentUpload.details.$form.find( '.mwe-upwiz-details-more-options a' );
+                                               if ( !moreInfo.hasClass( 
'mwe-upwiz-toggler-open' ) ) {
+                                                       moreInfo.click();
+                                               }
                                        }
+
+                                       currentUpload = 
currentUpload.nextUpload;
                                }
                        }
                },
diff --git a/resources/mw.UploadWizardUpload.js 
b/resources/mw.UploadWizardUpload.js
index da20c4d..1db7b18 100644
--- a/resources/mw.UploadWizardUpload.js
+++ b/resources/mw.UploadWizardUpload.js
@@ -25,7 +25,7 @@
         * @param {UploadWizard} wizard
         * @param {string} filesDiv Selector for the `div` where we will dump 
the interfaces for uploads
         */
-       mw.UploadWizardUpload = function MWUploadWizardUpload( wizard, filesDiv 
) {
+       mw.UploadWizardUpload = function MWUploadWizardUpload( api, filesDiv ) {
                var upload = this;
 
                OO.EventEmitter.call( this );
@@ -33,8 +33,7 @@
                this.index = mw.UploadWizardUpload.prototype.count;
                mw.UploadWizardUpload.prototype.count++;
 
-               this.wizard = wizard;
-               this.api = wizard.api;
+               this.api = api;
                this.state = 'new';
                this.thumbnailPublishers = {};
                this.imageinfo = {};
@@ -75,6 +74,12 @@
 
        // increments with each upload
        mw.UploadWizardUpload.prototype.count = 0;
+
+       mw.UploadWizardUpload.prototype.nextUpload = null;
+
+       mw.UploadWizardUpload.prototype.setNextUpload = function ( upload ) {
+               this.nextUpload = upload;
+       };
 
        /**
         * Manually fill the file input with a file.
@@ -334,9 +339,6 @@
                        this.ui.showStashed();
 
                        this.emit( 'success' );
-                       // check all uploads, if they're complete, show the 
next button
-                       // TODO Make wizard connect to 'success' event
-                       this.wizard.steps.file.showNext();
                } else {
                        this.setError( 'noimageinfo' );
                }
@@ -385,8 +387,8 @@
         * @param {Array} files Array of files, usually one; can be more for 
multi-file select.
         * @param {Function} fileNameOk Callback to use when ok, and upload 
object is ready
         */
-       mw.UploadWizardUpload.prototype.checkFile = function ( filename, files, 
fileNameOk ) {
-               var totalSize, duplicate, extension, toobig,
+       mw.UploadWizardUpload.prototype.checkFile = function ( filename, files, 
duplicate, fileNameOk ) {
+               var totalSize, extension, toobig,
                        actualMaxSize, binReader,
                        upload = this,
 
@@ -419,15 +421,6 @@
                                this.disablePreview();
                        }
                }
-
-               // check to see if the file has already been selected for 
upload.
-               duplicate = false;
-               $.each( this.wizard.uploads, function ( i, thisupload ) {
-                       if ( thisupload !== undefined && upload !== thisupload 
&& filename === thisupload.filename ) {
-                               duplicate = true;
-                               return false;
-                       }
-               } );
 
                if ( duplicate ) {
                        this.fileNameErr( 'dup', basename );

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5b2c0231cadbb7db3e5f38eb244efa090249592a
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/UploadWizard
Gerrit-Branch: master
Gerrit-Owner: MarkTraceur <mtrac...@member.fsf.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to