namespace dnd { "use strict" ; interface IDragConfig { onlyHover : boolean ; hoverTime : number ; } export function simulate ( draggable , droppable , config = { onlyHover : false , hoverTime : 0 } ) { if ( ! config . onlyHover ) { simulateDragAndDrop ( draggable , droppable ) ; } else { simulateDragOver ( draggable , droppable , config . hoverTime ) ; } } export function simulateDragAndDrop ( draggable , droppable ) { const store = new DragDataStore ( ) ; store . mode = "readwrite" ; const dataTransfer = new DataTransfer ( store ) ; dragStart ( draggable , dataTransfer ) ; dragOver ( store , droppable , dataTransfer ) ; drop ( droppable , dataTransfer ) ; endDrag ( store , draggable , dataTransfer ) ; } export function simulateDragOver ( draggable , droppable , hoverTime = 0 ) { const store = new DragDataStore ( ) ; store . mode = "readwrite" ; const dataTransfer = new DataTransfer ( store ) ; dragStart ( draggable , dataTransfer ) ; dragOver ( store , droppable , dataTransfer ) ; setTimeout ( ( ) => { dragLeave ( droppable , dataTransfer ) ; endDrag ( store , draggable , dataTransfer ) ; } , hoverTime ) ; } function dragStart ( draggable , dataTransfer ) { const dragstartEvent = createEventWithDataTransfer ( "dragstart" , dataTransfer ) ; draggable . dispatchEvent ( dragstartEvent ) ; } function dragOver ( store , droppable , dataTransfer ) { store . mode = "readonly" ; const dragEnterEvent = createEventWithDataTransfer ( "dragenter" , dataTransfer ) ; droppable . dispatchEvent ( dragEnterEvent ) ; const dragOverEvent = createEventWithDataTransfer ( "dragover" , dataTransfer ) ; droppable . dispatchEvent ( dragOverEvent ) ; } function drop ( droppable , dataTransfer ) { const dropEvent = createEventWithDataTransfer ( "drop" , dataTransfer ) ; droppable . dispatchEvent ( dropEvent ) ; } function dragLeave ( droppable , dataTransfer ) { const dragExitEvent = createEventWithDataTransfer ( "dragexit" , dataTransfer ) ; droppable . dispatchEvent ( dragExitEvent ) ; const dragLeaveEvent = createEventWithDataTransfer ( "dragleave" , dataTransfer ) ; droppable . dispatchEvent ( dragLeaveEvent ) ; } function endDrag ( store , draggable , dataTransfer ) { store . mode = "protected" ; const dragendEvent = createEventWithDataTransfer ( "dragend" , dataTransfer ) ; draggable . dispatchEvent ( dragendEvent ) ; } /**
     * Creates an event instance with a DataTransfer.
     */ function createEventWithDataTransfer ( type , dataTransfer ) { const event = < any > document . createEvent ( "CustomEvent" ) ; event . initCustomEvent ( type , true , true , null ) ; event . dataTransfer = dataTransfer ; return event ; } type EventType = 'dragstart' | 'drag' | 'dragenter' | 'dragexit' | 'dragleave' | 'dragover' | 'drop' | 'dragend' ; see https export class DataTransfer { constructor ( private store ) { } see DataTransfer private typeTable : { [ type ] : string ; } = { } ; /**
         * Returns the kind of operation that is currently selected. If the kind of
         * operation isn't one of those that is allowed by the effectAllowed
         * attribute, then the operation will fail.
         *
         * Can be set, to change the selected operation.
         *
         * The possible values are "none", "copy", "link", and "move".
         */ dropEffect : DropEffect ; /**
         * Returns the kinds of operations that are to be allowed.
         *
         * Can be set (during the dragstart event), to change the allowed
         * operations.
         *
         * The possible values are "none", "copy", "copyLink", "copyMove", "link",
         * "linkMove", "move", "all", and "uninitialized",
         */ effectAllowed : EffectAllowed = "uninitialized" ; /**
         * Returns a DataTransferItemList object, with the drag data.
         */ items : DataTransferItemList ; /**
         * Uses the given element to update the drag feedback, replacing any
         * previously specified feedback.
         */ setDragImage ( element , x , y ) { } /**
         * Returns an array listing the formats that were set in the dragstart
         * event. In addition, if any files are being dragged, then one of the types
         * will be the string "Files".
         */ types : string [ ] = [ ] ; /**
         * Returns the specified data. If there is no such data, returns the empty
         * string.
         */ getData ( format ) { if ( this . store . mode === "protected" ) { return "" ; } format = format . toLowerCase ( ) ; let convertToUrl = false ; if ( format === "text" ) { format = "text/plain" ; } else if ( format === "url" ) { format = "text/uri-list" ; convertToUrl = true ; } if ( ! ( format in this . typeTable ) ) { return "" ; } let result = this . typeTable [ format ] ; if ( convertToUrl ) { result = parseTextUriList ( result ) [ 0 ] || "" ; } return result ; } /**
         * Adds the specified data.
         */ setData ( format , data ) { if ( ! this . store ) { return ; } if ( this . store . mode !== "readwrite" ) { return ; } format = format . toLowerCase ( ) ; if ( format === "text" ) { format = "text/plain" ; } else if ( format === "url" ) { format = "text/uri-list" ; } this . typeTable [ format ] = data ; this . types = Object . keys ( this . typeTable ) ; } /**
         * Removes the data of the specified formats. Removes all data if the
         * argument is omitted.
         */ clearData ( format ? ) { if ( ! this . store ) { return ; } if ( this . store . mode !== "readwrite" ) { return ; } if ( typeof format === "undefined" ) { this . types . filter ( ( type ) => type !== "Files" ) . forEach ( ( type ) => this . clearData ( type ) ) ; return ; } format = format . toLowerCase ( ) ; if ( format === "text" ) { format = "text/plain" ; } else if ( format === "url" ) { format = "text/uri-list" ; } delete this . typeTable [ format ] ; this . types = Object . keys ( this . typeTable ) ; } /**
         * Returns a FileList of the files being dragged, if any.
         */ files : FileList = new FileList ( ) ; } see DataTransfer type DropEffect = "none" | "copy" | "link" | "move" ; see DataTransfer type EffectAllowed = "none" | "copy" | "copyLink" | "copyMove" | "link" | "linkMove" | "move" | "all" | "uninitialized" ; see https export class FileList { length = 0 ; item ( index ) { return null ; } } /**
     * The data that underlies a drag-and-drop operation, known as the drag data
     * store, consists of the following information:
     *
     */ class DragDataStore { mode : DragDataStoreMode ; } see DragDataStore type DragDataStoreMode = "readwrite" | "readonly" | "protected" ; see https export class DataTransferItemList { constructor ( private store ) { } /**
         * Each DataTransfer object is associated with a DataTransferItemList
         * object.
         */ private items : DataTransferItem [ ] = [ ] ; see DataTransferItemList private typeTable : { [ type ] : boolean ; } = { } ; /**
         * Returns the number of items in the drag data store.
         */ length : number = 0 ; /**
         * Returns the DataTransferItem object representing the indexth entry in the
         * drag data store.
         */ [ index ] : DataTransferItem ; /**
         * Removes the indexth entry in the drag data store.
         */ remove ( idx ) { if ( this . store . mode !== "readwrite" ) { throw InvalidStateError . createByDefaultMessage ( ) ; } const [ removed ] = this . items . splice ( idx , 1 ) ; this . syncInternal ( ) ; if ( removed ) { delete this . typeTable [ removed . type ] ; } } /**
         * Removes all the entries in the drag data store.
         */ clear ( ) { if ( this . store . mode !== "readwrite" ) { throw InvalidStateError . createByDefaultMessage ( ) ; } this . items = [ ] ; this . syncInternal ( ) ; } /**
         * Adds a new entry for the given data to the drag data store. If the data
         * is plain text then a type string has to be provided also.
         */ add ( data ) ; add ( data , type ) ; add ( data , type ? ) { if ( this . store . mode !== "readwrite" ) { return null ; } if ( typeof data === "string" ) { const typeLowerCase = type . toLowerCase ( ) ; if ( this . typeTable [ typeLowerCase ] ) { throw NotSupportedError . createByDefaultMessage ( ) ; } const stringItem = DataTransferItem . createForString ( data , typeLowerCase , this . store ) ; this . items . push ( stringItem ) ; this . typeTable [ typeLowerCase ] = true ; } else { const fileItem = DataTransferItem . createForFile ( data , this . store ) ; this . items . push ( fileItem ) ; } this . syncInternal ( ) ; } private syncInternal ( ) { for ( let i = 0 ; i < this . length ; i ++ ) { delete this [ i ] ; } this . items . forEach ( ( item , j ) => { this [ j ] = item ; } ) ; this . length = this . items . length ; } } see https class DataTransferItem { constructor ( private data , kind , typeLowerCase , private store ) { this . type = typeLowerCase ; this . kind = kind ; } /**
         * The type attribute must return the empty string if the DataTransferItem
         * object is in the disabled mode; otherwise it must return the drag data
         * item type string of the item represented by the DataTransferItem object.
         */ public type : string ; /**
         * The kind attribute must return the empty string if the DataTransferItem
         * object is in the disabled mode; otherwise it must return the string given
         * in the cell from the second column of the following table from the row
         * whose cell in the first column contains the drag data item kind of the item
         * represented by the DataTransferItem object:
         *
         * | Kind                 | String   |
         * |:---------------------|:---------|
         * | Plain Unicode string | "string" |
         * | File                 | "file"   |
         */ public kind : DataTransferItemKind ; getAsString ( callback ) { if ( callback ) { return ; } if ( this . store . mode !== "readwrite" ) { return ; } if ( this . kind !== "string" ) { return ; } setTimeout ( ( ) => { callback ( < string > this . data ) ; } , 0 ) ; } getAsFile ( ) { if ( this . store . mode !== "readwrite" ) { return null ; } if ( this . kind !== "string" ) { return null ; } return < File > this . data ; } static createForString ( data , type , store ) { return new DataTransferItem ( data , "string" , type , store ) ; } static createForFile ( data , store ) { return new DataTransferItem ( data , "file" , null , store ) ; } } see DataTransferItem type DataTransferItemKind = "string" | "file" ; see https class InvalidStateError extends Error { constructor ( message ) { super ( message ) ; this . message = message ; this . name = "InvalidStateError" ; } static createByDefaultMessage ( ) { return new InvalidStateError ( "The object is in an invalid state" ) ; } } see https class NotSupportedError extends Error { constructor ( message ) { super ( message ) ; this . message = message ; this . name = "NotSupportedError" ; } static createByDefaultMessage ( ) { return new InvalidStateError ( "The operation is not supported" ) ; } } see http export function parseTextUriList ( textUriList ) { textUriList = textUriList . replace ( /\r\n$/ , "" ) ; if ( textUriList === "" ) { return < string [ ] > [ ] ; } return textUriList . split ( /\r\n/ ) . filter ( ( line ) => { return line [ 0 ] !== "#" ; } ) ; } ; }