prosemirror-view 1.23.13 → 1.24.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +5733 -0
- package/dist/index.d.ts +799 -0
- package/dist/index.es.js +41 -41
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +4823 -5139
- package/dist/index.js.map +1 -1
- package/package.json +14 -14
- package/src/README.md +2 -0
- package/src/browser.ts +23 -0
- package/src/{capturekeys.js → capturekeys.ts} +38 -37
- package/src/{clipboard.js → clipboard.ts} +44 -41
- package/src/{decoration.js → decoration.ts} +313 -268
- package/src/{dom.js → dom.ts} +27 -24
- package/src/{domchange.js → domchange.ts} +38 -36
- package/src/{domcoords.js → domcoords.ts} +120 -99
- package/src/{domobserver.js → domobserver.ts} +41 -28
- package/src/index.ts +705 -0
- package/src/{input.js → input.ts} +203 -183
- package/src/{selection.js → selection.ts} +54 -48
- package/src/{viewdesc.js → viewdesc.ts} +342 -336
- package/rollup.config.js +0 -14
- package/src/browser.js +0 -23
- package/src/index.js +0 -668
|
@@ -1,46 +1,44 @@
|
|
|
1
1
|
import {Selection, NodeSelection, TextSelection} from "prosemirror-state"
|
|
2
2
|
import {dropPoint} from "prosemirror-transform"
|
|
3
|
-
import {Slice} from "prosemirror-model"
|
|
3
|
+
import {Slice, Node} from "prosemirror-model"
|
|
4
4
|
|
|
5
|
-
import browser from "./browser"
|
|
5
|
+
import * as browser from "./browser"
|
|
6
6
|
import {captureKeyDown} from "./capturekeys"
|
|
7
|
-
import {readDOMChange} from "./domchange"
|
|
8
7
|
import {parseFromClipboard, serializeForClipboard} from "./clipboard"
|
|
9
|
-
import {DOMObserver} from "./domobserver"
|
|
10
8
|
import {selectionBetween, selectionToDOM, selectionFromDOM} from "./selection"
|
|
11
|
-
import {keyEvent} from "./dom"
|
|
9
|
+
import {keyEvent, DOMNode} from "./dom"
|
|
10
|
+
import {EditorView} from "./index"
|
|
11
|
+
import {ViewDesc} from "./viewdesc"
|
|
12
12
|
|
|
13
13
|
// A collection of DOM events that occur within the editor, and callback functions
|
|
14
14
|
// to invoke when the event fires.
|
|
15
|
-
const handlers
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
view.eventHandlers = Object.create(null)
|
|
15
|
+
const handlers: {[event: string]: (view: EditorView, event: Event) => void} = {}
|
|
16
|
+
let editHandlers: {[event: string]: (view: EditorView, event: Event) => void} = {}
|
|
17
|
+
|
|
18
|
+
export class InputState {
|
|
19
|
+
shiftKey = false
|
|
20
|
+
mouseDown: MouseDown | null = null
|
|
21
|
+
lastKeyCode: number | null = null
|
|
22
|
+
lastKeyCodeTime = 0
|
|
23
|
+
lastClick = {time: 0, x: 0, y: 0, type: ""}
|
|
24
|
+
lastSelectionOrigin: string | null = null
|
|
25
|
+
lastSelectionTime = 0
|
|
26
|
+
lastIOSEnter = 0
|
|
27
|
+
lastIOSEnterFallbackTimeout = -1
|
|
28
|
+
lastAndroidDelete = 0
|
|
29
|
+
composing = false
|
|
30
|
+
composingTimeout = -1
|
|
31
|
+
compositionNodes: ViewDesc[] = []
|
|
32
|
+
compositionEndedAt = -2e8
|
|
33
|
+
domChangeCount = 0
|
|
34
|
+
eventHandlers: {[event: string]: (event: Event) => void} = Object.create(null)
|
|
35
|
+
hideSelectionGuard: (() => void) | null = null
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function initInput(view: EditorView) {
|
|
41
39
|
for (let event in handlers) {
|
|
42
40
|
let handler = handlers[event]
|
|
43
|
-
view.dom.addEventListener(event, view.eventHandlers[event] = event => {
|
|
41
|
+
view.dom.addEventListener(event, view.input.eventHandlers[event] = (event: Event) => {
|
|
44
42
|
if (eventBelongsToView(view, event) && !runCustomHandler(view, event) &&
|
|
45
43
|
(view.editable || !(event.type in editHandlers)))
|
|
46
44
|
handler(view, event)
|
|
@@ -54,54 +52,55 @@ export function initInput(view) {
|
|
|
54
52
|
ensureListeners(view)
|
|
55
53
|
}
|
|
56
54
|
|
|
57
|
-
function setSelectionOrigin(view, origin) {
|
|
58
|
-
view.lastSelectionOrigin = origin
|
|
59
|
-
view.lastSelectionTime = Date.now()
|
|
55
|
+
function setSelectionOrigin(view: EditorView, origin: string) {
|
|
56
|
+
view.input.lastSelectionOrigin = origin
|
|
57
|
+
view.input.lastSelectionTime = Date.now()
|
|
60
58
|
}
|
|
61
59
|
|
|
62
|
-
export function destroyInput(view) {
|
|
60
|
+
export function destroyInput(view: EditorView) {
|
|
63
61
|
view.domObserver.stop()
|
|
64
|
-
for (let type in view.eventHandlers)
|
|
65
|
-
view.dom.removeEventListener(type, view.eventHandlers[type])
|
|
66
|
-
clearTimeout(view.composingTimeout)
|
|
67
|
-
clearTimeout(view.lastIOSEnterFallbackTimeout)
|
|
62
|
+
for (let type in view.input.eventHandlers)
|
|
63
|
+
view.dom.removeEventListener(type, view.input.eventHandlers[type])
|
|
64
|
+
clearTimeout(view.input.composingTimeout)
|
|
65
|
+
clearTimeout(view.input.lastIOSEnterFallbackTimeout)
|
|
68
66
|
}
|
|
69
67
|
|
|
70
|
-
export function ensureListeners(view) {
|
|
68
|
+
export function ensureListeners(view: EditorView) {
|
|
71
69
|
view.someProp("handleDOMEvents", currentHandlers => {
|
|
72
|
-
for (let type in currentHandlers) if (!view.eventHandlers[type])
|
|
73
|
-
view.dom.addEventListener(type, view.eventHandlers[type] = event => runCustomHandler(view, event))
|
|
70
|
+
for (let type in currentHandlers) if (!view.input.eventHandlers[type])
|
|
71
|
+
view.dom.addEventListener(type, view.input.eventHandlers[type] = event => runCustomHandler(view, event))
|
|
74
72
|
})
|
|
75
73
|
}
|
|
76
74
|
|
|
77
|
-
function runCustomHandler(view, event) {
|
|
75
|
+
function runCustomHandler(view: EditorView, event: Event) {
|
|
78
76
|
return view.someProp("handleDOMEvents", handlers => {
|
|
79
77
|
let handler = handlers[event.type]
|
|
80
78
|
return handler ? handler(view, event) || event.defaultPrevented : false
|
|
81
79
|
})
|
|
82
80
|
}
|
|
83
81
|
|
|
84
|
-
function eventBelongsToView(view, event) {
|
|
82
|
+
function eventBelongsToView(view: EditorView, event: Event) {
|
|
85
83
|
if (!event.bubbles) return true
|
|
86
84
|
if (event.defaultPrevented) return false
|
|
87
|
-
for (let node = event.target; node != view.dom; node = node.parentNode)
|
|
85
|
+
for (let node = event.target as DOMNode; node != view.dom; node = node.parentNode!)
|
|
88
86
|
if (!node || node.nodeType == 11 ||
|
|
89
87
|
(node.pmViewDesc && node.pmViewDesc.stopEvent(event)))
|
|
90
88
|
return false
|
|
91
89
|
return true
|
|
92
90
|
}
|
|
93
91
|
|
|
94
|
-
export function dispatchEvent(view, event) {
|
|
92
|
+
export function dispatchEvent(view: EditorView, event: Event) {
|
|
95
93
|
if (!runCustomHandler(view, event) && handlers[event.type] &&
|
|
96
94
|
(view.editable || !(event.type in editHandlers)))
|
|
97
95
|
handlers[event.type](view, event)
|
|
98
96
|
}
|
|
99
97
|
|
|
100
|
-
editHandlers.keydown = (view,
|
|
101
|
-
|
|
98
|
+
editHandlers.keydown = (view: EditorView, _event: Event) => {
|
|
99
|
+
let event = _event as KeyboardEvent
|
|
100
|
+
view.input.shiftKey = event.keyCode == 16 || event.shiftKey
|
|
102
101
|
if (inOrNearComposition(view, event)) return
|
|
103
|
-
view.lastKeyCode = event.keyCode
|
|
104
|
-
view.lastKeyCodeTime = Date.now()
|
|
102
|
+
view.input.lastKeyCode = event.keyCode
|
|
103
|
+
view.input.lastKeyCodeTime = Date.now()
|
|
105
104
|
// Suppress enter key events on Chrome Android, because those tend
|
|
106
105
|
// to be part of a confused sequence of composition events fired,
|
|
107
106
|
// and handling them eagerly tends to corrupt the input.
|
|
@@ -114,11 +113,11 @@ editHandlers.keydown = (view, event) => {
|
|
|
114
113
|
// be replaced by whatever the Enter key handlers do.
|
|
115
114
|
if (browser.ios && event.keyCode == 13 && !event.ctrlKey && !event.altKey && !event.metaKey) {
|
|
116
115
|
let now = Date.now()
|
|
117
|
-
view.lastIOSEnter = now
|
|
118
|
-
view.lastIOSEnterFallbackTimeout = setTimeout(() => {
|
|
119
|
-
if (view.lastIOSEnter == now) {
|
|
116
|
+
view.input.lastIOSEnter = now
|
|
117
|
+
view.input.lastIOSEnterFallbackTimeout = setTimeout(() => {
|
|
118
|
+
if (view.input.lastIOSEnter == now) {
|
|
120
119
|
view.someProp("handleKeyDown", f => f(view, keyEvent(13, "Enter")))
|
|
121
|
-
view.lastIOSEnter = 0
|
|
120
|
+
view.input.lastIOSEnter = 0
|
|
122
121
|
}
|
|
123
122
|
}, 200)
|
|
124
123
|
} else if (view.someProp("handleKeyDown", f => f(view, event)) || captureKeyDown(view, event)) {
|
|
@@ -128,11 +127,12 @@ editHandlers.keydown = (view, event) => {
|
|
|
128
127
|
}
|
|
129
128
|
}
|
|
130
129
|
|
|
131
|
-
editHandlers.keyup = (view,
|
|
132
|
-
if (
|
|
130
|
+
editHandlers.keyup = (view, event) => {
|
|
131
|
+
if ((event as KeyboardEvent).keyCode == 16) view.input.shiftKey = false
|
|
133
132
|
}
|
|
134
133
|
|
|
135
|
-
editHandlers.keypress = (view,
|
|
134
|
+
editHandlers.keypress = (view, _event) => {
|
|
135
|
+
let event = _event as KeyboardEvent
|
|
136
136
|
if (inOrNearComposition(view, event) || !event.charCode ||
|
|
137
137
|
event.ctrlKey && !event.altKey || browser.mac && event.metaKey) return
|
|
138
138
|
|
|
@@ -150,32 +150,38 @@ editHandlers.keypress = (view, event) => {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
-
function eventCoords(event) { return {left: event.clientX, top: event.clientY} }
|
|
153
|
+
function eventCoords(event: MouseEvent) { return {left: event.clientX, top: event.clientY} }
|
|
154
154
|
|
|
155
|
-
function isNear(event, click) {
|
|
155
|
+
function isNear(event: MouseEvent, click: {x: number, y: number}) {
|
|
156
156
|
let dx = click.x - event.clientX, dy = click.y - event.clientY
|
|
157
157
|
return dx * dx + dy * dy < 100
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
function runHandlerOnContext(
|
|
160
|
+
function runHandlerOnContext(
|
|
161
|
+
view: EditorView,
|
|
162
|
+
propName: "handleClickOn" | "handleDoubleClickOn" | "handleTripleClickOn",
|
|
163
|
+
pos: number,
|
|
164
|
+
inside: number,
|
|
165
|
+
event: MouseEvent
|
|
166
|
+
) {
|
|
161
167
|
if (inside == -1) return false
|
|
162
168
|
let $pos = view.state.doc.resolve(inside)
|
|
163
169
|
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
164
|
-
if (view.someProp(propName, f => i > $pos.depth ? f(view, pos, $pos.nodeAfter
|
|
170
|
+
if (view.someProp(propName, f => i > $pos.depth ? f(view, pos, $pos.nodeAfter!, $pos.before(i), event, true)
|
|
165
171
|
: f(view, pos, $pos.node(i), $pos.before(i), event, false)))
|
|
166
172
|
return true
|
|
167
173
|
}
|
|
168
174
|
return false
|
|
169
175
|
}
|
|
170
176
|
|
|
171
|
-
function updateSelection(view, selection, origin) {
|
|
177
|
+
function updateSelection(view: EditorView, selection: Selection, origin: string) {
|
|
172
178
|
if (!view.focused) view.focus()
|
|
173
179
|
let tr = view.state.tr.setSelection(selection)
|
|
174
180
|
if (origin == "pointer") tr.setMeta("pointer", true)
|
|
175
181
|
view.dispatch(tr)
|
|
176
182
|
}
|
|
177
183
|
|
|
178
|
-
function selectClickedLeaf(view, inside) {
|
|
184
|
+
function selectClickedLeaf(view: EditorView, inside: number) {
|
|
179
185
|
if (inside == -1) return false
|
|
180
186
|
let $pos = view.state.doc.resolve(inside), node = $pos.nodeAfter
|
|
181
187
|
if (node && node.isAtom && NodeSelection.isSelectable(node)) {
|
|
@@ -185,14 +191,14 @@ function selectClickedLeaf(view, inside) {
|
|
|
185
191
|
return false
|
|
186
192
|
}
|
|
187
193
|
|
|
188
|
-
function selectClickedNode(view, inside) {
|
|
194
|
+
function selectClickedNode(view: EditorView, inside: number) {
|
|
189
195
|
if (inside == -1) return false
|
|
190
196
|
let sel = view.state.selection, selectedNode, selectAt
|
|
191
197
|
if (sel instanceof NodeSelection) selectedNode = sel.node
|
|
192
198
|
|
|
193
199
|
let $pos = view.state.doc.resolve(inside)
|
|
194
200
|
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
195
|
-
let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i)
|
|
201
|
+
let node = i > $pos.depth ? $pos.nodeAfter! : $pos.node(i)
|
|
196
202
|
if (NodeSelection.isSelectable(node)) {
|
|
197
203
|
if (selectedNode && sel.$from.depth > 0 &&
|
|
198
204
|
i >= sel.$from.depth && $pos.before(sel.$from.depth + 1) == sel.$from.pos)
|
|
@@ -211,24 +217,24 @@ function selectClickedNode(view, inside) {
|
|
|
211
217
|
}
|
|
212
218
|
}
|
|
213
219
|
|
|
214
|
-
function handleSingleClick(view, pos, inside, event, selectNode) {
|
|
220
|
+
function handleSingleClick(view: EditorView, pos: number, inside: number, event: MouseEvent, selectNode: boolean) {
|
|
215
221
|
return runHandlerOnContext(view, "handleClickOn", pos, inside, event) ||
|
|
216
222
|
view.someProp("handleClick", f => f(view, pos, event)) ||
|
|
217
223
|
(selectNode ? selectClickedNode(view, inside) : selectClickedLeaf(view, inside))
|
|
218
224
|
}
|
|
219
225
|
|
|
220
|
-
function handleDoubleClick(view, pos, inside, event) {
|
|
226
|
+
function handleDoubleClick(view: EditorView, pos: number, inside: number, event: MouseEvent) {
|
|
221
227
|
return runHandlerOnContext(view, "handleDoubleClickOn", pos, inside, event) ||
|
|
222
228
|
view.someProp("handleDoubleClick", f => f(view, pos, event))
|
|
223
229
|
}
|
|
224
230
|
|
|
225
|
-
function handleTripleClick(view, pos, inside, event) {
|
|
231
|
+
function handleTripleClick(view: EditorView, pos: number, inside: number, event: MouseEvent) {
|
|
226
232
|
return runHandlerOnContext(view, "handleTripleClickOn", pos, inside, event) ||
|
|
227
233
|
view.someProp("handleTripleClick", f => f(view, pos, event)) ||
|
|
228
234
|
defaultTripleClick(view, inside, event)
|
|
229
235
|
}
|
|
230
236
|
|
|
231
|
-
function defaultTripleClick(view, inside, event) {
|
|
237
|
+
function defaultTripleClick(view: EditorView, inside: number, event: MouseEvent) {
|
|
232
238
|
if (event.button != 0) return false
|
|
233
239
|
let doc = view.state.doc
|
|
234
240
|
if (inside == -1) {
|
|
@@ -241,7 +247,7 @@ function defaultTripleClick(view, inside, event) {
|
|
|
241
247
|
|
|
242
248
|
let $pos = doc.resolve(inside)
|
|
243
249
|
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
244
|
-
let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i)
|
|
250
|
+
let node = i > $pos.depth ? $pos.nodeAfter! : $pos.node(i)
|
|
245
251
|
let nodePos = $pos.before(i)
|
|
246
252
|
if (node.inlineContent)
|
|
247
253
|
updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer")
|
|
@@ -253,28 +259,29 @@ function defaultTripleClick(view, inside, event) {
|
|
|
253
259
|
}
|
|
254
260
|
}
|
|
255
261
|
|
|
256
|
-
function forceDOMFlush(view) {
|
|
262
|
+
function forceDOMFlush(view: EditorView) {
|
|
257
263
|
return endComposition(view)
|
|
258
264
|
}
|
|
259
265
|
|
|
260
|
-
const selectNodeModifier = browser.mac ? "metaKey" : "ctrlKey"
|
|
266
|
+
const selectNodeModifier: keyof MouseEvent = browser.mac ? "metaKey" : "ctrlKey"
|
|
261
267
|
|
|
262
|
-
handlers.mousedown = (view,
|
|
263
|
-
|
|
268
|
+
handlers.mousedown = (view, _event) => {
|
|
269
|
+
let event = _event as MouseEvent
|
|
270
|
+
view.input.shiftKey = event.shiftKey
|
|
264
271
|
let flushed = forceDOMFlush(view)
|
|
265
272
|
let now = Date.now(), type = "singleClick"
|
|
266
|
-
if (now - view.lastClick.time < 500 && isNear(event, view.lastClick) && !event[selectNodeModifier]) {
|
|
267
|
-
if (view.lastClick.type == "singleClick") type = "doubleClick"
|
|
268
|
-
else if (view.lastClick.type == "doubleClick") type = "tripleClick"
|
|
273
|
+
if (now - view.input.lastClick.time < 500 && isNear(event, view.input.lastClick) && !event[selectNodeModifier]) {
|
|
274
|
+
if (view.input.lastClick.type == "singleClick") type = "doubleClick"
|
|
275
|
+
else if (view.input.lastClick.type == "doubleClick") type = "tripleClick"
|
|
269
276
|
}
|
|
270
|
-
view.lastClick = {time: now, x: event.clientX, y: event.clientY, type}
|
|
277
|
+
view.input.lastClick = {time: now, x: event.clientX, y: event.clientY, type}
|
|
271
278
|
|
|
272
279
|
let pos = view.posAtCoords(eventCoords(event))
|
|
273
280
|
if (!pos) return
|
|
274
281
|
|
|
275
282
|
if (type == "singleClick") {
|
|
276
|
-
if (view.mouseDown) view.mouseDown.done()
|
|
277
|
-
view.mouseDown = new MouseDown(view, pos, event, flushed)
|
|
283
|
+
if (view.input.mouseDown) view.input.mouseDown.done()
|
|
284
|
+
view.input.mouseDown = new MouseDown(view, pos, event, !!flushed)
|
|
278
285
|
} else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event)) {
|
|
279
286
|
event.preventDefault()
|
|
280
287
|
} else {
|
|
@@ -283,19 +290,26 @@ handlers.mousedown = (view, event) => {
|
|
|
283
290
|
}
|
|
284
291
|
|
|
285
292
|
class MouseDown {
|
|
286
|
-
|
|
287
|
-
|
|
293
|
+
startDoc: Node
|
|
294
|
+
selectNode: boolean
|
|
295
|
+
allowDefault: boolean
|
|
296
|
+
delayedSelectionSync = false
|
|
297
|
+
mightDrag: {node: Node, pos: number, addAttr: boolean, setUneditable: boolean} | null = null
|
|
298
|
+
target: HTMLElement | null
|
|
299
|
+
|
|
300
|
+
constructor(
|
|
301
|
+
readonly view: EditorView,
|
|
302
|
+
readonly pos: {pos: number, inside: number},
|
|
303
|
+
readonly event: MouseEvent,
|
|
304
|
+
readonly flushed: boolean
|
|
305
|
+
) {
|
|
288
306
|
this.startDoc = view.state.doc
|
|
289
|
-
this.
|
|
290
|
-
this.event = event
|
|
291
|
-
this.flushed = flushed
|
|
292
|
-
this.selectNode = event[selectNodeModifier]
|
|
307
|
+
this.selectNode = !!event[selectNodeModifier]
|
|
293
308
|
this.allowDefault = event.shiftKey
|
|
294
|
-
this.delayedSelectionSync = false
|
|
295
309
|
|
|
296
|
-
let targetNode, targetPos
|
|
310
|
+
let targetNode: Node, targetPos
|
|
297
311
|
if (pos.inside > -1) {
|
|
298
|
-
targetNode = view.state.doc.nodeAt(pos.inside)
|
|
312
|
+
targetNode = view.state.doc.nodeAt(pos.inside)!
|
|
299
313
|
targetPos = pos.inside
|
|
300
314
|
} else {
|
|
301
315
|
let $pos = view.state.doc.resolve(pos.pos)
|
|
@@ -303,39 +317,39 @@ class MouseDown {
|
|
|
303
317
|
targetPos = $pos.depth ? $pos.before() : 0
|
|
304
318
|
}
|
|
305
319
|
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const target = flushed ? null : event.target
|
|
320
|
+
const target = flushed ? null : event.target as HTMLElement
|
|
309
321
|
const targetDesc = target ? view.docView.nearestDesc(target, true) : null
|
|
310
|
-
this.target = targetDesc ? targetDesc.dom : null
|
|
322
|
+
this.target = targetDesc ? targetDesc.dom as HTMLElement : null
|
|
311
323
|
|
|
312
324
|
let {selection} = view.state
|
|
313
325
|
if (event.button == 0 &&
|
|
314
326
|
targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
|
|
315
327
|
selection instanceof NodeSelection && selection.from <= targetPos && selection.to > targetPos)
|
|
316
|
-
this.mightDrag = {
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
328
|
+
this.mightDrag = {
|
|
329
|
+
node: targetNode,
|
|
330
|
+
pos: targetPos,
|
|
331
|
+
addAttr: !!(this.target && !this.target.draggable),
|
|
332
|
+
setUneditable: !!(this.target && browser.gecko && !this.target.hasAttribute("contentEditable"))
|
|
333
|
+
}
|
|
320
334
|
|
|
321
335
|
if (this.target && this.mightDrag && (this.mightDrag.addAttr || this.mightDrag.setUneditable)) {
|
|
322
336
|
this.view.domObserver.stop()
|
|
323
337
|
if (this.mightDrag.addAttr) this.target.draggable = true
|
|
324
338
|
if (this.mightDrag.setUneditable)
|
|
325
339
|
setTimeout(() => {
|
|
326
|
-
if (this.view.mouseDown == this) this.target
|
|
340
|
+
if (this.view.input.mouseDown == this) this.target!.setAttribute("contentEditable", "false")
|
|
327
341
|
}, 20)
|
|
328
342
|
this.view.domObserver.start()
|
|
329
343
|
}
|
|
330
344
|
|
|
331
|
-
view.root.addEventListener("mouseup", this.up = this.up.bind(this))
|
|
332
|
-
view.root.addEventListener("mousemove", this.move = this.move.bind(this))
|
|
345
|
+
view.root.addEventListener("mouseup", this.up = this.up.bind(this) as any)
|
|
346
|
+
view.root.addEventListener("mousemove", this.move = this.move.bind(this) as any)
|
|
333
347
|
setSelectionOrigin(view, "pointer")
|
|
334
348
|
}
|
|
335
349
|
|
|
336
350
|
done() {
|
|
337
|
-
this.view.root.removeEventListener("mouseup", this.up)
|
|
338
|
-
this.view.root.removeEventListener("mousemove", this.move)
|
|
351
|
+
this.view.root.removeEventListener("mouseup", this.up as any)
|
|
352
|
+
this.view.root.removeEventListener("mousemove", this.move as any)
|
|
339
353
|
if (this.mightDrag && this.target) {
|
|
340
354
|
this.view.domObserver.stop()
|
|
341
355
|
if (this.mightDrag.addAttr) this.target.removeAttribute("draggable")
|
|
@@ -343,16 +357,16 @@ class MouseDown {
|
|
|
343
357
|
this.view.domObserver.start()
|
|
344
358
|
}
|
|
345
359
|
if (this.delayedSelectionSync) setTimeout(() => selectionToDOM(this.view))
|
|
346
|
-
this.view.mouseDown = null
|
|
360
|
+
this.view.input.mouseDown = null
|
|
347
361
|
}
|
|
348
362
|
|
|
349
|
-
up(event) {
|
|
363
|
+
up(event: MouseEvent) {
|
|
350
364
|
this.done()
|
|
351
365
|
|
|
352
|
-
if (!this.view.dom.contains(event.target
|
|
366
|
+
if (!this.view.dom.contains(event.target as HTMLElement))
|
|
353
367
|
return
|
|
354
368
|
|
|
355
|
-
let pos = this.pos
|
|
369
|
+
let pos: {pos: number, inside: number} | null = this.pos
|
|
356
370
|
if (this.view.state.doc != this.startDoc) pos = this.view.posAtCoords(eventCoords(event))
|
|
357
371
|
|
|
358
372
|
if (this.allowDefault || !pos) {
|
|
@@ -380,7 +394,7 @@ class MouseDown {
|
|
|
380
394
|
}
|
|
381
395
|
}
|
|
382
396
|
|
|
383
|
-
move(event) {
|
|
397
|
+
move(event: MouseEvent) {
|
|
384
398
|
if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
|
|
385
399
|
Math.abs(this.event.y - event.clientY) > 4))
|
|
386
400
|
this.allowDefault = true
|
|
@@ -396,7 +410,7 @@ handlers.touchdown = view => {
|
|
|
396
410
|
|
|
397
411
|
handlers.contextmenu = view => forceDOMFlush(view)
|
|
398
412
|
|
|
399
|
-
function inOrNearComposition(view, event) {
|
|
413
|
+
function inOrNearComposition(view: EditorView, event: Event) {
|
|
400
414
|
if (view.composing) return true
|
|
401
415
|
// See https://www.stum.de/2016/06/24/handling-ime-events-in-javascript/.
|
|
402
416
|
// On Japanese input method editors (IMEs), the Enter key is used to confirm character
|
|
@@ -408,8 +422,8 @@ function inOrNearComposition(view, event) {
|
|
|
408
422
|
// This guards against the case where compositionend is triggered without the keyboard
|
|
409
423
|
// (e.g. character confirmation may be done with the mouse), and keydown is triggered
|
|
410
424
|
// afterwards- we wouldn't want to ignore the keydown event in this case.
|
|
411
|
-
if (browser.safari && Math.abs(event.timeStamp - view.compositionEndedAt) < 500) {
|
|
412
|
-
view.compositionEndedAt = -2e8
|
|
425
|
+
if (browser.safari && Math.abs(event.timeStamp - view.input.compositionEndedAt) < 500) {
|
|
426
|
+
view.input.compositionEndedAt = -2e8
|
|
413
427
|
return true
|
|
414
428
|
}
|
|
415
429
|
return false
|
|
@@ -424,7 +438,7 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
424
438
|
let {state} = view, $pos = state.selection.$from
|
|
425
439
|
if (state.selection.empty &&
|
|
426
440
|
(state.storedMarks ||
|
|
427
|
-
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore
|
|
441
|
+
(!$pos.textOffset && $pos.parentOffset && $pos.nodeBefore!.marks.some(m => m.type.spec.inclusive === false)))) {
|
|
428
442
|
// Need to wrap the cursor in mark nodes different from the ones in the DOM context
|
|
429
443
|
view.markCursor = view.state.storedMarks || $pos.marks()
|
|
430
444
|
endComposition(view, true)
|
|
@@ -434,13 +448,13 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
434
448
|
// In firefox, if the cursor is after but outside a marked node,
|
|
435
449
|
// the inserted text won't inherit the marks. So this moves it
|
|
436
450
|
// inside if necessary.
|
|
437
|
-
if (browser.gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore
|
|
438
|
-
let sel = view.
|
|
451
|
+
if (browser.gecko && state.selection.empty && $pos.parentOffset && !$pos.textOffset && $pos.nodeBefore!.marks.length) {
|
|
452
|
+
let sel = view.domSelection()
|
|
439
453
|
for (let node = sel.focusNode, offset = sel.focusOffset; node && node.nodeType == 1 && offset != 0;) {
|
|
440
454
|
let before = offset < 0 ? node.lastChild : node.childNodes[offset - 1]
|
|
441
455
|
if (!before) break
|
|
442
456
|
if (before.nodeType == 3) {
|
|
443
|
-
sel.collapse(before, before.nodeValue
|
|
457
|
+
sel.collapse(before, before.nodeValue!.length)
|
|
444
458
|
break
|
|
445
459
|
} else {
|
|
446
460
|
node = before
|
|
@@ -449,30 +463,30 @@ editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
|
449
463
|
}
|
|
450
464
|
}
|
|
451
465
|
}
|
|
452
|
-
view.composing = true
|
|
466
|
+
view.input.composing = true
|
|
453
467
|
}
|
|
454
468
|
scheduleComposeEnd(view, timeoutComposition)
|
|
455
469
|
}
|
|
456
470
|
|
|
457
471
|
editHandlers.compositionend = (view, event) => {
|
|
458
472
|
if (view.composing) {
|
|
459
|
-
view.composing = false
|
|
460
|
-
view.compositionEndedAt = event.timeStamp
|
|
473
|
+
view.input.composing = false
|
|
474
|
+
view.input.compositionEndedAt = event.timeStamp
|
|
461
475
|
scheduleComposeEnd(view, 20)
|
|
462
476
|
}
|
|
463
477
|
}
|
|
464
478
|
|
|
465
|
-
function scheduleComposeEnd(view, delay) {
|
|
466
|
-
clearTimeout(view.composingTimeout)
|
|
467
|
-
if (delay > -1) view.composingTimeout = setTimeout(() => endComposition(view), delay)
|
|
479
|
+
function scheduleComposeEnd(view: EditorView, delay: number) {
|
|
480
|
+
clearTimeout(view.input.composingTimeout)
|
|
481
|
+
if (delay > -1) view.input.composingTimeout = setTimeout(() => endComposition(view), delay)
|
|
468
482
|
}
|
|
469
483
|
|
|
470
|
-
export function clearComposition(view) {
|
|
484
|
+
export function clearComposition(view: EditorView) {
|
|
471
485
|
if (view.composing) {
|
|
472
|
-
view.composing = false
|
|
473
|
-
view.compositionEndedAt = timestampFromCustomEvent()
|
|
486
|
+
view.input.composing = false
|
|
487
|
+
view.input.compositionEndedAt = timestampFromCustomEvent()
|
|
474
488
|
}
|
|
475
|
-
while (view.compositionNodes.length > 0) view.compositionNodes.pop()
|
|
489
|
+
while (view.input.compositionNodes.length > 0) view.input.compositionNodes.pop()!.markParentsDirty()
|
|
476
490
|
}
|
|
477
491
|
|
|
478
492
|
function timestampFromCustomEvent() {
|
|
@@ -481,7 +495,8 @@ function timestampFromCustomEvent() {
|
|
|
481
495
|
return event.timeStamp
|
|
482
496
|
}
|
|
483
497
|
|
|
484
|
-
|
|
498
|
+
/// @internal
|
|
499
|
+
export function endComposition(view: EditorView, forceUpdate = false) {
|
|
485
500
|
if (browser.android && view.domObserver.flushingSoon >= 0) return
|
|
486
501
|
view.domObserver.forceFlush()
|
|
487
502
|
clearComposition(view)
|
|
@@ -494,14 +509,14 @@ export function endComposition(view, forceUpdate) {
|
|
|
494
509
|
return false
|
|
495
510
|
}
|
|
496
511
|
|
|
497
|
-
function captureCopy(view, dom) {
|
|
512
|
+
function captureCopy(view: EditorView, dom: HTMLElement) {
|
|
498
513
|
// The extra wrapper is somehow necessary on IE/Edge to prevent the
|
|
499
514
|
// content from being mangled when it is put onto the clipboard
|
|
500
515
|
if (!view.dom.parentNode) return
|
|
501
516
|
let wrap = view.dom.parentNode.appendChild(document.createElement("div"))
|
|
502
517
|
wrap.appendChild(dom)
|
|
503
518
|
wrap.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
504
|
-
let sel = getSelection()
|
|
519
|
+
let sel = getSelection()!, range = document.createRange()
|
|
505
520
|
range.selectNodeContents(dom)
|
|
506
521
|
// Done because IE will fire a selectionchange moving the selection
|
|
507
522
|
// to its start when removeAllRanges is called and the editor still
|
|
@@ -521,15 +536,16 @@ function captureCopy(view, dom) {
|
|
|
521
536
|
const brokenClipboardAPI = (browser.ie && browser.ie_version < 15) ||
|
|
522
537
|
(browser.ios && browser.webkit_version < 604)
|
|
523
538
|
|
|
524
|
-
handlers.copy = editHandlers.cut = (view,
|
|
525
|
-
let
|
|
539
|
+
handlers.copy = editHandlers.cut = (view, _event) => {
|
|
540
|
+
let event = _event as ClipboardEvent
|
|
541
|
+
let sel = view.state.selection, cut = event.type == "cut"
|
|
526
542
|
if (sel.empty) return
|
|
527
543
|
|
|
528
544
|
// IE and Edge's clipboard interface is completely broken
|
|
529
|
-
let data = brokenClipboardAPI ? null :
|
|
545
|
+
let data = brokenClipboardAPI ? null : event.clipboardData
|
|
530
546
|
let slice = sel.content(), {dom, text} = serializeForClipboard(view, slice)
|
|
531
547
|
if (data) {
|
|
532
|
-
|
|
548
|
+
event.preventDefault()
|
|
533
549
|
data.clearData()
|
|
534
550
|
data.setData("text/html", dom.innerHTML)
|
|
535
551
|
data.setData("text/plain", text)
|
|
@@ -539,13 +555,13 @@ handlers.copy = editHandlers.cut = (view, e) => {
|
|
|
539
555
|
if (cut) view.dispatch(view.state.tr.deleteSelection().scrollIntoView().setMeta("uiEvent", "cut"))
|
|
540
556
|
}
|
|
541
557
|
|
|
542
|
-
function sliceSingleNode(slice) {
|
|
558
|
+
function sliceSingleNode(slice: Slice) {
|
|
543
559
|
return slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1 ? slice.content.firstChild : null
|
|
544
560
|
}
|
|
545
561
|
|
|
546
|
-
function capturePaste(view,
|
|
562
|
+
function capturePaste(view: EditorView, event: ClipboardEvent) {
|
|
547
563
|
if (!view.dom.parentNode) return
|
|
548
|
-
let plainText = view.shiftKey || view.state.selection.$from.parent.type.spec.code
|
|
564
|
+
let plainText = view.input.shiftKey || view.state.selection.$from.parent.type.spec.code
|
|
549
565
|
let target = view.dom.parentNode.appendChild(document.createElement(plainText ? "textarea" : "div"))
|
|
550
566
|
if (!plainText) target.contentEditable = "true"
|
|
551
567
|
target.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
@@ -553,65 +569,66 @@ function capturePaste(view, e) {
|
|
|
553
569
|
setTimeout(() => {
|
|
554
570
|
view.focus()
|
|
555
571
|
if (target.parentNode) target.parentNode.removeChild(target)
|
|
556
|
-
if (plainText) doPaste(view, target.value, null,
|
|
557
|
-
else doPaste(view, target.textContent
|
|
572
|
+
if (plainText) doPaste(view, (target as HTMLTextAreaElement).value, null, event)
|
|
573
|
+
else doPaste(view, target.textContent!, target.innerHTML, event)
|
|
558
574
|
}, 50)
|
|
559
575
|
}
|
|
560
576
|
|
|
561
|
-
function doPaste(view, text, html,
|
|
562
|
-
let slice = parseFromClipboard(view, text, html, view.shiftKey, view.state.selection.$from)
|
|
563
|
-
if (view.someProp("handlePaste", f => f(view,
|
|
577
|
+
function doPaste(view: EditorView, text: string, html: string | null, event: ClipboardEvent) {
|
|
578
|
+
let slice = parseFromClipboard(view, text, html, view.input.shiftKey, view.state.selection.$from)
|
|
579
|
+
if (view.someProp("handlePaste", f => f(view, event, slice || Slice.empty))) return true
|
|
564
580
|
if (!slice) return false
|
|
565
581
|
|
|
566
582
|
let singleNode = sliceSingleNode(slice)
|
|
567
|
-
let tr = singleNode
|
|
583
|
+
let tr = singleNode
|
|
584
|
+
? view.state.tr.replaceSelectionWith(singleNode, view.input.shiftKey)
|
|
585
|
+
: view.state.tr.replaceSelection(slice)
|
|
568
586
|
view.dispatch(tr.scrollIntoView().setMeta("paste", true).setMeta("uiEvent", "paste"))
|
|
569
587
|
return true
|
|
570
588
|
}
|
|
571
589
|
|
|
572
|
-
editHandlers.paste = (view,
|
|
590
|
+
editHandlers.paste = (view, _event) => {
|
|
591
|
+
let event = _event as ClipboardEvent
|
|
573
592
|
// Handling paste from JavaScript during composition is very poorly
|
|
574
593
|
// handled by browsers, so as a dodgy but preferable kludge, we just
|
|
575
594
|
// let the browser do its native thing there, except on Android,
|
|
576
595
|
// where the editor is almost always composing.
|
|
577
596
|
if (view.composing && !browser.android) return
|
|
578
|
-
let data = brokenClipboardAPI ? null :
|
|
579
|
-
if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"),
|
|
580
|
-
else capturePaste(view,
|
|
597
|
+
let data = brokenClipboardAPI ? null : event.clipboardData
|
|
598
|
+
if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), event)) event.preventDefault()
|
|
599
|
+
else capturePaste(view, event)
|
|
581
600
|
}
|
|
582
601
|
|
|
583
602
|
class Dragging {
|
|
584
|
-
constructor(slice, move) {
|
|
585
|
-
this.slice = slice
|
|
586
|
-
this.move = move
|
|
587
|
-
}
|
|
603
|
+
constructor(readonly slice: Slice, readonly move: boolean) {}
|
|
588
604
|
}
|
|
589
605
|
|
|
590
|
-
const dragCopyModifier = browser.mac ? "altKey" : "ctrlKey"
|
|
606
|
+
const dragCopyModifier: keyof DragEvent = browser.mac ? "altKey" : "ctrlKey"
|
|
591
607
|
|
|
592
|
-
handlers.dragstart = (view,
|
|
593
|
-
let
|
|
608
|
+
handlers.dragstart = (view, _event) => {
|
|
609
|
+
let event = _event as DragEvent
|
|
610
|
+
let mouseDown = view.input.mouseDown
|
|
594
611
|
if (mouseDown) mouseDown.done()
|
|
595
|
-
if (!
|
|
612
|
+
if (!event.dataTransfer) return
|
|
596
613
|
|
|
597
614
|
let sel = view.state.selection
|
|
598
|
-
let pos = sel.empty ? null : view.posAtCoords(eventCoords(
|
|
615
|
+
let pos = sel.empty ? null : view.posAtCoords(eventCoords(event))
|
|
599
616
|
if (pos && pos.pos >= sel.from && pos.pos <= (sel instanceof NodeSelection ? sel.to - 1: sel.to)) {
|
|
600
617
|
// In selection
|
|
601
618
|
} else if (mouseDown && mouseDown.mightDrag) {
|
|
602
619
|
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)))
|
|
603
|
-
} else if (
|
|
604
|
-
let desc = view.docView.nearestDesc(
|
|
605
|
-
if (desc && desc.node
|
|
620
|
+
} else if (event.target && (event.target as HTMLElement).nodeType == 1) {
|
|
621
|
+
let desc = view.docView.nearestDesc(event.target as HTMLElement, true)
|
|
622
|
+
if (desc && desc.node!.type.spec.draggable && desc != view.docView)
|
|
606
623
|
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, desc.posBefore)))
|
|
607
624
|
}
|
|
608
625
|
let slice = view.state.selection.content(), {dom, text} = serializeForClipboard(view, slice)
|
|
609
|
-
|
|
610
|
-
|
|
626
|
+
event.dataTransfer.clearData()
|
|
627
|
+
event.dataTransfer.setData(brokenClipboardAPI ? "Text" : "text/html", dom.innerHTML)
|
|
611
628
|
// See https://github.com/ProseMirror/prosemirror/issues/1156
|
|
612
|
-
|
|
613
|
-
if (!brokenClipboardAPI)
|
|
614
|
-
view.dragging = new Dragging(slice, !
|
|
629
|
+
event.dataTransfer.effectAllowed = "copyMove"
|
|
630
|
+
if (!brokenClipboardAPI) event.dataTransfer.setData("text/plain", text)
|
|
631
|
+
view.dragging = new Dragging(slice, !event[dragCopyModifier])
|
|
615
632
|
}
|
|
616
633
|
|
|
617
634
|
handlers.dragend = view => {
|
|
@@ -623,31 +640,32 @@ handlers.dragend = view => {
|
|
|
623
640
|
|
|
624
641
|
editHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault()
|
|
625
642
|
|
|
626
|
-
editHandlers.drop = (view,
|
|
643
|
+
editHandlers.drop = (view, _event) => {
|
|
644
|
+
let event = _event as DragEvent
|
|
627
645
|
let dragging = view.dragging
|
|
628
646
|
view.dragging = null
|
|
629
647
|
|
|
630
|
-
if (!
|
|
648
|
+
if (!event.dataTransfer) return
|
|
631
649
|
|
|
632
|
-
let eventPos = view.posAtCoords(eventCoords(
|
|
650
|
+
let eventPos = view.posAtCoords(eventCoords(event))
|
|
633
651
|
if (!eventPos) return
|
|
634
652
|
let $mouse = view.state.doc.resolve(eventPos.pos)
|
|
635
653
|
if (!$mouse) return
|
|
636
654
|
let slice = dragging && dragging.slice
|
|
637
655
|
if (slice) {
|
|
638
|
-
view.someProp("transformPasted", f => { slice = f(slice) })
|
|
656
|
+
view.someProp("transformPasted", f => { slice = f(slice!) })
|
|
639
657
|
} else {
|
|
640
|
-
slice = parseFromClipboard(view,
|
|
641
|
-
brokenClipboardAPI ? null :
|
|
658
|
+
slice = parseFromClipboard(view, event.dataTransfer.getData(brokenClipboardAPI ? "Text" : "text/plain"),
|
|
659
|
+
brokenClipboardAPI ? null : event.dataTransfer.getData("text/html"), false, $mouse)
|
|
642
660
|
}
|
|
643
|
-
let move = dragging && !
|
|
644
|
-
if (view.someProp("handleDrop", f => f(view,
|
|
645
|
-
|
|
661
|
+
let move = !!(dragging && !event[dragCopyModifier])
|
|
662
|
+
if (view.someProp("handleDrop", f => f(view, event, slice || Slice.empty, move))) {
|
|
663
|
+
event.preventDefault()
|
|
646
664
|
return
|
|
647
665
|
}
|
|
648
666
|
if (!slice) return
|
|
649
667
|
|
|
650
|
-
|
|
668
|
+
event.preventDefault()
|
|
651
669
|
let insertPos = slice ? dropPoint(view.state.doc, $mouse.pos, slice) : $mouse.pos
|
|
652
670
|
if (insertPos == null) insertPos = $mouse.pos
|
|
653
671
|
|
|
@@ -658,14 +676,14 @@ editHandlers.drop = (view, e) => {
|
|
|
658
676
|
let isNode = slice.openStart == 0 && slice.openEnd == 0 && slice.content.childCount == 1
|
|
659
677
|
let beforeInsert = tr.doc
|
|
660
678
|
if (isNode)
|
|
661
|
-
tr.replaceRangeWith(pos, pos, slice.content.firstChild)
|
|
679
|
+
tr.replaceRangeWith(pos, pos, slice.content.firstChild!)
|
|
662
680
|
else
|
|
663
681
|
tr.replaceRange(pos, pos, slice)
|
|
664
682
|
if (tr.doc.eq(beforeInsert)) return
|
|
665
683
|
|
|
666
684
|
let $pos = tr.doc.resolve(pos)
|
|
667
|
-
if (isNode && NodeSelection.isSelectable(slice.content.firstChild) &&
|
|
668
|
-
$pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild)) {
|
|
685
|
+
if (isNode && NodeSelection.isSelectable(slice.content.firstChild!) &&
|
|
686
|
+
$pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild!)) {
|
|
669
687
|
tr.setSelection(new NodeSelection($pos))
|
|
670
688
|
} else {
|
|
671
689
|
let end = tr.mapping.map(insertPos)
|
|
@@ -683,24 +701,26 @@ handlers.focus = view => {
|
|
|
683
701
|
view.domObserver.start()
|
|
684
702
|
view.focused = true
|
|
685
703
|
setTimeout(() => {
|
|
686
|
-
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.
|
|
704
|
+
if (view.docView && view.hasFocus() && !view.domObserver.currentSelection.eq(view.domSelection()))
|
|
687
705
|
selectionToDOM(view)
|
|
688
706
|
}, 20)
|
|
689
707
|
}
|
|
690
708
|
}
|
|
691
709
|
|
|
692
|
-
handlers.blur = (view,
|
|
710
|
+
handlers.blur = (view, _event) => {
|
|
711
|
+
let event = _event as FocusEvent
|
|
693
712
|
if (view.focused) {
|
|
694
713
|
view.domObserver.stop()
|
|
695
714
|
view.dom.classList.remove("ProseMirror-focused")
|
|
696
715
|
view.domObserver.start()
|
|
697
|
-
if (
|
|
698
|
-
view.domObserver.currentSelection.
|
|
716
|
+
if (event.relatedTarget && view.dom.contains(event.relatedTarget as HTMLElement))
|
|
717
|
+
view.domObserver.currentSelection.clear()
|
|
699
718
|
view.focused = false
|
|
700
719
|
}
|
|
701
720
|
}
|
|
702
721
|
|
|
703
|
-
handlers.beforeinput = (view,
|
|
722
|
+
handlers.beforeinput = (view, _event: Event) => {
|
|
723
|
+
let event = _event as InputEvent
|
|
704
724
|
// We should probably do more with beforeinput events, but support
|
|
705
725
|
// is so spotty that I'm still waiting to see where they are going.
|
|
706
726
|
|
|
@@ -708,14 +728,14 @@ handlers.beforeinput = (view, event) => {
|
|
|
708
728
|
// Chrome Android when after an uneditable node.
|
|
709
729
|
if (browser.chrome && browser.android && event.inputType == "deleteContentBackward") {
|
|
710
730
|
view.domObserver.flushSoon()
|
|
711
|
-
let {domChangeCount} = view
|
|
731
|
+
let {domChangeCount} = view.input
|
|
712
732
|
setTimeout(() => {
|
|
713
|
-
if (view.domChangeCount != domChangeCount) return // Event already had some effect
|
|
733
|
+
if (view.input.domChangeCount != domChangeCount) return // Event already had some effect
|
|
714
734
|
// This bug tends to close the virtual keyboard, so we refocus
|
|
715
735
|
view.dom.blur()
|
|
716
736
|
view.focus()
|
|
717
737
|
if (view.someProp("handleKeyDown", f => f(view, keyEvent(8, "Backspace")))) return
|
|
718
|
-
let {$cursor} = view.state.selection
|
|
738
|
+
let {$cursor} = view.state.selection as TextSelection
|
|
719
739
|
// Crude approximation of backspace behavior when no command handled it
|
|
720
740
|
if ($cursor && $cursor.pos > 0) view.dispatch(view.state.tr.delete($cursor.pos - 1, $cursor.pos).scrollIntoView())
|
|
721
741
|
}, 50)
|