| /******************************************************************************** |
| * Copyright (c) 2020 Contributors to the Eclipse Foundation |
| * |
| * See the NOTICE file(s) distributed with this work for additional |
| * information regarding copyright ownership. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0 |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| ********************************************************************************/ |
| |
| import {Component, ElementRef, EventEmitter, forwardRef, HostBinding, HostListener, Input, Output, ViewChild} from "@angular/core"; |
| import {ControlValueAccessor, NG_VALUE_ACCESSOR} from "@angular/forms"; |
| |
| @Component({ |
| selector: "app-file-drop", |
| templateUrl: "./file-drop.component.html", |
| styleUrls: ["./file-drop.component.scss"], |
| providers: [ |
| { |
| provide: NG_VALUE_ACCESSOR, |
| useExisting: forwardRef(() => FileDropComponent), |
| multi: true |
| } |
| ] |
| }) |
| export class FileDropComponent implements ControlValueAccessor { |
| |
| @HostBinding("class.no-drop") |
| @Input() |
| public appDisabled = false; |
| |
| @Input() |
| public appValue: File[]; |
| |
| @Output() |
| public appValueChange = new EventEmitter<File[]>(); |
| |
| @Output() |
| public appValueDelete = new EventEmitter<File>(); |
| |
| @ViewChild("inputElement") |
| public inputElement: ElementRef<HTMLInputElement>; |
| |
| public onChange = (_: File[]) => null; |
| |
| public onTouch = () => null; |
| |
| @HostListener("dragover", ["$event"]) |
| public onDragOver(event: DragEvent) { |
| if (this.appDisabled) { |
| return; |
| } |
| |
| try { |
| // Prevent dropped files from being opened. |
| event.preventDefault(); |
| } catch (e) { |
| return; |
| } |
| } |
| |
| @HostListener("drop", ["$event"]) |
| public onDrop(event: DragEvent) { |
| if (this.appDisabled) { |
| return; |
| } |
| |
| if (event?.dataTransfer?.files?.length > 0) { |
| event.preventDefault(); |
| this.onInput(event?.dataTransfer?.files); |
| } |
| } |
| |
| public openDialog(): void { |
| if (!this.appDisabled && typeof this.inputElement?.nativeElement?.click === "function") { |
| this.inputElement.nativeElement.value = ""; |
| this.inputElement.nativeElement.click(); |
| } |
| } |
| |
| public onInput(fileList: FileList) { |
| if (this.appDisabled) { |
| return; |
| } |
| |
| this.appValue = [ |
| ...(Array.isArray(this.appValue) ? this.appValue : []), |
| ...fileListToFileArray(fileList) |
| ]; |
| this.appValueChange.emit(this.appValue); |
| this.onChange(this.appValue); |
| this.onTouch(); |
| } |
| |
| public onDelete(index: number) { |
| if (this.appDisabled || this.appValue[index] == null || typeof index !== "number") { |
| return; |
| } |
| const file = this.appValue[index]; |
| |
| this.appValue = [ |
| ...this.appValue.slice(0, index), |
| ...this.appValue.slice(index + 1) |
| ]; |
| |
| this.appValueDelete.emit(file); |
| this.appValueChange.emit(this.appValue); |
| this.onChange(this.appValue); |
| this.onTouch(); |
| } |
| |
| public writeValue(obj: File[]): void { |
| if (!Array.isArray(obj)) { |
| return; |
| } |
| this.appValue = obj.filter((file) => file instanceof File); |
| } |
| |
| public registerOnChange(fn: any): void { |
| this.onChange = typeof fn === "function" ? fn : this.onChange; |
| } |
| |
| public registerOnTouched(fn: any): void { |
| this.onTouch = typeof fn === "function" ? fn : this.onTouch; |
| } |
| |
| } |
| |
| function fileListToFileArray(fileList: FileList): File[] { |
| try { |
| const result: File[] = []; |
| for (let i = 0; i < fileList?.length; i++) { |
| result.push(fileList?.item(i)); |
| } |
| return result; |
| } catch (e) { |
| return []; |
| } |
| } |