UNPKG

angular2-json-schema-form

Version:
145 lines (132 loc) 4.74 kB
import { Directive, ElementRef, HostListener, Input, OnInit } from '@angular/core'; import { JsonSchemaFormService } from '../json-schema-form.service'; import { JsonPointer } from './index'; /** * OrderableDirective * * Enables array elements to be reordered by dragging and dropping. * * Only works for arrays that have at least two elements. * * Also detects arrays-within-arrays, and correctly moves either * the child array element or the parent array element, * depending on the drop targert. * */ @Directive({ selector: '[orderable]', }) export class OrderableDirective implements OnInit { private arrayPointer: string; private listen: boolean = false; private element: any; private overParentElement: boolean = false; private overChildElement: boolean = false; @Input() orderable: boolean; @Input() formID: number; @Input() layoutNode: any; @Input() layoutIndex: number[]; @Input() dataIndex: number[]; constructor( private elementRef: ElementRef, private jsf: JsonSchemaFormService ) { } ngOnInit() { if (this.orderable && this.layoutNode && this.layoutIndex && this.dataIndex) { this.element = this.elementRef.nativeElement; this.element.draggable = true; this.arrayPointer = JsonPointer.compile( JsonPointer.parse(this.jsf.getLayoutPointer(this)).slice(0, -1) ); this.listen = true; } } /** * Listeners for movable element being dragged: * * dragstart: add 'dragging' class to element, set effectAllowed = 'move' * dragover: set dropEffect = 'move' * dragend: remove 'dragging' class from element */ @HostListener('dragstart', ['$event']) onDragStart(event) { if (this.listen) { this.element.classList.add('dragging'); event.dataTransfer.effectAllowed = 'move'; // Hack to bypass stupid HTML drag-and-drop dataTransfer protection // so drag source info will be available on dragenter sessionStorage.setItem( this.arrayPointer, this.dataIndex[this.dataIndex.length - 1] + '' ); event.dataTransfer.setData('text/plain', this.dataIndex[this.dataIndex.length - 1] + this.arrayPointer); } } @HostListener('dragover', ['$event']) onDragOver(event) { if (event.preventDefault) event.preventDefault(); event.dataTransfer.dropEffect = 'move'; return false; } @HostListener('dragend', ['$event']) onDragEnd(event) { event.preventDefault(); if (this.listen) { this.element.classList.remove('dragging'); } } /** * Listeners for stationary items being dragged over: * * dragenter: add 'drag-target-...' class to element * dragleave: remove 'drag-target-...' class from element * drop: remove 'drag-target-...' class from element, move dropped array item */ @HostListener('dragenter', ['$event']) onDragEnter(event) { // Part 1 of a hack, inspired by Dragster, to simulate mouseover and mouseout // behavior while dragging items - http://bensmithett.github.io/dragster/ if (this.overParentElement) { return this.overChildElement = true; } else { this.overParentElement = true; } if (this.listen) { let sourceArrayIndex = sessionStorage.getItem(this.arrayPointer); if (sourceArrayIndex !== null) { if (this.dataIndex[this.dataIndex.length - 1] < +sourceArrayIndex) { this.element.classList.add('drag-target-top'); } else if (this.dataIndex[this.dataIndex.length - 1] > +sourceArrayIndex) { this.element.classList.add('drag-target-bottom'); } } } } @HostListener('dragleave', ['$event']) onDragLeave(event) { // Part 2 of the Dragster hack if (this.overChildElement) { this.overChildElement = false; } else if (this.overParentElement) { this.overParentElement = false; } if (!this.overParentElement && !this.overChildElement && this.listen) { this.element.classList.remove('drag-target-top'); this.element.classList.remove('drag-target-bottom'); } } @HostListener('drop', ['$event']) onDrop(event) { if (this.listen) { this.element.classList.remove('drag-target-top'); this.element.classList.remove('drag-target-bottom'); // Confirm that drop target is another item in the same array as source item const sourceArrayIndex: number = +sessionStorage.getItem(this.arrayPointer); if (sourceArrayIndex !== this.dataIndex[this.dataIndex.length - 1]) { // Move array item this.jsf.moveArrayItem( this, sourceArrayIndex, this.dataIndex[this.dataIndex.length - 1] ); } sessionStorage.removeItem(this.arrayPointer); } return false; } }