prosemirror-view 0.20.1 → 0.20.5
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/browser.js +1 -0
- package/dist/capturekeys.js +2 -6
- package/dist/clipboard.js +1 -3
- package/dist/dom.js +3 -1
- package/dist/domcoords.js +6 -3
- package/dist/input.js +7 -5
- package/dist/selection.js +3 -3
- package/dist/viewdesc.js +5 -1
- package/package.json +1 -1
- package/src/browser.js +1 -0
- package/src/capturekeys.js +2 -6
- package/src/clipboard.js +1 -3
- package/src/dom.js +3 -1
- package/src/domcoords.js +6 -3
- package/src/input.js +7 -5
- package/src/selection.js +3 -3
- package/src/viewdesc.js +5 -1
- package/src/#input.js# +0 -532
package/dist/browser.js
CHANGED
|
@@ -9,6 +9,7 @@ if (typeof navigator != "undefined") {
|
|
|
9
9
|
var ie = result.ie = !!(ie_upto10 || ie_11up || ie_edge)
|
|
10
10
|
result.ie_version = ie_upto10 ? document.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : null
|
|
11
11
|
result.gecko = !ie && /gecko\/\d/i.test(navigator.userAgent)
|
|
12
|
+
result.chrome = !ie && /Chrome\//.test(navigator.userAgent)
|
|
12
13
|
result.ios = !ie && /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)
|
|
13
14
|
result.webkit = !ie && 'WebkitAppearance' in document.documentElement.style
|
|
14
15
|
}
|
package/dist/capturekeys.js
CHANGED
|
@@ -209,9 +209,9 @@ function getMods(event) {
|
|
|
209
209
|
|
|
210
210
|
function captureKeyDown(view, event) {
|
|
211
211
|
var code = event.keyCode, mods = getMods(event)
|
|
212
|
-
if (code == 8) { // Backspace
|
|
212
|
+
if (code == 8 || (browser.mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
|
|
213
213
|
return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodesLeft(view)
|
|
214
|
-
} else if (code == 46) { // Delete
|
|
214
|
+
} else if (code == 46 || (browser.mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
|
|
215
215
|
return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodesRight(view)
|
|
216
216
|
} else if (code == 13 || code == 27) { // Enter, Esc
|
|
217
217
|
return true
|
|
@@ -226,10 +226,6 @@ function captureKeyDown(view, event) {
|
|
|
226
226
|
} else if (mods == (browser.mac ? "m" : "c") &&
|
|
227
227
|
(code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
|
|
228
228
|
return true
|
|
229
|
-
} else if (browser.mac && // Ctrl-[dh] and Alt-d on Mac
|
|
230
|
-
((code == 68 || code == 72) && mods == "c") ||
|
|
231
|
-
(code == 68 && mods == "a")) {
|
|
232
|
-
return stopNativeHorizontalDelete(view, code == 68 ? 1 : -1) || skipIgnoredNodesRight(view)
|
|
233
229
|
}
|
|
234
230
|
return false
|
|
235
231
|
}
|
package/dist/clipboard.js
CHANGED
|
@@ -4,8 +4,6 @@ var Fragment = ref.Fragment;
|
|
|
4
4
|
var DOMParser = ref.DOMParser;
|
|
5
5
|
var DOMSerializer = ref.DOMSerializer;
|
|
6
6
|
|
|
7
|
-
var browser = require("./browser")
|
|
8
|
-
|
|
9
7
|
function serializeForClipboard(view, slice) {
|
|
10
8
|
var context = [];
|
|
11
9
|
var content = slice.content;
|
|
@@ -35,7 +33,7 @@ exports.serializeForClipboard = serializeForClipboard
|
|
|
35
33
|
// Read a slice of content from the clipboard (or drop data).
|
|
36
34
|
function parseFromClipboard(view, text, html, plainText, $context) {
|
|
37
35
|
var dom, inCode = $context.parent.type.spec.code
|
|
38
|
-
if (!html &&
|
|
36
|
+
if (!html && !text) { return null }
|
|
39
37
|
if ((plainText || inCode || !html) && text) {
|
|
40
38
|
view.someProp("transformPastedText", function (f) { return text = f(text); })
|
|
41
39
|
if (inCode) { return new Slice(Fragment.from(view.state.schema.text(text)), 0, 0) }
|
package/dist/dom.js
CHANGED
|
@@ -27,12 +27,14 @@ exports.isEquivalentPosition = function(node, off, targetNode, targetOff) {
|
|
|
27
27
|
scanFor(node, off, targetNode, targetOff, 1))
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
var atomElements = /^(img|br|input|textarea|hr)$/i
|
|
31
|
+
|
|
30
32
|
function scanFor(node, off, targetNode, targetOff, dir) {
|
|
31
33
|
for (;;) {
|
|
32
34
|
if (node == targetNode && off == targetOff) { return true }
|
|
33
35
|
if (off == (dir < 0 ? 0 : nodeSize(node))) {
|
|
34
36
|
var parent = node.parentNode
|
|
35
|
-
if (parent.nodeType != 1 || hasBlockDesc(
|
|
37
|
+
if (parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName)) { return false }
|
|
36
38
|
off = domIndex(node) + (dir < 0 ? 0 : 1)
|
|
37
39
|
node = parent
|
|
38
40
|
} else if (node.nodeType == 1) {
|
package/dist/domcoords.js
CHANGED
|
@@ -197,10 +197,13 @@ function posAtCoords(view, coords) {
|
|
|
197
197
|
((assign$1 = range, node = assign$1.startContainer, offset = assign$1.startOffset)) }
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
var elt = root.elementFromPoint(coords.left, coords.top + 1)
|
|
200
|
+
var elt = root.elementFromPoint(coords.left, coords.top + 1), pos
|
|
201
201
|
if (!elt) { return null }
|
|
202
|
-
|
|
203
|
-
if (pos == null) {
|
|
202
|
+
if (node) { pos = posFromCaret(view, node, offset, coords) }
|
|
203
|
+
if (pos == null) {
|
|
204
|
+
pos = posFromElement(view, elt, coords)
|
|
205
|
+
if (pos == null) { return null }
|
|
206
|
+
}
|
|
204
207
|
|
|
205
208
|
var desc = view.docView.nearestDesc(elt, true)
|
|
206
209
|
return {pos: pos, inside: desc ? desc.posAtStart - desc.border : -1}
|
package/dist/input.js
CHANGED
|
@@ -419,14 +419,16 @@ function sliceSingleNode(slice) {
|
|
|
419
419
|
}
|
|
420
420
|
|
|
421
421
|
function capturePaste(view, e) {
|
|
422
|
-
var
|
|
422
|
+
var plainText = view.shiftKey || view.state.selection.$from.parent.type.spec.code
|
|
423
|
+
var target = document.body.appendChild(document.createElement(plainText ? "textarea" : "div"))
|
|
424
|
+
if (!plainText) { target.contentEditable = "true" }
|
|
423
425
|
target.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
424
|
-
target.contentEditable = "true"
|
|
425
426
|
target.focus()
|
|
426
427
|
setTimeout(function () {
|
|
427
428
|
view.focus()
|
|
428
429
|
document.body.removeChild(target)
|
|
429
|
-
doPaste(view, target.
|
|
430
|
+
if (plainText) { doPaste(view, target.value, null, e) }
|
|
431
|
+
else { doPaste(view, target.textContent, target.innerHTML, e) }
|
|
430
432
|
}, 50)
|
|
431
433
|
}
|
|
432
434
|
|
|
@@ -484,8 +486,8 @@ handlers.dragstart = function (view, e) {
|
|
|
484
486
|
}
|
|
485
487
|
var slice = view.state.selection.content(), dom = serializeForClipboard(view, slice)
|
|
486
488
|
e.dataTransfer.clearData()
|
|
487
|
-
e.
|
|
488
|
-
e.
|
|
489
|
+
e.dataTransfer.setData("text/html", dom.innerHTML)
|
|
490
|
+
e.dataTransfer.setData("text/plain", slice.content.textBetween(0, slice.content.size, "\n\n"))
|
|
489
491
|
view.dragging = new Dragging(slice, !e.ctrlKey)
|
|
490
492
|
}
|
|
491
493
|
|
package/dist/selection.js
CHANGED
|
@@ -75,8 +75,8 @@ SelectionReader.prototype.readFromDOM = function (origin) {
|
|
|
75
75
|
if (selectionCollapsed(domSel)) {
|
|
76
76
|
$anchor = $head
|
|
77
77
|
while (nearestDesc && !nearestDesc.node) { nearestDesc = nearestDesc.parent }
|
|
78
|
-
if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node)) {
|
|
79
|
-
var pos = nearestDesc.
|
|
78
|
+
if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) && nearestDesc.parent) {
|
|
79
|
+
var pos = nearestDesc.posBefore
|
|
80
80
|
selection = new NodeSelection(head == pos ? $head : doc.resolve(pos))
|
|
81
81
|
}
|
|
82
82
|
} else {
|
|
@@ -287,5 +287,5 @@ exports.selectionBetween = selectionBetween
|
|
|
287
287
|
function hasFocusAndSelection(view) {
|
|
288
288
|
if (view.editable && view.root.activeElement != view.dom) { return false }
|
|
289
289
|
var sel = view.root.getSelection()
|
|
290
|
-
return sel.
|
|
290
|
+
return sel.anchorNode && view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode)
|
|
291
291
|
}
|
package/dist/viewdesc.js
CHANGED
|
@@ -282,6 +282,9 @@ ViewDesc.prototype.parseRange = function (from, to, base) {
|
|
|
282
282
|
var this$1 = this;
|
|
283
283
|
if ( base === void 0 ) base = 0;
|
|
284
284
|
|
|
285
|
+
if (this.children.length == 0)
|
|
286
|
+
{ return {node: this.contentDOM, from: from, to: to, fromOffset: 0, toOffset: this.contentDOM.childNodes.length} }
|
|
287
|
+
|
|
285
288
|
var fromOffset = -1, toOffset = -1
|
|
286
289
|
for (var offset = 0, i = 0;; i++) {
|
|
287
290
|
var child = this$1.children[i], end = offset + child.size
|
|
@@ -703,7 +706,8 @@ var TextViewDesc = (function (NodeViewDesc) {
|
|
|
703
706
|
TextViewDesc.prototype.constructor = TextViewDesc;
|
|
704
707
|
|
|
705
708
|
TextViewDesc.prototype.parseRule = function () {
|
|
706
|
-
|
|
709
|
+
var parent = this.nodeDOM.parentNode
|
|
710
|
+
return parent ? {skip: parent} : {ignore: true}
|
|
707
711
|
};
|
|
708
712
|
|
|
709
713
|
TextViewDesc.prototype.update = function (node, outerDeco) {
|
package/package.json
CHANGED
package/src/browser.js
CHANGED
|
@@ -9,6 +9,7 @@ if (typeof navigator != "undefined") {
|
|
|
9
9
|
let ie = result.ie = !!(ie_upto10 || ie_11up || ie_edge)
|
|
10
10
|
result.ie_version = ie_upto10 ? document.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : null
|
|
11
11
|
result.gecko = !ie && /gecko\/\d/i.test(navigator.userAgent)
|
|
12
|
+
result.chrome = !ie && /Chrome\//.test(navigator.userAgent)
|
|
12
13
|
result.ios = !ie && /AppleWebKit/.test(navigator.userAgent) && /Mobile\/\w+/.test(navigator.userAgent)
|
|
13
14
|
result.webkit = !ie && 'WebkitAppearance' in document.documentElement.style
|
|
14
15
|
}
|
package/src/capturekeys.js
CHANGED
|
@@ -199,9 +199,9 @@ function getMods(event) {
|
|
|
199
199
|
|
|
200
200
|
function captureKeyDown(view, event) {
|
|
201
201
|
let code = event.keyCode, mods = getMods(event)
|
|
202
|
-
if (code == 8) { // Backspace
|
|
202
|
+
if (code == 8 || (browser.mac && code == 72 && mods == "c")) { // Backspace, Ctrl-h on Mac
|
|
203
203
|
return stopNativeHorizontalDelete(view, -1) || skipIgnoredNodesLeft(view)
|
|
204
|
-
} else if (code == 46) { // Delete
|
|
204
|
+
} else if (code == 46 || (browser.mac && code == 68 && mods == "c")) { // Delete, Ctrl-d on Mac
|
|
205
205
|
return stopNativeHorizontalDelete(view, 1) || skipIgnoredNodesRight(view)
|
|
206
206
|
} else if (code == 13 || code == 27) { // Enter, Esc
|
|
207
207
|
return true
|
|
@@ -216,10 +216,6 @@ function captureKeyDown(view, event) {
|
|
|
216
216
|
} else if (mods == (browser.mac ? "m" : "c") &&
|
|
217
217
|
(code == 66 || code == 73 || code == 89 || code == 90)) { // Mod-[biyz]
|
|
218
218
|
return true
|
|
219
|
-
} else if (browser.mac && // Ctrl-[dh] and Alt-d on Mac
|
|
220
|
-
((code == 68 || code == 72) && mods == "c") ||
|
|
221
|
-
(code == 68 && mods == "a")) {
|
|
222
|
-
return stopNativeHorizontalDelete(view, code == 68 ? 1 : -1) || skipIgnoredNodesRight(view)
|
|
223
219
|
}
|
|
224
220
|
return false
|
|
225
221
|
}
|
package/src/clipboard.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
const {Slice, Fragment, DOMParser, DOMSerializer} = require("prosemirror-model")
|
|
2
2
|
|
|
3
|
-
const browser = require("./browser")
|
|
4
|
-
|
|
5
3
|
function serializeForClipboard(view, slice) {
|
|
6
4
|
let context = [], {content, openLeft, openRight} = slice
|
|
7
5
|
while (openLeft > 1 && openRight > 1 && content.childCount == 1 && content.firstChild.childCount == 1) {
|
|
@@ -28,7 +26,7 @@ exports.serializeForClipboard = serializeForClipboard
|
|
|
28
26
|
// Read a slice of content from the clipboard (or drop data).
|
|
29
27
|
function parseFromClipboard(view, text, html, plainText, $context) {
|
|
30
28
|
let dom, inCode = $context.parent.type.spec.code
|
|
31
|
-
if (!html &&
|
|
29
|
+
if (!html && !text) return null
|
|
32
30
|
if ((plainText || inCode || !html) && text) {
|
|
33
31
|
view.someProp("transformPastedText", f => text = f(text))
|
|
34
32
|
if (inCode) return new Slice(Fragment.from(view.state.schema.text(text)), 0, 0)
|
package/src/dom.js
CHANGED
|
@@ -27,12 +27,14 @@ exports.isEquivalentPosition = function(node, off, targetNode, targetOff) {
|
|
|
27
27
|
scanFor(node, off, targetNode, targetOff, 1))
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
const atomElements = /^(img|br|input|textarea|hr)$/i
|
|
31
|
+
|
|
30
32
|
function scanFor(node, off, targetNode, targetOff, dir) {
|
|
31
33
|
for (;;) {
|
|
32
34
|
if (node == targetNode && off == targetOff) return true
|
|
33
35
|
if (off == (dir < 0 ? 0 : nodeSize(node))) {
|
|
34
36
|
let parent = node.parentNode
|
|
35
|
-
if (parent.nodeType != 1 || hasBlockDesc(
|
|
37
|
+
if (parent.nodeType != 1 || hasBlockDesc(node) || atomElements.test(node.nodeName)) return false
|
|
36
38
|
off = domIndex(node) + (dir < 0 ? 0 : 1)
|
|
37
39
|
node = parent
|
|
38
40
|
} else if (node.nodeType == 1) {
|
package/src/domcoords.js
CHANGED
|
@@ -183,10 +183,13 @@ function posAtCoords(view, coords) {
|
|
|
183
183
|
if (range) ({startContainer: node, startOffset: offset} = range)
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
let elt = root.elementFromPoint(coords.left, coords.top + 1)
|
|
186
|
+
let elt = root.elementFromPoint(coords.left, coords.top + 1), pos
|
|
187
187
|
if (!elt) return null
|
|
188
|
-
|
|
189
|
-
if (pos == null)
|
|
188
|
+
if (node) pos = posFromCaret(view, node, offset, coords)
|
|
189
|
+
if (pos == null) {
|
|
190
|
+
pos = posFromElement(view, elt, coords)
|
|
191
|
+
if (pos == null) return null
|
|
192
|
+
}
|
|
190
193
|
|
|
191
194
|
let desc = view.docView.nearestDesc(elt, true)
|
|
192
195
|
return {pos, inside: desc ? desc.posAtStart - desc.border : -1}
|
package/src/input.js
CHANGED
|
@@ -402,14 +402,16 @@ function sliceSingleNode(slice) {
|
|
|
402
402
|
}
|
|
403
403
|
|
|
404
404
|
function capturePaste(view, e) {
|
|
405
|
-
let
|
|
405
|
+
let plainText = view.shiftKey || view.state.selection.$from.parent.type.spec.code
|
|
406
|
+
let target = document.body.appendChild(document.createElement(plainText ? "textarea" : "div"))
|
|
407
|
+
if (!plainText) target.contentEditable = "true"
|
|
406
408
|
target.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
407
|
-
target.contentEditable = "true"
|
|
408
409
|
target.focus()
|
|
409
410
|
setTimeout(() => {
|
|
410
411
|
view.focus()
|
|
411
412
|
document.body.removeChild(target)
|
|
412
|
-
doPaste(view, target.
|
|
413
|
+
if (plainText) doPaste(view, target.value, null, e)
|
|
414
|
+
else doPaste(view, target.textContent, target.innerHTML, e)
|
|
413
415
|
}, 50)
|
|
414
416
|
}
|
|
415
417
|
|
|
@@ -469,8 +471,8 @@ handlers.dragstart = (view, e) => {
|
|
|
469
471
|
}
|
|
470
472
|
let slice = view.state.selection.content(), dom = serializeForClipboard(view, slice)
|
|
471
473
|
e.dataTransfer.clearData()
|
|
472
|
-
e.
|
|
473
|
-
e.
|
|
474
|
+
e.dataTransfer.setData("text/html", dom.innerHTML)
|
|
475
|
+
e.dataTransfer.setData("text/plain", slice.content.textBetween(0, slice.content.size, "\n\n"))
|
|
474
476
|
view.dragging = new Dragging(slice, !e.ctrlKey)
|
|
475
477
|
}
|
|
476
478
|
|
package/src/selection.js
CHANGED
|
@@ -71,8 +71,8 @@ class SelectionReader {
|
|
|
71
71
|
if (selectionCollapsed(domSel)) {
|
|
72
72
|
$anchor = $head
|
|
73
73
|
while (nearestDesc && !nearestDesc.node) nearestDesc = nearestDesc.parent
|
|
74
|
-
if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node)) {
|
|
75
|
-
let pos = nearestDesc.
|
|
74
|
+
if (nearestDesc && nearestDesc.node.isAtom && NodeSelection.isSelectable(nearestDesc.node) && nearestDesc.parent) {
|
|
75
|
+
let pos = nearestDesc.posBefore
|
|
76
76
|
selection = new NodeSelection(head == pos ? $head : doc.resolve(pos))
|
|
77
77
|
}
|
|
78
78
|
} else {
|
|
@@ -282,5 +282,5 @@ exports.selectionBetween = selectionBetween
|
|
|
282
282
|
function hasFocusAndSelection(view) {
|
|
283
283
|
if (view.editable && view.root.activeElement != view.dom) return false
|
|
284
284
|
let sel = view.root.getSelection()
|
|
285
|
-
return sel.
|
|
285
|
+
return sel.anchorNode && view.dom.contains(sel.anchorNode.nodeType == 3 ? sel.anchorNode.parentNode : sel.anchorNode)
|
|
286
286
|
}
|
package/src/viewdesc.js
CHANGED
|
@@ -257,6 +257,9 @@ class ViewDesc {
|
|
|
257
257
|
// Used to find a DOM range in a single parent for a given changed
|
|
258
258
|
// range.
|
|
259
259
|
parseRange(from, to, base = 0) {
|
|
260
|
+
if (this.children.length == 0)
|
|
261
|
+
return {node: this.contentDOM, from, to, fromOffset: 0, toOffset: this.contentDOM.childNodes.length}
|
|
262
|
+
|
|
260
263
|
let fromOffset = -1, toOffset = -1
|
|
261
264
|
for (let offset = 0, i = 0;; i++) {
|
|
262
265
|
let child = this.children[i], end = offset + child.size
|
|
@@ -633,7 +636,8 @@ class TextViewDesc extends NodeViewDesc {
|
|
|
633
636
|
}
|
|
634
637
|
|
|
635
638
|
parseRule() {
|
|
636
|
-
|
|
639
|
+
let parent = this.nodeDOM.parentNode
|
|
640
|
+
return parent ? {skip: parent} : {ignore: true}
|
|
637
641
|
}
|
|
638
642
|
|
|
639
643
|
update(node, outerDeco) {
|
package/src/#input.js#
DELETED
|
@@ -1,532 +0,0 @@
|
|
|
1
|
-
const {Selection, NodeSelection, TextSelection} = require("prosemirror-state")
|
|
2
|
-
|
|
3
|
-
const browser = require("./browser")
|
|
4
|
-
const {captureKeyDown} = require("./capturekeys")
|
|
5
|
-
const {DOMChange} = require("./domchange")
|
|
6
|
-
const {parseFromClipboard, serializeForClipboard} = require("./clipboard")
|
|
7
|
-
const {DOMObserver} = require("./domobserver")
|
|
8
|
-
const {selectionBetween} = require("./selection")
|
|
9
|
-
|
|
10
|
-
// A collection of DOM events that occur within the editor, and callback functions
|
|
11
|
-
// to invoke when the event fires.
|
|
12
|
-
const handlers = {}, editHandlers = {}
|
|
13
|
-
|
|
14
|
-
function initInput(view) {
|
|
15
|
-
view.shiftKey = false
|
|
16
|
-
view.mouseDown = null
|
|
17
|
-
view.dragging = null
|
|
18
|
-
view.inDOMChange = null
|
|
19
|
-
view.domObserver = new DOMObserver(view)
|
|
20
|
-
view.domObserver.start()
|
|
21
|
-
|
|
22
|
-
for (let event in handlers) {
|
|
23
|
-
let handler = handlers[event]
|
|
24
|
-
view.dom.addEventListener(event, event => {
|
|
25
|
-
if (eventBelongsToView(view, event) && !runCustomHandler(view, event) &&
|
|
26
|
-
(view.editable || !(event.type in editHandlers)))
|
|
27
|
-
handler(view, event)
|
|
28
|
-
})
|
|
29
|
-
}
|
|
30
|
-
view.extraHandlers = Object.create(null)
|
|
31
|
-
ensureListeners(view)
|
|
32
|
-
}
|
|
33
|
-
exports.initInput = initInput
|
|
34
|
-
|
|
35
|
-
function destroyInput(view) {
|
|
36
|
-
view.domObserver.stop()
|
|
37
|
-
if (view.inDOMChange) view.inDOMChange.destroy()
|
|
38
|
-
}
|
|
39
|
-
exports.destroyInput = destroyInput
|
|
40
|
-
|
|
41
|
-
function ensureListeners(view) {
|
|
42
|
-
view.someProp("handleDOMEvents", currentHandlers => {
|
|
43
|
-
for (let type in currentHandlers) if (!view.extraHandlers[type] && !handlers.hasOwnProperty(type)) {
|
|
44
|
-
view.extraHandlers[type] = true
|
|
45
|
-
view.dom.addEventListener(type, event => runCustomHandler(view, event))
|
|
46
|
-
}
|
|
47
|
-
})
|
|
48
|
-
}
|
|
49
|
-
exports.ensureListeners = ensureListeners
|
|
50
|
-
|
|
51
|
-
function runCustomHandler(view, event) {
|
|
52
|
-
return view.someProp("handleDOMEvents", handlers => {
|
|
53
|
-
let handler = handlers[event.type]
|
|
54
|
-
return handler ? handler(view, event) || event.defaultPrevented : false
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function eventBelongsToView(view, event) {
|
|
59
|
-
if (!event.bubbles) return true
|
|
60
|
-
if (event.defaultPrevented) return false
|
|
61
|
-
for (let node = event.target; node != view.dom; node = node.parentNode)
|
|
62
|
-
if (!node || node.nodeType == 11 ||
|
|
63
|
-
(node.pmViewDesc && node.pmViewDesc.stopEvent(event)))
|
|
64
|
-
return false
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
function dispatchEvent(view, event) {
|
|
69
|
-
if (!runCustomHandler(view, event) && handlers[event.type] &&
|
|
70
|
-
(view.editable || !(event.type in editHandlers)))
|
|
71
|
-
handlers[event.type](view, event)
|
|
72
|
-
}
|
|
73
|
-
exports.dispatchEvent = dispatchEvent
|
|
74
|
-
|
|
75
|
-
editHandlers.keydown = (view, event) => {
|
|
76
|
-
if (event.keyCode == 16) view.shiftKey = true
|
|
77
|
-
if (view.inDOMChange) return
|
|
78
|
-
if (view.someProp("handleKeyDown", f => f(view, event)) || captureKeyDown(view, event))
|
|
79
|
-
event.preventDefault()
|
|
80
|
-
else
|
|
81
|
-
view.selectionReader.poll()
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
editHandlers.keyup = (view, e) => {
|
|
85
|
-
if (e.keyCode == 16) view.shiftKey = false
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
editHandlers.keypress = (view, event) => {
|
|
89
|
-
if (view.inDOMChange || !event.charCode ||
|
|
90
|
-
event.ctrlKey && !event.altKey || browser.mac && event.metaKey) return
|
|
91
|
-
|
|
92
|
-
if (view.someProp("handleKeyPress", f => f(view, event))) {
|
|
93
|
-
event.preventDefault()
|
|
94
|
-
return
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let sel = view.state.selection
|
|
98
|
-
if (!(sel instanceof TextSelection) || !sel.$from.sameParent(sel.$to)) {
|
|
99
|
-
let text = String.fromCharCode(event.charCode)
|
|
100
|
-
if (!view.someProp("handleTextInput", f => f(view, sel.$from.pos, sel.$to.pos, text)))
|
|
101
|
-
view.dispatch(view.state.tr.insertText(text).scrollIntoView())
|
|
102
|
-
event.preventDefault()
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function eventCoords(event) { return {left: event.clientX, top: event.clientY} }
|
|
107
|
-
|
|
108
|
-
let lastClick = {time: 0, x: 0, y: 0}, oneButLastClick = lastClick
|
|
109
|
-
|
|
110
|
-
function isNear(event, click) {
|
|
111
|
-
let dx = click.x - event.clientX, dy = click.y - event.clientY
|
|
112
|
-
return dx * dx + dy * dy < 100
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function runHandlerOnContext(view, propName, pos, inside, event) {
|
|
116
|
-
if (inside == -1) return false
|
|
117
|
-
let $pos = view.state.doc.resolve(inside)
|
|
118
|
-
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
119
|
-
if (view.someProp(propName, f => i > $pos.depth ? f(view, pos, $pos.nodeAfter, $pos.before(i), event, true)
|
|
120
|
-
: f(view, pos, $pos.node(i), $pos.before(i), event, false)))
|
|
121
|
-
return true
|
|
122
|
-
}
|
|
123
|
-
return false
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function updateSelection(view, selection, origin) {
|
|
127
|
-
if (!view.focused) view.focus()
|
|
128
|
-
let tr = view.state.tr.setSelection(selection)
|
|
129
|
-
if (origin == "pointer") tr.setMeta("pointer", true)
|
|
130
|
-
view.dispatch(tr)
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
function selectClickedLeaf(view, inside) {
|
|
134
|
-
if (inside == -1) return false
|
|
135
|
-
let $pos = view.state.doc.resolve(inside), node = $pos.nodeAfter
|
|
136
|
-
if (node && node.isAtom && NodeSelection.isSelectable(node)) {
|
|
137
|
-
updateSelection(view, new NodeSelection($pos), "pointer")
|
|
138
|
-
return true
|
|
139
|
-
}
|
|
140
|
-
return false
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function selectClickedNode(view, inside) {
|
|
144
|
-
if (inside == -1) return false
|
|
145
|
-
let sel = view.state.selection, selectedNode, selectAt
|
|
146
|
-
if (sel instanceof NodeSelection) selectedNode = sel.node
|
|
147
|
-
|
|
148
|
-
let $pos = view.state.doc.resolve(inside)
|
|
149
|
-
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
150
|
-
let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i)
|
|
151
|
-
if (NodeSelection.isSelectable(node)) {
|
|
152
|
-
if (selectedNode && sel.$from.depth > 0 &&
|
|
153
|
-
i >= sel.$from.depth && $pos.before(sel.$from.depth + 1) == sel.$from.pos)
|
|
154
|
-
selectAt = $pos.before(sel.$from.depth)
|
|
155
|
-
else
|
|
156
|
-
selectAt = $pos.before(i)
|
|
157
|
-
break
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (selectAt != null) {
|
|
162
|
-
updateSelection(view, NodeSelection.create(view.state.doc, selectAt), "pointer")
|
|
163
|
-
return true
|
|
164
|
-
} else {
|
|
165
|
-
return false
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
function handleSingleClick(view, pos, inside, event, selectNode) {
|
|
170
|
-
return runHandlerOnContext(view, "handleClickOn", pos, inside, event) ||
|
|
171
|
-
view.someProp("handleClick", f => f(view, pos, event)) ||
|
|
172
|
-
(selectNode ? selectClickedNode(view, inside) : selectClickedLeaf(view, inside))
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
function handleDoubleClick(view, pos, inside, event) {
|
|
176
|
-
return runHandlerOnContext(view, "handleDoubleClickOn", pos, inside, event) ||
|
|
177
|
-
view.someProp("handleDoubleClick", f => f(view, pos, event))
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
function handleTripleClick(view, pos, inside, event) {
|
|
181
|
-
return runHandlerOnContext(view, "handleTripleClickOn", pos, inside, event) ||
|
|
182
|
-
view.someProp("handleTripleClick", f => f(view, pos, event)) ||
|
|
183
|
-
defaultTripleClick(view, inside)
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
function defaultTripleClick(view, inside) {
|
|
187
|
-
let doc = view.state.doc
|
|
188
|
-
if (inside == -1) {
|
|
189
|
-
if (doc.inlineContent) {
|
|
190
|
-
updateSelection(view, TextSelection.create(doc, 0, doc.content.size), "pointer")
|
|
191
|
-
return true
|
|
192
|
-
}
|
|
193
|
-
return false
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
let $pos = doc.resolve(inside)
|
|
197
|
-
for (let i = $pos.depth + 1; i > 0; i--) {
|
|
198
|
-
let node = i > $pos.depth ? $pos.nodeAfter : $pos.node(i)
|
|
199
|
-
let nodePos = $pos.before(i)
|
|
200
|
-
if (node.inlineContent)
|
|
201
|
-
updateSelection(view, TextSelection.create(doc, nodePos + 1, nodePos + 1 + node.content.size), "pointer")
|
|
202
|
-
else if (NodeSelection.isSelectable(node))
|
|
203
|
-
updateSelection(view, NodeSelection.create(doc, nodePos), "pointer")
|
|
204
|
-
else
|
|
205
|
-
continue
|
|
206
|
-
return true
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function forceDOMFlush(view) {
|
|
211
|
-
if (!view.inDOMChange) return false
|
|
212
|
-
view.inDOMChange.finish(true)
|
|
213
|
-
return true
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
const selectNodeModifier = browser.mac ? "metaKey" : "ctrlKey"
|
|
217
|
-
|
|
218
|
-
handlers.mousedown = (view, event) => {
|
|
219
|
-
let flushed = forceDOMFlush(view)
|
|
220
|
-
let now = Date.now(), type
|
|
221
|
-
if (now - lastClick.time >= 500 || !isNear(event, lastClick) || event[selectNodeModifier]) type = "singleClick"
|
|
222
|
-
else if (now - oneButLastClick.time >= 600 || !isNear(event, oneButLastClick)) type = "doubleClick"
|
|
223
|
-
else type = "tripleClick"
|
|
224
|
-
oneButLastClick = lastClick
|
|
225
|
-
lastClick = {time: now, x: event.clientX, y: event.clientY}
|
|
226
|
-
|
|
227
|
-
let pos = view.posAtCoords(eventCoords(event))
|
|
228
|
-
if (!pos) return
|
|
229
|
-
|
|
230
|
-
if (type == "singleClick")
|
|
231
|
-
view.mouseDown = new MouseDown(view, pos, event, flushed)
|
|
232
|
-
else if ((type == "doubleClick" ? handleDoubleClick : handleTripleClick)(view, pos.pos, pos.inside, event))
|
|
233
|
-
event.preventDefault()
|
|
234
|
-
else
|
|
235
|
-
view.selectionReader.poll("pointer")
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
class MouseDown {
|
|
239
|
-
constructor(view, pos, event, flushed) {
|
|
240
|
-
this.view = view
|
|
241
|
-
this.pos = pos
|
|
242
|
-
this.event = event
|
|
243
|
-
this.flushed = flushed
|
|
244
|
-
this.selectNode = event[selectNodeModifier]
|
|
245
|
-
this.allowDefault = event.shiftKey
|
|
246
|
-
|
|
247
|
-
let targetNode, targetPos
|
|
248
|
-
if (pos.inside > -1) {
|
|
249
|
-
targetNode = view.state.doc.nodeAt(pos.inside)
|
|
250
|
-
targetPos = pos.inside
|
|
251
|
-
} else {
|
|
252
|
-
let $pos = view.state.doc.resolve(pos.pos)
|
|
253
|
-
targetNode = $pos.parent
|
|
254
|
-
targetPos = $pos.depth ? $pos.before() : 0
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
this.mightDrag = null
|
|
258
|
-
if (targetNode.type.spec.draggable && targetNode.type.spec.selectable !== false ||
|
|
259
|
-
view.state.selection instanceof NodeSelection && targetPos == view.state.selection.from)
|
|
260
|
-
this.mightDrag = {node: targetNode, pos: targetPos}
|
|
261
|
-
|
|
262
|
-
this.target = flushed ? null : event.target
|
|
263
|
-
if (this.target && this.mightDrag) {
|
|
264
|
-
this.view.domObserver.stop()
|
|
265
|
-
this.target.draggable = true
|
|
266
|
-
if (browser.gecko && (this.setContentEditable = !this.target.hasAttribute("contentEditable")))
|
|
267
|
-
setTimeout(() => this.target.setAttribute("contentEditable", "false"), 20)
|
|
268
|
-
this.view.domObserver.start()
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
view.root.addEventListener("mouseup", this.up = this.up.bind(this))
|
|
272
|
-
view.root.addEventListener("mousemove", this.move = this.move.bind(this))
|
|
273
|
-
view.selectionReader.poll("pointer")
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
done() {
|
|
277
|
-
this.view.root.removeEventListener("mouseup", this.up)
|
|
278
|
-
this.view.root.removeEventListener("mousemove", this.move)
|
|
279
|
-
if (this.mightDrag && this.target) {
|
|
280
|
-
this.view.domObserver.stop()
|
|
281
|
-
this.target.draggable = false
|
|
282
|
-
if (browser.gecko && this.setContentEditable)
|
|
283
|
-
this.target.removeAttribute("contentEditable")
|
|
284
|
-
this.view.domObserver.start()
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
up(event) {
|
|
289
|
-
this.done()
|
|
290
|
-
|
|
291
|
-
if (!this.view.dom.contains(event.target.nodeType == 3 ? event.target.parentNode : event.target))
|
|
292
|
-
return
|
|
293
|
-
|
|
294
|
-
if (this.allowDefault) {
|
|
295
|
-
this.view.selectionReader.poll("pointer")
|
|
296
|
-
} else if (handleSingleClick(this.view, this.pos.pos, this.pos.inside, event, this.selectNode)) {
|
|
297
|
-
event.preventDefault()
|
|
298
|
-
} else if (this.flushed) {
|
|
299
|
-
updateSelection(this.view, Selection.near(this.view.state.doc.resolve(this.pos.pos)), "pointer")
|
|
300
|
-
event.preventDefault()
|
|
301
|
-
} else {
|
|
302
|
-
this.view.selectionReader.poll("pointer")
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
move(event) {
|
|
307
|
-
if (!this.allowDefault && (Math.abs(this.event.x - event.clientX) > 4 ||
|
|
308
|
-
Math.abs(this.event.y - event.clientY) > 4))
|
|
309
|
-
this.allowDefault = true
|
|
310
|
-
this.view.selectionReader.poll("pointer")
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
handlers.touchdown = view => {
|
|
315
|
-
forceDOMFlush(view)
|
|
316
|
-
view.selectionReader.poll("pointer")
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
handlers.contextmenu = (view, e) => {
|
|
320
|
-
forceDOMFlush(view)
|
|
321
|
-
let pos = view.posAtCoords(eventCoords(e))
|
|
322
|
-
if (pos && view.someProp("handleContextMenu", f => f(view, pos.pos, e)))
|
|
323
|
-
e.preventDefault()
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Input compositions are hard. Mostly because the events fired by
|
|
327
|
-
// browsers are A) very unpredictable and inconsistent, and B) not
|
|
328
|
-
// cancelable.
|
|
329
|
-
//
|
|
330
|
-
// ProseMirror has the problem that it must not update the DOM during
|
|
331
|
-
// a composition, or the browser will cancel it. What it does is keep
|
|
332
|
-
// long-running operations (delayed DOM updates) when a composition is
|
|
333
|
-
// active.
|
|
334
|
-
//
|
|
335
|
-
// We _do not_ trust the information in the composition events which,
|
|
336
|
-
// apart from being very uninformative to begin with, is often just
|
|
337
|
-
// plain wrong. Instead, when a composition ends, we parse the dom
|
|
338
|
-
// around the original selection, and derive an update from that.
|
|
339
|
-
|
|
340
|
-
editHandlers.compositionstart = editHandlers.compositionupdate = view => {
|
|
341
|
-
DOMChange.start(view, true)
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
editHandlers.compositionend = (view, e) => {
|
|
345
|
-
if (!view.inDOMChange) {
|
|
346
|
-
// We received a compositionend without having seen any previous
|
|
347
|
-
// events for the composition. If there's data in the event
|
|
348
|
-
// object, we assume that it's a real change, and start a
|
|
349
|
-
// composition. Otherwise, we just ignore it.
|
|
350
|
-
if (e.data) DOMChange.start(view, true)
|
|
351
|
-
else return
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
view.inDOMChange.compositionEnd()
|
|
355
|
-
}
|
|
356
|
-
|
|
357
|
-
editHandlers.input = view => DOMChange.start(view)
|
|
358
|
-
|
|
359
|
-
function captureCopy(view, dom) {
|
|
360
|
-
// The extra wrapper is somehow necessary on IE/Edge to prevent the
|
|
361
|
-
// content from being mangled when it is put onto the clipboard
|
|
362
|
-
let wrap = document.body.appendChild(document.createElement("div"))
|
|
363
|
-
wrap.appendChild(dom)
|
|
364
|
-
wrap.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
365
|
-
let sel = getSelection(), range = document.createRange()
|
|
366
|
-
range.selectNodeContents(dom)
|
|
367
|
-
sel.removeAllRanges()
|
|
368
|
-
sel.addRange(range)
|
|
369
|
-
setTimeout(() => {
|
|
370
|
-
document.body.removeChild(wrap)
|
|
371
|
-
view.focus()
|
|
372
|
-
}, 50)
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
// This is very crude, but unfortunately both these browsers _pretend_
|
|
376
|
-
// that they have a clipboard API---all the objects and methods are there
|
|
377
|
-
const brokenClipboardAPI = browser.ie || browser.ios
|
|
378
|
-
|
|
379
|
-
handlers.copy = editHandlers.cut = (view, e) => {
|
|
380
|
-
let sel = view.state.selection, cut = e.type == "cut"
|
|
381
|
-
if (sel.empty) return
|
|
382
|
-
|
|
383
|
-
// IE and Edge's clipboard interface is completely broken
|
|
384
|
-
let data = brokenClipboardAPI ? null : e.clipboardData
|
|
385
|
-
let slice = sel.content(), dom = serializeForClipboard(view, slice)
|
|
386
|
-
if (data) {
|
|
387
|
-
e.preventDefault()
|
|
388
|
-
data.clearData()
|
|
389
|
-
data.setData("text/html", dom.innerHTML)
|
|
390
|
-
data.setData("text/plain", slice.content.textBetween(0, slice.content.size, "\n\n"))
|
|
391
|
-
} else {
|
|
392
|
-
captureCopy(view, dom)
|
|
393
|
-
}
|
|
394
|
-
if (cut) view.dispatch(view.state.tr.deleteSelection().scrollIntoView())
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
function sliceSingleNode(slice) {
|
|
398
|
-
return slice.openLeft == 0 && slice.openRight == 0 && slice.content.childCount == 1 ? slice.content.firstChild : null
|
|
399
|
-
}
|
|
400
|
-
|
|
401
|
-
function capturePaste(view, e) {
|
|
402
|
-
let target = document.body.appendChild(document.createElement("div"))
|
|
403
|
-
target.style.cssText = "position: fixed; left: -10000px; top: 10px"
|
|
404
|
-
target.contentEditable = "true"
|
|
405
|
-
target.focus()
|
|
406
|
-
setTimeout(() => {
|
|
407
|
-
view.focus()
|
|
408
|
-
document.body.removeChild(target)
|
|
409
|
-
doPaste(view, target.textContent, target.innerHTML, e)
|
|
410
|
-
}, 50)
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
function doPaste(view, text, html, e) {
|
|
414
|
-
let slice = parseFromClipboard(view, text, html, view.shiftKey, view.state.selection.$from)
|
|
415
|
-
if (!slice) return false
|
|
416
|
-
|
|
417
|
-
if (view.someProp("handlePaste", f => f(view, e, slice))) return true
|
|
418
|
-
|
|
419
|
-
let singleNode = sliceSingleNode(slice)
|
|
420
|
-
let tr = singleNode ? view.state.tr.replaceSelectionWith(singleNode) : view.state.tr.replaceSelection(slice)
|
|
421
|
-
view.dispatch(tr.scrollIntoView())
|
|
422
|
-
return true
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
editHandlers.paste = (view, e) => {
|
|
426
|
-
let data = brokenClipboardAPI ? null : e.clipboardData
|
|
427
|
-
if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), e))
|
|
428
|
-
e.preventDefault()
|
|
429
|
-
else
|
|
430
|
-
capturePaste(view, e)
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
class Dragging {
|
|
434
|
-
constructor(slice, move) {
|
|
435
|
-
this.slice = slice
|
|
436
|
-
this.move = move
|
|
437
|
-
}
|
|
438
|
-
}
|
|
439
|
-
|
|
440
|
-
function dropPos(slice, $pos) {
|
|
441
|
-
if (!slice || !slice.content.size) return $pos.pos
|
|
442
|
-
let content = slice.content
|
|
443
|
-
for (let i = 0; i < slice.openLeft; i++) content = content.firstChild.content
|
|
444
|
-
for (let d = $pos.depth; d >= 0; d--) {
|
|
445
|
-
let bias = d == $pos.depth ? 0 : $pos.pos <= ($pos.start(d + 1) + $pos.end(d + 1)) / 2 ? -1 : 1
|
|
446
|
-
let insertPos = $pos.index(d) + (bias > 0 ? 1 : 0)
|
|
447
|
-
if ($pos.node(d).canReplace(insertPos, insertPos, content))
|
|
448
|
-
return bias == 0 ? $pos.pos : bias < 0 ? $pos.before(d + 1) : $pos.after(d + 1)
|
|
449
|
-
}
|
|
450
|
-
return $pos.pos
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
handlers.dragstart = (view, e) => {
|
|
454
|
-
let mouseDown = view.mouseDown
|
|
455
|
-
if (mouseDown) mouseDown.done()
|
|
456
|
-
if (!e.dataTransfer) return
|
|
457
|
-
|
|
458
|
-
let sel = view.state.selection
|
|
459
|
-
let pos = sel.empty ? null : view.posAtCoords(eventCoords(e))
|
|
460
|
-
if (pos && pos.pos >= sel.from && pos.pos <= sel.to) {
|
|
461
|
-
// In selection
|
|
462
|
-
} else if (mouseDown && mouseDown.mightDrag) {
|
|
463
|
-
view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)))
|
|
464
|
-
} else {
|
|
465
|
-
return
|
|
466
|
-
}
|
|
467
|
-
let slice = view.state.selection.content(), dom = serializeForClipboard(view, slice)
|
|
468
|
-
e.dataTransfer.clearData()
|
|
469
|
-
e.dataTranser.setData("text/html", dom.innerHTML)
|
|
470
|
-
e.dataTranser.setData("text/plain", slice.content.textBetween(0, slice.content.size, "\n\n"))
|
|
471
|
-
view.dragging = new Dragging(slice, !e.ctrlKey)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
handlers.dragend = view => {
|
|
475
|
-
window.setTimeout(() => view.dragging = null, 50)
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
editHandlers.dragover = editHandlers.dragenter = (_, e) => e.preventDefault()
|
|
479
|
-
|
|
480
|
-
editHandlers.drop = (view, e) => {
|
|
481
|
-
let dragging = view.dragging
|
|
482
|
-
view.dragging = null
|
|
483
|
-
|
|
484
|
-
if (!e.dataTransfer) return
|
|
485
|
-
|
|
486
|
-
let $mouse = view.state.doc.resolve(view.posAtCoords(eventCoords(e)).pos)
|
|
487
|
-
if (!$mouse) return
|
|
488
|
-
let slice = dragging && dragging.slice ||
|
|
489
|
-
parseFromClipboard(view, e.dataTransfer.getData("text/plain"), e.dataTransfer.getData("text/html"), false, $mouse)
|
|
490
|
-
if (!slice) return
|
|
491
|
-
|
|
492
|
-
e.preventDefault()
|
|
493
|
-
if (view.someProp("handleDrop", e, slice, dragging && dragging.move)) return
|
|
494
|
-
let insertPos = dropPos(slice, view.state.doc.resolve($mouse.pos))
|
|
495
|
-
|
|
496
|
-
let tr = view.state.tr
|
|
497
|
-
if (dragging && dragging.move) tr.deleteSelection()
|
|
498
|
-
|
|
499
|
-
let pos = tr.mapping.map(insertPos)
|
|
500
|
-
let isNode = slice.openLeft == 0 && slice.openRight == 0 && slice.content.childCount == 1
|
|
501
|
-
if (isNode)
|
|
502
|
-
tr.replaceRangeWith(pos, pos, slice.content.firstChild)
|
|
503
|
-
else
|
|
504
|
-
tr.replaceRange(pos, pos, slice)
|
|
505
|
-
let $pos = tr.doc.resolve(pos)
|
|
506
|
-
if (isNode && NodeSelection.isSelectable(slice.content.firstChild) &&
|
|
507
|
-
$pos.nodeAfter && $pos.nodeAfter.sameMarkup(slice.content.firstChild))
|
|
508
|
-
tr.setSelection(new NodeSelection($pos))
|
|
509
|
-
else
|
|
510
|
-
tr.setSelection(selectionBetween(view, $pos, tr.doc.resolve(tr.mapping.map(insertPos))))
|
|
511
|
-
view.focus()
|
|
512
|
-
view.dispatch(tr)
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
handlers.focus = (view, event) => {
|
|
516
|
-
if (!view.focused) {
|
|
517
|
-
view.dom.classList.add("ProseMirror-focused")
|
|
518
|
-
view.focused = true
|
|
519
|
-
}
|
|
520
|
-
view.someProp("onFocus", f => { f(view, event) })
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
handlers.blur = (view, event) => {
|
|
524
|
-
if (view.focused) {
|
|
525
|
-
view.dom.classList.remove("ProseMirror-focused")
|
|
526
|
-
view.focused = false
|
|
527
|
-
}
|
|
528
|
-
view.someProp("onBlur", f => { f(view, event) })
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
// Make sure all handlers get registered
|
|
532
|
-
for (let prop in editHandlers) handlers[prop] = editHandlers[prop]
|