prosemirror-view 1.29.2 → 1.30.1

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/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## 1.30.1 (2023-02-04)
2
+
3
+ ### Bug fixes
4
+
5
+ Fix a bug that caused `posAtCoords` to always return the position after a leaf node when querying a position on top of the node's element.
6
+
7
+ Fix an issue where, when putting focus on the editor by clicking at the very start of the document, the editor would restore a previous selection.
8
+
9
+ ## 1.30.0 (2023-01-19)
10
+
11
+ ### New features
12
+
13
+ `EditorView` now has `pasteHTML` and `pasteText` methods which initiate paste handling.
14
+
1
15
  ## 1.29.2 (2023-01-17)
2
16
 
3
17
  ### Bug fixes
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (C) 2015-2017 by Marijn Haverbeke <marijnh@gmail.com> and others
1
+ Copyright (C) 2015-2017 by Marijn Haverbeke <marijn@haverbeke.berlin> and others
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy
4
4
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.cjs CHANGED
@@ -386,22 +386,30 @@ function posFromElement(view, elt, coords) {
386
386
  }
387
387
 
388
388
  function posFromCaret(view, node, offset, coords) {
389
- var outside = -1;
389
+ var outsideBlock = -1;
390
390
 
391
391
  for (var cur = node;;) {
392
392
  if (cur == view.dom) break;
393
393
  var desc = view.docView.nearestDesc(cur, true);
394
394
  if (!desc) return null;
395
395
 
396
- if (desc.node.isBlock && desc.parent) {
396
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
397
397
  var rect = desc.dom.getBoundingClientRect();
398
- if (rect.left > coords.left || rect.top > coords.top) outside = desc.posBefore;else if (rect.right < coords.left || rect.bottom < coords.top) outside = desc.posAfter;else break;
398
+
399
+ if (desc.node.isBlock && desc.parent) {
400
+ if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore;else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter;
401
+ }
402
+
403
+ if (!desc.contentDOM && outsideBlock < 0) {
404
+ var before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2 : coords.left < (rect.left + rect.right) / 2;
405
+ return before ? desc.posBefore : desc.posAfter;
406
+ }
399
407
  }
400
408
 
401
409
  cur = desc.dom.parentNode;
402
410
  }
403
411
 
404
- return outside > -1 ? outside : view.docView.posFromDOM(node, offset, 1);
412
+ return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1);
405
413
  }
406
414
 
407
415
  function elementFromPoint(element, coords, box) {
@@ -3795,12 +3803,12 @@ function capturePaste(view, event) {
3795
3803
  setTimeout(function () {
3796
3804
  view.focus();
3797
3805
  if (target.parentNode) target.parentNode.removeChild(target);
3798
- if (plainText) doPaste(view, target.value, null, event);else doPaste(view, target.textContent, target.innerHTML, event);
3806
+ if (plainText) doPaste(view, target.value, null, view.input.shiftKey, event);else doPaste(view, target.textContent, target.innerHTML, view.input.shiftKey, event);
3799
3807
  }, 50);
3800
3808
  }
3801
3809
 
3802
- function doPaste(view, text, html, event) {
3803
- var slice = parseFromClipboard(view, text, html, view.input.shiftKey, view.state.selection.$from);
3810
+ function doPaste(view, text, html, preferPlain, event) {
3811
+ var slice = parseFromClipboard(view, text, html, preferPlain, view.state.selection.$from);
3804
3812
  if (view.someProp("handlePaste", function (f) {
3805
3813
  return f(view, event, slice || prosemirrorModel.Slice.empty);
3806
3814
  })) return true;
@@ -3815,7 +3823,7 @@ editHandlers.paste = function (view, _event) {
3815
3823
  var event = _event;
3816
3824
  if (view.composing && !android) return;
3817
3825
  var data = brokenClipboardAPI ? null : event.clipboardData;
3818
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), event)) event.preventDefault();else capturePaste(view, event);
3826
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event)) event.preventDefault();else capturePaste(view, event);
3819
3827
  };
3820
3828
 
3821
3829
  var Dragging = _createClass(function Dragging(slice, move) {
@@ -4943,7 +4951,7 @@ var DOMObserver = function () {
4943
4951
 
4944
4952
  var readSel = null;
4945
4953
 
4946
- if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 && view.input.lastTouch < Date.now() - 300 && selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) && readSel.eq(prosemirrorState.Selection.near(view.state.doc.resolve(0), 1))) {
4954
+ if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 && Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 && selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) && readSel.eq(prosemirrorState.Selection.near(view.state.doc.resolve(0), 1))) {
4947
4955
  view.input.lastFocus = 0;
4948
4956
  selectionToDOM(view);
4949
4957
  this.currentSelection.set(sel);
@@ -5772,6 +5780,16 @@ var EditorView = function () {
5772
5780
  value: function endOfTextblock(dir, state) {
5773
5781
  return _endOfTextblock(this, state || this.state, dir);
5774
5782
  }
5783
+ }, {
5784
+ key: "pasteHTML",
5785
+ value: function pasteHTML(html, event) {
5786
+ return doPaste(this, "", html, false, event || new ClipboardEvent("paste"));
5787
+ }
5788
+ }, {
5789
+ key: "pasteText",
5790
+ value: function pasteText(text, event) {
5791
+ return doPaste(this, text, null, true, event || new ClipboardEvent("paste"));
5792
+ }
5775
5793
  }, {
5776
5794
  key: "destroy",
5777
5795
  value: function destroy() {
package/dist/index.d.ts CHANGED
@@ -319,7 +319,8 @@ declare class ViewDesc {
319
319
  get posAfter(): number;
320
320
  get posAtEnd(): number;
321
321
  localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
322
- nearestDesc(dom: DOMNode, onlyNodes?: boolean): ViewDesc | undefined;
322
+ nearestDesc(dom: DOMNode): ViewDesc | undefined;
323
+ nearestDesc(dom: DOMNode, onlyNodes: true): NodeViewDesc | undefined;
323
324
  getDesc(dom: DOMNode): ViewDesc | undefined;
324
325
  posFromDOM(dom: DOMNode, offset: number, bias: number): number;
325
326
  descAt(pos: number): ViewDesc | undefined;
@@ -345,6 +346,50 @@ declare class ViewDesc {
345
346
  get domAtom(): boolean;
346
347
  get ignoreForCoords(): boolean;
347
348
  }
349
+ declare class NodeViewDesc extends ViewDesc {
350
+ node: Node;
351
+ outerDeco: readonly Decoration[];
352
+ innerDeco: DecorationSource;
353
+ readonly nodeDOM: DOMNode;
354
+ constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, contentDOM: HTMLElement | null, nodeDOM: DOMNode, view: EditorView, pos: number);
355
+ static create(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView, pos: number): NodeViewDesc | TextViewDesc;
356
+ parseRule(): ParseRule | null;
357
+ matchesNode(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource): boolean;
358
+ get size(): number;
359
+ get border(): 1 | 0;
360
+ updateChildren(view: EditorView, pos: number): void;
361
+ localCompositionInfo(view: EditorView, pos: number): {
362
+ node: Text;
363
+ pos: number;
364
+ text: string;
365
+ } | null;
366
+ protectLocalComposition(view: EditorView, { node, pos, text }: {
367
+ node: Text;
368
+ pos: number;
369
+ text: string;
370
+ }): void;
371
+ update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
372
+ updateInner(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): void;
373
+ updateOuterDeco(outerDeco: readonly Decoration[]): void;
374
+ selectNode(): void;
375
+ deselectNode(): void;
376
+ get domAtom(): boolean;
377
+ }
378
+ declare class TextViewDesc extends NodeViewDesc {
379
+ constructor(parent: ViewDesc | undefined, node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, dom: DOMNode, nodeDOM: DOMNode, view: EditorView);
380
+ parseRule(): ParseRule;
381
+ update(node: Node, outerDeco: readonly Decoration[], innerDeco: DecorationSource, view: EditorView): boolean;
382
+ inParent(): boolean;
383
+ domFromPos(pos: number): {
384
+ node: globalThis.Node;
385
+ offset: number;
386
+ };
387
+ localPosFromDOM(dom: DOMNode, offset: number, bias: number): number;
388
+ ignoreMutation(mutation: MutationRecord): boolean;
389
+ slice(from: number, to: number, view: EditorView): TextViewDesc;
390
+ markDirty(from: number, to: number): void;
391
+ get domAtom(): boolean;
392
+ }
348
393
 
349
394
  /**
350
395
  An editor view manages the DOM structure that represents an
@@ -520,6 +565,16 @@ declare class EditorView {
520
565
  */
521
566
  endOfTextblock(dir: "up" | "down" | "left" | "right" | "forward" | "backward", state?: EditorState): boolean;
522
567
  /**
568
+ Run the editor's paste logic with the given HTML string. The
569
+ `event`, if given, will be passed to the
570
+ [`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste) hook.
571
+ */
572
+ pasteHTML(html: string, event?: ClipboardEvent): boolean;
573
+ /**
574
+ Run the editor's paste logic with the given plain-text input.
575
+ */
576
+ pasteText(text: string, event?: ClipboardEvent): boolean;
577
+ /**
523
578
  Removes the editor from the DOM and destroys all [node
524
579
  views](https://prosemirror.net/docs/ref/#view.NodeView).
525
580
  */
package/dist/index.js CHANGED
@@ -314,25 +314,31 @@ function posFromCaret(view, node, offset, coords) {
314
314
  // of nodes to see if there are block nodes that the coordinates
315
315
  // fall outside of. If so, we take the position before/after that
316
316
  // block. If not, we call `posFromDOM` on the raw node/offset.
317
- let outside = -1;
317
+ let outsideBlock = -1;
318
318
  for (let cur = node;;) {
319
319
  if (cur == view.dom)
320
320
  break;
321
321
  let desc = view.docView.nearestDesc(cur, true);
322
322
  if (!desc)
323
323
  return null;
324
- if (desc.node.isBlock && desc.parent) {
324
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
325
325
  let rect = desc.dom.getBoundingClientRect();
326
- if (rect.left > coords.left || rect.top > coords.top)
327
- outside = desc.posBefore;
328
- else if (rect.right < coords.left || rect.bottom < coords.top)
329
- outside = desc.posAfter;
330
- else
331
- break;
326
+ if (desc.node.isBlock && desc.parent) {
327
+ if (rect.left > coords.left || rect.top > coords.top)
328
+ outsideBlock = desc.posBefore;
329
+ else if (rect.right < coords.left || rect.bottom < coords.top)
330
+ outsideBlock = desc.posAfter;
331
+ }
332
+ if (!desc.contentDOM && outsideBlock < 0) {
333
+ // If we are inside a leaf, return the side of the leaf closer to the coords
334
+ let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2
335
+ : coords.left < (rect.left + rect.right) / 2;
336
+ return before ? desc.posBefore : desc.posAfter;
337
+ }
332
338
  }
333
339
  cur = desc.dom.parentNode;
334
340
  }
335
- return outside > -1 ? outside : view.docView.posFromDOM(node, offset, 1);
341
+ return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1);
336
342
  }
337
343
  function elementFromPoint(element, coords, box) {
338
344
  let len = element.childNodes.length;
@@ -760,8 +766,6 @@ class ViewDesc {
760
766
  }
761
767
  return (atEnd == null ? bias > 0 : atEnd) ? this.posAtEnd : this.posAtStart;
762
768
  }
763
- // Scan up the dom finding the first desc that is a descendant of
764
- // this one.
765
769
  nearestDesc(dom, onlyNodes = false) {
766
770
  for (let first = true, cur = dom; cur; cur = cur.parentNode) {
767
771
  let desc = this.getDesc(cur), nodeDOM;
@@ -3345,13 +3349,13 @@ function capturePaste(view, event) {
3345
3349
  if (target.parentNode)
3346
3350
  target.parentNode.removeChild(target);
3347
3351
  if (plainText)
3348
- doPaste(view, target.value, null, event);
3352
+ doPaste(view, target.value, null, view.input.shiftKey, event);
3349
3353
  else
3350
- doPaste(view, target.textContent, target.innerHTML, event);
3354
+ doPaste(view, target.textContent, target.innerHTML, view.input.shiftKey, event);
3351
3355
  }, 50);
3352
3356
  }
3353
- function doPaste(view, text, html, event) {
3354
- let slice = parseFromClipboard(view, text, html, view.input.shiftKey, view.state.selection.$from);
3357
+ function doPaste(view, text, html, preferPlain, event) {
3358
+ let slice = parseFromClipboard(view, text, html, preferPlain, view.state.selection.$from);
3355
3359
  if (view.someProp("handlePaste", f => f(view, event, slice || Slice.empty)))
3356
3360
  return true;
3357
3361
  if (!slice)
@@ -3372,7 +3376,7 @@ editHandlers.paste = (view, _event) => {
3372
3376
  if (view.composing && !android)
3373
3377
  return;
3374
3378
  let data = brokenClipboardAPI ? null : event.clipboardData;
3375
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), event))
3379
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event))
3376
3380
  event.preventDefault();
3377
3381
  else
3378
3382
  capturePaste(view, event);
@@ -4381,7 +4385,7 @@ class DOMObserver {
4381
4385
  // start of the document after focus, restore the selection from
4382
4386
  // the state
4383
4387
  if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 &&
4384
- view.input.lastTouch < Date.now() - 300 &&
4388
+ Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 &&
4385
4389
  selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) &&
4386
4390
  readSel.eq(Selection.near(view.state.doc.resolve(0), 1))) {
4387
4391
  view.input.lastFocus = 0;
@@ -5262,6 +5266,20 @@ class EditorView {
5262
5266
  return endOfTextblock(this, state || this.state, dir);
5263
5267
  }
5264
5268
  /**
5269
+ Run the editor's paste logic with the given HTML string. The
5270
+ `event`, if given, will be passed to the
5271
+ [`handlePaste`](https://prosemirror.net/docs/ref/#view.EditorProps.handlePaste) hook.
5272
+ */
5273
+ pasteHTML(html, event) {
5274
+ return doPaste(this, "", html, false, event || new ClipboardEvent("paste"));
5275
+ }
5276
+ /**
5277
+ Run the editor's paste logic with the given plain-text input.
5278
+ */
5279
+ pasteText(text, event) {
5280
+ return doPaste(this, text, null, true, event || new ClipboardEvent("paste"));
5281
+ }
5282
+ /**
5265
5283
  Removes the editor from the DOM and destroys all [node
5266
5284
  views](https://prosemirror.net/docs/ref/#view.NodeView).
5267
5285
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prosemirror-view",
3
- "version": "1.29.2",
3
+ "version": "1.30.1",
4
4
  "description": "ProseMirror's view component",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",
@@ -19,7 +19,7 @@
19
19
  "maintainers": [
20
20
  {
21
21
  "name": "Marijn Haverbeke",
22
- "email": "marijnh@gmail.com",
22
+ "email": "marijn@haverbeke.berlin",
23
23
  "web": "http://marijnhaverbeke.nl"
24
24
  }
25
25
  ],
package/src/domcoords.ts CHANGED
@@ -2,7 +2,6 @@ import {EditorState} from "prosemirror-state"
2
2
  import {nodeSize, textRange, parentNode} from "./dom"
3
3
  import * as browser from "./browser"
4
4
  import {EditorView} from "./index"
5
- import {NodeViewDesc} from "./viewdesc"
6
5
 
7
6
  export type Rect = {left: number, right: number, top: number, bottom: number}
8
7
 
@@ -211,20 +210,27 @@ function posFromCaret(view: EditorView, node: Node, offset: number, coords: {top
211
210
  // of nodes to see if there are block nodes that the coordinates
212
211
  // fall outside of. If so, we take the position before/after that
213
212
  // block. If not, we call `posFromDOM` on the raw node/offset.
214
- let outside = -1
213
+ let outsideBlock = -1
215
214
  for (let cur = node;;) {
216
215
  if (cur == view.dom) break
217
216
  let desc = view.docView.nearestDesc(cur, true)
218
217
  if (!desc) return null
219
- if ((desc as NodeViewDesc).node.isBlock && desc.parent) {
218
+ if (desc.dom.nodeType == 1 && (desc.node.isBlock && desc.parent || !desc.contentDOM)) {
220
219
  let rect = (desc.dom as HTMLElement).getBoundingClientRect()
221
- if (rect.left > coords.left || rect.top > coords.top) outside = desc.posBefore
222
- else if (rect.right < coords.left || rect.bottom < coords.top) outside = desc.posAfter
223
- else break
220
+ if (desc.node.isBlock && desc.parent) {
221
+ if (rect.left > coords.left || rect.top > coords.top) outsideBlock = desc.posBefore
222
+ else if (rect.right < coords.left || rect.bottom < coords.top) outsideBlock = desc.posAfter
223
+ }
224
+ if (!desc.contentDOM && outsideBlock < 0) {
225
+ // If we are inside a leaf, return the side of the leaf closer to the coords
226
+ let before = desc.node.isBlock ? coords.top < (rect.top + rect.bottom) / 2
227
+ : coords.left < (rect.left + rect.right) / 2
228
+ return before ? desc.posBefore : desc.posAfter
229
+ }
224
230
  }
225
231
  cur = desc.dom.parentNode!
226
232
  }
227
- return outside > -1 ? outside : view.docView.posFromDOM(node, offset, 1)
233
+ return outsideBlock > -1 ? outsideBlock : view.docView.posFromDOM(node, offset, -1)
228
234
  }
229
235
 
230
236
  function elementFromPoint(element: HTMLElement, coords: {top: number, left: number}, box: Rect): HTMLElement {
@@ -413,7 +419,7 @@ function endOfTextblockVertical(view: EditorView, state: EditorState, dir: "up"
413
419
  for (;;) {
414
420
  let nearest = view.docView.nearestDesc(dom, true)
415
421
  if (!nearest) break
416
- if (nearest.node!.isBlock) { dom = nearest.contentDOM || nearest.dom; break }
422
+ if (nearest.node.isBlock) { dom = nearest.contentDOM || nearest.dom; break }
417
423
  dom = nearest.dom.parentNode!
418
424
  }
419
425
  let coords = coordsAtPos(view, $pos.pos, 1)
@@ -195,7 +195,7 @@ export class DOMObserver {
195
195
  // start of the document after focus, restore the selection from
196
196
  // the state
197
197
  if (from < 0 && newSel && view.input.lastFocus > Date.now() - 200 &&
198
- view.input.lastTouch < Date.now() - 300 &&
198
+ Math.max(view.input.lastTouch, view.input.lastClick.time) < Date.now() - 300 &&
199
199
  selectionCollapsed(sel) && (readSel = selectionFromDOM(view)) &&
200
200
  readSel.eq(Selection.near(view.state.doc.resolve(0), 1))) {
201
201
  view.input.lastFocus = 0
package/src/index.ts CHANGED
@@ -4,7 +4,7 @@ import {Slice, ResolvedPos, DOMParser, DOMSerializer, Node, Mark} from "prosemir
4
4
  import {scrollRectIntoView, posAtCoords, coordsAtPos, endOfTextblock, storeScrollPos,
5
5
  resetScrollPos, focusPreventScroll} from "./domcoords"
6
6
  import {docViewDesc, ViewDesc, NodeView, NodeViewDesc} from "./viewdesc"
7
- import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition, InputState} from "./input"
7
+ import {initInput, destroyInput, dispatchEvent, ensureListeners, clearComposition, InputState, doPaste} from "./input"
8
8
  import {selectionToDOM, anchorInRightPlace, syncNodeSelection} from "./selection"
9
9
  import {Decoration, viewDecorations, DecorationSource} from "./decoration"
10
10
  import {DOMObserver, safariShadowSelectionRange} from "./domobserver"
@@ -409,6 +409,18 @@ export class EditorView {
409
409
  return endOfTextblock(this, state || this.state, dir)
410
410
  }
411
411
 
412
+ /// Run the editor's paste logic with the given HTML string. The
413
+ /// `event`, if given, will be passed to the
414
+ /// [`handlePaste`](#view.EditorProps.handlePaste) hook.
415
+ pasteHTML(html: string, event?: ClipboardEvent) {
416
+ return doPaste(this, "", html, false, event || new ClipboardEvent("paste"))
417
+ }
418
+
419
+ /// Run the editor's paste logic with the given plain-text input.
420
+ pasteText(text: string, event?: ClipboardEvent) {
421
+ return doPaste(this, text, null, true, event || new ClipboardEvent("paste"))
422
+ }
423
+
412
424
  /// Removes the editor from the DOM and destroys all [node
413
425
  /// views](#view.NodeView).
414
426
  destroy() {
package/src/input.ts CHANGED
@@ -583,13 +583,13 @@ function capturePaste(view: EditorView, event: ClipboardEvent) {
583
583
  setTimeout(() => {
584
584
  view.focus()
585
585
  if (target.parentNode) target.parentNode.removeChild(target)
586
- if (plainText) doPaste(view, (target as HTMLTextAreaElement).value, null, event)
587
- else doPaste(view, target.textContent!, target.innerHTML, event)
586
+ if (plainText) doPaste(view, (target as HTMLTextAreaElement).value, null, view.input.shiftKey, event)
587
+ else doPaste(view, target.textContent!, target.innerHTML, view.input.shiftKey, event)
588
588
  }, 50)
589
589
  }
590
590
 
591
- function doPaste(view: EditorView, text: string, html: string | null, event: ClipboardEvent) {
592
- let slice = parseFromClipboard(view, text, html, view.input.shiftKey, view.state.selection.$from)
591
+ export function doPaste(view: EditorView, text: string, html: string | null, preferPlain: boolean, event: ClipboardEvent) {
592
+ let slice = parseFromClipboard(view, text, html, preferPlain, view.state.selection.$from)
593
593
  if (view.someProp("handlePaste", f => f(view, event, slice || Slice.empty))) return true
594
594
  if (!slice) return false
595
595
 
@@ -609,8 +609,10 @@ editHandlers.paste = (view, _event) => {
609
609
  // where the editor is almost always composing.
610
610
  if (view.composing && !browser.android) return
611
611
  let data = brokenClipboardAPI ? null : event.clipboardData
612
- if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), event)) event.preventDefault()
613
- else capturePaste(view, event)
612
+ if (data && doPaste(view, data.getData("text/plain"), data.getData("text/html"), view.input.shiftKey, event))
613
+ event.preventDefault()
614
+ else
615
+ capturePaste(view, event)
614
616
  }
615
617
 
616
618
  class Dragging {
@@ -633,7 +635,7 @@ handlers.dragstart = (view, _event) => {
633
635
  view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, mouseDown.mightDrag.pos)))
634
636
  } else if (event.target && (event.target as HTMLElement).nodeType == 1) {
635
637
  let desc = view.docView.nearestDesc(event.target as HTMLElement, true)
636
- if (desc && desc.node!.type.spec.draggable && desc != view.docView)
638
+ if (desc && desc.node.type.spec.draggable && desc != view.docView)
637
639
  view.dispatch(view.state.tr.setSelection(NodeSelection.create(view.state.doc, desc.posBefore)))
638
640
  }
639
641
  let slice = view.state.selection.content(), {dom, text} = serializeForClipboard(view, slice)
package/src/viewdesc.ts CHANGED
@@ -221,6 +221,8 @@ export class ViewDesc {
221
221
 
222
222
  // Scan up the dom finding the first desc that is a descendant of
223
223
  // this one.
224
+ nearestDesc(dom: DOMNode): ViewDesc | undefined
225
+ nearestDesc(dom: DOMNode, onlyNodes: true): NodeViewDesc | undefined
224
226
  nearestDesc(dom: DOMNode, onlyNodes: boolean = false) {
225
227
  for (let first = true, cur: DOMNode | null = dom; cur; cur = cur.parentNode) {
226
228
  let desc = this.getDesc(cur), nodeDOM