@codemirror/view 0.19.10 → 0.19.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -0
- package/dist/index.cjs +76 -41
- package/dist/index.d.ts +5 -3
- package/dist/index.js +76 -41
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
## 0.19.11 (2021-11-03)
|
|
2
|
+
|
|
3
|
+
### Breaking changes
|
|
4
|
+
|
|
5
|
+
`EditorView.scrollPosIntoView` has been deprecated. Use the `EditorView.scrollTo` effect instead.
|
|
6
|
+
|
|
7
|
+
### New features
|
|
8
|
+
|
|
9
|
+
The new `EditorView.centerOn` effect can be used to scroll a given range to the center of the view.
|
|
10
|
+
|
|
1
11
|
## 0.19.10 (2021-11-02)
|
|
2
12
|
|
|
3
13
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -102,9 +102,9 @@ function windowRect(win) {
|
|
|
102
102
|
top: 0, bottom: win.innerHeight };
|
|
103
103
|
}
|
|
104
104
|
const ScrollSpace = 5;
|
|
105
|
-
function scrollRectIntoView(dom, rect, side) {
|
|
105
|
+
function scrollRectIntoView(dom, rect, side, center) {
|
|
106
106
|
let doc = dom.ownerDocument, win = doc.defaultView;
|
|
107
|
-
for (let cur = dom
|
|
107
|
+
for (let cur = dom; cur;) {
|
|
108
108
|
if (cur.nodeType == 1) { // Element
|
|
109
109
|
let bounding, top = cur == doc.body;
|
|
110
110
|
if (top) {
|
|
@@ -121,7 +121,20 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
121
121
|
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
122
122
|
}
|
|
123
123
|
let moveX = 0, moveY = 0;
|
|
124
|
-
if (
|
|
124
|
+
if (center) {
|
|
125
|
+
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
126
|
+
let targetTop;
|
|
127
|
+
if (rectHeight <= boundingHeight)
|
|
128
|
+
targetTop = rect.top + rectHeight / 2 - boundingHeight / 2;
|
|
129
|
+
else if (side < 0)
|
|
130
|
+
targetTop = rect.top - ScrollSpace;
|
|
131
|
+
else
|
|
132
|
+
targetTop = rect.bottom + ScrollSpace - boundingHeight;
|
|
133
|
+
moveY = targetTop - bounding.top;
|
|
134
|
+
if (Math.abs(moveY) <= 1)
|
|
135
|
+
moveY = 0;
|
|
136
|
+
}
|
|
137
|
+
else if (rect.top < bounding.top) {
|
|
125
138
|
moveY = -(bounding.top - rect.top + ScrollSpace);
|
|
126
139
|
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
127
140
|
moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
|
|
@@ -163,6 +176,7 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
163
176
|
if (top)
|
|
164
177
|
break;
|
|
165
178
|
cur = cur.assignedSlot || cur.parentNode;
|
|
179
|
+
center = false;
|
|
166
180
|
}
|
|
167
181
|
else if (cur.nodeType == 11) { // A shadow root
|
|
168
182
|
cur = cur.host;
|
|
@@ -1560,6 +1574,9 @@ const inputHandler = state.Facet.define();
|
|
|
1560
1574
|
const scrollTo = state.StateEffect.define({
|
|
1561
1575
|
map: (range, changes) => range.map(changes)
|
|
1562
1576
|
});
|
|
1577
|
+
const centerOn = state.StateEffect.define({
|
|
1578
|
+
map: (range, changes) => range.map(changes)
|
|
1579
|
+
});
|
|
1563
1580
|
/**
|
|
1564
1581
|
Log or report an unhandled exception in client code. Should
|
|
1565
1582
|
probably only be used by extension code that allows client code to
|
|
@@ -2304,7 +2321,7 @@ class DocView extends ContentView {
|
|
|
2304
2321
|
this.view.viewState.lineGapDeco
|
|
2305
2322
|
];
|
|
2306
2323
|
}
|
|
2307
|
-
|
|
2324
|
+
scrollIntoView({ range, center }) {
|
|
2308
2325
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
2309
2326
|
if (!rect)
|
|
2310
2327
|
return;
|
|
@@ -2324,10 +2341,10 @@ class DocView extends ContentView {
|
|
|
2324
2341
|
if (bottom != null)
|
|
2325
2342
|
mBottom = Math.max(mBottom, bottom);
|
|
2326
2343
|
}
|
|
2327
|
-
scrollRectIntoView(this.
|
|
2344
|
+
scrollRectIntoView(this.view.scrollDOM, {
|
|
2328
2345
|
left: rect.left - mLeft, top: rect.top - mTop,
|
|
2329
2346
|
right: rect.right + mRight, bottom: rect.bottom + mBottom
|
|
2330
|
-
}, range.head < range.anchor ? -1 : 1);
|
|
2347
|
+
}, range.head < range.anchor ? -1 : 1, center);
|
|
2331
2348
|
}
|
|
2332
2349
|
}
|
|
2333
2350
|
function betweenUneditable(pos) {
|
|
@@ -4446,6 +4463,15 @@ class LineGapWidget extends WidgetType {
|
|
|
4446
4463
|
}
|
|
4447
4464
|
get estimatedHeight() { return this.vertical ? this.size : -1; }
|
|
4448
4465
|
}
|
|
4466
|
+
class ScrollTarget {
|
|
4467
|
+
constructor(range, center = false) {
|
|
4468
|
+
this.range = range;
|
|
4469
|
+
this.center = center;
|
|
4470
|
+
}
|
|
4471
|
+
map(changes) {
|
|
4472
|
+
return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4449
4475
|
class ViewState {
|
|
4450
4476
|
constructor(state) {
|
|
4451
4477
|
this.state = state;
|
|
@@ -4458,7 +4484,7 @@ class ViewState {
|
|
|
4458
4484
|
this.heightOracle = new HeightOracle;
|
|
4459
4485
|
// See VP.MaxDOMHeight
|
|
4460
4486
|
this.scaler = IdScaler;
|
|
4461
|
-
this.
|
|
4487
|
+
this.scrollTarget = null;
|
|
4462
4488
|
// Briefly set to true when printing, to disable viewport limiting
|
|
4463
4489
|
this.printing = false;
|
|
4464
4490
|
this.visibleRanges = [];
|
|
@@ -4491,7 +4517,7 @@ class ViewState {
|
|
|
4491
4517
|
this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler :
|
|
4492
4518
|
new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
|
|
4493
4519
|
}
|
|
4494
|
-
update(update,
|
|
4520
|
+
update(update, scrollTarget = null) {
|
|
4495
4521
|
let prev = this.state;
|
|
4496
4522
|
this.state = update.state;
|
|
4497
4523
|
let newDeco = this.state.facet(decorations);
|
|
@@ -4502,15 +4528,16 @@ class ViewState {
|
|
|
4502
4528
|
if (this.heightMap.height != prevHeight)
|
|
4503
4529
|
update.flags |= 2 /* Height */;
|
|
4504
4530
|
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
|
4505
|
-
if (
|
|
4506
|
-
|
|
4531
|
+
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
4532
|
+
!this.viewportIsAppropriate(viewport))
|
|
4533
|
+
viewport = this.getViewport(0, scrollTarget);
|
|
4507
4534
|
this.viewport = viewport;
|
|
4508
4535
|
this.updateForViewport();
|
|
4509
4536
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4510
4537
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
4511
4538
|
update.flags |= this.computeVisibleRanges();
|
|
4512
|
-
if (
|
|
4513
|
-
this.
|
|
4539
|
+
if (scrollTarget)
|
|
4540
|
+
this.scrollTarget = scrollTarget;
|
|
4514
4541
|
if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
|
|
4515
4542
|
update.state.selection.main.empty && update.state.selection.main.assoc)
|
|
4516
4543
|
this.mustEnforceCursorAssoc = true;
|
|
@@ -4563,8 +4590,8 @@ class ViewState {
|
|
|
4563
4590
|
if (oracle.heightChanged)
|
|
4564
4591
|
result |= 2 /* Height */;
|
|
4565
4592
|
if (!this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4566
|
-
this.
|
|
4567
|
-
this.viewport = this.getViewport(bias, this.
|
|
4593
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to))
|
|
4594
|
+
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4568
4595
|
this.updateForViewport();
|
|
4569
4596
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4570
4597
|
this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
|
|
@@ -4581,22 +4608,25 @@ class ViewState {
|
|
|
4581
4608
|
}
|
|
4582
4609
|
get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top, 0); }
|
|
4583
4610
|
get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom, 0); }
|
|
4584
|
-
getViewport(bias,
|
|
4611
|
+
getViewport(bias, scrollTarget) {
|
|
4585
4612
|
// This will divide VP.Margin between the top and the
|
|
4586
4613
|
// bottom, depending on the bias (the change in viewport position
|
|
4587
4614
|
// since the last update). It'll hold a number between 0 and 1
|
|
4588
4615
|
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* Margin */ / 2));
|
|
4589
4616
|
let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
|
|
4590
4617
|
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to);
|
|
4591
|
-
// If
|
|
4592
|
-
if (
|
|
4593
|
-
|
|
4594
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
4618
|
+
// If scrollTarget is given, make sure the viewport includes that position
|
|
4619
|
+
if (scrollTarget) {
|
|
4620
|
+
let { head } = scrollTarget.range, viewHeight = visibleBottom - visibleTop;
|
|
4621
|
+
if (head < viewport.from || head > viewport.to) {
|
|
4622
|
+
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4623
|
+
if (scrollTarget.center)
|
|
4624
|
+
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
4625
|
+
else if (head < viewport.from)
|
|
4626
|
+
topPos = block.top;
|
|
4627
|
+
else
|
|
4628
|
+
topPos = block.bottom - viewHeight;
|
|
4629
|
+
viewport = new Viewport(map.lineAt(topPos - 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to);
|
|
4600
4630
|
}
|
|
4601
4631
|
}
|
|
4602
4632
|
return viewport;
|
|
@@ -5691,21 +5721,24 @@ class EditorView {
|
|
|
5691
5721
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
5692
5722
|
return this.setState(state$1);
|
|
5693
5723
|
update = new ViewUpdate(this, state$1, transactions);
|
|
5694
|
-
let
|
|
5724
|
+
let scrollTarget = null;
|
|
5695
5725
|
try {
|
|
5696
5726
|
this.updateState = 2 /* Updating */;
|
|
5697
5727
|
for (let tr of transactions) {
|
|
5698
|
-
if (
|
|
5699
|
-
|
|
5728
|
+
if (scrollTarget)
|
|
5729
|
+
scrollTarget = scrollTarget.map(tr.changes);
|
|
5700
5730
|
if (tr.scrollIntoView) {
|
|
5701
5731
|
let { main } = tr.state.selection;
|
|
5702
|
-
|
|
5732
|
+
scrollTarget = new ScrollTarget(main.empty ? main : state.EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
|
5703
5733
|
}
|
|
5704
|
-
for (let e of tr.effects)
|
|
5734
|
+
for (let e of tr.effects) {
|
|
5705
5735
|
if (e.is(scrollTo))
|
|
5706
|
-
|
|
5736
|
+
scrollTarget = new ScrollTarget(e.value);
|
|
5737
|
+
else if (e.is(centerOn))
|
|
5738
|
+
scrollTarget = new ScrollTarget(e.value, true);
|
|
5739
|
+
}
|
|
5707
5740
|
}
|
|
5708
|
-
this.viewState.update(update,
|
|
5741
|
+
this.viewState.update(update, scrollTarget);
|
|
5709
5742
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
5710
5743
|
if (!update.empty) {
|
|
5711
5744
|
this.updatePlugins(update);
|
|
@@ -5720,7 +5753,7 @@ class EditorView {
|
|
|
5720
5753
|
finally {
|
|
5721
5754
|
this.updateState = 0 /* Idle */;
|
|
5722
5755
|
}
|
|
5723
|
-
if (redrawn ||
|
|
5756
|
+
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc)
|
|
5724
5757
|
this.requestMeasure();
|
|
5725
5758
|
if (!update.empty)
|
|
5726
5759
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -5802,7 +5835,7 @@ class EditorView {
|
|
|
5802
5835
|
this.updateState = 1 /* Measuring */;
|
|
5803
5836
|
let oldViewport = this.viewport;
|
|
5804
5837
|
let changed = this.viewState.measure(this.docView, i > 0);
|
|
5805
|
-
if (!changed && !this.measureRequests.length && this.viewState.
|
|
5838
|
+
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
|
5806
5839
|
break;
|
|
5807
5840
|
if (i > 5) {
|
|
5808
5841
|
console.warn("Viewport failed to stabilize");
|
|
@@ -5844,9 +5877,9 @@ class EditorView {
|
|
|
5844
5877
|
logException(this.state, e);
|
|
5845
5878
|
}
|
|
5846
5879
|
}
|
|
5847
|
-
if (this.viewState.
|
|
5848
|
-
this.docView.
|
|
5849
|
-
this.viewState.
|
|
5880
|
+
if (this.viewState.scrollTarget) {
|
|
5881
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5882
|
+
this.viewState.scrollTarget = null;
|
|
5850
5883
|
}
|
|
5851
5884
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5852
5885
|
break;
|
|
@@ -6069,12 +6102,9 @@ class EditorView {
|
|
|
6069
6102
|
moveVertically(start, forward, distance) {
|
|
6070
6103
|
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
|
6071
6104
|
}
|
|
6072
|
-
|
|
6073
|
-
Scroll the given document position into view.
|
|
6074
|
-
*/
|
|
6105
|
+
// FIXME remove on next major version
|
|
6075
6106
|
scrollPosIntoView(pos) {
|
|
6076
|
-
this.
|
|
6077
|
-
this.requestMeasure();
|
|
6107
|
+
this.dispatch({ effects: scrollTo.of(state.EditorSelection.cursor(pos)) });
|
|
6078
6108
|
}
|
|
6079
6109
|
/**
|
|
6080
6110
|
Find the DOM parent node and offset (child offset if `node` is
|
|
@@ -6250,6 +6280,11 @@ transaction to make it scroll the given range into view.
|
|
|
6250
6280
|
*/
|
|
6251
6281
|
EditorView.scrollTo = scrollTo;
|
|
6252
6282
|
/**
|
|
6283
|
+
Effect that makes the editor scroll the given range to the
|
|
6284
|
+
center of the visible view.
|
|
6285
|
+
*/
|
|
6286
|
+
EditorView.centerOn = centerOn;
|
|
6287
|
+
/**
|
|
6253
6288
|
Facet to add a [style
|
|
6254
6289
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
6255
6290
|
an editor view. The view will ensure that the module is
|
package/dist/index.d.ts
CHANGED
|
@@ -856,9 +856,6 @@ declare class EditorView {
|
|
|
856
856
|
used.
|
|
857
857
|
*/
|
|
858
858
|
moveVertically(start: SelectionRange, forward: boolean, distance?: number): SelectionRange;
|
|
859
|
-
/**
|
|
860
|
-
Scroll the given document position into view.
|
|
861
|
-
*/
|
|
862
859
|
scrollPosIntoView(pos: number): void;
|
|
863
860
|
/**
|
|
864
861
|
Find the DOM parent node and offset (child offset if `node` is
|
|
@@ -949,6 +946,11 @@ declare class EditorView {
|
|
|
949
946
|
*/
|
|
950
947
|
static scrollTo: _codemirror_state.StateEffectType<SelectionRange>;
|
|
951
948
|
/**
|
|
949
|
+
Effect that makes the editor scroll the given range to the
|
|
950
|
+
center of the visible view.
|
|
951
|
+
*/
|
|
952
|
+
static centerOn: _codemirror_state.StateEffectType<SelectionRange>;
|
|
953
|
+
/**
|
|
952
954
|
Facet to add a [style
|
|
953
955
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
954
956
|
an editor view. The view will ensure that the module is
|
package/dist/index.js
CHANGED
|
@@ -99,9 +99,9 @@ function windowRect(win) {
|
|
|
99
99
|
top: 0, bottom: win.innerHeight };
|
|
100
100
|
}
|
|
101
101
|
const ScrollSpace = 5;
|
|
102
|
-
function scrollRectIntoView(dom, rect, side) {
|
|
102
|
+
function scrollRectIntoView(dom, rect, side, center) {
|
|
103
103
|
let doc = dom.ownerDocument, win = doc.defaultView;
|
|
104
|
-
for (let cur = dom
|
|
104
|
+
for (let cur = dom; cur;) {
|
|
105
105
|
if (cur.nodeType == 1) { // Element
|
|
106
106
|
let bounding, top = cur == doc.body;
|
|
107
107
|
if (top) {
|
|
@@ -118,7 +118,20 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
118
118
|
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
119
119
|
}
|
|
120
120
|
let moveX = 0, moveY = 0;
|
|
121
|
-
if (
|
|
121
|
+
if (center) {
|
|
122
|
+
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
123
|
+
let targetTop;
|
|
124
|
+
if (rectHeight <= boundingHeight)
|
|
125
|
+
targetTop = rect.top + rectHeight / 2 - boundingHeight / 2;
|
|
126
|
+
else if (side < 0)
|
|
127
|
+
targetTop = rect.top - ScrollSpace;
|
|
128
|
+
else
|
|
129
|
+
targetTop = rect.bottom + ScrollSpace - boundingHeight;
|
|
130
|
+
moveY = targetTop - bounding.top;
|
|
131
|
+
if (Math.abs(moveY) <= 1)
|
|
132
|
+
moveY = 0;
|
|
133
|
+
}
|
|
134
|
+
else if (rect.top < bounding.top) {
|
|
122
135
|
moveY = -(bounding.top - rect.top + ScrollSpace);
|
|
123
136
|
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
124
137
|
moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
|
|
@@ -160,6 +173,7 @@ function scrollRectIntoView(dom, rect, side) {
|
|
|
160
173
|
if (top)
|
|
161
174
|
break;
|
|
162
175
|
cur = cur.assignedSlot || cur.parentNode;
|
|
176
|
+
center = false;
|
|
163
177
|
}
|
|
164
178
|
else if (cur.nodeType == 11) { // A shadow root
|
|
165
179
|
cur = cur.host;
|
|
@@ -1556,6 +1570,9 @@ const inputHandler = /*@__PURE__*/Facet.define();
|
|
|
1556
1570
|
const scrollTo = /*@__PURE__*/StateEffect.define({
|
|
1557
1571
|
map: (range, changes) => range.map(changes)
|
|
1558
1572
|
});
|
|
1573
|
+
const centerOn = /*@__PURE__*/StateEffect.define({
|
|
1574
|
+
map: (range, changes) => range.map(changes)
|
|
1575
|
+
});
|
|
1559
1576
|
/**
|
|
1560
1577
|
Log or report an unhandled exception in client code. Should
|
|
1561
1578
|
probably only be used by extension code that allows client code to
|
|
@@ -2300,7 +2317,7 @@ class DocView extends ContentView {
|
|
|
2300
2317
|
this.view.viewState.lineGapDeco
|
|
2301
2318
|
];
|
|
2302
2319
|
}
|
|
2303
|
-
|
|
2320
|
+
scrollIntoView({ range, center }) {
|
|
2304
2321
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
2305
2322
|
if (!rect)
|
|
2306
2323
|
return;
|
|
@@ -2320,10 +2337,10 @@ class DocView extends ContentView {
|
|
|
2320
2337
|
if (bottom != null)
|
|
2321
2338
|
mBottom = Math.max(mBottom, bottom);
|
|
2322
2339
|
}
|
|
2323
|
-
scrollRectIntoView(this.
|
|
2340
|
+
scrollRectIntoView(this.view.scrollDOM, {
|
|
2324
2341
|
left: rect.left - mLeft, top: rect.top - mTop,
|
|
2325
2342
|
right: rect.right + mRight, bottom: rect.bottom + mBottom
|
|
2326
|
-
}, range.head < range.anchor ? -1 : 1);
|
|
2343
|
+
}, range.head < range.anchor ? -1 : 1, center);
|
|
2327
2344
|
}
|
|
2328
2345
|
}
|
|
2329
2346
|
function betweenUneditable(pos) {
|
|
@@ -4440,6 +4457,15 @@ class LineGapWidget extends WidgetType {
|
|
|
4440
4457
|
}
|
|
4441
4458
|
get estimatedHeight() { return this.vertical ? this.size : -1; }
|
|
4442
4459
|
}
|
|
4460
|
+
class ScrollTarget {
|
|
4461
|
+
constructor(range, center = false) {
|
|
4462
|
+
this.range = range;
|
|
4463
|
+
this.center = center;
|
|
4464
|
+
}
|
|
4465
|
+
map(changes) {
|
|
4466
|
+
return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
|
|
4467
|
+
}
|
|
4468
|
+
}
|
|
4443
4469
|
class ViewState {
|
|
4444
4470
|
constructor(state) {
|
|
4445
4471
|
this.state = state;
|
|
@@ -4452,7 +4478,7 @@ class ViewState {
|
|
|
4452
4478
|
this.heightOracle = new HeightOracle;
|
|
4453
4479
|
// See VP.MaxDOMHeight
|
|
4454
4480
|
this.scaler = IdScaler;
|
|
4455
|
-
this.
|
|
4481
|
+
this.scrollTarget = null;
|
|
4456
4482
|
// Briefly set to true when printing, to disable viewport limiting
|
|
4457
4483
|
this.printing = false;
|
|
4458
4484
|
this.visibleRanges = [];
|
|
@@ -4485,7 +4511,7 @@ class ViewState {
|
|
|
4485
4511
|
this.scaler = this.heightMap.height <= 7000000 /* MaxDOMHeight */ ? IdScaler :
|
|
4486
4512
|
new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
|
|
4487
4513
|
}
|
|
4488
|
-
update(update,
|
|
4514
|
+
update(update, scrollTarget = null) {
|
|
4489
4515
|
let prev = this.state;
|
|
4490
4516
|
this.state = update.state;
|
|
4491
4517
|
let newDeco = this.state.facet(decorations);
|
|
@@ -4496,15 +4522,16 @@ class ViewState {
|
|
|
4496
4522
|
if (this.heightMap.height != prevHeight)
|
|
4497
4523
|
update.flags |= 2 /* Height */;
|
|
4498
4524
|
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
|
4499
|
-
if (
|
|
4500
|
-
|
|
4525
|
+
if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
|
4526
|
+
!this.viewportIsAppropriate(viewport))
|
|
4527
|
+
viewport = this.getViewport(0, scrollTarget);
|
|
4501
4528
|
this.viewport = viewport;
|
|
4502
4529
|
this.updateForViewport();
|
|
4503
4530
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4504
4531
|
this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
|
4505
4532
|
update.flags |= this.computeVisibleRanges();
|
|
4506
|
-
if (
|
|
4507
|
-
this.
|
|
4533
|
+
if (scrollTarget)
|
|
4534
|
+
this.scrollTarget = scrollTarget;
|
|
4508
4535
|
if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
|
|
4509
4536
|
update.state.selection.main.empty && update.state.selection.main.assoc)
|
|
4510
4537
|
this.mustEnforceCursorAssoc = true;
|
|
@@ -4557,8 +4584,8 @@ class ViewState {
|
|
|
4557
4584
|
if (oracle.heightChanged)
|
|
4558
4585
|
result |= 2 /* Height */;
|
|
4559
4586
|
if (!this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4560
|
-
this.
|
|
4561
|
-
this.viewport = this.getViewport(bias, this.
|
|
4587
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to))
|
|
4588
|
+
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4562
4589
|
this.updateForViewport();
|
|
4563
4590
|
if (this.lineGaps.length || this.viewport.to - this.viewport.from > 15000 /* MinViewPort */)
|
|
4564
4591
|
this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
|
|
@@ -4575,22 +4602,25 @@ class ViewState {
|
|
|
4575
4602
|
}
|
|
4576
4603
|
get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top, 0); }
|
|
4577
4604
|
get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom, 0); }
|
|
4578
|
-
getViewport(bias,
|
|
4605
|
+
getViewport(bias, scrollTarget) {
|
|
4579
4606
|
// This will divide VP.Margin between the top and the
|
|
4580
4607
|
// bottom, depending on the bias (the change in viewport position
|
|
4581
4608
|
// since the last update). It'll hold a number between 0 and 1
|
|
4582
4609
|
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* Margin */ / 2));
|
|
4583
4610
|
let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
|
|
4584
4611
|
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to);
|
|
4585
|
-
// If
|
|
4586
|
-
if (
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4612
|
+
// If scrollTarget is given, make sure the viewport includes that position
|
|
4613
|
+
if (scrollTarget) {
|
|
4614
|
+
let { head } = scrollTarget.range, viewHeight = visibleBottom - visibleTop;
|
|
4615
|
+
if (head < viewport.from || head > viewport.to) {
|
|
4616
|
+
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4617
|
+
if (scrollTarget.center)
|
|
4618
|
+
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
4619
|
+
else if (head < viewport.from)
|
|
4620
|
+
topPos = block.top;
|
|
4621
|
+
else
|
|
4622
|
+
topPos = block.bottom - viewHeight;
|
|
4623
|
+
viewport = new Viewport(map.lineAt(topPos - 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* Margin */ / 2, QueryType.ByHeight, doc, 0, 0).to);
|
|
4594
4624
|
}
|
|
4595
4625
|
}
|
|
4596
4626
|
return viewport;
|
|
@@ -5685,21 +5715,24 @@ class EditorView {
|
|
|
5685
5715
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
5686
5716
|
return this.setState(state);
|
|
5687
5717
|
update = new ViewUpdate(this, state, transactions);
|
|
5688
|
-
let
|
|
5718
|
+
let scrollTarget = null;
|
|
5689
5719
|
try {
|
|
5690
5720
|
this.updateState = 2 /* Updating */;
|
|
5691
5721
|
for (let tr of transactions) {
|
|
5692
|
-
if (
|
|
5693
|
-
|
|
5722
|
+
if (scrollTarget)
|
|
5723
|
+
scrollTarget = scrollTarget.map(tr.changes);
|
|
5694
5724
|
if (tr.scrollIntoView) {
|
|
5695
5725
|
let { main } = tr.state.selection;
|
|
5696
|
-
|
|
5726
|
+
scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
|
5697
5727
|
}
|
|
5698
|
-
for (let e of tr.effects)
|
|
5728
|
+
for (let e of tr.effects) {
|
|
5699
5729
|
if (e.is(scrollTo))
|
|
5700
|
-
|
|
5730
|
+
scrollTarget = new ScrollTarget(e.value);
|
|
5731
|
+
else if (e.is(centerOn))
|
|
5732
|
+
scrollTarget = new ScrollTarget(e.value, true);
|
|
5733
|
+
}
|
|
5701
5734
|
}
|
|
5702
|
-
this.viewState.update(update,
|
|
5735
|
+
this.viewState.update(update, scrollTarget);
|
|
5703
5736
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
5704
5737
|
if (!update.empty) {
|
|
5705
5738
|
this.updatePlugins(update);
|
|
@@ -5714,7 +5747,7 @@ class EditorView {
|
|
|
5714
5747
|
finally {
|
|
5715
5748
|
this.updateState = 0 /* Idle */;
|
|
5716
5749
|
}
|
|
5717
|
-
if (redrawn ||
|
|
5750
|
+
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc)
|
|
5718
5751
|
this.requestMeasure();
|
|
5719
5752
|
if (!update.empty)
|
|
5720
5753
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -5796,7 +5829,7 @@ class EditorView {
|
|
|
5796
5829
|
this.updateState = 1 /* Measuring */;
|
|
5797
5830
|
let oldViewport = this.viewport;
|
|
5798
5831
|
let changed = this.viewState.measure(this.docView, i > 0);
|
|
5799
|
-
if (!changed && !this.measureRequests.length && this.viewState.
|
|
5832
|
+
if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
|
5800
5833
|
break;
|
|
5801
5834
|
if (i > 5) {
|
|
5802
5835
|
console.warn("Viewport failed to stabilize");
|
|
@@ -5838,9 +5871,9 @@ class EditorView {
|
|
|
5838
5871
|
logException(this.state, e);
|
|
5839
5872
|
}
|
|
5840
5873
|
}
|
|
5841
|
-
if (this.viewState.
|
|
5842
|
-
this.docView.
|
|
5843
|
-
this.viewState.
|
|
5874
|
+
if (this.viewState.scrollTarget) {
|
|
5875
|
+
this.docView.scrollIntoView(this.viewState.scrollTarget);
|
|
5876
|
+
this.viewState.scrollTarget = null;
|
|
5844
5877
|
}
|
|
5845
5878
|
if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
|
|
5846
5879
|
break;
|
|
@@ -6063,12 +6096,9 @@ class EditorView {
|
|
|
6063
6096
|
moveVertically(start, forward, distance) {
|
|
6064
6097
|
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
|
6065
6098
|
}
|
|
6066
|
-
|
|
6067
|
-
Scroll the given document position into view.
|
|
6068
|
-
*/
|
|
6099
|
+
// FIXME remove on next major version
|
|
6069
6100
|
scrollPosIntoView(pos) {
|
|
6070
|
-
this.
|
|
6071
|
-
this.requestMeasure();
|
|
6101
|
+
this.dispatch({ effects: scrollTo.of(EditorSelection.cursor(pos)) });
|
|
6072
6102
|
}
|
|
6073
6103
|
/**
|
|
6074
6104
|
Find the DOM parent node and offset (child offset if `node` is
|
|
@@ -6244,6 +6274,11 @@ transaction to make it scroll the given range into view.
|
|
|
6244
6274
|
*/
|
|
6245
6275
|
EditorView.scrollTo = scrollTo;
|
|
6246
6276
|
/**
|
|
6277
|
+
Effect that makes the editor scroll the given range to the
|
|
6278
|
+
center of the visible view.
|
|
6279
|
+
*/
|
|
6280
|
+
EditorView.centerOn = centerOn;
|
|
6281
|
+
/**
|
|
6247
6282
|
Facet to add a [style
|
|
6248
6283
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
6249
6284
|
an editor view. The view will ensure that the module is
|