@codemirror/view 0.19.46 → 0.20.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 +50 -0
- package/dist/index.cjs +1644 -405
- package/dist/index.d.ts +533 -247
- package/dist/index.js +1604 -379
- package/package.json +2 -4
package/dist/index.cjs
CHANGED
|
@@ -4,8 +4,6 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
4
4
|
|
|
5
5
|
var state = require('@codemirror/state');
|
|
6
6
|
var styleMod = require('style-mod');
|
|
7
|
-
var rangeset = require('@codemirror/rangeset');
|
|
8
|
-
var text = require('@codemirror/text');
|
|
9
7
|
var w3cKeyname = require('w3c-keyname');
|
|
10
8
|
|
|
11
9
|
function getSelection(root) {
|
|
@@ -318,32 +316,34 @@ class ContentView {
|
|
|
318
316
|
sync(track) {
|
|
319
317
|
if (this.dirty & 2 /* Node */) {
|
|
320
318
|
let parent = this.dom;
|
|
321
|
-
let
|
|
319
|
+
let prev = null, next;
|
|
322
320
|
for (let child of this.children) {
|
|
323
321
|
if (child.dirty) {
|
|
324
|
-
if (!child.dom &&
|
|
325
|
-
let contentView = ContentView.get(
|
|
322
|
+
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
|
323
|
+
let contentView = ContentView.get(next);
|
|
326
324
|
if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
|
|
327
|
-
child.reuseDOM(
|
|
325
|
+
child.reuseDOM(next);
|
|
328
326
|
}
|
|
329
327
|
child.sync(track);
|
|
330
328
|
child.dirty = 0 /* Not */;
|
|
331
329
|
}
|
|
332
|
-
|
|
330
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
331
|
+
if (track && !track.written && track.node == parent && next != child.dom)
|
|
333
332
|
track.written = true;
|
|
334
333
|
if (child.dom.parentNode == parent) {
|
|
335
|
-
while (
|
|
336
|
-
|
|
337
|
-
pos = child.dom.nextSibling;
|
|
334
|
+
while (next && next != child.dom)
|
|
335
|
+
next = rm$1(next);
|
|
338
336
|
}
|
|
339
337
|
else {
|
|
340
|
-
parent.insertBefore(child.dom,
|
|
338
|
+
parent.insertBefore(child.dom, next);
|
|
341
339
|
}
|
|
340
|
+
prev = child.dom;
|
|
342
341
|
}
|
|
343
|
-
|
|
342
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
343
|
+
if (next && track && track.node == parent)
|
|
344
344
|
track.written = true;
|
|
345
|
-
while (
|
|
346
|
-
|
|
345
|
+
while (next)
|
|
346
|
+
next = rm$1(next);
|
|
347
347
|
}
|
|
348
348
|
else if (this.dirty & 1 /* Child */) {
|
|
349
349
|
for (let child of this.children)
|
|
@@ -489,7 +489,7 @@ class ContentView {
|
|
|
489
489
|
}
|
|
490
490
|
ContentView.prototype.breakAfter = 0;
|
|
491
491
|
// Remove a DOM node and return its next sibling.
|
|
492
|
-
function rm(dom) {
|
|
492
|
+
function rm$1(dom) {
|
|
493
493
|
let next = dom.nextSibling;
|
|
494
494
|
dom.parentNode.removeChild(dom);
|
|
495
495
|
return next;
|
|
@@ -825,12 +825,12 @@ class WidgetView extends ContentView {
|
|
|
825
825
|
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
826
826
|
get overrideDOMText() {
|
|
827
827
|
if (this.length == 0)
|
|
828
|
-
return
|
|
828
|
+
return state.Text.empty;
|
|
829
829
|
let top = this;
|
|
830
830
|
while (top.parent)
|
|
831
831
|
top = top.parent;
|
|
832
|
-
let view = top.editorView, text
|
|
833
|
-
return text
|
|
832
|
+
let view = top.editorView, text = view && view.state.doc, start = this.posAtStart;
|
|
833
|
+
return text ? text.slice(start, start + this.length) : state.Text.empty;
|
|
834
834
|
}
|
|
835
835
|
domAtPos(pos) {
|
|
836
836
|
return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
|
|
@@ -936,6 +936,7 @@ class WidgetBufferView extends ContentView {
|
|
|
936
936
|
if (!this.dom) {
|
|
937
937
|
let dom = document.createElement("img");
|
|
938
938
|
dom.className = "cm-widgetBuffer";
|
|
939
|
+
dom.setAttribute("aria-hidden", "true");
|
|
939
940
|
this.setDOM(dom);
|
|
940
941
|
}
|
|
941
942
|
}
|
|
@@ -952,7 +953,7 @@ class WidgetBufferView extends ContentView {
|
|
|
952
953
|
? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect;
|
|
953
954
|
}
|
|
954
955
|
get overrideDOMText() {
|
|
955
|
-
return
|
|
956
|
+
return state.Text.empty;
|
|
956
957
|
}
|
|
957
958
|
}
|
|
958
959
|
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
@@ -1076,7 +1077,7 @@ function updateAttrs(dom, prev, attrs) {
|
|
|
1076
1077
|
Widgets added to the content are described by subclasses of this
|
|
1077
1078
|
class. Using a description object like that makes it possible to
|
|
1078
1079
|
delay creating of the DOM structure for a widget until it is
|
|
1079
|
-
needed, and to avoid redrawing widgets even
|
|
1080
|
+
needed, and to avoid redrawing widgets even if the decorations
|
|
1080
1081
|
that define them are recreated.
|
|
1081
1082
|
*/
|
|
1082
1083
|
class WidgetType {
|
|
@@ -1089,7 +1090,7 @@ class WidgetType {
|
|
|
1089
1090
|
returns `false`, which will cause new instances of the widget to
|
|
1090
1091
|
always be redrawn.
|
|
1091
1092
|
*/
|
|
1092
|
-
eq(
|
|
1093
|
+
eq(widget) { return false; }
|
|
1093
1094
|
/**
|
|
1094
1095
|
Update a DOM element created by a widget of the same type (but
|
|
1095
1096
|
different, non-`eq` content) to reflect this widget. May return
|
|
@@ -1097,7 +1098,7 @@ class WidgetType {
|
|
|
1097
1098
|
couldn't (in which case the widget will be redrawn). The default
|
|
1098
1099
|
implementation just returns false.
|
|
1099
1100
|
*/
|
|
1100
|
-
updateDOM(
|
|
1101
|
+
updateDOM(dom) { return false; }
|
|
1101
1102
|
/**
|
|
1102
1103
|
@internal
|
|
1103
1104
|
*/
|
|
@@ -1116,7 +1117,7 @@ class WidgetType {
|
|
|
1116
1117
|
should be ignored by the editor. The default is to ignore all
|
|
1117
1118
|
events.
|
|
1118
1119
|
*/
|
|
1119
|
-
ignoreEvent(
|
|
1120
|
+
ignoreEvent(event) { return true; }
|
|
1120
1121
|
/**
|
|
1121
1122
|
@internal
|
|
1122
1123
|
*/
|
|
@@ -1125,7 +1126,7 @@ class WidgetType {
|
|
|
1125
1126
|
This is called when the an instance of the widget is removed
|
|
1126
1127
|
from the editor view.
|
|
1127
1128
|
*/
|
|
1128
|
-
destroy(
|
|
1129
|
+
destroy(dom) { }
|
|
1129
1130
|
}
|
|
1130
1131
|
/**
|
|
1131
1132
|
The different types of blocks that can occur in an editor view.
|
|
@@ -1152,9 +1153,10 @@ exports.BlockType = void 0;
|
|
|
1152
1153
|
/**
|
|
1153
1154
|
A decoration provides information on how to draw or style a piece
|
|
1154
1155
|
of content. You'll usually use it wrapped in a
|
|
1155
|
-
[`Range`](https://codemirror.net/6/docs/ref/#
|
|
1156
|
+
[`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position.
|
|
1157
|
+
@nonabstract
|
|
1156
1158
|
*/
|
|
1157
|
-
class Decoration extends
|
|
1159
|
+
class Decoration extends state.RangeValue {
|
|
1158
1160
|
/**
|
|
1159
1161
|
@internal
|
|
1160
1162
|
*/
|
|
@@ -1191,22 +1193,21 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1191
1193
|
Create a mark decoration, which influences the styling of the
|
|
1192
1194
|
content in its range. Nested mark decorations will cause nested
|
|
1193
1195
|
DOM elements to be created. Nesting order is determined by
|
|
1194
|
-
precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations)
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
decorations.
|
|
1196
|
+
precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
|
|
1197
|
+
the higher-precedence decorations creating the inner DOM nodes.
|
|
1198
|
+
Such elements are split on line boundaries and on the boundaries
|
|
1199
|
+
of lower-precedence decorations.
|
|
1199
1200
|
*/
|
|
1200
1201
|
static mark(spec) {
|
|
1201
1202
|
return new MarkDecoration(spec);
|
|
1202
1203
|
}
|
|
1203
1204
|
/**
|
|
1204
|
-
Create a widget decoration, which
|
|
1205
|
-
position.
|
|
1205
|
+
Create a widget decoration, which displays a DOM element at the
|
|
1206
|
+
given position.
|
|
1206
1207
|
*/
|
|
1207
1208
|
static widget(spec) {
|
|
1208
1209
|
let side = spec.side || 0, block = !!spec.block;
|
|
1209
|
-
side += block ? (side > 0 ?
|
|
1210
|
+
side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
|
|
1210
1211
|
return new PointDecoration(spec, side, side, block, spec.widget || null, false);
|
|
1211
1212
|
}
|
|
1212
1213
|
/**
|
|
@@ -1216,8 +1217,8 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1216
1217
|
static replace(spec) {
|
|
1217
1218
|
let block = !!spec.block, startSide, endSide;
|
|
1218
1219
|
if (spec.isBlockGap) {
|
|
1219
|
-
startSide = -
|
|
1220
|
-
endSide =
|
|
1220
|
+
startSide = -500000000 /* GapStart */;
|
|
1221
|
+
endSide = 400000000 /* GapEnd */;
|
|
1221
1222
|
}
|
|
1222
1223
|
else {
|
|
1223
1224
|
let { start, end } = getInclusive(spec, block);
|
|
@@ -1239,7 +1240,7 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1239
1240
|
pass `true` for `sort` to make the library sort them for you.
|
|
1240
1241
|
*/
|
|
1241
1242
|
static set(of, sort = false) {
|
|
1242
|
-
return
|
|
1243
|
+
return state.RangeSet.of(of, sort);
|
|
1243
1244
|
}
|
|
1244
1245
|
/**
|
|
1245
1246
|
@internal
|
|
@@ -1249,7 +1250,7 @@ class Decoration extends rangeset.RangeValue {
|
|
|
1249
1250
|
/**
|
|
1250
1251
|
The empty set of decorations.
|
|
1251
1252
|
*/
|
|
1252
|
-
Decoration.none =
|
|
1253
|
+
Decoration.none = state.RangeSet.empty;
|
|
1253
1254
|
class MarkDecoration extends Decoration {
|
|
1254
1255
|
constructor(spec) {
|
|
1255
1256
|
let { start, end } = getInclusive(spec);
|
|
@@ -1434,7 +1435,7 @@ class LineView extends ContentView {
|
|
|
1434
1435
|
let last = this.dom.lastChild;
|
|
1435
1436
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1436
1437
|
last = last.lastChild;
|
|
1437
|
-
if (!last ||
|
|
1438
|
+
if (!last || !this.length ||
|
|
1438
1439
|
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1439
1440
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1440
1441
|
let hack = document.createElement("BR");
|
|
@@ -1540,11 +1541,11 @@ class BlockWidgetView extends ContentView {
|
|
|
1540
1541
|
}
|
|
1541
1542
|
|
|
1542
1543
|
class ContentBuilder {
|
|
1543
|
-
constructor(doc, pos, end,
|
|
1544
|
+
constructor(doc, pos, end, disallowBlockEffectsFor) {
|
|
1544
1545
|
this.doc = doc;
|
|
1545
1546
|
this.pos = pos;
|
|
1546
1547
|
this.end = end;
|
|
1547
|
-
this.
|
|
1548
|
+
this.disallowBlockEffectsFor = disallowBlockEffectsFor;
|
|
1548
1549
|
this.content = [];
|
|
1549
1550
|
this.curLine = null;
|
|
1550
1551
|
this.breakAtStart = 0;
|
|
@@ -1629,7 +1630,13 @@ class ContentBuilder {
|
|
|
1629
1630
|
if (this.openStart < 0)
|
|
1630
1631
|
this.openStart = openStart;
|
|
1631
1632
|
}
|
|
1632
|
-
point(from, to, deco, active, openStart) {
|
|
1633
|
+
point(from, to, deco, active, openStart, index) {
|
|
1634
|
+
if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
|
|
1635
|
+
if (deco.block)
|
|
1636
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1637
|
+
if (to > this.doc.lineAt(this.pos).to)
|
|
1638
|
+
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1639
|
+
}
|
|
1633
1640
|
let len = to - from;
|
|
1634
1641
|
if (deco instanceof PointDecoration) {
|
|
1635
1642
|
if (deco.block) {
|
|
@@ -1673,18 +1680,9 @@ class ContentBuilder {
|
|
|
1673
1680
|
if (this.openStart < 0)
|
|
1674
1681
|
this.openStart = openStart;
|
|
1675
1682
|
}
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1680
|
-
if (to > this.doc.lineAt(this.pos).to)
|
|
1681
|
-
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1682
|
-
}
|
|
1683
|
-
return true;
|
|
1684
|
-
}
|
|
1685
|
-
static build(text, from, to, decorations, pluginDecorationLength) {
|
|
1686
|
-
let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
|
|
1687
|
-
builder.openEnd = rangeset.RangeSet.spans(decorations, from, to, builder);
|
|
1683
|
+
static build(text, from, to, decorations, dynamicDecorationMap) {
|
|
1684
|
+
let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
|
|
1685
|
+
builder.openEnd = state.RangeSet.spans(decorations, from, to, builder);
|
|
1688
1686
|
if (builder.openStart < 0)
|
|
1689
1687
|
builder.openStart = builder.openEnd;
|
|
1690
1688
|
builder.finish(builder.openEnd);
|
|
@@ -1713,13 +1711,8 @@ const mouseSelectionStyle = state.Facet.define();
|
|
|
1713
1711
|
const exceptionSink = state.Facet.define();
|
|
1714
1712
|
const updateListener = state.Facet.define();
|
|
1715
1713
|
const inputHandler = state.Facet.define();
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
map: (range, changes) => range.map(changes)
|
|
1719
|
-
});
|
|
1720
|
-
// FIXME remove
|
|
1721
|
-
const centerOn = state.StateEffect.define({
|
|
1722
|
-
map: (range, changes) => range.map(changes)
|
|
1714
|
+
const perLineTextDirection = state.Facet.define({
|
|
1715
|
+
combine: values => values.some(x => x)
|
|
1723
1716
|
});
|
|
1724
1717
|
class ScrollTarget {
|
|
1725
1718
|
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
|
|
@@ -1758,83 +1751,6 @@ function logException(state, exception, context) {
|
|
|
1758
1751
|
console.error(exception);
|
|
1759
1752
|
}
|
|
1760
1753
|
const editable = state.Facet.define({ combine: values => values.length ? values[0] : true });
|
|
1761
|
-
/**
|
|
1762
|
-
Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which
|
|
1763
|
-
[fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin)
|
|
1764
|
-
provides.
|
|
1765
|
-
*/
|
|
1766
|
-
class PluginFieldProvider {
|
|
1767
|
-
/**
|
|
1768
|
-
@internal
|
|
1769
|
-
*/
|
|
1770
|
-
constructor(
|
|
1771
|
-
/**
|
|
1772
|
-
@internal
|
|
1773
|
-
*/
|
|
1774
|
-
field,
|
|
1775
|
-
/**
|
|
1776
|
-
@internal
|
|
1777
|
-
*/
|
|
1778
|
-
get) {
|
|
1779
|
-
this.field = field;
|
|
1780
|
-
this.get = get;
|
|
1781
|
-
}
|
|
1782
|
-
}
|
|
1783
|
-
/**
|
|
1784
|
-
Plugin fields are a mechanism for allowing plugins to provide
|
|
1785
|
-
values that can be retrieved through the
|
|
1786
|
-
[`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method.
|
|
1787
|
-
*/
|
|
1788
|
-
class PluginField {
|
|
1789
|
-
/**
|
|
1790
|
-
Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field,
|
|
1791
|
-
to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide)
|
|
1792
|
-
option.
|
|
1793
|
-
*/
|
|
1794
|
-
from(get) {
|
|
1795
|
-
return new PluginFieldProvider(this, get);
|
|
1796
|
-
}
|
|
1797
|
-
/**
|
|
1798
|
-
Define a new plugin field.
|
|
1799
|
-
*/
|
|
1800
|
-
static define() { return new PluginField(); }
|
|
1801
|
-
}
|
|
1802
|
-
/**
|
|
1803
|
-
This field can be used by plugins to provide
|
|
1804
|
-
[decorations](https://codemirror.net/6/docs/ref/#view.Decoration).
|
|
1805
|
-
|
|
1806
|
-
**Note**: For reasons of data flow (plugins are only updated
|
|
1807
|
-
after the viewport is computed), decorations produced by plugins
|
|
1808
|
-
are _not_ taken into account when predicting the vertical layout
|
|
1809
|
-
structure of the editor. They **must not** introduce block
|
|
1810
|
-
widgets (that will raise an error) or replacing decorations that
|
|
1811
|
-
cover line breaks (these will be ignored if they occur). Such
|
|
1812
|
-
decorations, or others that cause a large amount of vertical
|
|
1813
|
-
size shift compared to the undecorated content, should be
|
|
1814
|
-
provided through the state-level [`decorations`
|
|
1815
|
-
facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
|
|
1816
|
-
*/
|
|
1817
|
-
PluginField.decorations = PluginField.define();
|
|
1818
|
-
/**
|
|
1819
|
-
Used to provide ranges that should be treated as atoms as far as
|
|
1820
|
-
cursor motion is concerned. This causes methods like
|
|
1821
|
-
[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
|
|
1822
|
-
[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
|
|
1823
|
-
commands built on top of them) to skip across such regions when
|
|
1824
|
-
a selection endpoint would enter them. This does _not_ prevent
|
|
1825
|
-
direct programmatic [selection
|
|
1826
|
-
updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
|
|
1827
|
-
regions.
|
|
1828
|
-
*/
|
|
1829
|
-
PluginField.atomicRanges = PluginField.define();
|
|
1830
|
-
/**
|
|
1831
|
-
Plugins can provide additional scroll margins (space around the
|
|
1832
|
-
sides of the scrolling element that should be considered
|
|
1833
|
-
invisible) through this field. This can be useful when the
|
|
1834
|
-
plugin introduces elements that cover part of that element (for
|
|
1835
|
-
example a horizontally fixed gutter).
|
|
1836
|
-
*/
|
|
1837
|
-
PluginField.scrollMargins = PluginField.define();
|
|
1838
1754
|
let nextPluginID = 0;
|
|
1839
1755
|
const viewPlugin = state.Facet.define();
|
|
1840
1756
|
/**
|
|
@@ -1855,27 +1771,29 @@ class ViewPlugin {
|
|
|
1855
1771
|
/**
|
|
1856
1772
|
@internal
|
|
1857
1773
|
*/
|
|
1858
|
-
|
|
1774
|
+
domEventHandlers, buildExtensions) {
|
|
1859
1775
|
this.id = id;
|
|
1860
1776
|
this.create = create;
|
|
1861
|
-
this.
|
|
1862
|
-
this.extension =
|
|
1777
|
+
this.domEventHandlers = domEventHandlers;
|
|
1778
|
+
this.extension = buildExtensions(this);
|
|
1863
1779
|
}
|
|
1864
1780
|
/**
|
|
1865
1781
|
Define a plugin from a constructor function that creates the
|
|
1866
1782
|
plugin's value, given an editor view.
|
|
1867
1783
|
*/
|
|
1868
1784
|
static define(create, spec) {
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1785
|
+
const { eventHandlers, provide, decorations: deco } = spec || {};
|
|
1786
|
+
return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
|
|
1787
|
+
let ext = [viewPlugin.of(plugin)];
|
|
1788
|
+
if (deco)
|
|
1789
|
+
ext.push(decorations.of(view => {
|
|
1790
|
+
let pluginInst = view.plugin(plugin);
|
|
1791
|
+
return pluginInst ? deco(pluginInst) : Decoration.none;
|
|
1792
|
+
}));
|
|
1793
|
+
if (provide)
|
|
1794
|
+
ext.push(provide(plugin));
|
|
1795
|
+
return ext;
|
|
1796
|
+
});
|
|
1879
1797
|
}
|
|
1880
1798
|
/**
|
|
1881
1799
|
Create a plugin for a class whose constructor takes a single
|
|
@@ -1885,7 +1803,6 @@ class ViewPlugin {
|
|
|
1885
1803
|
return ViewPlugin.define(view => new cls(view), spec);
|
|
1886
1804
|
}
|
|
1887
1805
|
}
|
|
1888
|
-
const domEventHandlers = PluginField.define();
|
|
1889
1806
|
class PluginInstance {
|
|
1890
1807
|
constructor(spec) {
|
|
1891
1808
|
this.spec = spec;
|
|
@@ -1898,12 +1815,6 @@ class PluginInstance {
|
|
|
1898
1815
|
// initialized on the first update.
|
|
1899
1816
|
this.value = null;
|
|
1900
1817
|
}
|
|
1901
|
-
takeField(type, target) {
|
|
1902
|
-
if (this.spec)
|
|
1903
|
-
for (let { field, get } of this.spec.fields)
|
|
1904
|
-
if (field == type)
|
|
1905
|
-
target.push(get(this.value));
|
|
1906
|
-
}
|
|
1907
1818
|
update(view) {
|
|
1908
1819
|
if (!this.value) {
|
|
1909
1820
|
if (this.spec) {
|
|
@@ -1955,6 +1866,8 @@ const editorAttributes = state.Facet.define();
|
|
|
1955
1866
|
const contentAttributes = state.Facet.define();
|
|
1956
1867
|
// Provide decorations
|
|
1957
1868
|
const decorations = state.Facet.define();
|
|
1869
|
+
const atomicRanges = state.Facet.define();
|
|
1870
|
+
const scrollMargins = state.Facet.define();
|
|
1958
1871
|
const styleModule = state.Facet.define();
|
|
1959
1872
|
class ChangedRange {
|
|
1960
1873
|
constructor(fromA, toA, fromB, toB) {
|
|
@@ -2055,8 +1968,8 @@ class ViewUpdate {
|
|
|
2055
1968
|
return (this.flags & 4 /* Viewport */) > 0;
|
|
2056
1969
|
}
|
|
2057
1970
|
/**
|
|
2058
|
-
Indicates whether the height of
|
|
2059
|
-
in this update.
|
|
1971
|
+
Indicates whether the height of a block element in the editor
|
|
1972
|
+
changed in this update.
|
|
2060
1973
|
*/
|
|
2061
1974
|
get heightChanged() {
|
|
2062
1975
|
return (this.flags & 2 /* Height */) > 0;
|
|
@@ -2392,7 +2305,7 @@ function moveVisually(line, order, dir, start, forward) {
|
|
|
2392
2305
|
startIndex = span.side(!forward, dir);
|
|
2393
2306
|
}
|
|
2394
2307
|
let indexForward = forward == (span.dir == dir);
|
|
2395
|
-
let nextIndex =
|
|
2308
|
+
let nextIndex = state.findClusterBreak(line.text, startIndex, indexForward);
|
|
2396
2309
|
movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
|
|
2397
2310
|
if (nextIndex != span.side(forward, dir))
|
|
2398
2311
|
return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
|
|
@@ -2516,7 +2429,7 @@ class DocView extends ContentView {
|
|
|
2516
2429
|
this.view = view;
|
|
2517
2430
|
this.compositionDeco = Decoration.none;
|
|
2518
2431
|
this.decorations = [];
|
|
2519
|
-
this.
|
|
2432
|
+
this.dynamicDecorationMap = [];
|
|
2520
2433
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2521
2434
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
2522
2435
|
// of a given element and its extent in the document. When a change
|
|
@@ -2622,7 +2535,7 @@ class DocView extends ContentView {
|
|
|
2622
2535
|
if (!next)
|
|
2623
2536
|
break;
|
|
2624
2537
|
let { fromA, toA, fromB, toB } = next;
|
|
2625
|
-
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.
|
|
2538
|
+
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap);
|
|
2626
2539
|
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2627
2540
|
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2628
2541
|
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
@@ -2763,11 +2676,11 @@ class DocView extends ContentView {
|
|
|
2763
2676
|
off = start;
|
|
2764
2677
|
}
|
|
2765
2678
|
}
|
|
2766
|
-
measureVisibleLineHeights() {
|
|
2767
|
-
let result = [], { from, to } =
|
|
2679
|
+
measureVisibleLineHeights(viewport) {
|
|
2680
|
+
let result = [], { from, to } = viewport;
|
|
2768
2681
|
let contentWidth = this.view.contentDOM.clientWidth;
|
|
2769
2682
|
let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
|
|
2770
|
-
let widest = -1;
|
|
2683
|
+
let widest = -1, ltr = this.view.textDirection == exports.Direction.LTR;
|
|
2771
2684
|
for (let pos = 0, i = 0; i < this.children.length; i++) {
|
|
2772
2685
|
let child = this.children[i], end = pos + child.length;
|
|
2773
2686
|
if (end > to)
|
|
@@ -2780,8 +2693,7 @@ class DocView extends ContentView {
|
|
|
2780
2693
|
let rects = last ? clientRectsFor(last) : [];
|
|
2781
2694
|
if (rects.length) {
|
|
2782
2695
|
let rect = rects[rects.length - 1];
|
|
2783
|
-
let width =
|
|
2784
|
-
: childRect.right - rect.left;
|
|
2696
|
+
let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
|
|
2785
2697
|
if (width > widest) {
|
|
2786
2698
|
widest = width;
|
|
2787
2699
|
this.minWidth = contentWidth;
|
|
@@ -2795,6 +2707,10 @@ class DocView extends ContentView {
|
|
|
2795
2707
|
}
|
|
2796
2708
|
return result;
|
|
2797
2709
|
}
|
|
2710
|
+
textDirectionAt(pos) {
|
|
2711
|
+
let { i } = this.childPos(pos, 1);
|
|
2712
|
+
return getComputedStyle(this.children[i].dom).direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
|
|
2713
|
+
}
|
|
2798
2714
|
measureTextSize() {
|
|
2799
2715
|
for (let child of this.children) {
|
|
2800
2716
|
if (child instanceof LineView) {
|
|
@@ -2846,11 +2762,14 @@ class DocView extends ContentView {
|
|
|
2846
2762
|
return Decoration.set(deco);
|
|
2847
2763
|
}
|
|
2848
2764
|
updateDeco() {
|
|
2849
|
-
let
|
|
2850
|
-
|
|
2765
|
+
let allDeco = this.view.state.facet(decorations).map((d, i) => {
|
|
2766
|
+
let dynamic = this.dynamicDecorationMap[i] = typeof d == "function";
|
|
2767
|
+
return dynamic ? d(this.view) : d;
|
|
2768
|
+
});
|
|
2769
|
+
for (let i = allDeco.length; i < allDeco.length + 3; i++)
|
|
2770
|
+
this.dynamicDecorationMap[i] = false;
|
|
2851
2771
|
return this.decorations = [
|
|
2852
|
-
...
|
|
2853
|
-
...this.view.state.facet(decorations),
|
|
2772
|
+
...allDeco,
|
|
2854
2773
|
this.compositionDeco,
|
|
2855
2774
|
this.computeBlockGapDeco(),
|
|
2856
2775
|
this.view.viewState.lineGapDeco
|
|
@@ -2865,7 +2784,7 @@ class DocView extends ContentView {
|
|
|
2865
2784
|
rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
|
|
2866
2785
|
right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
|
|
2867
2786
|
let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
|
|
2868
|
-
for (let margins of this.view.
|
|
2787
|
+
for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
|
|
2869
2788
|
if (margins) {
|
|
2870
2789
|
let { left, right, top, bottom } = margins;
|
|
2871
2790
|
if (left != null)
|
|
@@ -3007,7 +2926,7 @@ class DecorationComparator$1 {
|
|
|
3007
2926
|
}
|
|
3008
2927
|
function findChangedDeco(a, b, diff) {
|
|
3009
2928
|
let comp = new DecorationComparator$1;
|
|
3010
|
-
|
|
2929
|
+
state.RangeSet.compare(a, b, diff, comp);
|
|
3011
2930
|
return comp.changes;
|
|
3012
2931
|
}
|
|
3013
2932
|
function inUneditable(node, inside) {
|
|
@@ -3030,18 +2949,18 @@ function groupAt(state$1, pos, bias = 1) {
|
|
|
3030
2949
|
bias = -1;
|
|
3031
2950
|
let from = linePos, to = linePos;
|
|
3032
2951
|
if (bias < 0)
|
|
3033
|
-
from =
|
|
2952
|
+
from = state.findClusterBreak(line.text, linePos, false);
|
|
3034
2953
|
else
|
|
3035
|
-
to =
|
|
2954
|
+
to = state.findClusterBreak(line.text, linePos);
|
|
3036
2955
|
let cat = categorize(line.text.slice(from, to));
|
|
3037
2956
|
while (from > 0) {
|
|
3038
|
-
let prev =
|
|
2957
|
+
let prev = state.findClusterBreak(line.text, from, false);
|
|
3039
2958
|
if (categorize(line.text.slice(prev, from)) != cat)
|
|
3040
2959
|
break;
|
|
3041
2960
|
from = prev;
|
|
3042
2961
|
}
|
|
3043
2962
|
while (to < line.length) {
|
|
3044
|
-
let next =
|
|
2963
|
+
let next = state.findClusterBreak(line.text, to);
|
|
3045
2964
|
if (categorize(line.text.slice(to, next)) != cat)
|
|
3046
2965
|
break;
|
|
3047
2966
|
to = next;
|
|
@@ -3233,7 +3152,7 @@ function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
|
3233
3152
|
into += line * view.viewState.heightOracle.lineLength;
|
|
3234
3153
|
}
|
|
3235
3154
|
let content = view.state.sliceDoc(block.from, block.to);
|
|
3236
|
-
return block.from +
|
|
3155
|
+
return block.from + state.findColumn(content, into, view.state.tabSize);
|
|
3237
3156
|
}
|
|
3238
3157
|
// In case of a high line height, Safari's caretRangeFromPoint treats
|
|
3239
3158
|
// the space between lines as belonging to the last character of the
|
|
@@ -3254,7 +3173,8 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
|
3254
3173
|
: view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
|
|
3255
3174
|
if (coords) {
|
|
3256
3175
|
let editorRect = view.dom.getBoundingClientRect();
|
|
3257
|
-
let
|
|
3176
|
+
let direction = view.textDirectionAt(line.from);
|
|
3177
|
+
let pos = view.posAtCoords({ x: forward == (direction == exports.Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
|
|
3258
3178
|
y: (coords.top + coords.bottom) / 2 });
|
|
3259
3179
|
if (pos != null)
|
|
3260
3180
|
return state.EditorSelection.cursor(pos, forward ? -1 : 1);
|
|
@@ -3265,8 +3185,9 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
|
3265
3185
|
}
|
|
3266
3186
|
function moveByChar(view, start, forward, by) {
|
|
3267
3187
|
let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
|
|
3188
|
+
let direction = view.textDirectionAt(line.from);
|
|
3268
3189
|
for (let cur = start, check = null;;) {
|
|
3269
|
-
let next = moveVisually(line, spans,
|
|
3190
|
+
let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
|
|
3270
3191
|
if (!next) {
|
|
3271
3192
|
if (line.number == (forward ? view.state.doc.lines : 1))
|
|
3272
3193
|
return cur;
|
|
@@ -3324,7 +3245,7 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3324
3245
|
}
|
|
3325
3246
|
}
|
|
3326
3247
|
function skipAtoms(view, oldPos, pos) {
|
|
3327
|
-
let atoms = view.
|
|
3248
|
+
let atoms = view.state.facet(atomicRanges).map(f => f(view));
|
|
3328
3249
|
for (;;) {
|
|
3329
3250
|
let moved = false;
|
|
3330
3251
|
for (let set of atoms) {
|
|
@@ -3372,10 +3293,10 @@ class InputState {
|
|
|
3372
3293
|
for (let type in handlers) {
|
|
3373
3294
|
let handler = handlers[type];
|
|
3374
3295
|
view.contentDOM.addEventListener(type, (event) => {
|
|
3375
|
-
if (type == "keydown" && this.keydown(view, event))
|
|
3376
|
-
return;
|
|
3377
3296
|
if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
|
|
3378
3297
|
return;
|
|
3298
|
+
if (type == "keydown" && this.keydown(view, event))
|
|
3299
|
+
return;
|
|
3379
3300
|
if (this.mustFlushObserver(event))
|
|
3380
3301
|
view.observer.forceFlush();
|
|
3381
3302
|
if (this.runCustomHandlers(type, view, event))
|
|
@@ -3386,7 +3307,6 @@ class InputState {
|
|
|
3386
3307
|
this.registeredEvents.push(type);
|
|
3387
3308
|
}
|
|
3388
3309
|
this.notifiedFocused = view.hasFocus;
|
|
3389
|
-
this.ensureHandlers(view);
|
|
3390
3310
|
// On Safari adding an input event handler somehow prevents an
|
|
3391
3311
|
// issue where the composition vanishes when you press enter.
|
|
3392
3312
|
if (browser.safari)
|
|
@@ -3396,20 +3316,23 @@ class InputState {
|
|
|
3396
3316
|
this.lastSelectionOrigin = origin;
|
|
3397
3317
|
this.lastSelectionTime = Date.now();
|
|
3398
3318
|
}
|
|
3399
|
-
ensureHandlers(view) {
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
event
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3319
|
+
ensureHandlers(view, plugins) {
|
|
3320
|
+
var _a;
|
|
3321
|
+
let handlers;
|
|
3322
|
+
for (let plugin of plugins)
|
|
3323
|
+
if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
|
|
3324
|
+
this.customHandlers.push({ plugin: plugin.value, handlers });
|
|
3325
|
+
for (let type in handlers)
|
|
3326
|
+
if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
|
|
3327
|
+
this.registeredEvents.push(type);
|
|
3328
|
+
view.contentDOM.addEventListener(type, (event) => {
|
|
3329
|
+
if (!eventBelongsToEditor(view, event))
|
|
3330
|
+
return;
|
|
3331
|
+
if (this.runCustomHandlers(type, view, event))
|
|
3332
|
+
event.preventDefault();
|
|
3333
|
+
});
|
|
3334
|
+
}
|
|
3335
|
+
}
|
|
3413
3336
|
}
|
|
3414
3337
|
runCustomHandlers(type, view, event) {
|
|
3415
3338
|
for (let set of this.customHandlers) {
|
|
@@ -3443,7 +3366,7 @@ class InputState {
|
|
|
3443
3366
|
// Must always run, even if a custom handler handled the event
|
|
3444
3367
|
this.lastKeyCode = event.keyCode;
|
|
3445
3368
|
this.lastKeyTime = Date.now();
|
|
3446
|
-
if (
|
|
3369
|
+
if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
|
3447
3370
|
return true;
|
|
3448
3371
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3449
3372
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
@@ -3487,20 +3410,12 @@ class InputState {
|
|
|
3487
3410
|
// compositionend and keydown events are sometimes emitted in the
|
|
3488
3411
|
// wrong order. The key event should still be ignored, even when
|
|
3489
3412
|
// it happens after the compositionend event.
|
|
3490
|
-
if (browser.safari && Date.now() - this.compositionEndedAt <
|
|
3413
|
+
if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
|
|
3491
3414
|
this.compositionEndedAt = 0;
|
|
3492
3415
|
return true;
|
|
3493
3416
|
}
|
|
3494
3417
|
return false;
|
|
3495
3418
|
}
|
|
3496
|
-
screenKeyEvent(view, event) {
|
|
3497
|
-
let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000;
|
|
3498
|
-
if (event.keyCode == 27)
|
|
3499
|
-
this.lastEscPress = Date.now();
|
|
3500
|
-
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3501
|
-
this.lastEscPress = 0;
|
|
3502
|
-
return protectedTab;
|
|
3503
|
-
}
|
|
3504
3419
|
mustFlushObserver(event) {
|
|
3505
3420
|
return (event.type == "keydown" && event.keyCode != 229) ||
|
|
3506
3421
|
event.type == "compositionend" && !browser.ios;
|
|
@@ -3674,6 +3589,10 @@ function doPaste(view, input) {
|
|
|
3674
3589
|
}
|
|
3675
3590
|
handlers.keydown = (view, event) => {
|
|
3676
3591
|
view.inputState.setSelectionOrigin("select");
|
|
3592
|
+
if (event.keyCode == 27)
|
|
3593
|
+
view.inputState.lastEscPress = Date.now();
|
|
3594
|
+
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3595
|
+
view.inputState.lastEscPress = 0;
|
|
3677
3596
|
};
|
|
3678
3597
|
let lastTouch = 0;
|
|
3679
3598
|
handlers.touchstart = (view, e) => {
|
|
@@ -3931,14 +3850,6 @@ handlers.focus = handlers.blur = view => {
|
|
|
3931
3850
|
view.update([]);
|
|
3932
3851
|
}, 10);
|
|
3933
3852
|
};
|
|
3934
|
-
handlers.beforeprint = view => {
|
|
3935
|
-
view.viewState.printing = true;
|
|
3936
|
-
view.requestMeasure();
|
|
3937
|
-
setTimeout(() => {
|
|
3938
|
-
view.viewState.printing = false;
|
|
3939
|
-
view.requestMeasure();
|
|
3940
|
-
}, 2000);
|
|
3941
|
-
};
|
|
3942
3853
|
function forceClearComposition(view, rapid) {
|
|
3943
3854
|
if (view.docView.compositionDeco.size) {
|
|
3944
3855
|
view.inputState.rapidCompositionStart = rapid;
|
|
@@ -4005,9 +3916,8 @@ handlers.beforeinput = (view, event) => {
|
|
|
4005
3916
|
const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
|
4006
3917
|
class HeightOracle {
|
|
4007
3918
|
constructor() {
|
|
4008
|
-
this.doc =
|
|
3919
|
+
this.doc = state.Text.empty;
|
|
4009
3920
|
this.lineWrapping = false;
|
|
4010
|
-
this.direction = exports.Direction.LTR;
|
|
4011
3921
|
this.heightSamples = {};
|
|
4012
3922
|
this.lineHeight = 14;
|
|
4013
3923
|
this.charWidth = 7;
|
|
@@ -4028,8 +3938,8 @@ class HeightOracle {
|
|
|
4028
3938
|
return lines * this.lineHeight;
|
|
4029
3939
|
}
|
|
4030
3940
|
setDoc(doc) { this.doc = doc; return this; }
|
|
4031
|
-
|
|
4032
|
-
return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping
|
|
3941
|
+
mustRefreshForWrapping(whiteSpace) {
|
|
3942
|
+
return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
|
|
4033
3943
|
}
|
|
4034
3944
|
mustRefreshForHeights(lineHeights) {
|
|
4035
3945
|
let newHeight = false;
|
|
@@ -4045,13 +3955,10 @@ class HeightOracle {
|
|
|
4045
3955
|
}
|
|
4046
3956
|
return newHeight;
|
|
4047
3957
|
}
|
|
4048
|
-
refresh(whiteSpace,
|
|
3958
|
+
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4049
3959
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4050
|
-
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) ||
|
|
4051
|
-
this.lineWrapping != lineWrapping ||
|
|
4052
|
-
this.direction != direction;
|
|
3960
|
+
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4053
3961
|
this.lineWrapping = lineWrapping;
|
|
4054
|
-
this.direction = direction;
|
|
4055
3962
|
this.lineHeight = lineHeight;
|
|
4056
3963
|
this.charWidth = charWidth;
|
|
4057
3964
|
this.lineLength = lineLength;
|
|
@@ -4132,12 +4039,6 @@ class BlockInfo {
|
|
|
4132
4039
|
.concat(Array.isArray(other.type) ? other.type : [other]);
|
|
4133
4040
|
return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
|
|
4134
4041
|
}
|
|
4135
|
-
/**
|
|
4136
|
-
FIXME remove on next breaking release @internal
|
|
4137
|
-
*/
|
|
4138
|
-
moveY(offset) {
|
|
4139
|
-
return !offset ? this : new BlockInfo(this.from, this.length, this.top + offset, this.height, Array.isArray(this.type) ? this.type.map(b => b.moveY(offset)) : this.type);
|
|
4140
|
-
}
|
|
4141
4042
|
}
|
|
4142
4043
|
var QueryType;
|
|
4143
4044
|
(function (QueryType) {
|
|
@@ -4262,8 +4163,9 @@ class HeightMapBlock extends HeightMap {
|
|
|
4262
4163
|
lineAt(_value, _type, doc, top, offset) {
|
|
4263
4164
|
return this.blockAt(0, doc, top, offset);
|
|
4264
4165
|
}
|
|
4265
|
-
forEachLine(
|
|
4266
|
-
|
|
4166
|
+
forEachLine(from, to, doc, top, offset, f) {
|
|
4167
|
+
if (from <= offset + this.length && to >= offset)
|
|
4168
|
+
f(this.blockAt(0, doc, top, offset));
|
|
4267
4169
|
}
|
|
4268
4170
|
updateHeight(oracle, offset = 0, _force = false, measured) {
|
|
4269
4171
|
if (measured && measured.from <= offset && measured.more)
|
|
@@ -4645,13 +4547,13 @@ class NodeBuilder {
|
|
|
4645
4547
|
// to each other.
|
|
4646
4548
|
static build(oracle, decorations, from, to) {
|
|
4647
4549
|
let builder = new NodeBuilder(from, oracle);
|
|
4648
|
-
|
|
4550
|
+
state.RangeSet.spans(decorations, from, to, builder, 0);
|
|
4649
4551
|
return builder.finish(from);
|
|
4650
4552
|
}
|
|
4651
4553
|
}
|
|
4652
4554
|
function heightRelevantDecoChanges(a, b, diff) {
|
|
4653
4555
|
let comp = new DecorationComparator;
|
|
4654
|
-
|
|
4556
|
+
state.RangeSet.compare(a, b, diff, comp, 0);
|
|
4655
4557
|
return comp.changes;
|
|
4656
4558
|
}
|
|
4657
4559
|
class DecorationComparator {
|
|
@@ -4694,6 +4596,11 @@ function visiblePixelRange(dom, paddingTop) {
|
|
|
4694
4596
|
return { left: left - rect.left, right: Math.max(left, right) - rect.left,
|
|
4695
4597
|
top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
|
|
4696
4598
|
}
|
|
4599
|
+
function fullPixelRange(dom, paddingTop) {
|
|
4600
|
+
let rect = dom.getBoundingClientRect();
|
|
4601
|
+
return { left: 0, right: rect.right - rect.left,
|
|
4602
|
+
top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) };
|
|
4603
|
+
}
|
|
4697
4604
|
// Line gaps are placeholder widgets used to hide pieces of overlong
|
|
4698
4605
|
// lines within the viewport, as a kludge to keep the editor
|
|
4699
4606
|
// responsive when a ridiculously long line is loaded into it.
|
|
@@ -4739,8 +4646,8 @@ class LineGapWidget extends WidgetType {
|
|
|
4739
4646
|
get estimatedHeight() { return this.vertical ? this.size : -1; }
|
|
4740
4647
|
}
|
|
4741
4648
|
class ViewState {
|
|
4742
|
-
constructor(state) {
|
|
4743
|
-
this.state = state;
|
|
4649
|
+
constructor(state$1) {
|
|
4650
|
+
this.state = state$1;
|
|
4744
4651
|
// These are contentDOM-local coordinates
|
|
4745
4652
|
this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
|
|
4746
4653
|
this.inView = true;
|
|
@@ -4759,6 +4666,7 @@ class ViewState {
|
|
|
4759
4666
|
// Flag set when editor content was redrawn, so that the next
|
|
4760
4667
|
// measure stage knows it must read DOM layout
|
|
4761
4668
|
this.mustMeasureContent = true;
|
|
4669
|
+
this.defaultTextDirection = exports.Direction.RTL;
|
|
4762
4670
|
this.visibleRanges = [];
|
|
4763
4671
|
// Cursor 'assoc' is only significant when the cursor is on a line
|
|
4764
4672
|
// wrap point, where it must stick to the character that it is
|
|
@@ -4769,7 +4677,8 @@ class ViewState {
|
|
|
4769
4677
|
// boundary and, if so, reset it to make sure it is positioned in
|
|
4770
4678
|
// the right place.
|
|
4771
4679
|
this.mustEnforceCursorAssoc = false;
|
|
4772
|
-
this.
|
|
4680
|
+
this.stateDeco = state$1.facet(decorations).filter(d => typeof d != "function");
|
|
4681
|
+
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, state.Text.empty, this.heightOracle.setDoc(state$1.doc), [new ChangedRange(0, 0, 0, state$1.doc.length)]);
|
|
4773
4682
|
this.viewport = this.getViewport(0, null);
|
|
4774
4683
|
this.updateViewportLines();
|
|
4775
4684
|
this.updateForViewport();
|
|
@@ -4797,13 +4706,13 @@ class ViewState {
|
|
|
4797
4706
|
});
|
|
4798
4707
|
}
|
|
4799
4708
|
update(update, scrollTarget = null) {
|
|
4800
|
-
let prev = this.state;
|
|
4801
4709
|
this.state = update.state;
|
|
4802
|
-
let
|
|
4710
|
+
let prevDeco = this.stateDeco;
|
|
4711
|
+
this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
|
|
4803
4712
|
let contentChanges = update.changedRanges;
|
|
4804
|
-
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(
|
|
4713
|
+
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : state.ChangeSet.empty(this.state.doc.length)));
|
|
4805
4714
|
let prevHeight = this.heightMap.height;
|
|
4806
|
-
this.heightMap = this.heightMap.applyChanges(
|
|
4715
|
+
this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
|
|
4807
4716
|
if (this.heightMap.height != prevHeight)
|
|
4808
4717
|
update.flags |= 2 /* Height */;
|
|
4809
4718
|
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
|
@@ -4828,8 +4737,9 @@ class ViewState {
|
|
|
4828
4737
|
measure(view) {
|
|
4829
4738
|
let dom = view.contentDOM, style = window.getComputedStyle(dom);
|
|
4830
4739
|
let oracle = this.heightOracle;
|
|
4831
|
-
let whiteSpace = style.whiteSpace
|
|
4832
|
-
|
|
4740
|
+
let whiteSpace = style.whiteSpace;
|
|
4741
|
+
this.defaultTextDirection = style.direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
|
|
4742
|
+
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4833
4743
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4834
4744
|
let result = 0, bias = 0;
|
|
4835
4745
|
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
@@ -4850,8 +4760,7 @@ class ViewState {
|
|
|
4850
4760
|
}
|
|
4851
4761
|
}
|
|
4852
4762
|
// Pixel viewport
|
|
4853
|
-
let pixelViewport = this.printing ?
|
|
4854
|
-
: visiblePixelRange(dom, this.paddingTop);
|
|
4763
|
+
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
|
4855
4764
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
4856
4765
|
this.pixelViewport = pixelViewport;
|
|
4857
4766
|
let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
|
@@ -4869,12 +4778,12 @@ class ViewState {
|
|
|
4869
4778
|
result |= 8 /* Geometry */;
|
|
4870
4779
|
}
|
|
4871
4780
|
if (measureContent) {
|
|
4872
|
-
let lineHeights = view.docView.measureVisibleLineHeights();
|
|
4781
|
+
let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
|
|
4873
4782
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
4874
4783
|
refresh = true;
|
|
4875
4784
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4876
4785
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4877
|
-
refresh = oracle.refresh(whiteSpace,
|
|
4786
|
+
refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4878
4787
|
if (refresh) {
|
|
4879
4788
|
view.docView.minWidth = 0;
|
|
4880
4789
|
result |= 8 /* Geometry */;
|
|
@@ -4885,7 +4794,10 @@ class ViewState {
|
|
|
4885
4794
|
else if (dTop < 0 && dBottom < 0)
|
|
4886
4795
|
bias = Math.min(dTop, dBottom);
|
|
4887
4796
|
oracle.heightChanged = false;
|
|
4888
|
-
|
|
4797
|
+
for (let vp of this.viewports) {
|
|
4798
|
+
let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
|
|
4799
|
+
this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
|
|
4800
|
+
}
|
|
4889
4801
|
if (oracle.heightChanged)
|
|
4890
4802
|
result |= 2 /* Height */;
|
|
4891
4803
|
}
|
|
@@ -4971,12 +4883,12 @@ class ViewState {
|
|
|
4971
4883
|
ensureLineGaps(current) {
|
|
4972
4884
|
let gaps = [];
|
|
4973
4885
|
// This won't work at all in predominantly right-to-left text.
|
|
4974
|
-
if (this.
|
|
4886
|
+
if (this.defaultTextDirection != exports.Direction.LTR)
|
|
4975
4887
|
return gaps;
|
|
4976
4888
|
for (let line of this.viewportLines) {
|
|
4977
4889
|
if (line.length < 4000 /* DoubleMargin */)
|
|
4978
4890
|
continue;
|
|
4979
|
-
let structure = lineStructure(line.from, line.to, this.
|
|
4891
|
+
let structure = lineStructure(line.from, line.to, this.stateDeco);
|
|
4980
4892
|
if (structure.total < 4000 /* DoubleMargin */)
|
|
4981
4893
|
continue;
|
|
4982
4894
|
let viewFrom, viewTo;
|
|
@@ -5027,11 +4939,11 @@ class ViewState {
|
|
|
5027
4939
|
}
|
|
5028
4940
|
}
|
|
5029
4941
|
computeVisibleRanges() {
|
|
5030
|
-
let deco = this.
|
|
4942
|
+
let deco = this.stateDeco;
|
|
5031
4943
|
if (this.lineGaps.length)
|
|
5032
4944
|
deco = deco.concat(this.lineGapDeco);
|
|
5033
4945
|
let ranges = [];
|
|
5034
|
-
|
|
4946
|
+
state.RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
|
|
5035
4947
|
span(from, to) { ranges.push({ from, to }); },
|
|
5036
4948
|
point() { }
|
|
5037
4949
|
}, 20);
|
|
@@ -5063,9 +4975,9 @@ class Viewport {
|
|
|
5063
4975
|
this.to = to;
|
|
5064
4976
|
}
|
|
5065
4977
|
}
|
|
5066
|
-
function lineStructure(from, to,
|
|
4978
|
+
function lineStructure(from, to, stateDeco) {
|
|
5067
4979
|
let ranges = [], pos = from, total = 0;
|
|
5068
|
-
|
|
4980
|
+
state.RangeSet.spans(stateDeco, from, to, {
|
|
5069
4981
|
span() { },
|
|
5070
4982
|
point(from, to) {
|
|
5071
4983
|
if (from > pos) {
|
|
@@ -5198,7 +5110,7 @@ function buildTheme(main, spec, scopes) {
|
|
|
5198
5110
|
}
|
|
5199
5111
|
});
|
|
5200
5112
|
}
|
|
5201
|
-
const baseTheme = buildTheme("." + baseThemeID, {
|
|
5113
|
+
const baseTheme$1 = buildTheme("." + baseThemeID, {
|
|
5202
5114
|
"&.cm-editor": {
|
|
5203
5115
|
position: "relative !important",
|
|
5204
5116
|
boxSizing: "border-box",
|
|
@@ -5303,6 +5215,65 @@ const baseTheme = buildTheme("." + baseThemeID, {
|
|
|
5303
5215
|
"&dark .cm-activeLine": { backgroundColor: "#223039" },
|
|
5304
5216
|
"&light .cm-specialChar": { color: "red" },
|
|
5305
5217
|
"&dark .cm-specialChar": { color: "#f78" },
|
|
5218
|
+
".cm-gutters": {
|
|
5219
|
+
display: "flex",
|
|
5220
|
+
height: "100%",
|
|
5221
|
+
boxSizing: "border-box",
|
|
5222
|
+
left: 0,
|
|
5223
|
+
zIndex: 200
|
|
5224
|
+
},
|
|
5225
|
+
"&light .cm-gutters": {
|
|
5226
|
+
backgroundColor: "#f5f5f5",
|
|
5227
|
+
color: "#6c6c6c",
|
|
5228
|
+
borderRight: "1px solid #ddd"
|
|
5229
|
+
},
|
|
5230
|
+
"&dark .cm-gutters": {
|
|
5231
|
+
backgroundColor: "#333338",
|
|
5232
|
+
color: "#ccc"
|
|
5233
|
+
},
|
|
5234
|
+
".cm-gutter": {
|
|
5235
|
+
display: "flex !important",
|
|
5236
|
+
flexDirection: "column",
|
|
5237
|
+
flexShrink: 0,
|
|
5238
|
+
boxSizing: "border-box",
|
|
5239
|
+
minHeight: "100%",
|
|
5240
|
+
overflow: "hidden"
|
|
5241
|
+
},
|
|
5242
|
+
".cm-gutterElement": {
|
|
5243
|
+
boxSizing: "border-box"
|
|
5244
|
+
},
|
|
5245
|
+
".cm-lineNumbers .cm-gutterElement": {
|
|
5246
|
+
padding: "0 3px 0 5px",
|
|
5247
|
+
minWidth: "20px",
|
|
5248
|
+
textAlign: "right",
|
|
5249
|
+
whiteSpace: "nowrap"
|
|
5250
|
+
},
|
|
5251
|
+
"&light .cm-activeLineGutter": {
|
|
5252
|
+
backgroundColor: "#e2f2ff"
|
|
5253
|
+
},
|
|
5254
|
+
"&dark .cm-activeLineGutter": {
|
|
5255
|
+
backgroundColor: "#222227"
|
|
5256
|
+
},
|
|
5257
|
+
".cm-panels": {
|
|
5258
|
+
boxSizing: "border-box",
|
|
5259
|
+
position: "sticky",
|
|
5260
|
+
left: 0,
|
|
5261
|
+
right: 0
|
|
5262
|
+
},
|
|
5263
|
+
"&light .cm-panels": {
|
|
5264
|
+
backgroundColor: "#f5f5f5",
|
|
5265
|
+
color: "black"
|
|
5266
|
+
},
|
|
5267
|
+
"&light .cm-panels-top": {
|
|
5268
|
+
borderBottom: "1px solid #ddd"
|
|
5269
|
+
},
|
|
5270
|
+
"&light .cm-panels-bottom": {
|
|
5271
|
+
borderTop: "1px solid #ddd"
|
|
5272
|
+
},
|
|
5273
|
+
"&dark .cm-panels": {
|
|
5274
|
+
backgroundColor: "#333338",
|
|
5275
|
+
color: "white"
|
|
5276
|
+
},
|
|
5306
5277
|
".cm-tab": {
|
|
5307
5278
|
display: "inline-block",
|
|
5308
5279
|
overflow: "hidden",
|
|
@@ -5428,6 +5399,7 @@ class DOMObserver {
|
|
|
5428
5399
|
});
|
|
5429
5400
|
this.resize.observe(view.scrollDOM);
|
|
5430
5401
|
}
|
|
5402
|
+
window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
|
|
5431
5403
|
this.start();
|
|
5432
5404
|
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5433
5405
|
if (typeof IntersectionObserver == "function") {
|
|
@@ -5462,6 +5434,14 @@ class DOMObserver {
|
|
|
5462
5434
|
this.view.requestMeasure();
|
|
5463
5435
|
}, 50);
|
|
5464
5436
|
}
|
|
5437
|
+
onPrint() {
|
|
5438
|
+
this.view.viewState.printing = true;
|
|
5439
|
+
this.view.measure();
|
|
5440
|
+
setTimeout(() => {
|
|
5441
|
+
this.view.viewState.printing = false;
|
|
5442
|
+
this.view.requestMeasure();
|
|
5443
|
+
}, 500);
|
|
5444
|
+
}
|
|
5465
5445
|
updateGaps(gaps) {
|
|
5466
5446
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5467
5447
|
this.gapIntersection.disconnect();
|
|
@@ -5679,6 +5659,7 @@ class DOMObserver {
|
|
|
5679
5659
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5680
5660
|
window.removeEventListener("scroll", this.onScroll);
|
|
5681
5661
|
window.removeEventListener("resize", this.onResize);
|
|
5662
|
+
window.removeEventListener("beforeprint", this.onPrint);
|
|
5682
5663
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5683
5664
|
clearTimeout(this.parentCheck);
|
|
5684
5665
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5941,9 +5922,9 @@ transactions for editing actions.
|
|
|
5941
5922
|
*/
|
|
5942
5923
|
class EditorView {
|
|
5943
5924
|
/**
|
|
5944
|
-
Construct a new view. You'll
|
|
5945
|
-
|
|
5946
|
-
|
|
5925
|
+
Construct a new view. You'll want to either provide a `parent`
|
|
5926
|
+
option, or put `view.dom` into your document after creating a
|
|
5927
|
+
view, so that the user can see the editor.
|
|
5947
5928
|
*/
|
|
5948
5929
|
constructor(
|
|
5949
5930
|
/**
|
|
@@ -5994,6 +5975,7 @@ class EditorView {
|
|
|
5994
5975
|
this.measure();
|
|
5995
5976
|
});
|
|
5996
5977
|
this.inputState = new InputState(this);
|
|
5978
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
5997
5979
|
this.docView = new DocView(this);
|
|
5998
5980
|
this.mountStyles();
|
|
5999
5981
|
this.updateAttrs();
|
|
@@ -6081,14 +6063,9 @@ class EditorView {
|
|
|
6081
6063
|
let { main } = tr.state.selection;
|
|
6082
6064
|
scrollTarget = new ScrollTarget(main.empty ? main : state.EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
|
6083
6065
|
}
|
|
6084
|
-
for (let e of tr.effects)
|
|
6085
|
-
if (e.is(
|
|
6086
|
-
scrollTarget = new ScrollTarget(e.value);
|
|
6087
|
-
else if (e.is(centerOn))
|
|
6088
|
-
scrollTarget = new ScrollTarget(e.value, "center");
|
|
6089
|
-
else if (e.is(scrollIntoView))
|
|
6066
|
+
for (let e of tr.effects)
|
|
6067
|
+
if (e.is(scrollIntoView))
|
|
6090
6068
|
scrollTarget = e.value;
|
|
6091
|
-
}
|
|
6092
6069
|
}
|
|
6093
6070
|
this.viewState.update(update, scrollTarget);
|
|
6094
6071
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
@@ -6139,7 +6116,7 @@ class EditorView {
|
|
|
6139
6116
|
for (let plugin of this.plugins)
|
|
6140
6117
|
plugin.update(this);
|
|
6141
6118
|
this.docView = new DocView(this);
|
|
6142
|
-
this.inputState.ensureHandlers(this);
|
|
6119
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
6143
6120
|
this.mountStyles();
|
|
6144
6121
|
this.updateAttrs();
|
|
6145
6122
|
this.bidiCache = [];
|
|
@@ -6171,7 +6148,7 @@ class EditorView {
|
|
|
6171
6148
|
plugin.destroy(this);
|
|
6172
6149
|
this.plugins = newPlugins;
|
|
6173
6150
|
this.pluginMap.clear();
|
|
6174
|
-
this.inputState.ensureHandlers(this);
|
|
6151
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
6175
6152
|
}
|
|
6176
6153
|
else {
|
|
6177
6154
|
for (let p of this.plugins)
|
|
@@ -6309,7 +6286,7 @@ class EditorView {
|
|
|
6309
6286
|
}
|
|
6310
6287
|
mountStyles() {
|
|
6311
6288
|
this.styleModules = this.state.facet(styleModule);
|
|
6312
|
-
styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse());
|
|
6289
|
+
styleMod.StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
|
|
6313
6290
|
}
|
|
6314
6291
|
readMeasured() {
|
|
6315
6292
|
if (this.updateState == 2 /* Updating */)
|
|
@@ -6340,16 +6317,6 @@ class EditorView {
|
|
|
6340
6317
|
}
|
|
6341
6318
|
}
|
|
6342
6319
|
/**
|
|
6343
|
-
Collect all values provided by the active plugins for a given
|
|
6344
|
-
field.
|
|
6345
|
-
*/
|
|
6346
|
-
pluginField(field) {
|
|
6347
|
-
let result = [];
|
|
6348
|
-
for (let plugin of this.plugins)
|
|
6349
|
-
plugin.update(this).takeField(field, result);
|
|
6350
|
-
return result;
|
|
6351
|
-
}
|
|
6352
|
-
/**
|
|
6353
6320
|
Get the value of a specific plugin, if present. Note that
|
|
6354
6321
|
plugins that crash can be dropped from a view, so even when you
|
|
6355
6322
|
know you registered a given plugin, it is recommended to check
|
|
@@ -6376,23 +6343,6 @@ class EditorView {
|
|
|
6376
6343
|
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
|
6377
6344
|
}
|
|
6378
6345
|
/**
|
|
6379
|
-
Find the line or block widget at the given vertical position.
|
|
6380
|
-
|
|
6381
|
-
By default, this position is interpreted as a screen position,
|
|
6382
|
-
meaning `docTop` is set to the DOM top position of the editor
|
|
6383
|
-
content (forcing a layout). You can pass a different `docTop`
|
|
6384
|
-
value—for example 0 to interpret `height` as a document-relative
|
|
6385
|
-
position, or a precomputed document top
|
|
6386
|
-
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
6387
|
-
queries.
|
|
6388
|
-
|
|
6389
|
-
*Deprecated: use `elementAtHeight` instead.*
|
|
6390
|
-
*/
|
|
6391
|
-
blockAtHeight(height, docTop) {
|
|
6392
|
-
let top = ensureTop(docTop, this);
|
|
6393
|
-
return this.elementAtHeight(height - top).moveY(top);
|
|
6394
|
-
}
|
|
6395
|
-
/**
|
|
6396
6346
|
Find the text line or block widget at the given vertical
|
|
6397
6347
|
position (which is interpreted as relative to the [top of the
|
|
6398
6348
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
|
|
@@ -6402,23 +6352,6 @@ class EditorView {
|
|
|
6402
6352
|
return this.viewState.elementAtHeight(height);
|
|
6403
6353
|
}
|
|
6404
6354
|
/**
|
|
6405
|
-
Find information for the visual line (see
|
|
6406
|
-
[`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given
|
|
6407
|
-
vertical position. The resulting block info might hold another
|
|
6408
|
-
array of block info structs in its `type` field if this line
|
|
6409
|
-
consists of more than one block.
|
|
6410
|
-
|
|
6411
|
-
Defaults to treating `height` as a screen position. See
|
|
6412
|
-
[`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
|
|
6413
|
-
interpretation of the `docTop` parameter.
|
|
6414
|
-
|
|
6415
|
-
*Deprecated: use `lineBlockAtHeight` instead.*
|
|
6416
|
-
*/
|
|
6417
|
-
visualLineAtHeight(height, docTop) {
|
|
6418
|
-
let top = ensureTop(docTop, this);
|
|
6419
|
-
return this.lineBlockAtHeight(height - top).moveY(top);
|
|
6420
|
-
}
|
|
6421
|
-
/**
|
|
6422
6355
|
Find the line block (see
|
|
6423
6356
|
[`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
|
|
6424
6357
|
height.
|
|
@@ -6428,19 +6361,6 @@ class EditorView {
|
|
|
6428
6361
|
return this.viewState.lineBlockAtHeight(height);
|
|
6429
6362
|
}
|
|
6430
6363
|
/**
|
|
6431
|
-
Iterate over the height information of the visual lines in the
|
|
6432
|
-
viewport. The heights of lines are reported relative to the
|
|
6433
|
-
given document top, which defaults to the screen position of the
|
|
6434
|
-
document (forcing a layout).
|
|
6435
|
-
|
|
6436
|
-
*Deprecated: use `viewportLineBlocks` instead.*
|
|
6437
|
-
*/
|
|
6438
|
-
viewportLines(f, docTop) {
|
|
6439
|
-
let top = ensureTop(docTop, this);
|
|
6440
|
-
for (let line of this.viewportLineBlocks)
|
|
6441
|
-
f(line.moveY(top));
|
|
6442
|
-
}
|
|
6443
|
-
/**
|
|
6444
6364
|
Get the extent and vertical position of all [line
|
|
6445
6365
|
blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
|
|
6446
6366
|
are relative to the [top of the
|
|
@@ -6450,24 +6370,9 @@ class EditorView {
|
|
|
6450
6370
|
return this.viewState.viewportLines;
|
|
6451
6371
|
}
|
|
6452
6372
|
/**
|
|
6453
|
-
Find the extent and height of the visual line (a range delimited
|
|
6454
|
-
on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
|
|
6455
|
-
line breaks, or the start/end of the document) at the given position.
|
|
6456
|
-
|
|
6457
|
-
Vertical positions are computed relative to the `docTop`
|
|
6458
|
-
argument, which defaults to 0 for this method. You can pass
|
|
6459
|
-
`view.contentDOM.getBoundingClientRect().top` here to get screen
|
|
6460
|
-
coordinates.
|
|
6461
|
-
|
|
6462
|
-
*Deprecated: use `lineBlockAt` instead.*
|
|
6463
|
-
*/
|
|
6464
|
-
visualLineAt(pos, docTop = 0) {
|
|
6465
|
-
return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
|
|
6466
|
-
}
|
|
6467
|
-
/**
|
|
6468
6373
|
Find the line block around the given document position. A line
|
|
6469
6374
|
block is a range delimited on both sides by either a
|
|
6470
|
-
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^
|
|
6375
|
+
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the
|
|
6471
6376
|
start/end of the document. It will usually just hold a line of
|
|
6472
6377
|
text, but may be broken into multiple textblocks by block
|
|
6473
6378
|
widgets.
|
|
@@ -6483,13 +6388,13 @@ class EditorView {
|
|
|
6483
6388
|
}
|
|
6484
6389
|
/**
|
|
6485
6390
|
Move a cursor position by [grapheme
|
|
6486
|
-
cluster](https://codemirror.net/6/docs/ref/#
|
|
6487
|
-
the motion is away from the line start, or towards it.
|
|
6488
|
-
bidirectional text is in visual order,
|
|
6489
|
-
direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
6490
|
-
position was the last one on the line, the
|
|
6491
|
-
will be across the line break. If there is no
|
|
6492
|
-
original position is returned.
|
|
6391
|
+
cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
|
|
6392
|
+
the motion is away from the line start, or towards it. In
|
|
6393
|
+
bidirectional text, the line is traversed in visual order, using
|
|
6394
|
+
the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
6395
|
+
When the start position was the last one on the line, the
|
|
6396
|
+
returned position will be across the line break. If there is no
|
|
6397
|
+
further line, the original position is returned.
|
|
6493
6398
|
|
|
6494
6399
|
By default, this method moves over a single cluster. The
|
|
6495
6400
|
optional `by` argument can be used to move across more. It will
|
|
@@ -6534,10 +6439,6 @@ class EditorView {
|
|
|
6534
6439
|
moveVertically(start, forward, distance) {
|
|
6535
6440
|
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
|
6536
6441
|
}
|
|
6537
|
-
// FIXME remove on next major version
|
|
6538
|
-
scrollPosIntoView(pos) {
|
|
6539
|
-
this.dispatch({ effects: scrollTo.of(state.EditorSelection.cursor(pos)) });
|
|
6540
|
-
}
|
|
6541
6442
|
/**
|
|
6542
6443
|
Find the DOM parent node and offset (child offset if `node` is
|
|
6543
6444
|
an element, character offset when it is a text node) at the
|
|
@@ -6593,9 +6494,25 @@ class EditorView {
|
|
|
6593
6494
|
/**
|
|
6594
6495
|
The text direction
|
|
6595
6496
|
([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
|
|
6596
|
-
CSS property) of the editor.
|
|
6497
|
+
CSS property) of the editor's content element.
|
|
6498
|
+
*/
|
|
6499
|
+
get textDirection() { return this.viewState.defaultTextDirection; }
|
|
6500
|
+
/**
|
|
6501
|
+
Find the text direction of the block at the given position, as
|
|
6502
|
+
assigned by CSS. If
|
|
6503
|
+
[`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
|
|
6504
|
+
isn't enabled, or the given position is outside of the viewport,
|
|
6505
|
+
this will always return the same as
|
|
6506
|
+
[`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
|
|
6507
|
+
this may trigger a DOM layout.
|
|
6597
6508
|
*/
|
|
6598
|
-
|
|
6509
|
+
textDirectionAt(pos) {
|
|
6510
|
+
let perLine = this.state.facet(perLineTextDirection);
|
|
6511
|
+
if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
|
|
6512
|
+
return this.textDirection;
|
|
6513
|
+
this.readMeasured();
|
|
6514
|
+
return this.docView.textDirectionAt(pos);
|
|
6515
|
+
}
|
|
6599
6516
|
/**
|
|
6600
6517
|
Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
|
|
6601
6518
|
(as determined by the
|
|
@@ -6614,11 +6531,11 @@ class EditorView {
|
|
|
6614
6531
|
bidiSpans(line) {
|
|
6615
6532
|
if (line.length > MaxBidiLine)
|
|
6616
6533
|
return trivialOrder(line.length);
|
|
6617
|
-
let dir = this.
|
|
6534
|
+
let dir = this.textDirectionAt(line.from);
|
|
6618
6535
|
for (let entry of this.bidiCache)
|
|
6619
6536
|
if (entry.from == line.from && entry.dir == dir)
|
|
6620
6537
|
return entry.order;
|
|
6621
|
-
let order = computeOrder(line.text,
|
|
6538
|
+
let order = computeOrder(line.text, dir);
|
|
6622
6539
|
this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
|
|
6623
6540
|
return order;
|
|
6624
6541
|
}
|
|
@@ -6669,16 +6586,16 @@ class EditorView {
|
|
|
6669
6586
|
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? state.EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
|
6670
6587
|
}
|
|
6671
6588
|
/**
|
|
6672
|
-
|
|
6673
|
-
should be an object mapping event names to handler
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6677
|
-
These are registered
|
|
6678
|
-
element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
|
|
6679
|
-
handlers, which will be called any time the
|
|
6680
|
-
element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
|
|
6681
|
-
is scrolled.
|
|
6589
|
+
Returns an extension that can be used to add DOM event handlers.
|
|
6590
|
+
The value should be an object mapping event names to handler
|
|
6591
|
+
functions. For any given event, such functions are ordered by
|
|
6592
|
+
extension precedence, and the first handler to return true will
|
|
6593
|
+
be assumed to have handled that event, and no other handlers or
|
|
6594
|
+
built-in behavior will be activated for it. These are registered
|
|
6595
|
+
on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
|
|
6596
|
+
for `scroll` handlers, which will be called any time the
|
|
6597
|
+
editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
|
|
6598
|
+
its parent nodes is scrolled.
|
|
6682
6599
|
*/
|
|
6683
6600
|
static domEventHandlers(handlers) {
|
|
6684
6601
|
return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
|
@@ -6720,20 +6637,6 @@ class EditorView {
|
|
|
6720
6637
|
}
|
|
6721
6638
|
}
|
|
6722
6639
|
/**
|
|
6723
|
-
Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
|
|
6724
|
-
transaction to make it scroll the given range into view.
|
|
6725
|
-
|
|
6726
|
-
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6727
|
-
*/
|
|
6728
|
-
EditorView.scrollTo = scrollTo;
|
|
6729
|
-
/**
|
|
6730
|
-
Effect that makes the editor scroll the given range to the
|
|
6731
|
-
center of the visible view.
|
|
6732
|
-
|
|
6733
|
-
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6734
|
-
*/
|
|
6735
|
-
EditorView.centerOn = centerOn;
|
|
6736
|
-
/**
|
|
6737
6640
|
Facet to add a [style
|
|
6738
6641
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
6739
6642
|
an editor view. The view will ensure that the module is
|
|
@@ -6750,6 +6653,13 @@ called and the default behavior is prevented.
|
|
|
6750
6653
|
*/
|
|
6751
6654
|
EditorView.inputHandler = inputHandler;
|
|
6752
6655
|
/**
|
|
6656
|
+
By default, the editor assumes all its content has the same
|
|
6657
|
+
[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
|
|
6658
|
+
value to make it read and store the text direction of every
|
|
6659
|
+
(rendered) line separately.
|
|
6660
|
+
*/
|
|
6661
|
+
EditorView.perLineTextDirection = perLineTextDirection;
|
|
6662
|
+
/**
|
|
6753
6663
|
Allows you to provide a function that should be called when the
|
|
6754
6664
|
library catches an exception from an extension (mostly from view
|
|
6755
6665
|
plugins, but may be used by other extensions to route exceptions
|
|
@@ -6765,9 +6675,9 @@ EditorView.updateListener = updateListener;
|
|
|
6765
6675
|
/**
|
|
6766
6676
|
Facet that controls whether the editor content DOM is editable.
|
|
6767
6677
|
When its highest-precedence value is `false`, the element will
|
|
6768
|
-
not
|
|
6769
|
-
|
|
6770
|
-
|
|
6678
|
+
not have its `contenteditable` attribute set. (Note that this
|
|
6679
|
+
doesn't affect API calls that change the editor content, even
|
|
6680
|
+
when those are bound to keys or buttons. See the
|
|
6771
6681
|
[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
|
|
6772
6682
|
*/
|
|
6773
6683
|
EditorView.editable = editable;
|
|
@@ -6786,18 +6696,45 @@ the drag should move the content.
|
|
|
6786
6696
|
*/
|
|
6787
6697
|
EditorView.dragMovesSelection = dragMovesSelection$1;
|
|
6788
6698
|
/**
|
|
6789
|
-
Facet used to configure whether a given selecting click adds
|
|
6790
|
-
|
|
6699
|
+
Facet used to configure whether a given selecting click adds a
|
|
6700
|
+
new range to the existing selection or replaces it entirely. The
|
|
6701
|
+
default behavior is to check `event.metaKey` on macOS, and
|
|
6702
|
+
`event.ctrlKey` elsewhere.
|
|
6791
6703
|
*/
|
|
6792
6704
|
EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
|
|
6793
6705
|
/**
|
|
6794
6706
|
A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
|
|
6795
|
-
are shown in the view.
|
|
6796
|
-
|
|
6797
|
-
|
|
6707
|
+
are shown in the view. Decorations can be provided in two
|
|
6708
|
+
ways—directly, or via a function that takes an editor view.
|
|
6709
|
+
|
|
6710
|
+
Only decoration sets provided directly are allowed to influence
|
|
6711
|
+
the editor's vertical layout structure. The ones provided as
|
|
6712
|
+
functions are called _after_ the new viewport has been computed,
|
|
6713
|
+
and thus **must not** introduce block widgets or replacing
|
|
6714
|
+
decorations that cover line breaks.
|
|
6798
6715
|
*/
|
|
6799
6716
|
EditorView.decorations = decorations;
|
|
6800
6717
|
/**
|
|
6718
|
+
Used to provide ranges that should be treated as atoms as far as
|
|
6719
|
+
cursor motion is concerned. This causes methods like
|
|
6720
|
+
[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
|
|
6721
|
+
[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
|
|
6722
|
+
commands built on top of them) to skip across such regions when
|
|
6723
|
+
a selection endpoint would enter them. This does _not_ prevent
|
|
6724
|
+
direct programmatic [selection
|
|
6725
|
+
updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
|
|
6726
|
+
regions.
|
|
6727
|
+
*/
|
|
6728
|
+
EditorView.atomicRanges = atomicRanges;
|
|
6729
|
+
/**
|
|
6730
|
+
Facet that allows extensions to provide additional scroll
|
|
6731
|
+
margins (space around the sides of the scrolling element that
|
|
6732
|
+
should be considered invisible). This can be useful when the
|
|
6733
|
+
plugin introduces elements that cover part of that element (for
|
|
6734
|
+
example a horizontally fixed gutter).
|
|
6735
|
+
*/
|
|
6736
|
+
EditorView.scrollMargins = scrollMargins;
|
|
6737
|
+
/**
|
|
6801
6738
|
This facet records whether a dark theme is active. The extension
|
|
6802
6739
|
returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
|
|
6803
6740
|
includes an instance of this when the `dark` option is set to
|
|
@@ -6830,10 +6767,6 @@ search match).
|
|
|
6830
6767
|
EditorView.announce = state.StateEffect.define();
|
|
6831
6768
|
// Maximum line length for which we compute accurate bidi info
|
|
6832
6769
|
const MaxBidiLine = 4096;
|
|
6833
|
-
// FIXME remove this and its callers on next breaking release
|
|
6834
|
-
function ensureTop(given, view) {
|
|
6835
|
-
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6836
|
-
}
|
|
6837
6770
|
const BadMeasure = {};
|
|
6838
6771
|
class CachedOrder {
|
|
6839
6772
|
constructor(from, to, dir, order) {
|
|
@@ -6936,7 +6869,7 @@ function getKeymap(state) {
|
|
|
6936
6869
|
}
|
|
6937
6870
|
/**
|
|
6938
6871
|
Run the key handlers registered for a given scope. The event
|
|
6939
|
-
object should be `"keydown"` event. Returns true if any of the
|
|
6872
|
+
object should be a `"keydown"` event. Returns true if any of the
|
|
6940
6873
|
handlers handled it.
|
|
6941
6874
|
*/
|
|
6942
6875
|
function runScopeHandlers(view, event, scope) {
|
|
@@ -7416,7 +7349,7 @@ class MatchDecorator {
|
|
|
7416
7349
|
plugin.
|
|
7417
7350
|
*/
|
|
7418
7351
|
createDeco(view) {
|
|
7419
|
-
let build = new
|
|
7352
|
+
let build = new state.RangeSetBuilder();
|
|
7420
7353
|
for (let { from, to } of matchRanges(view, this.maxLength))
|
|
7421
7354
|
iterMatches(view.state.doc, this.regexp, from, to, (a, b, m) => build.add(a, b, this.getDeco(m, view, a)));
|
|
7422
7355
|
return build.finish();
|
|
@@ -7548,10 +7481,10 @@ function specialCharPlugin() {
|
|
|
7548
7481
|
regexp: conf.specialChars,
|
|
7549
7482
|
decoration: (m, view, pos) => {
|
|
7550
7483
|
let { doc } = view.state;
|
|
7551
|
-
let code =
|
|
7484
|
+
let code = state.codePointAt(m[0], 0);
|
|
7552
7485
|
if (code == 9) {
|
|
7553
7486
|
let line = doc.lineAt(pos);
|
|
7554
|
-
let size = view.state.tabSize, col =
|
|
7487
|
+
let size = view.state.tabSize, col = state.countColumn(line.text, size, pos - line.from);
|
|
7555
7488
|
return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) });
|
|
7556
7489
|
}
|
|
7557
7490
|
return this.decorationCache[code] ||
|
|
@@ -7713,32 +7646,1338 @@ function placeholder(content) {
|
|
|
7713
7646
|
}, { decorations: v => v.decorations });
|
|
7714
7647
|
}
|
|
7715
7648
|
|
|
7649
|
+
// Don't compute precise column positions for line offsets above this
|
|
7650
|
+
// (since it could get expensive). Assume offset==column for them.
|
|
7651
|
+
const MaxOff = 2000;
|
|
7652
|
+
function rectangleFor(state$1, a, b) {
|
|
7653
|
+
let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
|
|
7654
|
+
let ranges = [];
|
|
7655
|
+
if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
|
|
7656
|
+
let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
|
|
7657
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
7658
|
+
let line = state$1.doc.line(i);
|
|
7659
|
+
if (line.length <= endOff)
|
|
7660
|
+
ranges.push(state.EditorSelection.range(line.from + startOff, line.to + endOff));
|
|
7661
|
+
}
|
|
7662
|
+
}
|
|
7663
|
+
else {
|
|
7664
|
+
let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
|
|
7665
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
7666
|
+
let line = state$1.doc.line(i);
|
|
7667
|
+
let start = state.findColumn(line.text, startCol, state$1.tabSize, true);
|
|
7668
|
+
if (start > -1) {
|
|
7669
|
+
let end = state.findColumn(line.text, endCol, state$1.tabSize);
|
|
7670
|
+
ranges.push(state.EditorSelection.range(line.from + start, line.from + end));
|
|
7671
|
+
}
|
|
7672
|
+
}
|
|
7673
|
+
}
|
|
7674
|
+
return ranges;
|
|
7675
|
+
}
|
|
7676
|
+
function absoluteColumn(view, x) {
|
|
7677
|
+
let ref = view.coordsAtPos(view.viewport.from);
|
|
7678
|
+
return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
|
|
7679
|
+
}
|
|
7680
|
+
function getPos(view, event) {
|
|
7681
|
+
let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
7682
|
+
let line = view.state.doc.lineAt(offset), off = offset - line.from;
|
|
7683
|
+
let col = off > MaxOff ? -1
|
|
7684
|
+
: off == line.length ? absoluteColumn(view, event.clientX)
|
|
7685
|
+
: state.countColumn(line.text, view.state.tabSize, offset - line.from);
|
|
7686
|
+
return { line: line.number, col, off };
|
|
7687
|
+
}
|
|
7688
|
+
function rectangleSelectionStyle(view, event) {
|
|
7689
|
+
let start = getPos(view, event), startSel = view.state.selection;
|
|
7690
|
+
if (!start)
|
|
7691
|
+
return null;
|
|
7692
|
+
return {
|
|
7693
|
+
update(update) {
|
|
7694
|
+
if (update.docChanged) {
|
|
7695
|
+
let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
|
|
7696
|
+
let newLine = update.state.doc.lineAt(newStart);
|
|
7697
|
+
start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
|
|
7698
|
+
startSel = startSel.map(update.changes);
|
|
7699
|
+
}
|
|
7700
|
+
},
|
|
7701
|
+
get(event, _extend, multiple) {
|
|
7702
|
+
let cur = getPos(view, event);
|
|
7703
|
+
if (!cur)
|
|
7704
|
+
return startSel;
|
|
7705
|
+
let ranges = rectangleFor(view.state, start, cur);
|
|
7706
|
+
if (!ranges.length)
|
|
7707
|
+
return startSel;
|
|
7708
|
+
if (multiple)
|
|
7709
|
+
return state.EditorSelection.create(ranges.concat(startSel.ranges));
|
|
7710
|
+
else
|
|
7711
|
+
return state.EditorSelection.create(ranges);
|
|
7712
|
+
}
|
|
7713
|
+
};
|
|
7714
|
+
}
|
|
7716
7715
|
/**
|
|
7717
|
-
|
|
7716
|
+
Create an extension that enables rectangular selections. By
|
|
7717
|
+
default, it will react to left mouse drag with the Alt key held
|
|
7718
|
+
down. When such a selection occurs, the text within the rectangle
|
|
7719
|
+
that was dragged over will be selected, as one selection
|
|
7720
|
+
[range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line.
|
|
7718
7721
|
*/
|
|
7719
|
-
|
|
7722
|
+
function rectangularSelection(options) {
|
|
7723
|
+
let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0);
|
|
7724
|
+
return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
|
|
7725
|
+
}
|
|
7726
|
+
const keys = {
|
|
7727
|
+
Alt: [18, e => e.altKey],
|
|
7728
|
+
Control: [17, e => e.ctrlKey],
|
|
7729
|
+
Shift: [16, e => e.shiftKey],
|
|
7730
|
+
Meta: [91, e => e.metaKey]
|
|
7731
|
+
};
|
|
7732
|
+
const showCrosshair = { style: "cursor: crosshair" };
|
|
7733
|
+
/**
|
|
7734
|
+
Returns an extension that turns the pointer cursor into a
|
|
7735
|
+
crosshair when a given modifier key, defaulting to Alt, is held
|
|
7736
|
+
down. Can serve as a visual hint that rectangular selection is
|
|
7737
|
+
going to happen when paired with
|
|
7738
|
+
[`rectangularSelection`](https://codemirror.net/6/docs/ref/#view.rectangularSelection).
|
|
7739
|
+
*/
|
|
7740
|
+
function crosshairCursor(options = {}) {
|
|
7741
|
+
let [code, getter] = keys[options.key || "Alt"];
|
|
7742
|
+
let plugin = ViewPlugin.fromClass(class {
|
|
7743
|
+
constructor(view) {
|
|
7744
|
+
this.view = view;
|
|
7745
|
+
this.isDown = false;
|
|
7746
|
+
}
|
|
7747
|
+
set(isDown) {
|
|
7748
|
+
if (this.isDown != isDown) {
|
|
7749
|
+
this.isDown = isDown;
|
|
7750
|
+
this.view.update([]);
|
|
7751
|
+
}
|
|
7752
|
+
}
|
|
7753
|
+
}, {
|
|
7754
|
+
eventHandlers: {
|
|
7755
|
+
keydown(e) {
|
|
7756
|
+
this.set(e.keyCode == code || getter(e));
|
|
7757
|
+
},
|
|
7758
|
+
keyup(e) {
|
|
7759
|
+
if (e.keyCode == code || !getter(e))
|
|
7760
|
+
this.set(false);
|
|
7761
|
+
}
|
|
7762
|
+
}
|
|
7763
|
+
});
|
|
7764
|
+
return [
|
|
7765
|
+
plugin,
|
|
7766
|
+
EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; })
|
|
7767
|
+
];
|
|
7768
|
+
}
|
|
7720
7769
|
|
|
7721
|
-
|
|
7722
|
-
|
|
7723
|
-
|
|
7770
|
+
const Outside = "-10000px";
|
|
7771
|
+
class TooltipViewManager {
|
|
7772
|
+
constructor(view, facet, createTooltipView) {
|
|
7773
|
+
this.facet = facet;
|
|
7774
|
+
this.createTooltipView = createTooltipView;
|
|
7775
|
+
this.input = view.state.facet(facet);
|
|
7776
|
+
this.tooltips = this.input.filter(t => t);
|
|
7777
|
+
this.tooltipViews = this.tooltips.map(createTooltipView);
|
|
7778
|
+
}
|
|
7779
|
+
update(update) {
|
|
7780
|
+
let input = update.state.facet(this.facet);
|
|
7781
|
+
let tooltips = input.filter(x => x);
|
|
7782
|
+
if (input === this.input) {
|
|
7783
|
+
for (let t of this.tooltipViews)
|
|
7784
|
+
if (t.update)
|
|
7785
|
+
t.update(update);
|
|
7786
|
+
return false;
|
|
7787
|
+
}
|
|
7788
|
+
let tooltipViews = [];
|
|
7789
|
+
for (let i = 0; i < tooltips.length; i++) {
|
|
7790
|
+
let tip = tooltips[i], known = -1;
|
|
7791
|
+
if (!tip)
|
|
7792
|
+
continue;
|
|
7793
|
+
for (let i = 0; i < this.tooltips.length; i++) {
|
|
7794
|
+
let other = this.tooltips[i];
|
|
7795
|
+
if (other && other.create == tip.create)
|
|
7796
|
+
known = i;
|
|
7797
|
+
}
|
|
7798
|
+
if (known < 0) {
|
|
7799
|
+
tooltipViews[i] = this.createTooltipView(tip);
|
|
7800
|
+
}
|
|
7801
|
+
else {
|
|
7802
|
+
let tooltipView = tooltipViews[i] = this.tooltipViews[known];
|
|
7803
|
+
if (tooltipView.update)
|
|
7804
|
+
tooltipView.update(update);
|
|
7805
|
+
}
|
|
7806
|
+
}
|
|
7807
|
+
for (let t of this.tooltipViews)
|
|
7808
|
+
if (tooltipViews.indexOf(t) < 0)
|
|
7809
|
+
t.dom.remove();
|
|
7810
|
+
this.input = input;
|
|
7811
|
+
this.tooltips = tooltips;
|
|
7812
|
+
this.tooltipViews = tooltipViews;
|
|
7813
|
+
return true;
|
|
7814
|
+
}
|
|
7815
|
+
}
|
|
7816
|
+
/**
|
|
7817
|
+
Creates an extension that configures tooltip behavior.
|
|
7818
|
+
*/
|
|
7819
|
+
function tooltips(config = {}) {
|
|
7820
|
+
return tooltipConfig.of(config);
|
|
7821
|
+
}
|
|
7822
|
+
function windowSpace() {
|
|
7823
|
+
return { top: 0, left: 0, bottom: innerHeight, right: innerWidth };
|
|
7824
|
+
}
|
|
7825
|
+
const tooltipConfig = state.Facet.define({
|
|
7826
|
+
combine: values => {
|
|
7827
|
+
var _a, _b, _c;
|
|
7828
|
+
return ({
|
|
7829
|
+
position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
|
|
7830
|
+
parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
|
|
7831
|
+
tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
|
|
7832
|
+
});
|
|
7833
|
+
}
|
|
7834
|
+
});
|
|
7835
|
+
const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
7836
|
+
constructor(view) {
|
|
7837
|
+
var _a;
|
|
7838
|
+
this.view = view;
|
|
7839
|
+
this.inView = true;
|
|
7840
|
+
this.lastTransaction = 0;
|
|
7841
|
+
this.measureTimeout = -1;
|
|
7842
|
+
let config = view.state.facet(tooltipConfig);
|
|
7843
|
+
this.position = config.position;
|
|
7844
|
+
this.parent = config.parent;
|
|
7845
|
+
this.classes = view.themeClasses;
|
|
7846
|
+
this.createContainer();
|
|
7847
|
+
this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
|
|
7848
|
+
this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
|
|
7849
|
+
this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
|
|
7850
|
+
if (Date.now() > this.lastTransaction - 50 &&
|
|
7851
|
+
entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
|
|
7852
|
+
this.measureSoon();
|
|
7853
|
+
}, { threshold: [1] }) : null;
|
|
7854
|
+
this.observeIntersection();
|
|
7855
|
+
(_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
|
|
7856
|
+
this.maybeMeasure();
|
|
7857
|
+
}
|
|
7858
|
+
createContainer() {
|
|
7859
|
+
if (this.parent) {
|
|
7860
|
+
this.container = document.createElement("div");
|
|
7861
|
+
this.container.style.position = "relative";
|
|
7862
|
+
this.container.className = this.view.themeClasses;
|
|
7863
|
+
this.parent.appendChild(this.container);
|
|
7864
|
+
}
|
|
7865
|
+
else {
|
|
7866
|
+
this.container = this.view.dom;
|
|
7867
|
+
}
|
|
7868
|
+
}
|
|
7869
|
+
observeIntersection() {
|
|
7870
|
+
if (this.intersectionObserver) {
|
|
7871
|
+
this.intersectionObserver.disconnect();
|
|
7872
|
+
for (let tooltip of this.manager.tooltipViews)
|
|
7873
|
+
this.intersectionObserver.observe(tooltip.dom);
|
|
7874
|
+
}
|
|
7875
|
+
}
|
|
7876
|
+
measureSoon() {
|
|
7877
|
+
if (this.measureTimeout < 0)
|
|
7878
|
+
this.measureTimeout = setTimeout(() => {
|
|
7879
|
+
this.measureTimeout = -1;
|
|
7880
|
+
this.maybeMeasure();
|
|
7881
|
+
}, 50);
|
|
7882
|
+
}
|
|
7883
|
+
update(update) {
|
|
7884
|
+
if (update.transactions.length)
|
|
7885
|
+
this.lastTransaction = Date.now();
|
|
7886
|
+
let updated = this.manager.update(update);
|
|
7887
|
+
if (updated)
|
|
7888
|
+
this.observeIntersection();
|
|
7889
|
+
let shouldMeasure = updated || update.geometryChanged;
|
|
7890
|
+
let newConfig = update.state.facet(tooltipConfig);
|
|
7891
|
+
if (newConfig.position != this.position) {
|
|
7892
|
+
this.position = newConfig.position;
|
|
7893
|
+
for (let t of this.manager.tooltipViews)
|
|
7894
|
+
t.dom.style.position = this.position;
|
|
7895
|
+
shouldMeasure = true;
|
|
7896
|
+
}
|
|
7897
|
+
if (newConfig.parent != this.parent) {
|
|
7898
|
+
if (this.parent)
|
|
7899
|
+
this.container.remove();
|
|
7900
|
+
this.parent = newConfig.parent;
|
|
7901
|
+
this.createContainer();
|
|
7902
|
+
for (let t of this.manager.tooltipViews)
|
|
7903
|
+
this.container.appendChild(t.dom);
|
|
7904
|
+
shouldMeasure = true;
|
|
7905
|
+
}
|
|
7906
|
+
else if (this.parent && this.view.themeClasses != this.classes) {
|
|
7907
|
+
this.classes = this.container.className = this.view.themeClasses;
|
|
7908
|
+
}
|
|
7909
|
+
if (shouldMeasure)
|
|
7910
|
+
this.maybeMeasure();
|
|
7911
|
+
}
|
|
7912
|
+
createTooltip(tooltip) {
|
|
7913
|
+
let tooltipView = tooltip.create(this.view);
|
|
7914
|
+
tooltipView.dom.classList.add("cm-tooltip");
|
|
7915
|
+
if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
|
|
7916
|
+
let arrow = document.createElement("div");
|
|
7917
|
+
arrow.className = "cm-tooltip-arrow";
|
|
7918
|
+
tooltipView.dom.appendChild(arrow);
|
|
7919
|
+
}
|
|
7920
|
+
tooltipView.dom.style.position = this.position;
|
|
7921
|
+
tooltipView.dom.style.top = Outside;
|
|
7922
|
+
this.container.appendChild(tooltipView.dom);
|
|
7923
|
+
if (tooltipView.mount)
|
|
7924
|
+
tooltipView.mount(this.view);
|
|
7925
|
+
return tooltipView;
|
|
7926
|
+
}
|
|
7927
|
+
destroy() {
|
|
7928
|
+
var _a, _b;
|
|
7929
|
+
(_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon);
|
|
7930
|
+
for (let { dom } of this.manager.tooltipViews)
|
|
7931
|
+
dom.remove();
|
|
7932
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
7933
|
+
clearTimeout(this.measureTimeout);
|
|
7934
|
+
}
|
|
7935
|
+
readMeasure() {
|
|
7936
|
+
let editor = this.view.dom.getBoundingClientRect();
|
|
7937
|
+
return {
|
|
7938
|
+
editor,
|
|
7939
|
+
parent: this.parent ? this.container.getBoundingClientRect() : editor,
|
|
7940
|
+
pos: this.manager.tooltips.map((t, i) => {
|
|
7941
|
+
let tv = this.manager.tooltipViews[i];
|
|
7942
|
+
return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
|
|
7943
|
+
}),
|
|
7944
|
+
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
7945
|
+
space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
|
|
7946
|
+
};
|
|
7947
|
+
}
|
|
7948
|
+
writeMeasure(measured) {
|
|
7949
|
+
let { editor, space } = measured;
|
|
7950
|
+
let others = [];
|
|
7951
|
+
for (let i = 0; i < this.manager.tooltips.length; i++) {
|
|
7952
|
+
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
|
7953
|
+
let pos = measured.pos[i], size = measured.size[i];
|
|
7954
|
+
// Hide tooltips that are outside of the editor.
|
|
7955
|
+
if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
|
|
7956
|
+
pos.top >= Math.min(editor.bottom, space.bottom) ||
|
|
7957
|
+
pos.right < Math.max(editor.left, space.left) - .1 ||
|
|
7958
|
+
pos.left > Math.min(editor.right, space.right) + .1) {
|
|
7959
|
+
dom.style.top = Outside;
|
|
7960
|
+
continue;
|
|
7961
|
+
}
|
|
7962
|
+
let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
|
|
7963
|
+
let arrowHeight = arrow ? 7 /* Size */ : 0;
|
|
7964
|
+
let width = size.right - size.left, height = size.bottom - size.top;
|
|
7965
|
+
let offset = tView.offset || noOffset, ltr = this.view.textDirection == exports.Direction.LTR;
|
|
7966
|
+
let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
|
|
7967
|
+
: ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width)
|
|
7968
|
+
: Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x);
|
|
7969
|
+
let above = !!tooltip.above;
|
|
7970
|
+
if (!tooltip.strictSide && (above
|
|
7971
|
+
? pos.top - (size.bottom - size.top) - offset.y < space.top
|
|
7972
|
+
: pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
|
|
7973
|
+
above == (space.bottom - pos.bottom > pos.top - space.top))
|
|
7974
|
+
above = !above;
|
|
7975
|
+
let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
|
|
7976
|
+
let right = left + width;
|
|
7977
|
+
if (tView.overlap !== true)
|
|
7978
|
+
for (let r of others)
|
|
7979
|
+
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
7980
|
+
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
7981
|
+
if (this.position == "absolute") {
|
|
7982
|
+
dom.style.top = (top - measured.parent.top) + "px";
|
|
7983
|
+
dom.style.left = (left - measured.parent.left) + "px";
|
|
7984
|
+
}
|
|
7985
|
+
else {
|
|
7986
|
+
dom.style.top = top + "px";
|
|
7987
|
+
dom.style.left = left + "px";
|
|
7988
|
+
}
|
|
7989
|
+
if (arrow)
|
|
7990
|
+
arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`;
|
|
7991
|
+
if (tView.overlap !== true)
|
|
7992
|
+
others.push({ left, top, right, bottom: top + height });
|
|
7993
|
+
dom.classList.toggle("cm-tooltip-above", above);
|
|
7994
|
+
dom.classList.toggle("cm-tooltip-below", !above);
|
|
7995
|
+
if (tView.positioned)
|
|
7996
|
+
tView.positioned();
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
maybeMeasure() {
|
|
8000
|
+
if (this.manager.tooltips.length) {
|
|
8001
|
+
if (this.view.inView)
|
|
8002
|
+
this.view.requestMeasure(this.measureReq);
|
|
8003
|
+
if (this.inView != this.view.inView) {
|
|
8004
|
+
this.inView = this.view.inView;
|
|
8005
|
+
if (!this.inView)
|
|
8006
|
+
for (let tv of this.manager.tooltipViews)
|
|
8007
|
+
tv.dom.style.top = Outside;
|
|
8008
|
+
}
|
|
8009
|
+
}
|
|
8010
|
+
}
|
|
8011
|
+
}, {
|
|
8012
|
+
eventHandlers: {
|
|
8013
|
+
scroll() { this.maybeMeasure(); }
|
|
8014
|
+
}
|
|
7724
8015
|
});
|
|
8016
|
+
const baseTheme = EditorView.baseTheme({
|
|
8017
|
+
".cm-tooltip": {
|
|
8018
|
+
zIndex: 100
|
|
8019
|
+
},
|
|
8020
|
+
"&light .cm-tooltip": {
|
|
8021
|
+
border: "1px solid #bbb",
|
|
8022
|
+
backgroundColor: "#f5f5f5"
|
|
8023
|
+
},
|
|
8024
|
+
"&light .cm-tooltip-section:not(:first-child)": {
|
|
8025
|
+
borderTop: "1px solid #bbb",
|
|
8026
|
+
},
|
|
8027
|
+
"&dark .cm-tooltip": {
|
|
8028
|
+
backgroundColor: "#333338",
|
|
8029
|
+
color: "white"
|
|
8030
|
+
},
|
|
8031
|
+
".cm-tooltip-arrow": {
|
|
8032
|
+
height: `${7 /* Size */}px`,
|
|
8033
|
+
width: `${7 /* Size */ * 2}px`,
|
|
8034
|
+
position: "absolute",
|
|
8035
|
+
zIndex: -1,
|
|
8036
|
+
overflow: "hidden",
|
|
8037
|
+
"&:before, &:after": {
|
|
8038
|
+
content: "''",
|
|
8039
|
+
position: "absolute",
|
|
8040
|
+
width: 0,
|
|
8041
|
+
height: 0,
|
|
8042
|
+
borderLeft: `${7 /* Size */}px solid transparent`,
|
|
8043
|
+
borderRight: `${7 /* Size */}px solid transparent`,
|
|
8044
|
+
},
|
|
8045
|
+
".cm-tooltip-above &": {
|
|
8046
|
+
bottom: `-${7 /* Size */}px`,
|
|
8047
|
+
"&:before": {
|
|
8048
|
+
borderTop: `${7 /* Size */}px solid #bbb`,
|
|
8049
|
+
},
|
|
8050
|
+
"&:after": {
|
|
8051
|
+
borderTop: `${7 /* Size */}px solid #f5f5f5`,
|
|
8052
|
+
bottom: "1px"
|
|
8053
|
+
}
|
|
8054
|
+
},
|
|
8055
|
+
".cm-tooltip-below &": {
|
|
8056
|
+
top: `-${7 /* Size */}px`,
|
|
8057
|
+
"&:before": {
|
|
8058
|
+
borderBottom: `${7 /* Size */}px solid #bbb`,
|
|
8059
|
+
},
|
|
8060
|
+
"&:after": {
|
|
8061
|
+
borderBottom: `${7 /* Size */}px solid #f5f5f5`,
|
|
8062
|
+
top: "1px"
|
|
8063
|
+
}
|
|
8064
|
+
},
|
|
8065
|
+
},
|
|
8066
|
+
"&dark .cm-tooltip .cm-tooltip-arrow": {
|
|
8067
|
+
"&:before": {
|
|
8068
|
+
borderTopColor: "#333338",
|
|
8069
|
+
borderBottomColor: "#333338"
|
|
8070
|
+
},
|
|
8071
|
+
"&:after": {
|
|
8072
|
+
borderTopColor: "transparent",
|
|
8073
|
+
borderBottomColor: "transparent"
|
|
8074
|
+
}
|
|
8075
|
+
}
|
|
8076
|
+
});
|
|
8077
|
+
const noOffset = { x: 0, y: 0 };
|
|
8078
|
+
/**
|
|
8079
|
+
Facet to which an extension can add a value to show a tooltip.
|
|
8080
|
+
*/
|
|
8081
|
+
const showTooltip = state.Facet.define({
|
|
8082
|
+
enables: [tooltipPlugin, baseTheme]
|
|
8083
|
+
});
|
|
8084
|
+
const showHoverTooltip = state.Facet.define({
|
|
8085
|
+
combine(x) { console.log("show", x.map(x => !!x)); return x; }
|
|
8086
|
+
});
|
|
8087
|
+
class HoverTooltipHost {
|
|
8088
|
+
constructor(view) {
|
|
8089
|
+
this.view = view;
|
|
8090
|
+
this.mounted = false;
|
|
8091
|
+
this.dom = document.createElement("div");
|
|
8092
|
+
this.dom.classList.add("cm-tooltip-hover");
|
|
8093
|
+
this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
|
|
8094
|
+
}
|
|
8095
|
+
// Needs to be static so that host tooltip instances always match
|
|
8096
|
+
static create(view) {
|
|
8097
|
+
return new HoverTooltipHost(view);
|
|
8098
|
+
}
|
|
8099
|
+
createHostedView(tooltip) {
|
|
8100
|
+
let hostedView = tooltip.create(this.view);
|
|
8101
|
+
hostedView.dom.classList.add("cm-tooltip-section");
|
|
8102
|
+
this.dom.appendChild(hostedView.dom);
|
|
8103
|
+
if (this.mounted && hostedView.mount)
|
|
8104
|
+
hostedView.mount(this.view);
|
|
8105
|
+
return hostedView;
|
|
8106
|
+
}
|
|
8107
|
+
mount(view) {
|
|
8108
|
+
for (let hostedView of this.manager.tooltipViews) {
|
|
8109
|
+
if (hostedView.mount)
|
|
8110
|
+
hostedView.mount(view);
|
|
8111
|
+
}
|
|
8112
|
+
this.mounted = true;
|
|
8113
|
+
}
|
|
8114
|
+
positioned() {
|
|
8115
|
+
for (let hostedView of this.manager.tooltipViews) {
|
|
8116
|
+
if (hostedView.positioned)
|
|
8117
|
+
hostedView.positioned();
|
|
8118
|
+
}
|
|
8119
|
+
}
|
|
8120
|
+
update(update) {
|
|
8121
|
+
this.manager.update(update);
|
|
8122
|
+
}
|
|
8123
|
+
}
|
|
8124
|
+
const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
|
|
8125
|
+
let tooltips = state.facet(showHoverTooltip).filter(t => t);
|
|
8126
|
+
console.log("hover tooltips: ", tooltips.length);
|
|
8127
|
+
if (tooltips.length === 0)
|
|
8128
|
+
return null;
|
|
8129
|
+
return {
|
|
8130
|
+
pos: Math.min(...tooltips.map(t => t.pos)),
|
|
8131
|
+
end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
|
|
8132
|
+
create: HoverTooltipHost.create,
|
|
8133
|
+
above: tooltips[0].above,
|
|
8134
|
+
arrow: tooltips.some(t => t.arrow),
|
|
8135
|
+
};
|
|
8136
|
+
});
|
|
8137
|
+
class HoverPlugin {
|
|
8138
|
+
constructor(view, source, field, setHover, hoverTime) {
|
|
8139
|
+
this.view = view;
|
|
8140
|
+
this.source = source;
|
|
8141
|
+
this.field = field;
|
|
8142
|
+
this.setHover = setHover;
|
|
8143
|
+
this.hoverTime = hoverTime;
|
|
8144
|
+
this.hoverTimeout = -1;
|
|
8145
|
+
this.restartTimeout = -1;
|
|
8146
|
+
this.pending = null;
|
|
8147
|
+
this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
|
|
8148
|
+
this.checkHover = this.checkHover.bind(this);
|
|
8149
|
+
view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
|
|
8150
|
+
view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
|
|
8151
|
+
}
|
|
8152
|
+
update() {
|
|
8153
|
+
if (this.pending) {
|
|
8154
|
+
this.pending = null;
|
|
8155
|
+
clearTimeout(this.restartTimeout);
|
|
8156
|
+
this.restartTimeout = setTimeout(() => this.startHover(), 20);
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
8159
|
+
get active() {
|
|
8160
|
+
return this.view.state.field(this.field);
|
|
8161
|
+
}
|
|
8162
|
+
checkHover() {
|
|
8163
|
+
this.hoverTimeout = -1;
|
|
8164
|
+
if (this.active)
|
|
8165
|
+
return;
|
|
8166
|
+
let hovered = Date.now() - this.lastMove.time;
|
|
8167
|
+
if (hovered < this.hoverTime)
|
|
8168
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
|
|
8169
|
+
else
|
|
8170
|
+
this.startHover();
|
|
8171
|
+
}
|
|
8172
|
+
startHover() {
|
|
8173
|
+
var _a;
|
|
8174
|
+
clearTimeout(this.restartTimeout);
|
|
8175
|
+
let { lastMove } = this;
|
|
8176
|
+
let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
|
|
8177
|
+
if (pos == null)
|
|
8178
|
+
return;
|
|
8179
|
+
let posCoords = this.view.coordsAtPos(pos);
|
|
8180
|
+
if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
|
|
8181
|
+
lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
|
|
8182
|
+
lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
|
|
8183
|
+
return;
|
|
8184
|
+
let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
|
|
8185
|
+
let rtl = bidi && bidi.dir == exports.Direction.RTL ? -1 : 1;
|
|
8186
|
+
let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
|
|
8187
|
+
if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) {
|
|
8188
|
+
let pending = this.pending = { pos };
|
|
8189
|
+
open.then(result => {
|
|
8190
|
+
if (this.pending == pending) {
|
|
8191
|
+
this.pending = null;
|
|
8192
|
+
if (result)
|
|
8193
|
+
this.view.dispatch({ effects: this.setHover.of(result) });
|
|
8194
|
+
}
|
|
8195
|
+
}, e => logException(this.view.state, e, "hover tooltip"));
|
|
8196
|
+
}
|
|
8197
|
+
else if (open) {
|
|
8198
|
+
this.view.dispatch({ effects: this.setHover.of(open) });
|
|
8199
|
+
}
|
|
8200
|
+
}
|
|
8201
|
+
mousemove(event) {
|
|
8202
|
+
var _a;
|
|
8203
|
+
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
|
|
8204
|
+
if (this.hoverTimeout < 0)
|
|
8205
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
|
|
8206
|
+
let tooltip = this.active;
|
|
8207
|
+
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
8208
|
+
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
8209
|
+
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
8210
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) {
|
|
8211
|
+
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
8212
|
+
this.pending = null;
|
|
8213
|
+
}
|
|
8214
|
+
}
|
|
8215
|
+
}
|
|
8216
|
+
mouseleave() {
|
|
8217
|
+
clearTimeout(this.hoverTimeout);
|
|
8218
|
+
this.hoverTimeout = -1;
|
|
8219
|
+
if (this.active)
|
|
8220
|
+
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
8221
|
+
}
|
|
8222
|
+
destroy() {
|
|
8223
|
+
clearTimeout(this.hoverTimeout);
|
|
8224
|
+
this.view.dom.removeEventListener("mouseleave", this.mouseleave);
|
|
8225
|
+
this.view.dom.removeEventListener("mousemove", this.mousemove);
|
|
8226
|
+
}
|
|
8227
|
+
}
|
|
8228
|
+
function isInTooltip(elt) {
|
|
8229
|
+
for (let cur = elt; cur; cur = cur.parentNode)
|
|
8230
|
+
if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
|
|
8231
|
+
return true;
|
|
8232
|
+
return false;
|
|
8233
|
+
}
|
|
8234
|
+
function isOverRange(view, from, to, x, y, margin) {
|
|
8235
|
+
let range = document.createRange();
|
|
8236
|
+
let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
|
|
8237
|
+
range.setEnd(toDOM.node, toDOM.offset);
|
|
8238
|
+
range.setStart(fromDOM.node, fromDOM.offset);
|
|
8239
|
+
let rects = range.getClientRects();
|
|
8240
|
+
range.detach();
|
|
8241
|
+
for (let i = 0; i < rects.length; i++) {
|
|
8242
|
+
let rect = rects[i];
|
|
8243
|
+
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
8244
|
+
if (dist <= margin)
|
|
8245
|
+
return true;
|
|
8246
|
+
}
|
|
8247
|
+
return false;
|
|
8248
|
+
}
|
|
8249
|
+
/**
|
|
8250
|
+
Set up a hover tooltip, which shows up when the pointer hovers
|
|
8251
|
+
over ranges of text. The callback is called when the mouse hovers
|
|
8252
|
+
over the document text. It should, if there is a tooltip
|
|
8253
|
+
associated with position `pos`, return the tooltip description
|
|
8254
|
+
(either directly or in a promise). The `side` argument indicates
|
|
8255
|
+
on which side of the position the pointer is—it will be -1 if the
|
|
8256
|
+
pointer is before the position, 1 if after the position.
|
|
8257
|
+
|
|
8258
|
+
Note that all hover tooltips are hosted within a single tooltip
|
|
8259
|
+
container element. This allows multiple tooltips over the same
|
|
8260
|
+
range to be "merged" together without overlapping.
|
|
8261
|
+
*/
|
|
8262
|
+
function hoverTooltip(source, options = {}) {
|
|
8263
|
+
let setHover = state.StateEffect.define();
|
|
8264
|
+
let hoverState = state.StateField.define({
|
|
8265
|
+
create() { return null; },
|
|
8266
|
+
update(value, tr) {
|
|
8267
|
+
console.log("update tooltip", !!value);
|
|
8268
|
+
if (value && (options.hideOnChange && (tr.docChanged || tr.selection)))
|
|
8269
|
+
return null;
|
|
8270
|
+
if (value && tr.docChanged) {
|
|
8271
|
+
let newPos = tr.changes.mapPos(value.pos, -1, state.MapMode.TrackDel);
|
|
8272
|
+
if (newPos == null)
|
|
8273
|
+
return null;
|
|
8274
|
+
let copy = Object.assign(Object.create(null), value);
|
|
8275
|
+
copy.pos = newPos;
|
|
8276
|
+
if (value.end != null)
|
|
8277
|
+
copy.end = tr.changes.mapPos(value.end);
|
|
8278
|
+
value = copy;
|
|
8279
|
+
}
|
|
8280
|
+
for (let effect of tr.effects) {
|
|
8281
|
+
if (effect.is(setHover))
|
|
8282
|
+
value = effect.value;
|
|
8283
|
+
if (effect.is(closeHoverTooltipEffect))
|
|
8284
|
+
value = (console.log("CLOSE"), null);
|
|
8285
|
+
}
|
|
8286
|
+
console.log("updated: " + !!value);
|
|
8287
|
+
return value;
|
|
8288
|
+
},
|
|
8289
|
+
provide: f => showHoverTooltip.from(f)
|
|
8290
|
+
});
|
|
8291
|
+
return [
|
|
8292
|
+
hoverState,
|
|
8293
|
+
ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Time */)),
|
|
8294
|
+
showHoverTooltipHost
|
|
8295
|
+
];
|
|
8296
|
+
}
|
|
8297
|
+
/**
|
|
8298
|
+
Get the active tooltip view for a given tooltip, if available.
|
|
8299
|
+
*/
|
|
8300
|
+
function getTooltip(view, tooltip) {
|
|
8301
|
+
let plugin = view.plugin(tooltipPlugin);
|
|
8302
|
+
if (!plugin)
|
|
8303
|
+
return null;
|
|
8304
|
+
let found = plugin.manager.tooltips.indexOf(tooltip);
|
|
8305
|
+
return found < 0 ? null : plugin.manager.tooltipViews[found];
|
|
8306
|
+
}
|
|
8307
|
+
/**
|
|
8308
|
+
Returns true if any hover tooltips are currently active.
|
|
8309
|
+
*/
|
|
8310
|
+
function hasHoverTooltips(state) {
|
|
8311
|
+
return state.facet(showHoverTooltip).some(x => x);
|
|
8312
|
+
}
|
|
8313
|
+
const closeHoverTooltipEffect = state.StateEffect.define();
|
|
8314
|
+
/**
|
|
8315
|
+
Transaction effect that closes all hover tooltips.
|
|
8316
|
+
*/
|
|
8317
|
+
const closeHoverTooltips = closeHoverTooltipEffect.of(null);
|
|
8318
|
+
/**
|
|
8319
|
+
Tell the tooltip extension to recompute the position of the active
|
|
8320
|
+
tooltips. This can be useful when something happens (such as a
|
|
8321
|
+
re-positioning or CSS change affecting the editor) that could
|
|
8322
|
+
invalidate the existing tooltip positions.
|
|
8323
|
+
*/
|
|
8324
|
+
function repositionTooltips(view) {
|
|
8325
|
+
var _a;
|
|
8326
|
+
(_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
|
|
8327
|
+
}
|
|
8328
|
+
|
|
8329
|
+
const panelConfig = state.Facet.define({
|
|
8330
|
+
combine(configs) {
|
|
8331
|
+
let topContainer, bottomContainer;
|
|
8332
|
+
for (let c of configs) {
|
|
8333
|
+
topContainer = topContainer || c.topContainer;
|
|
8334
|
+
bottomContainer = bottomContainer || c.bottomContainer;
|
|
8335
|
+
}
|
|
8336
|
+
return { topContainer, bottomContainer };
|
|
8337
|
+
}
|
|
8338
|
+
});
|
|
8339
|
+
/**
|
|
8340
|
+
Configures the panel-managing extension.
|
|
8341
|
+
*/
|
|
8342
|
+
function panels(config) {
|
|
8343
|
+
return config ? [panelConfig.of(config)] : [];
|
|
8344
|
+
}
|
|
8345
|
+
/**
|
|
8346
|
+
Get the active panel created by the given constructor, if any.
|
|
8347
|
+
This can be useful when you need access to your panels' DOM
|
|
8348
|
+
structure.
|
|
8349
|
+
*/
|
|
8350
|
+
function getPanel(view, panel) {
|
|
8351
|
+
let plugin = view.plugin(panelPlugin);
|
|
8352
|
+
let index = plugin ? plugin.specs.indexOf(panel) : -1;
|
|
8353
|
+
return index > -1 ? plugin.panels[index] : null;
|
|
8354
|
+
}
|
|
8355
|
+
const panelPlugin = ViewPlugin.fromClass(class {
|
|
8356
|
+
constructor(view) {
|
|
8357
|
+
this.input = view.state.facet(showPanel);
|
|
8358
|
+
this.specs = this.input.filter(s => s);
|
|
8359
|
+
this.panels = this.specs.map(spec => spec(view));
|
|
8360
|
+
let conf = view.state.facet(panelConfig);
|
|
8361
|
+
this.top = new PanelGroup(view, true, conf.topContainer);
|
|
8362
|
+
this.bottom = new PanelGroup(view, false, conf.bottomContainer);
|
|
8363
|
+
this.top.sync(this.panels.filter(p => p.top));
|
|
8364
|
+
this.bottom.sync(this.panels.filter(p => !p.top));
|
|
8365
|
+
for (let p of this.panels) {
|
|
8366
|
+
p.dom.classList.add("cm-panel");
|
|
8367
|
+
if (p.mount)
|
|
8368
|
+
p.mount();
|
|
8369
|
+
}
|
|
8370
|
+
}
|
|
8371
|
+
update(update) {
|
|
8372
|
+
let conf = update.state.facet(panelConfig);
|
|
8373
|
+
if (this.top.container != conf.topContainer) {
|
|
8374
|
+
this.top.sync([]);
|
|
8375
|
+
this.top = new PanelGroup(update.view, true, conf.topContainer);
|
|
8376
|
+
}
|
|
8377
|
+
if (this.bottom.container != conf.bottomContainer) {
|
|
8378
|
+
this.bottom.sync([]);
|
|
8379
|
+
this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
|
|
8380
|
+
}
|
|
8381
|
+
this.top.syncClasses();
|
|
8382
|
+
this.bottom.syncClasses();
|
|
8383
|
+
let input = update.state.facet(showPanel);
|
|
8384
|
+
if (input != this.input) {
|
|
8385
|
+
let specs = input.filter(x => x);
|
|
8386
|
+
let panels = [], top = [], bottom = [], mount = [];
|
|
8387
|
+
for (let spec of specs) {
|
|
8388
|
+
let known = this.specs.indexOf(spec), panel;
|
|
8389
|
+
if (known < 0) {
|
|
8390
|
+
panel = spec(update.view);
|
|
8391
|
+
mount.push(panel);
|
|
8392
|
+
}
|
|
8393
|
+
else {
|
|
8394
|
+
panel = this.panels[known];
|
|
8395
|
+
if (panel.update)
|
|
8396
|
+
panel.update(update);
|
|
8397
|
+
}
|
|
8398
|
+
panels.push(panel);
|
|
8399
|
+
(panel.top ? top : bottom).push(panel);
|
|
8400
|
+
}
|
|
8401
|
+
this.specs = specs;
|
|
8402
|
+
this.panels = panels;
|
|
8403
|
+
this.top.sync(top);
|
|
8404
|
+
this.bottom.sync(bottom);
|
|
8405
|
+
for (let p of mount) {
|
|
8406
|
+
p.dom.classList.add("cm-panel");
|
|
8407
|
+
if (p.mount)
|
|
8408
|
+
p.mount();
|
|
8409
|
+
}
|
|
8410
|
+
}
|
|
8411
|
+
else {
|
|
8412
|
+
for (let p of this.panels)
|
|
8413
|
+
if (p.update)
|
|
8414
|
+
p.update(update);
|
|
8415
|
+
}
|
|
8416
|
+
}
|
|
8417
|
+
destroy() {
|
|
8418
|
+
this.top.sync([]);
|
|
8419
|
+
this.bottom.sync([]);
|
|
8420
|
+
}
|
|
8421
|
+
}, {
|
|
8422
|
+
provide: plugin => EditorView.scrollMargins.of(view => {
|
|
8423
|
+
let value = view.plugin(plugin);
|
|
8424
|
+
return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
|
|
8425
|
+
})
|
|
8426
|
+
});
|
|
8427
|
+
class PanelGroup {
|
|
8428
|
+
constructor(view, top, container) {
|
|
8429
|
+
this.view = view;
|
|
8430
|
+
this.top = top;
|
|
8431
|
+
this.container = container;
|
|
8432
|
+
this.dom = undefined;
|
|
8433
|
+
this.classes = "";
|
|
8434
|
+
this.panels = [];
|
|
8435
|
+
this.syncClasses();
|
|
8436
|
+
}
|
|
8437
|
+
sync(panels) {
|
|
8438
|
+
for (let p of this.panels)
|
|
8439
|
+
if (p.destroy && panels.indexOf(p) < 0)
|
|
8440
|
+
p.destroy();
|
|
8441
|
+
this.panels = panels;
|
|
8442
|
+
this.syncDOM();
|
|
8443
|
+
}
|
|
8444
|
+
syncDOM() {
|
|
8445
|
+
if (this.panels.length == 0) {
|
|
8446
|
+
if (this.dom) {
|
|
8447
|
+
this.dom.remove();
|
|
8448
|
+
this.dom = undefined;
|
|
8449
|
+
}
|
|
8450
|
+
return;
|
|
8451
|
+
}
|
|
8452
|
+
if (!this.dom) {
|
|
8453
|
+
this.dom = document.createElement("div");
|
|
8454
|
+
this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
|
|
8455
|
+
this.dom.style[this.top ? "top" : "bottom"] = "0";
|
|
8456
|
+
let parent = this.container || this.view.dom;
|
|
8457
|
+
parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
|
|
8458
|
+
}
|
|
8459
|
+
let curDOM = this.dom.firstChild;
|
|
8460
|
+
for (let panel of this.panels) {
|
|
8461
|
+
if (panel.dom.parentNode == this.dom) {
|
|
8462
|
+
while (curDOM != panel.dom)
|
|
8463
|
+
curDOM = rm(curDOM);
|
|
8464
|
+
curDOM = curDOM.nextSibling;
|
|
8465
|
+
}
|
|
8466
|
+
else {
|
|
8467
|
+
this.dom.insertBefore(panel.dom, curDOM);
|
|
8468
|
+
}
|
|
8469
|
+
}
|
|
8470
|
+
while (curDOM)
|
|
8471
|
+
curDOM = rm(curDOM);
|
|
8472
|
+
}
|
|
8473
|
+
scrollMargin() {
|
|
8474
|
+
return !this.dom || this.container ? 0
|
|
8475
|
+
: Math.max(0, this.top ?
|
|
8476
|
+
this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
|
|
8477
|
+
Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
|
|
8478
|
+
}
|
|
8479
|
+
syncClasses() {
|
|
8480
|
+
if (!this.container || this.classes == this.view.themeClasses)
|
|
8481
|
+
return;
|
|
8482
|
+
for (let cls of this.classes.split(" "))
|
|
8483
|
+
if (cls)
|
|
8484
|
+
this.container.classList.remove(cls);
|
|
8485
|
+
for (let cls of (this.classes = this.view.themeClasses).split(" "))
|
|
8486
|
+
if (cls)
|
|
8487
|
+
this.container.classList.add(cls);
|
|
8488
|
+
}
|
|
8489
|
+
}
|
|
8490
|
+
function rm(node) {
|
|
8491
|
+
let next = node.nextSibling;
|
|
8492
|
+
node.remove();
|
|
8493
|
+
return next;
|
|
8494
|
+
}
|
|
8495
|
+
/**
|
|
8496
|
+
Opening a panel is done by providing a constructor function for
|
|
8497
|
+
the panel through this facet. (The panel is closed again when its
|
|
8498
|
+
constructor is no longer provided.) Values of `null` are ignored.
|
|
8499
|
+
*/
|
|
8500
|
+
const showPanel = state.Facet.define({
|
|
8501
|
+
enables: panelPlugin
|
|
8502
|
+
});
|
|
8503
|
+
|
|
8504
|
+
/**
|
|
8505
|
+
A gutter marker represents a bit of information attached to a line
|
|
8506
|
+
in a specific gutter. Your own custom markers have to extend this
|
|
8507
|
+
class.
|
|
8508
|
+
*/
|
|
8509
|
+
class GutterMarker extends state.RangeValue {
|
|
8510
|
+
/**
|
|
8511
|
+
@internal
|
|
8512
|
+
*/
|
|
8513
|
+
compare(other) {
|
|
8514
|
+
return this == other || this.constructor == other.constructor && this.eq(other);
|
|
8515
|
+
}
|
|
8516
|
+
/**
|
|
8517
|
+
Compare this marker to another marker of the same type.
|
|
8518
|
+
*/
|
|
8519
|
+
eq(other) { return false; }
|
|
8520
|
+
/**
|
|
8521
|
+
Called if the marker has a `toDOM` method and its representation
|
|
8522
|
+
was removed from a gutter.
|
|
8523
|
+
*/
|
|
8524
|
+
destroy(dom) { }
|
|
8525
|
+
}
|
|
8526
|
+
GutterMarker.prototype.elementClass = "";
|
|
8527
|
+
GutterMarker.prototype.toDOM = undefined;
|
|
8528
|
+
GutterMarker.prototype.mapMode = state.MapMode.TrackBefore;
|
|
8529
|
+
GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
|
|
8530
|
+
GutterMarker.prototype.point = true;
|
|
8531
|
+
/**
|
|
8532
|
+
Facet used to add a class to all gutter elements for a given line.
|
|
8533
|
+
Markers given to this facet should _only_ define an
|
|
8534
|
+
[`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
|
|
8535
|
+
[`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
|
|
8536
|
+
in all gutters for the line).
|
|
8537
|
+
*/
|
|
8538
|
+
const gutterLineClass = state.Facet.define();
|
|
8539
|
+
const defaults = {
|
|
8540
|
+
class: "",
|
|
8541
|
+
renderEmptyElements: false,
|
|
8542
|
+
elementStyle: "",
|
|
8543
|
+
markers: () => state.RangeSet.empty,
|
|
8544
|
+
lineMarker: () => null,
|
|
8545
|
+
lineMarkerChange: null,
|
|
8546
|
+
initialSpacer: null,
|
|
8547
|
+
updateSpacer: null,
|
|
8548
|
+
domEventHandlers: {}
|
|
8549
|
+
};
|
|
8550
|
+
const activeGutters = state.Facet.define();
|
|
8551
|
+
/**
|
|
8552
|
+
Define an editor gutter. The order in which the gutters appear is
|
|
8553
|
+
determined by their extension priority.
|
|
8554
|
+
*/
|
|
8555
|
+
function gutter(config) {
|
|
8556
|
+
return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
|
|
8557
|
+
}
|
|
8558
|
+
const unfixGutters = state.Facet.define({
|
|
8559
|
+
combine: values => values.some(x => x)
|
|
8560
|
+
});
|
|
8561
|
+
/**
|
|
8562
|
+
The gutter-drawing plugin is automatically enabled when you add a
|
|
8563
|
+
gutter, but you can use this function to explicitly configure it.
|
|
8564
|
+
|
|
8565
|
+
Unless `fixed` is explicitly set to `false`, the gutters are
|
|
8566
|
+
fixed, meaning they don't scroll along with the content
|
|
8567
|
+
horizontally (except on Internet Explorer, which doesn't support
|
|
8568
|
+
CSS [`position:
|
|
8569
|
+
sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
|
|
8570
|
+
*/
|
|
8571
|
+
function gutters(config) {
|
|
8572
|
+
let result = [
|
|
8573
|
+
gutterView,
|
|
8574
|
+
];
|
|
8575
|
+
if (config && config.fixed === false)
|
|
8576
|
+
result.push(unfixGutters.of(true));
|
|
8577
|
+
return result;
|
|
8578
|
+
}
|
|
8579
|
+
const gutterView = ViewPlugin.fromClass(class {
|
|
8580
|
+
constructor(view) {
|
|
8581
|
+
this.view = view;
|
|
8582
|
+
this.prevViewport = view.viewport;
|
|
8583
|
+
this.dom = document.createElement("div");
|
|
8584
|
+
this.dom.className = "cm-gutters";
|
|
8585
|
+
this.dom.setAttribute("aria-hidden", "true");
|
|
8586
|
+
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
8587
|
+
this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
|
|
8588
|
+
for (let gutter of this.gutters)
|
|
8589
|
+
this.dom.appendChild(gutter.dom);
|
|
8590
|
+
this.fixed = !view.state.facet(unfixGutters);
|
|
8591
|
+
if (this.fixed) {
|
|
8592
|
+
// FIXME IE11 fallback, which doesn't support position: sticky,
|
|
8593
|
+
// by using position: relative + event handlers that realign the
|
|
8594
|
+
// gutter (or just force fixed=false on IE11?)
|
|
8595
|
+
this.dom.style.position = "sticky";
|
|
8596
|
+
}
|
|
8597
|
+
this.syncGutters(false);
|
|
8598
|
+
view.scrollDOM.insertBefore(this.dom, view.contentDOM);
|
|
8599
|
+
}
|
|
8600
|
+
update(update) {
|
|
8601
|
+
if (this.updateGutters(update)) {
|
|
8602
|
+
// Detach during sync when the viewport changed significantly
|
|
8603
|
+
// (such as during scrolling), since for large updates that is
|
|
8604
|
+
// faster.
|
|
8605
|
+
let vpA = this.prevViewport, vpB = update.view.viewport;
|
|
8606
|
+
let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
|
|
8607
|
+
this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
|
|
8608
|
+
}
|
|
8609
|
+
if (update.geometryChanged)
|
|
8610
|
+
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
8611
|
+
if (this.view.state.facet(unfixGutters) != !this.fixed) {
|
|
8612
|
+
this.fixed = !this.fixed;
|
|
8613
|
+
this.dom.style.position = this.fixed ? "sticky" : "";
|
|
8614
|
+
}
|
|
8615
|
+
this.prevViewport = update.view.viewport;
|
|
8616
|
+
}
|
|
8617
|
+
syncGutters(detach) {
|
|
8618
|
+
let after = this.dom.nextSibling;
|
|
8619
|
+
if (detach)
|
|
8620
|
+
this.dom.remove();
|
|
8621
|
+
let lineClasses = state.RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
|
|
8622
|
+
let classSet = [];
|
|
8623
|
+
let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
|
|
8624
|
+
for (let line of this.view.viewportLineBlocks) {
|
|
8625
|
+
let text;
|
|
8626
|
+
if (Array.isArray(line.type)) {
|
|
8627
|
+
for (let b of line.type)
|
|
8628
|
+
if (b.type == exports.BlockType.Text) {
|
|
8629
|
+
text = b;
|
|
8630
|
+
break;
|
|
8631
|
+
}
|
|
8632
|
+
}
|
|
8633
|
+
else {
|
|
8634
|
+
text = line.type == exports.BlockType.Text ? line : undefined;
|
|
8635
|
+
}
|
|
8636
|
+
if (!text)
|
|
8637
|
+
continue;
|
|
8638
|
+
if (classSet.length)
|
|
8639
|
+
classSet = [];
|
|
8640
|
+
advanceCursor(lineClasses, classSet, line.from);
|
|
8641
|
+
for (let cx of contexts)
|
|
8642
|
+
cx.line(this.view, text, classSet);
|
|
8643
|
+
}
|
|
8644
|
+
for (let cx of contexts)
|
|
8645
|
+
cx.finish();
|
|
8646
|
+
if (detach)
|
|
8647
|
+
this.view.scrollDOM.insertBefore(this.dom, after);
|
|
8648
|
+
}
|
|
8649
|
+
updateGutters(update) {
|
|
8650
|
+
let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
|
|
8651
|
+
let change = update.docChanged || update.heightChanged || update.viewportChanged ||
|
|
8652
|
+
!state.RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
|
|
8653
|
+
if (prev == cur) {
|
|
8654
|
+
for (let gutter of this.gutters)
|
|
8655
|
+
if (gutter.update(update))
|
|
8656
|
+
change = true;
|
|
8657
|
+
}
|
|
8658
|
+
else {
|
|
8659
|
+
change = true;
|
|
8660
|
+
let gutters = [];
|
|
8661
|
+
for (let conf of cur) {
|
|
8662
|
+
let known = prev.indexOf(conf);
|
|
8663
|
+
if (known < 0) {
|
|
8664
|
+
gutters.push(new SingleGutterView(this.view, conf));
|
|
8665
|
+
}
|
|
8666
|
+
else {
|
|
8667
|
+
this.gutters[known].update(update);
|
|
8668
|
+
gutters.push(this.gutters[known]);
|
|
8669
|
+
}
|
|
8670
|
+
}
|
|
8671
|
+
for (let g of this.gutters) {
|
|
8672
|
+
g.dom.remove();
|
|
8673
|
+
if (gutters.indexOf(g) < 0)
|
|
8674
|
+
g.destroy();
|
|
8675
|
+
}
|
|
8676
|
+
for (let g of gutters)
|
|
8677
|
+
this.dom.appendChild(g.dom);
|
|
8678
|
+
this.gutters = gutters;
|
|
8679
|
+
}
|
|
8680
|
+
return change;
|
|
8681
|
+
}
|
|
8682
|
+
destroy() {
|
|
8683
|
+
for (let view of this.gutters)
|
|
8684
|
+
view.destroy();
|
|
8685
|
+
this.dom.remove();
|
|
8686
|
+
}
|
|
8687
|
+
}, {
|
|
8688
|
+
provide: plugin => EditorView.scrollMargins.of(view => {
|
|
8689
|
+
let value = view.plugin(plugin);
|
|
8690
|
+
if (!value || value.gutters.length == 0 || !value.fixed)
|
|
8691
|
+
return null;
|
|
8692
|
+
return view.textDirection == exports.Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
|
|
8693
|
+
})
|
|
8694
|
+
});
|
|
8695
|
+
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
|
|
8696
|
+
function advanceCursor(cursor, collect, pos) {
|
|
8697
|
+
while (cursor.value && cursor.from <= pos) {
|
|
8698
|
+
if (cursor.from == pos)
|
|
8699
|
+
collect.push(cursor.value);
|
|
8700
|
+
cursor.next();
|
|
8701
|
+
}
|
|
8702
|
+
}
|
|
8703
|
+
class UpdateContext {
|
|
8704
|
+
constructor(gutter, viewport, height) {
|
|
8705
|
+
this.gutter = gutter;
|
|
8706
|
+
this.height = height;
|
|
8707
|
+
this.localMarkers = [];
|
|
8708
|
+
this.i = 0;
|
|
8709
|
+
this.cursor = state.RangeSet.iter(gutter.markers, viewport.from);
|
|
8710
|
+
}
|
|
8711
|
+
line(view, line, extraMarkers) {
|
|
8712
|
+
if (this.localMarkers.length)
|
|
8713
|
+
this.localMarkers = [];
|
|
8714
|
+
advanceCursor(this.cursor, this.localMarkers, line.from);
|
|
8715
|
+
let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
|
|
8716
|
+
let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
|
|
8717
|
+
if (forLine)
|
|
8718
|
+
localMarkers.unshift(forLine);
|
|
8719
|
+
let gutter = this.gutter;
|
|
8720
|
+
if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
|
|
8721
|
+
return;
|
|
8722
|
+
let above = line.top - this.height;
|
|
8723
|
+
if (this.i == gutter.elements.length) {
|
|
8724
|
+
let newElt = new GutterElement(view, line.height, above, localMarkers);
|
|
8725
|
+
gutter.elements.push(newElt);
|
|
8726
|
+
gutter.dom.appendChild(newElt.dom);
|
|
8727
|
+
}
|
|
8728
|
+
else {
|
|
8729
|
+
gutter.elements[this.i].update(view, line.height, above, localMarkers);
|
|
8730
|
+
}
|
|
8731
|
+
this.height = line.bottom;
|
|
8732
|
+
this.i++;
|
|
8733
|
+
}
|
|
8734
|
+
finish() {
|
|
8735
|
+
let gutter = this.gutter;
|
|
8736
|
+
while (gutter.elements.length > this.i) {
|
|
8737
|
+
let last = gutter.elements.pop();
|
|
8738
|
+
gutter.dom.removeChild(last.dom);
|
|
8739
|
+
last.destroy();
|
|
8740
|
+
}
|
|
8741
|
+
}
|
|
8742
|
+
}
|
|
8743
|
+
class SingleGutterView {
|
|
8744
|
+
constructor(view, config) {
|
|
8745
|
+
this.view = view;
|
|
8746
|
+
this.config = config;
|
|
8747
|
+
this.elements = [];
|
|
8748
|
+
this.spacer = null;
|
|
8749
|
+
this.dom = document.createElement("div");
|
|
8750
|
+
this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
|
|
8751
|
+
for (let prop in config.domEventHandlers) {
|
|
8752
|
+
this.dom.addEventListener(prop, (event) => {
|
|
8753
|
+
let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
|
|
8754
|
+
if (config.domEventHandlers[prop](view, line, event))
|
|
8755
|
+
event.preventDefault();
|
|
8756
|
+
});
|
|
8757
|
+
}
|
|
8758
|
+
this.markers = asArray(config.markers(view));
|
|
8759
|
+
if (config.initialSpacer) {
|
|
8760
|
+
this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
|
|
8761
|
+
this.dom.appendChild(this.spacer.dom);
|
|
8762
|
+
this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
|
|
8763
|
+
}
|
|
8764
|
+
}
|
|
8765
|
+
update(update) {
|
|
8766
|
+
let prevMarkers = this.markers;
|
|
8767
|
+
this.markers = asArray(this.config.markers(update.view));
|
|
8768
|
+
if (this.spacer && this.config.updateSpacer) {
|
|
8769
|
+
let updated = this.config.updateSpacer(this.spacer.markers[0], update);
|
|
8770
|
+
if (updated != this.spacer.markers[0])
|
|
8771
|
+
this.spacer.update(update.view, 0, 0, [updated]);
|
|
8772
|
+
}
|
|
8773
|
+
let vp = update.view.viewport;
|
|
8774
|
+
return !state.RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
|
|
8775
|
+
(this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
|
|
8776
|
+
}
|
|
8777
|
+
destroy() {
|
|
8778
|
+
for (let elt of this.elements)
|
|
8779
|
+
elt.destroy();
|
|
8780
|
+
}
|
|
8781
|
+
}
|
|
8782
|
+
class GutterElement {
|
|
8783
|
+
constructor(view, height, above, markers) {
|
|
8784
|
+
this.height = -1;
|
|
8785
|
+
this.above = 0;
|
|
8786
|
+
this.markers = [];
|
|
8787
|
+
this.dom = document.createElement("div");
|
|
8788
|
+
this.update(view, height, above, markers);
|
|
8789
|
+
}
|
|
8790
|
+
update(view, height, above, markers) {
|
|
8791
|
+
if (this.height != height)
|
|
8792
|
+
this.dom.style.height = (this.height = height) + "px";
|
|
8793
|
+
if (this.above != above)
|
|
8794
|
+
this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
|
|
8795
|
+
if (!sameMarkers(this.markers, markers))
|
|
8796
|
+
this.setMarkers(view, markers);
|
|
8797
|
+
}
|
|
8798
|
+
setMarkers(view, markers) {
|
|
8799
|
+
let cls = "cm-gutterElement", domPos = this.dom.firstChild;
|
|
8800
|
+
for (let iNew = 0, iOld = 0;;) {
|
|
8801
|
+
let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
|
|
8802
|
+
if (marker) {
|
|
8803
|
+
let c = marker.elementClass;
|
|
8804
|
+
if (c)
|
|
8805
|
+
cls += " " + c;
|
|
8806
|
+
for (let i = iOld; i < this.markers.length; i++)
|
|
8807
|
+
if (this.markers[i].compare(marker)) {
|
|
8808
|
+
skipTo = i;
|
|
8809
|
+
matched = true;
|
|
8810
|
+
break;
|
|
8811
|
+
}
|
|
8812
|
+
}
|
|
8813
|
+
else {
|
|
8814
|
+
skipTo = this.markers.length;
|
|
8815
|
+
}
|
|
8816
|
+
while (iOld < skipTo) {
|
|
8817
|
+
let next = this.markers[iOld++];
|
|
8818
|
+
if (next.toDOM) {
|
|
8819
|
+
next.destroy(domPos);
|
|
8820
|
+
let after = domPos.nextSibling;
|
|
8821
|
+
domPos.remove();
|
|
8822
|
+
domPos = after;
|
|
8823
|
+
}
|
|
8824
|
+
}
|
|
8825
|
+
if (!marker)
|
|
8826
|
+
break;
|
|
8827
|
+
if (marker.toDOM) {
|
|
8828
|
+
if (matched)
|
|
8829
|
+
domPos = domPos.nextSibling;
|
|
8830
|
+
else
|
|
8831
|
+
this.dom.insertBefore(marker.toDOM(view), domPos);
|
|
8832
|
+
}
|
|
8833
|
+
if (matched)
|
|
8834
|
+
iOld++;
|
|
8835
|
+
}
|
|
8836
|
+
this.dom.className = cls;
|
|
8837
|
+
this.markers = markers;
|
|
8838
|
+
}
|
|
8839
|
+
destroy() {
|
|
8840
|
+
this.setMarkers(null, []); // First argument not used unless creating markers
|
|
8841
|
+
}
|
|
8842
|
+
}
|
|
8843
|
+
function sameMarkers(a, b) {
|
|
8844
|
+
if (a.length != b.length)
|
|
8845
|
+
return false;
|
|
8846
|
+
for (let i = 0; i < a.length; i++)
|
|
8847
|
+
if (!a[i].compare(b[i]))
|
|
8848
|
+
return false;
|
|
8849
|
+
return true;
|
|
8850
|
+
}
|
|
8851
|
+
/**
|
|
8852
|
+
Facet used to provide markers to the line number gutter.
|
|
8853
|
+
*/
|
|
8854
|
+
const lineNumberMarkers = state.Facet.define();
|
|
8855
|
+
const lineNumberConfig = state.Facet.define({
|
|
8856
|
+
combine(values) {
|
|
8857
|
+
return state.combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
|
|
8858
|
+
domEventHandlers(a, b) {
|
|
8859
|
+
let result = Object.assign({}, a);
|
|
8860
|
+
for (let event in b) {
|
|
8861
|
+
let exists = result[event], add = b[event];
|
|
8862
|
+
result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
|
|
8863
|
+
}
|
|
8864
|
+
return result;
|
|
8865
|
+
}
|
|
8866
|
+
});
|
|
8867
|
+
}
|
|
8868
|
+
});
|
|
8869
|
+
class NumberMarker extends GutterMarker {
|
|
8870
|
+
constructor(number) {
|
|
8871
|
+
super();
|
|
8872
|
+
this.number = number;
|
|
8873
|
+
}
|
|
8874
|
+
eq(other) { return this.number == other.number; }
|
|
8875
|
+
toDOM() { return document.createTextNode(this.number); }
|
|
8876
|
+
}
|
|
8877
|
+
function formatNumber(view, number) {
|
|
8878
|
+
return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
|
|
8879
|
+
}
|
|
8880
|
+
const lineNumberGutter = activeGutters.compute([lineNumberConfig], state => ({
|
|
8881
|
+
class: "cm-lineNumbers",
|
|
8882
|
+
renderEmptyElements: false,
|
|
8883
|
+
markers(view) { return view.state.facet(lineNumberMarkers); },
|
|
8884
|
+
lineMarker(view, line, others) {
|
|
8885
|
+
if (others.some(m => m.toDOM))
|
|
8886
|
+
return null;
|
|
8887
|
+
return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
|
|
8888
|
+
},
|
|
8889
|
+
lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
|
|
8890
|
+
initialSpacer(view) {
|
|
8891
|
+
return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
|
|
8892
|
+
},
|
|
8893
|
+
updateSpacer(spacer, update) {
|
|
8894
|
+
let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
|
|
8895
|
+
return max == spacer.number ? spacer : new NumberMarker(max);
|
|
8896
|
+
},
|
|
8897
|
+
domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
|
|
8898
|
+
}));
|
|
8899
|
+
/**
|
|
8900
|
+
Create a line number gutter extension.
|
|
8901
|
+
*/
|
|
8902
|
+
function lineNumbers(config = {}) {
|
|
8903
|
+
return [
|
|
8904
|
+
lineNumberConfig.of(config),
|
|
8905
|
+
gutters(),
|
|
8906
|
+
lineNumberGutter
|
|
8907
|
+
];
|
|
8908
|
+
}
|
|
8909
|
+
function maxLineNumber(lines) {
|
|
8910
|
+
let last = 9;
|
|
8911
|
+
while (last < lines)
|
|
8912
|
+
last = last * 10 + 9;
|
|
8913
|
+
return last;
|
|
8914
|
+
}
|
|
8915
|
+
const activeLineGutterMarker = new class extends GutterMarker {
|
|
8916
|
+
constructor() {
|
|
8917
|
+
super(...arguments);
|
|
8918
|
+
this.elementClass = "cm-activeLineGutter";
|
|
8919
|
+
}
|
|
8920
|
+
};
|
|
8921
|
+
const activeLineGutterHighlighter = gutterLineClass.compute(["selection"], state$1 => {
|
|
8922
|
+
let marks = [], last = -1;
|
|
8923
|
+
for (let range of state$1.selection.ranges)
|
|
8924
|
+
if (range.empty) {
|
|
8925
|
+
let linePos = state$1.doc.lineAt(range.head).from;
|
|
8926
|
+
if (linePos > last) {
|
|
8927
|
+
last = linePos;
|
|
8928
|
+
marks.push(activeLineGutterMarker.range(linePos));
|
|
8929
|
+
}
|
|
8930
|
+
}
|
|
8931
|
+
return state.RangeSet.of(marks);
|
|
8932
|
+
});
|
|
8933
|
+
/**
|
|
8934
|
+
Returns an extension that adds a `cm-activeLineGutter` class to
|
|
8935
|
+
all gutter elements on the [active
|
|
8936
|
+
line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
|
|
8937
|
+
*/
|
|
8938
|
+
function highlightActiveLineGutter() {
|
|
8939
|
+
return activeLineGutterHighlighter;
|
|
8940
|
+
}
|
|
8941
|
+
|
|
8942
|
+
/**
|
|
8943
|
+
@internal
|
|
8944
|
+
*/
|
|
8945
|
+
const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
|
|
8946
|
+
|
|
7725
8947
|
exports.BidiSpan = BidiSpan;
|
|
7726
8948
|
exports.BlockInfo = BlockInfo;
|
|
7727
8949
|
exports.Decoration = Decoration;
|
|
7728
8950
|
exports.EditorView = EditorView;
|
|
8951
|
+
exports.GutterMarker = GutterMarker;
|
|
7729
8952
|
exports.MatchDecorator = MatchDecorator;
|
|
7730
|
-
exports.PluginField = PluginField;
|
|
7731
|
-
exports.PluginFieldProvider = PluginFieldProvider;
|
|
7732
8953
|
exports.ViewPlugin = ViewPlugin;
|
|
7733
8954
|
exports.ViewUpdate = ViewUpdate;
|
|
7734
8955
|
exports.WidgetType = WidgetType;
|
|
7735
8956
|
exports.__test = __test;
|
|
8957
|
+
exports.closeHoverTooltips = closeHoverTooltips;
|
|
8958
|
+
exports.crosshairCursor = crosshairCursor;
|
|
7736
8959
|
exports.drawSelection = drawSelection;
|
|
7737
8960
|
exports.dropCursor = dropCursor;
|
|
8961
|
+
exports.getPanel = getPanel;
|
|
8962
|
+
exports.getTooltip = getTooltip;
|
|
8963
|
+
exports.gutter = gutter;
|
|
8964
|
+
exports.gutterLineClass = gutterLineClass;
|
|
8965
|
+
exports.gutters = gutters;
|
|
8966
|
+
exports.hasHoverTooltips = hasHoverTooltips;
|
|
7738
8967
|
exports.highlightActiveLine = highlightActiveLine;
|
|
8968
|
+
exports.highlightActiveLineGutter = highlightActiveLineGutter;
|
|
7739
8969
|
exports.highlightSpecialChars = highlightSpecialChars;
|
|
8970
|
+
exports.hoverTooltip = hoverTooltip;
|
|
7740
8971
|
exports.keymap = keymap;
|
|
8972
|
+
exports.lineNumberMarkers = lineNumberMarkers;
|
|
8973
|
+
exports.lineNumbers = lineNumbers;
|
|
7741
8974
|
exports.logException = logException;
|
|
8975
|
+
exports.panels = panels;
|
|
7742
8976
|
exports.placeholder = placeholder;
|
|
8977
|
+
exports.rectangularSelection = rectangularSelection;
|
|
8978
|
+
exports.repositionTooltips = repositionTooltips;
|
|
7743
8979
|
exports.runScopeHandlers = runScopeHandlers;
|
|
7744
8980
|
exports.scrollPastEnd = scrollPastEnd;
|
|
8981
|
+
exports.showPanel = showPanel;
|
|
8982
|
+
exports.showTooltip = showTooltip;
|
|
8983
|
+
exports.tooltips = tooltips;
|