Mercurial
comparison .cms/lib/codemirror/src/edit/drop_events.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
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 const markAsReadAndPasteIfAllFilesAreRead = () => { | |
33 if (++read == n) { | |
34 operation(cm, () => { | |
35 pos = clipPos(cm.doc, pos) | |
36 let change = {from: pos, to: pos, | |
37 text: cm.doc.splitLines( | |
38 text.filter(t => t != null).join(cm.doc.lineSeparator())), | |
39 origin: "paste"} | |
40 makeChange(cm.doc, change) | |
41 setSelectionReplaceHistory(cm.doc, simpleSelection(clipPos(cm.doc, pos), clipPos(cm.doc, changeEnd(change)))) | |
42 })() | |
43 } | |
44 } | |
45 const readTextFromFile = (file, i) => { | |
46 if (cm.options.allowDropFileTypes && | |
47 indexOf(cm.options.allowDropFileTypes, file.type) == -1) { | |
48 markAsReadAndPasteIfAllFilesAreRead() | |
49 return | |
50 } | |
51 let reader = new FileReader | |
52 reader.onerror = () => markAsReadAndPasteIfAllFilesAreRead() | |
53 reader.onload = () => { | |
54 let content = reader.result | |
55 if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { | |
56 markAsReadAndPasteIfAllFilesAreRead() | |
57 return | |
58 } | |
59 text[i] = content | |
60 markAsReadAndPasteIfAllFilesAreRead() | |
61 } | |
62 reader.readAsText(file) | |
63 } | |
64 for (let i = 0; i < files.length; i++) readTextFromFile(files[i], i) | |
65 } else { // Normal drop | |
66 // Don't do a replace if the drop happened inside of the selected text. | |
67 if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) { | |
68 cm.state.draggingText(e) | |
69 // Ensure the editor is re-focused | |
70 setTimeout(() => cm.display.input.focus(), 20) | |
71 return | |
72 } | |
73 try { | |
74 let text = e.dataTransfer.getData("Text") | |
75 if (text) { | |
76 let selected | |
77 if (cm.state.draggingText && !cm.state.draggingText.copy) | |
78 selected = cm.listSelections() | |
79 setSelectionNoUndo(cm.doc, simpleSelection(pos, pos)) | |
80 if (selected) for (let i = 0; i < selected.length; ++i) | |
81 replaceRange(cm.doc, "", selected[i].anchor, selected[i].head, "drag") | |
82 cm.replaceSelection(text, "around", "paste") | |
83 cm.display.input.focus() | |
84 } | |
85 } | |
86 catch(e){} | |
87 } | |
88 } | |
89 | |
90 export function onDragStart(cm, e) { | |
91 if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return } | |
92 if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) return | |
93 | |
94 e.dataTransfer.setData("Text", cm.getSelection()) | |
95 e.dataTransfer.effectAllowed = "copyMove" | |
96 | |
97 // Use dummy image instead of default browsers image. | |
98 // Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there. | |
99 if (e.dataTransfer.setDragImage && !safari) { | |
100 let img = elt("img", null, null, "position: fixed; left: 0; top: 0;") | |
101 img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" | |
102 if (presto) { | |
103 img.width = img.height = 1 | |
104 cm.display.wrapper.appendChild(img) | |
105 // Force a relayout, or Opera won't use our image for some obscure reason | |
106 img._top = img.offsetTop | |
107 } | |
108 e.dataTransfer.setDragImage(img, 0, 0) | |
109 if (presto) img.parentNode.removeChild(img) | |
110 } | |
111 } | |
112 | |
113 export function onDragOver(cm, e) { | |
114 let pos = posFromMouse(cm, e) | |
115 if (!pos) return | |
116 let frag = document.createDocumentFragment() | |
117 drawSelectionCursor(cm, pos, frag) | |
118 if (!cm.display.dragCursor) { | |
119 cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors") | |
120 cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv) | |
121 } | |
122 removeChildrenAndAdd(cm.display.dragCursor, frag) | |
123 } | |
124 | |
125 export function clearDragCursor(cm) { | |
126 if (cm.display.dragCursor) { | |
127 cm.display.lineSpace.removeChild(cm.display.dragCursor) | |
128 cm.display.dragCursor = null | |
129 } | |
130 } |