UNPKG

@progress/kendo-angular-treelist

Version:

Kendo UI TreeList for Angular - Display hierarchical data in an Angular tree grid view that supports sorting, filtering, paging, and much more.

142 lines (141 loc) 6.78 kB
/**----------------------------------------------------------------------------------------- * Copyright © 2025 Progress Software Corporation. All rights reserved. * Licensed under commercial license. See LICENSE.md in the project root for more information *-------------------------------------------------------------------------------------------*/ import { Directive, ElementRef, EventEmitter, Host, Input, NgZone, Output, Renderer2, HostBinding } from '@angular/core'; import { Subscription, of } from 'rxjs'; import { DraggableDirective } from '@progress/kendo-angular-common'; import { DragAndDropService } from './drag-and-drop.service'; import { DragHintService } from './drag-hint.service'; import { DropCueService } from './drop-cue.service'; import { and, not, or } from '../utils'; import { NavigationService } from '../navigation/navigation.service'; import { takeUntil, delay, filter, tap, switchMap, switchMapTo, map } from 'rxjs/operators'; import { isFocusableWithTabKey, matchesNodeName } from '../rendering/common/dom-queries'; import * as i0 from "@angular/core"; import * as i1 from "@progress/kendo-angular-common"; import * as i2 from "./drag-and-drop.service"; import * as i3 from "./drag-hint.service"; import * as i4 from "./drop-cue.service"; import * as i5 from "../navigation/navigation.service"; /** * @hidden */ const preventOnDblClick = release => mouseDown => of(mouseDown).pipe(delay(150), takeUntil(release)); const hasClass = className => el => new RegExp(`(^| )${className}( |$)`).test(el.className); const isDeleteButton = or(hasClass('k-i-x'), hasClass('k-svg-i-x'), hasClass('k-icon-button')); const isSortIcon = or(hasClass('k-i-sort-asc-small'), hasClass('k-i-sort-desc-small'), hasClass('k-svg-i-sort-asc-small'), hasClass('k-svg-i-sort-desc-small')); const skipButtons = and(not(isDeleteButton), not(isSortIcon), not(isFocusableWithTabKey), not(matchesNodeName('label'))); const elementUnderCursor = ({ clientX, clientY }) => document.elementFromPoint(clientX, clientY); const hideThenShow = (element, cont) => { element.style.display = 'none'; const result = cont(); element.style.display = 'block'; return result; }; /** * @hidden */ export class DraggableColumnDirective { draggable; element; zone; service; hint; cue; nav; renderer; context = {}; set enableDrag(enabled) { this.enabled = enabled; this.updateTouchAction(); } drag = new EventEmitter(); get hostClass() { return this.enabled; } subscriptions = new Subscription(); enabled; constructor(draggable, element, zone, service, hint, cue, nav, renderer) { this.draggable = draggable; this.element = element; this.zone = zone; this.service = service; this.hint = hint; this.cue = cue; this.nav = nav; this.renderer = renderer; } ngOnInit() { this.subscriptions.add(this.zone.runOutsideAngular(() => this.draggable.kendoPress.pipe(filter(_ => this.enabled), filter(({ originalEvent: { target } }) => target === this.element.nativeElement || skipButtons(target)), tap((e) => { const originalEvent = e.originalEvent; if (!e.isTouch) { originalEvent.preventDefault(); } this.nav.navigateTo(originalEvent.target); }), switchMap(preventOnDblClick(this.draggable.kendoRelease)), tap(() => { this.hint.create(this.context.hint); this.cue.create(); }), switchMap(down => this.draggable.kendoDrag.pipe(tap((e) => { if (e.isTouch) { e.originalEvent.preventDefault(); } }), tap(this.hint.attach()), tap(this.cue.attach()), takeUntil(this.draggable.kendoRelease), map(move => ({ move, down })))), tap(this.performDrag.bind(this)), switchMapTo(this.draggable.kendoRelease)).subscribe(this.drop.bind(this)))); } ngOnDestroy() { if (this.subscriptions) { this.subscriptions.unsubscribe(); } } drop(upEvent) { this.hint.remove(); this.cue.remove(); this.service.notifyDrop(this, upEvent); } performDrag({ move }) { this.hint.move(move); const cursorElement = this.elementUnderCursor(move); if (cursorElement) { this.service.notifyDrag(this, cursorElement, move); } this.drag.emit({ draggable: this, mouseEvent: move }); } elementUnderCursor(mouseEvent) { this.hint.hide(); let target = elementUnderCursor(mouseEvent); if (target && /k-grouping-dropclue/.test(target.className)) { target = hideThenShow(target, elementUnderCursor.bind(this, mouseEvent)); } this.hint.show(); return target; } updateTouchAction() { if (!this.element) { return; } this.renderer.setStyle(this.element.nativeElement, 'touch-action', this.enabled ? 'none' : ''); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DraggableColumnDirective, deps: [{ token: i1.DraggableDirective, host: true }, { token: i0.ElementRef }, { token: i0.NgZone }, { token: i2.DragAndDropService }, { token: i3.DragHintService }, { token: i4.DropCueService }, { token: i5.NavigationService }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive }); static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "18.2.14", type: DraggableColumnDirective, isStandalone: true, selector: "[kendoDraggableColumn]", inputs: { context: "context", enableDrag: "enableDrag" }, outputs: { drag: "drag" }, host: { properties: { "class.k-grid-draggable-header": "this.hostClass" } }, ngImport: i0 }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: DraggableColumnDirective, decorators: [{ type: Directive, args: [{ selector: '[kendoDraggableColumn]', standalone: true }] }], ctorParameters: () => [{ type: i1.DraggableDirective, decorators: [{ type: Host }] }, { type: i0.ElementRef }, { type: i0.NgZone }, { type: i2.DragAndDropService }, { type: i3.DragHintService }, { type: i4.DropCueService }, { type: i5.NavigationService }, { type: i0.Renderer2 }], propDecorators: { context: [{ type: Input }], enableDrag: [{ type: Input }], drag: [{ type: Output }], hostClass: [{ type: HostBinding, args: ['class.k-grid-draggable-header'] }] } });