/* global moment */ ( function ( mw, $, moment ) { /** * This is a progress bar for monitoring multiple objects, giving summary view * * @class mw.GroupProgressbar * @constructor * @param {string} selector * @param {mw.UploadWizardUpload[]} uploads * @param {string[]} successStates * @param {string[]} errorStates * @param {string} progressProperty * @param {string} weightProperty */ mw.GroupProgressBar = function ( selector, uploads, successStates, errorStates, progressProperty, weightProperty ) { this.$selector = $( selector ); this.$selector.html( '
' + '
' + '' + '
' + '
' + '
' ); this.progressBarWidget = new OO.ui.ProgressBarWidget( { classes: [ 'mwe-upwiz-progress-bar' ], progress: 0 } ); this.$selector.find( '.mwe-upwiz-progress-bar-etr' ) .prepend( this.progressBarWidget.$element ); this.uploads = uploads; this.successStates = successStates; this.errorStates = errorStates; this.progressProperty = progressProperty; this.weightProperty = weightProperty; this.beginTime = undefined; }; mw.GroupProgressBar.prototype = { /** * Show the progress bar */ showBar: function () { this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeIn( 200 ); }, /** * loop around the uploads, summing certain properties for a weighted total fraction */ start: function () { var bar = this, shown = false; this.setBeginTime(); function displayer() { var totalWeight = 0.0, fraction = 0.0, successStateCount = 0, errorStateCount = 0, hasData = false; $.each( bar.uploads, function ( i, upload ) { totalWeight += upload[ bar.weightProperty ]; } ); $.each( bar.uploads, function ( i, upload ) { if ( upload.state === 'aborted' ) { return; } if ( $.inArray( upload.state, bar.successStates ) !== -1 ) { successStateCount++; } if ( $.inArray( upload.state, bar.errorStates ) !== -1 ) { errorStateCount++; } if ( upload[ bar.progressProperty ] !== undefined ) { fraction += upload[ bar.progressProperty ] * ( upload[ bar.weightProperty ] / totalWeight ); if ( upload[ bar.progressProperty ] > 0 ) { hasData = true; } } } ); // sometimes, the first data we have just tells us that it's over. So only show the bar // if we have good data AND the fraction is less than 1. if ( hasData && fraction < 1.0 ) { if ( !shown ) { bar.showBar(); shown = true; } bar.showProgress( fraction ); } bar.showCount( successStateCount ); if ( successStateCount + errorStateCount < bar.uploads.length - bar.countRemoved() ) { setTimeout( displayer, 200 ); } else { bar.showProgress( 1.0 ); bar.finished = true; setTimeout( function () { bar.hideBar(); }, 500 ); } } displayer(); }, /** * Hide the progress bar with a slideup motion */ hideBar: function () { this.$selector.find( '.mwe-upwiz-progress-bar-etr' ).fadeOut( 200 ); }, /** * sets the beginning time (useful for figuring out estimated time remaining) * if time parameter omitted, will set beginning time to now * * @param {number} [time] The time this bar is presumed to have started (epoch milliseconds) */ setBeginTime: function ( time ) { this.beginTime = time || ( new Date() ).getTime(); }, /** * Show overall progress for the entire UploadWizard * The current design doesn't have individual progress bars, just one giant one. * We did some tricky calculations in startUploads to try to weight each individual file's progress against * the overall progress. * * @param {number} fraction The amount of whatever it is that's done whatever it's done */ showProgress: function ( fraction ) { var t, timeString, remainingTime = this.getRemainingTime( fraction ); this.progressBarWidget.setProgress( parseInt( fraction * 100, 10 ) ); if ( remainingTime !== null ) { if ( remainingTime === 0 ) { timeString = mw.message( 'mwe-upwiz-finished' ).text(); } else if ( remainingTime < 1000 ) { timeString = mw.message( 'mwe-upwiz-almost-finished' ).text(); } else { t = moment.duration( remainingTime ); timeString = t.humanize(); } this.$selector.find( '.mwe-upwiz-etr' ).text( timeString ); } }, /** * Calculate remaining time for all uploads to complete. * * @param {number} fraction Fraction of progress to show * @return {number} Estimated time remaining (in milliseconds) */ getRemainingTime: function ( fraction ) { var elapsedTime, rate; if ( this.beginTime ) { elapsedTime = ( new Date() ).getTime() - this.beginTime; if ( fraction > 0.0 && elapsedTime > 0 ) { // or some other minimums for good data rate = fraction / elapsedTime; return ( ( 1.0 - fraction ) / rate ); } } return null; }, /** * Show the overall count as we upload * * @param {number} completed The number of items that have done whatever has been done e.g. in "uploaded 2 of 5", this is the 2 */ showCount: function ( completed ) { var total = this.uploads.length - this.countRemoved(); this.$selector .find( '.mwe-upwiz-count' ) // Hide if there are no uploads, show otherwise .toggle( total !== 0 ) .html( mw.message( 'mwe-upwiz-upload-count', completed, total ).escaped() ); }, countRemoved: function () { var count = 0; $.each( this.uploads, function ( i, upload ) { if ( !upload || upload.state === 'aborted' ) { count += 1; } } ); return count; } }; }( mediaWiki, jQuery, moment ) );