mirror of https://github.com/Squidex/squidex.git
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
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);
|
|
}
|
|
}
|