From b8682d89953f0b289bc69bcd1347083532dedd32 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Mon, 19 Jun 2017 23:17:17 -0400 Subject: [PATCH 01/16] Add simple reset() method to core that clears files and totalProgress --- src/core/Core.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/core/Core.js b/src/core/Core.js index ca7e71279..099935459 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -101,6 +101,13 @@ class Uppy { return this.state } + reset () { + this.setState({ + files: {}, + totalProgress: 0 + }) + } + addPreProcessor (fn) { this.preProcessors.push(fn) } From d0122f951f4cd834798a7fbf8c50bb0cf786b26c Mon Sep 17 00:00:00 2001 From: Ifedapo Olarewaju Date: Sun, 18 Jun 2017 12:18:29 +0100 Subject: [PATCH 02/16] feature: instagram plugin [WIP] --- examples/bundled-example/main.js | 2 + src/generic-provider-views/index.js | 4 +- src/index.js | 2 + src/plugins/Dropbox/index.js | 4 + src/plugins/GoogleDrive/index.js | 4 + src/plugins/Instagram/index.js | 125 ++++++++++++++++++++++++++++ 6 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 src/plugins/Instagram/index.js diff --git a/examples/bundled-example/main.js b/examples/bundled-example/main.js index a77b7ee57..7d3b8a323 100644 --- a/examples/bundled-example/main.js +++ b/examples/bundled-example/main.js @@ -2,6 +2,7 @@ const Uppy = require('../../src/core/Core.js') const Dashboard = require('../../src/plugins/Dashboard') const GoogleDrive = require('../../src/plugins/GoogleDrive') const Dropbox = require('../../src/plugins/Dropbox') +const Instagram = require('../../src/plugins/Instagram') const Webcam = require('../../src/plugins/Webcam') const Tus10 = require('../../src/plugins/Tus10') // const Multipart = require('../../src/plugins/Multipart') @@ -32,6 +33,7 @@ const uppy = Uppy({debug: true, autoProceed: false}) }) .use(GoogleDrive, {target: Dashboard, host: 'http://localhost:3020'}) .use(Dropbox, {target: Dashboard, host: 'http://localhost:3020'}) + .use(Instagram, {target: Dashboard, host: 'http://localhost:3020'}) // .use(FileInput, {target: '.Uppy', locale: { // strings: {selectToUpload: 'Выберите файл для загрузки'} // }}) diff --git a/src/generic-provider-views/index.js b/src/generic-provider-views/index.js index 11801518e..8732300c3 100644 --- a/src/generic-provider-views/index.js +++ b/src/generic-provider-views/index.js @@ -34,6 +34,8 @@ const Utils = require('../core/Utils') * @return {String} unique request path of the item when making calls to uppy server * getItemModifiedDate * @return {object} or {String} date of when last the item was modified + * getItemThumbnailUrl + * @return {String} */ module.exports = class View { /** @@ -141,7 +143,7 @@ module.exports = class View { Utils.getFileType(tagFile).then(fileType => { if (Utils.isPreviewSupported(fileType[1])) { - tagFile.preview = `${this.plugin.opts.host}/${this.Provider.id}/thumbnail/${this.plugin.getItemRequestPath(file)}` + tagFile.preview = this.plugin.getItemThumbnailUrl(file) } this.plugin.core.log('Adding remote file') this.plugin.core.emitter.emit('core:file-add', tagFile) diff --git a/src/index.js b/src/index.js index 202c62d99..8d1503bb8 100644 --- a/src/index.js +++ b/src/index.js @@ -12,6 +12,7 @@ const DragDrop = require('./plugins/DragDrop/index.js') const FileInput = require('./plugins/FileInput.js') const GoogleDrive = require('./plugins/GoogleDrive/index.js') const Dropbox = require('./plugins/Dropbox/index.js') +const Instagram = require('./plugins/Instagram/index.js') const Webcam = require('./plugins/Webcam/index.js') // Progressindicators @@ -35,6 +36,7 @@ module.exports = { DragDrop, GoogleDrive, Dropbox, + Instagram, FileInput, Tus10, Multipart, diff --git a/src/plugins/Dropbox/index.js b/src/plugins/Dropbox/index.js index ee51c354d..36157d809 100644 --- a/src/plugins/Dropbox/index.js +++ b/src/plugins/Dropbox/index.js @@ -122,6 +122,10 @@ module.exports = class Dropbox extends Plugin { return item.modified } + getItemThumbnailUrl (item) { + return `${this.opts.host}/${this.Dropbox.id}/thumbnail/${this.getItemRequestPath(item)}` + } + render (state) { return this.view.render(state) } diff --git a/src/plugins/GoogleDrive/index.js b/src/plugins/GoogleDrive/index.js index a64b6ba91..1b3d499bc 100644 --- a/src/plugins/GoogleDrive/index.js +++ b/src/plugins/GoogleDrive/index.js @@ -113,6 +113,10 @@ module.exports = class Google extends Plugin { return item.modifiedByMeDate } + getItemThumbnailUrl (item) { + return `${this.opts.host}/${this.GoogleDrive.id}/thumbnail/${this.getItemRequestPath(item)}` + } + render (state) { return this.view.render(state) } diff --git a/src/plugins/Instagram/index.js b/src/plugins/Instagram/index.js new file mode 100644 index 000000000..07e02bfaa --- /dev/null +++ b/src/plugins/Instagram/index.js @@ -0,0 +1,125 @@ +const html = require('yo-yo') +const Plugin = require('../Plugin') + +const Provider = require('../../uppy-base/src/plugins/Provider') + +const View = require('../../generic-provider-views/index') + +module.exports = class Instagram extends Plugin { + constructor (core, opts) { + super(core, opts) + this.type = 'acquirer' + this.id = 'Instagram' + this.title = 'Instagram' + this.stateId = 'instagram' + this.icon = () => html` + + + + + + ` + + // writing out the key explicitly for readability the key used to store + // the provider instance must be equal to this.id. + this.Instagram = new Provider({ + host: this.opts.host, + provider: 'instagram', + authProvider: 'instagram' + }) + + this.files = [] + + this.onAuth = this.onAuth.bind(this) + // Visual + this.render = this.render.bind(this) + + // set default options + const defaultOptions = {} + + // merge default options with the ones set by user + this.opts = Object.assign({}, defaultOptions, opts) + } + + install () { + this.view = new View(this) + // Set default state for Google Drive + this.core.setState({ + // writing out the key explicitly for readability the key used to store + // the plugin state must be equal to this.stateId. + instagram: { + authenticated: false, + files: [], + folders: [], + directories: [], + activeRow: -1, + filterInput: '' + } + }) + + const target = this.opts.target + const plugin = this + this.target = this.mount(target, plugin) + + // catch error here. + this[this.id].auth().then(this.onAuth).catch(this.view.handleError) + return + } + + uninstall () { + this.unmount() + } + + onAuth (authenticated) { + this.view.updateState({authenticated}) + if (authenticated) { + this.view.getFolder('recent') + } + } + + isFolder (item) { + return false + } + + getItemData (item) { + return item + } + + getItemIcon (item) { + return html`` + } + + getItemSubList (item) { + return item.data + } + + getItemName (item) { + return '' + } + + getMimeType (item) { + return item.type === 'video' ? 'video/mp4' : 'image/jpg' + } + + getItemId (item) { + return item.id + } + + getItemRequestPath (item) { + return this.getItemId(item) + } + + getItemModifiedDate (item) { + return item.created_time + } + + getItemThumbnailUrl (item) { + return item.images.thumbnail.url + } + + render (state) { + return this.view.render(state) + } +} From dde1b4f83a304cedcaea1044ade64c49e0402b2b Mon Sep 17 00:00:00 2001 From: Ifedapo Olarewaju Date: Thu, 22 Jun 2017 01:42:29 +0100 Subject: [PATCH 03/16] feature: endless pagination for instagram plugin --- src/generic-provider-views/Browser.js | 4 +- src/generic-provider-views/Table.js | 4 +- src/generic-provider-views/index.js | 55 ++++++++++++++------------- src/plugins/Instagram/index.js | 7 +++- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/generic-provider-views/Browser.js b/src/generic-provider-views/Browser.js index 13f883812..457b49d47 100644 --- a/src/generic-provider-views/Browser.js +++ b/src/generic-provider-views/Browser.js @@ -40,11 +40,11 @@ module.exports = (props) => { activeRow: props.isActiveRow, sortByTitle: props.sortByTitle, sortByDate: props.sortByDate, - // handleRowClick: props.handleRowClick, handleFileClick: props.addFile, handleFolderClick: props.getNextFolder, getItemName: props.getItemName, - getItemIcon: props.getItemIcon + getItemIcon: props.getItemIcon, + handleScroll: props.handleScroll })} diff --git a/src/generic-provider-views/Table.js b/src/generic-provider-views/Table.js index dc6b1aa7d..04ac8f08e 100644 --- a/src/generic-provider-views/Table.js +++ b/src/generic-provider-views/Table.js @@ -17,13 +17,12 @@ module.exports = (props) => { ${headers} - + ${props.folders.map((folder) => { return Row({ title: props.getItemName(folder), active: props.activeRow(folder), getItemIcon: () => props.getItemIcon(folder), - // handleClick: () => props.handleRowClick(folder), handleClick: () => props.handleFolderClick(folder), columns: props.columns }) @@ -33,7 +32,6 @@ module.exports = (props) => { title: props.getItemName(file), active: props.activeRow(file), getItemIcon: () => props.getItemIcon(file), - // handleClick: () => props.handleRowClick(file), handleClick: () => props.handleFileClick(file), columns: props.columns }) diff --git a/src/generic-provider-views/index.js b/src/generic-provider-views/index.js index 8732300c3..c17e54296 100644 --- a/src/generic-provider-views/index.js +++ b/src/generic-provider-views/index.js @@ -59,6 +59,7 @@ module.exports = class View { this.sortByDate = this.sortByDate.bind(this) this.isActiveRow = this.isActiveRow.bind(this) this.handleError = this.handleError.bind(this) + this.handleScroll = this.handleScroll.bind(this) // Visual this.render = this.render.bind(this) @@ -74,6 +75,18 @@ module.exports = class View { this.plugin.core.setState({[stateId]: Object.assign({}, state[stateId], newState)}) } + _updateFilesAndFolders (res, files, folders) { + this.plugin.getItemSubList(res).forEach((item) => { + if (this.plugin.isFolder(item)) { + folders.push(item) + } else { + files.push(item) + } + }) + + this.updateState({ folders, files }) + } + /** * Based on folder ID, fetch a new folder and update it to state * @param {String} id Folder id @@ -96,18 +109,8 @@ module.exports = class View { updatedDirectories = state.directories.concat([{id, title: name || this.plugin.getItemName(res)}]) } - this.plugin.getItemSubList(res).forEach((item) => { - if (this.plugin.isFolder(item)) { - folders.push(item) - } else { - files.push(item) - } - }) - - let data = {folders, files, directories: updatedDirectories} - this.updateState(data) - - return data + this._updateFilesAndFolders(res, files, folders) + this.updateState({ directories: updatedDirectories }) }, this.handleError) } @@ -169,19 +172,6 @@ module.exports = class View { }).catch(this.handleError) } - /** - * Used to set active file/folder. - * @param {Object} file Active file/folder - */ - // handleRowClick (file) { - // const state = this.plugin.core.getState()[this.plugin.stateId] - // const newState = Object.assign({}, state, { - // activeRow: this.plugin.getItemId(file) - // }) - - // this.updateState(newState) - // } - filterQuery (e) { const state = this.plugin.core.getState()[this.plugin.stateId] this.updateState(Object.assign({}, state, { @@ -299,6 +289,18 @@ module.exports = class View { this.updateState({ error }) } + handleScroll (e) { + const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight) + const path = this.plugin.getNextPagePath() + if (scrollPos < 50 && path) { + this.Provider.list(path) + .then((res) => { + const { files, folders } = this.plugin.core.getState()[this.plugin.stateId] + this._updateFilesAndFolders(res, files, folders) + }) + } + } + // displays loader view while asynchronous request is being made. _loaderWrapper (promise, then, catch_) { promise @@ -347,7 +349,8 @@ module.exports = class View { demo: this.plugin.opts.demo, isActiveRow: this.isActiveRow, getItemName: this.plugin.getItemName, - getItemIcon: this.plugin.getItemIcon + getItemIcon: this.plugin.getItemIcon, + handleScroll: this.handleScroll }) return Browser(browserProps) diff --git a/src/plugins/Instagram/index.js b/src/plugins/Instagram/index.js index 07e02bfaa..bad1b91b4 100644 --- a/src/plugins/Instagram/index.js +++ b/src/plugins/Instagram/index.js @@ -100,7 +100,7 @@ module.exports = class Instagram extends Plugin { } getMimeType (item) { - return item.type === 'video' ? 'video/mp4' : 'image/jpg' + return item.type === 'video' ? 'video/mp4' : 'image/jpeg' } getItemId (item) { @@ -119,6 +119,11 @@ module.exports = class Instagram extends Plugin { return item.images.thumbnail.url } + getNextPagePath () { + const { files } = this.core.getState()[this.stateId] + return `recent?max_id=${this.getItemId(files[files.length - 1])}` + } + render (state) { return this.view.render(state) } From 21c78c9978d100bef52ccae4b9606b7c45a2029c Mon Sep 17 00:00:00 2001 From: Ifedapo Olarewaju Date: Mon, 26 Jun 2017 22:48:39 +0100 Subject: [PATCH 04/16] refactor: finish instagram plugin --- src/generic-provider-views/index.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/generic-provider-views/index.js b/src/generic-provider-views/index.js index c17e54296..41f1ddf59 100644 --- a/src/generic-provider-views/index.js +++ b/src/generic-provider-views/index.js @@ -51,7 +51,6 @@ module.exports = class View { this.filterQuery = this.filterQuery.bind(this) this.getFolder = this.getFolder.bind(this) this.getNextFolder = this.getNextFolder.bind(this) - // this.handleRowClick = this.handleRowClick.bind(this) this.logout = this.logout.bind(this) this.handleAuth = this.handleAuth.bind(this) this.handleDemoAuth = this.handleDemoAuth.bind(this) @@ -291,27 +290,25 @@ module.exports = class View { handleScroll (e) { const scrollPos = e.target.scrollHeight - (e.target.scrollTop + e.target.offsetHeight) - const path = this.plugin.getNextPagePath() - if (scrollPos < 50 && path) { + const path = this.plugin.getNextPagePath ? this.plugin.getNextPagePath() : null + + if (scrollPos < 50 && path && !this._isHandlingScroll) { this.Provider.list(path) .then((res) => { const { files, folders } = this.plugin.core.getState()[this.plugin.stateId] this._updateFilesAndFolders(res, files, folders) - }) + }).catch(this.handleError) + .then(() => { this._isHandlingScroll = false }) // always called + + this._isHandlingScroll = true } } // displays loader view while asynchronous request is being made. _loaderWrapper (promise, then, catch_) { promise - .then((result) => { - this.updateState({ loading: false }) - then(result) - }) - .catch((err) => { - this.updateState({ loading: false }) - catch_(err) - }) + .then(then).catch(catch_) + .then(() => this.updateState({ loading: false })) // always called. this.updateState({ loading: true }) } @@ -342,7 +339,6 @@ module.exports = class View { addFile: this.addFile, filterItems: this.filterItems, filterQuery: this.filterQuery, - handleRowClick: this.handleRowClick, sortByTitle: this.sortByTitle, sortByDate: this.sortByDate, logout: this.logout, From 7c5d38b56662093f9f8831362dba789843bcbb7b Mon Sep 17 00:00:00 2001 From: Ifedapo Olarewaju Date: Tue, 27 Jun 2017 00:48:22 +0100 Subject: [PATCH 05/16] docs: update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4a9aac6f6..b3853abb6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -94,7 +94,7 @@ To be released: 2017-06-30 - [ ] statusbar: show status “Upload started...” when the remote upload has begun, but no progress events received yet (@arturi) - [ ] test: add tests for `npm install uppy` and running in different browsers, the real world use case (@arturi) - [ ] uploaders: add direct-to-s3 upload plugin and test it with the flow to then upload to transloadit (@goto-bus-stop) -- [ ] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) +- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) - [x] uppy/uppy-server: some file types cannot be downloaded/uploaded on google drive (e.g google docs). How to handle that? (@ifedapoolarewaju) - [x] uppy: fix google drive uploads on mobile (double click issue) (@arturi) - [ ] website: new demo video / gif (@arturi) From 6f80ea709cae213ee592932b60cd1e3d8dd54a71 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Wed, 28 Jun 2017 20:21:23 -0400 Subject: [PATCH 06/16] Extract metadata from form, closes #153 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR adds support for extracting metadata from `
` elements. This was asked #153 and came up elsewhere too, I believe. You can use it like this: ```html
``` ```js uppy.use(DragDrop, { target: '.MyForm', locale: { strings: {chooseFile: 'Выберите файл'} }, setMetaFromTargetForm: true }) ``` Then UI acquire type plugins, like Dashboard, FileInput and DragDrop, before mounting themselves or doing anything else, extract FormData from the `target` `
` element (it must be a form currently), and merge the object with the global `state.meta`. This is done via `setMeta` method on core. Then, when a file is added, `state.meta` is merged to that file’s meta right away. The ability to add more fields via UI plugin MetaData is also still there, though probably needs an update. In addition a new `meta` option is added in core: ```js const uppy = Uppy({ debug: true, autoProceed: true, meta: { username: 'Artur' } }) ``` This way some data can be set right away, it becomes the initial `state.meta` object. --- examples/bundled-example/index.html | 7 ++- examples/bundled-example/main.js | 68 ++++++++++++++++++----------- src/core/Core.js | 24 ++++++---- src/core/Utils.js | 22 ++++++++++ src/plugins/Dashboard/index.js | 29 +++++++----- src/plugins/DragDrop/index.js | 5 +++ src/plugins/FileInput.js | 9 +++- src/plugins/MetaData.js | 4 +- src/plugins/Plugin.js | 14 +++++- 9 files changed, 128 insertions(+), 54 deletions(-) diff --git a/examples/bundled-example/index.html b/examples/bundled-example/index.html index 50df14205..5255b3e57 100644 --- a/examples/bundled-example/index.html +++ b/examples/bundled-example/index.html @@ -7,12 +7,15 @@

Uppy is here

- +
- + + + +
diff --git a/examples/bundled-example/main.js b/examples/bundled-example/main.js index a77b7ee57..90cc56bfa 100644 --- a/examples/bundled-example/main.js +++ b/examples/bundled-example/main.js @@ -1,10 +1,12 @@ const Uppy = require('../../src/core/Core.js') -const Dashboard = require('../../src/plugins/Dashboard') -const GoogleDrive = require('../../src/plugins/GoogleDrive') -const Dropbox = require('../../src/plugins/Dropbox') -const Webcam = require('../../src/plugins/Webcam') +// const Dashboard = require('../../src/plugins/Dashboard') +// const GoogleDrive = require('../../src/plugins/GoogleDrive') +// const Dropbox = require('../../src/plugins/Dropbox') +// const Webcam = require('../../src/plugins/Webcam') const Tus10 = require('../../src/plugins/Tus10') // const Multipart = require('../../src/plugins/Multipart') +// const DragDrop = require('../../src/plugins/FileInput') +const FileInput = require('../../src/plugins/FileInput') const MetaData = require('../../src/plugins/MetaData') // const Informer = require('../../src/plugins/Informer') // const StatusBar = require('../../src/plugins/StatusBar') @@ -17,30 +19,44 @@ const TUS_ENDPOINT = PROTOCOL + '://master.tus.io/files/' // import MagicLog from '../../src/plugins/MagicLog' // import PersistentState from '../../src/plugins/PersistentState' -const uppy = Uppy({debug: true, autoProceed: false}) - .use(Dashboard, { - trigger: '#uppyModalOpener', - // maxWidth: 350, - // maxHeight: 400, - // inline: false, - // disableStatusBar: true, - // disableInformer: true, - target: 'body', +const uppy = Uppy({ + debug: true, + autoProceed: true, + meta: { + username: 'Artur' + } +}) + // .use(Dashboard, { + // trigger: '#uppyModalOpener', + // // maxWidth: 350, + // // maxHeight: 400, + // inline: false, + // // disableStatusBar: true, + // // disableInformer: true, + // setMetaFromTargetForm: true, + // target: '.MyForm', + // locale: { + // strings: { browse: 'wow' } + // } + // }) + // .use(GoogleDrive, {target: Dashboard, host: 'http://localhost:3020'}) + // .use(Dropbox, {target: Dashboard, host: 'http://localhost:3020'}) + .use(FileInput, { + target: '.MyForm', + replaceTargetContent: false, + setMetaFromTargetForm: true, locale: { - strings: {browse: 'wow'} - } - }) - .use(GoogleDrive, {target: Dashboard, host: 'http://localhost:3020'}) - .use(Dropbox, {target: Dashboard, host: 'http://localhost:3020'}) - // .use(FileInput, {target: '.Uppy', locale: { - // strings: {selectToUpload: 'Выберите файл для загрузки'} - // }}) - // .use(DragDrop, {target: 'body', locale: { - // strings: {chooseFile: 'Выберите файл'} - // }}) + strings: { selectToUpload: 'Выберите файл для загрузки' } + }}) + // .use(DragDrop, { + // target: '.MyForm', + // locale: { + // strings: {chooseFile: 'Выберите файл'} + // }, + // setMetaFromTargetForm: true + // }) // .use(ProgressBar, {target: 'body'}) - // .use(dummy) - .use(Webcam, {target: Dashboard}) + // .use(Webcam, {target: Dashboard}) // .use(Multipart, {endpoint: '//api2.transloadit.com'}) .use(Tus10, {endpoint: TUS_ENDPOINT, resume: true}) // .use(Informer, {target: Dashboard}) diff --git a/src/core/Core.js b/src/core/Core.js index f36c34dd5..739d1e2a9 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -53,7 +53,8 @@ class Uppy { capabilities: { resumableUploads: false }, - totalProgress: 0 + totalProgress: 0, + meta: Object.assign({}, this.opts.meta) } // for debugging and testing @@ -134,6 +135,11 @@ class Uppy { } } + setMeta (data) { + const newMeta = Object.assign({}, this.getState().meta, data) + this.setState({meta: newMeta}) + } + updateMeta (data, fileID) { const updatedFiles = Object.assign({}, this.getState().files) const newMeta = Object.assign({}, updatedFiles[fileID].meta, data) @@ -159,9 +165,7 @@ class Uppy { id: fileID, name: fileName, extension: fileExtension || '', - meta: { - name: fileName - }, + meta: Object.assign({}, this.getState().metaData), type: { general: fileTypeGeneral, specific: fileTypeSpecific @@ -187,7 +191,7 @@ class Uppy { updatedFiles[fileID] = newFile this.setState({files: updatedFiles}) - this.bus.emit('file-added', fileID) + this.bus.emit('core:file-added', fileID) this.log(`Added file: ${fileName}, ${fileID}, mime type: ${fileType}`) if (this.opts.autoProceed && !this.scheduledAutoProceed) { @@ -526,16 +530,18 @@ class Uppy { if (!this.opts.debug) { return } + + if (type === 'error') { + console.error(`LOG: ${msg}`) + return + } + if (msg === `${msg}`) { console.log(`LOG: ${msg}`) } else { console.dir(msg) } - if (type === 'error') { - console.error(`LOG: ${msg}`) - } - global.uppyLog = global.uppyLog + '\n' + 'DEBUG LOG: ' + msg } diff --git a/src/core/Utils.js b/src/core/Utils.js index 07dfeadf9..5c6713af3 100644 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -401,6 +401,27 @@ function findDOMElement (element) { } } +/** +* Get metadata object from a form element +* +* @param {Node|string} element +* @return {Object|null} +*/ + +function getMetaFromForm (element) { + if (!element || element.tagName !== 'FORM') { + console.error('Metadata can only be extracted from form elements') + return null + } + + var formData = new FormData(element) + var result = {} + for (var entry of formData.entries()) { + result[entry[0]] = entry[1] + } + return result +} + function getSocketHost (url) { // get the host domain var regex = /^(?:https?:\/\/|\/\/)?(?:[^@\n]+@)?(?:www\.)?([^\n]+)/ @@ -451,6 +472,7 @@ module.exports = { copyToClipboard, prettyETA, findDOMElement, + getMetaFromForm, getSocketHost, emitSocketProgress } diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 6bbcb142b..8a1432659 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -48,6 +48,7 @@ module.exports = class DashboardUI extends Plugin { semiTransparent: false, defaultTabIcon: defaultTabIcon(), showProgressDetails: false, + setMetaFromTargetForm: false, locale: defaultLocale } @@ -88,7 +89,7 @@ module.exports = class DashboardUI extends Plugin { if (callerPluginType !== 'acquirer' && callerPluginType !== 'progressindicator' && callerPluginType !== 'presenter') { - let msg = 'Error: Modal can only be used by plugins of types: acquirer, progressindicator, presenter' + let msg = 'Dashboard: Modal can only be used by plugins of types: acquirer, progressindicator, presenter' this.core.log(msg) return } @@ -162,9 +163,9 @@ module.exports = class DashboardUI extends Plugin { // focus on modal inner block this.target.querySelector('.UppyDashboard-inner').focus() - this.updateDashboardElWidth() + // this.updateDashboardElWidth() // to be sure, sometimes when the function runs, container size is still 0 - setTimeout(this.updateDashboardElWidth, 300) + setTimeout(this.updateDashboardElWidth, 500) } // Close the Modal on esc key press @@ -175,14 +176,14 @@ module.exports = class DashboardUI extends Plugin { } initEvents () { - // const dashboardEl = this.target.querySelector(`${this.opts.target} .UppyDashboard`) - // Modal open button const showModalTrigger = findDOMElement(this.opts.trigger) if (!this.opts.inline && showModalTrigger) { showModalTrigger.addEventListener('click', this.showModal) - } else { - this.core.log('Modal trigger wasn’t found') + } + + if (!this.opts.inline && !showModalTrigger) { + console.error('Dashboard modal trigger not found, you won’t be able to select files. Make sure `trigger` is set correctly in Dashboard options') } document.body.addEventListener('keyup', this.handleEscapeKeyPress) @@ -223,7 +224,7 @@ module.exports = class DashboardUI extends Plugin { updateDashboardElWidth () { const dashboardEl = this.target.querySelector('.UppyDashboard-inner') - // console.log(dashboardEl.offsetWidth) + this.core.log(`Dashboard width: ${dashboardEl.offsetWidth}`) const modal = this.core.getState().modal this.core.setState({ @@ -303,9 +304,9 @@ module.exports = class DashboardUI extends Plugin { return target.type === 'progressindicator' }) - const addFile = (file) => { - this.core.emitter.emit('core:file-add', file) - } + // const addFile = (file) => { + // this.core.emitter.emit('core:file-add', file) + // } const removeFile = (fileID) => { this.core.emitter.emit('core:file-remove', fileID) @@ -364,7 +365,7 @@ module.exports = class DashboardUI extends Plugin { i18n: this.containerWidth, pauseAll: this.pauseAll, resumeAll: this.resumeAll, - addFile: addFile, + addFile: this.core.addFile, removeFile: removeFile, info: info, metaFields: state.metaFields, @@ -392,6 +393,10 @@ module.exports = class DashboardUI extends Plugin { targets: [] }}) + if (this.opts.setMetaFromTargetForm) { + this.setMetaFromTargetForm() + } + const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/DragDrop/index.js b/src/plugins/DragDrop/index.js index 38078f038..f1c7fd40b 100644 --- a/src/plugins/DragDrop/index.js +++ b/src/plugins/DragDrop/index.js @@ -37,6 +37,7 @@ module.exports = class DragDrop extends Plugin { // Default options const defaultOpts = { target: '.UppyDragDrop', + setMetaFromTargetForm: false, locale: defaultLocale } @@ -143,6 +144,10 @@ module.exports = class DragDrop extends Plugin { } install () { + if (this.opts.setMetaFromTargetForm) { + this.setMetaFromTargetForm() + } + const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/FileInput.js b/src/plugins/FileInput.js index 7d2e4c3a0..05390fa04 100644 --- a/src/plugins/FileInput.js +++ b/src/plugins/FileInput.js @@ -7,7 +7,7 @@ module.exports = class FileInput extends Plugin { constructor (core, opts) { super(core, opts) this.id = 'FileInput' - this.title = 'FileInput' + this.title = 'File Input' this.type = 'acquirer' const defaultLocale = { @@ -23,7 +23,8 @@ module.exports = class FileInput extends Plugin { multipleFiles: true, pretty: true, locale: defaultLocale, - inputName: 'files[]' + inputName: 'files[]', + getMetaDataFromForm: false } // Merge default options with the ones set by user @@ -77,6 +78,10 @@ module.exports = class FileInput extends Plugin { } install () { + if (this.opts.setMetaFromTargetForm) { + this.setMetaFromTargetForm() + } + const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/MetaData.js b/src/plugins/MetaData.js index 41e560ff1..bb10e3fd7 100644 --- a/src/plugins/MetaData.js +++ b/src/plugins/MetaData.js @@ -38,7 +38,7 @@ module.exports = class MetaData extends Plugin { metaFields: metaFields }) - this.core.emitter.on('file-added', this.handleFileAdded) + this.core.emitter.on('core:file-added', this.handleFileAdded) } install () { @@ -46,6 +46,6 @@ module.exports = class MetaData extends Plugin { } uninstall () { - this.core.emitter.off('file-added', this.handleFileAdded) + this.core.emitter.off('core:file-added', this.handleFileAdded) } } diff --git a/src/plugins/Plugin.js b/src/plugins/Plugin.js index dcb0c1c4d..01cb35e7d 100644 --- a/src/plugins/Plugin.js +++ b/src/plugins/Plugin.js @@ -1,6 +1,6 @@ const yo = require('yo-yo') const nanoraf = require('nanoraf') -const { findDOMElement } = require('../core/Utils') +const { findDOMElement, getMetaFromForm } = require('../core/Utils') /** * Boilerplate that all Plugins share - and should not be used @@ -89,6 +89,18 @@ module.exports = class Plugin { } } + setMetaFromTargetForm () { + const el = findDOMElement(this.opts.target) + const formMetaData = getMetaFromForm(el) + if (formMetaData) { + this.core.log('Adding metadata from form:') + this.core.log(formMetaData) + this.core.setMeta(formMetaData) + } else { + this.core.log('Couldn’t extract metadata from form') + } + } + // focus () { // return // } From 0c88bf7bb32fbb17a47149371e1bad8f6a2f0021 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Thu, 29 Jun 2017 06:35:33 -0400 Subject: [PATCH 07/16] tweak reset and core:cancel-all, add reset to close --- src/core/Core.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 099935459..eb65ce4f4 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -102,8 +102,9 @@ class Uppy { } reset () { + this.emit('core:pause-all') + this.emit('core:cancel-all') this.setState({ - files: {}, totalProgress: 0 }) } @@ -297,10 +298,9 @@ class Uppy { }) this.on('core:cancel-all', () => { - const files = this.getState().files - Object.keys(files).forEach((file) => { - this.removeFile(files[file].id) - }) + let updatedFiles = this.getState().files + updatedFiles = {} + this.setState({files: updatedFiles}) }) this.on('core:upload-started', (fileID, upload) => { @@ -513,6 +513,8 @@ class Uppy { * Uninstall all plugins and close down this Uppy instance. */ close () { + this.reset() + this.iteratePlugins((plugin) => { plugin.uninstall() }) From 589b3b3d3f27ee8867678345575be762e454a0c0 Mon Sep 17 00:00:00 2001 From: Ifedapo Olarewaju Date: Thu, 29 Jun 2017 13:49:49 +0100 Subject: [PATCH 08/16] fix: set file id as fallback name --- src/generic-provider-views/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/generic-provider-views/index.js b/src/generic-provider-views/index.js index 41f1ddf59..24536f0eb 100644 --- a/src/generic-provider-views/index.js +++ b/src/generic-provider-views/index.js @@ -128,7 +128,7 @@ module.exports = class View { const tagFile = { source: this.plugin.id, data: this.plugin.getItemData(file), - name: this.plugin.getItemName(file), + name: this.plugin.getItemName(file) || this.plugin.getItemId(file), type: this.plugin.getMimeType(file), isRemote: true, body: { From 047e51b77b3c536bcb334b5515eae3c6ad2247fc Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Thu, 29 Jun 2017 19:06:04 -0400 Subject: [PATCH 09/16] add get-form-data, move things around --- examples/bundled-example/main.js | 3 +-- package-lock.json | 5 +++++ package.json | 1 + src/core/Core.js | 2 +- src/plugins/Dashboard/index.js | 4 ---- src/plugins/DragDrop/index.js | 4 ---- src/plugins/FileInput.js | 12 ++++-------- src/plugins/Plugin.js | 27 +++++++++------------------ 8 files changed, 21 insertions(+), 37 deletions(-) diff --git a/examples/bundled-example/main.js b/examples/bundled-example/main.js index 90cc56bfa..20fd3842d 100644 --- a/examples/bundled-example/main.js +++ b/examples/bundled-example/main.js @@ -43,8 +43,7 @@ const uppy = Uppy({ // .use(Dropbox, {target: Dashboard, host: 'http://localhost:3020'}) .use(FileInput, { target: '.MyForm', - replaceTargetContent: false, - setMetaFromTargetForm: true, + // replaceTargetContent: false, locale: { strings: { selectToUpload: 'Выберите файл для загрузки' } }}) diff --git a/package-lock.json b/package-lock.json index 03b27d9e1..4cf269b2e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3449,6 +3449,11 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-form-data": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/get-form-data/-/get-form-data-1.2.5.tgz", + "integrity": "sha1-yQ+bix0tvbRulIDoi6xjKT/msYI=" + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", diff --git a/package.json b/package.json index 5a0fec935..744c5743f 100644 --- a/package.json +++ b/package.json @@ -76,6 +76,7 @@ "dependencies": { "drag-drop": "2.13.2", "es6-promise": "3.2.1", + "get-form-data": "^1.2.5", "lodash.throttle": "4.1.1", "namespace-emitter": "1.0.0", "nanoraf": "3.0.1", diff --git a/src/core/Core.js b/src/core/Core.js index 739d1e2a9..6b2d33689 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -165,7 +165,7 @@ class Uppy { id: fileID, name: fileName, extension: fileExtension || '', - meta: Object.assign({}, this.getState().metaData), + meta: Object.assign({}, this.getState().meta), type: { general: fileTypeGeneral, specific: fileTypeSpecific diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 8a1432659..1781bf54c 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -393,10 +393,6 @@ module.exports = class DashboardUI extends Plugin { targets: [] }}) - if (this.opts.setMetaFromTargetForm) { - this.setMetaFromTargetForm() - } - const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/DragDrop/index.js b/src/plugins/DragDrop/index.js index f1c7fd40b..7c3bba9ae 100644 --- a/src/plugins/DragDrop/index.js +++ b/src/plugins/DragDrop/index.js @@ -144,10 +144,6 @@ module.exports = class DragDrop extends Plugin { } install () { - if (this.opts.setMetaFromTargetForm) { - this.setMetaFromTargetForm() - } - const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/FileInput.js b/src/plugins/FileInput.js index 05390fa04..6366c683b 100644 --- a/src/plugins/FileInput.js +++ b/src/plugins/FileInput.js @@ -1,5 +1,5 @@ const Plugin = require('./Plugin') -const Utils = require('../core/Utils') +const { toArray } = require('../core/Utils') const Translator = require('../core/Translator') const html = require('yo-yo') @@ -19,12 +19,12 @@ module.exports = class FileInput extends Plugin { // Default options const defaultOptions = { target: '.UppyForm', + getMetaDataFromForm: true, replaceTargetContent: true, multipleFiles: true, pretty: true, locale: defaultLocale, - inputName: 'files[]', - getMetaDataFromForm: false + inputName: 'files[]' } // Merge default options with the ones set by user @@ -43,7 +43,7 @@ module.exports = class FileInput extends Plugin { handleInputChange (ev) { this.core.log('All right, something selected through input...') - const files = Utils.toArray(ev.target.files) + const files = toArray(ev.target.files) files.forEach((file) => { this.core.emitter.emit('core:file-add', { @@ -78,10 +78,6 @@ module.exports = class FileInput extends Plugin { } install () { - if (this.opts.setMetaFromTargetForm) { - this.setMetaFromTargetForm() - } - const target = this.opts.target const plugin = this this.target = this.mount(target, plugin) diff --git a/src/plugins/Plugin.js b/src/plugins/Plugin.js index 01cb35e7d..432e7289d 100644 --- a/src/plugins/Plugin.js +++ b/src/plugins/Plugin.js @@ -1,6 +1,7 @@ const yo = require('yo-yo') const nanoraf = require('nanoraf') -const { findDOMElement, getMetaFromForm } = require('../core/Utils') +const { findDOMElement } = require('../core/Utils') +const getFormData = require('get-form-data') /** * Boilerplate that all Plugins share - and should not be used @@ -23,7 +24,6 @@ module.exports = class Plugin { this.update = this.update.bind(this) this.mount = this.mount.bind(this) - // this.focus = this.focus.bind(this) this.install = this.install.bind(this) this.uninstall = this.uninstall.bind(this) } @@ -59,6 +59,13 @@ module.exports = class Plugin { if (targetElement) { this.core.log(`Installing ${callerPluginName} to a DOM element`) + // attempt to extract meta from form element + if (this.opts.getMetaDataFromForm && targetElement.nodeName === 'FORM') { + const formMeta = getFormData(targetElement) + this.core.log('Adding metadata from form') + this.core.log(formMeta) + } + // clear everything inside the target container if (this.opts.replaceTargetContent) { targetElement.innerHTML = '' @@ -89,22 +96,6 @@ module.exports = class Plugin { } } - setMetaFromTargetForm () { - const el = findDOMElement(this.opts.target) - const formMetaData = getMetaFromForm(el) - if (formMetaData) { - this.core.log('Adding metadata from form:') - this.core.log(formMetaData) - this.core.setMeta(formMetaData) - } else { - this.core.log('Couldn’t extract metadata from form') - } - } - - // focus () { - // return - // } - install () { return } From db133fb9ebb0f5634d1bc2ee90794062300cc72d Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Thu, 29 Jun 2017 19:16:22 -0400 Subject: [PATCH 10/16] Update CHANGELOG.md --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7b60a405f..2343e817d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -83,8 +83,8 @@ maybe later: To be released: 2017-06-30 -- [ ] core: add `uppy.reset()` as discussed in #179 (@arturi) -- [ ] core: research !important styles to be immune to any environment/page. Maybe use smth like https://www.npmjs.com/package/postcss-safe-important. Or increase specificity (with .Uppy) (@arturi) +- [x] core: add `uppy.reset()` as discussed in #179 (@arturi) +- [ ] core: research !important styles to be immune to any environment/page. Maybe use smth like `postcss-safe-important`. Or increase specificity (with .Uppy) (@arturi) - [ ] core: restrictions — by file type, size, number of files (@arturi) - [ ] core: see if we can figure out css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop) - [ ] fileinput: allow retriving fields/options from form (@arturi #153) @@ -96,7 +96,7 @@ To be released: 2017-06-30 - [ ] test: add tests for `npm install uppy` and running in different browsers, the real world use case (@arturi) - [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) - [x] uploaders: add direct-to-s3 upload plugin and test it with the flow to then upload to transloadit, stage 1, WIP (@goto-bus-stop) -- [ ] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) +- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) - [x] uppy/uppy-server: some file types cannot be downloaded/uploaded on google drive (e.g google docs). How to handle that? (@ifedapoolarewaju) - [x] uppy: fix google drive uploads on mobile (double click issue) (@arturi) - [ ] website: new demo video / gif (@arturi) From cf6e75522ba189898e6d9177d2e7f18006a90e11 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 30 Jun 2017 12:05:57 -0400 Subject: [PATCH 11/16] cleanup, getMetaFromForm: true by default --- src/core/Core.js | 2 ++ src/core/Utils.js | 22 ---------------------- src/plugins/Dashboard/index.js | 5 +++-- src/plugins/DragDrop/index.js | 2 +- src/plugins/FileInput.js | 2 +- src/plugins/Plugin.js | 5 ++--- 6 files changed, 9 insertions(+), 29 deletions(-) diff --git a/src/core/Core.js b/src/core/Core.js index 6b2d33689..3b7e83e4a 100644 --- a/src/core/Core.js +++ b/src/core/Core.js @@ -137,6 +137,8 @@ class Uppy { setMeta (data) { const newMeta = Object.assign({}, this.getState().meta, data) + this.log('Adding metadata:') + this.log(data) this.setState({meta: newMeta}) } diff --git a/src/core/Utils.js b/src/core/Utils.js index 5c6713af3..07dfeadf9 100644 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -401,27 +401,6 @@ function findDOMElement (element) { } } -/** -* Get metadata object from a form element -* -* @param {Node|string} element -* @return {Object|null} -*/ - -function getMetaFromForm (element) { - if (!element || element.tagName !== 'FORM') { - console.error('Metadata can only be extracted from form elements') - return null - } - - var formData = new FormData(element) - var result = {} - for (var entry of formData.entries()) { - result[entry[0]] = entry[1] - } - return result -} - function getSocketHost (url) { // get the host domain var regex = /^(?:https?:\/\/|\/\/)?(?:[^@\n]+@)?(?:www\.)?([^\n]+)/ @@ -472,7 +451,6 @@ module.exports = { copyToClipboard, prettyETA, findDOMElement, - getMetaFromForm, getSocketHost, emitSocketProgress } diff --git a/src/plugins/Dashboard/index.js b/src/plugins/Dashboard/index.js index 1781bf54c..8829b5285 100644 --- a/src/plugins/Dashboard/index.js +++ b/src/plugins/Dashboard/index.js @@ -42,13 +42,14 @@ module.exports = class DashboardUI extends Plugin { // set default options const defaultOptions = { target: 'body', + getMetaFromForm: true, inline: false, width: 750, height: 550, semiTransparent: false, defaultTabIcon: defaultTabIcon(), showProgressDetails: false, - setMetaFromTargetForm: false, + setMetaFromTargetForm: true, locale: defaultLocale } @@ -183,7 +184,7 @@ module.exports = class DashboardUI extends Plugin { } if (!this.opts.inline && !showModalTrigger) { - console.error('Dashboard modal trigger not found, you won’t be able to select files. Make sure `trigger` is set correctly in Dashboard options') + this.core.log('Dashboard modal trigger not found, you won’t be able to select files. Make sure `trigger` is set correctly in Dashboard options', 'error') } document.body.addEventListener('keyup', this.handleEscapeKeyPress) diff --git a/src/plugins/DragDrop/index.js b/src/plugins/DragDrop/index.js index 7c3bba9ae..d4a605d52 100644 --- a/src/plugins/DragDrop/index.js +++ b/src/plugins/DragDrop/index.js @@ -37,7 +37,7 @@ module.exports = class DragDrop extends Plugin { // Default options const defaultOpts = { target: '.UppyDragDrop', - setMetaFromTargetForm: false, + getMetaFromForm: true, locale: defaultLocale } diff --git a/src/plugins/FileInput.js b/src/plugins/FileInput.js index 6366c683b..8de81113d 100644 --- a/src/plugins/FileInput.js +++ b/src/plugins/FileInput.js @@ -19,7 +19,7 @@ module.exports = class FileInput extends Plugin { // Default options const defaultOptions = { target: '.UppyForm', - getMetaDataFromForm: true, + getMetaFromForm: true, replaceTargetContent: true, multipleFiles: true, pretty: true, diff --git a/src/plugins/Plugin.js b/src/plugins/Plugin.js index 432e7289d..91a008610 100644 --- a/src/plugins/Plugin.js +++ b/src/plugins/Plugin.js @@ -60,10 +60,9 @@ module.exports = class Plugin { this.core.log(`Installing ${callerPluginName} to a DOM element`) // attempt to extract meta from form element - if (this.opts.getMetaDataFromForm && targetElement.nodeName === 'FORM') { + if (this.opts.getMetaFromForm && targetElement.nodeName === 'FORM') { const formMeta = getFormData(targetElement) - this.core.log('Adding metadata from form') - this.core.log(formMeta) + this.core.setMeta(formMeta) } // clear everything inside the target container From 5b6396e986b4e800d43a2c8981bed137407f6242 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 30 Jun 2017 20:28:34 -0400 Subject: [PATCH 12/16] changelog --- CHANGELOG.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2343e817d..2a2fa082c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,44 +72,46 @@ maybe later: ## 0.18.0 +To be released: 2017-07-28 + - [ ] test: add https://github.com/pa11y/pa11y for automated accessibility testing (@arturi) - [ ] webcam: look into simplifying / improving webcam plugin (@arturi, @goto-bus-stop) - [ ] core: add error in file progress state? (@arturi) +- [ ] core: research !important styles to be immune to any environment/page. Maybe use smth like `postcss-safe-important`. Or increase specificity (with .Uppy) (@arturi) - [ ] uppy-server: add uppy-server metrics to Librato (@ifedapoolarewaju) - [ ] dashboard: error UI, question mark button, `core:error` (@arturi) - [ ] uploaders: add direct-to-s3 upload plugin and test it with the flow to then upload to transloadit, stage 2, release (@goto-bus-stop) +- [ ] server: what if smth changed in GDrive while it was open in Uppy? refresh file list? (@ifedapoolarewaju) +- [ ] core: see if we can figure out css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop) +- [ ] test: add tests for `npm install uppy` and running in different browsers, the real world use case (@arturi) +- [ ] provider: improve UI: add icons for file types (@arturi) ## 0.17.0 To be released: 2017-06-30 -- [x] core: add `uppy.reset()` as discussed in #179 (@arturi) -- [ ] core: research !important styles to be immune to any environment/page. Maybe use smth like `postcss-safe-important`. Or increase specificity (with .Uppy) (@arturi) - [ ] core: restrictions — by file type, size, number of files (@arturi) -- [ ] core: see if we can figure out css-in-js, while keeping non-random classnames (ideally prefixed) and useful preprocessor features. also see simple https://github.com/codemirror/CodeMirror/blob/master/lib/codemirror.css (@arturi, @goto-bus-stop) -- [ ] fileinput: allow retriving fields/options from form (@arturi #153) -- [ ] provider: improve UI: add icons for file types (@arturi) -- [ ] provider: improve UI: improve overall look, breadcrumbs (@arturi) -- [ ] provider: improve UI: steps towards making it responsive (@arturi) -- [ ] server: what if smth changed in GDrive while it was open in Uppy? refresh file list? (@ifedapoolarewaju) -- [x] statusbar: show status “Upload started...” when the remote upload has begun, but no progress events received yet (@arturi) -- [ ] test: add tests for `npm install uppy` and running in different browsers, the real world use case (@arturi) -- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) -- [x] uploaders: add direct-to-s3 upload plugin and test it with the flow to then upload to transloadit, stage 1, WIP (@goto-bus-stop) -- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) -- [x] uppy/uppy-server: some file types cannot be downloaded/uploaded on google drive (e.g google docs). How to handle that? (@ifedapoolarewaju) -- [x] uppy: fix google drive uploads on mobile (double click issue) (@arturi) +- [ ] provider: improve UI: improve overall look, breadcrumbs, more responsive (@arturi) - [ ] website: new demo video / gif (@arturi) +- [x] core: css-in-js demos, try template-css (@arturi @goto-bus-stop #239) +- [x] core: add `uppy.reset()` as discussed in #179 (@arturi) - [x] core: add nanoraf https://github.com/yoshuawuyts/choo/pull/135/files?diff=unified (@goto-bus-stop, @arturi) - [x] core: file type detection: archives, markdown (possible modules: file-type, identify-filetype) example: http://requirebin.com/?gist=f9bea9602030f1320a227cf7f140c45f, http://stackoverflow.com/a/29672957 (@arturi) - [x] dashboard: make file icons prettier: https://uppy.io/images/blog/0.16/service-logos.png (@arturi, @nqst / #215) +- [x] fileinput: allow retriving fields/options from form (@arturi #153) +- [x] server: configurable server port (@ifedapoolarewaju) - [x] server: support for custom providers (@ifedapoolarewaju) - [x] statusbar: also show major errors, add “error” state (@goto-bus-stop) - [x] statusbar: pre/postprocessing status updates in the StatusBar (@goto-bus-stop, #202) +- [x] statusbar: show status “Upload started...” when the remote upload has begun, but no progress events received yet (@arturi) - [x] statusbar: work towards extracting StatusBar to a separate plugin, bundle that with Dashboard? (@goto-bus-stop, @arturi) - [x] tus/uppy-server: Support metadata in remote tus uploads (@ifedapoolarewaju, @goto-bus-stop / #210) +- [x] uploaders: add direct-to-s3 upload plugin and test it with the flow to then upload to transloadit, stage 1, WIP (@goto-bus-stop) +- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) +- [x] uppy/uppy-server: Make a barely working Instagram Plugin (@ifedapoolarewaju / #21) - [x] uppy/uppy-server: allow google drive/dropbox non-tus (i.e multipart) remote uploads (@arturi, @ifedapoolarewaju / #205) -- [x] server: configurable server port (@ifedapoolarewaju) +- [x] uppy/uppy-server: some file types cannot be downloaded/uploaded on google drive (e.g google docs). How to handle that? (@ifedapoolarewaju) +- [x] uppy: fix google drive uploads on mobile (double click issue) (@arturi) ## 0.16.2 - 2017-05-31 From ba405dba13482d516886730c24087d54ccc90314 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Sat, 1 Jul 2017 16:19:33 -0400 Subject: [PATCH 13/16] Buttons should have type="button", otherwise they submit forms :scream_cat: --- src/plugins/Dashboard/Dashboard.js | 2 ++ src/plugins/Dashboard/FileCard.js | 2 +- src/plugins/Dashboard/FileItem.js | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/plugins/Dashboard/Dashboard.js b/src/plugins/Dashboard/Dashboard.js index a2cd6afc7..1b98d8b5b 100644 --- a/src/plugins/Dashboard/Dashboard.js +++ b/src/plugins/Dashboard/Dashboard.js @@ -58,6 +58,7 @@ module.exports = function Dashboard (props) { onload=${() => props.updateDashboardElWidth()}> @@ -134,6 +135,7 @@ module.exports = function Dashboard (props) { ${props.i18n('importFrom')} ${props.activePanel ? props.activePanel.name : null} ${props.activePanel ? props.activePanel.render(props.state) : ''} diff --git a/src/plugins/Dashboard/FileCard.js b/src/plugins/Dashboard/FileCard.js index 2d6f0e751..5e7fd3775 100644 --- a/src/plugins/Dashboard/FileCard.js +++ b/src/plugins/Dashboard/FileCard.js @@ -29,7 +29,7 @@ module.exports = function fileCard (props) { return html`

Editing ${file.meta ? file.meta.name : file.name}

-
${props.fileCardFor diff --git a/src/plugins/Dashboard/FileItem.js b/src/plugins/Dashboard/FileItem.js index f0d6ef8d5..ee53249de 100644 --- a/src/plugins/Dashboard/FileItem.js +++ b/src/plugins/Dashboard/FileItem.js @@ -49,6 +49,7 @@ module.exports = function fileItem (props) {
@@ -24,6 +25,7 @@ Webcam: document.querySelector('#opts-Webcam'), GoogleDrive: document.querySelector('#opts-GoogleDrive'), Dropbox: document.querySelector('#opts-Dropbox'), + Instagram: document.querySelector('#opts-Instagram'), autoProceed: document.querySelector('#opts-autoProceed') } @@ -31,6 +33,7 @@ DashboardInline: false, Webcam: true, GoogleDrive: true, + Instagram: true, Dropbox: false, autoProceed: false }