summaryrefslogtreecommitdiff
path: root/www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js')
-rw-r--r--www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js363
1 files changed, 363 insertions, 0 deletions
diff --git a/www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js b/www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js
new file mode 100644
index 00000000..aae6c791
--- /dev/null
+++ b/www/wiki/extensions/UploadWizard/resources/controller/uw.controller.Upload.js
@@ -0,0 +1,363 @@
+/*
+ * This file is part of the MediaWiki extension UploadWizard.
+ *
+ * UploadWizard is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * UploadWizard is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with UploadWizard. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+( function ( mw, uw, $, OO ) {
+
+ /**
+ * Upload step controller.
+ *
+ * @class
+ * @extends uw.controller.Step
+ * @param {mw.Api} api
+ * @param {Object} config UploadWizard config object.
+ */
+ uw.controller.Upload = function UWControllerUpload( api, config ) {
+ var step = this;
+
+ uw.controller.Step.call(
+ this,
+ new uw.ui.Upload( config )
+ .connect( this, {
+ retry: 'retry'
+ } ),
+ api,
+ config
+ );
+
+ this.stepName = 'file';
+ this.finishState = 'stashed';
+
+ this.queue = new uw.ConcurrentQueue( {
+ count: this.config.maxSimultaneousConnections,
+ action: this.transitionOne.bind( this )
+ } );
+ this.queue.on( 'complete', this.showNext.bind( this ) );
+
+ this.ui.on( 'files-added', function ( files ) {
+ var totalFiles = files.length + step.uploads.length,
+ tooManyFiles = totalFiles > step.config.maxUploads;
+
+ if ( tooManyFiles ) {
+ step.ui.showTooManyFilesError( totalFiles );
+ } else {
+ step.addFiles( files );
+ }
+ } );
+ };
+
+ OO.inheritClass( uw.controller.Upload, uw.controller.Step );
+
+ /**
+ * Updates the upload step data when a file is added or removed.
+ */
+ uw.controller.Upload.prototype.updateFileCounts = function () {
+ var fewerThanMax, haveUploads,
+ max = this.config.maxUploads;
+
+ haveUploads = this.uploads.length > 0;
+ fewerThanMax = this.uploads.length < max;
+
+ this.updateProgressBarCount( this.uploads.length );
+ this.ui.updateFileCounts( haveUploads, fewerThanMax );
+ };
+
+ uw.controller.Upload.prototype.load = function ( uploads ) {
+ var controller = this;
+
+ uw.controller.Step.prototype.load.call( this, uploads );
+ this.updateFileCounts();
+ this.startProgressBar();
+
+ // make sure queue is empty before starting this step
+ this.queue.abortExecuting();
+
+ if ( uploads.length > 0 ) {
+ /*
+ * If we have uploads already, we'll want to to update the "next"
+ * buttons accordingly. showNext() does that, but relies on upload
+ * state being set correctly.
+ * Since every step overwrites the upload state, we'll need to reset
+ * it to reflect the correct upload success state.
+ * If other files are to be added, the showNext() callback will deal
+ * with new uploads, and still understand the existing files that
+ * we've just reset the state for.
+ */
+ $.each( uploads, function ( i, upload ) {
+ upload.state = upload.fileKey === undefined ? 'error' : controller.finishState;
+ } );
+
+ this.showNext();
+ }
+ };
+
+ uw.controller.Upload.prototype.moveNext = function () {
+ this.removeErrorUploads();
+
+ uw.controller.Step.prototype.moveNext.call( this );
+ };
+
+ /**
+ * Starts the upload progress bar.
+ */
+ uw.controller.Upload.prototype.startProgressBar = function () {
+ this.ui.showProgressBar();
+ this.progressBar = new mw.GroupProgressBar( this.ui.$progress,
+ this.uploads,
+ [ 'stashed' ],
+ [ 'error' ],
+ 'transportProgress',
+ 'transportWeight' );
+ this.progressBar.start();
+ };
+
+ /**
+ * Starts progress bar if there's not an existing one.
+ */
+ uw.controller.Upload.prototype.maybeStartProgressBar = function () {
+ if ( this.progressBarEmptyOrFinished() ) {
+ this.startProgressBar();
+ }
+ };
+
+ /**
+ * Check if there is a vacancy for a new progress bar.
+ *
+ * @return {boolean}
+ */
+ uw.controller.Upload.prototype.progressBarEmptyOrFinished = function () {
+ return !this.progressBar || this.progressBar.finished === true;
+ };
+
+ /**
+ * Update success count on the progress bar.
+ *
+ * @param {number} okCount
+ */
+ uw.controller.Upload.prototype.updateProgressBarCount = function ( okCount ) {
+ if ( this.progressBar ) {
+ this.progressBar.showCount( okCount );
+ }
+ };
+
+ uw.controller.Upload.prototype.canTransition = function ( upload ) {
+ return (
+ uw.controller.Step.prototype.canTransition.call( this, upload ) &&
+ upload.state === 'new'
+ );
+ };
+
+ /**
+ * Perform this step's changes on one upload.
+ *
+ * @param {mw.UploadWizardUpload} upload
+ * @return {jQuery.Promise}
+ */
+ uw.controller.Upload.prototype.transitionOne = function ( upload ) {
+ var promise = upload.start();
+ this.maybeStartProgressBar();
+ return promise;
+ };
+
+ /**
+ * Queue an upload object to be uploaded.
+ *
+ * @param {mw.UploadWizardUpload} upload
+ */
+ uw.controller.Upload.prototype.queueUpload = function ( upload ) {
+ if ( this.canTransition( upload ) ) {
+ this.queue.addItem( upload );
+ }
+ };
+
+ /**
+ * Kick off the upload processes.
+ */
+ uw.controller.Upload.prototype.startQueuedUploads = function () {
+ this.queue.startExecuting();
+ };
+
+ uw.controller.Upload.prototype.retry = function () {
+ var controller = this;
+ uw.eventFlowLogger.logEvent( 'retry-uploads-button-clicked' );
+
+ $.each( this.uploads, function ( i, upload ) {
+ if ( upload.state === 'error' ) {
+ // reset any uploads in error state back to be shiny & new
+ upload.state = 'new';
+ upload.ui.clearIndicator();
+ upload.ui.clearStatus();
+ // and queue them
+ controller.queueUpload( upload );
+ }
+ } );
+
+ this.startQueuedUploads();
+ };
+
+ /**
+ * Create the upload interface, a handler to transport it to the server, and UI for the upload
+ * itself; and immediately fill it with a file and add it to the list of uploads.
+ *
+ * @param {File} file
+ * @return {UploadWizardUpload|false} The new upload, or false if it can't be added
+ */
+ uw.controller.Upload.prototype.addFile = function ( file ) {
+ var upload;
+
+ if ( this.uploads.length >= this.config.maxUploads ) {
+ return false;
+ }
+
+ upload = new mw.UploadWizardUpload( this, file );
+
+ if ( !this.validateFile( upload ) ) {
+ return false;
+ }
+
+ upload.fileChangedOk();
+
+ // attach controller-specific event handlers (they're automatically
+ // bound on load already, but we've only just added these files...)
+ this.bindUploadHandlers( upload );
+
+ this.setUploadFilled( upload );
+
+ return upload;
+ };
+
+ /**
+ * Do everything that needs to be done to start uploading a file. Calls #addFile, then appends
+ * each mw.UploadWizardUploadInterface to the DOM and queues thumbnails to be generated.
+ *
+ * @param {File[]} files
+ */
+ uw.controller.Upload.prototype.addFiles = function ( files ) {
+ var
+ uploadObj,
+ uploadObjs = [],
+ controller = this;
+
+ $.each( files, function ( i, file ) {
+ uploadObj = controller.addFile( file );
+ if ( uploadObj ) {
+ uploadObjs.push( uploadObj );
+ }
+ } );
+
+ this.ui.displayUploads( uploadObjs );
+
+ uw.eventFlowLogger.logUploadEvent( 'uploads-added', { quantity: files.length } );
+ };
+
+ /**
+ * 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 {mw.UploadWizardUpload} upload
+ */
+ uw.controller.Upload.prototype.removeUpload = function ( upload ) {
+ uw.controller.Step.prototype.removeUpload.call( this, upload );
+
+ this.queue.removeItem( upload );
+
+ this.updateFileCounts();
+
+ // check all uploads, if they're complete, show the next button
+ this.showNext();
+ };
+
+ /**
+ * When an upload is filled with a real file, accept it in the list of uploads
+ * and set up some other interfaces
+ *
+ * @param {mw.UploadWizardUpload} upload
+ */
+ uw.controller.Upload.prototype.setUploadFilled = function ( upload ) {
+ this.addUpload( upload );
+ this.updateFileCounts();
+ // Start uploads now, no reason to wait--leave the remove button alone
+ this.queueUpload( upload );
+ this.startQueuedUploads();
+ };
+
+ /**
+ * Checks for file validity.
+ *
+ * @param {mw.UploadWizardUpload} upload
+ * @return {boolean} Error in [code, info] format, or empty [] for no errors
+ */
+ uw.controller.Upload.prototype.validateFile = function ( upload ) {
+ var extension,
+ i,
+ actualMaxSize = mw.UploadWizard.config.maxMwUploadSize,
+
+ // Check if filename is acceptable
+ // TODO sanitize filename
+ filename = upload.getFilename(),
+ basename = upload.getBasename();
+
+ // check to see if this file has already been selected for upload
+ for ( i = 0; i < this.uploads.length; i++ ) {
+ if ( upload !== this.uploads[ i ] && filename === this.uploads[ i ].getFilename() ) {
+ this.ui.showDuplicateError( filename, basename );
+ return false;
+ }
+ }
+
+ // check if the filename is valid
+ upload.setTitle( basename );
+ if ( !upload.title ) {
+ if ( basename.indexOf( '.' ) === -1 ) {
+ this.ui.showMissingExtensionError( filename );
+ return false;
+ } else {
+ this.ui.showUnparseableFilenameError( filename );
+ return false;
+ }
+ }
+
+ // check if extension is acceptable
+ extension = upload.title.getExtension();
+ if ( !extension ) {
+ this.ui.showMissingExtensionError( filename );
+ return false;
+ }
+
+ if (
+ mw.UploadWizard.config.fileExtensions !== null &&
+ $.inArray( extension.toLowerCase(), mw.UploadWizard.config.fileExtensions ) === -1
+ ) {
+ this.ui.showBadExtensionError( filename, extension );
+ return false;
+ }
+
+ // make sure the file isn't too large
+ // TODO need a way to find the size of the Flickr image
+ if ( upload.file.size ) {
+ upload.transportWeight = upload.file.size;
+ if ( upload.transportWeight > actualMaxSize ) {
+ this.ui.showFileTooLargeError( actualMaxSize, upload.transportWeight );
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+}( mediaWiki, mediaWiki.uploadWizard, jQuery, OO ) );