diff --git a/src/core/Core.js b/src/core/Core.js index 345a9d93d..f32dd49d9 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -95,15 +95,18 @@ export default class Core { addFile (file) { const updatedFiles = Object.assign({}, this.state.files) - const fileType = file.type.split('/') + const fileType = Utils.getFileType(file) ? Utils.getFileType(file).split('/') : ['', ''] const fileTypeGeneral = fileType[0] const fileTypeSpecific = fileType[1] + const fileExtension = Utils.getFileNameAndExtension(file.name)[1] + const fileID = Utils.generateFileID(file.name) updatedFiles[fileID] = { source: file.source || '', id: fileID, name: file.name, + extension: fileExtension, type: { general: fileTypeGeneral, specific: fileTypeSpecific @@ -119,8 +122,10 @@ export default class Core { this.setState({files: updatedFiles}) if (fileTypeGeneral === 'image') { - // this.addImgPreviewToFile(updatedFiles[fileID]) - Utils.readImage(updatedFiles[fileID].data, (imgEl) => { + Utils.readImage(updatedFiles[fileID].data, (err, imgEl) => { + if (err) { + return this.log(err) + } const newImageWidth = 200 const newImageHeight = Utils.getProportionalImageHeight(imgEl, newImageWidth) const resizedImgSrc = Utils.resizeImage(imgEl, newImageWidth, newImageHeight) @@ -188,8 +193,6 @@ export default class Core { const updatedFiles = Object.assign({}, this.state.files) updatedFiles[file.id] = file this.setState({files: updatedFiles}) - // this.log(this.state.uploadedFiles) - // this.emitter.emit('file-remove', file.id) }) } @@ -314,27 +317,6 @@ export default class Core { }) return - - // Each Plugin can have `run` and/or `install` methods. - // `install` adds event listeners and does some non-blocking work, useful for `progressindicator`, - // `run` waits for the previous step to finish (user selects files) before proceeding - // ['install', 'run'].forEach((method) => { - // // First we select only plugins of current type, - // // then create an array of runType methods of this plugins - // const typeMethods = this.types.filter((type) => this.plugins[type]) - // .map((type) => this.runType.bind(this, type, method)) - // // Run waterfall of typeMethods - // return Utils.promiseWaterfall(typeMethods) - // .then((result) => { - // // If results are empty, don't log upload results. Hasn't run yet. - // if (result[0] !== undefined) { - // this.log(result) - // this.log('Upload result -> success!') - // return result - // } - // }) - // .catch((error) => this.log('Upload result -> failed:', error)) - // }) } initSocket (opts) { diff --git a/src/core/Utils.js b/src/core/Utils.js index bbd5248df..0d2462b69 100644 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -1,3 +1,5 @@ +import mime from 'mime-types' + /** * A collection of small utility functions that help with dom manipulation, adding listeners, * promises and other good things. @@ -35,10 +37,44 @@ function isTouchDevice () { }; /** - * `querySelectorAll` that returns a normal array instead of fileList + * Shorter and fast way to select multiple nodes in the DOM + * @param { String|Array } selector - DOM selector or nodes list + * @param { Object } ctx - DOM node where the targets of our search will is located + * @returns { Object } dom nodes found */ -function qsa (selector, context) { - return Array.prototype.slice.call((context || document).querySelectorAll(selector) || []) +export function $$ (selector, ctx) { + var els + if (typeof selector === 'string') { + els = (ctx || document).querySelectorAll(selector) + } else { + els = selector + return Array.prototype.slice.call(els) + } +} + +/** + * Shorter and fast way to select a single node in the DOM + * @param { String } selector - unique dom selector + * @param { Object } ctx - DOM node where the target of our search will is located + * @returns { Object } dom node found + */ +export function $ (selector, ctx) { + return (ctx || document).querySelector(selector) +} + +// returns [fileName, fileExt] +function getFileNameAndExtension (fullFileName) { + var re = /(?:\.([^.]+))?$/ + var fileExt = re.exec(fullFileName)[1] + var fileName = fullFileName.replace('.' + fileExt, '') + return [fileName, fileExt] +} + +function truncateString (string, length) { + if (string.length > length) { + return string.substring(0, length) + '…' + } + return string } /** @@ -131,13 +167,16 @@ function readImage (imgObject, cb) { reader.addEventListener('load', function (ev) { var imgSrcBase64 = ev.target.result var img = new Image() - img.onload = function () { - return cb(img) - } + img.addEventListener('load', function () { + return cb(null, img) + }) + img.addEventListener('error', function (err) { + return cb(err) + }) img.src = imgSrcBase64 }) reader.addEventListener('error', function (err) { - console.log('FileReader error' + err) + console.log('FileReader error ' + err) }) reader.readAsDataURL(imgObject) } @@ -148,6 +187,19 @@ function getProportionalImageHeight (img, newWidth) { return newHeight } +function getFileType (file) { + // if (file.type) { + // const fileType = file.type.split('/') + // return fileType + // } + // const fileExtension = getFileNameAndExtension(file.name)[1] + // return fileExtension + if (file.type) { + return file.type + } + return mime.lookup(file.name) +} + /** * Resizes an image to specified width and height, using canvas * See https://davidwalsh.name/resize-image-canvas @@ -167,11 +219,12 @@ function resizeImage (img, width, height) { canvas.height = height // draw source image into the off-screen canvas: + // ctx.clearRect(0, 0, width, height) ctx.drawImage(img, 0, 0, width, height) // encode image to data-uri with base64 version of compressed image // canvas.toDataURL('image/jpeg', quality); // quality = [0.0, 1.0] - return canvas.toDataURL() + return canvas.toDataURL('image/jpeg', 0.7) } export default { @@ -182,10 +235,14 @@ export default { every, flatten, groupBy, - qsa, + $, + $$, extend, readImage, resizeImage, getProportionalImageHeight, - isTouchDevice + isTouchDevice, + getFileNameAndExtension, + truncateString, + getFileType } diff --git a/src/plugins/Modal/FileItem.js b/src/plugins/Modal/FileItem.js index a61b4fec4..8cd3d5484 100644 --- a/src/plugins/Modal/FileItem.js +++ b/src/plugins/Modal/FileItem.js @@ -1,31 +1,62 @@ import html from 'yo-yo' -import { fileIcon, checkIcon, removeIcon } from './icons' +import Utils from '../../core/Utils' +import { checkIcon, removeIcon, iconText, iconFile, iconAudio } from './icons' + +function getIconByMime (fileTypeGeneral) { + switch (fileTypeGeneral) { + case 'text': + return iconText() + case 'audio': + return iconAudio() + default: + return iconFile() + } +} export default function fileItem (bus, file) { const isUploaded = file.progress === 100 const uploadInProgress = file.progress > 0 && file.progress < 100 - const remove = (ev) => { - bus.emit('file-remove', file.id) + function remove (ev) { + const el = document.querySelector(`#${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) } + const truncatedFileName = Utils.truncateString(file.name, 30) + + //
${file.extension ? '.' + file.extension : '?'}
+ return html`
  • -
    - ${file.type.general === 'image' ? file.previewEl : fileIcon(file.type)} -
    -

    - ${file.uploadURL - ? html`${file.name}` - : html`${file.name}` - } -
    -

    -
    -
    ${file.totalSize}
    - ${uploadInProgress ? 'Uploading… ' + file.progress + '%' : ''} - ${isUploaded ? 'Completed' : ''} +
    + ${file.previewEl + ? file.previewEl + : html`
    ${getIconByMime(file.type.general)}
    ` + } +
    +
    ${file.progress}%
    +
    +
    +
    +
    +

    + ${file.uploadURL + ? html`${truncatedFileName}` + : truncatedFileName + } +

    +
    + ${file.totalSize} +
    ${isUploaded @@ -37,8 +68,5 @@ export default function fileItem (bus, file) { ` }
    -
    -
    -
  • ` } diff --git a/src/plugins/Modal/index.js b/src/plugins/Modal/index.js index a0d107986..3900ea42e 100644 --- a/src/plugins/Modal/index.js +++ b/src/plugins/Modal/index.js @@ -338,7 +338,7 @@ export default class Modal extends Plugin {

    Import From ${target.name}

    + onclick=${this.hideAllPanels}>Done
    ${target.render(state)} `