wikimedia/mediawiki-extensions-UploadWizard

View on GitHub
resources/mw.UploadWizardUploadInterface.js

Summary

Maintainability
D
1 day
Test Coverage
( function ( uw ) {
    /**
     * Create an interface fragment corresponding to a file input, suitable for Upload Wizard.
     *
     * @class
     * @mixes OO.EventEmitter
     * @param {mw.UploadWizardUpload} upload
     */
    mw.UploadWizardUploadInterface = function MWUploadWizardUploadInterface( upload ) {
        var ui = this;

        OO.EventEmitter.call( this );

        this.upload = upload;

        // May need to collaborate with the particular upload type sometimes
        // for the interface, as well as the uploadwizard. OY.
        this.$div = $( '<div>' ).addClass( 'mwe-upwiz-file' );

        this.isFilled = false;

        this.statusMessage = new OO.ui.MessageWidget( { inline: true } );
        this.statusMessage.toggle( false );
        this.$spinner = $.createSpinner( { size: 'small', type: 'inline' } );
        this.$spinner.hide();
        this.$indicator = $( '<div>' ).addClass( 'mwe-upwiz-file-indicator' ).append(
            this.$spinner,
            this.statusMessage.$element
        );

        this.$visibleFilenameDiv = $( '<div>' ).addClass( 'mwe-upwiz-visible-file' ).append(
            this.$indicator,
            $( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename' ).append(
                $( '<div>' ).addClass( 'mwe-upwiz-file-preview' ),
                $( '<div>' ).addClass( 'mwe-upwiz-file-texts' ).append(
                    $( '<div>' ).addClass( 'mwe-upwiz-visible-file-filename-text' ),
                    $( '<div>' ).addClass( 'mwe-upwiz-file-license' ),
                    $( '<div>' ).addClass( 'mwe-upwiz-file-status-line' ).append(
                        $( '<div>' ).addClass( 'mwe-upwiz-file-status' )
                    )
                )
            )
        );

        this.removeCtrl = new OO.ui.ButtonWidget( {
            label: mw.message( 'mwe-upwiz-remove' ).text(),
            title: mw.message( 'mwe-upwiz-remove-upload' ).text(),
            flags: 'destructive',
            icon: 'trash',
            framed: false
        } ).on( 'click', () => {
            ui.emit( 'upload-removed' );
        } );

        if ( mw.UploadWizard.config.defaults && mw.UploadWizard.config.defaults.objref !== '' ) {
            this.$imagePicker = this.createImagePickerField(
                this.upload.index,
                mw.UploadWizard.config.defaults.updateList === ''
            );
            this.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )
                .append( this.$imagePicker );
        }

        this.$visibleFilenameDiv.find( '.mwe-upwiz-file-status-line' )
            .append( this.removeCtrl.$element );

        this.$form = $( '<form>' )
            .addClass( 'mwe-upwiz-form' )
            .append( this.$visibleFilenameDiv );

        this.$div.append( this.$form );

        // this.progressBar = ( no progress bar for individual uploads yet )
        // we bind to the ui div since .off() doesn't work for non-DOM objects
        // TODO Convert this to an OO.EventEmitter, and use OOjs events
        this.$div.on( 'transportProgressEvent', () => {
            ui.showTransportProgress();
        } );
    };

    OO.mixinClass( mw.UploadWizardUploadInterface, OO.EventEmitter );

    /**
     * Change the graphic indicator at the far end of the row for this file
     *
     * @param {string} [status] Either a OO.ui.MessageWidget type (error/success/...) or 'progress'.
     *  Omit to hide the indicator
     */
    mw.UploadWizardUploadInterface.prototype.showIndicator = function ( status ) {
        var progress = status === 'progress';
        this.$spinner.toggle( progress );
        this.statusMessage.toggle( status && !progress ).setType( status );
        this.$indicator.toggleClass( 'mwe-upwiz-file-indicator-visible', !!status );
    };

    /**
     * @param {string} license License text
     */
    mw.UploadWizardUploadInterface.prototype.setLicenseText = function ( license ) {
        this.$div.find( '.mwe-upwiz-file-license' ).text( license );
    };

    /**
     * Set the status line for this upload with an internationalized message string.
     *
     * @param {string} msgKey Key for the message
     * @param {Array} [args] Array of values, in case any need to be fed to the image.
     */
    mw.UploadWizardUploadInterface.prototype.setStatus = function ( msgKey, args ) {
        // get the status line for our upload
        var $status = this.$div.find( '.mwe-upwiz-file-status' );
        $status.msg( msgKey, args || [] ).show();
    };

    /**
     * Set status line directly with a string
     *
     * @param {string} html
     */
    mw.UploadWizardUploadInterface.prototype.setStatusString = function ( html ) {
        this.$div.find( '.mwe-upwiz-file-status' ).html( html ).show();
    };

    /**
     * Set additional status information
     *
     * @param {jQuery} [$status] If not given or null, additional status is cleared
     */
    mw.UploadWizardUploadInterface.prototype.setAdditionalStatus = function ( $status ) {
        if ( this.$additionalStatus ) {
            this.$additionalStatus.remove();
        }
        this.$additionalStatus = $status;
        if ( this.$additionalStatus ) {
            this.$div.find( '.mwe-upwiz-file-status' ).after( this.$additionalStatus );
        }
    };

    /**
     * Clear the status line for this upload (hide it, in case there are paddings and such which offset other things.)
     */
    mw.UploadWizardUploadInterface.prototype.clearStatus = function () {
        this.$div.find( '.mwe-upwiz-file-status' ).hide();
        this.setAdditionalStatus( null );
    };

    /**
     * Put the visual state of an individual upload into "progress"
     *
     * @param {number} fraction The fraction of progress. Float between 0 and 1
     */
    mw.UploadWizardUploadInterface.prototype.showTransportProgress = function () {
        // if fraction available, update individual progress bar / estimates, etc.
        this.showIndicator( 'progress' );
        this.setStatus( 'mwe-upwiz-uploading' );
        this.setAdditionalStatus( null );
    };

    /**
     * Show that upload is transported
     */
    mw.UploadWizardUploadInterface.prototype.showStashed = function () {
        this.showIndicator( 'success' );
        this.setStatus( 'mwe-upwiz-stashed-upload' );
        this.setAdditionalStatus( null );
    };

    /**
     * Show that transport has failed
     *
     * @param {string} code Error code from API
     * @param {string} html Error message
     * @param {jQuery} [$additionalStatus]
     */
    mw.UploadWizardUploadInterface.prototype.showError = function ( code, html, $additionalStatus ) {
        this.showIndicator( 'error' );
        this.setStatusString( html );
        this.setAdditionalStatus( $additionalStatus );
    };

    /**
     * Run this when the value of the file input has changed and we know it's acceptable -- this
     * will update interface to show as much info as possible, including preview.
     * n.b. in older browsers we only will know the filename
     *
     * @param {Object} imageinfo
     * @param {File} file
     */
    mw.UploadWizardUploadInterface.prototype.fileChangedOk = function ( imageinfo, file ) {
        var statusItems = [];

        this.updateFilename();

        // set the status string - e.g. "256 Kb, 100 x 200"
        if ( imageinfo && imageinfo.width && imageinfo.height ) {
            statusItems.push( imageinfo.width + '\u00d7' + imageinfo.height );
        }

        if ( file && file.size ) {
            statusItems.push( uw.units.bytes( file.size ) );
        }

        this.clearStatus();
        this.setStatusString( statusItems.join( ' \u00b7 ' ) );
    };

    /**
     * Display thumbnail preview.
     *
     * @return {jQuery.Promise} Promise resolved when the thumbnail is displayed or when displaying it
     *     fails
     */
    mw.UploadWizardUploadInterface.prototype.showThumbnail = function () {
        var $preview = this.$div.find( '.mwe-upwiz-file-preview' ),
            deferred = $.Deferred();
        // This must match the CSS dimensions of .mwe-upwiz-file-preview
        this.upload.getThumbnail( 120, 120 ).done( ( thumb ) => {
            mw.UploadWizard.placeThumbnail( $preview, thumb );
            deferred.resolve();
        } );
        return deferred.promise();
    };

    /**
     * this does two things:
     *   1 ) since the file input has been hidden with some clever CSS ( to avoid x-browser styling issues ),
     *       update the visible filename
     *
     *   2 ) update the underlying "title" which we are targeting to add to mediawiki.
     *       TODO silently fix to have unique filename? unnecessary at this point...
     */
    mw.UploadWizardUploadInterface.prototype.updateFilename = function () {
        var path = this.upload.getFilename();

        // visible filename
        this.$form.find( '.mwe-upwiz-visible-file-filename-text' )
            .text( path );

        if ( !this.isFilled ) {
            this.isFilled = true;
            this.$div.addClass( 'filled' );
        }
    };

    /**
     * Create a checkbox to process the object reference parameter
     *
     * @param {number} index Number of the file for which the field is being created
     * @param {boolean} setDisabled Disable in case there already is an image in the referring list
     * @return {jQuery} A `div` containing a checkbox, label, and optional notice
     */
    mw.UploadWizardUploadInterface.prototype.createImagePickerField = function ( index, setDisabled ) {
        var $fieldContainer = $( '<div>' ).addClass( 'mwe-upwiz-objref-pick-image' ),
            attributes = {
                type: 'checkbox',
                class: 'imgPicker',
                id: 'imgPicker' + index,
                disabled: false,
                checked: false
            };

        if ( setDisabled ) {
            attributes.disabled = 'disabled';
        } else if ( index === 0 ) {
            attributes.checked = 'checked';
        }

        $fieldContainer.append(
            $( '<input>' ).attr( attributes ).on( 'click', function () {
                $( this )
                    .prop( 'checked', true )
                    .closest( '.mwe-upwiz-file' )
                    .siblings()
                    .find( '.imgPicker' )
                    .prop( 'checked', false );
            } ),

            $( '<label>' ).attr( {
                for: 'imgPicker' + index
            } ).text( this.getPickImageLabel() )
        );

        if ( setDisabled ) {
            $fieldContainer.append(
                $( '<div>' )
                    .addClass( 'mwe-upwiz-objref-notice-existing-image' )
                    .text( this.getExistingImageNotice() )
            );
        }

        return $fieldContainer;
    };

    mw.UploadWizardUploadInterface.prototype.getExistingImageNotice = function () {
        if ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.noticeExistingImage ) {
            return mw.UploadWizard.config.display.noticeExistingImage;
        } else {
            return mw.message( 'mwe-upwiz-objref-notice-existing-image' ).text();
        }
    };

    mw.UploadWizardUploadInterface.prototype.getPickImageLabel = function () {
        if ( mw.UploadWizard.config && mw.UploadWizard.config.display && mw.UploadWizard.config.display.labelPickImage ) {
            return mw.UploadWizard.config.display.labelPickImage;
        } else {
            return mw.message( 'mwe-upwiz-objref-pick-image' ).text();
        }
    };

}( mw.uploadWizard ) );