@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.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Prec, Transaction, combineConfig, StateField, RangeSetBuilder, codePointAt, countColumn } from '@codemirror/state';
|
|
2
2
|
import { StyleModule } from 'style-mod';
|
|
3
|
-
import { RangeSet, RangeValue, RangeSetBuilder } from '@codemirror/rangeset';
|
|
4
|
-
export { Range } from '@codemirror/rangeset';
|
|
5
|
-
import { Text, findClusterBreak, findColumn, codePointAt, countColumn } from '@codemirror/text';
|
|
6
3
|
import { keyName, base } from 'w3c-keyname';
|
|
7
4
|
|
|
8
5
|
function getSelection(root) {
|
|
@@ -315,32 +312,34 @@ class ContentView {
|
|
|
315
312
|
sync(track) {
|
|
316
313
|
if (this.dirty & 2 /* Node */) {
|
|
317
314
|
let parent = this.dom;
|
|
318
|
-
let
|
|
315
|
+
let prev = null, next;
|
|
319
316
|
for (let child of this.children) {
|
|
320
317
|
if (child.dirty) {
|
|
321
|
-
if (!child.dom &&
|
|
322
|
-
let contentView = ContentView.get(
|
|
318
|
+
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
|
319
|
+
let contentView = ContentView.get(next);
|
|
323
320
|
if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
|
|
324
|
-
child.reuseDOM(
|
|
321
|
+
child.reuseDOM(next);
|
|
325
322
|
}
|
|
326
323
|
child.sync(track);
|
|
327
324
|
child.dirty = 0 /* Not */;
|
|
328
325
|
}
|
|
329
|
-
|
|
326
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
327
|
+
if (track && !track.written && track.node == parent && next != child.dom)
|
|
330
328
|
track.written = true;
|
|
331
329
|
if (child.dom.parentNode == parent) {
|
|
332
|
-
while (
|
|
333
|
-
|
|
334
|
-
pos = child.dom.nextSibling;
|
|
330
|
+
while (next && next != child.dom)
|
|
331
|
+
next = rm$1(next);
|
|
335
332
|
}
|
|
336
333
|
else {
|
|
337
|
-
parent.insertBefore(child.dom,
|
|
334
|
+
parent.insertBefore(child.dom, next);
|
|
338
335
|
}
|
|
336
|
+
prev = child.dom;
|
|
339
337
|
}
|
|
340
|
-
|
|
338
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
339
|
+
if (next && track && track.node == parent)
|
|
341
340
|
track.written = true;
|
|
342
|
-
while (
|
|
343
|
-
|
|
341
|
+
while (next)
|
|
342
|
+
next = rm$1(next);
|
|
344
343
|
}
|
|
345
344
|
else if (this.dirty & 1 /* Child */) {
|
|
346
345
|
for (let child of this.children)
|
|
@@ -486,7 +485,7 @@ class ContentView {
|
|
|
486
485
|
}
|
|
487
486
|
ContentView.prototype.breakAfter = 0;
|
|
488
487
|
// Remove a DOM node and return its next sibling.
|
|
489
|
-
function rm(dom) {
|
|
488
|
+
function rm$1(dom) {
|
|
490
489
|
let next = dom.nextSibling;
|
|
491
490
|
dom.parentNode.removeChild(dom);
|
|
492
491
|
return next;
|
|
@@ -933,6 +932,7 @@ class WidgetBufferView extends ContentView {
|
|
|
933
932
|
if (!this.dom) {
|
|
934
933
|
let dom = document.createElement("img");
|
|
935
934
|
dom.className = "cm-widgetBuffer";
|
|
935
|
+
dom.setAttribute("aria-hidden", "true");
|
|
936
936
|
this.setDOM(dom);
|
|
937
937
|
}
|
|
938
938
|
}
|
|
@@ -1073,7 +1073,7 @@ function updateAttrs(dom, prev, attrs) {
|
|
|
1073
1073
|
Widgets added to the content are described by subclasses of this
|
|
1074
1074
|
class. Using a description object like that makes it possible to
|
|
1075
1075
|
delay creating of the DOM structure for a widget until it is
|
|
1076
|
-
needed, and to avoid redrawing widgets even
|
|
1076
|
+
needed, and to avoid redrawing widgets even if the decorations
|
|
1077
1077
|
that define them are recreated.
|
|
1078
1078
|
*/
|
|
1079
1079
|
class WidgetType {
|
|
@@ -1086,7 +1086,7 @@ class WidgetType {
|
|
|
1086
1086
|
returns `false`, which will cause new instances of the widget to
|
|
1087
1087
|
always be redrawn.
|
|
1088
1088
|
*/
|
|
1089
|
-
eq(
|
|
1089
|
+
eq(widget) { return false; }
|
|
1090
1090
|
/**
|
|
1091
1091
|
Update a DOM element created by a widget of the same type (but
|
|
1092
1092
|
different, non-`eq` content) to reflect this widget. May return
|
|
@@ -1094,7 +1094,7 @@ class WidgetType {
|
|
|
1094
1094
|
couldn't (in which case the widget will be redrawn). The default
|
|
1095
1095
|
implementation just returns false.
|
|
1096
1096
|
*/
|
|
1097
|
-
updateDOM(
|
|
1097
|
+
updateDOM(dom) { return false; }
|
|
1098
1098
|
/**
|
|
1099
1099
|
@internal
|
|
1100
1100
|
*/
|
|
@@ -1113,7 +1113,7 @@ class WidgetType {
|
|
|
1113
1113
|
should be ignored by the editor. The default is to ignore all
|
|
1114
1114
|
events.
|
|
1115
1115
|
*/
|
|
1116
|
-
ignoreEvent(
|
|
1116
|
+
ignoreEvent(event) { return true; }
|
|
1117
1117
|
/**
|
|
1118
1118
|
@internal
|
|
1119
1119
|
*/
|
|
@@ -1122,7 +1122,7 @@ class WidgetType {
|
|
|
1122
1122
|
This is called when the an instance of the widget is removed
|
|
1123
1123
|
from the editor view.
|
|
1124
1124
|
*/
|
|
1125
|
-
destroy(
|
|
1125
|
+
destroy(dom) { }
|
|
1126
1126
|
}
|
|
1127
1127
|
/**
|
|
1128
1128
|
The different types of blocks that can occur in an editor view.
|
|
@@ -1148,7 +1148,8 @@ return BlockType})(BlockType || (BlockType = {}));
|
|
|
1148
1148
|
/**
|
|
1149
1149
|
A decoration provides information on how to draw or style a piece
|
|
1150
1150
|
of content. You'll usually use it wrapped in a
|
|
1151
|
-
[`Range`](https://codemirror.net/6/docs/ref/#
|
|
1151
|
+
[`Range`](https://codemirror.net/6/docs/ref/#state.Range), which adds a start and end position.
|
|
1152
|
+
@nonabstract
|
|
1152
1153
|
*/
|
|
1153
1154
|
class Decoration extends RangeValue {
|
|
1154
1155
|
/**
|
|
@@ -1187,22 +1188,21 @@ class Decoration extends RangeValue {
|
|
|
1187
1188
|
Create a mark decoration, which influences the styling of the
|
|
1188
1189
|
content in its range. Nested mark decorations will cause nested
|
|
1189
1190
|
DOM elements to be created. Nesting order is determined by
|
|
1190
|
-
precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations)
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
decorations.
|
|
1191
|
+
precedence of the [facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), with
|
|
1192
|
+
the higher-precedence decorations creating the inner DOM nodes.
|
|
1193
|
+
Such elements are split on line boundaries and on the boundaries
|
|
1194
|
+
of lower-precedence decorations.
|
|
1195
1195
|
*/
|
|
1196
1196
|
static mark(spec) {
|
|
1197
1197
|
return new MarkDecoration(spec);
|
|
1198
1198
|
}
|
|
1199
1199
|
/**
|
|
1200
|
-
Create a widget decoration, which
|
|
1201
|
-
position.
|
|
1200
|
+
Create a widget decoration, which displays a DOM element at the
|
|
1201
|
+
given position.
|
|
1202
1202
|
*/
|
|
1203
1203
|
static widget(spec) {
|
|
1204
1204
|
let side = spec.side || 0, block = !!spec.block;
|
|
1205
|
-
side += block ? (side > 0 ?
|
|
1205
|
+
side += block ? (side > 0 ? 300000000 /* BlockAfter */ : -400000000 /* BlockBefore */) : (side > 0 ? 100000000 /* InlineAfter */ : -100000000 /* InlineBefore */);
|
|
1206
1206
|
return new PointDecoration(spec, side, side, block, spec.widget || null, false);
|
|
1207
1207
|
}
|
|
1208
1208
|
/**
|
|
@@ -1212,8 +1212,8 @@ class Decoration extends RangeValue {
|
|
|
1212
1212
|
static replace(spec) {
|
|
1213
1213
|
let block = !!spec.block, startSide, endSide;
|
|
1214
1214
|
if (spec.isBlockGap) {
|
|
1215
|
-
startSide = -
|
|
1216
|
-
endSide =
|
|
1215
|
+
startSide = -500000000 /* GapStart */;
|
|
1216
|
+
endSide = 400000000 /* GapEnd */;
|
|
1217
1217
|
}
|
|
1218
1218
|
else {
|
|
1219
1219
|
let { start, end } = getInclusive(spec, block);
|
|
@@ -1430,7 +1430,7 @@ class LineView extends ContentView {
|
|
|
1430
1430
|
let last = this.dom.lastChild;
|
|
1431
1431
|
while (last && ContentView.get(last) instanceof MarkView)
|
|
1432
1432
|
last = last.lastChild;
|
|
1433
|
-
if (!last ||
|
|
1433
|
+
if (!last || !this.length ||
|
|
1434
1434
|
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1435
1435
|
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1436
1436
|
let hack = document.createElement("BR");
|
|
@@ -1509,7 +1509,7 @@ class BlockWidgetView extends ContentView {
|
|
|
1509
1509
|
}
|
|
1510
1510
|
}
|
|
1511
1511
|
get overrideDOMText() {
|
|
1512
|
-
return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text
|
|
1512
|
+
return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty;
|
|
1513
1513
|
}
|
|
1514
1514
|
domBoundsAround() { return null; }
|
|
1515
1515
|
become(other) {
|
|
@@ -1536,11 +1536,11 @@ class BlockWidgetView extends ContentView {
|
|
|
1536
1536
|
}
|
|
1537
1537
|
|
|
1538
1538
|
class ContentBuilder {
|
|
1539
|
-
constructor(doc, pos, end,
|
|
1539
|
+
constructor(doc, pos, end, disallowBlockEffectsFor) {
|
|
1540
1540
|
this.doc = doc;
|
|
1541
1541
|
this.pos = pos;
|
|
1542
1542
|
this.end = end;
|
|
1543
|
-
this.
|
|
1543
|
+
this.disallowBlockEffectsFor = disallowBlockEffectsFor;
|
|
1544
1544
|
this.content = [];
|
|
1545
1545
|
this.curLine = null;
|
|
1546
1546
|
this.breakAtStart = 0;
|
|
@@ -1625,7 +1625,13 @@ class ContentBuilder {
|
|
|
1625
1625
|
if (this.openStart < 0)
|
|
1626
1626
|
this.openStart = openStart;
|
|
1627
1627
|
}
|
|
1628
|
-
point(from, to, deco, active, openStart) {
|
|
1628
|
+
point(from, to, deco, active, openStart, index) {
|
|
1629
|
+
if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
|
|
1630
|
+
if (deco.block)
|
|
1631
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1632
|
+
if (to > this.doc.lineAt(this.pos).to)
|
|
1633
|
+
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1634
|
+
}
|
|
1629
1635
|
let len = to - from;
|
|
1630
1636
|
if (deco instanceof PointDecoration) {
|
|
1631
1637
|
if (deco.block) {
|
|
@@ -1669,17 +1675,8 @@ class ContentBuilder {
|
|
|
1669
1675
|
if (this.openStart < 0)
|
|
1670
1676
|
this.openStart = openStart;
|
|
1671
1677
|
}
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
if (value.block)
|
|
1675
|
-
throw new RangeError("Block decorations may not be specified via plugins");
|
|
1676
|
-
if (to > this.doc.lineAt(this.pos).to)
|
|
1677
|
-
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
1678
|
-
}
|
|
1679
|
-
return true;
|
|
1680
|
-
}
|
|
1681
|
-
static build(text, from, to, decorations, pluginDecorationLength) {
|
|
1682
|
-
let builder = new ContentBuilder(text, from, to, pluginDecorationLength);
|
|
1678
|
+
static build(text, from, to, decorations, dynamicDecorationMap) {
|
|
1679
|
+
let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
|
|
1683
1680
|
builder.openEnd = RangeSet.spans(decorations, from, to, builder);
|
|
1684
1681
|
if (builder.openStart < 0)
|
|
1685
1682
|
builder.openStart = builder.openEnd;
|
|
@@ -1709,13 +1706,8 @@ const mouseSelectionStyle = /*@__PURE__*/Facet.define();
|
|
|
1709
1706
|
const exceptionSink = /*@__PURE__*/Facet.define();
|
|
1710
1707
|
const updateListener = /*@__PURE__*/Facet.define();
|
|
1711
1708
|
const inputHandler = /*@__PURE__*/Facet.define();
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
map: (range, changes) => range.map(changes)
|
|
1715
|
-
});
|
|
1716
|
-
// FIXME remove
|
|
1717
|
-
const centerOn = /*@__PURE__*/StateEffect.define({
|
|
1718
|
-
map: (range, changes) => range.map(changes)
|
|
1709
|
+
const perLineTextDirection = /*@__PURE__*/Facet.define({
|
|
1710
|
+
combine: values => values.some(x => x)
|
|
1719
1711
|
});
|
|
1720
1712
|
class ScrollTarget {
|
|
1721
1713
|
constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
|
|
@@ -1754,83 +1746,6 @@ function logException(state, exception, context) {
|
|
|
1754
1746
|
console.error(exception);
|
|
1755
1747
|
}
|
|
1756
1748
|
const editable = /*@__PURE__*/Facet.define({ combine: values => values.length ? values[0] : true });
|
|
1757
|
-
/**
|
|
1758
|
-
Used to [declare](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide) which
|
|
1759
|
-
[fields](https://codemirror.net/6/docs/ref/#view.PluginValue) a [view plugin](https://codemirror.net/6/docs/ref/#view.ViewPlugin)
|
|
1760
|
-
provides.
|
|
1761
|
-
*/
|
|
1762
|
-
class PluginFieldProvider {
|
|
1763
|
-
/**
|
|
1764
|
-
@internal
|
|
1765
|
-
*/
|
|
1766
|
-
constructor(
|
|
1767
|
-
/**
|
|
1768
|
-
@internal
|
|
1769
|
-
*/
|
|
1770
|
-
field,
|
|
1771
|
-
/**
|
|
1772
|
-
@internal
|
|
1773
|
-
*/
|
|
1774
|
-
get) {
|
|
1775
|
-
this.field = field;
|
|
1776
|
-
this.get = get;
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
/**
|
|
1780
|
-
Plugin fields are a mechanism for allowing plugins to provide
|
|
1781
|
-
values that can be retrieved through the
|
|
1782
|
-
[`pluginField`](https://codemirror.net/6/docs/ref/#view.EditorView.pluginField) view method.
|
|
1783
|
-
*/
|
|
1784
|
-
class PluginField {
|
|
1785
|
-
/**
|
|
1786
|
-
Create a [provider](https://codemirror.net/6/docs/ref/#view.PluginFieldProvider) for this field,
|
|
1787
|
-
to use with a plugin's [provide](https://codemirror.net/6/docs/ref/#view.PluginSpec.provide)
|
|
1788
|
-
option.
|
|
1789
|
-
*/
|
|
1790
|
-
from(get) {
|
|
1791
|
-
return new PluginFieldProvider(this, get);
|
|
1792
|
-
}
|
|
1793
|
-
/**
|
|
1794
|
-
Define a new plugin field.
|
|
1795
|
-
*/
|
|
1796
|
-
static define() { return new PluginField(); }
|
|
1797
|
-
}
|
|
1798
|
-
/**
|
|
1799
|
-
This field can be used by plugins to provide
|
|
1800
|
-
[decorations](https://codemirror.net/6/docs/ref/#view.Decoration).
|
|
1801
|
-
|
|
1802
|
-
**Note**: For reasons of data flow (plugins are only updated
|
|
1803
|
-
after the viewport is computed), decorations produced by plugins
|
|
1804
|
-
are _not_ taken into account when predicting the vertical layout
|
|
1805
|
-
structure of the editor. They **must not** introduce block
|
|
1806
|
-
widgets (that will raise an error) or replacing decorations that
|
|
1807
|
-
cover line breaks (these will be ignored if they occur). Such
|
|
1808
|
-
decorations, or others that cause a large amount of vertical
|
|
1809
|
-
size shift compared to the undecorated content, should be
|
|
1810
|
-
provided through the state-level [`decorations`
|
|
1811
|
-
facet](https://codemirror.net/6/docs/ref/#view.EditorView^decorations) instead.
|
|
1812
|
-
*/
|
|
1813
|
-
PluginField.decorations = /*@__PURE__*/PluginField.define();
|
|
1814
|
-
/**
|
|
1815
|
-
Used to provide ranges that should be treated as atoms as far as
|
|
1816
|
-
cursor motion is concerned. This causes methods like
|
|
1817
|
-
[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
|
|
1818
|
-
[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
|
|
1819
|
-
commands built on top of them) to skip across such regions when
|
|
1820
|
-
a selection endpoint would enter them. This does _not_ prevent
|
|
1821
|
-
direct programmatic [selection
|
|
1822
|
-
updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
|
|
1823
|
-
regions.
|
|
1824
|
-
*/
|
|
1825
|
-
PluginField.atomicRanges = /*@__PURE__*/PluginField.define();
|
|
1826
|
-
/**
|
|
1827
|
-
Plugins can provide additional scroll margins (space around the
|
|
1828
|
-
sides of the scrolling element that should be considered
|
|
1829
|
-
invisible) through this field. This can be useful when the
|
|
1830
|
-
plugin introduces elements that cover part of that element (for
|
|
1831
|
-
example a horizontally fixed gutter).
|
|
1832
|
-
*/
|
|
1833
|
-
PluginField.scrollMargins = /*@__PURE__*/PluginField.define();
|
|
1834
1749
|
let nextPluginID = 0;
|
|
1835
1750
|
const viewPlugin = /*@__PURE__*/Facet.define();
|
|
1836
1751
|
/**
|
|
@@ -1851,27 +1766,29 @@ class ViewPlugin {
|
|
|
1851
1766
|
/**
|
|
1852
1767
|
@internal
|
|
1853
1768
|
*/
|
|
1854
|
-
|
|
1769
|
+
domEventHandlers, buildExtensions) {
|
|
1855
1770
|
this.id = id;
|
|
1856
1771
|
this.create = create;
|
|
1857
|
-
this.
|
|
1858
|
-
this.extension =
|
|
1772
|
+
this.domEventHandlers = domEventHandlers;
|
|
1773
|
+
this.extension = buildExtensions(this);
|
|
1859
1774
|
}
|
|
1860
1775
|
/**
|
|
1861
1776
|
Define a plugin from a constructor function that creates the
|
|
1862
1777
|
plugin's value, given an editor view.
|
|
1863
1778
|
*/
|
|
1864
1779
|
static define(create, spec) {
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1780
|
+
const { eventHandlers, provide, decorations: deco } = spec || {};
|
|
1781
|
+
return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
|
|
1782
|
+
let ext = [viewPlugin.of(plugin)];
|
|
1783
|
+
if (deco)
|
|
1784
|
+
ext.push(decorations.of(view => {
|
|
1785
|
+
let pluginInst = view.plugin(plugin);
|
|
1786
|
+
return pluginInst ? deco(pluginInst) : Decoration.none;
|
|
1787
|
+
}));
|
|
1788
|
+
if (provide)
|
|
1789
|
+
ext.push(provide(plugin));
|
|
1790
|
+
return ext;
|
|
1791
|
+
});
|
|
1875
1792
|
}
|
|
1876
1793
|
/**
|
|
1877
1794
|
Create a plugin for a class whose constructor takes a single
|
|
@@ -1881,7 +1798,6 @@ class ViewPlugin {
|
|
|
1881
1798
|
return ViewPlugin.define(view => new cls(view), spec);
|
|
1882
1799
|
}
|
|
1883
1800
|
}
|
|
1884
|
-
const domEventHandlers = /*@__PURE__*/PluginField.define();
|
|
1885
1801
|
class PluginInstance {
|
|
1886
1802
|
constructor(spec) {
|
|
1887
1803
|
this.spec = spec;
|
|
@@ -1894,12 +1810,6 @@ class PluginInstance {
|
|
|
1894
1810
|
// initialized on the first update.
|
|
1895
1811
|
this.value = null;
|
|
1896
1812
|
}
|
|
1897
|
-
takeField(type, target) {
|
|
1898
|
-
if (this.spec)
|
|
1899
|
-
for (let { field, get } of this.spec.fields)
|
|
1900
|
-
if (field == type)
|
|
1901
|
-
target.push(get(this.value));
|
|
1902
|
-
}
|
|
1903
1813
|
update(view) {
|
|
1904
1814
|
if (!this.value) {
|
|
1905
1815
|
if (this.spec) {
|
|
@@ -1951,6 +1861,8 @@ const editorAttributes = /*@__PURE__*/Facet.define();
|
|
|
1951
1861
|
const contentAttributes = /*@__PURE__*/Facet.define();
|
|
1952
1862
|
// Provide decorations
|
|
1953
1863
|
const decorations = /*@__PURE__*/Facet.define();
|
|
1864
|
+
const atomicRanges = /*@__PURE__*/Facet.define();
|
|
1865
|
+
const scrollMargins = /*@__PURE__*/Facet.define();
|
|
1954
1866
|
const styleModule = /*@__PURE__*/Facet.define();
|
|
1955
1867
|
class ChangedRange {
|
|
1956
1868
|
constructor(fromA, toA, fromB, toB) {
|
|
@@ -2051,8 +1963,8 @@ class ViewUpdate {
|
|
|
2051
1963
|
return (this.flags & 4 /* Viewport */) > 0;
|
|
2052
1964
|
}
|
|
2053
1965
|
/**
|
|
2054
|
-
Indicates whether the height of
|
|
2055
|
-
in this update.
|
|
1966
|
+
Indicates whether the height of a block element in the editor
|
|
1967
|
+
changed in this update.
|
|
2056
1968
|
*/
|
|
2057
1969
|
get heightChanged() {
|
|
2058
1970
|
return (this.flags & 2 /* Height */) > 0;
|
|
@@ -2511,7 +2423,7 @@ class DocView extends ContentView {
|
|
|
2511
2423
|
this.view = view;
|
|
2512
2424
|
this.compositionDeco = Decoration.none;
|
|
2513
2425
|
this.decorations = [];
|
|
2514
|
-
this.
|
|
2426
|
+
this.dynamicDecorationMap = [];
|
|
2515
2427
|
// Track a minimum width for the editor. When measuring sizes in
|
|
2516
2428
|
// measureVisibleLineHeights, this is updated to point at the width
|
|
2517
2429
|
// of a given element and its extent in the document. When a change
|
|
@@ -2617,7 +2529,7 @@ class DocView extends ContentView {
|
|
|
2617
2529
|
if (!next)
|
|
2618
2530
|
break;
|
|
2619
2531
|
let { fromA, toA, fromB, toB } = next;
|
|
2620
|
-
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.
|
|
2532
|
+
let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap);
|
|
2621
2533
|
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2622
2534
|
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2623
2535
|
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
@@ -2758,11 +2670,11 @@ class DocView extends ContentView {
|
|
|
2758
2670
|
off = start;
|
|
2759
2671
|
}
|
|
2760
2672
|
}
|
|
2761
|
-
measureVisibleLineHeights() {
|
|
2762
|
-
let result = [], { from, to } =
|
|
2673
|
+
measureVisibleLineHeights(viewport) {
|
|
2674
|
+
let result = [], { from, to } = viewport;
|
|
2763
2675
|
let contentWidth = this.view.contentDOM.clientWidth;
|
|
2764
2676
|
let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
|
|
2765
|
-
let widest = -1;
|
|
2677
|
+
let widest = -1, ltr = this.view.textDirection == Direction.LTR;
|
|
2766
2678
|
for (let pos = 0, i = 0; i < this.children.length; i++) {
|
|
2767
2679
|
let child = this.children[i], end = pos + child.length;
|
|
2768
2680
|
if (end > to)
|
|
@@ -2775,8 +2687,7 @@ class DocView extends ContentView {
|
|
|
2775
2687
|
let rects = last ? clientRectsFor(last) : [];
|
|
2776
2688
|
if (rects.length) {
|
|
2777
2689
|
let rect = rects[rects.length - 1];
|
|
2778
|
-
let width =
|
|
2779
|
-
: childRect.right - rect.left;
|
|
2690
|
+
let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
|
|
2780
2691
|
if (width > widest) {
|
|
2781
2692
|
widest = width;
|
|
2782
2693
|
this.minWidth = contentWidth;
|
|
@@ -2790,6 +2701,10 @@ class DocView extends ContentView {
|
|
|
2790
2701
|
}
|
|
2791
2702
|
return result;
|
|
2792
2703
|
}
|
|
2704
|
+
textDirectionAt(pos) {
|
|
2705
|
+
let { i } = this.childPos(pos, 1);
|
|
2706
|
+
return getComputedStyle(this.children[i].dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
|
|
2707
|
+
}
|
|
2793
2708
|
measureTextSize() {
|
|
2794
2709
|
for (let child of this.children) {
|
|
2795
2710
|
if (child instanceof LineView) {
|
|
@@ -2841,11 +2756,14 @@ class DocView extends ContentView {
|
|
|
2841
2756
|
return Decoration.set(deco);
|
|
2842
2757
|
}
|
|
2843
2758
|
updateDeco() {
|
|
2844
|
-
let
|
|
2845
|
-
|
|
2759
|
+
let allDeco = this.view.state.facet(decorations).map((d, i) => {
|
|
2760
|
+
let dynamic = this.dynamicDecorationMap[i] = typeof d == "function";
|
|
2761
|
+
return dynamic ? d(this.view) : d;
|
|
2762
|
+
});
|
|
2763
|
+
for (let i = allDeco.length; i < allDeco.length + 3; i++)
|
|
2764
|
+
this.dynamicDecorationMap[i] = false;
|
|
2846
2765
|
return this.decorations = [
|
|
2847
|
-
...
|
|
2848
|
-
...this.view.state.facet(decorations),
|
|
2766
|
+
...allDeco,
|
|
2849
2767
|
this.compositionDeco,
|
|
2850
2768
|
this.computeBlockGapDeco(),
|
|
2851
2769
|
this.view.viewState.lineGapDeco
|
|
@@ -2860,7 +2778,7 @@ class DocView extends ContentView {
|
|
|
2860
2778
|
rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
|
|
2861
2779
|
right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
|
|
2862
2780
|
let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
|
|
2863
|
-
for (let margins of this.view.
|
|
2781
|
+
for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
|
|
2864
2782
|
if (margins) {
|
|
2865
2783
|
let { left, right, top, bottom } = margins;
|
|
2866
2784
|
if (left != null)
|
|
@@ -3249,7 +3167,8 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
|
3249
3167
|
: view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
|
|
3250
3168
|
if (coords) {
|
|
3251
3169
|
let editorRect = view.dom.getBoundingClientRect();
|
|
3252
|
-
let
|
|
3170
|
+
let direction = view.textDirectionAt(line.from);
|
|
3171
|
+
let pos = view.posAtCoords({ x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
|
|
3253
3172
|
y: (coords.top + coords.bottom) / 2 });
|
|
3254
3173
|
if (pos != null)
|
|
3255
3174
|
return EditorSelection.cursor(pos, forward ? -1 : 1);
|
|
@@ -3260,8 +3179,9 @@ function moveToLineBoundary(view, start, forward, includeWrap) {
|
|
|
3260
3179
|
}
|
|
3261
3180
|
function moveByChar(view, start, forward, by) {
|
|
3262
3181
|
let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
|
|
3182
|
+
let direction = view.textDirectionAt(line.from);
|
|
3263
3183
|
for (let cur = start, check = null;;) {
|
|
3264
|
-
let next = moveVisually(line, spans,
|
|
3184
|
+
let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
|
|
3265
3185
|
if (!next) {
|
|
3266
3186
|
if (line.number == (forward ? view.state.doc.lines : 1))
|
|
3267
3187
|
return cur;
|
|
@@ -3319,7 +3239,7 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3319
3239
|
}
|
|
3320
3240
|
}
|
|
3321
3241
|
function skipAtoms(view, oldPos, pos) {
|
|
3322
|
-
let atoms = view.
|
|
3242
|
+
let atoms = view.state.facet(atomicRanges).map(f => f(view));
|
|
3323
3243
|
for (;;) {
|
|
3324
3244
|
let moved = false;
|
|
3325
3245
|
for (let set of atoms) {
|
|
@@ -3367,10 +3287,10 @@ class InputState {
|
|
|
3367
3287
|
for (let type in handlers) {
|
|
3368
3288
|
let handler = handlers[type];
|
|
3369
3289
|
view.contentDOM.addEventListener(type, (event) => {
|
|
3370
|
-
if (type == "keydown" && this.keydown(view, event))
|
|
3371
|
-
return;
|
|
3372
3290
|
if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
|
|
3373
3291
|
return;
|
|
3292
|
+
if (type == "keydown" && this.keydown(view, event))
|
|
3293
|
+
return;
|
|
3374
3294
|
if (this.mustFlushObserver(event))
|
|
3375
3295
|
view.observer.forceFlush();
|
|
3376
3296
|
if (this.runCustomHandlers(type, view, event))
|
|
@@ -3381,7 +3301,6 @@ class InputState {
|
|
|
3381
3301
|
this.registeredEvents.push(type);
|
|
3382
3302
|
}
|
|
3383
3303
|
this.notifiedFocused = view.hasFocus;
|
|
3384
|
-
this.ensureHandlers(view);
|
|
3385
3304
|
// On Safari adding an input event handler somehow prevents an
|
|
3386
3305
|
// issue where the composition vanishes when you press enter.
|
|
3387
3306
|
if (browser.safari)
|
|
@@ -3391,20 +3310,23 @@ class InputState {
|
|
|
3391
3310
|
this.lastSelectionOrigin = origin;
|
|
3392
3311
|
this.lastSelectionTime = Date.now();
|
|
3393
3312
|
}
|
|
3394
|
-
ensureHandlers(view) {
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
event
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3313
|
+
ensureHandlers(view, plugins) {
|
|
3314
|
+
var _a;
|
|
3315
|
+
let handlers;
|
|
3316
|
+
for (let plugin of plugins)
|
|
3317
|
+
if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
|
|
3318
|
+
this.customHandlers.push({ plugin: plugin.value, handlers });
|
|
3319
|
+
for (let type in handlers)
|
|
3320
|
+
if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
|
|
3321
|
+
this.registeredEvents.push(type);
|
|
3322
|
+
view.contentDOM.addEventListener(type, (event) => {
|
|
3323
|
+
if (!eventBelongsToEditor(view, event))
|
|
3324
|
+
return;
|
|
3325
|
+
if (this.runCustomHandlers(type, view, event))
|
|
3326
|
+
event.preventDefault();
|
|
3327
|
+
});
|
|
3328
|
+
}
|
|
3329
|
+
}
|
|
3408
3330
|
}
|
|
3409
3331
|
runCustomHandlers(type, view, event) {
|
|
3410
3332
|
for (let set of this.customHandlers) {
|
|
@@ -3438,7 +3360,7 @@ class InputState {
|
|
|
3438
3360
|
// Must always run, even if a custom handler handled the event
|
|
3439
3361
|
this.lastKeyCode = event.keyCode;
|
|
3440
3362
|
this.lastKeyTime = Date.now();
|
|
3441
|
-
if (
|
|
3363
|
+
if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
|
3442
3364
|
return true;
|
|
3443
3365
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3444
3366
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
@@ -3482,20 +3404,12 @@ class InputState {
|
|
|
3482
3404
|
// compositionend and keydown events are sometimes emitted in the
|
|
3483
3405
|
// wrong order. The key event should still be ignored, even when
|
|
3484
3406
|
// it happens after the compositionend event.
|
|
3485
|
-
if (browser.safari && Date.now() - this.compositionEndedAt <
|
|
3407
|
+
if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
|
|
3486
3408
|
this.compositionEndedAt = 0;
|
|
3487
3409
|
return true;
|
|
3488
3410
|
}
|
|
3489
3411
|
return false;
|
|
3490
3412
|
}
|
|
3491
|
-
screenKeyEvent(view, event) {
|
|
3492
|
-
let protectedTab = event.keyCode == 9 && Date.now() < this.lastEscPress + 2000;
|
|
3493
|
-
if (event.keyCode == 27)
|
|
3494
|
-
this.lastEscPress = Date.now();
|
|
3495
|
-
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3496
|
-
this.lastEscPress = 0;
|
|
3497
|
-
return protectedTab;
|
|
3498
|
-
}
|
|
3499
3413
|
mustFlushObserver(event) {
|
|
3500
3414
|
return (event.type == "keydown" && event.keyCode != 229) ||
|
|
3501
3415
|
event.type == "compositionend" && !browser.ios;
|
|
@@ -3669,6 +3583,10 @@ function doPaste(view, input) {
|
|
|
3669
3583
|
}
|
|
3670
3584
|
handlers.keydown = (view, event) => {
|
|
3671
3585
|
view.inputState.setSelectionOrigin("select");
|
|
3586
|
+
if (event.keyCode == 27)
|
|
3587
|
+
view.inputState.lastEscPress = Date.now();
|
|
3588
|
+
else if (modifierCodes.indexOf(event.keyCode) < 0)
|
|
3589
|
+
view.inputState.lastEscPress = 0;
|
|
3672
3590
|
};
|
|
3673
3591
|
let lastTouch = 0;
|
|
3674
3592
|
handlers.touchstart = (view, e) => {
|
|
@@ -3926,14 +3844,6 @@ handlers.focus = handlers.blur = view => {
|
|
|
3926
3844
|
view.update([]);
|
|
3927
3845
|
}, 10);
|
|
3928
3846
|
};
|
|
3929
|
-
handlers.beforeprint = view => {
|
|
3930
|
-
view.viewState.printing = true;
|
|
3931
|
-
view.requestMeasure();
|
|
3932
|
-
setTimeout(() => {
|
|
3933
|
-
view.viewState.printing = false;
|
|
3934
|
-
view.requestMeasure();
|
|
3935
|
-
}, 2000);
|
|
3936
|
-
};
|
|
3937
3847
|
function forceClearComposition(view, rapid) {
|
|
3938
3848
|
if (view.docView.compositionDeco.size) {
|
|
3939
3849
|
view.inputState.rapidCompositionStart = rapid;
|
|
@@ -4002,7 +3912,6 @@ class HeightOracle {
|
|
|
4002
3912
|
constructor() {
|
|
4003
3913
|
this.doc = Text.empty;
|
|
4004
3914
|
this.lineWrapping = false;
|
|
4005
|
-
this.direction = Direction.LTR;
|
|
4006
3915
|
this.heightSamples = {};
|
|
4007
3916
|
this.lineHeight = 14;
|
|
4008
3917
|
this.charWidth = 7;
|
|
@@ -4023,8 +3932,8 @@ class HeightOracle {
|
|
|
4023
3932
|
return lines * this.lineHeight;
|
|
4024
3933
|
}
|
|
4025
3934
|
setDoc(doc) { this.doc = doc; return this; }
|
|
4026
|
-
|
|
4027
|
-
return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping
|
|
3935
|
+
mustRefreshForWrapping(whiteSpace) {
|
|
3936
|
+
return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
|
|
4028
3937
|
}
|
|
4029
3938
|
mustRefreshForHeights(lineHeights) {
|
|
4030
3939
|
let newHeight = false;
|
|
@@ -4040,13 +3949,10 @@ class HeightOracle {
|
|
|
4040
3949
|
}
|
|
4041
3950
|
return newHeight;
|
|
4042
3951
|
}
|
|
4043
|
-
refresh(whiteSpace,
|
|
3952
|
+
refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
|
4044
3953
|
let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
|
4045
|
-
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) ||
|
|
4046
|
-
this.lineWrapping != lineWrapping ||
|
|
4047
|
-
this.direction != direction;
|
|
3954
|
+
let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
|
4048
3955
|
this.lineWrapping = lineWrapping;
|
|
4049
|
-
this.direction = direction;
|
|
4050
3956
|
this.lineHeight = lineHeight;
|
|
4051
3957
|
this.charWidth = charWidth;
|
|
4052
3958
|
this.lineLength = lineLength;
|
|
@@ -4127,12 +4033,6 @@ class BlockInfo {
|
|
|
4127
4033
|
.concat(Array.isArray(other.type) ? other.type : [other]);
|
|
4128
4034
|
return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
|
|
4129
4035
|
}
|
|
4130
|
-
/**
|
|
4131
|
-
FIXME remove on next breaking release @internal
|
|
4132
|
-
*/
|
|
4133
|
-
moveY(offset) {
|
|
4134
|
-
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);
|
|
4135
|
-
}
|
|
4136
4036
|
}
|
|
4137
4037
|
var QueryType = /*@__PURE__*/(function (QueryType) {
|
|
4138
4038
|
QueryType[QueryType["ByPos"] = 0] = "ByPos";
|
|
@@ -4256,8 +4156,9 @@ class HeightMapBlock extends HeightMap {
|
|
|
4256
4156
|
lineAt(_value, _type, doc, top, offset) {
|
|
4257
4157
|
return this.blockAt(0, doc, top, offset);
|
|
4258
4158
|
}
|
|
4259
|
-
forEachLine(
|
|
4260
|
-
|
|
4159
|
+
forEachLine(from, to, doc, top, offset, f) {
|
|
4160
|
+
if (from <= offset + this.length && to >= offset)
|
|
4161
|
+
f(this.blockAt(0, doc, top, offset));
|
|
4261
4162
|
}
|
|
4262
4163
|
updateHeight(oracle, offset = 0, _force = false, measured) {
|
|
4263
4164
|
if (measured && measured.from <= offset && measured.more)
|
|
@@ -4688,6 +4589,11 @@ function visiblePixelRange(dom, paddingTop) {
|
|
|
4688
4589
|
return { left: left - rect.left, right: Math.max(left, right) - rect.left,
|
|
4689
4590
|
top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
|
|
4690
4591
|
}
|
|
4592
|
+
function fullPixelRange(dom, paddingTop) {
|
|
4593
|
+
let rect = dom.getBoundingClientRect();
|
|
4594
|
+
return { left: 0, right: rect.right - rect.left,
|
|
4595
|
+
top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) };
|
|
4596
|
+
}
|
|
4691
4597
|
// Line gaps are placeholder widgets used to hide pieces of overlong
|
|
4692
4598
|
// lines within the viewport, as a kludge to keep the editor
|
|
4693
4599
|
// responsive when a ridiculously long line is loaded into it.
|
|
@@ -4753,6 +4659,7 @@ class ViewState {
|
|
|
4753
4659
|
// Flag set when editor content was redrawn, so that the next
|
|
4754
4660
|
// measure stage knows it must read DOM layout
|
|
4755
4661
|
this.mustMeasureContent = true;
|
|
4662
|
+
this.defaultTextDirection = Direction.RTL;
|
|
4756
4663
|
this.visibleRanges = [];
|
|
4757
4664
|
// Cursor 'assoc' is only significant when the cursor is on a line
|
|
4758
4665
|
// wrap point, where it must stick to the character that it is
|
|
@@ -4763,7 +4670,8 @@ class ViewState {
|
|
|
4763
4670
|
// boundary and, if so, reset it to make sure it is positioned in
|
|
4764
4671
|
// the right place.
|
|
4765
4672
|
this.mustEnforceCursorAssoc = false;
|
|
4766
|
-
this.
|
|
4673
|
+
this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
|
|
4674
|
+
this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
|
4767
4675
|
this.viewport = this.getViewport(0, null);
|
|
4768
4676
|
this.updateViewportLines();
|
|
4769
4677
|
this.updateForViewport();
|
|
@@ -4791,13 +4699,13 @@ class ViewState {
|
|
|
4791
4699
|
});
|
|
4792
4700
|
}
|
|
4793
4701
|
update(update, scrollTarget = null) {
|
|
4794
|
-
let prev = this.state;
|
|
4795
4702
|
this.state = update.state;
|
|
4796
|
-
let
|
|
4703
|
+
let prevDeco = this.stateDeco;
|
|
4704
|
+
this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
|
|
4797
4705
|
let contentChanges = update.changedRanges;
|
|
4798
|
-
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(
|
|
4706
|
+
let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
|
|
4799
4707
|
let prevHeight = this.heightMap.height;
|
|
4800
|
-
this.heightMap = this.heightMap.applyChanges(
|
|
4708
|
+
this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
|
|
4801
4709
|
if (this.heightMap.height != prevHeight)
|
|
4802
4710
|
update.flags |= 2 /* Height */;
|
|
4803
4711
|
let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
|
@@ -4822,8 +4730,9 @@ class ViewState {
|
|
|
4822
4730
|
measure(view) {
|
|
4823
4731
|
let dom = view.contentDOM, style = window.getComputedStyle(dom);
|
|
4824
4732
|
let oracle = this.heightOracle;
|
|
4825
|
-
let whiteSpace = style.whiteSpace
|
|
4826
|
-
|
|
4733
|
+
let whiteSpace = style.whiteSpace;
|
|
4734
|
+
this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
|
|
4735
|
+
let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
|
4827
4736
|
let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
|
4828
4737
|
let result = 0, bias = 0;
|
|
4829
4738
|
if (this.editorWidth != view.scrollDOM.clientWidth) {
|
|
@@ -4844,8 +4753,7 @@ class ViewState {
|
|
|
4844
4753
|
}
|
|
4845
4754
|
}
|
|
4846
4755
|
// Pixel viewport
|
|
4847
|
-
let pixelViewport = this.printing ?
|
|
4848
|
-
: visiblePixelRange(dom, this.paddingTop);
|
|
4756
|
+
let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
|
4849
4757
|
let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
|
4850
4758
|
this.pixelViewport = pixelViewport;
|
|
4851
4759
|
let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
|
@@ -4863,12 +4771,12 @@ class ViewState {
|
|
|
4863
4771
|
result |= 8 /* Geometry */;
|
|
4864
4772
|
}
|
|
4865
4773
|
if (measureContent) {
|
|
4866
|
-
let lineHeights = view.docView.measureVisibleLineHeights();
|
|
4774
|
+
let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
|
|
4867
4775
|
if (oracle.mustRefreshForHeights(lineHeights))
|
|
4868
4776
|
refresh = true;
|
|
4869
4777
|
if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
|
4870
4778
|
let { lineHeight, charWidth } = view.docView.measureTextSize();
|
|
4871
|
-
refresh = oracle.refresh(whiteSpace,
|
|
4779
|
+
refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
|
4872
4780
|
if (refresh) {
|
|
4873
4781
|
view.docView.minWidth = 0;
|
|
4874
4782
|
result |= 8 /* Geometry */;
|
|
@@ -4879,7 +4787,10 @@ class ViewState {
|
|
|
4879
4787
|
else if (dTop < 0 && dBottom < 0)
|
|
4880
4788
|
bias = Math.min(dTop, dBottom);
|
|
4881
4789
|
oracle.heightChanged = false;
|
|
4882
|
-
|
|
4790
|
+
for (let vp of this.viewports) {
|
|
4791
|
+
let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
|
|
4792
|
+
this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
|
|
4793
|
+
}
|
|
4883
4794
|
if (oracle.heightChanged)
|
|
4884
4795
|
result |= 2 /* Height */;
|
|
4885
4796
|
}
|
|
@@ -4965,12 +4876,12 @@ class ViewState {
|
|
|
4965
4876
|
ensureLineGaps(current) {
|
|
4966
4877
|
let gaps = [];
|
|
4967
4878
|
// This won't work at all in predominantly right-to-left text.
|
|
4968
|
-
if (this.
|
|
4879
|
+
if (this.defaultTextDirection != Direction.LTR)
|
|
4969
4880
|
return gaps;
|
|
4970
4881
|
for (let line of this.viewportLines) {
|
|
4971
4882
|
if (line.length < 4000 /* DoubleMargin */)
|
|
4972
4883
|
continue;
|
|
4973
|
-
let structure = lineStructure(line.from, line.to, this.
|
|
4884
|
+
let structure = lineStructure(line.from, line.to, this.stateDeco);
|
|
4974
4885
|
if (structure.total < 4000 /* DoubleMargin */)
|
|
4975
4886
|
continue;
|
|
4976
4887
|
let viewFrom, viewTo;
|
|
@@ -5021,7 +4932,7 @@ class ViewState {
|
|
|
5021
4932
|
}
|
|
5022
4933
|
}
|
|
5023
4934
|
computeVisibleRanges() {
|
|
5024
|
-
let deco = this.
|
|
4935
|
+
let deco = this.stateDeco;
|
|
5025
4936
|
if (this.lineGaps.length)
|
|
5026
4937
|
deco = deco.concat(this.lineGapDeco);
|
|
5027
4938
|
let ranges = [];
|
|
@@ -5057,9 +4968,9 @@ class Viewport {
|
|
|
5057
4968
|
this.to = to;
|
|
5058
4969
|
}
|
|
5059
4970
|
}
|
|
5060
|
-
function lineStructure(from, to,
|
|
4971
|
+
function lineStructure(from, to, stateDeco) {
|
|
5061
4972
|
let ranges = [], pos = from, total = 0;
|
|
5062
|
-
RangeSet.spans(
|
|
4973
|
+
RangeSet.spans(stateDeco, from, to, {
|
|
5063
4974
|
span() { },
|
|
5064
4975
|
point(from, to) {
|
|
5065
4976
|
if (from > pos) {
|
|
@@ -5192,7 +5103,7 @@ function buildTheme(main, spec, scopes) {
|
|
|
5192
5103
|
}
|
|
5193
5104
|
});
|
|
5194
5105
|
}
|
|
5195
|
-
const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
5106
|
+
const baseTheme$1 = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
5196
5107
|
"&.cm-editor": {
|
|
5197
5108
|
position: "relative !important",
|
|
5198
5109
|
boxSizing: "border-box",
|
|
@@ -5297,6 +5208,65 @@ const baseTheme = /*@__PURE__*/buildTheme("." + baseThemeID, {
|
|
|
5297
5208
|
"&dark .cm-activeLine": { backgroundColor: "#223039" },
|
|
5298
5209
|
"&light .cm-specialChar": { color: "red" },
|
|
5299
5210
|
"&dark .cm-specialChar": { color: "#f78" },
|
|
5211
|
+
".cm-gutters": {
|
|
5212
|
+
display: "flex",
|
|
5213
|
+
height: "100%",
|
|
5214
|
+
boxSizing: "border-box",
|
|
5215
|
+
left: 0,
|
|
5216
|
+
zIndex: 200
|
|
5217
|
+
},
|
|
5218
|
+
"&light .cm-gutters": {
|
|
5219
|
+
backgroundColor: "#f5f5f5",
|
|
5220
|
+
color: "#6c6c6c",
|
|
5221
|
+
borderRight: "1px solid #ddd"
|
|
5222
|
+
},
|
|
5223
|
+
"&dark .cm-gutters": {
|
|
5224
|
+
backgroundColor: "#333338",
|
|
5225
|
+
color: "#ccc"
|
|
5226
|
+
},
|
|
5227
|
+
".cm-gutter": {
|
|
5228
|
+
display: "flex !important",
|
|
5229
|
+
flexDirection: "column",
|
|
5230
|
+
flexShrink: 0,
|
|
5231
|
+
boxSizing: "border-box",
|
|
5232
|
+
minHeight: "100%",
|
|
5233
|
+
overflow: "hidden"
|
|
5234
|
+
},
|
|
5235
|
+
".cm-gutterElement": {
|
|
5236
|
+
boxSizing: "border-box"
|
|
5237
|
+
},
|
|
5238
|
+
".cm-lineNumbers .cm-gutterElement": {
|
|
5239
|
+
padding: "0 3px 0 5px",
|
|
5240
|
+
minWidth: "20px",
|
|
5241
|
+
textAlign: "right",
|
|
5242
|
+
whiteSpace: "nowrap"
|
|
5243
|
+
},
|
|
5244
|
+
"&light .cm-activeLineGutter": {
|
|
5245
|
+
backgroundColor: "#e2f2ff"
|
|
5246
|
+
},
|
|
5247
|
+
"&dark .cm-activeLineGutter": {
|
|
5248
|
+
backgroundColor: "#222227"
|
|
5249
|
+
},
|
|
5250
|
+
".cm-panels": {
|
|
5251
|
+
boxSizing: "border-box",
|
|
5252
|
+
position: "sticky",
|
|
5253
|
+
left: 0,
|
|
5254
|
+
right: 0
|
|
5255
|
+
},
|
|
5256
|
+
"&light .cm-panels": {
|
|
5257
|
+
backgroundColor: "#f5f5f5",
|
|
5258
|
+
color: "black"
|
|
5259
|
+
},
|
|
5260
|
+
"&light .cm-panels-top": {
|
|
5261
|
+
borderBottom: "1px solid #ddd"
|
|
5262
|
+
},
|
|
5263
|
+
"&light .cm-panels-bottom": {
|
|
5264
|
+
borderTop: "1px solid #ddd"
|
|
5265
|
+
},
|
|
5266
|
+
"&dark .cm-panels": {
|
|
5267
|
+
backgroundColor: "#333338",
|
|
5268
|
+
color: "white"
|
|
5269
|
+
},
|
|
5300
5270
|
".cm-tab": {
|
|
5301
5271
|
display: "inline-block",
|
|
5302
5272
|
overflow: "hidden",
|
|
@@ -5422,6 +5392,7 @@ class DOMObserver {
|
|
|
5422
5392
|
});
|
|
5423
5393
|
this.resize.observe(view.scrollDOM);
|
|
5424
5394
|
}
|
|
5395
|
+
window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
|
|
5425
5396
|
this.start();
|
|
5426
5397
|
window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
|
5427
5398
|
if (typeof IntersectionObserver == "function") {
|
|
@@ -5456,6 +5427,14 @@ class DOMObserver {
|
|
|
5456
5427
|
this.view.requestMeasure();
|
|
5457
5428
|
}, 50);
|
|
5458
5429
|
}
|
|
5430
|
+
onPrint() {
|
|
5431
|
+
this.view.viewState.printing = true;
|
|
5432
|
+
this.view.measure();
|
|
5433
|
+
setTimeout(() => {
|
|
5434
|
+
this.view.viewState.printing = false;
|
|
5435
|
+
this.view.requestMeasure();
|
|
5436
|
+
}, 500);
|
|
5437
|
+
}
|
|
5459
5438
|
updateGaps(gaps) {
|
|
5460
5439
|
if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
|
5461
5440
|
this.gapIntersection.disconnect();
|
|
@@ -5673,6 +5652,7 @@ class DOMObserver {
|
|
|
5673
5652
|
dom.removeEventListener("scroll", this.onScroll);
|
|
5674
5653
|
window.removeEventListener("scroll", this.onScroll);
|
|
5675
5654
|
window.removeEventListener("resize", this.onResize);
|
|
5655
|
+
window.removeEventListener("beforeprint", this.onPrint);
|
|
5676
5656
|
this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
|
5677
5657
|
clearTimeout(this.parentCheck);
|
|
5678
5658
|
clearTimeout(this.resizeTimeout);
|
|
@@ -5744,7 +5724,7 @@ function applyDOMChange(view, start, end, typeOver) {
|
|
|
5744
5724
|
diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
|
5745
5725
|
diff.toB--;
|
|
5746
5726
|
change = { from: from + diff.from, to: from + diff.toA,
|
|
5747
|
-
insert: Text
|
|
5727
|
+
insert: Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
|
5748
5728
|
}
|
|
5749
5729
|
newSel = selectionFromPoints(selPoints, from);
|
|
5750
5730
|
}
|
|
@@ -5935,9 +5915,9 @@ transactions for editing actions.
|
|
|
5935
5915
|
*/
|
|
5936
5916
|
class EditorView {
|
|
5937
5917
|
/**
|
|
5938
|
-
Construct a new view. You'll
|
|
5939
|
-
|
|
5940
|
-
|
|
5918
|
+
Construct a new view. You'll want to either provide a `parent`
|
|
5919
|
+
option, or put `view.dom` into your document after creating a
|
|
5920
|
+
view, so that the user can see the editor.
|
|
5941
5921
|
*/
|
|
5942
5922
|
constructor(
|
|
5943
5923
|
/**
|
|
@@ -5988,6 +5968,7 @@ class EditorView {
|
|
|
5988
5968
|
this.measure();
|
|
5989
5969
|
});
|
|
5990
5970
|
this.inputState = new InputState(this);
|
|
5971
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
5991
5972
|
this.docView = new DocView(this);
|
|
5992
5973
|
this.mountStyles();
|
|
5993
5974
|
this.updateAttrs();
|
|
@@ -6075,14 +6056,9 @@ class EditorView {
|
|
|
6075
6056
|
let { main } = tr.state.selection;
|
|
6076
6057
|
scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
|
6077
6058
|
}
|
|
6078
|
-
for (let e of tr.effects)
|
|
6079
|
-
if (e.is(
|
|
6080
|
-
scrollTarget = new ScrollTarget(e.value);
|
|
6081
|
-
else if (e.is(centerOn))
|
|
6082
|
-
scrollTarget = new ScrollTarget(e.value, "center");
|
|
6083
|
-
else if (e.is(scrollIntoView))
|
|
6059
|
+
for (let e of tr.effects)
|
|
6060
|
+
if (e.is(scrollIntoView))
|
|
6084
6061
|
scrollTarget = e.value;
|
|
6085
|
-
}
|
|
6086
6062
|
}
|
|
6087
6063
|
this.viewState.update(update, scrollTarget);
|
|
6088
6064
|
this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
|
@@ -6133,7 +6109,7 @@ class EditorView {
|
|
|
6133
6109
|
for (let plugin of this.plugins)
|
|
6134
6110
|
plugin.update(this);
|
|
6135
6111
|
this.docView = new DocView(this);
|
|
6136
|
-
this.inputState.ensureHandlers(this);
|
|
6112
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
6137
6113
|
this.mountStyles();
|
|
6138
6114
|
this.updateAttrs();
|
|
6139
6115
|
this.bidiCache = [];
|
|
@@ -6165,7 +6141,7 @@ class EditorView {
|
|
|
6165
6141
|
plugin.destroy(this);
|
|
6166
6142
|
this.plugins = newPlugins;
|
|
6167
6143
|
this.pluginMap.clear();
|
|
6168
|
-
this.inputState.ensureHandlers(this);
|
|
6144
|
+
this.inputState.ensureHandlers(this, this.plugins);
|
|
6169
6145
|
}
|
|
6170
6146
|
else {
|
|
6171
6147
|
for (let p of this.plugins)
|
|
@@ -6303,7 +6279,7 @@ class EditorView {
|
|
|
6303
6279
|
}
|
|
6304
6280
|
mountStyles() {
|
|
6305
6281
|
this.styleModules = this.state.facet(styleModule);
|
|
6306
|
-
StyleModule.mount(this.root, this.styleModules.concat(baseTheme).reverse());
|
|
6282
|
+
StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
|
|
6307
6283
|
}
|
|
6308
6284
|
readMeasured() {
|
|
6309
6285
|
if (this.updateState == 2 /* Updating */)
|
|
@@ -6334,16 +6310,6 @@ class EditorView {
|
|
|
6334
6310
|
}
|
|
6335
6311
|
}
|
|
6336
6312
|
/**
|
|
6337
|
-
Collect all values provided by the active plugins for a given
|
|
6338
|
-
field.
|
|
6339
|
-
*/
|
|
6340
|
-
pluginField(field) {
|
|
6341
|
-
let result = [];
|
|
6342
|
-
for (let plugin of this.plugins)
|
|
6343
|
-
plugin.update(this).takeField(field, result);
|
|
6344
|
-
return result;
|
|
6345
|
-
}
|
|
6346
|
-
/**
|
|
6347
6313
|
Get the value of a specific plugin, if present. Note that
|
|
6348
6314
|
plugins that crash can be dropped from a view, so even when you
|
|
6349
6315
|
know you registered a given plugin, it is recommended to check
|
|
@@ -6370,23 +6336,6 @@ class EditorView {
|
|
|
6370
6336
|
return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
|
6371
6337
|
}
|
|
6372
6338
|
/**
|
|
6373
|
-
Find the line or block widget at the given vertical position.
|
|
6374
|
-
|
|
6375
|
-
By default, this position is interpreted as a screen position,
|
|
6376
|
-
meaning `docTop` is set to the DOM top position of the editor
|
|
6377
|
-
content (forcing a layout). You can pass a different `docTop`
|
|
6378
|
-
value—for example 0 to interpret `height` as a document-relative
|
|
6379
|
-
position, or a precomputed document top
|
|
6380
|
-
(`view.contentDOM.getBoundingClientRect().top`) to limit layout
|
|
6381
|
-
queries.
|
|
6382
|
-
|
|
6383
|
-
*Deprecated: use `elementAtHeight` instead.*
|
|
6384
|
-
*/
|
|
6385
|
-
blockAtHeight(height, docTop) {
|
|
6386
|
-
let top = ensureTop(docTop, this);
|
|
6387
|
-
return this.elementAtHeight(height - top).moveY(top);
|
|
6388
|
-
}
|
|
6389
|
-
/**
|
|
6390
6339
|
Find the text line or block widget at the given vertical
|
|
6391
6340
|
position (which is interpreted as relative to the [top of the
|
|
6392
6341
|
document](https://codemirror.net/6/docs/ref/#view.EditorView.documentTop)
|
|
@@ -6396,23 +6345,6 @@ class EditorView {
|
|
|
6396
6345
|
return this.viewState.elementAtHeight(height);
|
|
6397
6346
|
}
|
|
6398
6347
|
/**
|
|
6399
|
-
Find information for the visual line (see
|
|
6400
|
-
[`visualLineAt`](https://codemirror.net/6/docs/ref/#view.EditorView.visualLineAt)) at the given
|
|
6401
|
-
vertical position. The resulting block info might hold another
|
|
6402
|
-
array of block info structs in its `type` field if this line
|
|
6403
|
-
consists of more than one block.
|
|
6404
|
-
|
|
6405
|
-
Defaults to treating `height` as a screen position. See
|
|
6406
|
-
[`blockAtHeight`](https://codemirror.net/6/docs/ref/#view.EditorView.blockAtHeight) for the
|
|
6407
|
-
interpretation of the `docTop` parameter.
|
|
6408
|
-
|
|
6409
|
-
*Deprecated: use `lineBlockAtHeight` instead.*
|
|
6410
|
-
*/
|
|
6411
|
-
visualLineAtHeight(height, docTop) {
|
|
6412
|
-
let top = ensureTop(docTop, this);
|
|
6413
|
-
return this.lineBlockAtHeight(height - top).moveY(top);
|
|
6414
|
-
}
|
|
6415
|
-
/**
|
|
6416
6348
|
Find the line block (see
|
|
6417
6349
|
[`lineBlockAt`](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) at the given
|
|
6418
6350
|
height.
|
|
@@ -6422,19 +6354,6 @@ class EditorView {
|
|
|
6422
6354
|
return this.viewState.lineBlockAtHeight(height);
|
|
6423
6355
|
}
|
|
6424
6356
|
/**
|
|
6425
|
-
Iterate over the height information of the visual lines in the
|
|
6426
|
-
viewport. The heights of lines are reported relative to the
|
|
6427
|
-
given document top, which defaults to the screen position of the
|
|
6428
|
-
document (forcing a layout).
|
|
6429
|
-
|
|
6430
|
-
*Deprecated: use `viewportLineBlocks` instead.*
|
|
6431
|
-
*/
|
|
6432
|
-
viewportLines(f, docTop) {
|
|
6433
|
-
let top = ensureTop(docTop, this);
|
|
6434
|
-
for (let line of this.viewportLineBlocks)
|
|
6435
|
-
f(line.moveY(top));
|
|
6436
|
-
}
|
|
6437
|
-
/**
|
|
6438
6357
|
Get the extent and vertical position of all [line
|
|
6439
6358
|
blocks](https://codemirror.net/6/docs/ref/#view.EditorView.lineBlockAt) in the viewport. Positions
|
|
6440
6359
|
are relative to the [top of the
|
|
@@ -6444,24 +6363,9 @@ class EditorView {
|
|
|
6444
6363
|
return this.viewState.viewportLines;
|
|
6445
6364
|
}
|
|
6446
6365
|
/**
|
|
6447
|
-
Find the extent and height of the visual line (a range delimited
|
|
6448
|
-
on both sides by either non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^range)
|
|
6449
|
-
line breaks, or the start/end of the document) at the given position.
|
|
6450
|
-
|
|
6451
|
-
Vertical positions are computed relative to the `docTop`
|
|
6452
|
-
argument, which defaults to 0 for this method. You can pass
|
|
6453
|
-
`view.contentDOM.getBoundingClientRect().top` here to get screen
|
|
6454
|
-
coordinates.
|
|
6455
|
-
|
|
6456
|
-
*Deprecated: use `lineBlockAt` instead.*
|
|
6457
|
-
*/
|
|
6458
|
-
visualLineAt(pos, docTop = 0) {
|
|
6459
|
-
return this.lineBlockAt(pos).moveY(docTop + this.viewState.paddingTop);
|
|
6460
|
-
}
|
|
6461
|
-
/**
|
|
6462
6366
|
Find the line block around the given document position. A line
|
|
6463
6367
|
block is a range delimited on both sides by either a
|
|
6464
|
-
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^
|
|
6368
|
+
non-[hidden](https://codemirror.net/6/docs/ref/#view.Decoration^replace) line breaks, or the
|
|
6465
6369
|
start/end of the document. It will usually just hold a line of
|
|
6466
6370
|
text, but may be broken into multiple textblocks by block
|
|
6467
6371
|
widgets.
|
|
@@ -6477,13 +6381,13 @@ class EditorView {
|
|
|
6477
6381
|
}
|
|
6478
6382
|
/**
|
|
6479
6383
|
Move a cursor position by [grapheme
|
|
6480
|
-
cluster](https://codemirror.net/6/docs/ref/#
|
|
6481
|
-
the motion is away from the line start, or towards it.
|
|
6482
|
-
bidirectional text is in visual order,
|
|
6483
|
-
direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
6484
|
-
position was the last one on the line, the
|
|
6485
|
-
will be across the line break. If there is no
|
|
6486
|
-
original position is returned.
|
|
6384
|
+
cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak). `forward` determines whether
|
|
6385
|
+
the motion is away from the line start, or towards it. In
|
|
6386
|
+
bidirectional text, the line is traversed in visual order, using
|
|
6387
|
+
the editor's [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
6388
|
+
When the start position was the last one on the line, the
|
|
6389
|
+
returned position will be across the line break. If there is no
|
|
6390
|
+
further line, the original position is returned.
|
|
6487
6391
|
|
|
6488
6392
|
By default, this method moves over a single cluster. The
|
|
6489
6393
|
optional `by` argument can be used to move across more. It will
|
|
@@ -6528,10 +6432,6 @@ class EditorView {
|
|
|
6528
6432
|
moveVertically(start, forward, distance) {
|
|
6529
6433
|
return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
|
6530
6434
|
}
|
|
6531
|
-
// FIXME remove on next major version
|
|
6532
|
-
scrollPosIntoView(pos) {
|
|
6533
|
-
this.dispatch({ effects: scrollTo.of(EditorSelection.cursor(pos)) });
|
|
6534
|
-
}
|
|
6535
6435
|
/**
|
|
6536
6436
|
Find the DOM parent node and offset (child offset if `node` is
|
|
6537
6437
|
an element, character offset when it is a text node) at the
|
|
@@ -6587,9 +6487,25 @@ class EditorView {
|
|
|
6587
6487
|
/**
|
|
6588
6488
|
The text direction
|
|
6589
6489
|
([`direction`](https://developer.mozilla.org/en-US/docs/Web/CSS/direction)
|
|
6590
|
-
CSS property) of the editor.
|
|
6490
|
+
CSS property) of the editor's content element.
|
|
6491
|
+
*/
|
|
6492
|
+
get textDirection() { return this.viewState.defaultTextDirection; }
|
|
6493
|
+
/**
|
|
6494
|
+
Find the text direction of the block at the given position, as
|
|
6495
|
+
assigned by CSS. If
|
|
6496
|
+
[`perLineTextDirection`](https://codemirror.net/6/docs/ref/#view.EditorView^perLineTextDirection)
|
|
6497
|
+
isn't enabled, or the given position is outside of the viewport,
|
|
6498
|
+
this will always return the same as
|
|
6499
|
+
[`textDirection`](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection). Note that
|
|
6500
|
+
this may trigger a DOM layout.
|
|
6591
6501
|
*/
|
|
6592
|
-
|
|
6502
|
+
textDirectionAt(pos) {
|
|
6503
|
+
let perLine = this.state.facet(perLineTextDirection);
|
|
6504
|
+
if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
|
|
6505
|
+
return this.textDirection;
|
|
6506
|
+
this.readMeasured();
|
|
6507
|
+
return this.docView.textDirectionAt(pos);
|
|
6508
|
+
}
|
|
6593
6509
|
/**
|
|
6594
6510
|
Whether this editor [wraps lines](https://codemirror.net/6/docs/ref/#view.EditorView.lineWrapping)
|
|
6595
6511
|
(as determined by the
|
|
@@ -6608,11 +6524,11 @@ class EditorView {
|
|
|
6608
6524
|
bidiSpans(line) {
|
|
6609
6525
|
if (line.length > MaxBidiLine)
|
|
6610
6526
|
return trivialOrder(line.length);
|
|
6611
|
-
let dir = this.
|
|
6527
|
+
let dir = this.textDirectionAt(line.from);
|
|
6612
6528
|
for (let entry of this.bidiCache)
|
|
6613
6529
|
if (entry.from == line.from && entry.dir == dir)
|
|
6614
6530
|
return entry.order;
|
|
6615
|
-
let order = computeOrder(line.text,
|
|
6531
|
+
let order = computeOrder(line.text, dir);
|
|
6616
6532
|
this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
|
|
6617
6533
|
return order;
|
|
6618
6534
|
}
|
|
@@ -6663,16 +6579,16 @@ class EditorView {
|
|
|
6663
6579
|
return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
|
6664
6580
|
}
|
|
6665
6581
|
/**
|
|
6666
|
-
|
|
6667
|
-
should be an object mapping event names to handler
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
These are registered
|
|
6672
|
-
element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
|
|
6673
|
-
handlers, which will be called any time the
|
|
6674
|
-
element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
|
|
6675
|
-
is scrolled.
|
|
6582
|
+
Returns an extension that can be used to add DOM event handlers.
|
|
6583
|
+
The value should be an object mapping event names to handler
|
|
6584
|
+
functions. For any given event, such functions are ordered by
|
|
6585
|
+
extension precedence, and the first handler to return true will
|
|
6586
|
+
be assumed to have handled that event, and no other handlers or
|
|
6587
|
+
built-in behavior will be activated for it. These are registered
|
|
6588
|
+
on the [content element](https://codemirror.net/6/docs/ref/#view.EditorView.contentDOM), except
|
|
6589
|
+
for `scroll` handlers, which will be called any time the
|
|
6590
|
+
editor's [scroll element](https://codemirror.net/6/docs/ref/#view.EditorView.scrollDOM) or one of
|
|
6591
|
+
its parent nodes is scrolled.
|
|
6676
6592
|
*/
|
|
6677
6593
|
static domEventHandlers(handlers) {
|
|
6678
6594
|
return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
|
@@ -6714,20 +6630,6 @@ class EditorView {
|
|
|
6714
6630
|
}
|
|
6715
6631
|
}
|
|
6716
6632
|
/**
|
|
6717
|
-
Effect that can be [added](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects) to a
|
|
6718
|
-
transaction to make it scroll the given range into view.
|
|
6719
|
-
|
|
6720
|
-
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6721
|
-
*/
|
|
6722
|
-
EditorView.scrollTo = scrollTo;
|
|
6723
|
-
/**
|
|
6724
|
-
Effect that makes the editor scroll the given range to the
|
|
6725
|
-
center of the visible view.
|
|
6726
|
-
|
|
6727
|
-
*Deprecated*. Use [`scrollIntoView`](https://codemirror.net/6/docs/ref/#view.EditorView^scrollIntoView) instead.
|
|
6728
|
-
*/
|
|
6729
|
-
EditorView.centerOn = centerOn;
|
|
6730
|
-
/**
|
|
6731
6633
|
Facet to add a [style
|
|
6732
6634
|
module](https://github.com/marijnh/style-mod#documentation) to
|
|
6733
6635
|
an editor view. The view will ensure that the module is
|
|
@@ -6744,6 +6646,13 @@ called and the default behavior is prevented.
|
|
|
6744
6646
|
*/
|
|
6745
6647
|
EditorView.inputHandler = inputHandler;
|
|
6746
6648
|
/**
|
|
6649
|
+
By default, the editor assumes all its content has the same
|
|
6650
|
+
[text direction](https://codemirror.net/6/docs/ref/#view.Direction). Configure this with a `true`
|
|
6651
|
+
value to make it read and store the text direction of every
|
|
6652
|
+
(rendered) line separately.
|
|
6653
|
+
*/
|
|
6654
|
+
EditorView.perLineTextDirection = perLineTextDirection;
|
|
6655
|
+
/**
|
|
6747
6656
|
Allows you to provide a function that should be called when the
|
|
6748
6657
|
library catches an exception from an extension (mostly from view
|
|
6749
6658
|
plugins, but may be used by other extensions to route exceptions
|
|
@@ -6759,9 +6668,9 @@ EditorView.updateListener = updateListener;
|
|
|
6759
6668
|
/**
|
|
6760
6669
|
Facet that controls whether the editor content DOM is editable.
|
|
6761
6670
|
When its highest-precedence value is `false`, the element will
|
|
6762
|
-
not
|
|
6763
|
-
|
|
6764
|
-
|
|
6671
|
+
not have its `contenteditable` attribute set. (Note that this
|
|
6672
|
+
doesn't affect API calls that change the editor content, even
|
|
6673
|
+
when those are bound to keys or buttons. See the
|
|
6765
6674
|
[`readOnly`](https://codemirror.net/6/docs/ref/#state.EditorState.readOnly) facet for that.)
|
|
6766
6675
|
*/
|
|
6767
6676
|
EditorView.editable = editable;
|
|
@@ -6780,18 +6689,45 @@ the drag should move the content.
|
|
|
6780
6689
|
*/
|
|
6781
6690
|
EditorView.dragMovesSelection = dragMovesSelection$1;
|
|
6782
6691
|
/**
|
|
6783
|
-
Facet used to configure whether a given selecting click adds
|
|
6784
|
-
|
|
6692
|
+
Facet used to configure whether a given selecting click adds a
|
|
6693
|
+
new range to the existing selection or replaces it entirely. The
|
|
6694
|
+
default behavior is to check `event.metaKey` on macOS, and
|
|
6695
|
+
`event.ctrlKey` elsewhere.
|
|
6785
6696
|
*/
|
|
6786
6697
|
EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
|
|
6787
6698
|
/**
|
|
6788
6699
|
A facet that determines which [decorations](https://codemirror.net/6/docs/ref/#view.Decoration)
|
|
6789
|
-
are shown in the view.
|
|
6790
|
-
|
|
6791
|
-
|
|
6700
|
+
are shown in the view. Decorations can be provided in two
|
|
6701
|
+
ways—directly, or via a function that takes an editor view.
|
|
6702
|
+
|
|
6703
|
+
Only decoration sets provided directly are allowed to influence
|
|
6704
|
+
the editor's vertical layout structure. The ones provided as
|
|
6705
|
+
functions are called _after_ the new viewport has been computed,
|
|
6706
|
+
and thus **must not** introduce block widgets or replacing
|
|
6707
|
+
decorations that cover line breaks.
|
|
6792
6708
|
*/
|
|
6793
6709
|
EditorView.decorations = decorations;
|
|
6794
6710
|
/**
|
|
6711
|
+
Used to provide ranges that should be treated as atoms as far as
|
|
6712
|
+
cursor motion is concerned. This causes methods like
|
|
6713
|
+
[`moveByChar`](https://codemirror.net/6/docs/ref/#view.EditorView.moveByChar) and
|
|
6714
|
+
[`moveVertically`](https://codemirror.net/6/docs/ref/#view.EditorView.moveVertically) (and the
|
|
6715
|
+
commands built on top of them) to skip across such regions when
|
|
6716
|
+
a selection endpoint would enter them. This does _not_ prevent
|
|
6717
|
+
direct programmatic [selection
|
|
6718
|
+
updates](https://codemirror.net/6/docs/ref/#state.TransactionSpec.selection) from moving into such
|
|
6719
|
+
regions.
|
|
6720
|
+
*/
|
|
6721
|
+
EditorView.atomicRanges = atomicRanges;
|
|
6722
|
+
/**
|
|
6723
|
+
Facet that allows extensions to provide additional scroll
|
|
6724
|
+
margins (space around the sides of the scrolling element that
|
|
6725
|
+
should be considered invisible). This can be useful when the
|
|
6726
|
+
plugin introduces elements that cover part of that element (for
|
|
6727
|
+
example a horizontally fixed gutter).
|
|
6728
|
+
*/
|
|
6729
|
+
EditorView.scrollMargins = scrollMargins;
|
|
6730
|
+
/**
|
|
6795
6731
|
This facet records whether a dark theme is active. The extension
|
|
6796
6732
|
returned by [`theme`](https://codemirror.net/6/docs/ref/#view.EditorView^theme) automatically
|
|
6797
6733
|
includes an instance of this when the `dark` option is set to
|
|
@@ -6824,10 +6760,6 @@ search match).
|
|
|
6824
6760
|
EditorView.announce = /*@__PURE__*/StateEffect.define();
|
|
6825
6761
|
// Maximum line length for which we compute accurate bidi info
|
|
6826
6762
|
const MaxBidiLine = 4096;
|
|
6827
|
-
// FIXME remove this and its callers on next breaking release
|
|
6828
|
-
function ensureTop(given, view) {
|
|
6829
|
-
return (given == null ? view.contentDOM.getBoundingClientRect().top : given) + view.viewState.paddingTop;
|
|
6830
|
-
}
|
|
6831
6763
|
const BadMeasure = {};
|
|
6832
6764
|
class CachedOrder {
|
|
6833
6765
|
constructor(from, to, dir, order) {
|
|
@@ -6930,7 +6862,7 @@ function getKeymap(state) {
|
|
|
6930
6862
|
}
|
|
6931
6863
|
/**
|
|
6932
6864
|
Run the key handlers registered for a given scope. The event
|
|
6933
|
-
object should be `"keydown"` event. Returns true if any of the
|
|
6865
|
+
object should be a `"keydown"` event. Returns true if any of the
|
|
6934
6866
|
handlers handled it.
|
|
6935
6867
|
*/
|
|
6936
6868
|
function runScopeHandlers(view, event, scope) {
|
|
@@ -7707,9 +7639,1302 @@ function placeholder(content) {
|
|
|
7707
7639
|
}, { decorations: v => v.decorations });
|
|
7708
7640
|
}
|
|
7709
7641
|
|
|
7642
|
+
// Don't compute precise column positions for line offsets above this
|
|
7643
|
+
// (since it could get expensive). Assume offset==column for them.
|
|
7644
|
+
const MaxOff = 2000;
|
|
7645
|
+
function rectangleFor(state, a, b) {
|
|
7646
|
+
let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
|
|
7647
|
+
let ranges = [];
|
|
7648
|
+
if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
|
|
7649
|
+
let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
|
|
7650
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
7651
|
+
let line = state.doc.line(i);
|
|
7652
|
+
if (line.length <= endOff)
|
|
7653
|
+
ranges.push(EditorSelection.range(line.from + startOff, line.to + endOff));
|
|
7654
|
+
}
|
|
7655
|
+
}
|
|
7656
|
+
else {
|
|
7657
|
+
let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
|
|
7658
|
+
for (let i = startLine; i <= endLine; i++) {
|
|
7659
|
+
let line = state.doc.line(i);
|
|
7660
|
+
let start = findColumn(line.text, startCol, state.tabSize, true);
|
|
7661
|
+
if (start > -1) {
|
|
7662
|
+
let end = findColumn(line.text, endCol, state.tabSize);
|
|
7663
|
+
ranges.push(EditorSelection.range(line.from + start, line.from + end));
|
|
7664
|
+
}
|
|
7665
|
+
}
|
|
7666
|
+
}
|
|
7667
|
+
return ranges;
|
|
7668
|
+
}
|
|
7669
|
+
function absoluteColumn(view, x) {
|
|
7670
|
+
let ref = view.coordsAtPos(view.viewport.from);
|
|
7671
|
+
return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
|
|
7672
|
+
}
|
|
7673
|
+
function getPos(view, event) {
|
|
7674
|
+
let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
7675
|
+
let line = view.state.doc.lineAt(offset), off = offset - line.from;
|
|
7676
|
+
let col = off > MaxOff ? -1
|
|
7677
|
+
: off == line.length ? absoluteColumn(view, event.clientX)
|
|
7678
|
+
: countColumn(line.text, view.state.tabSize, offset - line.from);
|
|
7679
|
+
return { line: line.number, col, off };
|
|
7680
|
+
}
|
|
7681
|
+
function rectangleSelectionStyle(view, event) {
|
|
7682
|
+
let start = getPos(view, event), startSel = view.state.selection;
|
|
7683
|
+
if (!start)
|
|
7684
|
+
return null;
|
|
7685
|
+
return {
|
|
7686
|
+
update(update) {
|
|
7687
|
+
if (update.docChanged) {
|
|
7688
|
+
let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
|
|
7689
|
+
let newLine = update.state.doc.lineAt(newStart);
|
|
7690
|
+
start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
|
|
7691
|
+
startSel = startSel.map(update.changes);
|
|
7692
|
+
}
|
|
7693
|
+
},
|
|
7694
|
+
get(event, _extend, multiple) {
|
|
7695
|
+
let cur = getPos(view, event);
|
|
7696
|
+
if (!cur)
|
|
7697
|
+
return startSel;
|
|
7698
|
+
let ranges = rectangleFor(view.state, start, cur);
|
|
7699
|
+
if (!ranges.length)
|
|
7700
|
+
return startSel;
|
|
7701
|
+
if (multiple)
|
|
7702
|
+
return EditorSelection.create(ranges.concat(startSel.ranges));
|
|
7703
|
+
else
|
|
7704
|
+
return EditorSelection.create(ranges);
|
|
7705
|
+
}
|
|
7706
|
+
};
|
|
7707
|
+
}
|
|
7708
|
+
/**
|
|
7709
|
+
Create an extension that enables rectangular selections. By
|
|
7710
|
+
default, it will react to left mouse drag with the Alt key held
|
|
7711
|
+
down. When such a selection occurs, the text within the rectangle
|
|
7712
|
+
that was dragged over will be selected, as one selection
|
|
7713
|
+
[range](https://codemirror.net/6/docs/ref/#state.SelectionRange) per line.
|
|
7714
|
+
*/
|
|
7715
|
+
function rectangularSelection(options) {
|
|
7716
|
+
let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0);
|
|
7717
|
+
return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
|
|
7718
|
+
}
|
|
7719
|
+
const keys = {
|
|
7720
|
+
Alt: [18, e => e.altKey],
|
|
7721
|
+
Control: [17, e => e.ctrlKey],
|
|
7722
|
+
Shift: [16, e => e.shiftKey],
|
|
7723
|
+
Meta: [91, e => e.metaKey]
|
|
7724
|
+
};
|
|
7725
|
+
const showCrosshair = { style: "cursor: crosshair" };
|
|
7726
|
+
/**
|
|
7727
|
+
Returns an extension that turns the pointer cursor into a
|
|
7728
|
+
crosshair when a given modifier key, defaulting to Alt, is held
|
|
7729
|
+
down. Can serve as a visual hint that rectangular selection is
|
|
7730
|
+
going to happen when paired with
|
|
7731
|
+
[`rectangularSelection`](https://codemirror.net/6/docs/ref/#view.rectangularSelection).
|
|
7732
|
+
*/
|
|
7733
|
+
function crosshairCursor(options = {}) {
|
|
7734
|
+
let [code, getter] = keys[options.key || "Alt"];
|
|
7735
|
+
let plugin = ViewPlugin.fromClass(class {
|
|
7736
|
+
constructor(view) {
|
|
7737
|
+
this.view = view;
|
|
7738
|
+
this.isDown = false;
|
|
7739
|
+
}
|
|
7740
|
+
set(isDown) {
|
|
7741
|
+
if (this.isDown != isDown) {
|
|
7742
|
+
this.isDown = isDown;
|
|
7743
|
+
this.view.update([]);
|
|
7744
|
+
}
|
|
7745
|
+
}
|
|
7746
|
+
}, {
|
|
7747
|
+
eventHandlers: {
|
|
7748
|
+
keydown(e) {
|
|
7749
|
+
this.set(e.keyCode == code || getter(e));
|
|
7750
|
+
},
|
|
7751
|
+
keyup(e) {
|
|
7752
|
+
if (e.keyCode == code || !getter(e))
|
|
7753
|
+
this.set(false);
|
|
7754
|
+
}
|
|
7755
|
+
}
|
|
7756
|
+
});
|
|
7757
|
+
return [
|
|
7758
|
+
plugin,
|
|
7759
|
+
EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; })
|
|
7760
|
+
];
|
|
7761
|
+
}
|
|
7762
|
+
|
|
7763
|
+
const Outside = "-10000px";
|
|
7764
|
+
class TooltipViewManager {
|
|
7765
|
+
constructor(view, facet, createTooltipView) {
|
|
7766
|
+
this.facet = facet;
|
|
7767
|
+
this.createTooltipView = createTooltipView;
|
|
7768
|
+
this.input = view.state.facet(facet);
|
|
7769
|
+
this.tooltips = this.input.filter(t => t);
|
|
7770
|
+
this.tooltipViews = this.tooltips.map(createTooltipView);
|
|
7771
|
+
}
|
|
7772
|
+
update(update) {
|
|
7773
|
+
let input = update.state.facet(this.facet);
|
|
7774
|
+
let tooltips = input.filter(x => x);
|
|
7775
|
+
if (input === this.input) {
|
|
7776
|
+
for (let t of this.tooltipViews)
|
|
7777
|
+
if (t.update)
|
|
7778
|
+
t.update(update);
|
|
7779
|
+
return false;
|
|
7780
|
+
}
|
|
7781
|
+
let tooltipViews = [];
|
|
7782
|
+
for (let i = 0; i < tooltips.length; i++) {
|
|
7783
|
+
let tip = tooltips[i], known = -1;
|
|
7784
|
+
if (!tip)
|
|
7785
|
+
continue;
|
|
7786
|
+
for (let i = 0; i < this.tooltips.length; i++) {
|
|
7787
|
+
let other = this.tooltips[i];
|
|
7788
|
+
if (other && other.create == tip.create)
|
|
7789
|
+
known = i;
|
|
7790
|
+
}
|
|
7791
|
+
if (known < 0) {
|
|
7792
|
+
tooltipViews[i] = this.createTooltipView(tip);
|
|
7793
|
+
}
|
|
7794
|
+
else {
|
|
7795
|
+
let tooltipView = tooltipViews[i] = this.tooltipViews[known];
|
|
7796
|
+
if (tooltipView.update)
|
|
7797
|
+
tooltipView.update(update);
|
|
7798
|
+
}
|
|
7799
|
+
}
|
|
7800
|
+
for (let t of this.tooltipViews)
|
|
7801
|
+
if (tooltipViews.indexOf(t) < 0)
|
|
7802
|
+
t.dom.remove();
|
|
7803
|
+
this.input = input;
|
|
7804
|
+
this.tooltips = tooltips;
|
|
7805
|
+
this.tooltipViews = tooltipViews;
|
|
7806
|
+
return true;
|
|
7807
|
+
}
|
|
7808
|
+
}
|
|
7809
|
+
/**
|
|
7810
|
+
Creates an extension that configures tooltip behavior.
|
|
7811
|
+
*/
|
|
7812
|
+
function tooltips(config = {}) {
|
|
7813
|
+
return tooltipConfig.of(config);
|
|
7814
|
+
}
|
|
7815
|
+
function windowSpace() {
|
|
7816
|
+
return { top: 0, left: 0, bottom: innerHeight, right: innerWidth };
|
|
7817
|
+
}
|
|
7818
|
+
const tooltipConfig = /*@__PURE__*/Facet.define({
|
|
7819
|
+
combine: values => {
|
|
7820
|
+
var _a, _b, _c;
|
|
7821
|
+
return ({
|
|
7822
|
+
position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
|
|
7823
|
+
parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
|
|
7824
|
+
tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
|
|
7825
|
+
});
|
|
7826
|
+
}
|
|
7827
|
+
});
|
|
7828
|
+
const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
7829
|
+
constructor(view) {
|
|
7830
|
+
var _a;
|
|
7831
|
+
this.view = view;
|
|
7832
|
+
this.inView = true;
|
|
7833
|
+
this.lastTransaction = 0;
|
|
7834
|
+
this.measureTimeout = -1;
|
|
7835
|
+
let config = view.state.facet(tooltipConfig);
|
|
7836
|
+
this.position = config.position;
|
|
7837
|
+
this.parent = config.parent;
|
|
7838
|
+
this.classes = view.themeClasses;
|
|
7839
|
+
this.createContainer();
|
|
7840
|
+
this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
|
|
7841
|
+
this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
|
|
7842
|
+
this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
|
|
7843
|
+
if (Date.now() > this.lastTransaction - 50 &&
|
|
7844
|
+
entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
|
|
7845
|
+
this.measureSoon();
|
|
7846
|
+
}, { threshold: [1] }) : null;
|
|
7847
|
+
this.observeIntersection();
|
|
7848
|
+
(_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
|
|
7849
|
+
this.maybeMeasure();
|
|
7850
|
+
}
|
|
7851
|
+
createContainer() {
|
|
7852
|
+
if (this.parent) {
|
|
7853
|
+
this.container = document.createElement("div");
|
|
7854
|
+
this.container.style.position = "relative";
|
|
7855
|
+
this.container.className = this.view.themeClasses;
|
|
7856
|
+
this.parent.appendChild(this.container);
|
|
7857
|
+
}
|
|
7858
|
+
else {
|
|
7859
|
+
this.container = this.view.dom;
|
|
7860
|
+
}
|
|
7861
|
+
}
|
|
7862
|
+
observeIntersection() {
|
|
7863
|
+
if (this.intersectionObserver) {
|
|
7864
|
+
this.intersectionObserver.disconnect();
|
|
7865
|
+
for (let tooltip of this.manager.tooltipViews)
|
|
7866
|
+
this.intersectionObserver.observe(tooltip.dom);
|
|
7867
|
+
}
|
|
7868
|
+
}
|
|
7869
|
+
measureSoon() {
|
|
7870
|
+
if (this.measureTimeout < 0)
|
|
7871
|
+
this.measureTimeout = setTimeout(() => {
|
|
7872
|
+
this.measureTimeout = -1;
|
|
7873
|
+
this.maybeMeasure();
|
|
7874
|
+
}, 50);
|
|
7875
|
+
}
|
|
7876
|
+
update(update) {
|
|
7877
|
+
if (update.transactions.length)
|
|
7878
|
+
this.lastTransaction = Date.now();
|
|
7879
|
+
let updated = this.manager.update(update);
|
|
7880
|
+
if (updated)
|
|
7881
|
+
this.observeIntersection();
|
|
7882
|
+
let shouldMeasure = updated || update.geometryChanged;
|
|
7883
|
+
let newConfig = update.state.facet(tooltipConfig);
|
|
7884
|
+
if (newConfig.position != this.position) {
|
|
7885
|
+
this.position = newConfig.position;
|
|
7886
|
+
for (let t of this.manager.tooltipViews)
|
|
7887
|
+
t.dom.style.position = this.position;
|
|
7888
|
+
shouldMeasure = true;
|
|
7889
|
+
}
|
|
7890
|
+
if (newConfig.parent != this.parent) {
|
|
7891
|
+
if (this.parent)
|
|
7892
|
+
this.container.remove();
|
|
7893
|
+
this.parent = newConfig.parent;
|
|
7894
|
+
this.createContainer();
|
|
7895
|
+
for (let t of this.manager.tooltipViews)
|
|
7896
|
+
this.container.appendChild(t.dom);
|
|
7897
|
+
shouldMeasure = true;
|
|
7898
|
+
}
|
|
7899
|
+
else if (this.parent && this.view.themeClasses != this.classes) {
|
|
7900
|
+
this.classes = this.container.className = this.view.themeClasses;
|
|
7901
|
+
}
|
|
7902
|
+
if (shouldMeasure)
|
|
7903
|
+
this.maybeMeasure();
|
|
7904
|
+
}
|
|
7905
|
+
createTooltip(tooltip) {
|
|
7906
|
+
let tooltipView = tooltip.create(this.view);
|
|
7907
|
+
tooltipView.dom.classList.add("cm-tooltip");
|
|
7908
|
+
if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
|
|
7909
|
+
let arrow = document.createElement("div");
|
|
7910
|
+
arrow.className = "cm-tooltip-arrow";
|
|
7911
|
+
tooltipView.dom.appendChild(arrow);
|
|
7912
|
+
}
|
|
7913
|
+
tooltipView.dom.style.position = this.position;
|
|
7914
|
+
tooltipView.dom.style.top = Outside;
|
|
7915
|
+
this.container.appendChild(tooltipView.dom);
|
|
7916
|
+
if (tooltipView.mount)
|
|
7917
|
+
tooltipView.mount(this.view);
|
|
7918
|
+
return tooltipView;
|
|
7919
|
+
}
|
|
7920
|
+
destroy() {
|
|
7921
|
+
var _a, _b;
|
|
7922
|
+
(_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon);
|
|
7923
|
+
for (let { dom } of this.manager.tooltipViews)
|
|
7924
|
+
dom.remove();
|
|
7925
|
+
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
7926
|
+
clearTimeout(this.measureTimeout);
|
|
7927
|
+
}
|
|
7928
|
+
readMeasure() {
|
|
7929
|
+
let editor = this.view.dom.getBoundingClientRect();
|
|
7930
|
+
return {
|
|
7931
|
+
editor,
|
|
7932
|
+
parent: this.parent ? this.container.getBoundingClientRect() : editor,
|
|
7933
|
+
pos: this.manager.tooltips.map((t, i) => {
|
|
7934
|
+
let tv = this.manager.tooltipViews[i];
|
|
7935
|
+
return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
|
|
7936
|
+
}),
|
|
7937
|
+
size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
|
7938
|
+
space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
|
|
7939
|
+
};
|
|
7940
|
+
}
|
|
7941
|
+
writeMeasure(measured) {
|
|
7942
|
+
let { editor, space } = measured;
|
|
7943
|
+
let others = [];
|
|
7944
|
+
for (let i = 0; i < this.manager.tooltips.length; i++) {
|
|
7945
|
+
let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
|
7946
|
+
let pos = measured.pos[i], size = measured.size[i];
|
|
7947
|
+
// Hide tooltips that are outside of the editor.
|
|
7948
|
+
if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
|
|
7949
|
+
pos.top >= Math.min(editor.bottom, space.bottom) ||
|
|
7950
|
+
pos.right < Math.max(editor.left, space.left) - .1 ||
|
|
7951
|
+
pos.left > Math.min(editor.right, space.right) + .1) {
|
|
7952
|
+
dom.style.top = Outside;
|
|
7953
|
+
continue;
|
|
7954
|
+
}
|
|
7955
|
+
let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
|
|
7956
|
+
let arrowHeight = arrow ? 7 /* Size */ : 0;
|
|
7957
|
+
let width = size.right - size.left, height = size.bottom - size.top;
|
|
7958
|
+
let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
|
|
7959
|
+
let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
|
|
7960
|
+
: ltr ? Math.min(pos.left - (arrow ? 14 /* Offset */ : 0) + offset.x, space.right - width)
|
|
7961
|
+
: Math.max(space.left, pos.left - width + (arrow ? 14 /* Offset */ : 0) - offset.x);
|
|
7962
|
+
let above = !!tooltip.above;
|
|
7963
|
+
if (!tooltip.strictSide && (above
|
|
7964
|
+
? pos.top - (size.bottom - size.top) - offset.y < space.top
|
|
7965
|
+
: pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
|
|
7966
|
+
above == (space.bottom - pos.bottom > pos.top - space.top))
|
|
7967
|
+
above = !above;
|
|
7968
|
+
let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
|
|
7969
|
+
let right = left + width;
|
|
7970
|
+
if (tView.overlap !== true)
|
|
7971
|
+
for (let r of others)
|
|
7972
|
+
if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
|
7973
|
+
top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
|
7974
|
+
if (this.position == "absolute") {
|
|
7975
|
+
dom.style.top = (top - measured.parent.top) + "px";
|
|
7976
|
+
dom.style.left = (left - measured.parent.left) + "px";
|
|
7977
|
+
}
|
|
7978
|
+
else {
|
|
7979
|
+
dom.style.top = top + "px";
|
|
7980
|
+
dom.style.left = left + "px";
|
|
7981
|
+
}
|
|
7982
|
+
if (arrow)
|
|
7983
|
+
arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`;
|
|
7984
|
+
if (tView.overlap !== true)
|
|
7985
|
+
others.push({ left, top, right, bottom: top + height });
|
|
7986
|
+
dom.classList.toggle("cm-tooltip-above", above);
|
|
7987
|
+
dom.classList.toggle("cm-tooltip-below", !above);
|
|
7988
|
+
if (tView.positioned)
|
|
7989
|
+
tView.positioned();
|
|
7990
|
+
}
|
|
7991
|
+
}
|
|
7992
|
+
maybeMeasure() {
|
|
7993
|
+
if (this.manager.tooltips.length) {
|
|
7994
|
+
if (this.view.inView)
|
|
7995
|
+
this.view.requestMeasure(this.measureReq);
|
|
7996
|
+
if (this.inView != this.view.inView) {
|
|
7997
|
+
this.inView = this.view.inView;
|
|
7998
|
+
if (!this.inView)
|
|
7999
|
+
for (let tv of this.manager.tooltipViews)
|
|
8000
|
+
tv.dom.style.top = Outside;
|
|
8001
|
+
}
|
|
8002
|
+
}
|
|
8003
|
+
}
|
|
8004
|
+
}, {
|
|
8005
|
+
eventHandlers: {
|
|
8006
|
+
scroll() { this.maybeMeasure(); }
|
|
8007
|
+
}
|
|
8008
|
+
});
|
|
8009
|
+
const baseTheme = /*@__PURE__*/EditorView.baseTheme({
|
|
8010
|
+
".cm-tooltip": {
|
|
8011
|
+
zIndex: 100
|
|
8012
|
+
},
|
|
8013
|
+
"&light .cm-tooltip": {
|
|
8014
|
+
border: "1px solid #bbb",
|
|
8015
|
+
backgroundColor: "#f5f5f5"
|
|
8016
|
+
},
|
|
8017
|
+
"&light .cm-tooltip-section:not(:first-child)": {
|
|
8018
|
+
borderTop: "1px solid #bbb",
|
|
8019
|
+
},
|
|
8020
|
+
"&dark .cm-tooltip": {
|
|
8021
|
+
backgroundColor: "#333338",
|
|
8022
|
+
color: "white"
|
|
8023
|
+
},
|
|
8024
|
+
".cm-tooltip-arrow": {
|
|
8025
|
+
height: `${7 /* Size */}px`,
|
|
8026
|
+
width: `${7 /* Size */ * 2}px`,
|
|
8027
|
+
position: "absolute",
|
|
8028
|
+
zIndex: -1,
|
|
8029
|
+
overflow: "hidden",
|
|
8030
|
+
"&:before, &:after": {
|
|
8031
|
+
content: "''",
|
|
8032
|
+
position: "absolute",
|
|
8033
|
+
width: 0,
|
|
8034
|
+
height: 0,
|
|
8035
|
+
borderLeft: `${7 /* Size */}px solid transparent`,
|
|
8036
|
+
borderRight: `${7 /* Size */}px solid transparent`,
|
|
8037
|
+
},
|
|
8038
|
+
".cm-tooltip-above &": {
|
|
8039
|
+
bottom: `-${7 /* Size */}px`,
|
|
8040
|
+
"&:before": {
|
|
8041
|
+
borderTop: `${7 /* Size */}px solid #bbb`,
|
|
8042
|
+
},
|
|
8043
|
+
"&:after": {
|
|
8044
|
+
borderTop: `${7 /* Size */}px solid #f5f5f5`,
|
|
8045
|
+
bottom: "1px"
|
|
8046
|
+
}
|
|
8047
|
+
},
|
|
8048
|
+
".cm-tooltip-below &": {
|
|
8049
|
+
top: `-${7 /* Size */}px`,
|
|
8050
|
+
"&:before": {
|
|
8051
|
+
borderBottom: `${7 /* Size */}px solid #bbb`,
|
|
8052
|
+
},
|
|
8053
|
+
"&:after": {
|
|
8054
|
+
borderBottom: `${7 /* Size */}px solid #f5f5f5`,
|
|
8055
|
+
top: "1px"
|
|
8056
|
+
}
|
|
8057
|
+
},
|
|
8058
|
+
},
|
|
8059
|
+
"&dark .cm-tooltip .cm-tooltip-arrow": {
|
|
8060
|
+
"&:before": {
|
|
8061
|
+
borderTopColor: "#333338",
|
|
8062
|
+
borderBottomColor: "#333338"
|
|
8063
|
+
},
|
|
8064
|
+
"&:after": {
|
|
8065
|
+
borderTopColor: "transparent",
|
|
8066
|
+
borderBottomColor: "transparent"
|
|
8067
|
+
}
|
|
8068
|
+
}
|
|
8069
|
+
});
|
|
8070
|
+
const noOffset = { x: 0, y: 0 };
|
|
8071
|
+
/**
|
|
8072
|
+
Facet to which an extension can add a value to show a tooltip.
|
|
8073
|
+
*/
|
|
8074
|
+
const showTooltip = /*@__PURE__*/Facet.define({
|
|
8075
|
+
enables: [tooltipPlugin, baseTheme]
|
|
8076
|
+
});
|
|
8077
|
+
const showHoverTooltip = /*@__PURE__*/Facet.define({
|
|
8078
|
+
combine(x) { console.log("show", x.map(x => !!x)); return x; }
|
|
8079
|
+
});
|
|
8080
|
+
class HoverTooltipHost {
|
|
8081
|
+
constructor(view) {
|
|
8082
|
+
this.view = view;
|
|
8083
|
+
this.mounted = false;
|
|
8084
|
+
this.dom = document.createElement("div");
|
|
8085
|
+
this.dom.classList.add("cm-tooltip-hover");
|
|
8086
|
+
this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
|
|
8087
|
+
}
|
|
8088
|
+
// Needs to be static so that host tooltip instances always match
|
|
8089
|
+
static create(view) {
|
|
8090
|
+
return new HoverTooltipHost(view);
|
|
8091
|
+
}
|
|
8092
|
+
createHostedView(tooltip) {
|
|
8093
|
+
let hostedView = tooltip.create(this.view);
|
|
8094
|
+
hostedView.dom.classList.add("cm-tooltip-section");
|
|
8095
|
+
this.dom.appendChild(hostedView.dom);
|
|
8096
|
+
if (this.mounted && hostedView.mount)
|
|
8097
|
+
hostedView.mount(this.view);
|
|
8098
|
+
return hostedView;
|
|
8099
|
+
}
|
|
8100
|
+
mount(view) {
|
|
8101
|
+
for (let hostedView of this.manager.tooltipViews) {
|
|
8102
|
+
if (hostedView.mount)
|
|
8103
|
+
hostedView.mount(view);
|
|
8104
|
+
}
|
|
8105
|
+
this.mounted = true;
|
|
8106
|
+
}
|
|
8107
|
+
positioned() {
|
|
8108
|
+
for (let hostedView of this.manager.tooltipViews) {
|
|
8109
|
+
if (hostedView.positioned)
|
|
8110
|
+
hostedView.positioned();
|
|
8111
|
+
}
|
|
8112
|
+
}
|
|
8113
|
+
update(update) {
|
|
8114
|
+
this.manager.update(update);
|
|
8115
|
+
}
|
|
8116
|
+
}
|
|
8117
|
+
const showHoverTooltipHost = /*@__PURE__*/showTooltip.compute([showHoverTooltip], state => {
|
|
8118
|
+
let tooltips = state.facet(showHoverTooltip).filter(t => t);
|
|
8119
|
+
console.log("hover tooltips: ", tooltips.length);
|
|
8120
|
+
if (tooltips.length === 0)
|
|
8121
|
+
return null;
|
|
8122
|
+
return {
|
|
8123
|
+
pos: Math.min(...tooltips.map(t => t.pos)),
|
|
8124
|
+
end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
|
|
8125
|
+
create: HoverTooltipHost.create,
|
|
8126
|
+
above: tooltips[0].above,
|
|
8127
|
+
arrow: tooltips.some(t => t.arrow),
|
|
8128
|
+
};
|
|
8129
|
+
});
|
|
8130
|
+
class HoverPlugin {
|
|
8131
|
+
constructor(view, source, field, setHover, hoverTime) {
|
|
8132
|
+
this.view = view;
|
|
8133
|
+
this.source = source;
|
|
8134
|
+
this.field = field;
|
|
8135
|
+
this.setHover = setHover;
|
|
8136
|
+
this.hoverTime = hoverTime;
|
|
8137
|
+
this.hoverTimeout = -1;
|
|
8138
|
+
this.restartTimeout = -1;
|
|
8139
|
+
this.pending = null;
|
|
8140
|
+
this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
|
|
8141
|
+
this.checkHover = this.checkHover.bind(this);
|
|
8142
|
+
view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
|
|
8143
|
+
view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
|
|
8144
|
+
}
|
|
8145
|
+
update() {
|
|
8146
|
+
if (this.pending) {
|
|
8147
|
+
this.pending = null;
|
|
8148
|
+
clearTimeout(this.restartTimeout);
|
|
8149
|
+
this.restartTimeout = setTimeout(() => this.startHover(), 20);
|
|
8150
|
+
}
|
|
8151
|
+
}
|
|
8152
|
+
get active() {
|
|
8153
|
+
return this.view.state.field(this.field);
|
|
8154
|
+
}
|
|
8155
|
+
checkHover() {
|
|
8156
|
+
this.hoverTimeout = -1;
|
|
8157
|
+
if (this.active)
|
|
8158
|
+
return;
|
|
8159
|
+
let hovered = Date.now() - this.lastMove.time;
|
|
8160
|
+
if (hovered < this.hoverTime)
|
|
8161
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
|
|
8162
|
+
else
|
|
8163
|
+
this.startHover();
|
|
8164
|
+
}
|
|
8165
|
+
startHover() {
|
|
8166
|
+
var _a;
|
|
8167
|
+
clearTimeout(this.restartTimeout);
|
|
8168
|
+
let { lastMove } = this;
|
|
8169
|
+
let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
|
|
8170
|
+
if (pos == null)
|
|
8171
|
+
return;
|
|
8172
|
+
let posCoords = this.view.coordsAtPos(pos);
|
|
8173
|
+
if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
|
|
8174
|
+
lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
|
|
8175
|
+
lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
|
|
8176
|
+
return;
|
|
8177
|
+
let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
|
|
8178
|
+
let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
|
|
8179
|
+
let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
|
|
8180
|
+
if ((_a = open) === null || _a === void 0 ? void 0 : _a.then) {
|
|
8181
|
+
let pending = this.pending = { pos };
|
|
8182
|
+
open.then(result => {
|
|
8183
|
+
if (this.pending == pending) {
|
|
8184
|
+
this.pending = null;
|
|
8185
|
+
if (result)
|
|
8186
|
+
this.view.dispatch({ effects: this.setHover.of(result) });
|
|
8187
|
+
}
|
|
8188
|
+
}, e => logException(this.view.state, e, "hover tooltip"));
|
|
8189
|
+
}
|
|
8190
|
+
else if (open) {
|
|
8191
|
+
this.view.dispatch({ effects: this.setHover.of(open) });
|
|
8192
|
+
}
|
|
8193
|
+
}
|
|
8194
|
+
mousemove(event) {
|
|
8195
|
+
var _a;
|
|
8196
|
+
this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
|
|
8197
|
+
if (this.hoverTimeout < 0)
|
|
8198
|
+
this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
|
|
8199
|
+
let tooltip = this.active;
|
|
8200
|
+
if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
|
8201
|
+
let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
|
8202
|
+
if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
|
8203
|
+
: !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 /* MaxDist */))) {
|
|
8204
|
+
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
8205
|
+
this.pending = null;
|
|
8206
|
+
}
|
|
8207
|
+
}
|
|
8208
|
+
}
|
|
8209
|
+
mouseleave() {
|
|
8210
|
+
clearTimeout(this.hoverTimeout);
|
|
8211
|
+
this.hoverTimeout = -1;
|
|
8212
|
+
if (this.active)
|
|
8213
|
+
this.view.dispatch({ effects: this.setHover.of(null) });
|
|
8214
|
+
}
|
|
8215
|
+
destroy() {
|
|
8216
|
+
clearTimeout(this.hoverTimeout);
|
|
8217
|
+
this.view.dom.removeEventListener("mouseleave", this.mouseleave);
|
|
8218
|
+
this.view.dom.removeEventListener("mousemove", this.mousemove);
|
|
8219
|
+
}
|
|
8220
|
+
}
|
|
8221
|
+
function isInTooltip(elt) {
|
|
8222
|
+
for (let cur = elt; cur; cur = cur.parentNode)
|
|
8223
|
+
if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
|
|
8224
|
+
return true;
|
|
8225
|
+
return false;
|
|
8226
|
+
}
|
|
8227
|
+
function isOverRange(view, from, to, x, y, margin) {
|
|
8228
|
+
let range = document.createRange();
|
|
8229
|
+
let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
|
|
8230
|
+
range.setEnd(toDOM.node, toDOM.offset);
|
|
8231
|
+
range.setStart(fromDOM.node, fromDOM.offset);
|
|
8232
|
+
let rects = range.getClientRects();
|
|
8233
|
+
range.detach();
|
|
8234
|
+
for (let i = 0; i < rects.length; i++) {
|
|
8235
|
+
let rect = rects[i];
|
|
8236
|
+
let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
|
8237
|
+
if (dist <= margin)
|
|
8238
|
+
return true;
|
|
8239
|
+
}
|
|
8240
|
+
return false;
|
|
8241
|
+
}
|
|
8242
|
+
/**
|
|
8243
|
+
Set up a hover tooltip, which shows up when the pointer hovers
|
|
8244
|
+
over ranges of text. The callback is called when the mouse hovers
|
|
8245
|
+
over the document text. It should, if there is a tooltip
|
|
8246
|
+
associated with position `pos`, return the tooltip description
|
|
8247
|
+
(either directly or in a promise). The `side` argument indicates
|
|
8248
|
+
on which side of the position the pointer is—it will be -1 if the
|
|
8249
|
+
pointer is before the position, 1 if after the position.
|
|
8250
|
+
|
|
8251
|
+
Note that all hover tooltips are hosted within a single tooltip
|
|
8252
|
+
container element. This allows multiple tooltips over the same
|
|
8253
|
+
range to be "merged" together without overlapping.
|
|
8254
|
+
*/
|
|
8255
|
+
function hoverTooltip(source, options = {}) {
|
|
8256
|
+
let setHover = StateEffect.define();
|
|
8257
|
+
let hoverState = StateField.define({
|
|
8258
|
+
create() { return null; },
|
|
8259
|
+
update(value, tr) {
|
|
8260
|
+
console.log("update tooltip", !!value);
|
|
8261
|
+
if (value && (options.hideOnChange && (tr.docChanged || tr.selection)))
|
|
8262
|
+
return null;
|
|
8263
|
+
if (value && tr.docChanged) {
|
|
8264
|
+
let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel);
|
|
8265
|
+
if (newPos == null)
|
|
8266
|
+
return null;
|
|
8267
|
+
let copy = Object.assign(Object.create(null), value);
|
|
8268
|
+
copy.pos = newPos;
|
|
8269
|
+
if (value.end != null)
|
|
8270
|
+
copy.end = tr.changes.mapPos(value.end);
|
|
8271
|
+
value = copy;
|
|
8272
|
+
}
|
|
8273
|
+
for (let effect of tr.effects) {
|
|
8274
|
+
if (effect.is(setHover))
|
|
8275
|
+
value = effect.value;
|
|
8276
|
+
if (effect.is(closeHoverTooltipEffect))
|
|
8277
|
+
value = (console.log("CLOSE"), null);
|
|
8278
|
+
}
|
|
8279
|
+
console.log("updated: " + !!value);
|
|
8280
|
+
return value;
|
|
8281
|
+
},
|
|
8282
|
+
provide: f => showHoverTooltip.from(f)
|
|
8283
|
+
});
|
|
8284
|
+
return [
|
|
8285
|
+
hoverState,
|
|
8286
|
+
ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 /* Time */)),
|
|
8287
|
+
showHoverTooltipHost
|
|
8288
|
+
];
|
|
8289
|
+
}
|
|
8290
|
+
/**
|
|
8291
|
+
Get the active tooltip view for a given tooltip, if available.
|
|
8292
|
+
*/
|
|
8293
|
+
function getTooltip(view, tooltip) {
|
|
8294
|
+
let plugin = view.plugin(tooltipPlugin);
|
|
8295
|
+
if (!plugin)
|
|
8296
|
+
return null;
|
|
8297
|
+
let found = plugin.manager.tooltips.indexOf(tooltip);
|
|
8298
|
+
return found < 0 ? null : plugin.manager.tooltipViews[found];
|
|
8299
|
+
}
|
|
8300
|
+
/**
|
|
8301
|
+
Returns true if any hover tooltips are currently active.
|
|
8302
|
+
*/
|
|
8303
|
+
function hasHoverTooltips(state) {
|
|
8304
|
+
return state.facet(showHoverTooltip).some(x => x);
|
|
8305
|
+
}
|
|
8306
|
+
const closeHoverTooltipEffect = /*@__PURE__*/StateEffect.define();
|
|
8307
|
+
/**
|
|
8308
|
+
Transaction effect that closes all hover tooltips.
|
|
8309
|
+
*/
|
|
8310
|
+
const closeHoverTooltips = /*@__PURE__*/closeHoverTooltipEffect.of(null);
|
|
8311
|
+
/**
|
|
8312
|
+
Tell the tooltip extension to recompute the position of the active
|
|
8313
|
+
tooltips. This can be useful when something happens (such as a
|
|
8314
|
+
re-positioning or CSS change affecting the editor) that could
|
|
8315
|
+
invalidate the existing tooltip positions.
|
|
8316
|
+
*/
|
|
8317
|
+
function repositionTooltips(view) {
|
|
8318
|
+
var _a;
|
|
8319
|
+
(_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
|
|
8320
|
+
}
|
|
8321
|
+
|
|
8322
|
+
const panelConfig = /*@__PURE__*/Facet.define({
|
|
8323
|
+
combine(configs) {
|
|
8324
|
+
let topContainer, bottomContainer;
|
|
8325
|
+
for (let c of configs) {
|
|
8326
|
+
topContainer = topContainer || c.topContainer;
|
|
8327
|
+
bottomContainer = bottomContainer || c.bottomContainer;
|
|
8328
|
+
}
|
|
8329
|
+
return { topContainer, bottomContainer };
|
|
8330
|
+
}
|
|
8331
|
+
});
|
|
8332
|
+
/**
|
|
8333
|
+
Configures the panel-managing extension.
|
|
8334
|
+
*/
|
|
8335
|
+
function panels(config) {
|
|
8336
|
+
return config ? [panelConfig.of(config)] : [];
|
|
8337
|
+
}
|
|
8338
|
+
/**
|
|
8339
|
+
Get the active panel created by the given constructor, if any.
|
|
8340
|
+
This can be useful when you need access to your panels' DOM
|
|
8341
|
+
structure.
|
|
8342
|
+
*/
|
|
8343
|
+
function getPanel(view, panel) {
|
|
8344
|
+
let plugin = view.plugin(panelPlugin);
|
|
8345
|
+
let index = plugin ? plugin.specs.indexOf(panel) : -1;
|
|
8346
|
+
return index > -1 ? plugin.panels[index] : null;
|
|
8347
|
+
}
|
|
8348
|
+
const panelPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
8349
|
+
constructor(view) {
|
|
8350
|
+
this.input = view.state.facet(showPanel);
|
|
8351
|
+
this.specs = this.input.filter(s => s);
|
|
8352
|
+
this.panels = this.specs.map(spec => spec(view));
|
|
8353
|
+
let conf = view.state.facet(panelConfig);
|
|
8354
|
+
this.top = new PanelGroup(view, true, conf.topContainer);
|
|
8355
|
+
this.bottom = new PanelGroup(view, false, conf.bottomContainer);
|
|
8356
|
+
this.top.sync(this.panels.filter(p => p.top));
|
|
8357
|
+
this.bottom.sync(this.panels.filter(p => !p.top));
|
|
8358
|
+
for (let p of this.panels) {
|
|
8359
|
+
p.dom.classList.add("cm-panel");
|
|
8360
|
+
if (p.mount)
|
|
8361
|
+
p.mount();
|
|
8362
|
+
}
|
|
8363
|
+
}
|
|
8364
|
+
update(update) {
|
|
8365
|
+
let conf = update.state.facet(panelConfig);
|
|
8366
|
+
if (this.top.container != conf.topContainer) {
|
|
8367
|
+
this.top.sync([]);
|
|
8368
|
+
this.top = new PanelGroup(update.view, true, conf.topContainer);
|
|
8369
|
+
}
|
|
8370
|
+
if (this.bottom.container != conf.bottomContainer) {
|
|
8371
|
+
this.bottom.sync([]);
|
|
8372
|
+
this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
|
|
8373
|
+
}
|
|
8374
|
+
this.top.syncClasses();
|
|
8375
|
+
this.bottom.syncClasses();
|
|
8376
|
+
let input = update.state.facet(showPanel);
|
|
8377
|
+
if (input != this.input) {
|
|
8378
|
+
let specs = input.filter(x => x);
|
|
8379
|
+
let panels = [], top = [], bottom = [], mount = [];
|
|
8380
|
+
for (let spec of specs) {
|
|
8381
|
+
let known = this.specs.indexOf(spec), panel;
|
|
8382
|
+
if (known < 0) {
|
|
8383
|
+
panel = spec(update.view);
|
|
8384
|
+
mount.push(panel);
|
|
8385
|
+
}
|
|
8386
|
+
else {
|
|
8387
|
+
panel = this.panels[known];
|
|
8388
|
+
if (panel.update)
|
|
8389
|
+
panel.update(update);
|
|
8390
|
+
}
|
|
8391
|
+
panels.push(panel);
|
|
8392
|
+
(panel.top ? top : bottom).push(panel);
|
|
8393
|
+
}
|
|
8394
|
+
this.specs = specs;
|
|
8395
|
+
this.panels = panels;
|
|
8396
|
+
this.top.sync(top);
|
|
8397
|
+
this.bottom.sync(bottom);
|
|
8398
|
+
for (let p of mount) {
|
|
8399
|
+
p.dom.classList.add("cm-panel");
|
|
8400
|
+
if (p.mount)
|
|
8401
|
+
p.mount();
|
|
8402
|
+
}
|
|
8403
|
+
}
|
|
8404
|
+
else {
|
|
8405
|
+
for (let p of this.panels)
|
|
8406
|
+
if (p.update)
|
|
8407
|
+
p.update(update);
|
|
8408
|
+
}
|
|
8409
|
+
}
|
|
8410
|
+
destroy() {
|
|
8411
|
+
this.top.sync([]);
|
|
8412
|
+
this.bottom.sync([]);
|
|
8413
|
+
}
|
|
8414
|
+
}, {
|
|
8415
|
+
provide: plugin => EditorView.scrollMargins.of(view => {
|
|
8416
|
+
let value = view.plugin(plugin);
|
|
8417
|
+
return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
|
|
8418
|
+
})
|
|
8419
|
+
});
|
|
8420
|
+
class PanelGroup {
|
|
8421
|
+
constructor(view, top, container) {
|
|
8422
|
+
this.view = view;
|
|
8423
|
+
this.top = top;
|
|
8424
|
+
this.container = container;
|
|
8425
|
+
this.dom = undefined;
|
|
8426
|
+
this.classes = "";
|
|
8427
|
+
this.panels = [];
|
|
8428
|
+
this.syncClasses();
|
|
8429
|
+
}
|
|
8430
|
+
sync(panels) {
|
|
8431
|
+
for (let p of this.panels)
|
|
8432
|
+
if (p.destroy && panels.indexOf(p) < 0)
|
|
8433
|
+
p.destroy();
|
|
8434
|
+
this.panels = panels;
|
|
8435
|
+
this.syncDOM();
|
|
8436
|
+
}
|
|
8437
|
+
syncDOM() {
|
|
8438
|
+
if (this.panels.length == 0) {
|
|
8439
|
+
if (this.dom) {
|
|
8440
|
+
this.dom.remove();
|
|
8441
|
+
this.dom = undefined;
|
|
8442
|
+
}
|
|
8443
|
+
return;
|
|
8444
|
+
}
|
|
8445
|
+
if (!this.dom) {
|
|
8446
|
+
this.dom = document.createElement("div");
|
|
8447
|
+
this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
|
|
8448
|
+
this.dom.style[this.top ? "top" : "bottom"] = "0";
|
|
8449
|
+
let parent = this.container || this.view.dom;
|
|
8450
|
+
parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
|
|
8451
|
+
}
|
|
8452
|
+
let curDOM = this.dom.firstChild;
|
|
8453
|
+
for (let panel of this.panels) {
|
|
8454
|
+
if (panel.dom.parentNode == this.dom) {
|
|
8455
|
+
while (curDOM != panel.dom)
|
|
8456
|
+
curDOM = rm(curDOM);
|
|
8457
|
+
curDOM = curDOM.nextSibling;
|
|
8458
|
+
}
|
|
8459
|
+
else {
|
|
8460
|
+
this.dom.insertBefore(panel.dom, curDOM);
|
|
8461
|
+
}
|
|
8462
|
+
}
|
|
8463
|
+
while (curDOM)
|
|
8464
|
+
curDOM = rm(curDOM);
|
|
8465
|
+
}
|
|
8466
|
+
scrollMargin() {
|
|
8467
|
+
return !this.dom || this.container ? 0
|
|
8468
|
+
: Math.max(0, this.top ?
|
|
8469
|
+
this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
|
|
8470
|
+
Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
|
|
8471
|
+
}
|
|
8472
|
+
syncClasses() {
|
|
8473
|
+
if (!this.container || this.classes == this.view.themeClasses)
|
|
8474
|
+
return;
|
|
8475
|
+
for (let cls of this.classes.split(" "))
|
|
8476
|
+
if (cls)
|
|
8477
|
+
this.container.classList.remove(cls);
|
|
8478
|
+
for (let cls of (this.classes = this.view.themeClasses).split(" "))
|
|
8479
|
+
if (cls)
|
|
8480
|
+
this.container.classList.add(cls);
|
|
8481
|
+
}
|
|
8482
|
+
}
|
|
8483
|
+
function rm(node) {
|
|
8484
|
+
let next = node.nextSibling;
|
|
8485
|
+
node.remove();
|
|
8486
|
+
return next;
|
|
8487
|
+
}
|
|
8488
|
+
/**
|
|
8489
|
+
Opening a panel is done by providing a constructor function for
|
|
8490
|
+
the panel through this facet. (The panel is closed again when its
|
|
8491
|
+
constructor is no longer provided.) Values of `null` are ignored.
|
|
8492
|
+
*/
|
|
8493
|
+
const showPanel = /*@__PURE__*/Facet.define({
|
|
8494
|
+
enables: panelPlugin
|
|
8495
|
+
});
|
|
8496
|
+
|
|
8497
|
+
/**
|
|
8498
|
+
A gutter marker represents a bit of information attached to a line
|
|
8499
|
+
in a specific gutter. Your own custom markers have to extend this
|
|
8500
|
+
class.
|
|
8501
|
+
*/
|
|
8502
|
+
class GutterMarker extends RangeValue {
|
|
8503
|
+
/**
|
|
8504
|
+
@internal
|
|
8505
|
+
*/
|
|
8506
|
+
compare(other) {
|
|
8507
|
+
return this == other || this.constructor == other.constructor && this.eq(other);
|
|
8508
|
+
}
|
|
8509
|
+
/**
|
|
8510
|
+
Compare this marker to another marker of the same type.
|
|
8511
|
+
*/
|
|
8512
|
+
eq(other) { return false; }
|
|
8513
|
+
/**
|
|
8514
|
+
Called if the marker has a `toDOM` method and its representation
|
|
8515
|
+
was removed from a gutter.
|
|
8516
|
+
*/
|
|
8517
|
+
destroy(dom) { }
|
|
8518
|
+
}
|
|
8519
|
+
GutterMarker.prototype.elementClass = "";
|
|
8520
|
+
GutterMarker.prototype.toDOM = undefined;
|
|
8521
|
+
GutterMarker.prototype.mapMode = MapMode.TrackBefore;
|
|
8522
|
+
GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
|
|
8523
|
+
GutterMarker.prototype.point = true;
|
|
8524
|
+
/**
|
|
8525
|
+
Facet used to add a class to all gutter elements for a given line.
|
|
8526
|
+
Markers given to this facet should _only_ define an
|
|
8527
|
+
[`elementclass`](https://codemirror.net/6/docs/ref/#view.GutterMarker.elementClass), not a
|
|
8528
|
+
[`toDOM`](https://codemirror.net/6/docs/ref/#view.GutterMarker.toDOM) (or the marker will appear
|
|
8529
|
+
in all gutters for the line).
|
|
8530
|
+
*/
|
|
8531
|
+
const gutterLineClass = /*@__PURE__*/Facet.define();
|
|
8532
|
+
const defaults = {
|
|
8533
|
+
class: "",
|
|
8534
|
+
renderEmptyElements: false,
|
|
8535
|
+
elementStyle: "",
|
|
8536
|
+
markers: () => RangeSet.empty,
|
|
8537
|
+
lineMarker: () => null,
|
|
8538
|
+
lineMarkerChange: null,
|
|
8539
|
+
initialSpacer: null,
|
|
8540
|
+
updateSpacer: null,
|
|
8541
|
+
domEventHandlers: {}
|
|
8542
|
+
};
|
|
8543
|
+
const activeGutters = /*@__PURE__*/Facet.define();
|
|
8544
|
+
/**
|
|
8545
|
+
Define an editor gutter. The order in which the gutters appear is
|
|
8546
|
+
determined by their extension priority.
|
|
8547
|
+
*/
|
|
8548
|
+
function gutter(config) {
|
|
8549
|
+
return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
|
|
8550
|
+
}
|
|
8551
|
+
const unfixGutters = /*@__PURE__*/Facet.define({
|
|
8552
|
+
combine: values => values.some(x => x)
|
|
8553
|
+
});
|
|
8554
|
+
/**
|
|
8555
|
+
The gutter-drawing plugin is automatically enabled when you add a
|
|
8556
|
+
gutter, but you can use this function to explicitly configure it.
|
|
8557
|
+
|
|
8558
|
+
Unless `fixed` is explicitly set to `false`, the gutters are
|
|
8559
|
+
fixed, meaning they don't scroll along with the content
|
|
8560
|
+
horizontally (except on Internet Explorer, which doesn't support
|
|
8561
|
+
CSS [`position:
|
|
8562
|
+
sticky`](https://developer.mozilla.org/en-US/docs/Web/CSS/position#sticky)).
|
|
8563
|
+
*/
|
|
8564
|
+
function gutters(config) {
|
|
8565
|
+
let result = [
|
|
8566
|
+
gutterView,
|
|
8567
|
+
];
|
|
8568
|
+
if (config && config.fixed === false)
|
|
8569
|
+
result.push(unfixGutters.of(true));
|
|
8570
|
+
return result;
|
|
8571
|
+
}
|
|
8572
|
+
const gutterView = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
8573
|
+
constructor(view) {
|
|
8574
|
+
this.view = view;
|
|
8575
|
+
this.prevViewport = view.viewport;
|
|
8576
|
+
this.dom = document.createElement("div");
|
|
8577
|
+
this.dom.className = "cm-gutters";
|
|
8578
|
+
this.dom.setAttribute("aria-hidden", "true");
|
|
8579
|
+
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
8580
|
+
this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
|
|
8581
|
+
for (let gutter of this.gutters)
|
|
8582
|
+
this.dom.appendChild(gutter.dom);
|
|
8583
|
+
this.fixed = !view.state.facet(unfixGutters);
|
|
8584
|
+
if (this.fixed) {
|
|
8585
|
+
// FIXME IE11 fallback, which doesn't support position: sticky,
|
|
8586
|
+
// by using position: relative + event handlers that realign the
|
|
8587
|
+
// gutter (or just force fixed=false on IE11?)
|
|
8588
|
+
this.dom.style.position = "sticky";
|
|
8589
|
+
}
|
|
8590
|
+
this.syncGutters(false);
|
|
8591
|
+
view.scrollDOM.insertBefore(this.dom, view.contentDOM);
|
|
8592
|
+
}
|
|
8593
|
+
update(update) {
|
|
8594
|
+
if (this.updateGutters(update)) {
|
|
8595
|
+
// Detach during sync when the viewport changed significantly
|
|
8596
|
+
// (such as during scrolling), since for large updates that is
|
|
8597
|
+
// faster.
|
|
8598
|
+
let vpA = this.prevViewport, vpB = update.view.viewport;
|
|
8599
|
+
let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
|
|
8600
|
+
this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
|
|
8601
|
+
}
|
|
8602
|
+
if (update.geometryChanged)
|
|
8603
|
+
this.dom.style.minHeight = this.view.contentHeight + "px";
|
|
8604
|
+
if (this.view.state.facet(unfixGutters) != !this.fixed) {
|
|
8605
|
+
this.fixed = !this.fixed;
|
|
8606
|
+
this.dom.style.position = this.fixed ? "sticky" : "";
|
|
8607
|
+
}
|
|
8608
|
+
this.prevViewport = update.view.viewport;
|
|
8609
|
+
}
|
|
8610
|
+
syncGutters(detach) {
|
|
8611
|
+
let after = this.dom.nextSibling;
|
|
8612
|
+
if (detach)
|
|
8613
|
+
this.dom.remove();
|
|
8614
|
+
let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
|
|
8615
|
+
let classSet = [];
|
|
8616
|
+
let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
|
|
8617
|
+
for (let line of this.view.viewportLineBlocks) {
|
|
8618
|
+
let text;
|
|
8619
|
+
if (Array.isArray(line.type)) {
|
|
8620
|
+
for (let b of line.type)
|
|
8621
|
+
if (b.type == BlockType.Text) {
|
|
8622
|
+
text = b;
|
|
8623
|
+
break;
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
else {
|
|
8627
|
+
text = line.type == BlockType.Text ? line : undefined;
|
|
8628
|
+
}
|
|
8629
|
+
if (!text)
|
|
8630
|
+
continue;
|
|
8631
|
+
if (classSet.length)
|
|
8632
|
+
classSet = [];
|
|
8633
|
+
advanceCursor(lineClasses, classSet, line.from);
|
|
8634
|
+
for (let cx of contexts)
|
|
8635
|
+
cx.line(this.view, text, classSet);
|
|
8636
|
+
}
|
|
8637
|
+
for (let cx of contexts)
|
|
8638
|
+
cx.finish();
|
|
8639
|
+
if (detach)
|
|
8640
|
+
this.view.scrollDOM.insertBefore(this.dom, after);
|
|
8641
|
+
}
|
|
8642
|
+
updateGutters(update) {
|
|
8643
|
+
let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
|
|
8644
|
+
let change = update.docChanged || update.heightChanged || update.viewportChanged ||
|
|
8645
|
+
!RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
|
|
8646
|
+
if (prev == cur) {
|
|
8647
|
+
for (let gutter of this.gutters)
|
|
8648
|
+
if (gutter.update(update))
|
|
8649
|
+
change = true;
|
|
8650
|
+
}
|
|
8651
|
+
else {
|
|
8652
|
+
change = true;
|
|
8653
|
+
let gutters = [];
|
|
8654
|
+
for (let conf of cur) {
|
|
8655
|
+
let known = prev.indexOf(conf);
|
|
8656
|
+
if (known < 0) {
|
|
8657
|
+
gutters.push(new SingleGutterView(this.view, conf));
|
|
8658
|
+
}
|
|
8659
|
+
else {
|
|
8660
|
+
this.gutters[known].update(update);
|
|
8661
|
+
gutters.push(this.gutters[known]);
|
|
8662
|
+
}
|
|
8663
|
+
}
|
|
8664
|
+
for (let g of this.gutters) {
|
|
8665
|
+
g.dom.remove();
|
|
8666
|
+
if (gutters.indexOf(g) < 0)
|
|
8667
|
+
g.destroy();
|
|
8668
|
+
}
|
|
8669
|
+
for (let g of gutters)
|
|
8670
|
+
this.dom.appendChild(g.dom);
|
|
8671
|
+
this.gutters = gutters;
|
|
8672
|
+
}
|
|
8673
|
+
return change;
|
|
8674
|
+
}
|
|
8675
|
+
destroy() {
|
|
8676
|
+
for (let view of this.gutters)
|
|
8677
|
+
view.destroy();
|
|
8678
|
+
this.dom.remove();
|
|
8679
|
+
}
|
|
8680
|
+
}, {
|
|
8681
|
+
provide: plugin => EditorView.scrollMargins.of(view => {
|
|
8682
|
+
let value = view.plugin(plugin);
|
|
8683
|
+
if (!value || value.gutters.length == 0 || !value.fixed)
|
|
8684
|
+
return null;
|
|
8685
|
+
return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
|
|
8686
|
+
})
|
|
8687
|
+
});
|
|
8688
|
+
function asArray(val) { return (Array.isArray(val) ? val : [val]); }
|
|
8689
|
+
function advanceCursor(cursor, collect, pos) {
|
|
8690
|
+
while (cursor.value && cursor.from <= pos) {
|
|
8691
|
+
if (cursor.from == pos)
|
|
8692
|
+
collect.push(cursor.value);
|
|
8693
|
+
cursor.next();
|
|
8694
|
+
}
|
|
8695
|
+
}
|
|
8696
|
+
class UpdateContext {
|
|
8697
|
+
constructor(gutter, viewport, height) {
|
|
8698
|
+
this.gutter = gutter;
|
|
8699
|
+
this.height = height;
|
|
8700
|
+
this.localMarkers = [];
|
|
8701
|
+
this.i = 0;
|
|
8702
|
+
this.cursor = RangeSet.iter(gutter.markers, viewport.from);
|
|
8703
|
+
}
|
|
8704
|
+
line(view, line, extraMarkers) {
|
|
8705
|
+
if (this.localMarkers.length)
|
|
8706
|
+
this.localMarkers = [];
|
|
8707
|
+
advanceCursor(this.cursor, this.localMarkers, line.from);
|
|
8708
|
+
let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
|
|
8709
|
+
let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
|
|
8710
|
+
if (forLine)
|
|
8711
|
+
localMarkers.unshift(forLine);
|
|
8712
|
+
let gutter = this.gutter;
|
|
8713
|
+
if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
|
|
8714
|
+
return;
|
|
8715
|
+
let above = line.top - this.height;
|
|
8716
|
+
if (this.i == gutter.elements.length) {
|
|
8717
|
+
let newElt = new GutterElement(view, line.height, above, localMarkers);
|
|
8718
|
+
gutter.elements.push(newElt);
|
|
8719
|
+
gutter.dom.appendChild(newElt.dom);
|
|
8720
|
+
}
|
|
8721
|
+
else {
|
|
8722
|
+
gutter.elements[this.i].update(view, line.height, above, localMarkers);
|
|
8723
|
+
}
|
|
8724
|
+
this.height = line.bottom;
|
|
8725
|
+
this.i++;
|
|
8726
|
+
}
|
|
8727
|
+
finish() {
|
|
8728
|
+
let gutter = this.gutter;
|
|
8729
|
+
while (gutter.elements.length > this.i) {
|
|
8730
|
+
let last = gutter.elements.pop();
|
|
8731
|
+
gutter.dom.removeChild(last.dom);
|
|
8732
|
+
last.destroy();
|
|
8733
|
+
}
|
|
8734
|
+
}
|
|
8735
|
+
}
|
|
8736
|
+
class SingleGutterView {
|
|
8737
|
+
constructor(view, config) {
|
|
8738
|
+
this.view = view;
|
|
8739
|
+
this.config = config;
|
|
8740
|
+
this.elements = [];
|
|
8741
|
+
this.spacer = null;
|
|
8742
|
+
this.dom = document.createElement("div");
|
|
8743
|
+
this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
|
|
8744
|
+
for (let prop in config.domEventHandlers) {
|
|
8745
|
+
this.dom.addEventListener(prop, (event) => {
|
|
8746
|
+
let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
|
|
8747
|
+
if (config.domEventHandlers[prop](view, line, event))
|
|
8748
|
+
event.preventDefault();
|
|
8749
|
+
});
|
|
8750
|
+
}
|
|
8751
|
+
this.markers = asArray(config.markers(view));
|
|
8752
|
+
if (config.initialSpacer) {
|
|
8753
|
+
this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
|
|
8754
|
+
this.dom.appendChild(this.spacer.dom);
|
|
8755
|
+
this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
|
|
8756
|
+
}
|
|
8757
|
+
}
|
|
8758
|
+
update(update) {
|
|
8759
|
+
let prevMarkers = this.markers;
|
|
8760
|
+
this.markers = asArray(this.config.markers(update.view));
|
|
8761
|
+
if (this.spacer && this.config.updateSpacer) {
|
|
8762
|
+
let updated = this.config.updateSpacer(this.spacer.markers[0], update);
|
|
8763
|
+
if (updated != this.spacer.markers[0])
|
|
8764
|
+
this.spacer.update(update.view, 0, 0, [updated]);
|
|
8765
|
+
}
|
|
8766
|
+
let vp = update.view.viewport;
|
|
8767
|
+
return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
|
|
8768
|
+
(this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
|
|
8769
|
+
}
|
|
8770
|
+
destroy() {
|
|
8771
|
+
for (let elt of this.elements)
|
|
8772
|
+
elt.destroy();
|
|
8773
|
+
}
|
|
8774
|
+
}
|
|
8775
|
+
class GutterElement {
|
|
8776
|
+
constructor(view, height, above, markers) {
|
|
8777
|
+
this.height = -1;
|
|
8778
|
+
this.above = 0;
|
|
8779
|
+
this.markers = [];
|
|
8780
|
+
this.dom = document.createElement("div");
|
|
8781
|
+
this.update(view, height, above, markers);
|
|
8782
|
+
}
|
|
8783
|
+
update(view, height, above, markers) {
|
|
8784
|
+
if (this.height != height)
|
|
8785
|
+
this.dom.style.height = (this.height = height) + "px";
|
|
8786
|
+
if (this.above != above)
|
|
8787
|
+
this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
|
|
8788
|
+
if (!sameMarkers(this.markers, markers))
|
|
8789
|
+
this.setMarkers(view, markers);
|
|
8790
|
+
}
|
|
8791
|
+
setMarkers(view, markers) {
|
|
8792
|
+
let cls = "cm-gutterElement", domPos = this.dom.firstChild;
|
|
8793
|
+
for (let iNew = 0, iOld = 0;;) {
|
|
8794
|
+
let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
|
|
8795
|
+
if (marker) {
|
|
8796
|
+
let c = marker.elementClass;
|
|
8797
|
+
if (c)
|
|
8798
|
+
cls += " " + c;
|
|
8799
|
+
for (let i = iOld; i < this.markers.length; i++)
|
|
8800
|
+
if (this.markers[i].compare(marker)) {
|
|
8801
|
+
skipTo = i;
|
|
8802
|
+
matched = true;
|
|
8803
|
+
break;
|
|
8804
|
+
}
|
|
8805
|
+
}
|
|
8806
|
+
else {
|
|
8807
|
+
skipTo = this.markers.length;
|
|
8808
|
+
}
|
|
8809
|
+
while (iOld < skipTo) {
|
|
8810
|
+
let next = this.markers[iOld++];
|
|
8811
|
+
if (next.toDOM) {
|
|
8812
|
+
next.destroy(domPos);
|
|
8813
|
+
let after = domPos.nextSibling;
|
|
8814
|
+
domPos.remove();
|
|
8815
|
+
domPos = after;
|
|
8816
|
+
}
|
|
8817
|
+
}
|
|
8818
|
+
if (!marker)
|
|
8819
|
+
break;
|
|
8820
|
+
if (marker.toDOM) {
|
|
8821
|
+
if (matched)
|
|
8822
|
+
domPos = domPos.nextSibling;
|
|
8823
|
+
else
|
|
8824
|
+
this.dom.insertBefore(marker.toDOM(view), domPos);
|
|
8825
|
+
}
|
|
8826
|
+
if (matched)
|
|
8827
|
+
iOld++;
|
|
8828
|
+
}
|
|
8829
|
+
this.dom.className = cls;
|
|
8830
|
+
this.markers = markers;
|
|
8831
|
+
}
|
|
8832
|
+
destroy() {
|
|
8833
|
+
this.setMarkers(null, []); // First argument not used unless creating markers
|
|
8834
|
+
}
|
|
8835
|
+
}
|
|
8836
|
+
function sameMarkers(a, b) {
|
|
8837
|
+
if (a.length != b.length)
|
|
8838
|
+
return false;
|
|
8839
|
+
for (let i = 0; i < a.length; i++)
|
|
8840
|
+
if (!a[i].compare(b[i]))
|
|
8841
|
+
return false;
|
|
8842
|
+
return true;
|
|
8843
|
+
}
|
|
8844
|
+
/**
|
|
8845
|
+
Facet used to provide markers to the line number gutter.
|
|
8846
|
+
*/
|
|
8847
|
+
const lineNumberMarkers = /*@__PURE__*/Facet.define();
|
|
8848
|
+
const lineNumberConfig = /*@__PURE__*/Facet.define({
|
|
8849
|
+
combine(values) {
|
|
8850
|
+
return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
|
|
8851
|
+
domEventHandlers(a, b) {
|
|
8852
|
+
let result = Object.assign({}, a);
|
|
8853
|
+
for (let event in b) {
|
|
8854
|
+
let exists = result[event], add = b[event];
|
|
8855
|
+
result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
|
|
8856
|
+
}
|
|
8857
|
+
return result;
|
|
8858
|
+
}
|
|
8859
|
+
});
|
|
8860
|
+
}
|
|
8861
|
+
});
|
|
8862
|
+
class NumberMarker extends GutterMarker {
|
|
8863
|
+
constructor(number) {
|
|
8864
|
+
super();
|
|
8865
|
+
this.number = number;
|
|
8866
|
+
}
|
|
8867
|
+
eq(other) { return this.number == other.number; }
|
|
8868
|
+
toDOM() { return document.createTextNode(this.number); }
|
|
8869
|
+
}
|
|
8870
|
+
function formatNumber(view, number) {
|
|
8871
|
+
return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
|
|
8872
|
+
}
|
|
8873
|
+
const lineNumberGutter = /*@__PURE__*/activeGutters.compute([lineNumberConfig], state => ({
|
|
8874
|
+
class: "cm-lineNumbers",
|
|
8875
|
+
renderEmptyElements: false,
|
|
8876
|
+
markers(view) { return view.state.facet(lineNumberMarkers); },
|
|
8877
|
+
lineMarker(view, line, others) {
|
|
8878
|
+
if (others.some(m => m.toDOM))
|
|
8879
|
+
return null;
|
|
8880
|
+
return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
|
|
8881
|
+
},
|
|
8882
|
+
lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
|
|
8883
|
+
initialSpacer(view) {
|
|
8884
|
+
return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
|
|
8885
|
+
},
|
|
8886
|
+
updateSpacer(spacer, update) {
|
|
8887
|
+
let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
|
|
8888
|
+
return max == spacer.number ? spacer : new NumberMarker(max);
|
|
8889
|
+
},
|
|
8890
|
+
domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
|
|
8891
|
+
}));
|
|
8892
|
+
/**
|
|
8893
|
+
Create a line number gutter extension.
|
|
8894
|
+
*/
|
|
8895
|
+
function lineNumbers(config = {}) {
|
|
8896
|
+
return [
|
|
8897
|
+
lineNumberConfig.of(config),
|
|
8898
|
+
gutters(),
|
|
8899
|
+
lineNumberGutter
|
|
8900
|
+
];
|
|
8901
|
+
}
|
|
8902
|
+
function maxLineNumber(lines) {
|
|
8903
|
+
let last = 9;
|
|
8904
|
+
while (last < lines)
|
|
8905
|
+
last = last * 10 + 9;
|
|
8906
|
+
return last;
|
|
8907
|
+
}
|
|
8908
|
+
const activeLineGutterMarker = /*@__PURE__*/new class extends GutterMarker {
|
|
8909
|
+
constructor() {
|
|
8910
|
+
super(...arguments);
|
|
8911
|
+
this.elementClass = "cm-activeLineGutter";
|
|
8912
|
+
}
|
|
8913
|
+
};
|
|
8914
|
+
const activeLineGutterHighlighter = /*@__PURE__*/gutterLineClass.compute(["selection"], state => {
|
|
8915
|
+
let marks = [], last = -1;
|
|
8916
|
+
for (let range of state.selection.ranges)
|
|
8917
|
+
if (range.empty) {
|
|
8918
|
+
let linePos = state.doc.lineAt(range.head).from;
|
|
8919
|
+
if (linePos > last) {
|
|
8920
|
+
last = linePos;
|
|
8921
|
+
marks.push(activeLineGutterMarker.range(linePos));
|
|
8922
|
+
}
|
|
8923
|
+
}
|
|
8924
|
+
return RangeSet.of(marks);
|
|
8925
|
+
});
|
|
8926
|
+
/**
|
|
8927
|
+
Returns an extension that adds a `cm-activeLineGutter` class to
|
|
8928
|
+
all gutter elements on the [active
|
|
8929
|
+
line](https://codemirror.net/6/docs/ref/#view.highlightActiveLine).
|
|
8930
|
+
*/
|
|
8931
|
+
function highlightActiveLineGutter() {
|
|
8932
|
+
return activeLineGutterHighlighter;
|
|
8933
|
+
}
|
|
8934
|
+
|
|
7710
8935
|
/**
|
|
7711
8936
|
@internal
|
|
7712
8937
|
*/
|
|
7713
8938
|
const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
|
|
7714
8939
|
|
|
7715
|
-
export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView,
|
|
8940
|
+
export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, GutterMarker, MatchDecorator, ViewPlugin, ViewUpdate, WidgetType, __test, closeHoverTooltips, crosshairCursor, drawSelection, dropCursor, getPanel, getTooltip, gutter, gutterLineClass, gutters, hasHoverTooltips, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, hoverTooltip, keymap, lineNumberMarkers, lineNumbers, logException, panels, placeholder, rectangularSelection, repositionTooltips, runScopeHandlers, scrollPastEnd, showPanel, showTooltip, tooltips };
|