feat(core): added nx
This commit is contained in:
21
libs/ng2-file-upload/.eslintrc.json
Normal file
21
libs/ng2-file-upload/.eslintrc.json
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"extends": ["../../.eslintrc.json"],
|
||||
"ignorePatterns": ["!**/*"],
|
||||
"overrides": [
|
||||
{
|
||||
"files": ["*.ts"],
|
||||
"extends": [
|
||||
"plugin:@nrwl/nx/angular",
|
||||
"plugin:@angular-eslint/template/process-inline-templates"
|
||||
],
|
||||
"parserOptions": { "project": ["src/accordion/tsconfig.*?.json"] },
|
||||
"rules": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["*.html"],
|
||||
"extends": ["plugin:@nrwl/nx/angular-template"],
|
||||
"rules": {}
|
||||
}
|
||||
]
|
||||
}
|
||||
10
libs/ng2-file-upload/README.md
Normal file
10
libs/ng2-file-upload/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# libs-ng2-file-upload
|
||||
|
||||
This library was generated with [Nx](https://nx.dev).
|
||||
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `nx test libs-ng2-file-upload` to execute the unit tests via [Jest](https://jestjs.io).
|
||||
|
||||
|
||||
89
libs/ng2-file-upload/file-upload/file-drop.directive.ts
Normal file
89
libs/ng2-file-upload/file-upload/file-drop.directive.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { Directive, EventEmitter, ElementRef, HostListener, Input, Output } from '@angular/core';
|
||||
|
||||
import { FileUploader, FileUploaderOptions } from './file-uploader.class';
|
||||
|
||||
@Directive({ selector: '[ng2FileDrop]' })
|
||||
export class FileDropDirective {
|
||||
@Input() public uploader?: FileUploader;
|
||||
@Output() public fileOver: EventEmitter<any> = new EventEmitter();
|
||||
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
||||
@Output() public onFileDrop: EventEmitter<File[]> = new EventEmitter<File[]>();
|
||||
|
||||
protected element: ElementRef;
|
||||
|
||||
public constructor(element: ElementRef) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public getOptions(): FileUploaderOptions | void {
|
||||
return this.uploader?.options;
|
||||
}
|
||||
|
||||
public getFilters(): any {
|
||||
return {};
|
||||
}
|
||||
|
||||
@HostListener('drop', [ '$event' ])
|
||||
public onDrop(event: any): void {
|
||||
const transfer = this._getTransfer(event);
|
||||
if (!transfer) {
|
||||
return;
|
||||
}
|
||||
|
||||
const options = this.getOptions();
|
||||
const filters = this.getFilters();
|
||||
this._preventAndStop(event);
|
||||
if (options) {
|
||||
this.uploader?.addToQueue(transfer.files, options, filters);
|
||||
}
|
||||
this.fileOver.emit(false);
|
||||
this.onFileDrop.emit(transfer.files);
|
||||
}
|
||||
|
||||
@HostListener('dragover', [ '$event' ])
|
||||
public onDragOver(event: any): void {
|
||||
const transfer = this._getTransfer(event);
|
||||
if (!this._haveFiles(transfer.types)) {
|
||||
return;
|
||||
}
|
||||
|
||||
transfer.dropEffect = 'copy';
|
||||
this._preventAndStop(event);
|
||||
this.fileOver.emit(true);
|
||||
}
|
||||
|
||||
@HostListener('dragleave', [ '$event' ])
|
||||
public onDragLeave(event: any): any {
|
||||
if ((this as any).element) {
|
||||
if (event.currentTarget === (this as any).element[ 0 ]) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this._preventAndStop(event);
|
||||
this.fileOver.emit(false);
|
||||
}
|
||||
|
||||
protected _getTransfer(event: any): any {
|
||||
return event.dataTransfer ? event.dataTransfer : event.originalEvent.dataTransfer; // jQuery fix;
|
||||
}
|
||||
|
||||
protected _preventAndStop(event: any): any {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
protected _haveFiles(types: any): any {
|
||||
if (!types) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (types.indexOf) {
|
||||
return types.indexOf('Files') !== -1;
|
||||
} else if (types.contains) {
|
||||
return types.contains('Files');
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
154
libs/ng2-file-upload/file-upload/file-item.class.ts
Normal file
154
libs/ng2-file-upload/file-upload/file-item.class.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import { FileLikeObject } from './file-like-object.class';
|
||||
import { FileUploader, ParsedResponseHeaders, FileUploaderOptions } from './file-uploader.class';
|
||||
|
||||
export class FileItem {
|
||||
public file: FileLikeObject;
|
||||
public _file: File;
|
||||
public alias?: string;
|
||||
public url? = '/';
|
||||
public method?: string;
|
||||
public headers: any = [];
|
||||
public withCredentials = true;
|
||||
public formData: any = [];
|
||||
public isReady = false;
|
||||
public isUploading = false;
|
||||
public isUploaded = false;
|
||||
public isSuccess = false;
|
||||
public isCancel = false;
|
||||
public isError = false;
|
||||
public progress = 0;
|
||||
public index?: number;
|
||||
public _xhr?: XMLHttpRequest;
|
||||
public _form: any;
|
||||
|
||||
protected uploader: FileUploader;
|
||||
protected some: File;
|
||||
protected options: FileUploaderOptions;
|
||||
|
||||
public constructor(uploader: FileUploader, some: File, options: FileUploaderOptions) {
|
||||
this.uploader = uploader;
|
||||
this.some = some;
|
||||
this.options = options;
|
||||
this.file = new FileLikeObject(some);
|
||||
this._file = some;
|
||||
if (uploader.options) {
|
||||
this.method = uploader.options.method || 'POST';
|
||||
this.alias = uploader.options.itemAlias || 'file';
|
||||
}
|
||||
this.url = uploader.options.url;
|
||||
}
|
||||
|
||||
public upload(): void {
|
||||
try {
|
||||
this.uploader.uploadItem(this);
|
||||
} catch (e) {
|
||||
this.uploader._onCompleteItem(this, '', 0, {});
|
||||
this.uploader._onErrorItem(this, '', 0, {});
|
||||
}
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
this.uploader.cancelItem(this);
|
||||
}
|
||||
|
||||
public remove(): void {
|
||||
this.uploader.removeFromQueue(this);
|
||||
}
|
||||
|
||||
public onBeforeUpload(): void {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public onBuildForm(form: any): any {
|
||||
return { form };
|
||||
}
|
||||
|
||||
public onProgress(progress: number): any {
|
||||
return { progress };
|
||||
}
|
||||
|
||||
public onSuccess(response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { response, status, headers };
|
||||
}
|
||||
|
||||
public onError(response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { response, status, headers };
|
||||
}
|
||||
|
||||
public onCancel(response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { response, status, headers };
|
||||
}
|
||||
|
||||
public onComplete(response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { response, status, headers };
|
||||
}
|
||||
|
||||
public _onBeforeUpload(): void {
|
||||
this.isReady = true;
|
||||
this.isUploading = true;
|
||||
this.isUploaded = false;
|
||||
this.isSuccess = false;
|
||||
this.isCancel = false;
|
||||
this.isError = false;
|
||||
this.progress = 0;
|
||||
this.onBeforeUpload();
|
||||
}
|
||||
|
||||
public _onBuildForm(form: any): void {
|
||||
this.onBuildForm(form);
|
||||
}
|
||||
|
||||
public _onProgress(progress: number): void {
|
||||
this.progress = progress;
|
||||
this.onProgress(progress);
|
||||
}
|
||||
|
||||
public _onSuccess(response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
this.isReady = false;
|
||||
this.isUploading = false;
|
||||
this.isUploaded = true;
|
||||
this.isSuccess = true;
|
||||
this.isCancel = false;
|
||||
this.isError = false;
|
||||
this.progress = 100;
|
||||
this.index = undefined;
|
||||
this.onSuccess(response, status, headers);
|
||||
}
|
||||
|
||||
public _onError(response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
this.isReady = false;
|
||||
this.isUploading = false;
|
||||
this.isUploaded = true;
|
||||
this.isSuccess = false;
|
||||
this.isCancel = false;
|
||||
this.isError = true;
|
||||
this.progress = 0;
|
||||
this.index = undefined;
|
||||
this.onError(response, status, headers);
|
||||
}
|
||||
|
||||
public _onCancel(response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
this.isReady = false;
|
||||
this.isUploading = false;
|
||||
this.isUploaded = false;
|
||||
this.isSuccess = false;
|
||||
this.isCancel = true;
|
||||
this.isError = false;
|
||||
this.progress = 0;
|
||||
this.index = undefined;
|
||||
this.onCancel(response, status, headers);
|
||||
}
|
||||
|
||||
public _onComplete(response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
this.onComplete(response, status, headers);
|
||||
|
||||
if (this.uploader.options.removeAfterUpload) {
|
||||
this.remove();
|
||||
}
|
||||
}
|
||||
|
||||
public _prepareToUploading(): void {
|
||||
this.index = this.index || ++this.uploader._nextIndex;
|
||||
this.isReady = true;
|
||||
}
|
||||
}
|
||||
33
libs/ng2-file-upload/file-upload/file-like-object.class.ts
Normal file
33
libs/ng2-file-upload/file-upload/file-like-object.class.ts
Normal file
@@ -0,0 +1,33 @@
|
||||
function isElement(node: any): boolean {
|
||||
return !!(node && (node.nodeName || node.prop && node.attr && node.find));
|
||||
}
|
||||
|
||||
export class FileLikeObject {
|
||||
public lastModifiedDate: any;
|
||||
public size: any;
|
||||
public type?: string;
|
||||
public name?: string;
|
||||
public rawFile: string;
|
||||
|
||||
public constructor(fileOrInput: any) {
|
||||
this.rawFile = fileOrInput;
|
||||
const isInput = isElement(fileOrInput);
|
||||
const fakePathOrObject = isInput ? fileOrInput.value : fileOrInput;
|
||||
const postfix = typeof fakePathOrObject === 'string' ? 'FakePath' : 'Object';
|
||||
const method = '_createFrom' + postfix;
|
||||
(this as any)[ method ](fakePathOrObject);
|
||||
}
|
||||
|
||||
public _createFromFakePath(path: string): void {
|
||||
this.lastModifiedDate = void 0;
|
||||
this.size = void 0;
|
||||
this.type = 'like/' + path.slice(path.lastIndexOf('.') + 1).toLowerCase();
|
||||
this.name = path.slice(path.lastIndexOf('/') + path.lastIndexOf('\\') + 2);
|
||||
}
|
||||
|
||||
public _createFromObject(object: { size: number, type: string, name: string }): void {
|
||||
this.size = object.size;
|
||||
this.type = object.type;
|
||||
this.name = object.name;
|
||||
}
|
||||
}
|
||||
43
libs/ng2-file-upload/file-upload/file-select.directive.ts
Normal file
43
libs/ng2-file-upload/file-upload/file-select.directive.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Directive, EventEmitter, ElementRef, Input, HostListener, Output } from '@angular/core';
|
||||
|
||||
import {FileUploader, FileUploaderOptions} from './file-uploader.class';
|
||||
|
||||
@Directive({ selector: '[ng2FileSelect]' })
|
||||
export class FileSelectDirective {
|
||||
@Input() public uploader?: FileUploader;
|
||||
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
|
||||
@Output() public onFileSelected: EventEmitter<File[]> = new EventEmitter<File[]>();
|
||||
|
||||
protected element: ElementRef;
|
||||
|
||||
public constructor(element: ElementRef) {
|
||||
this.element = element;
|
||||
}
|
||||
|
||||
public getOptions(): FileUploaderOptions | void {
|
||||
return this.uploader?.options;
|
||||
}
|
||||
|
||||
public getFilters(): any {
|
||||
return {};
|
||||
}
|
||||
|
||||
public isEmptyAfterSelection(): boolean {
|
||||
return !!this.element.nativeElement.attributes.multiple;
|
||||
}
|
||||
|
||||
@HostListener('change')
|
||||
public onChange(): any {
|
||||
const files = this.element.nativeElement.files;
|
||||
const options = this.getOptions();
|
||||
const filters = this.getFilters();
|
||||
if (options) {
|
||||
this.uploader?.addToQueue(files, options, filters);
|
||||
}
|
||||
|
||||
this.onFileSelected.emit(files);
|
||||
if (this.isEmptyAfterSelection()) {
|
||||
this.element.nativeElement.value = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
164
libs/ng2-file-upload/file-upload/file-type.class.ts
Normal file
164
libs/ng2-file-upload/file-upload/file-type.class.ts
Normal file
@@ -0,0 +1,164 @@
|
||||
import { FileLikeObject } from "../index";
|
||||
|
||||
export class FileType {
|
||||
/* MS office */
|
||||
public static mime_doc: string[] = [
|
||||
'application/msword',
|
||||
'application/msword',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'application/vnd.openxmlformats-officedocument.wordprocessingml.template',
|
||||
'application/vnd.ms-word.document.macroEnabled.12',
|
||||
'application/vnd.ms-word.template.macroEnabled.12'
|
||||
];
|
||||
public static mime_xsl: string[] = [
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.ms-excel',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.template',
|
||||
'application/vnd.ms-excel.sheet.macroEnabled.12',
|
||||
'application/vnd.ms-excel.template.macroEnabled.12',
|
||||
'application/vnd.ms-excel.addin.macroEnabled.12',
|
||||
'application/vnd.ms-excel.sheet.binary.macroEnabled.12'
|
||||
];
|
||||
public static mime_ppt: string[] = [
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.ms-powerpoint',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.template',
|
||||
'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
|
||||
'application/vnd.ms-powerpoint.addin.macroEnabled.12',
|
||||
'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||
'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
|
||||
'application/vnd.ms-powerpoint.slideshow.macroEnabled.12'
|
||||
];
|
||||
|
||||
/* PSD */
|
||||
public static mime_psd: string[] = [
|
||||
'image/photoshop',
|
||||
'image/x-photoshop',
|
||||
'image/psd',
|
||||
'application/photoshop',
|
||||
'application/psd',
|
||||
'zz-application/zz-winassoc-psd'
|
||||
];
|
||||
|
||||
/* Compressed files */
|
||||
public static mime_compress: string[] = [
|
||||
'application/x-gtar',
|
||||
'application/x-gcompress',
|
||||
'application/compress',
|
||||
'application/x-tar',
|
||||
'application/x-rar-compressed',
|
||||
'application/octet-stream',
|
||||
'application/x-zip-compressed',
|
||||
'application/zip-compressed',
|
||||
'application/x-7z-compressed',
|
||||
'application/gzip',
|
||||
'application/x-bzip2'
|
||||
];
|
||||
|
||||
public static getMimeClass(file: FileLikeObject): string {
|
||||
let mimeClass = 'application';
|
||||
if (file?.type && this.mime_psd.indexOf(file.type) !== -1) {
|
||||
mimeClass = 'image';
|
||||
} else if (file?.type?.match('image.*')) {
|
||||
mimeClass = 'image';
|
||||
} else if (file?.type?.match('video.*')) {
|
||||
mimeClass = 'video';
|
||||
} else if (file?.type?.match('audio.*')) {
|
||||
mimeClass = 'audio';
|
||||
} else if (file?.type === 'application/pdf') {
|
||||
mimeClass = 'pdf';
|
||||
} else if (file?.type && this.mime_compress.indexOf(file.type) !== -1) {
|
||||
mimeClass = 'compress';
|
||||
} else if (file?.type && this.mime_doc.indexOf(file.type) !== -1) {
|
||||
mimeClass = 'doc';
|
||||
} else if (file?.type && this.mime_xsl.indexOf(file.type) !== -1) {
|
||||
mimeClass = 'xls';
|
||||
} else if (file?.type && this.mime_ppt.indexOf(file.type) !== -1) {
|
||||
mimeClass = 'ppt';
|
||||
}
|
||||
if (mimeClass === 'application' && file?.name) {
|
||||
mimeClass = this.fileTypeDetection(file.name);
|
||||
}
|
||||
|
||||
return mimeClass;
|
||||
}
|
||||
|
||||
public static fileTypeDetection(inputFilename: string): string {
|
||||
const types: { [ key: string ]: string } = {
|
||||
'jpg': 'image',
|
||||
'jpeg': 'image',
|
||||
'tif': 'image',
|
||||
'psd': 'image',
|
||||
'bmp': 'image',
|
||||
'png': 'image',
|
||||
'nef': 'image',
|
||||
'tiff': 'image',
|
||||
'cr2': 'image',
|
||||
'dwg': 'image',
|
||||
'cdr': 'image',
|
||||
'ai': 'image',
|
||||
'indd': 'image',
|
||||
'pin': 'image',
|
||||
'cdp': 'image',
|
||||
'skp': 'image',
|
||||
'stp': 'image',
|
||||
'3dm': 'image',
|
||||
'mp3': 'audio',
|
||||
'wav': 'audio',
|
||||
'wma': 'audio',
|
||||
'mod': 'audio',
|
||||
'm4a': 'audio',
|
||||
'compress': 'compress',
|
||||
'zip': 'compress',
|
||||
'rar': 'compress',
|
||||
'7z': 'compress',
|
||||
'lz': 'compress',
|
||||
'z01': 'compress',
|
||||
'bz2': 'compress',
|
||||
'gz': 'compress',
|
||||
'pdf': 'pdf',
|
||||
'xls': 'xls',
|
||||
'xlsx': 'xls',
|
||||
'ods': 'xls',
|
||||
'mp4': 'video',
|
||||
'avi': 'video',
|
||||
'wmv': 'video',
|
||||
'mpg': 'video',
|
||||
'mts': 'video',
|
||||
'flv': 'video',
|
||||
'3gp': 'video',
|
||||
'vob': 'video',
|
||||
'm4v': 'video',
|
||||
'mpeg': 'video',
|
||||
'm2ts': 'video',
|
||||
'mov': 'video',
|
||||
'doc': 'doc',
|
||||
'docx': 'doc',
|
||||
'eps': 'doc',
|
||||
'txt': 'doc',
|
||||
'odt': 'doc',
|
||||
'rtf': 'doc',
|
||||
'ppt': 'ppt',
|
||||
'pptx': 'ppt',
|
||||
'pps': 'ppt',
|
||||
'ppsx': 'ppt',
|
||||
'odp': 'ppt'
|
||||
};
|
||||
|
||||
const chunks = inputFilename.split('.');
|
||||
if (chunks.length < 2) {
|
||||
return 'application';
|
||||
}
|
||||
const extension = chunks[ chunks.length - 1 ].toLowerCase();
|
||||
if (types[ extension ] === undefined) {
|
||||
return 'application';
|
||||
} else {
|
||||
return types[ extension ];
|
||||
}
|
||||
}
|
||||
}
|
||||
13
libs/ng2-file-upload/file-upload/file-upload.module.ts
Normal file
13
libs/ng2-file-upload/file-upload/file-upload.module.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { FileDropDirective } from './file-drop.directive';
|
||||
import { FileSelectDirective } from './file-select.directive';
|
||||
|
||||
@NgModule({
|
||||
imports: [ CommonModule ],
|
||||
declarations: [ FileDropDirective, FileSelectDirective ],
|
||||
exports: [ FileDropDirective, FileSelectDirective ]
|
||||
})
|
||||
export class FileUploadModule {
|
||||
}
|
||||
510
libs/ng2-file-upload/file-upload/file-uploader.class.ts
Normal file
510
libs/ng2-file-upload/file-upload/file-uploader.class.ts
Normal file
@@ -0,0 +1,510 @@
|
||||
import { EventEmitter } from '@angular/core';
|
||||
import { FileLikeObject } from './file-like-object.class';
|
||||
import { FileItem } from './file-item.class';
|
||||
import { FileType } from './file-type.class';
|
||||
|
||||
function isFile(value: any): boolean {
|
||||
return (File && value instanceof File);
|
||||
}
|
||||
|
||||
export interface Headers {
|
||||
name: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export type ParsedResponseHeaders = { [ headerFieldName: string ]: string };
|
||||
|
||||
export type FilterFunction = {
|
||||
name: string,
|
||||
fn: (item: FileLikeObject, options?: FileUploaderOptions) => boolean
|
||||
};
|
||||
|
||||
export interface FileUploaderOptions {
|
||||
allowedMimeType?: string[];
|
||||
allowedFileType?: string[];
|
||||
autoUpload?: boolean;
|
||||
isHTML5?: boolean;
|
||||
filters?: FilterFunction[];
|
||||
headers?: Headers[];
|
||||
method?: string;
|
||||
authToken?: string;
|
||||
maxFileSize?: number;
|
||||
queueLimit?: number;
|
||||
removeAfterUpload?: boolean;
|
||||
url?: string;
|
||||
disableMultipart?: boolean;
|
||||
itemAlias?: string;
|
||||
authTokenHeader?: string;
|
||||
additionalParameter?: { [ key: string ]: any };
|
||||
parametersBeforeFiles?: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/ban-types
|
||||
formatDataFunction?: Function;
|
||||
formatDataFunctionIsAsync?: boolean;
|
||||
}
|
||||
|
||||
export class FileUploader {
|
||||
|
||||
public authToken?: string;
|
||||
public isUploading = false;
|
||||
public queue: FileItem[] = [];
|
||||
public progress = 0;
|
||||
public _nextIndex = 0;
|
||||
public autoUpload: any;
|
||||
public authTokenHeader?: string;
|
||||
public response: EventEmitter<any>;
|
||||
|
||||
public options: FileUploaderOptions = {
|
||||
autoUpload: false,
|
||||
isHTML5: true,
|
||||
filters: [],
|
||||
removeAfterUpload: false,
|
||||
disableMultipart: false,
|
||||
formatDataFunction: (item: FileItem) => item._file,
|
||||
formatDataFunctionIsAsync: false
|
||||
};
|
||||
|
||||
protected _failFilterIndex?: number;
|
||||
|
||||
public constructor(options: FileUploaderOptions) {
|
||||
this.setOptions(options);
|
||||
this.response = new EventEmitter<any>();
|
||||
}
|
||||
|
||||
public setOptions(options: FileUploaderOptions): void {
|
||||
this.options = Object.assign(this.options, options);
|
||||
|
||||
this.authToken = this.options.authToken;
|
||||
this.authTokenHeader = this.options.authTokenHeader || 'Authorization';
|
||||
this.autoUpload = this.options.autoUpload;
|
||||
this.options.filters?.unshift({ name: 'queueLimit', fn: this._queueLimitFilter });
|
||||
|
||||
if (this.options.maxFileSize && this.options.filters) {
|
||||
this.options.filters.unshift({ name: 'fileSize', fn: this._fileSizeFilter });
|
||||
}
|
||||
|
||||
if (this.options.allowedFileType) {
|
||||
this.options.filters?.unshift({ name: 'fileType', fn: this._fileTypeFilter });
|
||||
}
|
||||
|
||||
if (this.options.allowedMimeType) {
|
||||
this.options.filters?.unshift({ name: 'mimeType', fn: this._mimeTypeFilter });
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.queue.length; i++) {
|
||||
this.queue[ i ].url = this.options.url;
|
||||
}
|
||||
}
|
||||
|
||||
public addToQueue(files: File[], options?: FileUploaderOptions, filters?: FilterFunction[] | string): void {
|
||||
const list: File[] = [];
|
||||
for (const file of files) {
|
||||
list.push(file);
|
||||
}
|
||||
const arrayOfFilters = this._getFilters(filters);
|
||||
const count = this.queue.length;
|
||||
const addedFileItems: FileItem[] = [];
|
||||
list.map((some: File) => {
|
||||
if (!options) {
|
||||
options = this.options;
|
||||
}
|
||||
|
||||
const temp = new FileLikeObject(some);
|
||||
if (this._isValidFile(temp, arrayOfFilters, options)) {
|
||||
const fileItem = new FileItem(this, some, options);
|
||||
addedFileItems.push(fileItem);
|
||||
this.queue.push(fileItem);
|
||||
this._onAfterAddingFile(fileItem);
|
||||
} else {
|
||||
if (this._failFilterIndex) {
|
||||
const filter = arrayOfFilters[ this._failFilterIndex ];
|
||||
this._onWhenAddingFileFailed(temp, filter, options);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (this.queue.length !== count) {
|
||||
this._onAfterAddingAll(addedFileItems);
|
||||
this.progress = this._getTotalProgress();
|
||||
}
|
||||
this._render();
|
||||
if (this.options.autoUpload) {
|
||||
this.uploadAll();
|
||||
}
|
||||
}
|
||||
|
||||
public removeFromQueue(value: FileItem): void {
|
||||
const index = this.getIndexOfItem(value);
|
||||
const item = this.queue[ index ];
|
||||
if (item.isUploading) {
|
||||
item.cancel();
|
||||
}
|
||||
this.queue.splice(index, 1);
|
||||
this.progress = this._getTotalProgress();
|
||||
}
|
||||
|
||||
public clearQueue(): void {
|
||||
while (this.queue.length) {
|
||||
this.queue[ 0 ].remove();
|
||||
}
|
||||
this.progress = 0;
|
||||
}
|
||||
|
||||
public uploadItem(value: FileItem): void {
|
||||
const index = this.getIndexOfItem(value);
|
||||
const item = this.queue[ index ];
|
||||
const transport = this.options.isHTML5 ? '_xhrTransport' : '_iframeTransport';
|
||||
item._prepareToUploading();
|
||||
if (this.isUploading) {
|
||||
return;
|
||||
}
|
||||
this.isUploading = true;
|
||||
(this as any)[ transport ](item);
|
||||
}
|
||||
|
||||
public cancelItem(value: FileItem): void {
|
||||
const index = this.getIndexOfItem(value);
|
||||
const item = this.queue[ index ];
|
||||
const prop = this.options.isHTML5 ? item._xhr : item._form;
|
||||
if (item && item.isUploading) {
|
||||
prop.abort();
|
||||
}
|
||||
}
|
||||
|
||||
public uploadAll(): void {
|
||||
const items = this.getNotUploadedItems().filter((item: FileItem) => !item.isUploading);
|
||||
if (!items.length) {
|
||||
return;
|
||||
}
|
||||
items.map((item: FileItem) => item._prepareToUploading());
|
||||
items[ 0 ].upload();
|
||||
}
|
||||
|
||||
public cancelAll(): void {
|
||||
const items = this.getNotUploadedItems();
|
||||
items.map((item: FileItem) => item.cancel());
|
||||
}
|
||||
|
||||
public isFile(value: any): boolean {
|
||||
return isFile(value);
|
||||
}
|
||||
|
||||
public isFileLikeObject(value: any): boolean {
|
||||
return value instanceof FileLikeObject;
|
||||
}
|
||||
|
||||
public getIndexOfItem(value: any): number {
|
||||
return typeof value === 'number' ? value : this.queue.indexOf(value);
|
||||
}
|
||||
|
||||
public getNotUploadedItems(): any[] {
|
||||
return this.queue.filter((item: FileItem) => !item.isUploaded);
|
||||
}
|
||||
|
||||
public getReadyItems(): any[] {
|
||||
return this.queue
|
||||
.filter((item: FileItem) => (item.isReady && !item.isUploading))
|
||||
.sort((item1: any, item2: any) => item1.index - item2.index);
|
||||
}
|
||||
|
||||
public destroy(): void {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public onAfterAddingAll(fileItems: any): any {
|
||||
return { fileItems };
|
||||
}
|
||||
|
||||
public onBuildItemForm(fileItem: FileItem, form: any): any {
|
||||
return { fileItem, form };
|
||||
}
|
||||
|
||||
public onAfterAddingFile(fileItem: FileItem): any {
|
||||
return { fileItem };
|
||||
}
|
||||
|
||||
public onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): any {
|
||||
return { item, filter, options };
|
||||
}
|
||||
|
||||
public onBeforeUploadItem(fileItem: FileItem): any {
|
||||
return { fileItem };
|
||||
}
|
||||
|
||||
public onProgressItem(fileItem: FileItem, progress: any): any {
|
||||
return { fileItem, progress };
|
||||
}
|
||||
|
||||
public onProgressAll(progress: any): any {
|
||||
return { progress };
|
||||
}
|
||||
|
||||
public onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { item, response, status, headers };
|
||||
}
|
||||
|
||||
public onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { item, response, status, headers };
|
||||
}
|
||||
|
||||
public onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { item, response, status, headers };
|
||||
}
|
||||
|
||||
public onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): any {
|
||||
return { item, response, status, headers };
|
||||
}
|
||||
|
||||
public onCompleteAll(): any {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
public _mimeTypeFilter(item: FileLikeObject): boolean {
|
||||
return !(item?.type && this.options.allowedMimeType && this.options.allowedMimeType?.indexOf(item.type) === -1);
|
||||
}
|
||||
|
||||
public _fileSizeFilter(item: FileLikeObject): boolean {
|
||||
return !(this.options.maxFileSize && item.size > this.options.maxFileSize);
|
||||
}
|
||||
|
||||
public _fileTypeFilter(item: FileLikeObject): boolean {
|
||||
return !(this.options.allowedFileType &&
|
||||
this.options.allowedFileType.indexOf(FileType.getMimeClass(item)) === -1);
|
||||
}
|
||||
|
||||
public _onErrorItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
item._onError(response, status, headers);
|
||||
this.onErrorItem(item, response, status, headers);
|
||||
}
|
||||
|
||||
public _onCompleteItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
item._onComplete(response, status, headers);
|
||||
this.onCompleteItem(item, response, status, headers);
|
||||
const nextItem = this.getReadyItems()[ 0 ];
|
||||
this.isUploading = false;
|
||||
if (nextItem) {
|
||||
nextItem.upload();
|
||||
return;
|
||||
}
|
||||
this.onCompleteAll();
|
||||
this.progress = this._getTotalProgress();
|
||||
this._render();
|
||||
}
|
||||
|
||||
protected _headersGetter(parsedHeaders: ParsedResponseHeaders): any {
|
||||
return (name: any): any => {
|
||||
if (name) {
|
||||
return parsedHeaders[ name.toLowerCase() ] || void 0;
|
||||
}
|
||||
return parsedHeaders;
|
||||
};
|
||||
}
|
||||
|
||||
protected _xhrTransport(item: FileItem): any {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const that = this;
|
||||
const xhr = item._xhr = new XMLHttpRequest();
|
||||
let sendable: any;
|
||||
this._onBeforeUploadItem(item);
|
||||
|
||||
if (typeof item._file.size !== 'number') {
|
||||
throw new TypeError('The file specified is no longer valid');
|
||||
}
|
||||
if (!this.options.disableMultipart) {
|
||||
sendable = new FormData();
|
||||
this._onBuildItemForm(item, sendable);
|
||||
let appendFile;
|
||||
if (item.alias && item._file && item.file.name) {
|
||||
appendFile = () => sendable.append(item.alias, item._file, item.file.name);
|
||||
if (!this.options.parametersBeforeFiles) {
|
||||
appendFile();
|
||||
}
|
||||
}
|
||||
|
||||
// For AWS, Additional Parameters must come BEFORE Files
|
||||
if (this.options.additionalParameter !== undefined) {
|
||||
Object.keys(this.options.additionalParameter).forEach((key: string) => {
|
||||
let paramVal = this.options.additionalParameter?.[ key ];
|
||||
// Allow an additional parameter to include the filename
|
||||
if (typeof paramVal === 'string' && paramVal.indexOf('{{file_name}}') >= 0 && item.file?.name) {
|
||||
paramVal = paramVal.replace('{{file_name}}', item.file.name);
|
||||
}
|
||||
sendable.append(key, paramVal);
|
||||
});
|
||||
}
|
||||
|
||||
if (appendFile && this.options.parametersBeforeFiles) {
|
||||
appendFile();
|
||||
}
|
||||
} else {
|
||||
if (this.options.formatDataFunction) {
|
||||
sendable = this.options.formatDataFunction(item);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.upload.onprogress = (event: any) => {
|
||||
const progress = Math.round(event.lengthComputable ? event.loaded * 100 / event.total : 0);
|
||||
this._onProgressItem(item, progress);
|
||||
};
|
||||
xhr.onload = () => {
|
||||
const headers = this._parseHeaders(xhr.getAllResponseHeaders());
|
||||
const response = this._transformResponse(xhr.response, headers);
|
||||
const gist = this._isSuccessCode(xhr.status) ? 'Success' : 'Error';
|
||||
const method = '_on' + gist + 'Item';
|
||||
(this as any)[ method ](item, response, xhr.status, headers);
|
||||
this._onCompleteItem(item, response, xhr.status, headers);
|
||||
};
|
||||
xhr.onerror = () => {
|
||||
const headers = this._parseHeaders(xhr.getAllResponseHeaders());
|
||||
const response = this._transformResponse(xhr.response, headers);
|
||||
this._onErrorItem(item, response, xhr.status, headers);
|
||||
this._onCompleteItem(item, response, xhr.status, headers);
|
||||
};
|
||||
xhr.onabort = () => {
|
||||
const headers = this._parseHeaders(xhr.getAllResponseHeaders());
|
||||
const response = this._transformResponse(xhr.response, headers);
|
||||
this._onCancelItem(item, response, xhr.status, headers);
|
||||
this._onCompleteItem(item, response, xhr.status, headers);
|
||||
};
|
||||
if (item.method && item.url) {
|
||||
xhr.open(item.method, item.url, true);
|
||||
}
|
||||
xhr.withCredentials = item.withCredentials;
|
||||
if (this.options.headers) {
|
||||
for (const header of this.options.headers) {
|
||||
xhr.setRequestHeader(header.name, header.value);
|
||||
}
|
||||
}
|
||||
if (item.headers.length) {
|
||||
for (const header of item.headers) {
|
||||
xhr.setRequestHeader(header.name, header.value);
|
||||
}
|
||||
}
|
||||
if (this.authToken && this.authTokenHeader) {
|
||||
xhr.setRequestHeader(this.authTokenHeader, this.authToken);
|
||||
}
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState == XMLHttpRequest.DONE) {
|
||||
that.response.emit(xhr.responseText);
|
||||
}
|
||||
};
|
||||
if (this.options.formatDataFunctionIsAsync) {
|
||||
sendable.then(
|
||||
(result: any) => xhr.send(JSON.stringify(result))
|
||||
);
|
||||
} else {
|
||||
xhr.send(sendable);
|
||||
}
|
||||
this._render();
|
||||
}
|
||||
|
||||
protected _getTotalProgress(value = 0): number {
|
||||
if (this.options.removeAfterUpload) {
|
||||
return value;
|
||||
}
|
||||
const notUploaded = this.getNotUploadedItems().length;
|
||||
const uploaded = notUploaded ? this.queue.length - notUploaded : this.queue.length;
|
||||
const ratio = 100 / this.queue.length;
|
||||
const current = value * ratio / 100;
|
||||
return Math.round(uploaded * ratio + current);
|
||||
}
|
||||
|
||||
protected _getFilters(filters?: FilterFunction[] | string): FilterFunction[] | [] {
|
||||
if (!filters) {
|
||||
return this.options?.filters || [];
|
||||
}
|
||||
if (Array.isArray(filters)) {
|
||||
return filters;
|
||||
}
|
||||
if (typeof filters === 'string') {
|
||||
const names = filters.match(/[^\s,]+/g);
|
||||
return this.options?.filters || []
|
||||
.filter((filter: any) => names?.indexOf(filter.name) !== -1);
|
||||
}
|
||||
return this.options?.filters || [];
|
||||
}
|
||||
|
||||
protected _render(): any {
|
||||
return void 0;
|
||||
}
|
||||
|
||||
protected _queueLimitFilter(): boolean {
|
||||
return this.options.queueLimit === undefined || this.queue.length < this.options.queueLimit;
|
||||
}
|
||||
|
||||
protected _isValidFile(file: FileLikeObject, filters: FilterFunction[], options: FileUploaderOptions): boolean {
|
||||
this._failFilterIndex = -1;
|
||||
return !filters.length ? true : filters.every((filter: FilterFunction) => {
|
||||
if (typeof this._failFilterIndex === 'number') {
|
||||
this._failFilterIndex++;
|
||||
}
|
||||
return filter.fn.call(this, file, options);
|
||||
});
|
||||
}
|
||||
|
||||
protected _isSuccessCode(status: number): boolean {
|
||||
return (status >= 200 && status < 300) || status === 304;
|
||||
}
|
||||
|
||||
protected _transformResponse(response: string, headers: ParsedResponseHeaders): string {
|
||||
return response;
|
||||
}
|
||||
|
||||
protected _parseHeaders(headers: string): ParsedResponseHeaders {
|
||||
const parsed: any = {};
|
||||
let key: any;
|
||||
let val: any;
|
||||
let i: any;
|
||||
if (!headers) {
|
||||
return parsed;
|
||||
}
|
||||
headers.split('\n').map((line: any) => {
|
||||
i = line.indexOf(':');
|
||||
key = line.slice(0, i).trim().toLowerCase();
|
||||
val = line.slice(i + 1).trim();
|
||||
if (key) {
|
||||
parsed[ key ] = parsed[ key ] ? parsed[ key ] + ', ' + val : val;
|
||||
}
|
||||
});
|
||||
return parsed;
|
||||
}
|
||||
|
||||
protected _onWhenAddingFileFailed(item: FileLikeObject, filter: any, options: any): void {
|
||||
this.onWhenAddingFileFailed(item, filter, options);
|
||||
}
|
||||
|
||||
protected _onAfterAddingFile(item: FileItem): void {
|
||||
this.onAfterAddingFile(item);
|
||||
}
|
||||
|
||||
protected _onAfterAddingAll(items: any): void {
|
||||
this.onAfterAddingAll(items);
|
||||
}
|
||||
|
||||
protected _onBeforeUploadItem(item: FileItem): void {
|
||||
item._onBeforeUpload();
|
||||
this.onBeforeUploadItem(item);
|
||||
}
|
||||
|
||||
protected _onBuildItemForm(item: FileItem, form: any): void {
|
||||
item._onBuildForm(form);
|
||||
this.onBuildItemForm(item, form);
|
||||
}
|
||||
|
||||
protected _onProgressItem(item: FileItem, progress: any): void {
|
||||
const total = this._getTotalProgress(progress);
|
||||
this.progress = total;
|
||||
item._onProgress(progress);
|
||||
this.onProgressItem(item, progress);
|
||||
this.onProgressAll(total);
|
||||
this._render();
|
||||
}
|
||||
|
||||
protected _onSuccessItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
item._onSuccess(response, status, headers);
|
||||
this.onSuccessItem(item, response, status, headers);
|
||||
}
|
||||
|
||||
protected _onCancelItem(item: FileItem, response: string, status: number, headers: ParsedResponseHeaders): void {
|
||||
item._onCancel(response, status, headers);
|
||||
this.onCancelItem(item, response, status, headers);
|
||||
}
|
||||
}
|
||||
9
libs/ng2-file-upload/index.ts
Normal file
9
libs/ng2-file-upload/index.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
export * from './file-upload/file-drop.directive';
|
||||
export * from './file-upload/file-uploader.class';
|
||||
export * from './file-upload/file-item.class';
|
||||
export * from './file-upload/file-like-object.class';
|
||||
export * from './file-upload/file-like-object.class';
|
||||
|
||||
export { FileUploadModule } from './file-upload/file-upload.module';
|
||||
export { FileSelectDirective } from './file-upload/file-select.directive';
|
||||
26
libs/ng2-file-upload/jest.config.js
Normal file
26
libs/ng2-file-upload/jest.config.js
Normal file
@@ -0,0 +1,26 @@
|
||||
module.exports = {
|
||||
displayName: 'ng2-file-upload',
|
||||
preset: '../../jest.preset.js',
|
||||
setupFilesAfterEnv: ['<rootDir>/testing/test-setup.ts'],
|
||||
globals: {
|
||||
'ts-jest': {
|
||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
||||
astTransformers: {
|
||||
before: [
|
||||
'jest-preset-angular/build/InlineFilesTransformer',
|
||||
'jest-preset-angular/build/StripStylesTransformer',
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest'
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
|
||||
coverageDirectory: '../../coverage/libs/ng2-file-upload',
|
||||
snapshotSerializers: [
|
||||
'jest-preset-angular/build/AngularNoNgAttributesSnapshotSerializer.js',
|
||||
'jest-preset-angular/build/AngularSnapshotSerializer.js',
|
||||
'jest-preset-angular/build/HTMLCommentSerializer.js',
|
||||
]
|
||||
};
|
||||
7
libs/ng2-file-upload/ng-package.json
Normal file
7
libs/ng2-file-upload/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../dist/libs/ng2-file-upload",
|
||||
"lib": {
|
||||
"entryFile": "index.ts"
|
||||
}
|
||||
}
|
||||
4
libs/ng2-file-upload/package.json
Normal file
4
libs/ng2-file-upload/package.json
Normal file
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"name": "ng2-file-upload",
|
||||
"version": "1.3.0"
|
||||
}
|
||||
148
libs/ng2-file-upload/testing/spec/file-drop.directive.spec.ts
Normal file
148
libs/ng2-file-upload/testing/spec/file-drop.directive.spec.ts
Normal file
@@ -0,0 +1,148 @@
|
||||
import { Component, DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
import { inject, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FileUploader } from '../../file-upload/file-uploader.class';
|
||||
import { FileUploadModule } from '../../file-upload/file-upload.module';
|
||||
import { FileDropDirective } from '../../file-upload/file-drop.directive';
|
||||
|
||||
@Component({
|
||||
selector: 'container',
|
||||
template: `<div type="file"
|
||||
ng2FileDrop
|
||||
[uploader]="uploader"
|
||||
></div>`
|
||||
})
|
||||
export class ContainerComponent {
|
||||
public get url(): string { return 'localhost:3000'; }
|
||||
public uploader: FileUploader = new FileUploader({ url: this.url });
|
||||
}
|
||||
|
||||
describe('Directive: FileDropDirective', () => {
|
||||
|
||||
let fixture: ComponentFixture<ContainerComponent>;
|
||||
let hostComponent: ContainerComponent;
|
||||
let directiveElement: DebugElement;
|
||||
let fileDropDirective: FileDropDirective;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ FileUploadModule ],
|
||||
declarations: [ ContainerComponent ],
|
||||
providers: [ ContainerComponent ]
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ContainerComponent);
|
||||
hostComponent = fixture.componentInstance;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
directiveElement = fixture.debugElement.query(By.directive(FileDropDirective));
|
||||
fileDropDirective = directiveElement.injector.get(FileDropDirective) as FileDropDirective;
|
||||
});
|
||||
|
||||
it('can be initialized', () => {
|
||||
expect(fixture).toBeDefined();
|
||||
expect(hostComponent).toBeDefined();
|
||||
expect(fileDropDirective).toBeDefined();
|
||||
});
|
||||
|
||||
it('can set file uploader', () => {
|
||||
expect(fileDropDirective.uploader).toBe(hostComponent.uploader);
|
||||
});
|
||||
|
||||
it('can get uploader options', () => {
|
||||
const options = fileDropDirective.getOptions();
|
||||
|
||||
// Check url set through binding
|
||||
// Check default options
|
||||
expect(options).toBeTruthy();
|
||||
if (options) {
|
||||
expect(options.url).toBe(hostComponent.url);
|
||||
expect(options.autoUpload).toBeFalsy();
|
||||
expect(options.isHTML5).toBeTruthy();
|
||||
expect(options.removeAfterUpload).toBeFalsy();
|
||||
expect(options.disableMultipart).toBeFalsy();
|
||||
}
|
||||
});
|
||||
|
||||
it('can get filters', () => {
|
||||
const filters = fileDropDirective.getFilters();
|
||||
|
||||
// TODO: Update test once implemented
|
||||
expect(filters).toEqual({});
|
||||
});
|
||||
|
||||
it('handles drop event', () => {
|
||||
spyOn(fileDropDirective, 'onDrop');
|
||||
|
||||
directiveElement.triggerEventHandler('drop', getFakeEventData());
|
||||
|
||||
expect(fileDropDirective.onDrop).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('adds file to upload', () => {
|
||||
spyOn(fileDropDirective.uploader, 'addToQueue');
|
||||
|
||||
let fileOverData;
|
||||
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
|
||||
|
||||
let fileDropData;
|
||||
fileDropDirective.onFileDrop.subscribe((data: File[]) => fileDropData = data);
|
||||
|
||||
fileDropDirective.onDrop(getFakeEventData());
|
||||
|
||||
const uploadedFiles = getFakeEventData().dataTransfer.files;
|
||||
|
||||
expect(fileDropDirective.uploader.addToQueue).toHaveBeenCalledWith(uploadedFiles, fileDropDirective.getOptions(), fileDropDirective.getFilters());
|
||||
expect(fileOverData).toBeFalsy();
|
||||
expect(fileDropData).toEqual(uploadedFiles);
|
||||
});
|
||||
|
||||
it('handles dragover event', () => {
|
||||
spyOn(fileDropDirective, 'onDragOver');
|
||||
|
||||
directiveElement.triggerEventHandler('dragover', getFakeEventData());
|
||||
|
||||
expect(fileDropDirective.onDragOver).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles file over', () => {
|
||||
let fileOverData;
|
||||
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
|
||||
|
||||
fileDropDirective.onDragOver(getFakeEventData());
|
||||
|
||||
expect(fileOverData).toBeTruthy();
|
||||
});
|
||||
|
||||
it('handles dragleave event', () => {
|
||||
spyOn(fileDropDirective, 'onDragLeave');
|
||||
|
||||
directiveElement.triggerEventHandler('dragleave', getFakeEventData());
|
||||
|
||||
expect(fileDropDirective.onDragLeave).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles file over leave', () => {
|
||||
let fileOverData;
|
||||
fileDropDirective.fileOver.subscribe((data: any) => fileOverData = data);
|
||||
|
||||
fileDropDirective.onDragLeave(getFakeEventData());
|
||||
|
||||
expect(fileOverData).toBeFalsy();
|
||||
});
|
||||
});
|
||||
|
||||
function getFakeEventData(): any {
|
||||
return {
|
||||
dataTransfer: {
|
||||
files: [ 'foo.bar' ],
|
||||
types: [ 'Files' ]
|
||||
},
|
||||
preventDefault: () => undefined,
|
||||
stopPropagation: () => undefined
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { Component, DebugElement } from '@angular/core';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
import { FileUploadModule } from '../../file-upload/file-upload.module';
|
||||
import { FileSelectDirective } from '../../file-upload/file-select.directive';
|
||||
import { FileUploader } from '../../file-upload/file-uploader.class';
|
||||
|
||||
@Component({
|
||||
selector: 'container',
|
||||
template: `<input type="file"
|
||||
ng2FileSelect
|
||||
[uploader]="uploader"
|
||||
/>`
|
||||
})
|
||||
export class ContainerComponent {
|
||||
public get url(): string { return 'localhost:3000'; }
|
||||
public uploader: FileUploader = new FileUploader({ url: this.url });
|
||||
}
|
||||
|
||||
describe('Directive: FileSelectDirective', () => {
|
||||
let fixture: ComponentFixture<ContainerComponent>;
|
||||
let hostComponent: ContainerComponent;
|
||||
let directiveElement: DebugElement;
|
||||
let fileSelectDirective: FileSelectDirective;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [ FileUploadModule ],
|
||||
declarations: [ ContainerComponent ],
|
||||
providers: [ ContainerComponent ]
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ContainerComponent);
|
||||
hostComponent = fixture.componentInstance;
|
||||
|
||||
fixture.detectChanges();
|
||||
|
||||
directiveElement = fixture.debugElement.query(By.directive(FileSelectDirective));
|
||||
fileSelectDirective = directiveElement.injector.get(FileSelectDirective) as FileSelectDirective;
|
||||
});
|
||||
|
||||
it('can be initialized', () => {
|
||||
expect(fixture).toBeDefined();
|
||||
expect(hostComponent).toBeDefined();
|
||||
expect(fileSelectDirective).toBeDefined();
|
||||
});
|
||||
|
||||
it('can set file uploader', () => {
|
||||
expect(fileSelectDirective.uploader).toBe(hostComponent.uploader);
|
||||
});
|
||||
|
||||
it('can get uploader options', () => {
|
||||
const options = fileSelectDirective.getOptions();
|
||||
expect(options).toBeTruthy();
|
||||
if (options) {
|
||||
// Check url set through binding
|
||||
expect(options.url).toBe(hostComponent.url);
|
||||
|
||||
// Check default options
|
||||
expect(options.autoUpload).toBeFalsy();
|
||||
expect(options.isHTML5).toBeTruthy();
|
||||
expect(options.removeAfterUpload).toBeFalsy();
|
||||
expect(options.disableMultipart).toBeFalsy();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
it('can get filters', () => {
|
||||
const filters = fileSelectDirective.getFilters();
|
||||
|
||||
// TODO: Update test once implemented
|
||||
expect(filters).toEqual({});
|
||||
});
|
||||
|
||||
it('can check if element is empty', () => {
|
||||
const isElementEmpty = fileSelectDirective.isEmptyAfterSelection();
|
||||
|
||||
expect(isElementEmpty).toBeFalsy();
|
||||
});
|
||||
|
||||
it('can listed on change event', () => {
|
||||
spyOn(fileSelectDirective, 'onChange');
|
||||
|
||||
directiveElement.triggerEventHandler('change', {});
|
||||
|
||||
expect(fileSelectDirective.onChange).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('handles change event', () => {
|
||||
spyOn(fileSelectDirective.uploader, 'addToQueue');
|
||||
|
||||
fileSelectDirective.onChange();
|
||||
|
||||
expect(fileSelectDirective.uploader.addToQueue).toHaveBeenCalledWith(directiveElement.nativeElement.files, fileSelectDirective.getOptions(), fileSelectDirective.getFilters());
|
||||
});
|
||||
});
|
||||
1
libs/ng2-file-upload/testing/test-setup.ts
Normal file
1
libs/ng2-file-upload/testing/test-setup.ts
Normal file
@@ -0,0 +1 @@
|
||||
import 'jest-preset-angular';
|
||||
28
libs/ng2-file-upload/tsconfig.json
Normal file
28
libs/ng2-file-upload/tsconfig.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"files": [],
|
||||
"include": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.lib.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.lib.prod.json"
|
||||
},
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
],
|
||||
"compilerOptions": {
|
||||
"forceConsistentCasingInFileNames": false,
|
||||
"strict": false,
|
||||
"noImplicitReturns": false,
|
||||
"noFallthroughCasesInSwitch": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"strictInjectionParameters": false,
|
||||
"strictTemplates": false,
|
||||
"fullTemplateTypeCheck": false
|
||||
}
|
||||
}
|
||||
|
||||
23
libs/ng2-file-upload/tsconfig.lib.json
Normal file
23
libs/ng2-file-upload/tsconfig.lib.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": ["dom", "es2018"]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"include": [
|
||||
"**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
libs/ng2-file-upload/tsconfig.lib.prod.json
Normal file
10
libs/ng2-file-upload/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
12
libs/ng2-file-upload/tsconfig.spec.json
Normal file
12
libs/ng2-file-upload/tsconfig.spec.json
Normal file
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user