ohayolibs
Version:
Ohayo is a set of essential modules for ohayojp.
99 lines (93 loc) • 3.43 kB
text/typescript
import { HttpResponse } from '@angular/common/http';
import { Directive, ElementRef, EventEmitter, Input, Output } from '@angular/core';
import { _HttpClient } from '@ohayo/theme';
import { saveAs } from 'file-saver';
import { NzSafeAny } from 'ng-zorro-antd/core/types';
({
selector: '[down-file]',
exportAs: 'downFile',
host: {
'(click)': '_click($event)',
},
})
export class DownFileDirective {
private isFileSaverSupported = true;
/** URL请求参数 */
('http-data') httpData: {};
/** URL请求参数 */
('http-body') httpBody: {};
/** 请求类型 */
('http-method') httpMethod: string = 'get';
/** 下载地址 */
('http-url') httpUrl: string;
/** 指定文件名,若为空从服务端返回的 `header` 中获取 `filename`、`x-filename` */
('file-name') fileName: string | ((rep: HttpResponse<Blob>) => string);
/** 下载前回调 */
() pre: (ev: MouseEvent) => Promise<boolean>;
/** 成功回调 */
// tslint:disable-next-line:no-output-native
() readonly success = new EventEmitter<HttpResponse<Blob>>();
/** 错误回调 */
// tslint:disable-next-line:no-output-native
() readonly error = new EventEmitter<any>();
private getDisposition(data: string | null): NzSafeAny {
const arr: Array<{}> = (data || '')
.split(';')
.filter(i => i.includes('='))
.map(v => {
const strArr = v.split('=');
const utfId = `UTF-8''`;
let value = strArr[1];
if (value.startsWith(utfId)) value = value.substr(utfId.length);
return { [strArr[0].trim()]: value };
});
return arr.reduce((_o, item) => item, {});
}
constructor(private el: ElementRef<HTMLButtonElement>, private _http: _HttpClient) {
let isFileSaverSupported = false;
try {
isFileSaverSupported = !!new Blob();
} catch { }
this.isFileSaverSupported = isFileSaverSupported;
if (!isFileSaverSupported) {
el.nativeElement.classList.add(`down-file__not-support`);
}
}
private setDisabled(status: boolean): void {
const el = this.el.nativeElement;
el.disabled = status;
el.classList[status ? 'add' : 'remove'](`down-file__disabled`);
}
async _click(ev: MouseEvent): Promise<void> {
if (!this.isFileSaverSupported || (typeof this.pre === 'function' && !(await this.pre(ev)))) {
ev.stopPropagation();
ev.preventDefault();
return;
}
this.setDisabled(true);
this._http
.request(this.httpMethod, this.httpUrl, {
params: this.httpData || {},
responseType: 'blob',
observe: 'response',
body: this.httpBody,
})
.subscribe(
(res: HttpResponse<Blob>) => {
if (res.status !== 200 || res.body!.size <= 0) {
this.error.emit(res);
return;
}
const disposition = this.getDisposition(res.headers.get('content-disposition'));
let fileName = this.fileName;
if (typeof fileName === 'function') fileName = fileName(res);
fileName =
fileName || disposition[`filename*`] || disposition[`filename`] || res.headers.get('filename') || res.headers.get('x-filename');
saveAs(res.body!, decodeURI(fileName as string));
this.success.emit(res);
},
(err) => this.error.emit(err),
() => this.setDisabled(false),
);
}
}