drop_events.js (4701B)
1 import { drawSelectionCursor } from "../display/selection.js" 2 import { operation } from "../display/operations.js" 3 import { clipPos } from "../line/pos.js" 4 import { posFromMouse } from "../measurement/position_measurement.js" 5 import { eventInWidget } from "../measurement/widgets.js" 6 import { makeChange, replaceRange } from "../model/changes.js" 7 import { changeEnd } from "../model/change_measurement.js" 8 import { simpleSelection } from "../model/selection.js" 9 import { setSelectionNoUndo, setSelectionReplaceHistory } from "../model/selection_updates.js" 10 import { ie, presto, safari } from "../util/browser.js" 11 import { elt, removeChildrenAndAdd } from "../util/dom.js" 12 import { e_preventDefault, e_stop, signalDOMEvent } from "../util/event.js" 13 import { indexOf } from "../util/misc.js" 14 15 // Kludge to work around strange IE behavior where it'll sometimes 16 // re-fire a series of drag-related events right after the drop (#1551) 17 let lastDrop = 0 18 19 export function onDrop(e) { 20 let cm = this 21 clearDragCursor(cm) 22 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) 23 return 24 e_preventDefault(e) 25 if (ie) lastDrop = +new Date 26 let pos = posFromMouse(cm, e, true), files = e.dataTransfer.files 27 if (!pos || cm.isReadOnly()) return 28 // Might be a file drop, in which case we simply extract the text 29 // and insert it. 30 if (files && files.length && window.FileReader && window.File) { 31 let n = files.length, text = Array(n), read = 0 32 let loadFile = (file, i) => { 33 if (cm.options.allowDropFileTypes && 34 indexOf(cm.options.allowDropFileTypes, file.type) == -1) 35 return 36 37 let reader = new FileReader 38 reader.onload = operation(cm, () => { 39 let content = reader.result 40 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) content = "" 41 text[i] = content 42 if (++read == n) { 43 pos = clipPos(cm.doc, pos) 44 let change = {from: pos, to: pos, 45 text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())), 46 origin: "paste"} 47 makeChange(cm.doc, change) 48 setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change))) 49 } 50 }) 51 reader.readAsText(file) 52 } 53 for (let i = 0; i < n; ++i) loadFile(files[i], i) 54 } else { // Normal drop 55 // Don't do a replace if the drop happened inside of the selected text. 56 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { 57 cm.state.draggingText(e) 58 // Ensure the editor is re-focused 59 setTimeout(() => cm.display.input.focus(), 20) 60 return 61 } 62 try { 63 let text = e.dataTransfer.getData("Text") 64 if (text) { 65 let selected 66 if (cm.state.draggingText && !cm.state.draggingText.copy) 67 selected = cm.listSelections() 68 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) 69 if (selected) for (let i = 0; i < selected.length; ++i) 70 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag") 71 cm.replaceSelection(text, "around", "paste") 72 cm.display.input.focus() 73 } 74 } 75 catch(e){} 76 } 77 } 78 79 export function onDragStart(cm, e) { 80 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } 81 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return 82 83 e.dataTransfer.setData("Text", cm.getSelection()) 84 e.dataTransfer.effectAllowed = "copyMove" 85 86 // Use dummy image instead of default browsers image. 87 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. 88 if (e.dataTransfer.setDragImage && !safari) { 89 let img = elt("img", null, null, "position: fixed; left: 0; top: 0;") 90 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" 91 if (presto) { 92 img.width = img.height = 1 93 cm.display.wrapper.appendChild(img) 94 // Force a relayout, or Opera won't use our image for some obscure reason 95 img._top = img.offsetTop 96 } 97 e.dataTransfer.setDragImage(img, 0, 0) 98 if (presto) img.parentNode.removeChild(img) 99 } 100 } 101 102 export function onDragOver(cm, e) { 103 let pos = posFromMouse(cm, e) 104 if (!pos) return 105 let frag = document.createDocumentFragment() 106 drawSelectionCursor(cm, pos, frag) 107 if (!cm.display.dragCursor) { 108 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") 109 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) 110 } 111 removeChildrenAndAdd(cm.display.dragCursor, frag) 112 } 113 114 export function clearDragCursor(cm) { 115 if (cm.display.dragCursor) { 116 cm.display.lineSpace.removeChild(cm.display.dragCursor) 117 cm.display.dragCursor = null 118 } 119 }