@codemirror/view 0.19.37 → 0.19.41
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 +54 -0
- package/dist/index.cjs +190 -82
- package/dist/index.d.ts +8 -1
- package/dist/index.js +191 -83
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
## 0.19.41 (2022-02-04)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where the editor's view of its content height could go out of sync with the DOM when a line-wrapping editor had its width changed, causing wrapping to change.
|
|
6
|
+
|
|
7
|
+
Fix a bug that caused the editor to draw way too much content when scrolling to a position in an editor (much) taller than the window.
|
|
8
|
+
|
|
9
|
+
Report an error when a replace decoration from a plugin crosses a line break, rather than silently ignoring it.
|
|
10
|
+
|
|
11
|
+
Fix an issue where reading DOM changes was broken when `lineSeparator` contained more than one character.
|
|
12
|
+
|
|
13
|
+
Make ordering of replace and mark decorations with the same extent and inclusivness more predictable by giving replace decorations precedence.
|
|
14
|
+
|
|
15
|
+
Fix a bug where, on Chrome, replacement across line boundaries and next to widgets could cause bogus zero-width characters to appear in the content.
|
|
16
|
+
|
|
17
|
+
## 0.19.40 (2022-01-19)
|
|
18
|
+
|
|
19
|
+
### Bug fixes
|
|
20
|
+
|
|
21
|
+
Make composition input properly appear at secondary cursors (except when those are in the DOM node with the composition, in which case the browser won't allow us to intervene without aborting the composition).
|
|
22
|
+
|
|
23
|
+
Fix a bug that cause the editor to get confused about which content was visible after scrolling something into view.
|
|
24
|
+
|
|
25
|
+
Fix a bug where the dummy elements rendered around widgets could end up in a separate set of wrapping marks, and thus become visible.
|
|
26
|
+
|
|
27
|
+
`EditorView.moveVertically` now preserves the `assoc` property of the input range.
|
|
28
|
+
|
|
29
|
+
Get rid of gaps between selection elements drawn by `drawSelection`.
|
|
30
|
+
|
|
31
|
+
Fix an issue where replacing text next to a widget might leak bogus zero-width spaces into the document.
|
|
32
|
+
|
|
33
|
+
Avoid browser selection mishandling when a focused view has `setState` called by eagerly refocusing it.
|
|
34
|
+
|
|
35
|
+
## 0.19.39 (2022-01-06)
|
|
36
|
+
|
|
37
|
+
### Bug fixes
|
|
38
|
+
|
|
39
|
+
Make sure the editor signals a `geometryChanged` update when its width changes.
|
|
40
|
+
|
|
41
|
+
### New features
|
|
42
|
+
|
|
43
|
+
`EditorView.darkTheme` can now be queried to figure out whether the editor is using a dark theme.
|
|
44
|
+
|
|
45
|
+
## 0.19.38 (2022-01-05)
|
|
46
|
+
|
|
47
|
+
### Bug fixes
|
|
48
|
+
|
|
49
|
+
Fix a bug that caused line decorations with a `class` property to suppress all other line decorations for that line.
|
|
50
|
+
|
|
51
|
+
Fix a bug that caused scroll effects to be corrupted when further updates came in before they were applied.
|
|
52
|
+
|
|
53
|
+
Fix an issue where, depending on which way a floating point rounding error fell, `posAtCoords` (and thus vertical cursor motion) for positions outside of the vertical range of the document might or might not return the start/end of the document.
|
|
54
|
+
|
|
1
55
|
## 0.19.37 (2021-12-22)
|
|
2
56
|
|
|
3
57
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -602,9 +602,8 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
602
602
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
603
603
|
}
|
|
604
604
|
|
|
605
|
-
let
|
|
606
|
-
|
|
607
|
-
: [{ userAgent: "", vendor: "", platform: "" }, { documentElement: { style: {} } }];
|
|
605
|
+
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
606
|
+
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
608
607
|
const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
|
|
609
608
|
const ie_upto10 = /MSIE \d/.test(nav.userAgent);
|
|
610
609
|
const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
|
|
@@ -1131,8 +1130,8 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1131
1130
|
static replace(spec) {
|
|
1132
1131
|
let block = !!spec.block;
|
|
1133
1132
|
let { start, end } = getInclusive(spec, block);
|
|
1134
|
-
let startSide =
|
|
1135
|
-
let endSide =
|
|
1133
|
+
let startSide = (start ? (block ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */) - 1;
|
|
1134
|
+
let endSide = (end ? (block ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */) + 1;
|
|
1136
1135
|
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1137
1136
|
}
|
|
1138
1137
|
/**
|
|
@@ -1237,7 +1236,7 @@ function widgetsEq(a, b) {
|
|
|
1237
1236
|
}
|
|
1238
1237
|
function addRange(from, to, ranges, margin = 0) {
|
|
1239
1238
|
let last = ranges.length - 1;
|
|
1240
|
-
if (last >= 0 && ranges[last] + margin
|
|
1239
|
+
if (last >= 0 && ranges[last] + margin >= from)
|
|
1241
1240
|
ranges[last] = Math.max(ranges[last], to);
|
|
1242
1241
|
else
|
|
1243
1242
|
ranges.push(from, to);
|
|
@@ -1311,7 +1310,7 @@ class LineView extends ContentView {
|
|
|
1311
1310
|
if (attrs)
|
|
1312
1311
|
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1313
1312
|
if (cls)
|
|
1314
|
-
this.attrs = combineAttrs(
|
|
1313
|
+
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1315
1314
|
}
|
|
1316
1315
|
domAtPos(pos) {
|
|
1317
1316
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
@@ -1518,7 +1517,7 @@ class ContentBuilder {
|
|
|
1518
1517
|
}
|
|
1519
1518
|
}
|
|
1520
1519
|
let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */);
|
|
1521
|
-
this.flushBuffer(active);
|
|
1520
|
+
this.flushBuffer(active.slice(0, openStart));
|
|
1522
1521
|
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1523
1522
|
this.atCursorPos = true;
|
|
1524
1523
|
this.textOff += take;
|
|
@@ -1577,11 +1576,13 @@ class ContentBuilder {
|
|
|
1577
1576
|
this.openStart = openStart;
|
|
1578
1577
|
}
|
|
1579
1578
|
filterPoint(from, to, value, index) {
|
|
1580
|
-
if (index
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1579
|
+
if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) {
|
|
1580
|
+
if (value.block)
|
|
1581
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1582
|
+
if (to > this.doc.lineAt(this.pos).to)
|
|
1583
|
+
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1584
|
+
}
|
|
1585
|
+
return true;
|
|
1585
1586
|
}
|
|
1586
1587
|
static build(text, from, to, decorations, pluginDecorationLength) {
|
|
1587
1588
|
let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
|
|
@@ -2305,12 +2306,18 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
2305
2306
|
return state.EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
|
|
2306
2307
|
}
|
|
2307
2308
|
|
|
2309
|
+
const LineBreakPlaceholder = "\uffff";
|
|
2308
2310
|
class DOMReader {
|
|
2309
|
-
constructor(points,
|
|
2311
|
+
constructor(points, state$1) {
|
|
2310
2312
|
this.points = points;
|
|
2311
|
-
this.view = view;
|
|
2312
2313
|
this.text = "";
|
|
2313
|
-
this.
|
|
2314
|
+
this.lineSeparator = state$1.facet(state.EditorState.lineSeparator);
|
|
2315
|
+
}
|
|
2316
|
+
append(text) {
|
|
2317
|
+
this.text += text;
|
|
2318
|
+
}
|
|
2319
|
+
lineBreak() {
|
|
2320
|
+
this.text += LineBreakPlaceholder;
|
|
2314
2321
|
}
|
|
2315
2322
|
readRange(start, end) {
|
|
2316
2323
|
if (!start)
|
|
@@ -2326,33 +2333,61 @@ class DOMReader {
|
|
|
2326
2333
|
if (view && nextView ? view.breakAfter :
|
|
2327
2334
|
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
2328
2335
|
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
|
|
2329
|
-
this.
|
|
2336
|
+
this.lineBreak();
|
|
2330
2337
|
cur = next;
|
|
2331
2338
|
}
|
|
2332
2339
|
this.findPointBefore(parent, end);
|
|
2333
2340
|
return this;
|
|
2334
2341
|
}
|
|
2342
|
+
readTextNode(node) {
|
|
2343
|
+
let text = node.nodeValue;
|
|
2344
|
+
for (let point of this.points)
|
|
2345
|
+
if (point.node == node)
|
|
2346
|
+
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
2347
|
+
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
2348
|
+
let nextBreak = -1, breakSize = 1, m;
|
|
2349
|
+
if (this.lineSeparator) {
|
|
2350
|
+
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
2351
|
+
breakSize = this.lineSeparator.length;
|
|
2352
|
+
}
|
|
2353
|
+
else if (m = re.exec(text)) {
|
|
2354
|
+
nextBreak = m.index;
|
|
2355
|
+
breakSize = m[0].length;
|
|
2356
|
+
}
|
|
2357
|
+
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
2358
|
+
if (nextBreak < 0)
|
|
2359
|
+
break;
|
|
2360
|
+
this.lineBreak();
|
|
2361
|
+
if (breakSize > 1)
|
|
2362
|
+
for (let point of this.points)
|
|
2363
|
+
if (point.node == node && point.pos > this.text.length)
|
|
2364
|
+
point.pos -= breakSize - 1;
|
|
2365
|
+
off = nextBreak + breakSize;
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2335
2368
|
readNode(node) {
|
|
2336
2369
|
if (node.cmIgnore)
|
|
2337
2370
|
return;
|
|
2338
2371
|
let view = ContentView.get(node);
|
|
2339
2372
|
let fromView = view && view.overrideDOMText;
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2373
|
+
if (fromView != null) {
|
|
2374
|
+
this.findPointInside(node);
|
|
2375
|
+
for (let i = fromView.iter(); !i.next().done;) {
|
|
2376
|
+
if (i.lineBreak)
|
|
2377
|
+
this.lineBreak();
|
|
2378
|
+
else
|
|
2379
|
+
this.append(i.value);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
else if (node.nodeType == 3) {
|
|
2383
|
+
this.readTextNode(node);
|
|
2384
|
+
}
|
|
2385
|
+
else if (node.nodeName == "BR") {
|
|
2386
|
+
if (node.nextSibling)
|
|
2387
|
+
this.lineBreak();
|
|
2388
|
+
}
|
|
2389
|
+
else if (node.nodeType == 1) {
|
|
2348
2390
|
this.readRange(node.firstChild, null);
|
|
2349
|
-
if (text != null) {
|
|
2350
|
-
this.findPointIn(node, text.length);
|
|
2351
|
-
this.text += text;
|
|
2352
|
-
// Chrome inserts two newlines when pressing shift-enter at the
|
|
2353
|
-
// end of a line. This drops one of those.
|
|
2354
|
-
if (browser.chrome && this.view.inputState.lastKeyCode == 13 && !node.nextSibling && /\n\n$/.test(this.text))
|
|
2355
|
-
this.text = this.text.slice(0, -1);
|
|
2356
2391
|
}
|
|
2357
2392
|
}
|
|
2358
2393
|
findPointBefore(node, next) {
|
|
@@ -2360,10 +2395,10 @@ class DOMReader {
|
|
|
2360
2395
|
if (point.node == node && node.childNodes[point.offset] == next)
|
|
2361
2396
|
point.pos = this.text.length;
|
|
2362
2397
|
}
|
|
2363
|
-
|
|
2398
|
+
findPointInside(node) {
|
|
2364
2399
|
for (let point of this.points)
|
|
2365
|
-
if (point.node == node)
|
|
2366
|
-
point.pos = this.text.length
|
|
2400
|
+
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
2401
|
+
point.pos = this.text.length;
|
|
2367
2402
|
}
|
|
2368
2403
|
}
|
|
2369
2404
|
function isBlockElement(node) {
|
|
@@ -2768,51 +2803,57 @@ class BlockGapWidget extends WidgetType {
|
|
|
2768
2803
|
}
|
|
2769
2804
|
get estimatedHeight() { return this.height; }
|
|
2770
2805
|
}
|
|
2771
|
-
function
|
|
2806
|
+
function compositionSurroundingNode(view) {
|
|
2772
2807
|
let sel = view.observer.selectionRange;
|
|
2773
2808
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
2774
2809
|
if (!textNode)
|
|
2775
|
-
return
|
|
2810
|
+
return null;
|
|
2776
2811
|
let cView = view.docView.nearest(textNode);
|
|
2777
2812
|
if (!cView)
|
|
2778
|
-
return
|
|
2779
|
-
let from, to, topNode = textNode;
|
|
2813
|
+
return null;
|
|
2780
2814
|
if (cView instanceof LineView) {
|
|
2815
|
+
let topNode = textNode;
|
|
2781
2816
|
while (topNode.parentNode != cView.dom)
|
|
2782
2817
|
topNode = topNode.parentNode;
|
|
2783
2818
|
let prev = topNode.previousSibling;
|
|
2784
2819
|
while (prev && !ContentView.get(prev))
|
|
2785
2820
|
prev = prev.previousSibling;
|
|
2786
|
-
|
|
2821
|
+
let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
|
|
2822
|
+
return { from: pos, to: pos, node: topNode, text: textNode };
|
|
2787
2823
|
}
|
|
2788
2824
|
else {
|
|
2789
2825
|
for (;;) {
|
|
2790
2826
|
let { parent } = cView;
|
|
2791
2827
|
if (!parent)
|
|
2792
|
-
return
|
|
2828
|
+
return null;
|
|
2793
2829
|
if (parent instanceof LineView)
|
|
2794
2830
|
break;
|
|
2795
2831
|
cView = parent;
|
|
2796
2832
|
}
|
|
2797
|
-
from = cView.posAtStart;
|
|
2798
|
-
|
|
2799
|
-
topNode = cView.dom;
|
|
2833
|
+
let from = cView.posAtStart;
|
|
2834
|
+
return { from, to: from + cView.length, node: cView.dom, text: textNode };
|
|
2800
2835
|
}
|
|
2836
|
+
}
|
|
2837
|
+
function computeCompositionDeco(view, changes) {
|
|
2838
|
+
let surrounding = compositionSurroundingNode(view);
|
|
2839
|
+
if (!surrounding)
|
|
2840
|
+
return Decoration.none;
|
|
2841
|
+
let { from, to, node, text: textNode } = surrounding;
|
|
2801
2842
|
let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1));
|
|
2802
|
-
let { state } = view, text =
|
|
2803
|
-
new DOMReader([],
|
|
2843
|
+
let { state } = view, text = node.nodeType == 3 ? node.nodeValue :
|
|
2844
|
+
new DOMReader([], state).readRange(node.firstChild, null).text;
|
|
2804
2845
|
if (newTo - newFrom < text.length) {
|
|
2805
|
-
if (state.
|
|
2846
|
+
if (state.doc.sliceString(newFrom, Math.min(state.doc.length, newFrom + text.length), LineBreakPlaceholder) == text)
|
|
2806
2847
|
newTo = newFrom + text.length;
|
|
2807
|
-
else if (state.
|
|
2848
|
+
else if (state.doc.sliceString(Math.max(0, newTo - text.length), newTo, LineBreakPlaceholder) == text)
|
|
2808
2849
|
newFrom = newTo - text.length;
|
|
2809
2850
|
else
|
|
2810
2851
|
return Decoration.none;
|
|
2811
2852
|
}
|
|
2812
|
-
else if (state.
|
|
2853
|
+
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2813
2854
|
return Decoration.none;
|
|
2814
2855
|
}
|
|
2815
|
-
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(
|
|
2856
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode) }).range(newFrom, newTo));
|
|
2816
2857
|
}
|
|
2817
2858
|
class CompositionWidget extends WidgetType {
|
|
2818
2859
|
constructor(top, text) {
|
|
@@ -3005,7 +3046,11 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
3005
3046
|
var _a;
|
|
3006
3047
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
3007
3048
|
let block, { docHeight } = view.viewState;
|
|
3008
|
-
let yOffset =
|
|
3049
|
+
let yOffset = y - docTop;
|
|
3050
|
+
if (yOffset < 0)
|
|
3051
|
+
return 0;
|
|
3052
|
+
if (yOffset > docHeight)
|
|
3053
|
+
return view.state.doc.length;
|
|
3009
3054
|
// Scan for a text block near the queried y position
|
|
3010
3055
|
for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
|
|
3011
3056
|
block = view.elementAtHeight(yOffset);
|
|
@@ -3145,7 +3190,7 @@ function byGroup(view, pos, start) {
|
|
|
3145
3190
|
function moveVertically(view, start, forward, distance) {
|
|
3146
3191
|
let startPos = start.head, dir = forward ? 1 : -1;
|
|
3147
3192
|
if (startPos == (forward ? view.state.doc.length : 0))
|
|
3148
|
-
return state.EditorSelection.cursor(startPos);
|
|
3193
|
+
return state.EditorSelection.cursor(startPos, start.assoc);
|
|
3149
3194
|
let goal = start.goalColumn, startY;
|
|
3150
3195
|
let rect = view.contentDOM.getBoundingClientRect();
|
|
3151
3196
|
let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
|
|
@@ -3166,7 +3211,7 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3166
3211
|
let curY = startY + (dist + extra) * dir;
|
|
3167
3212
|
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
3168
3213
|
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
|
3169
|
-
return state.EditorSelection.cursor(pos,
|
|
3214
|
+
return state.EditorSelection.cursor(pos, start.assoc, undefined, goal);
|
|
3170
3215
|
}
|
|
3171
3216
|
}
|
|
3172
3217
|
function skipAtoms(view, oldPos, pos) {
|
|
@@ -4595,6 +4640,7 @@ class ViewState {
|
|
|
4595
4640
|
this.contentDOMWidth = 0;
|
|
4596
4641
|
this.contentDOMHeight = 0;
|
|
4597
4642
|
this.editorHeight = 0;
|
|
4643
|
+
this.editorWidth = 0;
|
|
4598
4644
|
this.heightOracle = new HeightOracle;
|
|
4599
4645
|
// See VP.MaxDOMHeight
|
|
4600
4646
|
this.scaler = IdScaler;
|
|
@@ -4677,6 +4723,12 @@ class ViewState {
|
|
|
4677
4723
|
let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
|
|
4678
4724
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4679
4725
|
let result = 0, bias = 0;
|
|
4726
|
+
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
4727
|
+
if (oracle.lineWrapping)
|
|
4728
|
+
measureContent = true;
|
|
4729
|
+
this.editorWidth = view.scrollDOM.clientWidth;
|
|
4730
|
+
result |= 8 /* Geometry */;
|
|
4731
|
+
}
|
|
4680
4732
|
if (measureContent) {
|
|
4681
4733
|
this.mustMeasureContent = false;
|
|
4682
4734
|
this.contentDOMHeight = dom.clientHeight;
|
|
@@ -4689,7 +4741,8 @@ class ViewState {
|
|
|
4689
4741
|
}
|
|
4690
4742
|
}
|
|
4691
4743
|
// Pixel viewport
|
|
4692
|
-
let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
|
|
4744
|
+
let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
|
|
4745
|
+
: visiblePixelRange(dom, this.paddingTop);
|
|
4693
4746
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
4694
4747
|
this.pixelViewport = pixelViewport;
|
|
4695
4748
|
let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
|
@@ -4700,11 +4753,16 @@ class ViewState {
|
|
|
4700
4753
|
}
|
|
4701
4754
|
if (!this.inView)
|
|
4702
4755
|
return 0;
|
|
4756
|
+
let contentWidth = dom.clientWidth;
|
|
4757
|
+
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4758
|
+
this.contentDOMWidth = contentWidth;
|
|
4759
|
+
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4760
|
+
result |= 8 /* Geometry */;
|
|
4761
|
+
}
|
|
4703
4762
|
if (measureContent) {
|
|
4704
4763
|
let lineHeights = view.docView.measureVisibleLineHeights();
|
|
4705
4764
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
4706
4765
|
refresh = true;
|
|
4707
|
-
let contentWidth = dom.clientWidth;
|
|
4708
4766
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4709
4767
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4710
4768
|
refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
@@ -4713,14 +4771,6 @@ class ViewState {
|
|
|
4713
4771
|
result |= 8 /* Geometry */;
|
|
4714
4772
|
}
|
|
4715
4773
|
}
|
|
4716
|
-
if (this.contentDOMWidth != contentWidth) {
|
|
4717
|
-
this.contentDOMWidth = contentWidth;
|
|
4718
|
-
result |= 8 /* Geometry */;
|
|
4719
|
-
}
|
|
4720
|
-
if (this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4721
|
-
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4722
|
-
result |= 8 /* Geometry */;
|
|
4723
|
-
}
|
|
4724
4774
|
if (dTop > 0 && dBottom > 0)
|
|
4725
4775
|
bias = Math.max(dTop, dBottom);
|
|
4726
4776
|
else if (dTop < 0 && dBottom < 0)
|
|
@@ -4761,8 +4811,9 @@ class ViewState {
|
|
|
4761
4811
|
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to);
|
|
4762
4812
|
// If scrollTarget is given, make sure the viewport includes that position
|
|
4763
4813
|
if (scrollTarget) {
|
|
4764
|
-
let { head } = scrollTarget.range
|
|
4814
|
+
let { head } = scrollTarget.range;
|
|
4765
4815
|
if (head < viewport.from || head > viewport.to) {
|
|
4816
|
+
let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
|
|
4766
4817
|
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4767
4818
|
if (scrollTarget.y == "center")
|
|
4768
4819
|
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
@@ -5562,9 +5613,8 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5562
5613
|
return;
|
|
5563
5614
|
let { from, to } = bounds;
|
|
5564
5615
|
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5565
|
-
let reader = new DOMReader(selPoints, view);
|
|
5616
|
+
let reader = new DOMReader(selPoints, view.state);
|
|
5566
5617
|
reader.readRange(bounds.startDOM, bounds.endDOM);
|
|
5567
|
-
newSel = selectionFromPoints(selPoints, from);
|
|
5568
5618
|
let preferredPos = sel.from, preferredSide = null;
|
|
5569
5619
|
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5570
5620
|
// Android, when something was deleted)
|
|
@@ -5573,10 +5623,29 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5573
5623
|
preferredPos = sel.to;
|
|
5574
5624
|
preferredSide = "end";
|
|
5575
5625
|
}
|
|
5576
|
-
let diff = findDiff(view.state.
|
|
5577
|
-
if (diff)
|
|
5626
|
+
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5627
|
+
if (diff) {
|
|
5628
|
+
let orig = diff;
|
|
5629
|
+
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5630
|
+
// end of a line. This drops one of those.
|
|
5631
|
+
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5632
|
+
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5633
|
+
diff.toB--;
|
|
5634
|
+
// Strip leading and trailing zero-width spaces from the inserted
|
|
5635
|
+
// content, to work around widget buffers being moved into text
|
|
5636
|
+
// nodes by the browser.
|
|
5637
|
+
while (diff.from < diff.toB && reader.text[diff.from] == "\u200b") {
|
|
5638
|
+
diff = { from: diff.from + 1, toA: diff.toA, toB: diff.toB };
|
|
5639
|
+
selPoints.forEach(p => p.pos -= p.pos > orig.from ? 1 : 0);
|
|
5640
|
+
}
|
|
5641
|
+
while (diff.toB > diff.from && reader.text[diff.toB - 1] == "\u200b") {
|
|
5642
|
+
diff = { from: diff.from, toA: diff.toA, toB: diff.toB - 1 };
|
|
5643
|
+
selPoints.forEach(p => p.pos -= p.pos > orig.toB ? 1 : 0);
|
|
5644
|
+
}
|
|
5578
5645
|
change = { from: from + diff.from, to: from + diff.toA,
|
|
5579
|
-
insert:
|
|
5646
|
+
insert: state.Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5647
|
+
}
|
|
5648
|
+
newSel = selectionFromPoints(selPoints, from);
|
|
5580
5649
|
}
|
|
5581
5650
|
else if (view.hasFocus || !view.state.facet(editable)) {
|
|
5582
5651
|
let domSel = view.observer.selectionRange;
|
|
@@ -5633,19 +5702,47 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5633
5702
|
view.inputState.composing++;
|
|
5634
5703
|
let tr;
|
|
5635
5704
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5636
|
-
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length)
|
|
5705
|
+
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5706
|
+
view.inputState.composing < 0) {
|
|
5637
5707
|
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5638
5708
|
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5639
|
-
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) +
|
|
5640
|
-
after));
|
|
5709
|
+
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5641
5710
|
}
|
|
5642
5711
|
else {
|
|
5643
5712
|
let changes = startState.changes(change);
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5713
|
+
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5714
|
+
? newSel.main : undefined;
|
|
5715
|
+
// Try to apply a composition change to all cursors
|
|
5716
|
+
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5717
|
+
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5718
|
+
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5719
|
+
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5720
|
+
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5721
|
+
tr = startState.changeByRange(range => {
|
|
5722
|
+
if (range.from == sel.from && range.to == sel.to)
|
|
5723
|
+
return { changes, range: mainSel || range.map(changes) };
|
|
5724
|
+
let to = range.to - offset, from = to - replaced.length;
|
|
5725
|
+
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5726
|
+
// Unfortunately, there's no way to make multiple
|
|
5727
|
+
// changes in the same node work without aborting
|
|
5728
|
+
// composition, so cursors in the composition range are
|
|
5729
|
+
// ignored.
|
|
5730
|
+
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5731
|
+
return { range };
|
|
5732
|
+
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5733
|
+
return {
|
|
5734
|
+
changes: rangeChanges,
|
|
5735
|
+
range: !mainSel ? range.map(rangeChanges) :
|
|
5736
|
+
state.EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
5737
|
+
};
|
|
5738
|
+
});
|
|
5739
|
+
}
|
|
5740
|
+
else {
|
|
5741
|
+
tr = {
|
|
5742
|
+
changes,
|
|
5743
|
+
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
5744
|
+
};
|
|
5745
|
+
}
|
|
5649
5746
|
}
|
|
5650
5747
|
let userEvent = "input.type";
|
|
5651
5748
|
if (view.composing) {
|
|
@@ -5860,7 +5957,7 @@ class EditorView {
|
|
|
5860
5957
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
5861
5958
|
return this.setState(state$1);
|
|
5862
5959
|
update = new ViewUpdate(this, state$1, transactions);
|
|
5863
|
-
let scrollTarget =
|
|
5960
|
+
let scrollTarget = this.viewState.scrollTarget;
|
|
5864
5961
|
try {
|
|
5865
5962
|
this.updateState = 2 /* Updating */;
|
|
5866
5963
|
for (let tr of transactions) {
|
|
@@ -5916,6 +6013,7 @@ class EditorView {
|
|
|
5916
6013
|
return;
|
|
5917
6014
|
}
|
|
5918
6015
|
this.updateState = 2 /* Updating */;
|
|
6016
|
+
let hadFocus = this.hasFocus;
|
|
5919
6017
|
try {
|
|
5920
6018
|
for (let plugin of this.plugins)
|
|
5921
6019
|
plugin.destroy(this);
|
|
@@ -5933,6 +6031,8 @@ class EditorView {
|
|
|
5933
6031
|
finally {
|
|
5934
6032
|
this.updateState = 0 /* Idle */;
|
|
5935
6033
|
}
|
|
6034
|
+
if (hadFocus)
|
|
6035
|
+
this.focus();
|
|
5936
6036
|
this.requestMeasure();
|
|
5937
6037
|
}
|
|
5938
6038
|
updatePlugins(update) {
|
|
@@ -6002,7 +6102,7 @@ class EditorView {
|
|
|
6002
6102
|
return BadMeasure;
|
|
6003
6103
|
}
|
|
6004
6104
|
});
|
|
6005
|
-
let update = new ViewUpdate(this, this.state), redrawn = false;
|
|
6105
|
+
let update = new ViewUpdate(this, this.state), redrawn = false, scrolled = false;
|
|
6006
6106
|
update.flags |= changed;
|
|
6007
6107
|
if (!updated)
|
|
6008
6108
|
updated = update;
|
|
@@ -6029,11 +6129,12 @@ class EditorView {
|
|
|
6029
6129
|
if (this.viewState.scrollTarget) {
|
|
6030
6130
|
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6031
6131
|
this.viewState.scrollTarget = null;
|
|
6132
|
+
scrolled = true;
|
|
6032
6133
|
}
|
|
6033
6134
|
if (redrawn)
|
|
6034
6135
|
this.docView.updateSelection(true);
|
|
6035
6136
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to &&
|
|
6036
|
-
this.measureRequests.length == 0)
|
|
6137
|
+
!scrolled && this.measureRequests.length == 0)
|
|
6037
6138
|
break;
|
|
6038
6139
|
}
|
|
6039
6140
|
}
|
|
@@ -6169,7 +6270,7 @@ class EditorView {
|
|
|
6169
6270
|
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
6170
6271
|
queries.
|
|
6171
6272
|
|
|
6172
|
-
*Deprecated: use `
|
|
6273
|
+
*Deprecated: use `elementAtHeight` instead.*
|
|
6173
6274
|
*/
|
|
6174
6275
|
blockAtHeight(height, docTop) {
|
|
6175
6276
|
let top = ensureTop(docTop, this);
|
|
@@ -6581,6 +6682,13 @@ mechanism for providing decorations.
|
|
|
6581
6682
|
*/
|
|
6582
6683
|
EditorView.decorations = decorations;
|
|
6583
6684
|
/**
|
|
6685
|
+
This facet records whether a dark theme is active. The extension
|
|
6686
|
+
returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
|
|
6687
|
+
includes an instance of this when the `dark` option is set to
|
|
6688
|
+
true.
|
|
6689
|
+
*/
|
|
6690
|
+
EditorView.darkTheme = darkTheme;
|
|
6691
|
+
/**
|
|
6584
6692
|
Facet that provides additional DOM attributes for the editor's
|
|
6585
6693
|
editable DOM element.
|
|
6586
6694
|
*/
|
|
@@ -7007,7 +7115,7 @@ function measureRange(view, range) {
|
|
|
7007
7115
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
7008
7116
|
}
|
|
7009
7117
|
function piece(left, top, right, bottom) {
|
|
7010
|
-
return new Piece(left - base.left, top - base.top
|
|
7118
|
+
return new Piece(left - base.left, top - base.top - 0.01 /* Epsilon */, right - left, bottom - top + 0.01 /* Epsilon */, "cm-selectionBackground");
|
|
7011
7119
|
}
|
|
7012
7120
|
function pieces({ top, bottom, horizontal }) {
|
|
7013
7121
|
let pieces = [];
|
package/dist/index.d.ts
CHANGED
|
@@ -802,7 +802,7 @@ declare class EditorView {
|
|
|
802
802
|
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
803
803
|
queries.
|
|
804
804
|
|
|
805
|
-
*Deprecated: use `
|
|
805
|
+
*Deprecated: use `elementAtHeight` instead.*
|
|
806
806
|
*/
|
|
807
807
|
blockAtHeight(height: number, docTop?: number): BlockInfo;
|
|
808
808
|
/**
|
|
@@ -1156,6 +1156,13 @@ declare class EditorView {
|
|
|
1156
1156
|
dark?: boolean;
|
|
1157
1157
|
}): Extension;
|
|
1158
1158
|
/**
|
|
1159
|
+
This facet records whether a dark theme is active. The extension
|
|
1160
|
+
returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
|
|
1161
|
+
includes an instance of this when the `dark` option is set to
|
|
1162
|
+
true.
|
|
1163
|
+
*/
|
|
1164
|
+
static darkTheme: Facet<boolean, boolean>;
|
|
1165
|
+
/**
|
|
1159
1166
|
Create an extension that adds styles to the base theme. Like
|
|
1160
1167
|
with [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme), use `&` to indicate the
|
|
1161
1168
|
place of the editor wrapper element when directly targeting
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection,
|
|
1
|
+
import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection, EditorState, CharCategory, Transaction, Prec, combineConfig, StateField } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
3
|
import { RangeSet, RangeValue, RangeSetBuilder } from '@codemirror/rangeset';
|
|
4
4
|
export { Range } from '@codemirror/rangeset';
|
|
@@ -599,9 +599,8 @@ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
|
599
599
|
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
600
600
|
}
|
|
601
601
|
|
|
602
|
-
let
|
|
603
|
-
|
|
604
|
-
: [{ userAgent: "", vendor: "", platform: "" }, { documentElement: { style: {} } }];
|
|
602
|
+
let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
|
603
|
+
let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
|
605
604
|
const ie_edge = /*@__PURE__*//Edge\/(\d+)/.exec(nav.userAgent);
|
|
606
605
|
const ie_upto10 = /*@__PURE__*//MSIE \d/.test(nav.userAgent);
|
|
607
606
|
const ie_11up = /*@__PURE__*//Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
|
|
@@ -1127,8 +1126,8 @@ class Decoration extends RangeValue {
|
|
|
1127
1126
|
static replace(spec) {
|
|
1128
1127
|
let block = !!spec.block;
|
|
1129
1128
|
let { start, end } = getInclusive(spec, block);
|
|
1130
|
-
let startSide =
|
|
1131
|
-
let endSide =
|
|
1129
|
+
let startSide = (start ? (block ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 400000000 /* NonIncStart */) - 1;
|
|
1130
|
+
let endSide = (end ? (block ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -500000000 /* NonIncEnd */) + 1;
|
|
1132
1131
|
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1133
1132
|
}
|
|
1134
1133
|
/**
|
|
@@ -1233,7 +1232,7 @@ function widgetsEq(a, b) {
|
|
|
1233
1232
|
}
|
|
1234
1233
|
function addRange(from, to, ranges, margin = 0) {
|
|
1235
1234
|
let last = ranges.length - 1;
|
|
1236
|
-
if (last >= 0 && ranges[last] + margin
|
|
1235
|
+
if (last >= 0 && ranges[last] + margin >= from)
|
|
1237
1236
|
ranges[last] = Math.max(ranges[last], to);
|
|
1238
1237
|
else
|
|
1239
1238
|
ranges.push(from, to);
|
|
@@ -1307,7 +1306,7 @@ class LineView extends ContentView {
|
|
|
1307
1306
|
if (attrs)
|
|
1308
1307
|
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1309
1308
|
if (cls)
|
|
1310
|
-
this.attrs = combineAttrs(
|
|
1309
|
+
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1311
1310
|
}
|
|
1312
1311
|
domAtPos(pos) {
|
|
1313
1312
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
@@ -1514,7 +1513,7 @@ class ContentBuilder {
|
|
|
1514
1513
|
}
|
|
1515
1514
|
}
|
|
1516
1515
|
let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */);
|
|
1517
|
-
this.flushBuffer(active);
|
|
1516
|
+
this.flushBuffer(active.slice(0, openStart));
|
|
1518
1517
|
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1519
1518
|
this.atCursorPos = true;
|
|
1520
1519
|
this.textOff += take;
|
|
@@ -1573,11 +1572,13 @@ class ContentBuilder {
|
|
|
1573
1572
|
this.openStart = openStart;
|
|
1574
1573
|
}
|
|
1575
1574
|
filterPoint(from, to, value, index) {
|
|
1576
|
-
if (index
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1575
|
+
if (index < this.disallowBlockEffectsBelow && value instanceof PointDecoration) {
|
|
1576
|
+
if (value.block)
|
|
1577
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1578
|
+
if (to > this.doc.lineAt(this.pos).to)
|
|
1579
|
+
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1580
|
+
}
|
|
1581
|
+
return true;
|
|
1581
1582
|
}
|
|
1582
1583
|
static build(text, from, to, decorations, pluginDecorationLength) {
|
|
1583
1584
|
let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
|
|
@@ -2300,12 +2301,18 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
2300
2301
|
return EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
|
|
2301
2302
|
}
|
|
2302
2303
|
|
|
2304
|
+
const LineBreakPlaceholder = "\uffff";
|
|
2303
2305
|
class DOMReader {
|
|
2304
|
-
constructor(points,
|
|
2306
|
+
constructor(points, state) {
|
|
2305
2307
|
this.points = points;
|
|
2306
|
-
this.view = view;
|
|
2307
2308
|
this.text = "";
|
|
2308
|
-
this.
|
|
2309
|
+
this.lineSeparator = state.facet(EditorState.lineSeparator);
|
|
2310
|
+
}
|
|
2311
|
+
append(text) {
|
|
2312
|
+
this.text += text;
|
|
2313
|
+
}
|
|
2314
|
+
lineBreak() {
|
|
2315
|
+
this.text += LineBreakPlaceholder;
|
|
2309
2316
|
}
|
|
2310
2317
|
readRange(start, end) {
|
|
2311
2318
|
if (!start)
|
|
@@ -2321,33 +2328,61 @@ class DOMReader {
|
|
|
2321
2328
|
if (view && nextView ? view.breakAfter :
|
|
2322
2329
|
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
2323
2330
|
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
|
|
2324
|
-
this.
|
|
2331
|
+
this.lineBreak();
|
|
2325
2332
|
cur = next;
|
|
2326
2333
|
}
|
|
2327
2334
|
this.findPointBefore(parent, end);
|
|
2328
2335
|
return this;
|
|
2329
2336
|
}
|
|
2337
|
+
readTextNode(node) {
|
|
2338
|
+
let text = node.nodeValue;
|
|
2339
|
+
for (let point of this.points)
|
|
2340
|
+
if (point.node == node)
|
|
2341
|
+
point.pos = this.text.length + Math.min(point.offset, text.length);
|
|
2342
|
+
for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
|
2343
|
+
let nextBreak = -1, breakSize = 1, m;
|
|
2344
|
+
if (this.lineSeparator) {
|
|
2345
|
+
nextBreak = text.indexOf(this.lineSeparator, off);
|
|
2346
|
+
breakSize = this.lineSeparator.length;
|
|
2347
|
+
}
|
|
2348
|
+
else if (m = re.exec(text)) {
|
|
2349
|
+
nextBreak = m.index;
|
|
2350
|
+
breakSize = m[0].length;
|
|
2351
|
+
}
|
|
2352
|
+
this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
|
2353
|
+
if (nextBreak < 0)
|
|
2354
|
+
break;
|
|
2355
|
+
this.lineBreak();
|
|
2356
|
+
if (breakSize > 1)
|
|
2357
|
+
for (let point of this.points)
|
|
2358
|
+
if (point.node == node && point.pos > this.text.length)
|
|
2359
|
+
point.pos -= breakSize - 1;
|
|
2360
|
+
off = nextBreak + breakSize;
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2330
2363
|
readNode(node) {
|
|
2331
2364
|
if (node.cmIgnore)
|
|
2332
2365
|
return;
|
|
2333
2366
|
let view = ContentView.get(node);
|
|
2334
2367
|
let fromView = view && view.overrideDOMText;
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2368
|
+
if (fromView != null) {
|
|
2369
|
+
this.findPointInside(node);
|
|
2370
|
+
for (let i = fromView.iter(); !i.next().done;) {
|
|
2371
|
+
if (i.lineBreak)
|
|
2372
|
+
this.lineBreak();
|
|
2373
|
+
else
|
|
2374
|
+
this.append(i.value);
|
|
2375
|
+
}
|
|
2376
|
+
}
|
|
2377
|
+
else if (node.nodeType == 3) {
|
|
2378
|
+
this.readTextNode(node);
|
|
2379
|
+
}
|
|
2380
|
+
else if (node.nodeName == "BR") {
|
|
2381
|
+
if (node.nextSibling)
|
|
2382
|
+
this.lineBreak();
|
|
2383
|
+
}
|
|
2384
|
+
else if (node.nodeType == 1) {
|
|
2343
2385
|
this.readRange(node.firstChild, null);
|
|
2344
|
-
if (text != null) {
|
|
2345
|
-
this.findPointIn(node, text.length);
|
|
2346
|
-
this.text += text;
|
|
2347
|
-
// Chrome inserts two newlines when pressing shift-enter at the
|
|
2348
|
-
// end of a line. This drops one of those.
|
|
2349
|
-
if (browser.chrome && this.view.inputState.lastKeyCode == 13 && !node.nextSibling && /\n\n$/.test(this.text))
|
|
2350
|
-
this.text = this.text.slice(0, -1);
|
|
2351
2386
|
}
|
|
2352
2387
|
}
|
|
2353
2388
|
findPointBefore(node, next) {
|
|
@@ -2355,10 +2390,10 @@ class DOMReader {
|
|
|
2355
2390
|
if (point.node == node && node.childNodes[point.offset] == next)
|
|
2356
2391
|
point.pos = this.text.length;
|
|
2357
2392
|
}
|
|
2358
|
-
|
|
2393
|
+
findPointInside(node) {
|
|
2359
2394
|
for (let point of this.points)
|
|
2360
|
-
if (point.node == node)
|
|
2361
|
-
point.pos = this.text.length
|
|
2395
|
+
if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
|
2396
|
+
point.pos = this.text.length;
|
|
2362
2397
|
}
|
|
2363
2398
|
}
|
|
2364
2399
|
function isBlockElement(node) {
|
|
@@ -2763,51 +2798,57 @@ class BlockGapWidget extends WidgetType {
|
|
|
2763
2798
|
}
|
|
2764
2799
|
get estimatedHeight() { return this.height; }
|
|
2765
2800
|
}
|
|
2766
|
-
function
|
|
2801
|
+
function compositionSurroundingNode(view) {
|
|
2767
2802
|
let sel = view.observer.selectionRange;
|
|
2768
2803
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
2769
2804
|
if (!textNode)
|
|
2770
|
-
return
|
|
2805
|
+
return null;
|
|
2771
2806
|
let cView = view.docView.nearest(textNode);
|
|
2772
2807
|
if (!cView)
|
|
2773
|
-
return
|
|
2774
|
-
let from, to, topNode = textNode;
|
|
2808
|
+
return null;
|
|
2775
2809
|
if (cView instanceof LineView) {
|
|
2810
|
+
let topNode = textNode;
|
|
2776
2811
|
while (topNode.parentNode != cView.dom)
|
|
2777
2812
|
topNode = topNode.parentNode;
|
|
2778
2813
|
let prev = topNode.previousSibling;
|
|
2779
2814
|
while (prev && !ContentView.get(prev))
|
|
2780
2815
|
prev = prev.previousSibling;
|
|
2781
|
-
|
|
2816
|
+
let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
|
|
2817
|
+
return { from: pos, to: pos, node: topNode, text: textNode };
|
|
2782
2818
|
}
|
|
2783
2819
|
else {
|
|
2784
2820
|
for (;;) {
|
|
2785
2821
|
let { parent } = cView;
|
|
2786
2822
|
if (!parent)
|
|
2787
|
-
return
|
|
2823
|
+
return null;
|
|
2788
2824
|
if (parent instanceof LineView)
|
|
2789
2825
|
break;
|
|
2790
2826
|
cView = parent;
|
|
2791
2827
|
}
|
|
2792
|
-
from = cView.posAtStart;
|
|
2793
|
-
|
|
2794
|
-
topNode = cView.dom;
|
|
2828
|
+
let from = cView.posAtStart;
|
|
2829
|
+
return { from, to: from + cView.length, node: cView.dom, text: textNode };
|
|
2795
2830
|
}
|
|
2831
|
+
}
|
|
2832
|
+
function computeCompositionDeco(view, changes) {
|
|
2833
|
+
let surrounding = compositionSurroundingNode(view);
|
|
2834
|
+
if (!surrounding)
|
|
2835
|
+
return Decoration.none;
|
|
2836
|
+
let { from, to, node, text: textNode } = surrounding;
|
|
2796
2837
|
let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1));
|
|
2797
|
-
let { state } = view, text =
|
|
2798
|
-
new DOMReader([],
|
|
2838
|
+
let { state } = view, text = node.nodeType == 3 ? node.nodeValue :
|
|
2839
|
+
new DOMReader([], state).readRange(node.firstChild, null).text;
|
|
2799
2840
|
if (newTo - newFrom < text.length) {
|
|
2800
|
-
if (state.
|
|
2841
|
+
if (state.doc.sliceString(newFrom, Math.min(state.doc.length, newFrom + text.length), LineBreakPlaceholder) == text)
|
|
2801
2842
|
newTo = newFrom + text.length;
|
|
2802
|
-
else if (state.
|
|
2843
|
+
else if (state.doc.sliceString(Math.max(0, newTo - text.length), newTo, LineBreakPlaceholder) == text)
|
|
2803
2844
|
newFrom = newTo - text.length;
|
|
2804
2845
|
else
|
|
2805
2846
|
return Decoration.none;
|
|
2806
2847
|
}
|
|
2807
|
-
else if (state.
|
|
2848
|
+
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2808
2849
|
return Decoration.none;
|
|
2809
2850
|
}
|
|
2810
|
-
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(
|
|
2851
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode) }).range(newFrom, newTo));
|
|
2811
2852
|
}
|
|
2812
2853
|
class CompositionWidget extends WidgetType {
|
|
2813
2854
|
constructor(top, text) {
|
|
@@ -3000,7 +3041,11 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
3000
3041
|
var _a;
|
|
3001
3042
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
3002
3043
|
let block, { docHeight } = view.viewState;
|
|
3003
|
-
let yOffset =
|
|
3044
|
+
let yOffset = y - docTop;
|
|
3045
|
+
if (yOffset < 0)
|
|
3046
|
+
return 0;
|
|
3047
|
+
if (yOffset > docHeight)
|
|
3048
|
+
return view.state.doc.length;
|
|
3004
3049
|
// Scan for a text block near the queried y position
|
|
3005
3050
|
for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
|
|
3006
3051
|
block = view.elementAtHeight(yOffset);
|
|
@@ -3140,7 +3185,7 @@ function byGroup(view, pos, start) {
|
|
|
3140
3185
|
function moveVertically(view, start, forward, distance) {
|
|
3141
3186
|
let startPos = start.head, dir = forward ? 1 : -1;
|
|
3142
3187
|
if (startPos == (forward ? view.state.doc.length : 0))
|
|
3143
|
-
return EditorSelection.cursor(startPos);
|
|
3188
|
+
return EditorSelection.cursor(startPos, start.assoc);
|
|
3144
3189
|
let goal = start.goalColumn, startY;
|
|
3145
3190
|
let rect = view.contentDOM.getBoundingClientRect();
|
|
3146
3191
|
let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
|
|
@@ -3161,7 +3206,7 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3161
3206
|
let curY = startY + (dist + extra) * dir;
|
|
3162
3207
|
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
3163
3208
|
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
|
3164
|
-
return EditorSelection.cursor(pos,
|
|
3209
|
+
return EditorSelection.cursor(pos, start.assoc, undefined, goal);
|
|
3165
3210
|
}
|
|
3166
3211
|
}
|
|
3167
3212
|
function skipAtoms(view, oldPos, pos) {
|
|
@@ -4589,6 +4634,7 @@ class ViewState {
|
|
|
4589
4634
|
this.contentDOMWidth = 0;
|
|
4590
4635
|
this.contentDOMHeight = 0;
|
|
4591
4636
|
this.editorHeight = 0;
|
|
4637
|
+
this.editorWidth = 0;
|
|
4592
4638
|
this.heightOracle = new HeightOracle;
|
|
4593
4639
|
// See VP.MaxDOMHeight
|
|
4594
4640
|
this.scaler = IdScaler;
|
|
@@ -4671,6 +4717,12 @@ class ViewState {
|
|
|
4671
4717
|
let refresh = this.heightOracle.mustRefreshForStyle(whiteSpace, direction);
|
|
4672
4718
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4673
4719
|
let result = 0, bias = 0;
|
|
4720
|
+
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
4721
|
+
if (oracle.lineWrapping)
|
|
4722
|
+
measureContent = true;
|
|
4723
|
+
this.editorWidth = view.scrollDOM.clientWidth;
|
|
4724
|
+
result |= 8 /* Geometry */;
|
|
4725
|
+
}
|
|
4674
4726
|
if (measureContent) {
|
|
4675
4727
|
this.mustMeasureContent = false;
|
|
4676
4728
|
this.contentDOMHeight = dom.clientHeight;
|
|
@@ -4683,7 +4735,8 @@ class ViewState {
|
|
|
4683
4735
|
}
|
|
4684
4736
|
}
|
|
4685
4737
|
// Pixel viewport
|
|
4686
|
-
let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
|
|
4738
|
+
let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 }
|
|
4739
|
+
: visiblePixelRange(dom, this.paddingTop);
|
|
4687
4740
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
4688
4741
|
this.pixelViewport = pixelViewport;
|
|
4689
4742
|
let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
|
@@ -4694,11 +4747,16 @@ class ViewState {
|
|
|
4694
4747
|
}
|
|
4695
4748
|
if (!this.inView)
|
|
4696
4749
|
return 0;
|
|
4750
|
+
let contentWidth = dom.clientWidth;
|
|
4751
|
+
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4752
|
+
this.contentDOMWidth = contentWidth;
|
|
4753
|
+
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4754
|
+
result |= 8 /* Geometry */;
|
|
4755
|
+
}
|
|
4697
4756
|
if (measureContent) {
|
|
4698
4757
|
let lineHeights = view.docView.measureVisibleLineHeights();
|
|
4699
4758
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
4700
4759
|
refresh = true;
|
|
4701
|
-
let contentWidth = dom.clientWidth;
|
|
4702
4760
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4703
4761
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4704
4762
|
refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
@@ -4707,14 +4765,6 @@ class ViewState {
|
|
|
4707
4765
|
result |= 8 /* Geometry */;
|
|
4708
4766
|
}
|
|
4709
4767
|
}
|
|
4710
|
-
if (this.contentDOMWidth != contentWidth) {
|
|
4711
|
-
this.contentDOMWidth = contentWidth;
|
|
4712
|
-
result |= 8 /* Geometry */;
|
|
4713
|
-
}
|
|
4714
|
-
if (this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4715
|
-
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4716
|
-
result |= 8 /* Geometry */;
|
|
4717
|
-
}
|
|
4718
4768
|
if (dTop > 0 && dBottom > 0)
|
|
4719
4769
|
bias = Math.max(dTop, dBottom);
|
|
4720
4770
|
else if (dTop < 0 && dBottom < 0)
|
|
@@ -4755,8 +4805,9 @@ class ViewState {
|
|
|
4755
4805
|
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to);
|
|
4756
4806
|
// If scrollTarget is given, make sure the viewport includes that position
|
|
4757
4807
|
if (scrollTarget) {
|
|
4758
|
-
let { head } = scrollTarget.range
|
|
4808
|
+
let { head } = scrollTarget.range;
|
|
4759
4809
|
if (head < viewport.from || head > viewport.to) {
|
|
4810
|
+
let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
|
|
4760
4811
|
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4761
4812
|
if (scrollTarget.y == "center")
|
|
4762
4813
|
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
@@ -5556,9 +5607,8 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5556
5607
|
return;
|
|
5557
5608
|
let { from, to } = bounds;
|
|
5558
5609
|
let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
|
5559
|
-
let reader = new DOMReader(selPoints, view);
|
|
5610
|
+
let reader = new DOMReader(selPoints, view.state);
|
|
5560
5611
|
reader.readRange(bounds.startDOM, bounds.endDOM);
|
|
5561
|
-
newSel = selectionFromPoints(selPoints, from);
|
|
5562
5612
|
let preferredPos = sel.from, preferredSide = null;
|
|
5563
5613
|
// Prefer anchoring to end when Backspace is pressed (or, on
|
|
5564
5614
|
// Android, when something was deleted)
|
|
@@ -5567,10 +5617,29 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5567
5617
|
preferredPos = sel.to;
|
|
5568
5618
|
preferredSide = "end";
|
|
5569
5619
|
}
|
|
5570
|
-
let diff = findDiff(view.state.
|
|
5571
|
-
if (diff)
|
|
5620
|
+
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5621
|
+
if (diff) {
|
|
5622
|
+
let orig = diff;
|
|
5623
|
+
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5624
|
+
// end of a line. This drops one of those.
|
|
5625
|
+
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5626
|
+
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5627
|
+
diff.toB--;
|
|
5628
|
+
// Strip leading and trailing zero-width spaces from the inserted
|
|
5629
|
+
// content, to work around widget buffers being moved into text
|
|
5630
|
+
// nodes by the browser.
|
|
5631
|
+
while (diff.from < diff.toB && reader.text[diff.from] == "\u200b") {
|
|
5632
|
+
diff = { from: diff.from + 1, toA: diff.toA, toB: diff.toB };
|
|
5633
|
+
selPoints.forEach(p => p.pos -= p.pos > orig.from ? 1 : 0);
|
|
5634
|
+
}
|
|
5635
|
+
while (diff.toB > diff.from && reader.text[diff.toB - 1] == "\u200b") {
|
|
5636
|
+
diff = { from: diff.from, toA: diff.toA, toB: diff.toB - 1 };
|
|
5637
|
+
selPoints.forEach(p => p.pos -= p.pos > orig.toB ? 1 : 0);
|
|
5638
|
+
}
|
|
5572
5639
|
change = { from: from + diff.from, to: from + diff.toA,
|
|
5573
|
-
insert:
|
|
5640
|
+
insert: Text$1.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5641
|
+
}
|
|
5642
|
+
newSel = selectionFromPoints(selPoints, from);
|
|
5574
5643
|
}
|
|
5575
5644
|
else if (view.hasFocus || !view.state.facet(editable)) {
|
|
5576
5645
|
let domSel = view.observer.selectionRange;
|
|
@@ -5627,19 +5696,47 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5627
5696
|
view.inputState.composing++;
|
|
5628
5697
|
let tr;
|
|
5629
5698
|
if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
|
5630
|
-
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length)
|
|
5699
|
+
(!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
|
5700
|
+
view.inputState.composing < 0) {
|
|
5631
5701
|
let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
|
5632
5702
|
let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
|
5633
|
-
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) +
|
|
5634
|
-
after));
|
|
5703
|
+
tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
|
5635
5704
|
}
|
|
5636
5705
|
else {
|
|
5637
5706
|
let changes = startState.changes(change);
|
|
5638
|
-
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5642
|
-
|
|
5707
|
+
let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
|
5708
|
+
? newSel.main : undefined;
|
|
5709
|
+
// Try to apply a composition change to all cursors
|
|
5710
|
+
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5711
|
+
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
5712
|
+
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
5713
|
+
let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
|
5714
|
+
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
5715
|
+
tr = startState.changeByRange(range => {
|
|
5716
|
+
if (range.from == sel.from && range.to == sel.to)
|
|
5717
|
+
return { changes, range: mainSel || range.map(changes) };
|
|
5718
|
+
let to = range.to - offset, from = to - replaced.length;
|
|
5719
|
+
if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
|
5720
|
+
// Unfortunately, there's no way to make multiple
|
|
5721
|
+
// changes in the same node work without aborting
|
|
5722
|
+
// composition, so cursors in the composition range are
|
|
5723
|
+
// ignored.
|
|
5724
|
+
compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
|
5725
|
+
return { range };
|
|
5726
|
+
let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
|
5727
|
+
return {
|
|
5728
|
+
changes: rangeChanges,
|
|
5729
|
+
range: !mainSel ? range.map(rangeChanges) :
|
|
5730
|
+
EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
|
5731
|
+
};
|
|
5732
|
+
});
|
|
5733
|
+
}
|
|
5734
|
+
else {
|
|
5735
|
+
tr = {
|
|
5736
|
+
changes,
|
|
5737
|
+
selection: mainSel && startState.selection.replaceRange(mainSel)
|
|
5738
|
+
};
|
|
5739
|
+
}
|
|
5643
5740
|
}
|
|
5644
5741
|
let userEvent = "input.type";
|
|
5645
5742
|
if (view.composing) {
|
|
@@ -5854,7 +5951,7 @@ class EditorView {
|
|
|
5854
5951
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
5855
5952
|
return this.setState(state);
|
|
5856
5953
|
update = new ViewUpdate(this, state, transactions);
|
|
5857
|
-
let scrollTarget =
|
|
5954
|
+
let scrollTarget = this.viewState.scrollTarget;
|
|
5858
5955
|
try {
|
|
5859
5956
|
this.updateState = 2 /* Updating */;
|
|
5860
5957
|
for (let tr of transactions) {
|
|
@@ -5910,6 +6007,7 @@ class EditorView {
|
|
|
5910
6007
|
return;
|
|
5911
6008
|
}
|
|
5912
6009
|
this.updateState = 2 /* Updating */;
|
|
6010
|
+
let hadFocus = this.hasFocus;
|
|
5913
6011
|
try {
|
|
5914
6012
|
for (let plugin of this.plugins)
|
|
5915
6013
|
plugin.destroy(this);
|
|
@@ -5927,6 +6025,8 @@ class EditorView {
|
|
|
5927
6025
|
finally {
|
|
5928
6026
|
this.updateState = 0 /* Idle */;
|
|
5929
6027
|
}
|
|
6028
|
+
if (hadFocus)
|
|
6029
|
+
this.focus();
|
|
5930
6030
|
this.requestMeasure();
|
|
5931
6031
|
}
|
|
5932
6032
|
updatePlugins(update) {
|
|
@@ -5996,7 +6096,7 @@ class EditorView {
|
|
|
5996
6096
|
return BadMeasure;
|
|
5997
6097
|
}
|
|
5998
6098
|
});
|
|
5999
|
-
let update = new ViewUpdate(this, this.state), redrawn = false;
|
|
6099
|
+
let update = new ViewUpdate(this, this.state), redrawn = false, scrolled = false;
|
|
6000
6100
|
update.flags |= changed;
|
|
6001
6101
|
if (!updated)
|
|
6002
6102
|
updated = update;
|
|
@@ -6023,11 +6123,12 @@ class EditorView {
|
|
|
6023
6123
|
if (this.viewState.scrollTarget) {
|
|
6024
6124
|
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
6025
6125
|
this.viewState.scrollTarget = null;
|
|
6126
|
+
scrolled = true;
|
|
6026
6127
|
}
|
|
6027
6128
|
if (redrawn)
|
|
6028
6129
|
this.docView.updateSelection(true);
|
|
6029
6130
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to &&
|
|
6030
|
-
this.measureRequests.length == 0)
|
|
6131
|
+
!scrolled && this.measureRequests.length == 0)
|
|
6031
6132
|
break;
|
|
6032
6133
|
}
|
|
6033
6134
|
}
|
|
@@ -6163,7 +6264,7 @@ class EditorView {
|
|
|
6163
6264
|
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
6164
6265
|
queries.
|
|
6165
6266
|
|
|
6166
|
-
*Deprecated: use `
|
|
6267
|
+
*Deprecated: use `elementAtHeight` instead.*
|
|
6167
6268
|
*/
|
|
6168
6269
|
blockAtHeight(height, docTop) {
|
|
6169
6270
|
let top = ensureTop(docTop, this);
|
|
@@ -6575,6 +6676,13 @@ mechanism for providing decorations.
|
|
|
6575
6676
|
*/
|
|
6576
6677
|
EditorView.decorations = decorations;
|
|
6577
6678
|
/**
|
|
6679
|
+
This facet records whether a dark theme is active. The extension
|
|
6680
|
+
returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
|
|
6681
|
+
includes an instance of this when the `dark` option is set to
|
|
6682
|
+
true.
|
|
6683
|
+
*/
|
|
6684
|
+
EditorView.darkTheme = darkTheme;
|
|
6685
|
+
/**
|
|
6578
6686
|
Facet that provides additional DOM attributes for the editor's
|
|
6579
6687
|
editable DOM element.
|
|
6580
6688
|
*/
|
|
@@ -7001,7 +7109,7 @@ function measureRange(view, range) {
|
|
|
7001
7109
|
return pieces(top).concat(between).concat(pieces(bottom));
|
|
7002
7110
|
}
|
|
7003
7111
|
function piece(left, top, right, bottom) {
|
|
7004
|
-
return new Piece(left - base.left, top - base.top
|
|
7112
|
+
return new Piece(left - base.left, top - base.top - 0.01 /* Epsilon */, right - left, bottom - top + 0.01 /* Epsilon */, "cm-selectionBackground");
|
|
7005
7113
|
}
|
|
7006
7114
|
function pieces({ top, bottom, horizontal }) {
|
|
7007
7115
|
let pieces = [];
|