@codemirror/view 6.43.11 → 6.43.13
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 +22 -0
- package/dist/index.cjs +91 -38
- package/dist/index.d.cts +3 -4
- package/dist/index.d.ts +3 -4
- package/dist/index.js +91 -38
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 6.43.13 (2026-09-22)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make `coordsAtPos` (and thus also the drawn cursor) return the outside of the line when the queried side points out of the line and there is non-dominant-direction text at that side.
|
|
6
|
+
|
|
7
|
+
`visualLineSide`, which is now deprecated because it doesn't do anything non-trivial, now just returns the logical line side, since that is actually the more correct thing to do when moving to the start or end of line.
|
|
8
|
+
|
|
9
|
+
`moveVisually` now uses positions at the logical start/end of the line to represent the first/last position in the line when the text at that side isn't int he line's dominant text direction.
|
|
10
|
+
|
|
11
|
+
## 6.43.12 (2026-09-15)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Make `visualLineSide` use bidi information when looking for the start or end of line with no wrap points.
|
|
16
|
+
|
|
17
|
+
Fix a bug in updating the DOM for marks around an active composition that could sometimes try to use the same DOM node twice.
|
|
18
|
+
|
|
19
|
+
Work around an issue on Firefox where a composition might be started outside of a line container.
|
|
20
|
+
|
|
21
|
+
Make sure repeated screen reader announcement messages don't get swallowed by VoiceOver.
|
|
22
|
+
|
|
1
23
|
## 6.43.11 (2026-09-03)
|
|
2
24
|
|
|
3
25
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -1273,10 +1273,12 @@ let movedOver = "";
|
|
|
1273
1273
|
// This implementation moves strictly visually, without concern for a
|
|
1274
1274
|
// traversal visiting every logical position in the string. It will
|
|
1275
1275
|
// still do so for simple input, but situations like multiple isolates
|
|
1276
|
-
// with the same level next to each other
|
|
1277
|
-
// main dir at the end of the line, will make some positions
|
|
1276
|
+
// with the same level next to each other will make some positions
|
|
1278
1277
|
// unreachable with this motion. Each visible cursor position will
|
|
1279
|
-
// correspond to the lower-level bidi span that touches it
|
|
1278
|
+
// correspond to the lower-level bidi span that touches it, except
|
|
1279
|
+
// positions at start/end of line, when the text there isn't in the
|
|
1280
|
+
// dominant direction, which will use a cursor at the start/end with
|
|
1281
|
+
// an an assoc pointing out of the line instead.
|
|
1280
1282
|
//
|
|
1281
1283
|
// The alternative would be to solve an order globally for a given
|
|
1282
1284
|
// line, making sure that it includes every position, but that would
|
|
@@ -1285,8 +1287,22 @@ let movedOver = "";
|
|
|
1285
1287
|
// people. (And would generally be a lot more complicated.)
|
|
1286
1288
|
function moveVisually(line, order, dir, start, forward) {
|
|
1287
1289
|
var _a;
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
+
if (!line.length)
|
|
1291
|
+
return null;
|
|
1292
|
+
let startIndex = start.head - line.from, spanI;
|
|
1293
|
+
if (start.head == line.from && start.assoc < 0) { // Start of line.
|
|
1294
|
+
if (!forward)
|
|
1295
|
+
return null;
|
|
1296
|
+
startIndex = order[spanI = 0].side(false, dir);
|
|
1297
|
+
}
|
|
1298
|
+
else if (start.head == line.to && start.assoc > 0) { // End of line
|
|
1299
|
+
if (forward)
|
|
1300
|
+
return null;
|
|
1301
|
+
startIndex = order[spanI = order.length - 1].side(true, dir);
|
|
1302
|
+
}
|
|
1303
|
+
else {
|
|
1304
|
+
spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
|
|
1305
|
+
}
|
|
1290
1306
|
let span = order[spanI], spanEnd = span.side(forward, dir);
|
|
1291
1307
|
// End of span
|
|
1292
1308
|
if (startIndex == spanEnd) {
|
|
@@ -1302,8 +1318,13 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
1302
1318
|
nextIndex = spanEnd;
|
|
1303
1319
|
movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
|
|
1304
1320
|
let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
|
|
1305
|
-
if (
|
|
1306
|
-
|
|
1321
|
+
if (nextIndex == spanEnd) {
|
|
1322
|
+
// End of line
|
|
1323
|
+
if (!nextSpan)
|
|
1324
|
+
return forward ? state.EditorSelection.cursor(line.to, 1) : state.EditorSelection.cursor(line.from, -1);
|
|
1325
|
+
if (nextSpan.level + (forward ? 0 : 1) < span.level)
|
|
1326
|
+
return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
|
|
1327
|
+
}
|
|
1307
1328
|
return state.EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
|
|
1308
1329
|
}
|
|
1309
1330
|
function autoDirection(text, from, to) {
|
|
@@ -2323,12 +2344,13 @@ class TileBuilder {
|
|
|
2323
2344
|
head = last;
|
|
2324
2345
|
}
|
|
2325
2346
|
else {
|
|
2347
|
+
let { dom } = mark;
|
|
2326
2348
|
if (this.cache.reused.get(mark)) {
|
|
2327
2349
|
let tile = Tile.get(mark.dom);
|
|
2328
2350
|
if (tile)
|
|
2329
|
-
|
|
2351
|
+
dom = freeNode(mark.dom);
|
|
2330
2352
|
}
|
|
2331
|
-
let nw = MarkTile.of(mark.mark,
|
|
2353
|
+
let nw = MarkTile.of(mark.mark, dom);
|
|
2332
2354
|
head.append(nw);
|
|
2333
2355
|
head = nw;
|
|
2334
2356
|
}
|
|
@@ -2828,12 +2850,14 @@ class TileUpdate {
|
|
|
2828
2850
|
else if (tile === null || tile === void 0 ? void 0 : tile.isLine())
|
|
2829
2851
|
line = tile;
|
|
2830
2852
|
else if (tile instanceof BlockWrapperTile) ; // Ignore
|
|
2831
|
-
else if (parent.nodeName == "DIV" && !line
|
|
2853
|
+
else if (parent.nodeName == "DIV" && !line)
|
|
2832
2854
|
line = new LineTile(parent, lineBaseAttrs);
|
|
2833
2855
|
else if (!line)
|
|
2834
2856
|
marks.push(MarkTile.of(new MarkDecoration({ tagName: parent.nodeName.toLowerCase(), attributes: getAttrs(parent) }), parent));
|
|
2835
2857
|
}
|
|
2836
|
-
|
|
2858
|
+
if (!line)
|
|
2859
|
+
return null;
|
|
2860
|
+
return { line, marks };
|
|
2837
2861
|
}
|
|
2838
2862
|
}
|
|
2839
2863
|
function hasContent(tile, requireText) {
|
|
@@ -3664,18 +3688,18 @@ function blockAt(view, pos, side) {
|
|
|
3664
3688
|
return line;
|
|
3665
3689
|
}
|
|
3666
3690
|
function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
3667
|
-
let
|
|
3668
|
-
let coords = !includeWrap ||
|
|
3669
|
-
: view.coordsAtPos(start.assoc < 0 && start.head >
|
|
3691
|
+
let block = blockAt(view, start.head, start.assoc || -1);
|
|
3692
|
+
let coords = !includeWrap || block.type != exports.BlockType.Text || !(view.lineWrapping || block.widgetLineBreaks) ? null
|
|
3693
|
+
: view.coordsAtPos(start.assoc < 0 && start.head > block.from ? start.head - 1 : start.head);
|
|
3670
3694
|
if (coords) {
|
|
3671
3695
|
let editorRect = view.dom.getBoundingClientRect();
|
|
3672
|
-
let direction = view.textDirectionAt(
|
|
3696
|
+
let direction = view.textDirectionAt(block.from);
|
|
3673
3697
|
let pos = view.posAtCoords({ x: forward == (direction == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
|
|
3674
3698
|
y: (coords.top + coords.bottom) / 2 });
|
|
3675
3699
|
if (pos != null)
|
|
3676
3700
|
return state.EditorSelection.cursor(pos, forward ? -1 : 1);
|
|
3677
3701
|
}
|
|
3678
|
-
return state.EditorSelection.cursor(forward ?
|
|
3702
|
+
return state.EditorSelection.cursor(forward ? block.to : block.from, forward ? -1 : 1);
|
|
3679
3703
|
}
|
|
3680
3704
|
function moveByChar(view, start, forward, by) {
|
|
3681
3705
|
let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
|
|
@@ -3688,7 +3712,7 @@ function moveByChar(view, start, forward, by) {
|
|
|
3688
3712
|
char = "\n";
|
|
3689
3713
|
line = view.state.doc.line(line.number + (forward ? 1 : -1));
|
|
3690
3714
|
spans = view.bidiSpans(line);
|
|
3691
|
-
next =
|
|
3715
|
+
next = forward ? state.EditorSelection.cursor(line.from, -1) : state.EditorSelection.cursor(line.to, 1);
|
|
3692
3716
|
}
|
|
3693
3717
|
if (!check) {
|
|
3694
3718
|
if (!by)
|
|
@@ -4476,7 +4500,9 @@ function selectionFromPoints(points, base) {
|
|
|
4476
4500
|
if (points.length == 0)
|
|
4477
4501
|
return null;
|
|
4478
4502
|
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
4479
|
-
return anchor
|
|
4503
|
+
return anchor < 0 || head < 0 ? null
|
|
4504
|
+
: anchor == head ? state.EditorSelection.create([state.EditorSelection.cursor(head + base, -1)])
|
|
4505
|
+
: state.EditorSelection.single(anchor + base, head + base);
|
|
4480
4506
|
}
|
|
4481
4507
|
function sameSelPos(selection, range) {
|
|
4482
4508
|
return range.head == selection.main.head && range.anchor == selection.main.anchor;
|
|
@@ -4628,8 +4654,9 @@ class InputState {
|
|
|
4628
4654
|
if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
|
|
4629
4655
|
iosVirtualKeyboardOpen(this.view.win))
|
|
4630
4656
|
mods.shiftKey = false;
|
|
4631
|
-
this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
|
|
4632
|
-
setTimeout(() => this.
|
|
4657
|
+
let pending = this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
|
|
4658
|
+
setTimeout(() => { if (this.pendingIOSKey == pending)
|
|
4659
|
+
this.flushIOSKey(); }, 50);
|
|
4633
4660
|
return true;
|
|
4634
4661
|
}
|
|
4635
4662
|
if (event.keyCode != 229)
|
|
@@ -4918,14 +4945,14 @@ function doPaste(view, input) {
|
|
|
4918
4945
|
lastLine = line.from;
|
|
4919
4946
|
let insert = state$1.toText((byLine ? text.line(i++).text : input) + state$1.lineBreak);
|
|
4920
4947
|
return { changes: { from: line.from, insert },
|
|
4921
|
-
range: state.EditorSelection.cursor(range.from + insert.length) };
|
|
4948
|
+
range: state.EditorSelection.cursor(range.from + insert.length, -1) };
|
|
4922
4949
|
});
|
|
4923
4950
|
}
|
|
4924
4951
|
else if (byLine) {
|
|
4925
4952
|
changes = state$1.changeByRange(range => {
|
|
4926
4953
|
let line = text.line(i++);
|
|
4927
4954
|
return { changes: { from: range.from, to: range.to, insert: line.text },
|
|
4928
|
-
range: state.EditorSelection.cursor(range.from + line.length) };
|
|
4955
|
+
range: state.EditorSelection.cursor(range.from + line.length, -1) };
|
|
4929
4956
|
});
|
|
4930
4957
|
}
|
|
4931
4958
|
else {
|
|
@@ -5263,6 +5290,13 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
5263
5290
|
if (view.inputState.compositionFirstChange == null)
|
|
5264
5291
|
view.inputState.compositionFirstChange = true;
|
|
5265
5292
|
if (view.inputState.composing < 0) {
|
|
5293
|
+
let { main } = view.state.selection;
|
|
5294
|
+
if (!main.empty && view.lineBlockAt(main.from).from != view.lineBlockAt(main.to).from) {
|
|
5295
|
+
view.dispatch({
|
|
5296
|
+
changes: view.state.selection.ranges.filter(r => !r.empty).map(r => ({ from: r.from, to: r.to })),
|
|
5297
|
+
userEvent: "input"
|
|
5298
|
+
});
|
|
5299
|
+
}
|
|
5266
5300
|
// FIXME possibly set a timeout to clear it again on Android
|
|
5267
5301
|
view.inputState.composing = 0;
|
|
5268
5302
|
}
|
|
@@ -5615,13 +5649,13 @@ class HeightMap {
|
|
|
5615
5649
|
after += next.size;
|
|
5616
5650
|
}
|
|
5617
5651
|
}
|
|
5618
|
-
let brk =
|
|
5652
|
+
let brk = false;
|
|
5619
5653
|
if (nodes[i - 1] == null) {
|
|
5620
|
-
brk =
|
|
5654
|
+
brk = true;
|
|
5621
5655
|
i--;
|
|
5622
5656
|
}
|
|
5623
5657
|
else if (nodes[i] == null) {
|
|
5624
|
-
brk =
|
|
5658
|
+
brk = true;
|
|
5625
5659
|
j++;
|
|
5626
5660
|
}
|
|
5627
5661
|
return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
|
|
@@ -5850,12 +5884,14 @@ class HeightMapGap extends HeightMap {
|
|
|
5850
5884
|
}
|
|
5851
5885
|
class HeightMapBranch extends HeightMap {
|
|
5852
5886
|
constructor(left, brk, right) {
|
|
5853
|
-
super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
|
|
5887
|
+
super(left.length + (brk ? 1 : 0) + right.length, left.height + right.height, (brk ? 1 /* Flag.Break */ : 0) | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
|
|
5854
5888
|
this.left = left;
|
|
5855
5889
|
this.right = right;
|
|
5856
5890
|
this.size = left.size + right.size;
|
|
5857
5891
|
}
|
|
5858
|
-
|
|
5892
|
+
// Returns 1 if there is a line break between this.left and
|
|
5893
|
+
// this.right, 0 otherwise.
|
|
5894
|
+
get break() { return (this.flags & 1 /* Flag.Break */); }
|
|
5859
5895
|
blockAt(height, oracle, top, offset) {
|
|
5860
5896
|
let mid = top + this.left.height;
|
|
5861
5897
|
return height < mid ? this.left.blockAt(height, oracle, top, offset)
|
|
@@ -5885,11 +5921,11 @@ class HeightMapBranch extends HeightMap {
|
|
|
5885
5921
|
else {
|
|
5886
5922
|
let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
|
|
5887
5923
|
if (from < mid.from)
|
|
5888
|
-
this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
|
|
5924
|
+
this.left.forEachLine(from, Math.min(to, mid.from - 1), oracle, top, offset, f);
|
|
5889
5925
|
if (mid.to >= from && mid.from <= to)
|
|
5890
5926
|
f(mid);
|
|
5891
5927
|
if (to > mid.to)
|
|
5892
|
-
this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
|
|
5928
|
+
this.right.forEachLine(Math.max(from, mid.to + 1), to, oracle, rightTop, rightOffset, f);
|
|
5893
5929
|
}
|
|
5894
5930
|
}
|
|
5895
5931
|
replace(from, to, nodes) {
|
|
@@ -7896,6 +7932,7 @@ class EditorView {
|
|
|
7896
7932
|
@internal
|
|
7897
7933
|
*/
|
|
7898
7934
|
this.measureRequests = [];
|
|
7935
|
+
this.clearAnnouncement = -1;
|
|
7899
7936
|
this.contentDOM = document.createElement("div");
|
|
7900
7937
|
this.scrollDOM = document.createElement("div");
|
|
7901
7938
|
this.scrollDOM.tabIndex = -1;
|
|
@@ -8301,9 +8338,14 @@ class EditorView {
|
|
|
8301
8338
|
for (let tr of trs)
|
|
8302
8339
|
for (let effect of tr.effects)
|
|
8303
8340
|
if (effect.is(EditorView.announce)) {
|
|
8304
|
-
if (first)
|
|
8341
|
+
if (first) {
|
|
8305
8342
|
this.announceDOM.textContent = "";
|
|
8306
|
-
|
|
8343
|
+
this.win.clearTimeout(this.clearAnnouncement);
|
|
8344
|
+
this.clearAnnouncement = this.win.setTimeout(() => {
|
|
8345
|
+
this.announceDOM.textContent = "\u00a0";
|
|
8346
|
+
}, 200);
|
|
8347
|
+
first = false;
|
|
8348
|
+
}
|
|
8307
8349
|
let div = this.announceDOM.appendChild(document.createElement("div"));
|
|
8308
8350
|
div.textContent = effect.value;
|
|
8309
8351
|
}
|
|
@@ -8452,15 +8494,11 @@ class EditorView {
|
|
|
8452
8494
|
return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
|
|
8453
8495
|
}
|
|
8454
8496
|
/**
|
|
8455
|
-
Get the cursor position visually at the start
|
|
8456
|
-
|
|
8457
|
-
start or end (which is simply at `line.from`/`line.to`) if text
|
|
8458
|
-
at the start or end goes against the line's base text direction.
|
|
8497
|
+
**\[DEPRECATED]** Get the cursor position visually at the start
|
|
8498
|
+
or end of a line.
|
|
8459
8499
|
*/
|
|
8460
8500
|
visualLineSide(line, end) {
|
|
8461
|
-
|
|
8462
|
-
let span = order[end ? order.length - 1 : 0];
|
|
8463
|
-
return state.EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
|
|
8501
|
+
return end ? state.EditorSelection.cursor(line.to, 1) : state.EditorSelection.cursor(line.from, -1);
|
|
8464
8502
|
}
|
|
8465
8503
|
/**
|
|
8466
8504
|
Move to the next line boundary in the given direction. If
|
|
@@ -8529,6 +8567,20 @@ class EditorView {
|
|
|
8529
8567
|
this.readMeasured();
|
|
8530
8568
|
let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
|
|
8531
8569
|
let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
|
|
8570
|
+
// For positions at start/end of line, if the side points out of
|
|
8571
|
+
// the line and the text there isn't in the dominant dir, return
|
|
8572
|
+
// the position of the outermost character on the line.
|
|
8573
|
+
if (line.length && (pos == line.from && side < 0 || pos == line.to && side > 0) &&
|
|
8574
|
+
span.dir != this.textDirectionAt(line.from)) {
|
|
8575
|
+
if (pos == line.to) {
|
|
8576
|
+
pos = line.from + span.from;
|
|
8577
|
+
side = 1;
|
|
8578
|
+
}
|
|
8579
|
+
else {
|
|
8580
|
+
pos = line.from + span.to;
|
|
8581
|
+
side = -1;
|
|
8582
|
+
}
|
|
8583
|
+
}
|
|
8532
8584
|
return this.docView.coordsAt(pos, side, span.dir == exports.Direction.RTL);
|
|
8533
8585
|
}
|
|
8534
8586
|
/**
|
|
@@ -8653,6 +8705,7 @@ class EditorView {
|
|
|
8653
8705
|
this.docView.destroy();
|
|
8654
8706
|
this.dom.remove();
|
|
8655
8707
|
this.observer.destroy();
|
|
8708
|
+
this.win.clearTimeout(this.clearAnnouncement);
|
|
8656
8709
|
if (this.measureScheduled > -1)
|
|
8657
8710
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
8658
8711
|
this.destroyed = true;
|
package/dist/index.d.cts
CHANGED
|
@@ -813,6 +813,7 @@ declare class EditorView {
|
|
|
813
813
|
private styleModules;
|
|
814
814
|
private bidiCache;
|
|
815
815
|
private destroyed;
|
|
816
|
+
private clearAnnouncement;
|
|
816
817
|
/**
|
|
817
818
|
Construct a new view. You'll want to either provide a `parent`
|
|
818
819
|
option, or put `view.dom` into your document after creating a
|
|
@@ -958,10 +959,8 @@ declare class EditorView {
|
|
|
958
959
|
*/
|
|
959
960
|
moveByGroup(start: SelectionRange, forward: boolean): SelectionRange;
|
|
960
961
|
/**
|
|
961
|
-
Get the cursor position visually at the start
|
|
962
|
-
|
|
963
|
-
start or end (which is simply at `line.from`/`line.to`) if text
|
|
964
|
-
at the start or end goes against the line's base text direction.
|
|
962
|
+
**\[DEPRECATED]** Get the cursor position visually at the start
|
|
963
|
+
or end of a line.
|
|
965
964
|
*/
|
|
966
965
|
visualLineSide(line: Line, end: boolean): SelectionRange;
|
|
967
966
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -813,6 +813,7 @@ declare class EditorView {
|
|
|
813
813
|
private styleModules;
|
|
814
814
|
private bidiCache;
|
|
815
815
|
private destroyed;
|
|
816
|
+
private clearAnnouncement;
|
|
816
817
|
/**
|
|
817
818
|
Construct a new view. You'll want to either provide a `parent`
|
|
818
819
|
option, or put `view.dom` into your document after creating a
|
|
@@ -958,10 +959,8 @@ declare class EditorView {
|
|
|
958
959
|
*/
|
|
959
960
|
moveByGroup(start: SelectionRange, forward: boolean): SelectionRange;
|
|
960
961
|
/**
|
|
961
|
-
Get the cursor position visually at the start
|
|
962
|
-
|
|
963
|
-
start or end (which is simply at `line.from`/`line.to`) if text
|
|
964
|
-
at the start or end goes against the line's base text direction.
|
|
962
|
+
**\[DEPRECATED]** Get the cursor position visually at the start
|
|
963
|
+
or end of a line.
|
|
965
964
|
*/
|
|
966
965
|
visualLineSide(line: Line, end: boolean): SelectionRange;
|
|
967
966
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1269,10 +1269,12 @@ let movedOver = "";
|
|
|
1269
1269
|
// This implementation moves strictly visually, without concern for a
|
|
1270
1270
|
// traversal visiting every logical position in the string. It will
|
|
1271
1271
|
// still do so for simple input, but situations like multiple isolates
|
|
1272
|
-
// with the same level next to each other
|
|
1273
|
-
// main dir at the end of the line, will make some positions
|
|
1272
|
+
// with the same level next to each other will make some positions
|
|
1274
1273
|
// unreachable with this motion. Each visible cursor position will
|
|
1275
|
-
// correspond to the lower-level bidi span that touches it
|
|
1274
|
+
// correspond to the lower-level bidi span that touches it, except
|
|
1275
|
+
// positions at start/end of line, when the text there isn't in the
|
|
1276
|
+
// dominant direction, which will use a cursor at the start/end with
|
|
1277
|
+
// an an assoc pointing out of the line instead.
|
|
1276
1278
|
//
|
|
1277
1279
|
// The alternative would be to solve an order globally for a given
|
|
1278
1280
|
// line, making sure that it includes every position, but that would
|
|
@@ -1281,8 +1283,22 @@ let movedOver = "";
|
|
|
1281
1283
|
// people. (And would generally be a lot more complicated.)
|
|
1282
1284
|
function moveVisually(line, order, dir, start, forward) {
|
|
1283
1285
|
var _a;
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
+
if (!line.length)
|
|
1287
|
+
return null;
|
|
1288
|
+
let startIndex = start.head - line.from, spanI;
|
|
1289
|
+
if (start.head == line.from && start.assoc < 0) { // Start of line.
|
|
1290
|
+
if (!forward)
|
|
1291
|
+
return null;
|
|
1292
|
+
startIndex = order[spanI = 0].side(false, dir);
|
|
1293
|
+
}
|
|
1294
|
+
else if (start.head == line.to && start.assoc > 0) { // End of line
|
|
1295
|
+
if (forward)
|
|
1296
|
+
return null;
|
|
1297
|
+
startIndex = order[spanI = order.length - 1].side(true, dir);
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
|
|
1301
|
+
}
|
|
1286
1302
|
let span = order[spanI], spanEnd = span.side(forward, dir);
|
|
1287
1303
|
// End of span
|
|
1288
1304
|
if (startIndex == spanEnd) {
|
|
@@ -1298,8 +1314,13 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
1298
1314
|
nextIndex = spanEnd;
|
|
1299
1315
|
movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
|
|
1300
1316
|
let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
|
|
1301
|
-
if (
|
|
1302
|
-
|
|
1317
|
+
if (nextIndex == spanEnd) {
|
|
1318
|
+
// End of line
|
|
1319
|
+
if (!nextSpan)
|
|
1320
|
+
return forward ? EditorSelection.cursor(line.to, 1) : EditorSelection.cursor(line.from, -1);
|
|
1321
|
+
if (nextSpan.level + (forward ? 0 : 1) < span.level)
|
|
1322
|
+
return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, nextSpan.forward(forward, dir) ? 1 : -1, nextSpan.level);
|
|
1323
|
+
}
|
|
1303
1324
|
return EditorSelection.cursor(nextIndex + line.from, span.forward(forward, dir) ? -1 : 1, span.level);
|
|
1304
1325
|
}
|
|
1305
1326
|
function autoDirection(text, from, to) {
|
|
@@ -2319,12 +2340,13 @@ class TileBuilder {
|
|
|
2319
2340
|
head = last;
|
|
2320
2341
|
}
|
|
2321
2342
|
else {
|
|
2343
|
+
let { dom } = mark;
|
|
2322
2344
|
if (this.cache.reused.get(mark)) {
|
|
2323
2345
|
let tile = Tile.get(mark.dom);
|
|
2324
2346
|
if (tile)
|
|
2325
|
-
|
|
2347
|
+
dom = freeNode(mark.dom);
|
|
2326
2348
|
}
|
|
2327
|
-
let nw = MarkTile.of(mark.mark,
|
|
2349
|
+
let nw = MarkTile.of(mark.mark, dom);
|
|
2328
2350
|
head.append(nw);
|
|
2329
2351
|
head = nw;
|
|
2330
2352
|
}
|
|
@@ -2824,12 +2846,14 @@ class TileUpdate {
|
|
|
2824
2846
|
else if (tile === null || tile === void 0 ? void 0 : tile.isLine())
|
|
2825
2847
|
line = tile;
|
|
2826
2848
|
else if (tile instanceof BlockWrapperTile) ; // Ignore
|
|
2827
|
-
else if (parent.nodeName == "DIV" && !line
|
|
2849
|
+
else if (parent.nodeName == "DIV" && !line)
|
|
2828
2850
|
line = new LineTile(parent, lineBaseAttrs);
|
|
2829
2851
|
else if (!line)
|
|
2830
2852
|
marks.push(MarkTile.of(new MarkDecoration({ tagName: parent.nodeName.toLowerCase(), attributes: getAttrs(parent) }), parent));
|
|
2831
2853
|
}
|
|
2832
|
-
|
|
2854
|
+
if (!line)
|
|
2855
|
+
return null;
|
|
2856
|
+
return { line, marks };
|
|
2833
2857
|
}
|
|
2834
2858
|
}
|
|
2835
2859
|
function hasContent(tile, requireText) {
|
|
@@ -3660,18 +3684,18 @@ function blockAt(view, pos, side) {
|
|
|
3660
3684
|
return line;
|
|
3661
3685
|
}
|
|
3662
3686
|
function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
3663
|
-
let
|
|
3664
|
-
let coords = !includeWrap ||
|
|
3665
|
-
: view.coordsAtPos(start.assoc < 0 && start.head >
|
|
3687
|
+
let block = blockAt(view, start.head, start.assoc || -1);
|
|
3688
|
+
let coords = !includeWrap || block.type != BlockType.Text || !(view.lineWrapping || block.widgetLineBreaks) ? null
|
|
3689
|
+
: view.coordsAtPos(start.assoc < 0 && start.head > block.from ? start.head - 1 : start.head);
|
|
3666
3690
|
if (coords) {
|
|
3667
3691
|
let editorRect = view.dom.getBoundingClientRect();
|
|
3668
|
-
let direction = view.textDirectionAt(
|
|
3692
|
+
let direction = view.textDirectionAt(block.from);
|
|
3669
3693
|
let pos = view.posAtCoords({ x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
|
|
3670
3694
|
y: (coords.top + coords.bottom) / 2 });
|
|
3671
3695
|
if (pos != null)
|
|
3672
3696
|
return EditorSelection.cursor(pos, forward ? -1 : 1);
|
|
3673
3697
|
}
|
|
3674
|
-
return EditorSelection.cursor(forward ?
|
|
3698
|
+
return EditorSelection.cursor(forward ? block.to : block.from, forward ? -1 : 1);
|
|
3675
3699
|
}
|
|
3676
3700
|
function moveByChar(view, start, forward, by) {
|
|
3677
3701
|
let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
|
|
@@ -3684,7 +3708,7 @@ function moveByChar(view, start, forward, by) {
|
|
|
3684
3708
|
char = "\n";
|
|
3685
3709
|
line = view.state.doc.line(line.number + (forward ? 1 : -1));
|
|
3686
3710
|
spans = view.bidiSpans(line);
|
|
3687
|
-
next =
|
|
3711
|
+
next = forward ? EditorSelection.cursor(line.from, -1) : EditorSelection.cursor(line.to, 1);
|
|
3688
3712
|
}
|
|
3689
3713
|
if (!check) {
|
|
3690
3714
|
if (!by)
|
|
@@ -4472,7 +4496,9 @@ function selectionFromPoints(points, base) {
|
|
|
4472
4496
|
if (points.length == 0)
|
|
4473
4497
|
return null;
|
|
4474
4498
|
let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
|
4475
|
-
return anchor
|
|
4499
|
+
return anchor < 0 || head < 0 ? null
|
|
4500
|
+
: anchor == head ? EditorSelection.create([EditorSelection.cursor(head + base, -1)])
|
|
4501
|
+
: EditorSelection.single(anchor + base, head + base);
|
|
4476
4502
|
}
|
|
4477
4503
|
function sameSelPos(selection, range) {
|
|
4478
4504
|
return range.head == selection.main.head && range.anchor == selection.main.anchor;
|
|
@@ -4624,8 +4650,9 @@ class InputState {
|
|
|
4624
4650
|
if (mods.shiftKey && browser.ios && !/^(off|none)$/.test(this.view.contentDOM.autocapitalize) &&
|
|
4625
4651
|
iosVirtualKeyboardOpen(this.view.win))
|
|
4626
4652
|
mods.shiftKey = false;
|
|
4627
|
-
this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
|
|
4628
|
-
setTimeout(() => this.
|
|
4653
|
+
let pending = this.pendingIOSKey = { key: event.key, keyCode: event.keyCode, mods };
|
|
4654
|
+
setTimeout(() => { if (this.pendingIOSKey == pending)
|
|
4655
|
+
this.flushIOSKey(); }, 50);
|
|
4629
4656
|
return true;
|
|
4630
4657
|
}
|
|
4631
4658
|
if (event.keyCode != 229)
|
|
@@ -4914,14 +4941,14 @@ function doPaste(view, input) {
|
|
|
4914
4941
|
lastLine = line.from;
|
|
4915
4942
|
let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
|
|
4916
4943
|
return { changes: { from: line.from, insert },
|
|
4917
|
-
range: EditorSelection.cursor(range.from + insert.length) };
|
|
4944
|
+
range: EditorSelection.cursor(range.from + insert.length, -1) };
|
|
4918
4945
|
});
|
|
4919
4946
|
}
|
|
4920
4947
|
else if (byLine) {
|
|
4921
4948
|
changes = state.changeByRange(range => {
|
|
4922
4949
|
let line = text.line(i++);
|
|
4923
4950
|
return { changes: { from: range.from, to: range.to, insert: line.text },
|
|
4924
|
-
range: EditorSelection.cursor(range.from + line.length) };
|
|
4951
|
+
range: EditorSelection.cursor(range.from + line.length, -1) };
|
|
4925
4952
|
});
|
|
4926
4953
|
}
|
|
4927
4954
|
else {
|
|
@@ -5259,6 +5286,13 @@ observers.compositionstart = observers.compositionupdate = view => {
|
|
|
5259
5286
|
if (view.inputState.compositionFirstChange == null)
|
|
5260
5287
|
view.inputState.compositionFirstChange = true;
|
|
5261
5288
|
if (view.inputState.composing < 0) {
|
|
5289
|
+
let { main } = view.state.selection;
|
|
5290
|
+
if (!main.empty && view.lineBlockAt(main.from).from != view.lineBlockAt(main.to).from) {
|
|
5291
|
+
view.dispatch({
|
|
5292
|
+
changes: view.state.selection.ranges.filter(r => !r.empty).map(r => ({ from: r.from, to: r.to })),
|
|
5293
|
+
userEvent: "input"
|
|
5294
|
+
});
|
|
5295
|
+
}
|
|
5262
5296
|
// FIXME possibly set a timeout to clear it again on Android
|
|
5263
5297
|
view.inputState.composing = 0;
|
|
5264
5298
|
}
|
|
@@ -5610,13 +5644,13 @@ class HeightMap {
|
|
|
5610
5644
|
after += next.size;
|
|
5611
5645
|
}
|
|
5612
5646
|
}
|
|
5613
|
-
let brk =
|
|
5647
|
+
let brk = false;
|
|
5614
5648
|
if (nodes[i - 1] == null) {
|
|
5615
|
-
brk =
|
|
5649
|
+
brk = true;
|
|
5616
5650
|
i--;
|
|
5617
5651
|
}
|
|
5618
5652
|
else if (nodes[i] == null) {
|
|
5619
|
-
brk =
|
|
5653
|
+
brk = true;
|
|
5620
5654
|
j++;
|
|
5621
5655
|
}
|
|
5622
5656
|
return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
|
|
@@ -5845,12 +5879,14 @@ class HeightMapGap extends HeightMap {
|
|
|
5845
5879
|
}
|
|
5846
5880
|
class HeightMapBranch extends HeightMap {
|
|
5847
5881
|
constructor(left, brk, right) {
|
|
5848
|
-
super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
|
|
5882
|
+
super(left.length + (brk ? 1 : 0) + right.length, left.height + right.height, (brk ? 1 /* Flag.Break */ : 0) | (left.outdated || right.outdated ? 2 /* Flag.Outdated */ : 0));
|
|
5849
5883
|
this.left = left;
|
|
5850
5884
|
this.right = right;
|
|
5851
5885
|
this.size = left.size + right.size;
|
|
5852
5886
|
}
|
|
5853
|
-
|
|
5887
|
+
// Returns 1 if there is a line break between this.left and
|
|
5888
|
+
// this.right, 0 otherwise.
|
|
5889
|
+
get break() { return (this.flags & 1 /* Flag.Break */); }
|
|
5854
5890
|
blockAt(height, oracle, top, offset) {
|
|
5855
5891
|
let mid = top + this.left.height;
|
|
5856
5892
|
return height < mid ? this.left.blockAt(height, oracle, top, offset)
|
|
@@ -5880,11 +5916,11 @@ class HeightMapBranch extends HeightMap {
|
|
|
5880
5916
|
else {
|
|
5881
5917
|
let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
|
|
5882
5918
|
if (from < mid.from)
|
|
5883
|
-
this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
|
|
5919
|
+
this.left.forEachLine(from, Math.min(to, mid.from - 1), oracle, top, offset, f);
|
|
5884
5920
|
if (mid.to >= from && mid.from <= to)
|
|
5885
5921
|
f(mid);
|
|
5886
5922
|
if (to > mid.to)
|
|
5887
|
-
this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
|
|
5923
|
+
this.right.forEachLine(Math.max(from, mid.to + 1), to, oracle, rightTop, rightOffset, f);
|
|
5888
5924
|
}
|
|
5889
5925
|
}
|
|
5890
5926
|
replace(from, to, nodes) {
|
|
@@ -7891,6 +7927,7 @@ class EditorView {
|
|
|
7891
7927
|
@internal
|
|
7892
7928
|
*/
|
|
7893
7929
|
this.measureRequests = [];
|
|
7930
|
+
this.clearAnnouncement = -1;
|
|
7894
7931
|
this.contentDOM = document.createElement("div");
|
|
7895
7932
|
this.scrollDOM = document.createElement("div");
|
|
7896
7933
|
this.scrollDOM.tabIndex = -1;
|
|
@@ -8296,9 +8333,14 @@ class EditorView {
|
|
|
8296
8333
|
for (let tr of trs)
|
|
8297
8334
|
for (let effect of tr.effects)
|
|
8298
8335
|
if (effect.is(EditorView.announce)) {
|
|
8299
|
-
if (first)
|
|
8336
|
+
if (first) {
|
|
8300
8337
|
this.announceDOM.textContent = "";
|
|
8301
|
-
|
|
8338
|
+
this.win.clearTimeout(this.clearAnnouncement);
|
|
8339
|
+
this.clearAnnouncement = this.win.setTimeout(() => {
|
|
8340
|
+
this.announceDOM.textContent = "\u00a0";
|
|
8341
|
+
}, 200);
|
|
8342
|
+
first = false;
|
|
8343
|
+
}
|
|
8302
8344
|
let div = this.announceDOM.appendChild(document.createElement("div"));
|
|
8303
8345
|
div.textContent = effect.value;
|
|
8304
8346
|
}
|
|
@@ -8447,15 +8489,11 @@ class EditorView {
|
|
|
8447
8489
|
return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
|
|
8448
8490
|
}
|
|
8449
8491
|
/**
|
|
8450
|
-
Get the cursor position visually at the start
|
|
8451
|
-
|
|
8452
|
-
start or end (which is simply at `line.from`/`line.to`) if text
|
|
8453
|
-
at the start or end goes against the line's base text direction.
|
|
8492
|
+
**\[DEPRECATED]** Get the cursor position visually at the start
|
|
8493
|
+
or end of a line.
|
|
8454
8494
|
*/
|
|
8455
8495
|
visualLineSide(line, end) {
|
|
8456
|
-
|
|
8457
|
-
let span = order[end ? order.length - 1 : 0];
|
|
8458
|
-
return EditorSelection.cursor(span.side(end, dir) + line.from, span.forward(!end, dir) ? 1 : -1);
|
|
8496
|
+
return end ? EditorSelection.cursor(line.to, 1) : EditorSelection.cursor(line.from, -1);
|
|
8459
8497
|
}
|
|
8460
8498
|
/**
|
|
8461
8499
|
Move to the next line boundary in the given direction. If
|
|
@@ -8524,6 +8562,20 @@ class EditorView {
|
|
|
8524
8562
|
this.readMeasured();
|
|
8525
8563
|
let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
|
|
8526
8564
|
let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
|
|
8565
|
+
// For positions at start/end of line, if the side points out of
|
|
8566
|
+
// the line and the text there isn't in the dominant dir, return
|
|
8567
|
+
// the position of the outermost character on the line.
|
|
8568
|
+
if (line.length && (pos == line.from && side < 0 || pos == line.to && side > 0) &&
|
|
8569
|
+
span.dir != this.textDirectionAt(line.from)) {
|
|
8570
|
+
if (pos == line.to) {
|
|
8571
|
+
pos = line.from + span.from;
|
|
8572
|
+
side = 1;
|
|
8573
|
+
}
|
|
8574
|
+
else {
|
|
8575
|
+
pos = line.from + span.to;
|
|
8576
|
+
side = -1;
|
|
8577
|
+
}
|
|
8578
|
+
}
|
|
8527
8579
|
return this.docView.coordsAt(pos, side, span.dir == Direction.RTL);
|
|
8528
8580
|
}
|
|
8529
8581
|
/**
|
|
@@ -8648,6 +8700,7 @@ class EditorView {
|
|
|
8648
8700
|
this.docView.destroy();
|
|
8649
8701
|
this.dom.remove();
|
|
8650
8702
|
this.observer.destroy();
|
|
8703
|
+
this.win.clearTimeout(this.clearAnnouncement);
|
|
8651
8704
|
if (this.measureScheduled > -1)
|
|
8652
8705
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
8653
8706
|
this.destroyed = true;
|