choerodon-ui
Version:
An enterprise-class UI design language and React-based implementation
690 lines (565 loc) • 21.6 kB
JavaScript
"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