From b0bda2a717f373c5e92a7d620c63085d6c13d6f0 Mon Sep 17 00:00:00 2001 From: "mikerodonnell89@gmail.com" Date: Wed, 11 Jun 2025 16:24:49 -0400 Subject: [PATCH 1/2] fix(platform): disable scrolling during table row drag and drop --- .../focusable-grid.directive.ts | 8 ++- .../directives/table-draggable.directive.ts | 68 +++++++++++++++++-- .../table-virtual-scroll.directive.ts | 11 ++- .../src/lib/table/table.component.html | 1 + .../src/lib/table/table.component.scss | 4 ++ 5 files changed, 84 insertions(+), 8 deletions(-) diff --git a/libs/cdk/src/lib/utils/directives/focusable-grid/focusable-grid.directive.ts b/libs/cdk/src/lib/utils/directives/focusable-grid/focusable-grid.directive.ts index 6e3e8bc7da1..7fe4049f693 100644 --- a/libs/cdk/src/lib/utils/directives/focusable-grid/focusable-grid.directive.ts +++ b/libs/cdk/src/lib/utils/directives/focusable-grid/focusable-grid.directive.ts @@ -62,6 +62,9 @@ export class FocusableGridDirective implements AfterViewInit { @ContentChildren(FDK_FOCUSABLE_LIST_DIRECTIVE, { descendants: true }) private readonly _focusableLists: QueryList; + /** @hidden */ + _preventKeydown = false; + /** @hidden */ constructor(private readonly _destroy$: DestroyedService) {} @@ -129,7 +132,10 @@ export class FocusableGridDirective implements AfterViewInit { /** @hidden */ _onKeydown(event: KeyboardEvent, list: FocusableListDirective, activeItemIndex: Nullable): void { - if (!KeyUtil.isKeyCode(event, [UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, PAGE_DOWN, PAGE_UP])) { + if ( + !KeyUtil.isKeyCode(event, [UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW, PAGE_DOWN, PAGE_UP]) || + this._preventKeydown + ) { return; } diff --git a/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts b/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts index bd4decd5820..d8d9d66c6ea 100644 --- a/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts +++ b/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts @@ -8,6 +8,7 @@ import { inject, Input, NgZone, + OnDestroy, Output } from '@angular/core'; import { @@ -15,7 +16,8 @@ import { DropPredicate, FdDndDropEventMode, FdDndDropType, - FdDropEvent + FdDropEvent, + KeyUtil } from '@fundamental-ngx/cdk/utils'; import { take } from 'rxjs/operators'; import { FDP_TABLE_DRAGGABLE_DIRECTIVE } from '../constants'; @@ -24,6 +26,17 @@ import { findRowChildren, getRowParents } from '../helpers'; import { TableRow, TableRowsRearrangeEvent, UpdatedDndRowsPosition } from '../models'; import { TableDraggable } from '../models/directives'; import { Table } from '../table'; +import { + DOWN_ARROW, + END, + HOME, + LEFT_ARROW, + PAGE_DOWN, + PAGE_UP, + RIGHT_ARROW, + SPACE, + UP_ARROW +} from '@angular/cdk/keycodes'; @Directive({ // eslint-disable-next-line @angular-eslint/directive-selector @@ -36,7 +49,7 @@ import { Table } from '../table'; } ] }) -export class TableDraggableDirective extends TableDraggable { +export class TableDraggableDirective extends TableDraggable implements OnDestroy { /** Whether to allow for row reordering on tree tables via drag and drop. */ @Input() enableRowReordering = true; @@ -86,6 +99,11 @@ export class TableDraggableDirective extends TableDraggable { /** @hidden */ dragDropInProgress = false; + /** @hidden */ + ngOnDestroy(): void { + this._setDragInProgress(false); + } + /** Sets table reference. */ setTable(table: Table): void { this._table = table; @@ -95,7 +113,7 @@ export class TableDraggableDirective extends TableDraggable { * Initiates drag&drop sequence. */ dragDropStart(): void { - this.dragDropInProgress = true; + this._setDragInProgress(true); } /** Method called when dnd performed with the keyboard. */ @@ -126,7 +144,9 @@ export class TableDraggableDirective extends TableDraggable { dropCancelled(): void { /** After timeout to make click event handled first */ this._ngZone.runOutsideAngular(() => { - setTimeout(() => (this.dragDropInProgress = false)); + setTimeout(() => { + this._setDragInProgress(false); + }); }); } @@ -193,6 +213,12 @@ export class TableDraggableDirective extends TableDraggable { ); } + /** @hidden */ + private _setDragInProgress(dragging: boolean): void { + this.dragDropInProgress = dragging; + dragging ? this._blockScrolling() : this._enableScrolling(); + } + /** @hidden */ private _isDroppedInsideItself(dropRow: TableRow, dragRow: TableRow): boolean { const dropRowParents = getRowParents(dropRow); @@ -311,4 +337,38 @@ export class TableDraggableDirective extends TableDraggable { callback(); }); } + + /** @hidden */ + private _blockScrolling(): void { + this._table._focusableGrid._preventKeydown = true; + this._table.tableContainer.nativeElement.addEventListener('DOMMouseScroll', preventDefault, false); + this._table.tableContainer.nativeElement.addEventListener('wheel', preventDefault, { passive: false }); + this._table.tableContainer.nativeElement.addEventListener('mousewheel', preventDefault, { passive: false }); + this._table.tableContainer.nativeElement.addEventListener('touchmove', preventDefault, { passive: false }); + this._table.tableContainer.nativeElement.addEventListener('keydown', preventDefaultForScrollKeys, false); + } + + /** @hidden */ + private _enableScrolling(): void { + this._table._focusableGrid._preventKeydown = false; + this._table.tableContainer.nativeElement.removeEventListener('DOMMouseScroll', preventDefault, false); + this._table.tableContainer.nativeElement.removeEventListener('wheel', preventDefault); + this._table.tableContainer.nativeElement.removeEventListener('mousewheel', preventDefault); + this._table.tableContainer.nativeElement.removeEventListener('touchmove', preventDefault); + this._table.tableContainer.nativeElement.removeEventListener('keydown', preventDefaultForScrollKeys, false); + } +} + +function preventDefault(event: Event): void { + event.preventDefault(); +} + +function preventDefaultForScrollKeys(event: KeyboardEvent): boolean | undefined { + if ( + !event.altKey && + KeyUtil.isKeyCode(event, [LEFT_ARROW, RIGHT_ARROW, UP_ARROW, DOWN_ARROW, SPACE, PAGE_DOWN, PAGE_UP, END, HOME]) + ) { + preventDefault(event); + return false; + } } diff --git a/libs/platform/src/lib/table-helpers/directives/table-virtual-scroll.directive.ts b/libs/platform/src/lib/table-helpers/directives/table-virtual-scroll.directive.ts index f312ea3615b..fe14f500bf9 100644 --- a/libs/platform/src/lib/table-helpers/directives/table-virtual-scroll.directive.ts +++ b/libs/platform/src/lib/table-helpers/directives/table-virtual-scroll.directive.ts @@ -3,8 +3,8 @@ import { DestroyedService, FocusableItemPosition, KeyUtil } from '@fundamental-n import { ContentDensityMode } from '@fundamental-ngx/core/content-density'; import { BehaviorSubject, filter, Subscription } from 'rxjs'; import { takeUntil } from 'rxjs/operators'; -import { FDP_TABLE_VIRTUAL_SCROLL_DIRECTIVE, ROW_HEIGHT } from '../constants'; -import { TableVirtualScroll } from '../models'; +import { FDP_TABLE_DRAGGABLE_DIRECTIVE, FDP_TABLE_VIRTUAL_SCROLL_DIRECTIVE, ROW_HEIGHT } from '../constants'; +import { TableDraggable, TableVirtualScroll } from '../models'; import { TableScrollDispatcherService } from '../services/table-scroll-dispatcher.service'; import { Table } from '../table'; import { DOWN_ARROW, UP_ARROW } from '@angular/cdk/keycodes'; @@ -77,6 +77,11 @@ export class TableVirtualScrollDirective extends TableVirtualScroll implements O /** @hidden */ private readonly _tableScrollDispatcher = inject(TableScrollDispatcherService); + /** @hidden */ + private readonly _dndTableDirective = inject(FDP_TABLE_DRAGGABLE_DIRECTIVE, { + optional: true + }); + /** @hidden */ private readonly _tableRowService = inject(TableRowService); @@ -174,7 +179,7 @@ export class TableVirtualScrollDirective extends TableVirtualScroll implements O this._focusedCell = event; }); } - if (!this.virtualScroll || !this.bodyHeight) { + if (!this.virtualScroll || !this.bodyHeight || this._dndTableDirective?.dragDropInProgress) { return; } diff --git a/libs/platform/src/lib/table/table.component.html b/libs/platform/src/lib/table/table.component.html index 9317aa0a9f6..4b53bc42e21 100644 --- a/libs/platform/src/lib/table/table.component.html +++ b/libs/platform/src/lib/table/table.component.html @@ -24,6 +24,7 @@
Date: Wed, 24 Sep 2025 15:01:45 -0400 Subject: [PATCH 2/2] fix(platform): call function to re-enable dragging after drop --- .../lib/table-helpers/directives/table-draggable.directive.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts b/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts index d8d9d66c6ea..6ff32accd7f 100644 --- a/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts +++ b/libs/platform/src/lib/table-helpers/directives/table-draggable.directive.ts @@ -154,7 +154,7 @@ export class TableDraggableDirective extends TableDraggable implemen dragDropItemDrop(event: FdDropEvent): void { /** After timeout to make click event handled first */ this._ngZone.runOutsideAngular(() => { - setTimeout(() => (this.dragDropInProgress = false)); + setTimeout(() => this._setDragInProgress(false)); }); this._onZoneFree(() => {