diff --git a/src/components/inputfile.component.ts b/src/components/inputfile.component.ts index d575bb2..9aae309 100644 --- a/src/components/inputfile.component.ts +++ b/src/components/inputfile.component.ts @@ -1,4 +1,4 @@ -import { Component, Injector, OnInit, Optional, Renderer2, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, Injector, Optional, Renderer2, ViewChild } from '@angular/core'; import { FormGroup, FormGroupDirective, NgForm } from '@angular/forms'; import { HttpClientUploadService } from '../'; import { InputFileOptions } from '../utils/configuration.model'; @@ -8,14 +8,15 @@ import { InputFileOptions } from '../utils/configuration.model'; selector: 'ngx-upload-inputfile', template: ` `, styles: ['input[type="file"] { display: none; } .input-file { width: 100%; }'] }) -export class InputfileComponent implements OnInit { +export class InputfileComponent implements AfterViewInit { - @ViewChild('file') file; + @ViewChild('file', {static: false}) file; files: Set = new Set(); @@ -24,6 +25,8 @@ export class InputfileComponent implements OnInit { private formGroup: FormGroup | null; + folder: boolean = false; + constructor(private injector: Injector, private uploader: HttpClientUploadService, private renderer: Renderer2, @Optional() private ngForm: NgForm, @Optional() private formGroupDirective: FormGroupDirective) { if (this.ngForm) { @@ -39,7 +42,7 @@ export class InputfileComponent implements OnInit { this.uploader.addToQueue(this.file.nativeElement.files, this.formGroup); } - ngOnInit() { + ngAfterViewInit() { if (this.options.multiple !== false) this.renderer.setProperty(this.file.nativeElement, 'multiple', 'multiple'); if (this.options.accept) this.renderer.setProperty(this.file.nativeElement, 'accept', this.options.accept.join()); if (this.options.capture) this.renderer.setProperty(this.file.nativeElement, 'capture', this.options.capture); diff --git a/src/directives/dropzone.directive.ts b/src/directives/dropzone.directive.ts index 9526b7a..c7c9634 100644 --- a/src/directives/dropzone.directive.ts +++ b/src/directives/dropzone.directive.ts @@ -78,9 +78,27 @@ export class NgxDragAndDropDirective implements OnInit { if (!transfer) { return; } + // Not support IE (folder upload) + if (this.dropOptions.folderAccept == true && NgxDragAndDropDirective.getVersionOfIE() == -1) + { + this.getFilesWebkitDataTransferItems(transfer.items).then( + (data : File[])=>{ + this.uploader.addToQueue(data, this.formGroup, this.dropOptions); + } + ) + } + else + { + var files = transfer.files; + var filelist: File[] = []; + for(var i = 0;i < files.length;i++) + { + filelist.push(files.item(i)); + } + this.uploader.addToQueue(filelist, this.formGroup, this.dropOptions); + } transfer.dropEffect = 'copy'; this.stopAndPrevent(event); - this.uploader.addToQueue(transfer.files, this.formGroup, this.dropOptions); } @@ -119,4 +137,66 @@ export class NgxDragAndDropDirective implements OnInit { } } + + private static getVersionOfIE() { + var word; + var agent = navigator.userAgent.toLowerCase(); + + // IE old version ( IE 10 or Lower ) + if ( navigator.appName == "Microsoft Internet Explorer" ) word = "msie "; + + // IE 11 + else if ( agent.search( "trident" ) > -1 ) word = "trident/.*rv:"; + + // Microsoft Edge + else if ( agent.search( "edge/" ) > -1 ) word = "edge/"; + + else return -1; + + var reg = new RegExp( word + "([0-9]{1,})(\\.{0,}[0-9]{0,1})" ); + if (reg.exec( agent ) != null) + return parseFloat( RegExp.$1 + RegExp.$2 ); + return -1; + } + + private getFilesWebkitDataTransferItems(dataTransferItems) { + function traverseFileTreePromise(item, path='') { + return new Promise( + resolve => { + if (item.isFile) { + item.file( + file => { + file.filePath = path + file.name; //save full path + files.push(file); + resolve(file); + } + ); + } else if (item.isDirectory) { + let dirReader = item.createReader(); + dirReader.readEntries(entries => { + let entriesPromises = []; + entries.forEach(element => { + entriesPromises.push(traverseFileTreePromise(element, path + item.name + "/")) + }); + resolve(Promise.all(entriesPromises)) + }) + } + }) + } + + let files = []; + return new Promise((resolve) => { + let entriesPromises = []; + + for (let it of dataTransferItems) + entriesPromises.push(traverseFileTreePromise(it.webkitGetAsEntry())); + + Promise.all(entriesPromises).then(entries => { + resolve(files) + }); + }); + } + + + } diff --git a/src/directives/inputfile.directive.ts b/src/directives/inputfile.directive.ts index fd0e9a4..c65ffaf 100644 --- a/src/directives/inputfile.directive.ts +++ b/src/directives/inputfile.directive.ts @@ -13,6 +13,9 @@ export class NgxInputFileDirective implements OnInit { @Input() ngxInputFile: InputFileOptions; + @Input() + folder: boolean = false; + constructor(private resolver: ComponentFactoryResolver, private injector: Injector, private vcRef: ViewContainerRef, private templateRef: TemplateRef) { } @@ -22,6 +25,7 @@ export class NgxInputFileDirective implements OnInit { const factory = this.resolver.resolveComponentFactory(InputfileComponent); const component: ComponentRef = this.vcRef.createComponent(factory, 0, this.injector, [_contentViewRef.rootNodes]); component.instance.options = (this.ngxInputFile) ? this.ngxInputFile : ngxInputFileOptions; + component.instance.folder = this.folder; _contentViewRef.detectChanges(); } } diff --git a/src/index.ts b/src/index.ts index 8cf7d8e..77b19c8 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,7 @@ import { HttpClientUploadService } from './services/httpClientUpload.service'; import { NgxThumbnailDirective } from './directives/thumbnail.directive'; import { NgxInputFileDirective } from './directives/inputfile.directive'; import { InputfileComponent } from './components/inputfile.component'; +import { CommonModule } from '@angular/common'; export { DropTargetOptions, UploadEndPoint, LoggerOptions, InputFileOptions } from './utils/configuration.model'; export { MineTypeEnum } from './utils/mimetype.model'; export { FileItem } from './services/fileItem.model'; @@ -43,6 +44,8 @@ export function _loggerFactory(options: LoggerOptions): NgxUploadLogger { } @NgModule({ + + imports: [CommonModule], declarations: [ ...ngxDeclarations ], diff --git a/src/services/abstractUpload.service.ts b/src/services/abstractUpload.service.ts index 8da6223..461ff99 100644 --- a/src/services/abstractUpload.service.ts +++ b/src/services/abstractUpload.service.ts @@ -33,7 +33,7 @@ export abstract class AbstractUploadService { /** * Adds files to the queue */ - addToQueue(files: FileList, formGroup: FormGroup | null, dropOptions?: DropTargetOptions) { + addToQueue(files: File[], formGroup: FormGroup | null, dropOptions?: DropTargetOptions) { this.logger.info('add to queue'); @@ -46,8 +46,8 @@ export abstract class AbstractUploadService { } for (let i = 0; i < files.length; i++) { - const file = files.item(i)!; - this.logger.debug(files.item(i)); + const file = files[i]!; + this.logger.debug(files[i]); if (dropOptions && dropOptions.accept) { const accepted = dropOptions.accept.some((type: string) => type === file.type); diff --git a/src/services/fileItem.model.ts b/src/services/fileItem.model.ts index 5a5ffdf..75b8dc7 100644 --- a/src/services/fileItem.model.ts +++ b/src/services/fileItem.model.ts @@ -21,6 +21,20 @@ export class FileItem { constructor(public file: File, private uploadService: AbstractUploadService, protected logger: NgxUploadLogger) { } + public get filePath() : string + { + var file : any = this.file; + if (file.webkitRelativePath != undefined && file.webkitRelativePath != "") + { + return file.webkitRelativePath; + } + + if (file.filePath != undefined) + return file.filePath; + + return file.name; + } + upload(endpoint: UploadEndPoint, options?: any) { if (endpoint) { this.uploadService.uploadFileItem(this, endpoint, options); diff --git a/src/utils/configuration.model.ts b/src/utils/configuration.model.ts index 46b48da..cc75763 100644 --- a/src/utils/configuration.model.ts +++ b/src/utils/configuration.model.ts @@ -13,7 +13,8 @@ export interface DropTargetOptions { colorDrop: string, accept?: MineTypeEnum[], capture?: 'user' | 'environment', - multiple?: boolean + multiple?: boolean, + folderAccept?: boolean } export interface LoggerOptions {