AjaxUploader.js 9.32 KB
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _createSuper from "@babel/runtime/helpers/esm/createSuper";

/* eslint react/no-is-mounted:0,react/sort-comp:0,react/prop-types:0 */
import React, { Component } from 'react';
import classNames from 'classnames';
import pickAttrs from "rc-util/es/pickAttrs";
import defaultRequest from './request';
import getUid from './uid';
import attrAccept from './attr-accept';
import traverseFileTree from './traverseFileTree';

var AjaxUploader = /*#__PURE__*/function (_Component) {
  _inherits(AjaxUploader, _Component);

  var _super = _createSuper(AjaxUploader);

  function AjaxUploader() {
    var _this;

    _classCallCheck(this, AjaxUploader);

    _this = _super.apply(this, arguments);
    _this.state = {
      uid: getUid()
    };
    _this.reqs = {};

    _this.onChange = function (e) {
      var files = e.target.files;

      _this.uploadFiles(files);

      _this.reset();
    };

    _this.onClick = function (e) {
      var el = _this.fileInput;

      if (!el) {
        return;
      }

      var _this$props = _this.props,
          children = _this$props.children,
          onClick = _this$props.onClick;

      if (children && children.type === 'button') {
        var parent = el.parentNode;
        parent.focus();
        parent.querySelector('button').blur();
      }

      el.click();

      if (onClick) {
        onClick(e);
      }
    };

    _this.onKeyDown = function (e) {
      if (e.key === 'Enter') {
        _this.onClick(e);
      }
    };

    _this.onFileDrop = function (e) {
      var multiple = _this.props.multiple;
      e.preventDefault();

      if (e.type === 'dragover') {
        return;
      }

      if (_this.props.directory) {
        traverseFileTree(Array.prototype.slice.call(e.dataTransfer.items), _this.uploadFiles, function (_file) {
          return attrAccept(_file, _this.props.accept);
        });
      } else {
        var files = Array.prototype.slice.call(e.dataTransfer.files).filter(function (file) {
          return attrAccept(file, _this.props.accept);
        });

        if (multiple === false) {
          files = files.slice(0, 1);
        }

        _this.uploadFiles(files);
      }
    };

    _this.uploadFiles = function (files) {
      var postFiles = Array.prototype.slice.call(files);
      postFiles.map(function (file) {
        // eslint-disable-next-line no-param-reassign
        file.uid = getUid();
        return file;
      }).forEach(function (file) {
        _this.upload(file, postFiles);
      });
    };

    _this.saveFileInput = function (node) {
      _this.fileInput = node;
    };

    return _this;
  }

  _createClass(AjaxUploader, [{
    key: "componentDidMount",
    value: function componentDidMount() {
      this._isMounted = true;
    }
  }, {
    key: "componentWillUnmount",
    value: function componentWillUnmount() {
      this._isMounted = false;
      this.abort();
    }
  }, {
    key: "upload",
    value: function upload(file, fileList) {
      var _this2 = this;

      var props = this.props;

      if (!props.beforeUpload) {
        // always async in case use react state to keep fileList
        Promise.resolve().then(function () {
          _this2.post(file);
        });
        return;
      }

      var before = props.beforeUpload(file, fileList);

      if (before && typeof before !== 'boolean' && before.then) {
        before.then(function (processedFile) {
          var processedFileType = Object.prototype.toString.call(processedFile);

          if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
            _this2.post(processedFile);

            return;
          }

          _this2.post(file);
        }).catch(function (e) {
          // eslint-disable-next-line no-console
          console.log(e);
        });
      } else if (before !== false) {
        Promise.resolve().then(function () {
          _this2.post(file);
        });
      }
    }
  }, {
    key: "post",
    value: function post(file) {
      var _this3 = this;

      if (!this._isMounted) {
        return;
      }

      var props = this.props;
      var onStart = props.onStart,
          onProgress = props.onProgress,
          _props$transformFile = props.transformFile,
          transformFile = _props$transformFile === void 0 ? function (originFile) {
        return originFile;
      } : _props$transformFile;
      new Promise(function (resolve) {
        var action = props.action;

        if (typeof action === 'function') {
          action = action(file);
        }

        return resolve(action);
      }).then(function (action) {
        var uid = file.uid;
        var request = props.customRequest || defaultRequest;
        var transform = Promise.resolve(transformFile(file)).then(function (transformedFile) {
          var data = props.data;

          if (typeof data === 'function') {
            data = data(transformedFile);
          }

          return Promise.all([transformedFile, data]);
        }).catch(function (e) {
          console.error(e); // eslint-disable-line no-console
        });
        transform.then(function (_ref) {
          var _ref2 = _slicedToArray(_ref, 2),
              transformedFile = _ref2[0],
              data = _ref2[1];

          var requestOption = {
            action: action,
            filename: props.name,
            data: data,
            file: transformedFile,
            headers: props.headers,
            withCredentials: props.withCredentials,
            method: props.method || 'post',
            onProgress: onProgress ? function (e) {
              onProgress(e, file);
            } : null,
            onSuccess: function onSuccess(ret, xhr) {
              delete _this3.reqs[uid];
              props.onSuccess(ret, file, xhr);
            },
            onError: function onError(err, ret) {
              delete _this3.reqs[uid];
              props.onError(err, ret, file);
            }
          };
          onStart(file);
          _this3.reqs[uid] = request(requestOption);
        });
      });
    }
  }, {
    key: "reset",
    value: function reset() {
      this.setState({
        uid: getUid()
      });
    }
  }, {
    key: "abort",
    value: function abort(file) {
      var reqs = this.reqs;

      if (file) {
        var uid = file.uid ? file.uid : file;

        if (reqs[uid] && reqs[uid].abort) {
          reqs[uid].abort();
        }

        delete reqs[uid];
      } else {
        Object.keys(reqs).forEach(function (uid) {
          if (reqs[uid] && reqs[uid].abort) {
            reqs[uid].abort();
          }

          delete reqs[uid];
        });
      }
    }
  }, {
    key: "render",
    value: function render() {
      var _classNames;

      var _this$props2 = this.props,
          Tag = _this$props2.component,
          prefixCls = _this$props2.prefixCls,
          className = _this$props2.className,
          disabled = _this$props2.disabled,
          id = _this$props2.id,
          style = _this$props2.style,
          multiple = _this$props2.multiple,
          accept = _this$props2.accept,
          children = _this$props2.children,
          directory = _this$props2.directory,
          openFileDialogOnClick = _this$props2.openFileDialogOnClick,
          onMouseEnter = _this$props2.onMouseEnter,
          onMouseLeave = _this$props2.onMouseLeave,
          otherProps = _objectWithoutProperties(_this$props2, ["component", "prefixCls", "className", "disabled", "id", "style", "multiple", "accept", "children", "directory", "openFileDialogOnClick", "onMouseEnter", "onMouseLeave"]);

      var cls = classNames((_classNames = {}, _defineProperty(_classNames, prefixCls, true), _defineProperty(_classNames, "".concat(prefixCls, "-disabled"), disabled), _defineProperty(_classNames, className, className), _classNames)); // because input don't have directory/webkitdirectory type declaration

      var dirProps = directory ? {
        directory: 'directory',
        webkitdirectory: 'webkitdirectory'
      } : {};
      var events = disabled ? {} : {
        onClick: openFileDialogOnClick ? this.onClick : function () {},
        onKeyDown: openFileDialogOnClick ? this.onKeyDown : function () {},
        onMouseEnter: onMouseEnter,
        onMouseLeave: onMouseLeave,
        onDrop: this.onFileDrop,
        onDragOver: this.onFileDrop,
        tabIndex: '0'
      };
      return React.createElement(Tag, Object.assign({}, events, {
        className: cls,
        role: "button",
        style: style
      }), React.createElement("input", Object.assign({}, pickAttrs(otherProps, {
        aria: true,
        data: true
      }), {
        id: id,
        type: "file",
        ref: this.saveFileInput,
        onClick: function onClick(e) {
          return e.stopPropagation();
        },
        key: this.state.uid,
        style: {
          display: 'none'
        },
        accept: accept
      }, dirProps, {
        multiple: multiple,
        onChange: this.onChange
      })), children);
    }
  }]);

  return AjaxUploader;
}(Component);

export default AjaxUploader;