import { Arr, Id, Optional, Type } from '@ephox/katamari'; import { createFileList } from '../file/FileList'; import { getData } from './DataTransferItem'; import { createDataTransferItemList } from './DataTransferItemList'; import { isInProtectedMode, isInReadWriteMode, setReadWriteMode } from './Mode'; type DropEffect = DataTransfer['dropEffect']; type EffectAllowed = DataTransfer['effectAllowed']; const imageId = Id.generate('image'); const validDropEffects: DropEffect[] = [ 'none', 'copy', 'link', 'move' ]; const validEffectAlloweds: EffectAllowed[] = [ 'none', 'copy', 'copyLink', 'copyMove', 'link', 'linkMove', 'move', 'all', 'uninitialized' ]; export interface DragImageData { image: Element; x: number; y: number; } const setDragImage = (transfer: DataTransfer, imageData: DragImageData) => { const dt: any = transfer; dt[imageId] = imageData; }; const getDragImage = (transfer: DataTransfer): Optional => { const dt: any = transfer; return Optional.from(dt[imageId]); }; const normalize = (format: string) => { const lcFormat = format.toLowerCase(); if (lcFormat === 'text') { return 'text/plain'; } else if (lcFormat === 'url') { return 'text/uri-list'; } else { return lcFormat; } }; const createDataTransfer = (): DataTransfer => { let dropEffect: DropEffect = 'move'; let effectAllowed: EffectAllowed = 'all'; const dataTransfer: DataTransfer = new window.DataTransfer(); Object.defineProperties(dataTransfer, { dropEffect: { get: () => { return dropEffect; }, set: (effect: DropEffect) => { if (Arr.contains(validDropEffects, effect)) { dropEffect = effect; } } }, effectAllowed: { get: () => effectAllowed, set: (allowed: EffectAllowed) => { if (Arr.contains(validEffectAlloweds, allowed)) { effectAllowed = allowed; } } }, items: { get: () => { return items; } }, files: { get: () => { if (isInProtectedMode(dataTransfer)) { return createFileList([]); } const files = Arr.bind(Arr.from(items), (item) => { if (item.kind === 'file') { const file = item.getAsFile(); return Type.isNull(file) ? [] : [ file ]; } else { return []; } }); return createFileList(files); } }, types: { get: () => { const types = Arr.map(Arr.from(items), (item) => item.type); const hasFiles = Arr.exists(Arr.from(items), (item) => item.kind === 'file'); return types.concat(hasFiles ? [ 'Files' ] : []); } }, setDragImage: { value: (image: Element, x: number, y: number) => { if (isInReadWriteMode(dataTransfer)) { setDragImage(dataTransfer, { image, x, y }); } } }, getData: { value: (format: string) => { if (isInProtectedMode(dataTransfer)) { return ''; } return Arr.find(Arr.from(items), (item) => item.type === normalize(format)).bind((item) => getData(item)).getOr(''); } }, setData: { value: (format: string, data: string) => { if (isInReadWriteMode(dataTransfer)) { dataTransfer.clearData(normalize(format)); items.add(data, normalize(format)); } } }, clearData: { value: (format?: string) => { if (isInReadWriteMode(dataTransfer)) { if (Type.isString(format)) { const normalizedFormat = normalize(format); Arr.findIndex(Arr.from(items), (item) => item.type === normalizedFormat).each((idx) => { items.remove(idx); }); } else { for (let i = items.length - 1; i >= 0; i--) { if (items[i].kind === 'string') { items.remove(i); } } } } } } }); const items = createDataTransferItemList(dataTransfer); setReadWriteMode(dataTransfer); return dataTransfer; }; export { createDataTransfer, getDragImage };