Browse Source

Drag and drop of folders.

release/4.x
Sebastian 5 years ago
parent
commit
393b9cf4ab
  1. 109
      frontend/app/framework/angular/forms/file-drop.directive.ts

109
frontend/app/framework/angular/forms/file-drop.directive.ts

@ -6,6 +6,7 @@
*/ */
// tslint:disable: prefer-for-of // tslint:disable: prefer-for-of
// tslint:disable: readonly-array
import { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2 } from '@angular/core'; import { Directive, ElementRef, EventEmitter, HostListener, Input, Output, Renderer2 } from '@angular/core';
import { Types } from '@app/framework/internal'; import { Types } from '@app/framework/internal';
@ -45,18 +46,16 @@ export class FileDropDirective {
} }
@HostListener('paste', ['$event']) @HostListener('paste', ['$event'])
public onPaste(event: ClipboardEvent) { public async onPaste(event: ClipboardEvent) {
if (this.noPaste) { if (!this.noPaste) {
return; this.stopEvent(event);
}
const files = this.getAllowedFiles(event.clipboardData); const files = await this.getAllowedFiles(event.clipboardData);
if (files && !this.disabled) { if (files && !this.disabled) {
this.drop.emit(files); this.drop.emit(files);
}
} }
this.stopEvent(event);
} }
@HostListener('dragend', ['$event']) @HostListener('dragend', ['$event'])
@ -88,16 +87,15 @@ export class FileDropDirective {
} }
@HostListener('drop', ['$event']) @HostListener('drop', ['$event'])
public onDrop(event: DragDropEvent) { public async onDrop(event: DragDropEvent) {
if (hasFiles(event.dataTransfer)) { if (hasFiles(event.dataTransfer)) {
const files = this.getAllowedFiles(event.dataTransfer); this.stopDrag(event);
const files = await this.getAllowedFiles(event.dataTransfer);
if (files && !this.disabled) { if (files && !this.disabled) {
this.drop.emit(files); this.drop.emit(files);
} }
this.dragEnd(0);
this.stopEvent(event);
} }
} }
@ -106,6 +104,11 @@ export class FileDropDirective {
event.stopPropagation(); event.stopPropagation();
} }
private stopDrag(event: DragDropEvent) {
this.dragEnd(0);
this.stopEvent(event);
}
private dragStart() { private dragStart() {
this.dragCounter++; this.dragCounter++;
@ -122,30 +125,20 @@ export class FileDropDirective {
} }
} }
private getAllowedFiles(dataTransfer: DataTransfer | null) { private async getAllowedFiles(dataTransfer: DataTransfer | null) {
if (!dataTransfer || !hasFiles(dataTransfer)) { if (!dataTransfer || !hasFiles(dataTransfer)) {
return null; return null;
} }
const files: File[] = []; let files: File[] = [];
for (let i = 0; i < dataTransfer.files.length; i++) { for (let i = 0; i < dataTransfer.items.length; i++) {
const file = dataTransfer.files.item(i); const item = dataTransfer.items[i];
if (file && this.isAllowedFile(file)) { await transferFileTree(item, files);
files.push(file);
}
} }
if (files.length === 0) { files = files.filter(f => this.isAllowedFile(f));
for (let i = 0; i < dataTransfer.items.length; i++) {
const file = dataTransfer.items[i].getAsFile();
if (file && this.isAllowedFile(file)) {
files.push(file);
}
}
}
return files.length > 0 ? files : null; return files.length > 0 ? files : null;
} }
@ -203,6 +196,62 @@ function hasFiles(dataTransfer: DataTransfer): boolean {
} }
} }
async function transferWebkitTree(item: any, files: File[]) {
if (item.isFile) {
const file = await getFilePromise(item);
files.push(file);
} else if (item.isDirectory) {
const entries = await getFilesPromise(item);
for (const entry of entries) {
await transferWebkitTree(entry, files);
}
}
}
async function transferFileTree(item: DataTransferItem, files: File[]) {
if (Types.isFunction(item['webkitGetAsEntry'])) {
const webkitEntry = item.webkitGetAsEntry();
if (webkitEntry) {
await transferWebkitTree(webkitEntry, files);
return;
}
}
if (Types.isFunction(item['getAsFile'])) {
const fileItem = item.getAsFile();
if (fileItem) {
files.push(fileItem);
}
}
}
function getFilesPromise(item: any): Promise<ReadonlyArray<any>> {
return new Promise((resolve, reject) => {
try {
const reader = item.createReader();
reader.readEntries(resolve);
} catch (ex) {
reject(ex);
}
});
}
function getFilePromise(item: any): Promise<File> {
return new Promise((resolve, reject) => {
try {
item.file(resolve);
} catch (ex) {
reject(ex);
}
});
}
interface DragDropEvent extends MouseEvent { interface DragDropEvent extends MouseEvent {
readonly dataTransfer: DataTransfer; readonly dataTransfer: DataTransfer;
} }
Loading…
Cancel
Save