import { cssClass } from '../styles' ; internal export function hasDnDType ( e , ... typesToCheck ) { const available = e . dataTransfer ! . types ; if ( typeof available . indexOf === 'function' ) { return typesToCheck . some ( ( type ) => available . indexOf ( type ) >= 0 ) ; } if ( typeof available . includes === 'function' ) { return typesToCheck . some ( ( type ) => available . includes ( type ) ) ; } if ( typeof available . contains === 'function' ) { return typesToCheck . some ( ( type ) => available . contains ( type ) ) ; } return false ; } type { Map < number , { [ p : string ] : string } > } const dndTransferStorage = new Map < number , { [ key ] : string ; } > ( ) ; function isEdgeDnD ( e ) { return dndTransferStorage . size > 0 && hasDnDType ( e , 'text/plain' ) ; } param e returns { boolean | RegExpMatchArray } internal export function copyDnD ( e ) { const dT = e . dataTransfer ! ; return Boolean ( ( e . ctrlKey && dT . effectAllowed . match ( /copy/gi ) ) || ! dT . effectAllowed . match ( /move/gi ) ) ; } param e internal export function updateDropEffect ( e ) { const dT = e . dataTransfer ! ; if ( copyDnD ( e ) ) { dT . dropEffect = 'copy' ; } else { dT . dropEffect = 'move' ; } } internal export type IDragEffect = 'none' | 'copy' | 'copyLink' | 'copyMove' | 'link' | 'linkMove' | 'move' | 'all' ; internal export interface IDragStartResult { effectAllowed : IDragEffect ; data : { [ mimeType ] : string ; } ; } internal export interface IDropResult { effect : IDragEffect ; data : { [ mimeType ] : string ; } ; } let idCounter = 0 ; param { HTMLElement } node param { ( ) => IDragStartResult } onDragStart param { boolean } stopPropagation internal export function dragAble ( node , onDragStart , stopPropagation = false ) { const id = ++ idCounter ; node . classList . add ( cssClass ( 'dragable' ) ) ; node . draggable = true ; node . addEventListener ( 'dragstart' , ( e ) => { node . classList . add ( cssClass ( 'dragging' ) ) ; const payload = onDragStart ( ) ; e . dataTransfer ! . effectAllowed = payload . effectAllowed ; if ( stopPropagation ) { e . stopPropagation ( ) ; } const keys = Object . keys ( payload . data ) ; const allSucceeded = keys . every ( ( k ) => { try { e . dataTransfer ! . setData ( k , payload . data [ k ] ) ; return true ; } catch ( e ) { return false ; } } ) ; if ( allSucceeded ) { return ; } const text = payload . data [ 'text/plain' ] || '' ; e . dataTransfer ! . setData ( 'text/plain' , `${ id }${ text ? `: ${ text }` : '' }` ) ; dndTransferStorage . set ( id , payload . data ) ; } ) ; node . addEventListener ( 'dragend' , ( e ) => { node . classList . remove ( cssClass ( 'dragging' ) ) ; if ( stopPropagation ) { e . stopPropagation ( ) ; } if ( dndTransferStorage . size > 0 ) { dndTransferStorage . delete ( id ) ; } const over = node . ownerDocument ! . getElementsByClassName ( cssClass ( 'dragover' ) ) [ 0 ] as HTMLElement ; if ( over ) { over . classList . remove ( cssClass ( 'dragover' ) ) ; } } ) ; } param { HTMLElement } node param { string [ ] } mimeTypes param { ( result : IDropResult , e : DragEvent ) => boolean } onDrop param { ( e : DragEvent ) => void } onDragOver param { boolean } stopPropagation param { ( ) => boolean } optional internal export function dropAble ( node , mimeTypes , onDrop , onDragOver = null , stopPropagation = false , canDrop = ( ) => true ) { node . addEventListener ( 'dragenter' , ( e ) => { if ( node . classList . contains ( cssClass ( 'dragging' ) ) || ! ( hasDnDType ( e , ... mimeTypes ) || isEdgeDnD ( e ) ) || ! canDrop ( ) ) { node . classList . remove ( cssClass ( 'dragover' ) ) ; return undefined ; } node . classList . add ( cssClass ( 'dragover' ) ) ; if ( stopPropagation ) { e . stopPropagation ( ) ; } return false ; } ) ; node . addEventListener ( 'dragover' , ( e ) => { if ( node . classList . contains ( cssClass ( 'dragging' ) ) || ! ( hasDnDType ( e , ... mimeTypes ) || isEdgeDnD ( e ) ) || ! canDrop ( ) ) { return undefined ; } e . preventDefault ( ) ; updateDropEffect ( e ) ; node . classList . add ( cssClass ( 'dragover' ) ) ; if ( stopPropagation ) { e . stopPropagation ( ) ; } if ( onDragOver ) { onDragOver ( e ) ; } return false ; } ) ; node . addEventListener ( 'dragleave' , ( evt ) => { ( evt . target as HTMLElement ) . classList . remove ( cssClass ( 'dragover' ) ) ; } ) ; node . addEventListener ( 'drop' , ( e ) => { e . preventDefault ( ) ; if ( stopPropagation ) { e . stopPropagation ( ) ; } updateDropEffect ( e ) ; const effect = e . dataTransfer ! . dropEffect as IDragEffect ; node . classList . remove ( cssClass ( 'dragover' ) ) ; if ( isEdgeDnD ( e ) ) { const base = e . dataTransfer ! . getData ( 'text/plain' ) ; const id = Number . parseInt ( base . indexOf ( ':' ) >= 0 ? base . substring ( 0 , base . indexOf ( ':' ) ) : base , 10 ) ; if ( dndTransferStorage . has ( id ) ) { const data = dndTransferStorage . get ( id ) ! ; dndTransferStorage . delete ( id ) ; return ! onDrop ( { effect , data } , e ) ; } return undefined ; } if ( ! hasDnDType ( e , ... mimeTypes ) ) { return undefined ; } const data = { } ; mimeTypes . forEach ( ( mime ) => { const value = e . dataTransfer ! . getData ( mime ) ; if ( value !== '' ) { data [ mime ] = value ; } } ) ; return ! onDrop ( { effect , data } , e ) ; } ) ; }