@codemirror/view 6.8.1 → 6.9.1
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 +165 -86
- package/dist/index.d.ts +5 -0
- package/dist/index.js +166 -87
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 6.9.1 (2023-02-17)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Improve the way `posAtCoords` picks the side of a widget to return by comparing the coordinates the center of the widget.
|
|
6
|
+
|
|
7
|
+
Fix an issue where transactions created for the `focusChangeEffect` facet were sometimes not dispatched.
|
|
8
|
+
|
|
9
|
+
## 6.9.0 (2023-02-15)
|
|
10
|
+
|
|
11
|
+
### Bug fixes
|
|
12
|
+
|
|
13
|
+
Fix an issue where inaccurate estimated vertical positions could cause the viewport to not converge in line-wrapped editors.
|
|
14
|
+
|
|
15
|
+
Don't suppress double-space to period conversion when autocorrect is enabled.
|
|
16
|
+
|
|
17
|
+
Make sure the measuring code notices when the scaling of the editor is changed, and does a full measure in that case.
|
|
18
|
+
|
|
19
|
+
### New features
|
|
20
|
+
|
|
21
|
+
The new `EditorView.focusChangeEffect` facet can be used to dispatch a state effect when the editor is focused or blurred.
|
|
22
|
+
|
|
1
23
|
## 6.8.1 (2023-02-08)
|
|
2
24
|
|
|
3
25
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -519,6 +519,7 @@ class ContentView {
|
|
|
519
519
|
}
|
|
520
520
|
static get(node) { return node.cmView; }
|
|
521
521
|
get isEditable() { return true; }
|
|
522
|
+
get isWidget() { return false; }
|
|
522
523
|
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
523
524
|
return false;
|
|
524
525
|
}
|
|
@@ -893,6 +894,7 @@ class WidgetView extends ContentView {
|
|
|
893
894
|
return this.length ? rect : flattenRect(rect, this.side > 0);
|
|
894
895
|
}
|
|
895
896
|
get isEditable() { return false; }
|
|
897
|
+
get isWidget() { return true; }
|
|
896
898
|
destroy() {
|
|
897
899
|
super.destroy();
|
|
898
900
|
if (this.dom)
|
|
@@ -1603,6 +1605,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1603
1605
|
}
|
|
1604
1606
|
ignoreMutation() { return true; }
|
|
1605
1607
|
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
1608
|
+
get isEditable() { return false; }
|
|
1609
|
+
get isWidget() { return true; }
|
|
1606
1610
|
destroy() {
|
|
1607
1611
|
super.destroy();
|
|
1608
1612
|
if (this.dom)
|
|
@@ -1784,6 +1788,7 @@ const mouseSelectionStyle = state.Facet.define();
|
|
|
1784
1788
|
const exceptionSink = state.Facet.define();
|
|
1785
1789
|
const updateListener = state.Facet.define();
|
|
1786
1790
|
const inputHandler = state.Facet.define();
|
|
1791
|
+
const focusChangeEffect = state.Facet.define();
|
|
1787
1792
|
const perLineTextDirection = state.Facet.define({
|
|
1788
1793
|
combine: values => values.some(x => x)
|
|
1789
1794
|
});
|
|
@@ -2026,11 +2031,6 @@ class ViewUpdate {
|
|
|
2026
2031
|
let changedRanges = [];
|
|
2027
2032
|
this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
|
|
2028
2033
|
this.changedRanges = changedRanges;
|
|
2029
|
-
let focus = view.hasFocus;
|
|
2030
|
-
if (focus != view.inputState.notifiedFocused) {
|
|
2031
|
-
view.inputState.notifiedFocused = focus;
|
|
2032
|
-
this.flags |= 1 /* UpdateFlag.Focus */;
|
|
2033
|
-
}
|
|
2034
2034
|
}
|
|
2035
2035
|
/**
|
|
2036
2036
|
@internal
|
|
@@ -3166,11 +3166,11 @@ function domPosInText(node, x, y) {
|
|
|
3166
3166
|
}
|
|
3167
3167
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
3168
3168
|
}
|
|
3169
|
-
function posAtCoords(view,
|
|
3169
|
+
function posAtCoords(view, coords, precise, bias = -1) {
|
|
3170
3170
|
var _a;
|
|
3171
3171
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
3172
3172
|
let block, { docHeight } = view.viewState;
|
|
3173
|
-
let yOffset = y - docTop;
|
|
3173
|
+
let { x, y } = coords, yOffset = y - docTop;
|
|
3174
3174
|
if (yOffset < 0)
|
|
3175
3175
|
return 0;
|
|
3176
3176
|
if (yOffset > docHeight)
|
|
@@ -3241,7 +3241,17 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
3241
3241
|
return yOffset > block.top + block.height / 2 ? block.to : block.from;
|
|
3242
3242
|
({ node, offset } = domPosAtCoords(line.dom, x, y));
|
|
3243
3243
|
}
|
|
3244
|
-
|
|
3244
|
+
let nearest = view.docView.nearest(node);
|
|
3245
|
+
if (!nearest)
|
|
3246
|
+
return null;
|
|
3247
|
+
if (nearest.isWidget) {
|
|
3248
|
+
let rect = nearest.dom.getBoundingClientRect();
|
|
3249
|
+
return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
|
|
3250
|
+
? nearest.posAtStart : nearest.posAtEnd;
|
|
3251
|
+
}
|
|
3252
|
+
else {
|
|
3253
|
+
return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
|
|
3254
|
+
}
|
|
3245
3255
|
}
|
|
3246
3256
|
function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
3247
3257
|
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
|
@@ -4032,10 +4042,26 @@ handlers.copy = handlers.cut = (view, event) => {
|
|
|
4032
4042
|
userEvent: "delete.cut"
|
|
4033
4043
|
});
|
|
4034
4044
|
};
|
|
4045
|
+
const isFocusChange = state.Annotation.define();
|
|
4046
|
+
function focusChangeTransaction(state, focus) {
|
|
4047
|
+
let effects = [];
|
|
4048
|
+
for (let getEffect of state.facet(focusChangeEffect)) {
|
|
4049
|
+
let effect = getEffect(state, focus);
|
|
4050
|
+
if (effect)
|
|
4051
|
+
effects.push(effect);
|
|
4052
|
+
}
|
|
4053
|
+
return effects ? state.update({ effects, annotations: isFocusChange.of(true) }) : null;
|
|
4054
|
+
}
|
|
4035
4055
|
function updateForFocusChange(view) {
|
|
4036
4056
|
setTimeout(() => {
|
|
4037
|
-
|
|
4038
|
-
|
|
4057
|
+
let focus = view.hasFocus;
|
|
4058
|
+
if (focus != view.inputState.notifiedFocused) {
|
|
4059
|
+
let tr = focusChangeTransaction(view.state, focus);
|
|
4060
|
+
if (tr)
|
|
4061
|
+
view.dispatch(tr);
|
|
4062
|
+
else
|
|
4063
|
+
view.update([]);
|
|
4064
|
+
}
|
|
4039
4065
|
}, 10);
|
|
4040
4066
|
}
|
|
4041
4067
|
handlers.focus = view => {
|
|
@@ -4117,7 +4143,7 @@ class HeightOracle {
|
|
|
4117
4143
|
heightForGap(from, to) {
|
|
4118
4144
|
let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
|
|
4119
4145
|
if (this.lineWrapping)
|
|
4120
|
-
lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength);
|
|
4146
|
+
lines += Math.max(0, Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength));
|
|
4121
4147
|
return this.lineHeight * lines;
|
|
4122
4148
|
}
|
|
4123
4149
|
heightForLine(length) {
|
|
@@ -4263,11 +4289,11 @@ class HeightMap {
|
|
|
4263
4289
|
decomposeLeft(_to, result) { result.push(this); }
|
|
4264
4290
|
decomposeRight(_from, result) { result.push(this); }
|
|
4265
4291
|
applyChanges(decorations, oldDoc, oracle, changes) {
|
|
4266
|
-
let me = this;
|
|
4292
|
+
let me = this, doc = oracle.doc;
|
|
4267
4293
|
for (let i = changes.length - 1; i >= 0; i--) {
|
|
4268
4294
|
let { fromA, toA, fromB, toB } = changes[i];
|
|
4269
|
-
let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
|
|
4270
|
-
let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight,
|
|
4295
|
+
let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
|
|
4296
|
+
let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
|
|
4271
4297
|
toB += end.to - toA;
|
|
4272
4298
|
toA = end.to;
|
|
4273
4299
|
while (i > 0 && start.from <= changes[i - 1].toA) {
|
|
@@ -4275,11 +4301,11 @@ class HeightMap {
|
|
|
4275
4301
|
fromB = changes[i - 1].fromB;
|
|
4276
4302
|
i--;
|
|
4277
4303
|
if (fromA < start.from)
|
|
4278
|
-
start = me.lineAt(fromA, QueryType.ByPosNoHeight,
|
|
4304
|
+
start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
|
|
4279
4305
|
}
|
|
4280
4306
|
fromB += start.from - fromA;
|
|
4281
4307
|
fromA = start.from;
|
|
4282
|
-
let nodes = NodeBuilder.build(oracle, decorations, fromB, toB);
|
|
4308
|
+
let nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
|
|
4283
4309
|
me = me.replace(fromA, toA, nodes);
|
|
4284
4310
|
}
|
|
4285
4311
|
return me.updateHeight(oracle, 0);
|
|
@@ -4346,15 +4372,15 @@ class HeightMapBlock extends HeightMap {
|
|
|
4346
4372
|
super(length, height);
|
|
4347
4373
|
this.type = type;
|
|
4348
4374
|
}
|
|
4349
|
-
blockAt(_height,
|
|
4375
|
+
blockAt(_height, _oracle, top, offset) {
|
|
4350
4376
|
return new BlockInfo(offset, this.length, top, this.height, this.type);
|
|
4351
4377
|
}
|
|
4352
|
-
lineAt(_value, _type,
|
|
4353
|
-
return this.blockAt(0,
|
|
4378
|
+
lineAt(_value, _type, oracle, top, offset) {
|
|
4379
|
+
return this.blockAt(0, oracle, top, offset);
|
|
4354
4380
|
}
|
|
4355
|
-
forEachLine(from, to,
|
|
4381
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4356
4382
|
if (from <= offset + this.length && to >= offset)
|
|
4357
|
-
f(this.blockAt(0,
|
|
4383
|
+
f(this.blockAt(0, oracle, top, offset));
|
|
4358
4384
|
}
|
|
4359
4385
|
updateHeight(oracle, offset = 0, _force = false, measured) {
|
|
4360
4386
|
if (measured && measured.from <= offset && measured.more)
|
|
@@ -4400,35 +4426,60 @@ class HeightMapText extends HeightMapBlock {
|
|
|
4400
4426
|
}
|
|
4401
4427
|
class HeightMapGap extends HeightMap {
|
|
4402
4428
|
constructor(length) { super(length, 0); }
|
|
4403
|
-
|
|
4404
|
-
let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number;
|
|
4405
|
-
|
|
4429
|
+
heightMetrics(oracle, offset) {
|
|
4430
|
+
let firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
|
|
4431
|
+
let lines = lastLine - firstLine + 1;
|
|
4432
|
+
let perLine, perChar = 0;
|
|
4433
|
+
if (oracle.lineWrapping) {
|
|
4434
|
+
let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
|
|
4435
|
+
perLine = totalPerLine / lines;
|
|
4436
|
+
perChar = (this.height - totalPerLine) / (this.length - lines - 1);
|
|
4437
|
+
}
|
|
4438
|
+
else {
|
|
4439
|
+
perLine = this.height / lines;
|
|
4440
|
+
}
|
|
4441
|
+
return { firstLine, lastLine, perLine, perChar };
|
|
4406
4442
|
}
|
|
4407
|
-
blockAt(height,
|
|
4408
|
-
let { firstLine, lastLine,
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4443
|
+
blockAt(height, oracle, top, offset) {
|
|
4444
|
+
let { firstLine, lastLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4445
|
+
if (oracle.lineWrapping) {
|
|
4446
|
+
let guess = offset + Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length);
|
|
4447
|
+
let line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
|
|
4448
|
+
let lineTop = Math.max(top, height - lineHeight / 2);
|
|
4449
|
+
return new BlockInfo(line.from, line.length, lineTop, lineHeight, exports.BlockType.Text);
|
|
4450
|
+
}
|
|
4451
|
+
else {
|
|
4452
|
+
let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
|
|
4453
|
+
let { from, length } = oracle.doc.line(firstLine + line);
|
|
4454
|
+
return new BlockInfo(from, length, top + perLine * line, perLine, exports.BlockType.Text);
|
|
4455
|
+
}
|
|
4412
4456
|
}
|
|
4413
|
-
lineAt(value, type,
|
|
4457
|
+
lineAt(value, type, oracle, top, offset) {
|
|
4414
4458
|
if (type == QueryType.ByHeight)
|
|
4415
|
-
return this.blockAt(value,
|
|
4459
|
+
return this.blockAt(value, oracle, top, offset);
|
|
4416
4460
|
if (type == QueryType.ByPosNoHeight) {
|
|
4417
|
-
let { from, to } = doc.lineAt(value);
|
|
4461
|
+
let { from, to } = oracle.doc.lineAt(value);
|
|
4418
4462
|
return new BlockInfo(from, to - from, 0, 0, exports.BlockType.Text);
|
|
4419
4463
|
}
|
|
4420
|
-
let { firstLine,
|
|
4421
|
-
let
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4464
|
+
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4465
|
+
let line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
|
|
4466
|
+
let linesAbove = line.number - firstLine;
|
|
4467
|
+
let lineTop = top + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
|
|
4468
|
+
return new BlockInfo(line.from, line.length, Math.max(top, Math.min(lineTop, top + this.height - lineHeight)), lineHeight, exports.BlockType.Text);
|
|
4469
|
+
}
|
|
4470
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4471
|
+
from = Math.max(from, offset);
|
|
4472
|
+
to = Math.min(to, offset + this.length);
|
|
4473
|
+
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4474
|
+
for (let pos = from, lineTop = top; pos <= to;) {
|
|
4475
|
+
let line = oracle.doc.lineAt(pos);
|
|
4476
|
+
if (pos == from) {
|
|
4477
|
+
let linesAbove = line.number - firstLine;
|
|
4478
|
+
lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
|
|
4479
|
+
}
|
|
4480
|
+
let lineHeight = perLine + perChar * line.length;
|
|
4481
|
+
f(new BlockInfo(line.from, line.length, lineTop, lineHeight, exports.BlockType.Text));
|
|
4482
|
+
lineTop += lineHeight;
|
|
4432
4483
|
pos = line.to + 1;
|
|
4433
4484
|
}
|
|
4434
4485
|
}
|
|
@@ -4464,7 +4515,6 @@ class HeightMapGap extends HeightMap {
|
|
|
4464
4515
|
// they would already have been added to the heightmap (gaps
|
|
4465
4516
|
// only contain plain text).
|
|
4466
4517
|
let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
|
|
4467
|
-
let wasChanged = oracle.heightChanged;
|
|
4468
4518
|
if (measured.from > offset)
|
|
4469
4519
|
nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
|
|
4470
4520
|
while (pos <= end && measured.more) {
|
|
@@ -4484,8 +4534,9 @@ class HeightMapGap extends HeightMap {
|
|
|
4484
4534
|
if (pos <= end)
|
|
4485
4535
|
nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
|
|
4486
4536
|
let result = HeightMap.of(nodes);
|
|
4487
|
-
|
|
4488
|
-
Math.abs(singleHeight - this.
|
|
4537
|
+
if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
|
|
4538
|
+
Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon)
|
|
4539
|
+
oracle.heightChanged = true;
|
|
4489
4540
|
return result;
|
|
4490
4541
|
}
|
|
4491
4542
|
else if (force || this.outdated) {
|
|
@@ -4504,40 +4555,40 @@ class HeightMapBranch extends HeightMap {
|
|
|
4504
4555
|
this.size = left.size + right.size;
|
|
4505
4556
|
}
|
|
4506
4557
|
get break() { return this.flags & 1 /* Flag.Break */; }
|
|
4507
|
-
blockAt(height,
|
|
4558
|
+
blockAt(height, oracle, top, offset) {
|
|
4508
4559
|
let mid = top + this.left.height;
|
|
4509
|
-
return height < mid ? this.left.blockAt(height,
|
|
4510
|
-
: this.right.blockAt(height,
|
|
4560
|
+
return height < mid ? this.left.blockAt(height, oracle, top, offset)
|
|
4561
|
+
: this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
|
|
4511
4562
|
}
|
|
4512
|
-
lineAt(value, type,
|
|
4563
|
+
lineAt(value, type, oracle, top, offset) {
|
|
4513
4564
|
let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
|
4514
4565
|
let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
|
|
4515
|
-
let base = left ? this.left.lineAt(value, type,
|
|
4516
|
-
: this.right.lineAt(value, type,
|
|
4566
|
+
let base = left ? this.left.lineAt(value, type, oracle, top, offset)
|
|
4567
|
+
: this.right.lineAt(value, type, oracle, rightTop, rightOffset);
|
|
4517
4568
|
if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
|
|
4518
4569
|
return base;
|
|
4519
4570
|
let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
|
|
4520
4571
|
if (left)
|
|
4521
|
-
return base.join(this.right.lineAt(rightOffset, subQuery,
|
|
4572
|
+
return base.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));
|
|
4522
4573
|
else
|
|
4523
|
-
return this.left.lineAt(rightOffset, subQuery,
|
|
4574
|
+
return this.left.lineAt(rightOffset, subQuery, oracle, top, offset).join(base);
|
|
4524
4575
|
}
|
|
4525
|
-
forEachLine(from, to,
|
|
4576
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4526
4577
|
let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
|
4527
4578
|
if (this.break) {
|
|
4528
4579
|
if (from < rightOffset)
|
|
4529
|
-
this.left.forEachLine(from, to,
|
|
4580
|
+
this.left.forEachLine(from, to, oracle, top, offset, f);
|
|
4530
4581
|
if (to >= rightOffset)
|
|
4531
|
-
this.right.forEachLine(from, to,
|
|
4582
|
+
this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
|
|
4532
4583
|
}
|
|
4533
4584
|
else {
|
|
4534
|
-
let mid = this.lineAt(rightOffset, QueryType.ByPos,
|
|
4585
|
+
let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
|
|
4535
4586
|
if (from < mid.from)
|
|
4536
|
-
this.left.forEachLine(from, mid.from - 1,
|
|
4587
|
+
this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
|
|
4537
4588
|
if (mid.to >= from && mid.from <= to)
|
|
4538
4589
|
f(mid);
|
|
4539
4590
|
if (to > mid.to)
|
|
4540
|
-
this.right.forEachLine(mid.to + 1, to,
|
|
4591
|
+
this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
|
|
4541
4592
|
}
|
|
4542
4593
|
}
|
|
4543
4594
|
replace(from, to, nodes) {
|
|
@@ -4887,11 +4938,11 @@ class ViewState {
|
|
|
4887
4938
|
}
|
|
4888
4939
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
4889
4940
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
4890
|
-
new BigScaler(this.heightOracle
|
|
4941
|
+
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
4891
4942
|
}
|
|
4892
4943
|
updateViewportLines() {
|
|
4893
4944
|
this.viewportLines = [];
|
|
4894
|
-
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
|
|
4945
|
+
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
4895
4946
|
this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
|
|
4896
4947
|
});
|
|
4897
4948
|
}
|
|
@@ -4931,8 +4982,9 @@ class ViewState {
|
|
|
4931
4982
|
let whiteSpace = style.whiteSpace;
|
|
4932
4983
|
this.defaultTextDirection = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
|
|
4933
4984
|
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4934
|
-
let
|
|
4935
|
-
this.contentDOMHeight
|
|
4985
|
+
let domRect = dom.getBoundingClientRect();
|
|
4986
|
+
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
|
|
4987
|
+
this.contentDOMHeight = domRect.height;
|
|
4936
4988
|
this.mustMeasureContent = false;
|
|
4937
4989
|
let result = 0, bias = 0;
|
|
4938
4990
|
// Vertical padding
|
|
@@ -4960,9 +5012,9 @@ class ViewState {
|
|
|
4960
5012
|
}
|
|
4961
5013
|
if (!this.inView && !this.scrollTarget)
|
|
4962
5014
|
return 0;
|
|
4963
|
-
let contentWidth =
|
|
5015
|
+
let contentWidth = domRect.width;
|
|
4964
5016
|
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4965
|
-
this.contentDOMWidth =
|
|
5017
|
+
this.contentDOMWidth = domRect.width;
|
|
4966
5018
|
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4967
5019
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
4968
5020
|
}
|
|
@@ -4991,7 +5043,8 @@ class ViewState {
|
|
|
4991
5043
|
result |= 2 /* UpdateFlag.Height */;
|
|
4992
5044
|
}
|
|
4993
5045
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4994
|
-
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5046
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5047
|
+
this.scrollTarget.range.head > this.viewport.to);
|
|
4995
5048
|
if (viewportChange)
|
|
4996
5049
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4997
5050
|
this.updateForViewport();
|
|
@@ -5017,36 +5070,37 @@ class ViewState {
|
|
|
5017
5070
|
// bottom, depending on the bias (the change in viewport position
|
|
5018
5071
|
// since the last update). It'll hold a number between 0 and 1
|
|
5019
5072
|
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
|
|
5020
|
-
let map = this.heightMap,
|
|
5021
|
-
let
|
|
5073
|
+
let map = this.heightMap, oracle = this.heightOracle;
|
|
5074
|
+
let { visibleTop, visibleBottom } = this;
|
|
5075
|
+
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).to);
|
|
5022
5076
|
// If scrollTarget is given, make sure the viewport includes that position
|
|
5023
5077
|
if (scrollTarget) {
|
|
5024
5078
|
let { head } = scrollTarget.range;
|
|
5025
5079
|
if (head < viewport.from || head > viewport.to) {
|
|
5026
5080
|
let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
|
|
5027
|
-
let block = map.lineAt(head, QueryType.ByPos,
|
|
5081
|
+
let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0), topPos;
|
|
5028
5082
|
if (scrollTarget.y == "center")
|
|
5029
5083
|
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
5030
5084
|
else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
|
|
5031
5085
|
topPos = block.top;
|
|
5032
5086
|
else
|
|
5033
5087
|
topPos = block.bottom - viewHeight;
|
|
5034
|
-
viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight,
|
|
5088
|
+
viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).to);
|
|
5035
5089
|
}
|
|
5036
5090
|
}
|
|
5037
5091
|
return viewport;
|
|
5038
5092
|
}
|
|
5039
5093
|
mapViewport(viewport, changes) {
|
|
5040
5094
|
let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
|
|
5041
|
-
return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.
|
|
5095
|
+
return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
|
|
5042
5096
|
}
|
|
5043
5097
|
// Checks if a given viewport covers the visible part of the
|
|
5044
5098
|
// document and not too much beyond that.
|
|
5045
5099
|
viewportIsAppropriate({ from, to }, bias = 0) {
|
|
5046
5100
|
if (!this.inView)
|
|
5047
5101
|
return true;
|
|
5048
|
-
let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.
|
|
5049
|
-
let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.
|
|
5102
|
+
let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
|
|
5103
|
+
let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
|
|
5050
5104
|
let { visibleTop, visibleBottom } = this;
|
|
5051
5105
|
return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) &&
|
|
5052
5106
|
(to == this.state.doc.length ||
|
|
@@ -5183,13 +5237,13 @@ class ViewState {
|
|
|
5183
5237
|
}
|
|
5184
5238
|
lineBlockAt(pos) {
|
|
5185
5239
|
return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5186
|
-
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.
|
|
5240
|
+
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5187
5241
|
}
|
|
5188
5242
|
lineBlockAtHeight(height) {
|
|
5189
|
-
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.
|
|
5243
|
+
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5190
5244
|
}
|
|
5191
5245
|
elementAtHeight(height) {
|
|
5192
|
-
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.
|
|
5246
|
+
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
|
|
5193
5247
|
}
|
|
5194
5248
|
get docHeight() {
|
|
5195
5249
|
return this.scaler.toDOM(this.heightMap.height);
|
|
@@ -5263,11 +5317,11 @@ const IdScaler = {
|
|
|
5263
5317
|
// regions outside the viewports so that the total height is
|
|
5264
5318
|
// VP.MaxDOMHeight.
|
|
5265
5319
|
class BigScaler {
|
|
5266
|
-
constructor(
|
|
5320
|
+
constructor(oracle, heightMap, viewports) {
|
|
5267
5321
|
let vpHeight = 0, base = 0, domBase = 0;
|
|
5268
5322
|
this.viewports = viewports.map(({ from, to }) => {
|
|
5269
|
-
let top = heightMap.lineAt(from, QueryType.ByPos,
|
|
5270
|
-
let bottom = heightMap.lineAt(to, QueryType.ByPos,
|
|
5323
|
+
let top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
|
|
5324
|
+
let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
|
|
5271
5325
|
vpHeight += bottom - top;
|
|
5272
5326
|
return { from, to, top, bottom, domTop: 0, domBottom: 0 };
|
|
5273
5327
|
});
|
|
@@ -5634,7 +5688,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5634
5688
|
};
|
|
5635
5689
|
}
|
|
5636
5690
|
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5637
|
-
/^\. ?$/.test(change.insert.toString())) {
|
|
5691
|
+
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
5638
5692
|
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5639
5693
|
// and transform it into a regular space insert.
|
|
5640
5694
|
if (newSel && change.insert.length == 2)
|
|
@@ -6388,6 +6442,20 @@ class EditorView {
|
|
|
6388
6442
|
this.viewState.state = state$1;
|
|
6389
6443
|
return;
|
|
6390
6444
|
}
|
|
6445
|
+
let focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
|
|
6446
|
+
if (transactions.some(tr => tr.annotation(isFocusChange))) {
|
|
6447
|
+
this.inputState.notifiedFocused = focus;
|
|
6448
|
+
// If a focus-change transaction is being dispatched, set this update flag.
|
|
6449
|
+
focusFlag = 1 /* UpdateFlag.Focus */;
|
|
6450
|
+
}
|
|
6451
|
+
else if (focus != this.inputState.notifiedFocused) {
|
|
6452
|
+
this.inputState.notifiedFocused = focus;
|
|
6453
|
+
// Schedule a separate focus transaction if necessary, otherwise
|
|
6454
|
+
// add a flag to this update
|
|
6455
|
+
dispatchFocus = focusChangeTransaction(state$1, focus);
|
|
6456
|
+
if (!dispatchFocus)
|
|
6457
|
+
focusFlag = 1 /* UpdateFlag.Focus */;
|
|
6458
|
+
}
|
|
6391
6459
|
// If there was a pending DOM change, eagerly read it and try to
|
|
6392
6460
|
// apply it after the given transactions.
|
|
6393
6461
|
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
|
|
@@ -6406,6 +6474,7 @@ class EditorView {
|
|
|
6406
6474
|
if (state$1.facet(state.EditorState.phrases) != this.state.facet(state.EditorState.phrases))
|
|
6407
6475
|
return this.setState(state$1);
|
|
6408
6476
|
update = ViewUpdate.create(this, state$1, transactions);
|
|
6477
|
+
update.flags |= focusFlag;
|
|
6409
6478
|
let scrollTarget = this.viewState.scrollTarget;
|
|
6410
6479
|
try {
|
|
6411
6480
|
this.updateState = 2 /* UpdateState.Updating */;
|
|
@@ -6443,10 +6512,15 @@ class EditorView {
|
|
|
6443
6512
|
if (!update.empty)
|
|
6444
6513
|
for (let listener of this.state.facet(updateListener))
|
|
6445
6514
|
listener(update);
|
|
6446
|
-
if (domChange)
|
|
6447
|
-
|
|
6448
|
-
|
|
6449
|
-
|
|
6515
|
+
if (dispatchFocus || domChange)
|
|
6516
|
+
Promise.resolve().then(() => {
|
|
6517
|
+
if (dispatchFocus && this.state == dispatchFocus.startState)
|
|
6518
|
+
this.dispatch(dispatchFocus);
|
|
6519
|
+
if (domChange) {
|
|
6520
|
+
if (!applyDOMChange(this, domChange) && pendingKey.force)
|
|
6521
|
+
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
|
|
6522
|
+
}
|
|
6523
|
+
});
|
|
6450
6524
|
}
|
|
6451
6525
|
/**
|
|
6452
6526
|
Reset the view to the given state. (This will cause the entire
|
|
@@ -7048,6 +7122,11 @@ called and the default behavior is prevented.
|
|
|
7048
7122
|
*/
|
|
7049
7123
|
EditorView.inputHandler = inputHandler;
|
|
7050
7124
|
/**
|
|
7125
|
+
This facet can be used to provide functions that create effects
|
|
7126
|
+
to be dispatched when the editor's focus state changes.
|
|
7127
|
+
*/
|
|
7128
|
+
EditorView.focusChangeEffect = focusChangeEffect;
|
|
7129
|
+
/**
|
|
7051
7130
|
By default, the editor assumes all its content has the same
|
|
7052
7131
|
[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
|
|
7053
7132
|
value to make it read the text direction of every (rendered)
|
package/dist/index.d.ts
CHANGED
|
@@ -995,6 +995,11 @@ declare class EditorView {
|
|
|
995
995
|
*/
|
|
996
996
|
static inputHandler: Facet<(view: EditorView, from: number, to: number, text: string) => boolean, readonly ((view: EditorView, from: number, to: number, text: string) => boolean)[]>;
|
|
997
997
|
/**
|
|
998
|
+
This facet can be used to provide functions that create effects
|
|
999
|
+
to be dispatched when the editor's focus state changes.
|
|
1000
|
+
*/
|
|
1001
|
+
static focusChangeEffect: Facet<(state: EditorState, focusing: boolean) => StateEffect<any> | null, readonly ((state: EditorState, focusing: boolean) => StateEffect<any> | null)[]>;
|
|
1002
|
+
/**
|
|
998
1003
|
By default, the editor assumes all its content has the same
|
|
999
1004
|
[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
|
|
1000
1005
|
value to make it read the text direction of every (rendered)
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
|
|
1
|
+
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Annotation, Transaction, Prec, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
3
|
import { keyName, base, shift } from 'w3c-keyname';
|
|
4
4
|
|
|
@@ -515,6 +515,7 @@ class ContentView {
|
|
|
515
515
|
}
|
|
516
516
|
static get(node) { return node.cmView; }
|
|
517
517
|
get isEditable() { return true; }
|
|
518
|
+
get isWidget() { return false; }
|
|
518
519
|
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
519
520
|
return false;
|
|
520
521
|
}
|
|
@@ -889,6 +890,7 @@ class WidgetView extends ContentView {
|
|
|
889
890
|
return this.length ? rect : flattenRect(rect, this.side > 0);
|
|
890
891
|
}
|
|
891
892
|
get isEditable() { return false; }
|
|
893
|
+
get isWidget() { return true; }
|
|
892
894
|
destroy() {
|
|
893
895
|
super.destroy();
|
|
894
896
|
if (this.dom)
|
|
@@ -1598,6 +1600,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1598
1600
|
}
|
|
1599
1601
|
ignoreMutation() { return true; }
|
|
1600
1602
|
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
1603
|
+
get isEditable() { return false; }
|
|
1604
|
+
get isWidget() { return true; }
|
|
1601
1605
|
destroy() {
|
|
1602
1606
|
super.destroy();
|
|
1603
1607
|
if (this.dom)
|
|
@@ -1779,6 +1783,7 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
|
|
|
1779
1783
|
const exceptionSink = /*@__PURE__*/Facet.define();
|
|
1780
1784
|
const updateListener = /*@__PURE__*/Facet.define();
|
|
1781
1785
|
const inputHandler = /*@__PURE__*/Facet.define();
|
|
1786
|
+
const focusChangeEffect = /*@__PURE__*/Facet.define();
|
|
1782
1787
|
const perLineTextDirection = /*@__PURE__*/Facet.define({
|
|
1783
1788
|
combine: values => values.some(x => x)
|
|
1784
1789
|
});
|
|
@@ -2021,11 +2026,6 @@ class ViewUpdate {
|
|
|
2021
2026
|
let changedRanges = [];
|
|
2022
2027
|
this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
|
|
2023
2028
|
this.changedRanges = changedRanges;
|
|
2024
|
-
let focus = view.hasFocus;
|
|
2025
|
-
if (focus != view.inputState.notifiedFocused) {
|
|
2026
|
-
view.inputState.notifiedFocused = focus;
|
|
2027
|
-
this.flags |= 1 /* UpdateFlag.Focus */;
|
|
2028
|
-
}
|
|
2029
2029
|
}
|
|
2030
2030
|
/**
|
|
2031
2031
|
@internal
|
|
@@ -3160,11 +3160,11 @@ function domPosInText(node, x, y) {
|
|
|
3160
3160
|
}
|
|
3161
3161
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
3162
3162
|
}
|
|
3163
|
-
function posAtCoords(view,
|
|
3163
|
+
function posAtCoords(view, coords, precise, bias = -1) {
|
|
3164
3164
|
var _a;
|
|
3165
3165
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
3166
3166
|
let block, { docHeight } = view.viewState;
|
|
3167
|
-
let yOffset = y - docTop;
|
|
3167
|
+
let { x, y } = coords, yOffset = y - docTop;
|
|
3168
3168
|
if (yOffset < 0)
|
|
3169
3169
|
return 0;
|
|
3170
3170
|
if (yOffset > docHeight)
|
|
@@ -3235,7 +3235,17 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
3235
3235
|
return yOffset > block.top + block.height / 2 ? block.to : block.from;
|
|
3236
3236
|
({ node, offset } = domPosAtCoords(line.dom, x, y));
|
|
3237
3237
|
}
|
|
3238
|
-
|
|
3238
|
+
let nearest = view.docView.nearest(node);
|
|
3239
|
+
if (!nearest)
|
|
3240
|
+
return null;
|
|
3241
|
+
if (nearest.isWidget) {
|
|
3242
|
+
let rect = nearest.dom.getBoundingClientRect();
|
|
3243
|
+
return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
|
|
3244
|
+
? nearest.posAtStart : nearest.posAtEnd;
|
|
3245
|
+
}
|
|
3246
|
+
else {
|
|
3247
|
+
return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
|
|
3248
|
+
}
|
|
3239
3249
|
}
|
|
3240
3250
|
function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
3241
3251
|
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
|
@@ -4026,10 +4036,26 @@ handlers.copy = handlers.cut = (view, event) => {
|
|
|
4026
4036
|
userEvent: "delete.cut"
|
|
4027
4037
|
});
|
|
4028
4038
|
};
|
|
4039
|
+
const isFocusChange = /*@__PURE__*/Annotation.define();
|
|
4040
|
+
function focusChangeTransaction(state, focus) {
|
|
4041
|
+
let effects = [];
|
|
4042
|
+
for (let getEffect of state.facet(focusChangeEffect)) {
|
|
4043
|
+
let effect = getEffect(state, focus);
|
|
4044
|
+
if (effect)
|
|
4045
|
+
effects.push(effect);
|
|
4046
|
+
}
|
|
4047
|
+
return effects ? state.update({ effects, annotations: isFocusChange.of(true) }) : null;
|
|
4048
|
+
}
|
|
4029
4049
|
function updateForFocusChange(view) {
|
|
4030
4050
|
setTimeout(() => {
|
|
4031
|
-
|
|
4032
|
-
|
|
4051
|
+
let focus = view.hasFocus;
|
|
4052
|
+
if (focus != view.inputState.notifiedFocused) {
|
|
4053
|
+
let tr = focusChangeTransaction(view.state, focus);
|
|
4054
|
+
if (tr)
|
|
4055
|
+
view.dispatch(tr);
|
|
4056
|
+
else
|
|
4057
|
+
view.update([]);
|
|
4058
|
+
}
|
|
4033
4059
|
}, 10);
|
|
4034
4060
|
}
|
|
4035
4061
|
handlers.focus = view => {
|
|
@@ -4111,7 +4137,7 @@ class HeightOracle {
|
|
|
4111
4137
|
heightForGap(from, to) {
|
|
4112
4138
|
let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
|
|
4113
4139
|
if (this.lineWrapping)
|
|
4114
|
-
lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength);
|
|
4140
|
+
lines += Math.max(0, Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength));
|
|
4115
4141
|
return this.lineHeight * lines;
|
|
4116
4142
|
}
|
|
4117
4143
|
heightForLine(length) {
|
|
@@ -4256,11 +4282,11 @@ class HeightMap {
|
|
|
4256
4282
|
decomposeLeft(_to, result) { result.push(this); }
|
|
4257
4283
|
decomposeRight(_from, result) { result.push(this); }
|
|
4258
4284
|
applyChanges(decorations, oldDoc, oracle, changes) {
|
|
4259
|
-
let me = this;
|
|
4285
|
+
let me = this, doc = oracle.doc;
|
|
4260
4286
|
for (let i = changes.length - 1; i >= 0; i--) {
|
|
4261
4287
|
let { fromA, toA, fromB, toB } = changes[i];
|
|
4262
|
-
let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
|
|
4263
|
-
let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight,
|
|
4288
|
+
let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle.setDoc(oldDoc), 0, 0);
|
|
4289
|
+
let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oracle, 0, 0);
|
|
4264
4290
|
toB += end.to - toA;
|
|
4265
4291
|
toA = end.to;
|
|
4266
4292
|
while (i > 0 && start.from <= changes[i - 1].toA) {
|
|
@@ -4268,11 +4294,11 @@ class HeightMap {
|
|
|
4268
4294
|
fromB = changes[i - 1].fromB;
|
|
4269
4295
|
i--;
|
|
4270
4296
|
if (fromA < start.from)
|
|
4271
|
-
start = me.lineAt(fromA, QueryType.ByPosNoHeight,
|
|
4297
|
+
start = me.lineAt(fromA, QueryType.ByPosNoHeight, oracle, 0, 0);
|
|
4272
4298
|
}
|
|
4273
4299
|
fromB += start.from - fromA;
|
|
4274
4300
|
fromA = start.from;
|
|
4275
|
-
let nodes = NodeBuilder.build(oracle, decorations, fromB, toB);
|
|
4301
|
+
let nodes = NodeBuilder.build(oracle.setDoc(doc), decorations, fromB, toB);
|
|
4276
4302
|
me = me.replace(fromA, toA, nodes);
|
|
4277
4303
|
}
|
|
4278
4304
|
return me.updateHeight(oracle, 0);
|
|
@@ -4339,15 +4365,15 @@ class HeightMapBlock extends HeightMap {
|
|
|
4339
4365
|
super(length, height);
|
|
4340
4366
|
this.type = type;
|
|
4341
4367
|
}
|
|
4342
|
-
blockAt(_height,
|
|
4368
|
+
blockAt(_height, _oracle, top, offset) {
|
|
4343
4369
|
return new BlockInfo(offset, this.length, top, this.height, this.type);
|
|
4344
4370
|
}
|
|
4345
|
-
lineAt(_value, _type,
|
|
4346
|
-
return this.blockAt(0,
|
|
4371
|
+
lineAt(_value, _type, oracle, top, offset) {
|
|
4372
|
+
return this.blockAt(0, oracle, top, offset);
|
|
4347
4373
|
}
|
|
4348
|
-
forEachLine(from, to,
|
|
4374
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4349
4375
|
if (from <= offset + this.length && to >= offset)
|
|
4350
|
-
f(this.blockAt(0,
|
|
4376
|
+
f(this.blockAt(0, oracle, top, offset));
|
|
4351
4377
|
}
|
|
4352
4378
|
updateHeight(oracle, offset = 0, _force = false, measured) {
|
|
4353
4379
|
if (measured && measured.from <= offset && measured.more)
|
|
@@ -4393,35 +4419,60 @@ class HeightMapText extends HeightMapBlock {
|
|
|
4393
4419
|
}
|
|
4394
4420
|
class HeightMapGap extends HeightMap {
|
|
4395
4421
|
constructor(length) { super(length, 0); }
|
|
4396
|
-
|
|
4397
|
-
let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number;
|
|
4398
|
-
|
|
4422
|
+
heightMetrics(oracle, offset) {
|
|
4423
|
+
let firstLine = oracle.doc.lineAt(offset).number, lastLine = oracle.doc.lineAt(offset + this.length).number;
|
|
4424
|
+
let lines = lastLine - firstLine + 1;
|
|
4425
|
+
let perLine, perChar = 0;
|
|
4426
|
+
if (oracle.lineWrapping) {
|
|
4427
|
+
let totalPerLine = Math.min(this.height, oracle.lineHeight * lines);
|
|
4428
|
+
perLine = totalPerLine / lines;
|
|
4429
|
+
perChar = (this.height - totalPerLine) / (this.length - lines - 1);
|
|
4430
|
+
}
|
|
4431
|
+
else {
|
|
4432
|
+
perLine = this.height / lines;
|
|
4433
|
+
}
|
|
4434
|
+
return { firstLine, lastLine, perLine, perChar };
|
|
4399
4435
|
}
|
|
4400
|
-
blockAt(height,
|
|
4401
|
-
let { firstLine, lastLine,
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4436
|
+
blockAt(height, oracle, top, offset) {
|
|
4437
|
+
let { firstLine, lastLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4438
|
+
if (oracle.lineWrapping) {
|
|
4439
|
+
let guess = offset + Math.round(Math.max(0, Math.min(1, (height - top) / this.height)) * this.length);
|
|
4440
|
+
let line = oracle.doc.lineAt(guess), lineHeight = perLine + line.length * perChar;
|
|
4441
|
+
let lineTop = Math.max(top, height - lineHeight / 2);
|
|
4442
|
+
return new BlockInfo(line.from, line.length, lineTop, lineHeight, BlockType.Text);
|
|
4443
|
+
}
|
|
4444
|
+
else {
|
|
4445
|
+
let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / perLine)));
|
|
4446
|
+
let { from, length } = oracle.doc.line(firstLine + line);
|
|
4447
|
+
return new BlockInfo(from, length, top + perLine * line, perLine, BlockType.Text);
|
|
4448
|
+
}
|
|
4405
4449
|
}
|
|
4406
|
-
lineAt(value, type,
|
|
4450
|
+
lineAt(value, type, oracle, top, offset) {
|
|
4407
4451
|
if (type == QueryType.ByHeight)
|
|
4408
|
-
return this.blockAt(value,
|
|
4452
|
+
return this.blockAt(value, oracle, top, offset);
|
|
4409
4453
|
if (type == QueryType.ByPosNoHeight) {
|
|
4410
|
-
let { from, to } = doc.lineAt(value);
|
|
4454
|
+
let { from, to } = oracle.doc.lineAt(value);
|
|
4411
4455
|
return new BlockInfo(from, to - from, 0, 0, BlockType.Text);
|
|
4412
4456
|
}
|
|
4413
|
-
let { firstLine,
|
|
4414
|
-
let
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4457
|
+
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4458
|
+
let line = oracle.doc.lineAt(value), lineHeight = perLine + line.length * perChar;
|
|
4459
|
+
let linesAbove = line.number - firstLine;
|
|
4460
|
+
let lineTop = top + perLine * linesAbove + perChar * (line.from - offset - linesAbove);
|
|
4461
|
+
return new BlockInfo(line.from, line.length, Math.max(top, Math.min(lineTop, top + this.height - lineHeight)), lineHeight, BlockType.Text);
|
|
4462
|
+
}
|
|
4463
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4464
|
+
from = Math.max(from, offset);
|
|
4465
|
+
to = Math.min(to, offset + this.length);
|
|
4466
|
+
let { firstLine, perLine, perChar } = this.heightMetrics(oracle, offset);
|
|
4467
|
+
for (let pos = from, lineTop = top; pos <= to;) {
|
|
4468
|
+
let line = oracle.doc.lineAt(pos);
|
|
4469
|
+
if (pos == from) {
|
|
4470
|
+
let linesAbove = line.number - firstLine;
|
|
4471
|
+
lineTop += perLine * linesAbove + perChar * (from - offset - linesAbove);
|
|
4472
|
+
}
|
|
4473
|
+
let lineHeight = perLine + perChar * line.length;
|
|
4474
|
+
f(new BlockInfo(line.from, line.length, lineTop, lineHeight, BlockType.Text));
|
|
4475
|
+
lineTop += lineHeight;
|
|
4425
4476
|
pos = line.to + 1;
|
|
4426
4477
|
}
|
|
4427
4478
|
}
|
|
@@ -4457,7 +4508,6 @@ class HeightMapGap extends HeightMap {
|
|
|
4457
4508
|
// they would already have been added to the heightmap (gaps
|
|
4458
4509
|
// only contain plain text).
|
|
4459
4510
|
let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
|
|
4460
|
-
let wasChanged = oracle.heightChanged;
|
|
4461
4511
|
if (measured.from > offset)
|
|
4462
4512
|
nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
|
|
4463
4513
|
while (pos <= end && measured.more) {
|
|
@@ -4477,8 +4527,9 @@ class HeightMapGap extends HeightMap {
|
|
|
4477
4527
|
if (pos <= end)
|
|
4478
4528
|
nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
|
|
4479
4529
|
let result = HeightMap.of(nodes);
|
|
4480
|
-
|
|
4481
|
-
Math.abs(singleHeight - this.
|
|
4530
|
+
if (singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
|
|
4531
|
+
Math.abs(singleHeight - this.heightMetrics(oracle, offset).perLine) >= Epsilon)
|
|
4532
|
+
oracle.heightChanged = true;
|
|
4482
4533
|
return result;
|
|
4483
4534
|
}
|
|
4484
4535
|
else if (force || this.outdated) {
|
|
@@ -4497,40 +4548,40 @@ class HeightMapBranch extends HeightMap {
|
|
|
4497
4548
|
this.size = left.size + right.size;
|
|
4498
4549
|
}
|
|
4499
4550
|
get break() { return this.flags & 1 /* Flag.Break */; }
|
|
4500
|
-
blockAt(height,
|
|
4551
|
+
blockAt(height, oracle, top, offset) {
|
|
4501
4552
|
let mid = top + this.left.height;
|
|
4502
|
-
return height < mid ? this.left.blockAt(height,
|
|
4503
|
-
: this.right.blockAt(height,
|
|
4553
|
+
return height < mid ? this.left.blockAt(height, oracle, top, offset)
|
|
4554
|
+
: this.right.blockAt(height, oracle, mid, offset + this.left.length + this.break);
|
|
4504
4555
|
}
|
|
4505
|
-
lineAt(value, type,
|
|
4556
|
+
lineAt(value, type, oracle, top, offset) {
|
|
4506
4557
|
let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
|
4507
4558
|
let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
|
|
4508
|
-
let base = left ? this.left.lineAt(value, type,
|
|
4509
|
-
: this.right.lineAt(value, type,
|
|
4559
|
+
let base = left ? this.left.lineAt(value, type, oracle, top, offset)
|
|
4560
|
+
: this.right.lineAt(value, type, oracle, rightTop, rightOffset);
|
|
4510
4561
|
if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
|
|
4511
4562
|
return base;
|
|
4512
4563
|
let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
|
|
4513
4564
|
if (left)
|
|
4514
|
-
return base.join(this.right.lineAt(rightOffset, subQuery,
|
|
4565
|
+
return base.join(this.right.lineAt(rightOffset, subQuery, oracle, rightTop, rightOffset));
|
|
4515
4566
|
else
|
|
4516
|
-
return this.left.lineAt(rightOffset, subQuery,
|
|
4567
|
+
return this.left.lineAt(rightOffset, subQuery, oracle, top, offset).join(base);
|
|
4517
4568
|
}
|
|
4518
|
-
forEachLine(from, to,
|
|
4569
|
+
forEachLine(from, to, oracle, top, offset, f) {
|
|
4519
4570
|
let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
|
4520
4571
|
if (this.break) {
|
|
4521
4572
|
if (from < rightOffset)
|
|
4522
|
-
this.left.forEachLine(from, to,
|
|
4573
|
+
this.left.forEachLine(from, to, oracle, top, offset, f);
|
|
4523
4574
|
if (to >= rightOffset)
|
|
4524
|
-
this.right.forEachLine(from, to,
|
|
4575
|
+
this.right.forEachLine(from, to, oracle, rightTop, rightOffset, f);
|
|
4525
4576
|
}
|
|
4526
4577
|
else {
|
|
4527
|
-
let mid = this.lineAt(rightOffset, QueryType.ByPos,
|
|
4578
|
+
let mid = this.lineAt(rightOffset, QueryType.ByPos, oracle, top, offset);
|
|
4528
4579
|
if (from < mid.from)
|
|
4529
|
-
this.left.forEachLine(from, mid.from - 1,
|
|
4580
|
+
this.left.forEachLine(from, mid.from - 1, oracle, top, offset, f);
|
|
4530
4581
|
if (mid.to >= from && mid.from <= to)
|
|
4531
4582
|
f(mid);
|
|
4532
4583
|
if (to > mid.to)
|
|
4533
|
-
this.right.forEachLine(mid.to + 1, to,
|
|
4584
|
+
this.right.forEachLine(mid.to + 1, to, oracle, rightTop, rightOffset, f);
|
|
4534
4585
|
}
|
|
4535
4586
|
}
|
|
4536
4587
|
replace(from, to, nodes) {
|
|
@@ -4880,11 +4931,11 @@ class ViewState {
|
|
|
4880
4931
|
}
|
|
4881
4932
|
this.viewports = viewports.sort((a, b) => a.from - b.from);
|
|
4882
4933
|
this.scaler = this.heightMap.height <= 7000000 /* VP.MaxDOMHeight */ ? IdScaler :
|
|
4883
|
-
new BigScaler(this.heightOracle
|
|
4934
|
+
new BigScaler(this.heightOracle, this.heightMap, this.viewports);
|
|
4884
4935
|
}
|
|
4885
4936
|
updateViewportLines() {
|
|
4886
4937
|
this.viewportLines = [];
|
|
4887
|
-
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
|
|
4938
|
+
this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.heightOracle.setDoc(this.state.doc), 0, 0, block => {
|
|
4888
4939
|
this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
|
|
4889
4940
|
});
|
|
4890
4941
|
}
|
|
@@ -4924,8 +4975,9 @@ class ViewState {
|
|
|
4924
4975
|
let whiteSpace = style.whiteSpace;
|
|
4925
4976
|
this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
|
|
4926
4977
|
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4927
|
-
let
|
|
4928
|
-
this.contentDOMHeight
|
|
4978
|
+
let domRect = dom.getBoundingClientRect();
|
|
4979
|
+
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != domRect.height;
|
|
4980
|
+
this.contentDOMHeight = domRect.height;
|
|
4929
4981
|
this.mustMeasureContent = false;
|
|
4930
4982
|
let result = 0, bias = 0;
|
|
4931
4983
|
// Vertical padding
|
|
@@ -4953,9 +5005,9 @@ class ViewState {
|
|
|
4953
5005
|
}
|
|
4954
5006
|
if (!this.inView && !this.scrollTarget)
|
|
4955
5007
|
return 0;
|
|
4956
|
-
let contentWidth =
|
|
5008
|
+
let contentWidth = domRect.width;
|
|
4957
5009
|
if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
|
4958
|
-
this.contentDOMWidth =
|
|
5010
|
+
this.contentDOMWidth = domRect.width;
|
|
4959
5011
|
this.editorHeight = view.scrollDOM.clientHeight;
|
|
4960
5012
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
4961
5013
|
}
|
|
@@ -4984,7 +5036,8 @@ class ViewState {
|
|
|
4984
5036
|
result |= 2 /* UpdateFlag.Height */;
|
|
4985
5037
|
}
|
|
4986
5038
|
let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
|
4987
|
-
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5039
|
+
this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from ||
|
|
5040
|
+
this.scrollTarget.range.head > this.viewport.to);
|
|
4988
5041
|
if (viewportChange)
|
|
4989
5042
|
this.viewport = this.getViewport(bias, this.scrollTarget);
|
|
4990
5043
|
this.updateForViewport();
|
|
@@ -5010,36 +5063,37 @@ class ViewState {
|
|
|
5010
5063
|
// bottom, depending on the bias (the change in viewport position
|
|
5011
5064
|
// since the last update). It'll hold a number between 0 and 1
|
|
5012
5065
|
let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 /* VP.Margin */ / 2));
|
|
5013
|
-
let map = this.heightMap,
|
|
5014
|
-
let
|
|
5066
|
+
let map = this.heightMap, oracle = this.heightOracle;
|
|
5067
|
+
let { visibleTop, visibleBottom } = this;
|
|
5068
|
+
let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* VP.Margin */, QueryType.ByHeight, oracle, 0, 0).to);
|
|
5015
5069
|
// If scrollTarget is given, make sure the viewport includes that position
|
|
5016
5070
|
if (scrollTarget) {
|
|
5017
5071
|
let { head } = scrollTarget.range;
|
|
5018
5072
|
if (head < viewport.from || head > viewport.to) {
|
|
5019
5073
|
let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
|
|
5020
|
-
let block = map.lineAt(head, QueryType.ByPos,
|
|
5074
|
+
let block = map.lineAt(head, QueryType.ByPos, oracle, 0, 0), topPos;
|
|
5021
5075
|
if (scrollTarget.y == "center")
|
|
5022
5076
|
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
5023
5077
|
else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
|
|
5024
5078
|
topPos = block.top;
|
|
5025
5079
|
else
|
|
5026
5080
|
topPos = block.bottom - viewHeight;
|
|
5027
|
-
viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight,
|
|
5081
|
+
viewport = new Viewport(map.lineAt(topPos - 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 /* VP.Margin */ / 2, QueryType.ByHeight, oracle, 0, 0).to);
|
|
5028
5082
|
}
|
|
5029
5083
|
}
|
|
5030
5084
|
return viewport;
|
|
5031
5085
|
}
|
|
5032
5086
|
mapViewport(viewport, changes) {
|
|
5033
5087
|
let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
|
|
5034
|
-
return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.
|
|
5088
|
+
return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0).to);
|
|
5035
5089
|
}
|
|
5036
5090
|
// Checks if a given viewport covers the visible part of the
|
|
5037
5091
|
// document and not too much beyond that.
|
|
5038
5092
|
viewportIsAppropriate({ from, to }, bias = 0) {
|
|
5039
5093
|
if (!this.inView)
|
|
5040
5094
|
return true;
|
|
5041
|
-
let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.
|
|
5042
|
-
let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.
|
|
5095
|
+
let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.heightOracle, 0, 0);
|
|
5096
|
+
let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.heightOracle, 0, 0);
|
|
5043
5097
|
let { visibleTop, visibleBottom } = this;
|
|
5044
5098
|
return (from == 0 || top <= visibleTop - Math.max(10 /* VP.MinCoverMargin */, Math.min(-bias, 250 /* VP.MaxCoverMargin */))) &&
|
|
5045
5099
|
(to == this.state.doc.length ||
|
|
@@ -5176,13 +5230,13 @@ class ViewState {
|
|
|
5176
5230
|
}
|
|
5177
5231
|
lineBlockAt(pos) {
|
|
5178
5232
|
return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
|
5179
|
-
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.
|
|
5233
|
+
scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.heightOracle, 0, 0), this.scaler);
|
|
5180
5234
|
}
|
|
5181
5235
|
lineBlockAtHeight(height) {
|
|
5182
|
-
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.
|
|
5236
|
+
return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.heightOracle, 0, 0), this.scaler);
|
|
5183
5237
|
}
|
|
5184
5238
|
elementAtHeight(height) {
|
|
5185
|
-
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.
|
|
5239
|
+
return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.heightOracle, 0, 0), this.scaler);
|
|
5186
5240
|
}
|
|
5187
5241
|
get docHeight() {
|
|
5188
5242
|
return this.scaler.toDOM(this.heightMap.height);
|
|
@@ -5256,11 +5310,11 @@ const IdScaler = {
|
|
|
5256
5310
|
// regions outside the viewports so that the total height is
|
|
5257
5311
|
// VP.MaxDOMHeight.
|
|
5258
5312
|
class BigScaler {
|
|
5259
|
-
constructor(
|
|
5313
|
+
constructor(oracle, heightMap, viewports) {
|
|
5260
5314
|
let vpHeight = 0, base = 0, domBase = 0;
|
|
5261
5315
|
this.viewports = viewports.map(({ from, to }) => {
|
|
5262
|
-
let top = heightMap.lineAt(from, QueryType.ByPos,
|
|
5263
|
-
let bottom = heightMap.lineAt(to, QueryType.ByPos,
|
|
5316
|
+
let top = heightMap.lineAt(from, QueryType.ByPos, oracle, 0, 0).top;
|
|
5317
|
+
let bottom = heightMap.lineAt(to, QueryType.ByPos, oracle, 0, 0).bottom;
|
|
5264
5318
|
vpHeight += bottom - top;
|
|
5265
5319
|
return { from, to, top, bottom, domTop: 0, domBottom: 0 };
|
|
5266
5320
|
});
|
|
@@ -5627,7 +5681,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5627
5681
|
};
|
|
5628
5682
|
}
|
|
5629
5683
|
else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
|
5630
|
-
/^\. ?$/.test(change.insert.toString())) {
|
|
5684
|
+
/^\. ?$/.test(change.insert.toString()) && view.contentDOM.getAttribute("autocorrect") == "off") {
|
|
5631
5685
|
// Detect insert-period-on-double-space Mac and Android behavior,
|
|
5632
5686
|
// and transform it into a regular space insert.
|
|
5633
5687
|
if (newSel && change.insert.length == 2)
|
|
@@ -6381,6 +6435,20 @@ class EditorView {
|
|
|
6381
6435
|
this.viewState.state = state;
|
|
6382
6436
|
return;
|
|
6383
6437
|
}
|
|
6438
|
+
let focus = this.hasFocus, focusFlag = 0, dispatchFocus = null;
|
|
6439
|
+
if (transactions.some(tr => tr.annotation(isFocusChange))) {
|
|
6440
|
+
this.inputState.notifiedFocused = focus;
|
|
6441
|
+
// If a focus-change transaction is being dispatched, set this update flag.
|
|
6442
|
+
focusFlag = 1 /* UpdateFlag.Focus */;
|
|
6443
|
+
}
|
|
6444
|
+
else if (focus != this.inputState.notifiedFocused) {
|
|
6445
|
+
this.inputState.notifiedFocused = focus;
|
|
6446
|
+
// Schedule a separate focus transaction if necessary, otherwise
|
|
6447
|
+
// add a flag to this update
|
|
6448
|
+
dispatchFocus = focusChangeTransaction(state, focus);
|
|
6449
|
+
if (!dispatchFocus)
|
|
6450
|
+
focusFlag = 1 /* UpdateFlag.Focus */;
|
|
6451
|
+
}
|
|
6384
6452
|
// If there was a pending DOM change, eagerly read it and try to
|
|
6385
6453
|
// apply it after the given transactions.
|
|
6386
6454
|
let pendingKey = this.observer.delayedAndroidKey, domChange = null;
|
|
@@ -6399,6 +6467,7 @@ class EditorView {
|
|
|
6399
6467
|
if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
|
6400
6468
|
return this.setState(state);
|
|
6401
6469
|
update = ViewUpdate.create(this, state, transactions);
|
|
6470
|
+
update.flags |= focusFlag;
|
|
6402
6471
|
let scrollTarget = this.viewState.scrollTarget;
|
|
6403
6472
|
try {
|
|
6404
6473
|
this.updateState = 2 /* UpdateState.Updating */;
|
|
@@ -6436,10 +6505,15 @@ class EditorView {
|
|
|
6436
6505
|
if (!update.empty)
|
|
6437
6506
|
for (let listener of this.state.facet(updateListener))
|
|
6438
6507
|
listener(update);
|
|
6439
|
-
if (domChange)
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6508
|
+
if (dispatchFocus || domChange)
|
|
6509
|
+
Promise.resolve().then(() => {
|
|
6510
|
+
if (dispatchFocus && this.state == dispatchFocus.startState)
|
|
6511
|
+
this.dispatch(dispatchFocus);
|
|
6512
|
+
if (domChange) {
|
|
6513
|
+
if (!applyDOMChange(this, domChange) && pendingKey.force)
|
|
6514
|
+
dispatchKey(this.contentDOM, pendingKey.key, pendingKey.keyCode);
|
|
6515
|
+
}
|
|
6516
|
+
});
|
|
6443
6517
|
}
|
|
6444
6518
|
/**
|
|
6445
6519
|
Reset the view to the given state. (This will cause the entire
|
|
@@ -7041,6 +7115,11 @@ called and the default behavior is prevented.
|
|
|
7041
7115
|
*/
|
|
7042
7116
|
EditorView.inputHandler = inputHandler;
|
|
7043
7117
|
/**
|
|
7118
|
+
This facet can be used to provide functions that create effects
|
|
7119
|
+
to be dispatched when the editor's focus state changes.
|
|
7120
|
+
*/
|
|
7121
|
+
EditorView.focusChangeEffect = focusChangeEffect;
|
|
7122
|
+
/**
|
|
7044
7123
|
By default, the editor assumes all its content has the same
|
|
7045
7124
|
[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
|
|
7046
7125
|
value to make it read the text direction of every (rendered)
|