@codemirror/view 6.18.1 → 6.19.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 +12 -0
- package/dist/index.cjs +509 -482
- package/dist/index.d.cts +15 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +509 -482
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1091,6 +1091,236 @@ function getAttrs(dom) {
|
|
|
1091
1091
|
return attrs;
|
|
1092
1092
|
}
|
|
1093
1093
|
|
|
1094
|
+
class LineView extends ContentView {
|
|
1095
|
+
constructor() {
|
|
1096
|
+
super(...arguments);
|
|
1097
|
+
this.children = [];
|
|
1098
|
+
this.length = 0;
|
|
1099
|
+
this.prevAttrs = undefined;
|
|
1100
|
+
this.attrs = null;
|
|
1101
|
+
this.breakAfter = 0;
|
|
1102
|
+
}
|
|
1103
|
+
// Consumes source
|
|
1104
|
+
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
1105
|
+
if (source) {
|
|
1106
|
+
if (!(source instanceof LineView))
|
|
1107
|
+
return false;
|
|
1108
|
+
if (!this.dom)
|
|
1109
|
+
source.transferDOM(this); // Reuse source.dom when appropriate
|
|
1110
|
+
}
|
|
1111
|
+
if (hasStart)
|
|
1112
|
+
this.setDeco(source ? source.attrs : null);
|
|
1113
|
+
mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
|
|
1114
|
+
return true;
|
|
1115
|
+
}
|
|
1116
|
+
split(at) {
|
|
1117
|
+
let end = new LineView;
|
|
1118
|
+
end.breakAfter = this.breakAfter;
|
|
1119
|
+
if (this.length == 0)
|
|
1120
|
+
return end;
|
|
1121
|
+
let { i, off } = this.childPos(at);
|
|
1122
|
+
if (off) {
|
|
1123
|
+
end.append(this.children[i].split(off), 0);
|
|
1124
|
+
this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
|
|
1125
|
+
i++;
|
|
1126
|
+
}
|
|
1127
|
+
for (let j = i; j < this.children.length; j++)
|
|
1128
|
+
end.append(this.children[j], 0);
|
|
1129
|
+
while (i > 0 && this.children[i - 1].length == 0)
|
|
1130
|
+
this.children[--i].destroy();
|
|
1131
|
+
this.children.length = i;
|
|
1132
|
+
this.markDirty();
|
|
1133
|
+
this.length = at;
|
|
1134
|
+
return end;
|
|
1135
|
+
}
|
|
1136
|
+
transferDOM(other) {
|
|
1137
|
+
if (!this.dom)
|
|
1138
|
+
return;
|
|
1139
|
+
this.markDirty();
|
|
1140
|
+
other.setDOM(this.dom);
|
|
1141
|
+
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1142
|
+
this.prevAttrs = undefined;
|
|
1143
|
+
this.dom = null;
|
|
1144
|
+
}
|
|
1145
|
+
setDeco(attrs) {
|
|
1146
|
+
if (!attrsEq(this.attrs, attrs)) {
|
|
1147
|
+
if (this.dom) {
|
|
1148
|
+
this.prevAttrs = this.attrs;
|
|
1149
|
+
this.markDirty();
|
|
1150
|
+
}
|
|
1151
|
+
this.attrs = attrs;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
append(child, openStart) {
|
|
1155
|
+
joinInlineInto(this, child, openStart);
|
|
1156
|
+
}
|
|
1157
|
+
// Only called when building a line view in ContentBuilder
|
|
1158
|
+
addLineDeco(deco) {
|
|
1159
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1160
|
+
if (attrs)
|
|
1161
|
+
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1162
|
+
if (cls)
|
|
1163
|
+
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1164
|
+
}
|
|
1165
|
+
domAtPos(pos) {
|
|
1166
|
+
return inlineDOMAtPos(this, pos);
|
|
1167
|
+
}
|
|
1168
|
+
reuseDOM(node) {
|
|
1169
|
+
if (node.nodeName == "DIV") {
|
|
1170
|
+
this.setDOM(node);
|
|
1171
|
+
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
sync(view, track) {
|
|
1175
|
+
var _a;
|
|
1176
|
+
if (!this.dom) {
|
|
1177
|
+
this.setDOM(document.createElement("div"));
|
|
1178
|
+
this.dom.className = "cm-line";
|
|
1179
|
+
this.prevAttrs = this.attrs ? null : undefined;
|
|
1180
|
+
}
|
|
1181
|
+
else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
|
|
1182
|
+
clearAttributes(this.dom);
|
|
1183
|
+
this.dom.className = "cm-line";
|
|
1184
|
+
this.prevAttrs = this.attrs ? null : undefined;
|
|
1185
|
+
}
|
|
1186
|
+
if (this.prevAttrs !== undefined) {
|
|
1187
|
+
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1188
|
+
this.dom.classList.add("cm-line");
|
|
1189
|
+
this.prevAttrs = undefined;
|
|
1190
|
+
}
|
|
1191
|
+
super.sync(view, track);
|
|
1192
|
+
let last = this.dom.lastChild;
|
|
1193
|
+
while (last && ContentView.get(last) instanceof MarkView)
|
|
1194
|
+
last = last.lastChild;
|
|
1195
|
+
if (!last || !this.length ||
|
|
1196
|
+
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1197
|
+
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1198
|
+
let hack = document.createElement("BR");
|
|
1199
|
+
hack.cmIgnore = true;
|
|
1200
|
+
this.dom.appendChild(hack);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
measureTextSize() {
|
|
1204
|
+
if (this.children.length == 0 || this.length > 20)
|
|
1205
|
+
return null;
|
|
1206
|
+
let totalWidth = 0, textHeight;
|
|
1207
|
+
for (let child of this.children) {
|
|
1208
|
+
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1209
|
+
return null;
|
|
1210
|
+
let rects = clientRectsFor(child.dom);
|
|
1211
|
+
if (rects.length != 1)
|
|
1212
|
+
return null;
|
|
1213
|
+
totalWidth += rects[0].width;
|
|
1214
|
+
textHeight = rects[0].height;
|
|
1215
|
+
}
|
|
1216
|
+
return !totalWidth ? null : {
|
|
1217
|
+
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1218
|
+
charWidth: totalWidth / this.length,
|
|
1219
|
+
textHeight
|
|
1220
|
+
};
|
|
1221
|
+
}
|
|
1222
|
+
coordsAt(pos, side) {
|
|
1223
|
+
let rect = coordsInChildren(this, pos, side);
|
|
1224
|
+
// Correct rectangle height for empty lines when the returned
|
|
1225
|
+
// height is larger than the text height.
|
|
1226
|
+
if (!this.children.length && rect && this.parent) {
|
|
1227
|
+
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1228
|
+
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1229
|
+
let dist = (height - heightOracle.textHeight) / 2;
|
|
1230
|
+
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
return rect;
|
|
1234
|
+
}
|
|
1235
|
+
become(_other) { return false; }
|
|
1236
|
+
covers() { return true; }
|
|
1237
|
+
static find(docView, pos) {
|
|
1238
|
+
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1239
|
+
let block = docView.children[i], end = off + block.length;
|
|
1240
|
+
if (end >= pos) {
|
|
1241
|
+
if (block instanceof LineView)
|
|
1242
|
+
return block;
|
|
1243
|
+
if (end > pos)
|
|
1244
|
+
break;
|
|
1245
|
+
}
|
|
1246
|
+
off = end + block.breakAfter;
|
|
1247
|
+
}
|
|
1248
|
+
return null;
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
class BlockWidgetView extends ContentView {
|
|
1252
|
+
constructor(widget, length, deco) {
|
|
1253
|
+
super();
|
|
1254
|
+
this.widget = widget;
|
|
1255
|
+
this.length = length;
|
|
1256
|
+
this.deco = deco;
|
|
1257
|
+
this.breakAfter = 0;
|
|
1258
|
+
this.prevWidget = null;
|
|
1259
|
+
}
|
|
1260
|
+
merge(from, to, source, _takeDeco, openStart, openEnd) {
|
|
1261
|
+
if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
|
1262
|
+
from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
|
|
1263
|
+
return false;
|
|
1264
|
+
this.length = from + (source ? source.length : 0) + (this.length - to);
|
|
1265
|
+
return true;
|
|
1266
|
+
}
|
|
1267
|
+
domAtPos(pos) {
|
|
1268
|
+
return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
|
|
1269
|
+
}
|
|
1270
|
+
split(at) {
|
|
1271
|
+
let len = this.length - at;
|
|
1272
|
+
this.length = at;
|
|
1273
|
+
let end = new BlockWidgetView(this.widget, len, this.deco);
|
|
1274
|
+
end.breakAfter = this.breakAfter;
|
|
1275
|
+
return end;
|
|
1276
|
+
}
|
|
1277
|
+
get children() { return noChildren; }
|
|
1278
|
+
sync(view) {
|
|
1279
|
+
if (!this.dom || !this.widget.updateDOM(this.dom, view)) {
|
|
1280
|
+
if (this.dom && this.prevWidget)
|
|
1281
|
+
this.prevWidget.destroy(this.dom);
|
|
1282
|
+
this.prevWidget = null;
|
|
1283
|
+
this.setDOM(this.widget.toDOM(view));
|
|
1284
|
+
this.dom.contentEditable = "false";
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
get overrideDOMText() {
|
|
1288
|
+
return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty;
|
|
1289
|
+
}
|
|
1290
|
+
domBoundsAround() { return null; }
|
|
1291
|
+
become(other) {
|
|
1292
|
+
if (other instanceof BlockWidgetView &&
|
|
1293
|
+
other.widget.constructor == this.widget.constructor) {
|
|
1294
|
+
if (!other.widget.compare(this.widget))
|
|
1295
|
+
this.markDirty(true);
|
|
1296
|
+
if (this.dom && !this.prevWidget)
|
|
1297
|
+
this.prevWidget = this.widget;
|
|
1298
|
+
this.widget = other.widget;
|
|
1299
|
+
this.length = other.length;
|
|
1300
|
+
this.deco = other.deco;
|
|
1301
|
+
this.breakAfter = other.breakAfter;
|
|
1302
|
+
return true;
|
|
1303
|
+
}
|
|
1304
|
+
return false;
|
|
1305
|
+
}
|
|
1306
|
+
ignoreMutation() { return true; }
|
|
1307
|
+
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
1308
|
+
get isEditable() { return false; }
|
|
1309
|
+
get isWidget() { return true; }
|
|
1310
|
+
coordsAt(pos, side) {
|
|
1311
|
+
return this.widget.coordsAt(this.dom, pos, side);
|
|
1312
|
+
}
|
|
1313
|
+
destroy() {
|
|
1314
|
+
super.destroy();
|
|
1315
|
+
if (this.dom)
|
|
1316
|
+
this.widget.destroy(this.dom);
|
|
1317
|
+
}
|
|
1318
|
+
covers(side) {
|
|
1319
|
+
let { startSide, endSide } = this.deco;
|
|
1320
|
+
return startSide == endSide ? false : side < 0 ? startSide < 0 : endSide > 0;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1094
1324
|
/**
|
|
1095
1325
|
Widgets added to the content are described by subclasses of this
|
|
1096
1326
|
class. Using a description object like that makes it possible to
|
|
@@ -1249,353 +1479,127 @@ class Decoration extends RangeValue {
|
|
|
1249
1479
|
let block = !!spec.block, startSide, endSide;
|
|
1250
1480
|
if (spec.isBlockGap) {
|
|
1251
1481
|
startSide = -500000000 /* Side.GapStart */;
|
|
1252
|
-
endSide = 400000000 /* Side.GapEnd */;
|
|
1253
|
-
}
|
|
1254
|
-
else {
|
|
1255
|
-
let { start, end } = getInclusive(spec, block);
|
|
1256
|
-
startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
|
|
1257
|
-
endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1;
|
|
1258
|
-
}
|
|
1259
|
-
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1260
|
-
}
|
|
1261
|
-
/**
|
|
1262
|
-
Create a line decoration, which can add DOM attributes to the
|
|
1263
|
-
line starting at the given position.
|
|
1264
|
-
*/
|
|
1265
|
-
static line(spec) {
|
|
1266
|
-
return new LineDecoration(spec);
|
|
1267
|
-
}
|
|
1268
|
-
/**
|
|
1269
|
-
Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
|
|
1270
|
-
decorated range or ranges. If the ranges aren't already sorted,
|
|
1271
|
-
pass `true` for `sort` to make the library sort them for you.
|
|
1272
|
-
*/
|
|
1273
|
-
static set(of, sort = false) {
|
|
1274
|
-
return RangeSet.of(of, sort);
|
|
1275
|
-
}
|
|
1276
|
-
/**
|
|
1277
|
-
@internal
|
|
1278
|
-
*/
|
|
1279
|
-
hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; }
|
|
1280
|
-
}
|
|
1281
|
-
/**
|
|
1282
|
-
The empty set of decorations.
|
|
1283
|
-
*/
|
|
1284
|
-
Decoration.none = RangeSet.empty;
|
|
1285
|
-
class MarkDecoration extends Decoration {
|
|
1286
|
-
constructor(spec) {
|
|
1287
|
-
let { start, end } = getInclusive(spec);
|
|
1288
|
-
super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
|
|
1289
|
-
this.tagName = spec.tagName || "span";
|
|
1290
|
-
this.class = spec.class || "";
|
|
1291
|
-
this.attrs = spec.attributes || null;
|
|
1292
|
-
}
|
|
1293
|
-
eq(other) {
|
|
1294
|
-
var _a, _b;
|
|
1295
|
-
return this == other ||
|
|
1296
|
-
other instanceof MarkDecoration &&
|
|
1297
|
-
this.tagName == other.tagName &&
|
|
1298
|
-
(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)) &&
|
|
1299
|
-
attrsEq(this.attrs, other.attrs, "class");
|
|
1300
|
-
}
|
|
1301
|
-
range(from, to = from) {
|
|
1302
|
-
if (from >= to)
|
|
1303
|
-
throw new RangeError("Mark decorations may not be empty");
|
|
1304
|
-
return super.range(from, to);
|
|
1305
|
-
}
|
|
1306
|
-
}
|
|
1307
|
-
MarkDecoration.prototype.point = false;
|
|
1308
|
-
class LineDecoration extends Decoration {
|
|
1309
|
-
constructor(spec) {
|
|
1310
|
-
super(-200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec);
|
|
1311
|
-
}
|
|
1312
|
-
eq(other) {
|
|
1313
|
-
return other instanceof LineDecoration &&
|
|
1314
|
-
this.spec.class == other.spec.class &&
|
|
1315
|
-
attrsEq(this.spec.attributes, other.spec.attributes);
|
|
1316
|
-
}
|
|
1317
|
-
range(from, to = from) {
|
|
1318
|
-
if (to != from)
|
|
1319
|
-
throw new RangeError("Line decoration ranges must be zero-length");
|
|
1320
|
-
return super.range(from, to);
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
LineDecoration.prototype.mapMode = MapMode.TrackBefore;
|
|
1324
|
-
LineDecoration.prototype.point = true;
|
|
1325
|
-
class PointDecoration extends Decoration {
|
|
1326
|
-
constructor(spec, startSide, endSide, block, widget, isReplace) {
|
|
1327
|
-
super(startSide, endSide, widget, spec);
|
|
1328
|
-
this.block = block;
|
|
1329
|
-
this.isReplace = isReplace;
|
|
1330
|
-
this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
|
|
1331
|
-
}
|
|
1332
|
-
// Only relevant when this.block == true
|
|
1333
|
-
get type() {
|
|
1334
|
-
return this.startSide < this.endSide ? BlockType.WidgetRange
|
|
1335
|
-
: this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
|
|
1336
|
-
}
|
|
1337
|
-
get heightRelevant() {
|
|
1338
|
-
return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
|
|
1339
|
-
}
|
|
1340
|
-
eq(other) {
|
|
1341
|
-
return other instanceof PointDecoration &&
|
|
1342
|
-
widgetsEq(this.widget, other.widget) &&
|
|
1343
|
-
this.block == other.block &&
|
|
1344
|
-
this.startSide == other.startSide && this.endSide == other.endSide;
|
|
1345
|
-
}
|
|
1346
|
-
range(from, to = from) {
|
|
1347
|
-
if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
|
|
1348
|
-
throw new RangeError("Invalid range for replacement decoration");
|
|
1349
|
-
if (!this.isReplace && to != from)
|
|
1350
|
-
throw new RangeError("Widget decorations can only have zero-length ranges");
|
|
1351
|
-
return super.range(from, to);
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
PointDecoration.prototype.point = true;
|
|
1355
|
-
function getInclusive(spec, block = false) {
|
|
1356
|
-
let { inclusiveStart: start, inclusiveEnd: end } = spec;
|
|
1357
|
-
if (start == null)
|
|
1358
|
-
start = spec.inclusive;
|
|
1359
|
-
if (end == null)
|
|
1360
|
-
end = spec.inclusive;
|
|
1361
|
-
return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
|
|
1362
|
-
}
|
|
1363
|
-
function widgetsEq(a, b) {
|
|
1364
|
-
return a == b || !!(a && b && a.compare(b));
|
|
1365
|
-
}
|
|
1366
|
-
function addRange(from, to, ranges, margin = 0) {
|
|
1367
|
-
let last = ranges.length - 1;
|
|
1368
|
-
if (last >= 0 && ranges[last] + margin >= from)
|
|
1369
|
-
ranges[last] = Math.max(ranges[last], to);
|
|
1370
|
-
else
|
|
1371
|
-
ranges.push(from, to);
|
|
1372
|
-
}
|
|
1373
|
-
|
|
1374
|
-
class LineView extends ContentView {
|
|
1375
|
-
constructor() {
|
|
1376
|
-
super(...arguments);
|
|
1377
|
-
this.children = [];
|
|
1378
|
-
this.length = 0;
|
|
1379
|
-
this.prevAttrs = undefined;
|
|
1380
|
-
this.attrs = null;
|
|
1381
|
-
this.breakAfter = 0;
|
|
1382
|
-
}
|
|
1383
|
-
// Consumes source
|
|
1384
|
-
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
1385
|
-
if (source) {
|
|
1386
|
-
if (!(source instanceof LineView))
|
|
1387
|
-
return false;
|
|
1388
|
-
if (!this.dom)
|
|
1389
|
-
source.transferDOM(this); // Reuse source.dom when appropriate
|
|
1390
|
-
}
|
|
1391
|
-
if (hasStart)
|
|
1392
|
-
this.setDeco(source ? source.attrs : null);
|
|
1393
|
-
mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
|
|
1394
|
-
return true;
|
|
1395
|
-
}
|
|
1396
|
-
split(at) {
|
|
1397
|
-
let end = new LineView;
|
|
1398
|
-
end.breakAfter = this.breakAfter;
|
|
1399
|
-
if (this.length == 0)
|
|
1400
|
-
return end;
|
|
1401
|
-
let { i, off } = this.childPos(at);
|
|
1402
|
-
if (off) {
|
|
1403
|
-
end.append(this.children[i].split(off), 0);
|
|
1404
|
-
this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
|
|
1405
|
-
i++;
|
|
1406
|
-
}
|
|
1407
|
-
for (let j = i; j < this.children.length; j++)
|
|
1408
|
-
end.append(this.children[j], 0);
|
|
1409
|
-
while (i > 0 && this.children[i - 1].length == 0)
|
|
1410
|
-
this.children[--i].destroy();
|
|
1411
|
-
this.children.length = i;
|
|
1412
|
-
this.markDirty();
|
|
1413
|
-
this.length = at;
|
|
1414
|
-
return end;
|
|
1415
|
-
}
|
|
1416
|
-
transferDOM(other) {
|
|
1417
|
-
if (!this.dom)
|
|
1418
|
-
return;
|
|
1419
|
-
this.markDirty();
|
|
1420
|
-
other.setDOM(this.dom);
|
|
1421
|
-
other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
|
1422
|
-
this.prevAttrs = undefined;
|
|
1423
|
-
this.dom = null;
|
|
1424
|
-
}
|
|
1425
|
-
setDeco(attrs) {
|
|
1426
|
-
if (!attrsEq(this.attrs, attrs)) {
|
|
1427
|
-
if (this.dom) {
|
|
1428
|
-
this.prevAttrs = this.attrs;
|
|
1429
|
-
this.markDirty();
|
|
1430
|
-
}
|
|
1431
|
-
this.attrs = attrs;
|
|
1432
|
-
}
|
|
1433
|
-
}
|
|
1434
|
-
append(child, openStart) {
|
|
1435
|
-
joinInlineInto(this, child, openStart);
|
|
1436
|
-
}
|
|
1437
|
-
// Only called when building a line view in ContentBuilder
|
|
1438
|
-
addLineDeco(deco) {
|
|
1439
|
-
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1440
|
-
if (attrs)
|
|
1441
|
-
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1442
|
-
if (cls)
|
|
1443
|
-
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1444
|
-
}
|
|
1445
|
-
domAtPos(pos) {
|
|
1446
|
-
return inlineDOMAtPos(this, pos);
|
|
1447
|
-
}
|
|
1448
|
-
reuseDOM(node) {
|
|
1449
|
-
if (node.nodeName == "DIV") {
|
|
1450
|
-
this.setDOM(node);
|
|
1451
|
-
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
sync(view, track) {
|
|
1455
|
-
var _a;
|
|
1456
|
-
if (!this.dom) {
|
|
1457
|
-
this.setDOM(document.createElement("div"));
|
|
1458
|
-
this.dom.className = "cm-line";
|
|
1459
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1460
|
-
}
|
|
1461
|
-
else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
|
|
1462
|
-
clearAttributes(this.dom);
|
|
1463
|
-
this.dom.className = "cm-line";
|
|
1464
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1465
|
-
}
|
|
1466
|
-
if (this.prevAttrs !== undefined) {
|
|
1467
|
-
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1468
|
-
this.dom.classList.add("cm-line");
|
|
1469
|
-
this.prevAttrs = undefined;
|
|
1470
|
-
}
|
|
1471
|
-
super.sync(view, track);
|
|
1472
|
-
let last = this.dom.lastChild;
|
|
1473
|
-
while (last && ContentView.get(last) instanceof MarkView)
|
|
1474
|
-
last = last.lastChild;
|
|
1475
|
-
if (!last || !this.length ||
|
|
1476
|
-
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1477
|
-
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1478
|
-
let hack = document.createElement("BR");
|
|
1479
|
-
hack.cmIgnore = true;
|
|
1480
|
-
this.dom.appendChild(hack);
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
measureTextSize() {
|
|
1484
|
-
if (this.children.length == 0 || this.length > 20)
|
|
1485
|
-
return null;
|
|
1486
|
-
let totalWidth = 0, textHeight;
|
|
1487
|
-
for (let child of this.children) {
|
|
1488
|
-
if (!(child instanceof TextView) || /[^ -~]/.test(child.text))
|
|
1489
|
-
return null;
|
|
1490
|
-
let rects = clientRectsFor(child.dom);
|
|
1491
|
-
if (rects.length != 1)
|
|
1492
|
-
return null;
|
|
1493
|
-
totalWidth += rects[0].width;
|
|
1494
|
-
textHeight = rects[0].height;
|
|
1495
|
-
}
|
|
1496
|
-
return !totalWidth ? null : {
|
|
1497
|
-
lineHeight: this.dom.getBoundingClientRect().height,
|
|
1498
|
-
charWidth: totalWidth / this.length,
|
|
1499
|
-
textHeight
|
|
1500
|
-
};
|
|
1501
|
-
}
|
|
1502
|
-
coordsAt(pos, side) {
|
|
1503
|
-
let rect = coordsInChildren(this, pos, side);
|
|
1504
|
-
// Correct rectangle height for empty lines when the returned
|
|
1505
|
-
// height is larger than the text height.
|
|
1506
|
-
if (!this.children.length && rect && this.parent) {
|
|
1507
|
-
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1508
|
-
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1509
|
-
let dist = (height - heightOracle.textHeight) / 2;
|
|
1510
|
-
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1511
|
-
}
|
|
1482
|
+
endSide = 400000000 /* Side.GapEnd */;
|
|
1512
1483
|
}
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
static find(docView, pos) {
|
|
1518
|
-
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1519
|
-
let block = docView.children[i], end = off + block.length;
|
|
1520
|
-
if (end >= pos) {
|
|
1521
|
-
if (block instanceof LineView)
|
|
1522
|
-
return block;
|
|
1523
|
-
if (end > pos)
|
|
1524
|
-
break;
|
|
1525
|
-
}
|
|
1526
|
-
off = end + block.breakAfter;
|
|
1484
|
+
else {
|
|
1485
|
+
let { start, end } = getInclusive(spec, block);
|
|
1486
|
+
startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
|
|
1487
|
+
endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1;
|
|
1527
1488
|
}
|
|
1528
|
-
return null;
|
|
1489
|
+
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1490
|
+
}
|
|
1491
|
+
/**
|
|
1492
|
+
Create a line decoration, which can add DOM attributes to the
|
|
1493
|
+
line starting at the given position.
|
|
1494
|
+
*/
|
|
1495
|
+
static line(spec) {
|
|
1496
|
+
return new LineDecoration(spec);
|
|
1497
|
+
}
|
|
1498
|
+
/**
|
|
1499
|
+
Build a [`DecorationSet`](https://codemirror.net/6/docs/ref/#view.DecorationSet) from the given
|
|
1500
|
+
decorated range or ranges. If the ranges aren't already sorted,
|
|
1501
|
+
pass `true` for `sort` to make the library sort them for you.
|
|
1502
|
+
*/
|
|
1503
|
+
static set(of, sort = false) {
|
|
1504
|
+
return RangeSet.of(of, sort);
|
|
1529
1505
|
}
|
|
1506
|
+
/**
|
|
1507
|
+
@internal
|
|
1508
|
+
*/
|
|
1509
|
+
hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; }
|
|
1530
1510
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1511
|
+
/**
|
|
1512
|
+
The empty set of decorations.
|
|
1513
|
+
*/
|
|
1514
|
+
Decoration.none = RangeSet.empty;
|
|
1515
|
+
class MarkDecoration extends Decoration {
|
|
1516
|
+
constructor(spec) {
|
|
1517
|
+
let { start, end } = getInclusive(spec);
|
|
1518
|
+
super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
|
|
1519
|
+
this.tagName = spec.tagName || "span";
|
|
1520
|
+
this.class = spec.class || "";
|
|
1521
|
+
this.attrs = spec.attributes || null;
|
|
1539
1522
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1523
|
+
eq(other) {
|
|
1524
|
+
var _a, _b;
|
|
1525
|
+
return this == other ||
|
|
1526
|
+
other instanceof MarkDecoration &&
|
|
1527
|
+
this.tagName == other.tagName &&
|
|
1528
|
+
(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)) &&
|
|
1529
|
+
attrsEq(this.attrs, other.attrs, "class");
|
|
1546
1530
|
}
|
|
1547
|
-
|
|
1548
|
-
|
|
1531
|
+
range(from, to = from) {
|
|
1532
|
+
if (from >= to)
|
|
1533
|
+
throw new RangeError("Mark decorations may not be empty");
|
|
1534
|
+
return super.range(from, to);
|
|
1549
1535
|
}
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
return end;
|
|
1536
|
+
}
|
|
1537
|
+
MarkDecoration.prototype.point = false;
|
|
1538
|
+
class LineDecoration extends Decoration {
|
|
1539
|
+
constructor(spec) {
|
|
1540
|
+
super(-200000000 /* Side.Line */, -200000000 /* Side.Line */, null, spec);
|
|
1556
1541
|
}
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
this.prevWidget.destroy(this.dom);
|
|
1562
|
-
this.prevWidget = null;
|
|
1563
|
-
this.setDOM(this.widget.toDOM(view));
|
|
1564
|
-
this.dom.contentEditable = "false";
|
|
1565
|
-
}
|
|
1542
|
+
eq(other) {
|
|
1543
|
+
return other instanceof LineDecoration &&
|
|
1544
|
+
this.spec.class == other.spec.class &&
|
|
1545
|
+
attrsEq(this.spec.attributes, other.spec.attributes);
|
|
1566
1546
|
}
|
|
1567
|
-
|
|
1568
|
-
|
|
1547
|
+
range(from, to = from) {
|
|
1548
|
+
if (to != from)
|
|
1549
|
+
throw new RangeError("Line decoration ranges must be zero-length");
|
|
1550
|
+
return super.range(from, to);
|
|
1569
1551
|
}
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
this.length = other.length;
|
|
1580
|
-
this.type = other.type;
|
|
1581
|
-
this.breakAfter = other.breakAfter;
|
|
1582
|
-
return true;
|
|
1583
|
-
}
|
|
1584
|
-
return false;
|
|
1552
|
+
}
|
|
1553
|
+
LineDecoration.prototype.mapMode = MapMode.TrackBefore;
|
|
1554
|
+
LineDecoration.prototype.point = true;
|
|
1555
|
+
class PointDecoration extends Decoration {
|
|
1556
|
+
constructor(spec, startSide, endSide, block, widget, isReplace) {
|
|
1557
|
+
super(startSide, endSide, widget, spec);
|
|
1558
|
+
this.block = block;
|
|
1559
|
+
this.isReplace = isReplace;
|
|
1560
|
+
this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
|
|
1585
1561
|
}
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
coordsAt(pos, side) {
|
|
1591
|
-
return this.widget.coordsAt(this.dom, pos, side);
|
|
1562
|
+
// Only relevant when this.block == true
|
|
1563
|
+
get type() {
|
|
1564
|
+
return this.startSide != this.endSide ? BlockType.WidgetRange
|
|
1565
|
+
: this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
|
|
1592
1566
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1567
|
+
get heightRelevant() {
|
|
1568
|
+
return this.block || !!this.widget && (this.widget.estimatedHeight >= 5 || this.widget.lineBreaks > 0);
|
|
1569
|
+
}
|
|
1570
|
+
eq(other) {
|
|
1571
|
+
return other instanceof PointDecoration &&
|
|
1572
|
+
widgetsEq(this.widget, other.widget) &&
|
|
1573
|
+
this.block == other.block &&
|
|
1574
|
+
this.startSide == other.startSide && this.endSide == other.endSide;
|
|
1575
|
+
}
|
|
1576
|
+
range(from, to = from) {
|
|
1577
|
+
if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
|
|
1578
|
+
throw new RangeError("Invalid range for replacement decoration");
|
|
1579
|
+
if (!this.isReplace && to != from)
|
|
1580
|
+
throw new RangeError("Widget decorations can only have zero-length ranges");
|
|
1581
|
+
return super.range(from, to);
|
|
1597
1582
|
}
|
|
1598
1583
|
}
|
|
1584
|
+
PointDecoration.prototype.point = true;
|
|
1585
|
+
function getInclusive(spec, block = false) {
|
|
1586
|
+
let { inclusiveStart: start, inclusiveEnd: end } = spec;
|
|
1587
|
+
if (start == null)
|
|
1588
|
+
start = spec.inclusive;
|
|
1589
|
+
if (end == null)
|
|
1590
|
+
end = spec.inclusive;
|
|
1591
|
+
return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
|
|
1592
|
+
}
|
|
1593
|
+
function widgetsEq(a, b) {
|
|
1594
|
+
return a == b || !!(a && b && a.compare(b));
|
|
1595
|
+
}
|
|
1596
|
+
function addRange(from, to, ranges, margin = 0) {
|
|
1597
|
+
let last = ranges.length - 1;
|
|
1598
|
+
if (last >= 0 && ranges[last] + margin >= from)
|
|
1599
|
+
ranges[last] = Math.max(ranges[last], to);
|
|
1600
|
+
else
|
|
1601
|
+
ranges.push(from, to);
|
|
1602
|
+
}
|
|
1599
1603
|
|
|
1600
1604
|
class ContentBuilder {
|
|
1601
1605
|
constructor(doc, pos, end, disallowBlockEffectsFor) {
|
|
@@ -1621,7 +1625,7 @@ class ContentBuilder {
|
|
|
1621
1625
|
if (this.content.length == 0)
|
|
1622
1626
|
return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos;
|
|
1623
1627
|
let last = this.content[this.content.length - 1];
|
|
1624
|
-
return !last.breakAfter
|
|
1628
|
+
return !(last.breakAfter || last instanceof BlockWidgetView && last.deco.endSide < 0);
|
|
1625
1629
|
}
|
|
1626
1630
|
getLine() {
|
|
1627
1631
|
if (!this.curLine) {
|
|
@@ -1646,7 +1650,7 @@ class ContentBuilder {
|
|
|
1646
1650
|
this.flushBuffer();
|
|
1647
1651
|
else
|
|
1648
1652
|
this.pendingBuffer = 0 /* Buf.No */;
|
|
1649
|
-
if (!this.posCovered())
|
|
1653
|
+
if (!openEnd && !this.posCovered())
|
|
1650
1654
|
this.getLine();
|
|
1651
1655
|
}
|
|
1652
1656
|
buildText(length, active, openStart) {
|
|
@@ -1699,10 +1703,9 @@ class ContentBuilder {
|
|
|
1699
1703
|
let len = to - from;
|
|
1700
1704
|
if (deco instanceof PointDecoration) {
|
|
1701
1705
|
if (deco.block) {
|
|
1702
|
-
|
|
1703
|
-
if (type == BlockType.WidgetAfter && !this.posCovered())
|
|
1706
|
+
if (deco.startSide > 0 && !this.posCovered())
|
|
1704
1707
|
this.getLine();
|
|
1705
|
-
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len,
|
|
1708
|
+
this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, deco));
|
|
1706
1709
|
}
|
|
1707
1710
|
else {
|
|
1708
1711
|
let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
|
|
@@ -1837,10 +1840,15 @@ class ViewPlugin {
|
|
|
1837
1840
|
/**
|
|
1838
1841
|
@internal
|
|
1839
1842
|
*/
|
|
1840
|
-
domEventHandlers,
|
|
1843
|
+
domEventHandlers,
|
|
1844
|
+
/**
|
|
1845
|
+
@internal
|
|
1846
|
+
*/
|
|
1847
|
+
domEventObservers, buildExtensions) {
|
|
1841
1848
|
this.id = id;
|
|
1842
1849
|
this.create = create;
|
|
1843
1850
|
this.domEventHandlers = domEventHandlers;
|
|
1851
|
+
this.domEventObservers = domEventObservers;
|
|
1844
1852
|
this.extension = buildExtensions(this);
|
|
1845
1853
|
}
|
|
1846
1854
|
/**
|
|
@@ -1848,8 +1856,8 @@ class ViewPlugin {
|
|
|
1848
1856
|
plugin's value, given an editor view.
|
|
1849
1857
|
*/
|
|
1850
1858
|
static define(create, spec) {
|
|
1851
|
-
const { eventHandlers, provide, decorations: deco } = spec || {};
|
|
1852
|
-
return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
|
|
1859
|
+
const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
|
|
1860
|
+
return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
|
|
1853
1861
|
let ext = [viewPlugin.of(plugin)];
|
|
1854
1862
|
if (deco)
|
|
1855
1863
|
ext.push(decorations.of(view => {
|
|
@@ -2934,15 +2942,19 @@ class DocView extends ContentView {
|
|
|
2934
2942
|
return this.children[i].domAtPos(off);
|
|
2935
2943
|
}
|
|
2936
2944
|
coordsAt(pos, side) {
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2945
|
+
let best = null, bestPos = 0;
|
|
2946
|
+
for (let off = this.length, i = this.children.length - 1; i >= 0; i--) {
|
|
2947
|
+
let child = this.children[i], end = off - child.breakAfter, start = end - child.length;
|
|
2948
|
+
if (end < pos)
|
|
2949
|
+
break;
|
|
2950
|
+
if (start <= pos && (start < pos || child.covers(-1)) && (end > pos || child.covers(1)) &&
|
|
2951
|
+
(!best || child instanceof LineView && !(best instanceof LineView && side >= 0))) {
|
|
2952
|
+
best = child;
|
|
2953
|
+
bestPos = start;
|
|
2954
|
+
}
|
|
2944
2955
|
off = start;
|
|
2945
2956
|
}
|
|
2957
|
+
return best ? best.coordsAt(pos - bestPos, side) : null;
|
|
2946
2958
|
}
|
|
2947
2959
|
coordsForChar(pos) {
|
|
2948
2960
|
let { i, off } = this.childPos(pos, 1), child = this.children[i];
|
|
@@ -3577,13 +3589,13 @@ class InputState {
|
|
|
3577
3589
|
this.lastSelectionTime = Date.now();
|
|
3578
3590
|
}
|
|
3579
3591
|
constructor(view) {
|
|
3592
|
+
this.view = view;
|
|
3580
3593
|
this.lastKeyCode = 0;
|
|
3581
3594
|
this.lastKeyTime = 0;
|
|
3582
3595
|
this.lastTouchTime = 0;
|
|
3583
3596
|
this.lastFocusTime = 0;
|
|
3584
3597
|
this.lastScrollTop = 0;
|
|
3585
3598
|
this.lastScrollLeft = 0;
|
|
3586
|
-
this.chromeScrollHack = -1;
|
|
3587
3599
|
// On iOS, some keys need to have their default behavior happen
|
|
3588
3600
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3589
3601
|
// avoid messing up the virtual keyboard state.
|
|
@@ -3593,8 +3605,7 @@ class InputState {
|
|
|
3593
3605
|
this.lastEscPress = 0;
|
|
3594
3606
|
this.lastContextMenu = 0;
|
|
3595
3607
|
this.scrollHandlers = [];
|
|
3596
|
-
this.
|
|
3597
|
-
this.customHandlers = [];
|
|
3608
|
+
this.handlers = Object.create(null);
|
|
3598
3609
|
// -1 means not in a composition. Otherwise, this counts the number
|
|
3599
3610
|
// of changes made during the composition. The count is used to
|
|
3600
3611
|
// avoid treating the start state of the composition, before any
|
|
@@ -3615,29 +3626,10 @@ class InputState {
|
|
|
3615
3626
|
// the mutation events fire shortly after the compositionend event
|
|
3616
3627
|
this.compositionPendingChange = false;
|
|
3617
3628
|
this.mouseSelection = null;
|
|
3618
|
-
|
|
3619
|
-
if (this.ignoreDuringComposition(event))
|
|
3620
|
-
return;
|
|
3621
|
-
if (event.type == "keydown" && this.keydown(view, event))
|
|
3622
|
-
return;
|
|
3623
|
-
if (this.mustFlushObserver(event))
|
|
3624
|
-
view.observer.forceFlush();
|
|
3625
|
-
if (this.runCustomHandlers(event.type, view, event))
|
|
3626
|
-
event.preventDefault();
|
|
3627
|
-
else
|
|
3628
|
-
handler(view, event);
|
|
3629
|
-
};
|
|
3630
|
-
for (let type in handlers) {
|
|
3631
|
-
let handler = handlers[type];
|
|
3632
|
-
view.contentDOM.addEventListener(type, event => {
|
|
3633
|
-
if (eventBelongsToEditor(view, event))
|
|
3634
|
-
handleEvent(handler, event);
|
|
3635
|
-
}, handlerOptions[type]);
|
|
3636
|
-
this.registeredEvents.push(type);
|
|
3637
|
-
}
|
|
3629
|
+
this.handleEvent = this.handleEvent.bind(this);
|
|
3638
3630
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3639
3631
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3640
|
-
handleEvent(
|
|
3632
|
+
this.handleEvent(event);
|
|
3641
3633
|
if (!event.defaultPrevented && event.button == 2) {
|
|
3642
3634
|
// Make sure the content covers the entire scroller height, in order
|
|
3643
3635
|
// to catch a native context menu click below it
|
|
@@ -3649,23 +3641,8 @@ class InputState {
|
|
|
3649
3641
|
});
|
|
3650
3642
|
view.scrollDOM.addEventListener("drop", (event) => {
|
|
3651
3643
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3652
|
-
handleEvent(
|
|
3644
|
+
this.handleEvent(event);
|
|
3653
3645
|
});
|
|
3654
|
-
if (browser.chrome && browser.chrome_version == 102) { // FIXME remove at some point
|
|
3655
|
-
// On Chrome 102, viewport updates somehow stop wheel-based
|
|
3656
|
-
// scrolling. Turning off pointer events during the scroll seems
|
|
3657
|
-
// to avoid the issue.
|
|
3658
|
-
view.scrollDOM.addEventListener("wheel", () => {
|
|
3659
|
-
if (this.chromeScrollHack < 0)
|
|
3660
|
-
view.contentDOM.style.pointerEvents = "none";
|
|
3661
|
-
else
|
|
3662
|
-
window.clearTimeout(this.chromeScrollHack);
|
|
3663
|
-
this.chromeScrollHack = setTimeout(() => {
|
|
3664
|
-
this.chromeScrollHack = -1;
|
|
3665
|
-
view.contentDOM.style.pointerEvents = "";
|
|
3666
|
-
}, 100);
|
|
3667
|
-
}, { passive: true });
|
|
3668
|
-
}
|
|
3669
3646
|
this.notifiedFocused = view.hasFocus;
|
|
3670
3647
|
// On Safari adding an input event handler somehow prevents an
|
|
3671
3648
|
// issue where the composition vanishes when you press enter.
|
|
@@ -3674,63 +3651,54 @@ class InputState {
|
|
|
3674
3651
|
if (browser.gecko)
|
|
3675
3652
|
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3676
3653
|
}
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
}
|
|
3696
|
-
runCustomHandlers(type, view, event) {
|
|
3697
|
-
for (let set of this.customHandlers) {
|
|
3698
|
-
let handler = set.handlers[type];
|
|
3699
|
-
if (handler) {
|
|
3700
|
-
try {
|
|
3701
|
-
if (handler.call(set.plugin, event, view) || event.defaultPrevented)
|
|
3702
|
-
return true;
|
|
3703
|
-
}
|
|
3704
|
-
catch (e) {
|
|
3705
|
-
logException(view.state, e);
|
|
3654
|
+
handleEvent(event) {
|
|
3655
|
+
if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event))
|
|
3656
|
+
return;
|
|
3657
|
+
if (event.type == "keydown" && this.keydown(event))
|
|
3658
|
+
return;
|
|
3659
|
+
this.runHandlers(event.type, event);
|
|
3660
|
+
}
|
|
3661
|
+
runHandlers(type, event) {
|
|
3662
|
+
let handlers = this.handlers[type];
|
|
3663
|
+
if (handlers) {
|
|
3664
|
+
for (let observer of handlers.observers)
|
|
3665
|
+
observer(this.view, event);
|
|
3666
|
+
for (let handler of handlers.handlers) {
|
|
3667
|
+
if (event.defaultPrevented)
|
|
3668
|
+
break;
|
|
3669
|
+
if (handler(this.view, event)) {
|
|
3670
|
+
event.preventDefault();
|
|
3671
|
+
break;
|
|
3706
3672
|
}
|
|
3707
3673
|
}
|
|
3708
3674
|
}
|
|
3709
|
-
return false;
|
|
3710
3675
|
}
|
|
3711
|
-
|
|
3712
|
-
this.
|
|
3713
|
-
|
|
3714
|
-
|
|
3715
|
-
|
|
3716
|
-
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
catch (e) {
|
|
3721
|
-
logException(view.state, e);
|
|
3676
|
+
ensureHandlers(plugins) {
|
|
3677
|
+
let handlers = computeHandlers(plugins), prev = this.handlers, dom = this.view.contentDOM;
|
|
3678
|
+
for (let type in handlers)
|
|
3679
|
+
if (type != "scroll") {
|
|
3680
|
+
let passive = !handlers[type].handlers.length;
|
|
3681
|
+
let exists = prev[type];
|
|
3682
|
+
if (exists && passive != !exists.handlers.length) {
|
|
3683
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3684
|
+
exists = null;
|
|
3722
3685
|
}
|
|
3686
|
+
if (!exists)
|
|
3687
|
+
dom.addEventListener(type, this.handleEvent, { passive });
|
|
3723
3688
|
}
|
|
3724
|
-
|
|
3689
|
+
for (let type in prev)
|
|
3690
|
+
if (type != "scroll" && !handlers[type])
|
|
3691
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3692
|
+
this.handlers = handlers;
|
|
3725
3693
|
}
|
|
3726
|
-
keydown(
|
|
3694
|
+
keydown(event) {
|
|
3727
3695
|
// Must always run, even if a custom handler handled the event
|
|
3728
3696
|
this.lastKeyCode = event.keyCode;
|
|
3729
3697
|
this.lastKeyTime = Date.now();
|
|
3730
3698
|
if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
|
3731
3699
|
return true;
|
|
3732
3700
|
if (event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3733
|
-
view.inputState.lastEscPress = 0;
|
|
3701
|
+
this.view.inputState.lastEscPress = 0;
|
|
3734
3702
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3735
3703
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
3736
3704
|
// composition changes. When an enter or backspace key event is
|
|
@@ -3738,10 +3706,10 @@ class InputState {
|
|
|
3738
3706
|
// dispatch it.
|
|
3739
3707
|
if (browser.android && browser.chrome && !event.synthetic &&
|
|
3740
3708
|
(event.keyCode == 13 || event.keyCode == 8)) {
|
|
3741
|
-
view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3709
|
+
this.view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3742
3710
|
return true;
|
|
3743
3711
|
}
|
|
3744
|
-
//
|
|
3712
|
+
// Preventing the default behavior of Enter on iOS makes the
|
|
3745
3713
|
// virtual keyboard get stuck in the wrong (lowercase)
|
|
3746
3714
|
// state. So we let it go through, and then, in
|
|
3747
3715
|
// applyDOMChange, notify key handlers of it and reset to
|
|
@@ -3751,17 +3719,19 @@ class InputState {
|
|
|
3751
3719
|
((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
|
|
3752
3720
|
EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
|
|
3753
3721
|
this.pendingIOSKey = pending || event;
|
|
3754
|
-
setTimeout(() => this.flushIOSKey(
|
|
3722
|
+
setTimeout(() => this.flushIOSKey(), 250);
|
|
3755
3723
|
return true;
|
|
3756
3724
|
}
|
|
3725
|
+
if (event.keyCode != 229)
|
|
3726
|
+
this.view.observer.forceFlush();
|
|
3757
3727
|
return false;
|
|
3758
3728
|
}
|
|
3759
|
-
flushIOSKey(
|
|
3729
|
+
flushIOSKey() {
|
|
3760
3730
|
let key = this.pendingIOSKey;
|
|
3761
3731
|
if (!key)
|
|
3762
3732
|
return false;
|
|
3763
3733
|
this.pendingIOSKey = undefined;
|
|
3764
|
-
return dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3734
|
+
return dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
|
3765
3735
|
}
|
|
3766
3736
|
ignoreDuringComposition(event) {
|
|
3767
3737
|
if (!/^key/.test(event.type))
|
|
@@ -3780,9 +3750,6 @@ class InputState {
|
|
|
3780
3750
|
}
|
|
3781
3751
|
return false;
|
|
3782
3752
|
}
|
|
3783
|
-
mustFlushObserver(event) {
|
|
3784
|
-
return event.type == "keydown" && event.keyCode != 229;
|
|
3785
|
-
}
|
|
3786
3753
|
startMouseSelection(mouseSelection) {
|
|
3787
3754
|
if (this.mouseSelection)
|
|
3788
3755
|
this.mouseSelection.destroy();
|
|
@@ -3799,6 +3766,42 @@ class InputState {
|
|
|
3799
3766
|
this.mouseSelection.destroy();
|
|
3800
3767
|
}
|
|
3801
3768
|
}
|
|
3769
|
+
function bindHandler(plugin, handler) {
|
|
3770
|
+
return (view, event) => {
|
|
3771
|
+
try {
|
|
3772
|
+
return handler.call(plugin, event, view);
|
|
3773
|
+
}
|
|
3774
|
+
catch (e) {
|
|
3775
|
+
logException(view.state, e);
|
|
3776
|
+
}
|
|
3777
|
+
};
|
|
3778
|
+
}
|
|
3779
|
+
function computeHandlers(plugins) {
|
|
3780
|
+
let result = Object.create(null);
|
|
3781
|
+
function record(type) {
|
|
3782
|
+
return result[type] || (result[type] = { observers: [], handlers: [] });
|
|
3783
|
+
}
|
|
3784
|
+
for (let plugin of plugins) {
|
|
3785
|
+
let spec = plugin.spec;
|
|
3786
|
+
if (spec && spec.domEventHandlers)
|
|
3787
|
+
for (let type in spec.domEventHandlers) {
|
|
3788
|
+
let f = spec.domEventHandlers[type];
|
|
3789
|
+
if (f)
|
|
3790
|
+
record(type).handlers.push(bindHandler(plugin.value, f));
|
|
3791
|
+
}
|
|
3792
|
+
if (spec && spec.domEventObservers)
|
|
3793
|
+
for (let type in spec.domEventObservers) {
|
|
3794
|
+
let f = spec.domEventObservers[type];
|
|
3795
|
+
if (f)
|
|
3796
|
+
record(type).observers.push(bindHandler(plugin.value, f));
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
for (let type in handlers)
|
|
3800
|
+
record(type).handlers.push(handlers[type]);
|
|
3801
|
+
for (let type in observers)
|
|
3802
|
+
record(type).observers.push(observers[type]);
|
|
3803
|
+
return result;
|
|
3804
|
+
}
|
|
3802
3805
|
const PendingKeys = [
|
|
3803
3806
|
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3804
3807
|
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
@@ -3836,10 +3839,8 @@ class MouseSelection {
|
|
|
3836
3839
|
start(event) {
|
|
3837
3840
|
// When clicking outside of the selection, immediately apply the
|
|
3838
3841
|
// effect of starting the selection
|
|
3839
|
-
if (this.dragging === false)
|
|
3840
|
-
event.preventDefault();
|
|
3842
|
+
if (this.dragging === false)
|
|
3841
3843
|
this.select(event);
|
|
3842
|
-
}
|
|
3843
3844
|
}
|
|
3844
3845
|
move(event) {
|
|
3845
3846
|
var _a;
|
|
@@ -3975,7 +3976,7 @@ function eventBelongsToEditor(view, event) {
|
|
|
3975
3976
|
return true;
|
|
3976
3977
|
}
|
|
3977
3978
|
const handlers = /*@__PURE__*/Object.create(null);
|
|
3978
|
-
const
|
|
3979
|
+
const observers = /*@__PURE__*/Object.create(null);
|
|
3979
3980
|
// This is very crude, but unfortunately both these browsers _pretend_
|
|
3980
3981
|
// that they have a clipboard API—all the objects and methods are
|
|
3981
3982
|
// there, they just don't work, and they are hard to test.
|
|
@@ -4025,23 +4026,27 @@ function doPaste(view, input) {
|
|
|
4025
4026
|
scrollIntoView: true
|
|
4026
4027
|
});
|
|
4027
4028
|
}
|
|
4029
|
+
observers.scroll = view => {
|
|
4030
|
+
view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
|
|
4031
|
+
view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
4032
|
+
};
|
|
4028
4033
|
handlers.keydown = (view, event) => {
|
|
4029
4034
|
view.inputState.setSelectionOrigin("select");
|
|
4030
4035
|
if (event.keyCode == 27)
|
|
4031
4036
|
view.inputState.lastEscPress = Date.now();
|
|
4037
|
+
return false;
|
|
4032
4038
|
};
|
|
4033
|
-
|
|
4039
|
+
observers.touchstart = (view, e) => {
|
|
4034
4040
|
view.inputState.lastTouchTime = Date.now();
|
|
4035
4041
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4036
4042
|
};
|
|
4037
|
-
|
|
4043
|
+
observers.touchmove = view => {
|
|
4038
4044
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4039
4045
|
};
|
|
4040
|
-
handlerOptions.touchstart = handlerOptions.touchmove = { passive: true };
|
|
4041
4046
|
handlers.mousedown = (view, event) => {
|
|
4042
4047
|
view.observer.flush();
|
|
4043
4048
|
if (view.inputState.lastTouchTime > Date.now() - 2000)
|
|
4044
|
-
return; // Ignore touch interaction
|
|
4049
|
+
return false; // Ignore touch interaction
|
|
4045
4050
|
let style = null;
|
|
4046
4051
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
4047
4052
|
style = makeStyle(view, event);
|
|
@@ -4055,9 +4060,13 @@ handlers.mousedown = (view, event) => {
|
|
|
4055
4060
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4056
4061
|
if (mustFocus)
|
|
4057
4062
|
view.observer.ignore(() => focusPreventScroll(view.contentDOM));
|
|
4058
|
-
|
|
4059
|
-
|
|
4063
|
+
let mouseSel = view.inputState.mouseSelection;
|
|
4064
|
+
if (mouseSel) {
|
|
4065
|
+
mouseSel.start(event);
|
|
4066
|
+
return !mouseSel.dragging;
|
|
4067
|
+
}
|
|
4060
4068
|
}
|
|
4069
|
+
return false;
|
|
4061
4070
|
};
|
|
4062
4071
|
function rangeForClick(view, pos, bias, type) {
|
|
4063
4072
|
if (type == 1) { // Single click
|
|
@@ -4161,12 +4170,12 @@ handlers.dragstart = (view, event) => {
|
|
|
4161
4170
|
event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to));
|
|
4162
4171
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4163
4172
|
}
|
|
4173
|
+
return false;
|
|
4164
4174
|
};
|
|
4165
4175
|
function dropText(view, event, text, direct) {
|
|
4166
4176
|
if (!text)
|
|
4167
4177
|
return;
|
|
4168
4178
|
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
4169
|
-
event.preventDefault();
|
|
4170
4179
|
let { mouseSelection } = view.inputState;
|
|
4171
4180
|
let del = direct && mouseSelection && mouseSelection.dragging && dragMovesSelection(view, event) ?
|
|
4172
4181
|
{ from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null;
|
|
@@ -4181,12 +4190,11 @@ function dropText(view, event, text, direct) {
|
|
|
4181
4190
|
}
|
|
4182
4191
|
handlers.drop = (view, event) => {
|
|
4183
4192
|
if (!event.dataTransfer)
|
|
4184
|
-
return;
|
|
4193
|
+
return false;
|
|
4185
4194
|
if (view.state.readOnly)
|
|
4186
|
-
return
|
|
4195
|
+
return true;
|
|
4187
4196
|
let files = event.dataTransfer.files;
|
|
4188
4197
|
if (files && files.length) { // For a file drop, read the file's text.
|
|
4189
|
-
event.preventDefault();
|
|
4190
4198
|
let text = Array(files.length), read = 0;
|
|
4191
4199
|
let finishFile = () => {
|
|
4192
4200
|
if (++read == files.length)
|
|
@@ -4202,22 +4210,29 @@ handlers.drop = (view, event) => {
|
|
|
4202
4210
|
};
|
|
4203
4211
|
reader.readAsText(files[i]);
|
|
4204
4212
|
}
|
|
4213
|
+
return true;
|
|
4205
4214
|
}
|
|
4206
4215
|
else {
|
|
4207
|
-
|
|
4216
|
+
let text = event.dataTransfer.getData("Text");
|
|
4217
|
+
if (text) {
|
|
4218
|
+
dropText(view, event, text, true);
|
|
4219
|
+
return true;
|
|
4220
|
+
}
|
|
4208
4221
|
}
|
|
4222
|
+
return false;
|
|
4209
4223
|
};
|
|
4210
4224
|
handlers.paste = (view, event) => {
|
|
4211
4225
|
if (view.state.readOnly)
|
|
4212
|
-
return
|
|
4226
|
+
return true;
|
|
4213
4227
|
view.observer.flush();
|
|
4214
4228
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4215
4229
|
if (data) {
|
|
4216
4230
|
doPaste(view, data.getData("text/plain") || data.getData("text/uri-text"));
|
|
4217
|
-
|
|
4231
|
+
return true;
|
|
4218
4232
|
}
|
|
4219
4233
|
else {
|
|
4220
4234
|
capturePaste(view);
|
|
4235
|
+
return false;
|
|
4221
4236
|
}
|
|
4222
4237
|
};
|
|
4223
4238
|
function captureCopy(view, text) {
|
|
@@ -4263,23 +4278,24 @@ let lastLinewiseCopy = null;
|
|
|
4263
4278
|
handlers.copy = handlers.cut = (view, event) => {
|
|
4264
4279
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
4265
4280
|
if (!text && !linewise)
|
|
4266
|
-
return;
|
|
4281
|
+
return false;
|
|
4267
4282
|
lastLinewiseCopy = linewise ? text : null;
|
|
4283
|
+
if (event.type == "cut" && !view.state.readOnly)
|
|
4284
|
+
view.dispatch({
|
|
4285
|
+
changes: ranges,
|
|
4286
|
+
scrollIntoView: true,
|
|
4287
|
+
userEvent: "delete.cut"
|
|
4288
|
+
});
|
|
4268
4289
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4269
4290
|
if (data) {
|
|
4270
|
-
event.preventDefault();
|
|
4271
4291
|
data.clearData();
|
|
4272
4292
|
data.setData("text/plain", text);
|
|
4293
|
+
return true;
|
|
4273
4294
|
}
|
|
4274
4295
|
else {
|
|
4275
4296
|
captureCopy(view, text);
|
|
4297
|
+
return false;
|
|
4276
4298
|
}
|
|
4277
|
-
if (event.type == "cut" && !view.state.readOnly)
|
|
4278
|
-
view.dispatch({
|
|
4279
|
-
changes: ranges,
|
|
4280
|
-
scrollIntoView: true,
|
|
4281
|
-
userEvent: "delete.cut"
|
|
4282
|
-
});
|
|
4283
4299
|
};
|
|
4284
4300
|
const isFocusChange = /*@__PURE__*/Annotation.define();
|
|
4285
4301
|
function focusChangeTransaction(state, focus) {
|
|
@@ -4303,7 +4319,7 @@ function updateForFocusChange(view) {
|
|
|
4303
4319
|
}
|
|
4304
4320
|
}, 10);
|
|
4305
4321
|
}
|
|
4306
|
-
|
|
4322
|
+
observers.focus = view => {
|
|
4307
4323
|
view.inputState.lastFocusTime = Date.now();
|
|
4308
4324
|
// When focusing reset the scroll position, move it back to where it was
|
|
4309
4325
|
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
|
|
@@ -4312,11 +4328,11 @@ handlers.focus = view => {
|
|
|
4312
4328
|
}
|
|
4313
4329
|
updateForFocusChange(view);
|
|
4314
4330
|
};
|
|
4315
|
-
|
|
4331
|
+
observers.blur = view => {
|
|
4316
4332
|
view.observer.clearSelectionRange();
|
|
4317
4333
|
updateForFocusChange(view);
|
|
4318
4334
|
};
|
|
4319
|
-
|
|
4335
|
+
observers.compositionstart = observers.compositionupdate = view => {
|
|
4320
4336
|
if (view.inputState.compositionFirstChange == null)
|
|
4321
4337
|
view.inputState.compositionFirstChange = true;
|
|
4322
4338
|
if (view.inputState.composing < 0) {
|
|
@@ -4324,7 +4340,7 @@ handlers.compositionstart = handlers.compositionupdate = view => {
|
|
|
4324
4340
|
view.inputState.composing = 0;
|
|
4325
4341
|
}
|
|
4326
4342
|
};
|
|
4327
|
-
|
|
4343
|
+
observers.compositionend = view => {
|
|
4328
4344
|
view.inputState.composing = -1;
|
|
4329
4345
|
view.inputState.compositionEndedAt = Date.now();
|
|
4330
4346
|
view.inputState.compositionPendingKey = true;
|
|
@@ -4348,7 +4364,7 @@ handlers.compositionend = view => {
|
|
|
4348
4364
|
}, 50);
|
|
4349
4365
|
}
|
|
4350
4366
|
};
|
|
4351
|
-
|
|
4367
|
+
observers.contextmenu = view => {
|
|
4352
4368
|
view.inputState.lastContextMenu = Date.now();
|
|
4353
4369
|
};
|
|
4354
4370
|
handlers.beforeinput = (view, event) => {
|
|
@@ -4377,6 +4393,7 @@ handlers.beforeinput = (view, event) => {
|
|
|
4377
4393
|
}, 100);
|
|
4378
4394
|
}
|
|
4379
4395
|
}
|
|
4396
|
+
return false;
|
|
4380
4397
|
};
|
|
4381
4398
|
const appliedFirefoxHack = /*@__PURE__*/new Set;
|
|
4382
4399
|
// In Firefox, when cut/copy handlers are added to the document, that
|
|
@@ -5046,14 +5063,13 @@ class NodeBuilder {
|
|
|
5046
5063
|
return line;
|
|
5047
5064
|
}
|
|
5048
5065
|
addBlock(block) {
|
|
5049
|
-
var _a;
|
|
5050
5066
|
this.enterLine();
|
|
5051
|
-
let
|
|
5052
|
-
if (
|
|
5067
|
+
let deco = block.deco;
|
|
5068
|
+
if (deco && deco.startSide > 0 && !this.isCovered)
|
|
5053
5069
|
this.ensureLine();
|
|
5054
5070
|
this.nodes.push(block);
|
|
5055
5071
|
this.writtenTo = this.pos = this.pos + block.length;
|
|
5056
|
-
if (
|
|
5072
|
+
if (deco && deco.endSide > 0)
|
|
5057
5073
|
this.covering = block;
|
|
5058
5074
|
}
|
|
5059
5075
|
addLineDeco(height, breaks, length) {
|
|
@@ -6161,7 +6177,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6161
6177
|
change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
|
6162
6178
|
}
|
|
6163
6179
|
if (change) {
|
|
6164
|
-
if (browser.ios && view.inputState.flushIOSKey(
|
|
6180
|
+
if (browser.ios && view.inputState.flushIOSKey())
|
|
6165
6181
|
return true;
|
|
6166
6182
|
// Android browsers don't fire reasonable key events for enter,
|
|
6167
6183
|
// backspace, or delete. So this detects changes that look like
|
|
@@ -6415,7 +6431,7 @@ class DOMObserver {
|
|
|
6415
6431
|
this.readSelectionRange();
|
|
6416
6432
|
}
|
|
6417
6433
|
onScrollChanged(e) {
|
|
6418
|
-
this.view.inputState.
|
|
6434
|
+
this.view.inputState.runHandlers("scroll", e);
|
|
6419
6435
|
if (this.intersecting)
|
|
6420
6436
|
this.view.measure();
|
|
6421
6437
|
}
|
|
@@ -6886,7 +6902,7 @@ class EditorView {
|
|
|
6886
6902
|
plugin.update(this);
|
|
6887
6903
|
this.observer = new DOMObserver(this);
|
|
6888
6904
|
this.inputState = new InputState(this);
|
|
6889
|
-
this.inputState.ensureHandlers(this
|
|
6905
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
6890
6906
|
this.docView = new DocView(this);
|
|
6891
6907
|
this.mountStyles();
|
|
6892
6908
|
this.updateAttrs();
|
|
@@ -7028,7 +7044,7 @@ class EditorView {
|
|
|
7028
7044
|
for (let plugin of this.plugins)
|
|
7029
7045
|
plugin.update(this);
|
|
7030
7046
|
this.docView = new DocView(this);
|
|
7031
|
-
this.inputState.ensureHandlers(this
|
|
7047
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7032
7048
|
this.mountStyles();
|
|
7033
7049
|
this.updateAttrs();
|
|
7034
7050
|
this.bidiCache = [];
|
|
@@ -7060,7 +7076,7 @@ class EditorView {
|
|
|
7060
7076
|
plugin.destroy(this);
|
|
7061
7077
|
this.plugins = newPlugins;
|
|
7062
7078
|
this.pluginMap.clear();
|
|
7063
|
-
this.inputState.ensureHandlers(this
|
|
7079
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7064
7080
|
}
|
|
7065
7081
|
else {
|
|
7066
7082
|
for (let p of this.plugins)
|
|
@@ -7588,6 +7604,17 @@ class EditorView {
|
|
|
7588
7604
|
return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
|
7589
7605
|
}
|
|
7590
7606
|
/**
|
|
7607
|
+
Create an extension that registers DOM event observers. Contrary
|
|
7608
|
+
to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers),
|
|
7609
|
+
observers can't be prevented from running by a higher-precedence
|
|
7610
|
+
handler returning true. They also don't prevent other handlers
|
|
7611
|
+
and observers from running when they return true, and should not
|
|
7612
|
+
call `preventDefault`.
|
|
7613
|
+
*/
|
|
7614
|
+
static domEventObservers(observers) {
|
|
7615
|
+
return ViewPlugin.define(() => ({}), { eventObservers: observers });
|
|
7616
|
+
}
|
|
7617
|
+
/**
|
|
7591
7618
|
Create a theme extension. The first argument can be a
|
|
7592
7619
|
[`style-mod`](https://github.com/marijnh/style-mod#documentation)
|
|
7593
7620
|
style spec providing the styles for the theme. These will be
|
|
@@ -8440,7 +8467,7 @@ const drawDropCursor = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
8440
8467
|
this.view.dispatch({ effects: setDropCursorPos.of(pos) });
|
|
8441
8468
|
}
|
|
8442
8469
|
}, {
|
|
8443
|
-
|
|
8470
|
+
eventObservers: {
|
|
8444
8471
|
dragover(event) {
|
|
8445
8472
|
this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
|
|
8446
8473
|
},
|
|
@@ -8950,7 +8977,7 @@ function crosshairCursor(options = {}) {
|
|
|
8950
8977
|
}
|
|
8951
8978
|
}
|
|
8952
8979
|
}, {
|
|
8953
|
-
|
|
8980
|
+
eventObservers: {
|
|
8954
8981
|
keydown(e) {
|
|
8955
8982
|
this.set(e.keyCode == code || getter(e));
|
|
8956
8983
|
},
|
|
@@ -9261,7 +9288,7 @@ const tooltipPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
|
|
|
9261
9288
|
}
|
|
9262
9289
|
}
|
|
9263
9290
|
}, {
|
|
9264
|
-
|
|
9291
|
+
eventObservers: {
|
|
9265
9292
|
scroll() { this.maybeMeasure(); }
|
|
9266
9293
|
}
|
|
9267
9294
|
});
|