prosemirror-view 1.26.3 → 1.27.0
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 +24 -0
- package/dist/index.cjs +13 -9
- package/dist/index.d.ts +28 -23
- package/dist/index.js +11 -9
- package/package.json +1 -1
- package/src/domchange.ts +2 -1
- package/src/domcoords.ts +7 -6
- package/src/index.ts +27 -23
- package/src/viewdesc.ts +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 1.27.0 (2022-07-20)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a bug that in some situations caused composition to be disrupted on Chrome due to a workaround for another browser issue activating inappropriately.
|
|
6
|
+
|
|
7
|
+
### New features
|
|
8
|
+
|
|
9
|
+
`EditorProps` now takes an optional type parameter that indicates the type of `this` in prop functions.
|
|
10
|
+
|
|
11
|
+
## 1.26.5 (2022-07-07)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Fix an issue where a composition happening at the same time as widget insertion/removal could corrupt the rendered DOM.
|
|
16
|
+
|
|
17
|
+
Fix a problem where `coordsAtPos` would look inside the DOM for atomic nodes, and sometimes return very odd positions that way.
|
|
18
|
+
|
|
19
|
+
## 1.26.4 (2022-07-04)
|
|
20
|
+
|
|
21
|
+
### Bug fixes
|
|
22
|
+
|
|
23
|
+
Avoid spurious type errors on `handleDOMEvents` by widening the type for unknown event objects.
|
|
24
|
+
|
|
1
25
|
## 1.26.3 (2022-06-29)
|
|
2
26
|
|
|
3
27
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -495,7 +495,8 @@ var BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
|
|
|
495
495
|
function _coordsAtPos(view, pos, side) {
|
|
496
496
|
var _view$docView$domFrom = view.docView.domFromPos(pos, side < 0 ? -1 : 1),
|
|
497
497
|
node = _view$docView$domFrom.node,
|
|
498
|
-
offset = _view$docView$domFrom.offset
|
|
498
|
+
offset = _view$docView$domFrom.offset,
|
|
499
|
+
atom = _view$docView$domFrom.atom;
|
|
499
500
|
|
|
500
501
|
var supportEmptyRange = webkit || gecko;
|
|
501
502
|
|
|
@@ -534,13 +535,15 @@ function _coordsAtPos(view, pos, side) {
|
|
|
534
535
|
}
|
|
535
536
|
}
|
|
536
537
|
|
|
537
|
-
|
|
538
|
-
|
|
538
|
+
var $dom = view.state.doc.resolve(pos - (atom || 0));
|
|
539
|
+
|
|
540
|
+
if (!$dom.parent.inlineContent) {
|
|
541
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
539
542
|
var before = node.childNodes[offset - 1];
|
|
540
543
|
if (before.nodeType == 1) return flattenH(before.getBoundingClientRect(), false);
|
|
541
544
|
}
|
|
542
545
|
|
|
543
|
-
if (offset < nodeSize(node)) {
|
|
546
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
544
547
|
var after = node.childNodes[offset];
|
|
545
548
|
if (after.nodeType == 1) return flattenH(after.getBoundingClientRect(), true);
|
|
546
549
|
}
|
|
@@ -548,13 +551,13 @@ function _coordsAtPos(view, pos, side) {
|
|
|
548
551
|
return flattenH(node.getBoundingClientRect(), side >= 0);
|
|
549
552
|
}
|
|
550
553
|
|
|
551
|
-
if (offset && (side < 0 || offset == nodeSize(node))) {
|
|
554
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
552
555
|
var _before = node.childNodes[offset - 1];
|
|
553
556
|
var target = _before.nodeType == 3 ? textRange(_before, nodeSize(_before) - (supportEmptyRange ? 0 : 1)) : _before.nodeType == 1 && (_before.nodeName != "BR" || !_before.nextSibling) ? _before : null;
|
|
554
557
|
if (target) return flattenV(singleRect(target, 1), false);
|
|
555
558
|
}
|
|
556
559
|
|
|
557
|
-
if (offset < nodeSize(node)) {
|
|
560
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
558
561
|
var _after = node.childNodes[offset];
|
|
559
562
|
|
|
560
563
|
while (_after.pmViewDesc && _after.pmViewDesc.ignoreForCoords) {
|
|
@@ -905,7 +908,8 @@ var ViewDesc = function () {
|
|
|
905
908
|
value: function domFromPos(pos, side) {
|
|
906
909
|
if (!this.contentDOM) return {
|
|
907
910
|
node: this.dom,
|
|
908
|
-
offset: 0
|
|
911
|
+
offset: 0,
|
|
912
|
+
atom: pos + 1
|
|
909
913
|
};
|
|
910
914
|
var i = 0,
|
|
911
915
|
offset = 0;
|
|
@@ -2077,7 +2081,7 @@ var ViewTreeUpdater = function () {
|
|
|
2077
2081
|
if (child.dirty == NODE_DIRTY && child.dom == child.contentDOM) child.dirty = CONTENT_DIRTY;
|
|
2078
2082
|
if (!child.update(node, outerDeco, innerDeco, view)) return false;
|
|
2079
2083
|
this.destroyBetween(this.index, index);
|
|
2080
|
-
this.index
|
|
2084
|
+
this.index++;
|
|
2081
2085
|
return true;
|
|
2082
2086
|
}
|
|
2083
2087
|
}, {
|
|
@@ -5045,7 +5049,7 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
5045
5049
|
var sel = view.state.selection;
|
|
5046
5050
|
var parse = parseBetween(view, from, to);
|
|
5047
5051
|
|
|
5048
|
-
if (chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from) {
|
|
5052
|
+
if (chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from && parse.sel.head == parse.sel.anchor) {
|
|
5049
5053
|
var text = view.cursorWrapper.deco.type.toDOM.nextSibling;
|
|
5050
5054
|
var size = text && text.nodeValue ? text.nodeValue.length : 1;
|
|
5051
5055
|
parse.sel = {
|
package/dist/index.d.ts
CHANGED
|
@@ -326,6 +326,7 @@ declare class ViewDesc {
|
|
|
326
326
|
domFromPos(pos: number, side: number): {
|
|
327
327
|
node: DOMNode;
|
|
328
328
|
offset: number;
|
|
329
|
+
atom?: number;
|
|
329
330
|
};
|
|
330
331
|
parseRange(from: number, to: number, base?: number): {
|
|
331
332
|
node: DOMNode;
|
|
@@ -563,7 +564,7 @@ includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
|
563
564
|
about.
|
|
564
565
|
*/
|
|
565
566
|
interface DOMEventMap extends HTMLElementEventMap {
|
|
566
|
-
[event: string]:
|
|
567
|
+
[event: string]: any;
|
|
567
568
|
}
|
|
568
569
|
/**
|
|
569
570
|
Props are configuration values that can be passed to an editor view
|
|
@@ -579,8 +580,12 @@ called one at a time, starting with the base props and then
|
|
|
579
580
|
searching through the plugins (in order of appearance) until one of
|
|
580
581
|
them returns true. For some props, the first plugin that yields a
|
|
581
582
|
value gets precedence.
|
|
583
|
+
|
|
584
|
+
The optional type parameter refers to the type of `this` in prop
|
|
585
|
+
functions, and is used to pass in the plugin type when defining a
|
|
586
|
+
[plugin](https://prosemirror.net/docs/ref/#state.Plugin).
|
|
582
587
|
*/
|
|
583
|
-
interface EditorProps {
|
|
588
|
+
interface EditorProps<P = any> {
|
|
584
589
|
/**
|
|
585
590
|
Can be an object mapping DOM event type names to functions that
|
|
586
591
|
handle them. Such functions will be called before any handling
|
|
@@ -591,72 +596,72 @@ interface EditorProps {
|
|
|
591
596
|
default behavior).
|
|
592
597
|
*/
|
|
593
598
|
handleDOMEvents?: {
|
|
594
|
-
[event in keyof DOMEventMap]?: (view: EditorView, event: DOMEventMap[event]) => boolean | void;
|
|
599
|
+
[event in keyof DOMEventMap]?: (this: P, view: EditorView, event: DOMEventMap[event]) => boolean | void;
|
|
595
600
|
};
|
|
596
601
|
/**
|
|
597
602
|
Called when the editor receives a `keydown` event.
|
|
598
603
|
*/
|
|
599
|
-
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean | void;
|
|
604
|
+
handleKeyDown?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void;
|
|
600
605
|
/**
|
|
601
606
|
Handler for `keypress` events.
|
|
602
607
|
*/
|
|
603
|
-
handleKeyPress?: (view: EditorView, event: KeyboardEvent) => boolean | void;
|
|
608
|
+
handleKeyPress?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void;
|
|
604
609
|
/**
|
|
605
610
|
Whenever the user directly input text, this handler is called
|
|
606
611
|
before the input is applied. If it returns `true`, the default
|
|
607
612
|
behavior of actually inserting the text is suppressed.
|
|
608
613
|
*/
|
|
609
|
-
handleTextInput?: (view: EditorView, from: number, to: number, text: string) => boolean | void;
|
|
614
|
+
handleTextInput?: (this: P, view: EditorView, from: number, to: number, text: string) => boolean | void;
|
|
610
615
|
/**
|
|
611
616
|
Called for each node around a click, from the inside out. The
|
|
612
617
|
`direct` flag will be true for the inner node.
|
|
613
618
|
*/
|
|
614
|
-
handleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
619
|
+
handleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
615
620
|
/**
|
|
616
621
|
Called when the editor is clicked, after `handleClickOn` handlers
|
|
617
622
|
have been called.
|
|
618
623
|
*/
|
|
619
|
-
handleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
624
|
+
handleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
620
625
|
/**
|
|
621
626
|
Called for each node around a double click.
|
|
622
627
|
*/
|
|
623
|
-
handleDoubleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
628
|
+
handleDoubleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
624
629
|
/**
|
|
625
630
|
Called when the editor is double-clicked, after `handleDoubleClickOn`.
|
|
626
631
|
*/
|
|
627
|
-
handleDoubleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
632
|
+
handleDoubleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
628
633
|
/**
|
|
629
634
|
Called for each node around a triple click.
|
|
630
635
|
*/
|
|
631
|
-
handleTripleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
636
|
+
handleTripleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void;
|
|
632
637
|
/**
|
|
633
638
|
Called when the editor is triple-clicked, after `handleTripleClickOn`.
|
|
634
639
|
*/
|
|
635
|
-
handleTripleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
640
|
+
handleTripleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void;
|
|
636
641
|
/**
|
|
637
642
|
Can be used to override the behavior of pasting. `slice` is the
|
|
638
643
|
pasted content parsed by the editor, but you can directly access
|
|
639
644
|
the event to get at the raw content.
|
|
640
645
|
*/
|
|
641
|
-
handlePaste?: (view: EditorView, event: ClipboardEvent, slice: Slice) => boolean | void;
|
|
646
|
+
handlePaste?: (this: P, view: EditorView, event: ClipboardEvent, slice: Slice) => boolean | void;
|
|
642
647
|
/**
|
|
643
648
|
Called when something is dropped on the editor. `moved` will be
|
|
644
649
|
true if this drop moves from the current selection (which should
|
|
645
650
|
thus be deleted).
|
|
646
651
|
*/
|
|
647
|
-
handleDrop?: (view: EditorView, event: DragEvent, slice: Slice, moved: boolean) => boolean | void;
|
|
652
|
+
handleDrop?: (this: P, view: EditorView, event: DragEvent, slice: Slice, moved: boolean) => boolean | void;
|
|
648
653
|
/**
|
|
649
654
|
Called when the view, after updating its state, tries to scroll
|
|
650
655
|
the selection into view. A handler function may return false to
|
|
651
656
|
indicate that it did not handle the scrolling and further
|
|
652
657
|
handlers or the default behavior should be tried.
|
|
653
658
|
*/
|
|
654
|
-
handleScrollToSelection?: (view: EditorView) => boolean;
|
|
659
|
+
handleScrollToSelection?: (this: P, view: EditorView) => boolean;
|
|
655
660
|
/**
|
|
656
661
|
Can be used to override the way a selection is created when
|
|
657
662
|
reading a DOM selection between the given anchor and head.
|
|
658
663
|
*/
|
|
659
|
-
createSelectionBetween?: (view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null;
|
|
664
|
+
createSelectionBetween?: (this: P, view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null;
|
|
660
665
|
/**
|
|
661
666
|
The [parser](https://prosemirror.net/docs/ref/#model.DOMParser) to use when reading editor changes
|
|
662
667
|
from the DOM. Defaults to calling
|
|
@@ -668,7 +673,7 @@ interface EditorProps {
|
|
|
668
673
|
Can be used to transform pasted HTML text, _before_ it is parsed,
|
|
669
674
|
for example to clean it up.
|
|
670
675
|
*/
|
|
671
|
-
transformPastedHTML?: (html: string) => string;
|
|
676
|
+
transformPastedHTML?: (this: P, html: string) => string;
|
|
672
677
|
/**
|
|
673
678
|
The [parser](https://prosemirror.net/docs/ref/#model.DOMParser) to use when reading content from
|
|
674
679
|
the clipboard. When not given, the value of the
|
|
@@ -679,7 +684,7 @@ interface EditorProps {
|
|
|
679
684
|
Transform pasted plain text. The `plain` flag will be true when
|
|
680
685
|
the text is pasted as plain text.
|
|
681
686
|
*/
|
|
682
|
-
transformPastedText?: (text: string, plain: boolean) => string;
|
|
687
|
+
transformPastedText?: (this: P, text: string, plain: boolean) => string;
|
|
683
688
|
/**
|
|
684
689
|
A function to parse text from the clipboard into a document
|
|
685
690
|
slice. Called after
|
|
@@ -689,12 +694,12 @@ interface EditorProps {
|
|
|
689
694
|
[`clipboardParser`](https://prosemirror.net/docs/ref/#view.EditorProps.clipboardParser) on it.
|
|
690
695
|
The `plain` flag will be true when the text is pasted as plain text.
|
|
691
696
|
*/
|
|
692
|
-
clipboardTextParser?: (text: string, $context: ResolvedPos, plain: boolean) => Slice;
|
|
697
|
+
clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean) => Slice;
|
|
693
698
|
/**
|
|
694
699
|
Can be used to transform pasted content before it is applied to
|
|
695
700
|
the document.
|
|
696
701
|
*/
|
|
697
|
-
transformPasted?: (slice: Slice) => Slice;
|
|
702
|
+
transformPasted?: (this: P, slice: Slice) => Slice;
|
|
698
703
|
/**
|
|
699
704
|
Allows you to pass custom rendering and behavior logic for
|
|
700
705
|
nodes. Should map node names to constructor functions that
|
|
@@ -749,17 +754,17 @@ interface EditorProps {
|
|
|
749
754
|
editor will use [`textBetween`](https://prosemirror.net/docs/ref/#model.Node.textBetween) on the
|
|
750
755
|
selected range.
|
|
751
756
|
*/
|
|
752
|
-
clipboardTextSerializer?: (content: Slice) => string;
|
|
757
|
+
clipboardTextSerializer?: (this: P, content: Slice) => string;
|
|
753
758
|
/**
|
|
754
759
|
A set of [document decorations](https://prosemirror.net/docs/ref/#view.Decoration) to show in the
|
|
755
760
|
view.
|
|
756
761
|
*/
|
|
757
|
-
decorations?: (state: EditorState) => DecorationSource | null | undefined;
|
|
762
|
+
decorations?: (this: P, state: EditorState) => DecorationSource | null | undefined;
|
|
758
763
|
/**
|
|
759
764
|
When this returns false, the content of the view is not directly
|
|
760
765
|
editable.
|
|
761
766
|
*/
|
|
762
|
-
editable?: (state: EditorState) => boolean;
|
|
767
|
+
editable?: (this: P, state: EditorState) => boolean;
|
|
763
768
|
/**
|
|
764
769
|
Control the DOM attributes of the editable element. May be either
|
|
765
770
|
an object or a function going from an editor state to an object.
|
package/dist/index.js
CHANGED
|
@@ -422,7 +422,7 @@ const BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
|
|
|
422
422
|
// Given a position in the document model, get a bounding box of the
|
|
423
423
|
// character at that position, relative to the window.
|
|
424
424
|
function coordsAtPos(view, pos, side) {
|
|
425
|
-
let { node, offset } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
|
|
425
|
+
let { node, offset, atom } = view.docView.domFromPos(pos, side < 0 ? -1 : 1);
|
|
426
426
|
let supportEmptyRange = webkit || gecko;
|
|
427
427
|
if (node.nodeType == 3) {
|
|
428
428
|
// These browsers support querying empty text ranges. Prefer that in
|
|
@@ -461,14 +461,15 @@ function coordsAtPos(view, pos, side) {
|
|
|
461
461
|
return flattenV(singleRect(textRange(node, from, to), takeSide), takeSide < 0);
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
|
+
let $dom = view.state.doc.resolve(pos - (atom || 0));
|
|
464
465
|
// Return a horizontal line in block context
|
|
465
|
-
if (
|
|
466
|
-
if (offset && (side < 0 || offset == nodeSize(node))) {
|
|
466
|
+
if (!$dom.parent.inlineContent) {
|
|
467
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
467
468
|
let before = node.childNodes[offset - 1];
|
|
468
469
|
if (before.nodeType == 1)
|
|
469
470
|
return flattenH(before.getBoundingClientRect(), false);
|
|
470
471
|
}
|
|
471
|
-
if (offset < nodeSize(node)) {
|
|
472
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
472
473
|
let after = node.childNodes[offset];
|
|
473
474
|
if (after.nodeType == 1)
|
|
474
475
|
return flattenH(after.getBoundingClientRect(), true);
|
|
@@ -476,7 +477,7 @@ function coordsAtPos(view, pos, side) {
|
|
|
476
477
|
return flattenH(node.getBoundingClientRect(), side >= 0);
|
|
477
478
|
}
|
|
478
479
|
// Inline, not in text node (this is not Bidi-safe)
|
|
479
|
-
if (offset && (side < 0 || offset == nodeSize(node))) {
|
|
480
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
480
481
|
let before = node.childNodes[offset - 1];
|
|
481
482
|
let target = before.nodeType == 3 ? textRange(before, nodeSize(before) - (supportEmptyRange ? 0 : 1))
|
|
482
483
|
// BR nodes tend to only return the rectangle before them.
|
|
@@ -485,7 +486,7 @@ function coordsAtPos(view, pos, side) {
|
|
|
485
486
|
if (target)
|
|
486
487
|
return flattenV(singleRect(target, 1), false);
|
|
487
488
|
}
|
|
488
|
-
if (offset < nodeSize(node)) {
|
|
489
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
489
490
|
let after = node.childNodes[offset];
|
|
490
491
|
while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords)
|
|
491
492
|
after = after.nextSibling;
|
|
@@ -797,7 +798,7 @@ class ViewDesc {
|
|
|
797
798
|
}
|
|
798
799
|
domFromPos(pos, side) {
|
|
799
800
|
if (!this.contentDOM)
|
|
800
|
-
return { node: this.dom, offset: 0 };
|
|
801
|
+
return { node: this.dom, offset: 0, atom: pos + 1 };
|
|
801
802
|
// First find the position in the child array
|
|
802
803
|
let i = 0, offset = 0;
|
|
803
804
|
for (let curPos = 0; i < this.children.length; i++) {
|
|
@@ -1723,7 +1724,7 @@ class ViewTreeUpdater {
|
|
|
1723
1724
|
if (!child.update(node, outerDeco, innerDeco, view))
|
|
1724
1725
|
return false;
|
|
1725
1726
|
this.destroyBetween(this.index, index);
|
|
1726
|
-
this.index
|
|
1727
|
+
this.index++;
|
|
1727
1728
|
return true;
|
|
1728
1729
|
}
|
|
1729
1730
|
findIndexWithChild(domNode) {
|
|
@@ -4500,7 +4501,8 @@ function readDOMChange(view, from, to, typeOver, addedNodes) {
|
|
|
4500
4501
|
let parse = parseBetween(view, from, to);
|
|
4501
4502
|
// Chrome sometimes leaves the cursor before the inserted text when
|
|
4502
4503
|
// composing after a cursor wrapper. This moves it forward.
|
|
4503
|
-
if (chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from
|
|
4504
|
+
if (chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from &&
|
|
4505
|
+
parse.sel.head == parse.sel.anchor) {
|
|
4504
4506
|
let text = view.cursorWrapper.deco.type.toDOM.nextSibling;
|
|
4505
4507
|
let size = text && text.nodeValue ? text.nodeValue.length : 1;
|
|
4506
4508
|
parse.sel = { anchor: parse.sel.anchor + size, head: parse.sel.anchor + size };
|
package/package.json
CHANGED
package/src/domchange.ts
CHANGED
|
@@ -99,7 +99,8 @@ export function readDOMChange(view: EditorView, from: number, to: number, typeOv
|
|
|
99
99
|
|
|
100
100
|
// Chrome sometimes leaves the cursor before the inserted text when
|
|
101
101
|
// composing after a cursor wrapper. This moves it forward.
|
|
102
|
-
if (browser.chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from
|
|
102
|
+
if (browser.chrome && view.cursorWrapper && parse.sel && parse.sel.anchor == view.cursorWrapper.deco.from &&
|
|
103
|
+
parse.sel.head == parse.sel.anchor) {
|
|
103
104
|
let text = (view.cursorWrapper.deco.type as any).toDOM.nextSibling as DOMNode
|
|
104
105
|
let size = text && text.nodeValue ? text.nodeValue.length : 1
|
|
105
106
|
parse.sel = {anchor: parse.sel.anchor + size, head: parse.sel.anchor + size}
|
package/src/domcoords.ts
CHANGED
|
@@ -315,7 +315,7 @@ const BIDI = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/
|
|
|
315
315
|
// Given a position in the document model, get a bounding box of the
|
|
316
316
|
// character at that position, relative to the window.
|
|
317
317
|
export function coordsAtPos(view: EditorView, pos: number, side: number): Rect {
|
|
318
|
-
let {node, offset} = view.docView.domFromPos(pos, side < 0 ? -1 : 1)
|
|
318
|
+
let {node, offset, atom} = view.docView.domFromPos(pos, side < 0 ? -1 : 1)
|
|
319
319
|
|
|
320
320
|
let supportEmptyRange = browser.webkit || browser.gecko
|
|
321
321
|
if (node.nodeType == 3) {
|
|
@@ -345,13 +345,14 @@ export function coordsAtPos(view: EditorView, pos: number, side: number): Rect {
|
|
|
345
345
|
}
|
|
346
346
|
}
|
|
347
347
|
|
|
348
|
+
let $dom = view.state.doc.resolve(pos - (atom || 0))
|
|
348
349
|
// Return a horizontal line in block context
|
|
349
|
-
if (
|
|
350
|
-
if (offset && (side < 0 || offset == nodeSize(node))) {
|
|
350
|
+
if (!$dom.parent.inlineContent) {
|
|
351
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
351
352
|
let before = node.childNodes[offset - 1]
|
|
352
353
|
if (before.nodeType == 1) return flattenH((before as HTMLElement).getBoundingClientRect(), false)
|
|
353
354
|
}
|
|
354
|
-
if (offset < nodeSize(node)) {
|
|
355
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
355
356
|
let after = node.childNodes[offset]
|
|
356
357
|
if (after.nodeType == 1) return flattenH((after as HTMLElement).getBoundingClientRect(), true)
|
|
357
358
|
}
|
|
@@ -359,7 +360,7 @@ export function coordsAtPos(view: EditorView, pos: number, side: number): Rect {
|
|
|
359
360
|
}
|
|
360
361
|
|
|
361
362
|
// Inline, not in text node (this is not Bidi-safe)
|
|
362
|
-
if (offset && (side < 0 || offset == nodeSize(node))) {
|
|
363
|
+
if (atom == null && offset && (side < 0 || offset == nodeSize(node))) {
|
|
363
364
|
let before = node.childNodes[offset - 1]
|
|
364
365
|
let target = before.nodeType == 3 ? textRange(before as Text, nodeSize(before) - (supportEmptyRange ? 0 : 1))
|
|
365
366
|
// BR nodes tend to only return the rectangle before them.
|
|
@@ -367,7 +368,7 @@ export function coordsAtPos(view: EditorView, pos: number, side: number): Rect {
|
|
|
367
368
|
: before.nodeType == 1 && (before.nodeName != "BR" || !before.nextSibling) ? before : null
|
|
368
369
|
if (target) return flattenV(singleRect(target as Range | HTMLElement, 1), false)
|
|
369
370
|
}
|
|
370
|
-
if (offset < nodeSize(node)) {
|
|
371
|
+
if (atom == null && offset < nodeSize(node)) {
|
|
371
372
|
let after = node.childNodes[offset]
|
|
372
373
|
while (after.pmViewDesc && after.pmViewDesc.ignoreForCoords) after = after.nextSibling!
|
|
373
374
|
let target = !after ? null : after.nodeType == 3 ? textRange(after as Text, 0, (supportEmptyRange ? 0 : 1))
|
package/src/index.ts
CHANGED
|
@@ -512,7 +512,7 @@ type NodeViewSet = {[name: string]: NodeViewConstructor | MarkViewConstructor}
|
|
|
512
512
|
/// includes events that TypeScript's HTMLElementEventMap doesn't know
|
|
513
513
|
/// about.
|
|
514
514
|
export interface DOMEventMap extends HTMLElementEventMap {
|
|
515
|
-
[event: string]:
|
|
515
|
+
[event: string]: any
|
|
516
516
|
}
|
|
517
517
|
|
|
518
518
|
/// Props are configuration values that can be passed to an editor view
|
|
@@ -528,7 +528,11 @@ export interface DOMEventMap extends HTMLElementEventMap {
|
|
|
528
528
|
/// searching through the plugins (in order of appearance) until one of
|
|
529
529
|
/// them returns true. For some props, the first plugin that yields a
|
|
530
530
|
/// value gets precedence.
|
|
531
|
-
|
|
531
|
+
///
|
|
532
|
+
/// The optional type parameter refers to the type of `this` in prop
|
|
533
|
+
/// functions, and is used to pass in the plugin type when defining a
|
|
534
|
+
/// [plugin](#state.Plugin).
|
|
535
|
+
export interface EditorProps<P = any> {
|
|
532
536
|
/// Can be an object mapping DOM event type names to functions that
|
|
533
537
|
/// handle them. Such functions will be called before any handling
|
|
534
538
|
/// ProseMirror does of events fired on the editable DOM element.
|
|
@@ -537,59 +541,59 @@ export interface EditorProps {
|
|
|
537
541
|
/// `preventDefault` yourself (or not, if you want to allow the
|
|
538
542
|
/// default behavior).
|
|
539
543
|
handleDOMEvents?: {
|
|
540
|
-
[event in keyof DOMEventMap]?: (view: EditorView, event: DOMEventMap[event]) => boolean | void
|
|
544
|
+
[event in keyof DOMEventMap]?: (this: P, view: EditorView, event: DOMEventMap[event]) => boolean | void
|
|
541
545
|
}
|
|
542
546
|
|
|
543
547
|
/// Called when the editor receives a `keydown` event.
|
|
544
|
-
handleKeyDown?: (view: EditorView, event: KeyboardEvent) => boolean | void
|
|
548
|
+
handleKeyDown?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void
|
|
545
549
|
|
|
546
550
|
/// Handler for `keypress` events.
|
|
547
|
-
handleKeyPress?: (view: EditorView, event: KeyboardEvent) => boolean | void
|
|
551
|
+
handleKeyPress?: (this: P, view: EditorView, event: KeyboardEvent) => boolean | void
|
|
548
552
|
|
|
549
553
|
/// Whenever the user directly input text, this handler is called
|
|
550
554
|
/// before the input is applied. If it returns `true`, the default
|
|
551
555
|
/// behavior of actually inserting the text is suppressed.
|
|
552
|
-
handleTextInput?: (view: EditorView, from: number, to: number, text: string) => boolean | void
|
|
556
|
+
handleTextInput?: (this: P, view: EditorView, from: number, to: number, text: string) => boolean | void
|
|
553
557
|
|
|
554
558
|
/// Called for each node around a click, from the inside out. The
|
|
555
559
|
/// `direct` flag will be true for the inner node.
|
|
556
|
-
handleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
560
|
+
handleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
557
561
|
|
|
558
562
|
/// Called when the editor is clicked, after `handleClickOn` handlers
|
|
559
563
|
/// have been called.
|
|
560
|
-
handleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
564
|
+
handleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
561
565
|
|
|
562
566
|
/// Called for each node around a double click.
|
|
563
|
-
handleDoubleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
567
|
+
handleDoubleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
564
568
|
|
|
565
569
|
/// Called when the editor is double-clicked, after `handleDoubleClickOn`.
|
|
566
|
-
handleDoubleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
570
|
+
handleDoubleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
567
571
|
|
|
568
572
|
/// Called for each node around a triple click.
|
|
569
|
-
handleTripleClickOn?: (view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
573
|
+
handleTripleClickOn?: (this: P, view: EditorView, pos: number, node: Node, nodePos: number, event: MouseEvent, direct: boolean) => boolean | void
|
|
570
574
|
|
|
571
575
|
/// Called when the editor is triple-clicked, after `handleTripleClickOn`.
|
|
572
|
-
handleTripleClick?: (view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
576
|
+
handleTripleClick?: (this: P, view: EditorView, pos: number, event: MouseEvent) => boolean | void
|
|
573
577
|
|
|
574
578
|
/// Can be used to override the behavior of pasting. `slice` is the
|
|
575
579
|
/// pasted content parsed by the editor, but you can directly access
|
|
576
580
|
/// the event to get at the raw content.
|
|
577
|
-
handlePaste?: (view: EditorView, event: ClipboardEvent, slice: Slice) => boolean | void
|
|
581
|
+
handlePaste?: (this: P, view: EditorView, event: ClipboardEvent, slice: Slice) => boolean | void
|
|
578
582
|
|
|
579
583
|
/// Called when something is dropped on the editor. `moved` will be
|
|
580
584
|
/// true if this drop moves from the current selection (which should
|
|
581
585
|
/// thus be deleted).
|
|
582
|
-
handleDrop?: (view: EditorView, event: DragEvent, slice: Slice, moved: boolean) => boolean | void
|
|
586
|
+
handleDrop?: (this: P, view: EditorView, event: DragEvent, slice: Slice, moved: boolean) => boolean | void
|
|
583
587
|
|
|
584
588
|
/// Called when the view, after updating its state, tries to scroll
|
|
585
589
|
/// the selection into view. A handler function may return false to
|
|
586
590
|
/// indicate that it did not handle the scrolling and further
|
|
587
591
|
/// handlers or the default behavior should be tried.
|
|
588
|
-
handleScrollToSelection?: (view: EditorView) => boolean
|
|
592
|
+
handleScrollToSelection?: (this: P, view: EditorView) => boolean
|
|
589
593
|
|
|
590
594
|
/// Can be used to override the way a selection is created when
|
|
591
595
|
/// reading a DOM selection between the given anchor and head.
|
|
592
|
-
createSelectionBetween?: (view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null
|
|
596
|
+
createSelectionBetween?: (this: P, view: EditorView, anchor: ResolvedPos, head: ResolvedPos) => Selection | null
|
|
593
597
|
|
|
594
598
|
/// The [parser](#model.DOMParser) to use when reading editor changes
|
|
595
599
|
/// from the DOM. Defaults to calling
|
|
@@ -599,7 +603,7 @@ export interface EditorProps {
|
|
|
599
603
|
|
|
600
604
|
/// Can be used to transform pasted HTML text, _before_ it is parsed,
|
|
601
605
|
/// for example to clean it up.
|
|
602
|
-
transformPastedHTML?: (html: string) => string
|
|
606
|
+
transformPastedHTML?: (this: P, html: string) => string
|
|
603
607
|
|
|
604
608
|
/// The [parser](#model.DOMParser) to use when reading content from
|
|
605
609
|
/// the clipboard. When not given, the value of the
|
|
@@ -608,7 +612,7 @@ export interface EditorProps {
|
|
|
608
612
|
|
|
609
613
|
/// Transform pasted plain text. The `plain` flag will be true when
|
|
610
614
|
/// the text is pasted as plain text.
|
|
611
|
-
transformPastedText?: (text: string, plain: boolean) => string
|
|
615
|
+
transformPastedText?: (this: P, text: string, plain: boolean) => string
|
|
612
616
|
|
|
613
617
|
/// A function to parse text from the clipboard into a document
|
|
614
618
|
/// slice. Called after
|
|
@@ -617,11 +621,11 @@ export interface EditorProps {
|
|
|
617
621
|
/// in `<p>` tags, and call
|
|
618
622
|
/// [`clipboardParser`](#view.EditorProps.clipboardParser) on it.
|
|
619
623
|
/// The `plain` flag will be true when the text is pasted as plain text.
|
|
620
|
-
clipboardTextParser?: (text: string, $context: ResolvedPos, plain: boolean) => Slice
|
|
624
|
+
clipboardTextParser?: (this: P, text: string, $context: ResolvedPos, plain: boolean) => Slice
|
|
621
625
|
|
|
622
626
|
/// Can be used to transform pasted content before it is applied to
|
|
623
627
|
/// the document.
|
|
624
|
-
transformPasted?: (slice: Slice) => Slice
|
|
628
|
+
transformPasted?: (this: P, slice: Slice) => Slice
|
|
625
629
|
|
|
626
630
|
/// Allows you to pass custom rendering and behavior logic for
|
|
627
631
|
/// nodes. Should map node names to constructor functions that
|
|
@@ -668,15 +672,15 @@ export interface EditorProps {
|
|
|
668
672
|
/// selection when copying text to the clipboard. By default, the
|
|
669
673
|
/// editor will use [`textBetween`](#model.Node.textBetween) on the
|
|
670
674
|
/// selected range.
|
|
671
|
-
clipboardTextSerializer?: (content: Slice) => string
|
|
675
|
+
clipboardTextSerializer?: (this: P, content: Slice) => string
|
|
672
676
|
|
|
673
677
|
/// A set of [document decorations](#view.Decoration) to show in the
|
|
674
678
|
/// view.
|
|
675
|
-
decorations?: (state: EditorState) => DecorationSource | null | undefined
|
|
679
|
+
decorations?: (this: P, state: EditorState) => DecorationSource | null | undefined
|
|
676
680
|
|
|
677
681
|
/// When this returns false, the content of the view is not directly
|
|
678
682
|
/// editable.
|
|
679
|
-
editable?: (state: EditorState) => boolean
|
|
683
|
+
editable?: (this: P, state: EditorState) => boolean
|
|
680
684
|
|
|
681
685
|
/// Control the DOM attributes of the editable element. May be either
|
|
682
686
|
/// an object or a function going from an editor state to an object.
|
package/src/viewdesc.ts
CHANGED
|
@@ -262,8 +262,8 @@ export class ViewDesc {
|
|
|
262
262
|
}
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
-
domFromPos(pos: number, side: number): {node: DOMNode, offset: number} {
|
|
266
|
-
if (!this.contentDOM) return {node: this.dom, offset: 0}
|
|
265
|
+
domFromPos(pos: number, side: number): {node: DOMNode, offset: number, atom?: number} {
|
|
266
|
+
if (!this.contentDOM) return {node: this.dom, offset: 0, atom: pos + 1}
|
|
267
267
|
// First find the position in the child array
|
|
268
268
|
let i = 0, offset = 0
|
|
269
269
|
for (let curPos = 0; i < this.children.length; i++) {
|
|
@@ -1196,7 +1196,7 @@ class ViewTreeUpdater {
|
|
|
1196
1196
|
if (child.dirty == NODE_DIRTY && child.dom == child.contentDOM) child.dirty = CONTENT_DIRTY
|
|
1197
1197
|
if (!child.update(node, outerDeco, innerDeco, view)) return false
|
|
1198
1198
|
this.destroyBetween(this.index, index)
|
|
1199
|
-
this.index
|
|
1199
|
+
this.index++
|
|
1200
1200
|
return true
|
|
1201
1201
|
}
|
|
1202
1202
|
|