Explorar el Código

Dashboard refactor

Artur Paikin hace 8 años
padre
commit
8c0c8b8fdf

+ 57 - 122
src/plugins/Dashboard/Dashboard.js

@@ -1,8 +1,9 @@
 import html from '../../core/html'
-import Utils from '../../core/Utils'
-import FileItem from './FileItem'
+import { isTouchDevice, toArray } from '../../core/Utils'
+import FileList from './FileList'
+import Tabs from './Tabs'
 import FileCard from './FileCard'
-import { closeIcon, localIcon, uploadIcon, dashboardBgIcon, iconPause, iconResume } from './icons'
+import { closeIcon } from './icons'
 
 export default function Dashboard (props) {
   // http://dev.edenspiekermann.com/2016/02/11/introducing-accessible-modal-dialog
@@ -11,7 +12,6 @@ export default function Dashboard (props) {
 
   const files = state.files
   const modal = state.modal
-  const showFileCard = modal.showFileCard
 
   const acquirers = modal.targets.filter((target) => {
     return target.type === 'acquirer'
@@ -21,22 +21,41 @@ export default function Dashboard (props) {
     return target.type === 'progressindicator'
   })
 
-  const isTouchDevice = Utils.isTouchDevice()
-
-  const onSelect = (ev) => {
-    const input = document.querySelector(`${props.container} .UppyDashboard-input`)
-    input.click()
+  const removeFile = (fileID) => {
+    // this seems to be working in latest Chrome, Firefox and Safari,
+    //   // but might not be 100% cross-browser, needs testing
+    //   // https://davidwalsh.name/css-animation-callback
+    //   // el.addEventListener('animationend', () => {
+    //   //   bus.emit('file-remove', file.id)
+    //   // })
+    props.bus.emit('file-remove', fileID)
   }
 
-  const next = (ev) => {
+  const startUpload = (ev) => {
     props.bus.emit('core:upload')
   }
 
-  const handleInputChange = (ev) => {
+  const pauseUpload = (fileID) => {
+    props.bus.emit('core:upload-pause', fileID)
+  }
+
+  const showFileCard = (fileID) => {
+    props.bus.emit('dashboard:file-card', fileID)
+  }
+
+  const fileCardDone = (meta, fileID) => {
+    props.bus.emit('core:update-meta', meta, fileID)
+    props.bus.emit('dashboard:file-card')
+  }
+
+  const info = (text, type, duration) => {
+    props.bus.emit('informer', text, type, duration)
+  }
+
+  const localInputChange = (ev) => {
     ev.preventDefault()
-    // log('All right, something selected through input...')
 
-    const files = Utils.toArray(ev.target.files)
+    const files = toArray(ev.target.files)
 
     files.forEach((file) => {
       // log(file)
@@ -49,49 +68,8 @@ export default function Dashboard (props) {
     })
   }
 
-  const newFiles = Object.keys(files).filter((file) => {
-    return !files[file].progress.uploadStarted
-  })
-  const uploadStartedFiles = Object.keys(files).filter((file) => {
-    return files[file].progress.uploadStarted
-  })
-  const completeFiles = Object.keys(files).filter((file) => {
-    return files[file].progress.uploadComplete
-  })
-  const inProgressFiles = Object.keys(files).filter((file) => {
-    return !files[file].progress.uploadComplete &&
-           files[file].progress.uploadStarted &&
-           !files[file].isPaused
-  })
-
-  const uploadStartedFilesCount = Object.keys(uploadStartedFiles).length
-  const completeFilesCount = Object.keys(completeFiles).length
-  const inProgressFilesCount = Object.keys(inProgressFiles).length
-  const totalFileCount = Object.keys(files).length
-  const newFileCount = Object.keys(newFiles).length
-
-  function renderPauseResume () {
-    if (uploadStartedFilesCount > 0) {
-      if (inProgressFilesCount > 0) {
-        return html`<button class="UppyDashboard-pauseResume
-                                   UppyButton--circular
-                                   UppyButton--yellow
-                                   UppyButton--sizeS"
-                            onclick=${() => props.bus.emit('core:pause-all')}>${iconPause()}</button>`
-      }
-
-      if (uploadStartedFilesCount !== completeFilesCount) {
-        return html`<button class="UppyDashboard-pauseResume
-                                   UppyButton--circular
-                                   UppyButton--green
-                                   UppyButton--sizeS"
-                            onclick=${() => props.bus.emit('core:resume-all')}>${iconResume()}</button>`
-      }
-    }
-  }
-
   return html`<div class="Uppy UppyTheme--default UppyDashboard
-                          ${isTouchDevice ? 'Uppy--isTouchDevice' : ''}
+                          ${isTouchDevice() ? 'Uppy--isTouchDevice' : ''}
                           ${!props.inline ? 'UppyDashboard--modal' : ''}"
                    aria-hidden="${props.inline ? 'false' : modal.isHidden}"
                    aria-label="Uppy Dialog Window (Press escape to close)"
@@ -101,85 +79,42 @@ export default function Dashboard (props) {
          onclick=${props.hideModal}></div>
 
     <button class="UppyDashboard-close"
+            aria-label="Close Uppy modal"
             title="Close Uppy modal"
             onclick=${props.hideModal}>${closeIcon()}</button>
 
     <div class="UppyDashboard-inner" tabindex="0">
       <div class="UppyDashboard-innerWrap">
-        <div class="UppyDashboardTabs">
-          <h3 class="UppyDashboardTabs-title">Drop files here, paste or import from</h3>
-          <nav>
-            <ul class="UppyDashboardTabs-list" role="tablist">
-              <li class="UppyDashboardTab">
-                <button class="UppyDashboardTab-btn UppyDashboard-focus"
-                        role="tab"
-                        tabindex="0"
-                        onclick=${onSelect}>
-                  ${localIcon()}
-                  <h5 class="UppyDashboardTab-name">Local Disk</h5>
-                </button>
-                <input class="UppyDashboard-input" type="file" name="files[]" multiple="true"
-                       onchange=${handleInputChange} />
-              </li>
-              ${acquirers.map((target) => {
-                return html`<li class="UppyDashboardTab">
-                  <button class="UppyDashboardTab-btn"
-                          role="tab"
-                          tabindex="0"
-                          aria-controls="${props.panelSelectorPrefix}--${target.id}"
-                          aria-selected="${target.isHidden ? 'false' : 'true'}"
-                          onclick=${() => props.showPanel(target.id)}>
-                    ${target.icon}
-                    <h5 class="UppyDashboardTab-name">${target.name}</h5>
-                  </button>
-                </li>`
-              })}
-            </ul>
-          </nav>
-        </div>
+
+        ${Tabs({
+          localInputChange: localInputChange,
+          acquirers: acquirers,
+          container: props.container,
+          panelSelectorPrefix: props.panelSelectorPrefix,
+          showPanel: props.showPanel
+        })}
 
         ${FileCard({
           files: files,
-          showFileCard: showFileCard,
+          fileCardFor: modal.fileCardFor,
+          done: fileCardDone,
           metaFields: state.metaFields,
-          bus: props.bus,
+          pauseUpload: pauseUpload,
           log: props.log
         })}
 
-        <div class="UppyDashboard-files">
-          <ul class="UppyDashboard-filesInner">
-            ${totalFileCount === 0
-              ? html`<div class="UppyDashboard-bgIcon">${dashboardBgIcon()}</div>`
-              : null
-            }
-            ${Object.keys(files).map((fileID) => {
-              return FileItem({
-                file: files[fileID],
-                showProgressDetails: props.showProgressDetails,
-                bus: props.bus,
-                log: props.log,
-                i18n: props.i18n
-              })
-            })}
-          </ul>
-          <div class="UppyDashboard-actions">
-            ${renderPauseResume()}
-            ${!props.autoProceed && newFileCount > 0
-              ? html`<button class="UppyButton--circular UppyButton--blue UppyButton--sizeM UppyDashboard-upload"
-                             type="button"
-                             title="Upload all files"
-                             aria-label="Upload all files"
-                             onclick=${next}>
-                        ${uploadIcon()}
-                        <sup class="UppyDashboard-uploadCount"
-                             title="Number of selected files"
-                             aria-label="Number of selected files">
-                              ${newFileCount}</sup>
-                     </button>`
-              : null
-            }
-          </div>
-        </div>
+        ${FileList({
+          files: files,
+          showFileCard: showFileCard,
+          showProgressDetails: props.showProgressDetails,
+          info: info,
+          i18n: props.i18n,
+          log: props.log,
+          removeFile: removeFile,
+          pauseAll: props.pauseAll,
+          resumeAll: props.resumeAll,
+          startUpload: startUpload
+        })}
 
         ${acquirers.map((target) => {
           return html`<div class="UppyDashboardContent-panel"

+ 11 - 13
src/plugins/Dashboard/FileCard.js

@@ -13,11 +13,9 @@ function getIconByMime (fileTypeGeneral) {
 }
 
 export default function fileCard (props) {
-  const { bus, files } = props
-  const showFileCard = props.showFileCard
-  let metaFields = props.metaFields
+  // const { bus } = props
 
-  const file = showFileCard ? files[showFileCard] : false
+  const file = props.fileCardFor ? props.files[props.fileCardFor] : false
   const meta = {}
 
   function tempStoreMeta (ev) {
@@ -26,13 +24,13 @@ export default function fileCard (props) {
     meta[name] = value
   }
 
-  function done () {
-    bus.emit('core:update-meta', meta, file.id)
-    bus.emit('dashboard:file-card')
-  }
+  // function done () {
+  //   bus.emit('core:update-meta', meta, file.id)
+  //   bus.emit('dashboard:file-card')
+  // }
 
   function renderMetaFields (file) {
-    metaFields = metaFields || []
+    const metaFields = props.metaFields || []
     return metaFields.map((field) => {
       return html`<fieldset class="UppyDashboardFileCard-fieldset">
         <label class="UppyDashboardFileCard-label">${field.name}</label>
@@ -45,13 +43,13 @@ export default function fileCard (props) {
     })
   }
 
-  return html`<div class="UppyDashboardFileCard" aria-hidden="${showFileCard ? 'false' : 'true'}">
+  return html`<div class="UppyDashboardFileCard" aria-hidden="${props.fileCardFor ? 'false' : 'true'}">
     <div class="UppyDashboardContent-bar">
       <h2 class="UppyDashboardContent-title">Editing <span class="UppyDashboardContent-titleFile">${file.meta ? file.meta.name : file.name}</span></h2>
       <button class="UppyDashboardContent-back" title="Finish editing file"
-              onclick=${done}>Done</button>
+              onclick=${() => props.done(meta, file.id)}>Done</button>
     </div>
-    ${showFileCard
+    ${props.fileCardFor
       ? html`<div class="UppyDashboardFileCard-inner">
           <div class="UppyDashboardFileCard-preview">
             ${file.preview
@@ -71,6 +69,6 @@ export default function fileCard (props) {
       : null
     }
     <button class="UppyButton--circular UppyButton--blue UppyButton--sizeM UppyDashboardFileCard-done" type="button"
-            title="Finish editing file" onclick=${done}>${checkIcon()}</button>
+            title="Finish editing file" onclick=${() => props.done(meta, file.id)}>${checkIcon()}</button>
     </div>`
 }

+ 12 - 24
src/plugins/Dashboard/FileItem.js

@@ -45,7 +45,7 @@ function getSpeed (fileProgress) {
 }
 
 export default function fileItem (props) {
-  const { bus, file, showProgressDetails } = props
+  const file = props.file
 
   const isUploaded = file.progress.uploadComplete
   const uploadInProgressOrComplete = file.progress.uploadStarted
@@ -55,19 +55,6 @@ export default function fileItem (props) {
   const fileName = getFileNameAndExtension(file.meta.name)[0]
   const truncatedFileName = truncateString(fileName, 15)
 
-  const remove = (ev) => {
-    // const el = document.querySelector(`#uppy_${file.id}`)
-    // el.classList.add('UppyAnimation-zoomOutLeft')
-
-    // this seems to be working in latest Chrome, Firefox and Safari,
-    // but might not be 100% cross-browser, needs testing
-    // https://davidwalsh.name/css-animation-callback
-    // el.addEventListener('animationend', () => {
-    //   bus.emit('file-remove', file.id)
-    // })
-    bus.emit('file-remove', file.id)
-  }
-
   return html`<li class="UppyDashboardItem
                         ${uploadInProgress ? 'is-inprogress' : ''}
                         ${isUploaded ? 'is-complete' : ''}
@@ -84,13 +71,16 @@ export default function fileItem (props) {
                   title="${isUploaded
                           ? 'upload complete'
                           : file.isPaused ? 'resume upload' : 'pause upload'}"
-                  onclick=${(e) => {
+                  onclick=${(ev) => {
                     if (isUploaded) return
-                    bus.emit('core:upload-pause', file.id)
+                    props.pauseUpload(file.id)
                   }}>
-            ${FileItemProgress({progress: file.progress.percentage, fileID: file.id}, bus)}
+            ${FileItemProgress({
+              progress: file.progress.percentage,
+              fileID: file.id
+            })}
           </button>
-          ${showProgressDetails
+          ${props.showProgressDetails
             ? html`<div class="UppyDashboardItem-progressInfo"
                    title="File progress: upload speed and ETA"
                    aria-label="File progress: upload speed and ETA">
@@ -119,7 +109,7 @@ export default function fileItem (props) {
         ? html`<button class="UppyDashboardItem-edit"
                        aria-label="Edit file"
                        title="Edit file"
-                       onclick=${(e) => bus.emit('dashboard:file-card', file.id)}>
+                       onclick=${(e) => props.showFileCard(file.id)}>
                         ${iconEdit()}</button>`
         : null
       }
@@ -131,11 +121,9 @@ export default function fileItem (props) {
                          copyToClipboard(file.uploadURL, props.i18n('copyLinkToClipboardFallback'))
                           .then(() => {
                             props.log('Link copied to clipboard.')
-                            bus.emit('informer', props.i18n('copyLinkToClipboardSuccess'), 'info', 3000)
-                          })
-                          .catch((err) => {
-                            props.log(err)
+                            props.info(props.i18n('copyLinkToClipboardSuccess'), 'info', 3000)
                           })
+                          .catch(props.log)
                        }}>${iconCopy()}</button>`
         : null
       }
@@ -145,7 +133,7 @@ export default function fileItem (props) {
         ? html`<button class="UppyDashboardItem-remove"
                        aria-label="Remove file"
                        title="Remove file"
-                       onclick=${remove}>
+                       onclick=${() => props.removeFile(file.id)}>
                   ${removeIcon()}
                </button>`
         : null

+ 2 - 4
src/plugins/Dashboard/FileItemProgress.js

@@ -3,14 +3,12 @@ import html from '../../core/html'
 // http://codepen.io/Harkko/pen/rVxvNM
 // https://gist.github.com/eswak/ad4ea57bcd5ff7aa5d42
 
-export default function (props, bus) {
-  const progress = props.progress
-
+export default function (props) {
   return html`
       <svg class="UppyIcon UppyIcon-progressCircle" width="25" height="25" viewBox="0 0 44 44">
         <g class="progress-group">
           <circle class="bg" r="15" cx="22" cy="22" stroke-width="4" fill="none" />
-          <circle class="progress" r="15" cx="22" cy="22" transform="rotate(-90, 22, 22)" stroke-width="4" fill="none" stroke-dasharray="100" stroke-dashoffset="${100 - progress}" />
+          <circle class="progress" r="15" cx="22" cy="22" transform="rotate(-90, 22, 22)" stroke-width="4" fill="none" stroke-dasharray="100" stroke-dashoffset="${100 - props.progress}" />
         </g>
         <polygon class="play" transform="translate(6, 5.5)" points="13 21.6666667 13 11 21 16.3333333" />
         <g transform="translate(18, 17)" class="pause">

+ 88 - 0
src/plugins/Dashboard/FileList.js

@@ -0,0 +1,88 @@
+import html from '../../core/html'
+import FileItem from './FileItem'
+import { dashboardBgIcon,
+         uploadIcon,
+         iconPause,
+         iconResume } from './icons'
+
+export default (props) => {
+  const files = props.files
+
+  const newFiles = Object.keys(files).filter((file) => {
+    return !files[file].progress.uploadStarted
+  })
+  const uploadStartedFiles = Object.keys(files).filter((file) => {
+    return files[file].progress.uploadStarted
+  })
+  const completeFiles = Object.keys(files).filter((file) => {
+    return files[file].progress.uploadComplete
+  })
+  const inProgressFiles = Object.keys(files).filter((file) => {
+    return !files[file].progress.uploadComplete &&
+           files[file].progress.uploadStarted &&
+           !files[file].isPaused
+  })
+
+  const uploadStartedFilesCount = uploadStartedFiles.length
+  const completeFilesCount = completeFiles.length
+  const inProgressFilesCount = inProgressFiles.length
+  const totalFileCount = Object.keys(files).length
+  const newFileCount = newFiles.length
+
+  const renderPauseResume = () => {
+    if (uploadStartedFilesCount > 0) {
+      if (inProgressFilesCount > 0) {
+        return html`<button class="UppyDashboard-pauseResume
+                                   UppyButton--circular
+                                   UppyButton--yellow
+                                   UppyButton--sizeS"
+                            onclick=${() => props.pauseAll()}>${iconPause()}</button>`
+      }
+
+      if (uploadStartedFilesCount !== completeFilesCount) {
+        return html`<button class="UppyDashboard-pauseResume
+                                   UppyButton--circular
+                                   UppyButton--green
+                                   UppyButton--sizeS"
+                            onclick=${() => props.resumeAll()}>${iconResume()}</button>`
+      }
+    }
+  }
+
+  return html`<div class="UppyDashboard-files">
+    <ul class="UppyDashboard-filesInner">
+      ${totalFileCount === 0
+        ? html`<div class="UppyDashboard-bgIcon">${dashboardBgIcon()}</div>`
+        : null
+      }
+      ${Object.keys(props.files).map((fileID) => {
+        return FileItem({
+          file: props.files[fileID],
+          showFileCard: props.showFileCard,
+          showProgressDetails: props.showProgressDetails,
+          info: props.info,
+          log: props.log,
+          i18n: props.i18n,
+          removeFile: props.removeFile
+        })
+      })}
+    </ul>
+    <div class="UppyDashboard-actions">
+      ${renderPauseResume()}
+      ${!props.autoProceed && newFileCount > 0
+        ? html`<button class="UppyButton--circular UppyButton--blue UppyButton--sizeM UppyDashboard-upload"
+                       type="button"
+                       title="Upload all files"
+                       aria-label="Upload all files"
+                       onclick=${props.startUpload}>
+                  ${uploadIcon()}
+                  <sup class="UppyDashboard-uploadCount"
+                       title="Number of selected files"
+                       aria-label="Number of selected files">
+                        ${newFileCount}</sup>
+               </button>`
+        : null
+      }
+    </div>
+  </div>`
+}

+ 39 - 0
src/plugins/Dashboard/Tabs.js

@@ -0,0 +1,39 @@
+import html from '../../core/html'
+import { localIcon } from './icons'
+
+export default (props) => {
+  return html`<div class="UppyDashboardTabs">
+    <h3 class="UppyDashboardTabs-title">Drop files here, paste or import from</h3>
+    <nav>
+      <ul class="UppyDashboardTabs-list" role="tablist">
+        <li class="UppyDashboardTab">
+          <button class="UppyDashboardTab-btn UppyDashboard-focus"
+                  role="tab"
+                  tabindex="0"
+                  onclick=${(ev) => {
+                    const input = document.querySelector(`${props.container} .UppyDashboard-input`)
+                    input.click()
+                  }}>
+            ${localIcon()}
+            <h5 class="UppyDashboardTab-name">Local Disk</h5>
+          </button>
+          <input class="UppyDashboard-input" type="file" name="files[]" multiple="true"
+                 onchange=${props.localInputChange} />
+        </li>
+        ${props.acquirers.map((target) => {
+          return html`<li class="UppyDashboardTab">
+            <button class="UppyDashboardTab-btn"
+                    role="tab"
+                    tabindex="0"
+                    aria-controls="${props.panelSelectorPrefix}--${target.id}"
+                    aria-selected="${target.isHidden ? 'false' : 'true'}"
+                    onclick=${() => props.showPanel(target.id)}>
+              ${target.icon}
+              <h5 class="UppyDashboardTab-name">${target.name}</h5>
+            </button>
+          </li>`
+        })}
+      </ul>
+    </nav>
+  </div>`
+}

+ 14 - 2
src/plugins/Dashboard/index.js

@@ -33,6 +33,8 @@ export default class DashboardUI extends Plugin {
     this.hideAllPanels = this.hideAllPanels.bind(this)
     this.showPanel = this.showPanel.bind(this)
     this.initEvents = this.initEvents.bind(this)
+    this.pauseAll = this.pauseAll.bind(this)
+    this.resumeAll = this.resumeAll.bind(this)
     this.render = this.render.bind(this)
     this.install = this.install.bind(this)
   }
@@ -204,7 +206,7 @@ export default class DashboardUI extends Plugin {
 
       this.core.setState({
         modal: Object.assign({}, modal, {
-          showFileCard: fileId || false
+          fileCardFor: fileId || false
         })
       })
     })
@@ -232,6 +234,14 @@ export default class DashboardUI extends Plugin {
     })
   }
 
+  pauseAll () {
+    this.core.bus.emit('core:pause-all')
+  }
+
+  resumeAll () {
+    this.core.bus.emit('core:resume-all')
+  }
+
   render (state) {
     return Dashboard({
       state: state,
@@ -247,7 +257,9 @@ export default class DashboardUI extends Plugin {
       hideAllPanels: this.hideAllPanels,
       log: this.core.log,
       bus: this.core.emitter,
-      i18n: this.core.i18n
+      i18n: this.core.i18n,
+      pauseAll: this.pauseAll,
+      resumeAll: this.resumeAll
     })
   }
 

+ 1 - 1
src/plugins/Informer.js

@@ -71,7 +71,7 @@ export default class Informer extends Plugin {
       }
     })
 
-    const bus = this.core.emitter
+    const bus = this.core.bus
 
     bus.on('informer', (msg, type, duration) => {
       this.showInformer(msg, type, duration)