@codemirror/view 0.19.44 → 0.19.47
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 +26 -0
- package/dist/index.cjs +141 -39
- package/dist/index.js +141 -39
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
## 0.19.47 (2022-03-08)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Fix an issue where block widgets at the start of the viewport could break height computations.
|
|
6
|
+
|
|
7
|
+
## 0.19.46 (2022-03-03)
|
|
8
|
+
|
|
9
|
+
### Bug fixes
|
|
10
|
+
|
|
11
|
+
Fix a bug where block widgets on the edges of viewports could cause the positioning of content to misalign with the gutter and height computations.
|
|
12
|
+
|
|
13
|
+
Improve cursor height next to widgets.
|
|
14
|
+
|
|
15
|
+
Fix a bug where mapping positions to screen coordinates could return incorred coordinates during composition.
|
|
16
|
+
|
|
17
|
+
## 0.19.45 (2022-02-23)
|
|
18
|
+
|
|
19
|
+
### Bug fixes
|
|
20
|
+
|
|
21
|
+
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.
|
|
22
|
+
|
|
23
|
+
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.
|
|
24
|
+
|
|
25
|
+
Fix leaking of resize event handlers.
|
|
26
|
+
|
|
1
27
|
## 0.19.44 (2022-02-17)
|
|
2
28
|
|
|
3
29
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -22,7 +22,7 @@ function getSelection(root) {
|
|
|
22
22
|
return target.getSelection();
|
|
23
23
|
}
|
|
24
24
|
function contains(dom, node) {
|
|
25
|
-
return node ? dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
25
|
+
return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
26
26
|
}
|
|
27
27
|
function deepActiveElement() {
|
|
28
28
|
let elt = document.activeElement;
|
|
@@ -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,16 +855,69 @@ class WidgetView extends ContentView {
|
|
|
849
855
|
}
|
|
850
856
|
}
|
|
851
857
|
class CompositionView extends WidgetView {
|
|
852
|
-
domAtPos(pos) {
|
|
858
|
+
domAtPos(pos) {
|
|
859
|
+
let { topView, text } = this.widget;
|
|
860
|
+
if (!topView)
|
|
861
|
+
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
862
|
+
return scanCompositionTree(pos, 0, topView, text, (v, p) => v.domAtPos(p), p => new DOMPos(text, Math.min(p, text.nodeValue.length)));
|
|
863
|
+
}
|
|
853
864
|
sync() { this.setDOM(this.widget.toDOM()); }
|
|
854
865
|
localPosFromDOM(node, offset) {
|
|
855
|
-
|
|
866
|
+
let { topView, text } = this.widget;
|
|
867
|
+
if (!topView)
|
|
868
|
+
return Math.min(offset, this.length);
|
|
869
|
+
return posFromDOMInCompositionTree(node, offset, topView, text);
|
|
856
870
|
}
|
|
857
871
|
ignoreMutation() { return false; }
|
|
858
872
|
get overrideDOMText() { return null; }
|
|
859
|
-
coordsAt(pos, side) {
|
|
873
|
+
coordsAt(pos, side) {
|
|
874
|
+
let { topView, text } = this.widget;
|
|
875
|
+
if (!topView)
|
|
876
|
+
return textCoords(text, pos, side);
|
|
877
|
+
return scanCompositionTree(pos, side, topView, text, (v, pos, side) => v.coordsAt(pos, side), (pos, side) => textCoords(text, pos, side));
|
|
878
|
+
}
|
|
879
|
+
destroy() {
|
|
880
|
+
var _a;
|
|
881
|
+
super.destroy();
|
|
882
|
+
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
883
|
+
}
|
|
860
884
|
get isEditable() { return true; }
|
|
861
885
|
}
|
|
886
|
+
// Uses the old structure of a chunk of content view frozen for
|
|
887
|
+
// composition to try and find a reasonable DOM location for the given
|
|
888
|
+
// offset.
|
|
889
|
+
function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
890
|
+
if (view instanceof MarkView) {
|
|
891
|
+
for (let child of view.children) {
|
|
892
|
+
let hasComp = contains(child.dom, text);
|
|
893
|
+
let len = hasComp ? text.nodeValue.length : child.length;
|
|
894
|
+
if (pos < len || pos == len && child.getSide() <= 0)
|
|
895
|
+
return hasComp ? scanCompositionTree(pos, side, child, text, enterView, fromText) : enterView(child, pos, side);
|
|
896
|
+
pos -= len;
|
|
897
|
+
}
|
|
898
|
+
return enterView(view, view.length, -1);
|
|
899
|
+
}
|
|
900
|
+
else if (view.dom == text) {
|
|
901
|
+
return fromText(pos, side);
|
|
902
|
+
}
|
|
903
|
+
else {
|
|
904
|
+
return enterView(view, pos, side);
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
908
|
+
if (view instanceof MarkView) {
|
|
909
|
+
for (let child of view.children) {
|
|
910
|
+
let pos = 0, hasComp = contains(child.dom, text);
|
|
911
|
+
if (contains(child.dom, node))
|
|
912
|
+
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
913
|
+
pos += hasComp ? text.nodeValue.length : child.length;
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
else if (view.dom == text) {
|
|
917
|
+
return Math.min(offset, text.nodeValue.length);
|
|
918
|
+
}
|
|
919
|
+
return view.localPosFromDOM(node, offset);
|
|
920
|
+
}
|
|
862
921
|
// These are drawn around uneditable widgets to avoid a number of
|
|
863
922
|
// browser bugs that show up when the cursor is directly next to
|
|
864
923
|
// uneditable inline content.
|
|
@@ -877,6 +936,7 @@ class WidgetBufferView extends ContentView {
|
|
|
877
936
|
if (!this.dom) {
|
|
878
937
|
let dom = document.createElement("img");
|
|
879
938
|
dom.className = "cm-widgetBuffer";
|
|
939
|
+
dom.setAttribute("aria-hidden", "true");
|
|
880
940
|
this.setDOM(dom);
|
|
881
941
|
}
|
|
882
942
|
}
|
|
@@ -885,13 +945,43 @@ class WidgetBufferView extends ContentView {
|
|
|
885
945
|
localPosFromDOM() { return 0; }
|
|
886
946
|
domBoundsAround() { return null; }
|
|
887
947
|
coordsAt(pos) {
|
|
888
|
-
|
|
948
|
+
let imgRect = this.dom.getBoundingClientRect();
|
|
949
|
+
// Since the <img> height doesn't correspond to text height, try
|
|
950
|
+
// to borrow the height from some sibling node.
|
|
951
|
+
let siblingRect = inlineSiblingRect(this, this.side > 0 ? -1 : 1);
|
|
952
|
+
return siblingRect && siblingRect.top < imgRect.bottom && siblingRect.bottom > imgRect.top
|
|
953
|
+
? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect;
|
|
889
954
|
}
|
|
890
955
|
get overrideDOMText() {
|
|
891
956
|
return text.Text.empty;
|
|
892
957
|
}
|
|
893
958
|
}
|
|
894
959
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
960
|
+
function inlineSiblingRect(view, side) {
|
|
961
|
+
let parent = view.parent, index = parent ? parent.children.indexOf(view) : -1;
|
|
962
|
+
while (parent && index >= 0) {
|
|
963
|
+
if (side < 0 ? index > 0 : index < parent.children.length) {
|
|
964
|
+
let next = parent.children[index + side];
|
|
965
|
+
if (next instanceof TextView) {
|
|
966
|
+
let nextRect = next.coordsAt(side < 0 ? next.length : 0, side);
|
|
967
|
+
if (nextRect)
|
|
968
|
+
return nextRect;
|
|
969
|
+
}
|
|
970
|
+
index += side;
|
|
971
|
+
}
|
|
972
|
+
else if (parent instanceof MarkView && parent.parent) {
|
|
973
|
+
index = parent.parent.children.indexOf(parent) + (side < 0 ? 0 : 1);
|
|
974
|
+
parent = parent.parent;
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
let last = parent.dom.lastChild;
|
|
978
|
+
if (last && last.nodeName == "BR")
|
|
979
|
+
return last.getClientRects()[0];
|
|
980
|
+
break;
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
return undefined;
|
|
984
|
+
}
|
|
895
985
|
function inlineDOMAtPos(dom, children, pos) {
|
|
896
986
|
let i = 0;
|
|
897
987
|
for (let off = 0; i < children.length; i++) {
|
|
@@ -1125,10 +1215,16 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1125
1215
|
a widget, or simply hides it.
|
|
1126
1216
|
*/
|
|
1127
1217
|
static replace(spec) {
|
|
1128
|
-
let block = !!spec.block;
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1218
|
+
let block = !!spec.block, startSide, endSide;
|
|
1219
|
+
if (spec.isBlockGap) {
|
|
1220
|
+
startSide = -500000000 /* GapStart */;
|
|
1221
|
+
endSide = 400000000 /* GapEnd */;
|
|
1222
|
+
}
|
|
1223
|
+
else {
|
|
1224
|
+
let { start, end } = getInclusive(spec, block);
|
|
1225
|
+
startSide = (start ? (block ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 500000000 /* NonIncStart */) - 1;
|
|
1226
|
+
endSide = (end ? (block ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -600000000 /* NonIncEnd */) + 1;
|
|
1227
|
+
}
|
|
1132
1228
|
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1133
1229
|
}
|
|
1134
1230
|
/**
|
|
@@ -1158,7 +1254,7 @@ Decoration.none = rangeset.RangeSet.empty;
|
|
|
1158
1254
|
class MarkDecoration extends Decoration {
|
|
1159
1255
|
constructor(spec) {
|
|
1160
1256
|
let { start, end } = getInclusive(spec);
|
|
1161
|
-
super(start ? -1 /* InlineIncStart */ :
|
|
1257
|
+
super(start ? -1 /* InlineIncStart */ : 500000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -600000000 /* NonIncEnd */, null, spec);
|
|
1162
1258
|
this.tagName = spec.tagName || "span";
|
|
1163
1259
|
this.class = spec.class || "";
|
|
1164
1260
|
this.attrs = spec.attributes || null;
|
|
@@ -1339,7 +1435,7 @@ class LineView extends ContentView {
|
|
|
1339
1435
|
let last = this.dom.lastChild;
|
|
1340
1436
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1341
1437
|
last = last.lastChild;
|
|
1342
|
-
if (!last ||
|
|
1438
|
+
if (!last || !this.length ||
|
|
1343
1439
|
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1344
1440
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1345
1441
|
let hack = document.createElement("BR");
|
|
@@ -1388,6 +1484,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1388
1484
|
this.length = length;
|
|
1389
1485
|
this.type = type;
|
|
1390
1486
|
this.breakAfter = 0;
|
|
1487
|
+
this.prevWidget = null;
|
|
1391
1488
|
}
|
|
1392
1489
|
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1393
1490
|
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
@@ -1409,6 +1506,9 @@ class BlockWidgetView extends ContentView {
|
|
|
1409
1506
|
get children() { return noChildren; }
|
|
1410
1507
|
sync() {
|
|
1411
1508
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
1509
|
+
if (this.dom && this.prevWidget)
|
|
1510
|
+
this.prevWidget.destroy(this.dom);
|
|
1511
|
+
this.prevWidget = null;
|
|
1412
1512
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
1413
1513
|
this.dom.contentEditable = "false";
|
|
1414
1514
|
}
|
|
@@ -1422,6 +1522,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1422
1522
|
other.widget.constructor == this.widget.constructor) {
|
|
1423
1523
|
if (!other.widget.eq(this.widget))
|
|
1424
1524
|
this.markDirty(true);
|
|
1525
|
+
if (this.dom && !this.prevWidget)
|
|
1526
|
+
this.prevWidget = this.widget;
|
|
1425
1527
|
this.widget = other.widget;
|
|
1426
1528
|
this.length = other.length;
|
|
1427
1529
|
this.breakAfter = other.breakAfter;
|
|
@@ -2731,7 +2833,12 @@ class DocView extends ContentView {
|
|
|
2731
2833
|
let end = next ? next.from - 1 : this.length;
|
|
2732
2834
|
if (end > pos) {
|
|
2733
2835
|
let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
|
2734
|
-
deco.push(Decoration.replace({
|
|
2836
|
+
deco.push(Decoration.replace({
|
|
2837
|
+
widget: new BlockGapWidget(height),
|
|
2838
|
+
block: true,
|
|
2839
|
+
inclusive: true,
|
|
2840
|
+
isBlockGap: true,
|
|
2841
|
+
}).range(pos, end));
|
|
2735
2842
|
}
|
|
2736
2843
|
if (!next)
|
|
2737
2844
|
break;
|
|
@@ -2850,13 +2957,19 @@ function computeCompositionDeco(view, changes) {
|
|
|
2850
2957
|
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2851
2958
|
return Decoration.none;
|
|
2852
2959
|
}
|
|
2853
|
-
|
|
2960
|
+
let topView = ContentView.get(node);
|
|
2961
|
+
if (topView instanceof CompositionView)
|
|
2962
|
+
topView = topView.widget.topView;
|
|
2963
|
+
else if (topView)
|
|
2964
|
+
topView.parent = null;
|
|
2965
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView) }).range(newFrom, newTo));
|
|
2854
2966
|
}
|
|
2855
2967
|
class CompositionWidget extends WidgetType {
|
|
2856
|
-
constructor(top, text) {
|
|
2968
|
+
constructor(top, text, topView) {
|
|
2857
2969
|
super();
|
|
2858
2970
|
this.top = top;
|
|
2859
2971
|
this.text = text;
|
|
2972
|
+
this.topView = topView;
|
|
2860
2973
|
}
|
|
2861
2974
|
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
2862
2975
|
toDOM() { return this.top; }
|
|
@@ -5197,8 +5310,9 @@ const baseTheme = buildTheme("." + baseThemeID, {
|
|
|
5197
5310
|
verticalAlign: "bottom"
|
|
5198
5311
|
},
|
|
5199
5312
|
".cm-widgetBuffer": {
|
|
5200
|
-
verticalAlign: "text-
|
|
5313
|
+
verticalAlign: "text-top",
|
|
5201
5314
|
height: "1em",
|
|
5315
|
+
display: "inline"
|
|
5202
5316
|
},
|
|
5203
5317
|
".cm-placeholder": {
|
|
5204
5318
|
color: "#888",
|
|
@@ -5307,19 +5421,16 @@ class DOMObserver {
|
|
|
5307
5421
|
this.flushSoon();
|
|
5308
5422
|
};
|
|
5309
5423
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5424
|
+
window.addEventListener("resize", this.onResize = this.onResize.bind(this));
|
|
5310
5425
|
if (typeof ResizeObserver == "function") {
|
|
5311
5426
|
this.resize = new ResizeObserver(() => {
|
|
5312
|
-
if (this.view.docView.lastUpdate < Date.now() - 75
|
|
5313
|
-
this.
|
|
5314
|
-
this.resizeTimeout = -1;
|
|
5315
|
-
this.view.requestMeasure();
|
|
5316
|
-
}, 50);
|
|
5427
|
+
if (this.view.docView.lastUpdate < Date.now() - 75)
|
|
5428
|
+
this.onResize();
|
|
5317
5429
|
});
|
|
5318
5430
|
this.resize.observe(view.scrollDOM);
|
|
5319
5431
|
}
|
|
5320
5432
|
this.start();
|
|
5321
|
-
this.onScroll = this.onScroll.bind(this);
|
|
5322
|
-
window.addEventListener("scroll", this.onScroll);
|
|
5433
|
+
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5323
5434
|
if (typeof IntersectionObserver == "function") {
|
|
5324
5435
|
this.intersection = new IntersectionObserver(entries => {
|
|
5325
5436
|
if (this.parentCheck < 0)
|
|
@@ -5345,6 +5456,13 @@ class DOMObserver {
|
|
|
5345
5456
|
this.flush(false);
|
|
5346
5457
|
this.onScrollChanged(e);
|
|
5347
5458
|
}
|
|
5459
|
+
onResize() {
|
|
5460
|
+
if (this.resizeTimeout < 0)
|
|
5461
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5462
|
+
this.resizeTimeout = -1;
|
|
5463
|
+
this.view.requestMeasure();
|
|
5464
|
+
}, 50);
|
|
5465
|
+
}
|
|
5348
5466
|
updateGaps(gaps) {
|
|
5349
5467
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5350
5468
|
this.gapIntersection.disconnect();
|
|
@@ -5561,6 +5679,7 @@ class DOMObserver {
|
|
|
5561
5679
|
for (let dom of this.scrollTargets)
|
|
5562
5680
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5563
5681
|
window.removeEventListener("scroll", this.onScroll);
|
|
5682
|
+
window.removeEventListener("resize", this.onResize);
|
|
5564
5683
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5565
5684
|
clearTimeout(this.parentCheck);
|
|
5566
5685
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5880,7 +5999,6 @@ class EditorView {
|
|
|
5880
5999
|
this.mountStyles();
|
|
5881
6000
|
this.updateAttrs();
|
|
5882
6001
|
this.updateState = 0 /* Idle */;
|
|
5883
|
-
ensureGlobalHandler();
|
|
5884
6002
|
this.requestMeasure();
|
|
5885
6003
|
if (config.parent)
|
|
5886
6004
|
config.parent.appendChild(this.dom);
|
|
@@ -6717,22 +6835,6 @@ const MaxBidiLine = 4096;
|
|
|
6717
6835
|
function ensureTop(given, view) {
|
|
6718
6836
|
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6719
6837
|
}
|
|
6720
|
-
let resizeDebounce = -1;
|
|
6721
|
-
function ensureGlobalHandler() {
|
|
6722
|
-
window.addEventListener("resize", () => {
|
|
6723
|
-
if (resizeDebounce == -1)
|
|
6724
|
-
resizeDebounce = setTimeout(handleResize, 50);
|
|
6725
|
-
});
|
|
6726
|
-
}
|
|
6727
|
-
function handleResize() {
|
|
6728
|
-
resizeDebounce = -1;
|
|
6729
|
-
let found = document.querySelectorAll(".cm-content");
|
|
6730
|
-
for (let i = 0; i < found.length; i++) {
|
|
6731
|
-
let docView = ContentView.get(found[i]);
|
|
6732
|
-
if (docView)
|
|
6733
|
-
docView.editorView.requestMeasure();
|
|
6734
|
-
}
|
|
6735
|
-
}
|
|
6736
6838
|
const BadMeasure = {};
|
|
6737
6839
|
class CachedOrder {
|
|
6738
6840
|
constructor(from, to, dir, order) {
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,7 @@ function getSelection(root) {
|
|
|
19
19
|
return target.getSelection();
|
|
20
20
|
}
|
|
21
21
|
function contains(dom, node) {
|
|
22
|
-
return node ? dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
22
|
+
return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
23
23
|
}
|
|
24
24
|
function deepActiveElement() {
|
|
25
25
|
let elt = document.activeElement;
|
|
@@ -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,16 +852,69 @@ class WidgetView extends ContentView {
|
|
|
846
852
|
}
|
|
847
853
|
}
|
|
848
854
|
class CompositionView extends WidgetView {
|
|
849
|
-
domAtPos(pos) {
|
|
855
|
+
domAtPos(pos) {
|
|
856
|
+
let { topView, text } = this.widget;
|
|
857
|
+
if (!topView)
|
|
858
|
+
return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
|
859
|
+
return scanCompositionTree(pos, 0, topView, text, (v, p) => v.domAtPos(p), p => new DOMPos(text, Math.min(p, text.nodeValue.length)));
|
|
860
|
+
}
|
|
850
861
|
sync() { this.setDOM(this.widget.toDOM()); }
|
|
851
862
|
localPosFromDOM(node, offset) {
|
|
852
|
-
|
|
863
|
+
let { topView, text } = this.widget;
|
|
864
|
+
if (!topView)
|
|
865
|
+
return Math.min(offset, this.length);
|
|
866
|
+
return posFromDOMInCompositionTree(node, offset, topView, text);
|
|
853
867
|
}
|
|
854
868
|
ignoreMutation() { return false; }
|
|
855
869
|
get overrideDOMText() { return null; }
|
|
856
|
-
coordsAt(pos, side) {
|
|
870
|
+
coordsAt(pos, side) {
|
|
871
|
+
let { topView, text } = this.widget;
|
|
872
|
+
if (!topView)
|
|
873
|
+
return textCoords(text, pos, side);
|
|
874
|
+
return scanCompositionTree(pos, side, topView, text, (v, pos, side) => v.coordsAt(pos, side), (pos, side) => textCoords(text, pos, side));
|
|
875
|
+
}
|
|
876
|
+
destroy() {
|
|
877
|
+
var _a;
|
|
878
|
+
super.destroy();
|
|
879
|
+
(_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
|
880
|
+
}
|
|
857
881
|
get isEditable() { return true; }
|
|
858
882
|
}
|
|
883
|
+
// Uses the old structure of a chunk of content view frozen for
|
|
884
|
+
// composition to try and find a reasonable DOM location for the given
|
|
885
|
+
// offset.
|
|
886
|
+
function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
887
|
+
if (view instanceof MarkView) {
|
|
888
|
+
for (let child of view.children) {
|
|
889
|
+
let hasComp = contains(child.dom, text);
|
|
890
|
+
let len = hasComp ? text.nodeValue.length : child.length;
|
|
891
|
+
if (pos < len || pos == len && child.getSide() <= 0)
|
|
892
|
+
return hasComp ? scanCompositionTree(pos, side, child, text, enterView, fromText) : enterView(child, pos, side);
|
|
893
|
+
pos -= len;
|
|
894
|
+
}
|
|
895
|
+
return enterView(view, view.length, -1);
|
|
896
|
+
}
|
|
897
|
+
else if (view.dom == text) {
|
|
898
|
+
return fromText(pos, side);
|
|
899
|
+
}
|
|
900
|
+
else {
|
|
901
|
+
return enterView(view, pos, side);
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
905
|
+
if (view instanceof MarkView) {
|
|
906
|
+
for (let child of view.children) {
|
|
907
|
+
let pos = 0, hasComp = contains(child.dom, text);
|
|
908
|
+
if (contains(child.dom, node))
|
|
909
|
+
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
910
|
+
pos += hasComp ? text.nodeValue.length : child.length;
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
else if (view.dom == text) {
|
|
914
|
+
return Math.min(offset, text.nodeValue.length);
|
|
915
|
+
}
|
|
916
|
+
return view.localPosFromDOM(node, offset);
|
|
917
|
+
}
|
|
859
918
|
// These are drawn around uneditable widgets to avoid a number of
|
|
860
919
|
// browser bugs that show up when the cursor is directly next to
|
|
861
920
|
// uneditable inline content.
|
|
@@ -874,6 +933,7 @@ class WidgetBufferView extends ContentView {
|
|
|
874
933
|
if (!this.dom) {
|
|
875
934
|
let dom = document.createElement("img");
|
|
876
935
|
dom.className = "cm-widgetBuffer";
|
|
936
|
+
dom.setAttribute("aria-hidden", "true");
|
|
877
937
|
this.setDOM(dom);
|
|
878
938
|
}
|
|
879
939
|
}
|
|
@@ -882,13 +942,43 @@ class WidgetBufferView extends ContentView {
|
|
|
882
942
|
localPosFromDOM() { return 0; }
|
|
883
943
|
domBoundsAround() { return null; }
|
|
884
944
|
coordsAt(pos) {
|
|
885
|
-
|
|
945
|
+
let imgRect = this.dom.getBoundingClientRect();
|
|
946
|
+
// Since the <img> height doesn't correspond to text height, try
|
|
947
|
+
// to borrow the height from some sibling node.
|
|
948
|
+
let siblingRect = inlineSiblingRect(this, this.side > 0 ? -1 : 1);
|
|
949
|
+
return siblingRect && siblingRect.top < imgRect.bottom && siblingRect.bottom > imgRect.top
|
|
950
|
+
? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect;
|
|
886
951
|
}
|
|
887
952
|
get overrideDOMText() {
|
|
888
953
|
return Text.empty;
|
|
889
954
|
}
|
|
890
955
|
}
|
|
891
956
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
957
|
+
function inlineSiblingRect(view, side) {
|
|
958
|
+
let parent = view.parent, index = parent ? parent.children.indexOf(view) : -1;
|
|
959
|
+
while (parent && index >= 0) {
|
|
960
|
+
if (side < 0 ? index > 0 : index < parent.children.length) {
|
|
961
|
+
let next = parent.children[index + side];
|
|
962
|
+
if (next instanceof TextView) {
|
|
963
|
+
let nextRect = next.coordsAt(side < 0 ? next.length : 0, side);
|
|
964
|
+
if (nextRect)
|
|
965
|
+
return nextRect;
|
|
966
|
+
}
|
|
967
|
+
index += side;
|
|
968
|
+
}
|
|
969
|
+
else if (parent instanceof MarkView && parent.parent) {
|
|
970
|
+
index = parent.parent.children.indexOf(parent) + (side < 0 ? 0 : 1);
|
|
971
|
+
parent = parent.parent;
|
|
972
|
+
}
|
|
973
|
+
else {
|
|
974
|
+
let last = parent.dom.lastChild;
|
|
975
|
+
if (last && last.nodeName == "BR")
|
|
976
|
+
return last.getClientRects()[0];
|
|
977
|
+
break;
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
return undefined;
|
|
981
|
+
}
|
|
892
982
|
function inlineDOMAtPos(dom, children, pos) {
|
|
893
983
|
let i = 0;
|
|
894
984
|
for (let off = 0; i < children.length; i++) {
|
|
@@ -1121,10 +1211,16 @@ class Decoration extends RangeValue {
|
|
|
1121
1211
|
a widget, or simply hides it.
|
|
1122
1212
|
*/
|
|
1123
1213
|
static replace(spec) {
|
|
1124
|
-
let block = !!spec.block;
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1214
|
+
let block = !!spec.block, startSide, endSide;
|
|
1215
|
+
if (spec.isBlockGap) {
|
|
1216
|
+
startSide = -500000000 /* GapStart */;
|
|
1217
|
+
endSide = 400000000 /* GapEnd */;
|
|
1218
|
+
}
|
|
1219
|
+
else {
|
|
1220
|
+
let { start, end } = getInclusive(spec, block);
|
|
1221
|
+
startSide = (start ? (block ? -300000000 /* BlockIncStart */ : -1 /* InlineIncStart */) : 500000000 /* NonIncStart */) - 1;
|
|
1222
|
+
endSide = (end ? (block ? 200000000 /* BlockIncEnd */ : 1 /* InlineIncEnd */) : -600000000 /* NonIncEnd */) + 1;
|
|
1223
|
+
}
|
|
1128
1224
|
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1129
1225
|
}
|
|
1130
1226
|
/**
|
|
@@ -1154,7 +1250,7 @@ Decoration.none = RangeSet.empty;
|
|
|
1154
1250
|
class MarkDecoration extends Decoration {
|
|
1155
1251
|
constructor(spec) {
|
|
1156
1252
|
let { start, end } = getInclusive(spec);
|
|
1157
|
-
super(start ? -1 /* InlineIncStart */ :
|
|
1253
|
+
super(start ? -1 /* InlineIncStart */ : 500000000 /* NonIncStart */, end ? 1 /* InlineIncEnd */ : -600000000 /* NonIncEnd */, null, spec);
|
|
1158
1254
|
this.tagName = spec.tagName || "span";
|
|
1159
1255
|
this.class = spec.class || "";
|
|
1160
1256
|
this.attrs = spec.attributes || null;
|
|
@@ -1335,7 +1431,7 @@ class LineView extends ContentView {
|
|
|
1335
1431
|
let last = this.dom.lastChild;
|
|
1336
1432
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1337
1433
|
last = last.lastChild;
|
|
1338
|
-
if (!last ||
|
|
1434
|
+
if (!last || !this.length ||
|
|
1339
1435
|
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1340
1436
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1341
1437
|
let hack = document.createElement("BR");
|
|
@@ -1384,6 +1480,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1384
1480
|
this.length = length;
|
|
1385
1481
|
this.type = type;
|
|
1386
1482
|
this.breakAfter = 0;
|
|
1483
|
+
this.prevWidget = null;
|
|
1387
1484
|
}
|
|
1388
1485
|
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1389
1486
|
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
@@ -1405,6 +1502,9 @@ class BlockWidgetView extends ContentView {
|
|
|
1405
1502
|
get children() { return noChildren; }
|
|
1406
1503
|
sync() {
|
|
1407
1504
|
if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
|
1505
|
+
if (this.dom && this.prevWidget)
|
|
1506
|
+
this.prevWidget.destroy(this.dom);
|
|
1507
|
+
this.prevWidget = null;
|
|
1408
1508
|
this.setDOM(this.widget.toDOM(this.editorView));
|
|
1409
1509
|
this.dom.contentEditable = "false";
|
|
1410
1510
|
}
|
|
@@ -1418,6 +1518,8 @@ class BlockWidgetView extends ContentView {
|
|
|
1418
1518
|
other.widget.constructor == this.widget.constructor) {
|
|
1419
1519
|
if (!other.widget.eq(this.widget))
|
|
1420
1520
|
this.markDirty(true);
|
|
1521
|
+
if (this.dom && !this.prevWidget)
|
|
1522
|
+
this.prevWidget = this.widget;
|
|
1421
1523
|
this.widget = other.widget;
|
|
1422
1524
|
this.length = other.length;
|
|
1423
1525
|
this.breakAfter = other.breakAfter;
|
|
@@ -2726,7 +2828,12 @@ class DocView extends ContentView {
|
|
|
2726
2828
|
let end = next ? next.from - 1 : this.length;
|
|
2727
2829
|
if (end > pos) {
|
|
2728
2830
|
let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
|
2729
|
-
deco.push(Decoration.replace({
|
|
2831
|
+
deco.push(Decoration.replace({
|
|
2832
|
+
widget: new BlockGapWidget(height),
|
|
2833
|
+
block: true,
|
|
2834
|
+
inclusive: true,
|
|
2835
|
+
isBlockGap: true,
|
|
2836
|
+
}).range(pos, end));
|
|
2730
2837
|
}
|
|
2731
2838
|
if (!next)
|
|
2732
2839
|
break;
|
|
@@ -2845,13 +2952,19 @@ function computeCompositionDeco(view, changes) {
|
|
|
2845
2952
|
else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
|
2846
2953
|
return Decoration.none;
|
|
2847
2954
|
}
|
|
2848
|
-
|
|
2955
|
+
let topView = ContentView.get(node);
|
|
2956
|
+
if (topView instanceof CompositionView)
|
|
2957
|
+
topView = topView.widget.topView;
|
|
2958
|
+
else if (topView)
|
|
2959
|
+
topView.parent = null;
|
|
2960
|
+
return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView) }).range(newFrom, newTo));
|
|
2849
2961
|
}
|
|
2850
2962
|
class CompositionWidget extends WidgetType {
|
|
2851
|
-
constructor(top, text) {
|
|
2963
|
+
constructor(top, text, topView) {
|
|
2852
2964
|
super();
|
|
2853
2965
|
this.top = top;
|
|
2854
2966
|
this.text = text;
|
|
2967
|
+
this.topView = topView;
|
|
2855
2968
|
}
|
|
2856
2969
|
eq(other) { return this.top == other.top && this.text == other.text; }
|
|
2857
2970
|
toDOM() { return this.top; }
|
|
@@ -5191,8 +5304,9 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
5191
5304
|
verticalAlign: "bottom"
|
|
5192
5305
|
},
|
|
5193
5306
|
".cm-widgetBuffer": {
|
|
5194
|
-
verticalAlign: "text-
|
|
5307
|
+
verticalAlign: "text-top",
|
|
5195
5308
|
height: "1em",
|
|
5309
|
+
display: "inline"
|
|
5196
5310
|
},
|
|
5197
5311
|
".cm-placeholder": {
|
|
5198
5312
|
color: "#888",
|
|
@@ -5301,19 +5415,16 @@ class DOMObserver {
|
|
|
5301
5415
|
this.flushSoon();
|
|
5302
5416
|
};
|
|
5303
5417
|
this.onSelectionChange = this.onSelectionChange.bind(this);
|
|
5418
|
+
window.addEventListener("resize", this.onResize = this.onResize.bind(this));
|
|
5304
5419
|
if (typeof ResizeObserver == "function") {
|
|
5305
5420
|
this.resize = new ResizeObserver(() => {
|
|
5306
|
-
if (this.view.docView.lastUpdate < Date.now() - 75
|
|
5307
|
-
this.
|
|
5308
|
-
this.resizeTimeout = -1;
|
|
5309
|
-
this.view.requestMeasure();
|
|
5310
|
-
}, 50);
|
|
5421
|
+
if (this.view.docView.lastUpdate < Date.now() - 75)
|
|
5422
|
+
this.onResize();
|
|
5311
5423
|
});
|
|
5312
5424
|
this.resize.observe(view.scrollDOM);
|
|
5313
5425
|
}
|
|
5314
5426
|
this.start();
|
|
5315
|
-
this.onScroll = this.onScroll.bind(this);
|
|
5316
|
-
window.addEventListener("scroll", this.onScroll);
|
|
5427
|
+
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5317
5428
|
if (typeof IntersectionObserver == "function") {
|
|
5318
5429
|
this.intersection = new IntersectionObserver(entries => {
|
|
5319
5430
|
if (this.parentCheck < 0)
|
|
@@ -5339,6 +5450,13 @@ class DOMObserver {
|
|
|
5339
5450
|
this.flush(false);
|
|
5340
5451
|
this.onScrollChanged(e);
|
|
5341
5452
|
}
|
|
5453
|
+
onResize() {
|
|
5454
|
+
if (this.resizeTimeout < 0)
|
|
5455
|
+
this.resizeTimeout = setTimeout(() => {
|
|
5456
|
+
this.resizeTimeout = -1;
|
|
5457
|
+
this.view.requestMeasure();
|
|
5458
|
+
}, 50);
|
|
5459
|
+
}
|
|
5342
5460
|
updateGaps(gaps) {
|
|
5343
5461
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5344
5462
|
this.gapIntersection.disconnect();
|
|
@@ -5555,6 +5673,7 @@ class DOMObserver {
|
|
|
5555
5673
|
for (let dom of this.scrollTargets)
|
|
5556
5674
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5557
5675
|
window.removeEventListener("scroll", this.onScroll);
|
|
5676
|
+
window.removeEventListener("resize", this.onResize);
|
|
5558
5677
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5559
5678
|
clearTimeout(this.parentCheck);
|
|
5560
5679
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5874,7 +5993,6 @@ class EditorView {
|
|
|
5874
5993
|
this.mountStyles();
|
|
5875
5994
|
this.updateAttrs();
|
|
5876
5995
|
this.updateState = 0 /* Idle */;
|
|
5877
|
-
ensureGlobalHandler();
|
|
5878
5996
|
this.requestMeasure();
|
|
5879
5997
|
if (config.parent)
|
|
5880
5998
|
config.parent.appendChild(this.dom);
|
|
@@ -6711,22 +6829,6 @@ const MaxBidiLine = 4096;
|
|
|
6711
6829
|
function ensureTop(given, view) {
|
|
6712
6830
|
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6713
6831
|
}
|
|
6714
|
-
let resizeDebounce = -1;
|
|
6715
|
-
function ensureGlobalHandler() {
|
|
6716
|
-
window.addEventListener("resize", () => {
|
|
6717
|
-
if (resizeDebounce == -1)
|
|
6718
|
-
resizeDebounce = setTimeout(handleResize, 50);
|
|
6719
|
-
});
|
|
6720
|
-
}
|
|
6721
|
-
function handleResize() {
|
|
6722
|
-
resizeDebounce = -1;
|
|
6723
|
-
let found = document.querySelectorAll(".cm-content");
|
|
6724
|
-
for (let i = 0; i < found.length; i++) {
|
|
6725
|
-
let docView = ContentView.get(found[i]);
|
|
6726
|
-
if (docView)
|
|
6727
|
-
docView.editorView.requestMeasure();
|
|
6728
|
-
}
|
|
6729
|
-
}
|
|
6730
6832
|
const BadMeasure = {};
|
|
6731
6833
|
class CachedOrder {
|
|
6732
6834
|
constructor(from, to, dir, order) {
|