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
JavaScript
/**
* @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;