blob: a87dcbe7a3f7b25a93bc6ad82ce0fb957f69a931 [file] [log] [blame]
import { Directive, ElementRef, HostListener, Input, AfterContentChecked } from '@angular/core';
import { ModificationsService, ModificationRecord, ModificationType } from './modifications.service';
import { SessionsService } from './sessions.service';
import { TreeService } from './tree.service';
@Directive( {
selector: '[orderingLists]'
} )
export class OrderingDirective implements AfterContentChecked {
private _draggingElement: HTMLElement;
private _droppedElement: HTMLElement;
private _dropSucceded: boolean;
private _isInsideContainer: boolean;
@Input() node;
@Input() activeSession;
constructor(private element: ElementRef,
private modsService: ModificationsService,
private sessionsService: SessionsService,
private treeService: TreeService) { }
ngAfterContentChecked() {
this.markDraggable();
//console.log(this.element)
}
@HostListener( 'dragstart', ['$event'] )
dragStart( event ) {
//console.log("dragStart");
this.savePositions( 'dragIndex' );
this._draggingElement = this.getDraggableElement( event );
event.dataTransfer.setDragImage(this._draggingElement.firstElementChild, event.offsetX, event.offsetY);
this._dropSucceded = false;
this._isInsideContainer = true;
/* Firefox hack */
event.dataTransfer.setData('text', 'bad firefox');
}
@HostListener( 'dragend', ['$event'] )
dragEnd( event: MouseEvent ) {
//console.log("dragEnd");
if ( !this._dropSucceded ) {
this.cancelDragging();
}
event.preventDefault();
}
@HostListener( 'dragover', ['$event'] )
dragOver( event: MouseEvent ) {
//console.log("dragOver");
// Required to receive "drop"" event
event.preventDefault();
}
@HostListener( 'drag', ['$event'] )
drag( event ) {
//console.log("drag");
// Check if mouse is outside container or not
const divCoords = this.element.nativeElement.getBoundingClientRect();
const inside = ( event.clientX >= divCoords.left && event.clientX <= divCoords.right && event.clientY >= divCoords.top && event.clientY <= divCoords.bottom );
// Check if mouse mouves outisde container
if ( this._isInsideContainer && !inside ) {
this.cancelDragging();
}
this._isInsideContainer = inside;
}
@HostListener( 'dragenter', ['$event'] )
dragEnter( event: MouseEvent ) {
//console.log("dragEnter");
const element: HTMLElement = this.getDraggableElement( event );
if ( element && element.attributes ) {
const draggingIndex = this._draggingElement.dataset['index'];
const dropIndex = element.dataset['index'];
if ( draggingIndex !== dropIndex ) {
// Move dragging ghost element at its new position
if ( draggingIndex > dropIndex ) {
this.element.nativeElement.insertBefore( this._draggingElement, element );
} else {
this.element.nativeElement.insertBefore( this._draggingElement, element.nextSibling );
}
this.markDraggable();
}
}
event.preventDefault();
}
@HostListener( 'drop', ['$event'] )
drop( event: MouseEvent ) {
//console.log("drop");
this._dropSucceded = true;
//console.log("moving " + this._draggingElement.dataset.dragIndex + " instead of " + this._draggingElement.dataset.index);
let lastIndex = -1;
let hasLast = false;
let maintainLast = (this.node['info']['type'] == 16);
let nodes = this.treeService.nodesToShow(this.activeSession, this.node);
for ( let i = 0; i < this.element.nativeElement.childElementCount; i++ ) {
let element = this.element.nativeElement.children[i];
if (i == element.dataset.dragIndex) {
/* no change */
continue;
}
nodes[element.dataset.dragIndex]['order'] = i;
if (maintainLast) {
/* maintain last flag in lists, it is not important to maintain it in leaflist,
* since it is enough to have it just present in one of them */
if ('last' in nodes[element.dataset.dragIndex]) {
hasLast = true;
delete nodes[element.dataset.dragIndex]['last'];
} else if (i == this.element.nativeElement.childElementCount - 1) {
lastIndex = element.dataset.dragIndex;
}
}
}
if (hasLast) {
nodes[lastIndex]['last'] = true;
}
let parent = this.treeService.nodeParent(this.activeSession, this.node);
if (!('new' in parent)) {
let path = this.treeService.pathCutPredicate(this.node['path'])
let record = this.modsService.createModificationsRecord(this.activeSession, path);
if (!('type' in record)) {
/* new record */
record['type'] = ModificationType.Reorder;
record['reorder'] = [];
for (let i in nodes) {
record['reorder'].push(Number(i));
}
}
let move = record['reorder'][this._draggingElement.dataset.dragIndex];
record['reorder'].splice(this._draggingElement.dataset.dragIndex, 1);
record['reorder'].splice(this._draggingElement.dataset.index, 0, move);
//console.log(record['reorder']);
let same = true;
for (let item of nodes) {
if (item['order'] != record['reorder'][item['order']]) {
same = false;
break;
}
}
if (same) {
this.modsService.removeModificationsRecord(this.activeSession, path);
}
}
this.sessionsService.storeSessions();
event.preventDefault();
}
private markDraggable() {
for ( let i = 0; i < this.element.nativeElement.childElementCount; i++ ) {
let element = this.element.nativeElement.children[i];
element.draggable = true;
element.dataset.index = i;
}
}
private savePositions( attribute ) {
for ( let i = 0; i < this.element.nativeElement.childElementCount; i++ ) {
let element = this.element.nativeElement.children[i];
element.dataset[attribute] = i;
}
}
private getElementAt( attribute, index ) {
for ( let i = 0; i < this.element.nativeElement.childElementCount; i++ ) {
let element = this.element.nativeElement.children[i];
if ( parseInt( element.dataset[attribute], 10 ) === index ) {
return element;
}
}
return null;
}
private cancelDragging() {
let index = this.element.nativeElement.childElementCount - 1;
// Get last element
let beforeElement = this.getElementAt( 'dragIndex', index );
while ( index > 0 ) {
const element = this.getElementAt( 'dragIndex', index - 1 );
this.element.nativeElement.insertBefore( element, beforeElement );
beforeElement = element;
index--;
}
}
private getDraggableElement( event ): HTMLElement {
let element: HTMLElement = <HTMLElement>event.target;
while ( element && element.attributes && !element.attributes['draggable'] ) {
element = <HTMLElement>element.parentNode;
}
return element;
}
}