{"version":3,"sources":["internal/constants.ts","internal/dom-utils.ts","internal/feature-detection.ts","internal/drag-data-store.ts","internal/drag-utils.ts","internal/drag-operation-controller.ts","index.ts"],"names":["CLASS_PREFIX","CLASS_DRAG_IMAGE_SNAPBACK","EVENT_PREFIX","EVENT_DRAG_DRAGSTART_PENDING","EVENT_DRAG_DRAGSTART_CANCEL","ALLOWED_EFFECTS","DROP_EFFECTS","supportsPassive","supportsPassiveEventListeners","opts","Object","defineProperty","get","window","addEventListener","e","supportsPassiveEventListener","isDOMElement","object","tagName","addDocumentListener","ev","handler","passive","document","removeDocumentListener","removeEventListener","onEvt","el","event","capture","options","off","average","array","length","reduce","s","v","isTouchIdentifierContainedInTouchEvent","touchEvent","touchIdentifier","i","changedTouches","identifier","updateCentroidCoordinatesOfTouchesIn","coordinateProp","outPoint","pageXs","pageYs","touches","touch","push","x","y","TRANSFORM_CSS_VENDOR_PREFIXES","translateElementToPoint","element","pnt","originalTransforms","offset","centerOnCoordinates","parseInt","offsetWidth","offsetHeight","translate","transformProp","style","DataTransfer","_dataStore","_setDragImageHandler","this","_dropEffect","prototype","value","mode","indexOf","freeze","types","effectAllowed","setData","type","data","Error","getData","clearData","format","index","splice","setDragImage","image","determineDropEffect","sourceNode","nodeType","dispatchDragEvent","dragEvent","targetElement","dataStore","dataTransfer","cancelable","relatedTarget","leaveEvt","dndEvent","Event","bubbles","screenX","screenY","clientX","clientY","pageX","pageY","targetRect","getBoundingClientRect","offsetX","left","offsetY","top","createDragEventFromTouch","defaultView","cancelled","dispatchEvent","determineDragOperation","dropEffect","activeDragOperation","DragOperationController","_initialEvent","_config","_sourceNode","_dragOperationEndedCb","_dragOperationState","_immediateUserSelection","_currentDropTarget","_lastTouchEvent","_initialTouch","_touchMoveHandler","_onTouchMove","bind","_touchEndOrCancelHandler","_onTouchEndOrCancel","_setup","_this","_currentDragOperation","_dragDataStore","undefined","_currentHotspotCoordinates","_dragImagePageCoordinates","dragImageSrc","_dataTransfer","_dragImageOffset","_cleanup","dragImage","dragImageSetup","_dragImageTransforms","map","prefix","transform","replace","position","zIndex","classList","add","_dragImage","dragImageOffset","dragImageCenterOnTouch","cs","getComputedStyle","marginLeft","marginTop","width","height","body","appendChild","_iterationIntervalId","setInterval","_iterationLock","_dragAndDropProcessModelIteration","iterationInterval","clearInterval","parentNode","removeChild","startDrag","dragStartConditionOverride","preventDefault","dragImageTranslateOverride","handledDragImageTranslate_1","previousDragOperation","dragCancelled","_dragOperationEnded","sourceEl","dragImageTransforms","transitionEndCb","visibility","display","csDragImage","durationInS","parseFloat","transitionDuration","isNaN","rect","scrollLeft","documentElement","scrollTop","delayInS","transitionDelay","durationInMs","Math","round","setTimeout","applyDragImageSnapback","_finishDragOperation","newUserSelection","elementFromPoint","previousTargetElement","remove","currentDragOperationClass","state","dragFailed","config","tryFindDraggableTarget","target","draggable","getAttribute","cloneNode","prepareNodeCopyAsDragImage","srcNode","dstNode","csName","setProperty","getPropertyValue","getPropertyPriority","pointerEvents","removeAttribute","nodeName","canvasSrc","canvasDst","canvasSrcImgData","getContext","getImageData","putImageData","hasChildNodes","childNodes","onTouchstart","dragTarget","dragOperationEnded","err","onDelayTouchstart","evt","onReleasedItem","end","cancel","move","scroll","CustomEvent","clearTimeout","timer","holdToDrag","defaultActionOverride","defaultPrevented","override","keys","forEach","key","forceApply","detectedFeatures","features","dragEvents","userAgentSupportingNativeDnD","isBlinkEngine","test","navigator","userAgent"],"mappings":"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","file":"index.min.js","sourcesContent":["// debug mode, which will highlight drop target, immediate user selection and events fired as you interact\n// only available in non-minified js / development environment\n// export const DEBUG = false;\n\n// css classes\nexport const CLASS_PREFIX = \"dnd-poly-\";\nexport const CLASS_DRAG_IMAGE = CLASS_PREFIX + \"drag-image\";\nexport const CLASS_DRAG_IMAGE_SNAPBACK = CLASS_PREFIX + \"snapback\";\nexport const CLASS_DRAG_OPERATION_ICON = CLASS_PREFIX + \"icon\";\n\n// custom event\nexport const EVENT_PREFIX = \"dnd-poly-\";\nexport const EVENT_DRAG_DRAGSTART_PENDING = EVENT_PREFIX + \"dragstart-pending\";\nexport const EVENT_DRAG_DRAGSTART_CANCEL = EVENT_PREFIX + \"dragstart-cancel\";\n\n// defines the array indexes to access string in ALLOWED_EFFECTS\nexport const enum EFFECT_ALLOWED {\n NONE = 0,\n COPY = 1,\n COPY_LINK = 2,\n COPY_MOVE = 3,\n LINK = 4,\n LINK_MOVE = 5,\n MOVE = 6,\n ALL = 7\n}\n\n// contains all possible values of the effectAllowed property\nexport const ALLOWED_EFFECTS = [ \"none\", \"copy\", \"copyLink\", \"copyMove\", \"link\", \"linkMove\", \"move\", \"all\" ];\n\n// defines the array indexes to access string in DROP_EFFECTS\nexport const enum DROP_EFFECT {\n NONE = 0,\n COPY = 1,\n MOVE = 2,\n LINK = 3,\n}\n\n// contains all possible values of the dropEffect property\nexport const DROP_EFFECTS = [ \"none\", \"copy\", \"move\", \"link\" ];\n","import { CLASS_DRAG_IMAGE_SNAPBACK } from \"./constants\";\nimport { supportsPassiveEventListener } from \"./feature-detection\";\n\n// evaluate once on startup\nconst supportsPassive = supportsPassiveEventListener();\n\nexport interface Point {\n x:number;\n y:number;\n}\n\nexport function isDOMElement( object:Element ) {\n return object && object.tagName;\n}\n\nexport function addDocumentListener( ev:string, handler:EventListener, passive:boolean = true ) {\n document.addEventListener( ev, handler, supportsPassive ? { passive: passive } : false );\n}\n\nexport function removeDocumentListener( ev:string, handler:EventListener ) {\n document.removeEventListener( ev, handler );\n}\n\nexport function onEvt(el:EventTarget, event:string, handler:EventListener, capture:boolean = false) {\n\n const options = supportsPassive ? {passive: true, capture: capture} : capture;\n\n el.addEventListener(event, handler, options);\n\n return {\n off() {\n el.removeEventListener(event, handler, options as any);\n }\n };\n}\n\nfunction prepareNodeCopyAsDragImage( srcNode:HTMLElement, dstNode:HTMLElement ) {\n\n // Is this node an element?\n if( srcNode.nodeType === 1 ) {\n\n // Clone the style\n const cs = getComputedStyle( srcNode );\n for( let i = 0; i < cs.length; i++ ) {\n const csName = cs[ i ];\n dstNode.style.setProperty( csName, cs.getPropertyValue( csName ), cs.getPropertyPriority( csName ) );\n }\n\n // no interaction with the drag image, pls! this is also important to make the drag image transparent for hit-testing\n // hit testing is done in the drag and drop iteration to find the element the user currently is hovering over while dragging.\n // if pointer-events is not none or a browser does behave in an unexpected way than the hit test transparency on the drag image\n // will break\n dstNode.style.pointerEvents = \"none\";\n\n // Remove any potential conflict attributes\n dstNode.removeAttribute( \"id\" );\n dstNode.removeAttribute( \"class\" );\n dstNode.removeAttribute( \"draggable\" );\n\n // canvas elements need special handling by copying canvas image data\n if( dstNode.nodeName === \"CANVAS\" ) {\n\n const canvasSrc = srcNode as HTMLCanvasElement;\n const canvasDst = dstNode as HTMLCanvasElement;\n\n const canvasSrcImgData = canvasSrc.getContext( \"2d\" ).getImageData( 0, 0, canvasSrc.width, canvasSrc.height );\n\n canvasDst.getContext( \"2d\" ).putImageData( canvasSrcImgData, 0, 0 );\n }\n }\n\n // Do the same for the children\n if( srcNode.hasChildNodes() ) {\n\n for( let i = 0; i < srcNode.childNodes.length; i++ ) {\n\n prepareNodeCopyAsDragImage( srcNode.childNodes[ i ], dstNode.childNodes[ i ] );\n }\n }\n}\n\nexport function createDragImage( sourceNode:HTMLElement ):HTMLElement {\n\n const dragImage = sourceNode.cloneNode( true );\n\n // this removes any id's and stuff that could interfere with drag and drop\n prepareNodeCopyAsDragImage( sourceNode, dragImage );\n\n return dragImage;\n}\n\nfunction average( array:Array ) {\n if( array.length === 0 ) {\n return 0;\n }\n return array.reduce( (function( s, v ) {\n return v + s;\n }), 0 ) / array.length;\n}\n\nexport function isTouchIdentifierContainedInTouchEvent( touchEvent:TouchEvent, touchIdentifier:number ) {\n for( let i = 0; i < touchEvent.changedTouches.length; i++ ) {\n const touch = touchEvent.changedTouches[ i ];\n if( touch.identifier === touchIdentifier ) {\n return true;\n }\n }\n return false;\n}\n\n/**\n * Calc center of polygon spanned by multiple touches in page (full page size, with hidden scrollable area) coordinates\n * or in viewport (screen coordinates) coordinates.\n */\nexport function updateCentroidCoordinatesOfTouchesIn( coordinateProp:\"page\" | \"client\", event:TouchEvent, outPoint:Point ):void {\n const pageXs:Array = [], pageYs:Array = [];\n for( let i = 0; i < event.touches.length; i++ ) {\n const touch = event.touches[ i ];\n pageXs.push( touch[ coordinateProp + \"X\" ] );\n pageYs.push( touch[ coordinateProp + \"Y\" ] );\n }\n outPoint.x = average( pageXs );\n outPoint.y = average( pageYs );\n}\n\n// cross-browser css transform property prefixes\nconst TRANSFORM_CSS_VENDOR_PREFIXES = [ \"\", \"-webkit-\" ];\n\nexport function extractTransformStyles( sourceNode:HTMLElement ):string[] {\n\n return TRANSFORM_CSS_VENDOR_PREFIXES.map( function( prefix:string ) {\n\n let transform = sourceNode.style[ prefix + \"transform\" ];\n\n if( !transform || transform === \"none\" ) {\n return \"\";\n }\n\n // removes translate(x,y)\n return transform.replace( /translate\\(\\D*\\d+[^,]*,\\D*\\d+[^,]*\\)\\s*/g, \"\" );\n } );\n}\n\nexport function translateElementToPoint( element:HTMLElement, pnt:Point, originalTransforms:string[], offset?:Point, centerOnCoordinates = true ):void {\n\n let x = pnt.x, y = pnt.y;\n\n if( offset ) {\n x += offset.x;\n y += offset.y;\n }\n\n if( centerOnCoordinates ) {\n x -= (parseInt( element.offsetWidth, 10 ) / 2);\n y -= (parseInt( element.offsetHeight, 10 ) / 2);\n }\n\n // using translate3d for max performance\n const translate = \"translate3d(\" + x + \"px,\" + y + \"px, 0)\";\n\n for( let i = 0; i < TRANSFORM_CSS_VENDOR_PREFIXES.length; i++ ) {\n const transformProp = TRANSFORM_CSS_VENDOR_PREFIXES[ i ] + \"transform\";\n element.style[ transformProp ] = translate + \" \" + originalTransforms[ i ];\n }\n}\n\n/**\n * calculates the coordinates of the drag source and transitions the drag image to those coordinates.\n * the drag operation is finished after the transition has ended.\n */\nexport function applyDragImageSnapback( sourceEl:HTMLElement, dragImage:HTMLElement, dragImageTransforms:string[], transitionEndCb:Function ):void {\n\n const cs = getComputedStyle( sourceEl );\n\n if( cs.visibility === \"hidden\" || cs.display === \"none\" ) {\n console.log( \"dnd-poly: source node is not visible. skipping snapback transition.\" );\n // shortcut to end the drag operation\n transitionEndCb();\n return;\n }\n // add class containing transition rules\n dragImage.classList.add( CLASS_DRAG_IMAGE_SNAPBACK );\n\n const csDragImage = getComputedStyle( dragImage );\n const durationInS = parseFloat( csDragImage.transitionDuration );\n if( isNaN( durationInS ) || durationInS === 0 ) {\n console.log( \"dnd-poly: no transition used - skipping snapback\" );\n transitionEndCb();\n return;\n }\n\n console.log( \"dnd-poly: starting dragimage snap back\" );\n\n // calc source node position\n const rect = sourceEl.getBoundingClientRect();\n\n const pnt:Point = {\n x: rect.left,\n y: rect.top\n };\n\n // add scroll offset of document\n pnt.x += (document.body.scrollLeft || document.documentElement.scrollLeft);\n pnt.y += (document.body.scrollTop || document.documentElement.scrollTop);\n\n //TODO this sometimes fails to calculate the correct origin position.. find out when exactly and how to detect\n pnt.x -= parseInt( cs.marginLeft, 10 );\n pnt.y -= parseInt( cs.marginTop, 10 );\n\n const delayInS = parseFloat( csDragImage.transitionDelay );\n const durationInMs = Math.round( (durationInS + delayInS) * 1000 );\n\n // apply the translate\n translateElementToPoint( dragImage, pnt, dragImageTransforms, undefined, false );\n\n setTimeout( transitionEndCb, durationInMs );\n}\n","export interface DetectedFeatures {\n draggable:boolean;\n dragEvents:boolean;\n userAgentSupportingNativeDnD:boolean;\n}\n\nexport function detectFeatures():DetectedFeatures {\n\n let features:DetectedFeatures = {\n dragEvents: (\"ondragstart\" in document.documentElement),\n draggable: (\"draggable\" in document.documentElement),\n userAgentSupportingNativeDnD: undefined\n };\n\n const isBlinkEngine = !!((window).chrome) || /chrome/i.test( navigator.userAgent );\n\n features.userAgentSupportingNativeDnD = !(\n // if is mobile safari or android browser -> no native dnd\n (/iPad|iPhone|iPod|Android/.test( navigator.userAgent ))\n || // OR\n //if is blink(chrome/opera) with touch events enabled -> no native dnd\n (isBlinkEngine && (\"ontouchstart\" in document.documentElement))\n );\n\n return features;\n}\n\nexport function supportsPassiveEventListener():boolean {\n\n let supportsPassiveEventListeners = false;\n\n // reference https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md\n try {\n let opts = Object.defineProperty( {}, \"passive\", {\n get: function() {\n supportsPassiveEventListeners = true;\n }\n } );\n window.addEventListener( \"test\", null, opts );\n }\n // tslint:disable-next-line:no-empty\n catch( e ) {\n }\n\n return supportsPassiveEventListeners;\n}\n","import { ALLOWED_EFFECTS, DROP_EFFECT, DROP_EFFECTS } from \"./constants\";\n\n/**\n * Polyfills https://html.spec.whatwg.org/multipage/interaction.html#drag-data-store-mode\n */\nexport const enum DragDataStoreMode {\n _DISCONNECTED, // adding an extra mode here because we need a special state to disconnect the data store from dataTransfer instance\n READONLY,\n READWRITE,\n PROTECTED\n}\n\n/**\n * Polyfills https://html.spec.whatwg.org/multipage/interaction.html#the-drag-data-store\n */\nexport interface DragDataStore {\n mode:DragDataStoreMode;\n data:{ [type:string]:any };\n types:Array;\n effectAllowed:string;\n}\n\n/**\n * Polyfills https://html.spec.whatwg.org/multipage/interaction.html#datatransfer\n */\nexport class DataTransfer {\n\n private _dropEffect:string = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n\n public get dropEffect() {\n return this._dropEffect;\n }\n\n //public get files():FileList {\n // return undefined;\n //}\n //\n //public get items():DataTransferItemList {\n // return undefined;\n //}\n\n public set dropEffect( value ) {\n if( this._dataStore.mode !== DragDataStoreMode._DISCONNECTED\n && ALLOWED_EFFECTS.indexOf( value ) > -1 ) {\n this._dropEffect = value;\n }\n }\n\n public get types():ReadonlyArray {\n if( this._dataStore.mode !== DragDataStoreMode._DISCONNECTED ) {\n return Object.freeze( this._dataStore.types );\n }\n }\n\n public get effectAllowed() {\n return this._dataStore.effectAllowed;\n }\n\n public set effectAllowed( value ) {\n if( this._dataStore.mode === DragDataStoreMode.READWRITE\n && ALLOWED_EFFECTS.indexOf( value ) > -1 ) {\n this._dataStore.effectAllowed = value;\n }\n }\n\n constructor( private _dataStore:DragDataStore,\n private _setDragImageHandler:( image:Element, x:number, y:number ) => void ) {\n }\n\n public setData( type:string, data:string ):void {\n if( this._dataStore.mode === DragDataStoreMode.READWRITE ) {\n\n if( type.indexOf( \" \" ) > -1 ) {\n throw new Error( \"illegal arg: type contains space\" );\n }\n\n this._dataStore.data[ type ] = data;\n\n if( this._dataStore.types.indexOf( type ) === -1 ) {\n this._dataStore.types.push( type );\n }\n }\n }\n\n public getData( type:string ):string {\n if( this._dataStore.mode === DragDataStoreMode.READONLY\n || this._dataStore.mode === DragDataStoreMode.READWRITE ) {\n return this._dataStore.data[ type ] || \"\";\n }\n }\n\n public clearData( format?:string ):void {\n if( this._dataStore.mode === DragDataStoreMode.READWRITE ) {\n // delete data for format\n if( format && this._dataStore.data[ format ] ) {\n delete this._dataStore.data[ format ];\n var index = this._dataStore.types.indexOf( format );\n if( index > -1 ) {\n this._dataStore.types.splice( index, 1 );\n }\n return;\n }\n // delete all data\n this._dataStore.data = {};\n this._dataStore.types = [];\n }\n }\n\n public setDragImage( image:Element, x:number, y:number ):void {\n if( this._dataStore.mode === DragDataStoreMode.READWRITE ) {\n this._setDragImageHandler( image, x, y );\n }\n }\n}\n","import { ALLOWED_EFFECTS, DROP_EFFECT, DROP_EFFECTS, EFFECT_ALLOWED } from \"./constants\";\nimport { DataTransfer, DragDataStore, DragDataStoreMode } from \"./drag-data-store\";\n\n/**\n * Search for a possible draggable item upon an event that can initialize a drag operation.\n * Can be overridden in polyfill config.\n */\nexport function tryFindDraggableTarget( event:TouchEvent ):HTMLElement | undefined {\n\n //1. Determine what is being dragged, as follows:\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // If the drag operation was invoked on a selection, then it is the selection that is being dragged.\n //if( (event.target).nodeType === 3 ) {\n //\n // config.log( \"drag on text\" );\n // return event.target;\n //}\n //Otherwise, if the drag operation was invoked on a Document, it is the first element, going up the ancestor chain, starting at the node that the\n // user tried to drag, that has the IDL attribute draggable set to true.\n //else {\n\n let el = event.target;\n\n do {\n if( el.draggable === false ) {\n continue;\n }\n if( el.draggable === true ) {\n return el;\n }\n if( el.getAttribute\n && el.getAttribute( \"draggable\" ) === \"true\" ) {\n return el;\n }\n } while( (el = el.parentNode) && el !== document.body );\n}\n\n/**\n * Implements \"6.\" in the processing steps defined for a dnd event\n * https://html.spec.whatwg.org/multipage/interaction.html#dragevent\n */\nexport function determineDropEffect( effectAllowed:string, sourceNode:Element ) {\n\n // uninitialized\n if( !effectAllowed ) {\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n //if( sourceNode.nodeType === 1 ) {\n //\n //return \"move\";\n //}\n\n // link\n if( sourceNode.nodeType === 3 && (sourceNode).tagName === \"A\" ) {\n return DROP_EFFECTS[ DROP_EFFECT.LINK ];\n }\n\n // copy\n return DROP_EFFECTS[ DROP_EFFECT.COPY ];\n }\n\n // none\n if( effectAllowed === ALLOWED_EFFECTS[ EFFECT_ALLOWED.NONE ] ) {\n return DROP_EFFECTS[ DROP_EFFECT.NONE ];\n }\n // copy or all\n if( effectAllowed.indexOf( ALLOWED_EFFECTS[ EFFECT_ALLOWED.COPY ] ) === 0 || effectAllowed === ALLOWED_EFFECTS[ EFFECT_ALLOWED.ALL ] ) {\n return DROP_EFFECTS[ DROP_EFFECT.COPY ];\n }\n // link\n if( effectAllowed.indexOf( ALLOWED_EFFECTS[ EFFECT_ALLOWED.LINK ] ) === 0 ) {\n return DROP_EFFECTS[ DROP_EFFECT.LINK ];\n }\n // move\n if( effectAllowed === ALLOWED_EFFECTS[ EFFECT_ALLOWED.MOVE ] ) {\n return DROP_EFFECTS[ DROP_EFFECT.MOVE ];\n }\n\n // copy\n return DROP_EFFECTS[ DROP_EFFECT.COPY ];\n}\n\nfunction createDragEventFromTouch( targetElement:Element,\n e:TouchEvent,\n type:string,\n cancelable:boolean,\n window:Window,\n dataTransfer:DataTransfer,\n relatedTarget:Element = null ) {\n\n const touch:Touch = e.changedTouches[ 0 ];\n\n const dndEvent:DragEvent = new Event( type, {\n bubbles: true,\n cancelable: cancelable\n } ) as DragEvent;\n\n // cast our polyfill\n (dndEvent as any).dataTransfer = dataTransfer as any;\n (dndEvent as any).relatedTarget = relatedTarget;\n\n // set the coordinates\n (dndEvent as any).screenX = touch.screenX;\n (dndEvent as any).screenY = touch.screenY;\n (dndEvent as any).clientX = touch.clientX;\n (dndEvent as any).clientY = touch.clientY;\n (dndEvent as any).pageX = touch.pageX;\n (dndEvent as any).pageY = touch.pageY;\n\n const targetRect = targetElement.getBoundingClientRect();\n (dndEvent as any).offsetX = dndEvent.clientX - targetRect.left;\n (dndEvent as any).offsetY = dndEvent.clientY - targetRect.top;\n\n return dndEvent;\n}\n\n/**\n * Reference https://html.spec.whatwg.org/multipage/interaction.html#dndevents\n */\nexport function dispatchDragEvent( dragEvent:string,\n targetElement:Element,\n touchEvent:TouchEvent,\n dataStore:DragDataStore,\n dataTransfer:DataTransfer,\n cancelable:boolean = true,\n relatedTarget:Element | null = null ):boolean {\n\n console.log( \"dnd-poly: dispatching \" + dragEvent );\n\n // if( DEBUG ) {\n // const debug_class = CLASS_PREFIX + \"debug\",\n // debug_class_event_target = CLASS_PREFIX + \"event-target\",\n // debug_class_event_related_target = CLASS_PREFIX + \"event-related-target\";\n // targetElement.classList.add( debug_class );\n // targetElement.classList.add( debug_class_event_target );\n // if( relatedTarget ) {\n // relatedTarget.classList.add( debug_class );\n // relatedTarget.classList.add( debug_class_event_related_target );\n // }\n // }\n\n const leaveEvt = createDragEventFromTouch( targetElement, touchEvent, dragEvent, cancelable, document.defaultView, dataTransfer, relatedTarget );\n const cancelled = !targetElement.dispatchEvent( leaveEvt );\n\n dataStore.mode = DragDataStoreMode._DISCONNECTED;\n\n // if( DEBUG ) {\n // const debug_class_event_target = CLASS_PREFIX + \"event-target\",\n // debug_class_event_related_target = CLASS_PREFIX + \"event-related-target\";\n // targetElement.classList.remove( debug_class_event_target );\n // if( relatedTarget ) {\n // relatedTarget.classList.remove( debug_class_event_related_target );\n // }\n // }\n\n return cancelled;\n}\n\n/**\n * according to https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model\n */\nexport function determineDragOperation( effectAllowed:string, dropEffect:string ):string {\n\n // unitialized or all\n if( !effectAllowed || effectAllowed === ALLOWED_EFFECTS[ 7 ] ) {\n return dropEffect;\n }\n\n if( dropEffect === DROP_EFFECTS[ DROP_EFFECT.COPY ] ) {\n if( effectAllowed.indexOf( DROP_EFFECTS[ DROP_EFFECT.COPY ] ) === 0 ) {\n return DROP_EFFECTS[ DROP_EFFECT.COPY ];\n }\n }\n else if( dropEffect === DROP_EFFECTS[ DROP_EFFECT.LINK ] ) {\n if( effectAllowed.indexOf( DROP_EFFECTS[ DROP_EFFECT.LINK ] ) === 0 || effectAllowed.indexOf( \"Link\" ) > -1 ) {\n return DROP_EFFECTS[ DROP_EFFECT.LINK ];\n }\n }\n else if( dropEffect === DROP_EFFECTS[ DROP_EFFECT.MOVE ] ) {\n if( effectAllowed.indexOf( DROP_EFFECTS[ DROP_EFFECT.MOVE ] ) === 0 || effectAllowed.indexOf( \"Move\" ) > -1 ) {\n return DROP_EFFECTS[ DROP_EFFECT.MOVE ];\n }\n }\n\n return DROP_EFFECTS[ DROP_EFFECT.NONE ];\n}\n","import { Config } from \"../index\";\nimport {\n CLASS_DRAG_IMAGE, CLASS_DRAG_OPERATION_ICON, CLASS_PREFIX, DROP_EFFECT, DROP_EFFECTS\n} from \"./constants\";\nimport {\n addDocumentListener, applyDragImageSnapback, extractTransformStyles, isDOMElement,\n isTouchIdentifierContainedInTouchEvent, Point, removeDocumentListener, translateElementToPoint,\n updateCentroidCoordinatesOfTouchesIn\n} from \"./dom-utils\";\nimport { DataTransfer, DragDataStore, DragDataStoreMode } from \"./drag-data-store\";\nimport { determineDragOperation, determineDropEffect, dispatchDragEvent } from \"./drag-utils\";\n\n/**\n * For tracking the different states of a drag operation.\n */\nexport const enum DragOperationState {\n // initial state of a controller, if no movement is detected the operation ends with this state\n POTENTIAL,\n // after movement is detected the drag operation starts and keeps this state until it ends\n STARTED,\n // when the drag operation ended normally\n ENDED,\n // when the drag operation ended with a cancelled input event\n CANCELLED\n}\n\n/**\n * Aims to implement the HTML5 d'n'd spec (https://html.spec.whatwg.org/multipage/interaction.html#dnd) as close as it can get.\n * Note that all props that are private should start with an underscore to enable better minification.\n *\n * TODO remove lengthy spec comments in favor of short references to the spec\n */\nexport class DragOperationController {\n\n private _dragOperationState:DragOperationState = DragOperationState.POTENTIAL;\n\n private _dragImage:HTMLElement;\n private _dragImageTransforms:string[];\n private _dragImagePageCoordinates:Point; // the current page coordinates of the dragImage\n private _dragImageOffset:Point; // offset of the drag image relative to the coordinates\n\n private _currentHotspotCoordinates:Point; // the point relative to viewport for determining the immediate user selection\n\n private _immediateUserSelection:HTMLElement = null; // the element the user currently hovers while dragging\n private _currentDropTarget:HTMLElement = null; // the element that was selected as a valid drop target by the d'n'd operation\n\n private _dragDataStore:DragDataStore;\n private _dataTransfer:DataTransfer;\n\n private _currentDragOperation:string; // the current drag operation set according to the d'n'd processing model\n\n private _initialTouch:Touch; // the identifier for the touch that initiated the drag operation\n private _touchMoveHandler:EventListener;\n private _touchEndOrCancelHandler:EventListener;\n private _lastTouchEvent:TouchEvent;\n\n private _iterationLock:boolean;\n private _iterationIntervalId:number;\n\n constructor( private _initialEvent:TouchEvent,\n private _config:Config,\n private _sourceNode:HTMLElement,\n private _dragOperationEndedCb:( config:Config, event:TouchEvent, state:DragOperationState ) => void ) {\n\n console.log( \"dnd-poly: setting up potential drag operation..\" );\n\n this._lastTouchEvent = _initialEvent;\n this._initialTouch = _initialEvent.changedTouches[ 0 ];\n\n // create bound event listeners\n this._touchMoveHandler = this._onTouchMove.bind( this );\n this._touchEndOrCancelHandler = this._onTouchEndOrCancel.bind( this );\n addDocumentListener( \"touchmove\", this._touchMoveHandler, false );\n addDocumentListener( \"touchend\", this._touchEndOrCancelHandler, false );\n addDocumentListener( \"touchcancel\", this._touchEndOrCancelHandler, false );\n\n // the only thing we do is setup the touch listeners. if drag will really start is decided in touch move handler.\n\n //\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // 3. Establish which DOM node is the source node, as follows:\n // If it is a selection that is being dragged, then the source node is the text node that the user started the drag on (typically the text node\n // that the user originally clicked). If the user did not specify a particular node, for example if the user just told the user agent to begin\n // a drag of \"the selection\", then the source node is the first text node containing a part of the selection. Otherwise, if it is an element\n // that is being dragged, then the source node is the element that is being dragged. Otherwise, the source node is part of another document or\n // application. When this specification requires that an event be dispatched at the source node in this case, the user agent must instead\n // follow the platform-specific conventions relevant to that situation.\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // 4. Determine the list of dragged nodes, as follows:\n\n // If it is a selection that is being dragged, then the list of dragged nodes contains, in tree order, every node that is partially or\n // completely included in the selection (including all their ancestors).\n\n // Otherwise, the list of dragged nodes contains only the source node, if any.\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // 5. If it is a selection that is being dragged, then add an item to the drag data store item list, with its properties set as follows:\n\n //The drag data item type string\n //\"text/plain\"\n //The drag data item kind\n //Plain Unicode string\n //The actual data\n //The text of the selection\n //Otherwise, if any files are being dragged, then add one item per file to the drag data store item list, with their properties set as follows:\n //\n //The drag data item type string\n //The MIME type of the file, if known, or \"application/octet-stream\" otherwise.\n // The drag data item kind\n //File\n //The actual data\n //The file's contents and name.\n //Dragging files can currently only happen from outside a browsing context, for example from a file system manager application.\n //\n // If the drag initiated outside of the application, the user agent must add items to the drag data store item list as appropriate for the data\n // being dragged, honoring platform conventions where appropriate; however, if the platform conventions do not use MIME types to label dragged\n // data, the user agent must make a best-effort attempt to map the types to MIME types, and, in any case, all the drag data item type strings must\n // be converted to ASCII lowercase. Perform drag-and-drop initialization steps defined in any other applicable specifications.\n\n //\n }\n\n //\n\n /**\n * Setup dragImage, input listeners and the drag\n * and drop process model iteration interval.\n */\n private _setup():boolean {\n console.log( \"dnd-poly: starting drag and drop operation\" );\n\n this._dragOperationState = DragOperationState.STARTED;\n\n this._currentDragOperation = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n\n this._dragDataStore = {\n data: {},\n effectAllowed: undefined,\n mode: DragDataStoreMode.PROTECTED,\n types: [],\n };\n\n this._currentHotspotCoordinates = {\n x: null,\n y: null\n };\n\n this._dragImagePageCoordinates = {\n x: null,\n y: null\n };\n\n let dragImageSrc:HTMLElement = this._sourceNode;\n\n this._dataTransfer = new DataTransfer( this._dragDataStore, ( element:HTMLElement, x:number, y:number ) => {\n\n dragImageSrc = element;\n\n if( typeof x === \"number\" || typeof y === \"number\" ) {\n this._dragImageOffset = {\n x: x || 0,\n y: y || 0\n };\n }\n } );\n\n // 9. Fire a DND event named dragstart at the source node.\n this._dragDataStore.mode = DragDataStoreMode.READWRITE;\n this._dataTransfer.dropEffect = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n if( dispatchDragEvent( \"dragstart\", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer ) ) {\n console.log( \"dnd-poly: dragstart cancelled\" );\n // dragstart has been prevented -> cancel d'n'd\n this._dragOperationState = DragOperationState.CANCELLED;\n this._cleanup();\n return false;\n }\n\n updateCentroidCoordinatesOfTouchesIn( \"page\", this._lastTouchEvent, this._dragImagePageCoordinates );\n const dragImage = this._config.dragImageSetup( dragImageSrc );\n this._dragImageTransforms = extractTransformStyles( dragImage );\n // set layout styles for freely moving it around\n dragImage.style.position = \"absolute\";\n dragImage.style.left = \"0px\";\n dragImage.style.top = \"0px\";\n // on top of all\n dragImage.style.zIndex = \"999999\";\n\n // add polyfill class for default styling\n dragImage.classList.add( CLASS_DRAG_IMAGE );\n dragImage.classList.add( CLASS_DRAG_OPERATION_ICON );\n this._dragImage = dragImage;\n\n if( !this._dragImageOffset ) {\n\n // apply specific offset\n if( this._config.dragImageOffset ) {\n\n this._dragImageOffset = {\n x: this._config.dragImageOffset.x,\n y: this._config.dragImageOffset.y\n };\n }\n // center drag image on touch coordinates\n else if( this._config.dragImageCenterOnTouch ) {\n\n const cs = getComputedStyle( dragImageSrc );\n this._dragImageOffset = {\n x: 0 - parseInt( cs.marginLeft, 10 ),\n y: 0 - parseInt( cs.marginTop, 10 )\n };\n }\n // by default initialize drag image offset the same as desktop\n else {\n\n const targetRect = dragImageSrc.getBoundingClientRect();\n const cs = getComputedStyle( dragImageSrc );\n this._dragImageOffset = {\n x: targetRect.left - this._initialTouch.clientX - parseInt( cs.marginLeft, 10 ) + targetRect.width / 2,\n y: targetRect.top - this._initialTouch.clientY - parseInt( cs.marginTop, 10 ) + targetRect.height / 2\n };\n }\n }\n\n translateElementToPoint( this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch );\n document.body.appendChild( this._dragImage );\n\n // 10. Initiate the drag-and-drop operation in a manner consistent with platform conventions, and as described below.\n this._iterationIntervalId = window.setInterval( () => {\n\n // If the user agent is still performing the previous iteration of the sequence (if any) when the next iteration becomes due,\n // abort these steps for this iteration (effectively \"skipping missed frames\" of the drag-and-drop operation).\n if( this._iterationLock ) {\n console.log( \"dnd-poly: iteration skipped because previous iteration hast not yet finished.\" );\n return;\n }\n this._iterationLock = true;\n\n this._dragAndDropProcessModelIteration();\n\n this._iterationLock = false;\n }, this._config.iterationInterval );\n\n return true;\n }\n\n private _cleanup() {\n\n console.log( \"dnd-poly: cleanup\" );\n\n if( this._iterationIntervalId ) {\n clearInterval( this._iterationIntervalId );\n this._iterationIntervalId = null;\n }\n\n removeDocumentListener( \"touchmove\", this._touchMoveHandler );\n removeDocumentListener( \"touchend\", this._touchEndOrCancelHandler );\n removeDocumentListener( \"touchcancel\", this._touchEndOrCancelHandler );\n\n if( this._dragImage ) {\n this._dragImage.parentNode.removeChild( this._dragImage );\n this._dragImage = null;\n }\n\n this._dragOperationEndedCb( this._config, this._lastTouchEvent, this._dragOperationState );\n }\n\n //\n\n //\n\n private _onTouchMove( event:TouchEvent ) {\n\n // filter unrelated touches\n if( isTouchIdentifierContainedInTouchEvent( event, this._initialTouch.identifier ) === false ) {\n return;\n }\n\n // update the reference to the last received touch event\n this._lastTouchEvent = event;\n\n // drag operation did not start yet but on movement it should start\n if( this._dragOperationState === DragOperationState.POTENTIAL ) {\n\n let startDrag:boolean;\n\n // is a lifecycle hook present?\n if( this._config.dragStartConditionOverride ) {\n\n try {\n startDrag = this._config.dragStartConditionOverride( event );\n }\n catch( e ) {\n console.error( \"dnd-poly: error in dragStartConditionOverride hook: \" + e );\n startDrag = false;\n }\n }\n else {\n\n // by default only allow a single moving finger to initiate a drag operation\n startDrag = (event.touches.length === 1);\n }\n\n if( !startDrag ) {\n\n this._cleanup();\n return;\n }\n\n // setup will return true when drag operation starts\n if( this._setup() === true ) {\n\n // prevent scrolling when drag operation starts\n this._initialEvent.preventDefault();\n event.preventDefault();\n }\n\n return;\n }\n\n console.log( \"dnd-poly: moving draggable..\" );\n\n // we emulate d'n'd so we dont want any defaults to apply\n event.preventDefault();\n\n // populate shared coordinates from touch event\n updateCentroidCoordinatesOfTouchesIn( \"client\", event, this._currentHotspotCoordinates );\n updateCentroidCoordinatesOfTouchesIn( \"page\", event, this._dragImagePageCoordinates );\n\n if( this._config.dragImageTranslateOverride ) {\n\n try {\n\n let handledDragImageTranslate = false;\n\n this._config.dragImageTranslateOverride(\n event,\n {\n x: this._currentHotspotCoordinates.x,\n y: this._currentHotspotCoordinates.y\n },\n this._immediateUserSelection,\n ( offsetX:number, offsetY:number ) => {\n\n // preventing translation of drag image when there was a drag operation cleanup meanwhile\n if( !this._dragImage ) {\n return;\n }\n\n handledDragImageTranslate = true;\n\n this._currentHotspotCoordinates.x += offsetX;\n this._currentHotspotCoordinates.y += offsetY;\n this._dragImagePageCoordinates.x += offsetX;\n this._dragImagePageCoordinates.y += offsetY;\n\n translateElementToPoint(\n this._dragImage,\n this._dragImagePageCoordinates,\n this._dragImageTransforms,\n this._dragImageOffset,\n this._config.dragImageCenterOnTouch\n );\n }\n );\n\n if( handledDragImageTranslate ) {\n return;\n }\n }\n catch( e ) {\n console.log( \"dnd-poly: error in dragImageTranslateOverride hook: \" + e );\n }\n }\n\n translateElementToPoint( this._dragImage, this._dragImagePageCoordinates, this._dragImageTransforms, this._dragImageOffset, this._config.dragImageCenterOnTouch );\n }\n\n private _onTouchEndOrCancel( event:TouchEvent ) {\n\n // filter unrelated touches\n if( isTouchIdentifierContainedInTouchEvent( event, this._initialTouch.identifier ) === false ) {\n return;\n }\n\n // let the dragImageTranslateOverride know that its over\n if( this._config.dragImageTranslateOverride ) {\n try {\n /* tslint:disable */\n this._config.dragImageTranslateOverride( undefined, undefined, undefined, function() {\n } );\n }\n catch( e ) {\n console.log( \"dnd-poly: error in dragImageTranslateOverride hook: \" + e );\n }\n }\n\n // drag operation did not even start\n if( this._dragOperationState === DragOperationState.POTENTIAL ) {\n this._cleanup();\n return;\n }\n\n // we emulate d'n'd so we dont want any defaults to apply\n event.preventDefault();\n\n this._dragOperationState = (event.type === \"touchcancel\") ? DragOperationState.CANCELLED : DragOperationState.ENDED;\n }\n\n //\n\n //\n\n /**\n * according to https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model\n */\n private _dragAndDropProcessModelIteration():void {\n\n // if( DEBUG ) {\n // var debug_class = CLASS_PREFIX + \"debug\",\n // debug_class_user_selection = CLASS_PREFIX + \"immediate-user-selection\",\n // debug_class_drop_target = CLASS_PREFIX + \"current-drop-target\";\n // }\n\n const previousDragOperation = this._currentDragOperation;\n\n // Fire a DND event named drag event at the source node.\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n const dragCancelled = dispatchDragEvent( \"drag\", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer );\n if( dragCancelled ) {\n console.log( \"dnd-poly: drag event cancelled.\" );\n // If this event is canceled, the user agent must set the current drag operation to \"none\" (no drag operation).\n this._currentDragOperation = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n }\n\n // Otherwise, if the user ended the drag-and-drop operation (e.g. by releasing the mouse button in a mouse-driven drag-and-drop interface),\n // or if the drag event was canceled, then this will be the last iteration.\n if( dragCancelled || this._dragOperationState === DragOperationState.ENDED || this._dragOperationState === DragOperationState.CANCELLED ) {\n\n const dragFailed = this._dragOperationEnded( this._dragOperationState );\n\n // if drag failed transition snap back\n if( dragFailed ) {\n\n applyDragImageSnapback( this._sourceNode, this._dragImage, this._dragImageTransforms, () => {\n this._finishDragOperation();\n } );\n return;\n }\n\n // Otherwise immediately\n // Fire a DND event named dragend at the source node.\n this._finishDragOperation();\n return;\n }\n\n // If the drag event was not canceled and the user has not ended the drag-and-drop operation,\n // check the state of the drag-and-drop operation, as follows:\n const newUserSelection:HTMLElement = this._config.elementFromPoint( this._currentHotspotCoordinates.x, this._currentHotspotCoordinates.y );\n\n console.log( \"dnd-poly: new immediate user selection is: \" + newUserSelection );\n\n const previousTargetElement = this._currentDropTarget;\n\n // If the user is indicating a different immediate user selection than during the last iteration (or if this is the first iteration),\n // and if this immediate user selection is not the same as the current target element,\n // then fire a DND event named dragexit at the current target element,\n // and then update the current target element as follows:\n if( newUserSelection !== this._immediateUserSelection && newUserSelection !== this._currentDropTarget ) {\n\n // if( DEBUG ) {\n //\n // if( this._immediateUserSelection ) {\n // this._immediateUserSelection.classList.remove( debug_class_user_selection );\n // }\n //\n // if( newUserSelection ) {\n // newUserSelection.classList.add( debug_class );\n // newUserSelection.classList.add( debug_class_user_selection );\n // }\n // }\n\n this._immediateUserSelection = newUserSelection;\n\n if( this._currentDropTarget !== null ) {\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n dispatchDragEvent( \"dragexit\", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false );\n }\n\n // If the new immediate user selection is null\n if( this._immediateUserSelection === null ) {\n //Set the current target element to null also.\n this._currentDropTarget = this._immediateUserSelection;\n\n console.log( \"dnd-poly: current drop target changed to null\" );\n }\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // If the new immediate user selection is in a non-DOM document or application\n // else if() {\n // Set the current target element to the immediate user selection.\n // this.currentDropTarget = this.immediateUserSelection;\n // return;\n // }\n // Otherwise\n else {\n // Fire a DND event named dragenter at the immediate user selection.\n //the polyfill cannot determine if a handler even exists as browsers do to silently\n // allow drop when no listener existed, so this event MUST be handled by the client\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = determineDropEffect( this._dragDataStore.effectAllowed, this._sourceNode );\n if( dispatchDragEvent( \"dragenter\", this._immediateUserSelection, this._lastTouchEvent, this._dragDataStore, this._dataTransfer ) ) {\n console.log( \"dnd-poly: dragenter default prevented\" );\n // If the event is canceled, then set the current target element to the immediate user selection.\n this._currentDropTarget = this._immediateUserSelection;\n this._currentDragOperation = determineDragOperation( this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect );\n }\n // Otherwise, run the appropriate step from the following list:\n else {\n\n // NO DROPZONE SUPPORT SINCE NATIVE IMPLEMENTATIONS IN BROWSERS ALSO DO NOT\n //console.log( \"dnd-poly: dragenter not prevented, searching for dropzone..\" );\n //var newTarget = DragOperationController.FindDropzoneElement( this.immediateUserSelection );\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state) or an\n // editable element, and the drag data store item list has an item with the drag data item type string \"text/plain\" and the drag data\n // item kind Plain Unicode string\n //if( ElementIsTextDropzone( this.immediateUserSelection, this.dragDataStore ) ) {\n //Set the current target element to the immediate user selection anyway.\n //this.currentDropTarget = this.immediateUserSelection;\n //}\n //else\n // If the current target element is an element with a dropzone attribute that matches the drag data store\n //if( newTarget === this.immediateUserSelection &&\n // DragOperationController.GetOperationForMatchingDropzone( this.immediateUserSelection, this.dragDataStore ) !== \"none\" ) {\n // Set the current target element to the immediate user selection anyway.\n // this.currentDropTarget = this.immediateUserSelection;\n //}\n // If the immediate user selection is an element that itself has an ancestor element\n // with a dropzone attribute that matches the drag data store\n // NO DROPZONE SUPPORT SINCE NATIVE IMPLEMENTATIONS IN BROWSERS ALSO DO NOT\n //else if( newTarget !== null && DragOperationController.GetOperationForMatchingDropzone( newTarget, this.dragDataStore ) ) {\n\n // If the immediate user selection is new target, then leave the current target element unchanged.\n\n // Otherwise, fire a DND event named dragenter at new target, with the current target element\n // as the specific related target. Then, set the current target element to new target,\n // regardless of whether that event was canceled or not.\n //this.dragenter( newTarget, this.currentDropTarget );\n //this.currentDropTarget = newTarget;\n //}\n // If the current target element is not the body element\n //else\n if( this._immediateUserSelection !== document.body ) {\n // Fire a DND event named dragenter at the body element, and set the current target element to the body element, regardless of\n // whether that event was canceled or not.\n // Note: If the body element is null, then the event will be fired at the Document object (as\n // required by the definition of the body element), but the current target element would be set to null, not the Document object.\n\n // We do not listen to what the spec says here because this results in doubled events on the body/document because if the first one\n // was not cancelled it will have bubbled up to the body already ;)\n // this.dragenter( window.document.body );\n this._currentDropTarget = document.body;\n }\n // Otherwise\n //else {\n // leave the current drop target unchanged\n //}\n }\n }\n }\n\n // If the previous step caused the current target element to change,\n // and if the previous target element was not null or a part of a non-DOM document,\n // then fire a DND event named dragleave at the previous target element.\n if( previousTargetElement !== this._currentDropTarget && (isDOMElement( previousTargetElement )) ) {\n\n // if( DEBUG ) {\n // previousTargetElement.classList.remove( debug_class_drop_target );\n // }\n\n console.log( \"dnd-poly: current drop target changed.\" );\n\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n dispatchDragEvent( \"dragleave\", previousTargetElement, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false, this._currentDropTarget );\n }\n\n // If the current target element is a DOM element, then fire a DND event named dragover at this current target element.\n if( isDOMElement( this._currentDropTarget ) ) {\n\n // if( DEBUG ) {\n // this._currentDropTarget.classList.add( debug_class );\n // this._currentDropTarget.classList.add( debug_class_drop_target );\n // }\n\n // If the dragover event is not canceled, run the appropriate step from the following list:\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = determineDropEffect( this._dragDataStore.effectAllowed, this._sourceNode );\n if( dispatchDragEvent( \"dragover\", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer ) === false ) {\n\n console.log( \"dnd-poly: dragover not prevented on possible drop-target.\" );\n // NO DROPZONE SUPPORT SINCE NATIVE IMPLEMENTATIONS IN BROWSERS ALSO DO NOT\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state) or\n // an editable element, and the drag data store item list has an item with the drag data item type string \"text/plain\" and the drag\n // data item kind Plain Unicode string\n //if( ElementIsTextDropzone( this.currentDropTarget, this.dragDataStore ) ) {\n // Set the current drag operation to either \"copy\" or \"move\", as appropriate given the platform conventions.\n //this.currentDragOperation = \"copy\"; //or move. spec says its platform specific behaviour.\n //}\n //else {\n // If the current target element is an element with a dropzone attribute that matches the drag data store\n //this.currentDragOperation = DragOperationController.GetOperationForMatchingDropzone( this.currentDropTarget, this.dragDataStore );\n //}\n // when dragover is not prevented and no dropzones are there, no drag operation\n this._currentDragOperation = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n }\n // Otherwise (if the dragover event is canceled), set the current drag operation based on the values of the effectAllowed and\n // dropEffect attributes of the DragEvent object's dataTransfer object as they stood after the event dispatch finished\n else {\n\n console.log( \"dnd-poly: dragover prevented.\" );\n\n this._currentDragOperation = determineDragOperation( this._dataTransfer.effectAllowed, this._dataTransfer.dropEffect );\n }\n }\n\n console.log( \"dnd-poly: d'n'd iteration ended. current drag operation: \" + this._currentDragOperation );\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // Otherwise, if the current target element is not a DOM element, use platform-specific mechanisms to determine what drag operation is\n // being performed (none, copy, link, or move), and set the current drag operation accordingly.\n\n //Update the drag feedback (e.g. the mouse cursor) to match the current drag operation, as follows:\n // ---------------------------------------------------------------------------------------------------------\n // Drag operation |\tFeedback\n // \"copy\"\t | Data will be copied if dropped here.\n // \"link\"\t | Data will be linked if dropped here.\n // \"move\"\t | Data will be moved if dropped here.\n // \"none\"\t | No operation allowed, dropping here will cancel the drag-and-drop operation.\n // ---------------------------------------------------------------------------------------------------------\n\n if( previousDragOperation !== this._currentDragOperation ) {\n this._dragImage.classList.remove( CLASS_PREFIX + previousDragOperation );\n }\n\n const currentDragOperationClass = CLASS_PREFIX + this._currentDragOperation;\n\n this._dragImage.classList.add( currentDragOperationClass );\n }\n\n /**\n * according to https://html.spec.whatwg.org/multipage/interaction.html#drag-and-drop-processing-model\n */\n private _dragOperationEnded( state:DragOperationState ):boolean {\n\n console.log( \"dnd-poly: drag operation end detected with \" + this._currentDragOperation );\n\n // if( DEBUG ) {\n //\n // var debug_class_user_selection = CLASS_PREFIX + \"immediate-user-selection\",\n // debug_class_drop_target = CLASS_PREFIX + \"current-drop-target\";\n //\n // if( this._currentDropTarget ) {\n // this._currentDropTarget.classList.remove( debug_class_drop_target );\n //\n // }\n // if( this._immediateUserSelection ) {\n // this._immediateUserSelection.classList.remove( debug_class_user_selection );\n // }\n // }\n\n //var dropped:boolean = undefined;\n\n // Run the following steps, then stop the drag-and-drop operation:\n\n // If the current drag operation is \"none\" (no drag operation), or,\n // if the user ended the drag-and-drop operation by canceling it (e.g. by hitting the Escape key), or\n // if the current target element is null, then the drag operation failed.\n const dragFailed = (this._currentDragOperation === DROP_EFFECTS[ DROP_EFFECT.NONE ]\n || this._currentDropTarget === null\n || state === DragOperationState.CANCELLED);\n if( dragFailed ) {\n\n // Run these substeps:\n\n // Let dropped be false.\n //dropped = false;\n\n // If the current target element is a DOM element, fire a DND event named dragleave at it;\n if( isDOMElement( this._currentDropTarget ) ) {\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n dispatchDragEvent( \"dragleave\", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false );\n }\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // otherwise, if it is not null, use platform-specific conventions for drag cancellation.\n //else if( this.currentDropTarget !== null ) {\n //}\n }\n // Otherwise, the drag operation was as success; run these substeps:\n else {\n\n // Let dropped be true.\n //dropped = true;\n\n // If the current target element is a DOM element, fire a DND event named drop at it;\n if( isDOMElement( this._currentDropTarget ) ) {\n\n // If the event is canceled, set the current drag operation to the value of the dropEffect attribute of the\n // DragEvent object's dataTransfer object as it stood after the event dispatch finished.\n\n this._dragDataStore.mode = DragDataStoreMode.READONLY;\n this._dataTransfer.dropEffect = this._currentDragOperation;\n if( dispatchDragEvent( \"drop\", this._currentDropTarget, this._lastTouchEvent, this._dragDataStore, this._dataTransfer ) ===\n true ) {\n\n this._currentDragOperation = this._dataTransfer.dropEffect;\n }\n // Otherwise, the event is not canceled; perform the event's default action, which depends on the exact target as follows:\n else {\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // If the current target element is a text field (e.g. textarea, or an input element whose type attribute is in the Text state)\n // or an editable element,\n // and the drag data store item list has an item with the drag data item type string \"text/plain\"\n // and the drag data item kind Plain Unicode string\n //if( ElementIsTextDropzone( this.currentDropTarget, this.dragDataStore ) ) {\n // Insert the actual data of the first item in the drag data store item list to have a drag data item type string of\n // \"text/plain\" and a drag data item kind that is Plain Unicode string into the text field or editable element in a manner\n // consistent with platform-specific conventions (e.g. inserting it at the current mouse cursor position, or inserting it at\n // the end of the field).\n //}\n // Otherwise\n //else {\n // Reset the current drag operation to \"none\".\n this._currentDragOperation = DROP_EFFECTS[ DROP_EFFECT.NONE ];\n //}\n }\n }\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n // otherwise, use platform-specific conventions for indicating a drop.\n //else {\n //}\n }\n\n return dragFailed;\n\n // THIS IS SKIPPED SINCE SUPPORT IS ONLY AVAILABLE FOR DOM ELEMENTS\n //if( this.dragend( this.sourceNode ) ) {\n // return;\n //}\n\n // Run the appropriate steps from the following list as the default action of the dragend event:\n\n //if( !dropped ) {\n // return;\n //}\n // dropped is true\n\n //if( this.currentDragOperation !== \"move\" ) {\n // return;\n //}\n //// drag operation is move\n //\n //if( ElementIsTextDropzone( this.currentDropTarget ) === false ) {\n // return;\n //}\n //// element is textfield\n //\n //// and the source of the drag-and-drop operation is a selection in the DOM\n //if( this.sourceNode.nodeType === 1 ) {\n // // The user agent should delete the range representing the dragged selection from the DOM.\n //}\n //// and the source of the drag-and-drop operation is a selection in a text field\n //else if( this.sourceNode.nodeType === 3 ) {\n // // The user agent should delete the dragged selection from the relevant text field.\n //}\n //// Otherwise, The event has no default action.\n }\n\n // dispatch dragend event and cleanup drag operation\n private _finishDragOperation():void {\n console.log( \"dnd-poly: dragimage snap back transition ended\" );\n\n // Fire a DND event named dragend at the source node.\n this._dragDataStore.mode = DragDataStoreMode.PROTECTED;\n this._dataTransfer.dropEffect = this._currentDragOperation;\n dispatchDragEvent( \"dragend\", this._sourceNode, this._lastTouchEvent, this._dragDataStore, this._dataTransfer, false );\n\n // drag operation over and out\n this._dragOperationState = DragOperationState.ENDED;\n this._cleanup();\n }\n\n //\n}\n","import { addDocumentListener, createDragImage, onEvt, Point } from \"./internal/dom-utils\";\nimport { DragOperationController, DragOperationState } from \"./internal/drag-operation-controller\";\nimport { tryFindDraggableTarget } from \"./internal/drag-utils\";\nimport { detectFeatures } from \"./internal/feature-detection\";\nimport { EVENT_DRAG_DRAGSTART_PENDING, EVENT_DRAG_DRAGSTART_CANCEL } from \"./internal/constants\";\n\n// default config\nconst config:Config = {\n iterationInterval: 150,\n tryFindDraggableTarget: tryFindDraggableTarget,\n dragImageSetup: createDragImage,\n elementFromPoint: function( x, y ) { return document.elementFromPoint( x, y ); }\n};\n\n// reference to the currently active drag operation\nlet activeDragOperation:DragOperationController;\n\n/**\n * event handler for initial touch events that possibly start a drag and drop operation.\n */\nfunction onTouchstart( e:TouchEvent ) {\n\n console.log( \"dnd-poly: global touchstart\" );\n\n // From the moment that the user agent is to initiate the drag-and-drop operation,\n // until the end of the drag-and-drop operation, device input events (e.g. mouse and keyboard events) must be suppressed.\n\n // only allow one drag operation at a time\n if( activeDragOperation ) {\n console.log( \"dnd-poly: drag operation already active\" );\n return;\n }\n\n let dragTarget = config.tryFindDraggableTarget( e );\n\n // If there is no such element, then nothing is being dragged; abort these\n // steps, the drag-and-drop operation is never started.\n if( !dragTarget ) {\n console.log(\"dnd-poly: no draggable at touchstart coordinates\");\n return;\n }\n\n try {\n activeDragOperation = new DragOperationController( e, config, dragTarget as HTMLElement, dragOperationEnded );\n }\n catch( err ) {\n dragOperationEnded( config, e, DragOperationState.CANCELLED );\n // rethrow exception after cleanup\n throw err;\n }\n}\n\nfunction onDelayTouchstart( evt:TouchEvent ) {\n\n console.log(\"dnd-poly: setup delayed dragstart..\");\n\n const el = evt.target;\n\n const heldItem = () => {\n\n console.log(\"dnd-poly: starting delayed drag..\");\n\n end.off();\n cancel.off();\n move.off();\n scroll.off();\n onTouchstart( evt );\n };\n\n const onReleasedItem = (event:Event) => {\n\n console.log(\"dnd-poly: aborting delayed drag because of \" + event.type);\n\n end.off();\n cancel.off();\n move.off();\n scroll.off();\n\n if (el) {\n el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_CANCEL, { bubbles: true, cancelable: true }));\n }\n\n clearTimeout( timer );\n };\n\n if (el) {\n el.dispatchEvent(new CustomEvent(EVENT_DRAG_DRAGSTART_PENDING, { bubbles: true, cancelable: true }));\n }\n\n const timer = window.setTimeout( heldItem, config.holdToDrag );\n\n const end = onEvt( el, \"touchend\", onReleasedItem );\n const cancel = onEvt( el, \"touchcancel\", onReleasedItem );\n const move = onEvt( el, \"touchmove\", onReleasedItem );\n // scroll events don't bubble, only way to listen to scroll events\n // that are about to happen in nested scrollables is by listening in capture phase\n const scroll = onEvt( window, \"scroll\", onReleasedItem, true );\n}\n\n/**\n * Implements callback invoked when a drag operation has ended or crashed.\n */\nfunction dragOperationEnded( _config:Config, event:TouchEvent, state:DragOperationState ) {\n\n // we need to make the default action happen only when no drag operation took place\n if( state === DragOperationState.POTENTIAL ) {\n\n console.log( \"dnd-poly: Drag never started. Last event was \" + event.type );\n\n // when lifecycle hook is present\n if( _config.defaultActionOverride ) {\n\n try {\n\n _config.defaultActionOverride( event );\n\n if( event.defaultPrevented ) {\n\n console.log( \"dnd-poly: defaultActionOverride has taken care of triggering the default action. preventing default on original event\" );\n }\n\n }\n catch( e ) {\n\n console.log( \"dnd-poly: error in defaultActionOverride: \" + e );\n }\n }\n }\n\n // reset drag operation container\n activeDragOperation = null;\n}\n\n//\n\nexport { Point } from \"./internal/dom-utils\";\n\n// function signature for the dragImageTranslateOverride hook\nexport type DragImageTranslateOverrideFn = ( // corresponding touchmove event\n event:TouchEvent,\n // the processed touch event viewport coordinates\n hoverCoordinates:Point,\n // the element under the calculated touch coordinates\n hoveredElement:HTMLElement,\n // callback for updating the drag image offset\n translateDragImageFn:( offsetX:number, offsetY:number ) => void ) => void;\n\nexport interface Config {\n\n // flag to force the polyfill being applied and not rely on internal feature detection\n forceApply?:boolean;\n\n // useful for when you want the default drag image but still want to apply\n // some static offset from touch coordinates to drag image coordinates\n // defaults to (0,0)\n dragImageOffset?:Point;\n\n // if the dragImage shall be centered on the touch coordinates\n // defaults to false\n dragImageCenterOnTouch?:boolean;\n\n // the drag and drop operation involves some processing. here you can specify in what interval this processing takes place.\n // defaults to 150ms\n iterationInterval?:number;\n\n // hook for custom logic that decides if a drag operation should start\n dragStartConditionOverride?:( event:TouchEvent ) => boolean;\n\n // hook for custom logic that can manipulate the drag image translate offset\n dragImageTranslateOverride?:DragImageTranslateOverrideFn;\n\n // hook for custom logic that can override the default action based on the original touch event when the drag never started\n // be sure to call event.preventDefault() if handling the default action in the override to prevent the browser default.\n defaultActionOverride?:( event:TouchEvent ) => void;\n\n // Drag action delay on touch devices (\"hold to drag\" functionality, useful for scrolling draggable items). Defaults to no delay.\n holdToDrag?:number;\n\n // function invoked for each touchstart event to determine if and which touched element is detected as \"draggable\"\n tryFindDraggableTarget?:( event:TouchEvent ) => HTMLElement | undefined;\n\n // function for creating a copy of the dragged element\n dragImageSetup?:( element:HTMLElement ) => HTMLElement;\n\n // function for determining element that is currently hovered while dragging\n // defaults to `document.elementFromPoint()`\n elementFromPoint?:( x:number, y:number ) => Element;\n}\n\nexport function polyfill( override?:Config ):boolean {\n\n if( override ) {\n // overwrite default config with user config\n Object.keys( override ).forEach( function( key ) {\n config[ key ] = override[ key ];\n } );\n }\n\n // only do feature detection when config does not force apply the polyfill\n if( !config.forceApply ) {\n\n // feature/browser detection\n const detectedFeatures = detectFeatures();\n\n // if( DEBUG ) {\n // Object.keys( detectedFeatures ).forEach( function( key ) {\n // console.log( \"dnd-poly: detected feature '\" + key + \" = \" + detectedFeatures[ key ] + \"'\" );\n // } );\n // }\n\n // check if native drag and drop support is there\n if( detectedFeatures.userAgentSupportingNativeDnD\n && detectedFeatures.draggable\n && detectedFeatures.dragEvents ) {\n // no polyfilling required\n return false;\n }\n }\n\n console.log( \"dnd-poly: Applying mobile drag and drop polyfill.\" );\n\n // add listeners suitable for detecting a potential drag operation\n if( config.holdToDrag ) {\n console.log(\"dnd-poly: holdToDrag set to \" + config.holdToDrag);\n addDocumentListener( \"touchstart\", onDelayTouchstart, false );\n } else {\n addDocumentListener( \"touchstart\", onTouchstart, false );\n }\n\n return true;\n}\n\n//\n"]}