@codemirror/view 6.14.1 → 6.15.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 +24 -0
- package/dist/index.cjs +366 -378
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +367 -379
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection,
|
|
1
|
+
import { EditorState, Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, findColumn, CharCategory, Annotation, Prec, Transaction, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
3
|
import { keyName, base, shift } from 'w3c-keyname';
|
|
4
4
|
|
|
@@ -96,13 +96,15 @@ function windowRect(win) {
|
|
|
96
96
|
}
|
|
97
97
|
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
98
98
|
let doc = dom.ownerDocument, win = doc.defaultView || window;
|
|
99
|
-
for (let cur = dom; cur;) {
|
|
99
|
+
for (let cur = dom, stop = false; cur && !stop;) {
|
|
100
100
|
if (cur.nodeType == 1) { // Element
|
|
101
101
|
let bounding, top = cur == doc.body;
|
|
102
102
|
if (top) {
|
|
103
103
|
bounding = windowRect(win);
|
|
104
104
|
}
|
|
105
105
|
else {
|
|
106
|
+
if (/^(fixed|sticky)$/.test(getComputedStyle(cur).position))
|
|
107
|
+
stop = true;
|
|
106
108
|
if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
|
|
107
109
|
cur = cur.assignedSlot || cur.parentNode;
|
|
108
110
|
continue;
|
|
@@ -334,7 +336,7 @@ class ContentView {
|
|
|
334
336
|
constructor() {
|
|
335
337
|
this.parent = null;
|
|
336
338
|
this.dom = null;
|
|
337
|
-
this.
|
|
339
|
+
this.flags = 2 /* NodeDirty */;
|
|
338
340
|
}
|
|
339
341
|
get overrideDOMText() { return null; }
|
|
340
342
|
get posAtStart() {
|
|
@@ -356,18 +358,18 @@ class ContentView {
|
|
|
356
358
|
return this.posBefore(view) + view.length;
|
|
357
359
|
}
|
|
358
360
|
sync(view, track) {
|
|
359
|
-
if (this.
|
|
361
|
+
if (this.flags & 2 /* NodeDirty */) {
|
|
360
362
|
let parent = this.dom;
|
|
361
363
|
let prev = null, next;
|
|
362
364
|
for (let child of this.children) {
|
|
363
|
-
if (child.
|
|
364
|
-
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)
|
|
365
|
+
if (child.flags & 7 /* Dirty */) {
|
|
366
|
+
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
|
365
367
|
let contentView = ContentView.get(next);
|
|
366
368
|
if (!contentView || !contentView.parent && contentView.canReuseDOM(child))
|
|
367
369
|
child.reuseDOM(next);
|
|
368
370
|
}
|
|
369
371
|
child.sync(view, track);
|
|
370
|
-
child.
|
|
372
|
+
child.flags &= ~7 /* Dirty */;
|
|
371
373
|
}
|
|
372
374
|
next = prev ? prev.nextSibling : parent.firstChild;
|
|
373
375
|
if (track && !track.written && track.node == parent && next != child.dom)
|
|
@@ -387,11 +389,11 @@ class ContentView {
|
|
|
387
389
|
while (next)
|
|
388
390
|
next = rm$1(next);
|
|
389
391
|
}
|
|
390
|
-
else if (this.
|
|
392
|
+
else if (this.flags & 1 /* ChildDirty */) {
|
|
391
393
|
for (let child of this.children)
|
|
392
|
-
if (child.
|
|
394
|
+
if (child.flags & 7 /* Dirty */) {
|
|
393
395
|
child.sync(view, track);
|
|
394
|
-
child.
|
|
396
|
+
child.flags &= ~7 /* Dirty */;
|
|
395
397
|
}
|
|
396
398
|
}
|
|
397
399
|
}
|
|
@@ -456,23 +458,23 @@ class ContentView {
|
|
|
456
458
|
endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null };
|
|
457
459
|
}
|
|
458
460
|
markDirty(andParent = false) {
|
|
459
|
-
this.
|
|
461
|
+
this.flags |= 2 /* NodeDirty */;
|
|
460
462
|
this.markParentsDirty(andParent);
|
|
461
463
|
}
|
|
462
464
|
markParentsDirty(childList) {
|
|
463
465
|
for (let parent = this.parent; parent; parent = parent.parent) {
|
|
464
466
|
if (childList)
|
|
465
|
-
parent.
|
|
466
|
-
if (parent.
|
|
467
|
+
parent.flags |= 2 /* NodeDirty */;
|
|
468
|
+
if (parent.flags & 1 /* ChildDirty */)
|
|
467
469
|
return;
|
|
468
|
-
parent.
|
|
470
|
+
parent.flags |= 1 /* ChildDirty */;
|
|
469
471
|
childList = false;
|
|
470
472
|
}
|
|
471
473
|
}
|
|
472
474
|
setParent(parent) {
|
|
473
475
|
if (this.parent != parent) {
|
|
474
476
|
this.parent = parent;
|
|
475
|
-
if (this.
|
|
477
|
+
if (this.flags & 7 /* Dirty */)
|
|
476
478
|
this.markParentsDirty(true);
|
|
477
479
|
}
|
|
478
480
|
}
|
|
@@ -523,7 +525,9 @@ class ContentView {
|
|
|
523
525
|
return false;
|
|
524
526
|
}
|
|
525
527
|
become(other) { return false; }
|
|
526
|
-
canReuseDOM(other) {
|
|
528
|
+
canReuseDOM(other) {
|
|
529
|
+
return other.constructor == this.constructor && !((this.flags | other.flags) & 8 /* Composition */);
|
|
530
|
+
}
|
|
527
531
|
// When this is a zero-length view with a side, this should return a
|
|
528
532
|
// number <= 0 to indicate it is before its position, or a
|
|
529
533
|
// number > 0 when after its position.
|
|
@@ -647,6 +651,113 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
647
651
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
648
652
|
}
|
|
649
653
|
|
|
654
|
+
const LineBreakPlaceholder = "\uffff";
|
|
655
|
+
class DOMReader {
|
|
656
|
+
constructor(points, state) {
|
|
657
|
+
this.points = points;
|
|
658
|
+
this.text = "";
|
|
659
|
+
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
660
|
+
}
|
|
661
|
+
append(text) {
|
|
662
|
+
this.text += text;
|
|
663
|
+
}
|
|
664
|
+
lineBreak() {
|
|
665
|
+
this.text += LineBreakPlaceholder;
|
|
666
|
+
}
|
|
667
|
+
readRange(start, end) {
|
|
668
|
+
if (!start)
|
|
669
|
+
return this;
|
|
670
|
+
let parent = start.parentNode;
|
|
671
|
+
for (let cur = start;;) {
|
|
672
|
+
this.findPointBefore(parent, cur);
|
|
673
|
+
let oldLen = this.text.length;
|
|
674
|
+
this.readNode(cur);
|
|
675
|
+
let next = cur.nextSibling;
|
|
676
|
+
if (next == end)
|
|
677
|
+
break;
|
|
678
|
+
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
679
|
+
if (view && nextView ? view.breakAfter :
|
|
680
|
+
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
681
|
+
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
682
|
+
this.lineBreak();
|
|
683
|
+
cur = next;
|
|
684
|
+
}
|
|
685
|
+
this.findPointBefore(parent, end);
|
|
686
|
+
return this;
|
|
687
|
+
}
|
|
688
|
+
readTextNode(node) {
|
|
689
|
+
let text = node.nodeValue;
|
|
690
|
+
for (let point of this.points)
|
|
691
|
+
if (point.node == node)
|
|
692
|
+
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
693
|
+
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
694
|
+
let nextBreak = -1, breakSize = 1, m;
|
|
695
|
+
if (this.lineSeparator) {
|
|
696
|
+
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
697
|
+
breakSize = this.lineSeparator.length;
|
|
698
|
+
}
|
|
699
|
+
else if (m = re.exec(text)) {
|
|
700
|
+
nextBreak = m.index;
|
|
701
|
+
breakSize = m[0].length;
|
|
702
|
+
}
|
|
703
|
+
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
704
|
+
if (nextBreak < 0)
|
|
705
|
+
break;
|
|
706
|
+
this.lineBreak();
|
|
707
|
+
if (breakSize > 1)
|
|
708
|
+
for (let point of this.points)
|
|
709
|
+
if (point.node == node && point.pos > this.text.length)
|
|
710
|
+
point.pos -= breakSize - 1;
|
|
711
|
+
off = nextBreak + breakSize;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
readNode(node) {
|
|
715
|
+
if (node.cmIgnore)
|
|
716
|
+
return;
|
|
717
|
+
let view = ContentView.get(node);
|
|
718
|
+
let fromView = view && view.overrideDOMText;
|
|
719
|
+
if (fromView != null) {
|
|
720
|
+
this.findPointInside(node, fromView.length);
|
|
721
|
+
for (let i = fromView.iter(); !i.next().done;) {
|
|
722
|
+
if (i.lineBreak)
|
|
723
|
+
this.lineBreak();
|
|
724
|
+
else
|
|
725
|
+
this.append(i.value);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
else if (node.nodeType == 3) {
|
|
729
|
+
this.readTextNode(node);
|
|
730
|
+
}
|
|
731
|
+
else if (node.nodeName == "BR") {
|
|
732
|
+
if (node.nextSibling)
|
|
733
|
+
this.lineBreak();
|
|
734
|
+
}
|
|
735
|
+
else if (node.nodeType == 1) {
|
|
736
|
+
this.readRange(node.firstChild, null);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
findPointBefore(node, next) {
|
|
740
|
+
for (let point of this.points)
|
|
741
|
+
if (point.node == node && node.childNodes[point.offset] == next)
|
|
742
|
+
point.pos = this.text.length;
|
|
743
|
+
}
|
|
744
|
+
findPointInside(node, maxLen) {
|
|
745
|
+
for (let point of this.points)
|
|
746
|
+
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
747
|
+
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
function isBlockElement(node) {
|
|
751
|
+
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
752
|
+
}
|
|
753
|
+
class DOMPoint {
|
|
754
|
+
constructor(node, offset) {
|
|
755
|
+
this.node = node;
|
|
756
|
+
this.offset = offset;
|
|
757
|
+
this.pos = -1;
|
|
758
|
+
}
|
|
759
|
+
}
|
|
760
|
+
|
|
650
761
|
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
651
762
|
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
652
763
|
const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
|
|
@@ -700,7 +811,10 @@ class TextView extends ContentView {
|
|
|
700
811
|
this.createDOM(dom);
|
|
701
812
|
}
|
|
702
813
|
merge(from, to, source) {
|
|
703
|
-
if (
|
|
814
|
+
if ((this.flags & 8 /* Composition */) ||
|
|
815
|
+
source && (!(source instanceof TextView) ||
|
|
816
|
+
this.length - (to - from) + source.length > MaxJoinLen ||
|
|
817
|
+
(source.flags & 8 /* Composition */)))
|
|
704
818
|
return false;
|
|
705
819
|
this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to);
|
|
706
820
|
this.markDirty();
|
|
@@ -710,6 +824,7 @@ class TextView extends ContentView {
|
|
|
710
824
|
let result = new TextView(this.text.slice(from));
|
|
711
825
|
this.text = this.text.slice(0, from);
|
|
712
826
|
this.markDirty();
|
|
827
|
+
result.flags |= this.flags & 8 /* Composition */;
|
|
713
828
|
return result;
|
|
714
829
|
}
|
|
715
830
|
localPosFromDOM(node, offset) {
|
|
@@ -741,16 +856,19 @@ class MarkView extends ContentView {
|
|
|
741
856
|
dom.setAttribute(name, this.mark.attrs[name]);
|
|
742
857
|
return dom;
|
|
743
858
|
}
|
|
859
|
+
canReuseDOM(other) {
|
|
860
|
+
return super.canReuseDOM(other) && !((this.flags | other.flags) & 8 /* Composition */);
|
|
861
|
+
}
|
|
744
862
|
reuseDOM(node) {
|
|
745
863
|
if (node.nodeName == this.mark.tagName.toUpperCase()) {
|
|
746
864
|
this.setDOM(node);
|
|
747
|
-
this.
|
|
865
|
+
this.flags |= 4 /* AttrsDirty */ | 2 /* NodeDirty */;
|
|
748
866
|
}
|
|
749
867
|
}
|
|
750
868
|
sync(view, track) {
|
|
751
869
|
if (!this.dom)
|
|
752
870
|
this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
|
|
753
|
-
else if (this.
|
|
871
|
+
else if (this.flags & 4 /* AttrsDirty */)
|
|
754
872
|
this.setAttrs(this.dom);
|
|
755
873
|
super.sync(view, track);
|
|
756
874
|
}
|
|
@@ -829,7 +947,7 @@ class WidgetView extends ContentView {
|
|
|
829
947
|
this.prevWidget = null;
|
|
830
948
|
}
|
|
831
949
|
static create(widget, length, side) {
|
|
832
|
-
return new
|
|
950
|
+
return new WidgetView(widget, length, side);
|
|
833
951
|
}
|
|
834
952
|
split(from) {
|
|
835
953
|
let result = WidgetView.create(this.widget, this.length - from, this.side);
|
|
@@ -907,129 +1025,6 @@ class WidgetView extends ContentView {
|
|
|
907
1025
|
this.widget.destroy(this.dom);
|
|
908
1026
|
}
|
|
909
1027
|
}
|
|
910
|
-
class CompositionView extends WidgetView {
|
|
911
|
-
domAtPos(pos) {
|
|
912
|
-
let { topView, text } = this.widget;
|
|
913
|
-
if (!topView)
|
|
914
|
-
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
915
|
-
return scanCompositionTree(pos, 0, topView, text, this.length - topView.length, (v, p) => v.domAtPos(p), (text, p) => new DOMPos(text, Math.min(p, text.nodeValue.length)));
|
|
916
|
-
}
|
|
917
|
-
sync() { this.setDOM(this.widget.toDOM()); }
|
|
918
|
-
localPosFromDOM(node, offset) {
|
|
919
|
-
let { topView, text } = this.widget;
|
|
920
|
-
if (!topView)
|
|
921
|
-
return Math.min(offset, this.length);
|
|
922
|
-
return posFromDOMInCompositionTree(node, offset, topView, text, this.length - topView.length);
|
|
923
|
-
}
|
|
924
|
-
ignoreMutation() { return false; }
|
|
925
|
-
get overrideDOMText() { return null; }
|
|
926
|
-
coordsAt(pos, side) {
|
|
927
|
-
let { topView, text } = this.widget;
|
|
928
|
-
if (!topView)
|
|
929
|
-
return textCoords(text, pos, side);
|
|
930
|
-
return scanCompositionTree(pos, side, topView, text, this.length - topView.length, (v, pos, side) => v.coordsAt(pos, side), (text, pos, side) => textCoords(text, pos, side));
|
|
931
|
-
}
|
|
932
|
-
destroy() {
|
|
933
|
-
var _a;
|
|
934
|
-
super.destroy();
|
|
935
|
-
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
936
|
-
}
|
|
937
|
-
get isEditable() { return true; }
|
|
938
|
-
canReuseDOM() { return true; }
|
|
939
|
-
}
|
|
940
|
-
// Uses the old structure of a chunk of content view frozen for
|
|
941
|
-
// composition to try and find a reasonable DOM location for the given
|
|
942
|
-
// offset.
|
|
943
|
-
function scanCompositionTree(pos, side, view, text, dLen, enterView, fromText) {
|
|
944
|
-
if (view instanceof MarkView) {
|
|
945
|
-
for (let child = view.dom.firstChild; child; child = child.nextSibling) {
|
|
946
|
-
let desc = ContentView.get(child);
|
|
947
|
-
if (!desc) {
|
|
948
|
-
let inner = scanCompositionNode(pos, side, child, fromText);
|
|
949
|
-
if (typeof inner != "number")
|
|
950
|
-
return inner;
|
|
951
|
-
pos = inner;
|
|
952
|
-
}
|
|
953
|
-
else {
|
|
954
|
-
let hasComp = contains(child, text);
|
|
955
|
-
let len = desc.length + (hasComp ? dLen : 0);
|
|
956
|
-
if (pos < len || pos == len && desc.getSide() <= 0)
|
|
957
|
-
return hasComp ? scanCompositionTree(pos, side, desc, text, dLen, enterView, fromText) : enterView(desc, pos, side);
|
|
958
|
-
pos -= len;
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
return enterView(view, view.length, -1);
|
|
962
|
-
}
|
|
963
|
-
else if (view.dom == text) {
|
|
964
|
-
return fromText(text, pos, side);
|
|
965
|
-
}
|
|
966
|
-
else {
|
|
967
|
-
return enterView(view, pos, side);
|
|
968
|
-
}
|
|
969
|
-
}
|
|
970
|
-
function scanCompositionNode(pos, side, node, fromText) {
|
|
971
|
-
if (node.nodeType == 3) {
|
|
972
|
-
let len = node.nodeValue.length;
|
|
973
|
-
if (pos <= len)
|
|
974
|
-
return fromText(node, pos, side);
|
|
975
|
-
pos -= len;
|
|
976
|
-
}
|
|
977
|
-
else if (node.nodeType == 1 && node.contentEditable != "false") {
|
|
978
|
-
for (let child = node.firstChild; child; child = child.nextSibling) {
|
|
979
|
-
let inner = scanCompositionNode(pos, side, child, fromText);
|
|
980
|
-
if (typeof inner != "number")
|
|
981
|
-
return inner;
|
|
982
|
-
pos = inner;
|
|
983
|
-
}
|
|
984
|
-
}
|
|
985
|
-
return pos;
|
|
986
|
-
}
|
|
987
|
-
function posFromDOMInCompositionTree(node, offset, view, text, dLen) {
|
|
988
|
-
if (view instanceof MarkView) {
|
|
989
|
-
let pos = 0;
|
|
990
|
-
for (let child = view.dom.firstChild; child; child = child.nextSibling) {
|
|
991
|
-
let childView = ContentView.get(child);
|
|
992
|
-
if (childView) {
|
|
993
|
-
let hasComp = contains(child, text);
|
|
994
|
-
if (contains(child, node))
|
|
995
|
-
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, childView, text, dLen)
|
|
996
|
-
: childView.localPosFromDOM(node, offset));
|
|
997
|
-
pos += childView.length + (hasComp ? dLen : 0);
|
|
998
|
-
}
|
|
999
|
-
else {
|
|
1000
|
-
let inner = posFromDOMInOpaqueNode(node, offset, child);
|
|
1001
|
-
if (inner.result != null)
|
|
1002
|
-
return pos + inner.result;
|
|
1003
|
-
pos += inner.size;
|
|
1004
|
-
}
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
else if (view.dom == text) {
|
|
1008
|
-
return Math.min(offset, text.nodeValue.length);
|
|
1009
|
-
}
|
|
1010
|
-
return view.localPosFromDOM(node, offset);
|
|
1011
|
-
}
|
|
1012
|
-
function posFromDOMInOpaqueNode(node, offset, target) {
|
|
1013
|
-
if (target.nodeType == 3) {
|
|
1014
|
-
return node == target ? { result: offset } : { size: target.nodeValue.length };
|
|
1015
|
-
}
|
|
1016
|
-
else if (target.nodeType == 1 && target.contentEditable != "false") {
|
|
1017
|
-
let pos = 0;
|
|
1018
|
-
for (let child = target.firstChild, i = 0;; child = child.nextSibling, i++) {
|
|
1019
|
-
if (node == target && i == offset)
|
|
1020
|
-
return { result: pos };
|
|
1021
|
-
if (!child)
|
|
1022
|
-
return { size: pos };
|
|
1023
|
-
let inner = posFromDOMInOpaqueNode(node, offset, child);
|
|
1024
|
-
if (inner.result != null)
|
|
1025
|
-
return { result: offset + inner.result };
|
|
1026
|
-
pos += inner.size;
|
|
1027
|
-
}
|
|
1028
|
-
}
|
|
1029
|
-
else {
|
|
1030
|
-
return target.contains(node) ? { result: 0 } : { size: 0 };
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
1028
|
// These are drawn around uneditable widgets to avoid a number of
|
|
1034
1029
|
// browser bugs that show up when the cursor is directly next to
|
|
1035
1030
|
// uneditable inline content.
|
|
@@ -1149,16 +1144,20 @@ function combineAttrs(source, target) {
|
|
|
1149
1144
|
}
|
|
1150
1145
|
return target;
|
|
1151
1146
|
}
|
|
1152
|
-
|
|
1147
|
+
const noAttrs = /*@__PURE__*/Object.create(null);
|
|
1148
|
+
function attrsEq(a, b, ignore) {
|
|
1153
1149
|
if (a == b)
|
|
1154
1150
|
return true;
|
|
1155
|
-
if (!a
|
|
1156
|
-
|
|
1151
|
+
if (!a)
|
|
1152
|
+
a = noAttrs;
|
|
1153
|
+
if (!b)
|
|
1154
|
+
b = noAttrs;
|
|
1157
1155
|
let keysA = Object.keys(a), keysB = Object.keys(b);
|
|
1158
|
-
if (keysA.length
|
|
1156
|
+
if (keysA.length - (ignore && keysA.indexOf(ignore) > -1 ? 1 : 0) !=
|
|
1157
|
+
keysB.length - (ignore && keysB.indexOf(ignore) > -1 ? 1 : 0))
|
|
1159
1158
|
return false;
|
|
1160
1159
|
for (let key of keysA) {
|
|
1161
|
-
if (keysB.indexOf(key) == -1 || a[key] !== b[key])
|
|
1160
|
+
if (key != ignore && (keysB.indexOf(key) == -1 || a[key] !== b[key]))
|
|
1162
1161
|
return false;
|
|
1163
1162
|
}
|
|
1164
1163
|
return true;
|
|
@@ -1175,6 +1174,14 @@ function updateAttrs(dom, prev, attrs) {
|
|
|
1175
1174
|
dom.setAttribute(changed = name, attrs[name]);
|
|
1176
1175
|
return !!changed;
|
|
1177
1176
|
}
|
|
1177
|
+
function getAttrs(dom) {
|
|
1178
|
+
let attrs = Object.create(null);
|
|
1179
|
+
for (let i = 0; i < dom.attributes.length; i++) {
|
|
1180
|
+
let attr = dom.attributes[i];
|
|
1181
|
+
attrs[attr.name] = attr.value;
|
|
1182
|
+
}
|
|
1183
|
+
return attrs;
|
|
1184
|
+
}
|
|
1178
1185
|
|
|
1179
1186
|
/**
|
|
1180
1187
|
Widgets added to the content are described by subclasses of this
|
|
@@ -1239,10 +1246,6 @@ class WidgetType {
|
|
|
1239
1246
|
/**
|
|
1240
1247
|
@internal
|
|
1241
1248
|
*/
|
|
1242
|
-
get customView() { return null; }
|
|
1243
|
-
/**
|
|
1244
|
-
@internal
|
|
1245
|
-
*/
|
|
1246
1249
|
get isHidden() { return false; }
|
|
1247
1250
|
/**
|
|
1248
1251
|
This is called when the an instance of the widget is removed
|
|
@@ -1380,11 +1383,12 @@ class MarkDecoration extends Decoration {
|
|
|
1380
1383
|
this.attrs = spec.attributes || null;
|
|
1381
1384
|
}
|
|
1382
1385
|
eq(other) {
|
|
1386
|
+
var _a, _b;
|
|
1383
1387
|
return this == other ||
|
|
1384
1388
|
other instanceof MarkDecoration &&
|
|
1385
1389
|
this.tagName == other.tagName &&
|
|
1386
|
-
this.class == other.class &&
|
|
1387
|
-
attrsEq(this.attrs, other.attrs);
|
|
1390
|
+
(this.class || ((_a = this.attrs) === null || _a === void 0 ? void 0 : _a.class)) == (other.class || ((_b = other.attrs) === null || _b === void 0 ? void 0 : _b.class)) &&
|
|
1391
|
+
attrsEq(this.attrs, other.attrs, "class");
|
|
1388
1392
|
}
|
|
1389
1393
|
range(from, to = from) {
|
|
1390
1394
|
if (from >= to)
|
|
@@ -1536,7 +1540,7 @@ class LineView extends ContentView {
|
|
|
1536
1540
|
reuseDOM(node) {
|
|
1537
1541
|
if (node.nodeName == "DIV") {
|
|
1538
1542
|
this.setDOM(node);
|
|
1539
|
-
this.
|
|
1543
|
+
this.flags |= 4 /* AttrsDirty */ | 2 /* NodeDirty */;
|
|
1540
1544
|
}
|
|
1541
1545
|
}
|
|
1542
1546
|
sync(view, track) {
|
|
@@ -1546,7 +1550,7 @@ class LineView extends ContentView {
|
|
|
1546
1550
|
this.dom.className = "cm-line";
|
|
1547
1551
|
this.prevAttrs = this.attrs ? null : undefined;
|
|
1548
1552
|
}
|
|
1549
|
-
else if (this.
|
|
1553
|
+
else if (this.flags & 4 /* AttrsDirty */) {
|
|
1550
1554
|
clearAttributes(this.dom);
|
|
1551
1555
|
this.dom.className = "cm-line";
|
|
1552
1556
|
this.prevAttrs = this.attrs ? null : undefined;
|
|
@@ -2486,121 +2490,14 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
2486
2490
|
return EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
|
|
2487
2491
|
}
|
|
2488
2492
|
|
|
2489
|
-
const LineBreakPlaceholder = "\uffff";
|
|
2490
|
-
class DOMReader {
|
|
2491
|
-
constructor(points, state) {
|
|
2492
|
-
this.points = points;
|
|
2493
|
-
this.text = "";
|
|
2494
|
-
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
2495
|
-
}
|
|
2496
|
-
append(text) {
|
|
2497
|
-
this.text += text;
|
|
2498
|
-
}
|
|
2499
|
-
lineBreak() {
|
|
2500
|
-
this.text += LineBreakPlaceholder;
|
|
2501
|
-
}
|
|
2502
|
-
readRange(start, end) {
|
|
2503
|
-
if (!start)
|
|
2504
|
-
return this;
|
|
2505
|
-
let parent = start.parentNode;
|
|
2506
|
-
for (let cur = start;;) {
|
|
2507
|
-
this.findPointBefore(parent, cur);
|
|
2508
|
-
let oldLen = this.text.length;
|
|
2509
|
-
this.readNode(cur);
|
|
2510
|
-
let next = cur.nextSibling;
|
|
2511
|
-
if (next == end)
|
|
2512
|
-
break;
|
|
2513
|
-
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
2514
|
-
if (view && nextView ? view.breakAfter :
|
|
2515
|
-
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
2516
|
-
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
2517
|
-
this.lineBreak();
|
|
2518
|
-
cur = next;
|
|
2519
|
-
}
|
|
2520
|
-
this.findPointBefore(parent, end);
|
|
2521
|
-
return this;
|
|
2522
|
-
}
|
|
2523
|
-
readTextNode(node) {
|
|
2524
|
-
let text = node.nodeValue;
|
|
2525
|
-
for (let point of this.points)
|
|
2526
|
-
if (point.node == node)
|
|
2527
|
-
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
2528
|
-
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
2529
|
-
let nextBreak = -1, breakSize = 1, m;
|
|
2530
|
-
if (this.lineSeparator) {
|
|
2531
|
-
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
2532
|
-
breakSize = this.lineSeparator.length;
|
|
2533
|
-
}
|
|
2534
|
-
else if (m = re.exec(text)) {
|
|
2535
|
-
nextBreak = m.index;
|
|
2536
|
-
breakSize = m[0].length;
|
|
2537
|
-
}
|
|
2538
|
-
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
2539
|
-
if (nextBreak < 0)
|
|
2540
|
-
break;
|
|
2541
|
-
this.lineBreak();
|
|
2542
|
-
if (breakSize > 1)
|
|
2543
|
-
for (let point of this.points)
|
|
2544
|
-
if (point.node == node && point.pos > this.text.length)
|
|
2545
|
-
point.pos -= breakSize - 1;
|
|
2546
|
-
off = nextBreak + breakSize;
|
|
2547
|
-
}
|
|
2548
|
-
}
|
|
2549
|
-
readNode(node) {
|
|
2550
|
-
if (node.cmIgnore)
|
|
2551
|
-
return;
|
|
2552
|
-
let view = ContentView.get(node);
|
|
2553
|
-
let fromView = view && view.overrideDOMText;
|
|
2554
|
-
if (fromView != null) {
|
|
2555
|
-
this.findPointInside(node, fromView.length);
|
|
2556
|
-
for (let i = fromView.iter(); !i.next().done;) {
|
|
2557
|
-
if (i.lineBreak)
|
|
2558
|
-
this.lineBreak();
|
|
2559
|
-
else
|
|
2560
|
-
this.append(i.value);
|
|
2561
|
-
}
|
|
2562
|
-
}
|
|
2563
|
-
else if (node.nodeType == 3) {
|
|
2564
|
-
this.readTextNode(node);
|
|
2565
|
-
}
|
|
2566
|
-
else if (node.nodeName == "BR") {
|
|
2567
|
-
if (node.nextSibling)
|
|
2568
|
-
this.lineBreak();
|
|
2569
|
-
}
|
|
2570
|
-
else if (node.nodeType == 1) {
|
|
2571
|
-
this.readRange(node.firstChild, null);
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
findPointBefore(node, next) {
|
|
2575
|
-
for (let point of this.points)
|
|
2576
|
-
if (point.node == node && node.childNodes[point.offset] == next)
|
|
2577
|
-
point.pos = this.text.length;
|
|
2578
|
-
}
|
|
2579
|
-
findPointInside(node, maxLen) {
|
|
2580
|
-
for (let point of this.points)
|
|
2581
|
-
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
2582
|
-
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
function isBlockElement(node) {
|
|
2586
|
-
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
2587
|
-
}
|
|
2588
|
-
class DOMPoint {
|
|
2589
|
-
constructor(node, offset) {
|
|
2590
|
-
this.node = node;
|
|
2591
|
-
this.offset = offset;
|
|
2592
|
-
this.pos = -1;
|
|
2593
|
-
}
|
|
2594
|
-
}
|
|
2595
|
-
|
|
2596
2493
|
class DocView extends ContentView {
|
|
2597
2494
|
constructor(view) {
|
|
2598
2495
|
super();
|
|
2599
2496
|
this.view = view;
|
|
2600
|
-
this.compositionDeco = Decoration.none;
|
|
2601
|
-
this.compositionNode = null;
|
|
2602
2497
|
this.decorations = [];
|
|
2603
2498
|
this.dynamicDecorationMap = [];
|
|
2499
|
+
this.hasComposition = null;
|
|
2500
|
+
this.markedForComposition = new Set;
|
|
2604
2501
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2605
2502
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
2606
2503
|
// of a given element and its extent in the document. When a change
|
|
@@ -2623,7 +2520,7 @@ class DocView extends ContentView {
|
|
|
2623
2520
|
this.children = [new LineView];
|
|
2624
2521
|
this.children[0].setParent(this);
|
|
2625
2522
|
this.updateDeco();
|
|
2626
|
-
this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0);
|
|
2523
|
+
this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0, null);
|
|
2627
2524
|
}
|
|
2628
2525
|
get length() { return this.view.state.doc.length; }
|
|
2629
2526
|
// Update the document view to a given state.
|
|
@@ -2638,24 +2535,30 @@ class DocView extends ContentView {
|
|
|
2638
2535
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2639
2536
|
}
|
|
2640
2537
|
}
|
|
2641
|
-
|
|
2642
|
-
|
|
2538
|
+
let composition = this.view.inputState.composing < 0 ? null : findCompositionRange(this.view, update.changes);
|
|
2539
|
+
if (this.hasComposition) {
|
|
2540
|
+
this.markedForComposition.clear();
|
|
2541
|
+
let { from, to } = this.hasComposition;
|
|
2542
|
+
changedRanges = new ChangedRange(from, to, update.changes.mapPos(from, -1), update.changes.mapPos(to, 1))
|
|
2543
|
+
.addToSet(changedRanges.slice());
|
|
2544
|
+
}
|
|
2545
|
+
this.hasComposition = composition ? { from: composition.range.fromB, to: composition.range.toB } : null;
|
|
2643
2546
|
// When the DOM nodes around the selection are moved to another
|
|
2644
2547
|
// parent, Chrome sometimes reports a different selection through
|
|
2645
2548
|
// getSelection than the one that it actually shows to the user.
|
|
2646
2549
|
// This forces a selection update when lines are joined to work
|
|
2647
2550
|
// around that. Issue #54
|
|
2648
|
-
if ((browser.ie || browser.chrome) && !
|
|
2551
|
+
if ((browser.ie || browser.chrome) && !composition && update &&
|
|
2649
2552
|
update.state.doc.lines != update.startState.doc.lines)
|
|
2650
2553
|
this.forceSelection = true;
|
|
2651
2554
|
let prevDeco = this.decorations, deco = this.updateDeco();
|
|
2652
2555
|
let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
|
2653
2556
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
2654
|
-
if (this.
|
|
2557
|
+
if (!(this.flags & 7 /* Dirty */) && changedRanges.length == 0) {
|
|
2655
2558
|
return false;
|
|
2656
2559
|
}
|
|
2657
2560
|
else {
|
|
2658
|
-
this.updateInner(changedRanges, update.startState.doc.length);
|
|
2561
|
+
this.updateInner(changedRanges, update.startState.doc.length, composition);
|
|
2659
2562
|
if (update.transactions.length)
|
|
2660
2563
|
this.lastUpdate = Date.now();
|
|
2661
2564
|
return true;
|
|
@@ -2663,9 +2566,9 @@ class DocView extends ContentView {
|
|
|
2663
2566
|
}
|
|
2664
2567
|
// Used by update and the constructor do perform the actual DOM
|
|
2665
2568
|
// update
|
|
2666
|
-
updateInner(changes, oldLength) {
|
|
2569
|
+
updateInner(changes, oldLength, composition) {
|
|
2667
2570
|
this.view.viewState.mustMeasureContent = true;
|
|
2668
|
-
this.updateChildren(changes, oldLength);
|
|
2571
|
+
this.updateChildren(changes, oldLength, composition);
|
|
2669
2572
|
let { observer } = this.view;
|
|
2670
2573
|
observer.ignore(() => {
|
|
2671
2574
|
// Lock the height during redrawing, since Chrome sometimes
|
|
@@ -2680,11 +2583,12 @@ class DocView extends ContentView {
|
|
|
2680
2583
|
// to detect that situation.
|
|
2681
2584
|
let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
|
|
2682
2585
|
this.sync(this.view, track);
|
|
2683
|
-
this.
|
|
2586
|
+
this.flags &= ~7 /* Dirty */;
|
|
2684
2587
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2685
2588
|
this.forceSelection = true;
|
|
2686
2589
|
this.dom.style.height = "";
|
|
2687
2590
|
});
|
|
2591
|
+
this.markedForComposition.forEach(cView => cView.flags &= ~8 /* Composition */);
|
|
2688
2592
|
let gaps = [];
|
|
2689
2593
|
if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
|
|
2690
2594
|
for (let child of this.children)
|
|
@@ -2692,18 +2596,71 @@ class DocView extends ContentView {
|
|
|
2692
2596
|
gaps.push(child.dom);
|
|
2693
2597
|
observer.updateGaps(gaps);
|
|
2694
2598
|
}
|
|
2695
|
-
updateChildren(changes, oldLength) {
|
|
2599
|
+
updateChildren(changes, oldLength, composition) {
|
|
2600
|
+
let ranges = composition ? composition.range.addToSet(changes.slice()) : changes;
|
|
2696
2601
|
let cursor = this.childCursor(oldLength);
|
|
2697
|
-
for (let i =
|
|
2698
|
-
let next = i >= 0 ?
|
|
2602
|
+
for (let i = ranges.length - 1;; i--) {
|
|
2603
|
+
let next = i >= 0 ? ranges[i] : null;
|
|
2699
2604
|
if (!next)
|
|
2700
2605
|
break;
|
|
2701
|
-
let { fromA, toA, fromB, toB } = next;
|
|
2702
|
-
|
|
2606
|
+
let { fromA, toA, fromB, toB } = next, content, breakAtStart, openStart, openEnd;
|
|
2607
|
+
if (composition && composition.range.fromB < toB && composition.range.toB > fromB) {
|
|
2608
|
+
let before = ContentBuilder.build(this.view.state.doc, fromB, composition.range.fromB, this.decorations, this.dynamicDecorationMap);
|
|
2609
|
+
let after = ContentBuilder.build(this.view.state.doc, composition.range.toB, toB, this.decorations, this.dynamicDecorationMap);
|
|
2610
|
+
breakAtStart = before.breakAtStart;
|
|
2611
|
+
openStart = before.openStart;
|
|
2612
|
+
openEnd = after.openEnd;
|
|
2613
|
+
let compLine = this.compositionView(composition);
|
|
2614
|
+
if (after.content.length) {
|
|
2615
|
+
compLine.breakAfter = after.content[0].breakAfter;
|
|
2616
|
+
if (compLine.merge(compLine.length, compLine.length, after.content[0], false, after.openStart, 0))
|
|
2617
|
+
after.content.shift();
|
|
2618
|
+
}
|
|
2619
|
+
if (before.content.length) {
|
|
2620
|
+
if (compLine.merge(0, 0, before.content[before.content.length - 1], true, 0, before.openEnd))
|
|
2621
|
+
before.content.pop();
|
|
2622
|
+
}
|
|
2623
|
+
content = before.content.concat(compLine).concat(after.content);
|
|
2624
|
+
}
|
|
2625
|
+
else {
|
|
2626
|
+
({ content, breakAtStart, openStart, openEnd } =
|
|
2627
|
+
ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap));
|
|
2628
|
+
}
|
|
2703
2629
|
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2704
2630
|
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2705
2631
|
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
2706
2632
|
}
|
|
2633
|
+
if (composition)
|
|
2634
|
+
this.fixCompositionDOM(composition);
|
|
2635
|
+
}
|
|
2636
|
+
compositionView(composition) {
|
|
2637
|
+
let cur = new TextView(composition.text.nodeValue);
|
|
2638
|
+
cur.flags |= 8 /* Composition */;
|
|
2639
|
+
for (let { deco } of composition.marks)
|
|
2640
|
+
cur = new MarkView(deco, [cur], cur.length);
|
|
2641
|
+
let line = new LineView;
|
|
2642
|
+
line.append(cur, 0);
|
|
2643
|
+
return line;
|
|
2644
|
+
}
|
|
2645
|
+
fixCompositionDOM(composition) {
|
|
2646
|
+
let fix = (dom, cView) => {
|
|
2647
|
+
cView.flags |= 8 /* Composition */;
|
|
2648
|
+
this.markedForComposition.add(cView);
|
|
2649
|
+
let prev = ContentView.get(dom);
|
|
2650
|
+
if (prev != cView) {
|
|
2651
|
+
if (prev)
|
|
2652
|
+
prev.dom = null;
|
|
2653
|
+
cView.setDOM(dom);
|
|
2654
|
+
}
|
|
2655
|
+
};
|
|
2656
|
+
let pos = this.childPos(composition.range.fromB, 1);
|
|
2657
|
+
let cView = this.children[pos.i];
|
|
2658
|
+
fix(composition.line, cView);
|
|
2659
|
+
for (let i = composition.marks.length - 1; i >= -1; i--) {
|
|
2660
|
+
pos = cView.childPos(pos.off, 1);
|
|
2661
|
+
cView = cView.children[pos.i];
|
|
2662
|
+
fix(i >= 0 ? composition.marks[i].node : composition.text, cView);
|
|
2663
|
+
}
|
|
2707
2664
|
}
|
|
2708
2665
|
// Sync the DOM selection to this.state.selection
|
|
2709
2666
|
updateSelection(mustRead = false, fromPointer = false) {
|
|
@@ -2722,7 +2679,7 @@ class DocView extends ContentView {
|
|
|
2722
2679
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2723
2680
|
// Always reset on Firefox when next to an uneditable node to
|
|
2724
2681
|
// avoid invisible cursor bugs (#111)
|
|
2725
|
-
if (browser.gecko && main.empty && !this.
|
|
2682
|
+
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
|
|
2726
2683
|
let dummy = document.createTextNode("");
|
|
2727
2684
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
2728
2685
|
anchor = head = new DOMPos(dummy, 0);
|
|
@@ -2794,7 +2751,7 @@ class DocView extends ContentView {
|
|
|
2794
2751
|
this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
|
|
2795
2752
|
}
|
|
2796
2753
|
enforceCursorAssoc() {
|
|
2797
|
-
if (this.
|
|
2754
|
+
if (this.hasComposition)
|
|
2798
2755
|
return;
|
|
2799
2756
|
let { view } = this, cursor = view.state.selection.main;
|
|
2800
2757
|
let sel = getSelection(view.root);
|
|
@@ -2904,6 +2861,7 @@ class DocView extends ContentView {
|
|
|
2904
2861
|
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2905
2862
|
dummy.className = "cm-line";
|
|
2906
2863
|
dummy.style.width = "99999px";
|
|
2864
|
+
dummy.style.position = "absolute";
|
|
2907
2865
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
2908
2866
|
this.view.observer.ignore(() => {
|
|
2909
2867
|
this.dom.appendChild(dummy);
|
|
@@ -2953,7 +2911,6 @@ class DocView extends ContentView {
|
|
|
2953
2911
|
this.dynamicDecorationMap[i] = false;
|
|
2954
2912
|
return this.decorations = [
|
|
2955
2913
|
...allDeco,
|
|
2956
|
-
this.compositionDeco,
|
|
2957
2914
|
this.computeBlockGapDeco(),
|
|
2958
2915
|
this.view.viewState.lineGapDeco
|
|
2959
2916
|
];
|
|
@@ -2996,83 +2953,86 @@ class BlockGapWidget extends WidgetType {
|
|
|
2996
2953
|
}
|
|
2997
2954
|
get estimatedHeight() { return this.height; }
|
|
2998
2955
|
}
|
|
2999
|
-
function
|
|
2956
|
+
function findCompositionNode(view) {
|
|
3000
2957
|
let sel = view.observer.selectionRange;
|
|
3001
2958
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3002
2959
|
if (!textNode)
|
|
3003
2960
|
return null;
|
|
3004
|
-
let cView =
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
while (topNode.parentNode != cView.dom)
|
|
3010
|
-
topNode = topNode.parentNode;
|
|
3011
|
-
let prev = topNode.previousSibling;
|
|
3012
|
-
while (prev && !ContentView.get(prev))
|
|
3013
|
-
prev = prev.previousSibling;
|
|
3014
|
-
let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
|
|
3015
|
-
return { from: pos, to: pos, node: topNode, text: textNode };
|
|
2961
|
+
let cView = ContentView.get(textNode);
|
|
2962
|
+
let from, to;
|
|
2963
|
+
if (cView instanceof TextView) {
|
|
2964
|
+
from = cView.posAtStart;
|
|
2965
|
+
to = from + cView.length;
|
|
3016
2966
|
}
|
|
3017
2967
|
else {
|
|
3018
|
-
for (;;) {
|
|
3019
|
-
let
|
|
3020
|
-
|
|
2968
|
+
up: for (let offset = 0, node = textNode;;) {
|
|
2969
|
+
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
2970
|
+
if (cView = ContentView.get(sibling)) {
|
|
2971
|
+
from = to = cView.posAtEnd + offset;
|
|
2972
|
+
break up;
|
|
2973
|
+
}
|
|
2974
|
+
let reader = new DOMReader([], view.state);
|
|
2975
|
+
reader.readNode(sibling);
|
|
2976
|
+
if (reader.text.indexOf(LineBreakPlaceholder) > -1)
|
|
2977
|
+
return null;
|
|
2978
|
+
offset += reader.text.length;
|
|
2979
|
+
}
|
|
2980
|
+
node = node.parentNode;
|
|
2981
|
+
if (!node)
|
|
3021
2982
|
return null;
|
|
3022
|
-
|
|
2983
|
+
let parentView = ContentView.get(node);
|
|
2984
|
+
if (parentView) {
|
|
2985
|
+
from = to = parentView.posAtStart + offset;
|
|
3023
2986
|
break;
|
|
3024
|
-
|
|
3025
|
-
}
|
|
3026
|
-
|
|
3027
|
-
|
|
3028
|
-
}
|
|
3029
|
-
}
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
let
|
|
3036
|
-
let
|
|
3037
|
-
|
|
3038
|
-
if (
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
if (state.doc.sliceString(
|
|
3047
|
-
|
|
3048
|
-
else if (state.doc.sliceString(
|
|
3049
|
-
|
|
2987
|
+
}
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
let { main } = view.state.selection;
|
|
2991
|
+
return from > main.head || to < main.head ? null : { from, to, node: textNode };
|
|
2992
|
+
}
|
|
2993
|
+
function findCompositionRange(view, changes) {
|
|
2994
|
+
let found = findCompositionNode(view);
|
|
2995
|
+
if (!found)
|
|
2996
|
+
return null;
|
|
2997
|
+
let { from: fromA, to: toA, node: textNode } = found;
|
|
2998
|
+
let fromB = changes.mapPos(fromA, -1), toB = changes.mapPos(toA, 1);
|
|
2999
|
+
let text = textNode.nodeValue;
|
|
3000
|
+
// Don't try to preserve multi-line compositions
|
|
3001
|
+
if (/[\n\r]/.test(text))
|
|
3002
|
+
return null;
|
|
3003
|
+
if (toB - fromB != text.length) {
|
|
3004
|
+
// If there is a length mismatch, see if mapping non-inclusively helps
|
|
3005
|
+
let fromB2 = changes.mapPos(fromA, 1), toB2 = changes.mapPos(toA, -1);
|
|
3006
|
+
if (toB2 - fromB2 == text.length)
|
|
3007
|
+
fromB = fromB2, toB = toB2;
|
|
3008
|
+
// See if we can find an instance of the text at either side
|
|
3009
|
+
else if (view.state.doc.sliceString(toB - text.length, toB) == text)
|
|
3010
|
+
fromB = toB - text.length;
|
|
3011
|
+
else if (view.state.doc.sliceString(fromB, fromB + text.length) == text)
|
|
3012
|
+
toB = fromB + text.length;
|
|
3013
|
+
// Not found
|
|
3050
3014
|
else
|
|
3051
|
-
return
|
|
3052
|
-
}
|
|
3053
|
-
|
|
3054
|
-
return
|
|
3055
|
-
|
|
3056
|
-
let
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3067
|
-
|
|
3068
|
-
|
|
3069
|
-
|
|
3070
|
-
|
|
3015
|
+
return null;
|
|
3016
|
+
}
|
|
3017
|
+
if (view.state.doc.sliceString(fromB, toB) != text)
|
|
3018
|
+
return null;
|
|
3019
|
+
let marks = [];
|
|
3020
|
+
let range = new ChangedRange(fromA, toA, fromB, toB);
|
|
3021
|
+
for (let parent = textNode.parentNode;; parent = parent.parentNode) {
|
|
3022
|
+
let parentView = ContentView.get(parent);
|
|
3023
|
+
if (parentView instanceof MarkView)
|
|
3024
|
+
marks.push({ node: parent, deco: parentView.mark });
|
|
3025
|
+
else if (parentView instanceof LineView || parent.nodeName == "DIV" && parent.parentNode == view.contentDOM)
|
|
3026
|
+
return { range, text: textNode, marks, line: parent };
|
|
3027
|
+
else if (parent != view.contentDOM)
|
|
3028
|
+
marks.push({ node: parent, deco: new MarkDecoration({
|
|
3029
|
+
inclusive: true,
|
|
3030
|
+
attributes: getAttrs(parent),
|
|
3031
|
+
tagName: parent.tagName.toLowerCase()
|
|
3032
|
+
}) });
|
|
3033
|
+
else
|
|
3034
|
+
return null;
|
|
3071
3035
|
}
|
|
3072
|
-
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
3073
|
-
toDOM() { return this.top; }
|
|
3074
|
-
ignoreEvent() { return false; }
|
|
3075
|
-
get customView() { return CompositionView; }
|
|
3076
3036
|
}
|
|
3077
3037
|
function nearbyTextNode(startNode, startOffset, side) {
|
|
3078
3038
|
if (side <= 0)
|
|
@@ -3733,9 +3693,13 @@ const dragScrollMargin = 6;
|
|
|
3733
3693
|
function dragScrollSpeed(dist) {
|
|
3734
3694
|
return Math.max(0, dist) * 0.7 + 8;
|
|
3735
3695
|
}
|
|
3696
|
+
function dist(a, b) {
|
|
3697
|
+
return Math.max(Math.abs(a.clientX - b.clientX), Math.abs(a.clientY - b.clientY));
|
|
3698
|
+
}
|
|
3736
3699
|
class MouseSelection {
|
|
3737
3700
|
constructor(view, startEvent, style, mustSelect) {
|
|
3738
3701
|
this.view = view;
|
|
3702
|
+
this.startEvent = startEvent;
|
|
3739
3703
|
this.style = style;
|
|
3740
3704
|
this.mustSelect = mustSelect;
|
|
3741
3705
|
this.scrollSpeed = { x: 0, y: 0 };
|
|
@@ -3762,7 +3726,7 @@ class MouseSelection {
|
|
|
3762
3726
|
var _a;
|
|
3763
3727
|
if (event.buttons == 0)
|
|
3764
3728
|
return this.destroy();
|
|
3765
|
-
if (this.dragging
|
|
3729
|
+
if (this.dragging || this.dragging == null && dist(this.startEvent, event) < 10)
|
|
3766
3730
|
return;
|
|
3767
3731
|
this.select(this.lastEvent = event);
|
|
3768
3732
|
let sx = 0, sy = 0;
|
|
@@ -3841,7 +3805,7 @@ class MouseSelection {
|
|
|
3841
3805
|
select(event) {
|
|
3842
3806
|
let { view } = this, selection = this.skipAtoms(this.style.get(event, this.extend, this.multiple));
|
|
3843
3807
|
if (this.mustSelect || !selection.eq(view.state.selection) ||
|
|
3844
|
-
selection.main.assoc != view.state.selection.main.assoc)
|
|
3808
|
+
selection.main.assoc != view.state.selection.main.assoc && this.dragging === false)
|
|
3845
3809
|
this.view.dispatch({
|
|
3846
3810
|
selection,
|
|
3847
3811
|
userEvent: "select.pointer"
|
|
@@ -4260,7 +4224,7 @@ handlers.compositionend = view => {
|
|
|
4260
4224
|
// Otherwise, make sure that, if no changes come in soon, the
|
|
4261
4225
|
// composition view is cleared.
|
|
4262
4226
|
setTimeout(() => {
|
|
4263
|
-
if (view.inputState.composing < 0 && view.docView.
|
|
4227
|
+
if (view.inputState.composing < 0 && view.docView.hasComposition)
|
|
4264
4228
|
view.update([]);
|
|
4265
4229
|
}, 50);
|
|
4266
4230
|
}
|
|
@@ -5976,7 +5940,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5976
5940
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5977
5941
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5978
5942
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5979
|
-
let
|
|
5943
|
+
let composition = findCompositionNode(view) || view.state.doc.lineAt(sel.head);
|
|
5980
5944
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5981
5945
|
tr = startState.changeByRange(range => {
|
|
5982
5946
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -5987,7 +5951,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5987
5951
|
// changes in the same node work without aborting
|
|
5988
5952
|
// composition, so cursors in the composition range are
|
|
5989
5953
|
// ignored.
|
|
5990
|
-
|
|
5954
|
+
composition && range.to >= composition.from && range.from <= composition.to)
|
|
5991
5955
|
return { range };
|
|
5992
5956
|
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5993
5957
|
return {
|
|
@@ -6448,7 +6412,7 @@ class DOMObserver {
|
|
|
6448
6412
|
return null;
|
|
6449
6413
|
cView.markDirty(rec.type == "attributes");
|
|
6450
6414
|
if (rec.type == "attributes")
|
|
6451
|
-
cView.
|
|
6415
|
+
cView.flags |= 4 /* AttrsDirty */;
|
|
6452
6416
|
if (rec.type == "childList") {
|
|
6453
6417
|
let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1);
|
|
6454
6418
|
let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1);
|
|
@@ -7622,7 +7586,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7622
7586
|
else if (current != is)
|
|
7623
7587
|
throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix");
|
|
7624
7588
|
};
|
|
7625
|
-
let add = (scope, key, command, preventDefault) => {
|
|
7589
|
+
let add = (scope, key, command, preventDefault, stopPropagation) => {
|
|
7626
7590
|
var _a, _b;
|
|
7627
7591
|
let scopeObj = bound[scope] || (bound[scope] = Object.create(null));
|
|
7628
7592
|
let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform));
|
|
@@ -7632,6 +7596,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7632
7596
|
if (!scopeObj[prefix])
|
|
7633
7597
|
scopeObj[prefix] = {
|
|
7634
7598
|
preventDefault: true,
|
|
7599
|
+
stopPropagation: false,
|
|
7635
7600
|
run: [(view) => {
|
|
7636
7601
|
let ourObj = storedPrefix = { view, prefix, scope };
|
|
7637
7602
|
setTimeout(() => { if (storedPrefix == ourObj)
|
|
@@ -7642,11 +7607,17 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7642
7607
|
}
|
|
7643
7608
|
let full = parts.join(" ");
|
|
7644
7609
|
checkPrefix(full, false);
|
|
7645
|
-
let binding = scopeObj[full] || (scopeObj[full] = {
|
|
7610
|
+
let binding = scopeObj[full] || (scopeObj[full] = {
|
|
7611
|
+
preventDefault: false,
|
|
7612
|
+
stopPropagation: false,
|
|
7613
|
+
run: ((_b = (_a = scopeObj._any) === null || _a === void 0 ? void 0 : _a.run) === null || _b === void 0 ? void 0 : _b.slice()) || []
|
|
7614
|
+
});
|
|
7646
7615
|
if (command)
|
|
7647
7616
|
binding.run.push(command);
|
|
7648
7617
|
if (preventDefault)
|
|
7649
7618
|
binding.preventDefault = true;
|
|
7619
|
+
if (stopPropagation)
|
|
7620
|
+
binding.stopPropagation = true;
|
|
7650
7621
|
};
|
|
7651
7622
|
for (let b of bindings) {
|
|
7652
7623
|
let scopes = b.scope ? b.scope.split(" ") : ["editor"];
|
|
@@ -7654,7 +7625,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7654
7625
|
for (let scope of scopes) {
|
|
7655
7626
|
let scopeObj = bound[scope] || (bound[scope] = Object.create(null));
|
|
7656
7627
|
if (!scopeObj._any)
|
|
7657
|
-
scopeObj._any = { preventDefault: false, run: [] };
|
|
7628
|
+
scopeObj._any = { preventDefault: false, stopPropagation: false, run: [] };
|
|
7658
7629
|
for (let key in scopeObj)
|
|
7659
7630
|
scopeObj[key].run.push(b.any);
|
|
7660
7631
|
}
|
|
@@ -7662,9 +7633,9 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7662
7633
|
if (!name)
|
|
7663
7634
|
continue;
|
|
7664
7635
|
for (let scope of scopes) {
|
|
7665
|
-
add(scope, name, b.run, b.preventDefault);
|
|
7636
|
+
add(scope, name, b.run, b.preventDefault, b.stopPropagation);
|
|
7666
7637
|
if (b.shift)
|
|
7667
|
-
add(scope, "Shift-" + name, b.shift, b.preventDefault);
|
|
7638
|
+
add(scope, "Shift-" + name, b.shift, b.preventDefault, b.stopPropagation);
|
|
7668
7639
|
}
|
|
7669
7640
|
}
|
|
7670
7641
|
return bound;
|
|
@@ -7672,11 +7643,13 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7672
7643
|
function runHandlers(map, event, view, scope) {
|
|
7673
7644
|
let name = keyName(event);
|
|
7674
7645
|
let charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " ";
|
|
7675
|
-
let prefix = "",
|
|
7646
|
+
let prefix = "", handled = false, prevented = false, stopPropagation = false;
|
|
7676
7647
|
if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) {
|
|
7677
7648
|
prefix = storedPrefix.prefix + " ";
|
|
7678
|
-
if (
|
|
7649
|
+
if (modifierCodes.indexOf(event.keyCode) < 0) {
|
|
7650
|
+
prevented = true;
|
|
7679
7651
|
storedPrefix = null;
|
|
7652
|
+
}
|
|
7680
7653
|
}
|
|
7681
7654
|
let ran = new Set;
|
|
7682
7655
|
let runFor = (binding) => {
|
|
@@ -7684,36 +7657,49 @@ function runHandlers(map, event, view, scope) {
|
|
|
7684
7657
|
for (let cmd of binding.run)
|
|
7685
7658
|
if (!ran.has(cmd)) {
|
|
7686
7659
|
ran.add(cmd);
|
|
7687
|
-
if (cmd(view, event))
|
|
7660
|
+
if (cmd(view, event)) {
|
|
7661
|
+
if (binding.stopPropagation)
|
|
7662
|
+
stopPropagation = true;
|
|
7688
7663
|
return true;
|
|
7664
|
+
}
|
|
7689
7665
|
}
|
|
7690
|
-
if (binding.preventDefault)
|
|
7691
|
-
|
|
7666
|
+
if (binding.preventDefault) {
|
|
7667
|
+
if (binding.stopPropagation)
|
|
7668
|
+
stopPropagation = true;
|
|
7669
|
+
prevented = true;
|
|
7670
|
+
}
|
|
7692
7671
|
}
|
|
7693
7672
|
return false;
|
|
7694
7673
|
};
|
|
7695
7674
|
let scopeObj = map[scope], baseName, shiftName;
|
|
7696
7675
|
if (scopeObj) {
|
|
7697
|
-
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)]))
|
|
7698
|
-
|
|
7699
|
-
|
|
7676
|
+
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) {
|
|
7677
|
+
handled = true;
|
|
7678
|
+
}
|
|
7679
|
+
else if (isChar && (event.altKey || event.metaKey || event.ctrlKey) &&
|
|
7700
7680
|
// Ctrl-Alt may be used for AltGr on Windows
|
|
7701
7681
|
!(browser.windows && event.ctrlKey && event.altKey) &&
|
|
7702
7682
|
(baseName = base[event.keyCode]) && baseName != name) {
|
|
7703
|
-
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)]))
|
|
7704
|
-
|
|
7683
|
+
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) {
|
|
7684
|
+
handled = true;
|
|
7685
|
+
}
|
|
7705
7686
|
else if (event.shiftKey && (shiftName = shift[event.keyCode]) != name && shiftName != baseName &&
|
|
7706
|
-
runFor(scopeObj[prefix + modifiers(shiftName, event, false)]))
|
|
7707
|
-
|
|
7687
|
+
runFor(scopeObj[prefix + modifiers(shiftName, event, false)])) {
|
|
7688
|
+
handled = true;
|
|
7689
|
+
}
|
|
7708
7690
|
}
|
|
7709
|
-
else if (isChar && event.shiftKey
|
|
7710
|
-
|
|
7711
|
-
|
|
7691
|
+
else if (isChar && event.shiftKey &&
|
|
7692
|
+
runFor(scopeObj[prefix + modifiers(name, event, true)])) {
|
|
7693
|
+
handled = true;
|
|
7712
7694
|
}
|
|
7713
|
-
if (runFor(scopeObj._any))
|
|
7714
|
-
|
|
7695
|
+
if (!handled && runFor(scopeObj._any))
|
|
7696
|
+
handled = true;
|
|
7715
7697
|
}
|
|
7716
|
-
|
|
7698
|
+
if (prevented)
|
|
7699
|
+
handled = true;
|
|
7700
|
+
if (handled && stopPropagation)
|
|
7701
|
+
event.stopPropagation();
|
|
7702
|
+
return handled;
|
|
7717
7703
|
}
|
|
7718
7704
|
|
|
7719
7705
|
/**
|
|
@@ -8500,7 +8486,9 @@ function placeholder(content) {
|
|
|
8500
8486
|
return ViewPlugin.fromClass(class {
|
|
8501
8487
|
constructor(view) {
|
|
8502
8488
|
this.view = view;
|
|
8503
|
-
this.placeholder =
|
|
8489
|
+
this.placeholder = content
|
|
8490
|
+
? Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)])
|
|
8491
|
+
: Decoration.none;
|
|
8504
8492
|
}
|
|
8505
8493
|
get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; }
|
|
8506
8494
|
}, { decorations: v => v.decorations });
|