@codemirror/view 0.18.15 → 0.18.19
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 +44 -0
- package/dist/index.cjs +119 -86
- package/dist/index.d.ts +14 -6
- package/dist/index.js +120 -87
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,47 @@
|
|
|
1
|
+
## 0.18.19 (2021-07-12)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a regression where `EditorView.editable.of(false)` didn't disable editing on Webkit-based browsers.
|
|
6
|
+
|
|
7
|
+
## 0.18.18 (2021-07-06)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Fix a bug that caused `EditorView.moveVertically` to only move by one line, even when given a custom distance, in some cases.
|
|
12
|
+
|
|
13
|
+
Hide Safari's native bold/italic/underline controls for the content.
|
|
14
|
+
|
|
15
|
+
Fix a CSS problem that prevented Safari from breaking words longer than the line in line-wrapping mode.
|
|
16
|
+
|
|
17
|
+
Avoid a problem where composition would be inappropriately abored on Safari.
|
|
18
|
+
|
|
19
|
+
Fix drag-selection that scrolls the content by dragging past the visible viewport.
|
|
20
|
+
|
|
21
|
+
### New features
|
|
22
|
+
|
|
23
|
+
`posAtCoords` now has an imprecise mode where it'll return an approximate position even for parts of the document that aren't currently rendered.
|
|
24
|
+
|
|
25
|
+
## 0.18.17 (2021-06-14)
|
|
26
|
+
|
|
27
|
+
### Bug fixes
|
|
28
|
+
|
|
29
|
+
Make `drawSelection` behave properly when lines are split by block widgets.
|
|
30
|
+
|
|
31
|
+
Make sure drawn selections that span a single line break don't leave a gap between the lines.
|
|
32
|
+
|
|
33
|
+
## 0.18.16 (2021-06-03)
|
|
34
|
+
|
|
35
|
+
### Bug fixes
|
|
36
|
+
|
|
37
|
+
Fix a crash that could occur when the document changed during mouse selection.
|
|
38
|
+
|
|
39
|
+
Fix a bug where composition inside styled content would sometimes be inappropriately aborted by editor DOM updates.
|
|
40
|
+
|
|
41
|
+
### New features
|
|
42
|
+
|
|
43
|
+
`MouseSelectionStyle.update` may now return true to indicate it should be queried for a new selection after the update.
|
|
44
|
+
|
|
1
45
|
## 0.18.15 (2021-06-01)
|
|
2
46
|
|
|
3
47
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -216,6 +216,19 @@ function dispatchKey(elt, name, code) {
|
|
|
216
216
|
elt.dispatchEvent(up);
|
|
217
217
|
return down.defaultPrevented || up.defaultPrevented;
|
|
218
218
|
}
|
|
219
|
+
let _plainTextSupported = null;
|
|
220
|
+
function contentEditablePlainTextSupported() {
|
|
221
|
+
if (_plainTextSupported == null) {
|
|
222
|
+
_plainTextSupported = false;
|
|
223
|
+
let dummy = document.createElement("div");
|
|
224
|
+
try {
|
|
225
|
+
dummy.contentEditable = "plaintext-only";
|
|
226
|
+
_plainTextSupported = dummy.contentEditable == "plaintext-only";
|
|
227
|
+
}
|
|
228
|
+
catch (_) { }
|
|
229
|
+
}
|
|
230
|
+
return _plainTextSupported;
|
|
231
|
+
}
|
|
219
232
|
|
|
220
233
|
class DOMPos {
|
|
221
234
|
constructor(node, offset, precise = true) {
|
|
@@ -1957,6 +1970,8 @@ class DocView extends ContentView {
|
|
|
1957
1970
|
// FIXME need to handle the case where the selection falls inside a block range
|
|
1958
1971
|
let anchor = this.domAtPos(main.anchor);
|
|
1959
1972
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
1973
|
+
// Always reset on Firefox when next to an uneditable node to
|
|
1974
|
+
// avoid invisible cursor bugs (#111)
|
|
1960
1975
|
if (browser.gecko && main.empty && betweenUneditable(anchor)) {
|
|
1961
1976
|
let dummy = document.createTextNode("");
|
|
1962
1977
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
@@ -1966,9 +1981,6 @@ class DocView extends ContentView {
|
|
|
1966
1981
|
let domSel = this.view.observer.selectionRange;
|
|
1967
1982
|
// If the selection is already here, or in an equivalent position, don't touch it
|
|
1968
1983
|
if (force || !domSel.focusNode ||
|
|
1969
|
-
// Always reset on Firefox when next to an uneditable node to
|
|
1970
|
-
// avoid invisible cursor bugs (#111)
|
|
1971
|
-
(browser.gecko && main.empty && nextToUneditable(domSel.focusNode, domSel.focusOffset)) ||
|
|
1972
1984
|
!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
|
1973
1985
|
!isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
|
1974
1986
|
this.view.observer.ignore(() => {
|
|
@@ -2011,6 +2023,8 @@ class DocView extends ContentView {
|
|
|
2011
2023
|
this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
|
|
2012
2024
|
}
|
|
2013
2025
|
enforceCursorAssoc() {
|
|
2026
|
+
if (this.view.composing)
|
|
2027
|
+
return;
|
|
2014
2028
|
let cursor = this.view.state.selection.main;
|
|
2015
2029
|
let sel = getSelection(this.root);
|
|
2016
2030
|
if (!cursor.empty || !cursor.assoc || !sel.modify)
|
|
@@ -2061,7 +2075,10 @@ class DocView extends ContentView {
|
|
|
2061
2075
|
coordsAt(pos, side) {
|
|
2062
2076
|
for (let off = this.length, i = this.children.length - 1;; i--) {
|
|
2063
2077
|
let child = this.children[i], start = off - child.breakAfter - child.length;
|
|
2064
|
-
if (pos > start ||
|
|
2078
|
+
if (pos > start ||
|
|
2079
|
+
(pos == start && child.type != exports.BlockType.WidgetBefore && child.type != exports.BlockType.WidgetAfter &&
|
|
2080
|
+
(!i || side == 2 || this.children[i - 1].breakAfter ||
|
|
2081
|
+
(this.children[i - 1].type == exports.BlockType.WidgetBefore && side > -2))))
|
|
2065
2082
|
return child.coordsAt(pos - start, side);
|
|
2066
2083
|
off = start;
|
|
2067
2084
|
}
|
|
@@ -2133,11 +2150,11 @@ class DocView extends ContentView {
|
|
|
2133
2150
|
}
|
|
2134
2151
|
updateDeco() {
|
|
2135
2152
|
return this.decorations = [
|
|
2136
|
-
this.
|
|
2137
|
-
this.view.viewState.lineGapDeco,
|
|
2138
|
-
this.compositionDeco,
|
|
2153
|
+
...this.view.pluginField(PluginField.decorations),
|
|
2139
2154
|
...this.view.state.facet(decorations),
|
|
2140
|
-
|
|
2155
|
+
this.compositionDeco,
|
|
2156
|
+
this.computeBlockGapDeco(),
|
|
2157
|
+
this.view.viewState.lineGapDeco
|
|
2141
2158
|
];
|
|
2142
2159
|
}
|
|
2143
2160
|
scrollPosIntoView(pos, side) {
|
|
@@ -2719,7 +2736,7 @@ function domPosInText(node, x, y) {
|
|
|
2719
2736
|
}
|
|
2720
2737
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
2721
2738
|
}
|
|
2722
|
-
function posAtCoords(view, { x, y }, bias = -1) {
|
|
2739
|
+
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2723
2740
|
let content = view.contentDOM.getBoundingClientRect(), block;
|
|
2724
2741
|
let halfLine = view.defaultLineHeight / 2;
|
|
2725
2742
|
for (let bounced = false;;) {
|
|
@@ -2728,7 +2745,7 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2728
2745
|
bias = block.top > y ? -1 : 1;
|
|
2729
2746
|
y = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, y));
|
|
2730
2747
|
if (bounced)
|
|
2731
|
-
return null;
|
|
2748
|
+
return precise ? null : 0;
|
|
2732
2749
|
else
|
|
2733
2750
|
bounced = true;
|
|
2734
2751
|
}
|
|
@@ -2737,13 +2754,13 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2737
2754
|
y = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
|
|
2738
2755
|
}
|
|
2739
2756
|
let lineStart = block.from;
|
|
2757
|
+
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
2740
2758
|
// If this is outside of the rendered viewport, we can't determine a position
|
|
2741
2759
|
if (lineStart < view.viewport.from)
|
|
2742
|
-
return view.viewport.from == 0 ? 0 :
|
|
2760
|
+
return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
|
|
2743
2761
|
if (lineStart > view.viewport.to)
|
|
2744
|
-
return view.viewport.to == view.state.doc.length ? view.state.doc.length :
|
|
2762
|
+
return view.viewport.to == view.state.doc.length ? view.state.doc.length : posAtCoordsImprecise(view, content, block, x, y);
|
|
2745
2763
|
// Clip x to the viewport sides
|
|
2746
|
-
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
2747
2764
|
let root = view.root, element = root.elementFromPoint(x, y);
|
|
2748
2765
|
// There's visible editor content under the point, so we can try
|
|
2749
2766
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
@@ -2770,6 +2787,15 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2770
2787
|
}
|
|
2771
2788
|
return view.docView.posFromDOM(node, offset);
|
|
2772
2789
|
}
|
|
2790
|
+
function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
2791
|
+
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
|
2792
|
+
if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
|
|
2793
|
+
let line = Math.floor((y - block.top) / view.defaultLineHeight);
|
|
2794
|
+
into += line * view.viewState.heightOracle.lineLength;
|
|
2795
|
+
}
|
|
2796
|
+
let content = view.state.sliceDoc(block.from, block.to);
|
|
2797
|
+
return block.from + text.findColumn(content, into, view.state.tabSize);
|
|
2798
|
+
}
|
|
2773
2799
|
// In case of a high line height, Safari's caretRangeFromPoint treats
|
|
2774
2800
|
// the space between lines as belonging to the last character of the
|
|
2775
2801
|
// line before. This is used to detect such a result so that it can be
|
|
@@ -2832,48 +2858,31 @@ function byGroup(view, pos, start) {
|
|
|
2832
2858
|
};
|
|
2833
2859
|
}
|
|
2834
2860
|
function moveVertically(view, start, forward, distance) {
|
|
2835
|
-
var _a;
|
|
2836
2861
|
let startPos = start.head, dir = forward ? 1 : -1;
|
|
2837
2862
|
if (startPos == (forward ? view.state.doc.length : 0))
|
|
2838
2863
|
return state.EditorSelection.cursor(startPos);
|
|
2864
|
+
let goal = start.goalColumn, startY;
|
|
2865
|
+
let rect = view.contentDOM.getBoundingClientRect();
|
|
2839
2866
|
let startCoords = view.coordsAtPos(startPos);
|
|
2840
2867
|
if (startCoords) {
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
|
2845
|
-
for (let startY = dir < 0 ? startCoords.top : startCoords.bottom, extra = 0; extra < 50; extra += 10) {
|
|
2846
|
-
let pos = posAtCoords(view, { x: resolvedGoal, y: startY + (dist + extra) * dir }, dir);
|
|
2847
|
-
if (pos == null)
|
|
2848
|
-
break;
|
|
2849
|
-
if (pos != startPos)
|
|
2850
|
-
return state.EditorSelection.cursor(pos, undefined, undefined, goal);
|
|
2851
|
-
}
|
|
2852
|
-
}
|
|
2853
|
-
// Outside of the drawn viewport, use a crude column-based approach
|
|
2854
|
-
let { doc } = view.state, line = doc.lineAt(startPos), tabSize = view.state.tabSize;
|
|
2855
|
-
let goal = start.goalColumn, goalCol = 0;
|
|
2856
|
-
if (goal == null) {
|
|
2857
|
-
for (const iter = doc.iterRange(line.from, startPos); !iter.next().done;)
|
|
2858
|
-
goalCol = text.countColumn(iter.value, goalCol, tabSize);
|
|
2859
|
-
goal = goalCol * view.defaultCharacterWidth;
|
|
2868
|
+
if (goal == null)
|
|
2869
|
+
goal = startCoords.left - rect.left;
|
|
2870
|
+
startY = dir < 0 ? startCoords.top : startCoords.bottom;
|
|
2860
2871
|
}
|
|
2861
2872
|
else {
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
let
|
|
2869
|
-
let
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
}
|
|
2876
|
-
return state.EditorSelection.cursor(result, undefined, undefined, goal);
|
|
2873
|
+
let line = view.viewState.lineAt(startPos, view.dom.getBoundingClientRect().top);
|
|
2874
|
+
if (goal == null)
|
|
2875
|
+
goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
|
|
2876
|
+
startY = dir < 0 ? line.top : line.bottom;
|
|
2877
|
+
}
|
|
2878
|
+
let resolvedGoal = rect.left + goal;
|
|
2879
|
+
let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
|
2880
|
+
for (let extra = 0;; extra += 10) {
|
|
2881
|
+
let curY = startY + (dist + extra) * dir;
|
|
2882
|
+
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
2883
|
+
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
|
2884
|
+
return state.EditorSelection.cursor(pos, undefined, undefined, goal);
|
|
2885
|
+
}
|
|
2877
2886
|
}
|
|
2878
2887
|
function skipAtoms(view, oldPos, pos) {
|
|
2879
2888
|
let atoms = view.pluginField(PluginField.atomicRanges);
|
|
@@ -3053,7 +3062,8 @@ class InputState {
|
|
|
3053
3062
|
update(update) {
|
|
3054
3063
|
if (this.mouseSelection)
|
|
3055
3064
|
this.mouseSelection.update(update);
|
|
3056
|
-
|
|
3065
|
+
if (update.transactions.length)
|
|
3066
|
+
this.lastKeyCode = this.lastSelectionTime = 0;
|
|
3057
3067
|
}
|
|
3058
3068
|
destroy() {
|
|
3059
3069
|
if (this.mouseSelection)
|
|
@@ -3066,8 +3076,8 @@ class MouseSelection {
|
|
|
3066
3076
|
constructor(inputState, view, startEvent, style) {
|
|
3067
3077
|
this.inputState = inputState;
|
|
3068
3078
|
this.view = view;
|
|
3069
|
-
this.startEvent = startEvent;
|
|
3070
3079
|
this.style = style;
|
|
3080
|
+
this.lastEvent = startEvent;
|
|
3071
3081
|
let doc = view.contentDOM.ownerDocument;
|
|
3072
3082
|
doc.addEventListener("mousemove", this.move = this.move.bind(this));
|
|
3073
3083
|
doc.addEventListener("mouseup", this.up = this.up.bind(this));
|
|
@@ -3087,11 +3097,11 @@ class MouseSelection {
|
|
|
3087
3097
|
return this.destroy();
|
|
3088
3098
|
if (this.dragging !== false)
|
|
3089
3099
|
return;
|
|
3090
|
-
this.select(event);
|
|
3100
|
+
this.select(this.lastEvent = event);
|
|
3091
3101
|
}
|
|
3092
3102
|
up(event) {
|
|
3093
3103
|
if (this.dragging == null)
|
|
3094
|
-
this.select(this.
|
|
3104
|
+
this.select(this.lastEvent);
|
|
3095
3105
|
if (!this.dragging)
|
|
3096
3106
|
event.preventDefault();
|
|
3097
3107
|
this.destroy();
|
|
@@ -3114,7 +3124,8 @@ class MouseSelection {
|
|
|
3114
3124
|
update(update) {
|
|
3115
3125
|
if (update.docChanged && this.dragging)
|
|
3116
3126
|
this.dragging = this.dragging.map(update.changes);
|
|
3117
|
-
this.style.update(update)
|
|
3127
|
+
if (this.style.update(update))
|
|
3128
|
+
setTimeout(() => this.select(this.lastEvent), 20);
|
|
3118
3129
|
}
|
|
3119
3130
|
}
|
|
3120
3131
|
function addsSelectionRange(view, event) {
|
|
@@ -3274,9 +3285,7 @@ function findPositionSide(view, pos, x, y) {
|
|
|
3274
3285
|
return before && insideY(y, before) ? -1 : 1;
|
|
3275
3286
|
}
|
|
3276
3287
|
function queryPos(view, event) {
|
|
3277
|
-
let pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
|
3278
|
-
if (pos == null)
|
|
3279
|
-
return null;
|
|
3288
|
+
let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
3280
3289
|
return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) };
|
|
3281
3290
|
}
|
|
3282
3291
|
const BadMouseDetail = browser.ie && browser.ie_version <= 11;
|
|
@@ -3300,11 +3309,12 @@ function basicMouseSelection(view, event) {
|
|
|
3300
3309
|
if (start)
|
|
3301
3310
|
start.pos = update.changes.mapPos(start.pos);
|
|
3302
3311
|
startSel = startSel.map(update.changes);
|
|
3312
|
+
lastEvent = null;
|
|
3303
3313
|
}
|
|
3304
3314
|
},
|
|
3305
3315
|
get(event, extend, multiple) {
|
|
3306
3316
|
let cur;
|
|
3307
|
-
if (event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY)
|
|
3317
|
+
if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY)
|
|
3308
3318
|
cur = last;
|
|
3309
3319
|
else {
|
|
3310
3320
|
cur = last = queryPos(view, event);
|
|
@@ -4676,6 +4686,7 @@ const baseTheme = buildTheme("." + baseThemeID, {
|
|
|
4676
4686
|
},
|
|
4677
4687
|
".cm-lineWrapping": {
|
|
4678
4688
|
whiteSpace: "pre-wrap",
|
|
4689
|
+
wordBreak: "break-word",
|
|
4679
4690
|
overflowWrap: "anywhere"
|
|
4680
4691
|
},
|
|
4681
4692
|
"&light .cm-content": { caretColor: "black" },
|
|
@@ -5008,7 +5019,8 @@ class DOMObserver {
|
|
|
5008
5019
|
this.ignore(() => this.view.docView.sync());
|
|
5009
5020
|
this.view.docView.dirty = 0 /* Not */;
|
|
5010
5021
|
}
|
|
5011
|
-
|
|
5022
|
+
if (newSel)
|
|
5023
|
+
this.view.docView.updateSelection();
|
|
5012
5024
|
}
|
|
5013
5025
|
this.clearSelection();
|
|
5014
5026
|
}
|
|
@@ -5436,8 +5448,10 @@ class EditorView {
|
|
|
5436
5448
|
scrollTo = transactions.some(tr => tr.scrollIntoView) ? state$1.selection.main : null;
|
|
5437
5449
|
this.viewState.update(update, scrollTo);
|
|
5438
5450
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
5439
|
-
if (!update.empty)
|
|
5451
|
+
if (!update.empty) {
|
|
5440
5452
|
this.updatePlugins(update);
|
|
5453
|
+
this.inputState.update(update);
|
|
5454
|
+
}
|
|
5441
5455
|
redrawn = this.docView.update(update);
|
|
5442
5456
|
if (this.state.facet(styleModule) != this.styleModules)
|
|
5443
5457
|
this.mountStyles();
|
|
@@ -5511,10 +5525,12 @@ class EditorView {
|
|
|
5511
5525
|
/**
|
|
5512
5526
|
@internal
|
|
5513
5527
|
*/
|
|
5514
|
-
measure() {
|
|
5528
|
+
measure(flush = true) {
|
|
5515
5529
|
if (this.measureScheduled > -1)
|
|
5516
5530
|
cancelAnimationFrame(this.measureScheduled);
|
|
5517
5531
|
this.measureScheduled = -1; // Prevent requestMeasure calls from scheduling another animation frame
|
|
5532
|
+
if (flush)
|
|
5533
|
+
this.observer.flush();
|
|
5518
5534
|
let updated = null;
|
|
5519
5535
|
try {
|
|
5520
5536
|
for (let i = 0;; i++) {
|
|
@@ -5544,8 +5560,10 @@ class EditorView {
|
|
|
5544
5560
|
else
|
|
5545
5561
|
updated.flags |= changed;
|
|
5546
5562
|
this.updateState = 2 /* Updating */;
|
|
5547
|
-
if (!update.empty)
|
|
5563
|
+
if (!update.empty) {
|
|
5548
5564
|
this.updatePlugins(update);
|
|
5565
|
+
this.inputState.update(update);
|
|
5566
|
+
}
|
|
5549
5567
|
this.updateAttrs();
|
|
5550
5568
|
if (changed)
|
|
5551
5569
|
this.docView.update(update);
|
|
@@ -5593,7 +5611,7 @@ class EditorView {
|
|
|
5593
5611
|
spellcheck: "false",
|
|
5594
5612
|
autocorrect: "off",
|
|
5595
5613
|
autocapitalize: "off",
|
|
5596
|
-
contenteditable:
|
|
5614
|
+
contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
|
|
5597
5615
|
class: "cm-content",
|
|
5598
5616
|
style: `${browser.tabSize}: ${this.state.tabSize}`,
|
|
5599
5617
|
role: "textbox",
|
|
@@ -5622,7 +5640,7 @@ class EditorView {
|
|
|
5622
5640
|
if (this.updateState == 2 /* Updating */)
|
|
5623
5641
|
throw new Error("Reading the editor layout isn't allowed during an update");
|
|
5624
5642
|
if (this.updateState == 0 /* Idle */ && this.measureScheduled > -1)
|
|
5625
|
-
this.measure();
|
|
5643
|
+
this.measure(false);
|
|
5626
5644
|
}
|
|
5627
5645
|
/**
|
|
5628
5646
|
Schedule a layout measurement, optionally providing callbacks to
|
|
@@ -5709,11 +5727,9 @@ class EditorView {
|
|
|
5709
5727
|
this.viewState.forEachLine(from, to, f, ensureTop(docTop, this.contentDOM));
|
|
5710
5728
|
}
|
|
5711
5729
|
/**
|
|
5712
|
-
Find the extent and height of the visual line (
|
|
5713
|
-
|
|
5714
|
-
line
|
|
5715
|
-
line when line breaks are covered by replaced decorations) at
|
|
5716
|
-
the given position.
|
|
5730
|
+
Find the extent and height of the visual line (a range delimited
|
|
5731
|
+
on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
|
|
5732
|
+
line breaks, or the start/end of the document) at the given position.
|
|
5717
5733
|
|
|
5718
5734
|
Vertical positions are computed relative to the `docTop`
|
|
5719
5735
|
argument, which defaults to 0 for this method. You can pass
|
|
@@ -5805,13 +5821,9 @@ class EditorView {
|
|
|
5805
5821
|
posAtDOM(node, offset = 0) {
|
|
5806
5822
|
return this.docView.posFromDOM(node, offset);
|
|
5807
5823
|
}
|
|
5808
|
-
|
|
5809
|
-
Get the document position at the given screen coordinates.
|
|
5810
|
-
Returns null if no valid position could be found.
|
|
5811
|
-
*/
|
|
5812
|
-
posAtCoords(coords) {
|
|
5824
|
+
posAtCoords(coords, precise = true) {
|
|
5813
5825
|
this.readMeasured();
|
|
5814
|
-
return posAtCoords(this, coords);
|
|
5826
|
+
return posAtCoords(this, coords, precise);
|
|
5815
5827
|
}
|
|
5816
5828
|
/**
|
|
5817
5829
|
Get the screen coordinates at the given document position.
|
|
@@ -6401,7 +6413,17 @@ function getBase(view) {
|
|
|
6401
6413
|
function wrappedLine(view, pos, inside) {
|
|
6402
6414
|
let range = state.EditorSelection.cursor(pos);
|
|
6403
6415
|
return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from),
|
|
6404
|
-
to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from)
|
|
6416
|
+
to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from),
|
|
6417
|
+
type: exports.BlockType.Text };
|
|
6418
|
+
}
|
|
6419
|
+
function blockAt(view, pos) {
|
|
6420
|
+
let line = view.visualLineAt(pos);
|
|
6421
|
+
if (Array.isArray(line.type))
|
|
6422
|
+
for (let l of line.type) {
|
|
6423
|
+
if (l.to > pos || l.to == pos && (l.to == line.to || l.type == exports.BlockType.Text))
|
|
6424
|
+
return l;
|
|
6425
|
+
}
|
|
6426
|
+
return line;
|
|
6405
6427
|
}
|
|
6406
6428
|
function measureRange(view, range) {
|
|
6407
6429
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -6412,22 +6434,25 @@ function measureRange(view, range) {
|
|
|
6412
6434
|
let lineStyle = window.getComputedStyle(content.firstChild);
|
|
6413
6435
|
let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft);
|
|
6414
6436
|
let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
|
|
6415
|
-
let
|
|
6416
|
-
let
|
|
6437
|
+
let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
|
|
6438
|
+
let visualStart = startBlock.type == exports.BlockType.Text ? startBlock : null;
|
|
6439
|
+
let visualEnd = endBlock.type == exports.BlockType.Text ? endBlock : null;
|
|
6417
6440
|
if (view.lineWrapping) {
|
|
6418
|
-
|
|
6419
|
-
|
|
6441
|
+
if (visualStart)
|
|
6442
|
+
visualStart = wrappedLine(view, from, visualStart);
|
|
6443
|
+
if (visualEnd)
|
|
6444
|
+
visualEnd = wrappedLine(view, to, visualEnd);
|
|
6420
6445
|
}
|
|
6421
|
-
if (visualStart.from == visualEnd.from) {
|
|
6446
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
6422
6447
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
6423
6448
|
}
|
|
6424
6449
|
else {
|
|
6425
|
-
let top = drawForLine(range.from, null, visualStart);
|
|
6426
|
-
let bottom = drawForLine(null, range.to, visualEnd);
|
|
6450
|
+
let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
|
|
6451
|
+
let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
|
|
6427
6452
|
let between = [];
|
|
6428
|
-
if (visualStart.to < visualEnd.from - 1)
|
|
6453
|
+
if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1)
|
|
6429
6454
|
between.push(piece(leftSide, top.bottom, rightSide, bottom.top));
|
|
6430
|
-
else if (top.bottom < bottom.top && bottom.top
|
|
6455
|
+
else if (top.bottom < bottom.top && blockAt(view, (top.bottom + bottom.top) / 2).type == exports.BlockType.Text)
|
|
6431
6456
|
top.bottom = bottom.top = (top.bottom + bottom.top) / 2;
|
|
6432
6457
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
6433
6458
|
}
|
|
@@ -6444,8 +6469,12 @@ function measureRange(view, range) {
|
|
|
6444
6469
|
function drawForLine(from, to, line) {
|
|
6445
6470
|
let top = 1e9, bottom = -1e9, horizontal = [];
|
|
6446
6471
|
function addSpan(from, fromOpen, to, toOpen, dir) {
|
|
6447
|
-
|
|
6448
|
-
|
|
6472
|
+
// Passing 2/-2 is a kludge to force the view to return
|
|
6473
|
+
// coordinates on the proper side of block widgets, since
|
|
6474
|
+
// normalizing the side there, though appropriate for most
|
|
6475
|
+
// coordsAtPos queries, would break selection drawing.
|
|
6476
|
+
let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2));
|
|
6477
|
+
let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2));
|
|
6449
6478
|
top = Math.min(fromCoords.top, toCoords.top, top);
|
|
6450
6479
|
bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom);
|
|
6451
6480
|
if (dir == exports.Direction.LTR)
|
|
@@ -6475,6 +6504,10 @@ function measureRange(view, range) {
|
|
|
6475
6504
|
addSpan(start, from == null, end, to == null, view.textDirection);
|
|
6476
6505
|
return { top, bottom, horizontal };
|
|
6477
6506
|
}
|
|
6507
|
+
function drawForWidget(block, top) {
|
|
6508
|
+
let y = contentRect.top + (top ? block.top : block.bottom);
|
|
6509
|
+
return { top: y, bottom: y, horizontal: [] };
|
|
6510
|
+
}
|
|
6478
6511
|
}
|
|
6479
6512
|
function measureCursor(view, cursor, primary) {
|
|
6480
6513
|
let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
|
package/dist/index.d.ts
CHANGED
|
@@ -501,8 +501,14 @@ interface MouseSelectionStyle {
|
|
|
501
501
|
progress. When the document changes, it may be necessary to map
|
|
502
502
|
some data (like the original selection or start position)
|
|
503
503
|
through the changes.
|
|
504
|
+
|
|
505
|
+
This may return `true` to indicate that the `get` method should
|
|
506
|
+
get queried again after the update, because something in the
|
|
507
|
+
update could change its result. Be wary of infinite loops when
|
|
508
|
+
using this (where `get` returns a new selection, which will
|
|
509
|
+
trigger `update`, which schedules another `get` in response).
|
|
504
510
|
*/
|
|
505
|
-
update: (update: ViewUpdate) => void;
|
|
511
|
+
update: (update: ViewUpdate) => boolean | void;
|
|
506
512
|
}
|
|
507
513
|
declare type MakeSelectionStyle = (view: EditorView, event: MouseEvent) => MouseSelectionStyle | null;
|
|
508
514
|
|
|
@@ -782,11 +788,9 @@ declare class EditorView {
|
|
|
782
788
|
*/
|
|
783
789
|
viewportLines(f: (line: BlockInfo) => void, docTop?: number): void;
|
|
784
790
|
/**
|
|
785
|
-
Find the extent and height of the visual line (
|
|
786
|
-
|
|
787
|
-
line
|
|
788
|
-
line when line breaks are covered by replaced decorations) at
|
|
789
|
-
the given position.
|
|
791
|
+
Find the extent and height of the visual line (a range delimited
|
|
792
|
+
on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
|
|
793
|
+
line breaks, or the start/end of the document) at the given position.
|
|
790
794
|
|
|
791
795
|
Vertical positions are computed relative to the `docTop`
|
|
792
796
|
argument, which defaults to 0 for this method. You can pass
|
|
@@ -866,6 +870,10 @@ declare class EditorView {
|
|
|
866
870
|
Get the document position at the given screen coordinates.
|
|
867
871
|
Returns null if no valid position could be found.
|
|
868
872
|
*/
|
|
873
|
+
posAtCoords(coords: {
|
|
874
|
+
x: number;
|
|
875
|
+
y: number;
|
|
876
|
+
}, precise: false): number;
|
|
869
877
|
posAtCoords(coords: {
|
|
870
878
|
x: number;
|
|
871
879
|
y: number;
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { MapMode, Text as Text$1, Facet, ChangeSet, Transaction, EditorSelection
|
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
3
|
import { RangeValue, RangeSet, RangeSetBuilder } from '@codemirror/rangeset';
|
|
4
4
|
export { Range } from '@codemirror/rangeset';
|
|
5
|
-
import { Text, findClusterBreak,
|
|
5
|
+
import { Text, findClusterBreak, findColumn, codePointAt, countColumn } from '@codemirror/text';
|
|
6
6
|
import { keyName, base } from 'w3c-keyname';
|
|
7
7
|
|
|
8
8
|
function getSelection(root) {
|
|
@@ -213,6 +213,19 @@ function dispatchKey(elt, name, code) {
|
|
|
213
213
|
elt.dispatchEvent(up);
|
|
214
214
|
return down.defaultPrevented || up.defaultPrevented;
|
|
215
215
|
}
|
|
216
|
+
let _plainTextSupported = null;
|
|
217
|
+
function contentEditablePlainTextSupported() {
|
|
218
|
+
if (_plainTextSupported == null) {
|
|
219
|
+
_plainTextSupported = false;
|
|
220
|
+
let dummy = document.createElement("div");
|
|
221
|
+
try {
|
|
222
|
+
dummy.contentEditable = "plaintext-only";
|
|
223
|
+
_plainTextSupported = dummy.contentEditable == "plaintext-only";
|
|
224
|
+
}
|
|
225
|
+
catch (_) { }
|
|
226
|
+
}
|
|
227
|
+
return _plainTextSupported;
|
|
228
|
+
}
|
|
216
229
|
|
|
217
230
|
class DOMPos {
|
|
218
231
|
constructor(node, offset, precise = true) {
|
|
@@ -1953,6 +1966,8 @@ class DocView extends ContentView {
|
|
|
1953
1966
|
// FIXME need to handle the case where the selection falls inside a block range
|
|
1954
1967
|
let anchor = this.domAtPos(main.anchor);
|
|
1955
1968
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
1969
|
+
// Always reset on Firefox when next to an uneditable node to
|
|
1970
|
+
// avoid invisible cursor bugs (#111)
|
|
1956
1971
|
if (browser.gecko && main.empty && betweenUneditable(anchor)) {
|
|
1957
1972
|
let dummy = document.createTextNode("");
|
|
1958
1973
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
@@ -1962,9 +1977,6 @@ class DocView extends ContentView {
|
|
|
1962
1977
|
let domSel = this.view.observer.selectionRange;
|
|
1963
1978
|
// If the selection is already here, or in an equivalent position, don't touch it
|
|
1964
1979
|
if (force || !domSel.focusNode ||
|
|
1965
|
-
// Always reset on Firefox when next to an uneditable node to
|
|
1966
|
-
// avoid invisible cursor bugs (#111)
|
|
1967
|
-
(browser.gecko && main.empty && nextToUneditable(domSel.focusNode, domSel.focusOffset)) ||
|
|
1968
1980
|
!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
|
1969
1981
|
!isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
|
1970
1982
|
this.view.observer.ignore(() => {
|
|
@@ -2007,6 +2019,8 @@ class DocView extends ContentView {
|
|
|
2007
2019
|
this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
|
|
2008
2020
|
}
|
|
2009
2021
|
enforceCursorAssoc() {
|
|
2022
|
+
if (this.view.composing)
|
|
2023
|
+
return;
|
|
2010
2024
|
let cursor = this.view.state.selection.main;
|
|
2011
2025
|
let sel = getSelection(this.root);
|
|
2012
2026
|
if (!cursor.empty || !cursor.assoc || !sel.modify)
|
|
@@ -2057,7 +2071,10 @@ class DocView extends ContentView {
|
|
|
2057
2071
|
coordsAt(pos, side) {
|
|
2058
2072
|
for (let off = this.length, i = this.children.length - 1;; i--) {
|
|
2059
2073
|
let child = this.children[i], start = off - child.breakAfter - child.length;
|
|
2060
|
-
if (pos > start ||
|
|
2074
|
+
if (pos > start ||
|
|
2075
|
+
(pos == start && child.type != BlockType.WidgetBefore && child.type != BlockType.WidgetAfter &&
|
|
2076
|
+
(!i || side == 2 || this.children[i - 1].breakAfter ||
|
|
2077
|
+
(this.children[i - 1].type == BlockType.WidgetBefore && side > -2))))
|
|
2061
2078
|
return child.coordsAt(pos - start, side);
|
|
2062
2079
|
off = start;
|
|
2063
2080
|
}
|
|
@@ -2129,11 +2146,11 @@ class DocView extends ContentView {
|
|
|
2129
2146
|
}
|
|
2130
2147
|
updateDeco() {
|
|
2131
2148
|
return this.decorations = [
|
|
2132
|
-
this.
|
|
2133
|
-
this.view.viewState.lineGapDeco,
|
|
2134
|
-
this.compositionDeco,
|
|
2149
|
+
...this.view.pluginField(PluginField.decorations),
|
|
2135
2150
|
...this.view.state.facet(decorations),
|
|
2136
|
-
|
|
2151
|
+
this.compositionDeco,
|
|
2152
|
+
this.computeBlockGapDeco(),
|
|
2153
|
+
this.view.viewState.lineGapDeco
|
|
2137
2154
|
];
|
|
2138
2155
|
}
|
|
2139
2156
|
scrollPosIntoView(pos, side) {
|
|
@@ -2714,7 +2731,7 @@ function domPosInText(node, x, y) {
|
|
|
2714
2731
|
}
|
|
2715
2732
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
2716
2733
|
}
|
|
2717
|
-
function posAtCoords(view, { x, y }, bias = -1) {
|
|
2734
|
+
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2718
2735
|
let content = view.contentDOM.getBoundingClientRect(), block;
|
|
2719
2736
|
let halfLine = view.defaultLineHeight / 2;
|
|
2720
2737
|
for (let bounced = false;;) {
|
|
@@ -2723,7 +2740,7 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2723
2740
|
bias = block.top > y ? -1 : 1;
|
|
2724
2741
|
y = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, y));
|
|
2725
2742
|
if (bounced)
|
|
2726
|
-
return null;
|
|
2743
|
+
return precise ? null : 0;
|
|
2727
2744
|
else
|
|
2728
2745
|
bounced = true;
|
|
2729
2746
|
}
|
|
@@ -2732,13 +2749,13 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2732
2749
|
y = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
|
|
2733
2750
|
}
|
|
2734
2751
|
let lineStart = block.from;
|
|
2752
|
+
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
2735
2753
|
// If this is outside of the rendered viewport, we can't determine a position
|
|
2736
2754
|
if (lineStart < view.viewport.from)
|
|
2737
|
-
return view.viewport.from == 0 ? 0 :
|
|
2755
|
+
return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
|
|
2738
2756
|
if (lineStart > view.viewport.to)
|
|
2739
|
-
return view.viewport.to == view.state.doc.length ? view.state.doc.length :
|
|
2757
|
+
return view.viewport.to == view.state.doc.length ? view.state.doc.length : posAtCoordsImprecise(view, content, block, x, y);
|
|
2740
2758
|
// Clip x to the viewport sides
|
|
2741
|
-
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
2742
2759
|
let root = view.root, element = root.elementFromPoint(x, y);
|
|
2743
2760
|
// There's visible editor content under the point, so we can try
|
|
2744
2761
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
@@ -2765,6 +2782,15 @@ function posAtCoords(view, { x, y }, bias = -1) {
|
|
|
2765
2782
|
}
|
|
2766
2783
|
return view.docView.posFromDOM(node, offset);
|
|
2767
2784
|
}
|
|
2785
|
+
function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
2786
|
+
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
|
2787
|
+
if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
|
|
2788
|
+
let line = Math.floor((y - block.top) / view.defaultLineHeight);
|
|
2789
|
+
into += line * view.viewState.heightOracle.lineLength;
|
|
2790
|
+
}
|
|
2791
|
+
let content = view.state.sliceDoc(block.from, block.to);
|
|
2792
|
+
return block.from + findColumn(content, into, view.state.tabSize);
|
|
2793
|
+
}
|
|
2768
2794
|
// In case of a high line height, Safari's caretRangeFromPoint treats
|
|
2769
2795
|
// the space between lines as belonging to the last character of the
|
|
2770
2796
|
// line before. This is used to detect such a result so that it can be
|
|
@@ -2827,48 +2853,31 @@ function byGroup(view, pos, start) {
|
|
|
2827
2853
|
};
|
|
2828
2854
|
}
|
|
2829
2855
|
function moveVertically(view, start, forward, distance) {
|
|
2830
|
-
var _a;
|
|
2831
2856
|
let startPos = start.head, dir = forward ? 1 : -1;
|
|
2832
2857
|
if (startPos == (forward ? view.state.doc.length : 0))
|
|
2833
2858
|
return EditorSelection.cursor(startPos);
|
|
2859
|
+
let goal = start.goalColumn, startY;
|
|
2860
|
+
let rect = view.contentDOM.getBoundingClientRect();
|
|
2834
2861
|
let startCoords = view.coordsAtPos(startPos);
|
|
2835
2862
|
if (startCoords) {
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
|
2840
|
-
for (let startY = dir < 0 ? startCoords.top : startCoords.bottom, extra = 0; extra < 50; extra += 10) {
|
|
2841
|
-
let pos = posAtCoords(view, { x: resolvedGoal, y: startY + (dist + extra) * dir }, dir);
|
|
2842
|
-
if (pos == null)
|
|
2843
|
-
break;
|
|
2844
|
-
if (pos != startPos)
|
|
2845
|
-
return EditorSelection.cursor(pos, undefined, undefined, goal);
|
|
2846
|
-
}
|
|
2847
|
-
}
|
|
2848
|
-
// Outside of the drawn viewport, use a crude column-based approach
|
|
2849
|
-
let { doc } = view.state, line = doc.lineAt(startPos), tabSize = view.state.tabSize;
|
|
2850
|
-
let goal = start.goalColumn, goalCol = 0;
|
|
2851
|
-
if (goal == null) {
|
|
2852
|
-
for (const iter = doc.iterRange(line.from, startPos); !iter.next().done;)
|
|
2853
|
-
goalCol = countColumn(iter.value, goalCol, tabSize);
|
|
2854
|
-
goal = goalCol * view.defaultCharacterWidth;
|
|
2863
|
+
if (goal == null)
|
|
2864
|
+
goal = startCoords.left - rect.left;
|
|
2865
|
+
startY = dir < 0 ? startCoords.top : startCoords.bottom;
|
|
2855
2866
|
}
|
|
2856
2867
|
else {
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
let
|
|
2864
|
-
let
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
}
|
|
2871
|
-
return EditorSelection.cursor(result, undefined, undefined, goal);
|
|
2868
|
+
let line = view.viewState.lineAt(startPos, view.dom.getBoundingClientRect().top);
|
|
2869
|
+
if (goal == null)
|
|
2870
|
+
goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
|
|
2871
|
+
startY = dir < 0 ? line.top : line.bottom;
|
|
2872
|
+
}
|
|
2873
|
+
let resolvedGoal = rect.left + goal;
|
|
2874
|
+
let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
|
2875
|
+
for (let extra = 0;; extra += 10) {
|
|
2876
|
+
let curY = startY + (dist + extra) * dir;
|
|
2877
|
+
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
2878
|
+
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
|
2879
|
+
return EditorSelection.cursor(pos, undefined, undefined, goal);
|
|
2880
|
+
}
|
|
2872
2881
|
}
|
|
2873
2882
|
function skipAtoms(view, oldPos, pos) {
|
|
2874
2883
|
let atoms = view.pluginField(PluginField.atomicRanges);
|
|
@@ -3048,7 +3057,8 @@ class InputState {
|
|
|
3048
3057
|
update(update) {
|
|
3049
3058
|
if (this.mouseSelection)
|
|
3050
3059
|
this.mouseSelection.update(update);
|
|
3051
|
-
|
|
3060
|
+
if (update.transactions.length)
|
|
3061
|
+
this.lastKeyCode = this.lastSelectionTime = 0;
|
|
3052
3062
|
}
|
|
3053
3063
|
destroy() {
|
|
3054
3064
|
if (this.mouseSelection)
|
|
@@ -3061,8 +3071,8 @@ class MouseSelection {
|
|
|
3061
3071
|
constructor(inputState, view, startEvent, style) {
|
|
3062
3072
|
this.inputState = inputState;
|
|
3063
3073
|
this.view = view;
|
|
3064
|
-
this.startEvent = startEvent;
|
|
3065
3074
|
this.style = style;
|
|
3075
|
+
this.lastEvent = startEvent;
|
|
3066
3076
|
let doc = view.contentDOM.ownerDocument;
|
|
3067
3077
|
doc.addEventListener("mousemove", this.move = this.move.bind(this));
|
|
3068
3078
|
doc.addEventListener("mouseup", this.up = this.up.bind(this));
|
|
@@ -3082,11 +3092,11 @@ class MouseSelection {
|
|
|
3082
3092
|
return this.destroy();
|
|
3083
3093
|
if (this.dragging !== false)
|
|
3084
3094
|
return;
|
|
3085
|
-
this.select(event);
|
|
3095
|
+
this.select(this.lastEvent = event);
|
|
3086
3096
|
}
|
|
3087
3097
|
up(event) {
|
|
3088
3098
|
if (this.dragging == null)
|
|
3089
|
-
this.select(this.
|
|
3099
|
+
this.select(this.lastEvent);
|
|
3090
3100
|
if (!this.dragging)
|
|
3091
3101
|
event.preventDefault();
|
|
3092
3102
|
this.destroy();
|
|
@@ -3109,7 +3119,8 @@ class MouseSelection {
|
|
|
3109
3119
|
update(update) {
|
|
3110
3120
|
if (update.docChanged && this.dragging)
|
|
3111
3121
|
this.dragging = this.dragging.map(update.changes);
|
|
3112
|
-
this.style.update(update)
|
|
3122
|
+
if (this.style.update(update))
|
|
3123
|
+
setTimeout(() => this.select(this.lastEvent), 20);
|
|
3113
3124
|
}
|
|
3114
3125
|
}
|
|
3115
3126
|
function addsSelectionRange(view, event) {
|
|
@@ -3269,9 +3280,7 @@ function findPositionSide(view, pos, x, y) {
|
|
|
3269
3280
|
return before && insideY(y, before) ? -1 : 1;
|
|
3270
3281
|
}
|
|
3271
3282
|
function queryPos(view, event) {
|
|
3272
|
-
let pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
|
3273
|
-
if (pos == null)
|
|
3274
|
-
return null;
|
|
3283
|
+
let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
3275
3284
|
return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) };
|
|
3276
3285
|
}
|
|
3277
3286
|
const BadMouseDetail = browser.ie && browser.ie_version <= 11;
|
|
@@ -3295,11 +3304,12 @@ function basicMouseSelection(view, event) {
|
|
|
3295
3304
|
if (start)
|
|
3296
3305
|
start.pos = update.changes.mapPos(start.pos);
|
|
3297
3306
|
startSel = startSel.map(update.changes);
|
|
3307
|
+
lastEvent = null;
|
|
3298
3308
|
}
|
|
3299
3309
|
},
|
|
3300
3310
|
get(event, extend, multiple) {
|
|
3301
3311
|
let cur;
|
|
3302
|
-
if (event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY)
|
|
3312
|
+
if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY)
|
|
3303
3313
|
cur = last;
|
|
3304
3314
|
else {
|
|
3305
3315
|
cur = last = queryPos(view, event);
|
|
@@ -4670,6 +4680,7 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
4670
4680
|
},
|
|
4671
4681
|
".cm-lineWrapping": {
|
|
4672
4682
|
whiteSpace: "pre-wrap",
|
|
4683
|
+
wordBreak: "break-word",
|
|
4673
4684
|
overflowWrap: "anywhere"
|
|
4674
4685
|
},
|
|
4675
4686
|
"&light .cm-content": { caretColor: "black" },
|
|
@@ -5002,7 +5013,8 @@ class DOMObserver {
|
|
|
5002
5013
|
this.ignore(() => this.view.docView.sync());
|
|
5003
5014
|
this.view.docView.dirty = 0 /* Not */;
|
|
5004
5015
|
}
|
|
5005
|
-
|
|
5016
|
+
if (newSel)
|
|
5017
|
+
this.view.docView.updateSelection();
|
|
5006
5018
|
}
|
|
5007
5019
|
this.clearSelection();
|
|
5008
5020
|
}
|
|
@@ -5430,8 +5442,10 @@ class EditorView {
|
|
|
5430
5442
|
scrollTo = transactions.some(tr => tr.scrollIntoView) ? state.selection.main : null;
|
|
5431
5443
|
this.viewState.update(update, scrollTo);
|
|
5432
5444
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
5433
|
-
if (!update.empty)
|
|
5445
|
+
if (!update.empty) {
|
|
5434
5446
|
this.updatePlugins(update);
|
|
5447
|
+
this.inputState.update(update);
|
|
5448
|
+
}
|
|
5435
5449
|
redrawn = this.docView.update(update);
|
|
5436
5450
|
if (this.state.facet(styleModule) != this.styleModules)
|
|
5437
5451
|
this.mountStyles();
|
|
@@ -5505,10 +5519,12 @@ class EditorView {
|
|
|
5505
5519
|
/**
|
|
5506
5520
|
@internal
|
|
5507
5521
|
*/
|
|
5508
|
-
measure() {
|
|
5522
|
+
measure(flush = true) {
|
|
5509
5523
|
if (this.measureScheduled > -1)
|
|
5510
5524
|
cancelAnimationFrame(this.measureScheduled);
|
|
5511
5525
|
this.measureScheduled = -1; // Prevent requestMeasure calls from scheduling another animation frame
|
|
5526
|
+
if (flush)
|
|
5527
|
+
this.observer.flush();
|
|
5512
5528
|
let updated = null;
|
|
5513
5529
|
try {
|
|
5514
5530
|
for (let i = 0;; i++) {
|
|
@@ -5538,8 +5554,10 @@ class EditorView {
|
|
|
5538
5554
|
else
|
|
5539
5555
|
updated.flags |= changed;
|
|
5540
5556
|
this.updateState = 2 /* Updating */;
|
|
5541
|
-
if (!update.empty)
|
|
5557
|
+
if (!update.empty) {
|
|
5542
5558
|
this.updatePlugins(update);
|
|
5559
|
+
this.inputState.update(update);
|
|
5560
|
+
}
|
|
5543
5561
|
this.updateAttrs();
|
|
5544
5562
|
if (changed)
|
|
5545
5563
|
this.docView.update(update);
|
|
@@ -5587,7 +5605,7 @@ class EditorView {
|
|
|
5587
5605
|
spellcheck: "false",
|
|
5588
5606
|
autocorrect: "off",
|
|
5589
5607
|
autocapitalize: "off",
|
|
5590
|
-
contenteditable:
|
|
5608
|
+
contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
|
|
5591
5609
|
class: "cm-content",
|
|
5592
5610
|
style: `${browser.tabSize}: ${this.state.tabSize}`,
|
|
5593
5611
|
role: "textbox",
|
|
@@ -5616,7 +5634,7 @@ class EditorView {
|
|
|
5616
5634
|
if (this.updateState == 2 /* Updating */)
|
|
5617
5635
|
throw new Error("Reading the editor layout isn't allowed during an update");
|
|
5618
5636
|
if (this.updateState == 0 /* Idle */ && this.measureScheduled > -1)
|
|
5619
|
-
this.measure();
|
|
5637
|
+
this.measure(false);
|
|
5620
5638
|
}
|
|
5621
5639
|
/**
|
|
5622
5640
|
Schedule a layout measurement, optionally providing callbacks to
|
|
@@ -5703,11 +5721,9 @@ class EditorView {
|
|
|
5703
5721
|
this.viewState.forEachLine(from, to, f, ensureTop(docTop, this.contentDOM));
|
|
5704
5722
|
}
|
|
5705
5723
|
/**
|
|
5706
|
-
Find the extent and height of the visual line (
|
|
5707
|
-
|
|
5708
|
-
line
|
|
5709
|
-
line when line breaks are covered by replaced decorations) at
|
|
5710
|
-
the given position.
|
|
5724
|
+
Find the extent and height of the visual line (a range delimited
|
|
5725
|
+
on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
|
|
5726
|
+
line breaks, or the start/end of the document) at the given position.
|
|
5711
5727
|
|
|
5712
5728
|
Vertical positions are computed relative to the `docTop`
|
|
5713
5729
|
argument, which defaults to 0 for this method. You can pass
|
|
@@ -5799,13 +5815,9 @@ class EditorView {
|
|
|
5799
5815
|
posAtDOM(node, offset = 0) {
|
|
5800
5816
|
return this.docView.posFromDOM(node, offset);
|
|
5801
5817
|
}
|
|
5802
|
-
|
|
5803
|
-
Get the document position at the given screen coordinates.
|
|
5804
|
-
Returns null if no valid position could be found.
|
|
5805
|
-
*/
|
|
5806
|
-
posAtCoords(coords) {
|
|
5818
|
+
posAtCoords(coords, precise = true) {
|
|
5807
5819
|
this.readMeasured();
|
|
5808
|
-
return posAtCoords(this, coords);
|
|
5820
|
+
return posAtCoords(this, coords, precise);
|
|
5809
5821
|
}
|
|
5810
5822
|
/**
|
|
5811
5823
|
Get the screen coordinates at the given document position.
|
|
@@ -6395,7 +6407,17 @@ function getBase(view) {
|
|
|
6395
6407
|
function wrappedLine(view, pos, inside) {
|
|
6396
6408
|
let range = EditorSelection.cursor(pos);
|
|
6397
6409
|
return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from),
|
|
6398
|
-
to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from)
|
|
6410
|
+
to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from),
|
|
6411
|
+
type: BlockType.Text };
|
|
6412
|
+
}
|
|
6413
|
+
function blockAt(view, pos) {
|
|
6414
|
+
let line = view.visualLineAt(pos);
|
|
6415
|
+
if (Array.isArray(line.type))
|
|
6416
|
+
for (let l of line.type) {
|
|
6417
|
+
if (l.to > pos || l.to == pos && (l.to == line.to || l.type == BlockType.Text))
|
|
6418
|
+
return l;
|
|
6419
|
+
}
|
|
6420
|
+
return line;
|
|
6399
6421
|
}
|
|
6400
6422
|
function measureRange(view, range) {
|
|
6401
6423
|
if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
|
@@ -6406,22 +6428,25 @@ function measureRange(view, range) {
|
|
|
6406
6428
|
let lineStyle = window.getComputedStyle(content.firstChild);
|
|
6407
6429
|
let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft);
|
|
6408
6430
|
let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
|
|
6409
|
-
let
|
|
6410
|
-
let
|
|
6431
|
+
let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
|
|
6432
|
+
let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
|
|
6433
|
+
let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
|
|
6411
6434
|
if (view.lineWrapping) {
|
|
6412
|
-
|
|
6413
|
-
|
|
6435
|
+
if (visualStart)
|
|
6436
|
+
visualStart = wrappedLine(view, from, visualStart);
|
|
6437
|
+
if (visualEnd)
|
|
6438
|
+
visualEnd = wrappedLine(view, to, visualEnd);
|
|
6414
6439
|
}
|
|
6415
|
-
if (visualStart.from == visualEnd.from) {
|
|
6440
|
+
if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
|
6416
6441
|
return pieces(drawForLine(range.from, range.to, visualStart));
|
|
6417
6442
|
}
|
|
6418
6443
|
else {
|
|
6419
|
-
let top = drawForLine(range.from, null, visualStart);
|
|
6420
|
-
let bottom = drawForLine(null, range.to, visualEnd);
|
|
6444
|
+
let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
|
|
6445
|
+
let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
|
|
6421
6446
|
let between = [];
|
|
6422
|
-
if (visualStart.to < visualEnd.from - 1)
|
|
6447
|
+
if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1)
|
|
6423
6448
|
between.push(piece(leftSide, top.bottom, rightSide, bottom.top));
|
|
6424
|
-
else if (top.bottom < bottom.top && bottom.top
|
|
6449
|
+
else if (top.bottom < bottom.top && blockAt(view, (top.bottom + bottom.top) / 2).type == BlockType.Text)
|
|
6425
6450
|
top.bottom = bottom.top = (top.bottom + bottom.top) / 2;
|
|
6426
6451
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
6427
6452
|
}
|
|
@@ -6438,8 +6463,12 @@ function measureRange(view, range) {
|
|
|
6438
6463
|
function drawForLine(from, to, line) {
|
|
6439
6464
|
let top = 1e9, bottom = -1e9, horizontal = [];
|
|
6440
6465
|
function addSpan(from, fromOpen, to, toOpen, dir) {
|
|
6441
|
-
|
|
6442
|
-
|
|
6466
|
+
// Passing 2/-2 is a kludge to force the view to return
|
|
6467
|
+
// coordinates on the proper side of block widgets, since
|
|
6468
|
+
// normalizing the side there, though appropriate for most
|
|
6469
|
+
// coordsAtPos queries, would break selection drawing.
|
|
6470
|
+
let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2));
|
|
6471
|
+
let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2));
|
|
6443
6472
|
top = Math.min(fromCoords.top, toCoords.top, top);
|
|
6444
6473
|
bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom);
|
|
6445
6474
|
if (dir == Direction.LTR)
|
|
@@ -6469,6 +6498,10 @@ function measureRange(view, range) {
|
|
|
6469
6498
|
addSpan(start, from == null, end, to == null, view.textDirection);
|
|
6470
6499
|
return { top, bottom, horizontal };
|
|
6471
6500
|
}
|
|
6501
|
+
function drawForWidget(block, top) {
|
|
6502
|
+
let y = contentRect.top + (top ? block.top : block.bottom);
|
|
6503
|
+
return { top: y, bottom: y, horizontal: [] };
|
|
6504
|
+
}
|
|
6472
6505
|
}
|
|
6473
6506
|
function measureCursor(view, cursor, primary) {
|
|
6474
6507
|
let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codemirror/view",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.19",
|
|
4
4
|
"description": "DOM view component for the CodeMirror code editor",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"test": "cm-runtests",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"@codemirror/rangeset": "^0.18.2",
|
|
30
30
|
"@codemirror/state": "^0.18.0",
|
|
31
|
-
"@codemirror/text": "^0.18.
|
|
31
|
+
"@codemirror/text": "^0.18.1",
|
|
32
32
|
"style-mod": "^4.0.0",
|
|
33
33
|
"w3c-keyname": "^2.2.4"
|
|
34
34
|
},
|