Skip to content

Commit

Permalink
feat(module:upload): add directory support (#2164)
Browse files Browse the repository at this point in the history
close #2167 
close #2154
  • Loading branch information
cipchk authored and vthinkxie committed Sep 21, 2018
1 parent a00f004 commit 3ef8bcf
Show file tree
Hide file tree
Showing 12 changed files with 258 additions and 33 deletions.
14 changes: 14 additions & 0 deletions components/upload/demo/custom-request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 10
title:
zh-CN: 自定义上传
en-US: Custom request
---

## zh-CN

使用 `nzCustomRequest` 改变上传行为。

## en-US

Use `nzCustomRequest` override for the default xhr behavior.
80 changes: 80 additions & 0 deletions components/upload/demo/custom-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Component } from '@angular/core';
import { HttpRequest, HttpClient, HttpEventType, HttpEvent, HttpResponse } from '@angular/common/http';
import { NzMessageService, UploadXHRArgs } from 'ng-zorro-antd';
import { forkJoin } from 'rxjs';

@Component({
selector: 'nz-demo-upload-custom-request',
template: `
<nz-upload
nzAction="https://jsonplaceholder.typicode.com/posts/"
[nzCustomRequest]="customReq">
<button nz-button>
<i class="anticon anticon-upload"></i><span>Click to Upload</span>
</button>
</nz-upload>
`
})
export class NzDemoUploadCustomRequestComponent {

constructor(private http: HttpClient, private msg: NzMessageService) {}

customReq = (item: UploadXHRArgs) => {
// 构建一个 FormData 对象,用于存储文件或其他参数
const formData = new FormData();
// tslint:disable-next-line:no-any
formData.append('file', item.file as any);
formData.append('id', '1000');
const req = new HttpRequest('POST', item.action, formData, {
reportProgress : true,
withCredentials: true
});
// 始终返回一个 `Subscription` 对象,nz-upload 会在适当时机自动取消订阅
return this.http.request(req).subscribe((event: HttpEvent<{}>) => {
if (event.type === HttpEventType.UploadProgress) {
if (event.total > 0) {
// tslint:disable-next-line:no-any
(event as any).percent = event.loaded / event.total * 100;
}
// 处理上传进度条,必须指定 `percent` 属性来表示进度
item.onProgress(event, item.file);
} else if (event instanceof HttpResponse) {
// 处理成功
item.onSuccess(event.body, item.file, event);
}
}, (err) => {
// 处理失败
item.onError(err, item.file);
});
}

// 一个简单的分片上传
customBigReq = (item: UploadXHRArgs) => {
const size = item.file.size;
const chunkSize = parseInt((size / 3) + '', 10);
const maxChunk = Math.ceil(size / chunkSize);
const reqs = Array(maxChunk).fill(0).map((v: {}, index: number) => {
const start = index * chunkSize;
let end = start + chunkSize;
if (size - end < 0) {
end = size;
}
const formData = new FormData();
formData.append('file', item.file.slice(start, end));
formData.append('start', start.toString());
formData.append('end', end.toString());
formData.append('index', index.toString());
const req = new HttpRequest('POST', item.action, formData, {
withCredentials: true
});
return this.http.request(req);
});
return forkJoin(...reqs).subscribe(resules => {
// 处理成功
item.onSuccess({}, item.file, event);
}, (err) => {
// 处理失败
item.onError(err, item.file);
});
}
}
14 changes: 14 additions & 0 deletions components/upload/demo/directory.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
order: 6
title:
zh-CN: 文件夹上传
en-US: Upload directory
---

## zh-CN

支持上传一个文件夹里的所有文件。

## en-US

You can select and upload a whole directory.
15 changes: 15 additions & 0 deletions components/upload/demo/directory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Component } from '@angular/core';

@Component({
selector: 'nz-demo-upload-directory',
template: `
<nz-upload
nzAction="https://jsonplaceholder.typicode.com/posts/"
nzDirectory>
<button nz-button>
<i class="anticon anticon-upload"></i> Upload Directory
</button>
</nz-upload>
`
})
export class NzDemoUploadDirectoryComponent {}
2 changes: 1 addition & 1 deletion components/upload/demo/picture-style.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
order: 6
order: 8
title:
zh-CN: 图片列表样式
en-US: Pictures with list style
Expand Down
1 change: 1 addition & 0 deletions components/upload/doc/index.en-US.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Uploading is the process of publishing information (web pages, text, pictures, v
| --- | --- | --- | --- |
| `[nzAccept]` | File types that can be accepted. See [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept) | string | - |
| `[nzAction]` | Required. Uploading URL | string | - |
| `[nzDirectory]` | support upload whole directory ([caniuse](https://caniuse.com/#feat=input-file-directory)) | boolean | false |
| `[nzBeforeUpload]` | Hook function which will be executed before uploading. Uploading will be stopped with `false` or a Observable. **Warning:this function is not supported in IE9**. NOTICE: Muse be use `=>` to define the method. | (file, fileList) => `boolean|Observable` | - |
| `[nzCustomRequest]` | override for the default xhr behavior allowing for additional customization and ability to implement your own XMLHttpRequest. NOTICE: Muse be use `=>` to define the method. | `(item) => Subscription` | - |
| `[nzData]` | Uploading params or function which can return uploading params. NOTICE: Muse be use `=>` to define the method. | `Object|((file: UploadFile) => Object)` | - |
Expand Down
1 change: 1 addition & 0 deletions components/upload/doc/index.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ title: Upload
| --- | --- | --- | --- |
| `[nzAccept]` | 接受上传的文件类型, 详见 [input accept Attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attr-accept) | string | - |
| `[nzAction]` | 必选参数, 上传的地址 | string | - |
| `[nzDirectory]` | 支持上传文件夹([caniuse](https://caniuse.com/#feat=input-file-directory)| boolean | false |
| `[nzBeforeUpload]` | 上传文件之前的钩子,参数为上传的文件,若返回 `false` 则停止上传。注意:**IE9** 不支持该方法;注意:务必使用 `=>` 定义处理方法。 | (file, fileList) => `boolean|Observable` | - |
| `[nzCustomRequest]` | 通过覆盖默认的上传行为,可以自定义自己的上传实现;注意:务必使用 `=>` 定义处理方法。 | `(item) => Subscription` | - |
| `[nzData]` | 上传所需参数或返回上传参数的方法;注意:务必使用 `=>` 定义处理方法。 | `Object|((file: UploadFile) => Object)` | - |
Expand Down
1 change: 1 addition & 0 deletions components/upload/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface ZipButtonOptions {
disabled?: boolean;
accept?: string | string[];
action?: string;
directory?: boolean;
beforeUpload?: (file: UploadFile, fileList: UploadFile[]) => boolean | Observable<any>;
customRequest?: (item: any) => Subscription;
data?: {} | ((file: UploadFile) => {});
Expand Down
5 changes: 4 additions & 1 deletion components/upload/nz-upload-btn.component.html
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
<input type="file" #file (change)="onChange($event)"
[attr.accept]="options.accept" [multiple]="options.multiple" style="display: none;">
[attr.accept]="options.accept"
[attr.directory]="options.directory ? 'directory': null"
[attr.webkitdirectory]="options.directory ? 'webkitdirectory': null"
[multiple]="options.multiple" style="display: none;">
<ng-content></ng-content>
41 changes: 35 additions & 6 deletions components/upload/nz-upload-btn.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,15 @@ export class NzUploadBtnComponent implements OnInit, OnChanges, OnDestroy {
e.preventDefault();
return;
}
const files: File[] = Array.prototype.slice.call(e.dataTransfer.files).filter(
(file: File) => this.attrAccept(file, this.options.accept)
);
if (files.length) {
this.uploadFiles(files);
if (this.options.directory) {
this.traverseFileTree(e.dataTransfer.items);
} else {
const files: File[] = Array.prototype.slice.call(e.dataTransfer.files).filter(
(file: File) => this.attrAccept(file, this.options.accept)
);
if (files.length) {
this.uploadFiles(files);
}
}

e.preventDefault();
Expand All @@ -85,6 +89,31 @@ export class NzUploadBtnComponent implements OnInit, OnChanges, OnDestroy {
hie.value = '';
}

// tslint:disable-next-line:no-any
private traverseFileTree(files: any): void {
// tslint:disable-next-line:no-any
const _traverseFileTree = (item: any, path: string) => {
if (item.isFile) {
item.file((file) => {
if (this.attrAccept(file, this.options.accept)) {
this.uploadFiles([file]);
}
});
} else if (item.isDirectory) {
const dirReader = item.createReader();

dirReader.readEntries((entries) => {
for (const entrieItem of entries) {
_traverseFileTree(entrieItem, `${path}${item.name}/`);
}
});
}
};
for (const file of files) {
_traverseFileTree(file.webkitGetAsEntry(), '');
}
}

private attrAccept(file: File, acceptedFiles: string | string[]): boolean {
if (file && acceptedFiles) {
const acceptedFilesArray = Array.isArray(acceptedFiles) ? acceptedFiles : acceptedFiles.split(',');
Expand Down Expand Up @@ -133,7 +162,7 @@ export class NzUploadBtnComponent implements OnInit, OnChanges, OnDestroy {
if (processedFileType === '[object File]' || processedFileType === '[object Blob]') {
this.attachUid(processedFile);
this.post(processedFile);
} else {
} else if (typeof processedFile === 'boolean' && processedFile !== false) {
this.post(file);
}
});
Expand Down
9 changes: 4 additions & 5 deletions components/upload/nz-upload.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import { of, Observable, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';

import { toBoolean, toNumber } from '../core/util/convert';
import { toBoolean, toNumber, InputBoolean } from '../core/util/convert';
import { NzI18nService } from '../i18n/nz-i18n.service';

import {
Expand All @@ -39,8 +39,6 @@ import { NzUploadBtnComponent } from './nz-upload-btn.component';
export class NzUploadComponent implements OnInit, OnChanges, OnDestroy {
private i18n$: Subscription;
locale: any = {};
private inited = false;
private progressTimer: any;
@ViewChild('upload') upload: NzUploadBtnComponent;

// region: fields
Expand Down Expand Up @@ -70,6 +68,7 @@ export class NzUploadComponent implements OnInit, OnChanges, OnDestroy {
@Input() nzFileType: string;
@Input() nzAccept: string | string[];
@Input() nzAction: string;
@Input() @InputBoolean() nzDirectory: boolean = false;
@Input() nzBeforeUpload: (file: UploadFile, fileList: UploadFile[]) => boolean | Observable<any>;
@Input() nzCustomRequest: (item: any) => Subscription;
@Input() nzData: {} | ((file: UploadFile) => {});
Expand Down Expand Up @@ -176,6 +175,7 @@ export class NzUploadComponent implements OnInit, OnChanges, OnDestroy {
disabled : this.nzDisabled,
accept : this.nzAccept,
action : this.nzAction,
directory : this.nzDirectory,
beforeUpload : this.nzBeforeUpload,
customRequest : this.nzCustomRequest,
data : this.nzData,
Expand Down Expand Up @@ -240,7 +240,7 @@ export class NzUploadComponent implements OnInit, OnChanges, OnDestroy {
file.thumbUrl = '';

const reader = new FileReader();
reader.onloadend = () => file.thumbUrl = reader.result;
reader.onloadend = () => file.thumbUrl = reader.result as string;
reader.readAsDataURL(file.originFileObj);
}

Expand Down Expand Up @@ -361,7 +361,6 @@ export class NzUploadComponent implements OnInit, OnChanges, OnDestroy {

// endregion
ngOnInit(): void {
this.inited = true;
this.i18n$ = this.i18n.localeChange.subscribe(() => {
this.locale = this.i18n.getLocaleData('Upload');
this.cd.detectChanges();
Expand Down
Loading

0 comments on commit 3ef8bcf

Please sign in to comment.