@codemirror/view 6.9.2 → 6.9.4
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 +30 -0
- package/dist/index.cjs +115 -52
- package/dist/index.js +115 -52
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,33 @@
|
|
|
1
|
+
## 6.9.4 (2023-04-11)
|
|
2
|
+
|
|
3
|
+
### Bug fixes
|
|
4
|
+
|
|
5
|
+
Make the editor scroll while dragging a selection near its sides, even if the cursor isn't outside the scrollable element.
|
|
6
|
+
|
|
7
|
+
Fix a bug that interrupted composition after widgets in some circumstances on Firefox.
|
|
8
|
+
|
|
9
|
+
Make sure the last change in a composition has its user event set to `input.type.compose`, even if the `compositionend` event fires before the changes are applied.
|
|
10
|
+
|
|
11
|
+
Make it possible to remove additional selection ranges by clicking on them with ctrl/cmd held, even if they aren't cursors.
|
|
12
|
+
|
|
13
|
+
Keep widget buffers between widgets and compositions, since removing them confuses IME on macOS Firefox.
|
|
14
|
+
|
|
15
|
+
Fix a bug where, for DOM changes that put the selection in the middle of the changed range, the editor incorrectly set its selection state.
|
|
16
|
+
|
|
17
|
+
Fix a bug where `coordsAtPos` could return a coordinates before the line break when querying a line-wrapped position with a positive `side`.
|
|
18
|
+
|
|
19
|
+
## 6.9.3 (2023-03-21)
|
|
20
|
+
|
|
21
|
+
### Bug fixes
|
|
22
|
+
|
|
23
|
+
Work around a Firefox issue that caused `coordsAtPos` to return rectangles with the full line height on empty lines.
|
|
24
|
+
|
|
25
|
+
Opening a context menu by clicking below the content element but inside the editor now properly shows the browser's menu for editable elements.
|
|
26
|
+
|
|
27
|
+
Fix an issue that broke composition (especially of Chinese IME) after widget decorations.
|
|
28
|
+
|
|
29
|
+
Fix an issue that would cause the cursor to jump around during compositions inside nested mark decorations.
|
|
30
|
+
|
|
1
31
|
## 6.9.2 (2023-03-08)
|
|
2
32
|
|
|
3
33
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -520,6 +520,7 @@ class ContentView {
|
|
|
520
520
|
static get(node) { return node.cmView; }
|
|
521
521
|
get isEditable() { return true; }
|
|
522
522
|
get isWidget() { return false; }
|
|
523
|
+
get isHidden() { return false; }
|
|
523
524
|
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
524
525
|
return false;
|
|
525
526
|
}
|
|
@@ -857,7 +858,7 @@ class WidgetView extends ContentView {
|
|
|
857
858
|
become(other) {
|
|
858
859
|
if (other.length == this.length && other instanceof WidgetView && other.side == this.side) {
|
|
859
860
|
if (this.widget.constructor == other.widget.constructor) {
|
|
860
|
-
if (!this.widget.
|
|
861
|
+
if (!this.widget.compare(other.widget))
|
|
861
862
|
this.markDirty(true);
|
|
862
863
|
if (this.dom && !this.prevWidget)
|
|
863
864
|
this.prevWidget = this.widget;
|
|
@@ -879,7 +880,9 @@ class WidgetView extends ContentView {
|
|
|
879
880
|
return text ? text.slice(start, start + this.length) : state.Text.empty;
|
|
880
881
|
}
|
|
881
882
|
domAtPos(pos) {
|
|
882
|
-
return pos == 0
|
|
883
|
+
return (this.length ? pos == 0 : this.side > 0)
|
|
884
|
+
? DOMPos.before(this.dom)
|
|
885
|
+
: DOMPos.after(this.dom, pos == this.length);
|
|
883
886
|
}
|
|
884
887
|
domBoundsAround() { return null; }
|
|
885
888
|
coordsAt(pos, side) {
|
|
@@ -895,6 +898,7 @@ class WidgetView extends ContentView {
|
|
|
895
898
|
}
|
|
896
899
|
get isEditable() { return false; }
|
|
897
900
|
get isWidget() { return true; }
|
|
901
|
+
get isHidden() { return this.widget.isHidden; }
|
|
898
902
|
destroy() {
|
|
899
903
|
super.destroy();
|
|
900
904
|
if (this.dom)
|
|
@@ -957,8 +961,9 @@ function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
|
957
961
|
}
|
|
958
962
|
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
959
963
|
if (view instanceof MarkView) {
|
|
964
|
+
let pos = 0;
|
|
960
965
|
for (let child of view.children) {
|
|
961
|
-
let
|
|
966
|
+
let hasComp = contains(child.dom, text);
|
|
962
967
|
if (contains(child.dom, node))
|
|
963
968
|
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
964
969
|
pos += hasComp ? text.nodeValue.length : child.length;
|
|
@@ -992,7 +997,7 @@ class WidgetBufferView extends ContentView {
|
|
|
992
997
|
}
|
|
993
998
|
}
|
|
994
999
|
getSide() { return this.side; }
|
|
995
|
-
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
1000
|
+
domAtPos(pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); }
|
|
996
1001
|
localPosFromDOM() { return 0; }
|
|
997
1002
|
domBoundsAround() { return null; }
|
|
998
1003
|
coordsAt(pos) {
|
|
@@ -1006,6 +1011,7 @@ class WidgetBufferView extends ContentView {
|
|
|
1006
1011
|
get overrideDOMText() {
|
|
1007
1012
|
return state.Text.empty;
|
|
1008
1013
|
}
|
|
1014
|
+
get isHidden() { return true; }
|
|
1009
1015
|
}
|
|
1010
1016
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
1011
1017
|
function inlineSiblingRect(view, side) {
|
|
@@ -1079,7 +1085,8 @@ function coordsInChildren(view, pos, side) {
|
|
|
1079
1085
|
if (child.children.length) {
|
|
1080
1086
|
scan(child, pos - off);
|
|
1081
1087
|
}
|
|
1082
|
-
else if (!after
|
|
1088
|
+
else if ((!after || after instanceof WidgetBufferView && side > 0) &&
|
|
1089
|
+
(end > pos || off == end && child.getSide() > 0)) {
|
|
1083
1090
|
after = child;
|
|
1084
1091
|
afterPos = pos - off;
|
|
1085
1092
|
}
|
|
@@ -1193,6 +1200,10 @@ class WidgetType {
|
|
|
1193
1200
|
*/
|
|
1194
1201
|
get customView() { return null; }
|
|
1195
1202
|
/**
|
|
1203
|
+
@internal
|
|
1204
|
+
*/
|
|
1205
|
+
get isHidden() { return false; }
|
|
1206
|
+
/**
|
|
1196
1207
|
This is called when the an instance of the widget is removed
|
|
1197
1208
|
from the editor view.
|
|
1198
1209
|
*/
|
|
@@ -1516,7 +1527,7 @@ class LineView extends ContentView {
|
|
|
1516
1527
|
measureTextSize() {
|
|
1517
1528
|
if (this.children.length == 0 || this.length > 20)
|
|
1518
1529
|
return null;
|
|
1519
|
-
let totalWidth = 0;
|
|
1530
|
+
let totalWidth = 0, textHeight;
|
|
1520
1531
|
for (let child of this.children) {
|
|
1521
1532
|
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1522
1533
|
return null;
|
|
@@ -1524,14 +1535,26 @@ class LineView extends ContentView {
|
|
|
1524
1535
|
if (rects.length != 1)
|
|
1525
1536
|
return null;
|
|
1526
1537
|
totalWidth += rects[0].width;
|
|
1538
|
+
textHeight = rects[0].height;
|
|
1527
1539
|
}
|
|
1528
1540
|
return !totalWidth ? null : {
|
|
1529
1541
|
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1530
|
-
charWidth: totalWidth / this.length
|
|
1542
|
+
charWidth: totalWidth / this.length,
|
|
1543
|
+
textHeight
|
|
1531
1544
|
};
|
|
1532
1545
|
}
|
|
1533
1546
|
coordsAt(pos, side) {
|
|
1534
|
-
|
|
1547
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1548
|
+
// Correct rectangle height for empty lines when the returned
|
|
1549
|
+
// height is larger than the text height.
|
|
1550
|
+
if (!this.children.length && rect && this.parent) {
|
|
1551
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1552
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1553
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1554
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1555
|
+
}
|
|
1556
|
+
}
|
|
1557
|
+
return rect;
|
|
1535
1558
|
}
|
|
1536
1559
|
become(_other) { return false; }
|
|
1537
1560
|
get type() { return exports.BlockType.Text; }
|
|
@@ -1592,7 +1615,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1592
1615
|
become(other) {
|
|
1593
1616
|
if (other instanceof BlockWidgetView && other.type == this.type &&
|
|
1594
1617
|
other.widget.constructor == this.widget.constructor) {
|
|
1595
|
-
if (!other.widget.
|
|
1618
|
+
if (!other.widget.compare(this.widget))
|
|
1596
1619
|
this.markDirty(true);
|
|
1597
1620
|
if (this.dom && !this.prevWidget)
|
|
1598
1621
|
this.prevWidget = this.widget;
|
|
@@ -1723,10 +1746,11 @@ class ContentBuilder {
|
|
|
1723
1746
|
}
|
|
1724
1747
|
else {
|
|
1725
1748
|
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
1726
|
-
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
|
|
1749
|
+
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
|
|
1750
|
+
(from < to || deco.startSide > 0);
|
|
1727
1751
|
let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
|
|
1728
1752
|
let line = this.getLine();
|
|
1729
|
-
if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
|
|
1753
|
+
if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
|
|
1730
1754
|
this.pendingBuffer = 0 /* Buf.No */;
|
|
1731
1755
|
this.flushBuffer(active);
|
|
1732
1756
|
if (cursorBefore) {
|
|
@@ -1780,6 +1804,7 @@ class NullWidget extends WidgetType {
|
|
|
1780
1804
|
eq(other) { return other.tag == this.tag; }
|
|
1781
1805
|
toDOM() { return document.createElement(this.tag); }
|
|
1782
1806
|
updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
|
|
1807
|
+
get isHidden() { return true; }
|
|
1783
1808
|
}
|
|
1784
1809
|
|
|
1785
1810
|
const clickAddsSelectionRange = state.Facet.define();
|
|
@@ -2633,7 +2658,7 @@ class DocView extends ContentView {
|
|
|
2633
2658
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2634
2659
|
// Always reset on Firefox when next to an uneditable node to
|
|
2635
2660
|
// avoid invisible cursor bugs (#111)
|
|
2636
|
-
if (browser.gecko && main.empty && betweenUneditable(anchor)) {
|
|
2661
|
+
if (browser.gecko && main.empty && !this.compositionDeco.size && betweenUneditable(anchor)) {
|
|
2637
2662
|
let dummy = document.createTextNode("");
|
|
2638
2663
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
2639
2664
|
anchor = head = new DOMPos(dummy, 0);
|
|
@@ -2812,7 +2837,7 @@ class DocView extends ContentView {
|
|
|
2812
2837
|
}
|
|
2813
2838
|
}
|
|
2814
2839
|
// If no workable line exists, force a layout of a measurable element
|
|
2815
|
-
let dummy = document.createElement("div"), lineHeight, charWidth;
|
|
2840
|
+
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2816
2841
|
dummy.className = "cm-line";
|
|
2817
2842
|
dummy.style.width = "99999px";
|
|
2818
2843
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
@@ -2821,9 +2846,10 @@ class DocView extends ContentView {
|
|
|
2821
2846
|
let rect = clientRectsFor(dummy.firstChild)[0];
|
|
2822
2847
|
lineHeight = dummy.getBoundingClientRect().height;
|
|
2823
2848
|
charWidth = rect ? rect.width / 27 : 7;
|
|
2849
|
+
textHeight = rect ? rect.height : lineHeight;
|
|
2824
2850
|
dummy.remove();
|
|
2825
2851
|
});
|
|
2826
|
-
return { lineHeight, charWidth };
|
|
2852
|
+
return { lineHeight, charWidth, textHeight };
|
|
2827
2853
|
}
|
|
2828
2854
|
childCursor(pos = this.length) {
|
|
2829
2855
|
// Move back to start of last element when possible, so that
|
|
@@ -2988,22 +3014,32 @@ class CompositionWidget extends WidgetType {
|
|
|
2988
3014
|
ignoreEvent() { return false; }
|
|
2989
3015
|
get customView() { return CompositionView; }
|
|
2990
3016
|
}
|
|
2991
|
-
function nearbyTextNode(
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
node
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3017
|
+
function nearbyTextNode(startNode, startOffset, side) {
|
|
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 > 0) {
|
|
3023
|
+
node = node.childNodes[offset - 1];
|
|
3024
|
+
offset = maxOffset(node);
|
|
3025
|
+
}
|
|
3026
|
+
else {
|
|
3027
|
+
break;
|
|
3028
|
+
}
|
|
3002
3029
|
}
|
|
3003
|
-
|
|
3004
|
-
|
|
3030
|
+
if (side >= 0)
|
|
3031
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3032
|
+
if (node.nodeType == 3)
|
|
3033
|
+
return node;
|
|
3034
|
+
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3035
|
+
node = node.childNodes[offset];
|
|
3036
|
+
offset = 0;
|
|
3037
|
+
}
|
|
3038
|
+
else {
|
|
3039
|
+
break;
|
|
3040
|
+
}
|
|
3005
3041
|
}
|
|
3006
|
-
|
|
3042
|
+
return null;
|
|
3007
3043
|
}
|
|
3008
3044
|
function nextToUneditable(node, offset) {
|
|
3009
3045
|
if (node.nodeType != 1)
|
|
@@ -3416,7 +3452,15 @@ class InputState {
|
|
|
3416
3452
|
// first, false means first has already been marked for this
|
|
3417
3453
|
// composition)
|
|
3418
3454
|
this.compositionFirstChange = null;
|
|
3455
|
+
// End time of the previous composition
|
|
3419
3456
|
this.compositionEndedAt = 0;
|
|
3457
|
+
// Used in a kludge to detect when an Enter keypress should be
|
|
3458
|
+
// considered part of the composition on Safari, which fires events
|
|
3459
|
+
// in the wrong order
|
|
3460
|
+
this.compositionPendingKey = false;
|
|
3461
|
+
// Used to categorize changes as part of a composition, even when
|
|
3462
|
+
// the mutation events fire shortly after the compositionend event
|
|
3463
|
+
this.compositionPendingChange = false;
|
|
3420
3464
|
this.mouseSelection = null;
|
|
3421
3465
|
let handleEvent = (handler, event) => {
|
|
3422
3466
|
if (this.ignoreDuringComposition(event))
|
|
@@ -3439,8 +3483,16 @@ class InputState {
|
|
|
3439
3483
|
this.registeredEvents.push(type);
|
|
3440
3484
|
}
|
|
3441
3485
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3442
|
-
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3486
|
+
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3443
3487
|
handleEvent(handlers.mousedown, event);
|
|
3488
|
+
if (!event.defaultPrevented && event.button == 2) {
|
|
3489
|
+
// Make sure the content covers the entire scroller height, in order
|
|
3490
|
+
// to catch a native context menu click below it
|
|
3491
|
+
let start = view.contentDOM.style.minHeight;
|
|
3492
|
+
view.contentDOM.style.minHeight = "100%";
|
|
3493
|
+
setTimeout(() => view.contentDOM.style.minHeight = start, 200);
|
|
3494
|
+
}
|
|
3495
|
+
}
|
|
3444
3496
|
});
|
|
3445
3497
|
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3446
3498
|
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
@@ -3565,8 +3617,8 @@ class InputState {
|
|
|
3565
3617
|
// compositionend and keydown events are sometimes emitted in the
|
|
3566
3618
|
// wrong order. The key event should still be ignored, even when
|
|
3567
3619
|
// it happens after the compositionend event.
|
|
3568
|
-
if (browser.safari && !browser.ios && Date.now() - this.compositionEndedAt < 100) {
|
|
3569
|
-
this.
|
|
3620
|
+
if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
|
|
3621
|
+
this.compositionPendingKey = false;
|
|
3570
3622
|
return true;
|
|
3571
3623
|
}
|
|
3572
3624
|
return false;
|
|
@@ -3598,8 +3650,9 @@ const PendingKeys = [
|
|
|
3598
3650
|
const EmacsyPendingKeys = "dthko";
|
|
3599
3651
|
// Key codes for modifier keys
|
|
3600
3652
|
const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
|
3653
|
+
const dragScrollMargin = 6;
|
|
3601
3654
|
function dragScrollSpeed(dist) {
|
|
3602
|
-
return dist * 0.7 + 8;
|
|
3655
|
+
return Math.max(0, dist) * 0.7 + 8;
|
|
3603
3656
|
}
|
|
3604
3657
|
class MouseSelection {
|
|
3605
3658
|
constructor(view, startEvent, style, mustSelect) {
|
|
@@ -3636,13 +3689,13 @@ class MouseSelection {
|
|
|
3636
3689
|
let sx = 0, sy = 0;
|
|
3637
3690
|
let rect = ((_a = this.scrollParent) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect())
|
|
3638
3691
|
|| { left: 0, top: 0, right: this.view.win.innerWidth, bottom: this.view.win.innerHeight };
|
|
3639
|
-
if (event.clientX <= rect.left)
|
|
3692
|
+
if (event.clientX <= rect.left + dragScrollMargin)
|
|
3640
3693
|
sx = -dragScrollSpeed(rect.left - event.clientX);
|
|
3641
|
-
else if (event.clientX >= rect.right)
|
|
3694
|
+
else if (event.clientX >= rect.right - dragScrollMargin)
|
|
3642
3695
|
sx = dragScrollSpeed(event.clientX - rect.right);
|
|
3643
|
-
if (event.clientY <= rect.top)
|
|
3696
|
+
if (event.clientY <= rect.top + dragScrollMargin)
|
|
3644
3697
|
sy = -dragScrollSpeed(rect.top - event.clientY);
|
|
3645
|
-
else if (event.clientY >= rect.bottom)
|
|
3698
|
+
else if (event.clientY >= rect.bottom - dragScrollMargin)
|
|
3646
3699
|
sy = dragScrollSpeed(event.clientY - rect.bottom);
|
|
3647
3700
|
this.setScrollSpeed(sx, sy);
|
|
3648
3701
|
}
|
|
@@ -3889,7 +3942,7 @@ function basicMouseSelection(view, event) {
|
|
|
3889
3942
|
}
|
|
3890
3943
|
},
|
|
3891
3944
|
get(event, extend, multiple) {
|
|
3892
|
-
let cur = queryPos(view, event);
|
|
3945
|
+
let cur = queryPos(view, event), removed;
|
|
3893
3946
|
let range = rangeForClick(view, cur.pos, cur.bias, type);
|
|
3894
3947
|
if (start.pos != cur.pos && !extend) {
|
|
3895
3948
|
let startRange = rangeForClick(view, start.pos, start.bias, type);
|
|
@@ -3898,8 +3951,8 @@ function basicMouseSelection(view, event) {
|
|
|
3898
3951
|
}
|
|
3899
3952
|
if (extend)
|
|
3900
3953
|
return startSel.replaceRange(startSel.main.extend(range.from, range.to));
|
|
3901
|
-
else if (multiple && startSel.ranges.length > 1 &&
|
|
3902
|
-
return
|
|
3954
|
+
else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
|
|
3955
|
+
return removed;
|
|
3903
3956
|
else if (multiple)
|
|
3904
3957
|
return startSel.addRange(range);
|
|
3905
3958
|
else
|
|
@@ -3907,11 +3960,13 @@ function basicMouseSelection(view, event) {
|
|
|
3907
3960
|
}
|
|
3908
3961
|
};
|
|
3909
3962
|
}
|
|
3910
|
-
function
|
|
3911
|
-
for (let i = 0
|
|
3912
|
-
|
|
3963
|
+
function removeRangeAround(sel, pos) {
|
|
3964
|
+
for (let i = 0; i < sel.ranges.length; i++) {
|
|
3965
|
+
let { from, to } = sel.ranges[i];
|
|
3966
|
+
if (from <= pos && to >= pos)
|
|
3913
3967
|
return state.EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
|
|
3914
3968
|
}
|
|
3969
|
+
return null;
|
|
3915
3970
|
}
|
|
3916
3971
|
handlers.dragstart = (view, event) => {
|
|
3917
3972
|
let { selection: { main } } = view.state;
|
|
@@ -4088,6 +4143,8 @@ handlers.compositionstart = handlers.compositionupdate = view => {
|
|
|
4088
4143
|
handlers.compositionend = view => {
|
|
4089
4144
|
view.inputState.composing = -1;
|
|
4090
4145
|
view.inputState.compositionEndedAt = Date.now();
|
|
4146
|
+
view.inputState.compositionPendingKey = true;
|
|
4147
|
+
view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
|
|
4091
4148
|
view.inputState.compositionFirstChange = null;
|
|
4092
4149
|
if (browser.chrome && browser.android)
|
|
4093
4150
|
view.observer.flushSoon();
|
|
@@ -4134,8 +4191,9 @@ class HeightOracle {
|
|
|
4134
4191
|
this.lineWrapping = lineWrapping;
|
|
4135
4192
|
this.doc = state.Text.empty;
|
|
4136
4193
|
this.heightSamples = {};
|
|
4137
|
-
this.lineHeight = 14;
|
|
4194
|
+
this.lineHeight = 14; // The height of an entire line (line-height)
|
|
4138
4195
|
this.charWidth = 7;
|
|
4196
|
+
this.textHeight = 14; // The height of the actual font (font-size)
|
|
4139
4197
|
this.lineLength = 30;
|
|
4140
4198
|
// Used to track, during updateHeight, if any actual heights changed
|
|
4141
4199
|
this.heightChanged = false;
|
|
@@ -4170,12 +4228,13 @@ class HeightOracle {
|
|
|
4170
4228
|
}
|
|
4171
4229
|
return newHeight;
|
|
4172
4230
|
}
|
|
4173
|
-
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4231
|
+
refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
|
|
4174
4232
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4175
4233
|
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4176
4234
|
this.lineWrapping = lineWrapping;
|
|
4177
4235
|
this.lineHeight = lineHeight;
|
|
4178
4236
|
this.charWidth = charWidth;
|
|
4237
|
+
this.textHeight = textHeight;
|
|
4179
4238
|
this.lineLength = lineLength;
|
|
4180
4239
|
if (changed) {
|
|
4181
4240
|
this.heightSamples = {};
|
|
@@ -5023,8 +5082,8 @@ class ViewState {
|
|
|
5023
5082
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
5024
5083
|
refresh = true;
|
|
5025
5084
|
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);
|
|
5085
|
+
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
|
|
5086
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
|
|
5028
5087
|
if (refresh) {
|
|
5029
5088
|
view.docView.minWidth = 0;
|
|
5030
5089
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
@@ -5741,8 +5800,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5741
5800
|
}
|
|
5742
5801
|
else {
|
|
5743
5802
|
let changes = startState.changes(change);
|
|
5744
|
-
let mainSel = newSel &&
|
|
5745
|
-
? newSel.main : undefined;
|
|
5803
|
+
let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
|
|
5746
5804
|
// Try to apply a composition change to all cursors
|
|
5747
5805
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5748
5806
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
@@ -5776,7 +5834,9 @@ function applyDOMChange(view, domChange) {
|
|
|
5776
5834
|
}
|
|
5777
5835
|
}
|
|
5778
5836
|
let userEvent = "input.type";
|
|
5779
|
-
if (view.composing
|
|
5837
|
+
if (view.composing ||
|
|
5838
|
+
view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
|
|
5839
|
+
view.inputState.compositionPendingChange = false;
|
|
5780
5840
|
userEvent += ".compose";
|
|
5781
5841
|
if (view.inputState.compositionFirstChange) {
|
|
5782
5842
|
userEvent += ".start";
|
|
@@ -6152,10 +6212,13 @@ class DOMObserver {
|
|
|
6152
6212
|
}
|
|
6153
6213
|
this.flush();
|
|
6154
6214
|
}
|
|
6155
|
-
|
|
6156
|
-
let records = this.queue;
|
|
6215
|
+
pendingRecords() {
|
|
6157
6216
|
for (let mut of this.observer.takeRecords())
|
|
6158
|
-
|
|
6217
|
+
this.queue.push(mut);
|
|
6218
|
+
return this.queue;
|
|
6219
|
+
}
|
|
6220
|
+
processRecords() {
|
|
6221
|
+
let records = this.pendingRecords();
|
|
6159
6222
|
if (records.length)
|
|
6160
6223
|
this.queue = [];
|
|
6161
6224
|
let from = -1, to = -1, typeOver = false;
|
package/dist/index.js
CHANGED
|
@@ -516,6 +516,7 @@ class ContentView {
|
|
|
516
516
|
static get(node) { return node.cmView; }
|
|
517
517
|
get isEditable() { return true; }
|
|
518
518
|
get isWidget() { return false; }
|
|
519
|
+
get isHidden() { return false; }
|
|
519
520
|
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
520
521
|
return false;
|
|
521
522
|
}
|
|
@@ -853,7 +854,7 @@ class WidgetView extends ContentView {
|
|
|
853
854
|
become(other) {
|
|
854
855
|
if (other.length == this.length && other instanceof WidgetView && other.side == this.side) {
|
|
855
856
|
if (this.widget.constructor == other.widget.constructor) {
|
|
856
|
-
if (!this.widget.
|
|
857
|
+
if (!this.widget.compare(other.widget))
|
|
857
858
|
this.markDirty(true);
|
|
858
859
|
if (this.dom && !this.prevWidget)
|
|
859
860
|
this.prevWidget = this.widget;
|
|
@@ -875,7 +876,9 @@ class WidgetView extends ContentView {
|
|
|
875
876
|
return text ? text.slice(start, start + this.length) : Text.empty;
|
|
876
877
|
}
|
|
877
878
|
domAtPos(pos) {
|
|
878
|
-
return pos == 0
|
|
879
|
+
return (this.length ? pos == 0 : this.side > 0)
|
|
880
|
+
? DOMPos.before(this.dom)
|
|
881
|
+
: DOMPos.after(this.dom, pos == this.length);
|
|
879
882
|
}
|
|
880
883
|
domBoundsAround() { return null; }
|
|
881
884
|
coordsAt(pos, side) {
|
|
@@ -891,6 +894,7 @@ class WidgetView extends ContentView {
|
|
|
891
894
|
}
|
|
892
895
|
get isEditable() { return false; }
|
|
893
896
|
get isWidget() { return true; }
|
|
897
|
+
get isHidden() { return this.widget.isHidden; }
|
|
894
898
|
destroy() {
|
|
895
899
|
super.destroy();
|
|
896
900
|
if (this.dom)
|
|
@@ -953,8 +957,9 @@ function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
|
|
953
957
|
}
|
|
954
958
|
function posFromDOMInCompositionTree(node, offset, view, text) {
|
|
955
959
|
if (view instanceof MarkView) {
|
|
960
|
+
let pos = 0;
|
|
956
961
|
for (let child of view.children) {
|
|
957
|
-
let
|
|
962
|
+
let hasComp = contains(child.dom, text);
|
|
958
963
|
if (contains(child.dom, node))
|
|
959
964
|
return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
|
960
965
|
pos += hasComp ? text.nodeValue.length : child.length;
|
|
@@ -988,7 +993,7 @@ class WidgetBufferView extends ContentView {
|
|
|
988
993
|
}
|
|
989
994
|
}
|
|
990
995
|
getSide() { return this.side; }
|
|
991
|
-
domAtPos(pos) { return DOMPos.before(this.dom); }
|
|
996
|
+
domAtPos(pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); }
|
|
992
997
|
localPosFromDOM() { return 0; }
|
|
993
998
|
domBoundsAround() { return null; }
|
|
994
999
|
coordsAt(pos) {
|
|
@@ -1002,6 +1007,7 @@ class WidgetBufferView extends ContentView {
|
|
|
1002
1007
|
get overrideDOMText() {
|
|
1003
1008
|
return Text.empty;
|
|
1004
1009
|
}
|
|
1010
|
+
get isHidden() { return true; }
|
|
1005
1011
|
}
|
|
1006
1012
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
1007
1013
|
function inlineSiblingRect(view, side) {
|
|
@@ -1075,7 +1081,8 @@ function coordsInChildren(view, pos, side) {
|
|
|
1075
1081
|
if (child.children.length) {
|
|
1076
1082
|
scan(child, pos - off);
|
|
1077
1083
|
}
|
|
1078
|
-
else if (!after
|
|
1084
|
+
else if ((!after || after instanceof WidgetBufferView && side > 0) &&
|
|
1085
|
+
(end > pos || off == end && child.getSide() > 0)) {
|
|
1079
1086
|
after = child;
|
|
1080
1087
|
afterPos = pos - off;
|
|
1081
1088
|
}
|
|
@@ -1189,6 +1196,10 @@ class WidgetType {
|
|
|
1189
1196
|
*/
|
|
1190
1197
|
get customView() { return null; }
|
|
1191
1198
|
/**
|
|
1199
|
+
@internal
|
|
1200
|
+
*/
|
|
1201
|
+
get isHidden() { return false; }
|
|
1202
|
+
/**
|
|
1192
1203
|
This is called when the an instance of the widget is removed
|
|
1193
1204
|
from the editor view.
|
|
1194
1205
|
*/
|
|
@@ -1511,7 +1522,7 @@ class LineView extends ContentView {
|
|
|
1511
1522
|
measureTextSize() {
|
|
1512
1523
|
if (this.children.length == 0 || this.length > 20)
|
|
1513
1524
|
return null;
|
|
1514
|
-
let totalWidth = 0;
|
|
1525
|
+
let totalWidth = 0, textHeight;
|
|
1515
1526
|
for (let child of this.children) {
|
|
1516
1527
|
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1517
1528
|
return null;
|
|
@@ -1519,14 +1530,26 @@ class LineView extends ContentView {
|
|
|
1519
1530
|
if (rects.length != 1)
|
|
1520
1531
|
return null;
|
|
1521
1532
|
totalWidth += rects[0].width;
|
|
1533
|
+
textHeight = rects[0].height;
|
|
1522
1534
|
}
|
|
1523
1535
|
return !totalWidth ? null : {
|
|
1524
1536
|
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1525
|
-
charWidth: totalWidth / this.length
|
|
1537
|
+
charWidth: totalWidth / this.length,
|
|
1538
|
+
textHeight
|
|
1526
1539
|
};
|
|
1527
1540
|
}
|
|
1528
1541
|
coordsAt(pos, side) {
|
|
1529
|
-
|
|
1542
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1543
|
+
// Correct rectangle height for empty lines when the returned
|
|
1544
|
+
// height is larger than the text height.
|
|
1545
|
+
if (!this.children.length && rect && this.parent) {
|
|
1546
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1547
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1548
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1549
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
return rect;
|
|
1530
1553
|
}
|
|
1531
1554
|
become(_other) { return false; }
|
|
1532
1555
|
get type() { return BlockType.Text; }
|
|
@@ -1587,7 +1610,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1587
1610
|
become(other) {
|
|
1588
1611
|
if (other instanceof BlockWidgetView && other.type == this.type &&
|
|
1589
1612
|
other.widget.constructor == this.widget.constructor) {
|
|
1590
|
-
if (!other.widget.
|
|
1613
|
+
if (!other.widget.compare(this.widget))
|
|
1591
1614
|
this.markDirty(true);
|
|
1592
1615
|
if (this.dom && !this.prevWidget)
|
|
1593
1616
|
this.prevWidget = this.widget;
|
|
@@ -1718,10 +1741,11 @@ class ContentBuilder {
|
|
|
1718
1741
|
}
|
|
1719
1742
|
else {
|
|
1720
1743
|
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
1721
|
-
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
|
|
1744
|
+
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
|
|
1745
|
+
(from < to || deco.startSide > 0);
|
|
1722
1746
|
let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
|
|
1723
1747
|
let line = this.getLine();
|
|
1724
|
-
if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
|
|
1748
|
+
if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
|
|
1725
1749
|
this.pendingBuffer = 0 /* Buf.No */;
|
|
1726
1750
|
this.flushBuffer(active);
|
|
1727
1751
|
if (cursorBefore) {
|
|
@@ -1775,6 +1799,7 @@ class NullWidget extends WidgetType {
|
|
|
1775
1799
|
eq(other) { return other.tag == this.tag; }
|
|
1776
1800
|
toDOM() { return document.createElement(this.tag); }
|
|
1777
1801
|
updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
|
|
1802
|
+
get isHidden() { return true; }
|
|
1778
1803
|
}
|
|
1779
1804
|
|
|
1780
1805
|
const clickAddsSelectionRange = /*@__PURE__*/Facet.define();
|
|
@@ -2627,7 +2652,7 @@ class DocView extends ContentView {
|
|
|
2627
2652
|
let head = main.empty ? anchor : this.domAtPos(main.head);
|
|
2628
2653
|
// Always reset on Firefox when next to an uneditable node to
|
|
2629
2654
|
// avoid invisible cursor bugs (#111)
|
|
2630
|
-
if (browser.gecko && main.empty && betweenUneditable(anchor)) {
|
|
2655
|
+
if (browser.gecko && main.empty && !this.compositionDeco.size && betweenUneditable(anchor)) {
|
|
2631
2656
|
let dummy = document.createTextNode("");
|
|
2632
2657
|
this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
|
2633
2658
|
anchor = head = new DOMPos(dummy, 0);
|
|
@@ -2806,7 +2831,7 @@ class DocView extends ContentView {
|
|
|
2806
2831
|
}
|
|
2807
2832
|
}
|
|
2808
2833
|
// If no workable line exists, force a layout of a measurable element
|
|
2809
|
-
let dummy = document.createElement("div"), lineHeight, charWidth;
|
|
2834
|
+
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
2810
2835
|
dummy.className = "cm-line";
|
|
2811
2836
|
dummy.style.width = "99999px";
|
|
2812
2837
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
@@ -2815,9 +2840,10 @@ class DocView extends ContentView {
|
|
|
2815
2840
|
let rect = clientRectsFor(dummy.firstChild)[0];
|
|
2816
2841
|
lineHeight = dummy.getBoundingClientRect().height;
|
|
2817
2842
|
charWidth = rect ? rect.width / 27 : 7;
|
|
2843
|
+
textHeight = rect ? rect.height : lineHeight;
|
|
2818
2844
|
dummy.remove();
|
|
2819
2845
|
});
|
|
2820
|
-
return { lineHeight, charWidth };
|
|
2846
|
+
return { lineHeight, charWidth, textHeight };
|
|
2821
2847
|
}
|
|
2822
2848
|
childCursor(pos = this.length) {
|
|
2823
2849
|
// Move back to start of last element when possible, so that
|
|
@@ -2982,22 +3008,32 @@ class CompositionWidget extends WidgetType {
|
|
|
2982
3008
|
ignoreEvent() { return false; }
|
|
2983
3009
|
get customView() { return CompositionView; }
|
|
2984
3010
|
}
|
|
2985
|
-
function nearbyTextNode(
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
|
|
2990
|
-
node
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
3011
|
+
function nearbyTextNode(startNode, startOffset, side) {
|
|
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 > 0) {
|
|
3017
|
+
node = node.childNodes[offset - 1];
|
|
3018
|
+
offset = maxOffset(node);
|
|
3019
|
+
}
|
|
3020
|
+
else {
|
|
3021
|
+
break;
|
|
3022
|
+
}
|
|
2996
3023
|
}
|
|
2997
|
-
|
|
2998
|
-
|
|
3024
|
+
if (side >= 0)
|
|
3025
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
3026
|
+
if (node.nodeType == 3)
|
|
3027
|
+
return node;
|
|
3028
|
+
if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
|
3029
|
+
node = node.childNodes[offset];
|
|
3030
|
+
offset = 0;
|
|
3031
|
+
}
|
|
3032
|
+
else {
|
|
3033
|
+
break;
|
|
3034
|
+
}
|
|
2999
3035
|
}
|
|
3000
|
-
|
|
3036
|
+
return null;
|
|
3001
3037
|
}
|
|
3002
3038
|
function nextToUneditable(node, offset) {
|
|
3003
3039
|
if (node.nodeType != 1)
|
|
@@ -3410,7 +3446,15 @@ class InputState {
|
|
|
3410
3446
|
// first, false means first has already been marked for this
|
|
3411
3447
|
// composition)
|
|
3412
3448
|
this.compositionFirstChange = null;
|
|
3449
|
+
// End time of the previous composition
|
|
3413
3450
|
this.compositionEndedAt = 0;
|
|
3451
|
+
// Used in a kludge to detect when an Enter keypress should be
|
|
3452
|
+
// considered part of the composition on Safari, which fires events
|
|
3453
|
+
// in the wrong order
|
|
3454
|
+
this.compositionPendingKey = false;
|
|
3455
|
+
// Used to categorize changes as part of a composition, even when
|
|
3456
|
+
// the mutation events fire shortly after the compositionend event
|
|
3457
|
+
this.compositionPendingChange = false;
|
|
3414
3458
|
this.mouseSelection = null;
|
|
3415
3459
|
let handleEvent = (handler, event) => {
|
|
3416
3460
|
if (this.ignoreDuringComposition(event))
|
|
@@ -3433,8 +3477,16 @@ class InputState {
|
|
|
3433
3477
|
this.registeredEvents.push(type);
|
|
3434
3478
|
}
|
|
3435
3479
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3436
|
-
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3480
|
+
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3437
3481
|
handleEvent(handlers.mousedown, event);
|
|
3482
|
+
if (!event.defaultPrevented && event.button == 2) {
|
|
3483
|
+
// Make sure the content covers the entire scroller height, in order
|
|
3484
|
+
// to catch a native context menu click below it
|
|
3485
|
+
let start = view.contentDOM.style.minHeight;
|
|
3486
|
+
view.contentDOM.style.minHeight = "100%";
|
|
3487
|
+
setTimeout(() => view.contentDOM.style.minHeight = start, 200);
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3438
3490
|
});
|
|
3439
3491
|
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3440
3492
|
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
@@ -3559,8 +3611,8 @@ class InputState {
|
|
|
3559
3611
|
// compositionend and keydown events are sometimes emitted in the
|
|
3560
3612
|
// wrong order. The key event should still be ignored, even when
|
|
3561
3613
|
// it happens after the compositionend event.
|
|
3562
|
-
if (browser.safari && !browser.ios && Date.now() - this.compositionEndedAt < 100) {
|
|
3563
|
-
this.
|
|
3614
|
+
if (browser.safari && !browser.ios && this.compositionPendingKey && Date.now() - this.compositionEndedAt < 100) {
|
|
3615
|
+
this.compositionPendingKey = false;
|
|
3564
3616
|
return true;
|
|
3565
3617
|
}
|
|
3566
3618
|
return false;
|
|
@@ -3592,8 +3644,9 @@ const PendingKeys = [
|
|
|
3592
3644
|
const EmacsyPendingKeys = "dthko";
|
|
3593
3645
|
// Key codes for modifier keys
|
|
3594
3646
|
const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
|
3647
|
+
const dragScrollMargin = 6;
|
|
3595
3648
|
function dragScrollSpeed(dist) {
|
|
3596
|
-
return dist * 0.7 + 8;
|
|
3649
|
+
return Math.max(0, dist) * 0.7 + 8;
|
|
3597
3650
|
}
|
|
3598
3651
|
class MouseSelection {
|
|
3599
3652
|
constructor(view, startEvent, style, mustSelect) {
|
|
@@ -3630,13 +3683,13 @@ class MouseSelection {
|
|
|
3630
3683
|
let sx = 0, sy = 0;
|
|
3631
3684
|
let rect = ((_a = this.scrollParent) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect())
|
|
3632
3685
|
|| { left: 0, top: 0, right: this.view.win.innerWidth, bottom: this.view.win.innerHeight };
|
|
3633
|
-
if (event.clientX <= rect.left)
|
|
3686
|
+
if (event.clientX <= rect.left + dragScrollMargin)
|
|
3634
3687
|
sx = -dragScrollSpeed(rect.left - event.clientX);
|
|
3635
|
-
else if (event.clientX >= rect.right)
|
|
3688
|
+
else if (event.clientX >= rect.right - dragScrollMargin)
|
|
3636
3689
|
sx = dragScrollSpeed(event.clientX - rect.right);
|
|
3637
|
-
if (event.clientY <= rect.top)
|
|
3690
|
+
if (event.clientY <= rect.top + dragScrollMargin)
|
|
3638
3691
|
sy = -dragScrollSpeed(rect.top - event.clientY);
|
|
3639
|
-
else if (event.clientY >= rect.bottom)
|
|
3692
|
+
else if (event.clientY >= rect.bottom - dragScrollMargin)
|
|
3640
3693
|
sy = dragScrollSpeed(event.clientY - rect.bottom);
|
|
3641
3694
|
this.setScrollSpeed(sx, sy);
|
|
3642
3695
|
}
|
|
@@ -3883,7 +3936,7 @@ function basicMouseSelection(view, event) {
|
|
|
3883
3936
|
}
|
|
3884
3937
|
},
|
|
3885
3938
|
get(event, extend, multiple) {
|
|
3886
|
-
let cur = queryPos(view, event);
|
|
3939
|
+
let cur = queryPos(view, event), removed;
|
|
3887
3940
|
let range = rangeForClick(view, cur.pos, cur.bias, type);
|
|
3888
3941
|
if (start.pos != cur.pos && !extend) {
|
|
3889
3942
|
let startRange = rangeForClick(view, start.pos, start.bias, type);
|
|
@@ -3892,8 +3945,8 @@ function basicMouseSelection(view, event) {
|
|
|
3892
3945
|
}
|
|
3893
3946
|
if (extend)
|
|
3894
3947
|
return startSel.replaceRange(startSel.main.extend(range.from, range.to));
|
|
3895
|
-
else if (multiple && startSel.ranges.length > 1 &&
|
|
3896
|
-
return
|
|
3948
|
+
else if (multiple && type == 1 && startSel.ranges.length > 1 && (removed = removeRangeAround(startSel, cur.pos)))
|
|
3949
|
+
return removed;
|
|
3897
3950
|
else if (multiple)
|
|
3898
3951
|
return startSel.addRange(range);
|
|
3899
3952
|
else
|
|
@@ -3901,11 +3954,13 @@ function basicMouseSelection(view, event) {
|
|
|
3901
3954
|
}
|
|
3902
3955
|
};
|
|
3903
3956
|
}
|
|
3904
|
-
function
|
|
3905
|
-
for (let i = 0
|
|
3906
|
-
|
|
3957
|
+
function removeRangeAround(sel, pos) {
|
|
3958
|
+
for (let i = 0; i < sel.ranges.length; i++) {
|
|
3959
|
+
let { from, to } = sel.ranges[i];
|
|
3960
|
+
if (from <= pos && to >= pos)
|
|
3907
3961
|
return EditorSelection.create(sel.ranges.slice(0, i).concat(sel.ranges.slice(i + 1)), sel.mainIndex == i ? 0 : sel.mainIndex - (sel.mainIndex > i ? 1 : 0));
|
|
3908
3962
|
}
|
|
3963
|
+
return null;
|
|
3909
3964
|
}
|
|
3910
3965
|
handlers.dragstart = (view, event) => {
|
|
3911
3966
|
let { selection: { main } } = view.state;
|
|
@@ -4082,6 +4137,8 @@ handlers.compositionstart = handlers.compositionupdate = view => {
|
|
|
4082
4137
|
handlers.compositionend = view => {
|
|
4083
4138
|
view.inputState.composing = -1;
|
|
4084
4139
|
view.inputState.compositionEndedAt = Date.now();
|
|
4140
|
+
view.inputState.compositionPendingKey = true;
|
|
4141
|
+
view.inputState.compositionPendingChange = view.observer.pendingRecords().length > 0;
|
|
4085
4142
|
view.inputState.compositionFirstChange = null;
|
|
4086
4143
|
if (browser.chrome && browser.android)
|
|
4087
4144
|
view.observer.flushSoon();
|
|
@@ -4128,8 +4185,9 @@ class HeightOracle {
|
|
|
4128
4185
|
this.lineWrapping = lineWrapping;
|
|
4129
4186
|
this.doc = Text.empty;
|
|
4130
4187
|
this.heightSamples = {};
|
|
4131
|
-
this.lineHeight = 14;
|
|
4188
|
+
this.lineHeight = 14; // The height of an entire line (line-height)
|
|
4132
4189
|
this.charWidth = 7;
|
|
4190
|
+
this.textHeight = 14; // The height of the actual font (font-size)
|
|
4133
4191
|
this.lineLength = 30;
|
|
4134
4192
|
// Used to track, during updateHeight, if any actual heights changed
|
|
4135
4193
|
this.heightChanged = false;
|
|
@@ -4164,12 +4222,13 @@ class HeightOracle {
|
|
|
4164
4222
|
}
|
|
4165
4223
|
return newHeight;
|
|
4166
4224
|
}
|
|
4167
|
-
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4225
|
+
refresh(whiteSpace, lineHeight, charWidth, textHeight, lineLength, knownHeights) {
|
|
4168
4226
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4169
4227
|
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4170
4228
|
this.lineWrapping = lineWrapping;
|
|
4171
4229
|
this.lineHeight = lineHeight;
|
|
4172
4230
|
this.charWidth = charWidth;
|
|
4231
|
+
this.textHeight = textHeight;
|
|
4173
4232
|
this.lineLength = lineLength;
|
|
4174
4233
|
if (changed) {
|
|
4175
4234
|
this.heightSamples = {};
|
|
@@ -5016,8 +5075,8 @@ class ViewState {
|
|
|
5016
5075
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
5017
5076
|
refresh = true;
|
|
5018
5077
|
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);
|
|
5078
|
+
let { lineHeight, charWidth, textHeight } = view.docView.measureTextSize();
|
|
5079
|
+
refresh = lineHeight > 0 && oracle.refresh(whiteSpace, lineHeight, charWidth, textHeight, contentWidth / charWidth, lineHeights);
|
|
5021
5080
|
if (refresh) {
|
|
5022
5081
|
view.docView.minWidth = 0;
|
|
5023
5082
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
@@ -5734,8 +5793,7 @@ function applyDOMChange(view, domChange) {
|
|
|
5734
5793
|
}
|
|
5735
5794
|
else {
|
|
5736
5795
|
let changes = startState.changes(change);
|
|
5737
|
-
let mainSel = newSel &&
|
|
5738
|
-
? newSel.main : undefined;
|
|
5796
|
+
let mainSel = newSel && newSel.main.to <= changes.newLength ? newSel.main : undefined;
|
|
5739
5797
|
// Try to apply a composition change to all cursors
|
|
5740
5798
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
5741
5799
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
@@ -5769,7 +5827,9 @@ function applyDOMChange(view, domChange) {
|
|
|
5769
5827
|
}
|
|
5770
5828
|
}
|
|
5771
5829
|
let userEvent = "input.type";
|
|
5772
|
-
if (view.composing
|
|
5830
|
+
if (view.composing ||
|
|
5831
|
+
view.inputState.compositionPendingChange && view.inputState.compositionEndedAt > Date.now() - 50) {
|
|
5832
|
+
view.inputState.compositionPendingChange = false;
|
|
5773
5833
|
userEvent += ".compose";
|
|
5774
5834
|
if (view.inputState.compositionFirstChange) {
|
|
5775
5835
|
userEvent += ".start";
|
|
@@ -6145,10 +6205,13 @@ class DOMObserver {
|
|
|
6145
6205
|
}
|
|
6146
6206
|
this.flush();
|
|
6147
6207
|
}
|
|
6148
|
-
|
|
6149
|
-
let records = this.queue;
|
|
6208
|
+
pendingRecords() {
|
|
6150
6209
|
for (let mut of this.observer.takeRecords())
|
|
6151
|
-
|
|
6210
|
+
this.queue.push(mut);
|
|
6211
|
+
return this.queue;
|
|
6212
|
+
}
|
|
6213
|
+
processRecords() {
|
|
6214
|
+
let records = this.pendingRecords();
|
|
6152
6215
|
if (records.length)
|
|
6153
6216
|
this.queue = [];
|
|
6154
6217
|
let from = -1, to = -1, typeOver = false;
|