element-react-codish
Version:
Element UI for React
261 lines (234 loc) • 6.24 kB
JSX
/* @flow */
import React from 'react';
import { Component, PropTypes } from '../../libs';
import UploadList from './UploadList';
import iFrameUpload from './iFrameUpload';
import AjaxUpload from './AjaxUpload';
import type { UploadState, RawFile, _File, _ProgressEvent } from './Types';
export default class Upload extends Component {
state: UploadState;
static defaultProps = {
headers: {},
name: 'file',
type: 'select',
listType: 'text',
fileList: [],
showFileList: true,
autoUpload: true,
onRemove() {},
onPreview() {},
onProgress() {},
onSuccess() {},
onError() {},
onChange() {}
};
constructor(props: Object) {
super(props);
this.state = {
fileList: [],
tempIndex: 1
};
}
componentWillMount(): void {
this.init(this.props);
}
init(props: Object): void {
let { tempIndex } = this.state;
const { fileList } = props;
const uploadFiles = fileList.map(file => {
file.uid = file.uid || Date.now() + tempIndex++;
file.status = 'success';
return file;
});
this.setState({ fileList: uploadFiles });
}
getChildContext() {
return {
onPreview: this.handlePreview.bind(this),
onRemove: this.handleRemove.bind(this)
};
}
getFile(file: RawFile): ?_File {
if (file) {
return this.state.fileList.find(item => item.uid === file.uid);
}
return null;
}
handleStart(file: RawFile): void {
let { tempIndex, fileList } = this.state;
file.uid = Date.now() + tempIndex++;
let _file: _File = {
status: 'ready',
name: file.name,
size: file.size,
percentage: 0,
uid: file.uid,
raw: file
};
try {
_file.url = URL.createObjectURL(file);
} catch (err) {
return;
}
fileList.push(_file);
this.setState({
fileList,
tempIndex
});
}
handleProgress(e: _ProgressEvent, file: RawFile): void {
const { fileList } = this.state;
let _file = this.getFile(file);
if (_file) {
_file.percentage = e.percent || 0;
_file.status = 'uploading';
this.props.onProgress(e, _file, fileList);
this.setState({ fileList });
}
}
handleSuccess(res: Object, file: RawFile): void {
const { fileList } = this.state;
let _file = this.getFile(file);
if (_file) {
_file.status = 'success';
_file.response = res;
setTimeout(
() => {
this.setState({ fileList }, () => {
this.props.onSuccess(res, _file, fileList);
this.props.onChange(_file, fileList);
});
},
1000
);
}
}
handleError(err: Error, file: RawFile): void {
const { fileList } = this.state;
let _file = this.getFile(file);
if (_file) {
_file.status = 'fail';
fileList.splice(fileList.indexOf(_file), 1);
this.setState({ fileList }, () => {
this.props.onError(err, _file, fileList);
this.props.onChange(_file, fileList);
});
}
}
handleRemove(file: RawFile): void {
const { fileList } = this.state;
let _file = this.getFile(file);
if (_file) {
fileList.splice(fileList.indexOf(_file), 1);
this.setState({ fileList }, () => this.props.onRemove(file, fileList));
}
}
handlePreview(file: _File): void {
if (file.status === 'success') {
this.props.onPreview(file);
}
}
clearFiles(): void {
this.setState({
fileList: []
});
}
submit(): void {
this.state.fileList
.filter(file => file.status === 'ready')
.forEach(file => {
this.refs['upload-inner'].upload(file.raw, file);
});
}
showCover(): boolean {
const { fileList } = this.state;
const file = fileList[fileList.length - 1];
return file && file.status !== 'fail';
}
render(): React.Element<any> {
const { fileList } = this.state;
const {
showFileList,
autoUpload,
drag,
tip,
action,
multiple,
beforeUpload,
withCredentials,
headers,
name,
data,
accept,
listType,
className
} = this.props;
let uploadList;
if (showFileList && fileList.length) {
uploadList = <UploadList listType={listType} fileList={fileList} />;
}
const restProps = {
autoUpload,
drag,
action,
multiple,
beforeUpload,
withCredentials,
headers,
name,
data,
accept,
listType,
onStart: this.handleStart.bind(this),
onProgress: this.handleProgress.bind(this),
onSuccess: this.handleSuccess.bind(this),
onError: this.handleError.bind(this),
onPreview: this.handlePreview.bind(this),
onRemove: this.handleRemove.bind(this),
showCover: this.showCover(),
ref: 'upload-inner'
};
const trigger = this.props.trigger || this.props.children;
const uploadComponent = typeof FormData !== 'undefined'
? <AjaxUpload key="AjaxUpload" {...restProps}>{trigger}</AjaxUpload>
: <iFrameUpload key="iFrameUpload" {...restProps}>{trigger}</iFrameUpload>;
return (
<div className={className}>
{listType === 'picture-card' ? uploadList : ''}
{this.props.trigger
? [uploadComponent, this.props.children]
: uploadComponent}
{tip}
{listType !== 'picture-card' ? uploadList : ''}
</div>
);
}
}
Upload.childContextTypes = {
onPreview: PropTypes.func,
onRemove: PropTypes.func
};
Upload.propTypes = {
action: PropTypes.string.isRequired,
headers: PropTypes.object,
data: PropTypes.object,
multiple: PropTypes.bool,
name: PropTypes.string,
withCredentials: PropTypes.bool,
showFileList: PropTypes.bool,
fileList: PropTypes.array,
autoUpload: PropTypes.bool,
accept: PropTypes.string,
drag: PropTypes.bool,
listType: PropTypes.oneOf(['text', 'picture', 'picture-card']),
tip: PropTypes.node,
trigger: PropTypes.node,
beforeUpload: PropTypes.func,
onRemove: PropTypes.func,
onPreview: PropTypes.func,
onProgress: PropTypes.func,
onSuccess: PropTypes.func,
onError: PropTypes.func,
onChange: PropTypes.func,
className: PropTypes.string
};