UNPKG

choerodon-ui

Version:

An enterprise-class UI design language and React-based implementation

690 lines (565 loc) 21.6 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault")["default"]; Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _get2 = _interopRequireDefault(require("@babel/runtime/helpers/get")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _createSuper2 = _interopRequireDefault(require("@babel/runtime/helpers/createSuper")); var _tslib = require("tslib"); var _react = _interopRequireDefault(require("react")); var _mobx = require("mobx"); var _mobxReact = require("mobx-react"); var _uniqBy = _interopRequireDefault(require("lodash/uniqBy")); var _isEmpty = _interopRequireDefault(require("lodash/isEmpty")); var _isPromise = _interopRequireDefault(require("is-promise")); var _utils = require("../../../lib/upload/utils"); var _Button = _interopRequireDefault(require("../button/Button")); var _enum = require("../button/enum"); var _autobind = _interopRequireDefault(require("../_util/autobind")); var _FormField2 = require("../field/FormField"); var _icon = _interopRequireDefault(require("../icon")); var _message = _interopRequireDefault(require("../message")); var _modal = _interopRequireDefault(require("../modal")); var _UploadList = _interopRequireDefault(require("./UploadList")); var _Tooltip = _interopRequireDefault(require("../tooltip/Tooltip")); var _localeContext = require("../locale-context"); var _isIE = _interopRequireDefault(require("../_util/isIE")); /** * 把XMLHttpRequest对象的返回信息转化为字符串 * * @param {XMLHttpRequest} xhr * @returns {string} * @memberof Upload */ function getResponse(xhr) { var res = xhr.responseText || xhr.response; if (!res) { return res; } try { return JSON.parse(res).message; } catch (e) { return ''; } } var Upload = /*#__PURE__*/function (_FormField) { (0, _inherits2["default"])(Upload, _FormField); var _super = (0, _createSuper2["default"])(Upload); function Upload(props, context) { var _this; (0, _classCallCheck2["default"])(this, Upload); _this = _super.call(this, props, context); _this.saveNativeInputElement = function (elem) { return _this.nativeInputElement = elem; }; /** * 传递包装按钮的点击事件 * */ _this.handleWrapperBtnClick = function () { _this.nativeInputElement.click(); }; _this.handleUploadBtnClick = function () { _this.startUpload(); }; /** * 文件上传前的回调 * * @param {UploadFile} * @param {UploadFile[]} * @memberof Upload */ _this.beforeUpload = function (file, fileList) { var beforeUpload = _this.props.beforeUpload; if (!beforeUpload) { return true; } var result = beforeUpload(file, fileList); if (result === false) { _this.removeFileItem(file); return false; } if ((0, _isPromise["default"])(result)) { return result; } return true; }; _this.startUpload = function () { var fileList = (0, _toConsumableArray2["default"])(_this.fileList); if (fileList.length) { // <-- 当有文件时才上传 _this.uploadFiles(fileList); // this.nativeInputElement.value = ''; } else { _modal["default"].error((0, _localeContext.$l)('Upload', 'no_file')); } }; _this.handleRemove = function (file) { // this.removeFileItem(file); // this.upload.abort(file); file.status = 'removed'; _this.handleOnRemove(file); }; (0, _mobx.runInAction)(function () { _this.fileList = props.uploadFileList || props.defaultFileList || []; }); return _this; } (0, _createClass2["default"])(Upload, [{ key: "componentWillReceiveProps", value: function componentWillReceiveProps(nextProps) { var uploadFileList = nextProps.uploadFileList; if (uploadFileList !== this.fileList && uploadFileList !== undefined) { this.fileList = (0, _uniqBy["default"])(uploadFileList, function (item) { return item.uid; }); } } }, { key: "getOmitPropsKeys", value: function getOmitPropsKeys() { return (0, _get2["default"])((0, _getPrototypeOf2["default"])(Upload.prototype), "getOmitPropsKeys", this).call(this).concat(['accept', 'action', 'data', 'header', 'multiple', 'uploadImmediately', 'fileListMaxLength', 'showPreviewImage', 'previewImageWidth', 'showUploadBtn', 'showUploadList', 'onRemoveFile', 'onUploadSuccess', 'onUploadError', 'onFileChange', 'beforeUpload', 'withCredentials', 'partialUpload', 'appendUpload', 'uploadFileList']); } }, { key: "getOtherProps", value: function getOtherProps() { var otherProps = (0, _get2["default"])((0, _getPrototypeOf2["default"])(Upload.prototype), "getOtherProps", this).call(this); delete otherProps.ref; delete otherProps.onChange; return otherProps; } }, { key: "render", value: function render() { var prefixCls = this.prefixCls, _this$props = this.props, formAction = _this$props.action, children = _this$props.children, multiple = _this$props.multiple, accept = _this$props.accept, _this$props$name = _this$props.name, name = _this$props$name === void 0 ? 'file' : _this$props$name, uploadImmediately = _this$props.uploadImmediately, showPreviewImage = _this$props.showPreviewImage, previewImageWidth = _this$props.previewImageWidth, showUploadBtn = _this$props.showUploadBtn, showUploadList = _this$props.showUploadList, extra = _this$props.extra; var uploadProps = (0, _objectSpread2["default"])({ multiple: multiple, accept: accept ? accept.join(',') : undefined, action: formAction, name: name, type: 'file', ref: this.saveNativeInputElement, onChange: this.handleChange }, this.getOtherProps()); var inputWrapperBtn = [/*#__PURE__*/_react["default"].createElement(_Button["default"], { key: "upload-btn", onClick: this.handleWrapperBtnClick }, /*#__PURE__*/_react["default"].createElement(_icon["default"], { type: "insert_drive_file" }), /*#__PURE__*/_react["default"].createElement("span", null, children || (0, _localeContext.$l)('Upload', 'file_selection'))), /*#__PURE__*/_react["default"].createElement("input", (0, _extends2["default"])({ key: "upload" }, uploadProps, { hidden: true }))]; var uploadBtn = /*#__PURE__*/_react["default"].createElement(_Tooltip["default"], { title: (0, _localeContext.$l)('Upload', 'click_to_upload'), placement: "right" }, /*#__PURE__*/_react["default"].createElement(_Button["default"], { color: _enum.ButtonColor.primary, onClick: this.handleUploadBtnClick }, /*#__PURE__*/_react["default"].createElement(_icon["default"], { type: "file_upload" }))); /** * to solve the ie11 dispaly inline-block with the button cause unaligned */ var IeStyle = (0, _isIE["default"])() ? { display: '-ms-inline-flexbox' } : {}; return /*#__PURE__*/_react["default"].createElement("div", { className: "".concat(prefixCls), style: IeStyle }, /*#__PURE__*/_react["default"].createElement("div", { className: "flex-wrapper" }, /*#__PURE__*/_react["default"].createElement("div", { className: "".concat(prefixCls, "-select") }, inputWrapperBtn, !uploadImmediately && showUploadBtn ? uploadBtn : null), /*#__PURE__*/_react["default"].createElement("div", null, extra)), showUploadList ? /*#__PURE__*/_react["default"].createElement(_UploadList["default"], { previewImageWidth: previewImageWidth, showPreviewImage: showPreviewImage, items: (0, _toConsumableArray2["default"])(this.fileList), remove: this.handleRemove }) : null); } /** * 处理<input type="file">元素的change事件, * 主要是取出事件对象中的files对象并传递给uploadFiles方法 * * @param {*} e <input>元素的change事件对象 * @memberof Upload */ }, { key: "handleChange", value: function handleChange(e) { var _this2 = this; if (e.target.value === '') { return; } var _this$props2 = this.props, appendUpload = _this$props2.appendUpload, defaultFileList = _this$props2.defaultFileList, uploadFileList = _this$props2.uploadFileList; var fileList = e.target.files; var files = Array.from(fileList).slice(0); var tempFileList = appendUpload || defaultFileList || uploadFileList ? this.fileList.slice() : []; var fileBuffer = []; files.forEach(function (file, index) { file.uid = _this2.getUid(index); file.url = URL.createObjectURL(file); var res = _this2.beforeUpload(file, files); if (!res) { return; } fileBuffer.push(file); }); this.fileList = [].concat((0, _toConsumableArray2["default"])(tempFileList), fileBuffer); var _this$props3 = this.props, uploadImmediately = _this$props3.uploadImmediately, onFileChange = _this$props3.onFileChange; e.target.value = ''; if (uploadImmediately) { if (!(0, _isEmpty["default"])(fileBuffer)) { this.uploadFiles(this.fileList); } } if (onFileChange) { onFileChange(this.fileList.slice()); } } /** * 分别上传fileList中的每个文件对象 * * @param {UploadFile[]} fileList 文件对象数组 * @returns {void} * @memberof Upload */ }, { key: "uploadFiles", value: function uploadFiles(fileList) { var _this3 = this; var _this$props4 = this.props, formAction = _this$props4.action, accept = _this$props4.accept, _this$props4$fileList = _this$props4.fileListMaxLength, fileListMaxLength = _this$props4$fileList === void 0 ? 0 : _this$props4$fileList, partialUpload = _this$props4.partialUpload; if (!formAction) { _modal["default"].error((0, _localeContext.$l)('Upload', 'upload_path_unset')); return; } if (!this.isAcceptFiles(fileList)) { _modal["default"].error((0, _localeContext.$l)('Upload', 'not_acceptable_prompt') + accept.join(',')); return; } if (fileListMaxLength !== 0 && this.fileList.length > fileListMaxLength) { _modal["default"].error("".concat((0, _localeContext.$l)('Upload', 'file_list_max_length'), ": ").concat(fileListMaxLength)); return; } var files = partialUpload ? fileList.filter(function (item) { return !item.status || item.status !== 'success'; }) : Array.from(fileList); // eslint-disable-next-line @typescript-eslint/no-this-alias var that = this; if (!files.length) { _message["default"].info((0, _localeContext.$l)('Upload', 'been_uploaded')); } files.forEach(function (file, index) { file.uid = _this3.getUid(index); setTimeout(function () { that.upload(file); }, 0); }); } /** * 上传每个文件对象 * * @param {*} file * @returns {void} * @memberof Upload */ /* istanbul ignore next */ }, { key: "upload", value: function upload(file) { var _this4 = this; var _this$props5 = this.props, data = _this$props5.data, formAction = _this$props5.action, headers = _this$props5.headers, filename = _this$props5.name, xhrWithCredentials = _this$props5.withCredentials; if (typeof XMLHttpRequest === 'undefined') { return; } var xhr = new XMLHttpRequest(); var formData = new FormData(); // 修改文件状态,方便UploadList判断是否展示进度条 file.status = 'uploading'; if (xhr.upload) { xhr.upload.onprogress = function (e) { var percent = 0; if (e.total > 0) { percent = e.loaded / e.total * 100; } _this4.handleProgress(percent, file); }; } if (data) { var newData = typeof data === 'function' ? data(file) : data; Object.keys(newData).forEach(function (key) { return formData.append(key, newData[key]); }); } // TODO: `filename` default value needs better implementation formData.append(filename || 'file', file); var errorMsg = "cannot post ".concat(formAction, " ").concat(xhr.status); if (xhrWithCredentials && 'withCredentials' in xhr) { xhr.withCredentials = true; } xhr.open('post', formAction, true); xhr.onload = function () { // 以二开头的状态码都认为是成功,暂定? var isSuccessful = xhr.status.toString().startsWith('2'); if (isSuccessful) { _this4.handleSuccess(xhr.status, xhr.response, file); } else { _this4.handleError(new Error(errorMsg), getResponse(xhr), xhr.response, file); } }; xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); if (headers !== undefined) { Object.keys(headers).forEach(function (key) { if ({}.hasOwnProperty.call(headers, key)) { xhr.setRequestHeader(key, headers[key]); } }); } xhr.send(formData); xhr.onerror = function () { _this4.handleError(new Error(errorMsg), getResponse(xhr), xhr.response, file); }; xhr.ontimeout = function () { var timeoutMsg = "The request post for ".concat(_mobx.action, " timed out"); _this4.handleError(new Error(timeoutMsg), getResponse(xhr), xhr.response, file); }; } /** * 处理上传成功的函数,根据结果设置文件对象的状态, * 用于在UploadList中的展示 * * @param {number} status HTTP状态码 * @param {string} response 响应对象 * @param {UploadFile} file 文件对象 * @returns */ }, { key: "handleSuccess", value: function handleSuccess(status, response, file) { var targetItem = this.getFileItem(file); if (targetItem) { var onUploadSuccess = this.props.onUploadSuccess; targetItem.status = status === 200 ? 'success' : 'done'; targetItem.response = response; if (onUploadSuccess) { onUploadSuccess(response, file); } this.forceUpdate(); } } /** * 处理上传进度变化的函数,更新文件对象中的percent值, * 用于在UploadList中展示 * * @param {number} percent 上传百分比 * @param {UploadFile} file 文件对象 * @returns */ }, { key: "handleProgress", value: function handleProgress(percent, file) { var onUploadProgress = this.props.onUploadProgress; var targetItem = this.getFileItem(file); if (targetItem) { targetItem.percent = percent; if (onUploadProgress) { onUploadProgress(percent, file); } this.forceUpdate(); } } /** * 处理上传出错的函数,用于设置文件对象的status值, * * @param {Error} error 错误对象 * @param {string} responseText 处理成字符串的响应对象 * @param {UploadFile} file 文件对象 * @returns */ }, { key: "handleError", value: function handleError(error, responseText, response, file) { var onUploadError = this.props.onUploadError; var targetItem = this.getFileItem(file); if (targetItem) { targetItem.status = 'error'; targetItem.error = error; targetItem.response = responseText; if (onUploadError) { onUploadError(error, response, file); } this.forceUpdate(); } } }, { key: "handleOnRemove", value: function handleOnRemove(file) { var _this5 = this; var onRemoveFile = this.props.onRemoveFile; Promise.resolve(typeof onRemoveFile === 'function' ? onRemoveFile(file) : onRemoveFile).then(function (ret) { if (ret === false) { return; } _this5.removeFileItem(file); }); } /** * 判断文件后缀名是否合格 * this.props.accept值为falsy时返回true,否则正常判断 * * @param {UploadFile[]} fileList 文件对象数组 * @returns {boolean} * @memberof Upload */ }, { key: "isAcceptFiles", value: function isAcceptFiles(fileList) { var accept = this.props.accept; if (!accept) { return true; } var acceptTypes = accept.map(function (type) { type = type.replace(/\./g, '\\.'); type = type.replace(/\*/g, '.*'); return new RegExp(type); }); return fileList.some(function (_ref) { var name = _ref.name, type = _ref.type; return acceptTypes.some(function (acceptType) { return acceptType.test(name) || acceptType.test(type); }); }); } /** * 使用日期获取一个uid * * @param {number} index 索引 * @returns {string} * @memberof Upload */ }, { key: "getUid", value: function getUid(index) { var prefixCls = this.prefixCls; var now = new Date(); return "".concat(prefixCls, "-").concat(now, "-").concat(index); } /** * 从文件对象数组中获取一个文件对象的引用, * 首先尝试通过uid属性匹配文件对象,若失败则尝试name * * @param {UploadFile} file * @param {UploadFile[]} fileList 文件对象数组 * @returns {UploadFile} * @memberof Upload */ }, { key: "getFileItem", value: function getFileItem(file) { var matchKey = file.uid !== undefined ? 'uid' : 'name'; return this.fileList.find(function (item) { return item[matchKey] === file[matchKey]; }); } /** * 从文件对象数组中移除一个文件对象, * 首先尝试通过uid属性匹配文件对象,若失败则尝试name * * @param {UploadFile} file * @param {UploadFile[]} fileList * @returns {UploadFile[]} * @memberof Upload */ }, { key: "removeFileItem", value: function removeFileItem(file) { var matchKey = file.uid !== undefined ? 'uid' : 'name'; var index = this.fileList.findIndex(function (item) { return item[matchKey] === file[matchKey]; }); var uploadFileList = this.props.uploadFileList; if (uploadFileList && uploadFileList.length) { uploadFileList.splice(index, 1); this.fileList.splice(index, 1); } else { this.fileList.splice(index, 1); } } }]); return Upload; }(_FormField2.FormField); Upload.displayName = 'Upload'; Upload.defaultProps = (0, _objectSpread2["default"])((0, _objectSpread2["default"])({}, _FormField2.FormField.defaultProps), {}, { suffixCls: 'upload', multiple: false, headers: {}, data: {}, action: '', name: 'file', withCredentials: false, appendUpload: false, partialUpload: true, uploadImmediately: true, fileListMaxLength: 0, showPreviewImage: true, previewImageWidth: 100, showUploadBtn: true, showUploadList: true, beforeUpload: _utils.T, onUploadSuccess: function onUploadSuccess() { _message["default"].success((0, _localeContext.$l)('Upload', 'upload_success')); }, onUploadError: function onUploadError() { _message["default"].error((0, _localeContext.$l)('Upload', 'upload_failure')); } }); (0, _tslib.__decorate)([_mobx.observable], Upload.prototype, "fileList", void 0); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "componentWillReceiveProps", null); (0, _tslib.__decorate)([_autobind["default"], _mobx.action], Upload.prototype, "handleChange", null); (0, _tslib.__decorate)([_autobind["default"], _mobx.action], Upload.prototype, "uploadFiles", null); (0, _tslib.__decorate)([_autobind["default"], _mobx.action], Upload.prototype, "upload", null); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "handleSuccess", null); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "handleProgress", null); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "handleError", null); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "handleRemove", void 0); (0, _tslib.__decorate)([_mobx.action], Upload.prototype, "removeFileItem", null); Upload = (0, _tslib.__decorate)([_mobxReact.observer], Upload); var _default = Upload; exports["default"] = _default; //# sourceMappingURL=Upload.js.map