@codemirror/view 0.19.7 → 0.19.11
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 +382 -145
- package/dist/index.d.ts +16 -5
- package/dist/index.js +383 -146
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,12 +1,22 @@
|
|
|
1
1
|
import { MapMode, Text as Text$1, Facet, StateEffect, ChangeSet, EditorSelection, CharCategory, EditorState, Transaction, Prec, combineConfig } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
|
-
import {
|
|
3
|
+
import { RangeSet, RangeValue, RangeSetBuilder } from '@codemirror/rangeset';
|
|
4
4
|
export { Range } from '@codemirror/rangeset';
|
|
5
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) {
|
|
9
|
-
|
|
9
|
+
let target;
|
|
10
|
+
// Browsers differ on whether shadow roots have a getSelection
|
|
11
|
+
// method. If it exists, use that, otherwise, call it on the
|
|
12
|
+
// document.
|
|
13
|
+
if (root.nodeType == 11) { // Shadow root
|
|
14
|
+
target = root.getSelection ? root : root.ownerDocument;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
target = root;
|
|
18
|
+
}
|
|
19
|
+
return target.getSelection();
|
|
10
20
|
}
|
|
11
21
|
function contains(dom, node) {
|
|
12
22
|
return node ? dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
@@ -89,9 +99,9 @@ function windowRect(win) {
|
|
|
89
99
|
top: 0, bottom: win.innerHeight };
|
|
90
100
|
}
|
|
91
101
|
const ScrollSpace = 5;
|
|
92
|
-
function scrollRectIntoView(dom, rect, side) {
|
|
102
|
+
function scrollRectIntoView(dom, rect, side, center) {
|
|
93
103
|
let doc = dom.ownerDocument, win = doc.defaultView;
|
|
94
|
-
for (let cur = dom
|
|
104
|
+
for (let cur = dom; cur;) {
|
|
95
105
|
if (cur.nodeType == 1) { // Element
|
|
96
106
|
let bounding, top = cur == doc.body;
|
|
97
107
|
if (top) {
|
|
@@ -108,7 +118,20 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
108
118
|
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
109
119
|
}
|
|
110
120
|
let moveX = 0, moveY = 0;
|
|
111
|
-
if (
|
|
121
|
+
if (center) {
|
|
122
|
+
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
123
|
+
let targetTop;
|
|
124
|
+
if (rectHeight <= boundingHeight)
|
|
125
|
+
targetTop = rect.top + rectHeight / 2 - boundingHeight / 2;
|
|
126
|
+
else if (side < 0)
|
|
127
|
+
targetTop = rect.top - ScrollSpace;
|
|
128
|
+
else
|
|
129
|
+
targetTop = rect.bottom + ScrollSpace - boundingHeight;
|
|
130
|
+
moveY = targetTop - bounding.top;
|
|
131
|
+
if (Math.abs(moveY) <= 1)
|
|
132
|
+
moveY = 0;
|
|
133
|
+
}
|
|
134
|
+
else if (rect.top < bounding.top) {
|
|
112
135
|
moveY = -(bounding.top - rect.top + ScrollSpace);
|
|
113
136
|
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
114
137
|
moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
|
|
@@ -150,6 +173,7 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
150
173
|
if (top)
|
|
151
174
|
break;
|
|
152
175
|
cur = cur.assignedSlot || cur.parentNode;
|
|
176
|
+
center = false;
|
|
153
177
|
}
|
|
154
178
|
else if (cur.nodeType == 11) { // A shadow root
|
|
155
179
|
cur = cur.host;
|
|
@@ -238,6 +262,14 @@ function contentEditablePlainTextSupported() {
|
|
|
238
262
|
}
|
|
239
263
|
return _plainTextSupported;
|
|
240
264
|
}
|
|
265
|
+
function getRoot(node) {
|
|
266
|
+
while (node) {
|
|
267
|
+
node = node.assignedSlot || node.parentNode;
|
|
268
|
+
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
|
269
|
+
return node;
|
|
270
|
+
}
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
241
273
|
|
|
242
274
|
class DOMPos {
|
|
243
275
|
constructor(node, offset, precise = true) {
|
|
@@ -435,6 +467,7 @@ class ContentView {
|
|
|
435
467
|
(this.breakAfter ? "#" : "");
|
|
436
468
|
}
|
|
437
469
|
static get(node) { return node.cmView; }
|
|
470
|
+
get isEditable() { return true; }
|
|
438
471
|
}
|
|
439
472
|
ContentView.prototype.breakAfter = 0;
|
|
440
473
|
// Remove a DOM node and return its next sibling.
|
|
@@ -482,15 +515,18 @@ const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
|
|
|
482
515
|
const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
|
|
483
516
|
const webkit = "webkitFontSmoothing" in doc.documentElement.style;
|
|
484
517
|
const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
|
|
518
|
+
const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
|
|
485
519
|
var browser = {
|
|
486
|
-
mac: /*@__PURE__*//Mac/.test(nav.platform),
|
|
520
|
+
mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
|
|
521
|
+
windows: /*@__PURE__*//Win/.test(nav.platform),
|
|
522
|
+
linux: /*@__PURE__*//Linux|X11/.test(nav.platform),
|
|
487
523
|
ie,
|
|
488
524
|
ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
|
|
489
525
|
gecko,
|
|
490
526
|
gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
|
491
527
|
chrome: !!chrome,
|
|
492
528
|
chrome_version: chrome ? +chrome[1] : 0,
|
|
493
|
-
ios
|
|
529
|
+
ios,
|
|
494
530
|
android: /*@__PURE__*//Android\b/.test(nav.userAgent),
|
|
495
531
|
webkit,
|
|
496
532
|
safari,
|
|
@@ -712,6 +748,7 @@ class WidgetView extends InlineView {
|
|
|
712
748
|
}
|
|
713
749
|
return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0);
|
|
714
750
|
}
|
|
751
|
+
get isEditable() { return false; }
|
|
715
752
|
}
|
|
716
753
|
class CompositionView extends WidgetView {
|
|
717
754
|
domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
|
|
@@ -723,6 +760,38 @@ class CompositionView extends WidgetView {
|
|
|
723
760
|
ignoreMutation() { return false; }
|
|
724
761
|
get overrideDOMText() { return null; }
|
|
725
762
|
coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
|
|
763
|
+
get isEditable() { return true; }
|
|
764
|
+
}
|
|
765
|
+
// These are drawn around uneditable widgets to avoid a number of
|
|
766
|
+
// browser bugs that show up when the cursor is directly next to
|
|
767
|
+
// uneditable inline content.
|
|
768
|
+
class WidgetBufferView extends InlineView {
|
|
769
|
+
constructor(side) {
|
|
770
|
+
super();
|
|
771
|
+
this.side = side;
|
|
772
|
+
}
|
|
773
|
+
get length() { return 0; }
|
|
774
|
+
merge() { return false; }
|
|
775
|
+
become(other) {
|
|
776
|
+
return other instanceof WidgetBufferView && other.side == this.side;
|
|
777
|
+
}
|
|
778
|
+
slice() { return new WidgetBufferView(this.side); }
|
|
779
|
+
sync() {
|
|
780
|
+
if (!this.dom)
|
|
781
|
+
this.setDOM(document.createTextNode("\u200b"));
|
|
782
|
+
else if (this.dirty && this.dom.nodeValue != "\u200b")
|
|
783
|
+
this.dom.nodeValue = "\u200b";
|
|
784
|
+
}
|
|
785
|
+
getSide() { return this.side; }
|
|
786
|
+
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
787
|
+
domBoundsAround() { return null; }
|
|
788
|
+
coordsAt(pos) {
|
|
789
|
+
let rects = clientRectsFor(this.dom);
|
|
790
|
+
return rects[rects.length - 1];
|
|
791
|
+
}
|
|
792
|
+
get overrideDOMText() {
|
|
793
|
+
return Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]);
|
|
794
|
+
}
|
|
726
795
|
}
|
|
727
796
|
function mergeInlineChildren(parent, from, to, elts, openStart, openEnd) {
|
|
728
797
|
let cur = parent.childCursor();
|
|
@@ -1217,14 +1286,17 @@ class LineView extends ContentView {
|
|
|
1217
1286
|
}
|
|
1218
1287
|
// Only called when building a line view in ContentBuilder
|
|
1219
1288
|
addLineDeco(deco) {
|
|
1220
|
-
let attrs = deco.spec.attributes;
|
|
1289
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1221
1290
|
if (attrs)
|
|
1222
1291
|
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1292
|
+
if (cls)
|
|
1293
|
+
this.attrs = combineAttrs(attrs, { class: cls });
|
|
1223
1294
|
}
|
|
1224
1295
|
domAtPos(pos) {
|
|
1225
1296
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
1226
1297
|
}
|
|
1227
1298
|
sync(track) {
|
|
1299
|
+
var _a;
|
|
1228
1300
|
if (!this.dom || (this.dirty & 4 /* Attrs */)) {
|
|
1229
1301
|
this.setDOM(document.createElement("div"));
|
|
1230
1302
|
this.dom.className = "cm-line";
|
|
@@ -1240,7 +1312,7 @@ class LineView extends ContentView {
|
|
|
1240
1312
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1241
1313
|
last = last.lastChild;
|
|
1242
1314
|
if (!last ||
|
|
1243
|
-
last.nodeName != "BR" && ContentView.get(last)
|
|
1315
|
+
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1244
1316
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1245
1317
|
let hack = document.createElement("BR");
|
|
1246
1318
|
hack.cmIgnore = true;
|
|
@@ -1339,6 +1411,9 @@ class ContentBuilder {
|
|
|
1339
1411
|
this.content = [];
|
|
1340
1412
|
this.curLine = null;
|
|
1341
1413
|
this.breakAtStart = 0;
|
|
1414
|
+
this.pendingBuffer = 0 /* No */;
|
|
1415
|
+
// Set to false directly after a widget that covers the position after it
|
|
1416
|
+
this.atCursorPos = true;
|
|
1342
1417
|
this.openStart = -1;
|
|
1343
1418
|
this.openEnd = -1;
|
|
1344
1419
|
this.text = "";
|
|
@@ -1353,23 +1428,31 @@ class ContentBuilder {
|
|
|
1353
1428
|
return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == BlockType.WidgetBefore);
|
|
1354
1429
|
}
|
|
1355
1430
|
getLine() {
|
|
1356
|
-
if (!this.curLine)
|
|
1431
|
+
if (!this.curLine) {
|
|
1357
1432
|
this.content.push(this.curLine = new LineView);
|
|
1433
|
+
this.atCursorPos = true;
|
|
1434
|
+
}
|
|
1358
1435
|
return this.curLine;
|
|
1359
1436
|
}
|
|
1360
|
-
|
|
1437
|
+
flushBuffer(active) {
|
|
1438
|
+
if (this.pendingBuffer) {
|
|
1439
|
+
this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
|
|
1440
|
+
this.pendingBuffer = 0 /* No */;
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
addBlockWidget(view) {
|
|
1444
|
+
this.flushBuffer([]);
|
|
1361
1445
|
this.curLine = null;
|
|
1362
1446
|
this.content.push(view);
|
|
1363
1447
|
}
|
|
1364
|
-
finish() {
|
|
1448
|
+
finish(openEnd) {
|
|
1449
|
+
if (!openEnd)
|
|
1450
|
+
this.flushBuffer([]);
|
|
1451
|
+
else
|
|
1452
|
+
this.pendingBuffer = 0 /* No */;
|
|
1365
1453
|
if (!this.posCovered())
|
|
1366
1454
|
this.getLine();
|
|
1367
1455
|
}
|
|
1368
|
-
wrapMarks(view, active) {
|
|
1369
|
-
for (let mark of active)
|
|
1370
|
-
view = new MarkView(mark, [view], view.length);
|
|
1371
|
-
return view;
|
|
1372
|
-
}
|
|
1373
1456
|
buildText(length, active, openStart) {
|
|
1374
1457
|
while (length > 0) {
|
|
1375
1458
|
if (this.textOff == this.text.length) {
|
|
@@ -1384,6 +1467,7 @@ class ContentBuilder {
|
|
|
1384
1467
|
this.content[this.content.length - 1].breakAfter = 1;
|
|
1385
1468
|
else
|
|
1386
1469
|
this.breakAtStart = 1;
|
|
1470
|
+
this.flushBuffer([]);
|
|
1387
1471
|
this.curLine = null;
|
|
1388
1472
|
length--;
|
|
1389
1473
|
continue;
|
|
@@ -1394,7 +1478,9 @@ class ContentBuilder {
|
|
|
1394
1478
|
}
|
|
1395
1479
|
}
|
|
1396
1480
|
let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */);
|
|
1397
|
-
this.
|
|
1481
|
+
this.flushBuffer(active);
|
|
1482
|
+
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1483
|
+
this.atCursorPos = true;
|
|
1398
1484
|
this.textOff += take;
|
|
1399
1485
|
length -= take;
|
|
1400
1486
|
openStart = 0;
|
|
@@ -1413,11 +1499,23 @@ class ContentBuilder {
|
|
|
1413
1499
|
let { type } = deco;
|
|
1414
1500
|
if (type == BlockType.WidgetAfter && !this.posCovered())
|
|
1415
1501
|
this.getLine();
|
|
1416
|
-
this.
|
|
1502
|
+
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1417
1503
|
}
|
|
1418
1504
|
else {
|
|
1419
|
-
let
|
|
1420
|
-
this.
|
|
1505
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1506
|
+
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1507
|
+
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1508
|
+
let line = this.getLine();
|
|
1509
|
+
if (this.pendingBuffer == 2 /* IfCursor */ && !cursorBefore)
|
|
1510
|
+
this.pendingBuffer = 0 /* No */;
|
|
1511
|
+
this.flushBuffer(active);
|
|
1512
|
+
if (cursorBefore) {
|
|
1513
|
+
line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
|
|
1514
|
+
openStart = active.length + Math.max(0, openStart - active.length);
|
|
1515
|
+
}
|
|
1516
|
+
line.append(wrapMarks(view, active), openStart);
|
|
1517
|
+
this.atCursorPos = cursorAfter;
|
|
1518
|
+
this.pendingBuffer = !cursorAfter ? 0 /* No */ : from < to ? 1 /* Yes */ : 2 /* IfCursor */;
|
|
1421
1519
|
}
|
|
1422
1520
|
}
|
|
1423
1521
|
else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
|
|
@@ -1443,10 +1541,15 @@ class ContentBuilder {
|
|
|
1443
1541
|
builder.openEnd = RangeSet.spans(decorations, from, to, builder);
|
|
1444
1542
|
if (builder.openStart < 0)
|
|
1445
1543
|
builder.openStart = builder.openEnd;
|
|
1446
|
-
builder.finish();
|
|
1544
|
+
builder.finish(builder.openEnd);
|
|
1447
1545
|
return builder;
|
|
1448
1546
|
}
|
|
1449
1547
|
}
|
|
1548
|
+
function wrapMarks(view, active) {
|
|
1549
|
+
for (let mark of active)
|
|
1550
|
+
view = new MarkView(mark, [view], view.length);
|
|
1551
|
+
return view;
|
|
1552
|
+
}
|
|
1450
1553
|
class NullWidget extends WidgetType {
|
|
1451
1554
|
constructor(tag) {
|
|
1452
1555
|
super();
|
|
@@ -1467,6 +1570,9 @@ const inputHandler = /*@__PURE__*/Facet.define();
|
|
|
1467
1570
|
const scrollTo = /*@__PURE__*/StateEffect.define({
|
|
1468
1571
|
map: (range, changes) => range.map(changes)
|
|
1469
1572
|
});
|
|
1573
|
+
const centerOn = /*@__PURE__*/StateEffect.define({
|
|
1574
|
+
map: (range, changes) => range.map(changes)
|
|
1575
|
+
});
|
|
1470
1576
|
/**
|
|
1471
1577
|
Log or report an unhandled exception in client code. Should
|
|
1472
1578
|
probably only be used by extension code that allows client code to
|
|
@@ -1779,7 +1885,9 @@ class ViewUpdate {
|
|
|
1779
1885
|
this.flags |= 2 /* Height */;
|
|
1780
1886
|
}
|
|
1781
1887
|
/**
|
|
1782
|
-
Tells you whether the viewport
|
|
1888
|
+
Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or
|
|
1889
|
+
[visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this
|
|
1890
|
+
update.
|
|
1783
1891
|
*/
|
|
1784
1892
|
get viewportChanged() {
|
|
1785
1893
|
return (this.flags & 4 /* Viewport */) > 0;
|
|
@@ -1795,7 +1903,7 @@ class ViewUpdate {
|
|
|
1795
1903
|
or the lines or characters within it has changed.
|
|
1796
1904
|
*/
|
|
1797
1905
|
get geometryChanged() {
|
|
1798
|
-
return this.docChanged || (this.flags & (
|
|
1906
|
+
return this.docChanged || (this.flags & (8 /* Geometry */ | 2 /* Height */)) > 0;
|
|
1799
1907
|
}
|
|
1800
1908
|
/**
|
|
1801
1909
|
True when this update indicates a focus change.
|
|
@@ -1880,7 +1988,7 @@ class DocView extends ContentView {
|
|
|
1880
1988
|
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
1881
1989
|
let pointerSel = update.transactions.some(tr => tr.isUserEvent("select.pointer"));
|
|
1882
1990
|
if (this.dirty == 0 /* Not */ && changedRanges.length == 0 &&
|
|
1883
|
-
!(update.flags &
|
|
1991
|
+
!(update.flags & 4 /* Viewport */) &&
|
|
1884
1992
|
update.state.selection.main.from >= this.view.viewport.from &&
|
|
1885
1993
|
update.state.selection.main.to <= this.view.viewport.to) {
|
|
1886
1994
|
this.updateSelection(forceSelection, pointerSel);
|
|
@@ -1891,6 +1999,14 @@ class DocView extends ContentView {
|
|
|
1891
1999
|
return true;
|
|
1892
2000
|
}
|
|
1893
2001
|
}
|
|
2002
|
+
reset(sel) {
|
|
2003
|
+
if (this.dirty) {
|
|
2004
|
+
this.view.observer.ignore(() => this.view.docView.sync());
|
|
2005
|
+
this.dirty = 0 /* Not */;
|
|
2006
|
+
}
|
|
2007
|
+
if (sel)
|
|
2008
|
+
this.updateSelection();
|
|
2009
|
+
}
|
|
1894
2010
|
// Used both by update and checkLayout do perform the actual DOM
|
|
1895
2011
|
// update
|
|
1896
2012
|
updateInner(changes, deco, oldLength, forceSelection = false, pointerSel = false) {
|
|
@@ -1915,6 +2031,12 @@ class DocView extends ContentView {
|
|
|
1915
2031
|
this.updateSelection(forceSelection, pointerSel);
|
|
1916
2032
|
this.dom.style.height = "";
|
|
1917
2033
|
});
|
|
2034
|
+
let gaps = [];
|
|
2035
|
+
if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
|
|
2036
|
+
for (let child of this.children)
|
|
2037
|
+
if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget)
|
|
2038
|
+
gaps.push(child.dom);
|
|
2039
|
+
observer.updateGaps(gaps);
|
|
1918
2040
|
}
|
|
1919
2041
|
updateChildren(changes, deco, oldLength) {
|
|
1920
2042
|
let cursor = this.childCursor(oldLength);
|
|
@@ -2014,6 +2136,14 @@ class DocView extends ContentView {
|
|
|
2014
2136
|
!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
|
2015
2137
|
!isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
|
2016
2138
|
this.view.observer.ignore(() => {
|
|
2139
|
+
// Chrome Android will hide the virtual keyboard when tapping
|
|
2140
|
+
// inside an uneditable node, and not bring it back when we
|
|
2141
|
+
// move the cursor to its proper position. This tries to
|
|
2142
|
+
// restore the keyboard by cycling focus.
|
|
2143
|
+
if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, this.dom)) {
|
|
2144
|
+
this.dom.blur();
|
|
2145
|
+
this.dom.focus({ preventScroll: true });
|
|
2146
|
+
}
|
|
2017
2147
|
let rawSel = getSelection(this.root);
|
|
2018
2148
|
if (main.empty) {
|
|
2019
2149
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
|
|
@@ -2187,7 +2317,7 @@ class DocView extends ContentView {
|
|
|
2187
2317
|
this.view.viewState.lineGapDeco
|
|
2188
2318
|
];
|
|
2189
2319
|
}
|
|
2190
|
-
|
|
2320
|
+
scrollIntoView({ range, center }) {
|
|
2191
2321
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
2192
2322
|
if (!rect)
|
|
2193
2323
|
return;
|
|
@@ -2207,10 +2337,10 @@ class DocView extends ContentView {
|
|
|
2207
2337
|
if (bottom != null)
|
|
2208
2338
|
mBottom = Math.max(mBottom, bottom);
|
|
2209
2339
|
}
|
|
2210
|
-
scrollRectIntoView(this.
|
|
2340
|
+
scrollRectIntoView(this.view.scrollDOM, {
|
|
2211
2341
|
left: rect.left - mLeft, top: rect.top - mTop,
|
|
2212
2342
|
right: rect.right + mRight, bottom: rect.bottom + mBottom
|
|
2213
|
-
}, range.head < range.anchor ? -1 : 1);
|
|
2343
|
+
}, range.head < range.anchor ? -1 : 1, center);
|
|
2214
2344
|
}
|
|
2215
2345
|
}
|
|
2216
2346
|
function betweenUneditable(pos) {
|
|
@@ -2321,6 +2451,14 @@ function findChangedDeco(a, b, diff) {
|
|
|
2321
2451
|
RangeSet.compare(a, b, diff, comp);
|
|
2322
2452
|
return comp.changes;
|
|
2323
2453
|
}
|
|
2454
|
+
function inUneditable(node, inside) {
|
|
2455
|
+
for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
|
|
2456
|
+
if (cur.nodeType == 1 && cur.contentEditable == 'false') {
|
|
2457
|
+
return true;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
return false;
|
|
2461
|
+
}
|
|
2324
2462
|
|
|
2325
2463
|
/**
|
|
2326
2464
|
Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
@@ -2766,6 +2904,7 @@ function domPosInText(node, x, y) {
|
|
|
2766
2904
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
2767
2905
|
}
|
|
2768
2906
|
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2907
|
+
var _a;
|
|
2769
2908
|
let content = view.contentDOM.getBoundingClientRect(), block;
|
|
2770
2909
|
let halfLine = view.defaultLineHeight / 2;
|
|
2771
2910
|
for (let bounced = false;;) {
|
|
@@ -2783,25 +2922,27 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
2783
2922
|
y = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
|
|
2784
2923
|
}
|
|
2785
2924
|
let lineStart = block.from;
|
|
2925
|
+
// Clip x to the viewport sides
|
|
2786
2926
|
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
2787
2927
|
// If this is outside of the rendered viewport, we can't determine a position
|
|
2788
2928
|
if (lineStart < view.viewport.from)
|
|
2789
2929
|
return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
|
|
2790
2930
|
if (lineStart > view.viewport.to)
|
|
2791
2931
|
return view.viewport.to == view.state.doc.length ? view.state.doc.length : posAtCoordsImprecise(view, content, block, x, y);
|
|
2792
|
-
//
|
|
2793
|
-
let
|
|
2932
|
+
// Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not
|
|
2933
|
+
let doc = view.dom.ownerDocument;
|
|
2934
|
+
let element = (view.root.elementFromPoint ? view.root : doc).elementFromPoint(x, y);
|
|
2794
2935
|
// There's visible editor content under the point, so we can try
|
|
2795
2936
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
2796
2937
|
let node, offset = -1;
|
|
2797
|
-
if (element && view.contentDOM.contains(element) &&
|
|
2798
|
-
if (
|
|
2799
|
-
let pos =
|
|
2938
|
+
if (element && view.contentDOM.contains(element) && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
|
|
2939
|
+
if (doc.caretPositionFromPoint) {
|
|
2940
|
+
let pos = doc.caretPositionFromPoint(x, y);
|
|
2800
2941
|
if (pos)
|
|
2801
2942
|
({ offsetNode: node, offset } = pos);
|
|
2802
2943
|
}
|
|
2803
|
-
else if (
|
|
2804
|
-
let range =
|
|
2944
|
+
else if (doc.caretRangeFromPoint) {
|
|
2945
|
+
let range = doc.caretRangeFromPoint(x, y);
|
|
2805
2946
|
if (range) {
|
|
2806
2947
|
({ startContainer: node, startOffset: offset } = range);
|
|
2807
2948
|
if (browser.safari && isSuspiciousCaretResult(node, offset, x))
|
|
@@ -2935,7 +3076,23 @@ class InputState {
|
|
|
2935
3076
|
constructor(view) {
|
|
2936
3077
|
this.lastKeyCode = 0;
|
|
2937
3078
|
this.lastKeyTime = 0;
|
|
2938
|
-
|
|
3079
|
+
// On iOS, some keys need to have their default behavior happen
|
|
3080
|
+
// (after which we retroactively handle them and reset the DOM) to
|
|
3081
|
+
// avoid messing up the virtual keyboard state.
|
|
3082
|
+
//
|
|
3083
|
+
// On Chrome Android, backspace near widgets is just completely
|
|
3084
|
+
// broken, and there are no key events, so we need to handle the
|
|
3085
|
+
// beforeinput event. Deleting stuff will often create a flurry of
|
|
3086
|
+
// events, and interrupting it before it is done just makes
|
|
3087
|
+
// subsequent events even more broken, so again, we hold off doing
|
|
3088
|
+
// anything until the browser is finished with whatever it is trying
|
|
3089
|
+
// to do.
|
|
3090
|
+
//
|
|
3091
|
+
// setPendingKey sets this, causing the DOM observer to pause for a
|
|
3092
|
+
// bit, and setting an animation frame (which seems the most
|
|
3093
|
+
// reliable way to detect 'browser is done flailing') to fire a fake
|
|
3094
|
+
// key event and re-sync the view again.
|
|
3095
|
+
this.pendingKey = undefined;
|
|
2939
3096
|
this.lastSelectionOrigin = null;
|
|
2940
3097
|
this.lastSelectionTime = 0;
|
|
2941
3098
|
this.lastEscPress = 0;
|
|
@@ -3044,20 +3201,27 @@ class InputState {
|
|
|
3044
3201
|
// state. So we let it go through, and then, in
|
|
3045
3202
|
// applyDOMChange, notify key handlers of it and reset to
|
|
3046
3203
|
// the state they produce.
|
|
3047
|
-
|
|
3204
|
+
let pending;
|
|
3205
|
+
if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
|
|
3048
3206
|
!(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
|
|
3049
|
-
this.
|
|
3050
|
-
setTimeout(() => this.flushIOSKey(view), 250);
|
|
3207
|
+
this.setPendingKey(view, pending);
|
|
3051
3208
|
return true;
|
|
3052
3209
|
}
|
|
3053
3210
|
return false;
|
|
3054
3211
|
}
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
|
|
3212
|
+
setPendingKey(view, pending) {
|
|
3213
|
+
this.pendingKey = pending;
|
|
3214
|
+
requestAnimationFrame(() => {
|
|
3215
|
+
if (!this.pendingKey)
|
|
3216
|
+
return false;
|
|
3217
|
+
let key = this.pendingKey;
|
|
3218
|
+
this.pendingKey = undefined;
|
|
3219
|
+
view.observer.processRecords();
|
|
3220
|
+
let startState = view.state;
|
|
3221
|
+
dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3222
|
+
if (view.state == startState)
|
|
3223
|
+
view.docView.reset(true);
|
|
3224
|
+
});
|
|
3061
3225
|
}
|
|
3062
3226
|
ignoreDuringComposition(event) {
|
|
3063
3227
|
if (!/^key/.test(event.type))
|
|
@@ -3104,6 +3268,11 @@ class InputState {
|
|
|
3104
3268
|
this.mouseSelection.destroy();
|
|
3105
3269
|
}
|
|
3106
3270
|
}
|
|
3271
|
+
const PendingKeys = [
|
|
3272
|
+
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3273
|
+
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
3274
|
+
{ key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
|
|
3275
|
+
];
|
|
3107
3276
|
// Key codes for modifier keys
|
|
3108
3277
|
const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
|
3109
3278
|
class MouseSelection {
|
|
@@ -3220,7 +3389,7 @@ function capturePaste(view) {
|
|
|
3220
3389
|
function doPaste(view, input) {
|
|
3221
3390
|
let { state } = view, changes, i = 1, text = state.toText(input);
|
|
3222
3391
|
let byLine = text.lines == state.selection.ranges.length;
|
|
3223
|
-
let linewise = lastLinewiseCopy && state.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString();
|
|
3392
|
+
let linewise = lastLinewiseCopy != null && state.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString();
|
|
3224
3393
|
if (linewise) {
|
|
3225
3394
|
let lastLine = -1;
|
|
3226
3395
|
changes = state.changeByRange(range => {
|
|
@@ -3431,9 +3600,8 @@ handlers.paste = (view, event) => {
|
|
|
3431
3600
|
return event.preventDefault();
|
|
3432
3601
|
view.observer.flush();
|
|
3433
3602
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
doPaste(view, text);
|
|
3603
|
+
if (data) {
|
|
3604
|
+
doPaste(view, data.getData("text/plain"));
|
|
3437
3605
|
event.preventDefault();
|
|
3438
3606
|
}
|
|
3439
3607
|
else {
|
|
@@ -3482,7 +3650,7 @@ function copiedRange(state) {
|
|
|
3482
3650
|
let lastLinewiseCopy = null;
|
|
3483
3651
|
handlers.copy = handlers.cut = (view, event) => {
|
|
3484
3652
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
3485
|
-
if (!text)
|
|
3653
|
+
if (!text && !linewise)
|
|
3486
3654
|
return;
|
|
3487
3655
|
lastLinewiseCopy = linewise ? text : null;
|
|
3488
3656
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
@@ -3550,6 +3718,31 @@ handlers.compositionend = view => {
|
|
|
3550
3718
|
handlers.contextmenu = view => {
|
|
3551
3719
|
view.inputState.lastContextMenu = Date.now();
|
|
3552
3720
|
};
|
|
3721
|
+
handlers.beforeinput = (view, event) => {
|
|
3722
|
+
var _a;
|
|
3723
|
+
// Because Chrome Android doesn't fire useful key events, use
|
|
3724
|
+
// beforeinput to detect backspace (and possibly enter and delete,
|
|
3725
|
+
// but those usually don't even seem to fire beforeinput events at
|
|
3726
|
+
// the moment) and fake a key event for it.
|
|
3727
|
+
//
|
|
3728
|
+
// (preventDefault on beforeinput, though supported in the spec,
|
|
3729
|
+
// seems to do nothing at all on Chrome).
|
|
3730
|
+
let pending;
|
|
3731
|
+
if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
|
|
3732
|
+
view.inputState.setPendingKey(view, pending);
|
|
3733
|
+
let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
|
|
3734
|
+
setTimeout(() => {
|
|
3735
|
+
var _a;
|
|
3736
|
+
// Backspacing near uneditable nodes on Chrome Android sometimes
|
|
3737
|
+
// closes the virtual keyboard. This tries to crudely detect
|
|
3738
|
+
// that and refocus to get it back.
|
|
3739
|
+
if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) {
|
|
3740
|
+
view.contentDOM.blur();
|
|
3741
|
+
view.focus();
|
|
3742
|
+
}
|
|
3743
|
+
}, 50);
|
|
3744
|
+
}
|
|
3745
|
+
};
|
|
3553
3746
|
|
|
3554
3747
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line"];
|
|
3555
3748
|
class HeightOracle {
|
|
@@ -4264,6 +4457,15 @@ class LineGapWidget extends WidgetType {
|
|
|
4264
4457
|
}
|
|
4265
4458
|
get estimatedHeight() { return this.vertical ? this.size : -1; }
|
|
4266
4459
|
}
|
|
4460
|
+
class ScrollTarget {
|
|
4461
|
+
constructor(range, center = false) {
|
|
4462
|
+
this.range = range;
|
|
4463
|
+
this.center = center;
|
|
4464
|
+
}
|
|
4465
|
+
map(changes) {
|
|
4466
|
+
return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4267
4469
|
class ViewState {
|
|
4268
4470
|
constructor(state) {
|
|
4269
4471
|
this.state = state;
|
|
@@ -4276,7 +4478,7 @@ class ViewState {
|
|
|
4276
4478
|
this.heightOracle = new HeightOracle;
|
|
4277
4479
|
// See VP.MaxDOMHeight
|
|
4278
4480
|
this.scaler = IdScaler;
|
|
4279
|
-
this.
|
|
4481
|
+
this.scrollTarget = null;
|
|
4280
4482
|
// Briefly set to true when printing, to disable viewport limiting
|
|
4281
4483
|
this.printing = false;
|
|
4282
4484
|
this.visibleRanges = [];
|
|
@@ -4309,7 +4511,7 @@ class ViewState {
|
|
|
4309
4511
|
this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler :
|
|
4310
4512
|
new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
|
|
4311
4513
|
}
|
|
4312
|
-
update(update,
|
|
4514
|
+
update(update, scrollTarget = null) {
|
|
4313
4515
|
let prev = this.state;
|
|
4314
4516
|
this.state = update.state;
|
|
4315
4517
|
let newDeco = this.state.facet(decorations);
|
|
@@ -4320,30 +4522,33 @@ class ViewState {
|
|
|
4320
4522
|
if (this.heightMap.height != prevHeight)
|
|
4321
4523
|
update.flags |= 2 /* Height */;
|
|
4322
4524
|
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
|
4323
|
-
if (
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4327
|
-
update.flags |= 4 /* Viewport */;
|
|
4328
|
-
}
|
|
4525
|
+
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
4526
|
+
!this.viewportIsAppropriate(viewport))
|
|
4527
|
+
viewport = this.getViewport(0, scrollTarget);
|
|
4528
|
+
this.viewport = viewport;
|
|
4329
4529
|
this.updateForViewport();
|
|
4330
4530
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4331
|
-
|
|
4332
|
-
this.computeVisibleRanges();
|
|
4333
|
-
if (
|
|
4334
|
-
this.
|
|
4531
|
+
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
4532
|
+
update.flags |= this.computeVisibleRanges();
|
|
4533
|
+
if (scrollTarget)
|
|
4534
|
+
this.scrollTarget = scrollTarget;
|
|
4335
4535
|
if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
|
|
4336
4536
|
update.state.selection.main.empty && update.state.selection.main.assoc)
|
|
4337
4537
|
this.mustEnforceCursorAssoc = true;
|
|
4338
4538
|
}
|
|
4339
4539
|
measure(docView, repeated) {
|
|
4340
4540
|
let dom = docView.dom, whiteSpace = "", direction = Direction.LTR;
|
|
4541
|
+
let result = 0;
|
|
4341
4542
|
if (!repeated) {
|
|
4342
4543
|
// Vertical padding
|
|
4343
4544
|
let style = window.getComputedStyle(dom);
|
|
4344
4545
|
whiteSpace = style.whiteSpace, direction = (style.direction == "rtl" ? Direction.RTL : Direction.LTR);
|
|
4345
|
-
|
|
4346
|
-
this.
|
|
4546
|
+
let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
|
4547
|
+
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
4548
|
+
result |= 8 /* Geometry */;
|
|
4549
|
+
this.paddingTop = paddingTop;
|
|
4550
|
+
this.paddingBottom = paddingBottom;
|
|
4551
|
+
}
|
|
4347
4552
|
}
|
|
4348
4553
|
// Pixel viewport
|
|
4349
4554
|
let pixelViewport = this.printing ? { top: -1e8, bottom: 1e8, left: -1e8, right: 1e8 } : visiblePixelRange(dom, this.paddingTop);
|
|
@@ -4353,7 +4558,7 @@ class ViewState {
|
|
|
4353
4558
|
if (!this.inView)
|
|
4354
4559
|
return 0;
|
|
4355
4560
|
let lineHeights = docView.measureVisibleLineHeights();
|
|
4356
|
-
let refresh = false, bias = 0,
|
|
4561
|
+
let refresh = false, bias = 0, oracle = this.heightOracle;
|
|
4357
4562
|
if (!repeated) {
|
|
4358
4563
|
let contentWidth = docView.dom.clientWidth;
|
|
4359
4564
|
if (oracle.mustRefresh(lineHeights, whiteSpace, direction) ||
|
|
@@ -4362,12 +4567,12 @@ class ViewState {
|
|
|
4362
4567
|
refresh = oracle.refresh(whiteSpace, direction, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4363
4568
|
if (refresh) {
|
|
4364
4569
|
docView.minWidth = 0;
|
|
4365
|
-
result |=
|
|
4570
|
+
result |= 8 /* Geometry */;
|
|
4366
4571
|
}
|
|
4367
4572
|
}
|
|
4368
4573
|
if (this.contentWidth != contentWidth) {
|
|
4369
4574
|
this.contentWidth = contentWidth;
|
|
4370
|
-
result |=
|
|
4575
|
+
result |= 8 /* Geometry */;
|
|
4371
4576
|
}
|
|
4372
4577
|
if (dTop > 0 && dBottom > 0)
|
|
4373
4578
|
bias = Math.max(dTop, dBottom);
|
|
@@ -4379,17 +4584,12 @@ class ViewState {
|
|
|
4379
4584
|
if (oracle.heightChanged)
|
|
4380
4585
|
result |= 2 /* Height */;
|
|
4381
4586
|
if (!this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4382
|
-
this.
|
|
4383
|
-
|
|
4384
|
-
if (newVP.from != this.viewport.from || newVP.to != this.viewport.to) {
|
|
4385
|
-
this.viewport = newVP;
|
|
4386
|
-
result |= 4 /* Viewport */;
|
|
4387
|
-
}
|
|
4388
|
-
}
|
|
4587
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to))
|
|
4588
|
+
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4389
4589
|
this.updateForViewport();
|
|
4390
4590
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4391
|
-
|
|
4392
|
-
this.computeVisibleRanges();
|
|
4591
|
+
this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
|
|
4592
|
+
result |= this.computeVisibleRanges();
|
|
4393
4593
|
if (this.mustEnforceCursorAssoc) {
|
|
4394
4594
|
this.mustEnforceCursorAssoc = false;
|
|
4395
4595
|
// This is done in the read stage, because moving the selection
|
|
@@ -4402,22 +4602,25 @@ class ViewState {
|
|
|
4402
4602
|
}
|
|
4403
4603
|
get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top, 0); }
|
|
4404
4604
|
get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom, 0); }
|
|
4405
|
-
getViewport(bias,
|
|
4605
|
+
getViewport(bias, scrollTarget) {
|
|
4406
4606
|
// This will divide VP.Margin between the top and the
|
|
4407
4607
|
// bottom, depending on the bias (the change in viewport position
|
|
4408
4608
|
// since the last update). It'll hold a number between 0 and 1
|
|
4409
4609
|
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* Margin */ / 2));
|
|
4410
4610
|
let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
|
|
4411
4611
|
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);
|
|
4412
|
-
// If
|
|
4413
|
-
if (
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4612
|
+
// If scrollTarget is given, make sure the viewport includes that position
|
|
4613
|
+
if (scrollTarget) {
|
|
4614
|
+
let { head } = scrollTarget.range, viewHeight = visibleBottom - visibleTop;
|
|
4615
|
+
if (head < viewport.from || head > viewport.to) {
|
|
4616
|
+
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4617
|
+
if (scrollTarget.center)
|
|
4618
|
+
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
4619
|
+
else if (head < viewport.from)
|
|
4620
|
+
topPos = block.top;
|
|
4621
|
+
else
|
|
4622
|
+
topPos = block.bottom - viewHeight;
|
|
4623
|
+
viewport = new Viewport(map.lineAt(topPos - 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to);
|
|
4421
4624
|
}
|
|
4422
4625
|
}
|
|
4423
4626
|
return viewport;
|
|
@@ -4511,9 +4714,7 @@ class ViewState {
|
|
|
4511
4714
|
if (!LineGap.same(gaps, this.lineGaps)) {
|
|
4512
4715
|
this.lineGaps = gaps;
|
|
4513
4716
|
this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping)));
|
|
4514
|
-
return 8 /* LineGaps */;
|
|
4515
4717
|
}
|
|
4516
|
-
return 0;
|
|
4517
4718
|
}
|
|
4518
4719
|
computeVisibleRanges() {
|
|
4519
4720
|
let deco = this.state.facet(decorations);
|
|
@@ -4524,7 +4725,10 @@ class ViewState {
|
|
|
4524
4725
|
span(from, to) { ranges.push({ from, to }); },
|
|
4525
4726
|
point() { }
|
|
4526
4727
|
}, 20);
|
|
4728
|
+
let changed = ranges.length != this.visibleRanges.length ||
|
|
4729
|
+
this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to);
|
|
4527
4730
|
this.visibleRanges = ranges;
|
|
4731
|
+
return changed ? 4 /* Viewport */ : 0;
|
|
4528
4732
|
}
|
|
4529
4733
|
lineAt(pos, editorTop) {
|
|
4530
4734
|
editorTop += this.paddingTop;
|
|
@@ -4549,16 +4753,11 @@ class ViewState {
|
|
|
4549
4753
|
return this.scaler.toDOM(this.heightMap.height, this.paddingTop);
|
|
4550
4754
|
}
|
|
4551
4755
|
}
|
|
4552
|
-
/**
|
|
4553
|
-
Indicates the range of the document that is in the visible
|
|
4554
|
-
viewport.
|
|
4555
|
-
*/
|
|
4556
4756
|
class Viewport {
|
|
4557
4757
|
constructor(from, to) {
|
|
4558
4758
|
this.from = from;
|
|
4559
4759
|
this.to = to;
|
|
4560
4760
|
}
|
|
4561
|
-
eq(b) { return this.from == b.from && this.to == b.to; }
|
|
4562
4761
|
}
|
|
4563
4762
|
function lineStructure(from, to, state) {
|
|
4564
4763
|
let ranges = [], pos = from, total = 0;
|
|
@@ -4684,7 +4883,7 @@ function buildTheme(main, spec, scopes) {
|
|
|
4684
4883
|
});
|
|
4685
4884
|
}
|
|
4686
4885
|
const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
4687
|
-
"
|
|
4886
|
+
"&.cm-editor": {
|
|
4688
4887
|
position: "relative !important",
|
|
4689
4888
|
boxSizing: "border-box",
|
|
4690
4889
|
"&.cm-focused": {
|
|
@@ -4851,6 +5050,8 @@ class DOMObserver {
|
|
|
4851
5050
|
this.scrollTargets = [];
|
|
4852
5051
|
this.intersection = null;
|
|
4853
5052
|
this.intersecting = false;
|
|
5053
|
+
this.gapIntersection = null;
|
|
5054
|
+
this.gaps = [];
|
|
4854
5055
|
// Used to work around a Safari Selection/shadow DOM bug (#414)
|
|
4855
5056
|
this._selectionRange = null;
|
|
4856
5057
|
// Timeout for scheduling check of the parents that need scroll handlers
|
|
@@ -4891,13 +5092,17 @@ class DOMObserver {
|
|
|
4891
5092
|
this.intersection = new IntersectionObserver(entries => {
|
|
4892
5093
|
if (this.parentCheck < 0)
|
|
4893
5094
|
this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
|
|
4894
|
-
if (entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
5095
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
4895
5096
|
this.intersecting = !this.intersecting;
|
|
4896
5097
|
if (this.intersecting != this.view.inView)
|
|
4897
5098
|
this.onScrollChanged(document.createEvent("Event"));
|
|
4898
5099
|
}
|
|
4899
5100
|
}, {});
|
|
4900
5101
|
this.intersection.observe(this.dom);
|
|
5102
|
+
this.gapIntersection = new IntersectionObserver(entries => {
|
|
5103
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
|
|
5104
|
+
this.onScrollChanged(document.createEvent("Event"));
|
|
5105
|
+
}, {});
|
|
4901
5106
|
}
|
|
4902
5107
|
this.listenForScroll();
|
|
4903
5108
|
}
|
|
@@ -4906,6 +5111,14 @@ class DOMObserver {
|
|
|
4906
5111
|
this.flush();
|
|
4907
5112
|
this.onScrollChanged(e);
|
|
4908
5113
|
}
|
|
5114
|
+
updateGaps(gaps) {
|
|
5115
|
+
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5116
|
+
this.gapIntersection.disconnect();
|
|
5117
|
+
for (let gap of gaps)
|
|
5118
|
+
this.gapIntersection.observe(gap);
|
|
5119
|
+
this.gaps = gaps;
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
4909
5122
|
onSelectionChange(event) {
|
|
4910
5123
|
if (this.lastFlush < Date.now() - 50)
|
|
4911
5124
|
this._selectionRange = null;
|
|
@@ -5021,20 +5234,12 @@ class DOMObserver {
|
|
|
5021
5234
|
this.flush();
|
|
5022
5235
|
}
|
|
5023
5236
|
}
|
|
5024
|
-
|
|
5025
|
-
flush() {
|
|
5026
|
-
if (this.delayedFlush >= 0)
|
|
5027
|
-
return;
|
|
5028
|
-
this.lastFlush = Date.now();
|
|
5237
|
+
processRecords() {
|
|
5029
5238
|
let records = this.queue;
|
|
5030
5239
|
for (let mut of this.observer.takeRecords())
|
|
5031
5240
|
records.push(mut);
|
|
5032
5241
|
if (records.length)
|
|
5033
5242
|
this.queue = [];
|
|
5034
|
-
let selection = this.selectionRange;
|
|
5035
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5036
|
-
if (records.length == 0 && !newSel)
|
|
5037
|
-
return;
|
|
5038
5243
|
let from = -1, to = -1, typeOver = false;
|
|
5039
5244
|
for (let record of records) {
|
|
5040
5245
|
let range = this.readMutation(record);
|
|
@@ -5050,17 +5255,26 @@ class DOMObserver {
|
|
|
5050
5255
|
to = Math.max(range.to, to);
|
|
5051
5256
|
}
|
|
5052
5257
|
}
|
|
5258
|
+
return { from, to, typeOver };
|
|
5259
|
+
}
|
|
5260
|
+
// Apply pending changes, if any
|
|
5261
|
+
flush() {
|
|
5262
|
+
// Completely hold off flushing when pending keys are set—the code
|
|
5263
|
+
// managing those will make sure processRecords is called and the
|
|
5264
|
+
// view is resynchronized after
|
|
5265
|
+
if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
|
|
5266
|
+
return;
|
|
5267
|
+
this.lastFlush = Date.now();
|
|
5268
|
+
let { from, to, typeOver } = this.processRecords();
|
|
5269
|
+
let selection = this.selectionRange;
|
|
5270
|
+
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5271
|
+
if (from < 0 && !newSel)
|
|
5272
|
+
return;
|
|
5053
5273
|
let startState = this.view.state;
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
if (this.view.state == startState)
|
|
5057
|
-
|
|
5058
|
-
this.ignore(() => this.view.docView.sync());
|
|
5059
|
-
this.view.docView.dirty = 0 /* Not */;
|
|
5060
|
-
}
|
|
5061
|
-
if (newSel)
|
|
5062
|
-
this.view.docView.updateSelection();
|
|
5063
|
-
}
|
|
5274
|
+
this.onChange(from, to, typeOver);
|
|
5275
|
+
// The view wasn't updated
|
|
5276
|
+
if (this.view.state == startState)
|
|
5277
|
+
this.view.docView.reset(newSel);
|
|
5064
5278
|
this.clearSelection();
|
|
5065
5279
|
}
|
|
5066
5280
|
readMutation(rec) {
|
|
@@ -5087,6 +5301,8 @@ class DOMObserver {
|
|
|
5087
5301
|
this.stop();
|
|
5088
5302
|
if (this.intersection)
|
|
5089
5303
|
this.intersection.disconnect();
|
|
5304
|
+
if (this.gapIntersection)
|
|
5305
|
+
this.gapIntersection.disconnect();
|
|
5090
5306
|
for (let dom of this.scrollTargets)
|
|
5091
5307
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5092
5308
|
window.removeEventListener("scroll", this.onScroll);
|
|
@@ -5195,9 +5411,9 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5195
5411
|
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5196
5412
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5197
5413
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5198
|
-
dispatchKey(view.contentDOM, "Delete", 46)))
|
|
5199
|
-
browser.ios && view.inputState.flushIOSKey(view))
|
|
5414
|
+
dispatchKey(view.contentDOM, "Delete", 46)))) {
|
|
5200
5415
|
return;
|
|
5416
|
+
}
|
|
5201
5417
|
let text = change.insert.toString();
|
|
5202
5418
|
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5203
5419
|
return;
|
|
@@ -5287,8 +5503,9 @@ class DOMReader {
|
|
|
5287
5503
|
if (next == end)
|
|
5288
5504
|
break;
|
|
5289
5505
|
let view = ContentView.get(cur), nextView = ContentView.get(next);
|
|
5290
|
-
if (
|
|
5291
|
-
(
|
|
5506
|
+
if (view && nextView ? view.breakAfter :
|
|
5507
|
+
(view ? view.breakAfter : isBlockElement(cur)) ||
|
|
5508
|
+
(isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
|
|
5292
5509
|
this.text += this.lineBreak;
|
|
5293
5510
|
cur = next;
|
|
5294
5511
|
}
|
|
@@ -5391,6 +5608,7 @@ class EditorView {
|
|
|
5391
5608
|
this.editorAttrs = {};
|
|
5392
5609
|
this.contentAttrs = {};
|
|
5393
5610
|
this.bidiCache = [];
|
|
5611
|
+
this.destroyed = false;
|
|
5394
5612
|
/**
|
|
5395
5613
|
@internal
|
|
5396
5614
|
*/
|
|
@@ -5416,7 +5634,7 @@ class EditorView {
|
|
|
5416
5634
|
this.dom.appendChild(this.scrollDOM);
|
|
5417
5635
|
this._dispatch = config.dispatch || ((tr) => this.update([tr]));
|
|
5418
5636
|
this.dispatch = this.dispatch.bind(this);
|
|
5419
|
-
this.root = (config.root || document);
|
|
5637
|
+
this.root = (config.root || getRoot(config.parent) || document);
|
|
5420
5638
|
this.viewState = new ViewState(config.state || EditorState.create());
|
|
5421
5639
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
|
|
5422
5640
|
this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
|
@@ -5489,25 +5707,32 @@ class EditorView {
|
|
|
5489
5707
|
throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");
|
|
5490
5708
|
state = tr.state;
|
|
5491
5709
|
}
|
|
5710
|
+
if (this.destroyed) {
|
|
5711
|
+
this.viewState.state = state;
|
|
5712
|
+
return;
|
|
5713
|
+
}
|
|
5492
5714
|
// When the phrases change, redraw the editor
|
|
5493
5715
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
5494
5716
|
return this.setState(state);
|
|
5495
5717
|
update = new ViewUpdate(this, state, transactions);
|
|
5496
|
-
let
|
|
5718
|
+
let scrollTarget = null;
|
|
5497
5719
|
try {
|
|
5498
5720
|
this.updateState = 2 /* Updating */;
|
|
5499
5721
|
for (let tr of transactions) {
|
|
5500
|
-
if (
|
|
5501
|
-
|
|
5722
|
+
if (scrollTarget)
|
|
5723
|
+
scrollTarget = scrollTarget.map(tr.changes);
|
|
5502
5724
|
if (tr.scrollIntoView) {
|
|
5503
5725
|
let { main } = tr.state.selection;
|
|
5504
|
-
|
|
5726
|
+
scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
|
5505
5727
|
}
|
|
5506
|
-
for (let e of tr.effects)
|
|
5728
|
+
for (let e of tr.effects) {
|
|
5507
5729
|
if (e.is(scrollTo))
|
|
5508
|
-
|
|
5730
|
+
scrollTarget = new ScrollTarget(e.value);
|
|
5731
|
+
else if (e.is(centerOn))
|
|
5732
|
+
scrollTarget = new ScrollTarget(e.value, true);
|
|
5733
|
+
}
|
|
5509
5734
|
}
|
|
5510
|
-
this.viewState.update(update,
|
|
5735
|
+
this.viewState.update(update, scrollTarget);
|
|
5511
5736
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
5512
5737
|
if (!update.empty) {
|
|
5513
5738
|
this.updatePlugins(update);
|
|
@@ -5522,7 +5747,7 @@ class EditorView {
|
|
|
5522
5747
|
finally {
|
|
5523
5748
|
this.updateState = 0 /* Idle */;
|
|
5524
5749
|
}
|
|
5525
|
-
if (redrawn ||
|
|
5750
|
+
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc)
|
|
5526
5751
|
this.requestMeasure();
|
|
5527
5752
|
if (!update.empty)
|
|
5528
5753
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -5538,6 +5763,10 @@ class EditorView {
|
|
|
5538
5763
|
setState(newState) {
|
|
5539
5764
|
if (this.updateState != 0 /* Idle */)
|
|
5540
5765
|
throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");
|
|
5766
|
+
if (this.destroyed) {
|
|
5767
|
+
this.viewState.state = newState;
|
|
5768
|
+
return;
|
|
5769
|
+
}
|
|
5541
5770
|
this.updateState = 2 /* Updating */;
|
|
5542
5771
|
try {
|
|
5543
5772
|
for (let plugin of this.plugins)
|
|
@@ -5587,6 +5816,8 @@ class EditorView {
|
|
|
5587
5816
|
@internal
|
|
5588
5817
|
*/
|
|
5589
5818
|
measure(flush = true) {
|
|
5819
|
+
if (this.destroyed)
|
|
5820
|
+
return;
|
|
5590
5821
|
if (this.measureScheduled > -1)
|
|
5591
5822
|
cancelAnimationFrame(this.measureScheduled);
|
|
5592
5823
|
this.measureScheduled = -1; // Prevent requestMeasure calls from scheduling another animation frame
|
|
@@ -5596,15 +5827,18 @@ class EditorView {
|
|
|
5596
5827
|
try {
|
|
5597
5828
|
for (let i = 0;; i++) {
|
|
5598
5829
|
this.updateState = 1 /* Measuring */;
|
|
5830
|
+
let oldViewport = this.viewport;
|
|
5599
5831
|
let changed = this.viewState.measure(this.docView, i > 0);
|
|
5600
|
-
|
|
5601
|
-
if (!changed && !measuring.length && this.viewState.scrollTo == null)
|
|
5832
|
+
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
|
5602
5833
|
break;
|
|
5603
|
-
this.measureRequests = [];
|
|
5604
5834
|
if (i > 5) {
|
|
5605
5835
|
console.warn("Viewport failed to stabilize");
|
|
5606
5836
|
break;
|
|
5607
5837
|
}
|
|
5838
|
+
let measuring = [];
|
|
5839
|
+
// Only run measure requests in this cycle when the viewport didn't change
|
|
5840
|
+
if (!(changed & 4 /* Viewport */))
|
|
5841
|
+
[this.measureRequests, measuring] = [measuring, this.measureRequests];
|
|
5608
5842
|
let measured = measuring.map(m => {
|
|
5609
5843
|
try {
|
|
5610
5844
|
return m.read(this);
|
|
@@ -5637,11 +5871,11 @@ class EditorView {
|
|
|
5637
5871
|
logException(this.state, e);
|
|
5638
5872
|
}
|
|
5639
5873
|
}
|
|
5640
|
-
if (this.viewState.
|
|
5641
|
-
this.docView.
|
|
5642
|
-
this.viewState.
|
|
5874
|
+
if (this.viewState.scrollTarget) {
|
|
5875
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5876
|
+
this.viewState.scrollTarget = null;
|
|
5643
5877
|
}
|
|
5644
|
-
if (
|
|
5878
|
+
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5645
5879
|
break;
|
|
5646
5880
|
}
|
|
5647
5881
|
}
|
|
@@ -5671,6 +5905,7 @@ class EditorView {
|
|
|
5671
5905
|
spellcheck: "false",
|
|
5672
5906
|
autocorrect: "off",
|
|
5673
5907
|
autocapitalize: "off",
|
|
5908
|
+
translate: "no",
|
|
5674
5909
|
contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
|
|
5675
5910
|
class: "cm-content",
|
|
5676
5911
|
style: `${browser.tabSize}: ${this.state.tabSize}`,
|
|
@@ -5861,12 +6096,9 @@ class EditorView {
|
|
|
5861
6096
|
moveVertically(start, forward, distance) {
|
|
5862
6097
|
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
|
5863
6098
|
}
|
|
5864
|
-
|
|
5865
|
-
Scroll the given document position into view.
|
|
5866
|
-
*/
|
|
6099
|
+
// FIXME remove on next major version
|
|
5867
6100
|
scrollPosIntoView(pos) {
|
|
5868
|
-
this.
|
|
5869
|
-
this.requestMeasure();
|
|
6101
|
+
this.dispatch({ effects: scrollTo.of(EditorSelection.cursor(pos)) });
|
|
5870
6102
|
}
|
|
5871
6103
|
/**
|
|
5872
6104
|
Find the DOM parent node and offset (child offset if `node` is
|
|
@@ -5977,11 +6209,13 @@ class EditorView {
|
|
|
5977
6209
|
destroy() {
|
|
5978
6210
|
for (let plugin of this.plugins)
|
|
5979
6211
|
plugin.destroy(this);
|
|
6212
|
+
this.plugins = [];
|
|
5980
6213
|
this.inputState.destroy();
|
|
5981
6214
|
this.dom.remove();
|
|
5982
6215
|
this.observer.destroy();
|
|
5983
6216
|
if (this.measureScheduled > -1)
|
|
5984
6217
|
cancelAnimationFrame(this.measureScheduled);
|
|
6218
|
+
this.destroyed = true;
|
|
5985
6219
|
}
|
|
5986
6220
|
/**
|
|
5987
6221
|
Facet that can be used to add DOM event handlers. The value
|
|
@@ -6040,6 +6274,11 @@ transaction to make it scroll the given range into view.
|
|
|
6040
6274
|
*/
|
|
6041
6275
|
EditorView.scrollTo = scrollTo;
|
|
6042
6276
|
/**
|
|
6277
|
+
Effect that makes the editor scroll the given range to the
|
|
6278
|
+
center of the visible view.
|
|
6279
|
+
*/
|
|
6280
|
+
EditorView.centerOn = centerOn;
|
|
6281
|
+
/**
|
|
6043
6282
|
Facet to add a [style
|
|
6044
6283
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
6045
6284
|
an editor view. The view will ensure that the module is
|
|
@@ -6169,11 +6408,7 @@ class CachedOrder {
|
|
|
6169
6408
|
}
|
|
6170
6409
|
}
|
|
6171
6410
|
|
|
6172
|
-
const currentPlatform =
|
|
6173
|
-
: /*@__PURE__*//Mac/.test(navigator.platform) ? "mac"
|
|
6174
|
-
: /*@__PURE__*//Win/.test(navigator.platform) ? "win"
|
|
6175
|
-
: /*@__PURE__*//Linux|X11/.test(navigator.platform) ? "linux"
|
|
6176
|
-
: "key";
|
|
6411
|
+
const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
|
|
6177
6412
|
function normalizeKeyName(name, platform) {
|
|
6178
6413
|
const parts = name.split(/-(?!$)/);
|
|
6179
6414
|
let result = parts[parts.length - 1];
|
|
@@ -6679,7 +6914,7 @@ class MatchDecorator {
|
|
|
6679
6914
|
}
|
|
6680
6915
|
|
|
6681
6916
|
const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
|
6682
|
-
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6917
|
+
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6683
6918
|
const Names = {
|
|
6684
6919
|
0: "null",
|
|
6685
6920
|
7: "bell",
|
|
@@ -6694,6 +6929,8 @@ const Names = {
|
|
|
6694
6929
|
8206: "left-to-right mark",
|
|
6695
6930
|
8207: "right-to-left mark",
|
|
6696
6931
|
8232: "line separator",
|
|
6932
|
+
8237: "left-to-right override",
|
|
6933
|
+
8238: "right-to-left override",
|
|
6697
6934
|
8233: "paragraph separator",
|
|
6698
6935
|
65279: "zero width no-break space",
|
|
6699
6936
|
65532: "object replacement"
|
|
@@ -6860,7 +7097,7 @@ DOM class.
|
|
|
6860
7097
|
function highlightActiveLine() {
|
|
6861
7098
|
return activeLineHighlighter;
|
|
6862
7099
|
}
|
|
6863
|
-
const lineDeco = /*@__PURE__*/Decoration.line({
|
|
7100
|
+
const lineDeco = /*@__PURE__*/Decoration.line({ class: "cm-activeLine" });
|
|
6864
7101
|
const activeLineHighlighter = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
6865
7102
|
constructor(view) {
|
|
6866
7103
|
this.decorations = this.getDeco(view);
|