@codemirror/view 6.18.0 → 6.18.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 +10 -0
- package/dist/index.cjs +184 -181
- package/dist/index.js +185 -182
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 6.18.1 (2023-09-11)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where the editor duplicated text when the browser moved content into the focused text node on composition.
|
|
6
|
+
|
|
7
|
+
Make sure `widgetMarker` is called for gutters on lines covered by a block replace decoration.
|
|
8
|
+
|
|
9
|
+
Fix an issue where the cursor could be shown in a position that doesn't allow a cursor when the selection is in a block widget.
|
|
10
|
+
|
|
1
11
|
## 6.18.0 (2023-09-05)
|
|
2
12
|
|
|
3
13
|
### New features
|
package/dist/index.cjs
CHANGED
|
@@ -484,6 +484,8 @@ class ContentView {
|
|
|
484
484
|
}
|
|
485
485
|
}
|
|
486
486
|
setDOM(dom) {
|
|
487
|
+
if (this.dom == dom)
|
|
488
|
+
return;
|
|
487
489
|
if (this.dom)
|
|
488
490
|
this.dom.cmView = null;
|
|
489
491
|
this.dom = dom;
|
|
@@ -656,113 +658,6 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
656
658
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
657
659
|
}
|
|
658
660
|
|
|
659
|
-
const LineBreakPlaceholder = "\uffff";
|
|
660
|
-
class DOMReader {
|
|
661
|
-
constructor(points, state$1) {
|
|
662
|
-
this.points = points;
|
|
663
|
-
this.text = "";
|
|
664
|
-
this.lineSeparator = state$1.facet(state.EditorState.lineSeparator);
|
|
665
|
-
}
|
|
666
|
-
append(text) {
|
|
667
|
-
this.text += text;
|
|
668
|
-
}
|
|
669
|
-
lineBreak() {
|
|
670
|
-
this.text += LineBreakPlaceholder;
|
|
671
|
-
}
|
|
672
|
-
readRange(start, end) {
|
|
673
|
-
if (!start)
|
|
674
|
-
return this;
|
|
675
|
-
let parent = start.parentNode;
|
|
676
|
-
for (let cur = start;;) {
|
|
677
|
-
this.findPointBefore(parent, cur);
|
|
678
|
-
let oldLen = this.text.length;
|
|
679
|
-
this.readNode(cur);
|
|
680
|
-
let next = cur.nextSibling;
|
|
681
|
-
if (next == end)
|
|
682
|
-
break;
|
|
683
|
-
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
684
|
-
if (view && nextView ? view.breakAfter :
|
|
685
|
-
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
686
|
-
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
687
|
-
this.lineBreak();
|
|
688
|
-
cur = next;
|
|
689
|
-
}
|
|
690
|
-
this.findPointBefore(parent, end);
|
|
691
|
-
return this;
|
|
692
|
-
}
|
|
693
|
-
readTextNode(node) {
|
|
694
|
-
let text = node.nodeValue;
|
|
695
|
-
for (let point of this.points)
|
|
696
|
-
if (point.node == node)
|
|
697
|
-
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
698
|
-
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
699
|
-
let nextBreak = -1, breakSize = 1, m;
|
|
700
|
-
if (this.lineSeparator) {
|
|
701
|
-
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
702
|
-
breakSize = this.lineSeparator.length;
|
|
703
|
-
}
|
|
704
|
-
else if (m = re.exec(text)) {
|
|
705
|
-
nextBreak = m.index;
|
|
706
|
-
breakSize = m[0].length;
|
|
707
|
-
}
|
|
708
|
-
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
709
|
-
if (nextBreak < 0)
|
|
710
|
-
break;
|
|
711
|
-
this.lineBreak();
|
|
712
|
-
if (breakSize > 1)
|
|
713
|
-
for (let point of this.points)
|
|
714
|
-
if (point.node == node && point.pos > this.text.length)
|
|
715
|
-
point.pos -= breakSize - 1;
|
|
716
|
-
off = nextBreak + breakSize;
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
readNode(node) {
|
|
720
|
-
if (node.cmIgnore)
|
|
721
|
-
return;
|
|
722
|
-
let view = ContentView.get(node);
|
|
723
|
-
let fromView = view && view.overrideDOMText;
|
|
724
|
-
if (fromView != null) {
|
|
725
|
-
this.findPointInside(node, fromView.length);
|
|
726
|
-
for (let i = fromView.iter(); !i.next().done;) {
|
|
727
|
-
if (i.lineBreak)
|
|
728
|
-
this.lineBreak();
|
|
729
|
-
else
|
|
730
|
-
this.append(i.value);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
else if (node.nodeType == 3) {
|
|
734
|
-
this.readTextNode(node);
|
|
735
|
-
}
|
|
736
|
-
else if (node.nodeName == "BR") {
|
|
737
|
-
if (node.nextSibling)
|
|
738
|
-
this.lineBreak();
|
|
739
|
-
}
|
|
740
|
-
else if (node.nodeType == 1) {
|
|
741
|
-
this.readRange(node.firstChild, null);
|
|
742
|
-
}
|
|
743
|
-
}
|
|
744
|
-
findPointBefore(node, next) {
|
|
745
|
-
for (let point of this.points)
|
|
746
|
-
if (point.node == node && node.childNodes[point.offset] == next)
|
|
747
|
-
point.pos = this.text.length;
|
|
748
|
-
}
|
|
749
|
-
findPointInside(node, maxLen) {
|
|
750
|
-
for (let point of this.points)
|
|
751
|
-
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
752
|
-
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
function isBlockElement(node) {
|
|
756
|
-
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
757
|
-
}
|
|
758
|
-
class DOMPoint {
|
|
759
|
-
constructor(node, offset) {
|
|
760
|
-
this.node = node;
|
|
761
|
-
this.offset = offset;
|
|
762
|
-
this.pos = -1;
|
|
763
|
-
}
|
|
764
|
-
}
|
|
765
|
-
|
|
766
661
|
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
767
662
|
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
768
663
|
const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
|
|
@@ -2706,6 +2601,7 @@ class DocView extends ContentView {
|
|
|
2706
2601
|
this.view = view;
|
|
2707
2602
|
this.decorations = [];
|
|
2708
2603
|
this.dynamicDecorationMap = [];
|
|
2604
|
+
this.domChanged = null;
|
|
2709
2605
|
this.hasComposition = null;
|
|
2710
2606
|
this.markedForComposition = new Set;
|
|
2711
2607
|
// Track a minimum width for the editor. When measuring sizes in
|
|
@@ -2734,6 +2630,7 @@ class DocView extends ContentView {
|
|
|
2734
2630
|
}
|
|
2735
2631
|
// Update the document view to a given state.
|
|
2736
2632
|
update(update) {
|
|
2633
|
+
var _a;
|
|
2737
2634
|
let changedRanges = update.changedRanges;
|
|
2738
2635
|
if (this.minWidth > 0 && changedRanges.length) {
|
|
2739
2636
|
if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
|
|
@@ -2744,7 +2641,15 @@ class DocView extends ContentView {
|
|
|
2744
2641
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2745
2642
|
}
|
|
2746
2643
|
}
|
|
2747
|
-
let
|
|
2644
|
+
let readCompositionAt = -1;
|
|
2645
|
+
if (this.view.inputState.composing >= 0) {
|
|
2646
|
+
if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
|
|
2647
|
+
readCompositionAt = this.domChanged.newSel.head;
|
|
2648
|
+
else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
|
|
2649
|
+
readCompositionAt = update.state.selection.main.head;
|
|
2650
|
+
}
|
|
2651
|
+
let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
|
|
2652
|
+
this.domChanged = null;
|
|
2748
2653
|
if (this.hasComposition) {
|
|
2749
2654
|
this.markedForComposition.clear();
|
|
2750
2655
|
let { from, to } = this.hasComposition;
|
|
@@ -2859,11 +2764,9 @@ class DocView extends ContentView {
|
|
|
2859
2764
|
cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
|
|
2860
2765
|
this.markedForComposition.add(cView);
|
|
2861
2766
|
let prev = ContentView.get(dom);
|
|
2862
|
-
if (prev != cView)
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
cView.setDOM(dom);
|
|
2866
|
-
}
|
|
2767
|
+
if (prev && prev != cView)
|
|
2768
|
+
prev.dom = null;
|
|
2769
|
+
cView.setDOM(dom);
|
|
2867
2770
|
};
|
|
2868
2771
|
let pos = this.childPos(composition.range.fromB, 1);
|
|
2869
2772
|
let cView = this.children[pos.i];
|
|
@@ -2886,9 +2789,8 @@ class DocView extends ContentView {
|
|
|
2886
2789
|
let force = this.forceSelection;
|
|
2887
2790
|
this.forceSelection = false;
|
|
2888
2791
|
let main = this.view.state.selection.main;
|
|
2889
|
-
|
|
2890
|
-
let
|
|
2891
|
-
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2792
|
+
let anchor = this.moveToLine(this.domAtPos(main.anchor));
|
|
2793
|
+
let head = main.empty ? anchor : this.moveToLine(this.domAtPos(main.head));
|
|
2892
2794
|
// Always reset on Firefox when next to an uneditable node to
|
|
2893
2795
|
// avoid invisible cursor bugs (#111)
|
|
2894
2796
|
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
|
|
@@ -2921,12 +2823,12 @@ class DocView extends ContentView {
|
|
|
2921
2823
|
if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) {
|
|
2922
2824
|
let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* NextTo.Before */ ? 1 : -1);
|
|
2923
2825
|
if (text)
|
|
2924
|
-
anchor = new DOMPos(text,
|
|
2826
|
+
anchor = new DOMPos(text.node, text.offset);
|
|
2925
2827
|
}
|
|
2926
2828
|
}
|
|
2927
2829
|
rawSel.collapse(anchor.node, anchor.offset);
|
|
2928
|
-
if (main.bidiLevel != null &&
|
|
2929
|
-
|
|
2830
|
+
if (main.bidiLevel != null && rawSel.caretBidiLevel !== undefined)
|
|
2831
|
+
rawSel.caretBidiLevel = main.bidiLevel;
|
|
2930
2832
|
}
|
|
2931
2833
|
else if (rawSel.extend) {
|
|
2932
2834
|
// Selection.extend can be used to create an 'inverted' selection
|
|
@@ -2989,6 +2891,26 @@ class DocView extends ContentView {
|
|
|
2989
2891
|
if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
|
|
2990
2892
|
sel.collapse(anchorNode, anchorOffset);
|
|
2991
2893
|
}
|
|
2894
|
+
// If a position is in/near a block widget, move it to a nearby text
|
|
2895
|
+
// line, since we don't want the cursor inside a block widget.
|
|
2896
|
+
moveToLine(pos) {
|
|
2897
|
+
// Block widgets will return positions before/after them, which
|
|
2898
|
+
// are thus directly in the document DOM element.
|
|
2899
|
+
let dom = this.dom, newPos;
|
|
2900
|
+
if (pos.node != dom)
|
|
2901
|
+
return pos;
|
|
2902
|
+
for (let i = pos.offset; !newPos && i < dom.childNodes.length; i++) {
|
|
2903
|
+
let view = ContentView.get(dom.childNodes[i]);
|
|
2904
|
+
if (view instanceof LineView)
|
|
2905
|
+
newPos = view.domAtPos(0);
|
|
2906
|
+
}
|
|
2907
|
+
for (let i = pos.offset - 1; !newPos && i >= 0; i--) {
|
|
2908
|
+
let view = ContentView.get(dom.childNodes[i]);
|
|
2909
|
+
if (view instanceof LineView)
|
|
2910
|
+
newPos = view.domAtPos(view.length);
|
|
2911
|
+
}
|
|
2912
|
+
return newPos ? new DOMPos(newPos.node, newPos.offset, true) : pos;
|
|
2913
|
+
}
|
|
2992
2914
|
nearest(dom) {
|
|
2993
2915
|
for (let cur = dom; cur;) {
|
|
2994
2916
|
let domView = ContentView.get(cur);
|
|
@@ -3187,74 +3109,27 @@ class BlockGapWidget extends WidgetType {
|
|
|
3187
3109
|
}
|
|
3188
3110
|
get estimatedHeight() { return this.height; }
|
|
3189
3111
|
}
|
|
3190
|
-
function findCompositionNode(view,
|
|
3112
|
+
function findCompositionNode(view, headPos) {
|
|
3191
3113
|
let sel = view.observer.selectionRange;
|
|
3192
3114
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3193
3115
|
if (!textNode)
|
|
3194
3116
|
return null;
|
|
3195
|
-
let
|
|
3196
|
-
|
|
3197
|
-
if (cView instanceof TextView) {
|
|
3198
|
-
from = cView.posAtStart;
|
|
3199
|
-
to = from + cView.length;
|
|
3200
|
-
}
|
|
3201
|
-
else {
|
|
3202
|
-
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3203
|
-
up: for (let offset = 0, node = textNode;;) {
|
|
3204
|
-
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3205
|
-
if (cView = ContentView.get(sibling)) {
|
|
3206
|
-
to = cView.posAtEnd + offset;
|
|
3207
|
-
from = Math.max(0, to - oldLen);
|
|
3208
|
-
break up;
|
|
3209
|
-
}
|
|
3210
|
-
let reader = new DOMReader([], view.state);
|
|
3211
|
-
reader.readNode(sibling);
|
|
3212
|
-
if (reader.text.indexOf(LineBreakPlaceholder) > -1)
|
|
3213
|
-
return null;
|
|
3214
|
-
offset += reader.text.length;
|
|
3215
|
-
}
|
|
3216
|
-
node = node.parentNode;
|
|
3217
|
-
if (!node)
|
|
3218
|
-
return null;
|
|
3219
|
-
let parentView = ContentView.get(node);
|
|
3220
|
-
if (parentView) {
|
|
3221
|
-
from = parentView.posAtStart + offset;
|
|
3222
|
-
to = from + oldLen;
|
|
3223
|
-
break;
|
|
3224
|
-
}
|
|
3225
|
-
}
|
|
3226
|
-
}
|
|
3227
|
-
return { from, to: to, node: textNode };
|
|
3117
|
+
let from = headPos - textNode.offset;
|
|
3118
|
+
return { from, to: from + textNode.node.nodeValue.length, node: textNode.node };
|
|
3228
3119
|
}
|
|
3229
|
-
function findCompositionRange(view, changes) {
|
|
3230
|
-
let found = findCompositionNode(view,
|
|
3120
|
+
function findCompositionRange(view, changes, headPos) {
|
|
3121
|
+
let found = findCompositionNode(view, headPos);
|
|
3231
3122
|
if (!found)
|
|
3232
3123
|
return null;
|
|
3233
|
-
let {
|
|
3234
|
-
let fromB = changes.mapPos(fromA, -1), toB = changes.mapPos(toA, 1);
|
|
3235
|
-
let text = textNode.nodeValue;
|
|
3124
|
+
let { node: textNode, from, to } = found, text = textNode.nodeValue;
|
|
3236
3125
|
// Don't try to preserve multi-line compositions
|
|
3237
3126
|
if (/[\n\r]/.test(text))
|
|
3238
3127
|
return null;
|
|
3239
|
-
if (
|
|
3240
|
-
// If there is a length mismatch, see if mapping non-inclusively helps
|
|
3241
|
-
let fromB2 = changes.mapPos(fromA, 1), toB2 = changes.mapPos(toA, -1);
|
|
3242
|
-
if (toB2 - fromB2 == text.length)
|
|
3243
|
-
fromB = fromB2, toB = toB2;
|
|
3244
|
-
// See if we can find an instance of the text at either side
|
|
3245
|
-
else if (view.state.doc.sliceString(toB - text.length, toB) == text)
|
|
3246
|
-
fromB = toB - text.length;
|
|
3247
|
-
else if (view.state.doc.sliceString(fromB, fromB + text.length) == text)
|
|
3248
|
-
toB = fromB + text.length;
|
|
3249
|
-
// Not found
|
|
3250
|
-
else
|
|
3251
|
-
return null;
|
|
3252
|
-
}
|
|
3253
|
-
let { main } = view.state.selection;
|
|
3254
|
-
if (view.state.doc.sliceString(fromB, toB) != text || fromB > main.head || toB < main.head)
|
|
3128
|
+
if (view.state.doc.sliceString(found.from, found.to) != text)
|
|
3255
3129
|
return null;
|
|
3130
|
+
let inv = changes.invertedDesc;
|
|
3131
|
+
let range = new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to);
|
|
3256
3132
|
let marks = [];
|
|
3257
|
-
let range = new ChangedRange(fromA, toA, fromB, toB);
|
|
3258
3133
|
for (let parent = textNode.parentNode;; parent = parent.parentNode) {
|
|
3259
3134
|
let parentView = ContentView.get(parent);
|
|
3260
3135
|
if (parentView instanceof MarkView)
|
|
@@ -3275,7 +3150,7 @@ function nearbyTextNode(startNode, startOffset, side) {
|
|
|
3275
3150
|
if (side <= 0)
|
|
3276
3151
|
for (let node = startNode, offset = startOffset;;) {
|
|
3277
3152
|
if (node.nodeType == 3)
|
|
3278
|
-
return node;
|
|
3153
|
+
return { node: node, offset: offset };
|
|
3279
3154
|
if (node.nodeType == 1 && offset > 0) {
|
|
3280
3155
|
node = node.childNodes[offset - 1];
|
|
3281
3156
|
offset = maxOffset(node);
|
|
@@ -3287,7 +3162,7 @@ function nearbyTextNode(startNode, startOffset, side) {
|
|
|
3287
3162
|
if (side >= 0)
|
|
3288
3163
|
for (let node = startNode, offset = startOffset;;) {
|
|
3289
3164
|
if (node.nodeType == 3)
|
|
3290
|
-
return node;
|
|
3165
|
+
return { node: node, offset: offset };
|
|
3291
3166
|
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3292
3167
|
node = node.childNodes[offset];
|
|
3293
3168
|
offset = 0;
|
|
@@ -3324,6 +3199,15 @@ function inUneditable(node, inside) {
|
|
|
3324
3199
|
}
|
|
3325
3200
|
return false;
|
|
3326
3201
|
}
|
|
3202
|
+
function touchesComposition(changes, composition) {
|
|
3203
|
+
let touched = false;
|
|
3204
|
+
if (composition)
|
|
3205
|
+
changes.iterChangedRanges((from, to) => {
|
|
3206
|
+
if (from < composition.to && to > composition.from)
|
|
3207
|
+
touched = true;
|
|
3208
|
+
});
|
|
3209
|
+
return touched;
|
|
3210
|
+
}
|
|
3327
3211
|
|
|
3328
3212
|
function groupAt(state$1, pos, bias = 1) {
|
|
3329
3213
|
let categorize = state$1.charCategorizer(pos);
|
|
@@ -6082,6 +5966,113 @@ const baseTheme$1 = buildTheme("." + baseThemeID, {
|
|
|
6082
5966
|
}
|
|
6083
5967
|
}, lightDarkIDs);
|
|
6084
5968
|
|
|
5969
|
+
const LineBreakPlaceholder = "\uffff";
|
|
5970
|
+
class DOMReader {
|
|
5971
|
+
constructor(points, state$1) {
|
|
5972
|
+
this.points = points;
|
|
5973
|
+
this.text = "";
|
|
5974
|
+
this.lineSeparator = state$1.facet(state.EditorState.lineSeparator);
|
|
5975
|
+
}
|
|
5976
|
+
append(text) {
|
|
5977
|
+
this.text += text;
|
|
5978
|
+
}
|
|
5979
|
+
lineBreak() {
|
|
5980
|
+
this.text += LineBreakPlaceholder;
|
|
5981
|
+
}
|
|
5982
|
+
readRange(start, end) {
|
|
5983
|
+
if (!start)
|
|
5984
|
+
return this;
|
|
5985
|
+
let parent = start.parentNode;
|
|
5986
|
+
for (let cur = start;;) {
|
|
5987
|
+
this.findPointBefore(parent, cur);
|
|
5988
|
+
let oldLen = this.text.length;
|
|
5989
|
+
this.readNode(cur);
|
|
5990
|
+
let next = cur.nextSibling;
|
|
5991
|
+
if (next == end)
|
|
5992
|
+
break;
|
|
5993
|
+
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
5994
|
+
if (view && nextView ? view.breakAfter :
|
|
5995
|
+
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
5996
|
+
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
5997
|
+
this.lineBreak();
|
|
5998
|
+
cur = next;
|
|
5999
|
+
}
|
|
6000
|
+
this.findPointBefore(parent, end);
|
|
6001
|
+
return this;
|
|
6002
|
+
}
|
|
6003
|
+
readTextNode(node) {
|
|
6004
|
+
let text = node.nodeValue;
|
|
6005
|
+
for (let point of this.points)
|
|
6006
|
+
if (point.node == node)
|
|
6007
|
+
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
6008
|
+
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
6009
|
+
let nextBreak = -1, breakSize = 1, m;
|
|
6010
|
+
if (this.lineSeparator) {
|
|
6011
|
+
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
6012
|
+
breakSize = this.lineSeparator.length;
|
|
6013
|
+
}
|
|
6014
|
+
else if (m = re.exec(text)) {
|
|
6015
|
+
nextBreak = m.index;
|
|
6016
|
+
breakSize = m[0].length;
|
|
6017
|
+
}
|
|
6018
|
+
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
6019
|
+
if (nextBreak < 0)
|
|
6020
|
+
break;
|
|
6021
|
+
this.lineBreak();
|
|
6022
|
+
if (breakSize > 1)
|
|
6023
|
+
for (let point of this.points)
|
|
6024
|
+
if (point.node == node && point.pos > this.text.length)
|
|
6025
|
+
point.pos -= breakSize - 1;
|
|
6026
|
+
off = nextBreak + breakSize;
|
|
6027
|
+
}
|
|
6028
|
+
}
|
|
6029
|
+
readNode(node) {
|
|
6030
|
+
if (node.cmIgnore)
|
|
6031
|
+
return;
|
|
6032
|
+
let view = ContentView.get(node);
|
|
6033
|
+
let fromView = view && view.overrideDOMText;
|
|
6034
|
+
if (fromView != null) {
|
|
6035
|
+
this.findPointInside(node, fromView.length);
|
|
6036
|
+
for (let i = fromView.iter(); !i.next().done;) {
|
|
6037
|
+
if (i.lineBreak)
|
|
6038
|
+
this.lineBreak();
|
|
6039
|
+
else
|
|
6040
|
+
this.append(i.value);
|
|
6041
|
+
}
|
|
6042
|
+
}
|
|
6043
|
+
else if (node.nodeType == 3) {
|
|
6044
|
+
this.readTextNode(node);
|
|
6045
|
+
}
|
|
6046
|
+
else if (node.nodeName == "BR") {
|
|
6047
|
+
if (node.nextSibling)
|
|
6048
|
+
this.lineBreak();
|
|
6049
|
+
}
|
|
6050
|
+
else if (node.nodeType == 1) {
|
|
6051
|
+
this.readRange(node.firstChild, null);
|
|
6052
|
+
}
|
|
6053
|
+
}
|
|
6054
|
+
findPointBefore(node, next) {
|
|
6055
|
+
for (let point of this.points)
|
|
6056
|
+
if (point.node == node && node.childNodes[point.offset] == next)
|
|
6057
|
+
point.pos = this.text.length;
|
|
6058
|
+
}
|
|
6059
|
+
findPointInside(node, maxLen) {
|
|
6060
|
+
for (let point of this.points)
|
|
6061
|
+
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
6062
|
+
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
6063
|
+
}
|
|
6064
|
+
}
|
|
6065
|
+
function isBlockElement(node) {
|
|
6066
|
+
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
6067
|
+
}
|
|
6068
|
+
class DOMPoint {
|
|
6069
|
+
constructor(node, offset) {
|
|
6070
|
+
this.node = node;
|
|
6071
|
+
this.offset = offset;
|
|
6072
|
+
this.pos = -1;
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
|
|
6085
6076
|
class DOMChange {
|
|
6086
6077
|
constructor(view, start, end, typeOver) {
|
|
6087
6078
|
this.typeOver = typeOver;
|
|
@@ -6232,8 +6223,14 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6232
6223
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6233
6224
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6234
6225
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6235
|
-
let composition = findCompositionNode(view,
|
|
6236
|
-
|
|
6226
|
+
let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
|
|
6227
|
+
if (composition) {
|
|
6228
|
+
let dLen = change.insert.length - (change.to - change.from);
|
|
6229
|
+
compositionRange = { from: composition.from, to: composition.to - dLen };
|
|
6230
|
+
}
|
|
6231
|
+
else {
|
|
6232
|
+
compositionRange = view.state.doc.lineAt(sel.head);
|
|
6233
|
+
}
|
|
6237
6234
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6238
6235
|
tr = startState.changeByRange(range => {
|
|
6239
6236
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -6244,7 +6241,7 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6244
6241
|
// changes in the same node work without aborting
|
|
6245
6242
|
// composition, so cursors in the composition range are
|
|
6246
6243
|
// ignored.
|
|
6247
|
-
|
|
6244
|
+
range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
6248
6245
|
return { range };
|
|
6249
6246
|
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
6250
6247
|
return {
|
|
@@ -6663,7 +6660,9 @@ class DOMObserver {
|
|
|
6663
6660
|
this.lastChange = Date.now();
|
|
6664
6661
|
this.view.inputState.lastFocusTime = 0;
|
|
6665
6662
|
this.selectionChanged = false;
|
|
6666
|
-
|
|
6663
|
+
let change = new DOMChange(this.view, from, to, typeOver);
|
|
6664
|
+
this.view.docView.domChanged = { newSel: change.newSel ? change.newSel.main : null };
|
|
6665
|
+
return change;
|
|
6667
6666
|
}
|
|
6668
6667
|
// Apply pending changes, if any
|
|
6669
6668
|
flush(readSelection = true) {
|
|
@@ -9908,6 +9907,10 @@ const gutterView = ViewPlugin.fromClass(class {
|
|
|
9908
9907
|
for (let cx of contexts)
|
|
9909
9908
|
cx.line(this.view, line, classSet);
|
|
9910
9909
|
}
|
|
9910
|
+
else if (line.widget) {
|
|
9911
|
+
for (let cx of contexts)
|
|
9912
|
+
cx.widget(this.view, line);
|
|
9913
|
+
}
|
|
9911
9914
|
}
|
|
9912
9915
|
for (let cx of contexts)
|
|
9913
9916
|
cx.finish();
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, findColumn, CharCategory, Annotation, EditorState, Transaction, Prec, 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
|
|
|
@@ -482,6 +482,8 @@ class ContentView {
|
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
484
|
setDOM(dom) {
|
|
485
|
+
if (this.dom == dom)
|
|
486
|
+
return;
|
|
485
487
|
if (this.dom)
|
|
486
488
|
this.dom.cmView = null;
|
|
487
489
|
this.dom = dom;
|
|
@@ -654,113 +656,6 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
654
656
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
655
657
|
}
|
|
656
658
|
|
|
657
|
-
const LineBreakPlaceholder = "\uffff";
|
|
658
|
-
class DOMReader {
|
|
659
|
-
constructor(points, state) {
|
|
660
|
-
this.points = points;
|
|
661
|
-
this.text = "";
|
|
662
|
-
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
663
|
-
}
|
|
664
|
-
append(text) {
|
|
665
|
-
this.text += text;
|
|
666
|
-
}
|
|
667
|
-
lineBreak() {
|
|
668
|
-
this.text += LineBreakPlaceholder;
|
|
669
|
-
}
|
|
670
|
-
readRange(start, end) {
|
|
671
|
-
if (!start)
|
|
672
|
-
return this;
|
|
673
|
-
let parent = start.parentNode;
|
|
674
|
-
for (let cur = start;;) {
|
|
675
|
-
this.findPointBefore(parent, cur);
|
|
676
|
-
let oldLen = this.text.length;
|
|
677
|
-
this.readNode(cur);
|
|
678
|
-
let next = cur.nextSibling;
|
|
679
|
-
if (next == end)
|
|
680
|
-
break;
|
|
681
|
-
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
682
|
-
if (view && nextView ? view.breakAfter :
|
|
683
|
-
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
684
|
-
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
685
|
-
this.lineBreak();
|
|
686
|
-
cur = next;
|
|
687
|
-
}
|
|
688
|
-
this.findPointBefore(parent, end);
|
|
689
|
-
return this;
|
|
690
|
-
}
|
|
691
|
-
readTextNode(node) {
|
|
692
|
-
let text = node.nodeValue;
|
|
693
|
-
for (let point of this.points)
|
|
694
|
-
if (point.node == node)
|
|
695
|
-
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
696
|
-
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
697
|
-
let nextBreak = -1, breakSize = 1, m;
|
|
698
|
-
if (this.lineSeparator) {
|
|
699
|
-
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
700
|
-
breakSize = this.lineSeparator.length;
|
|
701
|
-
}
|
|
702
|
-
else if (m = re.exec(text)) {
|
|
703
|
-
nextBreak = m.index;
|
|
704
|
-
breakSize = m[0].length;
|
|
705
|
-
}
|
|
706
|
-
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
707
|
-
if (nextBreak < 0)
|
|
708
|
-
break;
|
|
709
|
-
this.lineBreak();
|
|
710
|
-
if (breakSize > 1)
|
|
711
|
-
for (let point of this.points)
|
|
712
|
-
if (point.node == node && point.pos > this.text.length)
|
|
713
|
-
point.pos -= breakSize - 1;
|
|
714
|
-
off = nextBreak + breakSize;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
readNode(node) {
|
|
718
|
-
if (node.cmIgnore)
|
|
719
|
-
return;
|
|
720
|
-
let view = ContentView.get(node);
|
|
721
|
-
let fromView = view && view.overrideDOMText;
|
|
722
|
-
if (fromView != null) {
|
|
723
|
-
this.findPointInside(node, fromView.length);
|
|
724
|
-
for (let i = fromView.iter(); !i.next().done;) {
|
|
725
|
-
if (i.lineBreak)
|
|
726
|
-
this.lineBreak();
|
|
727
|
-
else
|
|
728
|
-
this.append(i.value);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
else if (node.nodeType == 3) {
|
|
732
|
-
this.readTextNode(node);
|
|
733
|
-
}
|
|
734
|
-
else if (node.nodeName == "BR") {
|
|
735
|
-
if (node.nextSibling)
|
|
736
|
-
this.lineBreak();
|
|
737
|
-
}
|
|
738
|
-
else if (node.nodeType == 1) {
|
|
739
|
-
this.readRange(node.firstChild, null);
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
findPointBefore(node, next) {
|
|
743
|
-
for (let point of this.points)
|
|
744
|
-
if (point.node == node && node.childNodes[point.offset] == next)
|
|
745
|
-
point.pos = this.text.length;
|
|
746
|
-
}
|
|
747
|
-
findPointInside(node, maxLen) {
|
|
748
|
-
for (let point of this.points)
|
|
749
|
-
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
750
|
-
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
function isBlockElement(node) {
|
|
754
|
-
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
755
|
-
}
|
|
756
|
-
class DOMPoint {
|
|
757
|
-
constructor(node, offset) {
|
|
758
|
-
this.node = node;
|
|
759
|
-
this.offset = offset;
|
|
760
|
-
this.pos = -1;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
|
|
764
659
|
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
765
660
|
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
766
661
|
const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
|
|
@@ -2702,6 +2597,7 @@ class DocView extends ContentView {
|
|
|
2702
2597
|
this.view = view;
|
|
2703
2598
|
this.decorations = [];
|
|
2704
2599
|
this.dynamicDecorationMap = [];
|
|
2600
|
+
this.domChanged = null;
|
|
2705
2601
|
this.hasComposition = null;
|
|
2706
2602
|
this.markedForComposition = new Set;
|
|
2707
2603
|
// Track a minimum width for the editor. When measuring sizes in
|
|
@@ -2730,6 +2626,7 @@ class DocView extends ContentView {
|
|
|
2730
2626
|
}
|
|
2731
2627
|
// Update the document view to a given state.
|
|
2732
2628
|
update(update) {
|
|
2629
|
+
var _a;
|
|
2733
2630
|
let changedRanges = update.changedRanges;
|
|
2734
2631
|
if (this.minWidth > 0 && changedRanges.length) {
|
|
2735
2632
|
if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
|
|
@@ -2740,7 +2637,15 @@ class DocView extends ContentView {
|
|
|
2740
2637
|
this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
|
2741
2638
|
}
|
|
2742
2639
|
}
|
|
2743
|
-
let
|
|
2640
|
+
let readCompositionAt = -1;
|
|
2641
|
+
if (this.view.inputState.composing >= 0) {
|
|
2642
|
+
if ((_a = this.domChanged) === null || _a === void 0 ? void 0 : _a.newSel)
|
|
2643
|
+
readCompositionAt = this.domChanged.newSel.head;
|
|
2644
|
+
else if (!touchesComposition(update.changes, this.hasComposition) && !update.selectionSet)
|
|
2645
|
+
readCompositionAt = update.state.selection.main.head;
|
|
2646
|
+
}
|
|
2647
|
+
let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
|
|
2648
|
+
this.domChanged = null;
|
|
2744
2649
|
if (this.hasComposition) {
|
|
2745
2650
|
this.markedForComposition.clear();
|
|
2746
2651
|
let { from, to } = this.hasComposition;
|
|
@@ -2855,11 +2760,9 @@ class DocView extends ContentView {
|
|
|
2855
2760
|
cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
|
|
2856
2761
|
this.markedForComposition.add(cView);
|
|
2857
2762
|
let prev = ContentView.get(dom);
|
|
2858
|
-
if (prev != cView)
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
cView.setDOM(dom);
|
|
2862
|
-
}
|
|
2763
|
+
if (prev && prev != cView)
|
|
2764
|
+
prev.dom = null;
|
|
2765
|
+
cView.setDOM(dom);
|
|
2863
2766
|
};
|
|
2864
2767
|
let pos = this.childPos(composition.range.fromB, 1);
|
|
2865
2768
|
let cView = this.children[pos.i];
|
|
@@ -2882,9 +2785,8 @@ class DocView extends ContentView {
|
|
|
2882
2785
|
let force = this.forceSelection;
|
|
2883
2786
|
this.forceSelection = false;
|
|
2884
2787
|
let main = this.view.state.selection.main;
|
|
2885
|
-
|
|
2886
|
-
let
|
|
2887
|
-
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2788
|
+
let anchor = this.moveToLine(this.domAtPos(main.anchor));
|
|
2789
|
+
let head = main.empty ? anchor : this.moveToLine(this.domAtPos(main.head));
|
|
2888
2790
|
// Always reset on Firefox when next to an uneditable node to
|
|
2889
2791
|
// avoid invisible cursor bugs (#111)
|
|
2890
2792
|
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
|
|
@@ -2917,12 +2819,12 @@ class DocView extends ContentView {
|
|
|
2917
2819
|
if (nextTo && nextTo != (1 /* NextTo.Before */ | 2 /* NextTo.After */)) {
|
|
2918
2820
|
let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* NextTo.Before */ ? 1 : -1);
|
|
2919
2821
|
if (text)
|
|
2920
|
-
anchor = new DOMPos(text,
|
|
2822
|
+
anchor = new DOMPos(text.node, text.offset);
|
|
2921
2823
|
}
|
|
2922
2824
|
}
|
|
2923
2825
|
rawSel.collapse(anchor.node, anchor.offset);
|
|
2924
|
-
if (main.bidiLevel != null &&
|
|
2925
|
-
|
|
2826
|
+
if (main.bidiLevel != null && rawSel.caretBidiLevel !== undefined)
|
|
2827
|
+
rawSel.caretBidiLevel = main.bidiLevel;
|
|
2926
2828
|
}
|
|
2927
2829
|
else if (rawSel.extend) {
|
|
2928
2830
|
// Selection.extend can be used to create an 'inverted' selection
|
|
@@ -2985,6 +2887,26 @@ class DocView extends ContentView {
|
|
|
2985
2887
|
if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
|
|
2986
2888
|
sel.collapse(anchorNode, anchorOffset);
|
|
2987
2889
|
}
|
|
2890
|
+
// If a position is in/near a block widget, move it to a nearby text
|
|
2891
|
+
// line, since we don't want the cursor inside a block widget.
|
|
2892
|
+
moveToLine(pos) {
|
|
2893
|
+
// Block widgets will return positions before/after them, which
|
|
2894
|
+
// are thus directly in the document DOM element.
|
|
2895
|
+
let dom = this.dom, newPos;
|
|
2896
|
+
if (pos.node != dom)
|
|
2897
|
+
return pos;
|
|
2898
|
+
for (let i = pos.offset; !newPos && i < dom.childNodes.length; i++) {
|
|
2899
|
+
let view = ContentView.get(dom.childNodes[i]);
|
|
2900
|
+
if (view instanceof LineView)
|
|
2901
|
+
newPos = view.domAtPos(0);
|
|
2902
|
+
}
|
|
2903
|
+
for (let i = pos.offset - 1; !newPos && i >= 0; i--) {
|
|
2904
|
+
let view = ContentView.get(dom.childNodes[i]);
|
|
2905
|
+
if (view instanceof LineView)
|
|
2906
|
+
newPos = view.domAtPos(view.length);
|
|
2907
|
+
}
|
|
2908
|
+
return newPos ? new DOMPos(newPos.node, newPos.offset, true) : pos;
|
|
2909
|
+
}
|
|
2988
2910
|
nearest(dom) {
|
|
2989
2911
|
for (let cur = dom; cur;) {
|
|
2990
2912
|
let domView = ContentView.get(cur);
|
|
@@ -3183,74 +3105,27 @@ class BlockGapWidget extends WidgetType {
|
|
|
3183
3105
|
}
|
|
3184
3106
|
get estimatedHeight() { return this.height; }
|
|
3185
3107
|
}
|
|
3186
|
-
function findCompositionNode(view,
|
|
3108
|
+
function findCompositionNode(view, headPos) {
|
|
3187
3109
|
let sel = view.observer.selectionRange;
|
|
3188
3110
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3189
3111
|
if (!textNode)
|
|
3190
3112
|
return null;
|
|
3191
|
-
let
|
|
3192
|
-
|
|
3193
|
-
if (cView instanceof TextView) {
|
|
3194
|
-
from = cView.posAtStart;
|
|
3195
|
-
to = from + cView.length;
|
|
3196
|
-
}
|
|
3197
|
-
else {
|
|
3198
|
-
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3199
|
-
up: for (let offset = 0, node = textNode;;) {
|
|
3200
|
-
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3201
|
-
if (cView = ContentView.get(sibling)) {
|
|
3202
|
-
to = cView.posAtEnd + offset;
|
|
3203
|
-
from = Math.max(0, to - oldLen);
|
|
3204
|
-
break up;
|
|
3205
|
-
}
|
|
3206
|
-
let reader = new DOMReader([], view.state);
|
|
3207
|
-
reader.readNode(sibling);
|
|
3208
|
-
if (reader.text.indexOf(LineBreakPlaceholder) > -1)
|
|
3209
|
-
return null;
|
|
3210
|
-
offset += reader.text.length;
|
|
3211
|
-
}
|
|
3212
|
-
node = node.parentNode;
|
|
3213
|
-
if (!node)
|
|
3214
|
-
return null;
|
|
3215
|
-
let parentView = ContentView.get(node);
|
|
3216
|
-
if (parentView) {
|
|
3217
|
-
from = parentView.posAtStart + offset;
|
|
3218
|
-
to = from + oldLen;
|
|
3219
|
-
break;
|
|
3220
|
-
}
|
|
3221
|
-
}
|
|
3222
|
-
}
|
|
3223
|
-
return { from, to: to, node: textNode };
|
|
3113
|
+
let from = headPos - textNode.offset;
|
|
3114
|
+
return { from, to: from + textNode.node.nodeValue.length, node: textNode.node };
|
|
3224
3115
|
}
|
|
3225
|
-
function findCompositionRange(view, changes) {
|
|
3226
|
-
let found = findCompositionNode(view,
|
|
3116
|
+
function findCompositionRange(view, changes, headPos) {
|
|
3117
|
+
let found = findCompositionNode(view, headPos);
|
|
3227
3118
|
if (!found)
|
|
3228
3119
|
return null;
|
|
3229
|
-
let {
|
|
3230
|
-
let fromB = changes.mapPos(fromA, -1), toB = changes.mapPos(toA, 1);
|
|
3231
|
-
let text = textNode.nodeValue;
|
|
3120
|
+
let { node: textNode, from, to } = found, text = textNode.nodeValue;
|
|
3232
3121
|
// Don't try to preserve multi-line compositions
|
|
3233
3122
|
if (/[\n\r]/.test(text))
|
|
3234
3123
|
return null;
|
|
3235
|
-
if (
|
|
3236
|
-
// If there is a length mismatch, see if mapping non-inclusively helps
|
|
3237
|
-
let fromB2 = changes.mapPos(fromA, 1), toB2 = changes.mapPos(toA, -1);
|
|
3238
|
-
if (toB2 - fromB2 == text.length)
|
|
3239
|
-
fromB = fromB2, toB = toB2;
|
|
3240
|
-
// See if we can find an instance of the text at either side
|
|
3241
|
-
else if (view.state.doc.sliceString(toB - text.length, toB) == text)
|
|
3242
|
-
fromB = toB - text.length;
|
|
3243
|
-
else if (view.state.doc.sliceString(fromB, fromB + text.length) == text)
|
|
3244
|
-
toB = fromB + text.length;
|
|
3245
|
-
// Not found
|
|
3246
|
-
else
|
|
3247
|
-
return null;
|
|
3248
|
-
}
|
|
3249
|
-
let { main } = view.state.selection;
|
|
3250
|
-
if (view.state.doc.sliceString(fromB, toB) != text || fromB > main.head || toB < main.head)
|
|
3124
|
+
if (view.state.doc.sliceString(found.from, found.to) != text)
|
|
3251
3125
|
return null;
|
|
3126
|
+
let inv = changes.invertedDesc;
|
|
3127
|
+
let range = new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to);
|
|
3252
3128
|
let marks = [];
|
|
3253
|
-
let range = new ChangedRange(fromA, toA, fromB, toB);
|
|
3254
3129
|
for (let parent = textNode.parentNode;; parent = parent.parentNode) {
|
|
3255
3130
|
let parentView = ContentView.get(parent);
|
|
3256
3131
|
if (parentView instanceof MarkView)
|
|
@@ -3271,7 +3146,7 @@ function nearbyTextNode(startNode, startOffset, side) {
|
|
|
3271
3146
|
if (side <= 0)
|
|
3272
3147
|
for (let node = startNode, offset = startOffset;;) {
|
|
3273
3148
|
if (node.nodeType == 3)
|
|
3274
|
-
return node;
|
|
3149
|
+
return { node: node, offset: offset };
|
|
3275
3150
|
if (node.nodeType == 1 && offset > 0) {
|
|
3276
3151
|
node = node.childNodes[offset - 1];
|
|
3277
3152
|
offset = maxOffset(node);
|
|
@@ -3283,7 +3158,7 @@ function nearbyTextNode(startNode, startOffset, side) {
|
|
|
3283
3158
|
if (side >= 0)
|
|
3284
3159
|
for (let node = startNode, offset = startOffset;;) {
|
|
3285
3160
|
if (node.nodeType == 3)
|
|
3286
|
-
return node;
|
|
3161
|
+
return { node: node, offset: offset };
|
|
3287
3162
|
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3288
3163
|
node = node.childNodes[offset];
|
|
3289
3164
|
offset = 0;
|
|
@@ -3320,6 +3195,15 @@ function inUneditable(node, inside) {
|
|
|
3320
3195
|
}
|
|
3321
3196
|
return false;
|
|
3322
3197
|
}
|
|
3198
|
+
function touchesComposition(changes, composition) {
|
|
3199
|
+
let touched = false;
|
|
3200
|
+
if (composition)
|
|
3201
|
+
changes.iterChangedRanges((from, to) => {
|
|
3202
|
+
if (from < composition.to && to > composition.from)
|
|
3203
|
+
touched = true;
|
|
3204
|
+
});
|
|
3205
|
+
return touched;
|
|
3206
|
+
}
|
|
3323
3207
|
|
|
3324
3208
|
function groupAt(state, pos, bias = 1) {
|
|
3325
3209
|
let categorize = state.charCategorizer(pos);
|
|
@@ -6077,6 +5961,113 @@ const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
6077
5961
|
}
|
|
6078
5962
|
}, lightDarkIDs);
|
|
6079
5963
|
|
|
5964
|
+
const LineBreakPlaceholder = "\uffff";
|
|
5965
|
+
class DOMReader {
|
|
5966
|
+
constructor(points, state) {
|
|
5967
|
+
this.points = points;
|
|
5968
|
+
this.text = "";
|
|
5969
|
+
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
5970
|
+
}
|
|
5971
|
+
append(text) {
|
|
5972
|
+
this.text += text;
|
|
5973
|
+
}
|
|
5974
|
+
lineBreak() {
|
|
5975
|
+
this.text += LineBreakPlaceholder;
|
|
5976
|
+
}
|
|
5977
|
+
readRange(start, end) {
|
|
5978
|
+
if (!start)
|
|
5979
|
+
return this;
|
|
5980
|
+
let parent = start.parentNode;
|
|
5981
|
+
for (let cur = start;;) {
|
|
5982
|
+
this.findPointBefore(parent, cur);
|
|
5983
|
+
let oldLen = this.text.length;
|
|
5984
|
+
this.readNode(cur);
|
|
5985
|
+
let next = cur.nextSibling;
|
|
5986
|
+
if (next == end)
|
|
5987
|
+
break;
|
|
5988
|
+
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
5989
|
+
if (view && nextView ? view.breakAfter :
|
|
5990
|
+
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
5991
|
+
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore) && this.text.length > oldLen))
|
|
5992
|
+
this.lineBreak();
|
|
5993
|
+
cur = next;
|
|
5994
|
+
}
|
|
5995
|
+
this.findPointBefore(parent, end);
|
|
5996
|
+
return this;
|
|
5997
|
+
}
|
|
5998
|
+
readTextNode(node) {
|
|
5999
|
+
let text = node.nodeValue;
|
|
6000
|
+
for (let point of this.points)
|
|
6001
|
+
if (point.node == node)
|
|
6002
|
+
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
6003
|
+
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
6004
|
+
let nextBreak = -1, breakSize = 1, m;
|
|
6005
|
+
if (this.lineSeparator) {
|
|
6006
|
+
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
6007
|
+
breakSize = this.lineSeparator.length;
|
|
6008
|
+
}
|
|
6009
|
+
else if (m = re.exec(text)) {
|
|
6010
|
+
nextBreak = m.index;
|
|
6011
|
+
breakSize = m[0].length;
|
|
6012
|
+
}
|
|
6013
|
+
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
6014
|
+
if (nextBreak < 0)
|
|
6015
|
+
break;
|
|
6016
|
+
this.lineBreak();
|
|
6017
|
+
if (breakSize > 1)
|
|
6018
|
+
for (let point of this.points)
|
|
6019
|
+
if (point.node == node && point.pos > this.text.length)
|
|
6020
|
+
point.pos -= breakSize - 1;
|
|
6021
|
+
off = nextBreak + breakSize;
|
|
6022
|
+
}
|
|
6023
|
+
}
|
|
6024
|
+
readNode(node) {
|
|
6025
|
+
if (node.cmIgnore)
|
|
6026
|
+
return;
|
|
6027
|
+
let view = ContentView.get(node);
|
|
6028
|
+
let fromView = view && view.overrideDOMText;
|
|
6029
|
+
if (fromView != null) {
|
|
6030
|
+
this.findPointInside(node, fromView.length);
|
|
6031
|
+
for (let i = fromView.iter(); !i.next().done;) {
|
|
6032
|
+
if (i.lineBreak)
|
|
6033
|
+
this.lineBreak();
|
|
6034
|
+
else
|
|
6035
|
+
this.append(i.value);
|
|
6036
|
+
}
|
|
6037
|
+
}
|
|
6038
|
+
else if (node.nodeType == 3) {
|
|
6039
|
+
this.readTextNode(node);
|
|
6040
|
+
}
|
|
6041
|
+
else if (node.nodeName == "BR") {
|
|
6042
|
+
if (node.nextSibling)
|
|
6043
|
+
this.lineBreak();
|
|
6044
|
+
}
|
|
6045
|
+
else if (node.nodeType == 1) {
|
|
6046
|
+
this.readRange(node.firstChild, null);
|
|
6047
|
+
}
|
|
6048
|
+
}
|
|
6049
|
+
findPointBefore(node, next) {
|
|
6050
|
+
for (let point of this.points)
|
|
6051
|
+
if (point.node == node && node.childNodes[point.offset] == next)
|
|
6052
|
+
point.pos = this.text.length;
|
|
6053
|
+
}
|
|
6054
|
+
findPointInside(node, maxLen) {
|
|
6055
|
+
for (let point of this.points)
|
|
6056
|
+
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
6057
|
+
point.pos = this.text.length + Math.min(maxLen, point.offset);
|
|
6058
|
+
}
|
|
6059
|
+
}
|
|
6060
|
+
function isBlockElement(node) {
|
|
6061
|
+
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
6062
|
+
}
|
|
6063
|
+
class DOMPoint {
|
|
6064
|
+
constructor(node, offset) {
|
|
6065
|
+
this.node = node;
|
|
6066
|
+
this.offset = offset;
|
|
6067
|
+
this.pos = -1;
|
|
6068
|
+
}
|
|
6069
|
+
}
|
|
6070
|
+
|
|
6080
6071
|
class DOMChange {
|
|
6081
6072
|
constructor(view, start, end, typeOver) {
|
|
6082
6073
|
this.typeOver = typeOver;
|
|
@@ -6227,8 +6218,14 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6227
6218
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6228
6219
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6229
6220
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6230
|
-
let composition = findCompositionNode(view,
|
|
6231
|
-
|
|
6221
|
+
let compositionRange, composition = newSel && findCompositionNode(view, newSel.main.head);
|
|
6222
|
+
if (composition) {
|
|
6223
|
+
let dLen = change.insert.length - (change.to - change.from);
|
|
6224
|
+
compositionRange = { from: composition.from, to: composition.to - dLen };
|
|
6225
|
+
}
|
|
6226
|
+
else {
|
|
6227
|
+
compositionRange = view.state.doc.lineAt(sel.head);
|
|
6228
|
+
}
|
|
6232
6229
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6233
6230
|
tr = startState.changeByRange(range => {
|
|
6234
6231
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -6239,7 +6236,7 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6239
6236
|
// changes in the same node work without aborting
|
|
6240
6237
|
// composition, so cursors in the composition range are
|
|
6241
6238
|
// ignored.
|
|
6242
|
-
|
|
6239
|
+
range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
6243
6240
|
return { range };
|
|
6244
6241
|
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
6245
6242
|
return {
|
|
@@ -6658,7 +6655,9 @@ class DOMObserver {
|
|
|
6658
6655
|
this.lastChange = Date.now();
|
|
6659
6656
|
this.view.inputState.lastFocusTime = 0;
|
|
6660
6657
|
this.selectionChanged = false;
|
|
6661
|
-
|
|
6658
|
+
let change = new DOMChange(this.view, from, to, typeOver);
|
|
6659
|
+
this.view.docView.domChanged = { newSel: change.newSel ? change.newSel.main : null };
|
|
6660
|
+
return change;
|
|
6662
6661
|
}
|
|
6663
6662
|
// Apply pending changes, if any
|
|
6664
6663
|
flush(readSelection = true) {
|
|
@@ -9903,6 +9902,10 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9903
9902
|
for (let cx of contexts)
|
|
9904
9903
|
cx.line(this.view, line, classSet);
|
|
9905
9904
|
}
|
|
9905
|
+
else if (line.widget) {
|
|
9906
|
+
for (let cx of contexts)
|
|
9907
|
+
cx.widget(this.view, line);
|
|
9908
|
+
}
|
|
9906
9909
|
}
|
|
9907
9910
|
for (let cx of contexts)
|
|
9908
9911
|
cx.finish();
|