@codemirror/view 6.43.4 → 6.43.5
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 +12 -0
- package/dist/index.cjs +40 -23
- package/dist/index.js +40 -23
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 6.43.5 (2026-07-04)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue what would cause `domAtPos` to return positions on the wrong side of widgets.
|
|
6
|
+
|
|
7
|
+
Fix an issue that could cause the DOM cursor to be drawn on the wrong side of a collapsing decoration.
|
|
8
|
+
|
|
9
|
+
Don't return off-by-one coordinate positions at the edge of right-to-left text node in Safari.
|
|
10
|
+
|
|
11
|
+
Don't abort momentum scrolling on iOS by stabilizing the scroll position.
|
|
12
|
+
|
|
1
13
|
## 6.43.4 (2026-06-27)
|
|
2
14
|
|
|
3
15
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -514,8 +514,11 @@ function scanFor(node, off, targetNode, targetOff, dir) {
|
|
|
514
514
|
function maxOffset(node) {
|
|
515
515
|
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
516
516
|
}
|
|
517
|
-
function flattenRect(rect,
|
|
518
|
-
let
|
|
517
|
+
function flattenRect(rect, toLeft) {
|
|
518
|
+
let { left, right } = rect;
|
|
519
|
+
if (left == right)
|
|
520
|
+
return rect;
|
|
521
|
+
let x = toLeft ? left : right;
|
|
519
522
|
return { left: x, right: x, top: rect.top, bottom: rect.bottom };
|
|
520
523
|
}
|
|
521
524
|
function windowRect(win) {
|
|
@@ -1780,7 +1783,7 @@ class Tile {
|
|
|
1780
1783
|
return this.posBefore(tile) + tile.length;
|
|
1781
1784
|
}
|
|
1782
1785
|
covers(side) { return true; }
|
|
1783
|
-
coordsIn(pos, side) { return null; }
|
|
1786
|
+
coordsIn(pos, side, rtl) { return null; }
|
|
1784
1787
|
domPosFor(off, side) {
|
|
1785
1788
|
let index = domIndex(this.dom);
|
|
1786
1789
|
let after = this.length ? off > 0 : side > 0;
|
|
@@ -1976,7 +1979,7 @@ class LineTile extends CompositeTile {
|
|
|
1976
1979
|
if (child.isComposite()) {
|
|
1977
1980
|
scan(child, pos - off);
|
|
1978
1981
|
}
|
|
1979
|
-
else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) &&
|
|
1982
|
+
else if ((!after || after.isHidden && (side > 0 && !(after.flags & 32 /* TileFlag.After */) || forCoords && onSameLine(after, child))) &&
|
|
1980
1983
|
(end > pos || (child.flags & 32 /* TileFlag.After */))) {
|
|
1981
1984
|
after = child;
|
|
1982
1985
|
afterOff = pos - off;
|
|
@@ -1993,11 +1996,11 @@ class LineTile extends CompositeTile {
|
|
|
1993
1996
|
let target = ((side < 0 ? before : after) || before || after);
|
|
1994
1997
|
return target ? { tile: target, offset: target == before ? beforeOff : afterOff } : null;
|
|
1995
1998
|
}
|
|
1996
|
-
coordsIn(pos, side) {
|
|
1999
|
+
coordsIn(pos, side, rtl) {
|
|
1997
2000
|
let found = this.resolveInline(pos, side, true);
|
|
1998
2001
|
if (!found)
|
|
1999
2002
|
return fallbackRect(this);
|
|
2000
|
-
return found.tile.coordsIn(Math.max(0, found.offset), side);
|
|
2003
|
+
return found.tile.coordsIn(Math.max(0, found.offset), side, rtl);
|
|
2001
2004
|
}
|
|
2002
2005
|
domIn(pos, side) {
|
|
2003
2006
|
let found = this.resolveInline(pos, side);
|
|
@@ -2061,7 +2064,7 @@ class TextTile extends Tile {
|
|
|
2061
2064
|
}
|
|
2062
2065
|
isText() { return true; }
|
|
2063
2066
|
toString() { return JSON.stringify(this.text); }
|
|
2064
|
-
coordsIn(pos, side) {
|
|
2067
|
+
coordsIn(pos, side, rtl) {
|
|
2065
2068
|
let length = this.dom.nodeValue.length;
|
|
2066
2069
|
if (pos > length)
|
|
2067
2070
|
pos = length;
|
|
@@ -2071,7 +2074,7 @@ class TextTile extends Tile {
|
|
|
2071
2074
|
if (pos) {
|
|
2072
2075
|
from--;
|
|
2073
2076
|
flatten = 1;
|
|
2074
|
-
}
|
|
2077
|
+
}
|
|
2075
2078
|
else if (to < length) {
|
|
2076
2079
|
to++;
|
|
2077
2080
|
flatten = -1;
|
|
@@ -2090,7 +2093,7 @@ class TextTile extends Tile {
|
|
|
2090
2093
|
let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
|
|
2091
2094
|
if (browser.safari && !flatten && rect.width == 0)
|
|
2092
2095
|
rect = Array.prototype.find.call(rects, r => r.width) || rect;
|
|
2093
|
-
return
|
|
2096
|
+
return rtl == null ? rect : flattenRect(rect, (flatten ? flatten > 0 : side < 0) == rtl);
|
|
2094
2097
|
}
|
|
2095
2098
|
static of(text, dom) {
|
|
2096
2099
|
let tile = new TextTile(dom || document.createTextNode(text), text);
|
|
@@ -2166,7 +2169,10 @@ class WidgetBufferTile extends Tile {
|
|
|
2166
2169
|
}
|
|
2167
2170
|
get isHidden() { return true; }
|
|
2168
2171
|
get overrideDOMText() { return state.Text.empty; }
|
|
2169
|
-
coordsIn(pos
|
|
2172
|
+
coordsIn(pos, side, rtl) {
|
|
2173
|
+
let rect = this.dom.getBoundingClientRect();
|
|
2174
|
+
return rtl == null ? rect : flattenRect(rect, (side > 0) == rtl);
|
|
2175
|
+
}
|
|
2170
2176
|
}
|
|
2171
2177
|
// Represents a position in the tile tree.
|
|
2172
2178
|
class TilePointer {
|
|
@@ -2528,8 +2534,8 @@ class TileCache {
|
|
|
2528
2534
|
find(cls, test, type = 2 /* Reused.DOM */) {
|
|
2529
2535
|
let i = cls.bucket;
|
|
2530
2536
|
let bucket = this.buckets[i], off = this.index[i];
|
|
2531
|
-
for (let j =
|
|
2532
|
-
// Look at the most
|
|
2537
|
+
for (let j = 0; j < bucket.length; j++) {
|
|
2538
|
+
// Look at the most oldest items first (first-in, first-out)
|
|
2533
2539
|
let index = (j + off) % bucket.length, tile = bucket[index];
|
|
2534
2540
|
if ((!test || test(tile)) && !this.reused.has(tile)) {
|
|
2535
2541
|
bucket.splice(index, 1);
|
|
@@ -3195,7 +3201,7 @@ class DocView {
|
|
|
3195
3201
|
domAtPos(pos, side) {
|
|
3196
3202
|
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3197
3203
|
if (tile.isWidget())
|
|
3198
|
-
return tile.domPosFor(
|
|
3204
|
+
return tile.domPosFor(offset, side);
|
|
3199
3205
|
return tile.domIn(offset, side);
|
|
3200
3206
|
}
|
|
3201
3207
|
inlineDOMNearPos(pos, side) {
|
|
@@ -3232,14 +3238,16 @@ class DocView {
|
|
|
3232
3238
|
after = null;
|
|
3233
3239
|
return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
|
|
3234
3240
|
}
|
|
3235
|
-
|
|
3241
|
+
// Get the coord of the element at the given side of the given
|
|
3242
|
+
// position. If rtl is given, flatten it using that text direction.
|
|
3243
|
+
coordsAt(pos, side, rtl) {
|
|
3236
3244
|
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3237
3245
|
if (tile.isWidget()) {
|
|
3238
3246
|
if (tile.widget instanceof BlockGapWidget)
|
|
3239
3247
|
return null;
|
|
3240
3248
|
return tile.coordsInWidget(offset, side, true);
|
|
3241
3249
|
}
|
|
3242
|
-
return tile.coordsIn(offset, side);
|
|
3250
|
+
return tile.coordsIn(offset, side, rtl);
|
|
3243
3251
|
}
|
|
3244
3252
|
lineAt(pos, side) {
|
|
3245
3253
|
let { tile } = this.tile.resolveBlock(pos, side);
|
|
@@ -3413,7 +3421,6 @@ class DocView {
|
|
|
3413
3421
|
this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
|
|
3414
3422
|
}
|
|
3415
3423
|
scrollIntoView(target) {
|
|
3416
|
-
var _a;
|
|
3417
3424
|
if (target.isSnapshot) {
|
|
3418
3425
|
let ref = this.view.viewState.lineBlockAt(target.range.head);
|
|
3419
3426
|
this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
|
|
@@ -3430,7 +3437,7 @@ class DocView {
|
|
|
3430
3437
|
}
|
|
3431
3438
|
}
|
|
3432
3439
|
let { range } = target;
|
|
3433
|
-
let rect = this.coordsAt(range.head,
|
|
3440
|
+
let rect = this.coordsAt(range.head, range.assoc || (range.head > range.anchor ? -1 : 1)), other;
|
|
3434
3441
|
if (!rect)
|
|
3435
3442
|
return;
|
|
3436
3443
|
if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
|
|
@@ -4472,6 +4479,7 @@ class InputState {
|
|
|
4472
4479
|
this.view = view;
|
|
4473
4480
|
this.lastKeyCode = 0;
|
|
4474
4481
|
this.lastKeyTime = 0;
|
|
4482
|
+
this.touchActive = false;
|
|
4475
4483
|
this.lastTouchTime = 0;
|
|
4476
4484
|
this.lastTouchX = 0;
|
|
4477
4485
|
this.lastTouchY = 0;
|
|
@@ -4483,6 +4491,10 @@ class InputState {
|
|
|
4483
4491
|
// (after which we retroactively handle them and reset the DOM) to
|
|
4484
4492
|
// avoid messing up the virtual keyboard state.
|
|
4485
4493
|
this.pendingIOSKey = undefined;
|
|
4494
|
+
// Set to a time stap by scroll events when touch isn't active on
|
|
4495
|
+
// iOS, to work around an issue where Safari will abort the scroll
|
|
4496
|
+
// momentum if we set scrollTop
|
|
4497
|
+
this.lastIOSMomentumScroll = 0;
|
|
4486
4498
|
// When enabled (>-1), tab presses are not given to key handlers,
|
|
4487
4499
|
// leaving the browser's default behavior. If >0, the mode expires
|
|
4488
4500
|
// at that timestamp, and any other keypress clears it.
|
|
@@ -4913,8 +4925,11 @@ function doPaste(view, input) {
|
|
|
4913
4925
|
});
|
|
4914
4926
|
}
|
|
4915
4927
|
observers.scroll = view => {
|
|
4916
|
-
|
|
4917
|
-
|
|
4928
|
+
let iState = view.inputState;
|
|
4929
|
+
iState.lastScrollTop = view.scrollDOM.scrollTop;
|
|
4930
|
+
iState.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
4931
|
+
if (browser.ios && !iState.touchActive)
|
|
4932
|
+
iState.lastIOSMomentumScroll = Date.now();
|
|
4918
4933
|
};
|
|
4919
4934
|
observers.wheel = observers.mousewheel = view => {
|
|
4920
4935
|
view.inputState.lastWheelEvent = Date.now();
|
|
@@ -4927,6 +4942,7 @@ handlers.keydown = (view, event) => {
|
|
|
4927
4942
|
};
|
|
4928
4943
|
observers.touchstart = (view, e) => {
|
|
4929
4944
|
let iState = view.inputState, touch = e.targetTouches[0];
|
|
4945
|
+
iState.touchActive = true;
|
|
4930
4946
|
iState.lastTouchTime = Date.now();
|
|
4931
4947
|
if (touch) {
|
|
4932
4948
|
iState.lastTouchX = touch.clientX;
|
|
@@ -4937,6 +4953,9 @@ observers.touchstart = (view, e) => {
|
|
|
4937
4953
|
observers.touchmove = view => {
|
|
4938
4954
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4939
4955
|
};
|
|
4956
|
+
observers.touchend = (view, e) => {
|
|
4957
|
+
view.inputState.touchActive = false;
|
|
4958
|
+
};
|
|
4940
4959
|
handlers.mousedown = (view, event) => {
|
|
4941
4960
|
view.observer.flush();
|
|
4942
4961
|
if (view.inputState.lastTouchTime > Date.now() - 2000)
|
|
@@ -8199,6 +8218,7 @@ class EditorView {
|
|
|
8199
8218
|
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
8200
8219
|
let diff = (newAnchorHeight - scrollAnchorHeight) / this.scaleY;
|
|
8201
8220
|
if ((diff > 1 || diff < -1) &&
|
|
8221
|
+
!(browser.ios && this.inputState.lastIOSMomentumScroll > Date.now() - 100) &&
|
|
8202
8222
|
(scroll == this.scrollDOM || this.hasFocus ||
|
|
8203
8223
|
Math.max(this.inputState.lastWheelEvent, this.inputState.lastTouchTime) > Date.now() - 100)) {
|
|
8204
8224
|
scrollOffset = scrollOffset + diff;
|
|
@@ -8490,12 +8510,9 @@ class EditorView {
|
|
|
8490
8510
|
*/
|
|
8491
8511
|
coordsAtPos(pos, side = 1) {
|
|
8492
8512
|
this.readMeasured();
|
|
8493
|
-
let rect = this.docView.coordsAt(pos, side);
|
|
8494
|
-
if (!rect || rect.left == rect.right)
|
|
8495
|
-
return rect;
|
|
8496
8513
|
let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
|
|
8497
8514
|
let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
|
|
8498
|
-
return
|
|
8515
|
+
return this.docView.coordsAt(pos, side, span.dir == exports.Direction.RTL);
|
|
8499
8516
|
}
|
|
8500
8517
|
/**
|
|
8501
8518
|
Return the rectangle around a given character. If `pos` does not
|
package/dist/index.js
CHANGED
|
@@ -511,8 +511,11 @@ function scanFor(node, off, targetNode, targetOff, dir) {
|
|
|
511
511
|
function maxOffset(node) {
|
|
512
512
|
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
513
513
|
}
|
|
514
|
-
function flattenRect(rect,
|
|
515
|
-
let
|
|
514
|
+
function flattenRect(rect, toLeft) {
|
|
515
|
+
let { left, right } = rect;
|
|
516
|
+
if (left == right)
|
|
517
|
+
return rect;
|
|
518
|
+
let x = toLeft ? left : right;
|
|
516
519
|
return { left: x, right: x, top: rect.top, bottom: rect.bottom };
|
|
517
520
|
}
|
|
518
521
|
function windowRect(win) {
|
|
@@ -1776,7 +1779,7 @@ class Tile {
|
|
|
1776
1779
|
return this.posBefore(tile) + tile.length;
|
|
1777
1780
|
}
|
|
1778
1781
|
covers(side) { return true; }
|
|
1779
|
-
coordsIn(pos, side) { return null; }
|
|
1782
|
+
coordsIn(pos, side, rtl) { return null; }
|
|
1780
1783
|
domPosFor(off, side) {
|
|
1781
1784
|
let index = domIndex(this.dom);
|
|
1782
1785
|
let after = this.length ? off > 0 : side > 0;
|
|
@@ -1972,7 +1975,7 @@ class LineTile extends CompositeTile {
|
|
|
1972
1975
|
if (child.isComposite()) {
|
|
1973
1976
|
scan(child, pos - off);
|
|
1974
1977
|
}
|
|
1975
|
-
else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) &&
|
|
1978
|
+
else if ((!after || after.isHidden && (side > 0 && !(after.flags & 32 /* TileFlag.After */) || forCoords && onSameLine(after, child))) &&
|
|
1976
1979
|
(end > pos || (child.flags & 32 /* TileFlag.After */))) {
|
|
1977
1980
|
after = child;
|
|
1978
1981
|
afterOff = pos - off;
|
|
@@ -1989,11 +1992,11 @@ class LineTile extends CompositeTile {
|
|
|
1989
1992
|
let target = ((side < 0 ? before : after) || before || after);
|
|
1990
1993
|
return target ? { tile: target, offset: target == before ? beforeOff : afterOff } : null;
|
|
1991
1994
|
}
|
|
1992
|
-
coordsIn(pos, side) {
|
|
1995
|
+
coordsIn(pos, side, rtl) {
|
|
1993
1996
|
let found = this.resolveInline(pos, side, true);
|
|
1994
1997
|
if (!found)
|
|
1995
1998
|
return fallbackRect(this);
|
|
1996
|
-
return found.tile.coordsIn(Math.max(0, found.offset), side);
|
|
1999
|
+
return found.tile.coordsIn(Math.max(0, found.offset), side, rtl);
|
|
1997
2000
|
}
|
|
1998
2001
|
domIn(pos, side) {
|
|
1999
2002
|
let found = this.resolveInline(pos, side);
|
|
@@ -2057,7 +2060,7 @@ class TextTile extends Tile {
|
|
|
2057
2060
|
}
|
|
2058
2061
|
isText() { return true; }
|
|
2059
2062
|
toString() { return JSON.stringify(this.text); }
|
|
2060
|
-
coordsIn(pos, side) {
|
|
2063
|
+
coordsIn(pos, side, rtl) {
|
|
2061
2064
|
let length = this.dom.nodeValue.length;
|
|
2062
2065
|
if (pos > length)
|
|
2063
2066
|
pos = length;
|
|
@@ -2067,7 +2070,7 @@ class TextTile extends Tile {
|
|
|
2067
2070
|
if (pos) {
|
|
2068
2071
|
from--;
|
|
2069
2072
|
flatten = 1;
|
|
2070
|
-
}
|
|
2073
|
+
}
|
|
2071
2074
|
else if (to < length) {
|
|
2072
2075
|
to++;
|
|
2073
2076
|
flatten = -1;
|
|
@@ -2086,7 +2089,7 @@ class TextTile extends Tile {
|
|
|
2086
2089
|
let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
|
|
2087
2090
|
if (browser.safari && !flatten && rect.width == 0)
|
|
2088
2091
|
rect = Array.prototype.find.call(rects, r => r.width) || rect;
|
|
2089
|
-
return
|
|
2092
|
+
return rtl == null ? rect : flattenRect(rect, (flatten ? flatten > 0 : side < 0) == rtl);
|
|
2090
2093
|
}
|
|
2091
2094
|
static of(text, dom) {
|
|
2092
2095
|
let tile = new TextTile(dom || document.createTextNode(text), text);
|
|
@@ -2162,7 +2165,10 @@ class WidgetBufferTile extends Tile {
|
|
|
2162
2165
|
}
|
|
2163
2166
|
get isHidden() { return true; }
|
|
2164
2167
|
get overrideDOMText() { return Text.empty; }
|
|
2165
|
-
coordsIn(pos
|
|
2168
|
+
coordsIn(pos, side, rtl) {
|
|
2169
|
+
let rect = this.dom.getBoundingClientRect();
|
|
2170
|
+
return rtl == null ? rect : flattenRect(rect, (side > 0) == rtl);
|
|
2171
|
+
}
|
|
2166
2172
|
}
|
|
2167
2173
|
// Represents a position in the tile tree.
|
|
2168
2174
|
class TilePointer {
|
|
@@ -2524,8 +2530,8 @@ class TileCache {
|
|
|
2524
2530
|
find(cls, test, type = 2 /* Reused.DOM */) {
|
|
2525
2531
|
let i = cls.bucket;
|
|
2526
2532
|
let bucket = this.buckets[i], off = this.index[i];
|
|
2527
|
-
for (let j =
|
|
2528
|
-
// Look at the most
|
|
2533
|
+
for (let j = 0; j < bucket.length; j++) {
|
|
2534
|
+
// Look at the most oldest items first (first-in, first-out)
|
|
2529
2535
|
let index = (j + off) % bucket.length, tile = bucket[index];
|
|
2530
2536
|
if ((!test || test(tile)) && !this.reused.has(tile)) {
|
|
2531
2537
|
bucket.splice(index, 1);
|
|
@@ -3191,7 +3197,7 @@ class DocView {
|
|
|
3191
3197
|
domAtPos(pos, side) {
|
|
3192
3198
|
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3193
3199
|
if (tile.isWidget())
|
|
3194
|
-
return tile.domPosFor(
|
|
3200
|
+
return tile.domPosFor(offset, side);
|
|
3195
3201
|
return tile.domIn(offset, side);
|
|
3196
3202
|
}
|
|
3197
3203
|
inlineDOMNearPos(pos, side) {
|
|
@@ -3228,14 +3234,16 @@ class DocView {
|
|
|
3228
3234
|
after = null;
|
|
3229
3235
|
return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
|
|
3230
3236
|
}
|
|
3231
|
-
|
|
3237
|
+
// Get the coord of the element at the given side of the given
|
|
3238
|
+
// position. If rtl is given, flatten it using that text direction.
|
|
3239
|
+
coordsAt(pos, side, rtl) {
|
|
3232
3240
|
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3233
3241
|
if (tile.isWidget()) {
|
|
3234
3242
|
if (tile.widget instanceof BlockGapWidget)
|
|
3235
3243
|
return null;
|
|
3236
3244
|
return tile.coordsInWidget(offset, side, true);
|
|
3237
3245
|
}
|
|
3238
|
-
return tile.coordsIn(offset, side);
|
|
3246
|
+
return tile.coordsIn(offset, side, rtl);
|
|
3239
3247
|
}
|
|
3240
3248
|
lineAt(pos, side) {
|
|
3241
3249
|
let { tile } = this.tile.resolveBlock(pos, side);
|
|
@@ -3409,7 +3417,6 @@ class DocView {
|
|
|
3409
3417
|
this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
|
|
3410
3418
|
}
|
|
3411
3419
|
scrollIntoView(target) {
|
|
3412
|
-
var _a;
|
|
3413
3420
|
if (target.isSnapshot) {
|
|
3414
3421
|
let ref = this.view.viewState.lineBlockAt(target.range.head);
|
|
3415
3422
|
this.view.scrollDOM.scrollTop = ref.top - target.yMargin;
|
|
@@ -3426,7 +3433,7 @@ class DocView {
|
|
|
3426
3433
|
}
|
|
3427
3434
|
}
|
|
3428
3435
|
let { range } = target;
|
|
3429
|
-
let rect = this.coordsAt(range.head,
|
|
3436
|
+
let rect = this.coordsAt(range.head, range.assoc || (range.head > range.anchor ? -1 : 1)), other;
|
|
3430
3437
|
if (!rect)
|
|
3431
3438
|
return;
|
|
3432
3439
|
if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
|
|
@@ -4468,6 +4475,7 @@ class InputState {
|
|
|
4468
4475
|
this.view = view;
|
|
4469
4476
|
this.lastKeyCode = 0;
|
|
4470
4477
|
this.lastKeyTime = 0;
|
|
4478
|
+
this.touchActive = false;
|
|
4471
4479
|
this.lastTouchTime = 0;
|
|
4472
4480
|
this.lastTouchX = 0;
|
|
4473
4481
|
this.lastTouchY = 0;
|
|
@@ -4479,6 +4487,10 @@ class InputState {
|
|
|
4479
4487
|
// (after which we retroactively handle them and reset the DOM) to
|
|
4480
4488
|
// avoid messing up the virtual keyboard state.
|
|
4481
4489
|
this.pendingIOSKey = undefined;
|
|
4490
|
+
// Set to a time stap by scroll events when touch isn't active on
|
|
4491
|
+
// iOS, to work around an issue where Safari will abort the scroll
|
|
4492
|
+
// momentum if we set scrollTop
|
|
4493
|
+
this.lastIOSMomentumScroll = 0;
|
|
4482
4494
|
// When enabled (>-1), tab presses are not given to key handlers,
|
|
4483
4495
|
// leaving the browser's default behavior. If >0, the mode expires
|
|
4484
4496
|
// at that timestamp, and any other keypress clears it.
|
|
@@ -4909,8 +4921,11 @@ function doPaste(view, input) {
|
|
|
4909
4921
|
});
|
|
4910
4922
|
}
|
|
4911
4923
|
observers.scroll = view => {
|
|
4912
|
-
|
|
4913
|
-
|
|
4924
|
+
let iState = view.inputState;
|
|
4925
|
+
iState.lastScrollTop = view.scrollDOM.scrollTop;
|
|
4926
|
+
iState.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
4927
|
+
if (browser.ios && !iState.touchActive)
|
|
4928
|
+
iState.lastIOSMomentumScroll = Date.now();
|
|
4914
4929
|
};
|
|
4915
4930
|
observers.wheel = observers.mousewheel = view => {
|
|
4916
4931
|
view.inputState.lastWheelEvent = Date.now();
|
|
@@ -4923,6 +4938,7 @@ handlers.keydown = (view, event) => {
|
|
|
4923
4938
|
};
|
|
4924
4939
|
observers.touchstart = (view, e) => {
|
|
4925
4940
|
let iState = view.inputState, touch = e.targetTouches[0];
|
|
4941
|
+
iState.touchActive = true;
|
|
4926
4942
|
iState.lastTouchTime = Date.now();
|
|
4927
4943
|
if (touch) {
|
|
4928
4944
|
iState.lastTouchX = touch.clientX;
|
|
@@ -4933,6 +4949,9 @@ observers.touchstart = (view, e) => {
|
|
|
4933
4949
|
observers.touchmove = view => {
|
|
4934
4950
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4935
4951
|
};
|
|
4952
|
+
observers.touchend = (view, e) => {
|
|
4953
|
+
view.inputState.touchActive = false;
|
|
4954
|
+
};
|
|
4936
4955
|
handlers.mousedown = (view, event) => {
|
|
4937
4956
|
view.observer.flush();
|
|
4938
4957
|
if (view.inputState.lastTouchTime > Date.now() - 2000)
|
|
@@ -8194,6 +8213,7 @@ class EditorView {
|
|
|
8194
8213
|
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
8195
8214
|
let diff = (newAnchorHeight - scrollAnchorHeight) / this.scaleY;
|
|
8196
8215
|
if ((diff > 1 || diff < -1) &&
|
|
8216
|
+
!(browser.ios && this.inputState.lastIOSMomentumScroll > Date.now() - 100) &&
|
|
8197
8217
|
(scroll == this.scrollDOM || this.hasFocus ||
|
|
8198
8218
|
Math.max(this.inputState.lastWheelEvent, this.inputState.lastTouchTime) > Date.now() - 100)) {
|
|
8199
8219
|
scrollOffset = scrollOffset + diff;
|
|
@@ -8485,12 +8505,9 @@ class EditorView {
|
|
|
8485
8505
|
*/
|
|
8486
8506
|
coordsAtPos(pos, side = 1) {
|
|
8487
8507
|
this.readMeasured();
|
|
8488
|
-
let rect = this.docView.coordsAt(pos, side);
|
|
8489
|
-
if (!rect || rect.left == rect.right)
|
|
8490
|
-
return rect;
|
|
8491
8508
|
let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
|
|
8492
8509
|
let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
|
|
8493
|
-
return
|
|
8510
|
+
return this.docView.coordsAt(pos, side, span.dir == Direction.RTL);
|
|
8494
8511
|
}
|
|
8495
8512
|
/**
|
|
8496
8513
|
Return the rectangle around a given character. If `pos` does not
|