ng-zorro-antd-upload.mjs 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. import { ENTER } from '@angular/cdk/keycodes';
  2. import { HttpRequest, HttpHeaders, HttpEventType, HttpResponse, HttpClient } from '@angular/common/http';
  3. import * as i0 from '@angular/core';
  4. import { inject, Input, ViewChild, ViewEncapsulation, Component, ChangeDetectionStrategy, EventEmitter, booleanAttribute, numberAttribute, Output, NgModule } from '@angular/core';
  5. import { Subject, of, Observable, Subscription, fromEvent } from 'rxjs';
  6. import { switchMap, map, tap, takeUntil, filter } from 'rxjs/operators';
  7. import { warn } from 'ng-zorro-antd/core/logger';
  8. import { fromEventOutsideAngular, toBoolean } from 'ng-zorro-antd/core/util';
  9. import { trigger, transition, style, animate } from '@angular/animations';
  10. import { DOCUMENT, NgTemplateOutlet } from '@angular/common';
  11. import * as i4 from 'ng-zorro-antd/button';
  12. import { NzButtonModule } from 'ng-zorro-antd/button';
  13. import * as i3 from 'ng-zorro-antd/icon';
  14. import { NzIconModule } from 'ng-zorro-antd/icon';
  15. import * as i6 from 'ng-zorro-antd/progress';
  16. import { NzProgressModule } from 'ng-zorro-antd/progress';
  17. import * as i2 from 'ng-zorro-antd/tooltip';
  18. import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
  19. import * as i1 from '@angular/cdk/platform';
  20. import { Platform } from '@angular/cdk/platform';
  21. import * as i5 from 'ng-zorro-antd/core/transition-patch';
  22. import * as i1$1 from 'ng-zorro-antd/i18n';
  23. import * as i2$1 from '@angular/cdk/bidi';
  24. /**
  25. * Use of this source code is governed by an MIT-style license that can be
  26. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  27. */
  28. /**
  29. * Use of this source code is governed by an MIT-style license that can be
  30. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  31. */
  32. class NzUploadBtnComponent {
  33. elementRef;
  34. reqs = {};
  35. destroy = false;
  36. destroy$ = new Subject();
  37. file;
  38. options;
  39. onClick() {
  40. if (this.options.disabled || !this.options.openFileDialogOnClick) {
  41. return;
  42. }
  43. this.file.nativeElement.click();
  44. }
  45. // skip safari bug
  46. onFileDrop(e) {
  47. if (this.options.disabled || e.type === 'dragover') {
  48. e.preventDefault();
  49. return;
  50. }
  51. if (this.options.directory) {
  52. this.traverseFileTree(e.dataTransfer.items);
  53. }
  54. else {
  55. const files = Array.prototype.slice
  56. .call(e.dataTransfer.files)
  57. .filter((file) => this.attrAccept(file, this.options.accept));
  58. if (files.length) {
  59. this.uploadFiles(files);
  60. }
  61. }
  62. e.preventDefault();
  63. }
  64. onChange(e) {
  65. if (this.options.disabled) {
  66. return;
  67. }
  68. const hie = e.target;
  69. this.uploadFiles(hie.files);
  70. hie.value = '';
  71. }
  72. traverseFileTree(files) {
  73. const _traverseFileTree = (item, path) => {
  74. if (item.isFile) {
  75. item.file((file) => {
  76. if (this.attrAccept(file, this.options.accept)) {
  77. this.uploadFiles([file]);
  78. }
  79. });
  80. }
  81. else if (item.isDirectory) {
  82. const dirReader = item.createReader();
  83. dirReader.readEntries((entries) => {
  84. for (const entrieItem of entries) {
  85. _traverseFileTree(entrieItem, `${path}${item.name}/`);
  86. }
  87. });
  88. }
  89. };
  90. for (const file of files) {
  91. _traverseFileTree(file.webkitGetAsEntry(), '');
  92. }
  93. }
  94. attrAccept(file, acceptedFiles) {
  95. if (file && acceptedFiles) {
  96. const acceptedFilesArray = Array.isArray(acceptedFiles) ? acceptedFiles : acceptedFiles.split(',');
  97. const fileName = `${file.name}`;
  98. const mimeType = `${file.type}`;
  99. const baseMimeType = mimeType.replace(/\/.*$/, '');
  100. return acceptedFilesArray.some(type => {
  101. const validType = type.trim();
  102. if (validType.charAt(0) === '.') {
  103. return (fileName
  104. .toLowerCase()
  105. .indexOf(validType.toLowerCase(), fileName.toLowerCase().length - validType.toLowerCase().length) !== -1);
  106. }
  107. else if (/\/\*$/.test(validType)) {
  108. // This is something like an image/* mime type
  109. return baseMimeType === validType.replace(/\/.*$/, '');
  110. }
  111. return mimeType === validType;
  112. });
  113. }
  114. return true;
  115. }
  116. attachUid(file) {
  117. if (!file.uid) {
  118. file.uid = Math.random().toString(36).substring(2);
  119. }
  120. return file;
  121. }
  122. uploadFiles(fileList) {
  123. let filters$ = of(Array.prototype.slice.call(fileList));
  124. if (this.options.filters) {
  125. this.options.filters.forEach(f => {
  126. filters$ = filters$.pipe(switchMap(list => {
  127. const fnRes = f.fn(list);
  128. return fnRes instanceof Observable ? fnRes : of(fnRes);
  129. }));
  130. });
  131. }
  132. filters$.subscribe({
  133. next: list => {
  134. list.forEach((file) => {
  135. this.attachUid(file);
  136. this.upload(file, list);
  137. });
  138. },
  139. error: e => {
  140. warn(`Unhandled upload filter error`, e);
  141. }
  142. });
  143. }
  144. upload(file, fileList) {
  145. if (!this.options.beforeUpload) {
  146. return this.post(file);
  147. }
  148. const before = this.options.beforeUpload(file, fileList);
  149. if (before instanceof Observable) {
  150. before.subscribe({
  151. next: (processedFile) => {
  152. const processedFileType = Object.prototype.toString.call(processedFile);
  153. if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
  154. this.attachUid(processedFile);
  155. this.post(processedFile);
  156. }
  157. else if (processedFile) {
  158. this.post(file);
  159. }
  160. },
  161. error: e => {
  162. warn(`Unhandled upload beforeUpload error`, e);
  163. }
  164. });
  165. }
  166. else if (before) {
  167. return this.post(file);
  168. }
  169. }
  170. post(file) {
  171. if (this.destroy) {
  172. return;
  173. }
  174. let process$ = of(file);
  175. let transformedFile;
  176. const opt = this.options;
  177. const { uid } = file;
  178. const { action, data, headers, transformFile } = opt;
  179. const args = {
  180. action: typeof action === 'string' ? action : '',
  181. name: opt.name,
  182. headers,
  183. file,
  184. postFile: file,
  185. data,
  186. withCredentials: opt.withCredentials,
  187. onProgress: opt.onProgress
  188. ? e => {
  189. opt.onProgress(e, file);
  190. }
  191. : undefined,
  192. onSuccess: (ret, xhr) => {
  193. this.clean(uid);
  194. opt.onSuccess(ret, file, xhr);
  195. },
  196. onError: xhr => {
  197. this.clean(uid);
  198. opt.onError(xhr, file);
  199. }
  200. };
  201. if (typeof action === 'function') {
  202. const actionResult = action(file);
  203. if (actionResult instanceof Observable) {
  204. process$ = process$.pipe(switchMap(() => actionResult), map(res => {
  205. args.action = res;
  206. return file;
  207. }));
  208. }
  209. else {
  210. args.action = actionResult;
  211. }
  212. }
  213. if (typeof transformFile === 'function') {
  214. const transformResult = transformFile(file);
  215. process$ = process$.pipe(switchMap(() => (transformResult instanceof Observable ? transformResult : of(transformResult))), tap(newFile => (transformedFile = newFile)));
  216. }
  217. if (typeof data === 'function') {
  218. const dataResult = data(file);
  219. if (dataResult instanceof Observable) {
  220. process$ = process$.pipe(switchMap(() => dataResult), map(res => {
  221. args.data = res;
  222. return transformedFile ?? file;
  223. }));
  224. }
  225. else {
  226. args.data = dataResult;
  227. }
  228. }
  229. if (typeof headers === 'function') {
  230. const headersResult = headers(file);
  231. if (headersResult instanceof Observable) {
  232. process$ = process$.pipe(switchMap(() => headersResult), map(res => {
  233. args.headers = res;
  234. return transformedFile ?? file;
  235. }));
  236. }
  237. else {
  238. args.headers = headersResult;
  239. }
  240. }
  241. process$.subscribe(newFile => {
  242. args.postFile = newFile;
  243. const req$ = (opt.customRequest || this.xhr).call(this, args);
  244. if (!(req$ instanceof Subscription)) {
  245. warn(`Must return Subscription type in '[nzCustomRequest]' property`);
  246. }
  247. this.reqs[uid] = req$;
  248. opt.onStart(file);
  249. });
  250. }
  251. xhr(args) {
  252. const formData = new FormData();
  253. if (args.data) {
  254. Object.keys(args.data).map(key => {
  255. formData.append(key, args.data[key]);
  256. });
  257. }
  258. formData.append(args.name, args.postFile);
  259. if (!args.headers) {
  260. args.headers = {};
  261. }
  262. if (args.headers['X-Requested-With'] !== null) {
  263. args.headers['X-Requested-With'] = `XMLHttpRequest`;
  264. }
  265. else {
  266. delete args.headers['X-Requested-With'];
  267. }
  268. const req = new HttpRequest('POST', args.action, formData, {
  269. reportProgress: true,
  270. withCredentials: args.withCredentials,
  271. headers: new HttpHeaders(args.headers)
  272. });
  273. return this.http.request(req).subscribe({
  274. next: (event) => {
  275. if (event.type === HttpEventType.UploadProgress) {
  276. if (event.total > 0) {
  277. event.percent = (event.loaded / event.total) * 100;
  278. }
  279. args.onProgress(event, args.file);
  280. }
  281. else if (event instanceof HttpResponse) {
  282. args.onSuccess(event.body, args.file, event);
  283. }
  284. },
  285. error: err => {
  286. this.abort(args.file);
  287. args.onError(err, args.file);
  288. }
  289. });
  290. }
  291. clean(uid) {
  292. const req$ = this.reqs[uid];
  293. if (req$ instanceof Subscription) {
  294. req$.unsubscribe();
  295. }
  296. delete this.reqs[uid];
  297. }
  298. abort(file) {
  299. if (file) {
  300. this.clean(file && file.uid);
  301. }
  302. else {
  303. Object.keys(this.reqs).forEach(uid => this.clean(uid));
  304. }
  305. }
  306. http = inject(HttpClient, { optional: true });
  307. constructor(elementRef) {
  308. this.elementRef = elementRef;
  309. if (!this.http) {
  310. throw new Error(`Not found 'HttpClient', You can configure 'HttpClient' with 'provideHttpClient()' in your root module.`);
  311. }
  312. }
  313. ngOnInit() {
  314. // Caretaker note: `input[type=file].click()` will open a native OS file picker,
  315. // it doesn't require Angular to run `ApplicationRef.tick()`.
  316. fromEventOutsideAngular(this.elementRef.nativeElement, 'click')
  317. .pipe(takeUntil(this.destroy$))
  318. .subscribe(() => this.onClick());
  319. fromEventOutsideAngular(this.elementRef.nativeElement, 'keydown')
  320. .pipe(takeUntil(this.destroy$))
  321. .subscribe(event => {
  322. if (this.options.disabled) {
  323. return;
  324. }
  325. if (event.key === 'Enter' || event.keyCode === ENTER) {
  326. this.onClick();
  327. }
  328. });
  329. }
  330. ngOnDestroy() {
  331. this.destroy = true;
  332. this.destroy$.next();
  333. this.abort();
  334. }
  335. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadBtnComponent, deps: [{ token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
  336. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.2", type: NzUploadBtnComponent, isStandalone: true, selector: "[nz-upload-btn]", inputs: { options: "options" }, host: { listeners: { "drop": "onFileDrop($event)", "dragover": "onFileDrop($event)" }, properties: { "attr.tabindex": "\"0\"", "attr.role": "\"button\"", "class.ant-upload-disabled": "options.disabled" }, classAttribute: "ant-upload" }, viewQueries: [{ propertyName: "file", first: true, predicate: ["file"], descendants: true, static: true }], exportAs: ["nzUploadBtn"], ngImport: i0, template: "<!--\n We explicitly bind `style.display` to avoid using an inline style\n attribute property (which is not allowed when CSP `unsafe-inline`\n is not specified).\n-->\n<input\n type=\"file\"\n #file\n (change)=\"onChange($event)\"\n [attr.accept]=\"options.accept\"\n [attr.directory]=\"options.directory ? 'directory' : null\"\n [attr.webkitdirectory]=\"options.directory ? 'webkitdirectory' : null\"\n [multiple]=\"options.multiple\"\n [style.display]=\"'none'\"\n/>\n<ng-content></ng-content>\n", encapsulation: i0.ViewEncapsulation.None });
  337. }
  338. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadBtnComponent, decorators: [{
  339. type: Component,
  340. args: [{ selector: '[nz-upload-btn]', exportAs: 'nzUploadBtn', host: {
  341. class: 'ant-upload',
  342. '[attr.tabindex]': '"0"',
  343. '[attr.role]': '"button"',
  344. '[class.ant-upload-disabled]': 'options.disabled',
  345. '(drop)': 'onFileDrop($event)',
  346. '(dragover)': 'onFileDrop($event)'
  347. }, preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, template: "<!--\n We explicitly bind `style.display` to avoid using an inline style\n attribute property (which is not allowed when CSP `unsafe-inline`\n is not specified).\n-->\n<input\n type=\"file\"\n #file\n (change)=\"onChange($event)\"\n [attr.accept]=\"options.accept\"\n [attr.directory]=\"options.directory ? 'directory' : null\"\n [attr.webkitdirectory]=\"options.directory ? 'webkitdirectory' : null\"\n [multiple]=\"options.multiple\"\n [style.display]=\"'none'\"\n/>\n<ng-content></ng-content>\n" }]
  348. }], ctorParameters: () => [{ type: i0.ElementRef }], propDecorators: { file: [{
  349. type: ViewChild,
  350. args: ['file', { static: true }]
  351. }], options: [{
  352. type: Input
  353. }] } });
  354. /**
  355. * Use of this source code is governed by an MIT-style license that can be
  356. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  357. */
  358. const isImageFileType = (type) => !!type && type.indexOf('image/') === 0;
  359. const MEASURE_SIZE = 200;
  360. class NzUploadListComponent {
  361. cdr;
  362. ngZone;
  363. platform;
  364. list = [];
  365. get showPic() {
  366. return this.listType === 'picture' || this.listType === 'picture-card';
  367. }
  368. locale = {};
  369. listType;
  370. set items(list) {
  371. this.list = list;
  372. }
  373. icons;
  374. onPreview;
  375. onRemove;
  376. onDownload;
  377. previewFile;
  378. previewIsImage;
  379. iconRender = null;
  380. dir = 'ltr';
  381. document = inject(DOCUMENT);
  382. destroy$ = new Subject();
  383. genErr(file) {
  384. if (file.response && typeof file.response === 'string') {
  385. return file.response;
  386. }
  387. return (file.error && file.error.statusText) || this.locale.uploadError;
  388. }
  389. extname(url) {
  390. const temp = url.split('/');
  391. const filename = temp[temp.length - 1];
  392. const filenameWithoutSuffix = filename.split(/#|\?/)[0];
  393. return (/\.[^./\\]*$/.exec(filenameWithoutSuffix) || [''])[0];
  394. }
  395. isImageUrl(file) {
  396. if (isImageFileType(file.type)) {
  397. return true;
  398. }
  399. const url = (file.thumbUrl || file.url || '');
  400. if (!url) {
  401. return false;
  402. }
  403. const extension = this.extname(url);
  404. if (/^data:image\//.test(url) || /(webp|svg|png|gif|jpg|jpeg|jfif|bmp|dpg)$/i.test(extension)) {
  405. return true;
  406. }
  407. else if (/^data:/.test(url)) {
  408. // other file types of base64
  409. return false;
  410. }
  411. else if (extension) {
  412. // other file types which have extension
  413. return false;
  414. }
  415. return true;
  416. }
  417. getIconType(file) {
  418. if (!this.showPic) {
  419. return '';
  420. }
  421. if (file.isUploading || (!file.thumbUrl && !file.url)) {
  422. return 'uploading';
  423. }
  424. else {
  425. return 'thumbnail';
  426. }
  427. }
  428. previewImage(file) {
  429. if (!isImageFileType(file.type) || !this.platform.isBrowser) {
  430. return of('');
  431. }
  432. const canvas = this.document.createElement('canvas');
  433. canvas.width = MEASURE_SIZE;
  434. canvas.height = MEASURE_SIZE;
  435. canvas.style.cssText = `position: fixed; left: 0; top: 0; width: ${MEASURE_SIZE}px; height: ${MEASURE_SIZE}px; z-index: 9999; display: none;`;
  436. this.document.body.appendChild(canvas);
  437. const ctx = canvas.getContext('2d');
  438. const img = new Image();
  439. const objectUrl = URL.createObjectURL(file);
  440. img.src = objectUrl;
  441. return fromEvent(img, 'load').pipe(map(() => {
  442. const { width, height } = img;
  443. let drawWidth = MEASURE_SIZE;
  444. let drawHeight = MEASURE_SIZE;
  445. let offsetX = 0;
  446. let offsetY = 0;
  447. if (width < height) {
  448. drawHeight = height * (MEASURE_SIZE / width);
  449. offsetY = -(drawHeight - drawWidth) / 2;
  450. }
  451. else {
  452. drawWidth = width * (MEASURE_SIZE / height);
  453. offsetX = -(drawWidth - drawHeight) / 2;
  454. }
  455. try {
  456. ctx.drawImage(img, offsetX, offsetY, drawWidth, drawHeight);
  457. }
  458. catch {
  459. // noop
  460. }
  461. const dataURL = canvas.toDataURL();
  462. this.document.body.removeChild(canvas);
  463. URL.revokeObjectURL(objectUrl);
  464. return dataURL;
  465. }));
  466. }
  467. genThumb() {
  468. if (!this.platform.isBrowser) {
  469. return;
  470. }
  471. const win = window;
  472. if (!this.showPic ||
  473. typeof document === 'undefined' ||
  474. typeof win === 'undefined' ||
  475. !win.FileReader ||
  476. !win.File) {
  477. return;
  478. }
  479. this.list
  480. .filter(file => file.originFileObj instanceof File && file.thumbUrl === undefined)
  481. .forEach(file => {
  482. file.thumbUrl = '';
  483. // Caretaker note: we shouldn't use promises here since they're not cancellable.
  484. // A promise microtask can be resolved after the view is destroyed. Thus running `detectChanges()`
  485. // will cause a runtime exception (`detectChanges()` cannot be run on destroyed views).
  486. const dataUrl$ = (this.previewFile ? this.previewFile(file) : this.previewImage(file.originFileObj)).pipe(takeUntil(this.destroy$));
  487. this.ngZone.runOutsideAngular(() => {
  488. dataUrl$.subscribe(dataUrl => {
  489. this.ngZone.run(() => {
  490. file.thumbUrl = dataUrl;
  491. this.detectChanges();
  492. });
  493. });
  494. });
  495. });
  496. }
  497. showDownload(file) {
  498. return !!(this.icons.showDownloadIcon && file.status === 'done');
  499. }
  500. fixData() {
  501. this.list.forEach(file => {
  502. file.isUploading = file.status === 'uploading';
  503. file.message = this.genErr(file);
  504. file.linkProps = typeof file.linkProps === 'string' ? JSON.parse(file.linkProps) : file.linkProps;
  505. file.isImageUrl = this.previewIsImage ? this.previewIsImage(file) : this.isImageUrl(file);
  506. file.iconType = this.getIconType(file);
  507. file.showDownload = this.showDownload(file);
  508. });
  509. }
  510. handlePreview(file, e) {
  511. if (!this.onPreview) {
  512. return;
  513. }
  514. e.preventDefault();
  515. return this.onPreview(file);
  516. }
  517. handleRemove(file, e) {
  518. e.preventDefault();
  519. if (this.onRemove) {
  520. this.onRemove(file);
  521. }
  522. return;
  523. }
  524. handleDownload(file) {
  525. if (typeof this.onDownload === 'function') {
  526. this.onDownload(file);
  527. }
  528. else if (file.url) {
  529. window.open(file.url);
  530. }
  531. }
  532. // #endregion
  533. constructor(cdr, ngZone, platform) {
  534. this.cdr = cdr;
  535. this.ngZone = ngZone;
  536. this.platform = platform;
  537. }
  538. detectChanges() {
  539. this.fixData();
  540. this.cdr.detectChanges();
  541. }
  542. ngOnChanges() {
  543. this.fixData();
  544. this.genThumb();
  545. }
  546. ngOnDestroy() {
  547. this.destroy$.next();
  548. }
  549. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadListComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i1.Platform }], target: i0.ɵɵFactoryTarget.Component });
  550. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: NzUploadListComponent, isStandalone: true, selector: "nz-upload-list", inputs: { locale: "locale", listType: "listType", items: "items", icons: "icons", onPreview: "onPreview", onRemove: "onRemove", onDownload: "onDownload", previewFile: "previewFile", previewIsImage: "previewIsImage", iconRender: "iconRender", dir: "dir" }, host: { properties: { "class.ant-upload-list-rtl": "dir === 'rtl'", "class.ant-upload-list-text": "listType === 'text'", "class.ant-upload-list-picture": "listType === 'picture'", "class.ant-upload-list-picture-card": "listType === 'picture-card'" }, classAttribute: "ant-upload-list" }, exportAs: ["nzUploadList"], usesOnChanges: true, ngImport: i0, template: "@for (file of list; track file) {\n <div class=\"ant-upload-list-{{ listType }}-container\">\n <div\n class=\"ant-upload-list-item ant-upload-list-item-{{ file.status }} ant-upload-list-item-list-type-{{ listType }}\"\n [attr.data-key]=\"file.key\"\n @itemState\n nz-tooltip\n [nzTooltipTitle]=\"file.status === 'error' ? file.message : null\"\n >\n <ng-template #icon>\n @switch (file.iconType) {\n @case ('uploading') {\n <div class=\"ant-upload-list-item-thumbnail\" [class.ant-upload-list-item-file]=\"!file.isUploading\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n @case ('thumbnail') {\n <a\n class=\"ant-upload-list-item-thumbnail\"\n [class.ant-upload-list-item-file]=\"!file.isImageUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [href]=\"file.url || file.thumbUrl\"\n (click)=\"handlePreview(file, $event)\"\n >\n @if (file.isImageUrl) {\n <img class=\"ant-upload-list-item-image\" [src]=\"file.thumbUrl || file.url\" [attr.alt]=\"file.name\" />\n } @else {\n <ng-template\n [ngTemplateOutlet]=\"iconNode\"\n [ngTemplateOutletContext]=\"{ $implicit: file }\"\n ></ng-template>\n }\n </a>\n }\n @default {\n <div class=\"ant-upload-text-icon\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #iconNode let-file>\n @if (!iconRender) {\n @switch (listType) {\n @case ('picture') {\n @if (file.isUploading) {\n <nz-icon nzType=\"loading\" />\n } @else {\n <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n }\n }\n @case ('picture-card') {\n @if (file.isUploading) {\n {{ locale.uploading }}\n } @else {\n <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n }\n }\n @default {\n <nz-icon [nzType]=\"file.isUploading ? 'loading' : 'paper-clip'\" />\n }\n }\n } @else {\n <ng-template [ngTemplateOutlet]=\"iconRender\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n }\n </ng-template>\n\n <ng-template #removeIcon>\n @if (icons.showRemoveIcon) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleRemove(file, $event)\"\n [attr.title]=\"locale.removeFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <nz-icon nzType=\"delete\" />\n </button>\n }\n </ng-template>\n\n <ng-template #downloadIcon>\n @if (file.showDownload) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleDownload(file)\"\n [attr.title]=\"locale.downloadFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <nz-icon nzType=\"download\" />\n </button>\n }\n </ng-template>\n\n <ng-template #downloadOrDelete>\n @if (listType !== 'picture-card') {\n <span class=\"ant-upload-list-item-card-actions {{ listType === 'picture' ? 'picture' : '' }}\">\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n </ng-template>\n\n <ng-template #preview>\n @if (file.url) {\n <a\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ant-upload-list-item-name\"\n [attr.title]=\"file.name\"\n [href]=\"file.url\"\n [attr.download]=\"file.linkProps && file.linkProps.download\"\n (click)=\"handlePreview(file, $event)\"\n >\n {{ file.name }}\n </a>\n } @else {\n <span class=\"ant-upload-list-item-name\" [attr.title]=\"file.name\" (click)=\"handlePreview(file, $event)\">\n {{ file.name }}\n </span>\n }\n <ng-template [ngTemplateOutlet]=\"downloadOrDelete\"></ng-template>\n </ng-template>\n\n <div class=\"ant-upload-list-item-info\">\n <span class=\"ant-upload-span\">\n <ng-template [ngTemplateOutlet]=\"icon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"preview\"></ng-template>\n </span>\n </div>\n @if (listType === 'picture-card' && !file.isUploading) {\n <span class=\"ant-upload-list-item-actions\">\n @if (icons.showPreviewIcon) {\n <a\n [href]=\"file.url || file.thumbUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.title]=\"locale.previewFile\"\n [style]=\"!(file.url || file.thumbUrl) ? { opacity: 0.5, 'pointer-events': 'none' } : null\"\n (click)=\"handlePreview(file, $event)\"\n >\n <nz-icon nzType=\"eye\" />\n </a>\n }\n @if (file.status === 'done') {\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n }\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n @if (file.isUploading) {\n <div class=\"ant-upload-list-item-progress\">\n <nz-progress [nzPercent]=\"file.percent!\" nzType=\"line\" [nzShowInfo]=\"false\" [nzStrokeWidth]=\"2\"></nz-progress>\n </div>\n }\n </div>\n </div>\n}\n", dependencies: [{ kind: "ngmodule", type: NzToolTipModule }, { kind: "directive", type: i2.NzTooltipDirective, selector: "[nz-tooltip]", inputs: ["nzTooltipTitle", "nzTooltipTitleContext", "nz-tooltip", "nzTooltipTrigger", "nzTooltipPlacement", "nzTooltipOrigin", "nzTooltipVisible", "nzTooltipMouseEnterDelay", "nzTooltipMouseLeaveDelay", "nzTooltipOverlayClassName", "nzTooltipOverlayStyle", "nzTooltipArrowPointAtCenter", "cdkConnectedOverlayPush", "nzTooltipColor"], outputs: ["nzTooltipVisibleChange"], exportAs: ["nzTooltip"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: NzIconModule }, { kind: "directive", type: i3.NzIconDirective, selector: "nz-icon,[nz-icon]", inputs: ["nzSpin", "nzRotate", "nzType", "nzTheme", "nzTwotoneColor", "nzIconfont"], exportAs: ["nzIcon"] }, { kind: "ngmodule", type: NzButtonModule }, { kind: "component", type: i4.NzButtonComponent, selector: "button[nz-button], a[nz-button]", inputs: ["nzBlock", "nzGhost", "nzSearch", "nzLoading", "nzDanger", "disabled", "tabIndex", "nzType", "nzShape", "nzSize"], exportAs: ["nzButton"] }, { kind: "directive", type: i5.ɵNzTransitionPatchDirective, selector: "[nz-button], nz-button-group, [nz-icon], nz-icon, [nz-menu-item], [nz-submenu], nz-select-top-control, nz-select-placeholder, nz-input-group", inputs: ["hidden"] }, { kind: "ngmodule", type: NzProgressModule }, { kind: "component", type: i6.NzProgressComponent, selector: "nz-progress", inputs: ["nzShowInfo", "nzWidth", "nzStrokeColor", "nzSize", "nzFormat", "nzSuccessPercent", "nzPercent", "nzStrokeWidth", "nzGapDegree", "nzStatus", "nzType", "nzGapPosition", "nzStrokeLinecap", "nzSteps"], exportAs: ["nzProgress"] }], animations: [
  551. trigger('itemState', [
  552. transition(':enter', [
  553. style({ height: '0', width: '0', opacity: 0 }),
  554. animate(150, style({ height: '*', width: '*', opacity: 1 }))
  555. ]),
  556. transition(':leave', [animate(150, style({ height: '0', width: '0', opacity: 0 }))])
  557. ])
  558. ], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  559. }
  560. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadListComponent, decorators: [{
  561. type: Component,
  562. args: [{ selector: 'nz-upload-list', exportAs: 'nzUploadList', animations: [
  563. trigger('itemState', [
  564. transition(':enter', [
  565. style({ height: '0', width: '0', opacity: 0 }),
  566. animate(150, style({ height: '*', width: '*', opacity: 1 }))
  567. ]),
  568. transition(':leave', [animate(150, style({ height: '0', width: '0', opacity: 0 }))])
  569. ])
  570. ], host: {
  571. class: 'ant-upload-list',
  572. '[class.ant-upload-list-rtl]': `dir === 'rtl'`,
  573. '[class.ant-upload-list-text]': `listType === 'text'`,
  574. '[class.ant-upload-list-picture]': `listType === 'picture'`,
  575. '[class.ant-upload-list-picture-card]': `listType === 'picture-card'`
  576. }, preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NzToolTipModule, NgTemplateOutlet, NzIconModule, NzButtonModule, NzProgressModule], template: "@for (file of list; track file) {\n <div class=\"ant-upload-list-{{ listType }}-container\">\n <div\n class=\"ant-upload-list-item ant-upload-list-item-{{ file.status }} ant-upload-list-item-list-type-{{ listType }}\"\n [attr.data-key]=\"file.key\"\n @itemState\n nz-tooltip\n [nzTooltipTitle]=\"file.status === 'error' ? file.message : null\"\n >\n <ng-template #icon>\n @switch (file.iconType) {\n @case ('uploading') {\n <div class=\"ant-upload-list-item-thumbnail\" [class.ant-upload-list-item-file]=\"!file.isUploading\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n @case ('thumbnail') {\n <a\n class=\"ant-upload-list-item-thumbnail\"\n [class.ant-upload-list-item-file]=\"!file.isImageUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [href]=\"file.url || file.thumbUrl\"\n (click)=\"handlePreview(file, $event)\"\n >\n @if (file.isImageUrl) {\n <img class=\"ant-upload-list-item-image\" [src]=\"file.thumbUrl || file.url\" [attr.alt]=\"file.name\" />\n } @else {\n <ng-template\n [ngTemplateOutlet]=\"iconNode\"\n [ngTemplateOutletContext]=\"{ $implicit: file }\"\n ></ng-template>\n }\n </a>\n }\n @default {\n <div class=\"ant-upload-text-icon\">\n <ng-template [ngTemplateOutlet]=\"iconNode\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n </div>\n }\n }\n </ng-template>\n\n <ng-template #iconNode let-file>\n @if (!iconRender) {\n @switch (listType) {\n @case ('picture') {\n @if (file.isUploading) {\n <nz-icon nzType=\"loading\" />\n } @else {\n <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n }\n }\n @case ('picture-card') {\n @if (file.isUploading) {\n {{ locale.uploading }}\n } @else {\n <nz-icon [nzType]=\"file.isImageUrl ? 'picture' : 'file'\" nzTheme=\"twotone\" />\n }\n }\n @default {\n <nz-icon [nzType]=\"file.isUploading ? 'loading' : 'paper-clip'\" />\n }\n }\n } @else {\n <ng-template [ngTemplateOutlet]=\"iconRender\" [ngTemplateOutletContext]=\"{ $implicit: file }\"></ng-template>\n }\n </ng-template>\n\n <ng-template #removeIcon>\n @if (icons.showRemoveIcon) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleRemove(file, $event)\"\n [attr.title]=\"locale.removeFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <nz-icon nzType=\"delete\" />\n </button>\n }\n </ng-template>\n\n <ng-template #downloadIcon>\n @if (file.showDownload) {\n <button\n type=\"button\"\n nz-button\n nzType=\"text\"\n nzSize=\"small\"\n (click)=\"handleDownload(file)\"\n [attr.title]=\"locale.downloadFile\"\n class=\"ant-upload-list-item-card-actions-btn\"\n >\n <nz-icon nzType=\"download\" />\n </button>\n }\n </ng-template>\n\n <ng-template #downloadOrDelete>\n @if (listType !== 'picture-card') {\n <span class=\"ant-upload-list-item-card-actions {{ listType === 'picture' ? 'picture' : '' }}\">\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n </ng-template>\n\n <ng-template #preview>\n @if (file.url) {\n <a\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n class=\"ant-upload-list-item-name\"\n [attr.title]=\"file.name\"\n [href]=\"file.url\"\n [attr.download]=\"file.linkProps && file.linkProps.download\"\n (click)=\"handlePreview(file, $event)\"\n >\n {{ file.name }}\n </a>\n } @else {\n <span class=\"ant-upload-list-item-name\" [attr.title]=\"file.name\" (click)=\"handlePreview(file, $event)\">\n {{ file.name }}\n </span>\n }\n <ng-template [ngTemplateOutlet]=\"downloadOrDelete\"></ng-template>\n </ng-template>\n\n <div class=\"ant-upload-list-item-info\">\n <span class=\"ant-upload-span\">\n <ng-template [ngTemplateOutlet]=\"icon\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"preview\"></ng-template>\n </span>\n </div>\n @if (listType === 'picture-card' && !file.isUploading) {\n <span class=\"ant-upload-list-item-actions\">\n @if (icons.showPreviewIcon) {\n <a\n [href]=\"file.url || file.thumbUrl\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n [attr.title]=\"locale.previewFile\"\n [style]=\"!(file.url || file.thumbUrl) ? { opacity: 0.5, 'pointer-events': 'none' } : null\"\n (click)=\"handlePreview(file, $event)\"\n >\n <nz-icon nzType=\"eye\" />\n </a>\n }\n @if (file.status === 'done') {\n <ng-template [ngTemplateOutlet]=\"downloadIcon\"></ng-template>\n }\n <ng-template [ngTemplateOutlet]=\"removeIcon\"></ng-template>\n </span>\n }\n @if (file.isUploading) {\n <div class=\"ant-upload-list-item-progress\">\n <nz-progress [nzPercent]=\"file.percent!\" nzType=\"line\" [nzShowInfo]=\"false\" [nzStrokeWidth]=\"2\"></nz-progress>\n </div>\n }\n </div>\n </div>\n}\n" }]
  577. }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i1.Platform }], propDecorators: { locale: [{
  578. type: Input
  579. }], listType: [{
  580. type: Input
  581. }], items: [{
  582. type: Input
  583. }], icons: [{
  584. type: Input
  585. }], onPreview: [{
  586. type: Input
  587. }], onRemove: [{
  588. type: Input
  589. }], onDownload: [{
  590. type: Input
  591. }], previewFile: [{
  592. type: Input
  593. }], previewIsImage: [{
  594. type: Input
  595. }], iconRender: [{
  596. type: Input
  597. }], dir: [{
  598. type: Input
  599. }] } });
  600. class NzUploadComponent {
  601. cdr;
  602. i18n;
  603. directionality;
  604. static ngAcceptInputType_nzShowUploadList;
  605. destroy$ = new Subject();
  606. uploadComp;
  607. listComp;
  608. locale;
  609. dir = 'ltr';
  610. // #region fields
  611. nzType = 'select';
  612. nzLimit = 0;
  613. nzSize = 0;
  614. nzFileType;
  615. nzAccept;
  616. nzAction;
  617. nzDirectory = false;
  618. nzOpenFileDialogOnClick = true;
  619. nzBeforeUpload;
  620. nzCustomRequest;
  621. nzData;
  622. nzFilter = [];
  623. nzFileList = [];
  624. nzDisabled = false;
  625. nzHeaders;
  626. nzListType = 'text';
  627. nzMultiple = false;
  628. nzName = 'file';
  629. _showUploadList = true;
  630. document = inject(DOCUMENT);
  631. set nzShowUploadList(value) {
  632. this._showUploadList = typeof value === 'boolean' ? toBoolean(value) : value;
  633. }
  634. get nzShowUploadList() {
  635. return this._showUploadList;
  636. }
  637. nzShowButton = true;
  638. nzWithCredentials = false;
  639. nzRemove;
  640. nzPreview;
  641. nzPreviewFile;
  642. nzPreviewIsImage;
  643. nzTransformFile;
  644. nzDownload;
  645. nzIconRender = null;
  646. nzFileListRender = null;
  647. nzChange = new EventEmitter();
  648. nzFileListChange = new EventEmitter();
  649. _btnOptions;
  650. zipOptions() {
  651. if (typeof this.nzShowUploadList === 'boolean' && this.nzShowUploadList) {
  652. this.nzShowUploadList = {
  653. showPreviewIcon: true,
  654. showRemoveIcon: true,
  655. showDownloadIcon: true
  656. };
  657. }
  658. // filters
  659. const filters = this.nzFilter.slice();
  660. if (this.nzMultiple && this.nzLimit > 0 && filters.findIndex(w => w.name === 'limit') === -1) {
  661. filters.push({
  662. name: 'limit',
  663. fn: (fileList) => fileList.slice(-this.nzLimit)
  664. });
  665. }
  666. if (this.nzSize > 0 && filters.findIndex(w => w.name === 'size') === -1) {
  667. filters.push({
  668. name: 'size',
  669. fn: (fileList) => fileList.filter(w => w.size / 1024 <= this.nzSize)
  670. });
  671. }
  672. if (this.nzFileType && this.nzFileType.length > 0 && filters.findIndex(w => w.name === 'type') === -1) {
  673. const types = this.nzFileType.split(',');
  674. filters.push({
  675. name: 'type',
  676. fn: (fileList) => fileList.filter(w => ~types.indexOf(w.type))
  677. });
  678. }
  679. this._btnOptions = {
  680. disabled: this.nzDisabled,
  681. accept: this.nzAccept,
  682. action: this.nzAction,
  683. directory: this.nzDirectory,
  684. openFileDialogOnClick: this.nzOpenFileDialogOnClick,
  685. beforeUpload: this.nzBeforeUpload,
  686. customRequest: this.nzCustomRequest,
  687. data: this.nzData,
  688. headers: this.nzHeaders,
  689. name: this.nzName,
  690. multiple: this.nzMultiple,
  691. withCredentials: this.nzWithCredentials,
  692. filters,
  693. transformFile: this.nzTransformFile,
  694. onStart: this.onStart,
  695. onProgress: this.onProgress,
  696. onSuccess: this.onSuccess,
  697. onError: this.onError
  698. };
  699. return this;
  700. }
  701. platform = inject(Platform);
  702. // #endregion
  703. constructor(cdr, i18n, directionality) {
  704. this.cdr = cdr;
  705. this.i18n = i18n;
  706. this.directionality = directionality;
  707. }
  708. // #region upload
  709. fileToObject(file) {
  710. return {
  711. lastModified: file.lastModified,
  712. lastModifiedDate: file.lastModifiedDate,
  713. name: file.filename || file.name,
  714. size: file.size,
  715. type: file.type,
  716. uid: file.uid,
  717. response: file.response,
  718. error: file.error,
  719. percent: 0,
  720. originFileObj: file
  721. };
  722. }
  723. getFileItem(file, fileList) {
  724. return fileList.filter(item => item.uid === file.uid)[0];
  725. }
  726. removeFileItem(file, fileList) {
  727. return fileList.filter(item => item.uid !== file.uid);
  728. }
  729. onStart = (file) => {
  730. if (!this.nzFileList) {
  731. this.nzFileList = [];
  732. }
  733. const targetItem = this.fileToObject(file);
  734. targetItem.status = 'uploading';
  735. this.nzFileList = this.nzFileList.concat(targetItem);
  736. this.nzFileListChange.emit(this.nzFileList);
  737. this.nzChange.emit({ file: targetItem, fileList: this.nzFileList, type: 'start' });
  738. this.detectChangesList();
  739. };
  740. onProgress = (e, file) => {
  741. const fileList = this.nzFileList;
  742. const targetItem = this.getFileItem(file, fileList);
  743. targetItem.percent = e.percent;
  744. this.nzChange.emit({
  745. event: e,
  746. file: { ...targetItem },
  747. fileList: this.nzFileList,
  748. type: 'progress'
  749. });
  750. this.detectChangesList();
  751. };
  752. onSuccess = (res, file) => {
  753. const fileList = this.nzFileList;
  754. const targetItem = this.getFileItem(file, fileList);
  755. targetItem.status = 'done';
  756. targetItem.response = res;
  757. this.nzChange.emit({
  758. file: { ...targetItem },
  759. fileList,
  760. type: 'success'
  761. });
  762. this.detectChangesList();
  763. };
  764. onError = (err, file) => {
  765. const fileList = this.nzFileList;
  766. const targetItem = this.getFileItem(file, fileList);
  767. targetItem.error = err;
  768. targetItem.status = 'error';
  769. this.nzChange.emit({
  770. file: { ...targetItem },
  771. fileList,
  772. type: 'error'
  773. });
  774. this.detectChangesList();
  775. };
  776. // #endregion
  777. // #region drag
  778. dragState;
  779. // skip safari bug
  780. fileDrop(e) {
  781. if (e.type === this.dragState) {
  782. return;
  783. }
  784. this.dragState = e.type;
  785. this.setClassMap();
  786. }
  787. // #endregion
  788. // #region list
  789. detectChangesList() {
  790. this.cdr.detectChanges();
  791. this.listComp?.detectChanges();
  792. }
  793. onRemove = (file) => {
  794. this.uploadComp.abort(file);
  795. file.status = 'removed';
  796. const fnRes = typeof this.nzRemove === 'function' ? this.nzRemove(file) : this.nzRemove == null ? true : this.nzRemove;
  797. (fnRes instanceof Observable ? fnRes : of(fnRes)).pipe(filter((res) => res)).subscribe(() => {
  798. this.nzFileList = this.removeFileItem(file, this.nzFileList);
  799. this.nzChange.emit({
  800. file,
  801. fileList: this.nzFileList,
  802. type: 'removed'
  803. });
  804. this.nzFileListChange.emit(this.nzFileList);
  805. this.cdr.detectChanges();
  806. });
  807. };
  808. // #endregion
  809. // #region styles
  810. prefixCls = 'ant-upload';
  811. classList = [];
  812. setClassMap() {
  813. let subCls = [];
  814. if (this.nzType === 'drag') {
  815. if (this.nzFileList.some(file => file.status === 'uploading')) {
  816. subCls.push(`${this.prefixCls}-drag-uploading`);
  817. }
  818. if (this.dragState === 'dragover') {
  819. subCls.push(`${this.prefixCls}-drag-hover`);
  820. }
  821. }
  822. else {
  823. subCls = [`${this.prefixCls}-select-${this.nzListType}`];
  824. }
  825. this.classList = [
  826. this.prefixCls,
  827. `${this.prefixCls}-${this.nzType}`,
  828. ...subCls,
  829. (this.nzDisabled && `${this.prefixCls}-disabled`) || '',
  830. (this.dir === 'rtl' && `${this.prefixCls}-rtl`) || ''
  831. ].filter(item => !!item);
  832. this.cdr.detectChanges();
  833. }
  834. // #endregion
  835. ngOnInit() {
  836. this.dir = this.directionality.value;
  837. this.directionality.change?.pipe(takeUntil(this.destroy$)).subscribe((direction) => {
  838. this.dir = direction;
  839. this.setClassMap();
  840. this.cdr.detectChanges();
  841. });
  842. this.i18n.localeChange.pipe(takeUntil(this.destroy$)).subscribe(() => {
  843. this.locale = this.i18n.getLocaleData('Upload');
  844. this.detectChangesList();
  845. });
  846. }
  847. ngAfterViewInit() {
  848. if (this.platform.FIREFOX) {
  849. // fix firefox drop open new tab
  850. fromEventOutsideAngular(this.document.body, 'drop')
  851. .pipe(takeUntil(this.destroy$))
  852. .subscribe(event => {
  853. event.preventDefault();
  854. event.stopPropagation();
  855. });
  856. }
  857. }
  858. ngOnChanges() {
  859. this.zipOptions().setClassMap();
  860. }
  861. ngOnDestroy() {
  862. this.destroy$.next();
  863. this.destroy$.complete();
  864. }
  865. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1$1.NzI18nService }, { token: i2$1.Directionality }], target: i0.ɵɵFactoryTarget.Component });
  866. static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.2", type: NzUploadComponent, isStandalone: true, selector: "nz-upload", inputs: { nzType: "nzType", nzLimit: ["nzLimit", "nzLimit", numberAttribute], nzSize: ["nzSize", "nzSize", numberAttribute], nzFileType: "nzFileType", nzAccept: "nzAccept", nzAction: "nzAction", nzDirectory: ["nzDirectory", "nzDirectory", booleanAttribute], nzOpenFileDialogOnClick: ["nzOpenFileDialogOnClick", "nzOpenFileDialogOnClick", booleanAttribute], nzBeforeUpload: "nzBeforeUpload", nzCustomRequest: "nzCustomRequest", nzData: "nzData", nzFilter: "nzFilter", nzFileList: "nzFileList", nzDisabled: ["nzDisabled", "nzDisabled", booleanAttribute], nzHeaders: "nzHeaders", nzListType: "nzListType", nzMultiple: ["nzMultiple", "nzMultiple", booleanAttribute], nzName: "nzName", nzShowUploadList: "nzShowUploadList", nzShowButton: ["nzShowButton", "nzShowButton", booleanAttribute], nzWithCredentials: ["nzWithCredentials", "nzWithCredentials", booleanAttribute], nzRemove: "nzRemove", nzPreview: "nzPreview", nzPreviewFile: "nzPreviewFile", nzPreviewIsImage: "nzPreviewIsImage", nzTransformFile: "nzTransformFile", nzDownload: "nzDownload", nzIconRender: "nzIconRender", nzFileListRender: "nzFileListRender" }, outputs: { nzChange: "nzChange", nzFileListChange: "nzFileListChange" }, host: { properties: { "class.ant-upload-picture-card-wrapper": "nzListType === \"picture-card\"" } }, viewQueries: [{ propertyName: "uploadComp", first: true, predicate: ["uploadComp"], descendants: true }, { propertyName: "listComp", first: true, predicate: ["listComp"], descendants: true }], exportAs: ["nzUpload"], usesOnChanges: true, ngImport: i0, template: "<ng-template #list>\n @if (locale && !nzFileListRender) {\n <nz-upload-list\n #listComp\n [style.display]=\"nzShowUploadList ? '' : 'none'\"\n [locale]=\"locale\"\n [listType]=\"nzListType\"\n [items]=\"nzFileList || []\"\n [icons]=\"$any(nzShowUploadList)\"\n [iconRender]=\"nzIconRender\"\n [previewFile]=\"nzPreviewFile\"\n [previewIsImage]=\"nzPreviewIsImage\"\n [onPreview]=\"nzPreview\"\n [onRemove]=\"onRemove\"\n [onDownload]=\"nzDownload\"\n [dir]=\"dir\"\n ></nz-upload-list>\n }\n @if (nzFileListRender) {\n <ng-container *ngTemplateOutlet=\"nzFileListRender; context: { $implicit: nzFileList }\"></ng-container>\n }\n</ng-template>\n<ng-template #con><ng-content></ng-content></ng-template>\n<ng-template #btn>\n <div [class]=\"classList\" [style.display]=\"nzShowButton ? '' : 'none'\">\n <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\">\n <ng-template [ngTemplateOutlet]=\"con\"></ng-template>\n </div>\n </div>\n</ng-template>\n@if (nzType === 'drag') {\n <div [class]=\"classList\" (drop)=\"fileDrop($event)\" (dragover)=\"fileDrop($event)\" (dragleave)=\"fileDrop($event)\">\n <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\" class=\"ant-upload-btn\">\n <div class=\"ant-upload-drag-container\">\n <ng-template [ngTemplateOutlet]=\"con\"></ng-template>\n </div>\n </div>\n </div>\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n} @else {\n @if (nzListType === 'picture-card') {\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"btn\"></ng-template>\n } @else {\n <ng-template [ngTemplateOutlet]=\"btn\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n }\n}\n", dependencies: [{ kind: "component", type: NzUploadListComponent, selector: "nz-upload-list", inputs: ["locale", "listType", "items", "icons", "onPreview", "onRemove", "onDownload", "previewFile", "previewIsImage", "iconRender", "dir"], exportAs: ["nzUploadList"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: NzUploadBtnComponent, selector: "[nz-upload-btn]", inputs: ["options"], exportAs: ["nzUploadBtn"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
  867. }
  868. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadComponent, decorators: [{
  869. type: Component,
  870. args: [{ selector: 'nz-upload', exportAs: 'nzUpload', preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {
  871. '[class.ant-upload-picture-card-wrapper]': 'nzListType === "picture-card"'
  872. }, imports: [NzUploadListComponent, NgTemplateOutlet, NzUploadBtnComponent], template: "<ng-template #list>\n @if (locale && !nzFileListRender) {\n <nz-upload-list\n #listComp\n [style.display]=\"nzShowUploadList ? '' : 'none'\"\n [locale]=\"locale\"\n [listType]=\"nzListType\"\n [items]=\"nzFileList || []\"\n [icons]=\"$any(nzShowUploadList)\"\n [iconRender]=\"nzIconRender\"\n [previewFile]=\"nzPreviewFile\"\n [previewIsImage]=\"nzPreviewIsImage\"\n [onPreview]=\"nzPreview\"\n [onRemove]=\"onRemove\"\n [onDownload]=\"nzDownload\"\n [dir]=\"dir\"\n ></nz-upload-list>\n }\n @if (nzFileListRender) {\n <ng-container *ngTemplateOutlet=\"nzFileListRender; context: { $implicit: nzFileList }\"></ng-container>\n }\n</ng-template>\n<ng-template #con><ng-content></ng-content></ng-template>\n<ng-template #btn>\n <div [class]=\"classList\" [style.display]=\"nzShowButton ? '' : 'none'\">\n <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\">\n <ng-template [ngTemplateOutlet]=\"con\"></ng-template>\n </div>\n </div>\n</ng-template>\n@if (nzType === 'drag') {\n <div [class]=\"classList\" (drop)=\"fileDrop($event)\" (dragover)=\"fileDrop($event)\" (dragleave)=\"fileDrop($event)\">\n <div nz-upload-btn #uploadComp [options]=\"_btnOptions!\" class=\"ant-upload-btn\">\n <div class=\"ant-upload-drag-container\">\n <ng-template [ngTemplateOutlet]=\"con\"></ng-template>\n </div>\n </div>\n </div>\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n} @else {\n @if (nzListType === 'picture-card') {\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"btn\"></ng-template>\n } @else {\n <ng-template [ngTemplateOutlet]=\"btn\"></ng-template>\n <ng-template [ngTemplateOutlet]=\"list\"></ng-template>\n }\n}\n" }]
  873. }], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1$1.NzI18nService }, { type: i2$1.Directionality }], propDecorators: { uploadComp: [{
  874. type: ViewChild,
  875. args: ['uploadComp', { static: false }]
  876. }], listComp: [{
  877. type: ViewChild,
  878. args: ['listComp', { static: false }]
  879. }], nzType: [{
  880. type: Input
  881. }], nzLimit: [{
  882. type: Input,
  883. args: [{ transform: numberAttribute }]
  884. }], nzSize: [{
  885. type: Input,
  886. args: [{ transform: numberAttribute }]
  887. }], nzFileType: [{
  888. type: Input
  889. }], nzAccept: [{
  890. type: Input
  891. }], nzAction: [{
  892. type: Input
  893. }], nzDirectory: [{
  894. type: Input,
  895. args: [{ transform: booleanAttribute }]
  896. }], nzOpenFileDialogOnClick: [{
  897. type: Input,
  898. args: [{ transform: booleanAttribute }]
  899. }], nzBeforeUpload: [{
  900. type: Input
  901. }], nzCustomRequest: [{
  902. type: Input
  903. }], nzData: [{
  904. type: Input
  905. }], nzFilter: [{
  906. type: Input
  907. }], nzFileList: [{
  908. type: Input
  909. }], nzDisabled: [{
  910. type: Input,
  911. args: [{ transform: booleanAttribute }]
  912. }], nzHeaders: [{
  913. type: Input
  914. }], nzListType: [{
  915. type: Input
  916. }], nzMultiple: [{
  917. type: Input,
  918. args: [{ transform: booleanAttribute }]
  919. }], nzName: [{
  920. type: Input
  921. }], nzShowUploadList: [{
  922. type: Input
  923. }], nzShowButton: [{
  924. type: Input,
  925. args: [{ transform: booleanAttribute }]
  926. }], nzWithCredentials: [{
  927. type: Input,
  928. args: [{ transform: booleanAttribute }]
  929. }], nzRemove: [{
  930. type: Input
  931. }], nzPreview: [{
  932. type: Input
  933. }], nzPreviewFile: [{
  934. type: Input
  935. }], nzPreviewIsImage: [{
  936. type: Input
  937. }], nzTransformFile: [{
  938. type: Input
  939. }], nzDownload: [{
  940. type: Input
  941. }], nzIconRender: [{
  942. type: Input
  943. }], nzFileListRender: [{
  944. type: Input
  945. }], nzChange: [{
  946. type: Output
  947. }], nzFileListChange: [{
  948. type: Output
  949. }] } });
  950. /**
  951. * Use of this source code is governed by an MIT-style license that can be
  952. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  953. */
  954. class NzUploadModule {
  955. static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
  956. static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.2", ngImport: i0, type: NzUploadModule, imports: [NzUploadComponent, NzUploadBtnComponent, NzUploadListComponent], exports: [NzUploadComponent] });
  957. static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadModule, imports: [NzUploadComponent, NzUploadListComponent] });
  958. }
  959. i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.2", ngImport: i0, type: NzUploadModule, decorators: [{
  960. type: NgModule,
  961. args: [{
  962. imports: [NzUploadComponent, NzUploadBtnComponent, NzUploadListComponent],
  963. exports: [NzUploadComponent]
  964. }]
  965. }] });
  966. /**
  967. * Use of this source code is governed by an MIT-style license that can be
  968. * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE
  969. */
  970. /**
  971. * Generated bundle index. Do not edit.
  972. */
  973. export { NzUploadBtnComponent, NzUploadComponent, NzUploadListComponent, NzUploadModule };
  974. //# sourceMappingURL=ng-zorro-antd-upload.mjs.map