Home Reference Source Repository

src/Uploader.js

/**
 * @file melon/Uploader
 * @author leon([email protected])
 */

import React, {PropTypes} from 'react';
import Button from './Button';
import Icon from './Icon';
import Progress from './Progress';
import Link from './Link';
import Validity from 'melon-core/Validity';
import InputComponent from 'melon-core/InputComponent';

import {create} from 'melon-core/classname/cxBuilder';

const cx = create('Uploader');

export default class Uploader extends InputComponent {

    constructor(props, context) {

        super(props, context);

        this.state = {
            ...this.state,
            isUploading: false,
            isUploaded: !!this.props.value
        };

    }


    onFileChange(e) {

        this.setUploading();

        this
            .props
            .upload({
                target: this,
                files: e.target.files
            })
            .then(
                result => this.setFile(result),
                error => this.clearFile()
            );

    }

    setUploading() {
        this.setState({
            isUploading: true
        });
    }

    setFile(value) {

        this.setState({
            isUploaded: true,
            isUploading: false
        }, () => {
            super.onChange({
                type: 'change',
                target: this,
                value
            });
        });
    }

    clearFile() {

        this.setState({
            isUploaded: false,
            isUploading: false
        }, () => {

            super.onChange({
                type: 'change',
                target: this,
                value: ''
            });
        });

    }

    renderUploadFile() {

        const {isUploading, isUploaded} = this.state;

        return isUploading || isUploaded
            ? null
            : (
                <input
                    ref="file"
                    type="file"
                    className={cx().part('file').build()}
                    onChange={e => {
                        this.onFileChange(e);
                    }}
                    accept={this.props.accept} />
            );

    }

    renderUploadButton() {

        const {isUploading, isUploaded, value} = this.state;
        const {size, btnText} = this.props;

        if (isUploading) {
            return (
                <Progress
                    size={size}
                    mode="indeterminate"
                    shape="circle" />
            );
        }

        if (isUploaded) {

            return (
                <div className={cx().part('uploaded').build()}>
                    <Icon icon="done" size={size} /> 已上传
                    <Link
                        size={size}
                        href={value}
                        variants={['button']}
                        target="_blank">
                        查看
                    </Link>
                    <Button
                        size={size}
                        type="button"
                        onClick={() => {
                            this.clearFile();
                        }} >
                        重选
                    </Button>
                </div>
            );
        }

        return (
            <Button
                type="button"
                variants={['raised']}
                onClick={() => {
                    this.refs.file.click();
                }}>
                <Icon icon="file-upload" />
                {btnText}
            </Button>
        );

    }

    render() {

        const props = this.props;
        const {value, name, label} = props;

        return (
            <div className={cx(props).addStates(this.getStyleStates()).build()}>
                <input name={name} type="hidden" value={value} />
                {label ? <label className={cx().part('label').build()}>{label}</label> : null}
                {this.renderUploadFile()}
                {this.renderUploadButton()}
                <Validity validity={this.state.validity} />
            </div>
        );

    }

}

Uploader.displayName = 'Uploader';

Uploader.propTypes = {
    ...InputComponent.propTypes,
    multiple: PropTypes.bool,
    accept: PropTypes.string,
    files: PropTypes.array,
    upload: PropTypes.func.isRequired,
    btnText: PropTypes.string,
    label: PropTypes.string
};

Uploader.defaultProps = {
    ...InputComponent.defaultProps,
    btnText: '点击上传'
};

Uploader.childContextTypes = InputComponent.childContextTypes;
Uploader.contextTypes = InputComponent.contextTypes;