@codemirror/view 6.9.2 → 6.9.3
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 +12 -0
- package/dist/index.cjs +60 -26
- package/dist/index.js +60 -26
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## 6.9.3 (2023-03-21)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Work around a Firefox issue that caused `coordsAtPos` to return rectangles with the full line height on empty lines.
|
|
6
|
+
|
|
7
|
+
Opening a context menu by clicking below the content element but inside the editor now properly shows the browser's menu for editable elements.
|
|
8
|
+
|
|
9
|
+
Fix an issue that broke composition (especially of Chinese IME) after widget decorations.
|
|
10
|
+
|
|
11
|
+
Fix an issue that would cause the cursor to jump around during compositions inside nested mark decorations.
|
|
12
|
+
|
|
1
13
|
## 6.9.2 (2023-03-08)
|
|
2
14
|
|
|
3
15
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -957,8 +957,9 @@ function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
|
957
957
|
}
|
|
958
958
|
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
959
959
|
if (view instanceof MarkView) {
|
|
960
|
+
let pos = 0;
|
|
960
961
|
for (let child of view.children) {
|
|
961
|
-
let
|
|
962
|
+
let hasComp = contains(child.dom, text);
|
|
962
963
|
if (contains(child.dom, node))
|
|
963
964
|
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
964
965
|
pos += hasComp ? text.nodeValue.length : child.length;
|
|
@@ -992,7 +993,7 @@ class WidgetBufferView extends ContentView {
|
|
|
992
993
|
}
|
|
993
994
|
}
|
|
994
995
|
getSide() { return this.side; }
|
|
995
|
-
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
996
|
+
domAtPos(pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); }
|
|
996
997
|
localPosFromDOM() { return 0; }
|
|
997
998
|
domBoundsAround() { return null; }
|
|
998
999
|
coordsAt(pos) {
|
|
@@ -1516,7 +1517,7 @@ class LineView extends ContentView {
|
|
|
1516
1517
|
measureTextSize() {
|
|
1517
1518
|
if (this.children.length == 0 || this.length > 20)
|
|
1518
1519
|
return null;
|
|
1519
|
-
let totalWidth = 0;
|
|
1520
|
+
let totalWidth = 0, textHeight;
|
|
1520
1521
|
for (let child of this.children) {
|
|
1521
1522
|
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1522
1523
|
return null;
|
|
@@ -1524,14 +1525,26 @@ class LineView extends ContentView {
|
|
|
1524
1525
|
if (rects.length != 1)
|
|
1525
1526
|
return null;
|
|
1526
1527
|
totalWidth += rects[0].width;
|
|
1528
|
+
textHeight = rects[0].height;
|
|
1527
1529
|
}
|
|
1528
1530
|
return !totalWidth ? null : {
|
|
1529
1531
|
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1530
|
-
charWidth: totalWidth / this.length
|
|
1532
|
+
charWidth: totalWidth / this.length,
|
|
1533
|
+
textHeight
|
|
1531
1534
|
};
|
|
1532
1535
|
}
|
|
1533
1536
|
coordsAt(pos, side) {
|
|
1534
|
-
|
|
1537
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1538
|
+
// Correct rectangle height for empty lines when the returned
|
|
1539
|
+
// height is larger than the text height.
|
|
1540
|
+
if (!this.children.length && rect && this.parent) {
|
|
1541
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1542
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1543
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1544
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1545
|
+
}
|
|
1546
|
+
}
|
|
1547
|
+
return rect;
|
|
1535
1548
|
}
|
|
1536
1549
|
become(_other) { return false; }
|
|
1537
1550
|
get type() { return exports.BlockType.Text; }
|
|
@@ -2812,7 +2825,7 @@ class DocView extends ContentView {
|
|
|
2812
2825
|
}
|
|
2813
2826
|
}
|
|
2814
2827
|
// If no workable line exists, force a layout of a measurable element
|
|
2815
|
-
let dummy = document.createElement("div"), lineHeight, charWidth;
|
|
2828
|
+
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2816
2829
|
dummy.className = "cm-line";
|
|
2817
2830
|
dummy.style.width = "99999px";
|
|
2818
2831
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
@@ -2821,9 +2834,10 @@ class DocView extends ContentView {
|
|
|
2821
2834
|
let rect = clientRectsFor(dummy.firstChild)[0];
|
|
2822
2835
|
lineHeight = dummy.getBoundingClientRect().height;
|
|
2823
2836
|
charWidth = rect ? rect.width / 27 : 7;
|
|
2837
|
+
textHeight = rect ? rect.height : lineHeight;
|
|
2824
2838
|
dummy.remove();
|
|
2825
2839
|
});
|
|
2826
|
-
return { lineHeight, charWidth };
|
|
2840
|
+
return { lineHeight, charWidth, textHeight };
|
|
2827
2841
|
}
|
|
2828
2842
|
childCursor(pos = this.length) {
|
|
2829
2843
|
// Move back to start of last element when possible, so that
|
|
@@ -2988,22 +3002,32 @@ class CompositionWidget extends WidgetType {
|
|
|
2988
3002
|
ignoreEvent() { return false; }
|
|
2989
3003
|
get customView() { return CompositionView; }
|
|
2990
3004
|
}
|
|
2991
|
-
function nearbyTextNode(
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
node
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3005
|
+
function nearbyTextNode(startNode, startOffset, side) {
|
|
3006
|
+
if (side <= 0)
|
|
3007
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3008
|
+
if (node.nodeType == 3)
|
|
3009
|
+
return node;
|
|
3010
|
+
if (node.nodeType == 1 && offset > 0) {
|
|
3011
|
+
node = node.childNodes[offset - 1];
|
|
3012
|
+
offset = maxOffset(node);
|
|
3013
|
+
}
|
|
3014
|
+
else {
|
|
3015
|
+
break;
|
|
3016
|
+
}
|
|
3002
3017
|
}
|
|
3003
|
-
|
|
3004
|
-
|
|
3018
|
+
if (side >= 0)
|
|
3019
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3020
|
+
if (node.nodeType == 3)
|
|
3021
|
+
return node;
|
|
3022
|
+
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3023
|
+
node = node.childNodes[offset];
|
|
3024
|
+
offset = 0;
|
|
3025
|
+
}
|
|
3026
|
+
else {
|
|
3027
|
+
break;
|
|
3028
|
+
}
|
|
3005
3029
|
}
|
|
3006
|
-
|
|
3030
|
+
return null;
|
|
3007
3031
|
}
|
|
3008
3032
|
function nextToUneditable(node, offset) {
|
|
3009
3033
|
if (node.nodeType != 1)
|
|
@@ -3439,8 +3463,16 @@ class InputState {
|
|
|
3439
3463
|
this.registeredEvents.push(type);
|
|
3440
3464
|
}
|
|
3441
3465
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3442
|
-
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3466
|
+
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3443
3467
|
handleEvent(handlers.mousedown, event);
|
|
3468
|
+
if (!event.defaultPrevented && event.button == 2) {
|
|
3469
|
+
// Make sure the content covers the entire scroller height, in order
|
|
3470
|
+
// to catch a native context menu click below it
|
|
3471
|
+
let start = view.contentDOM.style.minHeight;
|
|
3472
|
+
view.contentDOM.style.minHeight = "100%";
|
|
3473
|
+
setTimeout(() => view.contentDOM.style.minHeight = start, 200);
|
|
3474
|
+
}
|
|
3475
|
+
}
|
|
3444
3476
|
});
|
|
3445
3477
|
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3446
3478
|
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
@@ -4134,8 +4166,9 @@ class HeightOracle {
|
|
|
4134
4166
|
this.lineWrapping = lineWrapping;
|
|
4135
4167
|
this.doc = state.Text.empty;
|
|
4136
4168
|
this.heightSamples = {};
|
|
4137
|
-
this.lineHeight = 14;
|
|
4169
|
+
this.lineHeight = 14; // The height of an entire line (line-height)
|
|
4138
4170
|
this.charWidth = 7;
|
|
4171
|
+
this.textHeight = 14; // The height of the actual font (font-size)
|
|
4139
4172
|
this.lineLength = 30;
|
|
4140
4173
|
// Used to track, during updateHeight, if any actual heights changed
|
|
4141
4174
|
this.heightChanged = false;
|
|
@@ -4170,12 +4203,13 @@ class HeightOracle {
|
|
|
4170
4203
|
}
|
|
4171
4204
|
return newHeight;
|
|
4172
4205
|
}
|
|
4173
|
-
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4206
|
+
refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
|
|
4174
4207
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4175
4208
|
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4176
4209
|
this.lineWrapping = lineWrapping;
|
|
4177
4210
|
this.lineHeight = lineHeight;
|
|
4178
4211
|
this.charWidth = charWidth;
|
|
4212
|
+
this.textHeight = textHeight;
|
|
4179
4213
|
this.lineLength = lineLength;
|
|
4180
4214
|
if (changed) {
|
|
4181
4215
|
this.heightSamples = {};
|
|
@@ -5023,8 +5057,8 @@ class ViewState {
|
|
|
5023
5057
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
5024
5058
|
refresh = true;
|
|
5025
5059
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
5026
|
-
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
5027
|
-
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
5060
|
+
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
|
|
5061
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
|
|
5028
5062
|
if (refresh) {
|
|
5029
5063
|
view.docView.minWidth = 0;
|
|
5030
5064
|
result |= 8 /* UpdateFlag.Geometry */;
|
package/dist/index.js
CHANGED
|
@@ -953,8 +953,9 @@ function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
|
953
953
|
}
|
|
954
954
|
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
955
955
|
if (view instanceof MarkView) {
|
|
956
|
+
let pos = 0;
|
|
956
957
|
for (let child of view.children) {
|
|
957
|
-
let
|
|
958
|
+
let hasComp = contains(child.dom, text);
|
|
958
959
|
if (contains(child.dom, node))
|
|
959
960
|
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
960
961
|
pos += hasComp ? text.nodeValue.length : child.length;
|
|
@@ -988,7 +989,7 @@ class WidgetBufferView extends ContentView {
|
|
|
988
989
|
}
|
|
989
990
|
}
|
|
990
991
|
getSide() { return this.side; }
|
|
991
|
-
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
992
|
+
domAtPos(pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); }
|
|
992
993
|
localPosFromDOM() { return 0; }
|
|
993
994
|
domBoundsAround() { return null; }
|
|
994
995
|
coordsAt(pos) {
|
|
@@ -1511,7 +1512,7 @@ class LineView extends ContentView {
|
|
|
1511
1512
|
measureTextSize() {
|
|
1512
1513
|
if (this.children.length == 0 || this.length > 20)
|
|
1513
1514
|
return null;
|
|
1514
|
-
let totalWidth = 0;
|
|
1515
|
+
let totalWidth = 0, textHeight;
|
|
1515
1516
|
for (let child of this.children) {
|
|
1516
1517
|
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1517
1518
|
return null;
|
|
@@ -1519,14 +1520,26 @@ class LineView extends ContentView {
|
|
|
1519
1520
|
if (rects.length != 1)
|
|
1520
1521
|
return null;
|
|
1521
1522
|
totalWidth += rects[0].width;
|
|
1523
|
+
textHeight = rects[0].height;
|
|
1522
1524
|
}
|
|
1523
1525
|
return !totalWidth ? null : {
|
|
1524
1526
|
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1525
|
-
charWidth: totalWidth / this.length
|
|
1527
|
+
charWidth: totalWidth / this.length,
|
|
1528
|
+
textHeight
|
|
1526
1529
|
};
|
|
1527
1530
|
}
|
|
1528
1531
|
coordsAt(pos, side) {
|
|
1529
|
-
|
|
1532
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1533
|
+
// Correct rectangle height for empty lines when the returned
|
|
1534
|
+
// height is larger than the text height.
|
|
1535
|
+
if (!this.children.length && rect && this.parent) {
|
|
1536
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1537
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1538
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1539
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1542
|
+
return rect;
|
|
1530
1543
|
}
|
|
1531
1544
|
become(_other) { return false; }
|
|
1532
1545
|
get type() { return BlockType.Text; }
|
|
@@ -2806,7 +2819,7 @@ class DocView extends ContentView {
|
|
|
2806
2819
|
}
|
|
2807
2820
|
}
|
|
2808
2821
|
// If no workable line exists, force a layout of a measurable element
|
|
2809
|
-
let dummy = document.createElement("div"), lineHeight, charWidth;
|
|
2822
|
+
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2810
2823
|
dummy.className = "cm-line";
|
|
2811
2824
|
dummy.style.width = "99999px";
|
|
2812
2825
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
@@ -2815,9 +2828,10 @@ class DocView extends ContentView {
|
|
|
2815
2828
|
let rect = clientRectsFor(dummy.firstChild)[0];
|
|
2816
2829
|
lineHeight = dummy.getBoundingClientRect().height;
|
|
2817
2830
|
charWidth = rect ? rect.width / 27 : 7;
|
|
2831
|
+
textHeight = rect ? rect.height : lineHeight;
|
|
2818
2832
|
dummy.remove();
|
|
2819
2833
|
});
|
|
2820
|
-
return { lineHeight, charWidth };
|
|
2834
|
+
return { lineHeight, charWidth, textHeight };
|
|
2821
2835
|
}
|
|
2822
2836
|
childCursor(pos = this.length) {
|
|
2823
2837
|
// Move back to start of last element when possible, so that
|
|
@@ -2982,22 +2996,32 @@ class CompositionWidget extends WidgetType {
|
|
|
2982
2996
|
ignoreEvent() { return false; }
|
|
2983
2997
|
get customView() { return CompositionView; }
|
|
2984
2998
|
}
|
|
2985
|
-
function nearbyTextNode(
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
node
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2999
|
+
function nearbyTextNode(startNode, startOffset, side) {
|
|
3000
|
+
if (side <= 0)
|
|
3001
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3002
|
+
if (node.nodeType == 3)
|
|
3003
|
+
return node;
|
|
3004
|
+
if (node.nodeType == 1 && offset > 0) {
|
|
3005
|
+
node = node.childNodes[offset - 1];
|
|
3006
|
+
offset = maxOffset(node);
|
|
3007
|
+
}
|
|
3008
|
+
else {
|
|
3009
|
+
break;
|
|
3010
|
+
}
|
|
2996
3011
|
}
|
|
2997
|
-
|
|
2998
|
-
|
|
3012
|
+
if (side >= 0)
|
|
3013
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3014
|
+
if (node.nodeType == 3)
|
|
3015
|
+
return node;
|
|
3016
|
+
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3017
|
+
node = node.childNodes[offset];
|
|
3018
|
+
offset = 0;
|
|
3019
|
+
}
|
|
3020
|
+
else {
|
|
3021
|
+
break;
|
|
3022
|
+
}
|
|
2999
3023
|
}
|
|
3000
|
-
|
|
3024
|
+
return null;
|
|
3001
3025
|
}
|
|
3002
3026
|
function nextToUneditable(node, offset) {
|
|
3003
3027
|
if (node.nodeType != 1)
|
|
@@ -3433,8 +3457,16 @@ class InputState {
|
|
|
3433
3457
|
this.registeredEvents.push(type);
|
|
3434
3458
|
}
|
|
3435
3459
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3436
|
-
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3460
|
+
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3437
3461
|
handleEvent(handlers.mousedown, event);
|
|
3462
|
+
if (!event.defaultPrevented && event.button == 2) {
|
|
3463
|
+
// Make sure the content covers the entire scroller height, in order
|
|
3464
|
+
// to catch a native context menu click below it
|
|
3465
|
+
let start = view.contentDOM.style.minHeight;
|
|
3466
|
+
view.contentDOM.style.minHeight = "100%";
|
|
3467
|
+
setTimeout(() => view.contentDOM.style.minHeight = start, 200);
|
|
3468
|
+
}
|
|
3469
|
+
}
|
|
3438
3470
|
});
|
|
3439
3471
|
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3440
3472
|
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
@@ -4128,8 +4160,9 @@ class HeightOracle {
|
|
|
4128
4160
|
this.lineWrapping = lineWrapping;
|
|
4129
4161
|
this.doc = Text.empty;
|
|
4130
4162
|
this.heightSamples = {};
|
|
4131
|
-
this.lineHeight = 14;
|
|
4163
|
+
this.lineHeight = 14; // The height of an entire line (line-height)
|
|
4132
4164
|
this.charWidth = 7;
|
|
4165
|
+
this.textHeight = 14; // The height of the actual font (font-size)
|
|
4133
4166
|
this.lineLength = 30;
|
|
4134
4167
|
// Used to track, during updateHeight, if any actual heights changed
|
|
4135
4168
|
this.heightChanged = false;
|
|
@@ -4164,12 +4197,13 @@ class HeightOracle {
|
|
|
4164
4197
|
}
|
|
4165
4198
|
return newHeight;
|
|
4166
4199
|
}
|
|
4167
|
-
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4200
|
+
refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
|
|
4168
4201
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4169
4202
|
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4170
4203
|
this.lineWrapping = lineWrapping;
|
|
4171
4204
|
this.lineHeight = lineHeight;
|
|
4172
4205
|
this.charWidth = charWidth;
|
|
4206
|
+
this.textHeight = textHeight;
|
|
4173
4207
|
this.lineLength = lineLength;
|
|
4174
4208
|
if (changed) {
|
|
4175
4209
|
this.heightSamples = {};
|
|
@@ -5016,8 +5050,8 @@ class ViewState {
|
|
|
5016
5050
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
5017
5051
|
refresh = true;
|
|
5018
5052
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
5019
|
-
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
5020
|
-
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
5053
|
+
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
|
|
5054
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
|
|
5021
5055
|
if (refresh) {
|
|
5022
5056
|
view.docView.minWidth = 0;
|
|
5023
5057
|
result |= 8 /* UpdateFlag.Geometry */;
|