Headless CMS and Content Managment Hub
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

118 lines
3.5 KiB

/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Sebastian Stehle. All rights reserved
*/
import { Directive, ElementRef, HostListener, Input, Renderer }from '@angular/core';
import { DragService } from './../services/drag.service';
import { Vec2 } from './../utils/vec2';
@Directive({
selector: '[sqxDragModel]'
})
export class DragModelDirective {
private startOffset: Vec2;
private startPosition: Vec2;
private mouseMoveSubscription: Function | null;
private mouseUpSubscription: Function | null;
private clonedElement: HTMLElement | null;
@Input('sqxDragModel')
public model: any;
constructor(
private readonly element: ElementRef,
private readonly renderer: Renderer,
private readonly dragService: DragService
) {
}
@HostListener('mousedown', ['$event'])
public onMouseDown(event: MouseEvent) {
this.startOffset = new Vec2(event.offsetX, event.offsetY);
this.startPosition = new Vec2(event.clientX, event.clientY);
this.mouseMoveSubscription =
this.renderer.listenGlobal('window', 'mousemove', (e: MouseEvent) => {
this.onMouseMove(e);
});
this.mouseUpSubscription =
this.renderer.listenGlobal('window', 'mouseup', (e: MouseEvent) => {
this.onMouseUp(e);
});
this.stopEvent(event);
}
private onMouseMove(event: MouseEvent) {
const position = new Vec2(event.clientX, event.clientY);
if (!this.clonedElement && position.sub(this.startPosition).lengtSquared > 100) {
this.clonedElement = this.element.nativeElement.cloneNode(true);
this.clonedElement!.style.position = 'fixed';
this.clonedElement!.style.zIndex = '10000';
document.body.appendChild(this.clonedElement!);
}
if (this.clonedElement) {
const elementPosition = position.sub(this.startOffset);
this.clonedElement.style.left = elementPosition.x + 'px';
this.clonedElement.style.top = elementPosition.y + 'px';
}
this.stopEvent(event);
}
private onMouseUp(event: MouseEvent) {
if (this.clonedElement) {
this.clonedElement.remove();
}
let dropCandidate: Element | null = document.elementFromPoint(event.clientX, event.clientY);
while (dropCandidate && (dropCandidate.classList && !dropCandidate.classList.contains('sqx-drop'))) {
dropCandidate = dropCandidate.parentNode as Element;
}
if (dropCandidate && dropCandidate.id) {
const position = this.getRelativeCoordinates(event, dropCandidate).sub(this.startOffset).round();
this.dragService.emitDrop({ position, model: this.model, dropTarget: dropCandidate.id });
}
if (this.mouseMoveSubscription) {
this.mouseMoveSubscription();
this.mouseMoveSubscription = null;
}
if (this.mouseUpSubscription) {
this.mouseUpSubscription();
this.mouseUpSubscription = null;
}
this.clonedElement = null;
this.stopEvent(event);
}
private stopEvent(event: Event) {
event.preventDefault();
event.stopPropagation();
}
private getRelativeCoordinates(e: any, container: any): Vec2 {
const rect = container.getBoundingClientRect();
const x = !!e.touches ? e.touches[0].pageX : e.pageX;
const y = !!e.touches ? e.touches[0].pageY : e.pageY;
return new Vec2(x - rect.left, y - rect.top);
}
}