diff options
Diffstat (limited to 'www/wiki/extensions/UploadWizard/resources/ui/steps/uw.ui.Upload.js')
-rw-r--r-- | www/wiki/extensions/UploadWizard/resources/ui/steps/uw.ui.Upload.js | 579 |
1 files changed, 579 insertions, 0 deletions
diff --git a/www/wiki/extensions/UploadWizard/resources/ui/steps/uw.ui.Upload.js b/www/wiki/extensions/UploadWizard/resources/ui/steps/uw.ui.Upload.js new file mode 100644 index 00000000..78c001db --- /dev/null +++ b/www/wiki/extensions/UploadWizard/resources/ui/steps/uw.ui.Upload.js @@ -0,0 +1,579 @@ +/* + * 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 ) { + /** + * Represents the UI for the wizard's Upload step. + * + * @class uw.ui.Upload + * @extends uw.ui.Step + * @constructor + * @param {Object} config UploadWizard config object. + */ + uw.ui.Upload = function UWUIUpload( config ) { + var upload = this; + + this.config = config; + + uw.ui.Step.call( + this, + 'file' + ); + + this.$addFileContainer = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-add-file-container' ) + .addClass( 'mwe-upwiz-add-files-0' ); + + this.$uploadCtrl = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-upload-ctrls' ) + .addClass( 'mwe-upwiz-file ui-helper-clearfix' ) + .append( this.$addFileContainer ); + + this.addFile = new OO.ui.ButtonWidget( { + id: 'mwe-upwiz-add-file', + label: mw.message( 'mwe-upwiz-add-file-0-free' ).text(), + flags: [ 'progressive', 'primary' ] + } ); + + this.$addFileContainer.append( this.addFile.$element ); + + if ( this.isFlickrImportEnabled() ) { + this.$flickrAddFileContainer = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-upload-ctrl-flickr-container' ); + + this.$uploadCenterDivide = $( '<p>' ) + .attr( 'id', 'mwe-upwiz-upload-ctr-divide' ) + .text( mw.message( 'mwe-upwiz-add-flickr-or' ).text() ); + + this.addFlickrFile = new OO.ui.ButtonWidget( { + id: 'mwe-upwiz-add-flickr-file', + label: mw.message( 'mwe-upwiz-add-file-flickr' ).text(), + flags: 'progressive' + } ).on( 'click', function () { + upload.flickrInterfaceInit(); + uw.eventFlowLogger.logEvent( 'flickr-upload-button-clicked' ); + } ); + + this.$flickrAddFileContainer.append( + this.$uploadCenterDivide, + this.addFlickrFile.$element + ); + + this.$addFileContainer + .append( this.$flickrAddFileContainer ); + + this.$flickrSelectList = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-flickr-select-list' ); + + this.$flickrSelectListContainer = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-flickr-select-list-container' ) + .addClass( 'ui-corner-all' ) + .append( + $( '<div>' ) + .text( mw.message( + 'mwe-upwiz-multi-file-select2', + config.maxUploads + ) ), + this.$flickrSelectList + ); + + // Button to move on & upload the files that were selected + this.flickrSelectButton = new OO.ui.ButtonWidget( { + id: 'mwe-upwiz-select-flickr', + label: mw.message( 'mwe-upwiz-add-file-0-free' ).text(), + flags: [ 'progressive', 'primary' ] + } ); + this.$flickrSelectListContainer.append( this.flickrSelectButton.$element ); + + // A container holding a form + this.$flickrContainer = $( '<div id="mwe-upwiz-upload-add-flickr-container"></div>' ); + + // Form whose submit event will be listened to and prevented + this.$flickrForm = $( '<form id="mwe-upwiz-flickr-url-form"></form>' ) + .appendTo( this.$flickrContainer ) + .on( 'submit', function () { + var checker = new mw.FlickrChecker( upload, upload.flickrSelectButton ); + upload.flickrButton.setDisabled( true ); + upload.flickrChecker( checker ); + // TODO Any particular reason to stopPropagation ? + return false; + } ); + + // The input that will hold a flickr URL entered by the user; will be appended to a form + this.$flickrInput = $( '<input id="mwe-upwiz-flickr-input" type="text" />' ) + .attr( 'placeholder', mw.message( 'mwe-upwiz-flickr-input-placeholder' ).text() ) + .prependTo( this.$flickrForm ); + + this.flickrButton = new OO.ui.ButtonInputWidget( { + id: 'mwe-upwiz-upload-ctrl-flickr', + label: mw.message( 'mwe-upwiz-add-flickr' ).text(), + flags: [ 'progressive', 'primary' ], + type: 'submit' + } ); + this.$flickrForm.append( this.flickrButton.$element ); + + // Add disclaimer + $( '<div id="mwe-upwiz-flickr-disclaimer"></div>' ) + .html( + mw.message( 'mwe-upwiz-flickr-disclaimer1' ).parse() + + '<br/>' + mw.message( 'mwe-upwiz-flickr-disclaimer2' ).parse() + ) + .appendTo( this.$flickrContainer ); + } + + this.nextStepButtonAllOk = new OO.ui.ButtonWidget( { + label: mw.message( 'mwe-upwiz-next-file' ).text(), + flags: [ 'progressive', 'primary' ] + } ).on( 'click', function () { + upload.emit( 'next-step' ); + } ); + + this.retryButtonSomeFailed = new OO.ui.ButtonWidget( { + label: mw.message( 'mwe-upwiz-file-retry' ).text(), + flags: [ 'progressive' ] + } ).on( 'click', function () { + upload.hideEndButtons(); + upload.emit( 'retry' ); + } ); + + this.nextStepButtonSomeFailed = new OO.ui.ButtonWidget( { + label: mw.message( 'mwe-upwiz-next-file-despite-failures' ).text(), + flags: [ 'progressive', 'primary' ] + } ).on( 'click', function () { + upload.emit( 'next-step' ); + } ); + + this.retryButtonAllFailed = new OO.ui.ButtonWidget( { + label: mw.message( 'mwe-upwiz-file-retry' ).text(), + flags: [ 'progressive' ] + } ).on( 'click', function () { + upload.hideEndButtons(); + upload.emit( 'retry' ); + } ); + + this.$fileList = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-filelist' ) + .addClass( 'ui-corner-all' ); + + this.$progress = $( '<div>' ) + .attr( 'id', 'mwe-upwiz-progress' ) + .addClass( 'ui-helper-clearfix' ); + + this.addPreviousButton(); + this.addNextButton(); + }; + + OO.inheritClass( uw.ui.Upload, uw.ui.Step ); + + /** + * Set up the "Add files" button (#mwe-upwiz-add-file) to open a file selection dialog on click + * by means of a hidden `<input type="file">`. + * + * @param {jQuery} $element The element to append to + */ + uw.ui.Upload.prototype.setupFileInputCtrl = function ( $element ) { + var $fileInputCtrl = $( '<input type="file" multiple name="file" class="mwe-upwiz-file-input" />' ), + ui = this; + + // Check for iOS 5 Safari's lack of file uploads (T34328#364508). + // While this looks extremely unlikely to be right, it actually is. Blame Apple. + if ( $fileInputCtrl.prop( 'disabled' ) ) { + $element.replaceWith( + $( '<span>' ).msg( 'mwe-upwiz-file-upload-notcapable' ) + ); + + return; + } + + $element.find( '.mwe-upwiz-file-input' ).remove(); + $element.append( $fileInputCtrl ); + + $fileInputCtrl.on( 'change', function () { + ui.emit( 'files-added', $fileInputCtrl[ 0 ].files ); + + // We can't clear the value of a file input, so replace the whole + // thing with a new one + ui.setupFileInputCtrl( $element ); + } ); + + $fileInputCtrl.on( 'focus', function () { + // In IE 11, focussing a file input (by clicking on it) displays a text cursor and scrolls + // the cursor into view (in this case, it scrolls the button, which has 'overflow: hidden'). + // Since this messes with our custom styling (the file input has large dimensions and this + // causes the label to scroll out of view), scroll the button back to top. (T192131) + $element.prop( 'scrollTop', 0 ); + } ); + }; + + uw.ui.Upload.prototype.showProgressBar = function () { + this.$progress.show(); + }; + + /** + * Updates the interface based on the number of uploads. + * + * @param {boolean} haveUploads Whether there are any uploads at all. + * @param {boolean} fewerThanMax Whether we can add more uploads. + */ + uw.ui.Upload.prototype.updateFileCounts = function ( haveUploads, fewerThanMax ) { + this.$fileList.toggleClass( 'mwe-upwiz-filled-filelist', haveUploads ); + this.$addFileContainer.toggleClass( 'mwe-upwiz-add-files-0', !haveUploads ); + + this.setAddButtonText( haveUploads ); + + if ( haveUploads ) { + // we have uploads ready to go, so allow us to proceed + this.$addFileContainer.add( this.$buttons ).show(); + + if ( this.isFlickrImportEnabled() ) { + this.$uploadCenterDivide.hide(); + } + + // fix the rounded corners on file elements. + // we want them to be rounded only when their edge touched the top or bottom of the filelist. + this.$fileListings = this.$fileList.find( '.filled' ); + + this.$visibleFileListings = this.$fileListings.find( '.mwe-upwiz-visible-file' ); + this.$visibleFileListings.removeClass( 'ui-corner-top ui-corner-bottom' ); + this.$visibleFileListings.first().addClass( 'ui-corner-top' ); + this.$visibleFileListings.last().addClass( 'ui-corner-bottom' ); + + this.$fileListings.filter( ':odd' ).addClass( 'odd' ); + this.$fileListings.filter( ':even' ).removeClass( 'odd' ); + } else { + this.hideEndButtons(); + + if ( this.isFlickrImportEnabled() ) { + this.$uploadCenterDivide.show(); + } + } + + this.addFile.setDisabled( !fewerThanMax ); + + if ( this.isFlickrImportEnabled() ) { + this.addFlickrFile.setDisabled( !fewerThanMax ); + } + + this.addFile.$element.find( '.mwe-upwiz-file-input' ).prop( 'disabled', !fewerThanMax ); + }; + + /** + * Changes the initial centered invitation button to something like "add another file" + * + * @param {boolean} more + */ + uw.ui.Upload.prototype.setAddButtonText = function ( more ) { + var msg = 'mwe-upwiz-add-file-', + fmsg = 'mwe-upwiz-add-file-flickr'; + + if ( more ) { + msg += 'n'; + fmsg += '-n'; + } else { + msg += '0-free'; + } + + this.addFile.setLabel( mw.message( msg ).text() ); + + // if Flickr uploading is available to this user, show the "add more files from flickr" button + if ( this.isFlickrImportEnabled() ) { + // changes the flickr add button to "add more files from flickr" if necessary. + this.addFlickrFile.setLabel( mw.message( fmsg ).text() ); + // jQuery likes to restore the wrong 'display' value when doing .show() + this.$flickrAddFileContainer.css( 'display', '' ); + } + }; + + uw.ui.Upload.prototype.load = function ( uploads ) { + uw.ui.Step.prototype.load.call( this, uploads ); + + if ( uploads.length === 0 ) { + this.$fileList.removeClass( 'mwe-upwiz-filled-filelist' ); + } + + this.$div.prepend( + $( '<div>' ) + .attr( 'id', 'mwe-upwiz-files' ) + .append( + this.$flickrSelectListContainer, + this.$fileList, + this.$uploadCtrl + ) + ); + + // append <input type="file"> to button + this.setupFileInputCtrl( this.addFile.$element.find( '.oo-ui-buttonElement-button' ) ); + + // Show the upload button, and the add file button + $( '#mwe-upwiz-upload-ctrls' ).show(); + $( '#mwe-upwiz-add-file' ).show(); + }; + + uw.ui.Upload.prototype.displayUploads = function ( uploads ) { + var + thumbPromise, + uploadInterfaceDivs = []; + + $.each( uploads, function ( i, upload ) { + // We'll attach all interfaces to the DOM at once rather than one-by-one, for better + // performance + uploadInterfaceDivs.push( upload.ui.div ); + } ); + + // Attach all interfaces to the DOM + this.$fileList.append( $( uploadInterfaceDivs ) ); + + // Display thumbnails, but not all at once because they're somewhat expensive to generate. + // This will wait for each thumbnail to be complete before starting the next one. + thumbPromise = $.Deferred().resolve(); + $.each( uploads, function ( i, upload ) { + thumbPromise = thumbPromise.then( function () { + var deferred = $.Deferred(); + setTimeout( function () { + if ( this.movedFrom ) { + // We're no longer displaying any of these thumbnails, stop + deferred.reject(); + } + upload.ui.showThumbnail().done( function () { + deferred.resolve(); + } ); + } ); + return deferred.promise(); + } ); + } ); + }; + + uw.ui.Upload.prototype.addNextButton = function () { + var ui = this; + + this.nextButtonPromise.done( function () { + ui.$buttons.append( + $( '<div>' ) + .addClass( 'mwe-upwiz-file-next-all-ok mwe-upwiz-file-endchoice' ) + .append( + new OO.ui.HorizontalLayout( { + items: [ + new OO.ui.LabelWidget( { + label: mw.message( 'mwe-upwiz-file-all-ok' ).text() + } ), + ui.nextStepButtonAllOk + ] + } ).$element + ) + ); + + ui.$buttons.append( + $( '<div>' ) + .addClass( 'mwe-upwiz-file-next-some-failed mwe-upwiz-file-endchoice' ) + .append( + new OO.ui.HorizontalLayout( { + items: [ + new OO.ui.LabelWidget( { + label: mw.message( 'mwe-upwiz-file-some-failed' ).text() + } ), + ui.retryButtonSomeFailed, + ui.nextStepButtonSomeFailed + ] + } ).$element + ) + ); + + ui.$buttons.append( + $( '<div>' ) + .addClass( 'mwe-upwiz-file-next-all-failed mwe-upwiz-file-endchoice' ) + .append( + new OO.ui.HorizontalLayout( { + items: [ + new OO.ui.LabelWidget( { + label: mw.message( 'mwe-upwiz-file-all-failed' ).text() + } ), + ui.retryButtonAllFailed + ] + } ).$element + ) + ); + + ui.$buttons.append( ui.$progress ); + } ); + }; + + /** + * Hide the buttons for moving to the next step. + */ + uw.ui.Upload.prototype.hideEndButtons = function () { + this.$div + .find( '.mwe-upwiz-buttons .mwe-upwiz-file-endchoice' ) + .hide(); + }; + + /** + * Shows an error dialog informing the user that some uploads have been omitted + * since they went over the max files limit. + * + * @param {number} filesUploaded The number of files that have been attempted to upload + */ + uw.ui.Upload.prototype.showTooManyFilesError = function ( filesUploaded ) { + mw.errorDialog( + mw.message( + 'mwe-upwiz-too-many-files-text', + this.config.maxUploads, + filesUploaded + ).text(), + mw.message( 'mwe-upwiz-too-many-files' ).text() + ); + }; + + /** + * Shows an error dialog informing the user that an upload omitted because + * it is too large. + * + * @param {number} maxSize The max upload file size + * @param {number} size The actual upload file size + */ + uw.ui.Upload.prototype.showFileTooLargeError = function ( maxSize, size ) { + mw.errorDialog( + mw.message( + 'mwe-upwiz-file-too-large-text', + uw.units.bytes( maxSize ), + uw.units.bytes( size ) + ).text(), + mw.message( 'mwe-upwiz-file-too-large' ).text() + ); + }; + + /** + * @param {string} filename + * @param {string} extension + */ + uw.ui.Upload.prototype.showBadExtensionError = function ( filename, extension ) { + var $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-extension', extension ); + this.showFilenameError( $errorMessage ); + }; + + uw.ui.Upload.prototype.showMissingExtensionError = function () { + var $errorMessage = $( '<p>' ).msg( 'mwe-upwiz-upload-error-bad-filename-no-extension' ); + this.showFilenameError( + $( '<div>' ).append( + $errorMessage, + $( '<p>' ).msg( 'mwe-upwiz-allowed-filename-extensions' ), + $( '<blockquote>' ).append( $( '<tt>' ).append( + mw.UploadWizard.config.fileExtensions.join( ' ' ) + ) ) + ) + ); + }; + + /** + * @param {string} filename + * @param {string} basename + */ + uw.ui.Upload.prototype.showDuplicateError = function ( filename, basename ) { + this.showFilenameError( $( '<p>' ).msg( 'mwe-upwiz-upload-error-duplicate-filename-error', basename ) ); + }; + + /** + * @param {string} filename + */ + uw.ui.Upload.prototype.showUnparseableFilenameError = function ( filename ) { + this.showFilenameError( mw.message( 'mwe-upwiz-unparseable-filename', filename ).escaped() ); + }; + + /** + * Shows an error dialog informing the user that an upload has been omitted + * over its filename. + * + * @param {jQuery} $text The error message + */ + uw.ui.Upload.prototype.showFilenameError = function ( $text ) { + var msgText; + + if ( $text instanceof jQuery ) { + msgText = $text.text(); + } else { + msgText = $text; + } + + uw.eventFlowLogger.logError( 'file', { code: 'filename', message: msgText } ); + mw.errorDialog( $text ); + }; + + /** + * Checks whether flickr import is enabled and the current user has the rights to use it + * + * @return {boolean} + */ + uw.ui.Upload.prototype.isFlickrImportEnabled = function () { + return this.config.UploadFromUrl && this.config.flickrApiKey !== ''; + }; + + /** + * Initiates the Interface to upload media from Flickr. + * Called when the user clicks on the 'Add images from Flickr' button. + */ + uw.ui.Upload.prototype.flickrInterfaceInit = function () { + // Hide containers for selecting files, and show the flickr interface instead + this.$addFileContainer.hide(); + this.$flickrAddFileContainer.hide(); + this.$flickrContainer.show(); + this.flickrSelectButton.$element.show(); + this.flickrButton.setDisabled( false ); + + // Insert form into the page + this.$div.find( '#mwe-upwiz-files' ).prepend( this.$flickrContainer ); + + this.$flickrInput.focus(); + }; + + /** + * Responsible for fetching license of the provided media. + * + * @param {mw.FlickrChecker} checker + */ + uw.ui.Upload.prototype.flickrChecker = function ( checker ) { + var flickrInputUrl = this.$flickrInput.val(); + + checker.getLicenses().done( function () { + checker.checkFlickr( flickrInputUrl ); + } ); + }; + + /** + * Reset the interface if there is a problem while fetching the images from + * the URL entered by the user. + */ + uw.ui.Upload.prototype.flickrInterfaceReset = function () { + // first destroy it completely, then reshow the add button + this.flickrInterfaceDestroy(); + this.flickrButton.setDisabled( false ); + this.$flickrContainer.show(); + this.flickrSelectButton.$element.show(); + }; + + /** + * Removes the flickr interface. + */ + uw.ui.Upload.prototype.flickrInterfaceDestroy = function () { + this.$flickrInput.val( '' ); + this.$flickrSelectList.empty(); + this.$flickrSelectListContainer.off(); + this.$flickrSelectListContainer.hide(); + this.$flickrContainer.hide(); + this.flickrButton.setDisabled( true ); + this.flickrSelectButton.$element.hide(); + }; + +}( mediaWiki, jQuery, mediaWiki.uploadWizard, OO ) ); |