Flickering due to fileover flag when child element is used
avi150890 opened this issue · 4 comments
avi150890 commented
Hi,
When drag area contains child element, then flickering happens as fileover value changes from true to false continuously.
I can't disable pointer event in child, as child element has click events.
How we will be able to resolve the issue?
avi150890 commented
Thanks a lot,
I will try to use in my existing code.
…On Sat, Dec 4, 2021, 23:35 Friederich Christophe ***@***.***> wrote:
import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from ***@***.***/core';import { FileUploaderOptions, FileUploader } from 'ng2-file-upload';
@directive({ selector: '[ng2FileDrop]' })export class FileDropDirective {
@input() uploader?: FileUploader;
@output() fileOver: EventEmitter<boolean> = new EventEmitter();
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
@output() onFileDrop: EventEmitter<FileList> = new EventEmitter<FileList>();
public isDraggingOverDropZone = false;
constructor(private _elementRef: ElementRef) {}
getOptions(): FileUploaderOptions | void {
return this.uploader?.options;
}
getFilters(): string {
return '';
}
@HostListener('drop', ['$event'])
onDrop(event: DragEvent): void {
this.isDraggingOverDropZone = false;
if (event.dataTransfer) {
const dataTransfer = event.dataTransfer;
const options = this.getOptions();
const filters = this.getFilters();
this._preventAndStop(event);
if (options) {
const files: File[] = [];
for (let index = 0; index < dataTransfer.files.length; index++) {
const element = dataTransfer.files.item(index);
if (element) files.push(element);
}
this.uploader?.addToQueue(files, options, filters);
}
this.fileOver.emit(false);
this.onFileDrop.emit(dataTransfer.files);
}
}
@HostListener('dragover', ['$event'])
onDragOver(event: DragEvent): void {
if (event.dataTransfer) {
const dataTransfer = event.dataTransfer;
if (!this.haveFiles(dataTransfer.types)) {
return;
}
if (!this.isDraggingOverDropZone) {
this.isDraggingOverDropZone = true;
this.fileOver.emit(true);
}
this._preventAndStop(event);
dataTransfer.dropEffect = 'copy';
}
}
@HostListener('dragleave', ['$event'])
onDragLeave(event: MouseEvent): void {
if (this._elementRef) {
if (event.currentTarget === this._elementRef.nativeElement) {
return;
}
}
if (this.isDraggingOverDropZone) {
this.isDraggingOverDropZone = false;
this.fileOver.emit(false);
}
}
protected _preventAndStop(event: MouseEvent): void {
event.preventDefault();
event.stopPropagation();
}
protected haveFiles(types: readonly string[]): boolean {
if (!types) {
return false;
}
return types.indexOf('Files') !== -1;
}}
Hi,
I don't try to find the problem, but after fix all types, the above code
works.
// maybe this change
if (event.currentTarget === (this as any).element[ 0 ]) {// to
if (event.currentTarget === this._elementRef.nativeElement) {
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#1190 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AKPAVZBFOQ6SXLRQH2ZZKE3UPJJ4ZANCNFSM5IEOQRCQ>
.
devacfr commented
Hi,
Sorry, I removed the comment because the dragleave didn’t work.
I can propose another following code. I add isDescendant function in dragleave to check if mouse pointer is in dropzone yet.
import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from ***@***.***/core';
import { FileUploaderOptions, FileUploader } from 'ng2-file-upload';
function isDescendant(parent: Element, child: Element | null): boolean {
if (child == null) return false;
if (child === parent) return false;
let node = child.parentNode;
while (node != null) {
if (node === parent) {
return true;
}
node = node.parentNode;
}
return false;
}
/**
* Modification of ng2FileDrop directive to fix the Flickering
* Issue: #1190
*/
@directive({ selector: ‘[ng2FileDrop]' })
export class FileDropDirective {
@input() uploader?: FileUploader;
@output() fileOver: EventEmitter<boolean> = new EventEmitter();
// eslint-disable-next-line @angular-eslint/no-output-on-prefix
@output() onFileDrop: EventEmitter<FileList> = new EventEmitter<FileList>();
public isDraggingOverDropZone = false;
constructor(private _elementRef: ElementRef) {}
public getOptions(): FileUploaderOptions | undefined {
return this.uploader?.options;
}
public getFilters(): string {
return '';
}
@HostListener('drop', ['$event'])
protected onDrop(event: DragEvent): void {
this.isDraggingOverDropZone = false;
if (event.dataTransfer) {
const dataTransfer = event.dataTransfer;
const options = this.getOptions();
const filters = this.getFilters();
this.preventAndStop(event);
if (options) {
const files: File[] = [];
if (dataTransfer.items) {
for (let index = 0; index < dataTransfer.items.length; index++) {
if (dataTransfer.items[index].kind === 'file') {
const element = dataTransfer.items[index].getAsFile();
if (element) files.push(element);
}
}
} else {
for (let index = 0; index < dataTransfer.files.length; index++) {
const element = dataTransfer.files[index];
if (element) files.push(element);
}
}
this.uploader?.addToQueue(files, options, filters);
this.fileOver.emit(this.isDraggingOverDropZone);
this.onFileDrop.emit(dataTransfer.files);
}
}
}
@HostListener('dragover', ['$event'])
protected onDragOver(event: DragEvent): void {
if (event.dataTransfer) {
const dataTransfer = event.dataTransfer;
if (!this.haveFiles(dataTransfer.types)) {
dataTransfer.dropEffect = 'none';
return;
} else if (!this.isDraggingOverDropZone) {
this.isDraggingOverDropZone = true;
this.fileOver.emit(this.isDraggingOverDropZone);
dataTransfer.dropEffect = 'copy';
}
}
this.preventAndStop(event);
}
@HostListener('dragleave', ['$event'])
protected onDragLeave(event: MouseEvent): void {
const el = this._elementRef.nativeElement as Element;
if (isDescendant(el, event.target as Element)) {
return;
}
if (this.isDraggingOverDropZone) {
this.isDraggingOverDropZone = false;
this.fileOver.emit(this.isDraggingOverDropZone);
}
this.preventAndStop(event);
}
protected preventAndStop(event: MouseEvent): void {
event.preventDefault();
event.stopPropagation();
}
protected haveFiles(types: readonly string[]): boolean {
return types.indexOf('Files') !== -1;
}
}
Regards,
Christophe Friederich
… Le 5 déc. 2021 à 08:09, AVINASH SHARMA ***@***.***> a écrit :
Thanks a lot,
I will try to use in my existing code.
On Sat, Dec 4, 2021, 23:35 Friederich Christophe ***@***.***>
wrote:
> import { Directive, ElementRef, EventEmitter, HostListener, Input, Output } from ***@***.***/core';import { FileUploaderOptions, FileUploader } from 'ng2-file-upload';
>
> @directive({ selector: '[ng2FileDrop]' })export class FileDropDirective {
> @input() uploader?: FileUploader;
> @output() fileOver: EventEmitter<boolean> = new EventEmitter();
> // eslint-disable-next-line @angular-eslint/no-output-on-prefix
> @output() onFileDrop: EventEmitter<FileList> = new EventEmitter<FileList>();
>
> public isDraggingOverDropZone = false;
>
> constructor(private _elementRef: ElementRef) {}
>
> getOptions(): FileUploaderOptions | void {
> return this.uploader?.options;
> }
>
> getFilters(): string {
> return '';
> }
>
> @HostListener('drop', ['$event'])
> onDrop(event: DragEvent): void {
> this.isDraggingOverDropZone = false;
> if (event.dataTransfer) {
> const dataTransfer = event.dataTransfer;
> const options = this.getOptions();
> const filters = this.getFilters();
> this._preventAndStop(event);
> if (options) {
> const files: File[] = [];
> for (let index = 0; index < dataTransfer.files.length; index++) {
> const element = dataTransfer.files.item(index);
> if (element) files.push(element);
> }
> this.uploader?.addToQueue(files, options, filters);
> }
> this.fileOver.emit(false);
> this.onFileDrop.emit(dataTransfer.files);
> }
> }
>
> @HostListener('dragover', ['$event'])
> onDragOver(event: DragEvent): void {
> if (event.dataTransfer) {
> const dataTransfer = event.dataTransfer;
> if (!this.haveFiles(dataTransfer.types)) {
> return;
> }
> if (!this.isDraggingOverDropZone) {
> this.isDraggingOverDropZone = true;
> this.fileOver.emit(true);
> }
> this._preventAndStop(event);
> dataTransfer.dropEffect = 'copy';
> }
> }
>
> @HostListener('dragleave', ['$event'])
> onDragLeave(event: MouseEvent): void {
> if (this._elementRef) {
> if (event.currentTarget === this._elementRef.nativeElement) {
> return;
> }
> }
> if (this.isDraggingOverDropZone) {
> this.isDraggingOverDropZone = false;
> this.fileOver.emit(false);
> }
> }
>
> protected _preventAndStop(event: MouseEvent): void {
> event.preventDefault();
> event.stopPropagation();
> }
>
> protected haveFiles(types: readonly string[]): boolean {
> if (!types) {
> return false;
> }
> return types.indexOf('Files') !== -1;
> }}
>
> Hi,
> I don't try to find the problem, but after fix all types, the above code
> works.
>
> // maybe this change
> if (event.currentTarget === (this as any).element[ 0 ]) {// to
> if (event.currentTarget === this._elementRef.nativeElement) {
>
> —
> You are receiving this because you authored the thread.
> Reply to this email directly, view it on GitHub
> <#1190 (comment)>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AKPAVZBFOQ6SXLRQH2ZZKE3UPJJ4ZANCNFSM5IEOQRCQ>
> .
>
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub <#1190 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AARRQZCYPQ72PH3LMXYQMSLUPMF23ANCNFSM5IEOQRCQ>.
xianshenglu commented
For me, I use .drag-over *{ pointer-events: none }
to disable descendent elements mouse events. And it works.
xianshenglu commented
Willing to send a PR if this solution is acceptable.