From 770dda5b97a6a17732a545b0d7fa506c13817872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BF=B0=E6=96=87?= Date: Wed, 1 Apr 2015 09:58:52 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E4=BD=BF=E7=94=A8flux=E6=A8=A1?= =?UTF-8?q?=E5=BC=8F=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/simple.js | 4 +- lib/Dropzone.js | 84 +++++++++---------------- lib/DzPreview.js | 2 +- lib/FileInput.js | 12 ++-- lib/FileQueues.js | 6 -- lib/actions/FileActions.js | 77 +++++++++++++++++++++++ lib/constants/DzConstants.js | 8 +++ lib/constants/StatusConstants.js | 6 ++ lib/dispatcher/DzDispatcher.js | 3 + lib/stores/FileStore.js | 104 +++++++++++++++++++++++++++++++ lib/utils/request.js | 10 ++- package.json | 10 ++- 12 files changed, 256 insertions(+), 70 deletions(-) delete mode 100644 lib/FileQueues.js create mode 100644 lib/actions/FileActions.js create mode 100644 lib/constants/DzConstants.js create mode 100644 lib/constants/StatusConstants.js create mode 100644 lib/dispatcher/DzDispatcher.js create mode 100644 lib/stores/FileStore.js diff --git a/examples/simple.js b/examples/simple.js index c868b2d..1941957 100644 --- a/examples/simple.js +++ b/examples/simple.js @@ -11,7 +11,9 @@ function accept(file) { } React.render( - +
Drop files here or click to upload.
(This is just a demo dropzone. Selected files are diff --git a/lib/Dropzone.js b/lib/Dropzone.js index 4b1fb6f..a8b40f1 100644 --- a/lib/Dropzone.js +++ b/lib/Dropzone.js @@ -5,11 +5,10 @@ * Dropzone */ var React = require('react'); +var FileStore = require('./stores/FileStore'); var FileInput = require('./FileInput'); var DzPreview = require('./DzPreview'); -var post = require('./utils/request').post; -var uid = require('./utils/uid'); -var createThumbnail = require('./utils/createThumbnail'); +var FileActions = require('./actions/FileActions'); var Dropzone = React.createClass({ @@ -19,27 +18,27 @@ var Dropzone = React.createClass({ paramName: 'file', accept: function(file) { return Promise.resolve(file); - } + }, + data: {}, + success: function() { }, + error: function() { } }; }, - accept: function(file) { - return createThumbnail(file).then(function(thumbnail) { - file.thumbnail = thumbnail; - return file; - }) - .then(this.props.accept) - .then(function() { - return file; - }); - }, - getInitialState: function() { return { - files: [] + files: FileStore.getAllFiles() }; }, + componentDidMount: function() { + FileStore.addChangeListener(this._onChange); + }, + + componentWillUnmount: function() { + FileStore.removeChangeListener(this._onChange); + }, + clickFileInput: function() { var input = this.refs.input; input.getDOMNode().click(); @@ -47,60 +46,33 @@ var Dropzone = React.createClass({ previews: function() { var files = this.state.files; - var remove = this.removeFile; - return files.map(function(file) { - return ; + return Object.keys(files).map(function(uid) { + return ; }); }, - removeFile: function(uid) { - console.log(uid); - }, - addFile: function(file) { - var self = this; - var files = this.state.files; - file.uid = uid(8); - files.push(file); - this.accept(file) - .then(this.startUploadFile) - .catch(function fileRejected(msg) { - file.done = msg; - self.updateFilesState(); - }); - }, - - startUploadFile: function(file) { - if (!file) { - return; - } - - var props = this.props; - var self = this; - post(props.action) - .attach(props.paramName, file, file.type) - .on('progress', function(e) { - file.percent = e.percent; - self.updateFilesState(); - }) - .end(function() { - file.done = true; - self.updateFilesState(); - }); + FileActions.upload(file, this.props.accept, { + action: this.props.action, + paramName: this.props.paramName, + success: this.props.success, + error: this.props.error, + data: this.props.data + }); }, - updateFilesState: function(files) { - files = files || this.state.files; + _onChange: function() { + var files = FileStore.getAllFiles(); this.setState({files: files}); }, render: function() { var props = this.props; var previews = this.previews(); - var fileNumber = this.state.files.length; + var fileNumber = Object.keys(this.state.files).length; return (
- + {previews} { !fileNumber ? props.children : '' } diff --git a/lib/DzPreview.js b/lib/DzPreview.js index 12634c0..6561d3f 100644 --- a/lib/DzPreview.js +++ b/lib/DzPreview.js @@ -43,7 +43,7 @@ var DzPreview = React.createClass({ return 'dz-preview dz-image-preivew dz-error dz-complete'; } - return 'dz-preivew dz-file-preview'; + return 'dz-preview dz-processing dz-image-preview'; }, fileResult: function(file) { diff --git a/lib/FileInput.js b/lib/FileInput.js index eb9fa8d..375bcf3 100644 --- a/lib/FileInput.js +++ b/lib/FileInput.js @@ -13,7 +13,7 @@ var FileInput = React.createClass({ getDefaultProps: function() { return { name: 'file', - addFile: function() {} + upload: function() {} }; }, @@ -25,15 +25,19 @@ var FileInput = React.createClass({ var fileList = this.getDOMNode().files; var len = fileList.length; for (var i = 0; i < len; i++) { - this.props.addFile(fileList.item(i)); + var file = fileList.item(i); + this.props.upload(file); } }, render: function() { var css = fileInputCss; return ( - + ); } }); diff --git a/lib/FileQueues.js b/lib/FileQueues.js deleted file mode 100644 index a9ec27b..0000000 --- a/lib/FileQueues.js +++ /dev/null @@ -1,6 +0,0 @@ -'use strict'; - -function FileQueues() { -} - -module.exports = FileQueues; diff --git a/lib/actions/FileActions.js b/lib/actions/FileActions.js new file mode 100644 index 0000000..357b123 --- /dev/null +++ b/lib/actions/FileActions.js @@ -0,0 +1,77 @@ +/**! + * desc + * Copyright(c) Alibaba Group Holding Limited. + * MIT Licensed + * + * Authors: + * 翰文 (http://shepherdwind.com) + */ +'use strict'; + +var DzDispatcher = require('../dispatcher/DzDispatcher'); +var DzConstants = require('../constants/DzConstants'); +var createThumbnail = require('../utils/createThumbnail'); +var request = require('../utils/request'); + +var FileActions = { + + upload: function(file, accept, config) { + + createThumbnail(file) + .then(function(thumbnail) { + file.thumbnail = thumbnail; + return file; + }) + .then(accept) + .then(function() { + DzDispatcher.dispatch({ + actionType: DzConstants.FILE_ADD, + file: file + }); + + upload(file, config); + }) + .catch(function(msg) { + DzDispatcher.dispatch({ + actionType: DzConstants.FILE_REJECTED, + file: file, + msg: msg + }); + }); + } + +}; + +function upload(file, config) { + request + .upload(file, config) + .on('progress', function(e) { + DzDispatcher.dispatch({ + actionType: DzConstants.FILE_UPLOAD_PROGRESS, + uid: file.uid, + percent: e.percent + }); + }) + .end(function(err, ret) { + if (err || ret.status !== 200) { + var message = err ? err.message : ret.text; + DzDispatcher.dispatch({ + actionType: DzConstants.FILE_UPLOAD_FAIL, + uid: file.uid, + error: message + }); + + config.error(message); + return; + } + + DzDispatcher.dispatch({ + actionType: DzConstants.FILE_UPLOAD_SUCCESS, + uid: file.uid, + body: ret.body + }); + + config.success(ret.body); + }); +} +module.exports = FileActions; diff --git a/lib/constants/DzConstants.js b/lib/constants/DzConstants.js new file mode 100644 index 0000000..08b11d0 --- /dev/null +++ b/lib/constants/DzConstants.js @@ -0,0 +1,8 @@ +var keymirror = require('keymirror'); +module.exports = keymirror({ + FILE_ADD: null, + FILE_REJECTED: null, + FILE_UPLOAD_PROGRESS: null, + FILE_UPLOAD_SUCCESS: null, + FILE_UPLOAD_FAIL: null +}); diff --git a/lib/constants/StatusConstants.js b/lib/constants/StatusConstants.js new file mode 100644 index 0000000..681f8c7 --- /dev/null +++ b/lib/constants/StatusConstants.js @@ -0,0 +1,6 @@ +var keymirror = require('keymirror'); +module.exports = keymirror({ + ADD: null, + REJECTED: null, + UPLOADING: null +}); diff --git a/lib/dispatcher/DzDispatcher.js b/lib/dispatcher/DzDispatcher.js new file mode 100644 index 0000000..5231a4e --- /dev/null +++ b/lib/dispatcher/DzDispatcher.js @@ -0,0 +1,3 @@ +var Dispatcher = require('flux').Dispatcher; + +module.exports = new Dispatcher(); diff --git a/lib/stores/FileStore.js b/lib/stores/FileStore.js new file mode 100644 index 0000000..8c6c86d --- /dev/null +++ b/lib/stores/FileStore.js @@ -0,0 +1,104 @@ +/**! + * desc + * Copyright(c) Alibaba Group Holding Limited. + * MIT Licensed + * + * Authors: + * 翰文 (http://shepherdwind.com) + */ +'use strict'; + +var DzDispatcher = require('../dispatcher/DzDispatcher'); +var DzConstants = require('../constants/DzConstants'); +var StatusConstants = require('../constants/StatusConstants'); +var EventEmitter = require('events').EventEmitter; +var assign = require('object-assign'); +var uid = require('../utils/uid'); + +var CHANGE_EVENT = 'change'; +var _files = {}; + +var FileStore = assign({}, EventEmitter.prototype, { + + getAllFiles: function() { + return _files; + }, + + getAddedFiles: function() { + return Object.keys(_files).filter(function(uid) { + var file = _files[uid]; + if (file.status === StatusConstants.ADD) { + return file; + } + }); + }, + + addChangeListener: function(callback) { + this.on(CHANGE_EVENT, callback); + }, + + removeChangeListener: function(callback) { + this.removeListener(CHANGE_EVENT, callback); + }, + + emitChange: function() { + this.emit(CHANGE_EVENT); + } + +}); + +function add(file) { + var _uid = uid(); + file.uid = _uid; + file.status = StatusConstants.ADD; + _files[_uid] = file; +} + +function reject(file, msg) { + add(file); + file.status = StatusConstants.REJECTED; + file.done = msg; +} + +function success(uid) { + _files[uid].done = true; +} + +function uploading(uid, percent) { + _files[uid].status = StatusConstants.UPLOADING; + _files[uid].percent = percent; +} + +function fail(uid, msg) { + _files[uid].done = msg; +} + +DzDispatcher.register(function(action) { + switch (action.actionType) { + case DzConstants.FILE_ADD: + add(action.file); + break; + + case DzConstants.FILE_REJECTED: + reject(action.file, action.msg); + break; + + case DzConstants.FILE_UPLOAD_PROGRESS: + uploading(action.uid, action.percent); + break; + + case DzConstants.FILE_UPLOAD_SUCCESS: + success(action.uid); + break; + + case DzConstants.FILE_UPLOAD_FAIL: + fail(action.uid, action.error); + break; + + default: + } + + FileStore.emitChange(); +}); + +module.exports = FileStore; diff --git a/lib/utils/request.js b/lib/utils/request.js index aa3b3f1..4b3a864 100644 --- a/lib/utils/request.js +++ b/lib/utils/request.js @@ -1,4 +1,12 @@ 'use strict'; var request = require('superagent'); -exports.post = request.post; +exports.upload = function(file, config) { + var req = request + .post(config.action) + .attach(config.paramName, file, file.type); + for (var key in config.data) { + req.field(key, config.data[key]); + } + return req; +}; diff --git a/package.json b/package.json index 5f3062f..7979865 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,11 @@ "superagent": "1.1.0", "uid": "0.0.2", "import-style": "1.0.0", - "react": "*" + "react": "*", + "flux": "2.0.1", + "keymirror": "0.1.0", + "object-assign": "2.0.0", + "events": "1.0.1" }, "buildArgs": "--global react:window.React" }, @@ -60,6 +64,10 @@ "less" ], "dependencies": { + "events": "^1.0.2", + "flux": "^2.0.1", + "keymirror": "^0.1.1", + "object-assign": "^2.0.0", "superagent": "^0.21.0", "uid": "0.0.2" }