@progress/kendo-angular-pivotgrid
Version:
PivotGrid package for Angular
191 lines (190 loc) • 10 kB
JavaScript
/**-----------------------------------------------------------------------------------------
* 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, Input, NgZone, Renderer2 } from "@angular/core";
import { PIVOT_CONFIGURATOR_ACTION } from "@progress/kendo-pivotgrid-common";
import { Subscription } from "rxjs";
import { ConfiguratorService } from "./configurator.service";
import { DropCueService } from "./drop-cue.service";
import { isPresent } from "../util";
import * as i0 from "@angular/core";
import * as i1 from "./configurator.service";
import * as i2 from "./drop-cue.service";
/**
* @hidden
*/
export class DropTargetDirective {
element;
configuratorService;
cue;
renderer;
zone;
item;
axes;
elementType;
elementSectionType;
targetElement;
nextChipOffset;
subs = new Subscription();
constructor(element, configuratorService, cue, renderer, zone) {
this.element = element;
this.configuratorService = configuratorService;
this.cue = cue;
this.renderer = renderer;
this.zone = zone;
}
ngOnInit() {
const element = this.element.nativeElement;
this.elementType = this.getElementType(element);
this.elementSectionType = element.getAttribute('axes')?.split('Axes')[0];
this.subs.add(this.renderer.listen(element, 'mouseenter', this.handleMouseEnter.bind(this)));
this.subs.add(this.renderer.listen(element, 'mousemove', this.handleMouseMove.bind(this)));
this.subs.add(this.renderer.listen(element, 'mouseleave', this.handleMouseLeave.bind(this)));
}
ngOnDestroy() {
this.subs.unsubscribe();
}
handleMouseEnter(event) {
this.zone.runOutsideAngular(() => {
if (this.configuratorService.state.dragItem) {
this.configuratorService.dropTargetElement = this.element.nativeElement;
if (this.configuratorService.draggedElement && !this.isDropAllowed(this.configuratorService.draggedElement.fromSection)) {
return;
}
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropTarget, payload: this.item });
this.targetElement = this.elementType === 'header' ? event.target.nextElementSibling : event.target;
// eslint-disable-next-line no-unused-expressions
this.cue.dom && this.cue.remove(this.getCueContainer());
this.cue.create();
this.cue.attach(this.getCueContainer());
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropZone, payload: this.axes });
}
});
}
handleMouseMove(event) {
this.zone.runOutsideAngular(() => {
event.stopImmediatePropagation();
if (this.configuratorService.state.dragItem) {
if (this.configuratorService.draggedElement && !this.isDropAllowed(this.configuratorService.draggedElement.fromSection)) {
this.renderer.setStyle(this.element.nativeElement, 'cursor', 'not-allowed');
return;
}
this.renderer.setStyle(this.element.nativeElement, 'cursor', 'pointer');
const singleOrNoChip = this.targetElement?.querySelectorAll('.k-chip').length < 2;
const isInOwnContainer = this.elementSectionType === this.configuratorService.draggedElement.fromSection;
if (!this.targetElement) {
return;
}
switch (this.elementType) {
case 'chip': {
const rect = this.element.nativeElement.getBoundingClientRect();
const x = event.clientX - rect.left;
const direction = x < rect.width / 2 ? 'before' : 'after';
this.cue.show(direction, this.configuratorService.cueContainer, this.targetElement);
if (direction !== this.configuratorService.state.dropDirection) {
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropDirection, payload: direction });
}
break;
}
case 'container':
case 'header':
if (singleOrNoChip && isInOwnContainer) {
return;
}
if (isInOwnContainer) {
const draggedElement = this.configuratorService.draggedElement.element;
const nextChip = this.getNextChip(draggedElement);
if (!nextChip) {
this.cue.show('before', this.configuratorService.cueContainer, draggedElement);
if (this.configuratorService.state.dropDirection !== 'before') {
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropDirection, payload: 'before' });
}
return;
}
const isVertical = this.configuratorService.orientation === 'vertical';
if (!isPresent(this.nextChipOffset)) {
this.nextChipOffset = isVertical ? nextChip.getBoundingClientRect().left : nextChip.getBoundingClientRect().top;
}
const isBefore = isVertical ? event.clientX < this.nextChipOffset : event.clientY < this.nextChipOffset;
if (isBefore) {
this.cue.show('after', this.configuratorService.cueContainer, draggedElement);
return;
}
}
if (this.configuratorService.state.dropDirection !== 'after') {
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropDirection, payload: 'after' });
}
this.cue.show('after', this.configuratorService.cueContainer, this.targetElement);
break;
default:
}
}
});
}
handleMouseLeave(event) {
this.renderer.removeStyle(this.element.nativeElement, 'cursor');
if (!this.configuratorService.draggedElement) {
return;
}
this.zone.runOutsideAngular(() => {
event.stopImmediatePropagation();
this.configuratorService.dropTargetElement = null;
this.cue.remove(this.getCueContainer());
if (this.elementType === 'chip') {
return;
}
if (this.configuratorService.state.dragItem) {
this.configuratorService.parseConfiguratorState({ type: PIVOT_CONFIGURATOR_ACTION.setDropZone, payload: null });
}
});
}
isDropAllowed(fromSection) {
const element = this.element.nativeElement;
const fromRowsOrColsToMeasures = (fromSection === 'row' || fromSection === 'column') && element.closest('[axes=measureAxes]');
const fromMeasuresToRowsOrCols = fromSection === 'measure' && (element.closest('[axes=rowAxes]') || element.closest('[axes=columnAxes]'));
return !(fromRowsOrColsToMeasures || fromMeasuresToRowsOrCols);
}
getElementType(element) {
return {
'KENDO-CHIP': 'chip',
'KENDO-CHIPLIST': 'container',
'DIV': 'header'
}[element.tagName];
}
getCueContainer() {
const element = this.element.nativeElement;
const cueContainer = {
chip: element.parentElement,
container: element,
header: element.classList.contains('k-settings-description') ? element : element.nextElementSibling
}[this.elementType];
this.configuratorService.cueContainer = cueContainer;
return cueContainer;
}
getNextChip(draggedElement) {
let nextChip = draggedElement.nextElementSibling;
if (nextChip && nextChip.matches('.k-chip')) {
return nextChip;
}
while (nextChip) {
nextChip = nextChip.nextElementSibling;
if (nextChip === null || nextChip.matches('.k-chip')) {
return nextChip;
}
}
}
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropTargetDirective, deps: [{ token: i0.ElementRef }, { token: i1.ConfiguratorService }, { token: i2.DropCueService }, { token: i0.Renderer2 }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive });
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "16.2.12", type: DropTargetDirective, isStandalone: true, selector: "[kendoDropTarget]", inputs: { item: "item", axes: "axes" }, ngImport: i0 });
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DropTargetDirective, decorators: [{
type: Directive,
args: [{
selector: '[kendoDropTarget]',
standalone: true
}]
}], ctorParameters: function () { return [{ type: i0.ElementRef }, { type: i1.ConfiguratorService }, { type: i2.DropCueService }, { type: i0.Renderer2 }, { type: i0.NgZone }]; }, propDecorators: { item: [{
type: Input
}], axes: [{
type: Input
}] } });