@codemirror/view 0.19.32 → 0.19.36
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 +42 -0
- package/dist/index.cjs +172 -102
- package/dist/index.d.ts +53 -11
- package/dist/index.js +172 -102
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,45 @@
|
|
|
1
|
+
## 0.19.36 (2021-12-22)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix a crash in `posAtCoords` when the position lies in a block widget that is rendered but scrolled out of view.
|
|
6
|
+
|
|
7
|
+
Adding block decorations from a plugin now raises an error. Replacing decorations that cross lines are ignored, when provided by a plugin.
|
|
8
|
+
|
|
9
|
+
Fix inverted interpretation of the `precise` argument to `posAtCoords`.
|
|
10
|
+
|
|
11
|
+
## 0.19.35 (2021-12-20)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
The editor will now handle double-taps as if they are double-clicks, rather than letting the browser's native behavior happen (because the latter often does the wrong thing).
|
|
16
|
+
|
|
17
|
+
Fix an issue where backspacing out a selection on Chrome Android would sometimes only delete the last character due to event order issues.
|
|
18
|
+
|
|
19
|
+
`posAtCoords`, without second argument, will no longer return null for positions below or above the document.
|
|
20
|
+
|
|
21
|
+
## 0.19.34 (2021-12-17)
|
|
22
|
+
|
|
23
|
+
### Bug fixes
|
|
24
|
+
|
|
25
|
+
Fix a bug where content line elements would in some cases lose their `cm-line` class. Move test to scrollIntoView
|
|
26
|
+
|
|
27
|
+
## 0.19.33 (2021-12-16)
|
|
28
|
+
|
|
29
|
+
### Breaking changes
|
|
30
|
+
|
|
31
|
+
`EditorView.scrollTo` and `EditorView.centerOn` are deprecated in favor of `EditorView.scrollIntoView`, and will be removed in the next breaking release.
|
|
32
|
+
|
|
33
|
+
### Bug fixes
|
|
34
|
+
|
|
35
|
+
Fix an issue that could cause the editor to unnecessarily interfere with composition (especially visible on macOS Chrome).
|
|
36
|
+
|
|
37
|
+
A composition started with multiple lines selected will no longer be interruptd by the editor.
|
|
38
|
+
|
|
39
|
+
### New features
|
|
40
|
+
|
|
41
|
+
The new `EditorView.scrollIntoView` function allows you to do more fine-grained scrolling.
|
|
42
|
+
|
|
1
43
|
## 0.19.32 (2021-12-15)
|
|
2
44
|
|
|
3
45
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -101,8 +101,7 @@ function windowRect(win) {
|
|
|
101
101
|
return { left: 0, right: win.innerWidth,
|
|
102
102
|
top: 0, bottom: win.innerHeight };
|
|
103
103
|
}
|
|
104
|
-
|
|
105
|
-
function scrollRectIntoView(dom, rect, side, center) {
|
|
104
|
+
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
106
105
|
let doc = dom.ownerDocument, win = doc.defaultView;
|
|
107
106
|
for (let cur = dom; cur;) {
|
|
108
107
|
if (cur.nodeType == 1) { // Element
|
|
@@ -121,38 +120,42 @@ function scrollRectIntoView(dom, rect, side, center) {
|
|
|
121
120
|
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
122
121
|
}
|
|
123
122
|
let moveX = 0, moveY = 0;
|
|
124
|
-
if (
|
|
123
|
+
if (y == "nearest") {
|
|
124
|
+
if (rect.top < bounding.top) {
|
|
125
|
+
moveY = -(bounding.top - rect.top + yMargin);
|
|
126
|
+
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
127
|
+
moveY = rect.bottom - bounding.bottom + moveY + yMargin;
|
|
128
|
+
}
|
|
129
|
+
else if (rect.bottom > bounding.bottom) {
|
|
130
|
+
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
131
|
+
if (side < 0 && (rect.top - moveY) < bounding.top)
|
|
132
|
+
moveY = -(bounding.top + moveY - rect.top + yMargin);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
125
136
|
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
126
|
-
let targetTop
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
else if (side < 0)
|
|
130
|
-
targetTop = rect.top - ScrollSpace;
|
|
131
|
-
else
|
|
132
|
-
targetTop = rect.bottom + ScrollSpace - boundingHeight;
|
|
137
|
+
let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
|
|
138
|
+
y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
|
|
139
|
+
rect.bottom - boundingHeight + yMargin;
|
|
133
140
|
moveY = targetTop - bounding.top;
|
|
134
|
-
if (Math.abs(moveY) <= 1)
|
|
135
|
-
moveY = 0;
|
|
136
|
-
}
|
|
137
|
-
else if (rect.top < bounding.top) {
|
|
138
|
-
moveY = -(bounding.top - rect.top + ScrollSpace);
|
|
139
|
-
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
140
|
-
moveY = rect.bottom - bounding.bottom + moveY + ScrollSpace;
|
|
141
|
-
}
|
|
142
|
-
else if (rect.bottom > bounding.bottom) {
|
|
143
|
-
moveY = rect.bottom - bounding.bottom + ScrollSpace;
|
|
144
|
-
if (side < 0 && (rect.top - moveY) < bounding.top)
|
|
145
|
-
moveY = -(bounding.top + moveY - rect.top + ScrollSpace);
|
|
146
141
|
}
|
|
147
|
-
if (
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
142
|
+
if (x == "nearest") {
|
|
143
|
+
if (rect.left < bounding.left) {
|
|
144
|
+
moveX = -(bounding.left - rect.left + xMargin);
|
|
145
|
+
if (side > 0 && rect.right > bounding.right + moveX)
|
|
146
|
+
moveX = rect.right - bounding.right + moveX + xMargin;
|
|
147
|
+
}
|
|
148
|
+
else if (rect.right > bounding.right) {
|
|
149
|
+
moveX = rect.right - bounding.right + xMargin;
|
|
150
|
+
if (side < 0 && rect.left < bounding.left + moveX)
|
|
151
|
+
moveX = -(bounding.left + moveX - rect.left + xMargin);
|
|
152
|
+
}
|
|
151
153
|
}
|
|
152
|
-
else
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
154
|
+
else {
|
|
155
|
+
let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
|
|
156
|
+
(x == "start") == ltr ? rect.left - xMargin :
|
|
157
|
+
rect.right - (bounding.right - bounding.left) + xMargin;
|
|
158
|
+
moveX = targetLeft - bounding.left;
|
|
156
159
|
}
|
|
157
160
|
if (moveX || moveY) {
|
|
158
161
|
if (top) {
|
|
@@ -176,7 +179,7 @@ function scrollRectIntoView(dom, rect, side, center) {
|
|
|
176
179
|
if (top)
|
|
177
180
|
break;
|
|
178
181
|
cur = cur.assignedSlot || cur.parentNode;
|
|
179
|
-
|
|
182
|
+
x = y = "nearest";
|
|
180
183
|
}
|
|
181
184
|
else if (cur.nodeType == 11) { // A shadow root
|
|
182
185
|
cur = cur.host;
|
|
@@ -263,6 +266,10 @@ function getRoot(node) {
|
|
|
263
266
|
}
|
|
264
267
|
return null;
|
|
265
268
|
}
|
|
269
|
+
function clearAttributes(node) {
|
|
270
|
+
while (node.attributes.length)
|
|
271
|
+
node.removeAttributeNode(node.attributes[0]);
|
|
272
|
+
}
|
|
266
273
|
|
|
267
274
|
class DOMPos {
|
|
268
275
|
constructor(node, offset, precise = true) {
|
|
@@ -309,14 +316,16 @@ class ContentView {
|
|
|
309
316
|
// given position.
|
|
310
317
|
coordsAt(_pos, _side) { return null; }
|
|
311
318
|
sync(track) {
|
|
312
|
-
var _a;
|
|
313
319
|
if (this.dirty & 2 /* Node */) {
|
|
314
320
|
let parent = this.dom;
|
|
315
321
|
let pos = parent.firstChild;
|
|
316
322
|
for (let child of this.children) {
|
|
317
323
|
if (child.dirty) {
|
|
318
|
-
if (!child.dom && pos
|
|
319
|
-
|
|
324
|
+
if (!child.dom && pos) {
|
|
325
|
+
let contentView = ContentView.get(pos);
|
|
326
|
+
if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
|
|
327
|
+
child.reuseDOM(pos);
|
|
328
|
+
}
|
|
320
329
|
child.sync(track);
|
|
321
330
|
child.dirty = 0 /* Not */;
|
|
322
331
|
}
|
|
@@ -344,7 +353,7 @@ class ContentView {
|
|
|
344
353
|
}
|
|
345
354
|
}
|
|
346
355
|
}
|
|
347
|
-
reuseDOM(_dom) {
|
|
356
|
+
reuseDOM(_dom) { }
|
|
348
357
|
localPosFromDOM(node, offset) {
|
|
349
358
|
let after;
|
|
350
359
|
if (node == this.dom) {
|
|
@@ -643,10 +652,8 @@ class TextView extends ContentView {
|
|
|
643
652
|
}
|
|
644
653
|
}
|
|
645
654
|
reuseDOM(dom) {
|
|
646
|
-
if (dom.nodeType
|
|
647
|
-
|
|
648
|
-
this.createDOM(dom);
|
|
649
|
-
return true;
|
|
655
|
+
if (dom.nodeType == 3)
|
|
656
|
+
this.createDOM(dom);
|
|
650
657
|
}
|
|
651
658
|
merge(from, to, source) {
|
|
652
659
|
if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen))
|
|
@@ -681,18 +688,26 @@ class MarkView extends ContentView {
|
|
|
681
688
|
for (let ch of children)
|
|
682
689
|
ch.setParent(this);
|
|
683
690
|
}
|
|
684
|
-
|
|
685
|
-
|
|
691
|
+
setAttrs(dom) {
|
|
692
|
+
clearAttributes(dom);
|
|
686
693
|
if (this.mark.class)
|
|
687
694
|
dom.className = this.mark.class;
|
|
688
695
|
if (this.mark.attrs)
|
|
689
696
|
for (let name in this.mark.attrs)
|
|
690
697
|
dom.setAttribute(name, this.mark.attrs[name]);
|
|
691
|
-
|
|
698
|
+
return dom;
|
|
699
|
+
}
|
|
700
|
+
reuseDOM(node) {
|
|
701
|
+
if (node.nodeName == this.mark.tagName.toUpperCase()) {
|
|
702
|
+
this.setDOM(node);
|
|
703
|
+
this.dirty |= 4 /* Attrs */ | 2 /* Node */;
|
|
704
|
+
}
|
|
692
705
|
}
|
|
693
706
|
sync(track) {
|
|
694
|
-
if (!this.dom
|
|
695
|
-
this.
|
|
707
|
+
if (!this.dom)
|
|
708
|
+
this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
|
|
709
|
+
else if (this.dirty & 4 /* Attrs */)
|
|
710
|
+
this.setAttrs(this.dom);
|
|
696
711
|
super.sync(track);
|
|
697
712
|
}
|
|
698
713
|
merge(from, to, source, _hasStart, openStart, openEnd) {
|
|
@@ -836,8 +851,7 @@ class WidgetView extends ContentView {
|
|
|
836
851
|
}
|
|
837
852
|
class CompositionView extends WidgetView {
|
|
838
853
|
domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
|
|
839
|
-
sync() {
|
|
840
|
-
this.setDOM(this.widget.toDOM()); }
|
|
854
|
+
sync() { this.setDOM(this.widget.toDOM()); }
|
|
841
855
|
localPosFromDOM(node, offset) {
|
|
842
856
|
return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length;
|
|
843
857
|
}
|
|
@@ -1302,13 +1316,24 @@ class LineView extends ContentView {
|
|
|
1302
1316
|
domAtPos(pos) {
|
|
1303
1317
|
return inlineDOMAtPos(this.dom, this.children, pos);
|
|
1304
1318
|
}
|
|
1319
|
+
reuseDOM(node) {
|
|
1320
|
+
if (node.nodeName == "DIV") {
|
|
1321
|
+
this.setDOM(node);
|
|
1322
|
+
this.dirty |= 4 /* Attrs */ | 2 /* Node */;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1305
1325
|
sync(track) {
|
|
1306
1326
|
var _a;
|
|
1307
|
-
if (!this.dom
|
|
1327
|
+
if (!this.dom) {
|
|
1308
1328
|
this.setDOM(document.createElement("div"));
|
|
1309
1329
|
this.dom.className = "cm-line";
|
|
1310
1330
|
this.prevAttrs = this.attrs ? null : undefined;
|
|
1311
1331
|
}
|
|
1332
|
+
else if (this.dirty & 4 /* Attrs */) {
|
|
1333
|
+
clearAttributes(this.dom);
|
|
1334
|
+
this.dom.className = "cm-line";
|
|
1335
|
+
this.prevAttrs = this.attrs ? null : undefined;
|
|
1336
|
+
}
|
|
1312
1337
|
if (this.prevAttrs !== undefined) {
|
|
1313
1338
|
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1314
1339
|
this.dom.classList.add("cm-line");
|
|
@@ -1347,16 +1372,17 @@ class LineView extends ContentView {
|
|
|
1347
1372
|
become(_other) { return false; }
|
|
1348
1373
|
get type() { return exports.BlockType.Text; }
|
|
1349
1374
|
static find(docView, pos) {
|
|
1350
|
-
for (let i = 0, off = 0
|
|
1375
|
+
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1351
1376
|
let block = docView.children[i], end = off + block.length;
|
|
1352
1377
|
if (end >= pos) {
|
|
1353
1378
|
if (block instanceof LineView)
|
|
1354
1379
|
return block;
|
|
1355
|
-
if (
|
|
1356
|
-
|
|
1380
|
+
if (end > pos)
|
|
1381
|
+
break;
|
|
1357
1382
|
}
|
|
1358
1383
|
off = end + block.breakAfter;
|
|
1359
1384
|
}
|
|
1385
|
+
return null;
|
|
1360
1386
|
}
|
|
1361
1387
|
}
|
|
1362
1388
|
class BlockWidgetView extends ContentView {
|
|
@@ -1417,10 +1443,11 @@ class BlockWidgetView extends ContentView {
|
|
|
1417
1443
|
}
|
|
1418
1444
|
|
|
1419
1445
|
class ContentBuilder {
|
|
1420
|
-
constructor(doc, pos, end) {
|
|
1446
|
+
constructor(doc, pos, end, disallowBlockEffectsBelow) {
|
|
1421
1447
|
this.doc = doc;
|
|
1422
1448
|
this.pos = pos;
|
|
1423
1449
|
this.end = end;
|
|
1450
|
+
this.disallowBlockEffectsBelow = disallowBlockEffectsBelow;
|
|
1424
1451
|
this.content = [];
|
|
1425
1452
|
this.curLine = null;
|
|
1426
1453
|
this.breakAtStart = 0;
|
|
@@ -1549,8 +1576,15 @@ class ContentBuilder {
|
|
|
1549
1576
|
if (this.openStart < 0)
|
|
1550
1577
|
this.openStart = openStart;
|
|
1551
1578
|
}
|
|
1552
|
-
|
|
1553
|
-
|
|
1579
|
+
filterPoint(from, to, value, index) {
|
|
1580
|
+
if (index >= this.disallowBlockEffectsBelow || !(value instanceof PointDecoration))
|
|
1581
|
+
return true;
|
|
1582
|
+
if (value.block)
|
|
1583
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1584
|
+
return to < this.doc.lineAt(this.pos).to;
|
|
1585
|
+
}
|
|
1586
|
+
static build(text, from, to, decorations, pluginDecorationLength) {
|
|
1587
|
+
let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
|
|
1554
1588
|
builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder);
|
|
1555
1589
|
if (builder.openStart < 0)
|
|
1556
1590
|
builder.openStart = builder.openEnd;
|
|
@@ -1580,12 +1614,27 @@ const mouseSelectionStyle = state.Facet.define();
|
|
|
1580
1614
|
const exceptionSink = state.Facet.define();
|
|
1581
1615
|
const updateListener = state.Facet.define();
|
|
1582
1616
|
const inputHandler = state.Facet.define();
|
|
1617
|
+
// FIXME remove
|
|
1583
1618
|
const scrollTo = state.StateEffect.define({
|
|
1584
1619
|
map: (range, changes) => range.map(changes)
|
|
1585
1620
|
});
|
|
1621
|
+
// FIXME remove
|
|
1586
1622
|
const centerOn = state.StateEffect.define({
|
|
1587
1623
|
map: (range, changes) => range.map(changes)
|
|
1588
1624
|
});
|
|
1625
|
+
class ScrollTarget {
|
|
1626
|
+
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
|
|
1627
|
+
this.range = range;
|
|
1628
|
+
this.y = y;
|
|
1629
|
+
this.x = x;
|
|
1630
|
+
this.yMargin = yMargin;
|
|
1631
|
+
this.xMargin = xMargin;
|
|
1632
|
+
}
|
|
1633
|
+
map(changes) {
|
|
1634
|
+
return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin);
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
const scrollIntoView = state.StateEffect.define({ map: (t, ch) => t.map(ch) });
|
|
1589
1638
|
/**
|
|
1590
1639
|
Log or report an unhandled exception in client code. Should
|
|
1591
1640
|
probably only be used by extension code that allows client code to
|
|
@@ -1658,11 +1707,13 @@ This field can be used by plugins to provide
|
|
|
1658
1707
|
**Note**: For reasons of data flow (plugins are only updated
|
|
1659
1708
|
after the viewport is computed), decorations produced by plugins
|
|
1660
1709
|
are _not_ taken into account when predicting the vertical layout
|
|
1661
|
-
structure of the editor.
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1710
|
+
structure of the editor. They **must not** introduce block
|
|
1711
|
+
widgets (that will raise an error) or replacing decorations that
|
|
1712
|
+
cover line breaks (these will be ignored if they occur). Such
|
|
1713
|
+
decorations, or others that cause a large amount of vertical
|
|
1714
|
+
size shift compared to the undecorated content, should be
|
|
1715
|
+
provided through the state-level [`decorations`
|
|
1716
|
+
facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
|
|
1666
1717
|
*/
|
|
1667
1718
|
PluginField.decorations = PluginField.define();
|
|
1668
1719
|
/**
|
|
@@ -1895,8 +1946,6 @@ class ViewUpdate {
|
|
|
1895
1946
|
view.inputState.notifiedFocused = focus;
|
|
1896
1947
|
this.flags |= 1 /* Focus */;
|
|
1897
1948
|
}
|
|
1898
|
-
if (this.docChanged)
|
|
1899
|
-
this.flags |= 2 /* Height */;
|
|
1900
1949
|
}
|
|
1901
1950
|
/**
|
|
1902
1951
|
Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or
|
|
@@ -1907,14 +1956,15 @@ class ViewUpdate {
|
|
|
1907
1956
|
return (this.flags & 4 /* Viewport */) > 0;
|
|
1908
1957
|
}
|
|
1909
1958
|
/**
|
|
1910
|
-
Indicates whether the
|
|
1959
|
+
Indicates whether the height of an element in the editor changed
|
|
1960
|
+
in this update.
|
|
1911
1961
|
*/
|
|
1912
1962
|
get heightChanged() {
|
|
1913
1963
|
return (this.flags & 2 /* Height */) > 0;
|
|
1914
1964
|
}
|
|
1915
1965
|
/**
|
|
1916
|
-
Returns true when the document
|
|
1917
|
-
|
|
1966
|
+
Returns true when the document was modified or the size of the
|
|
1967
|
+
editor, or elements within the editor, changed.
|
|
1918
1968
|
*/
|
|
1919
1969
|
get geometryChanged() {
|
|
1920
1970
|
return this.docChanged || (this.flags & (8 /* Geometry */ | 2 /* Height */)) > 0;
|
|
@@ -2333,6 +2383,7 @@ class DocView extends ContentView {
|
|
|
2333
2383
|
this.view = view;
|
|
2334
2384
|
this.compositionDeco = Decoration.none;
|
|
2335
2385
|
this.decorations = [];
|
|
2386
|
+
this.pluginDecorationLength = 0;
|
|
2336
2387
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2337
2388
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
2338
2389
|
// of a given element and its extent in the document. When a change
|
|
@@ -2354,7 +2405,8 @@ class DocView extends ContentView {
|
|
|
2354
2405
|
this.setDOM(view.contentDOM);
|
|
2355
2406
|
this.children = [new LineView];
|
|
2356
2407
|
this.children[0].setParent(this);
|
|
2357
|
-
this.
|
|
2408
|
+
this.updateDeco();
|
|
2409
|
+
this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0);
|
|
2358
2410
|
}
|
|
2359
2411
|
get root() { return this.view.root; }
|
|
2360
2412
|
get editorView() { return this.view; }
|
|
@@ -2393,7 +2445,7 @@ class DocView extends ContentView {
|
|
|
2393
2445
|
return false;
|
|
2394
2446
|
}
|
|
2395
2447
|
else {
|
|
2396
|
-
this.updateInner(changedRanges,
|
|
2448
|
+
this.updateInner(changedRanges, update.startState.doc.length);
|
|
2397
2449
|
if (update.transactions.length)
|
|
2398
2450
|
this.lastUpdate = Date.now();
|
|
2399
2451
|
return true;
|
|
@@ -2401,9 +2453,9 @@ class DocView extends ContentView {
|
|
|
2401
2453
|
}
|
|
2402
2454
|
// Used by update and the constructor do perform the actual DOM
|
|
2403
2455
|
// update
|
|
2404
|
-
updateInner(changes,
|
|
2456
|
+
updateInner(changes, oldLength) {
|
|
2405
2457
|
this.view.viewState.mustMeasureContent = true;
|
|
2406
|
-
this.updateChildren(changes,
|
|
2458
|
+
this.updateChildren(changes, oldLength);
|
|
2407
2459
|
let { observer } = this.view;
|
|
2408
2460
|
observer.ignore(() => {
|
|
2409
2461
|
// Lock the height during redrawing, since Chrome sometimes
|
|
@@ -2430,14 +2482,14 @@ class DocView extends ContentView {
|
|
|
2430
2482
|
gaps.push(child.dom);
|
|
2431
2483
|
observer.updateGaps(gaps);
|
|
2432
2484
|
}
|
|
2433
|
-
updateChildren(changes,
|
|
2485
|
+
updateChildren(changes, oldLength) {
|
|
2434
2486
|
let cursor = this.childCursor(oldLength);
|
|
2435
2487
|
for (let i = changes.length - 1;; i--) {
|
|
2436
2488
|
let next = i >= 0 ? changes[i] : null;
|
|
2437
2489
|
if (!next)
|
|
2438
2490
|
break;
|
|
2439
2491
|
let { fromA, toA, fromB, toB } = next;
|
|
2440
|
-
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB,
|
|
2492
|
+
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.pluginDecorationLength);
|
|
2441
2493
|
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2442
2494
|
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2443
2495
|
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
@@ -2656,15 +2708,18 @@ class DocView extends ContentView {
|
|
|
2656
2708
|
return Decoration.set(deco);
|
|
2657
2709
|
}
|
|
2658
2710
|
updateDeco() {
|
|
2711
|
+
let pluginDecorations = this.view.pluginField(PluginField.decorations);
|
|
2712
|
+
this.pluginDecorationLength = pluginDecorations.length;
|
|
2659
2713
|
return this.decorations = [
|
|
2660
|
-
...
|
|
2714
|
+
...pluginDecorations,
|
|
2661
2715
|
...this.view.state.facet(decorations),
|
|
2662
2716
|
this.compositionDeco,
|
|
2663
2717
|
this.computeBlockGapDeco(),
|
|
2664
2718
|
this.view.viewState.lineGapDeco
|
|
2665
2719
|
];
|
|
2666
2720
|
}
|
|
2667
|
-
scrollIntoView(
|
|
2721
|
+
scrollIntoView(target) {
|
|
2722
|
+
let { range } = target;
|
|
2668
2723
|
let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
|
2669
2724
|
if (!rect)
|
|
2670
2725
|
return;
|
|
@@ -2684,10 +2739,11 @@ class DocView extends ContentView {
|
|
|
2684
2739
|
if (bottom != null)
|
|
2685
2740
|
mBottom = Math.max(mBottom, bottom);
|
|
2686
2741
|
}
|
|
2687
|
-
|
|
2742
|
+
let targetRect = {
|
|
2688
2743
|
left: rect.left - mLeft, top: rect.top - mTop,
|
|
2689
2744
|
right: rect.right + mRight, bottom: rect.bottom + mBottom
|
|
2690
|
-
}
|
|
2745
|
+
};
|
|
2746
|
+
scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == exports.Direction.LTR);
|
|
2691
2747
|
}
|
|
2692
2748
|
}
|
|
2693
2749
|
function betweenUneditable(pos) {
|
|
@@ -2948,12 +3004,8 @@ function domPosInText(node, x, y) {
|
|
|
2948
3004
|
function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
2949
3005
|
var _a;
|
|
2950
3006
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
2951
|
-
let block,
|
|
2952
|
-
|
|
2953
|
-
if (precise)
|
|
2954
|
-
return null;
|
|
2955
|
-
yOffset = yOffset < 0 ? 0 : docHeight;
|
|
2956
|
-
}
|
|
3007
|
+
let block, { docHeight } = view.viewState;
|
|
3008
|
+
let yOffset = Math.max(0, Math.min(y - docTop, docHeight));
|
|
2957
3009
|
// Scan for a text block near the queried y position
|
|
2958
3010
|
for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
|
|
2959
3011
|
block = view.elementAtHeight(yOffset);
|
|
@@ -2974,20 +3026,29 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
2974
3026
|
}
|
|
2975
3027
|
y = docTop + yOffset;
|
|
2976
3028
|
let lineStart = block.from;
|
|
2977
|
-
// Clip x to the viewport sides
|
|
2978
|
-
x = Math.max(content.left + 1, Math.min(Math.max(content.right, content.left + view.docView.minWidth) - 1, x));
|
|
2979
3029
|
// If this is outside of the rendered viewport, we can't determine a position
|
|
2980
3030
|
if (lineStart < view.viewport.from)
|
|
2981
|
-
return view.viewport.from == 0 ? 0 : posAtCoordsImprecise(view, content, block, x, y);
|
|
3031
|
+
return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y);
|
|
2982
3032
|
if (lineStart > view.viewport.to)
|
|
2983
|
-
return view.viewport.to == view.state.doc.length ? view.state.doc.length :
|
|
3033
|
+
return view.viewport.to == view.state.doc.length ? view.state.doc.length :
|
|
3034
|
+
precise ? null : posAtCoordsImprecise(view, content, block, x, y);
|
|
2984
3035
|
// Prefer ShadowRootOrDocument.elementFromPoint if present, fall back to document if not
|
|
2985
3036
|
let doc = view.dom.ownerDocument;
|
|
2986
|
-
let
|
|
3037
|
+
let root = view.root.elementFromPoint ? view.root : doc;
|
|
3038
|
+
let element = root.elementFromPoint(x, y);
|
|
3039
|
+
if (element && !view.contentDOM.contains(element))
|
|
3040
|
+
element = null;
|
|
3041
|
+
// If the element is unexpected, clip x at the sides of the content area and try again
|
|
3042
|
+
if (!element) {
|
|
3043
|
+
x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
|
3044
|
+
element = root.elementFromPoint(x, y);
|
|
3045
|
+
if (element && !view.contentDOM.contains(element))
|
|
3046
|
+
element = null;
|
|
3047
|
+
}
|
|
2987
3048
|
// There's visible editor content under the point, so we can try
|
|
2988
3049
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
2989
3050
|
let node, offset = -1;
|
|
2990
|
-
if (element &&
|
|
3051
|
+
if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
|
|
2991
3052
|
if (doc.caretPositionFromPoint) {
|
|
2992
3053
|
let pos = doc.caretPositionFromPoint(x, y);
|
|
2993
3054
|
if (pos)
|
|
@@ -3005,6 +3066,8 @@ function posAtCoords(view, { x, y }, precise, bias = -1) {
|
|
|
3005
3066
|
// No luck, do our own (potentially expensive) search
|
|
3006
3067
|
if (!node || !view.docView.dom.contains(node)) {
|
|
3007
3068
|
let line = LineView.find(view.docView, lineStart);
|
|
3069
|
+
if (!line)
|
|
3070
|
+
return yOffset > block.top + block.height / 2 ? block.to : block.from;
|
|
3008
3071
|
({ node, offset } = domPosAtCoords(line.dom, x, y));
|
|
3009
3072
|
}
|
|
3010
3073
|
return view.docView.posFromDOM(node, offset);
|
|
@@ -3468,7 +3531,7 @@ handlers.touchmove = view => {
|
|
|
3468
3531
|
};
|
|
3469
3532
|
handlers.mousedown = (view, event) => {
|
|
3470
3533
|
view.observer.flush();
|
|
3471
|
-
if (lastTouch > Date.now() - 2000)
|
|
3534
|
+
if (lastTouch > Date.now() - 2000 && getClickType(event) == 1)
|
|
3472
3535
|
return; // Ignore touch interaction
|
|
3473
3536
|
let style = null;
|
|
3474
3537
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
@@ -3590,9 +3653,9 @@ handlers.dragstart = (view, event) => {
|
|
|
3590
3653
|
}
|
|
3591
3654
|
};
|
|
3592
3655
|
function dropText(view, event, text, direct) {
|
|
3593
|
-
|
|
3594
|
-
if (dropPos == null || !text)
|
|
3656
|
+
if (!text)
|
|
3595
3657
|
return;
|
|
3658
|
+
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
3596
3659
|
event.preventDefault();
|
|
3597
3660
|
let { mouseSelection } = view.inputState;
|
|
3598
3661
|
let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ?
|
|
@@ -4521,15 +4584,6 @@ class LineGapWidget extends WidgetType {
|
|
|
4521
4584
|
}
|
|
4522
4585
|
get estimatedHeight() { return this.vertical ? this.size : -1; }
|
|
4523
4586
|
}
|
|
4524
|
-
class ScrollTarget {
|
|
4525
|
-
constructor(range, center = false) {
|
|
4526
|
-
this.range = range;
|
|
4527
|
-
this.center = center;
|
|
4528
|
-
}
|
|
4529
|
-
map(changes) {
|
|
4530
|
-
return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.center);
|
|
4531
|
-
}
|
|
4532
|
-
}
|
|
4533
4587
|
class ViewState {
|
|
4534
4588
|
constructor(state) {
|
|
4535
4589
|
this.state = state;
|
|
@@ -4710,9 +4764,9 @@ class ViewState {
|
|
|
4710
4764
|
let { head } = scrollTarget.range, viewHeight = this.editorHeight;
|
|
4711
4765
|
if (head < viewport.from || head > viewport.to) {
|
|
4712
4766
|
let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
|
4713
|
-
if (scrollTarget.center)
|
|
4767
|
+
if (scrollTarget.y == "center")
|
|
4714
4768
|
topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
|
4715
|
-
else if (head < viewport.from)
|
|
4769
|
+
else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
|
|
4716
4770
|
topPos = block.top;
|
|
4717
4771
|
else
|
|
4718
4772
|
topPos = block.bottom - viewHeight;
|
|
@@ -5259,8 +5313,10 @@ class DOMObserver {
|
|
|
5259
5313
|
// Deletions on IE11 fire their events in the wrong order, giving
|
|
5260
5314
|
// us a selection change event before the DOM changes are
|
|
5261
5315
|
// reported.
|
|
5262
|
-
//
|
|
5263
|
-
|
|
5316
|
+
// Chrome Android has a similar issue when backspacing out a
|
|
5317
|
+
// selection (#645).
|
|
5318
|
+
if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty &&
|
|
5319
|
+
// (Selection.isCollapsed isn't reliable on IE)
|
|
5264
5320
|
sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
|
5265
5321
|
this.flushSoon();
|
|
5266
5322
|
else
|
|
@@ -5818,7 +5874,9 @@ class EditorView {
|
|
|
5818
5874
|
if (e.is(scrollTo))
|
|
5819
5875
|
scrollTarget = new ScrollTarget(e.value);
|
|
5820
5876
|
else if (e.is(centerOn))
|
|
5821
|
-
scrollTarget = new ScrollTarget(e.value,
|
|
5877
|
+
scrollTarget = new ScrollTarget(e.value, "center");
|
|
5878
|
+
else if (e.is(scrollIntoView))
|
|
5879
|
+
scrollTarget = e.value;
|
|
5822
5880
|
}
|
|
5823
5881
|
}
|
|
5824
5882
|
this.viewState.update(update, scrollTarget);
|
|
@@ -6386,6 +6444,14 @@ class EditorView {
|
|
|
6386
6444
|
this.destroyed = true;
|
|
6387
6445
|
}
|
|
6388
6446
|
/**
|
|
6447
|
+
Returns an effect that can be
|
|
6448
|
+
[added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a transaction to
|
|
6449
|
+
cause it to scroll the given position or range into view.
|
|
6450
|
+
*/
|
|
6451
|
+
static scrollIntoView(pos, options = {}) {
|
|
6452
|
+
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
|
6453
|
+
}
|
|
6454
|
+
/**
|
|
6389
6455
|
Facet that can be used to add DOM event handlers. The value
|
|
6390
6456
|
should be an object mapping event names to handler functions. The
|
|
6391
6457
|
first such function to return true will be assumed to have handled
|
|
@@ -6439,11 +6505,15 @@ class EditorView {
|
|
|
6439
6505
|
/**
|
|
6440
6506
|
Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
|
|
6441
6507
|
transaction to make it scroll the given range into view.
|
|
6508
|
+
|
|
6509
|
+
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6442
6510
|
*/
|
|
6443
6511
|
EditorView.scrollTo = scrollTo;
|
|
6444
6512
|
/**
|
|
6445
6513
|
Effect that makes the editor scroll the given range to the
|
|
6446
6514
|
center of the visible view.
|
|
6515
|
+
|
|
6516
|
+
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6447
6517
|
*/
|
|
6448
6518
|
EditorView.centerOn = centerOn;
|
|
6449
6519
|
/**
|