Upload.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = exports.LIST_IGNORE = void 0;
  7. var _vue = require("vue");
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
  10. var _vcUpload = _interopRequireDefault(require("../vc-upload"));
  11. var _UploadList = _interopRequireDefault(require("./UploadList"));
  12. var _interface = require("./interface");
  13. var _utils = require("./utils");
  14. var _LocaleReceiver = require("../locale-provider/LocaleReceiver");
  15. var _en_US = _interopRequireDefault(require("../locale/en_US"));
  16. var _propsUtil = require("../_util/props-util");
  17. var _useMergedState = _interopRequireDefault(require("../_util/hooks/useMergedState"));
  18. var _devWarning = _interopRequireDefault(require("../vc-util/devWarning"));
  19. var _useConfigInject = _interopRequireDefault(require("../config-provider/hooks/useConfigInject"));
  20. var _classNames = _interopRequireDefault(require("../_util/classNames"));
  21. var _form = require("../form");
  22. var _style = _interopRequireDefault(require("./style"));
  23. var _DisabledContext = require("../config-provider/DisabledContext");
  24. var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
  25. function adopt(value) {
  26. return value instanceof P ? value : new P(function (resolve) {
  27. resolve(value);
  28. });
  29. }
  30. return new (P || (P = Promise))(function (resolve, reject) {
  31. function fulfilled(value) {
  32. try {
  33. step(generator.next(value));
  34. } catch (e) {
  35. reject(e);
  36. }
  37. }
  38. function rejected(value) {
  39. try {
  40. step(generator["throw"](value));
  41. } catch (e) {
  42. reject(e);
  43. }
  44. }
  45. function step(result) {
  46. result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
  47. }
  48. step((generator = generator.apply(thisArg, _arguments || [])).next());
  49. });
  50. };
  51. var __rest = void 0 && (void 0).__rest || function (s, e) {
  52. var t = {};
  53. for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p];
  54. if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
  55. if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]];
  56. }
  57. return t;
  58. };
  59. // CSSINJS
  60. const LIST_IGNORE = exports.LIST_IGNORE = `__LIST_IGNORE_${Date.now()}__`;
  61. var _default = exports.default = (0, _vue.defineComponent)({
  62. compatConfig: {
  63. MODE: 3
  64. },
  65. name: 'AUpload',
  66. inheritAttrs: false,
  67. props: (0, _propsUtil.initDefaultProps)((0, _interface.uploadProps)(), {
  68. type: 'select',
  69. multiple: false,
  70. action: '',
  71. data: {},
  72. accept: '',
  73. showUploadList: true,
  74. listType: 'text',
  75. supportServerRender: true
  76. }),
  77. setup(props, _ref) {
  78. let {
  79. slots,
  80. attrs,
  81. expose
  82. } = _ref;
  83. const formItemContext = (0, _form.useInjectFormItemContext)();
  84. const {
  85. prefixCls,
  86. direction,
  87. disabled
  88. } = (0, _useConfigInject.default)('upload', props);
  89. // style
  90. const [wrapSSR, hashId] = (0, _style.default)(prefixCls);
  91. const disabledContext = (0, _DisabledContext.useInjectDisabled)();
  92. const mergedDisabled = (0, _vue.computed)(() => {
  93. var _a;
  94. return (_a = disabled.value) !== null && _a !== void 0 ? _a : disabledContext.value;
  95. });
  96. const [mergedFileList, setMergedFileList] = (0, _useMergedState.default)(props.defaultFileList || [], {
  97. value: (0, _vue.toRef)(props, 'fileList'),
  98. postState: list => {
  99. const timestamp = Date.now();
  100. return (list !== null && list !== void 0 ? list : []).map((file, index) => {
  101. if (!file.uid && !Object.isFrozen(file)) {
  102. file.uid = `__AUTO__${timestamp}_${index}__`;
  103. }
  104. return file;
  105. });
  106. }
  107. });
  108. const dragState = (0, _vue.ref)('drop');
  109. const upload = (0, _vue.ref)(null);
  110. (0, _vue.onMounted)(() => {
  111. (0, _devWarning.default)(props.fileList !== undefined || attrs.value === undefined, 'Upload', '`value` is not a valid prop, do you mean `fileList`?');
  112. (0, _devWarning.default)(props.transformFile === undefined, 'Upload', '`transformFile` is deprecated. Please use `beforeUpload` directly.');
  113. (0, _devWarning.default)(props.remove === undefined, 'Upload', '`remove` props is deprecated. Please use `remove` event.');
  114. });
  115. const onInternalChange = (file, changedFileList, event) => {
  116. var _a, _b;
  117. let cloneList = [...changedFileList];
  118. // Cut to match count
  119. if (props.maxCount === 1) {
  120. cloneList = cloneList.slice(-1);
  121. } else if (props.maxCount) {
  122. cloneList = cloneList.slice(0, props.maxCount);
  123. }
  124. setMergedFileList(cloneList);
  125. const changeInfo = {
  126. file: file,
  127. fileList: cloneList
  128. };
  129. if (event) {
  130. changeInfo.event = event;
  131. }
  132. (_a = props['onUpdate:fileList']) === null || _a === void 0 ? void 0 : _a.call(props, changeInfo.fileList);
  133. (_b = props.onChange) === null || _b === void 0 ? void 0 : _b.call(props, changeInfo);
  134. formItemContext.onFieldChange();
  135. };
  136. const mergedBeforeUpload = (file, fileListArgs) => __awaiter(this, void 0, void 0, function* () {
  137. const {
  138. beforeUpload,
  139. transformFile
  140. } = props;
  141. let parsedFile = file;
  142. if (beforeUpload) {
  143. const result = yield beforeUpload(file, fileListArgs);
  144. if (result === false) {
  145. return false;
  146. }
  147. // Hack for LIST_IGNORE, we add additional info to remove from the list
  148. delete file[LIST_IGNORE];
  149. if (result === LIST_IGNORE) {
  150. Object.defineProperty(file, LIST_IGNORE, {
  151. value: true,
  152. configurable: true
  153. });
  154. return false;
  155. }
  156. if (typeof result === 'object' && result) {
  157. parsedFile = result;
  158. }
  159. }
  160. if (transformFile) {
  161. parsedFile = yield transformFile(parsedFile);
  162. }
  163. return parsedFile;
  164. });
  165. const onBatchStart = batchFileInfoList => {
  166. // Skip file which marked as `LIST_IGNORE`, these file will not add to file list
  167. const filteredFileInfoList = batchFileInfoList.filter(info => !info.file[LIST_IGNORE]);
  168. // Nothing to do since no file need upload
  169. if (!filteredFileInfoList.length) {
  170. return;
  171. }
  172. const objectFileList = filteredFileInfoList.map(info => (0, _utils.file2Obj)(info.file));
  173. // Concat new files with prev files
  174. let newFileList = [...mergedFileList.value];
  175. objectFileList.forEach(fileObj => {
  176. // Replace file if exist
  177. newFileList = (0, _utils.updateFileList)(fileObj, newFileList);
  178. });
  179. objectFileList.forEach((fileObj, index) => {
  180. // Repeat trigger `onChange` event for compatible
  181. let triggerFileObj = fileObj;
  182. if (!filteredFileInfoList[index].parsedFile) {
  183. // `beforeUpload` return false
  184. const {
  185. originFileObj
  186. } = fileObj;
  187. let clone;
  188. try {
  189. clone = new File([originFileObj], originFileObj.name, {
  190. type: originFileObj.type
  191. });
  192. } catch (e) {
  193. clone = new Blob([originFileObj], {
  194. type: originFileObj.type
  195. });
  196. clone.name = originFileObj.name;
  197. clone.lastModifiedDate = new Date();
  198. clone.lastModified = new Date().getTime();
  199. }
  200. clone.uid = fileObj.uid;
  201. triggerFileObj = clone;
  202. } else {
  203. // Inject `uploading` status
  204. fileObj.status = 'uploading';
  205. }
  206. onInternalChange(triggerFileObj, newFileList);
  207. });
  208. };
  209. const onSuccess = (response, file, xhr) => {
  210. try {
  211. if (typeof response === 'string') {
  212. response = JSON.parse(response);
  213. }
  214. } catch (e) {
  215. /* do nothing */
  216. }
  217. // removed
  218. if (!(0, _utils.getFileItem)(file, mergedFileList.value)) {
  219. return;
  220. }
  221. const targetItem = (0, _utils.file2Obj)(file);
  222. targetItem.status = 'done';
  223. targetItem.percent = 100;
  224. targetItem.response = response;
  225. targetItem.xhr = xhr;
  226. const nextFileList = (0, _utils.updateFileList)(targetItem, mergedFileList.value);
  227. onInternalChange(targetItem, nextFileList);
  228. };
  229. const onProgress = (e, file) => {
  230. // removed
  231. if (!(0, _utils.getFileItem)(file, mergedFileList.value)) {
  232. return;
  233. }
  234. const targetItem = (0, _utils.file2Obj)(file);
  235. targetItem.status = 'uploading';
  236. targetItem.percent = e.percent;
  237. const nextFileList = (0, _utils.updateFileList)(targetItem, mergedFileList.value);
  238. onInternalChange(targetItem, nextFileList, e);
  239. };
  240. const onError = (error, response, file) => {
  241. // removed
  242. if (!(0, _utils.getFileItem)(file, mergedFileList.value)) {
  243. return;
  244. }
  245. const targetItem = (0, _utils.file2Obj)(file);
  246. targetItem.error = error;
  247. targetItem.response = response;
  248. targetItem.status = 'error';
  249. const nextFileList = (0, _utils.updateFileList)(targetItem, mergedFileList.value);
  250. onInternalChange(targetItem, nextFileList);
  251. };
  252. const handleRemove = file => {
  253. let currentFile;
  254. const mergedRemove = props.onRemove || props.remove;
  255. Promise.resolve(typeof mergedRemove === 'function' ? mergedRemove(file) : mergedRemove).then(ret => {
  256. var _a, _b;
  257. // Prevent removing file
  258. if (ret === false) {
  259. return;
  260. }
  261. const removedFileList = (0, _utils.removeFileItem)(file, mergedFileList.value);
  262. if (removedFileList) {
  263. currentFile = (0, _extends2.default)((0, _extends2.default)({}, file), {
  264. status: 'removed'
  265. });
  266. (_a = mergedFileList.value) === null || _a === void 0 ? void 0 : _a.forEach(item => {
  267. const matchKey = currentFile.uid !== undefined ? 'uid' : 'name';
  268. if (item[matchKey] === currentFile[matchKey] && !Object.isFrozen(item)) {
  269. item.status = 'removed';
  270. }
  271. });
  272. (_b = upload.value) === null || _b === void 0 ? void 0 : _b.abort(currentFile);
  273. onInternalChange(currentFile, removedFileList);
  274. }
  275. });
  276. };
  277. const onFileDrop = e => {
  278. var _a;
  279. dragState.value = e.type;
  280. if (e.type === 'drop') {
  281. (_a = props.onDrop) === null || _a === void 0 ? void 0 : _a.call(props, e);
  282. }
  283. };
  284. expose({
  285. onBatchStart,
  286. onSuccess,
  287. onProgress,
  288. onError,
  289. fileList: mergedFileList,
  290. upload
  291. });
  292. const [locale] = (0, _LocaleReceiver.useLocaleReceiver)('Upload', _en_US.default.Upload, (0, _vue.computed)(() => props.locale));
  293. const renderUploadList = (button, buttonVisible) => {
  294. const {
  295. removeIcon,
  296. previewIcon,
  297. downloadIcon,
  298. previewFile,
  299. onPreview,
  300. onDownload,
  301. isImageUrl,
  302. progress,
  303. itemRender,
  304. iconRender,
  305. showUploadList
  306. } = props;
  307. const {
  308. showDownloadIcon,
  309. showPreviewIcon,
  310. showRemoveIcon
  311. } = typeof showUploadList === 'boolean' ? {} : showUploadList;
  312. return showUploadList ? (0, _vue.createVNode)(_UploadList.default, {
  313. "prefixCls": prefixCls.value,
  314. "listType": props.listType,
  315. "items": mergedFileList.value,
  316. "previewFile": previewFile,
  317. "onPreview": onPreview,
  318. "onDownload": onDownload,
  319. "onRemove": handleRemove,
  320. "showRemoveIcon": !mergedDisabled.value && showRemoveIcon,
  321. "showPreviewIcon": showPreviewIcon,
  322. "showDownloadIcon": showDownloadIcon,
  323. "removeIcon": removeIcon,
  324. "previewIcon": previewIcon,
  325. "downloadIcon": downloadIcon,
  326. "iconRender": iconRender,
  327. "locale": locale.value,
  328. "isImageUrl": isImageUrl,
  329. "progress": progress,
  330. "itemRender": itemRender,
  331. "appendActionVisible": buttonVisible,
  332. "appendAction": button
  333. }, (0, _extends2.default)({}, slots)) : button === null || button === void 0 ? void 0 : button();
  334. };
  335. return () => {
  336. var _a, _b, _c;
  337. const {
  338. listType,
  339. type
  340. } = props;
  341. const {
  342. class: className,
  343. style: styleName
  344. } = attrs,
  345. transAttrs = __rest(attrs, ["class", "style"]);
  346. const rcUploadProps = (0, _extends2.default)((0, _extends2.default)((0, _extends2.default)({
  347. onBatchStart,
  348. onError,
  349. onProgress,
  350. onSuccess
  351. }, transAttrs), props), {
  352. id: (_a = props.id) !== null && _a !== void 0 ? _a : formItemContext.id.value,
  353. prefixCls: prefixCls.value,
  354. beforeUpload: mergedBeforeUpload,
  355. onChange: undefined,
  356. disabled: mergedDisabled.value
  357. });
  358. delete rcUploadProps.remove;
  359. // Remove id to avoid open by label when trigger is hidden
  360. // !children: https://github.com/ant-design/ant-design/issues/14298
  361. // disabled: https://github.com/ant-design/ant-design/issues/16478
  362. // https://github.com/ant-design/ant-design/issues/24197
  363. if (!slots.default || mergedDisabled.value) {
  364. delete rcUploadProps.id;
  365. }
  366. const rtlCls = {
  367. [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
  368. };
  369. if (type === 'drag') {
  370. const dragCls = (0, _classNames.default)(prefixCls.value, {
  371. [`${prefixCls.value}-drag`]: true,
  372. [`${prefixCls.value}-drag-uploading`]: mergedFileList.value.some(file => file.status === 'uploading'),
  373. [`${prefixCls.value}-drag-hover`]: dragState.value === 'dragover',
  374. [`${prefixCls.value}-disabled`]: mergedDisabled.value,
  375. [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
  376. }, attrs.class, hashId.value);
  377. return wrapSSR((0, _vue.createVNode)("span", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
  378. "class": (0, _classNames.default)(`${prefixCls.value}-wrapper`, rtlCls, className, hashId.value)
  379. }), [(0, _vue.createVNode)("div", {
  380. "class": dragCls,
  381. "onDrop": onFileDrop,
  382. "onDragover": onFileDrop,
  383. "onDragleave": onFileDrop,
  384. "style": attrs.style
  385. }, [(0, _vue.createVNode)(_vcUpload.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, rcUploadProps), {}, {
  386. "ref": upload,
  387. "class": `${prefixCls.value}-btn`
  388. }), (0, _objectSpread2.default)({
  389. default: () => [(0, _vue.createVNode)("div", {
  390. "class": `${prefixCls.value}-drag-container`
  391. }, [(_b = slots.default) === null || _b === void 0 ? void 0 : _b.call(slots)])]
  392. }, slots))]), renderUploadList()]));
  393. }
  394. const uploadButtonCls = (0, _classNames.default)(prefixCls.value, {
  395. [`${prefixCls.value}-select`]: true,
  396. [`${prefixCls.value}-select-${listType}`]: true,
  397. [`${prefixCls.value}-disabled`]: mergedDisabled.value,
  398. [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
  399. });
  400. const children = (0, _propsUtil.flattenChildren)((_c = slots.default) === null || _c === void 0 ? void 0 : _c.call(slots));
  401. const renderUploadButton = uploadButtonStyle => (0, _vue.createVNode)("div", {
  402. "class": uploadButtonCls,
  403. "style": uploadButtonStyle
  404. }, [(0, _vue.createVNode)(_vcUpload.default, (0, _objectSpread2.default)((0, _objectSpread2.default)({}, rcUploadProps), {}, {
  405. "ref": upload
  406. }), slots)]);
  407. if (listType === 'picture-card') {
  408. return wrapSSR((0, _vue.createVNode)("span", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
  409. "class": (0, _classNames.default)(`${prefixCls.value}-wrapper`, `${prefixCls.value}-picture-card-wrapper`, rtlCls, attrs.class, hashId.value)
  410. }), [renderUploadList(renderUploadButton, !!(children && children.length))]));
  411. }
  412. return wrapSSR((0, _vue.createVNode)("span", (0, _objectSpread2.default)((0, _objectSpread2.default)({}, attrs), {}, {
  413. "class": (0, _classNames.default)(`${prefixCls.value}-wrapper`, rtlCls, attrs.class, hashId.value)
  414. }), [renderUploadButton(children && children.length ? undefined : {
  415. display: 'none'
  416. }), renderUploadList()]));
  417. };
  418. }
  419. });