uppy
Version:
Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:
193 lines (167 loc) • 5.89 kB
JavaScript
const Plugin = require('../../core/Plugin')
const Translator = require('../../core/Translator')
const StatusBarUI = require('./StatusBar')
const { getSpeed } = require('../../core/Utils')
const { getBytesRemaining } = require('../../core/Utils')
const { prettyETA } = require('../../core/Utils')
const prettyBytes = require('prettier-bytes')
/**
* A status bar.
*/
module.exports = class StatusBar extends Plugin {
constructor (uppy, opts) {
super(uppy, opts)
this.id = this.opts.id || 'StatusBar'
this.title = 'StatusBar'
this.type = 'progressindicator'
const defaultLocale = {
strings: {
uploading: 'Uploading...',
uploadComplete: 'Upload complete',
uploadFailed: 'Upload failed',
pleasePressRetry: 'Please press Retry to upload again',
paused: 'Paused',
error: 'Error',
retry: 'Retry',
pressToRetry: 'Press to retry',
retryUpload: 'Retry upload',
resumeUpload: 'Resume upload',
cancelUpload: 'Cancel upload',
pauseUpload: 'Pause upload',
uploadXFiles: {
0: 'Upload %{smart_count} file',
1: 'Upload %{smart_count} files'
},
uploadXNewFiles: {
0: 'Upload +%{smart_count} file',
1: 'Upload +%{smart_count} files'
}
}
}
// set default options
const defaultOptions = {
target: 'body',
hideUploadButton: false,
showProgressDetails: false,
locale: defaultLocale,
hideAfterFinish: true
}
// merge default options with the ones set by user
this.opts = Object.assign({}, defaultOptions, opts)
this.locale = Object.assign({}, defaultLocale, this.opts.locale)
this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)
this.translator = new Translator({locale: this.locale})
this.i18n = this.translator.translate.bind(this.translator)
this.startUpload = this.startUpload.bind(this)
this.render = this.render.bind(this)
this.install = this.install.bind(this)
}
getTotalSpeed (files) {
let totalSpeed = 0
files.forEach((file) => {
totalSpeed = totalSpeed + getSpeed(file.progress)
})
return totalSpeed
}
getTotalETA (files) {
const totalSpeed = this.getTotalSpeed(files)
if (totalSpeed === 0) {
return 0
}
const totalBytesRemaining = files.reduce((total, file) => {
return total + getBytesRemaining(file.progress)
}, 0)
return Math.round(totalBytesRemaining / totalSpeed * 10) / 10
}
startUpload () {
return this.uppy.upload().catch(() => {
// Ignore
})
}
render (state) {
const files = state.files
const uploadStartedFiles = Object.keys(files).filter((file) => {
return files[file].progress.uploadStarted
})
const newFiles = Object.keys(files).filter((file) => {
return !files[file].progress.uploadStarted &&
!files[file].progress.preprocess &&
!files[file].progress.postprocess
})
const completeFiles = Object.keys(files).filter((file) => {
return files[file].progress.uploadComplete
})
const erroredFiles = Object.keys(files).filter((file) => {
return files[file].error
})
const inProgressFiles = Object.keys(files).filter((file) => {
return !files[file].progress.uploadComplete &&
files[file].progress.uploadStarted &&
!files[file].isPaused
})
const processingFiles = Object.keys(files).filter((file) => {
return files[file].progress.preprocess || files[file].progress.postprocess
})
let inProgressFilesArray = []
inProgressFiles.forEach((file) => {
inProgressFilesArray.push(files[file])
})
const totalSpeed = prettyBytes(this.getTotalSpeed(inProgressFilesArray))
const totalETA = prettyETA(this.getTotalETA(inProgressFilesArray))
// total size and uploaded size
let totalSize = 0
let totalUploadedSize = 0
inProgressFilesArray.forEach((file) => {
totalSize = totalSize + (file.progress.bytesTotal || 0)
totalUploadedSize = totalUploadedSize + (file.progress.bytesUploaded || 0)
})
totalSize = prettyBytes(totalSize)
totalUploadedSize = prettyBytes(totalUploadedSize)
const isUploadStarted = uploadStartedFiles.length > 0
const isAllComplete = state.totalProgress === 100 &&
completeFiles.length === Object.keys(files).length &&
processingFiles.length === 0
const isAllErrored = isUploadStarted &&
erroredFiles.length === uploadStartedFiles.length
const isAllPaused = inProgressFiles.length === 0 &&
!isAllComplete &&
!isAllErrored &&
uploadStartedFiles.length > 0
const resumableUploads = this.uppy.getState().capabilities.resumableUploads || false
return StatusBarUI({
error: state.error,
totalProgress: state.totalProgress,
totalSize: totalSize,
totalUploadedSize: totalUploadedSize,
uploadStartedFiles: uploadStartedFiles,
isAllComplete: isAllComplete,
isAllPaused: isAllPaused,
isAllErrored: isAllErrored,
isUploadStarted: isUploadStarted,
i18n: this.i18n,
pauseAll: this.uppy.pauseAll,
resumeAll: this.uppy.resumeAll,
retryAll: this.uppy.retryAll,
cancelAll: this.uppy.cancelAll,
startUpload: this.startUpload,
complete: completeFiles.length,
newFiles: newFiles.length,
inProgress: uploadStartedFiles.length,
totalSpeed: totalSpeed,
totalETA: totalETA,
files: state.files,
resumableUploads: resumableUploads,
hideUploadButton: this.opts.hideUploadButton,
hideAfterFinish: this.opts.hideAfterFinish
})
}
install () {
const target = this.opts.target
if (target) {
this.mount(target, this)
}
}
uninstall () {
this.unmount()
}
}