UNPKG

igniteui-angular

Version:

Ignite UI for Angular is a dependency-free Angular toolkit for building modern web apps

1,472 lines (1,471 loc) • 130 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,extraRequire,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ import { Directive, ElementRef, EventEmitter, HostBinding, HostListener, Input, NgModule, NgZone, Output, Renderer2, ChangeDetectorRef } from '@angular/core'; import { animationFrameScheduler, fromEvent, interval, Subject } from 'rxjs'; import { takeUntil, throttle } from 'rxjs/operators'; /** @enum {number} */ const RestrictDrag = { VERTICALLY: 0, HORIZONTALLY: 1, NONE: 2, }; export { RestrictDrag }; RestrictDrag[RestrictDrag.VERTICALLY] = 'VERTICALLY'; RestrictDrag[RestrictDrag.HORIZONTALLY] = 'HORIZONTALLY'; RestrictDrag[RestrictDrag.NONE] = 'NONE'; export class IgxDragCustomEventDetails { } if (false) { /** @type {?} */ IgxDragCustomEventDetails.prototype.startX; /** @type {?} */ IgxDragCustomEventDetails.prototype.startY; /** @type {?} */ IgxDragCustomEventDetails.prototype.pageX; /** @type {?} */ IgxDragCustomEventDetails.prototype.pageY; /** @type {?} */ IgxDragCustomEventDetails.prototype.owner; /** @type {?} */ IgxDragCustomEventDetails.prototype.originalEvent; } export class IgxDropEnterEventArgs { } if (false) { /** * Reference to the original event that caused the draggable element to enter the igxDrop element. * Can be PointerEvent, TouchEvent or MouseEvent. * @type {?} */ IgxDropEnterEventArgs.prototype.originalEvent; /** * The owner igxDrop directive that triggered this event. * @type {?} */ IgxDropEnterEventArgs.prototype.owner; /** * The igxDrag directive instanced on an element that entered the area of the igxDrop element * @type {?} */ IgxDropEnterEventArgs.prototype.drag; /** * The data contained for the draggable element in igxDrag directive. * @type {?} */ IgxDropEnterEventArgs.prototype.dragData; /** * The initial position of the pointer on X axis when the dragged element began moving * @type {?} */ IgxDropEnterEventArgs.prototype.startX; /** * The initial position of the pointer on Y axis when the dragged element began moving * @type {?} */ IgxDropEnterEventArgs.prototype.startY; /** * The current position of the pointer on X axis when the event was triggered. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEnterEventArgs.prototype.pageX; /** * The current position of the pointer on Y axis when the event was triggered. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEnterEventArgs.prototype.pageY; /** * The current position of the pointer on X axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEnterEventArgs.prototype.offsetX; /** * The current position of the pointer on Y axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEnterEventArgs.prototype.offsetY; } export class IgxDropLeaveEventArgs { } if (false) { /** * Reference to the original event that caused the draggable element to enter the igxDrop element. * Can be PointerEvent, TouchEvent or MouseEvent. * @type {?} */ IgxDropLeaveEventArgs.prototype.originalEvent; /** * The owner igxDrop directive that triggered this event. * @type {?} */ IgxDropLeaveEventArgs.prototype.owner; /** * The igxDrag directive instanced on an element that entered the area of the igxDrop element * @type {?} */ IgxDropLeaveEventArgs.prototype.drag; /** * The data contained for the draggable element in igxDrag directive. * @type {?} */ IgxDropLeaveEventArgs.prototype.dragData; /** * The initial position of the pointer on X axis when the dragged element began moving * @type {?} */ IgxDropLeaveEventArgs.prototype.startX; /** * The initial position of the pointer on Y axis when the dragged element began moving * @type {?} */ IgxDropLeaveEventArgs.prototype.startY; /** * The current position of the pointer on X axis when the event was triggered. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropLeaveEventArgs.prototype.pageX; /** * The current position of the pointer on Y axis when the event was triggered. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropLeaveEventArgs.prototype.pageY; /** * The current position of the pointer on X axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropLeaveEventArgs.prototype.offsetX; /** * The current position of the pointer on Y axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropLeaveEventArgs.prototype.offsetY; } export class IgxDropEventArgs { } if (false) { /** * Reference to the original event that caused the draggable element to enter the igxDrop element. * Can be PointerEvent, TouchEvent or MouseEvent. * @type {?} */ IgxDropEventArgs.prototype.originalEvent; /** * The owner igxDrop directive that triggered this event. * @type {?} */ IgxDropEventArgs.prototype.owner; /** * The igxDrag directive instanced on an element that entered the area of the igxDrop element * @type {?} */ IgxDropEventArgs.prototype.drag; /** * The current position of the pointer on X axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEventArgs.prototype.offsetX; /** * The current position of the pointer on Y axis relative to the container that initializes the igxDrop. * Note: The browser might trigger the event with some delay and pointer would be already inside the igxDrop. * @type {?} */ IgxDropEventArgs.prototype.offsetY; /** * Whether the default drop behavior of the igxDrop directive should be canceled. * Note: If you implement custom behavior and you use `animateOnRelease` for the igxDrag make sure to call 'event.drag.dropFinished();' * to notify the igxDrag directive that it has been dropped so it animates properly. * @type {?} */ IgxDropEventArgs.prototype.cancel; } /** * @record */ export function IDragBaseEventArgs() { } if (false) { /** * Reference to the original event that caused the interaction with the element. * Can be PointerEvent, TouchEvent or MouseEvent. * @type {?} */ IDragBaseEventArgs.prototype.originalEvent; /** * The owner igxDrag directive that triggered this event. * @type {?} */ IDragBaseEventArgs.prototype.owner; } /** * @record */ export function IDragStartEventArgs() { } if (false) { /** * Set if the the dragging should be canceled. * @type {?} */ IDragStartEventArgs.prototype.cancel; } export class IgxDragDirective { /** * @param {?} cdr * @param {?} element * @param {?} zone * @param {?} renderer */ constructor(cdr, element, zone, renderer) { this.cdr = cdr; this.element = element; this.zone = zone; this.renderer = renderer; /** * An \@Input property that indicates when the drag should start * By default the drag starts after the draggable element is moved by 5px * ```html * <div igxDrag [dragTolerance]="100"> * <span>Drag Me!</span> * </div> * ``` */ this.dragTolerance = 5; /** * Sets a custom class that will be added to the `dragGhost` element. * ```html * <div igxDrag [ghostImageClass]="'dragGhost'"> * <span>Drag Me!</span> * </div> * ``` */ this.ghostImageClass = ''; /** * An \@Input property that hides the draggable element. * By default it's set to false. * ```html * <div igxDrag [dragTolerance]="100" [hideBaseOnDrag]="'true'"> * <span>Drag Me!</span> * </div> * ``` */ this.hideBaseOnDrag = false; /** * An \@Input property that enables/disables the draggable element animation * when the element is released. * By default it's set to false. * ```html * <div igxDrag [animateOnRelease]="'true'"> * <span>Drag Me!</span> * </div> * ``` */ this.animateOnRelease = false; /** * An \@Input property that sets the element to which the dragged element will be appended. * By default it's set to null and the dragged element is appended to the body. * ```html * <div #hostDiv></div> * <div igxDrag [dragGhostHost]="hostDiv"> * <span>Drag Me!</span> * </div> * ``` */ this.dragGhostHost = null; /** * Event triggered when the draggable element drag starts. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragStart)="onDragStart()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onDragStart(){ * alert("The drag has stared!"); * } * ``` */ this.dragStart = new EventEmitter(); /** * Event triggered when the draggable element is released. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragEnd)="onDragEnd()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onDragEnd(){ * alert("The drag has ended!"); * } * ``` */ this.dragEnd = new EventEmitter(); /** * Event triggered after the draggable element is released and after its animation has finished. * ```html * <div igxDrag [animateOnRelease]="'true'" (returnMoveEnd)="onMoveEnd()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onMoveEnd(){ * alert("The move has ended!"); * } * ``` */ this.returnMoveEnd = new EventEmitter(); /** * Event triggered when the draggable element is clicked. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragClicked)="dragClicked()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public dragClicked(){ * alert("The elemented has been clicked!"); * } * ``` */ this.dragClicked = new EventEmitter(); /** * @hidden */ this.touch = 'none'; /** * @hidden */ this.transitionProperty = 'top, left'; /** * @hidden */ this._visibility = 'visible'; /** * @hidden */ this.defaultReturnDuration = '0.5s'; /** * @hidden */ this._startX = 0; /** * @hidden */ this._startY = 0; /** * @hidden */ this._dragStarted = false; /** * @hidden */ this._pointerDownId = null; /** * @hidden */ this._clicked = false; /** * @hidden */ this._lastDropArea = null; /** * @hidden */ this._destroy = new Subject(); /** * @hidden */ this._removeOnDestroy = true; } /** * Sets the visibility of the draggable element. * ```typescript * \@ViewChild("myDrag" ,{read: IgxDragDirective}) * public myDrag: IgxDragDirective; * ngAfterViewInit(){ * this.myDrag.visible = false; * } * ``` * @param {?} bVisible * @return {?} */ set visible(bVisible) { this._visibility = bVisible ? 'visible' : 'hidden'; this.cdr.detectChanges(); } /** * Returns the visibility state of the draggable element. * ```typescript * \@ViewChild("myDrag" ,{read: IgxDragDirective}) * public myDrag: IgxDragDirective; * ngAfterViewInit(){ * let dragVisibilty = this.myDrag.visible; * } * ``` * @return {?} */ get visible() { return this._visibility === 'visible'; } /** * @hidden * @param {?} val * @return {?} */ set left(val) { requestAnimationFrame(() => { if (this._dragGhost) { this._dragGhost.style.left = val + 'px'; } }); } /** * @hidden * @return {?} */ get left() { return parseInt(this._dragGhost.style.left, 10); } /** * @hidden * @param {?} val * @return {?} */ set top(val) { requestAnimationFrame(() => { if (this._dragGhost) { this._dragGhost.style.top = val + 'px'; } }); } /** * @hidden * @return {?} */ get top() { return parseInt(this._dragGhost.style.top, 10); } /** * Returns if the browser supports pointer events. * ```typescript * \@ViewChild("myDrag" ,{read: IgxDragDirective}) * public myDrag: IgxDragDirective; * ngAfterViewInit(){ * let pointerEvents = this.myDrag.pointerEventsEnabled; * } * ``` * @return {?} */ get pointerEventsEnabled() { return typeof PointerEvent !== 'undefined'; } /** * Returns if the browser supports touch events. * ```typescript * \@ViewChild("myDrag" ,{read: IgxDragDirective}) * public myDrag: IgxDragDirective; * ngAfterViewInit(){ * let touchEvents = this.myDrag.pointerEventsEnabled; * } * ``` * @return {?} */ get touchEventsEnabled() { return 'ontouchstart' in window; } /** * @hidden * @return {?} */ ngOnInit() { this.zone.runOutsideAngular(() => { if (this.pointerEventsEnabled) { fromEvent(this.element.nativeElement, 'pointerdown').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerDown(res)); fromEvent(this.element.nativeElement, 'pointermove').pipe(throttle(() => interval(0, animationFrameScheduler)), takeUntil(this._destroy)).subscribe((res) => this.onPointerMove(res)); fromEvent(this.element.nativeElement, 'pointerup').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerUp(res)); } else if (this.touchEventsEnabled) { // We don't have pointer events and touch events. Use then mouse events. fromEvent(this.element.nativeElement, 'touchstart').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerDown(res)); fromEvent(document.defaultView, 'touchmove').pipe(throttle(() => interval(0, animationFrameScheduler)), takeUntil(this._destroy)).subscribe((res) => this.onPointerMove(res)); fromEvent(document.defaultView, 'touchend').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerUp(res)); } else { // We don't have pointer events and touch events. Use then mouse events. fromEvent(this.element.nativeElement, 'mousedown').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerDown(res)); fromEvent(document.defaultView, 'mousemove').pipe(throttle(() => interval(0, animationFrameScheduler)), takeUntil(this._destroy)).subscribe((res) => this.onPointerMove(res)); fromEvent(document.defaultView, 'mouseup').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onPointerUp(res)); } }); } /** * @hidden * @return {?} */ ngOnDestroy() { this._destroy.next(true); this._destroy.complete(); if (this._dragGhost && this._removeOnDestroy) { this._dragGhost.parentNode.removeChild(this._dragGhost); this._dragGhost = null; } } /** * @hidden * Method bound to the PointerDown event of the base element igxDrag is initialized. * @param {?} event PointerDown event captured * @return {?} */ onPointerDown(event) { this._clicked = true; this._pointerDownId = event.pointerId; if (this.pointerEventsEnabled || !this.touchEventsEnabled) { // Check first for pointer events or non touch, because we can have pointer events and touch events at once. this._startX = event.pageX; this._startY = event.pageY; } else if (this.touchEventsEnabled) { this._startX = event.touches[0].pageX; this._startY = event.touches[0].pageY; } // Take margins because getBoundingClientRect() doesn't include margins of the element /** @type {?} */ const marginTop = parseInt(document.defaultView.getComputedStyle(this.element.nativeElement)['margin-top'], 10); /** @type {?} */ const marginLeft = parseInt(document.defaultView.getComputedStyle(this.element.nativeElement)['margin-left'], 10); this._dragOffsetX = (this._startX - this.element.nativeElement.getBoundingClientRect().left - this.getWindowScrollLeft()) + marginLeft; this._dragOffsetY = (this._startY - this.element.nativeElement.getBoundingClientRect().top - this.getWindowScrollTop()) + marginTop; this._dragStartX = this._startX - this._dragOffsetX; this._dragStartY = this._startY - this._dragOffsetY; // Set pointer capture so we detect pointermove even if mouse is out of bounds until dragGhost is created. if (this.pointerEventsEnabled) { this.element.nativeElement.setPointerCapture(this._pointerDownId); } else { this.element.nativeElement.focus(); event.preventDefault(); } } /** * @hidden * Perfmorm drag move logic when dragging and dispatching events if there is igxDrop under the pointer. * This method is bound at first at the base element. * If dragging starts and after the dragGhost is rendered the pointerId is reassigned to the dragGhost. Then this method is bound to it. * @param {?} event PointerMove event captured * @return {?} */ onPointerMove(event) { if (this._clicked) { /** @type {?} */ const dragStartArgs = { originalEvent: event, owner: this, cancel: false }; /** @type {?} */ let pageX; /** @type {?} */ let pageY; if (this.pointerEventsEnabled || !this.touchEventsEnabled) { // Check first for pointer events or non touch, because we can have pointer events and touch events at once. pageX = event.pageX; pageY = event.pageY; } else if (this.touchEventsEnabled) { pageX = event.touches[0].pageX; pageY = event.touches[0].pageY; // Prevent scrolling on touch while dragging event.preventDefault(); } /** @type {?} */ const totalMovedX = pageX - this._startX; /** @type {?} */ const totalMovedY = pageY - this._startY; if (!this._dragStarted && (Math.abs(totalMovedX) > this.dragTolerance || Math.abs(totalMovedY) > this.dragTolerance)) { this.zone.run(() => { this.dragStart.emit(dragStartArgs); }); if (!dragStartArgs.cancel) { this._dragStarted = true; // We moved enough so dragGhost can be rendered and actual dragging to start. this.createDragGhost(event); } return; } else if (!this._dragStarted) { return; } this.left = this._dragStartX + totalMovedX; this.top = this._dragStartY + totalMovedY; this.dispatchDragEvents(pageX, pageY, event); } } /** * @hidden * Perform drag end logic when releasing the dragGhost and dispatchind drop event if igxDrop is under the pointer. * This method is bound at first at the base element. * If dragging starts and after the dragGhost is rendered the pointerId is reassigned to the dragGhost. Then this method is bound to it. * @param {?} event PointerUp event captured * @return {?} */ onPointerUp(event) { if (!this._clicked) { return; } /** @type {?} */ const eventArgs = { originalEvent: event, owner: this }; this._clicked = false; if (this._dragStarted) { if (this._lastDropArea && this._lastDropArea !== this.element.nativeElement) { if (!this.animateOnRelease) { this.onTransitionEnd(null); } // dragging ended over a drop area. Call this after transition because onDrop might remove the element. this.dispatchDropEvent(event.pageX, event.pageY, event); // else the drop directive needs to call the dropFinished() method so the animation can perform } else if (this.animateOnRelease && (this.left !== Math.floor(this._dragStartX) || this.top !== Math.floor(this._dragStartY))) { // If the start positions are the same as the current the transition will not execute. // return the ghost to start position before removing it. See onTransitionEnd. this._dragGhost.style.transitionDuration = this.defaultReturnDuration; this.left = this._dragStartX; this.top = this._dragStartY; } else { this.onTransitionEnd(null); } this.zone.run(() => { this.dragEnd.emit(eventArgs); }); } else { this.zone.run(() => { this.dragClicked.emit(eventArgs); }); } } /** * @hidden * Create dragGhost element - if a Node object is provided it creates a clone of that node, * otherwise it clones the host element. * Bind all needed events. * @protected * @param {?} event Pointer event required when the dragGhost is being initialized. * @param {?=} node The Node object to be cloned. * @return {?} */ createDragGhost(event, node = null) { this._dragGhost = node ? node.cloneNode(true) : this.element.nativeElement.cloneNode(true); this._dragGhost.style.transitionDuration = '0.0s'; this._dragGhost.style.position = 'absolute'; /** @type {?} */ const hostLeft = this.dragGhostHost ? this.dragGhostHost.getBoundingClientRect().left : 0; /** @type {?} */ const hostTop = this.dragGhostHost ? this.dragGhostHost.getBoundingClientRect().top : 0; this._dragGhost.style.top = this._dragStartY - hostTop + 'px'; this._dragGhost.style.left = this._dragStartX - hostLeft + 'px'; if (this.ghostImageClass) { this.renderer.addClass(this._dragGhost, this.ghostImageClass); } if (this.dragGhostHost) { this.dragGhostHost.appendChild(this._dragGhost); } else { document.body.appendChild(this._dragGhost); } if (this.pointerEventsEnabled) { // The dragGhost takes control for moving and dragging after it has been shown. this._dragGhost.setPointerCapture(this._pointerDownId); this._dragGhost.addEventListener('pointermove', (args) => { this.onPointerMove(args); }); this._dragGhost.addEventListener('pointerup', (args) => { this.onPointerUp(args); }); } if (this.animateOnRelease) { // Transition animation when the dragGhost is released and it returns to it's original position. this._dragGhost.addEventListener('transitionend', (args) => { this.onTransitionEnd(args); }); } // Hide the base after the dragGhost is created, because otherwise the dragGhost will be not visible. if (this.hideBaseOnDrag) { this.visible = false; } } /** * @hidden * Dispatch custom igxDragEnter/igxDragLeave events based on current pointer position and if drop area is under. * @protected * @param {?} pageX * @param {?} pageY * @param {?} originalEvent * @return {?} */ dispatchDragEvents(pageX, pageY, originalEvent) { /** @type {?} */ let topDropArea; /** @type {?} */ const eventArgs = { startX: this._startX, startY: this._startY, pageX: pageX, pageY: pageY, owner: this, originalEvent: originalEvent }; /** @type {?} */ const elementsFromPoint = this.getElementsAtPoint(pageX, pageY); for (let i = 0; i < elementsFromPoint.length; i++) { if (elementsFromPoint[i].getAttribute('droppable') === 'true' && elementsFromPoint[i] !== this._dragGhost) { topDropArea = elementsFromPoint[i]; break; } } if (topDropArea) { this.dispatchEvent(topDropArea, 'igxDragOver', eventArgs); } if (topDropArea && (!this._lastDropArea || (this._lastDropArea && this._lastDropArea !== topDropArea))) { if (this._lastDropArea) { this.dispatchEvent(this._lastDropArea, 'igxDragLeave', eventArgs); } this._lastDropArea = topDropArea; this.dispatchEvent(this._lastDropArea, 'igxDragEnter', eventArgs); } else if (!topDropArea && this._lastDropArea) { this.dispatchEvent(this._lastDropArea, 'igxDragLeave', eventArgs); this._lastDropArea = null; } } /** * @hidden * Dispatch custom igxDrop event based on current pointer position if there is last recorder drop area under the pointer. * Last recorder drop area is updated in \@dispatchDragEvents method. * @protected * @param {?} pageX * @param {?} pageY * @param {?} originalEvent * @return {?} */ dispatchDropEvent(pageX, pageY, originalEvent) { /** @type {?} */ const eventArgs = { startX: this._startX, startY: this._startY, pageX: pageX, pageY: pageY, owner: this, originalEvent: originalEvent }; this.dispatchEvent(this._lastDropArea, 'igxDrop', eventArgs); this.dispatchEvent(this._lastDropArea, 'igxDragLeave', eventArgs); this._lastDropArea = null; } /** * @hidden * Update relative positions * @return {?} */ updateDragRelativePos() { if (!this._dragGhost) { return; } // Calculate the new dragGhost position to remain where the mouse is, so it doesn't jump /** @type {?} */ const totalDraggedX = this.left - this._dragStartX; /** @type {?} */ const totalDraggedY = this.top - this._dragStartY; /** @type {?} */ const newPosX = this.element.nativeElement.getBoundingClientRect().left; /** @type {?} */ const newPosY = this.element.nativeElement.getBoundingClientRect().top; /** @type {?} */ const diffStartX = this._dragStartX - newPosX; /** @type {?} */ const diffStartY = this._dragStartY - newPosY; this.top = newPosX + totalDraggedX - diffStartX; this.left = newPosY + totalDraggedY - diffStartY; } /** * Informs the `igxDrag` directive that it has been dropped/released. * This should usully be called when `animateOnRelease` is set to `true`. * When canceling or defining custom drop logic this tells the igxDrag to update it's positions and * animate correctly to the new position. * ```typescript * public onDropElem(event) { * // Function bound to the igxDrop directive event `onDrop` * // This cancels the default drop logic of the `igxDrop` * event.cancel = true; * event.drag.dropFinished(); * } * ``` * @return {?} */ dropFinished() { if (this.animateOnRelease && this._dragGhost) { this.updateDragRelativePos(); // Return the dragged element to the start. See onTransitionEnd next. // Take margins becuase getBoundingClientRect() doesn't include margins /** @type {?} */ const marginTop = parseInt(document.defaultView.getComputedStyle(this.element.nativeElement)['margin-top'], 10); /** @type {?} */ const marginLeft = parseInt(document.defaultView.getComputedStyle(this.element.nativeElement)['margin-left'], 10); /** @type {?} */ const newPosX = this.element.nativeElement.getBoundingClientRect().left + this.getWindowScrollLeft(); /** @type {?} */ const newPosY = this.element.nativeElement.getBoundingClientRect().top + this.getWindowScrollTop(); this._dragGhost.style.transitionDuration = this.defaultReturnDuration; this.left = newPosX - marginLeft; this.top = newPosY - marginTop; } } /** * @hidden * @param {?} event * @return {?} */ onTransitionEnd(event) { if (this._dragStarted && !this._clicked) { if (this.hideBaseOnDrag) { this.visible = true; } this._dragGhost.parentNode.removeChild(this._dragGhost); this._dragGhost = null; this.element.nativeElement.style.transitionDuration = '0.0s'; this._dragStarted = false; this.zone.run(() => { this.returnMoveEnd.emit({ originalEvent: event, owner: this }); }); } } /** * @hidden * @protected * @param {?} pageX * @param {?} pageY * @return {?} */ getElementsAtPoint(pageX, pageY) { // correct the coordinates with the current scroll position, because // document.elementsFromPoint conider position within the current viewport // window.pageXOffset == window.scrollX; // always true // using window.pageXOffset for IE9 compatibility /** @type {?} */ const viewPortX = pageX - window.pageXOffset; /** @type {?} */ const viewPortY = pageY - window.pageYOffset; if (document['msElementsFromPoint']) { // Edge and IE special snowflakes return document['msElementsFromPoint'](viewPortX, viewPortY); } else { // Other browsers like Chrome, Firefox, Opera return document.elementsFromPoint(viewPortX, viewPortY); } } /** * @hidden * @protected * @param {?} target * @param {?} eventName * @param {?} eventArgs * @return {?} */ dispatchEvent(target, eventName, eventArgs) { // This way is IE11 compatible. /** @type {?} */ const dragLeaveEvent = document.createEvent('CustomEvent'); dragLeaveEvent.initCustomEvent(eventName, false, false, eventArgs); target.dispatchEvent(dragLeaveEvent); // Othersie can be used `target.dispatchEvent(new CustomEvent(eventName, eventArgs));` } /** * @protected * @return {?} */ getWindowScrollTop() { return window.scrollY ? window.scrollY : (window.pageYOffset ? window.pageYOffset : 0); } /** * @protected * @return {?} */ getWindowScrollLeft() { return window.scrollX ? window.scrollX : (window.pageXOffset ? window.pageXOffset : 0); } } IgxDragDirective.decorators = [ { type: Directive, args: [{ selector: '[igxDrag]' },] } ]; /** @nocollapse */ IgxDragDirective.ctorParameters = () => [ { type: ChangeDetectorRef }, { type: ElementRef }, { type: NgZone }, { type: Renderer2 } ]; IgxDragDirective.propDecorators = { data: [{ type: Input, args: ['igxDrag',] }], dragTolerance: [{ type: Input }], ghostImageClass: [{ type: Input }], hideBaseOnDrag: [{ type: Input }], animateOnRelease: [{ type: Input }], dragGhostHost: [{ type: Input }], dragStart: [{ type: Output }], dragEnd: [{ type: Output }], returnMoveEnd: [{ type: Output }], dragClicked: [{ type: Output }], touch: [{ type: HostBinding, args: ['style.touchAction',] }], transitionProperty: [{ type: HostBinding, args: ['style.transitionProperty',] }], _visibility: [{ type: HostBinding, args: ['style.visibility',] }] }; if (false) { /** * - Save data inside the `igxDrag` directive. This can be set when instancing `igxDrag` on an element. * ```html * <div [igxDrag]="{ source: myElement }"></div> * ``` * @type {?} */ IgxDragDirective.prototype.data; /** * An \@Input property that indicates when the drag should start * By default the drag starts after the draggable element is moved by 5px * ```html * <div igxDrag [dragTolerance]="100"> * <span>Drag Me!</span> * </div> * ``` * @type {?} */ IgxDragDirective.prototype.dragTolerance; /** * Sets a custom class that will be added to the `dragGhost` element. * ```html * <div igxDrag [ghostImageClass]="'dragGhost'"> * <span>Drag Me!</span> * </div> * ``` * @type {?} */ IgxDragDirective.prototype.ghostImageClass; /** * An \@Input property that hides the draggable element. * By default it's set to false. * ```html * <div igxDrag [dragTolerance]="100" [hideBaseOnDrag]="'true'"> * <span>Drag Me!</span> * </div> * ``` * @type {?} */ IgxDragDirective.prototype.hideBaseOnDrag; /** * An \@Input property that enables/disables the draggable element animation * when the element is released. * By default it's set to false. * ```html * <div igxDrag [animateOnRelease]="'true'"> * <span>Drag Me!</span> * </div> * ``` * @type {?} */ IgxDragDirective.prototype.animateOnRelease; /** * An \@Input property that sets the element to which the dragged element will be appended. * By default it's set to null and the dragged element is appended to the body. * ```html * <div #hostDiv></div> * <div igxDrag [dragGhostHost]="hostDiv"> * <span>Drag Me!</span> * </div> * ``` * @type {?} */ IgxDragDirective.prototype.dragGhostHost; /** * Event triggered when the draggable element drag starts. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragStart)="onDragStart()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onDragStart(){ * alert("The drag has stared!"); * } * ``` * @type {?} */ IgxDragDirective.prototype.dragStart; /** * Event triggered when the draggable element is released. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragEnd)="onDragEnd()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onDragEnd(){ * alert("The drag has ended!"); * } * ``` * @type {?} */ IgxDragDirective.prototype.dragEnd; /** * Event triggered after the draggable element is released and after its animation has finished. * ```html * <div igxDrag [animateOnRelease]="'true'" (returnMoveEnd)="onMoveEnd()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public onMoveEnd(){ * alert("The move has ended!"); * } * ``` * @type {?} */ IgxDragDirective.prototype.returnMoveEnd; /** * Event triggered when the draggable element is clicked. * ```html * <div igxDrag [animateOnRelease]="'true'" (dragClicked)="dragClicked()"> * <span>Drag Me!</span> * </div> * ``` * ```typescript * public dragClicked(){ * alert("The elemented has been clicked!"); * } * ``` * @type {?} */ IgxDragDirective.prototype.dragClicked; /** * @hidden * @type {?} */ IgxDragDirective.prototype.touch; /** * @hidden * @type {?} */ IgxDragDirective.prototype.transitionProperty; /** * @hidden * @type {?} */ IgxDragDirective.prototype._visibility; /** * @hidden * @type {?} */ IgxDragDirective.prototype.defaultReturnDuration; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._startX; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._startY; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragGhost; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragStarted; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragOffsetX; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragOffsetY; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragStartX; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._dragStartY; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._pointerDownId; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._clicked; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._lastDropArea; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._destroy; /** * @hidden * @type {?} * @protected */ IgxDragDirective.prototype._removeOnDestroy; /** @type {?} */ IgxDragDirective.prototype.cdr; /** @type {?} */ IgxDragDirective.prototype.element; /** @type {?} */ IgxDragDirective.prototype.zone; /** @type {?} */ IgxDragDirective.prototype.renderer; } export class IgxDropDirective { /** * @param {?} element * @param {?} _renderer * @param {?} _zone */ constructor(element, _renderer, _zone) { this.element = element; this._renderer = _renderer; this._zone = _zone; /** * Event triggered when dragged element enters the area of the element. * ```html * <div class="cageArea" igxDrop (onEnter)="dragEnter()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragEnter(){ * alert("A draggable elemente has entered the chip area!"); * } * ``` */ this.onEnter = new EventEmitter(); /** * Event triggered when dragged element leaves the area of the element. * ```html * <div class="cageArea" igxDrop (onLeave)="dragLeave()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragLeave(){ * alert("A draggable elemente has left the chip area!"); * } * ``` */ this.onLeave = new EventEmitter(); /** * Event triggered when dragged element is dropped in the area of the element. * Since the `igxDrop` has default logic that appends the dropped element as a child, it can be canceled here. * To cancel the default logic the `cancel` property of the event needs to be set to true. * ```html * <div class="cageArea" igxDrop (onDrop)="dragDrop()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragDrop(){ * alert("A draggable elemente has been dropped in the chip area!"); * } * ``` */ this.onDrop = new EventEmitter(); /** * @hidden */ this.droppable = true; /** * @hidden */ this.dragover = false; /** * @hidden */ this._destroy = new Subject(); } /** * @return {?} */ ngOnInit() { this._zone.runOutsideAngular(() => { fromEvent(this.element.nativeElement, 'igxDragEnter').pipe(takeUntil(this._destroy)) .subscribe((res) => this.onDragEnter((/** @type {?} */ (res)))); fromEvent(this.element.nativeElement, 'igxDragLeave').pipe(takeUntil(this._destroy)).subscribe((res) => this.onDragLeave(res)); fromEvent(this.element.nativeElement, 'igxDragOver').pipe(takeUntil(this._destroy)).subscribe((res) => this.onDragOver(res)); }); } /** * @return {?} */ ngOnDestroy() { this._destroy.next(true); this._destroy.complete(); } /** * @hidden * @param {?} event * @return {?} */ onDragOver(event) { } /** * @hidden * @param {?} event * @return {?} */ onDragEnter(event) { this.dragover = true; /** @type {?} */ const elementPosX = this.element.nativeElement.getBoundingClientRect().left + this.getWindowScrollLeft(); /** @type {?} */ const elementPosY = this.element.nativeElement.getBoundingClientRect().top + this.getWindowScrollTop(); /** @type {?} */ const offsetX = event.detail.pageX - elementPosX; /** @type {?} */ const offsetY = event.detail.pageY - elementPosY; /** @type {?} */ const eventArgs = { originalEvent: event.detail.originalEvent, owner: this, drag: event.detail.owner, dragData: event.detail.owner.data, startX: event.detail.startX, startY: event.detail.startY, pageX: event.detail.pageX, pageY: event.detail.pageY, offsetX: offsetX, offsetY: offsetY }; this._zone.run(() => { this.onEnter.emit(eventArgs); }); } /** * @hidden * @param {?} event * @return {?} */ onDragLeave(event) { this.dragover = false; /** @type {?} */ const elementPosX = this.element.nativeElement.getBoundingClientRect().left + this.getWindowScrollLeft(); /** @type {?} */ const elementPosY = this.element.nativeElement.getBoundingClientRect().top + this.getWindowScrollTop(); /** @type {?} */ const offsetX = event.detail.pageX - elementPosX; /** @type {?} */ const offsetY = event.detail.pageY - elementPosY; /** @type {?} */ const eventArgs = { originalEvent: event.detail.originalEvent, owner: this, drag: event.detail.owner, dragData: event.detail.owner.data, startX: event.detail.startX, startY: event.detail.startY, pageX: event.detail.pageX, pageY: event.detail.pageY, offsetX: offsetX, offsetY: offsetY }; this._zone.run(() => { this.onLeave.emit(eventArgs); }); } /** * @hidden * @param {?} event * @return {?} */ onDragDrop(event) { /** @type {?} */ const elementPosX = this.element.nativeElement.getBoundingClientRect().left + this.getWindowScrollLeft(); /** @type {?} */ const elementPosY = this.element.nativeElement.getBoundingClientRect().top + this.getWindowScrollTop(); /** @type {?} */ const offsetX = event.detail.pageX - elementPosX; /** @type {?} */ const offsetY = event.detail.pageY - elementPosY; /** @type {?} */ const args = { owner: this, originalEvent: event.detail.originalEvent, drag: event.detail.owner, offsetX: offsetX, offsetY: offsetY, cancel: false }; this._zone.run(() => { this.onDrop.emit(args); }); if (!args.cancel) { // To do for generic scenario this._renderer.removeChild(event.detail.owner.element.nativeElement.parentNode, event.detail.owner.element.nativeElement); this._renderer.appendChild(this.element.nativeElement, event.detail.owner.element.nativeElement); setTimeout(() => { event.detail.owner.dropFinished(); }, 0); } } /** * @protected * @return {?} */ getWindowScrollTop() { return window.scrollY ? window.scrollY : (window.pageYOffset ? window.pageYOffset : 0); } /** * @protected * @return {?} */ getWindowScrollLeft() { return window.scrollX ? window.scrollX : (window.pageXOffset ? window.pageXOffset : 0); } } IgxDropDirective.decorators = [ { type: Directive, args: [{ selector: '[igxDrop]' },] } ]; /** @nocollapse */ IgxDropDirective.ctorParameters = () => [ { type: ElementRef }, { type: Renderer2 }, { type: NgZone } ]; IgxDropDirective.propDecorators = { data: [{ type: Input, args: ['igxDrop',] }], onEnter: [{ type: Output }], onLeave: [{ type: Output }], onDrop: [{ type: Output }], droppable: [{ type: HostBinding, args: ['attr.droppable',] }], dragover: [{ type: HostBinding, args: ['class.dragOver',] }], onDragDrop: [{ type: HostListener, args: ['igxDrop', ['$event'],] }] }; if (false) { /** * - Save data inside the `igxDrop` directive. This can be set when instancing `igxDrop` on an element. * ```html * <div [igxDrop]="{ source: myElement }"></div> * ``` * @type {?} */ IgxDropDirective.prototype.data; /** * Event triggered when dragged element enters the area of the element. * ```html * <div class="cageArea" igxDrop (onEnter)="dragEnter()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragEnter(){ * alert("A draggable elemente has entered the chip area!"); * } * ``` * @type {?} */ IgxDropDirective.prototype.onEnter; /** * Event triggered when dragged element leaves the area of the element. * ```html * <div class="cageArea" igxDrop (onLeave)="dragLeave()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragLeave(){ * alert("A draggable elemente has left the chip area!"); * } * ``` * @type {?} */ IgxDropDirective.prototype.onLeave; /** * Event triggered when dragged element is dropped in the area of the element. * Since the `igxDrop` has default logic that appends the dropped element as a child, it can be canceled here. * To cancel the default logic the `cancel` property of the event needs to be set to true. * ```html * <div class="cageArea" igxDrop (onDrop)="dragDrop()" (igxDragEnter)="onDragCageEnter()" (igxDragLeave)="onDragCageLeave()"> * </div> * ``` * ```typescript * public dragDrop(){ * alert("A draggable elemente has been dropped in the chip area!"); * } * ``` * @type {?} */ IgxDropDirective.prototype.onDrop; /** * @hidden * @type {?} */ IgxDropDirective.prototype.droppable; /** * @hidden * @type {?} */ IgxDropDirective.prototype.dragover; /** * @hidden * @type {?} * @protected */ IgxDropDirective.prototype._destroy;