@codemirror/view 6.14.0 → 6.15.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 +32 -0
- package/dist/index.cjs +391 -407
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +392 -408
- 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;
|
|
@@ -316,6 +318,9 @@ function atElementStart(doc, selection) {
|
|
|
316
318
|
}
|
|
317
319
|
}
|
|
318
320
|
}
|
|
321
|
+
function isScrolledToBottom(elt) {
|
|
322
|
+
return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
|
|
323
|
+
}
|
|
319
324
|
|
|
320
325
|
class DOMPos {
|
|
321
326
|
constructor(node, offset, precise = true) {
|
|
@@ -331,7 +336,7 @@ class ContentView {
|
|
|
331
336
|
constructor() {
|
|
332
337
|
this.parent = null;
|
|
333
338
|
this.dom = null;
|
|
334
|
-
this.
|
|
339
|
+
this.flags = 2 /* NodeDirty */;
|
|
335
340
|
}
|
|
336
341
|
get overrideDOMText() { return null; }
|
|
337
342
|
get posAtStart() {
|
|
@@ -353,18 +358,18 @@ class ContentView {
|
|
|
353
358
|
return this.posBefore(view) + view.length;
|
|
354
359
|
}
|
|
355
360
|
sync(view, track) {
|
|
356
|
-
if (this.
|
|
361
|
+
if (this.flags & 2 /* NodeDirty */) {
|
|
357
362
|
let parent = this.dom;
|
|
358
363
|
let prev = null, next;
|
|
359
364
|
for (let child of this.children) {
|
|
360
|
-
if (child.
|
|
365
|
+
if (child.flags & 7 /* Dirty */) {
|
|
361
366
|
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
|
362
367
|
let contentView = ContentView.get(next);
|
|
363
368
|
if (!contentView || !contentView.parent && contentView.canReuseDOM(child))
|
|
364
369
|
child.reuseDOM(next);
|
|
365
370
|
}
|
|
366
371
|
child.sync(view, track);
|
|
367
|
-
child.
|
|
372
|
+
child.flags &= ~7 /* Dirty */;
|
|
368
373
|
}
|
|
369
374
|
next = prev ? prev.nextSibling : parent.firstChild;
|
|
370
375
|
if (track && !track.written && track.node == parent && next != child.dom)
|
|
@@ -384,11 +389,11 @@ class ContentView {
|
|
|
384
389
|
while (next)
|
|
385
390
|
next = rm$1(next);
|
|
386
391
|
}
|
|
387
|
-
else if (this.
|
|
392
|
+
else if (this.flags & 1 /* ChildDirty */) {
|
|
388
393
|
for (let child of this.children)
|
|
389
|
-
if (child.
|
|
394
|
+
if (child.flags & 7 /* Dirty */) {
|
|
390
395
|
child.sync(view, track);
|
|
391
|
-
child.
|
|
396
|
+
child.flags &= ~7 /* Dirty */;
|
|
392
397
|
}
|
|
393
398
|
}
|
|
394
399
|
}
|
|
@@ -453,23 +458,23 @@ class ContentView {
|
|
|
453
458
|
endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null };
|
|
454
459
|
}
|
|
455
460
|
markDirty(andParent = false) {
|
|
456
|
-
this.
|
|
461
|
+
this.flags |= 2 /* NodeDirty */;
|
|
457
462
|
this.markParentsDirty(andParent);
|
|
458
463
|
}
|
|
459
464
|
markParentsDirty(childList) {
|
|
460
465
|
for (let parent = this.parent; parent; parent = parent.parent) {
|
|
461
466
|
if (childList)
|
|
462
|
-
parent.
|
|
463
|
-
if (parent.
|
|
467
|
+
parent.flags |= 2 /* NodeDirty */;
|
|
468
|
+
if (parent.flags & 1 /* ChildDirty */)
|
|
464
469
|
return;
|
|
465
|
-
parent.
|
|
470
|
+
parent.flags |= 1 /* ChildDirty */;
|
|
466
471
|
childList = false;
|
|
467
472
|
}
|
|
468
473
|
}
|
|
469
474
|
setParent(parent) {
|
|
470
475
|
if (this.parent != parent) {
|
|
471
476
|
this.parent = parent;
|
|
472
|
-
if (this.
|
|
477
|
+
if (this.flags & 7 /* Dirty */)
|
|
473
478
|
this.markParentsDirty(true);
|
|
474
479
|
}
|
|
475
480
|
}
|
|
@@ -520,7 +525,9 @@ class ContentView {
|
|
|
520
525
|
return false;
|
|
521
526
|
}
|
|
522
527
|
become(other) { return false; }
|
|
523
|
-
canReuseDOM(other) {
|
|
528
|
+
canReuseDOM(other) {
|
|
529
|
+
return other.constructor == this.constructor && !((this.flags | other.flags) & 8 /* Composition */);
|
|
530
|
+
}
|
|
524
531
|
// When this is a zero-length view with a side, this should return a
|
|
525
532
|
// number <= 0 to indicate it is before its position, or a
|
|
526
533
|
// number > 0 when after its position.
|
|
@@ -644,6 +651,113 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
644
651
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
645
652
|
}
|
|
646
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
|
+
|
|
647
761
|
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
648
762
|
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
649
763
|
const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
|
|
@@ -697,7 +811,10 @@ class TextView extends ContentView {
|
|
|
697
811
|
this.createDOM(dom);
|
|
698
812
|
}
|
|
699
813
|
merge(from, to, source) {
|
|
700
|
-
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 */)))
|
|
701
818
|
return false;
|
|
702
819
|
this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to);
|
|
703
820
|
this.markDirty();
|
|
@@ -707,6 +824,7 @@ class TextView extends ContentView {
|
|
|
707
824
|
let result = new TextView(this.text.slice(from));
|
|
708
825
|
this.text = this.text.slice(0, from);
|
|
709
826
|
this.markDirty();
|
|
827
|
+
result.flags |= this.flags & 8 /* Composition */;
|
|
710
828
|
return result;
|
|
711
829
|
}
|
|
712
830
|
localPosFromDOM(node, offset) {
|
|
@@ -738,16 +856,19 @@ class MarkView extends ContentView {
|
|
|
738
856
|
dom.setAttribute(name, this.mark.attrs[name]);
|
|
739
857
|
return dom;
|
|
740
858
|
}
|
|
859
|
+
canReuseDOM(other) {
|
|
860
|
+
return super.canReuseDOM(other) && !((this.flags | other.flags) & 8 /* Composition */);
|
|
861
|
+
}
|
|
741
862
|
reuseDOM(node) {
|
|
742
863
|
if (node.nodeName == this.mark.tagName.toUpperCase()) {
|
|
743
864
|
this.setDOM(node);
|
|
744
|
-
this.
|
|
865
|
+
this.flags |= 4 /* AttrsDirty */ | 2 /* NodeDirty */;
|
|
745
866
|
}
|
|
746
867
|
}
|
|
747
868
|
sync(view, track) {
|
|
748
869
|
if (!this.dom)
|
|
749
870
|
this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
|
|
750
|
-
else if (this.
|
|
871
|
+
else if (this.flags & 4 /* AttrsDirty */)
|
|
751
872
|
this.setAttrs(this.dom);
|
|
752
873
|
super.sync(view, track);
|
|
753
874
|
}
|
|
@@ -826,7 +947,7 @@ class WidgetView extends ContentView {
|
|
|
826
947
|
this.prevWidget = null;
|
|
827
948
|
}
|
|
828
949
|
static create(widget, length, side) {
|
|
829
|
-
return new
|
|
950
|
+
return new WidgetView(widget, length, side);
|
|
830
951
|
}
|
|
831
952
|
split(from) {
|
|
832
953
|
let result = WidgetView.create(this.widget, this.length - from, this.side);
|
|
@@ -904,129 +1025,6 @@ class WidgetView extends ContentView {
|
|
|
904
1025
|
this.widget.destroy(this.dom);
|
|
905
1026
|
}
|
|
906
1027
|
}
|
|
907
|
-
class CompositionView extends WidgetView {
|
|
908
|
-
domAtPos(pos) {
|
|
909
|
-
let { topView, text } = this.widget;
|
|
910
|
-
if (!topView)
|
|
911
|
-
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
912
|
-
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)));
|
|
913
|
-
}
|
|
914
|
-
sync() { this.setDOM(this.widget.toDOM()); }
|
|
915
|
-
localPosFromDOM(node, offset) {
|
|
916
|
-
let { topView, text } = this.widget;
|
|
917
|
-
if (!topView)
|
|
918
|
-
return Math.min(offset, this.length);
|
|
919
|
-
return posFromDOMInCompositionTree(node, offset, topView, text, this.length - topView.length);
|
|
920
|
-
}
|
|
921
|
-
ignoreMutation() { return false; }
|
|
922
|
-
get overrideDOMText() { return null; }
|
|
923
|
-
coordsAt(pos, side) {
|
|
924
|
-
let { topView, text } = this.widget;
|
|
925
|
-
if (!topView)
|
|
926
|
-
return textCoords(text, pos, side);
|
|
927
|
-
return scanCompositionTree(pos, side, topView, text, this.length - topView.length, (v, pos, side) => v.coordsAt(pos, side), (text, pos, side) => textCoords(text, pos, side));
|
|
928
|
-
}
|
|
929
|
-
destroy() {
|
|
930
|
-
var _a;
|
|
931
|
-
super.destroy();
|
|
932
|
-
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
933
|
-
}
|
|
934
|
-
get isEditable() { return true; }
|
|
935
|
-
canReuseDOM() { return true; }
|
|
936
|
-
}
|
|
937
|
-
// Uses the old structure of a chunk of content view frozen for
|
|
938
|
-
// composition to try and find a reasonable DOM location for the given
|
|
939
|
-
// offset.
|
|
940
|
-
function scanCompositionTree(pos, side, view, text, dLen, enterView, fromText) {
|
|
941
|
-
if (view instanceof MarkView) {
|
|
942
|
-
for (let child = view.dom.firstChild; child; child = child.nextSibling) {
|
|
943
|
-
let desc = ContentView.get(child);
|
|
944
|
-
if (!desc) {
|
|
945
|
-
let inner = scanCompositionNode(pos, side, child, fromText);
|
|
946
|
-
if (typeof inner != "number")
|
|
947
|
-
return inner;
|
|
948
|
-
pos = inner;
|
|
949
|
-
}
|
|
950
|
-
else {
|
|
951
|
-
let hasComp = contains(child, text);
|
|
952
|
-
let len = desc.length + (hasComp ? dLen : 0);
|
|
953
|
-
if (pos < len || pos == len && desc.getSide() <= 0)
|
|
954
|
-
return hasComp ? scanCompositionTree(pos, side, desc, text, dLen, enterView, fromText) : enterView(desc, pos, side);
|
|
955
|
-
pos -= len;
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
return enterView(view, view.length, -1);
|
|
959
|
-
}
|
|
960
|
-
else if (view.dom == text) {
|
|
961
|
-
return fromText(text, pos, side);
|
|
962
|
-
}
|
|
963
|
-
else {
|
|
964
|
-
return enterView(view, pos, side);
|
|
965
|
-
}
|
|
966
|
-
}
|
|
967
|
-
function scanCompositionNode(pos, side, node, fromText) {
|
|
968
|
-
if (node.nodeType == 3) {
|
|
969
|
-
let len = node.nodeValue.length;
|
|
970
|
-
if (pos <= len)
|
|
971
|
-
return fromText(node, pos, side);
|
|
972
|
-
pos -= len;
|
|
973
|
-
}
|
|
974
|
-
else if (node.nodeType == 1 && node.contentEditable != "false") {
|
|
975
|
-
for (let child = node.firstChild; child; child = child.nextSibling) {
|
|
976
|
-
let inner = scanCompositionNode(pos, side, child, fromText);
|
|
977
|
-
if (typeof inner != "number")
|
|
978
|
-
return inner;
|
|
979
|
-
pos = inner;
|
|
980
|
-
}
|
|
981
|
-
}
|
|
982
|
-
return pos;
|
|
983
|
-
}
|
|
984
|
-
function posFromDOMInCompositionTree(node, offset, view, text, dLen) {
|
|
985
|
-
if (view instanceof MarkView) {
|
|
986
|
-
let pos = 0;
|
|
987
|
-
for (let child = view.dom.firstChild; child; child = child.nextSibling) {
|
|
988
|
-
let childView = ContentView.get(child);
|
|
989
|
-
if (childView) {
|
|
990
|
-
let hasComp = contains(child, text);
|
|
991
|
-
if (contains(child, node))
|
|
992
|
-
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, childView, text, dLen)
|
|
993
|
-
: childView.localPosFromDOM(node, offset));
|
|
994
|
-
pos += childView.length + (hasComp ? dLen : 0);
|
|
995
|
-
}
|
|
996
|
-
else {
|
|
997
|
-
let inner = posFromDOMInOpaqueNode(node, offset, child);
|
|
998
|
-
if (inner.result != null)
|
|
999
|
-
return pos + inner.result;
|
|
1000
|
-
pos += inner.size;
|
|
1001
|
-
}
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
else if (view.dom == text) {
|
|
1005
|
-
return Math.min(offset, text.nodeValue.length);
|
|
1006
|
-
}
|
|
1007
|
-
return view.localPosFromDOM(node, offset);
|
|
1008
|
-
}
|
|
1009
|
-
function posFromDOMInOpaqueNode(node, offset, target) {
|
|
1010
|
-
if (target.nodeType == 3) {
|
|
1011
|
-
return node == target ? { result: offset } : { size: target.nodeValue.length };
|
|
1012
|
-
}
|
|
1013
|
-
else if (target.nodeType == 1 && target.contentEditable != "false") {
|
|
1014
|
-
let pos = 0;
|
|
1015
|
-
for (let child = target.firstChild, i = 0;; child = child.nextSibling, i++) {
|
|
1016
|
-
if (node == target && i == offset)
|
|
1017
|
-
return { result: pos };
|
|
1018
|
-
if (!child)
|
|
1019
|
-
return { size: pos };
|
|
1020
|
-
let inner = posFromDOMInOpaqueNode(node, offset, child);
|
|
1021
|
-
if (inner.result != null)
|
|
1022
|
-
return { result: offset + inner.result };
|
|
1023
|
-
pos += inner.size;
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
else {
|
|
1027
|
-
return target.contains(node) ? { result: 0 } : { size: 0 };
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
1028
|
// These are drawn around uneditable widgets to avoid a number of
|
|
1031
1029
|
// browser bugs that show up when the cursor is directly next to
|
|
1032
1030
|
// uneditable inline content.
|
|
@@ -1146,16 +1144,20 @@ function combineAttrs(source, target) {
|
|
|
1146
1144
|
}
|
|
1147
1145
|
return target;
|
|
1148
1146
|
}
|
|
1149
|
-
|
|
1147
|
+
const noAttrs = /*@__PURE__*/Object.create(null);
|
|
1148
|
+
function attrsEq(a, b, ignore) {
|
|
1150
1149
|
if (a == b)
|
|
1151
1150
|
return true;
|
|
1152
|
-
if (!a
|
|
1153
|
-
|
|
1151
|
+
if (!a)
|
|
1152
|
+
a = noAttrs;
|
|
1153
|
+
if (!b)
|
|
1154
|
+
b = noAttrs;
|
|
1154
1155
|
let keysA = Object.keys(a), keysB = Object.keys(b);
|
|
1155
|
-
if (keysA.length
|
|
1156
|
+
if (keysA.length - (ignore && keysA.indexOf(ignore) > -1 ? 1 : 0) !=
|
|
1157
|
+
keysB.length - (ignore && keysB.indexOf(ignore) > -1 ? 1 : 0))
|
|
1156
1158
|
return false;
|
|
1157
1159
|
for (let key of keysA) {
|
|
1158
|
-
if (keysB.indexOf(key) == -1 || a[key] !== b[key])
|
|
1160
|
+
if (key != ignore && (keysB.indexOf(key) == -1 || a[key] !== b[key]))
|
|
1159
1161
|
return false;
|
|
1160
1162
|
}
|
|
1161
1163
|
return true;
|
|
@@ -1172,6 +1174,14 @@ function updateAttrs(dom, prev, attrs) {
|
|
|
1172
1174
|
dom.setAttribute(changed = name, attrs[name]);
|
|
1173
1175
|
return !!changed;
|
|
1174
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
|
+
}
|
|
1175
1185
|
|
|
1176
1186
|
/**
|
|
1177
1187
|
Widgets added to the content are described by subclasses of this
|
|
@@ -1236,10 +1246,6 @@ class WidgetType {
|
|
|
1236
1246
|
/**
|
|
1237
1247
|
@internal
|
|
1238
1248
|
*/
|
|
1239
|
-
get customView() { return null; }
|
|
1240
|
-
/**
|
|
1241
|
-
@internal
|
|
1242
|
-
*/
|
|
1243
1249
|
get isHidden() { return false; }
|
|
1244
1250
|
/**
|
|
1245
1251
|
This is called when the an instance of the widget is removed
|
|
@@ -1377,11 +1383,12 @@ class MarkDecoration extends Decoration {
|
|
|
1377
1383
|
this.attrs = spec.attributes || null;
|
|
1378
1384
|
}
|
|
1379
1385
|
eq(other) {
|
|
1386
|
+
var _a, _b;
|
|
1380
1387
|
return this == other ||
|
|
1381
1388
|
other instanceof MarkDecoration &&
|
|
1382
1389
|
this.tagName == other.tagName &&
|
|
1383
|
-
this.class == other.class &&
|
|
1384
|
-
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");
|
|
1385
1392
|
}
|
|
1386
1393
|
range(from, to = from) {
|
|
1387
1394
|
if (from >= to)
|
|
@@ -1533,7 +1540,7 @@ class LineView extends ContentView {
|
|
|
1533
1540
|
reuseDOM(node) {
|
|
1534
1541
|
if (node.nodeName == "DIV") {
|
|
1535
1542
|
this.setDOM(node);
|
|
1536
|
-
this.
|
|
1543
|
+
this.flags |= 4 /* AttrsDirty */ | 2 /* NodeDirty */;
|
|
1537
1544
|
}
|
|
1538
1545
|
}
|
|
1539
1546
|
sync(view, track) {
|
|
@@ -1543,7 +1550,7 @@ class LineView extends ContentView {
|
|
|
1543
1550
|
this.dom.className = "cm-line";
|
|
1544
1551
|
this.prevAttrs = this.attrs ? null : undefined;
|
|
1545
1552
|
}
|
|
1546
|
-
else if (this.
|
|
1553
|
+
else if (this.flags & 4 /* AttrsDirty */) {
|
|
1547
1554
|
clearAttributes(this.dom);
|
|
1548
1555
|
this.dom.className = "cm-line";
|
|
1549
1556
|
this.prevAttrs = this.attrs ? null : undefined;
|
|
@@ -2483,120 +2490,14 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
2483
2490
|
return EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
|
|
2484
2491
|
}
|
|
2485
2492
|
|
|
2486
|
-
const LineBreakPlaceholder = "\uffff";
|
|
2487
|
-
class DOMReader {
|
|
2488
|
-
constructor(points, state) {
|
|
2489
|
-
this.points = points;
|
|
2490
|
-
this.text = "";
|
|
2491
|
-
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
2492
|
-
}
|
|
2493
|
-
append(text) {
|
|
2494
|
-
this.text += text;
|
|
2495
|
-
}
|
|
2496
|
-
lineBreak() {
|
|
2497
|
-
this.text += LineBreakPlaceholder;
|
|
2498
|
-
}
|
|
2499
|
-
readRange(start, end) {
|
|
2500
|
-
if (!start)
|
|
2501
|
-
return this;
|
|
2502
|
-
let parent = start.parentNode;
|
|
2503
|
-
for (let cur = start;;) {
|
|
2504
|
-
this.findPointBefore(parent, cur);
|
|
2505
|
-
let oldLen = this.text.length;
|
|
2506
|
-
this.readNode(cur);
|
|
2507
|
-
let next = cur.nextSibling;
|
|
2508
|
-
if (next == end)
|
|
2509
|
-
break;
|
|
2510
|
-
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
2511
|
-
if (view && nextView ? view.breakAfter :
|
|
2512
|
-
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
2513
|
-
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
2514
|
-
this.lineBreak();
|
|
2515
|
-
cur = next;
|
|
2516
|
-
}
|
|
2517
|
-
this.findPointBefore(parent, end);
|
|
2518
|
-
return this;
|
|
2519
|
-
}
|
|
2520
|
-
readTextNode(node) {
|
|
2521
|
-
let text = node.nodeValue;
|
|
2522
|
-
for (let point of this.points)
|
|
2523
|
-
if (point.node == node)
|
|
2524
|
-
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
2525
|
-
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
2526
|
-
let nextBreak = -1, breakSize = 1, m;
|
|
2527
|
-
if (this.lineSeparator) {
|
|
2528
|
-
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
2529
|
-
breakSize = this.lineSeparator.length;
|
|
2530
|
-
}
|
|
2531
|
-
else if (m = re.exec(text)) {
|
|
2532
|
-
nextBreak = m.index;
|
|
2533
|
-
breakSize = m[0].length;
|
|
2534
|
-
}
|
|
2535
|
-
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
2536
|
-
if (nextBreak < 0)
|
|
2537
|
-
break;
|
|
2538
|
-
this.lineBreak();
|
|
2539
|
-
if (breakSize > 1)
|
|
2540
|
-
for (let point of this.points)
|
|
2541
|
-
if (point.node == node && point.pos > this.text.length)
|
|
2542
|
-
point.pos -= breakSize - 1;
|
|
2543
|
-
off = nextBreak + breakSize;
|
|
2544
|
-
}
|
|
2545
|
-
}
|
|
2546
|
-
readNode(node) {
|
|
2547
|
-
if (node.cmIgnore)
|
|
2548
|
-
return;
|
|
2549
|
-
let view = ContentView.get(node);
|
|
2550
|
-
let fromView = view && view.overrideDOMText;
|
|
2551
|
-
if (fromView != null) {
|
|
2552
|
-
this.findPointInside(node, fromView.length);
|
|
2553
|
-
for (let i = fromView.iter(); !i.next().done;) {
|
|
2554
|
-
if (i.lineBreak)
|
|
2555
|
-
this.lineBreak();
|
|
2556
|
-
else
|
|
2557
|
-
this.append(i.value);
|
|
2558
|
-
}
|
|
2559
|
-
}
|
|
2560
|
-
else if (node.nodeType == 3) {
|
|
2561
|
-
this.readTextNode(node);
|
|
2562
|
-
}
|
|
2563
|
-
else if (node.nodeName == "BR") {
|
|
2564
|
-
if (node.nextSibling)
|
|
2565
|
-
this.lineBreak();
|
|
2566
|
-
}
|
|
2567
|
-
else if (node.nodeType == 1) {
|
|
2568
|
-
this.readRange(node.firstChild, null);
|
|
2569
|
-
}
|
|
2570
|
-
}
|
|
2571
|
-
findPointBefore(node, next) {
|
|
2572
|
-
for (let point of this.points)
|
|
2573
|
-
if (point.node == node && node.childNodes[point.offset] == next)
|
|
2574
|
-
point.pos = this.text.length;
|
|
2575
|
-
}
|
|
2576
|
-
findPointInside(node, maxLen) {
|
|
2577
|
-
for (let point of this.points)
|
|
2578
|
-
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
2579
|
-
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
2580
|
-
}
|
|
2581
|
-
}
|
|
2582
|
-
function isBlockElement(node) {
|
|
2583
|
-
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
2584
|
-
}
|
|
2585
|
-
class DOMPoint {
|
|
2586
|
-
constructor(node, offset) {
|
|
2587
|
-
this.node = node;
|
|
2588
|
-
this.offset = offset;
|
|
2589
|
-
this.pos = -1;
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
|
|
2593
2493
|
class DocView extends ContentView {
|
|
2594
2494
|
constructor(view) {
|
|
2595
2495
|
super();
|
|
2596
2496
|
this.view = view;
|
|
2597
|
-
this.compositionDeco = Decoration.none;
|
|
2598
2497
|
this.decorations = [];
|
|
2599
2498
|
this.dynamicDecorationMap = [];
|
|
2499
|
+
this.hasComposition = false;
|
|
2500
|
+
this.markedForComposition = new Set;
|
|
2600
2501
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2601
2502
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
2602
2503
|
// of a given element and its extent in the document. When a change
|
|
@@ -2619,7 +2520,7 @@ class DocView extends ContentView {
|
|
|
2619
2520
|
this.children = [new LineView];
|
|
2620
2521
|
this.children[0].setParent(this);
|
|
2621
2522
|
this.updateDeco();
|
|
2622
|
-
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);
|
|
2623
2524
|
}
|
|
2624
2525
|
get length() { return this.view.state.doc.length; }
|
|
2625
2526
|
// Update the document view to a given state.
|
|
@@ -2634,26 +2535,26 @@ class DocView extends ContentView {
|
|
|
2634
2535
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2635
2536
|
}
|
|
2636
2537
|
}
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2538
|
+
let composition = this.view.inputState.composing < 0 ? null : findCompositionRange(this.view, update.changes);
|
|
2539
|
+
if (this.hasComposition)
|
|
2540
|
+
this.markedForComposition.clear();
|
|
2541
|
+
this.hasComposition = !!composition;
|
|
2641
2542
|
// When the DOM nodes around the selection are moved to another
|
|
2642
2543
|
// parent, Chrome sometimes reports a different selection through
|
|
2643
2544
|
// getSelection than the one that it actually shows to the user.
|
|
2644
2545
|
// This forces a selection update when lines are joined to work
|
|
2645
2546
|
// around that. Issue #54
|
|
2646
|
-
if ((browser.ie || browser.chrome) && !
|
|
2547
|
+
if ((browser.ie || browser.chrome) && !composition && update &&
|
|
2647
2548
|
update.state.doc.lines != update.startState.doc.lines)
|
|
2648
2549
|
this.forceSelection = true;
|
|
2649
2550
|
let prevDeco = this.decorations, deco = this.updateDeco();
|
|
2650
2551
|
let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
|
2651
2552
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
2652
|
-
if (this.
|
|
2553
|
+
if (!(this.flags & 7 /* Dirty */) && changedRanges.length == 0) {
|
|
2653
2554
|
return false;
|
|
2654
2555
|
}
|
|
2655
2556
|
else {
|
|
2656
|
-
this.updateInner(changedRanges, update.startState.doc.length);
|
|
2557
|
+
this.updateInner(changedRanges, update.startState.doc.length, composition);
|
|
2657
2558
|
if (update.transactions.length)
|
|
2658
2559
|
this.lastUpdate = Date.now();
|
|
2659
2560
|
return true;
|
|
@@ -2661,9 +2562,9 @@ class DocView extends ContentView {
|
|
|
2661
2562
|
}
|
|
2662
2563
|
// Used by update and the constructor do perform the actual DOM
|
|
2663
2564
|
// update
|
|
2664
|
-
updateInner(changes, oldLength) {
|
|
2565
|
+
updateInner(changes, oldLength, composition) {
|
|
2665
2566
|
this.view.viewState.mustMeasureContent = true;
|
|
2666
|
-
this.updateChildren(changes, oldLength);
|
|
2567
|
+
this.updateChildren(changes, oldLength, composition);
|
|
2667
2568
|
let { observer } = this.view;
|
|
2668
2569
|
observer.ignore(() => {
|
|
2669
2570
|
// Lock the height during redrawing, since Chrome sometimes
|
|
@@ -2678,11 +2579,12 @@ class DocView extends ContentView {
|
|
|
2678
2579
|
// to detect that situation.
|
|
2679
2580
|
let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
|
|
2680
2581
|
this.sync(this.view, track);
|
|
2681
|
-
this.
|
|
2582
|
+
this.flags &= ~7 /* Dirty */;
|
|
2682
2583
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2683
2584
|
this.forceSelection = true;
|
|
2684
2585
|
this.dom.style.height = "";
|
|
2685
2586
|
});
|
|
2587
|
+
this.markedForComposition.forEach(cView => cView.flags &= ~8 /* Composition */);
|
|
2686
2588
|
let gaps = [];
|
|
2687
2589
|
if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
|
|
2688
2590
|
for (let child of this.children)
|
|
@@ -2690,18 +2592,62 @@ class DocView extends ContentView {
|
|
|
2690
2592
|
gaps.push(child.dom);
|
|
2691
2593
|
observer.updateGaps(gaps);
|
|
2692
2594
|
}
|
|
2693
|
-
updateChildren(changes, oldLength) {
|
|
2595
|
+
updateChildren(changes, oldLength, composition) {
|
|
2596
|
+
let ranges = composition ? composition.range.addToSet(changes.slice()) : changes;
|
|
2694
2597
|
let cursor = this.childCursor(oldLength);
|
|
2695
|
-
for (let i =
|
|
2696
|
-
let next = i >= 0 ?
|
|
2598
|
+
for (let i = ranges.length - 1;; i--) {
|
|
2599
|
+
let next = i >= 0 ? ranges[i] : null;
|
|
2697
2600
|
if (!next)
|
|
2698
2601
|
break;
|
|
2699
|
-
let { fromA, toA, fromB, toB } = next;
|
|
2700
|
-
|
|
2602
|
+
let { fromA, toA, fromB, toB } = next, content, breakAtStart, openStart, openEnd;
|
|
2603
|
+
if (composition && composition.range.fromB < toB && composition.range.toB > fromB) {
|
|
2604
|
+
let before = ContentBuilder.build(this.view.state.doc, fromB, composition.range.fromB, this.decorations, this.dynamicDecorationMap);
|
|
2605
|
+
let after = ContentBuilder.build(this.view.state.doc, composition.range.toB, toB, this.decorations, this.dynamicDecorationMap);
|
|
2606
|
+
breakAtStart = before.breakAtStart;
|
|
2607
|
+
openStart = before.openStart;
|
|
2608
|
+
openEnd = after.openEnd;
|
|
2609
|
+
let compLine = this.compositionView(composition);
|
|
2610
|
+
compLine.merge(compLine.length, compLine.length, after.content[0], false, after.openStart, 0);
|
|
2611
|
+
compLine.merge(0, 0, before.content[before.content.length - 1], true, 0, before.openEnd);
|
|
2612
|
+
content = before.content.slice(0, before.content.length - 1).concat(compLine).concat(after.content.slice(1));
|
|
2613
|
+
}
|
|
2614
|
+
else {
|
|
2615
|
+
({ content, breakAtStart, openStart, openEnd } =
|
|
2616
|
+
ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap));
|
|
2617
|
+
}
|
|
2701
2618
|
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2702
2619
|
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2703
2620
|
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
2704
2621
|
}
|
|
2622
|
+
if (composition)
|
|
2623
|
+
this.fixCompositionDOM(composition);
|
|
2624
|
+
}
|
|
2625
|
+
compositionView(composition) {
|
|
2626
|
+
let cur = new TextView(composition.text.nodeValue);
|
|
2627
|
+
cur.flags |= 8 /* Composition */;
|
|
2628
|
+
for (let { deco } of composition.marks)
|
|
2629
|
+
cur = new MarkView(deco, [cur], cur.length);
|
|
2630
|
+
let line = new LineView;
|
|
2631
|
+
line.append(cur, 0);
|
|
2632
|
+
return line;
|
|
2633
|
+
}
|
|
2634
|
+
fixCompositionDOM(composition) {
|
|
2635
|
+
let fix = (dom, cView) => {
|
|
2636
|
+
cView.flags |= 8 /* Composition */;
|
|
2637
|
+
this.markedForComposition.add(cView);
|
|
2638
|
+
let prev = ContentView.get(dom);
|
|
2639
|
+
if (prev)
|
|
2640
|
+
prev.dom = null;
|
|
2641
|
+
cView.setDOM(dom);
|
|
2642
|
+
};
|
|
2643
|
+
let pos = this.childPos(composition.range.fromB, 1);
|
|
2644
|
+
let cView = this.children[pos.i];
|
|
2645
|
+
fix(composition.line, cView);
|
|
2646
|
+
for (let i = composition.marks.length - 1; i >= -1; i--) {
|
|
2647
|
+
pos = cView.childPos(pos.off, 1);
|
|
2648
|
+
cView = cView.children[pos.i];
|
|
2649
|
+
fix(i >= 0 ? composition.marks[i].node : composition.text, cView);
|
|
2650
|
+
}
|
|
2705
2651
|
}
|
|
2706
2652
|
// Sync the DOM selection to this.state.selection
|
|
2707
2653
|
updateSelection(mustRead = false, fromPointer = false) {
|
|
@@ -2720,7 +2666,7 @@ class DocView extends ContentView {
|
|
|
2720
2666
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2721
2667
|
// Always reset on Firefox when next to an uneditable node to
|
|
2722
2668
|
// avoid invisible cursor bugs (#111)
|
|
2723
|
-
if (browser.gecko && main.empty && !this.
|
|
2669
|
+
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
|
|
2724
2670
|
let dummy = document.createTextNode("");
|
|
2725
2671
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
2726
2672
|
anchor = head = new DOMPos(dummy, 0);
|
|
@@ -2792,7 +2738,7 @@ class DocView extends ContentView {
|
|
|
2792
2738
|
this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
|
|
2793
2739
|
}
|
|
2794
2740
|
enforceCursorAssoc() {
|
|
2795
|
-
if (this.
|
|
2741
|
+
if (this.hasComposition)
|
|
2796
2742
|
return;
|
|
2797
2743
|
let { view } = this, cursor = view.state.selection.main;
|
|
2798
2744
|
let sel = getSelection(view.root);
|
|
@@ -2902,6 +2848,7 @@ class DocView extends ContentView {
|
|
|
2902
2848
|
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2903
2849
|
dummy.className = "cm-line";
|
|
2904
2850
|
dummy.style.width = "99999px";
|
|
2851
|
+
dummy.style.position = "absolute";
|
|
2905
2852
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
2906
2853
|
this.view.observer.ignore(() => {
|
|
2907
2854
|
this.dom.appendChild(dummy);
|
|
@@ -2951,7 +2898,6 @@ class DocView extends ContentView {
|
|
|
2951
2898
|
this.dynamicDecorationMap[i] = false;
|
|
2952
2899
|
return this.decorations = [
|
|
2953
2900
|
...allDeco,
|
|
2954
|
-
this.compositionDeco,
|
|
2955
2901
|
this.computeBlockGapDeco(),
|
|
2956
2902
|
this.view.viewState.lineGapDeco
|
|
2957
2903
|
];
|
|
@@ -2994,81 +2940,85 @@ class BlockGapWidget extends WidgetType {
|
|
|
2994
2940
|
}
|
|
2995
2941
|
get estimatedHeight() { return this.height; }
|
|
2996
2942
|
}
|
|
2997
|
-
function
|
|
2943
|
+
function findCompositionNode(view) {
|
|
2998
2944
|
let sel = view.observer.selectionRange;
|
|
2999
2945
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3000
2946
|
if (!textNode)
|
|
3001
2947
|
return null;
|
|
3002
|
-
let cView =
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
while (topNode.parentNode != cView.dom)
|
|
3008
|
-
topNode = topNode.parentNode;
|
|
3009
|
-
let prev = topNode.previousSibling;
|
|
3010
|
-
while (prev && !ContentView.get(prev))
|
|
3011
|
-
prev = prev.previousSibling;
|
|
3012
|
-
let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
|
|
3013
|
-
return { from: pos, to: pos, node: topNode, text: textNode };
|
|
2948
|
+
let cView = ContentView.get(textNode);
|
|
2949
|
+
let from, to;
|
|
2950
|
+
if (cView instanceof TextView) {
|
|
2951
|
+
from = cView.posAtStart;
|
|
2952
|
+
to = from + cView.length;
|
|
3014
2953
|
}
|
|
3015
2954
|
else {
|
|
3016
|
-
for (;;) {
|
|
3017
|
-
let
|
|
3018
|
-
|
|
2955
|
+
up: for (let offset = 0, node = textNode;;) {
|
|
2956
|
+
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
2957
|
+
if (cView = ContentView.get(sibling)) {
|
|
2958
|
+
from = to = cView.posAtEnd + offset;
|
|
2959
|
+
break up;
|
|
2960
|
+
}
|
|
2961
|
+
let reader = new DOMReader([], view.state);
|
|
2962
|
+
reader.readNode(sibling);
|
|
2963
|
+
if (reader.text.indexOf(LineBreakPlaceholder) > -1)
|
|
2964
|
+
return null;
|
|
2965
|
+
offset += reader.text.length;
|
|
2966
|
+
}
|
|
2967
|
+
node = node.parentNode;
|
|
2968
|
+
if (!node)
|
|
3019
2969
|
return null;
|
|
3020
|
-
|
|
2970
|
+
let parentView = ContentView.get(node);
|
|
2971
|
+
if (parentView) {
|
|
2972
|
+
from = to = parentView.posAtStart + offset;
|
|
3021
2973
|
break;
|
|
3022
|
-
|
|
2974
|
+
}
|
|
3023
2975
|
}
|
|
3024
|
-
let from = cView.posAtStart;
|
|
3025
|
-
return { from, to: from + cView.length, node: cView.dom, text: textNode };
|
|
3026
2976
|
}
|
|
2977
|
+
return { from, to, node: textNode };
|
|
3027
2978
|
}
|
|
3028
|
-
function
|
|
3029
|
-
let
|
|
3030
|
-
if (!
|
|
3031
|
-
return
|
|
3032
|
-
let { from, to, node
|
|
3033
|
-
let
|
|
3034
|
-
let
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
if
|
|
3044
|
-
|
|
3045
|
-
|
|
3046
|
-
|
|
2979
|
+
function findCompositionRange(view, changes) {
|
|
2980
|
+
let found = findCompositionNode(view);
|
|
2981
|
+
if (!found)
|
|
2982
|
+
return null;
|
|
2983
|
+
let { from: fromA, to: toA, node: textNode } = found;
|
|
2984
|
+
let fromB = changes.mapPos(fromA, -1), toB = changes.mapPos(toA, 1);
|
|
2985
|
+
let text = textNode.nodeValue;
|
|
2986
|
+
// Don't try to preserve multi-line compositions
|
|
2987
|
+
if (/[\n\r]/.test(text))
|
|
2988
|
+
return null;
|
|
2989
|
+
if (toB - fromB != text.length) {
|
|
2990
|
+
// If there is a length mismatch, see if mapping non-inclusively helps
|
|
2991
|
+
let fromB2 = changes.mapPos(fromA, 1), toB2 = changes.mapPos(toA, -1);
|
|
2992
|
+
if (toB2 - fromB2 == text.length)
|
|
2993
|
+
fromB = fromB2, toB = toB2;
|
|
2994
|
+
// See if we can find an instance of the text at either side
|
|
2995
|
+
else if (view.state.doc.sliceString(toB - text.length, toB) == text)
|
|
2996
|
+
fromB = toB - text.length;
|
|
2997
|
+
else if (view.state.doc.sliceString(fromB, fromB + text.length) == text)
|
|
2998
|
+
toB = fromB + text.length;
|
|
2999
|
+
// Not found
|
|
3047
3000
|
else
|
|
3048
|
-
return
|
|
3049
|
-
}
|
|
3050
|
-
else if (state.doc.sliceString(newFrom, newTo) != text) {
|
|
3051
|
-
return Decoration.none;
|
|
3001
|
+
return null;
|
|
3052
3002
|
}
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
}
|
|
3061
|
-
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
|
-
|
|
3065
|
-
|
|
3066
|
-
|
|
3003
|
+
if (view.state.doc.sliceString(fromB, toB) != text)
|
|
3004
|
+
return null;
|
|
3005
|
+
let marks = [];
|
|
3006
|
+
let range = new ChangedRange(fromA, toA, fromB, toB);
|
|
3007
|
+
for (let parent = textNode.parentNode;; parent = parent.parentNode) {
|
|
3008
|
+
let parentView = ContentView.get(parent);
|
|
3009
|
+
if (parentView instanceof MarkView)
|
|
3010
|
+
marks.push({ node: parent, deco: parentView.mark });
|
|
3011
|
+
else if (parentView instanceof LineView || parent.nodeName == "DIV" && parent.parentNode == view.contentDOM)
|
|
3012
|
+
return { range, text: textNode, marks, line: parent };
|
|
3013
|
+
else if (parent != view.contentDOM)
|
|
3014
|
+
marks.push({ node: parent, deco: new MarkDecoration({
|
|
3015
|
+
inclusive: true,
|
|
3016
|
+
attributes: getAttrs(parent),
|
|
3017
|
+
tagName: parent.tagName.toLowerCase()
|
|
3018
|
+
}) });
|
|
3019
|
+
else
|
|
3020
|
+
return null;
|
|
3067
3021
|
}
|
|
3068
|
-
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
3069
|
-
toDOM() { return this.top; }
|
|
3070
|
-
ignoreEvent() { return false; }
|
|
3071
|
-
get customView() { return CompositionView; }
|
|
3072
3022
|
}
|
|
3073
3023
|
function nearbyTextNode(startNode, startOffset, side) {
|
|
3074
3024
|
if (side <= 0)
|
|
@@ -3719,6 +3669,7 @@ class InputState {
|
|
|
3719
3669
|
const PendingKeys = [
|
|
3720
3670
|
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3721
3671
|
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
3672
|
+
{ key: "Enter", keyCode: 13, inputType: "insertLineBreak" },
|
|
3722
3673
|
{ key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
|
|
3723
3674
|
];
|
|
3724
3675
|
const EmacsyPendingKeys = "dthko";
|
|
@@ -3728,9 +3679,13 @@ const dragScrollMargin = 6;
|
|
|
3728
3679
|
function dragScrollSpeed(dist) {
|
|
3729
3680
|
return Math.max(0, dist) * 0.7 + 8;
|
|
3730
3681
|
}
|
|
3682
|
+
function dist(a, b) {
|
|
3683
|
+
return Math.max(Math.abs(a.clientX - b.clientX), Math.abs(a.clientY - b.clientY));
|
|
3684
|
+
}
|
|
3731
3685
|
class MouseSelection {
|
|
3732
3686
|
constructor(view, startEvent, style, mustSelect) {
|
|
3733
3687
|
this.view = view;
|
|
3688
|
+
this.startEvent = startEvent;
|
|
3734
3689
|
this.style = style;
|
|
3735
3690
|
this.mustSelect = mustSelect;
|
|
3736
3691
|
this.scrollSpeed = { x: 0, y: 0 };
|
|
@@ -3757,7 +3712,7 @@ class MouseSelection {
|
|
|
3757
3712
|
var _a;
|
|
3758
3713
|
if (event.buttons == 0)
|
|
3759
3714
|
return this.destroy();
|
|
3760
|
-
if (this.dragging
|
|
3715
|
+
if (this.dragging || this.dragging == null && dist(this.startEvent, event) < 10)
|
|
3761
3716
|
return;
|
|
3762
3717
|
this.select(this.lastEvent = event);
|
|
3763
3718
|
let sx = 0, sy = 0;
|
|
@@ -3836,7 +3791,7 @@ class MouseSelection {
|
|
|
3836
3791
|
select(event) {
|
|
3837
3792
|
let { view } = this, selection = this.skipAtoms(this.style.get(event, this.extend, this.multiple));
|
|
3838
3793
|
if (this.mustSelect || !selection.eq(view.state.selection) ||
|
|
3839
|
-
selection.main.assoc != view.state.selection.main.assoc)
|
|
3794
|
+
selection.main.assoc != view.state.selection.main.assoc && this.dragging === false)
|
|
3840
3795
|
this.view.dispatch({
|
|
3841
3796
|
selection,
|
|
3842
3797
|
userEvent: "select.pointer"
|
|
@@ -3963,7 +3918,7 @@ handlers.mousedown = (view, event) => {
|
|
|
3963
3918
|
if (!style && event.button == 0)
|
|
3964
3919
|
style = basicMouseSelection(view, event);
|
|
3965
3920
|
if (style) {
|
|
3966
|
-
let mustFocus = view.
|
|
3921
|
+
let mustFocus = !view.hasFocus;
|
|
3967
3922
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
3968
3923
|
if (mustFocus)
|
|
3969
3924
|
view.observer.ignore(() => focusPreventScroll(view.contentDOM));
|
|
@@ -4255,7 +4210,7 @@ handlers.compositionend = view => {
|
|
|
4255
4210
|
// Otherwise, make sure that, if no changes come in soon, the
|
|
4256
4211
|
// composition view is cleared.
|
|
4257
4212
|
setTimeout(() => {
|
|
4258
|
-
if (view.inputState.composing < 0 && view.docView.
|
|
4213
|
+
if (view.inputState.composing < 0 && view.docView.hasComposition)
|
|
4259
4214
|
view.update([]);
|
|
4260
4215
|
}, 50);
|
|
4261
4216
|
}
|
|
@@ -5159,7 +5114,7 @@ class ViewState {
|
|
|
5159
5114
|
let contentChanges = update.changedRanges;
|
|
5160
5115
|
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
|
|
5161
5116
|
let prevHeight = this.heightMap.height;
|
|
5162
|
-
let scrollAnchor = this.scrolledToBottom ? null : this.
|
|
5117
|
+
let scrollAnchor = this.scrolledToBottom ? null : this.scrollAnchorAt(this.scrollTop);
|
|
5163
5118
|
this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
|
|
5164
5119
|
if (this.heightMap.height != prevHeight)
|
|
5165
5120
|
update.flags |= 2 /* Height */;
|
|
@@ -5219,7 +5174,7 @@ class ViewState {
|
|
|
5219
5174
|
this.scrollAnchorHeight = -1;
|
|
5220
5175
|
this.scrollTop = view.scrollDOM.scrollTop;
|
|
5221
5176
|
}
|
|
5222
|
-
this.scrolledToBottom =
|
|
5177
|
+
this.scrolledToBottom = isScrolledToBottom(view.scrollDOM);
|
|
5223
5178
|
// Pixel viewport
|
|
5224
5179
|
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
|
5225
5180
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
@@ -5462,6 +5417,10 @@ class ViewState {
|
|
|
5462
5417
|
lineBlockAtHeight(height) {
|
|
5463
5418
|
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5464
5419
|
}
|
|
5420
|
+
scrollAnchorAt(scrollTop) {
|
|
5421
|
+
let block = this.lineBlockAtHeight(scrollTop + 8);
|
|
5422
|
+
return block.from >= this.viewport.from || this.viewportLines[0].top - scrollTop > 200 ? block : this.viewportLines[0];
|
|
5423
|
+
}
|
|
5465
5424
|
elementAtHeight(height) {
|
|
5466
5425
|
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
|
|
5467
5426
|
}
|
|
@@ -5967,7 +5926,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5967
5926
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5968
5927
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5969
5928
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5970
|
-
let
|
|
5929
|
+
let composition = findCompositionNode(view) || view.state.doc.lineAt(sel.head);
|
|
5971
5930
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5972
5931
|
tr = startState.changeByRange(range => {
|
|
5973
5932
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -5978,7 +5937,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5978
5937
|
// changes in the same node work without aborting
|
|
5979
5938
|
// composition, so cursors in the composition range are
|
|
5980
5939
|
// ignored.
|
|
5981
|
-
|
|
5940
|
+
composition && range.to >= composition.from && range.from <= composition.to)
|
|
5982
5941
|
return { range };
|
|
5983
5942
|
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5984
5943
|
return {
|
|
@@ -6439,7 +6398,7 @@ class DOMObserver {
|
|
|
6439
6398
|
return null;
|
|
6440
6399
|
cView.markDirty(rec.type == "attributes");
|
|
6441
6400
|
if (rec.type == "attributes")
|
|
6442
|
-
cView.
|
|
6401
|
+
cView.flags |= 4 /* AttrsDirty */;
|
|
6443
6402
|
if (rec.type == "childList") {
|
|
6444
6403
|
let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1);
|
|
6445
6404
|
let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1);
|
|
@@ -6834,22 +6793,23 @@ class EditorView {
|
|
|
6834
6793
|
let updated = null;
|
|
6835
6794
|
let sDOM = this.scrollDOM, { scrollTop } = sDOM;
|
|
6836
6795
|
let { scrollAnchorPos, scrollAnchorHeight } = this.viewState;
|
|
6796
|
+
if (scrollTop != this.viewState.scrollTop)
|
|
6797
|
+
scrollAnchorHeight = -1;
|
|
6837
6798
|
this.viewState.scrollAnchorHeight = -1;
|
|
6838
|
-
if (scrollAnchorHeight < 0 || scrollTop != this.viewState.scrollTop) {
|
|
6839
|
-
if (scrollTop > sDOM.scrollHeight - sDOM.clientHeight - 4) {
|
|
6840
|
-
scrollAnchorPos = -1;
|
|
6841
|
-
scrollAnchorHeight = this.viewState.heightMap.height;
|
|
6842
|
-
}
|
|
6843
|
-
else {
|
|
6844
|
-
let block = this.viewState.lineBlockAtHeight(scrollTop);
|
|
6845
|
-
scrollAnchorPos = block.from;
|
|
6846
|
-
scrollAnchorHeight = block.top;
|
|
6847
|
-
}
|
|
6848
|
-
}
|
|
6849
6799
|
try {
|
|
6850
6800
|
for (let i = 0;; i++) {
|
|
6801
|
+
if (scrollAnchorHeight < 0) {
|
|
6802
|
+
if (isScrolledToBottom(sDOM)) {
|
|
6803
|
+
scrollAnchorPos = -1;
|
|
6804
|
+
scrollAnchorHeight = this.viewState.heightMap.height;
|
|
6805
|
+
}
|
|
6806
|
+
else {
|
|
6807
|
+
let block = this.viewState.scrollAnchorAt(scrollTop);
|
|
6808
|
+
scrollAnchorPos = block.from;
|
|
6809
|
+
scrollAnchorHeight = block.top;
|
|
6810
|
+
}
|
|
6811
|
+
}
|
|
6851
6812
|
this.updateState = 1 /* Measuring */;
|
|
6852
|
-
let oldViewport = this.viewport;
|
|
6853
6813
|
let changed = this.viewState.measure(this);
|
|
6854
6814
|
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
|
6855
6815
|
break;
|
|
@@ -6872,7 +6832,7 @@ class EditorView {
|
|
|
6872
6832
|
return BadMeasure;
|
|
6873
6833
|
}
|
|
6874
6834
|
});
|
|
6875
|
-
let update = ViewUpdate.create(this, this.state, []), redrawn = false
|
|
6835
|
+
let update = ViewUpdate.create(this, this.state, []), redrawn = false;
|
|
6876
6836
|
update.flags |= changed;
|
|
6877
6837
|
if (!updated)
|
|
6878
6838
|
updated = update;
|
|
@@ -6896,28 +6856,28 @@ class EditorView {
|
|
|
6896
6856
|
logException(this.state, e);
|
|
6897
6857
|
}
|
|
6898
6858
|
}
|
|
6899
|
-
if (this.viewState.editorHeight) {
|
|
6900
|
-
if (this.viewState.scrollTarget) {
|
|
6901
|
-
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6902
|
-
this.viewState.scrollTarget = null;
|
|
6903
|
-
scrolled = true;
|
|
6904
|
-
}
|
|
6905
|
-
else if (scrollAnchorHeight > -1) {
|
|
6906
|
-
let newAnchorHeight = scrollAnchorPos < 0 ? this.viewState.heightMap.height :
|
|
6907
|
-
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
6908
|
-
let diff = newAnchorHeight - scrollAnchorHeight;
|
|
6909
|
-
if (diff > 1 || diff < -1) {
|
|
6910
|
-
sDOM.scrollTop = scrollTop + diff;
|
|
6911
|
-
scrolled = true;
|
|
6912
|
-
}
|
|
6913
|
-
}
|
|
6914
|
-
}
|
|
6915
6859
|
if (redrawn)
|
|
6916
6860
|
this.docView.updateSelection(true);
|
|
6917
|
-
if (
|
|
6918
|
-
|
|
6861
|
+
if (!update.viewportChanged && this.measureRequests.length == 0) {
|
|
6862
|
+
if (this.viewState.editorHeight) {
|
|
6863
|
+
if (this.viewState.scrollTarget) {
|
|
6864
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6865
|
+
this.viewState.scrollTarget = null;
|
|
6866
|
+
continue;
|
|
6867
|
+
}
|
|
6868
|
+
else {
|
|
6869
|
+
let newAnchorHeight = scrollAnchorPos < 0 ? this.viewState.heightMap.height :
|
|
6870
|
+
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
6871
|
+
let diff = newAnchorHeight - scrollAnchorHeight;
|
|
6872
|
+
if (diff > 1 || diff < -1) {
|
|
6873
|
+
scrollTop = sDOM.scrollTop = scrollTop + diff;
|
|
6874
|
+
scrollAnchorHeight = -1;
|
|
6875
|
+
continue;
|
|
6876
|
+
}
|
|
6877
|
+
}
|
|
6878
|
+
}
|
|
6919
6879
|
break;
|
|
6920
|
-
|
|
6880
|
+
}
|
|
6921
6881
|
}
|
|
6922
6882
|
}
|
|
6923
6883
|
finally {
|
|
@@ -7612,7 +7572,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7612
7572
|
else if (current != is)
|
|
7613
7573
|
throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix");
|
|
7614
7574
|
};
|
|
7615
|
-
let add = (scope, key, command, preventDefault) => {
|
|
7575
|
+
let add = (scope, key, command, preventDefault, stopPropagation) => {
|
|
7616
7576
|
var _a, _b;
|
|
7617
7577
|
let scopeObj = bound[scope] || (bound[scope] = Object.create(null));
|
|
7618
7578
|
let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform));
|
|
@@ -7622,6 +7582,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7622
7582
|
if (!scopeObj[prefix])
|
|
7623
7583
|
scopeObj[prefix] = {
|
|
7624
7584
|
preventDefault: true,
|
|
7585
|
+
stopPropagation: false,
|
|
7625
7586
|
run: [(view) => {
|
|
7626
7587
|
let ourObj = storedPrefix = { view, prefix, scope };
|
|
7627
7588
|
setTimeout(() => { if (storedPrefix == ourObj)
|
|
@@ -7632,11 +7593,17 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7632
7593
|
}
|
|
7633
7594
|
let full = parts.join(" ");
|
|
7634
7595
|
checkPrefix(full, false);
|
|
7635
|
-
let binding = scopeObj[full] || (scopeObj[full] = {
|
|
7596
|
+
let binding = scopeObj[full] || (scopeObj[full] = {
|
|
7597
|
+
preventDefault: false,
|
|
7598
|
+
stopPropagation: false,
|
|
7599
|
+
run: ((_b = (_a = scopeObj._any) === null || _a === void 0 ? void 0 : _a.run) === null || _b === void 0 ? void 0 : _b.slice()) || []
|
|
7600
|
+
});
|
|
7636
7601
|
if (command)
|
|
7637
7602
|
binding.run.push(command);
|
|
7638
7603
|
if (preventDefault)
|
|
7639
7604
|
binding.preventDefault = true;
|
|
7605
|
+
if (stopPropagation)
|
|
7606
|
+
binding.stopPropagation = true;
|
|
7640
7607
|
};
|
|
7641
7608
|
for (let b of bindings) {
|
|
7642
7609
|
let scopes = b.scope ? b.scope.split(" ") : ["editor"];
|
|
@@ -7644,7 +7611,7 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7644
7611
|
for (let scope of scopes) {
|
|
7645
7612
|
let scopeObj = bound[scope] || (bound[scope] = Object.create(null));
|
|
7646
7613
|
if (!scopeObj._any)
|
|
7647
|
-
scopeObj._any = { preventDefault: false, run: [] };
|
|
7614
|
+
scopeObj._any = { preventDefault: false, stopPropagation: false, run: [] };
|
|
7648
7615
|
for (let key in scopeObj)
|
|
7649
7616
|
scopeObj[key].run.push(b.any);
|
|
7650
7617
|
}
|
|
@@ -7652,9 +7619,9 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7652
7619
|
if (!name)
|
|
7653
7620
|
continue;
|
|
7654
7621
|
for (let scope of scopes) {
|
|
7655
|
-
add(scope, name, b.run, b.preventDefault);
|
|
7622
|
+
add(scope, name, b.run, b.preventDefault, b.stopPropagation);
|
|
7656
7623
|
if (b.shift)
|
|
7657
|
-
add(scope, "Shift-" + name, b.shift, b.preventDefault);
|
|
7624
|
+
add(scope, "Shift-" + name, b.shift, b.preventDefault, b.stopPropagation);
|
|
7658
7625
|
}
|
|
7659
7626
|
}
|
|
7660
7627
|
return bound;
|
|
@@ -7662,11 +7629,13 @@ function buildKeymap(bindings, platform = currentPlatform) {
|
|
|
7662
7629
|
function runHandlers(map, event, view, scope) {
|
|
7663
7630
|
let name = keyName(event);
|
|
7664
7631
|
let charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " ";
|
|
7665
|
-
let prefix = "",
|
|
7632
|
+
let prefix = "", handled = false, prevented = false, stopPropagation = false;
|
|
7666
7633
|
if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) {
|
|
7667
7634
|
prefix = storedPrefix.prefix + " ";
|
|
7668
|
-
if (
|
|
7635
|
+
if (modifierCodes.indexOf(event.keyCode) < 0) {
|
|
7636
|
+
prevented = true;
|
|
7669
7637
|
storedPrefix = null;
|
|
7638
|
+
}
|
|
7670
7639
|
}
|
|
7671
7640
|
let ran = new Set;
|
|
7672
7641
|
let runFor = (binding) => {
|
|
@@ -7674,36 +7643,49 @@ function runHandlers(map, event, view, scope) {
|
|
|
7674
7643
|
for (let cmd of binding.run)
|
|
7675
7644
|
if (!ran.has(cmd)) {
|
|
7676
7645
|
ran.add(cmd);
|
|
7677
|
-
if (cmd(view, event))
|
|
7646
|
+
if (cmd(view, event)) {
|
|
7647
|
+
if (binding.stopPropagation)
|
|
7648
|
+
stopPropagation = true;
|
|
7678
7649
|
return true;
|
|
7650
|
+
}
|
|
7679
7651
|
}
|
|
7680
|
-
if (binding.preventDefault)
|
|
7681
|
-
|
|
7652
|
+
if (binding.preventDefault) {
|
|
7653
|
+
if (binding.stopPropagation)
|
|
7654
|
+
stopPropagation = true;
|
|
7655
|
+
prevented = true;
|
|
7656
|
+
}
|
|
7682
7657
|
}
|
|
7683
7658
|
return false;
|
|
7684
7659
|
};
|
|
7685
7660
|
let scopeObj = map[scope], baseName, shiftName;
|
|
7686
7661
|
if (scopeObj) {
|
|
7687
|
-
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)]))
|
|
7688
|
-
|
|
7689
|
-
|
|
7662
|
+
if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)])) {
|
|
7663
|
+
handled = true;
|
|
7664
|
+
}
|
|
7665
|
+
else if (isChar && (event.altKey || event.metaKey || event.ctrlKey) &&
|
|
7690
7666
|
// Ctrl-Alt may be used for AltGr on Windows
|
|
7691
7667
|
!(browser.windows && event.ctrlKey && event.altKey) &&
|
|
7692
7668
|
(baseName = base[event.keyCode]) && baseName != name) {
|
|
7693
|
-
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)]))
|
|
7694
|
-
|
|
7669
|
+
if (runFor(scopeObj[prefix + modifiers(baseName, event, true)])) {
|
|
7670
|
+
handled = true;
|
|
7671
|
+
}
|
|
7695
7672
|
else if (event.shiftKey && (shiftName = shift[event.keyCode]) != name && shiftName != baseName &&
|
|
7696
|
-
runFor(scopeObj[prefix + modifiers(shiftName, event, false)]))
|
|
7697
|
-
|
|
7673
|
+
runFor(scopeObj[prefix + modifiers(shiftName, event, false)])) {
|
|
7674
|
+
handled = true;
|
|
7675
|
+
}
|
|
7698
7676
|
}
|
|
7699
|
-
else if (isChar && event.shiftKey
|
|
7700
|
-
|
|
7701
|
-
|
|
7677
|
+
else if (isChar && event.shiftKey &&
|
|
7678
|
+
runFor(scopeObj[prefix + modifiers(name, event, true)])) {
|
|
7679
|
+
handled = true;
|
|
7702
7680
|
}
|
|
7703
|
-
if (runFor(scopeObj._any))
|
|
7704
|
-
|
|
7681
|
+
if (!handled && runFor(scopeObj._any))
|
|
7682
|
+
handled = true;
|
|
7705
7683
|
}
|
|
7706
|
-
|
|
7684
|
+
if (prevented)
|
|
7685
|
+
handled = true;
|
|
7686
|
+
if (handled && stopPropagation)
|
|
7687
|
+
event.stopPropagation();
|
|
7688
|
+
return handled;
|
|
7707
7689
|
}
|
|
7708
7690
|
|
|
7709
7691
|
/**
|
|
@@ -8490,7 +8472,9 @@ function placeholder(content) {
|
|
|
8490
8472
|
return ViewPlugin.fromClass(class {
|
|
8491
8473
|
constructor(view) {
|
|
8492
8474
|
this.view = view;
|
|
8493
|
-
this.placeholder =
|
|
8475
|
+
this.placeholder = content
|
|
8476
|
+
? Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)])
|
|
8477
|
+
: Decoration.none;
|
|
8494
8478
|
}
|
|
8495
8479
|
get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; }
|
|
8496
8480
|
}, { decorations: v => v.decorations });
|