@codemirror/view 0.19.42 → 0.19.45
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 +31 -1
- package/dist/index.cjs +90 -53
- package/dist/index.d.ts +9 -1
- package/dist/index.js +90 -53
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## 0.19.45 (2022-02-23)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where the library failed to call `WidgetType.destroy` on the old widget when replacing a widget with a different widget of the same type.
|
|
6
|
+
|
|
7
|
+
Fix an issue where the editor would compute DOM positions inside composition contexts incorrectly in some cases, causing the selection to be put in the wrong place and needlessly interrupting compositions.
|
|
8
|
+
|
|
9
|
+
Fix leaking of resize event handlers.
|
|
10
|
+
|
|
11
|
+
## 0.19.44 (2022-02-17)
|
|
12
|
+
|
|
13
|
+
### Bug fixes
|
|
14
|
+
|
|
15
|
+
Fix a crash that occasionally occurred when drag-selecting in a way that scrolled the editor.
|
|
16
|
+
|
|
17
|
+
### New features
|
|
18
|
+
|
|
19
|
+
The new `EditorView.compositionStarted` property indicates whether a composition is starting.
|
|
20
|
+
|
|
21
|
+
## 0.19.43 (2022-02-16)
|
|
22
|
+
|
|
23
|
+
### Bug fixes
|
|
24
|
+
|
|
25
|
+
Fix several issues where editing or composition went wrong due to our zero-width space kludge characters ending up in unexpected places.
|
|
26
|
+
|
|
27
|
+
Make sure the editor re-measures its dimensions whenever its theme changes.
|
|
28
|
+
|
|
29
|
+
Fix an issue where some keys on Android phones could leave the editor DOM unsynced with the actual document.
|
|
30
|
+
|
|
1
31
|
## 0.19.42 (2022-02-05)
|
|
2
32
|
|
|
3
33
|
### Bug fixes
|
|
@@ -88,7 +118,7 @@ Fix an issue where backspacing out a selection on Chrome Android would sometimes
|
|
|
88
118
|
|
|
89
119
|
### Bug fixes
|
|
90
120
|
|
|
91
|
-
Fix a bug where content line elements would in some cases lose their `cm-line` class.
|
|
121
|
+
Fix a bug where content line elements would in some cases lose their `cm-line` class.
|
|
92
122
|
|
|
93
123
|
## 0.19.33 (2021-12-16)
|
|
94
124
|
|
package/dist/index.cjs
CHANGED
|
@@ -781,6 +781,7 @@ class WidgetView extends ContentView {
|
|
|
781
781
|
this.widget = widget;
|
|
782
782
|
this.length = length;
|
|
783
783
|
this.side = side;
|
|
784
|
+
this.prevWidget = null;
|
|
784
785
|
}
|
|
785
786
|
static create(widget, length, side) {
|
|
786
787
|
return new (widget.customView || WidgetView)(widget, length, side);
|
|
@@ -792,6 +793,9 @@ class WidgetView extends ContentView {
|
|
|
792
793
|
}
|
|
793
794
|
sync() {
|
|
794
795
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
796
|
+
if (this.dom && this.prevWidget)
|
|
797
|
+
this.prevWidget.destroy(this.dom);
|
|
798
|
+
this.prevWidget = null;
|
|
795
799
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
796
800
|
this.dom.contentEditable = "false";
|
|
797
801
|
}
|
|
@@ -809,6 +813,8 @@ class WidgetView extends ContentView {
|
|
|
809
813
|
if (this.widget.constructor == other.widget.constructor) {
|
|
810
814
|
if (!this.widget.eq(other.widget))
|
|
811
815
|
this.markDirty(true);
|
|
816
|
+
if (this.dom && !this.prevWidget)
|
|
817
|
+
this.prevWidget = this.widget;
|
|
812
818
|
this.widget = other.widget;
|
|
813
819
|
return true;
|
|
814
820
|
}
|
|
@@ -849,7 +855,12 @@ class WidgetView extends ContentView {
|
|
|
849
855
|
}
|
|
850
856
|
}
|
|
851
857
|
class CompositionView extends WidgetView {
|
|
852
|
-
domAtPos(pos) {
|
|
858
|
+
domAtPos(pos) {
|
|
859
|
+
let { topView } = this.widget;
|
|
860
|
+
if (!topView)
|
|
861
|
+
return new DOMPos(this.widget.text, Math.min(pos, this.widget.text.nodeValue.length));
|
|
862
|
+
return posInCompositionTree(pos, topView, this.widget.text);
|
|
863
|
+
}
|
|
853
864
|
sync() { this.setDOM(this.widget.toDOM()); }
|
|
854
865
|
localPosFromDOM(node, offset) {
|
|
855
866
|
return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length;
|
|
@@ -857,11 +868,34 @@ class CompositionView extends WidgetView {
|
|
|
857
868
|
ignoreMutation() { return false; }
|
|
858
869
|
get overrideDOMText() { return null; }
|
|
859
870
|
coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
|
|
871
|
+
destroy() {
|
|
872
|
+
var _a;
|
|
873
|
+
super.destroy();
|
|
874
|
+
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
875
|
+
}
|
|
860
876
|
get isEditable() { return true; }
|
|
861
877
|
}
|
|
862
|
-
//
|
|
863
|
-
//
|
|
864
|
-
|
|
878
|
+
// Uses the old structure of a chunk of content view frozen for
|
|
879
|
+
// composition to try and find a reasonable DOM location for the given
|
|
880
|
+
// offset.
|
|
881
|
+
function posInCompositionTree(pos, view, text) {
|
|
882
|
+
if (view instanceof MarkView) {
|
|
883
|
+
for (let child of view.children) {
|
|
884
|
+
let hasComp = child.dom == text || child.dom.contains(text.parentNode);
|
|
885
|
+
let len = hasComp ? text.nodeValue.length : child.length;
|
|
886
|
+
if (pos < len || pos == len && child.getSide() <= 0)
|
|
887
|
+
return hasComp ? posInCompositionTree(pos, child, text) : child.domAtPos(pos);
|
|
888
|
+
pos -= len;
|
|
889
|
+
}
|
|
890
|
+
return view.domAtPos(view.length);
|
|
891
|
+
}
|
|
892
|
+
else if (view.dom == text) {
|
|
893
|
+
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
894
|
+
}
|
|
895
|
+
else {
|
|
896
|
+
return view.domAtPos(pos);
|
|
897
|
+
}
|
|
898
|
+
}
|
|
865
899
|
// These are drawn around uneditable widgets to avoid a number of
|
|
866
900
|
// browser bugs that show up when the cursor is directly next to
|
|
867
901
|
// uneditable inline content.
|
|
@@ -877,21 +911,21 @@ class WidgetBufferView extends ContentView {
|
|
|
877
911
|
}
|
|
878
912
|
split() { return new WidgetBufferView(this.side); }
|
|
879
913
|
sync() {
|
|
880
|
-
if (!this.dom)
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
this.dom
|
|
914
|
+
if (!this.dom) {
|
|
915
|
+
let dom = document.createElement("img");
|
|
916
|
+
dom.className = "cm-widgetBuffer";
|
|
917
|
+
this.setDOM(dom);
|
|
918
|
+
}
|
|
884
919
|
}
|
|
885
920
|
getSide() { return this.side; }
|
|
886
921
|
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
887
922
|
localPosFromDOM() { return 0; }
|
|
888
923
|
domBoundsAround() { return null; }
|
|
889
924
|
coordsAt(pos) {
|
|
890
|
-
|
|
891
|
-
return rects[rects.length - 1] || null;
|
|
925
|
+
return this.dom.getBoundingClientRect();
|
|
892
926
|
}
|
|
893
927
|
get overrideDOMText() {
|
|
894
|
-
return text.Text.
|
|
928
|
+
return text.Text.empty;
|
|
895
929
|
}
|
|
896
930
|
}
|
|
897
931
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
@@ -938,7 +972,7 @@ function coordsInChildren(view, pos, side) {
|
|
|
938
972
|
continue;
|
|
939
973
|
flatten = side = -child.getSide();
|
|
940
974
|
}
|
|
941
|
-
let rect = child.coordsAt(pos - off, side);
|
|
975
|
+
let rect = child.coordsAt(Math.max(0, pos - off), side);
|
|
942
976
|
return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
|
943
977
|
}
|
|
944
978
|
off = end;
|
|
@@ -1391,6 +1425,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1391
1425
|
this.length = length;
|
|
1392
1426
|
this.type = type;
|
|
1393
1427
|
this.breakAfter = 0;
|
|
1428
|
+
this.prevWidget = null;
|
|
1394
1429
|
}
|
|
1395
1430
|
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1396
1431
|
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
@@ -1412,6 +1447,9 @@ class BlockWidgetView extends ContentView {
|
|
|
1412
1447
|
get children() { return noChildren; }
|
|
1413
1448
|
sync() {
|
|
1414
1449
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
1450
|
+
if (this.dom && this.prevWidget)
|
|
1451
|
+
this.prevWidget.destroy(this.dom);
|
|
1452
|
+
this.prevWidget = null;
|
|
1415
1453
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
1416
1454
|
this.dom.contentEditable = "false";
|
|
1417
1455
|
}
|
|
@@ -1425,6 +1463,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1425
1463
|
other.widget.constructor == this.widget.constructor) {
|
|
1426
1464
|
if (!other.widget.eq(this.widget))
|
|
1427
1465
|
this.markDirty(true);
|
|
1466
|
+
if (this.dom && !this.prevWidget)
|
|
1467
|
+
this.prevWidget = this.widget;
|
|
1428
1468
|
this.widget = other.widget;
|
|
1429
1469
|
this.length = other.length;
|
|
1430
1470
|
this.breakAfter = other.breakAfter;
|
|
@@ -2853,13 +2893,19 @@ function computeCompositionDeco(view, changes) {
|
|
|
2853
2893
|
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2854
2894
|
return Decoration.none;
|
|
2855
2895
|
}
|
|
2856
|
-
|
|
2896
|
+
let topView = ContentView.get(node);
|
|
2897
|
+
if (topView instanceof CompositionView)
|
|
2898
|
+
topView = topView.widget.topView;
|
|
2899
|
+
else if (topView)
|
|
2900
|
+
topView.parent = null;
|
|
2901
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView) }).range(newFrom, newTo));
|
|
2857
2902
|
}
|
|
2858
2903
|
class CompositionWidget extends WidgetType {
|
|
2859
|
-
constructor(top, text) {
|
|
2904
|
+
constructor(top, text, topView) {
|
|
2860
2905
|
super();
|
|
2861
2906
|
this.top = top;
|
|
2862
2907
|
this.text = text;
|
|
2908
|
+
this.topView = topView;
|
|
2863
2909
|
}
|
|
2864
2910
|
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
2865
2911
|
toDOM() { return this.top; }
|
|
@@ -5199,6 +5245,11 @@ const baseTheme = buildTheme("." + baseThemeID, {
|
|
|
5199
5245
|
overflow: "hidden",
|
|
5200
5246
|
verticalAlign: "bottom"
|
|
5201
5247
|
},
|
|
5248
|
+
".cm-widgetBuffer": {
|
|
5249
|
+
verticalAlign: "text-top",
|
|
5250
|
+
height: "1em",
|
|
5251
|
+
display: "inline"
|
|
5252
|
+
},
|
|
5202
5253
|
".cm-placeholder": {
|
|
5203
5254
|
color: "#888",
|
|
5204
5255
|
display: "inline-block",
|
|
@@ -5306,19 +5357,16 @@ class DOMObserver {
|
|
|
5306
5357
|
this.flushSoon();
|
|
5307
5358
|
};
|
|
5308
5359
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5360
|
+
window.addEventListener("resize", this.onResize = this.onResize.bind(this));
|
|
5309
5361
|
if (typeof ResizeObserver == "function") {
|
|
5310
5362
|
this.resize = new ResizeObserver(() => {
|
|
5311
|
-
if (this.view.docView.lastUpdate < Date.now() - 75
|
|
5312
|
-
this.
|
|
5313
|
-
this.resizeTimeout = -1;
|
|
5314
|
-
this.view.requestMeasure();
|
|
5315
|
-
}, 50);
|
|
5363
|
+
if (this.view.docView.lastUpdate < Date.now() - 75)
|
|
5364
|
+
this.onResize();
|
|
5316
5365
|
});
|
|
5317
5366
|
this.resize.observe(view.scrollDOM);
|
|
5318
5367
|
}
|
|
5319
5368
|
this.start();
|
|
5320
|
-
this.onScroll = this.onScroll.bind(this);
|
|
5321
|
-
window.addEventListener("scroll", this.onScroll);
|
|
5369
|
+
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5322
5370
|
if (typeof IntersectionObserver == "function") {
|
|
5323
5371
|
this.intersection = new IntersectionObserver(entries => {
|
|
5324
5372
|
if (this.parentCheck < 0)
|
|
@@ -5344,6 +5392,13 @@ class DOMObserver {
|
|
|
5344
5392
|
this.flush(false);
|
|
5345
5393
|
this.onScrollChanged(e);
|
|
5346
5394
|
}
|
|
5395
|
+
onResize() {
|
|
5396
|
+
if (this.resizeTimeout < 0)
|
|
5397
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5398
|
+
this.resizeTimeout = -1;
|
|
5399
|
+
this.view.requestMeasure();
|
|
5400
|
+
}, 50);
|
|
5401
|
+
}
|
|
5347
5402
|
updateGaps(gaps) {
|
|
5348
5403
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5349
5404
|
this.gapIntersection.disconnect();
|
|
@@ -5447,7 +5502,7 @@ class DOMObserver {
|
|
|
5447
5502
|
}
|
|
5448
5503
|
// Throw away any pending changes
|
|
5449
5504
|
clear() {
|
|
5450
|
-
this.
|
|
5505
|
+
this.processRecords();
|
|
5451
5506
|
this.queue.length = 0;
|
|
5452
5507
|
this.selectionChanged = false;
|
|
5453
5508
|
}
|
|
@@ -5560,6 +5615,7 @@ class DOMObserver {
|
|
|
5560
5615
|
for (let dom of this.scrollTargets)
|
|
5561
5616
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5562
5617
|
window.removeEventListener("scroll", this.onScroll);
|
|
5618
|
+
window.removeEventListener("resize", this.onResize);
|
|
5563
5619
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5564
5620
|
clearTimeout(this.parentCheck);
|
|
5565
5621
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5625,23 +5681,11 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5625
5681
|
}
|
|
5626
5682
|
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5627
5683
|
if (diff) {
|
|
5628
|
-
let orig = diff;
|
|
5629
5684
|
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5630
5685
|
// end of a line. This drops one of those.
|
|
5631
5686
|
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5632
5687
|
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5633
5688
|
diff.toB--;
|
|
5634
|
-
// Strip leading and trailing zero-width spaces from the inserted
|
|
5635
|
-
// content, to work around widget buffers being moved into text
|
|
5636
|
-
// nodes by the browser.
|
|
5637
|
-
while (diff.from < diff.toB && reader.text[diff.from] == "\u200b") {
|
|
5638
|
-
diff = { from: diff.from + 1, toA: diff.toA, toB: diff.toB };
|
|
5639
|
-
selPoints.forEach(p => p.pos -= p.pos > orig.from ? 1 : 0);
|
|
5640
|
-
}
|
|
5641
|
-
while (diff.toB > diff.from && reader.text[diff.toB - 1] == "\u200b") {
|
|
5642
|
-
diff = { from: diff.from, toA: diff.toA, toB: diff.toB - 1 };
|
|
5643
|
-
selPoints.forEach(p => p.pos -= p.pos > orig.toB ? 1 : 0);
|
|
5644
|
-
}
|
|
5645
5689
|
change = { from: from + diff.from, to: from + diff.toA,
|
|
5646
5690
|
insert: state.Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5647
5691
|
}
|
|
@@ -5891,7 +5935,6 @@ class EditorView {
|
|
|
5891
5935
|
this.mountStyles();
|
|
5892
5936
|
this.updateAttrs();
|
|
5893
5937
|
this.updateState = 0 /* Idle */;
|
|
5894
|
-
ensureGlobalHandler();
|
|
5895
5938
|
this.requestMeasure();
|
|
5896
5939
|
if (config.parent)
|
|
5897
5940
|
config.parent.appendChild(this.dom);
|
|
@@ -5924,9 +5967,17 @@ class EditorView {
|
|
|
5924
5967
|
get inView() { return this.viewState.inView; }
|
|
5925
5968
|
/**
|
|
5926
5969
|
Indicates whether the user is currently composing text via
|
|
5927
|
-
[IME](https://en.wikipedia.org/wiki/Input_method)
|
|
5970
|
+
[IME](https://en.wikipedia.org/wiki/Input_method), and at least
|
|
5971
|
+
one change has been made in the current composition.
|
|
5928
5972
|
*/
|
|
5929
5973
|
get composing() { return this.inputState.composing > 0; }
|
|
5974
|
+
/**
|
|
5975
|
+
Indicates whether the user is currently in composing state. Note
|
|
5976
|
+
that on some platforms, like Android, this will be the case a
|
|
5977
|
+
lot, since just putting the cursor on a word starts a
|
|
5978
|
+
composition there.
|
|
5979
|
+
*/
|
|
5980
|
+
get compositionStarted() { return this.inputState.composing >= 0; }
|
|
5930
5981
|
dispatch(...input) {
|
|
5931
5982
|
this._dispatch(input.length == 1 && input[0] instanceof state.Transaction ? input[0]
|
|
5932
5983
|
: this.state.update(...input));
|
|
@@ -5992,7 +6043,9 @@ class EditorView {
|
|
|
5992
6043
|
finally {
|
|
5993
6044
|
this.updateState = 0 /* Idle */;
|
|
5994
6045
|
}
|
|
5995
|
-
if (
|
|
6046
|
+
if (update.startState.facet(theme) != update.state.facet(theme))
|
|
6047
|
+
this.viewState.mustMeasureContent = true;
|
|
6048
|
+
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
5996
6049
|
this.requestMeasure();
|
|
5997
6050
|
if (!update.empty)
|
|
5998
6051
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -6718,22 +6771,6 @@ const MaxBidiLine = 4096;
|
|
|
6718
6771
|
function ensureTop(given, view) {
|
|
6719
6772
|
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6720
6773
|
}
|
|
6721
|
-
let resizeDebounce = -1;
|
|
6722
|
-
function ensureGlobalHandler() {
|
|
6723
|
-
window.addEventListener("resize", () => {
|
|
6724
|
-
if (resizeDebounce == -1)
|
|
6725
|
-
resizeDebounce = setTimeout(handleResize, 50);
|
|
6726
|
-
});
|
|
6727
|
-
}
|
|
6728
|
-
function handleResize() {
|
|
6729
|
-
resizeDebounce = -1;
|
|
6730
|
-
let found = document.querySelectorAll(".cm-content");
|
|
6731
|
-
for (let i = 0; i < found.length; i++) {
|
|
6732
|
-
let docView = ContentView.get(found[i]);
|
|
6733
|
-
if (docView)
|
|
6734
|
-
docView.editorView.requestMeasure();
|
|
6735
|
-
}
|
|
6736
|
-
}
|
|
6737
6774
|
const BadMeasure = {};
|
|
6738
6775
|
class CachedOrder {
|
|
6739
6776
|
constructor(from, to, dir, order) {
|
package/dist/index.d.ts
CHANGED
|
@@ -676,9 +676,17 @@ declare class EditorView {
|
|
|
676
676
|
get inView(): boolean;
|
|
677
677
|
/**
|
|
678
678
|
Indicates whether the user is currently composing text via
|
|
679
|
-
[IME](https://en.wikipedia.org/wiki/Input_method)
|
|
679
|
+
[IME](https://en.wikipedia.org/wiki/Input_method), and at least
|
|
680
|
+
one change has been made in the current composition.
|
|
680
681
|
*/
|
|
681
682
|
get composing(): boolean;
|
|
683
|
+
/**
|
|
684
|
+
Indicates whether the user is currently in composing state. Note
|
|
685
|
+
that on some platforms, like Android, this will be the case a
|
|
686
|
+
lot, since just putting the cursor on a word starts a
|
|
687
|
+
composition there.
|
|
688
|
+
*/
|
|
689
|
+
get compositionStarted(): boolean;
|
|
682
690
|
private _dispatch;
|
|
683
691
|
/**
|
|
684
692
|
The document or shadow root that the view lives in.
|
package/dist/index.js
CHANGED
|
@@ -778,6 +778,7 @@ class WidgetView extends ContentView {
|
|
|
778
778
|
this.widget = widget;
|
|
779
779
|
this.length = length;
|
|
780
780
|
this.side = side;
|
|
781
|
+
this.prevWidget = null;
|
|
781
782
|
}
|
|
782
783
|
static create(widget, length, side) {
|
|
783
784
|
return new (widget.customView || WidgetView)(widget, length, side);
|
|
@@ -789,6 +790,9 @@ class WidgetView extends ContentView {
|
|
|
789
790
|
}
|
|
790
791
|
sync() {
|
|
791
792
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
793
|
+
if (this.dom && this.prevWidget)
|
|
794
|
+
this.prevWidget.destroy(this.dom);
|
|
795
|
+
this.prevWidget = null;
|
|
792
796
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
793
797
|
this.dom.contentEditable = "false";
|
|
794
798
|
}
|
|
@@ -806,6 +810,8 @@ class WidgetView extends ContentView {
|
|
|
806
810
|
if (this.widget.constructor == other.widget.constructor) {
|
|
807
811
|
if (!this.widget.eq(other.widget))
|
|
808
812
|
this.markDirty(true);
|
|
813
|
+
if (this.dom && !this.prevWidget)
|
|
814
|
+
this.prevWidget = this.widget;
|
|
809
815
|
this.widget = other.widget;
|
|
810
816
|
return true;
|
|
811
817
|
}
|
|
@@ -846,7 +852,12 @@ class WidgetView extends ContentView {
|
|
|
846
852
|
}
|
|
847
853
|
}
|
|
848
854
|
class CompositionView extends WidgetView {
|
|
849
|
-
domAtPos(pos) {
|
|
855
|
+
domAtPos(pos) {
|
|
856
|
+
let { topView } = this.widget;
|
|
857
|
+
if (!topView)
|
|
858
|
+
return new DOMPos(this.widget.text, Math.min(pos, this.widget.text.nodeValue.length));
|
|
859
|
+
return posInCompositionTree(pos, topView, this.widget.text);
|
|
860
|
+
}
|
|
850
861
|
sync() { this.setDOM(this.widget.toDOM()); }
|
|
851
862
|
localPosFromDOM(node, offset) {
|
|
852
863
|
return !offset ? 0 : node.nodeType == 3 ? Math.min(offset, this.length) : this.length;
|
|
@@ -854,11 +865,34 @@ class CompositionView extends WidgetView {
|
|
|
854
865
|
ignoreMutation() { return false; }
|
|
855
866
|
get overrideDOMText() { return null; }
|
|
856
867
|
coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
|
|
868
|
+
destroy() {
|
|
869
|
+
var _a;
|
|
870
|
+
super.destroy();
|
|
871
|
+
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
872
|
+
}
|
|
857
873
|
get isEditable() { return true; }
|
|
858
874
|
}
|
|
859
|
-
//
|
|
860
|
-
//
|
|
861
|
-
|
|
875
|
+
// Uses the old structure of a chunk of content view frozen for
|
|
876
|
+
// composition to try and find a reasonable DOM location for the given
|
|
877
|
+
// offset.
|
|
878
|
+
function posInCompositionTree(pos, view, text) {
|
|
879
|
+
if (view instanceof MarkView) {
|
|
880
|
+
for (let child of view.children) {
|
|
881
|
+
let hasComp = child.dom == text || child.dom.contains(text.parentNode);
|
|
882
|
+
let len = hasComp ? text.nodeValue.length : child.length;
|
|
883
|
+
if (pos < len || pos == len && child.getSide() <= 0)
|
|
884
|
+
return hasComp ? posInCompositionTree(pos, child, text) : child.domAtPos(pos);
|
|
885
|
+
pos -= len;
|
|
886
|
+
}
|
|
887
|
+
return view.domAtPos(view.length);
|
|
888
|
+
}
|
|
889
|
+
else if (view.dom == text) {
|
|
890
|
+
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
891
|
+
}
|
|
892
|
+
else {
|
|
893
|
+
return view.domAtPos(pos);
|
|
894
|
+
}
|
|
895
|
+
}
|
|
862
896
|
// These are drawn around uneditable widgets to avoid a number of
|
|
863
897
|
// browser bugs that show up when the cursor is directly next to
|
|
864
898
|
// uneditable inline content.
|
|
@@ -874,21 +908,21 @@ class WidgetBufferView extends ContentView {
|
|
|
874
908
|
}
|
|
875
909
|
split() { return new WidgetBufferView(this.side); }
|
|
876
910
|
sync() {
|
|
877
|
-
if (!this.dom)
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
this.dom
|
|
911
|
+
if (!this.dom) {
|
|
912
|
+
let dom = document.createElement("img");
|
|
913
|
+
dom.className = "cm-widgetBuffer";
|
|
914
|
+
this.setDOM(dom);
|
|
915
|
+
}
|
|
881
916
|
}
|
|
882
917
|
getSide() { return this.side; }
|
|
883
918
|
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
884
919
|
localPosFromDOM() { return 0; }
|
|
885
920
|
domBoundsAround() { return null; }
|
|
886
921
|
coordsAt(pos) {
|
|
887
|
-
|
|
888
|
-
return rects[rects.length - 1] || null;
|
|
922
|
+
return this.dom.getBoundingClientRect();
|
|
889
923
|
}
|
|
890
924
|
get overrideDOMText() {
|
|
891
|
-
return Text.
|
|
925
|
+
return Text.empty;
|
|
892
926
|
}
|
|
893
927
|
}
|
|
894
928
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
@@ -935,7 +969,7 @@ function coordsInChildren(view, pos, side) {
|
|
|
935
969
|
continue;
|
|
936
970
|
flatten = side = -child.getSide();
|
|
937
971
|
}
|
|
938
|
-
let rect = child.coordsAt(pos - off, side);
|
|
972
|
+
let rect = child.coordsAt(Math.max(0, pos - off), side);
|
|
939
973
|
return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
|
940
974
|
}
|
|
941
975
|
off = end;
|
|
@@ -1387,6 +1421,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1387
1421
|
this.length = length;
|
|
1388
1422
|
this.type = type;
|
|
1389
1423
|
this.breakAfter = 0;
|
|
1424
|
+
this.prevWidget = null;
|
|
1390
1425
|
}
|
|
1391
1426
|
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1392
1427
|
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
@@ -1408,6 +1443,9 @@ class BlockWidgetView extends ContentView {
|
|
|
1408
1443
|
get children() { return noChildren; }
|
|
1409
1444
|
sync() {
|
|
1410
1445
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
1446
|
+
if (this.dom && this.prevWidget)
|
|
1447
|
+
this.prevWidget.destroy(this.dom);
|
|
1448
|
+
this.prevWidget = null;
|
|
1411
1449
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
1412
1450
|
this.dom.contentEditable = "false";
|
|
1413
1451
|
}
|
|
@@ -1421,6 +1459,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1421
1459
|
other.widget.constructor == this.widget.constructor) {
|
|
1422
1460
|
if (!other.widget.eq(this.widget))
|
|
1423
1461
|
this.markDirty(true);
|
|
1462
|
+
if (this.dom && !this.prevWidget)
|
|
1463
|
+
this.prevWidget = this.widget;
|
|
1424
1464
|
this.widget = other.widget;
|
|
1425
1465
|
this.length = other.length;
|
|
1426
1466
|
this.breakAfter = other.breakAfter;
|
|
@@ -2848,13 +2888,19 @@ function computeCompositionDeco(view, changes) {
|
|
|
2848
2888
|
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2849
2889
|
return Decoration.none;
|
|
2850
2890
|
}
|
|
2851
|
-
|
|
2891
|
+
let topView = ContentView.get(node);
|
|
2892
|
+
if (topView instanceof CompositionView)
|
|
2893
|
+
topView = topView.widget.topView;
|
|
2894
|
+
else if (topView)
|
|
2895
|
+
topView.parent = null;
|
|
2896
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView) }).range(newFrom, newTo));
|
|
2852
2897
|
}
|
|
2853
2898
|
class CompositionWidget extends WidgetType {
|
|
2854
|
-
constructor(top, text) {
|
|
2899
|
+
constructor(top, text, topView) {
|
|
2855
2900
|
super();
|
|
2856
2901
|
this.top = top;
|
|
2857
2902
|
this.text = text;
|
|
2903
|
+
this.topView = topView;
|
|
2858
2904
|
}
|
|
2859
2905
|
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
2860
2906
|
toDOM() { return this.top; }
|
|
@@ -5193,6 +5239,11 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
5193
5239
|
overflow: "hidden",
|
|
5194
5240
|
verticalAlign: "bottom"
|
|
5195
5241
|
},
|
|
5242
|
+
".cm-widgetBuffer": {
|
|
5243
|
+
verticalAlign: "text-top",
|
|
5244
|
+
height: "1em",
|
|
5245
|
+
display: "inline"
|
|
5246
|
+
},
|
|
5196
5247
|
".cm-placeholder": {
|
|
5197
5248
|
color: "#888",
|
|
5198
5249
|
display: "inline-block",
|
|
@@ -5300,19 +5351,16 @@ class DOMObserver {
|
|
|
5300
5351
|
this.flushSoon();
|
|
5301
5352
|
};
|
|
5302
5353
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5354
|
+
window.addEventListener("resize", this.onResize = this.onResize.bind(this));
|
|
5303
5355
|
if (typeof ResizeObserver == "function") {
|
|
5304
5356
|
this.resize = new ResizeObserver(() => {
|
|
5305
|
-
if (this.view.docView.lastUpdate < Date.now() - 75
|
|
5306
|
-
this.
|
|
5307
|
-
this.resizeTimeout = -1;
|
|
5308
|
-
this.view.requestMeasure();
|
|
5309
|
-
}, 50);
|
|
5357
|
+
if (this.view.docView.lastUpdate < Date.now() - 75)
|
|
5358
|
+
this.onResize();
|
|
5310
5359
|
});
|
|
5311
5360
|
this.resize.observe(view.scrollDOM);
|
|
5312
5361
|
}
|
|
5313
5362
|
this.start();
|
|
5314
|
-
this.onScroll = this.onScroll.bind(this);
|
|
5315
|
-
window.addEventListener("scroll", this.onScroll);
|
|
5363
|
+
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5316
5364
|
if (typeof IntersectionObserver == "function") {
|
|
5317
5365
|
this.intersection = new IntersectionObserver(entries => {
|
|
5318
5366
|
if (this.parentCheck < 0)
|
|
@@ -5338,6 +5386,13 @@ class DOMObserver {
|
|
|
5338
5386
|
this.flush(false);
|
|
5339
5387
|
this.onScrollChanged(e);
|
|
5340
5388
|
}
|
|
5389
|
+
onResize() {
|
|
5390
|
+
if (this.resizeTimeout < 0)
|
|
5391
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5392
|
+
this.resizeTimeout = -1;
|
|
5393
|
+
this.view.requestMeasure();
|
|
5394
|
+
}, 50);
|
|
5395
|
+
}
|
|
5341
5396
|
updateGaps(gaps) {
|
|
5342
5397
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5343
5398
|
this.gapIntersection.disconnect();
|
|
@@ -5441,7 +5496,7 @@ class DOMObserver {
|
|
|
5441
5496
|
}
|
|
5442
5497
|
// Throw away any pending changes
|
|
5443
5498
|
clear() {
|
|
5444
|
-
this.
|
|
5499
|
+
this.processRecords();
|
|
5445
5500
|
this.queue.length = 0;
|
|
5446
5501
|
this.selectionChanged = false;
|
|
5447
5502
|
}
|
|
@@ -5554,6 +5609,7 @@ class DOMObserver {
|
|
|
5554
5609
|
for (let dom of this.scrollTargets)
|
|
5555
5610
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5556
5611
|
window.removeEventListener("scroll", this.onScroll);
|
|
5612
|
+
window.removeEventListener("resize", this.onResize);
|
|
5557
5613
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5558
5614
|
clearTimeout(this.parentCheck);
|
|
5559
5615
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5619,23 +5675,11 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5619
5675
|
}
|
|
5620
5676
|
let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
|
5621
5677
|
if (diff) {
|
|
5622
|
-
let orig = diff;
|
|
5623
5678
|
// Chrome inserts two newlines when pressing shift-enter at the
|
|
5624
5679
|
// end of a line. This drops one of those.
|
|
5625
5680
|
if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
|
5626
5681
|
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5627
5682
|
diff.toB--;
|
|
5628
|
-
// Strip leading and trailing zero-width spaces from the inserted
|
|
5629
|
-
// content, to work around widget buffers being moved into text
|
|
5630
|
-
// nodes by the browser.
|
|
5631
|
-
while (diff.from < diff.toB && reader.text[diff.from] == "\u200b") {
|
|
5632
|
-
diff = { from: diff.from + 1, toA: diff.toA, toB: diff.toB };
|
|
5633
|
-
selPoints.forEach(p => p.pos -= p.pos > orig.from ? 1 : 0);
|
|
5634
|
-
}
|
|
5635
|
-
while (diff.toB > diff.from && reader.text[diff.toB - 1] == "\u200b") {
|
|
5636
|
-
diff = { from: diff.from, toA: diff.toA, toB: diff.toB - 1 };
|
|
5637
|
-
selPoints.forEach(p => p.pos -= p.pos > orig.toB ? 1 : 0);
|
|
5638
|
-
}
|
|
5639
5683
|
change = { from: from + diff.from, to: from + diff.toA,
|
|
5640
5684
|
insert: Text$1.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5641
5685
|
}
|
|
@@ -5885,7 +5929,6 @@ class EditorView {
|
|
|
5885
5929
|
this.mountStyles();
|
|
5886
5930
|
this.updateAttrs();
|
|
5887
5931
|
this.updateState = 0 /* Idle */;
|
|
5888
|
-
ensureGlobalHandler();
|
|
5889
5932
|
this.requestMeasure();
|
|
5890
5933
|
if (config.parent)
|
|
5891
5934
|
config.parent.appendChild(this.dom);
|
|
@@ -5918,9 +5961,17 @@ class EditorView {
|
|
|
5918
5961
|
get inView() { return this.viewState.inView; }
|
|
5919
5962
|
/**
|
|
5920
5963
|
Indicates whether the user is currently composing text via
|
|
5921
|
-
[IME](https://en.wikipedia.org/wiki/Input_method)
|
|
5964
|
+
[IME](https://en.wikipedia.org/wiki/Input_method), and at least
|
|
5965
|
+
one change has been made in the current composition.
|
|
5922
5966
|
*/
|
|
5923
5967
|
get composing() { return this.inputState.composing > 0; }
|
|
5968
|
+
/**
|
|
5969
|
+
Indicates whether the user is currently in composing state. Note
|
|
5970
|
+
that on some platforms, like Android, this will be the case a
|
|
5971
|
+
lot, since just putting the cursor on a word starts a
|
|
5972
|
+
composition there.
|
|
5973
|
+
*/
|
|
5974
|
+
get compositionStarted() { return this.inputState.composing >= 0; }
|
|
5924
5975
|
dispatch(...input) {
|
|
5925
5976
|
this._dispatch(input.length == 1 && input[0] instanceof Transaction ? input[0]
|
|
5926
5977
|
: this.state.update(...input));
|
|
@@ -5986,7 +6037,9 @@ class EditorView {
|
|
|
5986
6037
|
finally {
|
|
5987
6038
|
this.updateState = 0 /* Idle */;
|
|
5988
6039
|
}
|
|
5989
|
-
if (
|
|
6040
|
+
if (update.startState.facet(theme) != update.state.facet(theme))
|
|
6041
|
+
this.viewState.mustMeasureContent = true;
|
|
6042
|
+
if (redrawn || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
|
5990
6043
|
this.requestMeasure();
|
|
5991
6044
|
if (!update.empty)
|
|
5992
6045
|
for (let listener of this.state.facet(updateListener))
|
|
@@ -6712,22 +6765,6 @@ const MaxBidiLine = 4096;
|
|
|
6712
6765
|
function ensureTop(given, view) {
|
|
6713
6766
|
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6714
6767
|
}
|
|
6715
|
-
let resizeDebounce = -1;
|
|
6716
|
-
function ensureGlobalHandler() {
|
|
6717
|
-
window.addEventListener("resize", () => {
|
|
6718
|
-
if (resizeDebounce == -1)
|
|
6719
|
-
resizeDebounce = setTimeout(handleResize, 50);
|
|
6720
|
-
});
|
|
6721
|
-
}
|
|
6722
|
-
function handleResize() {
|
|
6723
|
-
resizeDebounce = -1;
|
|
6724
|
-
let found = document.querySelectorAll(".cm-content");
|
|
6725
|
-
for (let i = 0; i < found.length; i++) {
|
|
6726
|
-
let docView = ContentView.get(found[i]);
|
|
6727
|
-
if (docView)
|
|
6728
|
-
docView.editorView.requestMeasure();
|
|
6729
|
-
}
|
|
6730
|
-
}
|
|
6731
6768
|
const BadMeasure = {};
|
|
6732
6769
|
class CachedOrder {
|
|
6733
6770
|
constructor(from, to, dir, order) {
|