123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- const html = require('yo-yo')
- const throttle = require('lodash.throttle')
- function progressDetails (props) {
- return html`<span>${props.totalProgress || 0}%・${props.complete} / ${props.inProgress}・${props.totalUploadedSize} / ${props.totalSize}・↑ ${props.totalSpeed}/s・${props.totalETA}</span>`
- }
- const throttledProgressDetails = throttle(progressDetails, 1000, {leading: true, trailing: true})
- const STATE_ERROR = 'error'
- const STATE_WAITING = 'waiting'
- const STATE_PREPROCESSING = 'preprocessing'
- const STATE_UPLOADING = 'uploading'
- const STATE_POSTPROCESSING = 'postprocessing'
- const STATE_COMPLETE = 'complete'
- function getUploadingState (props, files) {
- if (props.error) {
- return STATE_ERROR
- }
- // If ALL files have been completed, show the completed state.
- if (props.isAllComplete) {
- return STATE_COMPLETE
- }
- let state = STATE_WAITING
- const fileIDs = Object.keys(files)
- for (let i = 0; i < fileIDs.length; i++) {
- const progress = files[fileIDs[i]].progress
- // If ANY files are being uploaded right now, show the uploading state.
- if (progress.uploadStarted && !progress.uploadComplete) {
- return STATE_UPLOADING
- }
- // If files are being preprocessed AND postprocessed at this time, we show the
- // preprocess state. If any files are being uploaded we show uploading.
- if (progress.preprocess && state !== STATE_UPLOADING) {
- state = STATE_PREPROCESSING
- }
- // If NO files are being preprocessed or uploaded right now, but some files are
- // being postprocessed, show the postprocess state.
- if (progress.postprocess && state !== STATE_UPLOADING && state !== STATE_PREPROCESSING) {
- state = STATE_POSTPROCESSING
- }
- }
- return state
- }
- module.exports = (props) => {
- props = props || {}
- const uploadState = getUploadingState(props, props.files || {})
- let progressValue = props.totalProgress
- let progressMode
- let progressBarContent
- if (uploadState === STATE_PREPROCESSING || uploadState === STATE_POSTPROCESSING) {
- // TODO set progressValue and progressMode depending on the actual pre/postprocess
- // progress state
- progressMode = 'indeterminate'
- progressValue = undefined
- progressBarContent = ProgressBarProcessing(props)
- } else if (uploadState === STATE_COMPLETE) {
- progressBarContent = ProgressBarComplete(props)
- } else if (uploadState === STATE_UPLOADING) {
- progressBarContent = ProgressBarUploading(props)
- } else if (uploadState === STATE_ERROR) {
- progressValue = undefined
- progressBarContent = ProgressBarError(props)
- }
- const width = typeof progressValue === 'number' ? progressValue : 100
- return html`
- <div class="UppyStatusBar is-${uploadState}"
- aria-hidden="${uploadState === STATE_WAITING}"
- title="">
- <progress style="display: none;" min="0" max="100" value=${progressValue}></progress>
- <div class="UppyStatusBar-progress ${progressMode ? `is-${progressMode}` : ''}"
- style="width: ${width}%"></div>
- ${progressBarContent}
- </div>
- `
- }
- const ProgressBarProcessing = (props) => {
- // Collect pre or postprocessing progress states.
- const progresses = []
- Object.keys(props.files).forEach((fileID) => {
- const { progress } = props.files[fileID]
- if (progress.preprocess) {
- progresses.push(progress.preprocess)
- }
- if (progress.postprocess) {
- progresses.push(progress.postprocess)
- }
- })
- // In the future we should probably do this differently. For now we'll take the
- // mode and message from the first file…
- const { mode, message } = progresses[0]
- const value = progresses.filter(isDeterminate).reduce((total, progress, all) => {
- return total + progress.value / all.length
- }, 0)
- function isDeterminate (progress) {
- return progress.mode === 'determinate'
- }
- return html`
- <div class="UppyStatusBar-content">
- ${mode === 'determinate' ? `${value * 100}%・` : ''}
- ${message}
- </div>
- `
- }
- const ProgressBarUploading = (props) => {
- return html`
- <div class="UppyStatusBar-content">
- ${props.isUploadStarted && !props.isAllComplete
- ? !props.isAllPaused
- ? html`<span title="Uploading">${pauseResumeButtons(props)} Uploading... ${throttledProgressDetails(props)}</span>`
- : html`<span title="Paused">${pauseResumeButtons(props)} Paused・${props.totalProgress}%</span>`
- : null
- }
- </div>
- `
- }
- const ProgressBarComplete = ({ totalProgress }) => {
- return html`
- <div class="UppyStatusBar-content">
- <span title="Complete">
- <svg class="UppyStatusBar-action UppyIcon" width="18" height="17" viewBox="0 0 23 17">
- <path d="M8.944 17L0 7.865l2.555-2.61 6.39 6.525L20.41 0 23 2.645z" />
- </svg>
- Upload complete・${totalProgress}%
- </span>
- </div>
- `
- }
- const ProgressBarError = ({ error }) => {
- return html`
- <div class="UppyStatusBar-content">
- <span>
- ${error.message}
- </span>
- </div>
- `
- }
- const pauseResumeButtons = (props) => {
- const title = props.resumableUploads
- ? props.isAllPaused
- ? 'resume upload'
- : 'pause upload'
- : 'cancel upload'
- return html`<button title="${title}" class="UppyStatusBar-action" type="button" onclick=${() => togglePauseResume(props)}>
- ${props.resumableUploads
- ? props.isAllPaused
- ? html`<svg class="UppyIcon" width="15" height="17" viewBox="0 0 11 13">
- <path d="M1.26 12.534a.67.67 0 0 1-.674.012.67.67 0 0 1-.336-.583v-11C.25.724.38.5.586.382a.658.658 0 0 1 .673.012l9.165 5.5a.66.66 0 0 1 .325.57.66.66 0 0 1-.325.573l-9.166 5.5z" />
- </svg>`
- : html`<svg class="UppyIcon" width="16" height="17" viewBox="0 0 12 13">
- <path d="M4.888.81v11.38c0 .446-.324.81-.722.81H2.722C2.324 13 2 12.636 2 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81zM9.888.81v11.38c0 .446-.324.81-.722.81H7.722C7.324 13 7 12.636 7 12.19V.81c0-.446.324-.81.722-.81h1.444c.398 0 .722.364.722.81z"/>
- </svg>`
- : html`<svg class="UppyIcon" width="16px" height="16px" viewBox="0 0 19 19">
- <path d="M17.318 17.232L9.94 9.854 9.586 9.5l-.354.354-7.378 7.378h.707l-.62-.62v.706L9.318 9.94l.354-.354-.354-.354L1.94 1.854v.707l.62-.62h-.706l7.378 7.378.354.354.354-.354 7.378-7.378h-.707l.622.62v-.706L9.854 9.232l-.354.354.354.354 7.378 7.378.708-.707-7.38-7.378v.708l7.38-7.38.353-.353-.353-.353-.622-.622-.353-.353-.354.352-7.378 7.38h.708L2.56 1.23 2.208.88l-.353.353-.622.62-.353.355.352.353 7.38 7.38v-.708l-7.38 7.38-.353.353.352.353.622.622.353.353.354-.353 7.38-7.38h-.708l7.38 7.38z"/>
- </svg>`
- }
- </button>`
- }
- const togglePauseResume = (props) => {
- if (props.isAllComplete) return
- if (!props.resumableUploads) {
- return props.cancelAll()
- }
- if (props.isAllPaused) {
- return props.resumeAll()
- }
- return props.pauseAll()
- }
|