@codemirror/view 6.17.0 → 6.18.0
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 +22 -0
- package/dist/index.cjs +179 -74
- package/dist/index.d.cts +13 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +179 -74
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 6.18.0 (2023-09-05)
|
|
2
|
+
|
|
3
|
+
### New features
|
|
4
|
+
|
|
5
|
+
The new `EditorView.scaleX` and `scaleY` properties return the CSS-transformed scale of the editor (or 1 when not scaled).
|
|
6
|
+
|
|
7
|
+
The editor now supports being scaled with CSS.
|
|
8
|
+
|
|
9
|
+
## 6.17.1 (2023-08-31)
|
|
10
|
+
|
|
11
|
+
### Bug fixes
|
|
12
|
+
|
|
13
|
+
Don't close the hover tooltip when the pointer moves over empty space caused by line breaks within the hovered range.
|
|
14
|
+
|
|
15
|
+
Fix a bug where on Chrome Android, if a virtual keyboard was slow to apply a change, the editor could end up dropping it.
|
|
16
|
+
|
|
17
|
+
Work around an issue where line-wise copy/cut didn't work in Firefox because the browser wasn't firing those events when nothing was selected.
|
|
18
|
+
|
|
19
|
+
Fix a crash triggered by the way some Android IME systems update the DOM.
|
|
20
|
+
|
|
21
|
+
Fix a bug that caused replacing a word by an emoji on Chrome Android to be treated as a backspace press.
|
|
22
|
+
|
|
1
23
|
## 6.17.0 (2023-08-28)
|
|
2
24
|
|
|
3
25
|
### Bug fixes
|
package/dist/index.cjs
CHANGED
|
@@ -101,6 +101,7 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
101
101
|
for (let cur = dom, stop = false; cur && !stop;) {
|
|
102
102
|
if (cur.nodeType == 1) { // Element
|
|
103
103
|
let bounding, top = cur == doc.body;
|
|
104
|
+
let scaleX = 1, scaleY = 1;
|
|
104
105
|
if (top) {
|
|
105
106
|
bounding = windowRect(win);
|
|
106
107
|
}
|
|
@@ -112,9 +113,11 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
112
113
|
continue;
|
|
113
114
|
}
|
|
114
115
|
let rect = cur.getBoundingClientRect();
|
|
116
|
+
scaleX = rect.width / cur.offsetWidth;
|
|
117
|
+
scaleY = rect.height / cur.offsetHeight;
|
|
115
118
|
// Make sure scrollbar width isn't included in the rectangle
|
|
116
|
-
bounding = { left: rect.left, right: rect.left + cur.clientWidth,
|
|
117
|
-
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
119
|
+
bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
|
|
120
|
+
top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
|
|
118
121
|
}
|
|
119
122
|
let moveX = 0, moveY = 0;
|
|
120
123
|
if (y == "nearest") {
|
|
@@ -162,13 +165,13 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
162
165
|
let movedX = 0, movedY = 0;
|
|
163
166
|
if (moveY) {
|
|
164
167
|
let start = cur.scrollTop;
|
|
165
|
-
cur.scrollTop += moveY;
|
|
166
|
-
movedY = cur.scrollTop - start;
|
|
168
|
+
cur.scrollTop += moveY / scaleY;
|
|
169
|
+
movedY = (cur.scrollTop - start) * scaleY;
|
|
167
170
|
}
|
|
168
171
|
if (moveX) {
|
|
169
172
|
let start = cur.scrollLeft;
|
|
170
|
-
cur.scrollLeft += moveX;
|
|
171
|
-
movedX = cur.scrollLeft - start;
|
|
173
|
+
cur.scrollLeft += moveX / scaleX;
|
|
174
|
+
movedX = (cur.scrollLeft - start) * scaleX;
|
|
172
175
|
}
|
|
173
176
|
rect = { left: rect.left - movedX, top: rect.top - movedY,
|
|
174
177
|
right: rect.right - movedX, bottom: rect.bottom - movedY };
|
|
@@ -2781,7 +2784,7 @@ class DocView extends ContentView {
|
|
|
2781
2784
|
// messes with the scroll position during DOM mutation (though
|
|
2782
2785
|
// no relayout is triggered and I cannot imagine how it can
|
|
2783
2786
|
// recompute the scroll position without a layout)
|
|
2784
|
-
this.dom.style.height = this.view.viewState.contentHeight + "px";
|
|
2787
|
+
this.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
|
|
2785
2788
|
this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2786
2789
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2787
2790
|
// around the selection, get confused and report a different
|
|
@@ -2853,7 +2856,7 @@ class DocView extends ContentView {
|
|
|
2853
2856
|
}
|
|
2854
2857
|
fixCompositionDOM(composition) {
|
|
2855
2858
|
let fix = (dom, cView) => {
|
|
2856
|
-
cView.flags |= 8 /* ViewFlag.Composition
|
|
2859
|
+
cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
|
|
2857
2860
|
this.markedForComposition.add(cView);
|
|
2858
2861
|
let prev = ContentView.get(dom);
|
|
2859
2862
|
if (prev != cView) {
|
|
@@ -3119,7 +3122,7 @@ class DocView extends ContentView {
|
|
|
3119
3122
|
let next = i == vs.viewports.length ? null : vs.viewports[i];
|
|
3120
3123
|
let end = next ? next.from - 1 : this.length;
|
|
3121
3124
|
if (end > pos) {
|
|
3122
|
-
let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
|
3125
|
+
let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
|
|
3123
3126
|
deco.push(Decoration.replace({
|
|
3124
3127
|
widget: new BlockGapWidget(height),
|
|
3125
3128
|
block: true,
|
|
@@ -3184,7 +3187,7 @@ class BlockGapWidget extends WidgetType {
|
|
|
3184
3187
|
}
|
|
3185
3188
|
get estimatedHeight() { return this.height; }
|
|
3186
3189
|
}
|
|
3187
|
-
function findCompositionNode(view) {
|
|
3190
|
+
function findCompositionNode(view, dLen) {
|
|
3188
3191
|
let sel = view.observer.selectionRange;
|
|
3189
3192
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3190
3193
|
if (!textNode)
|
|
@@ -3196,10 +3199,12 @@ function findCompositionNode(view) {
|
|
|
3196
3199
|
to = from + cView.length;
|
|
3197
3200
|
}
|
|
3198
3201
|
else {
|
|
3202
|
+
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3199
3203
|
up: for (let offset = 0, node = textNode;;) {
|
|
3200
3204
|
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3201
3205
|
if (cView = ContentView.get(sibling)) {
|
|
3202
|
-
|
|
3206
|
+
to = cView.posAtEnd + offset;
|
|
3207
|
+
from = Math.max(0, to - oldLen);
|
|
3203
3208
|
break up;
|
|
3204
3209
|
}
|
|
3205
3210
|
let reader = new DOMReader([], view.state);
|
|
@@ -3213,15 +3218,16 @@ function findCompositionNode(view) {
|
|
|
3213
3218
|
return null;
|
|
3214
3219
|
let parentView = ContentView.get(node);
|
|
3215
3220
|
if (parentView) {
|
|
3216
|
-
from =
|
|
3221
|
+
from = parentView.posAtStart + offset;
|
|
3222
|
+
to = from + oldLen;
|
|
3217
3223
|
break;
|
|
3218
3224
|
}
|
|
3219
3225
|
}
|
|
3220
3226
|
}
|
|
3221
|
-
return { from, to, node: textNode };
|
|
3227
|
+
return { from, to: to, node: textNode };
|
|
3222
3228
|
}
|
|
3223
3229
|
function findCompositionRange(view, changes) {
|
|
3224
|
-
let found = findCompositionNode(view);
|
|
3230
|
+
let found = findCompositionNode(view, changes.newLength - changes.length);
|
|
3225
3231
|
if (!found)
|
|
3226
3232
|
return null;
|
|
3227
3233
|
let { from: fromA, to: toA, node: textNode } = found;
|
|
@@ -3785,6 +3791,8 @@ class InputState {
|
|
|
3785
3791
|
// issue where the composition vanishes when you press enter.
|
|
3786
3792
|
if (browser.safari)
|
|
3787
3793
|
view.contentDOM.addEventListener("input", () => null);
|
|
3794
|
+
if (browser.gecko)
|
|
3795
|
+
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3788
3796
|
}
|
|
3789
3797
|
ensureHandlers(view, plugins) {
|
|
3790
3798
|
var _a;
|
|
@@ -4490,6 +4498,18 @@ handlers.beforeinput = (view, event) => {
|
|
|
4490
4498
|
}
|
|
4491
4499
|
}
|
|
4492
4500
|
};
|
|
4501
|
+
const appliedFirefoxHack = new Set;
|
|
4502
|
+
// In Firefox, when cut/copy handlers are added to the document, that
|
|
4503
|
+
// somehow avoids a bug where those events aren't fired when the
|
|
4504
|
+
// selection is empty. See https://github.com/codemirror/dev/issues/1082
|
|
4505
|
+
// and https://bugzilla.mozilla.org/show_bug.cgi?id=995961
|
|
4506
|
+
function firefoxCopyCutHack(doc) {
|
|
4507
|
+
if (!appliedFirefoxHack.has(doc)) {
|
|
4508
|
+
appliedFirefoxHack.add(doc);
|
|
4509
|
+
doc.addEventListener("copy", () => { });
|
|
4510
|
+
doc.addEventListener("cut", () => { });
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4493
4513
|
|
|
4494
4514
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
4495
4515
|
class HeightOracle {
|
|
@@ -5259,8 +5279,10 @@ class LineGap {
|
|
|
5259
5279
|
}
|
|
5260
5280
|
return true;
|
|
5261
5281
|
}
|
|
5262
|
-
draw(wrapping) {
|
|
5263
|
-
return Decoration.replace({
|
|
5282
|
+
draw(viewState, wrapping) {
|
|
5283
|
+
return Decoration.replace({
|
|
5284
|
+
widget: new LineGapWidget(this.size * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
|
|
5285
|
+
}).range(this.from, this.to);
|
|
5264
5286
|
}
|
|
5265
5287
|
}
|
|
5266
5288
|
class LineGapWidget extends WidgetType {
|
|
@@ -5290,14 +5312,18 @@ class ViewState {
|
|
|
5290
5312
|
// These are contentDOM-local coordinates
|
|
5291
5313
|
this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
|
|
5292
5314
|
this.inView = true;
|
|
5293
|
-
this.paddingTop = 0;
|
|
5294
|
-
this.paddingBottom = 0;
|
|
5295
|
-
this.contentDOMWidth = 0;
|
|
5296
|
-
this.contentDOMHeight = 0;
|
|
5297
|
-
this.editorHeight = 0;
|
|
5298
|
-
this.editorWidth = 0;
|
|
5299
|
-
this.scrollTop = 0;
|
|
5315
|
+
this.paddingTop = 0; // Padding above the document, scaled
|
|
5316
|
+
this.paddingBottom = 0; // Padding below the document, scaled
|
|
5317
|
+
this.contentDOMWidth = 0; // contentDOM.getBoundingClientRect().width
|
|
5318
|
+
this.contentDOMHeight = 0; // contentDOM.getBoundingClientRect().height
|
|
5319
|
+
this.editorHeight = 0; // scrollDOM.clientHeight, unscaled
|
|
5320
|
+
this.editorWidth = 0; // scrollDOM.clientWidth, unscaled
|
|
5321
|
+
this.scrollTop = 0; // Last seen scrollDOM.scrollTop, scaled
|
|
5300
5322
|
this.scrolledToBottom = true;
|
|
5323
|
+
// The CSS-transformation scale of the editor (transformed size /
|
|
5324
|
+
// concrete size)
|
|
5325
|
+
this.scaleX = 1;
|
|
5326
|
+
this.scaleY = 1;
|
|
5301
5327
|
// The vertical position (document-relative) to which to anchor the
|
|
5302
5328
|
// scroll position. -1 means anchor to the end of the document.
|
|
5303
5329
|
this.scrollAnchorPos = 0;
|
|
@@ -5331,7 +5357,7 @@ class ViewState {
|
|
|
5331
5357
|
this.updateViewportLines();
|
|
5332
5358
|
this.updateForViewport();
|
|
5333
5359
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5334
|
-
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
|
|
5360
|
+
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5335
5361
|
this.computeVisibleRanges();
|
|
5336
5362
|
}
|
|
5337
5363
|
updateForViewport() {
|
|
@@ -5403,8 +5429,23 @@ class ViewState {
|
|
|
5403
5429
|
this.contentDOMHeight = domRect.height;
|
|
5404
5430
|
this.mustMeasureContent = false;
|
|
5405
5431
|
let result = 0, bias = 0;
|
|
5432
|
+
if (domRect.width && domRect.height) {
|
|
5433
|
+
let scaleX = domRect.width / dom.offsetWidth;
|
|
5434
|
+
let scaleY = domRect.height / dom.offsetHeight;
|
|
5435
|
+
if (scaleX > 0.995 && scaleX < 1.005)
|
|
5436
|
+
scaleX = 1;
|
|
5437
|
+
if (scaleY > 0.995 && scaleY < 1.005)
|
|
5438
|
+
scaleY = 1;
|
|
5439
|
+
if (this.scaleX != scaleX || this.scaleY != scaleY) {
|
|
5440
|
+
this.scaleX = scaleX;
|
|
5441
|
+
this.scaleY = scaleY;
|
|
5442
|
+
result |= 8 /* UpdateFlag.Geometry */;
|
|
5443
|
+
refresh = measureContent = true;
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5406
5446
|
// Vertical padding
|
|
5407
|
-
let paddingTop = parseInt(style.paddingTop) || 0
|
|
5447
|
+
let paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
|
|
5448
|
+
let paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
|
|
5408
5449
|
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
5409
5450
|
this.paddingTop = paddingTop;
|
|
5410
5451
|
this.paddingBottom = paddingBottom;
|
|
@@ -5416,9 +5457,10 @@ class ViewState {
|
|
|
5416
5457
|
this.editorWidth = view.scrollDOM.clientWidth;
|
|
5417
5458
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
5418
5459
|
}
|
|
5419
|
-
|
|
5460
|
+
let scrollTop = view.scrollDOM.scrollTop * this.scaleY;
|
|
5461
|
+
if (this.scrollTop != scrollTop) {
|
|
5420
5462
|
this.scrollAnchorHeight = -1;
|
|
5421
|
-
this.scrollTop =
|
|
5463
|
+
this.scrollTop = scrollTop;
|
|
5422
5464
|
}
|
|
5423
5465
|
this.scrolledToBottom = isScrolledToBottom(view.scrollDOM);
|
|
5424
5466
|
// Pixel viewport
|
|
@@ -5639,7 +5681,7 @@ class ViewState {
|
|
|
5639
5681
|
updateLineGaps(gaps) {
|
|
5640
5682
|
if (!LineGap.same(gaps, this.lineGaps)) {
|
|
5641
5683
|
this.lineGaps = gaps;
|
|
5642
|
-
this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping)));
|
|
5684
|
+
this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
|
|
5643
5685
|
}
|
|
5644
5686
|
}
|
|
5645
5687
|
computeVisibleRanges() {
|
|
@@ -6146,7 +6188,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6146
6188
|
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6147
6189
|
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6148
6190
|
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6149
|
-
lastKey == 8 && change.insert.length < change.to - change.from) &&
|
|
6191
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6150
6192
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6151
6193
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6152
6194
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
@@ -6190,7 +6232,8 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6190
6232
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6191
6233
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6192
6234
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6193
|
-
let composition = findCompositionNode(view
|
|
6235
|
+
let composition = findCompositionNode(view, change.insert.length - (change.to - change.from)) ||
|
|
6236
|
+
view.state.doc.lineAt(sel.head);
|
|
6194
6237
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6195
6238
|
tr = startState.changeByRange(range => {
|
|
6196
6239
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -7040,13 +7083,18 @@ class EditorView {
|
|
|
7040
7083
|
return;
|
|
7041
7084
|
if (this.measureScheduled > -1)
|
|
7042
7085
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
7086
|
+
if (this.observer.delayedAndroidKey) {
|
|
7087
|
+
this.measureScheduled = -1;
|
|
7088
|
+
this.requestMeasure();
|
|
7089
|
+
return;
|
|
7090
|
+
}
|
|
7043
7091
|
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
7044
7092
|
if (flush)
|
|
7045
7093
|
this.observer.forceFlush();
|
|
7046
7094
|
let updated = null;
|
|
7047
|
-
let sDOM = this.scrollDOM,
|
|
7095
|
+
let sDOM = this.scrollDOM, scrollTop = sDOM.scrollTop * this.scaleY;
|
|
7048
7096
|
let { scrollAnchorPos, scrollAnchorHeight } = this.viewState;
|
|
7049
|
-
if (scrollTop
|
|
7097
|
+
if (Math.abs(scrollTop - this.viewState.scrollTop) > 1)
|
|
7050
7098
|
scrollAnchorHeight = -1;
|
|
7051
7099
|
this.viewState.scrollAnchorHeight = -1;
|
|
7052
7100
|
try {
|
|
@@ -7123,7 +7171,8 @@ class EditorView {
|
|
|
7123
7171
|
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
7124
7172
|
let diff = newAnchorHeight - scrollAnchorHeight;
|
|
7125
7173
|
if (diff > 1 || diff < -1) {
|
|
7126
|
-
scrollTop =
|
|
7174
|
+
scrollTop = scrollTop + diff;
|
|
7175
|
+
sDOM.scrollTop = scrollTop / this.scaleY;
|
|
7127
7176
|
scrollAnchorHeight = -1;
|
|
7128
7177
|
continue;
|
|
7129
7178
|
}
|
|
@@ -7250,6 +7299,16 @@ class EditorView {
|
|
|
7250
7299
|
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
|
7251
7300
|
}
|
|
7252
7301
|
/**
|
|
7302
|
+
If the editor is transformed with CSS, this provides the scale
|
|
7303
|
+
along the X axis. Otherwise, it will just be 1. Note that
|
|
7304
|
+
transforms other than translation and scaling are not supported.
|
|
7305
|
+
*/
|
|
7306
|
+
get scaleX() { return this.viewState.scaleX; }
|
|
7307
|
+
/**
|
|
7308
|
+
Provide the CSS transformed scale along the Y axis.
|
|
7309
|
+
*/
|
|
7310
|
+
get scaleY() { return this.viewState.scaleY; }
|
|
7311
|
+
/**
|
|
7253
7312
|
Find the text line or block widget at the given vertical
|
|
7254
7313
|
position (which is interpreted as relative to the [top of the
|
|
7255
7314
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
|
|
@@ -8040,8 +8099,8 @@ class RectangleMarker {
|
|
|
8040
8099
|
}
|
|
8041
8100
|
function getBase(view) {
|
|
8042
8101
|
let rect = view.scrollDOM.getBoundingClientRect();
|
|
8043
|
-
let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
|
|
8044
|
-
return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop };
|
|
8102
|
+
let left = view.textDirection == exports.Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8103
|
+
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8045
8104
|
}
|
|
8046
8105
|
function wrappedLine(view, pos, inside) {
|
|
8047
8106
|
let range = state.EditorSelection.cursor(pos);
|
|
@@ -8143,6 +8202,8 @@ class LayerView {
|
|
|
8143
8202
|
this.view = view;
|
|
8144
8203
|
this.layer = layer;
|
|
8145
8204
|
this.drawn = [];
|
|
8205
|
+
this.scaleX = 1;
|
|
8206
|
+
this.scaleY = 1;
|
|
8146
8207
|
this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
|
|
8147
8208
|
this.dom = view.scrollDOM.appendChild(document.createElement("div"));
|
|
8148
8209
|
this.dom.classList.add("cm-layer");
|
|
@@ -8150,6 +8211,7 @@ class LayerView {
|
|
|
8150
8211
|
this.dom.classList.add("cm-layer-above");
|
|
8151
8212
|
if (layer.class)
|
|
8152
8213
|
this.dom.classList.add(layer.class);
|
|
8214
|
+
this.scale();
|
|
8153
8215
|
this.dom.setAttribute("aria-hidden", "true");
|
|
8154
8216
|
this.setOrder(view.state);
|
|
8155
8217
|
view.requestMeasure(this.measureReq);
|
|
@@ -8159,8 +8221,10 @@ class LayerView {
|
|
|
8159
8221
|
update(update) {
|
|
8160
8222
|
if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
|
|
8161
8223
|
this.setOrder(update.state);
|
|
8162
|
-
if (this.layer.update(update, this.dom) || update.geometryChanged)
|
|
8224
|
+
if (this.layer.update(update, this.dom) || update.geometryChanged) {
|
|
8225
|
+
this.scale();
|
|
8163
8226
|
update.view.requestMeasure(this.measureReq);
|
|
8227
|
+
}
|
|
8164
8228
|
}
|
|
8165
8229
|
setOrder(state) {
|
|
8166
8230
|
let pos = 0, order = state.facet(layerOrder);
|
|
@@ -8171,6 +8235,14 @@ class LayerView {
|
|
|
8171
8235
|
measure() {
|
|
8172
8236
|
return this.layer.markers(this.view);
|
|
8173
8237
|
}
|
|
8238
|
+
scale() {
|
|
8239
|
+
let { scaleX, scaleY } = this.view;
|
|
8240
|
+
if (scaleX != this.scaleX || scaleY != this.scaleY) {
|
|
8241
|
+
this.scaleX = scaleX;
|
|
8242
|
+
this.scaleY = scaleY;
|
|
8243
|
+
this.dom.style.transform = `scale(${1 / scaleX}, ${1 / scaleY})`;
|
|
8244
|
+
}
|
|
8245
|
+
}
|
|
8174
8246
|
draw(markers) {
|
|
8175
8247
|
if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
|
|
8176
8248
|
let old = this.dom.firstChild, oldI = 0;
|
|
@@ -8340,23 +8412,25 @@ const drawDropCursor = ViewPlugin.fromClass(class {
|
|
|
8340
8412
|
}
|
|
8341
8413
|
}
|
|
8342
8414
|
readPos() {
|
|
8343
|
-
let
|
|
8344
|
-
let
|
|
8415
|
+
let { view } = this;
|
|
8416
|
+
let pos = view.state.field(dropCursorPos);
|
|
8417
|
+
let rect = pos != null && view.coordsAtPos(pos);
|
|
8345
8418
|
if (!rect)
|
|
8346
8419
|
return null;
|
|
8347
|
-
let outer =
|
|
8420
|
+
let outer = view.scrollDOM.getBoundingClientRect();
|
|
8348
8421
|
return {
|
|
8349
|
-
left: rect.left - outer.left +
|
|
8350
|
-
top: rect.top - outer.top +
|
|
8422
|
+
left: rect.left - outer.left + view.scrollDOM.scrollLeft * view.scaleX,
|
|
8423
|
+
top: rect.top - outer.top + view.scrollDOM.scrollTop * view.scaleY,
|
|
8351
8424
|
height: rect.bottom - rect.top
|
|
8352
8425
|
};
|
|
8353
8426
|
}
|
|
8354
8427
|
drawCursor(pos) {
|
|
8355
8428
|
if (this.cursor) {
|
|
8429
|
+
let { scaleX, scaleY } = this.view;
|
|
8356
8430
|
if (pos) {
|
|
8357
|
-
this.cursor.style.left = pos.left + "px";
|
|
8358
|
-
this.cursor.style.top = pos.top + "px";
|
|
8359
|
-
this.cursor.style.height = pos.height + "px";
|
|
8431
|
+
this.cursor.style.left = pos.left / scaleX + "px";
|
|
8432
|
+
this.cursor.style.top = pos.top / scaleY + "px";
|
|
8433
|
+
this.cursor.style.height = pos.height / scaleY + "px";
|
|
8360
8434
|
}
|
|
8361
8435
|
else {
|
|
8362
8436
|
this.cursor.style.left = "-100000px";
|
|
@@ -8598,7 +8672,9 @@ function specialCharPlugin() {
|
|
|
8598
8672
|
if (code == 9) {
|
|
8599
8673
|
let line = doc.lineAt(pos);
|
|
8600
8674
|
let size = view.state.tabSize, col = state.countColumn(line.text, size, pos - line.from);
|
|
8601
|
-
return Decoration.replace({
|
|
8675
|
+
return Decoration.replace({
|
|
8676
|
+
widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth / this.view.scaleX)
|
|
8677
|
+
});
|
|
8602
8678
|
}
|
|
8603
8679
|
return this.decorationCache[code] ||
|
|
8604
8680
|
(this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) }));
|
|
@@ -8675,7 +8751,8 @@ const plugin = ViewPlugin.fromClass(class {
|
|
|
8675
8751
|
}
|
|
8676
8752
|
update(update) {
|
|
8677
8753
|
let { view } = update;
|
|
8678
|
-
let height = view.viewState.editorHeight
|
|
8754
|
+
let height = view.viewState.editorHeight * view.scaleY -
|
|
8755
|
+
view.defaultLineHeight - view.documentPadding.top - 0.5;
|
|
8679
8756
|
if (height >= 0 && height != this.height) {
|
|
8680
8757
|
this.height = height;
|
|
8681
8758
|
this.attrs = { style: `padding-bottom: ${height}px` };
|
|
@@ -8972,6 +9049,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
8972
9049
|
constructor(view) {
|
|
8973
9050
|
this.view = view;
|
|
8974
9051
|
this.inView = true;
|
|
9052
|
+
this.madeAbsolute = false;
|
|
8975
9053
|
this.lastTransaction = 0;
|
|
8976
9054
|
this.measureTimeout = -1;
|
|
8977
9055
|
let config = view.state.facet(tooltipConfig);
|
|
@@ -9023,7 +9101,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9023
9101
|
this.observeIntersection();
|
|
9024
9102
|
let shouldMeasure = updated || update.geometryChanged;
|
|
9025
9103
|
let newConfig = update.state.facet(tooltipConfig);
|
|
9026
|
-
if (newConfig.position != this.position) {
|
|
9104
|
+
if (newConfig.position != this.position && !this.madeAbsolute) {
|
|
9027
9105
|
this.position = newConfig.position;
|
|
9028
9106
|
for (let t of this.manager.tooltipViews)
|
|
9029
9107
|
t.dom.style.position = this.position;
|
|
@@ -9071,6 +9149,27 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9071
9149
|
}
|
|
9072
9150
|
readMeasure() {
|
|
9073
9151
|
let editor = this.view.dom.getBoundingClientRect();
|
|
9152
|
+
let scaleX = 1, scaleY = 1, makeAbsolute = false;
|
|
9153
|
+
if (this.position == "fixed") {
|
|
9154
|
+
let views = this.manager.tooltipViews;
|
|
9155
|
+
// When the dialog's offset parent isn't the body, we are
|
|
9156
|
+
// probably in a transformed container, and should use absolute
|
|
9157
|
+
// positioning instead, since fixed positioning inside a
|
|
9158
|
+
// transform works in a very broken way.
|
|
9159
|
+
makeAbsolute = views.length > 0 && views[0].dom.offsetParent != this.container.ownerDocument.body;
|
|
9160
|
+
}
|
|
9161
|
+
if (makeAbsolute || this.position == "absolute") {
|
|
9162
|
+
if (this.parent) {
|
|
9163
|
+
let rect = this.parent.getBoundingClientRect();
|
|
9164
|
+
if (rect.width && rect.height) {
|
|
9165
|
+
scaleX = rect.width / this.parent.offsetWidth;
|
|
9166
|
+
scaleY = rect.height / this.parent.offsetHeight;
|
|
9167
|
+
}
|
|
9168
|
+
}
|
|
9169
|
+
else {
|
|
9170
|
+
({ scaleX, scaleY } = this.view.viewState);
|
|
9171
|
+
}
|
|
9172
|
+
}
|
|
9074
9173
|
return {
|
|
9075
9174
|
editor,
|
|
9076
9175
|
parent: this.parent ? this.container.getBoundingClientRect() : editor,
|
|
@@ -9080,11 +9179,18 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9080
9179
|
}),
|
|
9081
9180
|
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
9082
9181
|
space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
|
|
9182
|
+
scaleX, scaleY, makeAbsolute
|
|
9083
9183
|
};
|
|
9084
9184
|
}
|
|
9085
9185
|
writeMeasure(measured) {
|
|
9086
9186
|
var _a;
|
|
9087
|
-
|
|
9187
|
+
if (measured.makeAbsolute) {
|
|
9188
|
+
this.madeAbsolute = true;
|
|
9189
|
+
this.position = "absolute";
|
|
9190
|
+
for (let t of this.manager.tooltipViews)
|
|
9191
|
+
t.dom.style.position = "absolute";
|
|
9192
|
+
}
|
|
9193
|
+
let { editor, space, scaleX, scaleY } = measured;
|
|
9088
9194
|
let others = [];
|
|
9089
9195
|
for (let i = 0; i < this.manager.tooltips.length; i++) {
|
|
9090
9196
|
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
|
@@ -9117,7 +9223,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9117
9223
|
continue;
|
|
9118
9224
|
}
|
|
9119
9225
|
knownHeight.set(tView, height);
|
|
9120
|
-
dom.style.height = (height = spaceVert) + "px";
|
|
9226
|
+
dom.style.height = (height = spaceVert) / scaleY + "px";
|
|
9121
9227
|
}
|
|
9122
9228
|
else if (dom.style.height) {
|
|
9123
9229
|
dom.style.height = "";
|
|
@@ -9129,15 +9235,17 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9129
9235
|
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
9130
9236
|
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
9131
9237
|
if (this.position == "absolute") {
|
|
9132
|
-
dom.style.top = (top - measured.parent.top) + "px";
|
|
9133
|
-
dom.style.left = (left - measured.parent.left) + "px";
|
|
9238
|
+
dom.style.top = (top - measured.parent.top) / scaleY + "px";
|
|
9239
|
+
dom.style.left = (left - measured.parent.left) / scaleX + "px";
|
|
9134
9240
|
}
|
|
9135
9241
|
else {
|
|
9136
|
-
dom.style.top = top + "px";
|
|
9137
|
-
dom.style.left = left + "px";
|
|
9242
|
+
dom.style.top = top / scaleY + "px";
|
|
9243
|
+
dom.style.left = left / scaleX + "px";
|
|
9244
|
+
}
|
|
9245
|
+
if (arrow) {
|
|
9246
|
+
let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */);
|
|
9247
|
+
arrow.style.left = arrowLeft / scaleX + "px";
|
|
9138
9248
|
}
|
|
9139
|
-
if (arrow)
|
|
9140
|
-
arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */)}px`;
|
|
9141
9249
|
if (tView.overlap !== true)
|
|
9142
9250
|
others.push({ left, top, right, bottom: top + height });
|
|
9143
9251
|
dom.classList.toggle("cm-tooltip-above", above);
|
|
@@ -9370,7 +9478,7 @@ class HoverPlugin {
|
|
|
9370
9478
|
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
9371
9479
|
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
9372
9480
|
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
9373
|
-
: !isOverRange(this.view, pos, end, event.clientX, event.clientY
|
|
9481
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
|
|
9374
9482
|
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
9375
9483
|
this.pending = null;
|
|
9376
9484
|
}
|
|
@@ -9395,19 +9503,12 @@ function isInTooltip(elt) {
|
|
|
9395
9503
|
return false;
|
|
9396
9504
|
}
|
|
9397
9505
|
function isOverRange(view, from, to, x, y, margin) {
|
|
9398
|
-
let
|
|
9399
|
-
let
|
|
9400
|
-
|
|
9401
|
-
|
|
9402
|
-
let
|
|
9403
|
-
|
|
9404
|
-
for (let i = 0; i < rects.length; i++) {
|
|
9405
|
-
let rect = rects[i];
|
|
9406
|
-
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
9407
|
-
if (dist <= margin)
|
|
9408
|
-
return true;
|
|
9409
|
-
}
|
|
9410
|
-
return false;
|
|
9506
|
+
let rect = view.scrollDOM.getBoundingClientRect();
|
|
9507
|
+
let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
|
|
9508
|
+
if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y)
|
|
9509
|
+
return false;
|
|
9510
|
+
let pos = view.posAtCoords({ x, y }, false);
|
|
9511
|
+
return pos >= from && pos <= to;
|
|
9411
9512
|
}
|
|
9412
9513
|
/**
|
|
9413
9514
|
Set up a hover tooltip, which shows up when the pointer hovers
|
|
@@ -9746,7 +9847,7 @@ const gutterView = ViewPlugin.fromClass(class {
|
|
|
9746
9847
|
this.dom = document.createElement("div");
|
|
9747
9848
|
this.dom.className = "cm-gutters";
|
|
9748
9849
|
this.dom.setAttribute("aria-hidden", "true");
|
|
9749
|
-
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
9850
|
+
this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
|
|
9750
9851
|
this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
|
|
9751
9852
|
for (let gutter of this.gutters)
|
|
9752
9853
|
this.dom.appendChild(gutter.dom);
|
|
@@ -9856,7 +9957,9 @@ const gutterView = ViewPlugin.fromClass(class {
|
|
|
9856
9957
|
let value = view.plugin(plugin);
|
|
9857
9958
|
if (!value || value.gutters.length == 0 || !value.fixed)
|
|
9858
9959
|
return null;
|
|
9859
|
-
return view.textDirection == exports.Direction.LTR
|
|
9960
|
+
return view.textDirection == exports.Direction.LTR
|
|
9961
|
+
? { left: value.dom.offsetWidth * view.scaleX }
|
|
9962
|
+
: { right: value.dom.offsetWidth * view.scaleX };
|
|
9860
9963
|
})
|
|
9861
9964
|
});
|
|
9862
9965
|
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
|
|
@@ -9973,10 +10076,12 @@ class GutterElement {
|
|
|
9973
10076
|
this.update(view, height, above, markers);
|
|
9974
10077
|
}
|
|
9975
10078
|
update(view, height, above, markers) {
|
|
9976
|
-
if (this.height != height)
|
|
9977
|
-
this.
|
|
10079
|
+
if (this.height != height) {
|
|
10080
|
+
this.height = height;
|
|
10081
|
+
this.dom.style.height = height / view.scaleY + "px";
|
|
10082
|
+
}
|
|
9978
10083
|
if (this.above != above)
|
|
9979
|
-
this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
|
|
10084
|
+
this.dom.style.marginTop = (this.above = above) ? above / view.scaleY + "px" : "";
|
|
9980
10085
|
if (!sameMarkers(this.markers, markers))
|
|
9981
10086
|
this.setMarkers(view, markers);
|
|
9982
10087
|
}
|
package/dist/index.d.cts
CHANGED
|
@@ -802,6 +802,16 @@ declare class EditorView {
|
|
|
802
802
|
bottom: number;
|
|
803
803
|
};
|
|
804
804
|
/**
|
|
805
|
+
If the editor is transformed with CSS, this provides the scale
|
|
806
|
+
along the X axis. Otherwise, it will just be 1. Note that
|
|
807
|
+
transforms other than translation and scaling are not supported.
|
|
808
|
+
*/
|
|
809
|
+
get scaleX(): number;
|
|
810
|
+
/**
|
|
811
|
+
Provide the CSS transformed scale along the Y axis.
|
|
812
|
+
*/
|
|
813
|
+
get scaleY(): number;
|
|
814
|
+
/**
|
|
805
815
|
Find the text line or block widget at the given vertical
|
|
806
816
|
position (which is interpreted as relative to the [top of the
|
|
807
817
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
|
|
@@ -1653,6 +1663,9 @@ declare function tooltips(config?: {
|
|
|
1653
1663
|
On iOS, which at the time of writing still doesn't properly
|
|
1654
1664
|
support fixed positioning, the library always uses absolute
|
|
1655
1665
|
positioning.
|
|
1666
|
+
|
|
1667
|
+
If the tooltip parent element sits in a transformed element, the
|
|
1668
|
+
library also falls back to absolute positioning.
|
|
1656
1669
|
*/
|
|
1657
1670
|
position?: "fixed" | "absolute";
|
|
1658
1671
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -802,6 +802,16 @@ declare class EditorView {
|
|
|
802
802
|
bottom: number;
|
|
803
803
|
};
|
|
804
804
|
/**
|
|
805
|
+
If the editor is transformed with CSS, this provides the scale
|
|
806
|
+
along the X axis. Otherwise, it will just be 1. Note that
|
|
807
|
+
transforms other than translation and scaling are not supported.
|
|
808
|
+
*/
|
|
809
|
+
get scaleX(): number;
|
|
810
|
+
/**
|
|
811
|
+
Provide the CSS transformed scale along the Y axis.
|
|
812
|
+
*/
|
|
813
|
+
get scaleY(): number;
|
|
814
|
+
/**
|
|
805
815
|
Find the text line or block widget at the given vertical
|
|
806
816
|
position (which is interpreted as relative to the [top of the
|
|
807
817
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
|
|
@@ -1653,6 +1663,9 @@ declare function tooltips(config?: {
|
|
|
1653
1663
|
On iOS, which at the time of writing still doesn't properly
|
|
1654
1664
|
support fixed positioning, the library always uses absolute
|
|
1655
1665
|
positioning.
|
|
1666
|
+
|
|
1667
|
+
If the tooltip parent element sits in a transformed element, the
|
|
1668
|
+
library also falls back to absolute positioning.
|
|
1656
1669
|
*/
|
|
1657
1670
|
position?: "fixed" | "absolute";
|
|
1658
1671
|
/**
|
package/dist/index.js
CHANGED
|
@@ -99,6 +99,7 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
99
99
|
for (let cur = dom, stop = false; cur && !stop;) {
|
|
100
100
|
if (cur.nodeType == 1) { // Element
|
|
101
101
|
let bounding, top = cur == doc.body;
|
|
102
|
+
let scaleX = 1, scaleY = 1;
|
|
102
103
|
if (top) {
|
|
103
104
|
bounding = windowRect(win);
|
|
104
105
|
}
|
|
@@ -110,9 +111,11 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
110
111
|
continue;
|
|
111
112
|
}
|
|
112
113
|
let rect = cur.getBoundingClientRect();
|
|
114
|
+
scaleX = rect.width / cur.offsetWidth;
|
|
115
|
+
scaleY = rect.height / cur.offsetHeight;
|
|
113
116
|
// Make sure scrollbar width isn't included in the rectangle
|
|
114
|
-
bounding = { left: rect.left, right: rect.left + cur.clientWidth,
|
|
115
|
-
top: rect.top, bottom: rect.top + cur.clientHeight };
|
|
117
|
+
bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
|
|
118
|
+
top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
|
|
116
119
|
}
|
|
117
120
|
let moveX = 0, moveY = 0;
|
|
118
121
|
if (y == "nearest") {
|
|
@@ -160,13 +163,13 @@ function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
|
160
163
|
let movedX = 0, movedY = 0;
|
|
161
164
|
if (moveY) {
|
|
162
165
|
let start = cur.scrollTop;
|
|
163
|
-
cur.scrollTop += moveY;
|
|
164
|
-
movedY = cur.scrollTop - start;
|
|
166
|
+
cur.scrollTop += moveY / scaleY;
|
|
167
|
+
movedY = (cur.scrollTop - start) * scaleY;
|
|
165
168
|
}
|
|
166
169
|
if (moveX) {
|
|
167
170
|
let start = cur.scrollLeft;
|
|
168
|
-
cur.scrollLeft += moveX;
|
|
169
|
-
movedX = cur.scrollLeft - start;
|
|
171
|
+
cur.scrollLeft += moveX / scaleX;
|
|
172
|
+
movedX = (cur.scrollLeft - start) * scaleX;
|
|
170
173
|
}
|
|
171
174
|
rect = { left: rect.left - movedX, top: rect.top - movedY,
|
|
172
175
|
right: rect.right - movedX, bottom: rect.bottom - movedY };
|
|
@@ -2777,7 +2780,7 @@ class DocView extends ContentView {
|
|
|
2777
2780
|
// messes with the scroll position during DOM mutation (though
|
|
2778
2781
|
// no relayout is triggered and I cannot imagine how it can
|
|
2779
2782
|
// recompute the scroll position without a layout)
|
|
2780
|
-
this.dom.style.height = this.view.viewState.contentHeight + "px";
|
|
2783
|
+
this.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
|
|
2781
2784
|
this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2782
2785
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2783
2786
|
// around the selection, get confused and report a different
|
|
@@ -2849,7 +2852,7 @@ class DocView extends ContentView {
|
|
|
2849
2852
|
}
|
|
2850
2853
|
fixCompositionDOM(composition) {
|
|
2851
2854
|
let fix = (dom, cView) => {
|
|
2852
|
-
cView.flags |= 8 /* ViewFlag.Composition
|
|
2855
|
+
cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
|
|
2853
2856
|
this.markedForComposition.add(cView);
|
|
2854
2857
|
let prev = ContentView.get(dom);
|
|
2855
2858
|
if (prev != cView) {
|
|
@@ -3115,7 +3118,7 @@ class DocView extends ContentView {
|
|
|
3115
3118
|
let next = i == vs.viewports.length ? null : vs.viewports[i];
|
|
3116
3119
|
let end = next ? next.from - 1 : this.length;
|
|
3117
3120
|
if (end > pos) {
|
|
3118
|
-
let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
|
3121
|
+
let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
|
|
3119
3122
|
deco.push(Decoration.replace({
|
|
3120
3123
|
widget: new BlockGapWidget(height),
|
|
3121
3124
|
block: true,
|
|
@@ -3180,7 +3183,7 @@ class BlockGapWidget extends WidgetType {
|
|
|
3180
3183
|
}
|
|
3181
3184
|
get estimatedHeight() { return this.height; }
|
|
3182
3185
|
}
|
|
3183
|
-
function findCompositionNode(view) {
|
|
3186
|
+
function findCompositionNode(view, dLen) {
|
|
3184
3187
|
let sel = view.observer.selectionRange;
|
|
3185
3188
|
let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
|
3186
3189
|
if (!textNode)
|
|
@@ -3192,10 +3195,12 @@ function findCompositionNode(view) {
|
|
|
3192
3195
|
to = from + cView.length;
|
|
3193
3196
|
}
|
|
3194
3197
|
else {
|
|
3198
|
+
let oldLen = Math.max(0, textNode.nodeValue.length - dLen);
|
|
3195
3199
|
up: for (let offset = 0, node = textNode;;) {
|
|
3196
3200
|
for (let sibling = node.previousSibling, cView; sibling; sibling = sibling.previousSibling) {
|
|
3197
3201
|
if (cView = ContentView.get(sibling)) {
|
|
3198
|
-
|
|
3202
|
+
to = cView.posAtEnd + offset;
|
|
3203
|
+
from = Math.max(0, to - oldLen);
|
|
3199
3204
|
break up;
|
|
3200
3205
|
}
|
|
3201
3206
|
let reader = new DOMReader([], view.state);
|
|
@@ -3209,15 +3214,16 @@ function findCompositionNode(view) {
|
|
|
3209
3214
|
return null;
|
|
3210
3215
|
let parentView = ContentView.get(node);
|
|
3211
3216
|
if (parentView) {
|
|
3212
|
-
from =
|
|
3217
|
+
from = parentView.posAtStart + offset;
|
|
3218
|
+
to = from + oldLen;
|
|
3213
3219
|
break;
|
|
3214
3220
|
}
|
|
3215
3221
|
}
|
|
3216
3222
|
}
|
|
3217
|
-
return { from, to, node: textNode };
|
|
3223
|
+
return { from, to: to, node: textNode };
|
|
3218
3224
|
}
|
|
3219
3225
|
function findCompositionRange(view, changes) {
|
|
3220
|
-
let found = findCompositionNode(view);
|
|
3226
|
+
let found = findCompositionNode(view, changes.newLength - changes.length);
|
|
3221
3227
|
if (!found)
|
|
3222
3228
|
return null;
|
|
3223
3229
|
let { from: fromA, to: toA, node: textNode } = found;
|
|
@@ -3781,6 +3787,8 @@ class InputState {
|
|
|
3781
3787
|
// issue where the composition vanishes when you press enter.
|
|
3782
3788
|
if (browser.safari)
|
|
3783
3789
|
view.contentDOM.addEventListener("input", () => null);
|
|
3790
|
+
if (browser.gecko)
|
|
3791
|
+
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3784
3792
|
}
|
|
3785
3793
|
ensureHandlers(view, plugins) {
|
|
3786
3794
|
var _a;
|
|
@@ -4486,6 +4494,18 @@ handlers.beforeinput = (view, event) => {
|
|
|
4486
4494
|
}
|
|
4487
4495
|
}
|
|
4488
4496
|
};
|
|
4497
|
+
const appliedFirefoxHack = /*@__PURE__*/new Set;
|
|
4498
|
+
// In Firefox, when cut/copy handlers are added to the document, that
|
|
4499
|
+
// somehow avoids a bug where those events aren't fired when the
|
|
4500
|
+
// selection is empty. See https://github.com/codemirror/dev/issues/1082
|
|
4501
|
+
// and https://bugzilla.mozilla.org/show_bug.cgi?id=995961
|
|
4502
|
+
function firefoxCopyCutHack(doc) {
|
|
4503
|
+
if (!appliedFirefoxHack.has(doc)) {
|
|
4504
|
+
appliedFirefoxHack.add(doc);
|
|
4505
|
+
doc.addEventListener("copy", () => { });
|
|
4506
|
+
doc.addEventListener("cut", () => { });
|
|
4507
|
+
}
|
|
4508
|
+
}
|
|
4489
4509
|
|
|
4490
4510
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
4491
4511
|
class HeightOracle {
|
|
@@ -5254,8 +5274,10 @@ class LineGap {
|
|
|
5254
5274
|
}
|
|
5255
5275
|
return true;
|
|
5256
5276
|
}
|
|
5257
|
-
draw(wrapping) {
|
|
5258
|
-
return Decoration.replace({
|
|
5277
|
+
draw(viewState, wrapping) {
|
|
5278
|
+
return Decoration.replace({
|
|
5279
|
+
widget: new LineGapWidget(this.size * (wrapping ? viewState.scaleY : viewState.scaleX), wrapping)
|
|
5280
|
+
}).range(this.from, this.to);
|
|
5259
5281
|
}
|
|
5260
5282
|
}
|
|
5261
5283
|
class LineGapWidget extends WidgetType {
|
|
@@ -5285,14 +5307,18 @@ class ViewState {
|
|
|
5285
5307
|
// These are contentDOM-local coordinates
|
|
5286
5308
|
this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
|
|
5287
5309
|
this.inView = true;
|
|
5288
|
-
this.paddingTop = 0;
|
|
5289
|
-
this.paddingBottom = 0;
|
|
5290
|
-
this.contentDOMWidth = 0;
|
|
5291
|
-
this.contentDOMHeight = 0;
|
|
5292
|
-
this.editorHeight = 0;
|
|
5293
|
-
this.editorWidth = 0;
|
|
5294
|
-
this.scrollTop = 0;
|
|
5310
|
+
this.paddingTop = 0; // Padding above the document, scaled
|
|
5311
|
+
this.paddingBottom = 0; // Padding below the document, scaled
|
|
5312
|
+
this.contentDOMWidth = 0; // contentDOM.getBoundingClientRect().width
|
|
5313
|
+
this.contentDOMHeight = 0; // contentDOM.getBoundingClientRect().height
|
|
5314
|
+
this.editorHeight = 0; // scrollDOM.clientHeight, unscaled
|
|
5315
|
+
this.editorWidth = 0; // scrollDOM.clientWidth, unscaled
|
|
5316
|
+
this.scrollTop = 0; // Last seen scrollDOM.scrollTop, scaled
|
|
5295
5317
|
this.scrolledToBottom = true;
|
|
5318
|
+
// The CSS-transformation scale of the editor (transformed size /
|
|
5319
|
+
// concrete size)
|
|
5320
|
+
this.scaleX = 1;
|
|
5321
|
+
this.scaleY = 1;
|
|
5296
5322
|
// The vertical position (document-relative) to which to anchor the
|
|
5297
5323
|
// scroll position. -1 means anchor to the end of the document.
|
|
5298
5324
|
this.scrollAnchorPos = 0;
|
|
@@ -5326,7 +5352,7 @@ class ViewState {
|
|
|
5326
5352
|
this.updateViewportLines();
|
|
5327
5353
|
this.updateForViewport();
|
|
5328
5354
|
this.lineGaps = this.ensureLineGaps([]);
|
|
5329
|
-
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
|
|
5355
|
+
this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(this, false)));
|
|
5330
5356
|
this.computeVisibleRanges();
|
|
5331
5357
|
}
|
|
5332
5358
|
updateForViewport() {
|
|
@@ -5398,8 +5424,23 @@ class ViewState {
|
|
|
5398
5424
|
this.contentDOMHeight = domRect.height;
|
|
5399
5425
|
this.mustMeasureContent = false;
|
|
5400
5426
|
let result = 0, bias = 0;
|
|
5427
|
+
if (domRect.width && domRect.height) {
|
|
5428
|
+
let scaleX = domRect.width / dom.offsetWidth;
|
|
5429
|
+
let scaleY = domRect.height / dom.offsetHeight;
|
|
5430
|
+
if (scaleX > 0.995 && scaleX < 1.005)
|
|
5431
|
+
scaleX = 1;
|
|
5432
|
+
if (scaleY > 0.995 && scaleY < 1.005)
|
|
5433
|
+
scaleY = 1;
|
|
5434
|
+
if (this.scaleX != scaleX || this.scaleY != scaleY) {
|
|
5435
|
+
this.scaleX = scaleX;
|
|
5436
|
+
this.scaleY = scaleY;
|
|
5437
|
+
result |= 8 /* UpdateFlag.Geometry */;
|
|
5438
|
+
refresh = measureContent = true;
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5401
5441
|
// Vertical padding
|
|
5402
|
-
let paddingTop = parseInt(style.paddingTop) || 0
|
|
5442
|
+
let paddingTop = (parseInt(style.paddingTop) || 0) * this.scaleY;
|
|
5443
|
+
let paddingBottom = (parseInt(style.paddingBottom) || 0) * this.scaleY;
|
|
5403
5444
|
if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
|
5404
5445
|
this.paddingTop = paddingTop;
|
|
5405
5446
|
this.paddingBottom = paddingBottom;
|
|
@@ -5411,9 +5452,10 @@ class ViewState {
|
|
|
5411
5452
|
this.editorWidth = view.scrollDOM.clientWidth;
|
|
5412
5453
|
result |= 8 /* UpdateFlag.Geometry */;
|
|
5413
5454
|
}
|
|
5414
|
-
|
|
5455
|
+
let scrollTop = view.scrollDOM.scrollTop * this.scaleY;
|
|
5456
|
+
if (this.scrollTop != scrollTop) {
|
|
5415
5457
|
this.scrollAnchorHeight = -1;
|
|
5416
|
-
this.scrollTop =
|
|
5458
|
+
this.scrollTop = scrollTop;
|
|
5417
5459
|
}
|
|
5418
5460
|
this.scrolledToBottom = isScrolledToBottom(view.scrollDOM);
|
|
5419
5461
|
// Pixel viewport
|
|
@@ -5634,7 +5676,7 @@ class ViewState {
|
|
|
5634
5676
|
updateLineGaps(gaps) {
|
|
5635
5677
|
if (!LineGap.same(gaps, this.lineGaps)) {
|
|
5636
5678
|
this.lineGaps = gaps;
|
|
5637
|
-
this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping)));
|
|
5679
|
+
this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this, this.heightOracle.lineWrapping)));
|
|
5638
5680
|
}
|
|
5639
5681
|
}
|
|
5640
5682
|
computeVisibleRanges() {
|
|
@@ -6141,7 +6183,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6141
6183
|
change.insert.length == 1 && change.insert.lines == 2 &&
|
|
6142
6184
|
dispatchKey(view.contentDOM, "Enter", 13)) ||
|
|
6143
6185
|
((change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 ||
|
|
6144
|
-
lastKey == 8 && change.insert.length < change.to - change.from) &&
|
|
6186
|
+
lastKey == 8 && change.insert.length < change.to - change.from && change.to > sel.head) &&
|
|
6145
6187
|
dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
|
6146
6188
|
(change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
|
6147
6189
|
dispatchKey(view.contentDOM, "Delete", 46))))
|
|
@@ -6185,7 +6227,8 @@ function applyDefaultInsert(view, change, newSel) {
|
|
|
6185
6227
|
if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
|
6186
6228
|
change.to <= sel.to && change.to >= sel.to - 10) {
|
|
6187
6229
|
let replaced = view.state.sliceDoc(change.from, change.to);
|
|
6188
|
-
let composition = findCompositionNode(view
|
|
6230
|
+
let composition = findCompositionNode(view, change.insert.length - (change.to - change.from)) ||
|
|
6231
|
+
view.state.doc.lineAt(sel.head);
|
|
6189
6232
|
let offset = sel.to - change.to, size = sel.to - sel.from;
|
|
6190
6233
|
tr = startState.changeByRange(range => {
|
|
6191
6234
|
if (range.from == sel.from && range.to == sel.to)
|
|
@@ -7035,13 +7078,18 @@ class EditorView {
|
|
|
7035
7078
|
return;
|
|
7036
7079
|
if (this.measureScheduled > -1)
|
|
7037
7080
|
this.win.cancelAnimationFrame(this.measureScheduled);
|
|
7081
|
+
if (this.observer.delayedAndroidKey) {
|
|
7082
|
+
this.measureScheduled = -1;
|
|
7083
|
+
this.requestMeasure();
|
|
7084
|
+
return;
|
|
7085
|
+
}
|
|
7038
7086
|
this.measureScheduled = 0; // Prevent requestMeasure calls from scheduling another animation frame
|
|
7039
7087
|
if (flush)
|
|
7040
7088
|
this.observer.forceFlush();
|
|
7041
7089
|
let updated = null;
|
|
7042
|
-
let sDOM = this.scrollDOM,
|
|
7090
|
+
let sDOM = this.scrollDOM, scrollTop = sDOM.scrollTop * this.scaleY;
|
|
7043
7091
|
let { scrollAnchorPos, scrollAnchorHeight } = this.viewState;
|
|
7044
|
-
if (scrollTop
|
|
7092
|
+
if (Math.abs(scrollTop - this.viewState.scrollTop) > 1)
|
|
7045
7093
|
scrollAnchorHeight = -1;
|
|
7046
7094
|
this.viewState.scrollAnchorHeight = -1;
|
|
7047
7095
|
try {
|
|
@@ -7118,7 +7166,8 @@ class EditorView {
|
|
|
7118
7166
|
this.viewState.lineBlockAt(scrollAnchorPos).top;
|
|
7119
7167
|
let diff = newAnchorHeight - scrollAnchorHeight;
|
|
7120
7168
|
if (diff > 1 || diff < -1) {
|
|
7121
|
-
scrollTop =
|
|
7169
|
+
scrollTop = scrollTop + diff;
|
|
7170
|
+
sDOM.scrollTop = scrollTop / this.scaleY;
|
|
7122
7171
|
scrollAnchorHeight = -1;
|
|
7123
7172
|
continue;
|
|
7124
7173
|
}
|
|
@@ -7245,6 +7294,16 @@ class EditorView {
|
|
|
7245
7294
|
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
|
7246
7295
|
}
|
|
7247
7296
|
/**
|
|
7297
|
+
If the editor is transformed with CSS, this provides the scale
|
|
7298
|
+
along the X axis. Otherwise, it will just be 1. Note that
|
|
7299
|
+
transforms other than translation and scaling are not supported.
|
|
7300
|
+
*/
|
|
7301
|
+
get scaleX() { return this.viewState.scaleX; }
|
|
7302
|
+
/**
|
|
7303
|
+
Provide the CSS transformed scale along the Y axis.
|
|
7304
|
+
*/
|
|
7305
|
+
get scaleY() { return this.viewState.scaleY; }
|
|
7306
|
+
/**
|
|
7248
7307
|
Find the text line or block widget at the given vertical
|
|
7249
7308
|
position (which is interpreted as relative to the [top of the
|
|
7250
7309
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)).
|
|
@@ -8035,8 +8094,8 @@ class RectangleMarker {
|
|
|
8035
8094
|
}
|
|
8036
8095
|
function getBase(view) {
|
|
8037
8096
|
let rect = view.scrollDOM.getBoundingClientRect();
|
|
8038
|
-
let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
|
|
8039
|
-
return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop };
|
|
8097
|
+
let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth * view.scaleX;
|
|
8098
|
+
return { left: left - view.scrollDOM.scrollLeft * view.scaleX, top: rect.top - view.scrollDOM.scrollTop * view.scaleY };
|
|
8040
8099
|
}
|
|
8041
8100
|
function wrappedLine(view, pos, inside) {
|
|
8042
8101
|
let range = EditorSelection.cursor(pos);
|
|
@@ -8138,6 +8197,8 @@ class LayerView {
|
|
|
8138
8197
|
this.view = view;
|
|
8139
8198
|
this.layer = layer;
|
|
8140
8199
|
this.drawn = [];
|
|
8200
|
+
this.scaleX = 1;
|
|
8201
|
+
this.scaleY = 1;
|
|
8141
8202
|
this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
|
|
8142
8203
|
this.dom = view.scrollDOM.appendChild(document.createElement("div"));
|
|
8143
8204
|
this.dom.classList.add("cm-layer");
|
|
@@ -8145,6 +8206,7 @@ class LayerView {
|
|
|
8145
8206
|
this.dom.classList.add("cm-layer-above");
|
|
8146
8207
|
if (layer.class)
|
|
8147
8208
|
this.dom.classList.add(layer.class);
|
|
8209
|
+
this.scale();
|
|
8148
8210
|
this.dom.setAttribute("aria-hidden", "true");
|
|
8149
8211
|
this.setOrder(view.state);
|
|
8150
8212
|
view.requestMeasure(this.measureReq);
|
|
@@ -8154,8 +8216,10 @@ class LayerView {
|
|
|
8154
8216
|
update(update) {
|
|
8155
8217
|
if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
|
|
8156
8218
|
this.setOrder(update.state);
|
|
8157
|
-
if (this.layer.update(update, this.dom) || update.geometryChanged)
|
|
8219
|
+
if (this.layer.update(update, this.dom) || update.geometryChanged) {
|
|
8220
|
+
this.scale();
|
|
8158
8221
|
update.view.requestMeasure(this.measureReq);
|
|
8222
|
+
}
|
|
8159
8223
|
}
|
|
8160
8224
|
setOrder(state) {
|
|
8161
8225
|
let pos = 0, order = state.facet(layerOrder);
|
|
@@ -8166,6 +8230,14 @@ class LayerView {
|
|
|
8166
8230
|
measure() {
|
|
8167
8231
|
return this.layer.markers(this.view);
|
|
8168
8232
|
}
|
|
8233
|
+
scale() {
|
|
8234
|
+
let { scaleX, scaleY } = this.view;
|
|
8235
|
+
if (scaleX != this.scaleX || scaleY != this.scaleY) {
|
|
8236
|
+
this.scaleX = scaleX;
|
|
8237
|
+
this.scaleY = scaleY;
|
|
8238
|
+
this.dom.style.transform = `scale(${1 / scaleX}, ${1 / scaleY})`;
|
|
8239
|
+
}
|
|
8240
|
+
}
|
|
8169
8241
|
draw(markers) {
|
|
8170
8242
|
if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
|
|
8171
8243
|
let old = this.dom.firstChild, oldI = 0;
|
|
@@ -8335,23 +8407,25 @@ const drawDropCursor = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
8335
8407
|
}
|
|
8336
8408
|
}
|
|
8337
8409
|
readPos() {
|
|
8338
|
-
let
|
|
8339
|
-
let
|
|
8410
|
+
let { view } = this;
|
|
8411
|
+
let pos = view.state.field(dropCursorPos);
|
|
8412
|
+
let rect = pos != null && view.coordsAtPos(pos);
|
|
8340
8413
|
if (!rect)
|
|
8341
8414
|
return null;
|
|
8342
|
-
let outer =
|
|
8415
|
+
let outer = view.scrollDOM.getBoundingClientRect();
|
|
8343
8416
|
return {
|
|
8344
|
-
left: rect.left - outer.left +
|
|
8345
|
-
top: rect.top - outer.top +
|
|
8417
|
+
left: rect.left - outer.left + view.scrollDOM.scrollLeft * view.scaleX,
|
|
8418
|
+
top: rect.top - outer.top + view.scrollDOM.scrollTop * view.scaleY,
|
|
8346
8419
|
height: rect.bottom - rect.top
|
|
8347
8420
|
};
|
|
8348
8421
|
}
|
|
8349
8422
|
drawCursor(pos) {
|
|
8350
8423
|
if (this.cursor) {
|
|
8424
|
+
let { scaleX, scaleY } = this.view;
|
|
8351
8425
|
if (pos) {
|
|
8352
|
-
this.cursor.style.left = pos.left + "px";
|
|
8353
|
-
this.cursor.style.top = pos.top + "px";
|
|
8354
|
-
this.cursor.style.height = pos.height + "px";
|
|
8426
|
+
this.cursor.style.left = pos.left / scaleX + "px";
|
|
8427
|
+
this.cursor.style.top = pos.top / scaleY + "px";
|
|
8428
|
+
this.cursor.style.height = pos.height / scaleY + "px";
|
|
8355
8429
|
}
|
|
8356
8430
|
else {
|
|
8357
8431
|
this.cursor.style.left = "-100000px";
|
|
@@ -8593,7 +8667,9 @@ function specialCharPlugin() {
|
|
|
8593
8667
|
if (code == 9) {
|
|
8594
8668
|
let line = doc.lineAt(pos);
|
|
8595
8669
|
let size = view.state.tabSize, col = countColumn(line.text, size, pos - line.from);
|
|
8596
|
-
return Decoration.replace({
|
|
8670
|
+
return Decoration.replace({
|
|
8671
|
+
widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth / this.view.scaleX)
|
|
8672
|
+
});
|
|
8597
8673
|
}
|
|
8598
8674
|
return this.decorationCache[code] ||
|
|
8599
8675
|
(this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) }));
|
|
@@ -8670,7 +8746,8 @@ const plugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
8670
8746
|
}
|
|
8671
8747
|
update(update) {
|
|
8672
8748
|
let { view } = update;
|
|
8673
|
-
let height = view.viewState.editorHeight
|
|
8749
|
+
let height = view.viewState.editorHeight * view.scaleY -
|
|
8750
|
+
view.defaultLineHeight - view.documentPadding.top - 0.5;
|
|
8674
8751
|
if (height >= 0 && height != this.height) {
|
|
8675
8752
|
this.height = height;
|
|
8676
8753
|
this.attrs = { style: `padding-bottom: ${height}px` };
|
|
@@ -8967,6 +9044,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
8967
9044
|
constructor(view) {
|
|
8968
9045
|
this.view = view;
|
|
8969
9046
|
this.inView = true;
|
|
9047
|
+
this.madeAbsolute = false;
|
|
8970
9048
|
this.lastTransaction = 0;
|
|
8971
9049
|
this.measureTimeout = -1;
|
|
8972
9050
|
let config = view.state.facet(tooltipConfig);
|
|
@@ -9018,7 +9096,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9018
9096
|
this.observeIntersection();
|
|
9019
9097
|
let shouldMeasure = updated || update.geometryChanged;
|
|
9020
9098
|
let newConfig = update.state.facet(tooltipConfig);
|
|
9021
|
-
if (newConfig.position != this.position) {
|
|
9099
|
+
if (newConfig.position != this.position && !this.madeAbsolute) {
|
|
9022
9100
|
this.position = newConfig.position;
|
|
9023
9101
|
for (let t of this.manager.tooltipViews)
|
|
9024
9102
|
t.dom.style.position = this.position;
|
|
@@ -9066,6 +9144,27 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9066
9144
|
}
|
|
9067
9145
|
readMeasure() {
|
|
9068
9146
|
let editor = this.view.dom.getBoundingClientRect();
|
|
9147
|
+
let scaleX = 1, scaleY = 1, makeAbsolute = false;
|
|
9148
|
+
if (this.position == "fixed") {
|
|
9149
|
+
let views = this.manager.tooltipViews;
|
|
9150
|
+
// When the dialog's offset parent isn't the body, we are
|
|
9151
|
+
// probably in a transformed container, and should use absolute
|
|
9152
|
+
// positioning instead, since fixed positioning inside a
|
|
9153
|
+
// transform works in a very broken way.
|
|
9154
|
+
makeAbsolute = views.length > 0 && views[0].dom.offsetParent != this.container.ownerDocument.body;
|
|
9155
|
+
}
|
|
9156
|
+
if (makeAbsolute || this.position == "absolute") {
|
|
9157
|
+
if (this.parent) {
|
|
9158
|
+
let rect = this.parent.getBoundingClientRect();
|
|
9159
|
+
if (rect.width && rect.height) {
|
|
9160
|
+
scaleX = rect.width / this.parent.offsetWidth;
|
|
9161
|
+
scaleY = rect.height / this.parent.offsetHeight;
|
|
9162
|
+
}
|
|
9163
|
+
}
|
|
9164
|
+
else {
|
|
9165
|
+
({ scaleX, scaleY } = this.view.viewState);
|
|
9166
|
+
}
|
|
9167
|
+
}
|
|
9069
9168
|
return {
|
|
9070
9169
|
editor,
|
|
9071
9170
|
parent: this.parent ? this.container.getBoundingClientRect() : editor,
|
|
@@ -9075,11 +9174,18 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9075
9174
|
}),
|
|
9076
9175
|
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
9077
9176
|
space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
|
|
9177
|
+
scaleX, scaleY, makeAbsolute
|
|
9078
9178
|
};
|
|
9079
9179
|
}
|
|
9080
9180
|
writeMeasure(measured) {
|
|
9081
9181
|
var _a;
|
|
9082
|
-
|
|
9182
|
+
if (measured.makeAbsolute) {
|
|
9183
|
+
this.madeAbsolute = true;
|
|
9184
|
+
this.position = "absolute";
|
|
9185
|
+
for (let t of this.manager.tooltipViews)
|
|
9186
|
+
t.dom.style.position = "absolute";
|
|
9187
|
+
}
|
|
9188
|
+
let { editor, space, scaleX, scaleY } = measured;
|
|
9083
9189
|
let others = [];
|
|
9084
9190
|
for (let i = 0; i < this.manager.tooltips.length; i++) {
|
|
9085
9191
|
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
|
@@ -9112,7 +9218,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9112
9218
|
continue;
|
|
9113
9219
|
}
|
|
9114
9220
|
knownHeight.set(tView, height);
|
|
9115
|
-
dom.style.height = (height = spaceVert) + "px";
|
|
9221
|
+
dom.style.height = (height = spaceVert) / scaleY + "px";
|
|
9116
9222
|
}
|
|
9117
9223
|
else if (dom.style.height) {
|
|
9118
9224
|
dom.style.height = "";
|
|
@@ -9124,15 +9230,17 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9124
9230
|
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
9125
9231
|
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
9126
9232
|
if (this.position == "absolute") {
|
|
9127
|
-
dom.style.top = (top - measured.parent.top) + "px";
|
|
9128
|
-
dom.style.left = (left - measured.parent.left) + "px";
|
|
9233
|
+
dom.style.top = (top - measured.parent.top) / scaleY + "px";
|
|
9234
|
+
dom.style.left = (left - measured.parent.left) / scaleX + "px";
|
|
9129
9235
|
}
|
|
9130
9236
|
else {
|
|
9131
|
-
dom.style.top = top + "px";
|
|
9132
|
-
dom.style.left = left + "px";
|
|
9237
|
+
dom.style.top = top / scaleY + "px";
|
|
9238
|
+
dom.style.left = left / scaleX + "px";
|
|
9239
|
+
}
|
|
9240
|
+
if (arrow) {
|
|
9241
|
+
let arrowLeft = pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */);
|
|
9242
|
+
arrow.style.left = arrowLeft / scaleX + "px";
|
|
9133
9243
|
}
|
|
9134
|
-
if (arrow)
|
|
9135
|
-
arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Arrow.Offset */ - 7 /* Arrow.Size */)}px`;
|
|
9136
9244
|
if (tView.overlap !== true)
|
|
9137
9245
|
others.push({ left, top, right, bottom: top + height });
|
|
9138
9246
|
dom.classList.toggle("cm-tooltip-above", above);
|
|
@@ -9365,7 +9473,7 @@ class HoverPlugin {
|
|
|
9365
9473
|
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
9366
9474
|
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
9367
9475
|
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
9368
|
-
: !isOverRange(this.view, pos, end, event.clientX, event.clientY
|
|
9476
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY))) {
|
|
9369
9477
|
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
9370
9478
|
this.pending = null;
|
|
9371
9479
|
}
|
|
@@ -9390,19 +9498,12 @@ function isInTooltip(elt) {
|
|
|
9390
9498
|
return false;
|
|
9391
9499
|
}
|
|
9392
9500
|
function isOverRange(view, from, to, x, y, margin) {
|
|
9393
|
-
let
|
|
9394
|
-
let
|
|
9395
|
-
|
|
9396
|
-
|
|
9397
|
-
let
|
|
9398
|
-
|
|
9399
|
-
for (let i = 0; i < rects.length; i++) {
|
|
9400
|
-
let rect = rects[i];
|
|
9401
|
-
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
9402
|
-
if (dist <= margin)
|
|
9403
|
-
return true;
|
|
9404
|
-
}
|
|
9405
|
-
return false;
|
|
9501
|
+
let rect = view.scrollDOM.getBoundingClientRect();
|
|
9502
|
+
let docBottom = view.documentTop + view.documentPadding.top + view.contentHeight;
|
|
9503
|
+
if (rect.left > x || rect.right < x || rect.top > y || Math.min(rect.bottom, docBottom) < y)
|
|
9504
|
+
return false;
|
|
9505
|
+
let pos = view.posAtCoords({ x, y }, false);
|
|
9506
|
+
return pos >= from && pos <= to;
|
|
9406
9507
|
}
|
|
9407
9508
|
/**
|
|
9408
9509
|
Set up a hover tooltip, which shows up when the pointer hovers
|
|
@@ -9741,7 +9842,7 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9741
9842
|
this.dom = document.createElement("div");
|
|
9742
9843
|
this.dom.className = "cm-gutters";
|
|
9743
9844
|
this.dom.setAttribute("aria-hidden", "true");
|
|
9744
|
-
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
9845
|
+
this.dom.style.minHeight = (this.view.contentHeight / this.view.scaleY) + "px";
|
|
9745
9846
|
this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
|
|
9746
9847
|
for (let gutter of this.gutters)
|
|
9747
9848
|
this.dom.appendChild(gutter.dom);
|
|
@@ -9851,7 +9952,9 @@ const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9851
9952
|
let value = view.plugin(plugin);
|
|
9852
9953
|
if (!value || value.gutters.length == 0 || !value.fixed)
|
|
9853
9954
|
return null;
|
|
9854
|
-
return view.textDirection == Direction.LTR
|
|
9955
|
+
return view.textDirection == Direction.LTR
|
|
9956
|
+
? { left: value.dom.offsetWidth * view.scaleX }
|
|
9957
|
+
: { right: value.dom.offsetWidth * view.scaleX };
|
|
9855
9958
|
})
|
|
9856
9959
|
});
|
|
9857
9960
|
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
|
|
@@ -9968,10 +10071,12 @@ class GutterElement {
|
|
|
9968
10071
|
this.update(view, height, above, markers);
|
|
9969
10072
|
}
|
|
9970
10073
|
update(view, height, above, markers) {
|
|
9971
|
-
if (this.height != height)
|
|
9972
|
-
this.
|
|
10074
|
+
if (this.height != height) {
|
|
10075
|
+
this.height = height;
|
|
10076
|
+
this.dom.style.height = height / view.scaleY + "px";
|
|
10077
|
+
}
|
|
9973
10078
|
if (this.above != above)
|
|
9974
|
-
this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
|
|
10079
|
+
this.dom.style.marginTop = (this.above = above) ? above / view.scaleY + "px" : "";
|
|
9975
10080
|
if (!sameMarkers(this.markers, markers))
|
|
9976
10081
|
this.setMarkers(view, markers);
|
|
9977
10082
|
}
|