@swimlane/ngx-dnd
Version:
Drag and Drop for Angular2 and beyond!
145 lines (144 loc) • 15.3 kB
JavaScript
import { Directive, ElementRef, HostListener, Input, Output, EventEmitter } from '@angular/core';
import { DroppableDirective } from './ngx-droppable.directive';
import { DrakeStoreService } from '../services/drake-store.service';
import * as i0 from "@angular/core";
import * as i1 from "../services/drake-store.service";
import * as i2 from "./ngx-droppable.directive";
/**
* Adds properties and events to draggable elements
*
* @export
*/
export class DraggableDirective {
el;
drakesService;
droppableDirective;
ngxDraggable;
model;
get dropZones() {
return this._dropZones || this.ngxDraggable || this._parentDropzones;
}
set dropZones(val) {
this._dropZones = val;
}
_moves = true;
/*
ContentChildren doesn't get children created with NgTemplateOutlet
See https://github.com/angular/angular/issues/14842
Implemented via updateElements method
@ContentChildren(DragHandleDirective, {descendants: true})
handlesList: QueryList<DragHandleDirective>; */
handles = [];
get hasHandle() {
return !!this.handles.length;
}
drag = new EventEmitter();
dragDelay = 200; // milliseconds
dragDelayed = true;
touchTimeout;
get element() {
return this.el.nativeElement;
}
_dropZones;
_parentDropzones;
constructor(el, drakesService, droppableDirective) {
this.el = el;
this.drakesService = drakesService;
this.droppableDirective = droppableDirective;
}
// From: https://github.com/bevacqua/dragula/issues/289#issuecomment-277143172
onMove(e) {
if (!this._moves || this.dragDelayed) {
e.stopPropagation();
clearTimeout(this.touchTimeout);
}
}
onDown() {
if (this._moves) {
this.touchTimeout = setTimeout(() => {
this.dragDelayed = false;
}, this.dragDelay);
}
}
onUp() {
if (this._moves) {
clearTimeout(this.touchTimeout);
this.dragDelayed = true;
}
}
ngOnInit() {
this.update();
}
update() {
this._parentDropzones = [this.droppableDirective.dropZone];
this.drakesService.registerDraggable(this);
this.updateElements();
}
ngOnDestroy() {
this.drakesService.removeDraggable(this);
}
updateElements() {
const nativeElement = this.el.nativeElement;
const handles = nativeElement.querySelectorAll('[ngxdraghandle]');
this.handles = Array.from(handles).filter((h) => findFirstDraggableParent(h) === nativeElement);
function findFirstDraggableParent(c) {
while (c.parentNode) {
c = c.parentNode;
if (c.hasAttribute && c.hasAttribute('ngxdraggable')) {
return c;
}
}
}
}
canMove(source, handle, sibling) {
if (typeof this._moves === 'boolean')
return this._moves;
if (typeof this._moves === 'function')
return this._moves(this.model, source, handle, sibling);
return true;
}
moves(source, handle, sibling) {
if (!this.canMove(source, handle, sibling))
return false;
return this.hasHandle ? this.handles.some(h => handelFor(handle, h)) : true;
function handelFor(c, p) {
if (c === p)
return true;
while ((c = c.parentNode) && c !== p)
; // tslint:disable-line
return !!c;
}
}
ngDoCheck() {
this.updateElements();
}
static ɵfac = function DraggableDirective_Factory(t) { return new (t || DraggableDirective)(i0.ɵɵdirectiveInject(i0.ElementRef), i0.ɵɵdirectiveInject(i1.DrakeStoreService), i0.ɵɵdirectiveInject(i2.DroppableDirective)); };
static ɵdir = /*@__PURE__*/ i0.ɵɵdefineDirective({ type: DraggableDirective, selectors: [["", "ngxDraggable", ""]], hostBindings: function DraggableDirective_HostBindings(rf, ctx) { if (rf & 1) {
i0.ɵɵlistener("touchmove", function DraggableDirective_touchmove_HostBindingHandler($event) { return ctx.onMove($event); })("touchstart", function DraggableDirective_touchstart_HostBindingHandler() { return ctx.onDown(); })("touchend", function DraggableDirective_touchend_HostBindingHandler() { return ctx.onUp(); });
} }, inputs: { ngxDraggable: "ngxDraggable", model: "model", dropZones: "dropZones", _moves: [0, "moves", "_moves"] }, outputs: { drag: "drag" } });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DraggableDirective, [{
type: Directive,
args: [{ selector: '[ngxDraggable]' }]
}], () => [{ type: i0.ElementRef }, { type: i1.DrakeStoreService }, { type: i2.DroppableDirective }], { ngxDraggable: [{
type: Input
}], model: [{
type: Input
}], dropZones: [{
type: Input
}], _moves: [{
type: Input,
args: ['moves']
}], drag: [{
type: Output
}], onMove: [{
type: HostListener,
args: ['touchmove', ['$event']]
}], onDown: [{
type: HostListener,
args: ['touchstart']
}], onUp: [{
type: HostListener,
args: ['touchend']
}] }); })();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LWRyYWdnYWJsZS5kaXJlY3RpdmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9zd2ltbGFuZS9uZ3gtZG5kL3NyYy9saWIvZGlyZWN0aXZlcy9uZ3gtZHJhZ2dhYmxlLmRpcmVjdGl2ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxZQUFZLEVBQUUsS0FBSyxFQUFFLE1BQU0sRUFBRSxZQUFZLEVBQXFCLE1BQU0sZUFBZSxDQUFDO0FBRXBILE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQy9ELE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGlDQUFpQyxDQUFDOzs7O0FBRXBFOzs7O0dBSUc7QUFFSCxNQUFNLE9BQU8sa0JBQWtCO0lBMkNuQjtJQUNBO0lBQ0E7SUE1Q0QsWUFBWSxDQUFXO0lBQ3ZCLEtBQUssQ0FBTTtJQUVwQixJQUNJLFNBQVM7UUFDWCxPQUFPLElBQUksQ0FBQyxVQUFVLElBQUksSUFBSSxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUMsZ0JBQWdCLENBQUM7SUFDdkUsQ0FBQztJQUNELElBQUksU0FBUyxDQUFDLEdBQVE7UUFDcEIsSUFBSSxDQUFDLFVBQVUsR0FBRyxHQUFHLENBQUM7SUFDeEIsQ0FBQztJQUVlLE1BQU0sR0FBd0MsSUFBSSxDQUFDO0lBRW5FOzs7Ozs7bURBTStDO0lBRS9DLE9BQU8sR0FBVSxFQUFFLENBQUM7SUFFcEIsSUFBSSxTQUFTO1FBQ1gsT0FBTyxDQUFDLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7SUFDL0IsQ0FBQztJQUVTLElBQUksR0FBc0IsSUFBSSxZQUFZLEVBQU8sQ0FBQztJQUU1RCxTQUFTLEdBQVcsR0FBRyxDQUFDLENBQUMsZUFBZTtJQUN4QyxXQUFXLEdBQVksSUFBSSxDQUFDO0lBRTVCLFlBQVksQ0FBTTtJQUVsQixJ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QUMsWUFBWTtZQVUxQixJQUFJO2tCQURILFlBQVk7bUJBQUMsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERpcmVjdGl2ZSwgRWxlbWVudFJlZiwgSG9zdExpc3RlbmVyLCBJbnB1dCwgT3V0cHV0LCBFdmVudEVtaXR0ZXIsIE9uRGVzdHJveSwgT25Jbml0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbmltcG9ydCB7IERyb3BwYWJsZURpcmVjdGl2ZSB9IGZyb20gJy4vbmd4LWRyb3BwYWJsZS5kaXJlY3RpdmUnO1xuaW1wb3J0IHsgRHJha2VTdG9yZVNlcnZpY2UgfSBmcm9tICcuLi9zZXJ2aWNlcy9kcmFrZS1zdG9yZS5zZXJ2aWNlJztcblxuLyoqXG4gKiBBZGRzIHByb3BlcnRpZXMgYW5kIGV2ZW50cyB0byBkcmFnZ2FibGUgZWxlbWVudHNcbiAqXG4gKiBAZXhwb3J0XG4gKi9cbkBEaXJlY3RpdmUoeyBzZWxlY3RvcjogJ1tuZ3hEcmFnZ2FibGVdJyB9KVxuZXhwb3J0IGNsYXNzIERyYWdnYWJsZURpcmVjdGl2ZSBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcbiAgQElucHV0KCkgbmd4RHJhZ2dhYmxlOiBzdHJpbmdbXTtcbiAgQElucHV0KCkgbW9kZWw6IGFueTtcblxuICBASW5wdXQoKVxuICBnZXQgZHJvcFpvbmVzKCk6IGFueSB7XG4gICAgcmV0dXJuIHRoaXMuX2Ryb3Bab25lcyB8fCB0aGlzLm5neERyYWdnYWJsZSB8fCB0aGlzLl9wYXJlbnREcm9wem9uZXM7XG4gIH1cbiAgc2V0IGRyb3Bab25lcyh2YWw6IGFueSkge1xuICAgIHRoaXMuX2Ryb3Bab25lcyA9IHZhbDtcbiAgfVxuXG4gIEBJbnB1dCgnbW92ZXMnKSBfbW92ZXM6IGJvb2xlYW4gfCAoKC4uLmFyZ3M6IGFueVtdKSA9PiBhbnkpID0gdHJ1ZTtcblxuICAvKlxuICBDb250ZW50Q2hpbGRyZW4gZG9lc24ndCBnZXQgY2hpbGRyZW4gY3JlYXRlZCB3aXRoIE5nVGVtcGxhdGVPdXRsZXRcbiAgU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvaXNzdWVzLzE0ODQyXG4gIEltcGxlbWVudGVkIHZpYSB1cGRhdGVFbGVtZW50cyBtZXRob2RcblxuICBAQ29udGVudENoaWxkcmVuKERyYWdIYW5kbGVEaXJlY3RpdmUsIHtkZXNjZW5kYW50czogdHJ1ZX0pXG4gIGhhbmRsZXNMaXN0OiBRdWVyeUxpc3Q8RHJhZ0hhbmRsZURpcmVjdGl2ZT47ICovXG5cbiAgaGFuZGxlczogYW55W10gPSBbXTtcblxuICBnZXQgaGFzSGFuZGxlKCkge1xuICAgIHJldHVybiAhIXRoaXMuaGFuZGxlcy5sZW5ndGg7XG4gIH1cblxuICBAT3V0cHV0KCkgZHJhZzogRXZlbnRFbWl0dGVyPGFueT4gPSBuZXcgRXZlbnRFbWl0dGVyPGFueT4oKTtcblxuICBkcmFnRGVsYXk6IG51bWJlciA9IDIwMDsgLy8gbWlsbGlzZWNvbmRzXG4gIGRyYWdEZWxheWVkOiBib29sZWFuID0gdHJ1ZTtcblxuICB0b3VjaFRpbWVvdXQ6IGFueTtcblxuICBnZXQgZWxlbWVudCgpOiBhbnkge1xuICAgIHJldHVybiB0aGlzLmVsLm5hdGl2ZUVsZW1lbnQ7XG4gIH1cblxuICBfZHJvcFpvbmVzOiBzdHJpbmdbXTtcbiAgX3BhcmVudERyb3B6b25lczogc3RyaW5nW107XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBlbDogRWxlbWVudFJlZixcbiAgICBwcml2YXRlIGRyYWtlc1NlcnZpY2U6IERyYWtlU3RvcmVTZXJ2aWNlLFxuICAgIHByaXZhdGUgZHJvcHBhYmxlRGlyZWN0aXZlOiBEcm9wcGFibGVEaXJlY3RpdmVcbiAgKSB7fVxuXG4gIC8vIEZyb206IGh0dHBzOi8vZ2l0aHViLmNvbS9iZXZhY3F1YS9kcmFndWxhL2lzc3Vlcy8yODkjaXNzdWVjb21tZW50LTI3NzE0MzE3MlxuICBASG9zdExpc3RlbmVyKCd0b3VjaG1vdmUnLCBbJyRldmVudCddKVxuICBvbk1vdmUoZTogRXZlbnQpIHtcbiAgICBpZiAoIXRoaXMuX21vdmVzIHx8IHRoaXMuZHJhZ0RlbGF5ZWQpIHtcbiAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy50b3VjaFRpbWVvdXQpO1xuICAgIH1cbiAgfVxuXG4gIEBIb3N0TGlzdGVuZXIoJ3RvdWNoc3RhcnQnKVxuICBvbkRvd24oKSB7XG4gICAgaWYgKHRoaXMuX21vdmVzKSB7XG4gICAgICB0aGlzLnRvdWNoVGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0aGlzLmRyYWdEZWxheWVkID0gZmFsc2U7XG4gICAgICB9LCB0aGlzLmRyYWdEZWxheSk7XG4gICAgfVxuICB9XG5cbiAgQEhvc3RMaXN0ZW5lcigndG91Y2hlbmQnKVxuICBvblVwKCkge1xuICAgIGlmICh0aGlzLl9tb3Zlcykge1xuICAgICAgY2xlYXJUaW1lb3V0KDxudW1iZXI+dGhpcy50b3VjaFRpbWVvdXQpO1xuICAgICAgdGhpcy5kcmFnRGVsYXllZCA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgbmdPbkluaXQoKTogdm9pZCB7XG4gICAgdGhpcy51cGRhdGUoKTtcbiAgfVxuXG4gIHVwZGF0ZSgpOiB2b2lkIHtcbiAgICB0aGlzLl9wYXJlbnREcm9wem9uZXMgPSBbdGhpcy5kcm9wcGFibGVEaXJlY3RpdmUuZHJvcFpvbmVdO1xuICAgIHRoaXMuZHJha2VzU2VydmljZS5yZWdpc3RlckRyYWdnYWJsZSh0aGlzKTtcbiAgICB0aGlzLnVwZGF0ZUVsZW1lbnRzKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLmRyYWtlc1NlcnZpY2UucmVtb3ZlRHJhZ2dhYmxlKHRoaXMpO1xuICB9XG5cbiAgdXBkYXRlRWxlbWVudHMoKTogdm9pZCB7XG4gICAgY29uc3QgbmF0aXZlRWxlbWVudCA9IHRoaXMuZWwubmF0aXZlRWxlbWVudDtcbiAgICBjb25zdCBoYW5kbGVzOiBOb2RlTGlzdCA9IG5hdGl2ZUVsZW1lbnQucXVlcnlTZWxlY3RvckFsbCgnW25neGRyYWdoYW5kbGVdJyk7XG4gICAgdGhpcy5oYW5kbGVzID0gQXJyYXkuZnJvbShoYW5kbGVzKS5maWx0ZXIoKGg6IGFueSkgPT4gZmluZEZpcnN0RHJhZ2dhYmxlUGFyZW50KGgpID09PSBuYXRpdmVFbGVtZW50KTtcblxuICAgIGZ1bmN0aW9uIGZpbmRGaXJzdERyYWdnYWJsZVBhcmVudChjOiBhbnkpIHtcbiAgICAgIHdoaWxlIChjLnBhcmVudE5vZGUpIHtcbiAgICAgICAgYyA9IGMucGFyZW50Tm9kZTtcbiAgICAgICAgaWYgKGMuaGFzQXR0cmlidXRlICYmIGMuaGFzQXR0cmlidXRlKCduZ3hkcmFnZ2FibGUnKSkge1xuICAgICAgICAgIHJldHVybiBjO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY2FuTW92ZShzb3VyY2U/OiBhbnksIGhhbmRsZT86IGFueSwgc2libGluZz86IGFueSk6IGJvb2xlYW4ge1xuICAgIGlmICh0eXBlb2YgdGhpcy5fbW92ZXMgPT09ICdib29sZWFuJykgcmV0dXJuIHRoaXMuX21vdmVzO1xuICAgIGlmICh0eXBlb2YgdGhpcy5fbW92ZXMgPT09ICdmdW5jdGlvbicpIHJldHVybiB0aGlzLl9tb3Zlcyh0aGlzLm1vZGVsLCBzb3VyY2UsIGhhbmRsZSwgc2libGluZyk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBtb3Zlcyhzb3VyY2U6IGFueSwgaGFuZGxlOiBhbnksIHNpYmxpbmc6IGFueSk6IGJvb2xlYW4ge1xuICAgIGlmICghdGhpcy5jYW5Nb3ZlKHNvdXJjZSwgaGFuZGxlLCBzaWJsaW5nKSkgcmV0dXJuIGZhbHNlO1xuXG4gICAgcmV0dXJuIHRoaXMuaGFzSGFuZGxlID8gdGhpcy5oYW5kbGVzLnNvbWUoaCA9PiBoYW5kZWxGb3IoaGFuZGxlLCBoKSkgOiB0cnVlO1xuXG4gICAgZnVuY3Rpb24gaGFuZGVsRm9yKGM6IGFueSwgcDogYW55KSB7XG4gICAgICBpZiAoYyA9PT0gcCkgcmV0dXJuIHRydWU7XG4gICAgICB3aGlsZSAoKGMgPSBjLnBhcmVudE5vZGUpICYmIGMgIT09IHApOyAvLyB0c2xpbnQ6ZGlzYWJsZS1saW5lXG4gICAgICByZXR1cm4gISFjO1xuICAgIH1cbiAgfVxuXG4gIG5nRG9DaGVjaygpOiB2b2lkIHtcbiAgICB0aGlzLnVwZGF0ZUVsZW1lbnRzKCk7XG4gIH1cbn1cbiJdfQ==