@codemirror/view 0.19.9 → 0.19.10
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 +24 -0
- package/dist/index.cjs +217 -60
- package/dist/index.d.ts +7 -1
- package/dist/index.js +217 -60
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
## 0.19.10 (2021-11-02)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Don't crash when `IntersectionObserver` fires its callback without any records. Try to handle some backspace issues on Chrome Android
|
|
6
|
+
|
|
7
|
+
Using backspace near uneditable widgets on Chrome Android should now be more reliable.
|
|
8
|
+
|
|
9
|
+
Work around a number of browser bugs by always rendering zero-width spaces around in-content widgets, so that browsers will treat the positions near them as valid cursor positions and not try to run composition across widget boundaries.
|
|
10
|
+
|
|
11
|
+
Work around bogus composition changes created by Chrome Android after handled backspace presses.
|
|
12
|
+
|
|
13
|
+
Work around an issue where tapping on an uneditable node in the editor would sometimes fail to show the virtual keyboard on Chrome Android.
|
|
14
|
+
|
|
15
|
+
Prevent translation services from translating the editor content. Show direction override characters as special chars by default
|
|
16
|
+
|
|
17
|
+
`specialChars` will now, by default, replace direction override chars, to mitigate https://trojansource.codes/ attacks.
|
|
18
|
+
|
|
19
|
+
### New features
|
|
20
|
+
|
|
21
|
+
The editor view will, if `parent` is given but `root` is not, derive the root from the parent element.
|
|
22
|
+
|
|
23
|
+
Line decorations now accept a `class` property to directly add DOM classes to the line.
|
|
24
|
+
|
|
1
25
|
## 0.19.9 (2021-10-01)
|
|
2
26
|
|
|
3
27
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -251,6 +251,14 @@ function contentEditablePlainTextSupported() {
|
|
|
251
251
|
}
|
|
252
252
|
return _plainTextSupported;
|
|
253
253
|
}
|
|
254
|
+
function getRoot(node) {
|
|
255
|
+
while (node) {
|
|
256
|
+
node = node.assignedSlot || node.parentNode;
|
|
257
|
+
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
|
258
|
+
return node;
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
}
|
|
254
262
|
|
|
255
263
|
class DOMPos {
|
|
256
264
|
constructor(node, offset, precise = true) {
|
|
@@ -448,6 +456,7 @@ class ContentView {
|
|
|
448
456
|
(this.breakAfter ? "#" : "");
|
|
449
457
|
}
|
|
450
458
|
static get(node) { return node.cmView; }
|
|
459
|
+
get isEditable() { return true; }
|
|
451
460
|
}
|
|
452
461
|
ContentView.prototype.breakAfter = 0;
|
|
453
462
|
// Remove a DOM node and return its next sibling.
|
|
@@ -495,15 +504,18 @@ const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent);
|
|
|
495
504
|
const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent);
|
|
496
505
|
const webkit = "webkitFontSmoothing" in doc.documentElement.style;
|
|
497
506
|
const safari = !ie && /Apple Computer/.test(nav.vendor);
|
|
507
|
+
const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
|
|
498
508
|
var browser = {
|
|
499
|
-
mac: /Mac/.test(nav.platform),
|
|
509
|
+
mac: ios || /Mac/.test(nav.platform),
|
|
510
|
+
windows: /Win/.test(nav.platform),
|
|
511
|
+
linux: /Linux|X11/.test(nav.platform),
|
|
500
512
|
ie,
|
|
501
513
|
ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
|
|
502
514
|
gecko,
|
|
503
515
|
gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
|
504
516
|
chrome: !!chrome,
|
|
505
517
|
chrome_version: chrome ? +chrome[1] : 0,
|
|
506
|
-
ios
|
|
518
|
+
ios,
|
|
507
519
|
android: /Android\b/.test(nav.userAgent),
|
|
508
520
|
webkit,
|
|
509
521
|
safari,
|
|
@@ -725,6 +737,7 @@ class WidgetView extends InlineView {
|
|
|
725
737
|
}
|
|
726
738
|
return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0);
|
|
727
739
|
}
|
|
740
|
+
get isEditable() { return false; }
|
|
728
741
|
}
|
|
729
742
|
class CompositionView extends WidgetView {
|
|
730
743
|
domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
|
|
@@ -736,6 +749,38 @@ class CompositionView extends WidgetView {
|
|
|
736
749
|
ignoreMutation() { return false; }
|
|
737
750
|
get overrideDOMText() { return null; }
|
|
738
751
|
coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
|
|
752
|
+
get isEditable() { return true; }
|
|
753
|
+
}
|
|
754
|
+
// These are drawn around uneditable widgets to avoid a number of
|
|
755
|
+
// browser bugs that show up when the cursor is directly next to
|
|
756
|
+
// uneditable inline content.
|
|
757
|
+
class WidgetBufferView extends InlineView {
|
|
758
|
+
constructor(side) {
|
|
759
|
+
super();
|
|
760
|
+
this.side = side;
|
|
761
|
+
}
|
|
762
|
+
get length() { return 0; }
|
|
763
|
+
merge() { return false; }
|
|
764
|
+
become(other) {
|
|
765
|
+
return other instanceof WidgetBufferView && other.side == this.side;
|
|
766
|
+
}
|
|
767
|
+
slice() { return new WidgetBufferView(this.side); }
|
|
768
|
+
sync() {
|
|
769
|
+
if (!this.dom)
|
|
770
|
+
this.setDOM(document.createTextNode("\u200b"));
|
|
771
|
+
else if (this.dirty && this.dom.nodeValue != "\u200b")
|
|
772
|
+
this.dom.nodeValue = "\u200b";
|
|
773
|
+
}
|
|
774
|
+
getSide() { return this.side; }
|
|
775
|
+
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
776
|
+
domBoundsAround() { return null; }
|
|
777
|
+
coordsAt(pos) {
|
|
778
|
+
let rects = clientRectsFor(this.dom);
|
|
779
|
+
return rects[rects.length - 1];
|
|
780
|
+
}
|
|
781
|
+
get overrideDOMText() {
|
|
782
|
+
return text.Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]);
|
|
783
|
+
}
|
|
739
784
|
}
|
|
740
785
|
function mergeInlineChildren(parent, from, to, elts, openStart, openEnd) {
|
|
741
786
|
let cur = parent.childCursor();
|
|
@@ -1231,14 +1276,17 @@ class LineView extends ContentView {
|
|
|
1231
1276
|
}
|
|
1232
1277
|
// Only called when building a line view in ContentBuilder
|
|
1233
1278
|
addLineDeco(deco) {
|
|
1234
|
-
let attrs = deco.spec.attributes;
|
|
1279
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1235
1280
|
if (attrs)
|
|
1236
1281
|
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1282
|
+
if (cls)
|
|
1283
|
+
this.attrs = combineAttrs(attrs, { class: cls });
|
|
1237
1284
|
}
|
|
1238
1285
|
domAtPos(pos) {
|
|
1239
1286
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
1240
1287
|
}
|
|
1241
1288
|
sync(track) {
|
|
1289
|
+
var _a;
|
|
1242
1290
|
if (!this.dom || (this.dirty & 4 /* Attrs */)) {
|
|
1243
1291
|
this.setDOM(document.createElement("div"));
|
|
1244
1292
|
this.dom.className = "cm-line";
|
|
@@ -1254,7 +1302,7 @@ class LineView extends ContentView {
|
|
|
1254
1302
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1255
1303
|
last = last.lastChild;
|
|
1256
1304
|
if (!last ||
|
|
1257
|
-
last.nodeName != "BR" && ContentView.get(last)
|
|
1305
|
+
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1258
1306
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1259
1307
|
let hack = document.createElement("BR");
|
|
1260
1308
|
hack.cmIgnore = true;
|
|
@@ -1353,6 +1401,9 @@ class ContentBuilder {
|
|
|
1353
1401
|
this.content = [];
|
|
1354
1402
|
this.curLine = null;
|
|
1355
1403
|
this.breakAtStart = 0;
|
|
1404
|
+
this.pendingBuffer = 0 /* No */;
|
|
1405
|
+
// Set to false directly after a widget that covers the position after it
|
|
1406
|
+
this.atCursorPos = true;
|
|
1356
1407
|
this.openStart = -1;
|
|
1357
1408
|
this.openEnd = -1;
|
|
1358
1409
|
this.text = "";
|
|
@@ -1367,23 +1418,31 @@ class ContentBuilder {
|
|
|
1367
1418
|
return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == exports.BlockType.WidgetBefore);
|
|
1368
1419
|
}
|
|
1369
1420
|
getLine() {
|
|
1370
|
-
if (!this.curLine)
|
|
1421
|
+
if (!this.curLine) {
|
|
1371
1422
|
this.content.push(this.curLine = new LineView);
|
|
1423
|
+
this.atCursorPos = true;
|
|
1424
|
+
}
|
|
1372
1425
|
return this.curLine;
|
|
1373
1426
|
}
|
|
1374
|
-
|
|
1427
|
+
flushBuffer(active) {
|
|
1428
|
+
if (this.pendingBuffer) {
|
|
1429
|
+
this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
|
|
1430
|
+
this.pendingBuffer = 0 /* No */;
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
addBlockWidget(view) {
|
|
1434
|
+
this.flushBuffer([]);
|
|
1375
1435
|
this.curLine = null;
|
|
1376
1436
|
this.content.push(view);
|
|
1377
1437
|
}
|
|
1378
|
-
finish() {
|
|
1438
|
+
finish(openEnd) {
|
|
1439
|
+
if (!openEnd)
|
|
1440
|
+
this.flushBuffer([]);
|
|
1441
|
+
else
|
|
1442
|
+
this.pendingBuffer = 0 /* No */;
|
|
1379
1443
|
if (!this.posCovered())
|
|
1380
1444
|
this.getLine();
|
|
1381
1445
|
}
|
|
1382
|
-
wrapMarks(view, active) {
|
|
1383
|
-
for (let mark of active)
|
|
1384
|
-
view = new MarkView(mark, [view], view.length);
|
|
1385
|
-
return view;
|
|
1386
|
-
}
|
|
1387
1446
|
buildText(length, active, openStart) {
|
|
1388
1447
|
while (length > 0) {
|
|
1389
1448
|
if (this.textOff == this.text.length) {
|
|
@@ -1398,6 +1457,7 @@ class ContentBuilder {
|
|
|
1398
1457
|
this.content[this.content.length - 1].breakAfter = 1;
|
|
1399
1458
|
else
|
|
1400
1459
|
this.breakAtStart = 1;
|
|
1460
|
+
this.flushBuffer([]);
|
|
1401
1461
|
this.curLine = null;
|
|
1402
1462
|
length--;
|
|
1403
1463
|
continue;
|
|
@@ -1408,7 +1468,9 @@ class ContentBuilder {
|
|
|
1408
1468
|
}
|
|
1409
1469
|
}
|
|
1410
1470
|
let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */);
|
|
1411
|
-
this.
|
|
1471
|
+
this.flushBuffer(active);
|
|
1472
|
+
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1473
|
+
this.atCursorPos = true;
|
|
1412
1474
|
this.textOff += take;
|
|
1413
1475
|
length -= take;
|
|
1414
1476
|
openStart = 0;
|
|
@@ -1427,11 +1489,23 @@ class ContentBuilder {
|
|
|
1427
1489
|
let { type } = deco;
|
|
1428
1490
|
if (type == exports.BlockType.WidgetAfter && !this.posCovered())
|
|
1429
1491
|
this.getLine();
|
|
1430
|
-
this.
|
|
1492
|
+
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1431
1493
|
}
|
|
1432
1494
|
else {
|
|
1433
|
-
let
|
|
1434
|
-
this.
|
|
1495
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1496
|
+
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1497
|
+
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1498
|
+
let line = this.getLine();
|
|
1499
|
+
if (this.pendingBuffer == 2 /* IfCursor */ && !cursorBefore)
|
|
1500
|
+
this.pendingBuffer = 0 /* No */;
|
|
1501
|
+
this.flushBuffer(active);
|
|
1502
|
+
if (cursorBefore) {
|
|
1503
|
+
line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
|
|
1504
|
+
openStart = active.length + Math.max(0, openStart - active.length);
|
|
1505
|
+
}
|
|
1506
|
+
line.append(wrapMarks(view, active), openStart);
|
|
1507
|
+
this.atCursorPos = cursorAfter;
|
|
1508
|
+
this.pendingBuffer = !cursorAfter ? 0 /* No */ : from < to ? 1 /* Yes */ : 2 /* IfCursor */;
|
|
1435
1509
|
}
|
|
1436
1510
|
}
|
|
1437
1511
|
else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
|
|
@@ -1457,10 +1531,15 @@ class ContentBuilder {
|
|
|
1457
1531
|
builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder);
|
|
1458
1532
|
if (builder.openStart < 0)
|
|
1459
1533
|
builder.openStart = builder.openEnd;
|
|
1460
|
-
builder.finish();
|
|
1534
|
+
builder.finish(builder.openEnd);
|
|
1461
1535
|
return builder;
|
|
1462
1536
|
}
|
|
1463
1537
|
}
|
|
1538
|
+
function wrapMarks(view, active) {
|
|
1539
|
+
for (let mark of active)
|
|
1540
|
+
view = new MarkView(mark, [view], view.length);
|
|
1541
|
+
return view;
|
|
1542
|
+
}
|
|
1464
1543
|
class NullWidget extends WidgetType {
|
|
1465
1544
|
constructor(tag) {
|
|
1466
1545
|
super();
|
|
@@ -1907,6 +1986,14 @@ class DocView extends ContentView {
|
|
|
1907
1986
|
return true;
|
|
1908
1987
|
}
|
|
1909
1988
|
}
|
|
1989
|
+
reset(sel) {
|
|
1990
|
+
if (this.dirty) {
|
|
1991
|
+
this.view.observer.ignore(() => this.view.docView.sync());
|
|
1992
|
+
this.dirty = 0 /* Not */;
|
|
1993
|
+
}
|
|
1994
|
+
if (sel)
|
|
1995
|
+
this.updateSelection();
|
|
1996
|
+
}
|
|
1910
1997
|
// Used both by update and checkLayout do perform the actual DOM
|
|
1911
1998
|
// update
|
|
1912
1999
|
updateInner(changes, deco, oldLength, forceSelection = false, pointerSel = false) {
|
|
@@ -2036,6 +2123,14 @@ class DocView extends ContentView {
|
|
|
2036
2123
|
!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
|
2037
2124
|
!isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
|
2038
2125
|
this.view.observer.ignore(() => {
|
|
2126
|
+
// Chrome Android will hide the virtual keyboard when tapping
|
|
2127
|
+
// inside an uneditable node, and not bring it back when we
|
|
2128
|
+
// move the cursor to its proper position. This tries to
|
|
2129
|
+
// restore the keyboard by cycling focus.
|
|
2130
|
+
if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, this.dom)) {
|
|
2131
|
+
this.dom.blur();
|
|
2132
|
+
this.dom.focus({ preventScroll: true });
|
|
2133
|
+
}
|
|
2039
2134
|
let rawSel = getSelection(this.root);
|
|
2040
2135
|
if (main.empty) {
|
|
2041
2136
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
|
|
@@ -2343,6 +2438,14 @@ function findChangedDeco(a, b, diff) {
|
|
|
2343
2438
|
rangeset.RangeSet.compare(a, b, diff, comp);
|
|
2344
2439
|
return comp.changes;
|
|
2345
2440
|
}
|
|
2441
|
+
function inUneditable(node, inside) {
|
|
2442
|
+
for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
|
|
2443
|
+
if (cur.nodeType == 1 && cur.contentEditable == 'false') {
|
|
2444
|
+
return true;
|
|
2445
|
+
}
|
|
2446
|
+
}
|
|
2447
|
+
return false;
|
|
2448
|
+
}
|
|
2346
2449
|
|
|
2347
2450
|
/**
|
|
2348
2451
|
Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
@@ -2789,6 +2892,7 @@ function domPosInText(node, x, y) {
|
|
|
2789
2892
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
2790
2893
|
}
|
|
2791
2894
|
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2895
|
+
var _a;
|
|
2792
2896
|
let content = view.contentDOM.getBoundingClientRect(), block;
|
|
2793
2897
|
let halfLine = view.defaultLineHeight / 2;
|
|
2794
2898
|
for (let bounced = false;;) {
|
|
@@ -2819,7 +2923,7 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
2819
2923
|
// There's visible editor content under the point, so we can try
|
|
2820
2924
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
2821
2925
|
let node, offset = -1;
|
|
2822
|
-
if (element && view.contentDOM.contains(element) &&
|
|
2926
|
+
if (element && view.contentDOM.contains(element) && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
|
|
2823
2927
|
if (doc.caretPositionFromPoint) {
|
|
2824
2928
|
let pos = doc.caretPositionFromPoint(x, y);
|
|
2825
2929
|
if (pos)
|
|
@@ -2960,7 +3064,23 @@ class InputState {
|
|
|
2960
3064
|
constructor(view) {
|
|
2961
3065
|
this.lastKeyCode = 0;
|
|
2962
3066
|
this.lastKeyTime = 0;
|
|
2963
|
-
|
|
3067
|
+
// On iOS, some keys need to have their default behavior happen
|
|
3068
|
+
// (after which we retroactively handle them and reset the DOM) to
|
|
3069
|
+
// avoid messing up the virtual keyboard state.
|
|
3070
|
+
//
|
|
3071
|
+
// On Chrome Android, backspace near widgets is just completely
|
|
3072
|
+
// broken, and there are no key events, so we need to handle the
|
|
3073
|
+
// beforeinput event. Deleting stuff will often create a flurry of
|
|
3074
|
+
// events, and interrupting it before it is done just makes
|
|
3075
|
+
// subsequent events even more broken, so again, we hold off doing
|
|
3076
|
+
// anything until the browser is finished with whatever it is trying
|
|
3077
|
+
// to do.
|
|
3078
|
+
//
|
|
3079
|
+
// setPendingKey sets this, causing the DOM observer to pause for a
|
|
3080
|
+
// bit, and setting an animation frame (which seems the most
|
|
3081
|
+
// reliable way to detect 'browser is done flailing') to fire a fake
|
|
3082
|
+
// key event and re-sync the view again.
|
|
3083
|
+
this.pendingKey = undefined;
|
|
2964
3084
|
this.lastSelectionOrigin = null;
|
|
2965
3085
|
this.lastSelectionTime = 0;
|
|
2966
3086
|
this.lastEscPress = 0;
|
|
@@ -3069,20 +3189,27 @@ class InputState {
|
|
|
3069
3189
|
// state. So we let it go through, and then, in
|
|
3070
3190
|
// applyDOMChange, notify key handlers of it and reset to
|
|
3071
3191
|
// the state they produce.
|
|
3072
|
-
|
|
3192
|
+
let pending;
|
|
3193
|
+
if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
|
|
3073
3194
|
!(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
|
|
3074
|
-
this.
|
|
3075
|
-
setTimeout(() => this.flushIOSKey(view), 250);
|
|
3195
|
+
this.setPendingKey(view, pending);
|
|
3076
3196
|
return true;
|
|
3077
3197
|
}
|
|
3078
3198
|
return false;
|
|
3079
3199
|
}
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3200
|
+
setPendingKey(view, pending) {
|
|
3201
|
+
this.pendingKey = pending;
|
|
3202
|
+
requestAnimationFrame(() => {
|
|
3203
|
+
if (!this.pendingKey)
|
|
3204
|
+
return false;
|
|
3205
|
+
let key = this.pendingKey;
|
|
3206
|
+
this.pendingKey = undefined;
|
|
3207
|
+
view.observer.processRecords();
|
|
3208
|
+
let startState = view.state;
|
|
3209
|
+
dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3210
|
+
if (view.state == startState)
|
|
3211
|
+
view.docView.reset(true);
|
|
3212
|
+
});
|
|
3086
3213
|
}
|
|
3087
3214
|
ignoreDuringComposition(event) {
|
|
3088
3215
|
if (!/^key/.test(event.type))
|
|
@@ -3129,6 +3256,11 @@ class InputState {
|
|
|
3129
3256
|
this.mouseSelection.destroy();
|
|
3130
3257
|
}
|
|
3131
3258
|
}
|
|
3259
|
+
const PendingKeys = [
|
|
3260
|
+
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3261
|
+
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
3262
|
+
{ key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
|
|
3263
|
+
];
|
|
3132
3264
|
// Key codes for modifier keys
|
|
3133
3265
|
const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
|
3134
3266
|
class MouseSelection {
|
|
@@ -3574,6 +3706,31 @@ handlers.compositionend = view => {
|
|
|
3574
3706
|
handlers.contextmenu = view => {
|
|
3575
3707
|
view.inputState.lastContextMenu = Date.now();
|
|
3576
3708
|
};
|
|
3709
|
+
handlers.beforeinput = (view, event) => {
|
|
3710
|
+
var _a;
|
|
3711
|
+
// Because Chrome Android doesn't fire useful key events, use
|
|
3712
|
+
// beforeinput to detect backspace (and possibly enter and delete,
|
|
3713
|
+
// but those usually don't even seem to fire beforeinput events at
|
|
3714
|
+
// the moment) and fake a key event for it.
|
|
3715
|
+
//
|
|
3716
|
+
// (preventDefault on beforeinput, though supported in the spec,
|
|
3717
|
+
// seems to do nothing at all on Chrome).
|
|
3718
|
+
let pending;
|
|
3719
|
+
if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
|
|
3720
|
+
view.inputState.setPendingKey(view, pending);
|
|
3721
|
+
let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
|
|
3722
|
+
setTimeout(() => {
|
|
3723
|
+
var _a;
|
|
3724
|
+
// Backspacing near uneditable nodes on Chrome Android sometimes
|
|
3725
|
+
// closes the virtual keyboard. This tries to crudely detect
|
|
3726
|
+
// that and refocus to get it back.
|
|
3727
|
+
if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) {
|
|
3728
|
+
view.contentDOM.blur();
|
|
3729
|
+
view.focus();
|
|
3730
|
+
}
|
|
3731
|
+
}, 50);
|
|
3732
|
+
}
|
|
3733
|
+
};
|
|
3577
3734
|
|
|
3578
3735
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line"];
|
|
3579
3736
|
class HeightOracle {
|
|
@@ -4702,7 +4859,7 @@ function buildTheme(main, spec, scopes) {
|
|
|
4702
4859
|
});
|
|
4703
4860
|
}
|
|
4704
4861
|
const baseTheme = buildTheme("." + baseThemeID, {
|
|
4705
|
-
"
|
|
4862
|
+
"&.cm-editor": {
|
|
4706
4863
|
position: "relative !important",
|
|
4707
4864
|
boxSizing: "border-box",
|
|
4708
4865
|
"&.cm-focused": {
|
|
@@ -4911,7 +5068,7 @@ class DOMObserver {
|
|
|
4911
5068
|
this.intersection = new IntersectionObserver(entries => {
|
|
4912
5069
|
if (this.parentCheck < 0)
|
|
4913
5070
|
this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
|
|
4914
|
-
if (entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
5071
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
4915
5072
|
this.intersecting = !this.intersecting;
|
|
4916
5073
|
if (this.intersecting != this.view.inView)
|
|
4917
5074
|
this.onScrollChanged(document.createEvent("Event"));
|
|
@@ -4919,7 +5076,7 @@ class DOMObserver {
|
|
|
4919
5076
|
}, {});
|
|
4920
5077
|
this.intersection.observe(this.dom);
|
|
4921
5078
|
this.gapIntersection = new IntersectionObserver(entries => {
|
|
4922
|
-
if (entries[entries.length - 1].intersectionRatio > 0)
|
|
5079
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
|
|
4923
5080
|
this.onScrollChanged(document.createEvent("Event"));
|
|
4924
5081
|
}, {});
|
|
4925
5082
|
}
|
|
@@ -5053,20 +5210,12 @@ class DOMObserver {
|
|
|
5053
5210
|
this.flush();
|
|
5054
5211
|
}
|
|
5055
5212
|
}
|
|
5056
|
-
|
|
5057
|
-
flush() {
|
|
5058
|
-
if (this.delayedFlush >= 0)
|
|
5059
|
-
return;
|
|
5060
|
-
this.lastFlush = Date.now();
|
|
5213
|
+
processRecords() {
|
|
5061
5214
|
let records = this.queue;
|
|
5062
5215
|
for (let mut of this.observer.takeRecords())
|
|
5063
5216
|
records.push(mut);
|
|
5064
5217
|
if (records.length)
|
|
5065
5218
|
this.queue = [];
|
|
5066
|
-
let selection = this.selectionRange;
|
|
5067
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5068
|
-
if (records.length == 0 && !newSel)
|
|
5069
|
-
return;
|
|
5070
5219
|
let from = -1, to = -1, typeOver = false;
|
|
5071
5220
|
for (let record of records) {
|
|
5072
5221
|
let range = this.readMutation(record);
|
|
@@ -5082,17 +5231,26 @@ class DOMObserver {
|
|
|
5082
5231
|
to = Math.max(range.to, to);
|
|
5083
5232
|
}
|
|
5084
5233
|
}
|
|
5234
|
+
return { from, to, typeOver };
|
|
5235
|
+
}
|
|
5236
|
+
// Apply pending changes, if any
|
|
5237
|
+
flush() {
|
|
5238
|
+
// Completely hold off flushing when pending keys are set—the code
|
|
5239
|
+
// managing those will make sure processRecords is called and the
|
|
5240
|
+
// view is resynchronized after
|
|
5241
|
+
if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
|
|
5242
|
+
return;
|
|
5243
|
+
this.lastFlush = Date.now();
|
|
5244
|
+
let { from, to, typeOver } = this.processRecords();
|
|
5245
|
+
let selection = this.selectionRange;
|
|
5246
|
+
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5247
|
+
if (from < 0 && !newSel)
|
|
5248
|
+
return;
|
|
5085
5249
|
let startState = this.view.state;
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
if (this.view.state == startState)
|
|
5089
|
-
|
|
5090
|
-
this.ignore(() => this.view.docView.sync());
|
|
5091
|
-
this.view.docView.dirty = 0 /* Not */;
|
|
5092
|
-
}
|
|
5093
|
-
if (newSel)
|
|
5094
|
-
this.view.docView.updateSelection();
|
|
5095
|
-
}
|
|
5250
|
+
this.onChange(from, to, typeOver);
|
|
5251
|
+
// The view wasn't updated
|
|
5252
|
+
if (this.view.state == startState)
|
|
5253
|
+
this.view.docView.reset(newSel);
|
|
5096
5254
|
this.clearSelection();
|
|
5097
5255
|
}
|
|
5098
5256
|
readMutation(rec) {
|
|
@@ -5229,9 +5387,9 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5229
5387
|
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5230
5388
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5231
5389
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5232
|
-
dispatchKey(view.contentDOM, "Delete", 46)))
|
|
5233
|
-
browser.ios && view.inputState.flushIOSKey(view))
|
|
5390
|
+
dispatchKey(view.contentDOM, "Delete", 46)))) {
|
|
5234
5391
|
return;
|
|
5392
|
+
}
|
|
5235
5393
|
let text = change.insert.toString();
|
|
5236
5394
|
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5237
5395
|
return;
|
|
@@ -5452,7 +5610,7 @@ class EditorView {
|
|
|
5452
5610
|
this.dom.appendChild(this.scrollDOM);
|
|
5453
5611
|
this._dispatch = config.dispatch || ((tr) => this.update([tr]));
|
|
5454
5612
|
this.dispatch = this.dispatch.bind(this);
|
|
5455
|
-
this.root = (config.root || document);
|
|
5613
|
+
this.root = (config.root || getRoot(config.parent) || document);
|
|
5456
5614
|
this.viewState = new ViewState(config.state || state.EditorState.create());
|
|
5457
5615
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
|
|
5458
5616
|
this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
|
@@ -5720,6 +5878,7 @@ class EditorView {
|
|
|
5720
5878
|
spellcheck: "false",
|
|
5721
5879
|
autocorrect: "off",
|
|
5722
5880
|
autocapitalize: "off",
|
|
5881
|
+
translate: "no",
|
|
5723
5882
|
contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
|
|
5724
5883
|
class: "cm-content",
|
|
5725
5884
|
style: `${browser.tabSize}: ${this.state.tabSize}`,
|
|
@@ -6220,11 +6379,7 @@ class CachedOrder {
|
|
|
6220
6379
|
}
|
|
6221
6380
|
}
|
|
6222
6381
|
|
|
6223
|
-
const currentPlatform =
|
|
6224
|
-
: /Mac/.test(navigator.platform) ? "mac"
|
|
6225
|
-
: /Win/.test(navigator.platform) ? "win"
|
|
6226
|
-
: /Linux|X11/.test(navigator.platform) ? "linux"
|
|
6227
|
-
: "key";
|
|
6382
|
+
const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
|
|
6228
6383
|
function normalizeKeyName(name, platform) {
|
|
6229
6384
|
const parts = name.split(/-(?!$)/);
|
|
6230
6385
|
let result = parts[parts.length - 1];
|
|
@@ -6730,7 +6885,7 @@ class MatchDecorator {
|
|
|
6730
6885
|
}
|
|
6731
6886
|
|
|
6732
6887
|
const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
|
6733
|
-
const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6888
|
+
const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6734
6889
|
const Names = {
|
|
6735
6890
|
0: "null",
|
|
6736
6891
|
7: "bell",
|
|
@@ -6745,6 +6900,8 @@ const Names = {
|
|
|
6745
6900
|
8206: "left-to-right mark",
|
|
6746
6901
|
8207: "right-to-left mark",
|
|
6747
6902
|
8232: "line separator",
|
|
6903
|
+
8237: "left-to-right override",
|
|
6904
|
+
8238: "right-to-left override",
|
|
6748
6905
|
8233: "paragraph separator",
|
|
6749
6906
|
65279: "zero width no-break space",
|
|
6750
6907
|
65532: "object replacement"
|
|
@@ -6911,7 +7068,7 @@ DOM class.
|
|
|
6911
7068
|
function highlightActiveLine() {
|
|
6912
7069
|
return activeLineHighlighter;
|
|
6913
7070
|
}
|
|
6914
|
-
const lineDeco = Decoration.line({
|
|
7071
|
+
const lineDeco = Decoration.line({ class: "cm-activeLine" });
|
|
6915
7072
|
const activeLineHighlighter = ViewPlugin.fromClass(class {
|
|
6916
7073
|
constructor(view) {
|
|
6917
7074
|
this.decorations = this.getDeco(view);
|
package/dist/index.d.ts
CHANGED
|
@@ -119,6 +119,10 @@ interface LineDecorationSpec {
|
|
|
119
119
|
[key: string]: string;
|
|
120
120
|
};
|
|
121
121
|
/**
|
|
122
|
+
Shorthand for `{attributes: {class: value}}`.
|
|
123
|
+
*/
|
|
124
|
+
class?: string;
|
|
125
|
+
/**
|
|
122
126
|
Other properties are allowed.
|
|
123
127
|
*/
|
|
124
128
|
[other: string]: any;
|
|
@@ -599,7 +603,9 @@ interface EditorConfig {
|
|
|
599
603
|
/**
|
|
600
604
|
If the view is going to be mounted in a shadow root or document
|
|
601
605
|
other than the one held by the global variable `document` (the
|
|
602
|
-
default), you should pass it here.
|
|
606
|
+
default), you should pass it here. If you provide `parent`, but
|
|
607
|
+
not this option, the editor will automatically look up a root
|
|
608
|
+
from the parent.
|
|
603
609
|
*/
|
|
604
610
|
root?: Document | ShadowRoot;
|
|
605
611
|
/**
|
package/dist/index.js
CHANGED
|
@@ -248,6 +248,14 @@ function contentEditablePlainTextSupported() {
|
|
|
248
248
|
}
|
|
249
249
|
return _plainTextSupported;
|
|
250
250
|
}
|
|
251
|
+
function getRoot(node) {
|
|
252
|
+
while (node) {
|
|
253
|
+
node = node.assignedSlot || node.parentNode;
|
|
254
|
+
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
|
255
|
+
return node;
|
|
256
|
+
}
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
251
259
|
|
|
252
260
|
class DOMPos {
|
|
253
261
|
constructor(node, offset, precise = true) {
|
|
@@ -445,6 +453,7 @@ class ContentView {
|
|
|
445
453
|
(this.breakAfter ? "#" : "");
|
|
446
454
|
}
|
|
447
455
|
static get(node) { return node.cmView; }
|
|
456
|
+
get isEditable() { return true; }
|
|
448
457
|
}
|
|
449
458
|
ContentView.prototype.breakAfter = 0;
|
|
450
459
|
// Remove a DOM node and return its next sibling.
|
|
@@ -492,15 +501,18 @@ const gecko = !ie && /*@__PURE__*//gecko\/(\d+)/i.test(nav.userAgent);
|
|
|
492
501
|
const chrome = !ie && /*@__PURE__*//Chrome\/(\d+)/.exec(nav.userAgent);
|
|
493
502
|
const webkit = "webkitFontSmoothing" in doc.documentElement.style;
|
|
494
503
|
const safari = !ie && /*@__PURE__*//Apple Computer/.test(nav.vendor);
|
|
504
|
+
const ios = safari && (/*@__PURE__*//Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
|
|
495
505
|
var browser = {
|
|
496
|
-
mac: /*@__PURE__*//Mac/.test(nav.platform),
|
|
506
|
+
mac: ios || /*@__PURE__*//Mac/.test(nav.platform),
|
|
507
|
+
windows: /*@__PURE__*//Win/.test(nav.platform),
|
|
508
|
+
linux: /*@__PURE__*//Linux|X11/.test(nav.platform),
|
|
497
509
|
ie,
|
|
498
510
|
ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
|
|
499
511
|
gecko,
|
|
500
512
|
gecko_version: gecko ? +(/*@__PURE__*//Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
|
501
513
|
chrome: !!chrome,
|
|
502
514
|
chrome_version: chrome ? +chrome[1] : 0,
|
|
503
|
-
ios
|
|
515
|
+
ios,
|
|
504
516
|
android: /*@__PURE__*//Android\b/.test(nav.userAgent),
|
|
505
517
|
webkit,
|
|
506
518
|
safari,
|
|
@@ -722,6 +734,7 @@ class WidgetView extends InlineView {
|
|
|
722
734
|
}
|
|
723
735
|
return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0);
|
|
724
736
|
}
|
|
737
|
+
get isEditable() { return false; }
|
|
725
738
|
}
|
|
726
739
|
class CompositionView extends WidgetView {
|
|
727
740
|
domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
|
|
@@ -733,6 +746,38 @@ class CompositionView extends WidgetView {
|
|
|
733
746
|
ignoreMutation() { return false; }
|
|
734
747
|
get overrideDOMText() { return null; }
|
|
735
748
|
coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
|
|
749
|
+
get isEditable() { return true; }
|
|
750
|
+
}
|
|
751
|
+
// These are drawn around uneditable widgets to avoid a number of
|
|
752
|
+
// browser bugs that show up when the cursor is directly next to
|
|
753
|
+
// uneditable inline content.
|
|
754
|
+
class WidgetBufferView extends InlineView {
|
|
755
|
+
constructor(side) {
|
|
756
|
+
super();
|
|
757
|
+
this.side = side;
|
|
758
|
+
}
|
|
759
|
+
get length() { return 0; }
|
|
760
|
+
merge() { return false; }
|
|
761
|
+
become(other) {
|
|
762
|
+
return other instanceof WidgetBufferView && other.side == this.side;
|
|
763
|
+
}
|
|
764
|
+
slice() { return new WidgetBufferView(this.side); }
|
|
765
|
+
sync() {
|
|
766
|
+
if (!this.dom)
|
|
767
|
+
this.setDOM(document.createTextNode("\u200b"));
|
|
768
|
+
else if (this.dirty && this.dom.nodeValue != "\u200b")
|
|
769
|
+
this.dom.nodeValue = "\u200b";
|
|
770
|
+
}
|
|
771
|
+
getSide() { return this.side; }
|
|
772
|
+
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
773
|
+
domBoundsAround() { return null; }
|
|
774
|
+
coordsAt(pos) {
|
|
775
|
+
let rects = clientRectsFor(this.dom);
|
|
776
|
+
return rects[rects.length - 1];
|
|
777
|
+
}
|
|
778
|
+
get overrideDOMText() {
|
|
779
|
+
return Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]);
|
|
780
|
+
}
|
|
736
781
|
}
|
|
737
782
|
function mergeInlineChildren(parent, from, to, elts, openStart, openEnd) {
|
|
738
783
|
let cur = parent.childCursor();
|
|
@@ -1227,14 +1272,17 @@ class LineView extends ContentView {
|
|
|
1227
1272
|
}
|
|
1228
1273
|
// Only called when building a line view in ContentBuilder
|
|
1229
1274
|
addLineDeco(deco) {
|
|
1230
|
-
let attrs = deco.spec.attributes;
|
|
1275
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1231
1276
|
if (attrs)
|
|
1232
1277
|
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1278
|
+
if (cls)
|
|
1279
|
+
this.attrs = combineAttrs(attrs, { class: cls });
|
|
1233
1280
|
}
|
|
1234
1281
|
domAtPos(pos) {
|
|
1235
1282
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
1236
1283
|
}
|
|
1237
1284
|
sync(track) {
|
|
1285
|
+
var _a;
|
|
1238
1286
|
if (!this.dom || (this.dirty & 4 /* Attrs */)) {
|
|
1239
1287
|
this.setDOM(document.createElement("div"));
|
|
1240
1288
|
this.dom.className = "cm-line";
|
|
@@ -1250,7 +1298,7 @@ class LineView extends ContentView {
|
|
|
1250
1298
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1251
1299
|
last = last.lastChild;
|
|
1252
1300
|
if (!last ||
|
|
1253
|
-
last.nodeName != "BR" && ContentView.get(last)
|
|
1301
|
+
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1254
1302
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1255
1303
|
let hack = document.createElement("BR");
|
|
1256
1304
|
hack.cmIgnore = true;
|
|
@@ -1349,6 +1397,9 @@ class ContentBuilder {
|
|
|
1349
1397
|
this.content = [];
|
|
1350
1398
|
this.curLine = null;
|
|
1351
1399
|
this.breakAtStart = 0;
|
|
1400
|
+
this.pendingBuffer = 0 /* No */;
|
|
1401
|
+
// Set to false directly after a widget that covers the position after it
|
|
1402
|
+
this.atCursorPos = true;
|
|
1352
1403
|
this.openStart = -1;
|
|
1353
1404
|
this.openEnd = -1;
|
|
1354
1405
|
this.text = "";
|
|
@@ -1363,23 +1414,31 @@ class ContentBuilder {
|
|
|
1363
1414
|
return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == BlockType.WidgetBefore);
|
|
1364
1415
|
}
|
|
1365
1416
|
getLine() {
|
|
1366
|
-
if (!this.curLine)
|
|
1417
|
+
if (!this.curLine) {
|
|
1367
1418
|
this.content.push(this.curLine = new LineView);
|
|
1419
|
+
this.atCursorPos = true;
|
|
1420
|
+
}
|
|
1368
1421
|
return this.curLine;
|
|
1369
1422
|
}
|
|
1370
|
-
|
|
1423
|
+
flushBuffer(active) {
|
|
1424
|
+
if (this.pendingBuffer) {
|
|
1425
|
+
this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
|
|
1426
|
+
this.pendingBuffer = 0 /* No */;
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
addBlockWidget(view) {
|
|
1430
|
+
this.flushBuffer([]);
|
|
1371
1431
|
this.curLine = null;
|
|
1372
1432
|
this.content.push(view);
|
|
1373
1433
|
}
|
|
1374
|
-
finish() {
|
|
1434
|
+
finish(openEnd) {
|
|
1435
|
+
if (!openEnd)
|
|
1436
|
+
this.flushBuffer([]);
|
|
1437
|
+
else
|
|
1438
|
+
this.pendingBuffer = 0 /* No */;
|
|
1375
1439
|
if (!this.posCovered())
|
|
1376
1440
|
this.getLine();
|
|
1377
1441
|
}
|
|
1378
|
-
wrapMarks(view, active) {
|
|
1379
|
-
for (let mark of active)
|
|
1380
|
-
view = new MarkView(mark, [view], view.length);
|
|
1381
|
-
return view;
|
|
1382
|
-
}
|
|
1383
1442
|
buildText(length, active, openStart) {
|
|
1384
1443
|
while (length > 0) {
|
|
1385
1444
|
if (this.textOff == this.text.length) {
|
|
@@ -1394,6 +1453,7 @@ class ContentBuilder {
|
|
|
1394
1453
|
this.content[this.content.length - 1].breakAfter = 1;
|
|
1395
1454
|
else
|
|
1396
1455
|
this.breakAtStart = 1;
|
|
1456
|
+
this.flushBuffer([]);
|
|
1397
1457
|
this.curLine = null;
|
|
1398
1458
|
length--;
|
|
1399
1459
|
continue;
|
|
@@ -1404,7 +1464,9 @@ class ContentBuilder {
|
|
|
1404
1464
|
}
|
|
1405
1465
|
}
|
|
1406
1466
|
let take = Math.min(this.text.length - this.textOff, length, 512 /* Chunk */);
|
|
1407
|
-
this.
|
|
1467
|
+
this.flushBuffer(active);
|
|
1468
|
+
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1469
|
+
this.atCursorPos = true;
|
|
1408
1470
|
this.textOff += take;
|
|
1409
1471
|
length -= take;
|
|
1410
1472
|
openStart = 0;
|
|
@@ -1423,11 +1485,23 @@ class ContentBuilder {
|
|
|
1423
1485
|
let { type } = deco;
|
|
1424
1486
|
if (type == BlockType.WidgetAfter && !this.posCovered())
|
|
1425
1487
|
this.getLine();
|
|
1426
|
-
this.
|
|
1488
|
+
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
|
1427
1489
|
}
|
|
1428
1490
|
else {
|
|
1429
|
-
let
|
|
1430
|
-
this.
|
|
1491
|
+
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
|
1492
|
+
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
|
1493
|
+
let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
|
1494
|
+
let line = this.getLine();
|
|
1495
|
+
if (this.pendingBuffer == 2 /* IfCursor */ && !cursorBefore)
|
|
1496
|
+
this.pendingBuffer = 0 /* No */;
|
|
1497
|
+
this.flushBuffer(active);
|
|
1498
|
+
if (cursorBefore) {
|
|
1499
|
+
line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
|
|
1500
|
+
openStart = active.length + Math.max(0, openStart - active.length);
|
|
1501
|
+
}
|
|
1502
|
+
line.append(wrapMarks(view, active), openStart);
|
|
1503
|
+
this.atCursorPos = cursorAfter;
|
|
1504
|
+
this.pendingBuffer = !cursorAfter ? 0 /* No */ : from < to ? 1 /* Yes */ : 2 /* IfCursor */;
|
|
1431
1505
|
}
|
|
1432
1506
|
}
|
|
1433
1507
|
else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
|
|
@@ -1453,10 +1527,15 @@ class ContentBuilder {
|
|
|
1453
1527
|
builder.openEnd = RangeSet.spans(decorations, from, to, builder);
|
|
1454
1528
|
if (builder.openStart < 0)
|
|
1455
1529
|
builder.openStart = builder.openEnd;
|
|
1456
|
-
builder.finish();
|
|
1530
|
+
builder.finish(builder.openEnd);
|
|
1457
1531
|
return builder;
|
|
1458
1532
|
}
|
|
1459
1533
|
}
|
|
1534
|
+
function wrapMarks(view, active) {
|
|
1535
|
+
for (let mark of active)
|
|
1536
|
+
view = new MarkView(mark, [view], view.length);
|
|
1537
|
+
return view;
|
|
1538
|
+
}
|
|
1460
1539
|
class NullWidget extends WidgetType {
|
|
1461
1540
|
constructor(tag) {
|
|
1462
1541
|
super();
|
|
@@ -1903,6 +1982,14 @@ class DocView extends ContentView {
|
|
|
1903
1982
|
return true;
|
|
1904
1983
|
}
|
|
1905
1984
|
}
|
|
1985
|
+
reset(sel) {
|
|
1986
|
+
if (this.dirty) {
|
|
1987
|
+
this.view.observer.ignore(() => this.view.docView.sync());
|
|
1988
|
+
this.dirty = 0 /* Not */;
|
|
1989
|
+
}
|
|
1990
|
+
if (sel)
|
|
1991
|
+
this.updateSelection();
|
|
1992
|
+
}
|
|
1906
1993
|
// Used both by update and checkLayout do perform the actual DOM
|
|
1907
1994
|
// update
|
|
1908
1995
|
updateInner(changes, deco, oldLength, forceSelection = false, pointerSel = false) {
|
|
@@ -2032,6 +2119,14 @@ class DocView extends ContentView {
|
|
|
2032
2119
|
!isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
|
2033
2120
|
!isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
|
2034
2121
|
this.view.observer.ignore(() => {
|
|
2122
|
+
// Chrome Android will hide the virtual keyboard when tapping
|
|
2123
|
+
// inside an uneditable node, and not bring it back when we
|
|
2124
|
+
// move the cursor to its proper position. This tries to
|
|
2125
|
+
// restore the keyboard by cycling focus.
|
|
2126
|
+
if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, this.dom)) {
|
|
2127
|
+
this.dom.blur();
|
|
2128
|
+
this.dom.focus({ preventScroll: true });
|
|
2129
|
+
}
|
|
2035
2130
|
let rawSel = getSelection(this.root);
|
|
2036
2131
|
if (main.empty) {
|
|
2037
2132
|
// Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
|
|
@@ -2339,6 +2434,14 @@ function findChangedDeco(a, b, diff) {
|
|
|
2339
2434
|
RangeSet.compare(a, b, diff, comp);
|
|
2340
2435
|
return comp.changes;
|
|
2341
2436
|
}
|
|
2437
|
+
function inUneditable(node, inside) {
|
|
2438
|
+
for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
|
|
2439
|
+
if (cur.nodeType == 1 && cur.contentEditable == 'false') {
|
|
2440
|
+
return true;
|
|
2441
|
+
}
|
|
2442
|
+
}
|
|
2443
|
+
return false;
|
|
2444
|
+
}
|
|
2342
2445
|
|
|
2343
2446
|
/**
|
|
2344
2447
|
Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
@@ -2784,6 +2887,7 @@ function domPosInText(node, x, y) {
|
|
|
2784
2887
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
2785
2888
|
}
|
|
2786
2889
|
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2890
|
+
var _a;
|
|
2787
2891
|
let content = view.contentDOM.getBoundingClientRect(), block;
|
|
2788
2892
|
let halfLine = view.defaultLineHeight / 2;
|
|
2789
2893
|
for (let bounced = false;;) {
|
|
@@ -2814,7 +2918,7 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
2814
2918
|
// There's visible editor content under the point, so we can try
|
|
2815
2919
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
2816
2920
|
let node, offset = -1;
|
|
2817
|
-
if (element && view.contentDOM.contains(element) &&
|
|
2921
|
+
if (element && view.contentDOM.contains(element) && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
|
|
2818
2922
|
if (doc.caretPositionFromPoint) {
|
|
2819
2923
|
let pos = doc.caretPositionFromPoint(x, y);
|
|
2820
2924
|
if (pos)
|
|
@@ -2955,7 +3059,23 @@ class InputState {
|
|
|
2955
3059
|
constructor(view) {
|
|
2956
3060
|
this.lastKeyCode = 0;
|
|
2957
3061
|
this.lastKeyTime = 0;
|
|
2958
|
-
|
|
3062
|
+
// On iOS, some keys need to have their default behavior happen
|
|
3063
|
+
// (after which we retroactively handle them and reset the DOM) to
|
|
3064
|
+
// avoid messing up the virtual keyboard state.
|
|
3065
|
+
//
|
|
3066
|
+
// On Chrome Android, backspace near widgets is just completely
|
|
3067
|
+
// broken, and there are no key events, so we need to handle the
|
|
3068
|
+
// beforeinput event. Deleting stuff will often create a flurry of
|
|
3069
|
+
// events, and interrupting it before it is done just makes
|
|
3070
|
+
// subsequent events even more broken, so again, we hold off doing
|
|
3071
|
+
// anything until the browser is finished with whatever it is trying
|
|
3072
|
+
// to do.
|
|
3073
|
+
//
|
|
3074
|
+
// setPendingKey sets this, causing the DOM observer to pause for a
|
|
3075
|
+
// bit, and setting an animation frame (which seems the most
|
|
3076
|
+
// reliable way to detect 'browser is done flailing') to fire a fake
|
|
3077
|
+
// key event and re-sync the view again.
|
|
3078
|
+
this.pendingKey = undefined;
|
|
2959
3079
|
this.lastSelectionOrigin = null;
|
|
2960
3080
|
this.lastSelectionTime = 0;
|
|
2961
3081
|
this.lastEscPress = 0;
|
|
@@ -3064,20 +3184,27 @@ class InputState {
|
|
|
3064
3184
|
// state. So we let it go through, and then, in
|
|
3065
3185
|
// applyDOMChange, notify key handlers of it and reset to
|
|
3066
3186
|
// the state they produce.
|
|
3067
|
-
|
|
3187
|
+
let pending;
|
|
3188
|
+
if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
|
|
3068
3189
|
!(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
|
|
3069
|
-
this.
|
|
3070
|
-
setTimeout(() => this.flushIOSKey(view), 250);
|
|
3190
|
+
this.setPendingKey(view, pending);
|
|
3071
3191
|
return true;
|
|
3072
3192
|
}
|
|
3073
3193
|
return false;
|
|
3074
3194
|
}
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3195
|
+
setPendingKey(view, pending) {
|
|
3196
|
+
this.pendingKey = pending;
|
|
3197
|
+
requestAnimationFrame(() => {
|
|
3198
|
+
if (!this.pendingKey)
|
|
3199
|
+
return false;
|
|
3200
|
+
let key = this.pendingKey;
|
|
3201
|
+
this.pendingKey = undefined;
|
|
3202
|
+
view.observer.processRecords();
|
|
3203
|
+
let startState = view.state;
|
|
3204
|
+
dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3205
|
+
if (view.state == startState)
|
|
3206
|
+
view.docView.reset(true);
|
|
3207
|
+
});
|
|
3081
3208
|
}
|
|
3082
3209
|
ignoreDuringComposition(event) {
|
|
3083
3210
|
if (!/^key/.test(event.type))
|
|
@@ -3124,6 +3251,11 @@ class InputState {
|
|
|
3124
3251
|
this.mouseSelection.destroy();
|
|
3125
3252
|
}
|
|
3126
3253
|
}
|
|
3254
|
+
const PendingKeys = [
|
|
3255
|
+
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3256
|
+
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
3257
|
+
{ key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
|
|
3258
|
+
];
|
|
3127
3259
|
// Key codes for modifier keys
|
|
3128
3260
|
const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
|
3129
3261
|
class MouseSelection {
|
|
@@ -3569,6 +3701,31 @@ handlers.compositionend = view => {
|
|
|
3569
3701
|
handlers.contextmenu = view => {
|
|
3570
3702
|
view.inputState.lastContextMenu = Date.now();
|
|
3571
3703
|
};
|
|
3704
|
+
handlers.beforeinput = (view, event) => {
|
|
3705
|
+
var _a;
|
|
3706
|
+
// Because Chrome Android doesn't fire useful key events, use
|
|
3707
|
+
// beforeinput to detect backspace (and possibly enter and delete,
|
|
3708
|
+
// but those usually don't even seem to fire beforeinput events at
|
|
3709
|
+
// the moment) and fake a key event for it.
|
|
3710
|
+
//
|
|
3711
|
+
// (preventDefault on beforeinput, though supported in the spec,
|
|
3712
|
+
// seems to do nothing at all on Chrome).
|
|
3713
|
+
let pending;
|
|
3714
|
+
if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
|
|
3715
|
+
view.inputState.setPendingKey(view, pending);
|
|
3716
|
+
let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
|
|
3717
|
+
setTimeout(() => {
|
|
3718
|
+
var _a;
|
|
3719
|
+
// Backspacing near uneditable nodes on Chrome Android sometimes
|
|
3720
|
+
// closes the virtual keyboard. This tries to crudely detect
|
|
3721
|
+
// that and refocus to get it back.
|
|
3722
|
+
if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) {
|
|
3723
|
+
view.contentDOM.blur();
|
|
3724
|
+
view.focus();
|
|
3725
|
+
}
|
|
3726
|
+
}, 50);
|
|
3727
|
+
}
|
|
3728
|
+
};
|
|
3572
3729
|
|
|
3573
3730
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line"];
|
|
3574
3731
|
class HeightOracle {
|
|
@@ -4696,7 +4853,7 @@ function buildTheme(main, spec, scopes) {
|
|
|
4696
4853
|
});
|
|
4697
4854
|
}
|
|
4698
4855
|
const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
4699
|
-
"
|
|
4856
|
+
"&.cm-editor": {
|
|
4700
4857
|
position: "relative !important",
|
|
4701
4858
|
boxSizing: "border-box",
|
|
4702
4859
|
"&.cm-focused": {
|
|
@@ -4905,7 +5062,7 @@ class DOMObserver {
|
|
|
4905
5062
|
this.intersection = new IntersectionObserver(entries => {
|
|
4906
5063
|
if (this.parentCheck < 0)
|
|
4907
5064
|
this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
|
|
4908
|
-
if (entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
5065
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0 != this.intersecting) {
|
|
4909
5066
|
this.intersecting = !this.intersecting;
|
|
4910
5067
|
if (this.intersecting != this.view.inView)
|
|
4911
5068
|
this.onScrollChanged(document.createEvent("Event"));
|
|
@@ -4913,7 +5070,7 @@ class DOMObserver {
|
|
|
4913
5070
|
}, {});
|
|
4914
5071
|
this.intersection.observe(this.dom);
|
|
4915
5072
|
this.gapIntersection = new IntersectionObserver(entries => {
|
|
4916
|
-
if (entries[entries.length - 1].intersectionRatio > 0)
|
|
5073
|
+
if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
|
|
4917
5074
|
this.onScrollChanged(document.createEvent("Event"));
|
|
4918
5075
|
}, {});
|
|
4919
5076
|
}
|
|
@@ -5047,20 +5204,12 @@ class DOMObserver {
|
|
|
5047
5204
|
this.flush();
|
|
5048
5205
|
}
|
|
5049
5206
|
}
|
|
5050
|
-
|
|
5051
|
-
flush() {
|
|
5052
|
-
if (this.delayedFlush >= 0)
|
|
5053
|
-
return;
|
|
5054
|
-
this.lastFlush = Date.now();
|
|
5207
|
+
processRecords() {
|
|
5055
5208
|
let records = this.queue;
|
|
5056
5209
|
for (let mut of this.observer.takeRecords())
|
|
5057
5210
|
records.push(mut);
|
|
5058
5211
|
if (records.length)
|
|
5059
5212
|
this.queue = [];
|
|
5060
|
-
let selection = this.selectionRange;
|
|
5061
|
-
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5062
|
-
if (records.length == 0 && !newSel)
|
|
5063
|
-
return;
|
|
5064
5213
|
let from = -1, to = -1, typeOver = false;
|
|
5065
5214
|
for (let record of records) {
|
|
5066
5215
|
let range = this.readMutation(record);
|
|
@@ -5076,17 +5225,26 @@ class DOMObserver {
|
|
|
5076
5225
|
to = Math.max(range.to, to);
|
|
5077
5226
|
}
|
|
5078
5227
|
}
|
|
5228
|
+
return { from, to, typeOver };
|
|
5229
|
+
}
|
|
5230
|
+
// Apply pending changes, if any
|
|
5231
|
+
flush() {
|
|
5232
|
+
// Completely hold off flushing when pending keys are set—the code
|
|
5233
|
+
// managing those will make sure processRecords is called and the
|
|
5234
|
+
// view is resynchronized after
|
|
5235
|
+
if (this.delayedFlush >= 0 || this.view.inputState.pendingKey)
|
|
5236
|
+
return;
|
|
5237
|
+
this.lastFlush = Date.now();
|
|
5238
|
+
let { from, to, typeOver } = this.processRecords();
|
|
5239
|
+
let selection = this.selectionRange;
|
|
5240
|
+
let newSel = !this.ignoreSelection.eq(selection) && hasSelection(this.dom, selection);
|
|
5241
|
+
if (from < 0 && !newSel)
|
|
5242
|
+
return;
|
|
5079
5243
|
let startState = this.view.state;
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
if (this.view.state == startState)
|
|
5083
|
-
|
|
5084
|
-
this.ignore(() => this.view.docView.sync());
|
|
5085
|
-
this.view.docView.dirty = 0 /* Not */;
|
|
5086
|
-
}
|
|
5087
|
-
if (newSel)
|
|
5088
|
-
this.view.docView.updateSelection();
|
|
5089
|
-
}
|
|
5244
|
+
this.onChange(from, to, typeOver);
|
|
5245
|
+
// The view wasn't updated
|
|
5246
|
+
if (this.view.state == startState)
|
|
5247
|
+
this.view.docView.reset(newSel);
|
|
5090
5248
|
this.clearSelection();
|
|
5091
5249
|
}
|
|
5092
5250
|
readMutation(rec) {
|
|
@@ -5223,9 +5381,9 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5223
5381
|
(change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
|
5224
5382
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
5225
5383
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
5226
|
-
dispatchKey(view.contentDOM, "Delete", 46)))
|
|
5227
|
-
browser.ios && view.inputState.flushIOSKey(view))
|
|
5384
|
+
dispatchKey(view.contentDOM, "Delete", 46)))) {
|
|
5228
5385
|
return;
|
|
5386
|
+
}
|
|
5229
5387
|
let text = change.insert.toString();
|
|
5230
5388
|
if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
|
5231
5389
|
return;
|
|
@@ -5446,7 +5604,7 @@ class EditorView {
|
|
|
5446
5604
|
this.dom.appendChild(this.scrollDOM);
|
|
5447
5605
|
this._dispatch = config.dispatch || ((tr) => this.update([tr]));
|
|
5448
5606
|
this.dispatch = this.dispatch.bind(this);
|
|
5449
|
-
this.root = (config.root || document);
|
|
5607
|
+
this.root = (config.root || getRoot(config.parent) || document);
|
|
5450
5608
|
this.viewState = new ViewState(config.state || EditorState.create());
|
|
5451
5609
|
this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
|
|
5452
5610
|
this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
|
@@ -5714,6 +5872,7 @@ class EditorView {
|
|
|
5714
5872
|
spellcheck: "false",
|
|
5715
5873
|
autocorrect: "off",
|
|
5716
5874
|
autocapitalize: "off",
|
|
5875
|
+
translate: "no",
|
|
5717
5876
|
contenteditable: !this.state.facet(editable) ? "false" : contentEditablePlainTextSupported() ? "plaintext-only" : "true",
|
|
5718
5877
|
class: "cm-content",
|
|
5719
5878
|
style: `${browser.tabSize}: ${this.state.tabSize}`,
|
|
@@ -6214,11 +6373,7 @@ class CachedOrder {
|
|
|
6214
6373
|
}
|
|
6215
6374
|
}
|
|
6216
6375
|
|
|
6217
|
-
const currentPlatform =
|
|
6218
|
-
: /*@__PURE__*//Mac/.test(navigator.platform) ? "mac"
|
|
6219
|
-
: /*@__PURE__*//Win/.test(navigator.platform) ? "win"
|
|
6220
|
-
: /*@__PURE__*//Linux|X11/.test(navigator.platform) ? "linux"
|
|
6221
|
-
: "key";
|
|
6376
|
+
const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
|
|
6222
6377
|
function normalizeKeyName(name, platform) {
|
|
6223
6378
|
const parts = name.split(/-(?!$)/);
|
|
6224
6379
|
let result = parts[parts.length - 1];
|
|
@@ -6724,7 +6879,7 @@ class MatchDecorator {
|
|
|
6724
6879
|
}
|
|
6725
6880
|
|
|
6726
6881
|
const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
|
6727
|
-
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6882
|
+
const Specials = /*@__PURE__*/new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
|
6728
6883
|
const Names = {
|
|
6729
6884
|
0: "null",
|
|
6730
6885
|
7: "bell",
|
|
@@ -6739,6 +6894,8 @@ const Names = {
|
|
|
6739
6894
|
8206: "left-to-right mark",
|
|
6740
6895
|
8207: "right-to-left mark",
|
|
6741
6896
|
8232: "line separator",
|
|
6897
|
+
8237: "left-to-right override",
|
|
6898
|
+
8238: "right-to-left override",
|
|
6742
6899
|
8233: "paragraph separator",
|
|
6743
6900
|
65279: "zero width no-break space",
|
|
6744
6901
|
65532: "object replacement"
|
|
@@ -6905,7 +7062,7 @@ DOM class.
|
|
|
6905
7062
|
function highlightActiveLine() {
|
|
6906
7063
|
return activeLineHighlighter;
|
|
6907
7064
|
}
|
|
6908
|
-
const lineDeco = /*@__PURE__*/Decoration.line({
|
|
7065
|
+
const lineDeco = /*@__PURE__*/Decoration.line({ class: "cm-activeLine" });
|
|
6909
7066
|
const activeLineHighlighter = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
6910
7067
|
constructor(view) {
|
|
6911
7068
|
this.decorations = this.getDeco(view);
|