From 55113f37b651c126e7b2e847144adb1972a50f5b Mon Sep 17 00:00:00 2001 From: Denys Vuika Date: Tue, 30 Apr 2019 14:53:37 +0100 Subject: [PATCH] [ADF-4444] drag and drop fixes (#4674) * more granular control over drag and drop * fix performance, internal drop-zone directive --- .../datatable-dnd.component.html | 2 + .../drag-and-drop/datatable-dnd.component.ts | 4 + docs/core/components/datatable.component.md | 35 ++++++++ .../directives/file-draggable.directive.ts | 2 +- .../datatable/datatable.component.html | 6 +- .../datatable/datatable.component.ts | 36 -------- .../datatable/drop-zone.directive.ts | 90 +++++++++++++++++++ lib/core/datatable/datatable.module.ts | 7 +- lib/core/datatable/public-api.ts | 2 +- 9 files changed, 140 insertions(+), 44 deletions(-) create mode 100644 lib/core/datatable/components/datatable/drop-zone.directive.ts diff --git a/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.html b/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.html index 6342702eac..d623895216 100644 --- a/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.html +++ b/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.html @@ -1,6 +1,8 @@

DataTable Drag and Drop Demo

diff --git a/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.ts b/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.ts index 5b4f90e3e5..4193026c6d 100644 --- a/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.ts +++ b/demo-shell/src/app/components/datatable/drag-and-drop/datatable-dnd.component.ts @@ -88,6 +88,10 @@ export class DataTableDnDComponent implements OnInit { this.data.setSorting(new DataSorting('id', 'asc')); } + onDragOver(event: CustomEvent) { + event.preventDefault(); + } + onDrop(event: DataTableDropEvent) { event.preventDefault(); diff --git a/docs/core/components/datatable.component.md b/docs/core/components/datatable.component.md index 7a463c3ba3..45f125f9a5 100644 --- a/docs/core/components/datatable.component.md +++ b/docs/core/components/datatable.component.md @@ -401,7 +401,9 @@ These events bubble up the component tree and can be handled by any parent compo | row-unselect | Raised after user unselects a row | | row-keyup | Raised on the 'keyup' event for the focused row. | | sorting-changed | Raised after user clicks the sortable column header. | +| header-dragover | Raised when dragging content over the header. | | header-drop | Raised when data is dropped on the column header. | +| cell-dragover | Raised when dragging data over the cell. | | cell-drop | Raised when data is dropped on the column cell. | #### Drop Events @@ -424,6 +426,39 @@ export interface DataTableDropEvent { Note that `event` is the original `drop` event, and `row` is not available for Header events. +According to the [HTML5 Drag and Drop API](https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API), +you need to handle both `dragover` and `drop` events to handle the drop correctly. + +Given that DataTable raises bubbling DOM events, you can handle drop behavior from the parent elements as well: + +```html +
+ + + +
+``` + +Where the implementation of the handlers can look like following: + +```ts +onDragOver(event: CustomEvent) { + // always needed for custom drop handlers (!) + event.preventDefault(); +} + +onDrop(event: DataTableDropEvent) { + event.preventDefault(); + + const { column, row, target } = event.detail; + // do something with the details +} +``` + #### Example ```html diff --git a/lib/content-services/upload/directives/file-draggable.directive.ts b/lib/content-services/upload/directives/file-draggable.directive.ts index ceb3d6f62b..eea5b2637b 100644 --- a/lib/content-services/upload/directives/file-draggable.directive.ts +++ b/lib/content-services/upload/directives/file-draggable.directive.ts @@ -24,7 +24,7 @@ import { Directive, ElementRef, EventEmitter, Input, NgZone, OnDestroy, OnInit, * Directive selectors without adf- prefix will be deprecated on 3.0.0 */ @Directive({ - selector: '[adf-file-draggable], [file-draggable]' + selector: '[adf-file-draggable]' }) export class FileDraggableDirective implements OnInit, OnDestroy { diff --git a/lib/core/datatable/components/datatable/datatable.component.html b/lib/core/datatable/components/datatable/datatable.component.html index e005de1475..4c42a77fc8 100644 --- a/lib/core/datatable/components/datatable/datatable.component.html +++ b/lib/core/datatable/components/datatable/datatable.component.html @@ -26,8 +26,7 @@ role="columnheader" tabindex="0" title="{{ col.title | translate }}" - (dragover)="onDragOver($event)" - (drop)="onHeaderDrop($event, col)"> + adf-drop-zone dropTarget="header" [dropColumn]="col"> {{ col.srTitle | translate }} {{ col.title | translate}} @@ -98,8 +97,7 @@ (keydown.enter)="onEnterKeyPressed(row, $event)" [adf-context-menu]="getContextMenuActions(row, col)" [adf-context-menu-enabled]="contextMenu" - (dragover)="onDragOver($event)" - (drop)="onCellDrop($event, col, row)"> + adf-drop-zone dropTarget="cell" [dropColumn]="col" [dropRow]="row">
diff --git a/lib/core/datatable/components/datatable/datatable.component.ts b/lib/core/datatable/components/datatable/datatable.component.ts index 8dd36c03c0..82785b92af 100644 --- a/lib/core/datatable/components/datatable/datatable.component.ts +++ b/lib/core/datatable/components/datatable/datatable.component.ts @@ -701,42 +701,6 @@ export class DataTableComponent implements AfterContentInit, OnChanges, DoCheck, const name = this.getNameColumnValue(); return name ? row.getValue(name.key) : ''; } - - onDragOver(event: Event) { - event.preventDefault(); - } - - onHeaderDrop(event: Event, column: DataColumn) { - event.preventDefault(); - - this.elementRef.nativeElement.dispatchEvent( - new CustomEvent('header-drop', { - detail: { - target: 'header', - event, - column - }, - bubbles: true - }) - ); - } - - onCellDrop(event: Event, column: DataColumn, row: DataRow) { - event.preventDefault(); - - this.elementRef.nativeElement.dispatchEvent( - new CustomEvent('cell-drop', { - detail: { - target: 'cell', - event, - column, - row - }, - bubbles: true - }) - ); - } - } export interface DataTableDropEvent { diff --git a/lib/core/datatable/components/datatable/drop-zone.directive.ts b/lib/core/datatable/components/datatable/drop-zone.directive.ts new file mode 100644 index 0000000000..9097e02d80 --- /dev/null +++ b/lib/core/datatable/components/datatable/drop-zone.directive.ts @@ -0,0 +1,90 @@ +/*! + * @license + * Copyright 2019 Alfresco Software, Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Directive, Input, ElementRef, NgZone, OnInit, OnDestroy } from '@angular/core'; +import { DataRow } from '../../data/data-row.model'; +import { DataColumn } from '../../data/data-column.model'; + +@Directive({ + selector: '[adf-drop-zone]' +}) +export class DropZoneDirective implements OnInit, OnDestroy { + private element: HTMLElement; + + @Input() + dropTarget: 'header' | 'cell' = 'cell'; + + @Input() + dropRow: DataRow; + + @Input() + dropColumn: DataColumn; + + constructor(elementRef: ElementRef, private ngZone: NgZone) { + this.element = elementRef.nativeElement; + } + + ngOnInit() { + this.ngZone.runOutsideAngular(() => { + this.element.addEventListener('dragover', this.onDragOver.bind(this)); + this.element.addEventListener('drop', this.onDrop.bind(this)); + }); + } + + ngOnDestroy() { + this.element.removeEventListener('dragover', this.onDragOver); + this.element.removeEventListener('drop', this.onDrop); + } + + onDragOver(event: Event) { + const domEvent = new CustomEvent(`${this.dropTarget}-dragover`, { + detail: { + target: this.dropTarget, + event, + column: this.dropColumn, + row: this.dropRow + }, + bubbles: true + }); + + this.element.dispatchEvent(domEvent); + + if (domEvent.defaultPrevented) { + event.preventDefault(); + event.stopPropagation(); + } + } + + onDrop(event: Event) { + const domEvent = new CustomEvent(`${this.dropTarget}-drop`, { + detail: { + target: this.dropTarget, + event, + column: this.dropColumn, + row: this.dropRow + }, + bubbles: true + }); + + this.element.dispatchEvent(domEvent); + + if (domEvent.defaultPrevented) { + event.preventDefault(); + event.stopPropagation(); + } + } +} diff --git a/lib/core/datatable/datatable.module.ts b/lib/core/datatable/datatable.module.ts index 3b1c21abd2..23611bc2e1 100644 --- a/lib/core/datatable/datatable.module.ts +++ b/lib/core/datatable/datatable.module.ts @@ -42,6 +42,7 @@ import { CustomLoadingContentTemplateDirective } from './directives/custom-loadi import { CustomNoPermissionTemplateDirective } from './directives/custom-no-permission-template.directive'; import { JsonCellComponent } from './components/datatable/json-cell.component'; import { ClipboardModule } from '../clipboard/clipboard.module'; +import { DropZoneDirective } from './components/datatable/drop-zone.directive'; @NgModule({ imports: [ @@ -70,7 +71,8 @@ import { ClipboardModule } from '../clipboard/clipboard.module'; LoadingContentTemplateDirective, CustomEmptyContentTemplateDirective, CustomLoadingContentTemplateDirective, - CustomNoPermissionTemplateDirective + CustomNoPermissionTemplateDirective, + DropZoneDirective ], exports: [ DataTableComponent, @@ -88,7 +90,8 @@ import { ClipboardModule } from '../clipboard/clipboard.module'; LoadingContentTemplateDirective, CustomEmptyContentTemplateDirective, CustomLoadingContentTemplateDirective, - CustomNoPermissionTemplateDirective + CustomNoPermissionTemplateDirective, + DropZoneDirective ] }) diff --git a/lib/core/datatable/public-api.ts b/lib/core/datatable/public-api.ts index 94a15b276c..35551ba887 100644 --- a/lib/core/datatable/public-api.ts +++ b/lib/core/datatable/public-api.ts @@ -28,7 +28,7 @@ export * from './data/object-datacolumn.model'; export * from './components/datatable/data-cell.event'; export * from './components/datatable/data-row-action.event'; - +export * from './components/datatable/drop-zone.directive'; export * from './components/datatable/datatable-cell.component'; export * from './components/datatable/datatable.component'; export * from './components/datatable/date-cell.component';