@codemirror/view 6.18.1 → 6.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 +30 -0
- package/dist/index.cjs +524 -482
- package/dist/index.d.cts +22 -1
- package/dist/index.d.ts +22 -1
- package/dist/index.js +524 -483
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -581,7 +581,7 @@ function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart,
|
|
|
581
581
|
if (toI < children.length) {
|
|
582
582
|
let after = children[toI];
|
|
583
583
|
// Make sure the end of the child after the update is preserved in `after`
|
|
584
|
-
if (after && toOff < after.length) {
|
|
584
|
+
if (after && (toOff < after.length || after.breakAfter && (last === null || last === void 0 ? void 0 : last.breakAfter))) {
|
|
585
585
|
// If we're splitting a child, separate part of it to avoid that
|
|
586
586
|
// being mangled when updating the child before the update.
|
|
587
587
|
if (fromI == toI) {
|
|
@@ -1093,6 +1093,236 @@ function getAttrs(dom) {
|
|
|
1093
1093
|
return attrs;
|
|
1094
1094
|
}
|
|
1095
1095
|
|
|
1096
|
+
class LineView extends ContentView {
|
|
1097
|
+
constructor() {
|
|
1098
|
+
super(...arguments);
|
|
1099
|
+
this.children = [];
|
|
1100
|
+
this.length = 0;
|
|
1101
|
+
this.prevAttrs = undefined;
|
|
1102
|
+
this.attrs = null;
|
|
1103
|
+
this.breakAfter = 0;
|
|
1104
|
+
}
|
|
1105
|
+
// Consumes source
|
|
1106
|
+
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
1107
|
+
if (source) {
|
|
1108
|
+
if (!(source instanceof LineView))
|
|
1109
|
+
return false;
|
|
1110
|
+
if (!this.dom)
|
|
1111
|
+
source.transferDOM(this); // Reuse source.dom when appropriate
|
|
1112
|
+
}
|
|
1113
|
+
if (hasStart)
|
|
1114
|
+
this.setDeco(source ? source.attrs : null);
|
|
1115
|
+
mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
|
|
1116
|
+
return true;
|
|
1117
|
+
}
|
|
1118
|
+
split(at) {
|
|
1119
|
+
let end = new LineView;
|
|
1120
|
+
end.breakAfter = this.breakAfter;
|
|
1121
|
+
if (this.length == 0)
|
|
1122
|
+
return end;
|
|
1123
|
+
let { i, off } = this.childPos(at);
|
|
1124
|
+
if (off) {
|
|
1125
|
+
end.append(this.children[i].split(off), 0);
|
|
1126
|
+
this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
|
|
1127
|
+
i++;
|
|
1128
|
+
}
|
|
1129
|
+
for (let j = i; j < this.children.length; j++)
|
|
1130
|
+
end.append(this.children[j], 0);
|
|
1131
|
+
while (i > 0 && this.children[i - 1].length == 0)
|
|
1132
|
+
this.children[--i].destroy();
|
|
1133
|
+
this.children.length = i;
|
|
1134
|
+
this.markDirty();
|
|
1135
|
+
this.length = at;
|
|
1136
|
+
return end;
|
|
1137
|
+
}
|
|
1138
|
+
transferDOM(other) {
|
|
1139
|
+
if (!this.dom)
|
|
1140
|
+
return;
|
|
1141
|
+
this.markDirty();
|
|
1142
|
+
other.setDOM(this.dom);
|
|
1143
|
+
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1144
|
+
this.prevAttrs = undefined;
|
|
1145
|
+
this.dom = null;
|
|
1146
|
+
}
|
|
1147
|
+
setDeco(attrs) {
|
|
1148
|
+
if (!attrsEq(this.attrs, attrs)) {
|
|
1149
|
+
if (this.dom) {
|
|
1150
|
+
this.prevAttrs = this.attrs;
|
|
1151
|
+
this.markDirty();
|
|
1152
|
+
}
|
|
1153
|
+
this.attrs = attrs;
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
append(child, openStart) {
|
|
1157
|
+
joinInlineInto(this, child, openStart);
|
|
1158
|
+
}
|
|
1159
|
+
// Only called when building a line view in ContentBuilder
|
|
1160
|
+
addLineDeco(deco) {
|
|
1161
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1162
|
+
if (attrs)
|
|
1163
|
+
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1164
|
+
if (cls)
|
|
1165
|
+
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1166
|
+
}
|
|
1167
|
+
domAtPos(pos) {
|
|
1168
|
+
return inlineDOMAtPos(this, pos);
|
|
1169
|
+
}
|
|
1170
|
+
reuseDOM(node) {
|
|
1171
|
+
if (node.nodeName == "DIV") {
|
|
1172
|
+
this.setDOM(node);
|
|
1173
|
+
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
sync(view, track) {
|
|
1177
|
+
var _a;
|
|
1178
|
+
if (!this.dom) {
|
|
1179
|
+
this.setDOM(document.createElement("div"));
|
|
1180
|
+
this.dom.className = "cm-line";
|
|
1181
|
+
this.prevAttrs = this.attrs ? null : undefined;
|
|
1182
|
+
}
|
|
1183
|
+
else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
|
|
1184
|
+
clearAttributes(this.dom);
|
|
1185
|
+
this.dom.className = "cm-line";
|
|
1186
|
+
this.prevAttrs = this.attrs ? null : undefined;
|
|
1187
|
+
}
|
|
1188
|
+
if (this.prevAttrs !== undefined) {
|
|
1189
|
+
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1190
|
+
this.dom.classList.add("cm-line");
|
|
1191
|
+
this.prevAttrs = undefined;
|
|
1192
|
+
}
|
|
1193
|
+
super.sync(view, track);
|
|
1194
|
+
let last = this.dom.lastChild;
|
|
1195
|
+
while (last && ContentView.get(last) instanceof MarkView)
|
|
1196
|
+
last = last.lastChild;
|
|
1197
|
+
if (!last || !this.length ||
|
|
1198
|
+
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1199
|
+
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1200
|
+
let hack = document.createElement("BR");
|
|
1201
|
+
hack.cmIgnore = true;
|
|
1202
|
+
this.dom.appendChild(hack);
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
measureTextSize() {
|
|
1206
|
+
if (this.children.length == 0 || this.length > 20)
|
|
1207
|
+
return null;
|
|
1208
|
+
let totalWidth = 0, textHeight;
|
|
1209
|
+
for (let child of this.children) {
|
|
1210
|
+
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1211
|
+
return null;
|
|
1212
|
+
let rects = clientRectsFor(child.dom);
|
|
1213
|
+
if (rects.length != 1)
|
|
1214
|
+
return null;
|
|
1215
|
+
totalWidth += rects[0].width;
|
|
1216
|
+
textHeight = rects[0].height;
|
|
1217
|
+
}
|
|
1218
|
+
return !totalWidth ? null : {
|
|
1219
|
+
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1220
|
+
charWidth: totalWidth / this.length,
|
|
1221
|
+
textHeight
|
|
1222
|
+
};
|
|
1223
|
+
}
|
|
1224
|
+
coordsAt(pos, side) {
|
|
1225
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1226
|
+
// Correct rectangle height for empty lines when the returned
|
|
1227
|
+
// height is larger than the text height.
|
|
1228
|
+
if (!this.children.length && rect && this.parent) {
|
|
1229
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1230
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1231
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1232
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
return rect;
|
|
1236
|
+
}
|
|
1237
|
+
become(_other) { return false; }
|
|
1238
|
+
covers() { return true; }
|
|
1239
|
+
static find(docView, pos) {
|
|
1240
|
+
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1241
|
+
let block = docView.children[i], end = off + block.length;
|
|
1242
|
+
if (end >= pos) {
|
|
1243
|
+
if (block instanceof LineView)
|
|
1244
|
+
return block;
|
|
1245
|
+
if (end > pos)
|
|
1246
|
+
break;
|
|
1247
|
+
}
|
|
1248
|
+
off = end + block.breakAfter;
|
|
1249
|
+
}
|
|
1250
|
+
return null;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
class BlockWidgetView extends ContentView {
|
|
1254
|
+
constructor(widget, length, deco) {
|
|
1255
|
+
super();
|
|
1256
|
+
this.widget = widget;
|
|
1257
|
+
this.length = length;
|
|
1258
|
+
this.deco = deco;
|
|
1259
|
+
this.breakAfter = 0;
|
|
1260
|
+
this.prevWidget = null;
|
|
1261
|
+
}
|
|
1262
|
+
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1263
|
+
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
1264
|
+
from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
|
|
1265
|
+
return false;
|
|
1266
|
+
this.length = from + (source ? source.length : 0) + (this.length - to);
|
|
1267
|
+
return true;
|
|
1268
|
+
}
|
|
1269
|
+
domAtPos(pos) {
|
|
1270
|
+
return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
|
|
1271
|
+
}
|
|
1272
|
+
split(at) {
|
|
1273
|
+
let len = this.length - at;
|
|
1274
|
+
this.length = at;
|
|
1275
|
+
let end = new BlockWidgetView(this.widget, len, this.deco);
|
|
1276
|
+
end.breakAfter = this.breakAfter;
|
|
1277
|
+
return end;
|
|
1278
|
+
}
|
|
1279
|
+
get children() { return noChildren; }
|
|
1280
|
+
sync(view) {
|
|
1281
|
+
if (!this.dom || !this.widget.updateDOM(this.dom, view)) {
|
|
1282
|
+
if (this.dom && this.prevWidget)
|
|
1283
|
+
this.prevWidget.destroy(this.dom);
|
|
1284
|
+
this.prevWidget = null;
|
|
1285
|
+
this.setDOM(this.widget.toDOM(view));
|
|
1286
|
+
this.dom.contentEditable = "false";
|
|
1287
|
+
}
|
|
1288
|
+
}
|
|
1289
|
+
get overrideDOMText() {
|
|
1290
|
+
return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : state.Text.empty;
|
|
1291
|
+
}
|
|
1292
|
+
domBoundsAround() { return null; }
|
|
1293
|
+
become(other) {
|
|
1294
|
+
if (other instanceof BlockWidgetView &&
|
|
1295
|
+
other.widget.constructor == this.widget.constructor) {
|
|
1296
|
+
if (!other.widget.compare(this.widget))
|
|
1297
|
+
this.markDirty(true);
|
|
1298
|
+
if (this.dom && !this.prevWidget)
|
|
1299
|
+
this.prevWidget = this.widget;
|
|
1300
|
+
this.widget = other.widget;
|
|
1301
|
+
this.length = other.length;
|
|
1302
|
+
this.deco = other.deco;
|
|
1303
|
+
this.breakAfter = other.breakAfter;
|
|
1304
|
+
return true;
|
|
1305
|
+
}
|
|
1306
|
+
return false;
|
|
1307
|
+
}
|
|
1308
|
+
ignoreMutation() { return true; }
|
|
1309
|
+
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
1310
|
+
get isEditable() { return false; }
|
|
1311
|
+
get isWidget() { return true; }
|
|
1312
|
+
coordsAt(pos, side) {
|
|
1313
|
+
return this.widget.coordsAt(this.dom, pos, side);
|
|
1314
|
+
}
|
|
1315
|
+
destroy() {
|
|
1316
|
+
super.destroy();
|
|
1317
|
+
if (this.dom)
|
|
1318
|
+
this.widget.destroy(this.dom);
|
|
1319
|
+
}
|
|
1320
|
+
covers(side) {
|
|
1321
|
+
let { startSide, endSide } = this.deco;
|
|
1322
|
+
return startSide == endSide ? false : side < 0 ? startSide < 0 : endSide > 0;
|
|
1323
|
+
}
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1096
1326
|
/**
|
|
1097
1327
|
Widgets added to the content are described by subclasses of this
|
|
1098
1328
|
class. Using a description object like that makes it possible to
|
|
@@ -1259,346 +1489,120 @@ class Decoration extends state.RangeValue {
|
|
|
1259
1489
|
startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
|
|
1260
1490
|
endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1;
|
|
1261
1491
|
}
|
|
1262
|
-
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1263
|
-
}
|
|
1264
|
-
/**
|
|
1265
|
-
Create a line decoration, which can add DOM attributes to the
|
|
1266
|
-
line starting at the given position.
|
|
1267
|
-
*/
|
|
1268
|
-
static line(spec) {
|
|
1269
|
-
return new LineDecoration(spec);
|
|
1270
|
-
}
|
|
1271
|
-
/**
|
|
1272
|
-
Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
|
|
1273
|
-
decorated range or ranges. If the ranges aren't already sorted,
|
|
1274
|
-
pass `true` for `sort` to make the library sort them for you.
|
|
1275
|
-
*/
|
|
1276
|
-
static set(of, sort = false) {
|
|
1277
|
-
return state.RangeSet.of(of, sort);
|
|
1278
|
-
}
|
|
1279
|
-
/**
|
|
1280
|
-
@internal
|
|
1281
|
-
*/
|
|
1282
|
-
hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; }
|
|
1283
|
-
}
|
|
1284
|
-
/**
|
|
1285
|
-
The empty set of decorations.
|
|
1286
|
-
*/
|
|
1287
|
-
Decoration.none = state.RangeSet.empty;
|
|
1288
|
-
class MarkDecoration extends Decoration {
|
|
1289
|
-
constructor(spec) {
|
|
1290
|
-
let { start, end } = getInclusive(spec);
|
|
1291
|
-
super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
|
|
1292
|
-
this.tagName = spec.tagName || "span";
|
|
1293
|
-
this.class = spec.class || "";
|
|
1294
|
-
this.attrs = spec.attributes || null;
|
|
1295
|
-
}
|
|
1296
|
-
eq(other) {
|
|
1297
|
-
var _a, _b;
|
|
1298
|
-
return this == other ||
|
|
1299
|
-
other instanceof MarkDecoration &&
|
|
1300
|
-
this.tagName == other.tagName &&
|
|
1301
|
-
(this.class || ((_a = this.attrs) === null || _a === void 0 ? void 0 : _a.class)) == (other.class || ((_b = other.attrs) === null || _b === void 0 ? void 0 : _b.class)) &&
|
|
1302
|
-
attrsEq(this.attrs, other.attrs, "class");
|
|
1303
|
-
}
|
|
1304
|
-
range(from, to = from) {
|
|
1305
|
-
if (from >= to)
|
|
1306
|
-
throw new RangeError("Mark decorations may not be empty");
|
|
1307
|
-
return super.range(from, to);
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
MarkDecoration.prototype.point = false;
|
|
1311
|
-
class LineDecoration extends Decoration {
|
|
1312
|
-
constructor(spec) {
|
|
1313
|
-
super(-200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec);
|
|
1314
|
-
}
|
|
1315
|
-
eq(other) {
|
|
1316
|
-
return other instanceof LineDecoration &&
|
|
1317
|
-
this.spec.class == other.spec.class &&
|
|
1318
|
-
attrsEq(this.spec.attributes, other.spec.attributes);
|
|
1319
|
-
}
|
|
1320
|
-
range(from, to = from) {
|
|
1321
|
-
if (to != from)
|
|
1322
|
-
throw new RangeError("Line decoration ranges must be zero-length");
|
|
1323
|
-
return super.range(from, to);
|
|
1324
|
-
}
|
|
1325
|
-
}
|
|
1326
|
-
LineDecoration.prototype.mapMode = state.MapMode.TrackBefore;
|
|
1327
|
-
LineDecoration.prototype.point = true;
|
|
1328
|
-
class PointDecoration extends Decoration {
|
|
1329
|
-
constructor(spec, startSide, endSide, block, widget, isReplace) {
|
|
1330
|
-
super(startSide, endSide, widget, spec);
|
|
1331
|
-
this.block = block;
|
|
1332
|
-
this.isReplace = isReplace;
|
|
1333
|
-
this.mapMode = !block ? state.MapMode.TrackDel : startSide <= 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter;
|
|
1334
|
-
}
|
|
1335
|
-
// Only relevant when this.block == true
|
|
1336
|
-
get type() {
|
|
1337
|
-
return this.startSide < this.endSide ? exports.BlockType.WidgetRange
|
|
1338
|
-
: this.startSide <= 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter;
|
|
1339
|
-
}
|
|
1340
|
-
get heightRelevant() {
|
|
1341
|
-
return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
|
|
1342
|
-
}
|
|
1343
|
-
eq(other) {
|
|
1344
|
-
return other instanceof PointDecoration &&
|
|
1345
|
-
widgetsEq(this.widget, other.widget) &&
|
|
1346
|
-
this.block == other.block &&
|
|
1347
|
-
this.startSide == other.startSide && this.endSide == other.endSide;
|
|
1348
|
-
}
|
|
1349
|
-
range(from, to = from) {
|
|
1350
|
-
if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
|
|
1351
|
-
throw new RangeError("Invalid range for replacement decoration");
|
|
1352
|
-
if (!this.isReplace && to != from)
|
|
1353
|
-
throw new RangeError("Widget decorations can only have zero-length ranges");
|
|
1354
|
-
return super.range(from, to);
|
|
1355
|
-
}
|
|
1356
|
-
}
|
|
1357
|
-
PointDecoration.prototype.point = true;
|
|
1358
|
-
function getInclusive(spec, block = false) {
|
|
1359
|
-
let { inclusiveStart: start, inclusiveEnd: end } = spec;
|
|
1360
|
-
if (start == null)
|
|
1361
|
-
start = spec.inclusive;
|
|
1362
|
-
if (end == null)
|
|
1363
|
-
end = spec.inclusive;
|
|
1364
|
-
return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
|
|
1365
|
-
}
|
|
1366
|
-
function widgetsEq(a, b) {
|
|
1367
|
-
return a == b || !!(a && b && a.compare(b));
|
|
1368
|
-
}
|
|
1369
|
-
function addRange(from, to, ranges, margin = 0) {
|
|
1370
|
-
let last = ranges.length - 1;
|
|
1371
|
-
if (last >= 0 && ranges[last] + margin >= from)
|
|
1372
|
-
ranges[last] = Math.max(ranges[last], to);
|
|
1373
|
-
else
|
|
1374
|
-
ranges.push(from, to);
|
|
1375
|
-
}
|
|
1376
|
-
|
|
1377
|
-
class LineView extends ContentView {
|
|
1378
|
-
constructor() {
|
|
1379
|
-
super(...arguments);
|
|
1380
|
-
this.children = [];
|
|
1381
|
-
this.length = 0;
|
|
1382
|
-
this.prevAttrs = undefined;
|
|
1383
|
-
this.attrs = null;
|
|
1384
|
-
this.breakAfter = 0;
|
|
1385
|
-
}
|
|
1386
|
-
// Consumes source
|
|
1387
|
-
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
1388
|
-
if (source) {
|
|
1389
|
-
if (!(source instanceof LineView))
|
|
1390
|
-
return false;
|
|
1391
|
-
if (!this.dom)
|
|
1392
|
-
source.transferDOM(this); // Reuse source.dom when appropriate
|
|
1393
|
-
}
|
|
1394
|
-
if (hasStart)
|
|
1395
|
-
this.setDeco(source ? source.attrs : null);
|
|
1396
|
-
mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
|
|
1397
|
-
return true;
|
|
1398
|
-
}
|
|
1399
|
-
split(at) {
|
|
1400
|
-
let end = new LineView;
|
|
1401
|
-
end.breakAfter = this.breakAfter;
|
|
1402
|
-
if (this.length == 0)
|
|
1403
|
-
return end;
|
|
1404
|
-
let { i, off } = this.childPos(at);
|
|
1405
|
-
if (off) {
|
|
1406
|
-
end.append(this.children[i].split(off), 0);
|
|
1407
|
-
this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
|
|
1408
|
-
i++;
|
|
1409
|
-
}
|
|
1410
|
-
for (let j = i; j < this.children.length; j++)
|
|
1411
|
-
end.append(this.children[j], 0);
|
|
1412
|
-
while (i > 0 && this.children[i - 1].length == 0)
|
|
1413
|
-
this.children[--i].destroy();
|
|
1414
|
-
this.children.length = i;
|
|
1415
|
-
this.markDirty();
|
|
1416
|
-
this.length = at;
|
|
1417
|
-
return end;
|
|
1418
|
-
}
|
|
1419
|
-
transferDOM(other) {
|
|
1420
|
-
if (!this.dom)
|
|
1421
|
-
return;
|
|
1422
|
-
this.markDirty();
|
|
1423
|
-
other.setDOM(this.dom);
|
|
1424
|
-
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1425
|
-
this.prevAttrs = undefined;
|
|
1426
|
-
this.dom = null;
|
|
1427
|
-
}
|
|
1428
|
-
setDeco(attrs) {
|
|
1429
|
-
if (!attrsEq(this.attrs, attrs)) {
|
|
1430
|
-
if (this.dom) {
|
|
1431
|
-
this.prevAttrs = this.attrs;
|
|
1432
|
-
this.markDirty();
|
|
1433
|
-
}
|
|
1434
|
-
this.attrs = attrs;
|
|
1435
|
-
}
|
|
1436
|
-
}
|
|
1437
|
-
append(child, openStart) {
|
|
1438
|
-
joinInlineInto(this, child, openStart);
|
|
1439
|
-
}
|
|
1440
|
-
// Only called when building a line view in ContentBuilder
|
|
1441
|
-
addLineDeco(deco) {
|
|
1442
|
-
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1443
|
-
if (attrs)
|
|
1444
|
-
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1445
|
-
if (cls)
|
|
1446
|
-
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1447
|
-
}
|
|
1448
|
-
domAtPos(pos) {
|
|
1449
|
-
return inlineDOMAtPos(this, pos);
|
|
1450
|
-
}
|
|
1451
|
-
reuseDOM(node) {
|
|
1452
|
-
if (node.nodeName == "DIV") {
|
|
1453
|
-
this.setDOM(node);
|
|
1454
|
-
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
1455
|
-
}
|
|
1456
|
-
}
|
|
1457
|
-
sync(view, track) {
|
|
1458
|
-
var _a;
|
|
1459
|
-
if (!this.dom) {
|
|
1460
|
-
this.setDOM(document.createElement("div"));
|
|
1461
|
-
this.dom.className = "cm-line";
|
|
1462
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1463
|
-
}
|
|
1464
|
-
else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
|
|
1465
|
-
clearAttributes(this.dom);
|
|
1466
|
-
this.dom.className = "cm-line";
|
|
1467
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1468
|
-
}
|
|
1469
|
-
if (this.prevAttrs !== undefined) {
|
|
1470
|
-
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1471
|
-
this.dom.classList.add("cm-line");
|
|
1472
|
-
this.prevAttrs = undefined;
|
|
1473
|
-
}
|
|
1474
|
-
super.sync(view, track);
|
|
1475
|
-
let last = this.dom.lastChild;
|
|
1476
|
-
while (last && ContentView.get(last) instanceof MarkView)
|
|
1477
|
-
last = last.lastChild;
|
|
1478
|
-
if (!last || !this.length ||
|
|
1479
|
-
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1480
|
-
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1481
|
-
let hack = document.createElement("BR");
|
|
1482
|
-
hack.cmIgnore = true;
|
|
1483
|
-
this.dom.appendChild(hack);
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
measureTextSize() {
|
|
1487
|
-
if (this.children.length == 0 || this.length > 20)
|
|
1488
|
-
return null;
|
|
1489
|
-
let totalWidth = 0, textHeight;
|
|
1490
|
-
for (let child of this.children) {
|
|
1491
|
-
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1492
|
-
return null;
|
|
1493
|
-
let rects = clientRectsFor(child.dom);
|
|
1494
|
-
if (rects.length != 1)
|
|
1495
|
-
return null;
|
|
1496
|
-
totalWidth += rects[0].width;
|
|
1497
|
-
textHeight = rects[0].height;
|
|
1498
|
-
}
|
|
1499
|
-
return !totalWidth ? null : {
|
|
1500
|
-
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1501
|
-
charWidth: totalWidth / this.length,
|
|
1502
|
-
textHeight
|
|
1503
|
-
};
|
|
1504
|
-
}
|
|
1505
|
-
coordsAt(pos, side) {
|
|
1506
|
-
let rect = coordsInChildren(this, pos, side);
|
|
1507
|
-
// Correct rectangle height for empty lines when the returned
|
|
1508
|
-
// height is larger than the text height.
|
|
1509
|
-
if (!this.children.length && rect && this.parent) {
|
|
1510
|
-
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1511
|
-
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1512
|
-
let dist = (height - heightOracle.textHeight) / 2;
|
|
1513
|
-
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
return rect;
|
|
1492
|
+
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1517
1493
|
}
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
return
|
|
1494
|
+
/**
|
|
1495
|
+
Create a line decoration, which can add DOM attributes to the
|
|
1496
|
+
line starting at the given position.
|
|
1497
|
+
*/
|
|
1498
|
+
static line(spec) {
|
|
1499
|
+
return new LineDecoration(spec);
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
|
|
1503
|
+
decorated range or ranges. If the ranges aren't already sorted,
|
|
1504
|
+
pass `true` for `sort` to make the library sort them for you.
|
|
1505
|
+
*/
|
|
1506
|
+
static set(of, sort = false) {
|
|
1507
|
+
return state.RangeSet.of(of, sort);
|
|
1532
1508
|
}
|
|
1509
|
+
/**
|
|
1510
|
+
@internal
|
|
1511
|
+
*/
|
|
1512
|
+
hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; }
|
|
1533
1513
|
}
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1514
|
+
/**
|
|
1515
|
+
The empty set of decorations.
|
|
1516
|
+
*/
|
|
1517
|
+
Decoration.none = state.RangeSet.empty;
|
|
1518
|
+
class MarkDecoration extends Decoration {
|
|
1519
|
+
constructor(spec) {
|
|
1520
|
+
let { start, end } = getInclusive(spec);
|
|
1521
|
+
super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
|
|
1522
|
+
this.tagName = spec.tagName || "span";
|
|
1523
|
+
this.class = spec.class || "";
|
|
1524
|
+
this.attrs = spec.attributes || null;
|
|
1542
1525
|
}
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1526
|
+
eq(other) {
|
|
1527
|
+
var _a, _b;
|
|
1528
|
+
return this == other ||
|
|
1529
|
+
other instanceof MarkDecoration &&
|
|
1530
|
+
this.tagName == other.tagName &&
|
|
1531
|
+
(this.class || ((_a = this.attrs) === null || _a === void 0 ? void 0 : _a.class)) == (other.class || ((_b = other.attrs) === null || _b === void 0 ? void 0 : _b.class)) &&
|
|
1532
|
+
attrsEq(this.attrs, other.attrs, "class");
|
|
1549
1533
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1534
|
+
range(from, to = from) {
|
|
1535
|
+
if (from >= to)
|
|
1536
|
+
throw new RangeError("Mark decorations may not be empty");
|
|
1537
|
+
return super.range(from, to);
|
|
1552
1538
|
}
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
return end;
|
|
1539
|
+
}
|
|
1540
|
+
MarkDecoration.prototype.point = false;
|
|
1541
|
+
class LineDecoration extends Decoration {
|
|
1542
|
+
constructor(spec) {
|
|
1543
|
+
super(-200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec);
|
|
1559
1544
|
}
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
this.prevWidget.destroy(this.dom);
|
|
1565
|
-
this.prevWidget = null;
|
|
1566
|
-
this.setDOM(this.widget.toDOM(view));
|
|
1567
|
-
this.dom.contentEditable = "false";
|
|
1568
|
-
}
|
|
1545
|
+
eq(other) {
|
|
1546
|
+
return other instanceof LineDecoration &&
|
|
1547
|
+
this.spec.class == other.spec.class &&
|
|
1548
|
+
attrsEq(this.spec.attributes, other.spec.attributes);
|
|
1569
1549
|
}
|
|
1570
|
-
|
|
1571
|
-
|
|
1550
|
+
range(from, to = from) {
|
|
1551
|
+
if (to != from)
|
|
1552
|
+
throw new RangeError("Line decoration ranges must be zero-length");
|
|
1553
|
+
return super.range(from, to);
|
|
1572
1554
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
this.length = other.length;
|
|
1583
|
-
this.type = other.type;
|
|
1584
|
-
this.breakAfter = other.breakAfter;
|
|
1585
|
-
return true;
|
|
1586
|
-
}
|
|
1587
|
-
return false;
|
|
1555
|
+
}
|
|
1556
|
+
LineDecoration.prototype.mapMode = state.MapMode.TrackBefore;
|
|
1557
|
+
LineDecoration.prototype.point = true;
|
|
1558
|
+
class PointDecoration extends Decoration {
|
|
1559
|
+
constructor(spec, startSide, endSide, block, widget, isReplace) {
|
|
1560
|
+
super(startSide, endSide, widget, spec);
|
|
1561
|
+
this.block = block;
|
|
1562
|
+
this.isReplace = isReplace;
|
|
1563
|
+
this.mapMode = !block ? state.MapMode.TrackDel : startSide <= 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter;
|
|
1588
1564
|
}
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
coordsAt(pos, side) {
|
|
1594
|
-
return this.widget.coordsAt(this.dom, pos, side);
|
|
1565
|
+
// Only relevant when this.block == true
|
|
1566
|
+
get type() {
|
|
1567
|
+
return this.startSide != this.endSide ? exports.BlockType.WidgetRange
|
|
1568
|
+
: this.startSide <= 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter;
|
|
1595
1569
|
}
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1570
|
+
get heightRelevant() {
|
|
1571
|
+
return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
|
|
1572
|
+
}
|
|
1573
|
+
eq(other) {
|
|
1574
|
+
return other instanceof PointDecoration &&
|
|
1575
|
+
widgetsEq(this.widget, other.widget) &&
|
|
1576
|
+
this.block == other.block &&
|
|
1577
|
+
this.startSide == other.startSide && this.endSide == other.endSide;
|
|
1578
|
+
}
|
|
1579
|
+
range(from, to = from) {
|
|
1580
|
+
if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
|
|
1581
|
+
throw new RangeError("Invalid range for replacement decoration");
|
|
1582
|
+
if (!this.isReplace && to != from)
|
|
1583
|
+
throw new RangeError("Widget decorations can only have zero-length ranges");
|
|
1584
|
+
return super.range(from, to);
|
|
1600
1585
|
}
|
|
1601
1586
|
}
|
|
1587
|
+
PointDecoration.prototype.point = true;
|
|
1588
|
+
function getInclusive(spec, block = false) {
|
|
1589
|
+
let { inclusiveStart: start, inclusiveEnd: end } = spec;
|
|
1590
|
+
if (start == null)
|
|
1591
|
+
start = spec.inclusive;
|
|
1592
|
+
if (end == null)
|
|
1593
|
+
end = spec.inclusive;
|
|
1594
|
+
return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
|
|
1595
|
+
}
|
|
1596
|
+
function widgetsEq(a, b) {
|
|
1597
|
+
return a == b || !!(a && b && a.compare(b));
|
|
1598
|
+
}
|
|
1599
|
+
function addRange(from, to, ranges, margin = 0) {
|
|
1600
|
+
let last = ranges.length - 1;
|
|
1601
|
+
if (last >= 0 && ranges[last] + margin >= from)
|
|
1602
|
+
ranges[last] = Math.max(ranges[last], to);
|
|
1603
|
+
else
|
|
1604
|
+
ranges.push(from, to);
|
|
1605
|
+
}
|
|
1602
1606
|
|
|
1603
1607
|
class ContentBuilder {
|
|
1604
1608
|
constructor(doc, pos, end, disallowBlockEffectsFor) {
|
|
@@ -1624,7 +1628,7 @@ class ContentBuilder {
|
|
|
1624
1628
|
if (this.content.length == 0)
|
|
1625
1629
|
return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos;
|
|
1626
1630
|
let last = this.content[this.content.length - 1];
|
|
1627
|
-
return !last.breakAfter
|
|
1631
|
+
return !(last.breakAfter || last instanceof BlockWidgetView && last.deco.endSide < 0);
|
|
1628
1632
|
}
|
|
1629
1633
|
getLine() {
|
|
1630
1634
|
if (!this.curLine) {
|
|
@@ -1649,7 +1653,7 @@ class ContentBuilder {
|
|
|
1649
1653
|
this.flushBuffer();
|
|
1650
1654
|
else
|
|
1651
1655
|
this.pendingBuffer = 0 /* Buf.No */;
|
|
1652
|
-
if (!this.posCovered())
|
|
1656
|
+
if (!openEnd && !this.posCovered())
|
|
1653
1657
|
this.getLine();
|
|
1654
1658
|
}
|
|
1655
1659
|
buildText(length, active, openStart) {
|
|
@@ -1702,10 +1706,9 @@ class ContentBuilder {
|
|
|
1702
1706
|
let len = to - from;
|
|
1703
1707
|
if (deco instanceof PointDecoration) {
|
|
1704
1708
|
if (deco.block) {
|
|
1705
|
-
|
|
1706
|
-
if (type == exports.BlockType.WidgetAfter && !this.posCovered())
|
|
1709
|
+
if (deco.startSide > 0 && !this.posCovered())
|
|
1707
1710
|
this.getLine();
|
|
1708
|
-
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len,
|
|
1711
|
+
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, deco));
|
|
1709
1712
|
}
|
|
1710
1713
|
else {
|
|
1711
1714
|
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
@@ -1840,10 +1843,15 @@ class ViewPlugin {
|
|
|
1840
1843
|
/**
|
|
1841
1844
|
@internal
|
|
1842
1845
|
*/
|
|
1843
|
-
domEventHandlers,
|
|
1846
|
+
domEventHandlers,
|
|
1847
|
+
/**
|
|
1848
|
+
@internal
|
|
1849
|
+
*/
|
|
1850
|
+
domEventObservers, buildExtensions) {
|
|
1844
1851
|
this.id = id;
|
|
1845
1852
|
this.create = create;
|
|
1846
1853
|
this.domEventHandlers = domEventHandlers;
|
|
1854
|
+
this.domEventObservers = domEventObservers;
|
|
1847
1855
|
this.extension = buildExtensions(this);
|
|
1848
1856
|
}
|
|
1849
1857
|
/**
|
|
@@ -1851,8 +1859,8 @@ class ViewPlugin {
|
|
|
1851
1859
|
plugin's value, given an editor view.
|
|
1852
1860
|
*/
|
|
1853
1861
|
static define(create, spec) {
|
|
1854
|
-
const { eventHandlers, provide, decorations: deco } = spec || {};
|
|
1855
|
-
return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
|
|
1862
|
+
const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
|
|
1863
|
+
return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
|
|
1856
1864
|
let ext = [viewPlugin.of(plugin)];
|
|
1857
1865
|
if (deco)
|
|
1858
1866
|
ext.push(decorations.of(view => {
|
|
@@ -2938,15 +2946,19 @@ class DocView extends ContentView {
|
|
|
2938
2946
|
return this.children[i].domAtPos(off);
|
|
2939
2947
|
}
|
|
2940
2948
|
coordsAt(pos, side) {
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2949
|
+
let best = null, bestPos = 0;
|
|
2950
|
+
for (let off = this.length, i = this.children.length - 1; i >= 0; i--) {
|
|
2951
|
+
let child = this.children[i], end = off - child.breakAfter, start = end - child.length;
|
|
2952
|
+
if (end < pos)
|
|
2953
|
+
break;
|
|
2954
|
+
if (start <= pos && (start < pos || child.covers(-1)) && (end > pos || child.covers(1)) &&
|
|
2955
|
+
(!best || child instanceof LineView && !(best instanceof LineView && side >= 0))) {
|
|
2956
|
+
best = child;
|
|
2957
|
+
bestPos = start;
|
|
2958
|
+
}
|
|
2948
2959
|
off = start;
|
|
2949
2960
|
}
|
|
2961
|
+
return best ? best.coordsAt(pos - bestPos, side) : null;
|
|
2950
2962
|
}
|
|
2951
2963
|
coordsForChar(pos) {
|
|
2952
2964
|
let { i, off } = this.childPos(pos, 1), child = this.children[i];
|
|
@@ -3532,7 +3544,7 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3532
3544
|
return state.EditorSelection.cursor(startPos, start.assoc);
|
|
3533
3545
|
let goal = start.goalColumn, startY;
|
|
3534
3546
|
let rect = view.contentDOM.getBoundingClientRect();
|
|
3535
|
-
let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
|
|
3547
|
+
let startCoords = view.coordsAtPos(startPos, start.assoc || -1), docTop = view.documentTop;
|
|
3536
3548
|
if (startCoords) {
|
|
3537
3549
|
if (goal == null)
|
|
3538
3550
|
goal = startCoords.left - rect.left;
|
|
@@ -3549,8 +3561,11 @@ function moveVertically(view, start, forward, distance) {
|
|
|
3549
3561
|
for (let extra = 0;; extra += 10) {
|
|
3550
3562
|
let curY = startY + (dist + extra) * dir;
|
|
3551
3563
|
let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
|
3552
|
-
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
|
3553
|
-
|
|
3564
|
+
if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos)) {
|
|
3565
|
+
let charRect = view.docView.coordsForChar(pos);
|
|
3566
|
+
let assoc = !charRect || curY < charRect.top ? -1 : 1;
|
|
3567
|
+
return state.EditorSelection.cursor(pos, assoc, undefined, goal);
|
|
3568
|
+
}
|
|
3554
3569
|
}
|
|
3555
3570
|
}
|
|
3556
3571
|
function skipAtomicRanges(atoms, pos, bias) {
|
|
@@ -3581,13 +3596,13 @@ class InputState {
|
|
|
3581
3596
|
this.lastSelectionTime = Date.now();
|
|
3582
3597
|
}
|
|
3583
3598
|
constructor(view) {
|
|
3599
|
+
this.view = view;
|
|
3584
3600
|
this.lastKeyCode = 0;
|
|
3585
3601
|
this.lastKeyTime = 0;
|
|
3586
3602
|
this.lastTouchTime = 0;
|
|
3587
3603
|
this.lastFocusTime = 0;
|
|
3588
3604
|
this.lastScrollTop = 0;
|
|
3589
3605
|
this.lastScrollLeft = 0;
|
|
3590
|
-
this.chromeScrollHack = -1;
|
|
3591
3606
|
// On iOS, some keys need to have their default behavior happen
|
|
3592
3607
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3593
3608
|
// avoid messing up the virtual keyboard state.
|
|
@@ -3597,8 +3612,7 @@ class InputState {
|
|
|
3597
3612
|
this.lastEscPress = 0;
|
|
3598
3613
|
this.lastContextMenu = 0;
|
|
3599
3614
|
this.scrollHandlers = [];
|
|
3600
|
-
this.
|
|
3601
|
-
this.customHandlers = [];
|
|
3615
|
+
this.handlers = Object.create(null);
|
|
3602
3616
|
// -1 means not in a composition. Otherwise, this counts the number
|
|
3603
3617
|
// of changes made during the composition. The count is used to
|
|
3604
3618
|
// avoid treating the start state of the composition, before any
|
|
@@ -3619,29 +3633,10 @@ class InputState {
|
|
|
3619
3633
|
// the mutation events fire shortly after the compositionend event
|
|
3620
3634
|
this.compositionPendingChange = false;
|
|
3621
3635
|
this.mouseSelection = null;
|
|
3622
|
-
|
|
3623
|
-
if (this.ignoreDuringComposition(event))
|
|
3624
|
-
return;
|
|
3625
|
-
if (event.type == "keydown" && this.keydown(view, event))
|
|
3626
|
-
return;
|
|
3627
|
-
if (this.mustFlushObserver(event))
|
|
3628
|
-
view.observer.forceFlush();
|
|
3629
|
-
if (this.runCustomHandlers(event.type, view, event))
|
|
3630
|
-
event.preventDefault();
|
|
3631
|
-
else
|
|
3632
|
-
handler(view, event);
|
|
3633
|
-
};
|
|
3634
|
-
for (let type in handlers) {
|
|
3635
|
-
let handler = handlers[type];
|
|
3636
|
-
view.contentDOM.addEventListener(type, event => {
|
|
3637
|
-
if (eventBelongsToEditor(view, event))
|
|
3638
|
-
handleEvent(handler, event);
|
|
3639
|
-
}, handlerOptions[type]);
|
|
3640
|
-
this.registeredEvents.push(type);
|
|
3641
|
-
}
|
|
3636
|
+
this.handleEvent = this.handleEvent.bind(this);
|
|
3642
3637
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3643
3638
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3644
|
-
|
|
3639
|
+
this.runHandlers("mousedown", event);
|
|
3645
3640
|
if (!event.defaultPrevented && event.button == 2) {
|
|
3646
3641
|
// Make sure the content covers the entire scroller height, in order
|
|
3647
3642
|
// to catch a native context menu click below it
|
|
@@ -3653,23 +3648,8 @@ class InputState {
|
|
|
3653
3648
|
});
|
|
3654
3649
|
view.scrollDOM.addEventListener("drop", (event) => {
|
|
3655
3650
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3656
|
-
|
|
3651
|
+
this.runHandlers("drop", event);
|
|
3657
3652
|
});
|
|
3658
|
-
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3659
|
-
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
3660
|
-
// scrolling. Turning off pointer events during the scroll seems
|
|
3661
|
-
// to avoid the issue.
|
|
3662
|
-
view.scrollDOM.addEventListener("wheel", () => {
|
|
3663
|
-
if (this.chromeScrollHack < 0)
|
|
3664
|
-
view.contentDOM.style.pointerEvents = "none";
|
|
3665
|
-
else
|
|
3666
|
-
window.clearTimeout(this.chromeScrollHack);
|
|
3667
|
-
this.chromeScrollHack = setTimeout(() => {
|
|
3668
|
-
this.chromeScrollHack = -1;
|
|
3669
|
-
view.contentDOM.style.pointerEvents = "";
|
|
3670
|
-
}, 100);
|
|
3671
|
-
}, { passive: true });
|
|
3672
|
-
}
|
|
3673
3653
|
this.notifiedFocused = view.hasFocus;
|
|
3674
3654
|
// On Safari adding an input event handler somehow prevents an
|
|
3675
3655
|
// issue where the composition vanishes when you press enter.
|
|
@@ -3678,63 +3658,54 @@ class InputState {
|
|
|
3678
3658
|
if (browser.gecko)
|
|
3679
3659
|
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3680
3660
|
}
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
}
|
|
3700
|
-
runCustomHandlers(type, view, event) {
|
|
3701
|
-
for (let set of this.customHandlers) {
|
|
3702
|
-
let handler = set.handlers[type];
|
|
3703
|
-
if (handler) {
|
|
3704
|
-
try {
|
|
3705
|
-
if (handler.call(set.plugin, event, view) || event.defaultPrevented)
|
|
3706
|
-
return true;
|
|
3707
|
-
}
|
|
3708
|
-
catch (e) {
|
|
3709
|
-
logException(view.state, e);
|
|
3661
|
+
handleEvent(event) {
|
|
3662
|
+
if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event))
|
|
3663
|
+
return;
|
|
3664
|
+
if (event.type == "keydown" && this.keydown(event))
|
|
3665
|
+
return;
|
|
3666
|
+
this.runHandlers(event.type, event);
|
|
3667
|
+
}
|
|
3668
|
+
runHandlers(type, event) {
|
|
3669
|
+
let handlers = this.handlers[type];
|
|
3670
|
+
if (handlers) {
|
|
3671
|
+
for (let observer of handlers.observers)
|
|
3672
|
+
observer(this.view, event);
|
|
3673
|
+
for (let handler of handlers.handlers) {
|
|
3674
|
+
if (event.defaultPrevented)
|
|
3675
|
+
break;
|
|
3676
|
+
if (handler(this.view, event)) {
|
|
3677
|
+
event.preventDefault();
|
|
3678
|
+
break;
|
|
3710
3679
|
}
|
|
3711
3680
|
}
|
|
3712
3681
|
}
|
|
3713
|
-
return false;
|
|
3714
3682
|
}
|
|
3715
|
-
|
|
3716
|
-
this.
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
catch (e) {
|
|
3725
|
-
logException(view.state, e);
|
|
3683
|
+
ensureHandlers(plugins) {
|
|
3684
|
+
let handlers = computeHandlers(plugins), prev = this.handlers, dom = this.view.contentDOM;
|
|
3685
|
+
for (let type in handlers)
|
|
3686
|
+
if (type != "scroll") {
|
|
3687
|
+
let passive = !handlers[type].handlers.length;
|
|
3688
|
+
let exists = prev[type];
|
|
3689
|
+
if (exists && passive != !exists.handlers.length) {
|
|
3690
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3691
|
+
exists = null;
|
|
3726
3692
|
}
|
|
3693
|
+
if (!exists)
|
|
3694
|
+
dom.addEventListener(type, this.handleEvent, { passive });
|
|
3727
3695
|
}
|
|
3728
|
-
|
|
3696
|
+
for (let type in prev)
|
|
3697
|
+
if (type != "scroll" && !handlers[type])
|
|
3698
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3699
|
+
this.handlers = handlers;
|
|
3729
3700
|
}
|
|
3730
|
-
keydown(
|
|
3701
|
+
keydown(event) {
|
|
3731
3702
|
// Must always run, even if a custom handler handled the event
|
|
3732
3703
|
this.lastKeyCode = event.keyCode;
|
|
3733
3704
|
this.lastKeyTime = Date.now();
|
|
3734
3705
|
if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
|
3735
3706
|
return true;
|
|
3736
3707
|
if (event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3737
|
-
view.inputState.lastEscPress = 0;
|
|
3708
|
+
this.view.inputState.lastEscPress = 0;
|
|
3738
3709
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3739
3710
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
3740
3711
|
// composition changes. When an enter or backspace key event is
|
|
@@ -3742,10 +3713,10 @@ class InputState {
|
|
|
3742
3713
|
// dispatch it.
|
|
3743
3714
|
if (browser.android && browser.chrome && !event.synthetic &&
|
|
3744
3715
|
(event.keyCode == 13 || event.keyCode == 8)) {
|
|
3745
|
-
view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3716
|
+
this.view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3746
3717
|
return true;
|
|
3747
3718
|
}
|
|
3748
|
-
//
|
|
3719
|
+
// Preventing the default behavior of Enter on iOS makes the
|
|
3749
3720
|
// virtual keyboard get stuck in the wrong (lowercase)
|
|
3750
3721
|
// state. So we let it go through, and then, in
|
|
3751
3722
|
// applyDOMChange, notify key handlers of it and reset to
|
|
@@ -3755,17 +3726,19 @@ class InputState {
|
|
|
3755
3726
|
((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
|
|
3756
3727
|
EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
|
|
3757
3728
|
this.pendingIOSKey = pending || event;
|
|
3758
|
-
setTimeout(() => this.flushIOSKey(
|
|
3729
|
+
setTimeout(() => this.flushIOSKey(), 250);
|
|
3759
3730
|
return true;
|
|
3760
3731
|
}
|
|
3732
|
+
if (event.keyCode != 229)
|
|
3733
|
+
this.view.observer.forceFlush();
|
|
3761
3734
|
return false;
|
|
3762
3735
|
}
|
|
3763
|
-
flushIOSKey(
|
|
3736
|
+
flushIOSKey() {
|
|
3764
3737
|
let key = this.pendingIOSKey;
|
|
3765
3738
|
if (!key)
|
|
3766
3739
|
return false;
|
|
3767
3740
|
this.pendingIOSKey = undefined;
|
|
3768
|
-
return dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3741
|
+
return dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
|
3769
3742
|
}
|
|
3770
3743
|
ignoreDuringComposition(event) {
|
|
3771
3744
|
if (!/^key/.test(event.type))
|
|
@@ -3784,9 +3757,6 @@ class InputState {
|
|
|
3784
3757
|
}
|
|
3785
3758
|
return false;
|
|
3786
3759
|
}
|
|
3787
|
-
mustFlushObserver(event) {
|
|
3788
|
-
return event.type == "keydown" && event.keyCode != 229;
|
|
3789
|
-
}
|
|
3790
3760
|
startMouseSelection(mouseSelection) {
|
|
3791
3761
|
if (this.mouseSelection)
|
|
3792
3762
|
this.mouseSelection.destroy();
|
|
@@ -3803,6 +3773,42 @@ class InputState {
|
|
|
3803
3773
|
this.mouseSelection.destroy();
|
|
3804
3774
|
}
|
|
3805
3775
|
}
|
|
3776
|
+
function bindHandler(plugin, handler) {
|
|
3777
|
+
return (view, event) => {
|
|
3778
|
+
try {
|
|
3779
|
+
return handler.call(plugin, event, view);
|
|
3780
|
+
}
|
|
3781
|
+
catch (e) {
|
|
3782
|
+
logException(view.state, e);
|
|
3783
|
+
}
|
|
3784
|
+
};
|
|
3785
|
+
}
|
|
3786
|
+
function computeHandlers(plugins) {
|
|
3787
|
+
let result = Object.create(null);
|
|
3788
|
+
function record(type) {
|
|
3789
|
+
return result[type] || (result[type] = { observers: [], handlers: [] });
|
|
3790
|
+
}
|
|
3791
|
+
for (let plugin of plugins) {
|
|
3792
|
+
let spec = plugin.spec;
|
|
3793
|
+
if (spec && spec.domEventHandlers)
|
|
3794
|
+
for (let type in spec.domEventHandlers) {
|
|
3795
|
+
let f = spec.domEventHandlers[type];
|
|
3796
|
+
if (f)
|
|
3797
|
+
record(type).handlers.push(bindHandler(plugin.value, f));
|
|
3798
|
+
}
|
|
3799
|
+
if (spec && spec.domEventObservers)
|
|
3800
|
+
for (let type in spec.domEventObservers) {
|
|
3801
|
+
let f = spec.domEventObservers[type];
|
|
3802
|
+
if (f)
|
|
3803
|
+
record(type).observers.push(bindHandler(plugin.value, f));
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
for (let type in handlers)
|
|
3807
|
+
record(type).handlers.push(handlers[type]);
|
|
3808
|
+
for (let type in observers)
|
|
3809
|
+
record(type).observers.push(observers[type]);
|
|
3810
|
+
return result;
|
|
3811
|
+
}
|
|
3806
3812
|
const PendingKeys = [
|
|
3807
3813
|
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3808
3814
|
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
@@ -3840,10 +3846,8 @@ class MouseSelection {
|
|
|
3840
3846
|
start(event) {
|
|
3841
3847
|
// When clicking outside of the selection, immediately apply the
|
|
3842
3848
|
// effect of starting the selection
|
|
3843
|
-
if (this.dragging === false)
|
|
3844
|
-
event.preventDefault();
|
|
3849
|
+
if (this.dragging === false)
|
|
3845
3850
|
this.select(event);
|
|
3846
|
-
}
|
|
3847
3851
|
}
|
|
3848
3852
|
move(event) {
|
|
3849
3853
|
var _a;
|
|
@@ -3979,7 +3983,7 @@ function eventBelongsToEditor(view, event) {
|
|
|
3979
3983
|
return true;
|
|
3980
3984
|
}
|
|
3981
3985
|
const handlers = Object.create(null);
|
|
3982
|
-
const
|
|
3986
|
+
const observers = Object.create(null);
|
|
3983
3987
|
// This is very crude, but unfortunately both these browsers _pretend_
|
|
3984
3988
|
// that they have a clipboard API—all the objects and methods are
|
|
3985
3989
|
// there, they just don't work, and they are hard to test.
|
|
@@ -4029,23 +4033,27 @@ function doPaste(view, input) {
|
|
|
4029
4033
|
scrollIntoView: true
|
|
4030
4034
|
});
|
|
4031
4035
|
}
|
|
4036
|
+
observers.scroll = view => {
|
|
4037
|
+
view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
|
|
4038
|
+
view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
4039
|
+
};
|
|
4032
4040
|
handlers.keydown = (view, event) => {
|
|
4033
4041
|
view.inputState.setSelectionOrigin("select");
|
|
4034
4042
|
if (event.keyCode == 27)
|
|
4035
4043
|
view.inputState.lastEscPress = Date.now();
|
|
4044
|
+
return false;
|
|
4036
4045
|
};
|
|
4037
|
-
|
|
4046
|
+
observers.touchstart = (view, e) => {
|
|
4038
4047
|
view.inputState.lastTouchTime = Date.now();
|
|
4039
4048
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4040
4049
|
};
|
|
4041
|
-
|
|
4050
|
+
observers.touchmove = view => {
|
|
4042
4051
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4043
4052
|
};
|
|
4044
|
-
handlerOptions.touchstart = handlerOptions.touchmove = { passive: true };
|
|
4045
4053
|
handlers.mousedown = (view, event) => {
|
|
4046
4054
|
view.observer.flush();
|
|
4047
4055
|
if (view.inputState.lastTouchTime > Date.now() - 2000)
|
|
4048
|
-
return; // Ignore touch interaction
|
|
4056
|
+
return false; // Ignore touch interaction
|
|
4049
4057
|
let style = null;
|
|
4050
4058
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
4051
4059
|
style = makeStyle(view, event);
|
|
@@ -4059,9 +4067,13 @@ handlers.mousedown = (view, event) => {
|
|
|
4059
4067
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4060
4068
|
if (mustFocus)
|
|
4061
4069
|
view.observer.ignore(() => focusPreventScroll(view.contentDOM));
|
|
4062
|
-
|
|
4063
|
-
|
|
4070
|
+
let mouseSel = view.inputState.mouseSelection;
|
|
4071
|
+
if (mouseSel) {
|
|
4072
|
+
mouseSel.start(event);
|
|
4073
|
+
return !mouseSel.dragging;
|
|
4074
|
+
}
|
|
4064
4075
|
}
|
|
4076
|
+
return false;
|
|
4065
4077
|
};
|
|
4066
4078
|
function rangeForClick(view, pos, bias, type) {
|
|
4067
4079
|
if (type == 1) { // Single click
|
|
@@ -4165,12 +4177,12 @@ handlers.dragstart = (view, event) => {
|
|
|
4165
4177
|
event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to));
|
|
4166
4178
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4167
4179
|
}
|
|
4180
|
+
return false;
|
|
4168
4181
|
};
|
|
4169
4182
|
function dropText(view, event, text, direct) {
|
|
4170
4183
|
if (!text)
|
|
4171
4184
|
return;
|
|
4172
4185
|
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
4173
|
-
event.preventDefault();
|
|
4174
4186
|
let { mouseSelection } = view.inputState;
|
|
4175
4187
|
let del = direct && mouseSelection && mouseSelection.dragging && dragMovesSelection(view, event) ?
|
|
4176
4188
|
{ from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null;
|
|
@@ -4185,12 +4197,11 @@ function dropText(view, event, text, direct) {
|
|
|
4185
4197
|
}
|
|
4186
4198
|
handlers.drop = (view, event) => {
|
|
4187
4199
|
if (!event.dataTransfer)
|
|
4188
|
-
return;
|
|
4200
|
+
return false;
|
|
4189
4201
|
if (view.state.readOnly)
|
|
4190
|
-
return
|
|
4202
|
+
return true;
|
|
4191
4203
|
let files = event.dataTransfer.files;
|
|
4192
4204
|
if (files && files.length) { // For a file drop, read the file's text.
|
|
4193
|
-
event.preventDefault();
|
|
4194
4205
|
let text = Array(files.length), read = 0;
|
|
4195
4206
|
let finishFile = () => {
|
|
4196
4207
|
if (++read == files.length)
|
|
@@ -4206,22 +4217,29 @@ handlers.drop = (view, event) => {
|
|
|
4206
4217
|
};
|
|
4207
4218
|
reader.readAsText(files[i]);
|
|
4208
4219
|
}
|
|
4220
|
+
return true;
|
|
4209
4221
|
}
|
|
4210
4222
|
else {
|
|
4211
|
-
|
|
4223
|
+
let text = event.dataTransfer.getData("Text");
|
|
4224
|
+
if (text) {
|
|
4225
|
+
dropText(view, event, text, true);
|
|
4226
|
+
return true;
|
|
4227
|
+
}
|
|
4212
4228
|
}
|
|
4229
|
+
return false;
|
|
4213
4230
|
};
|
|
4214
4231
|
handlers.paste = (view, event) => {
|
|
4215
4232
|
if (view.state.readOnly)
|
|
4216
|
-
return
|
|
4233
|
+
return true;
|
|
4217
4234
|
view.observer.flush();
|
|
4218
4235
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4219
4236
|
if (data) {
|
|
4220
4237
|
doPaste(view, data.getData("text/plain") || data.getData("text/uri-text"));
|
|
4221
|
-
|
|
4238
|
+
return true;
|
|
4222
4239
|
}
|
|
4223
4240
|
else {
|
|
4224
4241
|
capturePaste(view);
|
|
4242
|
+
return false;
|
|
4225
4243
|
}
|
|
4226
4244
|
};
|
|
4227
4245
|
function captureCopy(view, text) {
|
|
@@ -4267,23 +4285,24 @@ let lastLinewiseCopy = null;
|
|
|
4267
4285
|
handlers.copy = handlers.cut = (view, event) => {
|
|
4268
4286
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
4269
4287
|
if (!text && !linewise)
|
|
4270
|
-
return;
|
|
4288
|
+
return false;
|
|
4271
4289
|
lastLinewiseCopy = linewise ? text : null;
|
|
4290
|
+
if (event.type == "cut" && !view.state.readOnly)
|
|
4291
|
+
view.dispatch({
|
|
4292
|
+
changes: ranges,
|
|
4293
|
+
scrollIntoView: true,
|
|
4294
|
+
userEvent: "delete.cut"
|
|
4295
|
+
});
|
|
4272
4296
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4273
4297
|
if (data) {
|
|
4274
|
-
event.preventDefault();
|
|
4275
4298
|
data.clearData();
|
|
4276
4299
|
data.setData("text/plain", text);
|
|
4300
|
+
return true;
|
|
4277
4301
|
}
|
|
4278
4302
|
else {
|
|
4279
4303
|
captureCopy(view, text);
|
|
4304
|
+
return false;
|
|
4280
4305
|
}
|
|
4281
|
-
if (event.type == "cut" && !view.state.readOnly)
|
|
4282
|
-
view.dispatch({
|
|
4283
|
-
changes: ranges,
|
|
4284
|
-
scrollIntoView: true,
|
|
4285
|
-
userEvent: "delete.cut"
|
|
4286
|
-
});
|
|
4287
4306
|
};
|
|
4288
4307
|
const isFocusChange = state.Annotation.define();
|
|
4289
4308
|
function focusChangeTransaction(state, focus) {
|
|
@@ -4307,7 +4326,7 @@ function updateForFocusChange(view) {
|
|
|
4307
4326
|
}
|
|
4308
4327
|
}, 10);
|
|
4309
4328
|
}
|
|
4310
|
-
|
|
4329
|
+
observers.focus = view => {
|
|
4311
4330
|
view.inputState.lastFocusTime = Date.now();
|
|
4312
4331
|
// When focusing reset the scroll position, move it back to where it was
|
|
4313
4332
|
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
|
|
@@ -4316,11 +4335,11 @@ handlers.focus = view => {
|
|
|
4316
4335
|
}
|
|
4317
4336
|
updateForFocusChange(view);
|
|
4318
4337
|
};
|
|
4319
|
-
|
|
4338
|
+
observers.blur = view => {
|
|
4320
4339
|
view.observer.clearSelectionRange();
|
|
4321
4340
|
updateForFocusChange(view);
|
|
4322
4341
|
};
|
|
4323
|
-
|
|
4342
|
+
observers.compositionstart = observers.compositionupdate = view => {
|
|
4324
4343
|
if (view.inputState.compositionFirstChange == null)
|
|
4325
4344
|
view.inputState.compositionFirstChange = true;
|
|
4326
4345
|
if (view.inputState.composing < 0) {
|
|
@@ -4328,7 +4347,7 @@ handlers.compositionstart = handlers.compositionupdate = view => {
|
|
|
4328
4347
|
view.inputState.composing = 0;
|
|
4329
4348
|
}
|
|
4330
4349
|
};
|
|
4331
|
-
|
|
4350
|
+
observers.compositionend = view => {
|
|
4332
4351
|
view.inputState.composing = -1;
|
|
4333
4352
|
view.inputState.compositionEndedAt = Date.now();
|
|
4334
4353
|
view.inputState.compositionPendingKey = true;
|
|
@@ -4352,7 +4371,7 @@ handlers.compositionend = view => {
|
|
|
4352
4371
|
}, 50);
|
|
4353
4372
|
}
|
|
4354
4373
|
};
|
|
4355
|
-
|
|
4374
|
+
observers.contextmenu = view => {
|
|
4356
4375
|
view.inputState.lastContextMenu = Date.now();
|
|
4357
4376
|
};
|
|
4358
4377
|
handlers.beforeinput = (view, event) => {
|
|
@@ -4381,6 +4400,7 @@ handlers.beforeinput = (view, event) => {
|
|
|
4381
4400
|
}, 100);
|
|
4382
4401
|
}
|
|
4383
4402
|
}
|
|
4403
|
+
return false;
|
|
4384
4404
|
};
|
|
4385
4405
|
const appliedFirefoxHack = new Set;
|
|
4386
4406
|
// In Firefox, when cut/copy handlers are added to the document, that
|
|
@@ -5051,14 +5071,13 @@ class NodeBuilder {
|
|
|
5051
5071
|
return line;
|
|
5052
5072
|
}
|
|
5053
5073
|
addBlock(block) {
|
|
5054
|
-
var _a;
|
|
5055
5074
|
this.enterLine();
|
|
5056
|
-
let
|
|
5057
|
-
if (
|
|
5075
|
+
let deco = block.deco;
|
|
5076
|
+
if (deco && deco.startSide > 0 && !this.isCovered)
|
|
5058
5077
|
this.ensureLine();
|
|
5059
5078
|
this.nodes.push(block);
|
|
5060
5079
|
this.writtenTo = this.pos = this.pos + block.length;
|
|
5061
|
-
if (
|
|
5080
|
+
if (deco && deco.endSide > 0)
|
|
5062
5081
|
this.covering = block;
|
|
5063
5082
|
}
|
|
5064
5083
|
addLineDeco(height, breaks, length) {
|
|
@@ -6166,7 +6185,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6166
6185
|
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
6167
6186
|
}
|
|
6168
6187
|
if (change) {
|
|
6169
|
-
if (browser.ios && view.inputState.flushIOSKey(
|
|
6188
|
+
if (browser.ios && view.inputState.flushIOSKey())
|
|
6170
6189
|
return true;
|
|
6171
6190
|
// Android browsers don't fire reasonable key events for enter,
|
|
6172
6191
|
// backspace, or delete. So this detects changes that look like
|
|
@@ -6420,7 +6439,7 @@ class DOMObserver {
|
|
|
6420
6439
|
this.readSelectionRange();
|
|
6421
6440
|
}
|
|
6422
6441
|
onScrollChanged(e) {
|
|
6423
|
-
this.view.inputState.
|
|
6442
|
+
this.view.inputState.runHandlers("scroll", e);
|
|
6424
6443
|
if (this.intersecting)
|
|
6425
6444
|
this.view.measure();
|
|
6426
6445
|
}
|
|
@@ -6891,7 +6910,7 @@ class EditorView {
|
|
|
6891
6910
|
plugin.update(this);
|
|
6892
6911
|
this.observer = new DOMObserver(this);
|
|
6893
6912
|
this.inputState = new InputState(this);
|
|
6894
|
-
this.inputState.ensureHandlers(this
|
|
6913
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
6895
6914
|
this.docView = new DocView(this);
|
|
6896
6915
|
this.mountStyles();
|
|
6897
6916
|
this.updateAttrs();
|
|
@@ -7033,7 +7052,7 @@ class EditorView {
|
|
|
7033
7052
|
for (let plugin of this.plugins)
|
|
7034
7053
|
plugin.update(this);
|
|
7035
7054
|
this.docView = new DocView(this);
|
|
7036
|
-
this.inputState.ensureHandlers(this
|
|
7055
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7037
7056
|
this.mountStyles();
|
|
7038
7057
|
this.updateAttrs();
|
|
7039
7058
|
this.bidiCache = [];
|
|
@@ -7065,7 +7084,7 @@ class EditorView {
|
|
|
7065
7084
|
plugin.destroy(this);
|
|
7066
7085
|
this.plugins = newPlugins;
|
|
7067
7086
|
this.pluginMap.clear();
|
|
7068
|
-
this.inputState.ensureHandlers(this
|
|
7087
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7069
7088
|
}
|
|
7070
7089
|
else {
|
|
7071
7090
|
for (let p of this.plugins)
|
|
@@ -7593,6 +7612,17 @@ class EditorView {
|
|
|
7593
7612
|
return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
|
7594
7613
|
}
|
|
7595
7614
|
/**
|
|
7615
|
+
Create an extension that registers DOM event observers. Contrary
|
|
7616
|
+
to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers),
|
|
7617
|
+
observers can't be prevented from running by a higher-precedence
|
|
7618
|
+
handler returning true. They also don't prevent other handlers
|
|
7619
|
+
and observers from running when they return true, and should not
|
|
7620
|
+
call `preventDefault`.
|
|
7621
|
+
*/
|
|
7622
|
+
static domEventObservers(observers) {
|
|
7623
|
+
return ViewPlugin.define(() => ({}), { eventObservers: observers });
|
|
7624
|
+
}
|
|
7625
|
+
/**
|
|
7596
7626
|
Create a theme extension. The first argument can be a
|
|
7597
7627
|
[`style-mod`](https://github.com/marijnh/style-mod#documentation)
|
|
7598
7628
|
style spec providing the styles for the theme. These will be
|
|
@@ -8319,6 +8349,14 @@ function drawSelection(config = {}) {
|
|
|
8319
8349
|
nativeSelectionHidden.of(true)
|
|
8320
8350
|
];
|
|
8321
8351
|
}
|
|
8352
|
+
/**
|
|
8353
|
+
Retrieve the [`drawSelection`](https://codemirror.net/6/docs/ref/#view.drawSelection) configuration
|
|
8354
|
+
for this state. (Note that this will return a set of defaults even
|
|
8355
|
+
if `drawSelection` isn't enabled.)
|
|
8356
|
+
*/
|
|
8357
|
+
function getDrawSelectionConfig(state) {
|
|
8358
|
+
return state.facet(selectionConfig);
|
|
8359
|
+
}
|
|
8322
8360
|
function configChanged(update) {
|
|
8323
8361
|
return update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
|
|
8324
8362
|
}
|
|
@@ -8445,7 +8483,7 @@ const drawDropCursor = ViewPlugin.fromClass(class {
|
|
|
8445
8483
|
this.view.dispatch({ effects: setDropCursorPos.of(pos) });
|
|
8446
8484
|
}
|
|
8447
8485
|
}, {
|
|
8448
|
-
|
|
8486
|
+
eventObservers: {
|
|
8449
8487
|
dragover(event) {
|
|
8450
8488
|
this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
|
|
8451
8489
|
},
|
|
@@ -8955,7 +8993,7 @@ function crosshairCursor(options = {}) {
|
|
|
8955
8993
|
}
|
|
8956
8994
|
}
|
|
8957
8995
|
}, {
|
|
8958
|
-
|
|
8996
|
+
eventObservers: {
|
|
8959
8997
|
keydown(e) {
|
|
8960
8998
|
this.set(e.keyCode == code || getter(e));
|
|
8961
8999
|
},
|
|
@@ -9143,6 +9181,8 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9143
9181
|
tooltipView.dom.remove();
|
|
9144
9182
|
(_a = tooltipView.destroy) === null || _a === void 0 ? void 0 : _a.call(tooltipView);
|
|
9145
9183
|
}
|
|
9184
|
+
if (this.parent)
|
|
9185
|
+
this.container.remove();
|
|
9146
9186
|
(_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
|
9147
9187
|
clearTimeout(this.measureTimeout);
|
|
9148
9188
|
}
|
|
@@ -9266,7 +9306,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9266
9306
|
}
|
|
9267
9307
|
}
|
|
9268
9308
|
}, {
|
|
9269
|
-
|
|
9309
|
+
eventObservers: {
|
|
9270
9310
|
scroll() { this.maybeMeasure(); }
|
|
9271
9311
|
}
|
|
9272
9312
|
});
|
|
@@ -9584,8 +9624,9 @@ re-positioning or CSS change affecting the editor) that could
|
|
|
9584
9624
|
invalidate the existing tooltip positions.
|
|
9585
9625
|
*/
|
|
9586
9626
|
function repositionTooltips(view) {
|
|
9587
|
-
|
|
9588
|
-
(
|
|
9627
|
+
let plugin = view.plugin(tooltipPlugin);
|
|
9628
|
+
if (plugin)
|
|
9629
|
+
plugin.maybeMeasure();
|
|
9589
9630
|
}
|
|
9590
9631
|
|
|
9591
9632
|
const panelConfig = state.Facet.define({
|
|
@@ -10303,6 +10344,7 @@ exports.closeHoverTooltips = closeHoverTooltips;
|
|
|
10303
10344
|
exports.crosshairCursor = crosshairCursor;
|
|
10304
10345
|
exports.drawSelection = drawSelection;
|
|
10305
10346
|
exports.dropCursor = dropCursor;
|
|
10347
|
+
exports.getDrawSelectionConfig = getDrawSelectionConfig;
|
|
10306
10348
|
exports.getPanel = getPanel;
|
|
10307
10349
|
exports.getTooltip = getTooltip;
|
|
10308
10350
|
exports.gutter = gutter;
|