@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.cjs
CHANGED
|
@@ -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
|
|
@@ -1252,353 +1482,127 @@ class Decoration extends state.RangeValue {
|
|
|
1252
1482
|
let block = !!spec.block, startSide, endSide;
|
|
1253
1483
|
if (spec.isBlockGap) {
|
|
1254
1484
|
startSide = -500000000 /* Side.GapStart */;
|
|
1255
|
-
endSide = 400000000 /* Side.GapEnd */;
|
|
1256
|
-
}
|
|
1257
|
-
else {
|
|
1258
|
-
let { start, end } = getInclusive(spec, block);
|
|
1259
|
-
startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
|
|
1260
|
-
endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1;
|
|
1261
|
-
}
|
|
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
|
-
}
|
|
1485
|
+
endSide = 400000000 /* Side.GapEnd */;
|
|
1515
1486
|
}
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
static find(docView, pos) {
|
|
1521
|
-
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1522
|
-
let block = docView.children[i], end = off + block.length;
|
|
1523
|
-
if (end >= pos) {
|
|
1524
|
-
if (block instanceof LineView)
|
|
1525
|
-
return block;
|
|
1526
|
-
if (end > pos)
|
|
1527
|
-
break;
|
|
1528
|
-
}
|
|
1529
|
-
off = end + block.breakAfter;
|
|
1487
|
+
else {
|
|
1488
|
+
let { start, end } = getInclusive(spec, block);
|
|
1489
|
+
startSide = (start ? (block ? -300000000 /* Side.BlockIncStart */ : -1 /* Side.InlineIncStart */) : 500000000 /* Side.NonIncStart */) - 1;
|
|
1490
|
+
endSide = (end ? (block ? 200000000 /* Side.BlockIncEnd */ : 1 /* Side.InlineIncEnd */) : -600000000 /* Side.NonIncEnd */) + 1;
|
|
1530
1491
|
}
|
|
1531
|
-
return null;
|
|
1492
|
+
return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
|
1493
|
+
}
|
|
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];
|
|
@@ -3581,13 +3593,13 @@ class InputState {
|
|
|
3581
3593
|
this.lastSelectionTime = Date.now();
|
|
3582
3594
|
}
|
|
3583
3595
|
constructor(view) {
|
|
3596
|
+
this.view = view;
|
|
3584
3597
|
this.lastKeyCode = 0;
|
|
3585
3598
|
this.lastKeyTime = 0;
|
|
3586
3599
|
this.lastTouchTime = 0;
|
|
3587
3600
|
this.lastFocusTime = 0;
|
|
3588
3601
|
this.lastScrollTop = 0;
|
|
3589
3602
|
this.lastScrollLeft = 0;
|
|
3590
|
-
this.chromeScrollHack = -1;
|
|
3591
3603
|
// On iOS, some keys need to have their default behavior happen
|
|
3592
3604
|
// (after which we retroactively handle them and reset the DOM) to
|
|
3593
3605
|
// avoid messing up the virtual keyboard state.
|
|
@@ -3597,8 +3609,7 @@ class InputState {
|
|
|
3597
3609
|
this.lastEscPress = 0;
|
|
3598
3610
|
this.lastContextMenu = 0;
|
|
3599
3611
|
this.scrollHandlers = [];
|
|
3600
|
-
this.
|
|
3601
|
-
this.customHandlers = [];
|
|
3612
|
+
this.handlers = Object.create(null);
|
|
3602
3613
|
// -1 means not in a composition. Otherwise, this counts the number
|
|
3603
3614
|
// of changes made during the composition. The count is used to
|
|
3604
3615
|
// avoid treating the start state of the composition, before any
|
|
@@ -3619,29 +3630,10 @@ class InputState {
|
|
|
3619
3630
|
// the mutation events fire shortly after the compositionend event
|
|
3620
3631
|
this.compositionPendingChange = false;
|
|
3621
3632
|
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
|
-
}
|
|
3633
|
+
this.handleEvent = this.handleEvent.bind(this);
|
|
3642
3634
|
view.scrollDOM.addEventListener("mousedown", (event) => {
|
|
3643
3635
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom) {
|
|
3644
|
-
handleEvent(
|
|
3636
|
+
this.handleEvent(event);
|
|
3645
3637
|
if (!event.defaultPrevented && event.button == 2) {
|
|
3646
3638
|
// Make sure the content covers the entire scroller height, in order
|
|
3647
3639
|
// to catch a native context menu click below it
|
|
@@ -3653,23 +3645,8 @@ class InputState {
|
|
|
3653
3645
|
});
|
|
3654
3646
|
view.scrollDOM.addEventListener("drop", (event) => {
|
|
3655
3647
|
if (event.target == view.scrollDOM && event.clientY > view.contentDOM.getBoundingClientRect().bottom)
|
|
3656
|
-
handleEvent(
|
|
3648
|
+
this.handleEvent(event);
|
|
3657
3649
|
});
|
|
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
3650
|
this.notifiedFocused = view.hasFocus;
|
|
3674
3651
|
// On Safari adding an input event handler somehow prevents an
|
|
3675
3652
|
// issue where the composition vanishes when you press enter.
|
|
@@ -3678,63 +3655,54 @@ class InputState {
|
|
|
3678
3655
|
if (browser.gecko)
|
|
3679
3656
|
firefoxCopyCutHack(view.contentDOM.ownerDocument);
|
|
3680
3657
|
}
|
|
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);
|
|
3658
|
+
handleEvent(event) {
|
|
3659
|
+
if (!eventBelongsToEditor(this.view, event) || this.ignoreDuringComposition(event))
|
|
3660
|
+
return;
|
|
3661
|
+
if (event.type == "keydown" && this.keydown(event))
|
|
3662
|
+
return;
|
|
3663
|
+
this.runHandlers(event.type, event);
|
|
3664
|
+
}
|
|
3665
|
+
runHandlers(type, event) {
|
|
3666
|
+
let handlers = this.handlers[type];
|
|
3667
|
+
if (handlers) {
|
|
3668
|
+
for (let observer of handlers.observers)
|
|
3669
|
+
observer(this.view, event);
|
|
3670
|
+
for (let handler of handlers.handlers) {
|
|
3671
|
+
if (event.defaultPrevented)
|
|
3672
|
+
break;
|
|
3673
|
+
if (handler(this.view, event)) {
|
|
3674
|
+
event.preventDefault();
|
|
3675
|
+
break;
|
|
3710
3676
|
}
|
|
3711
3677
|
}
|
|
3712
3678
|
}
|
|
3713
|
-
return false;
|
|
3714
3679
|
}
|
|
3715
|
-
|
|
3716
|
-
this.
|
|
3717
|
-
|
|
3718
|
-
|
|
3719
|
-
|
|
3720
|
-
|
|
3721
|
-
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
catch (e) {
|
|
3725
|
-
logException(view.state, e);
|
|
3680
|
+
ensureHandlers(plugins) {
|
|
3681
|
+
let handlers = computeHandlers(plugins), prev = this.handlers, dom = this.view.contentDOM;
|
|
3682
|
+
for (let type in handlers)
|
|
3683
|
+
if (type != "scroll") {
|
|
3684
|
+
let passive = !handlers[type].handlers.length;
|
|
3685
|
+
let exists = prev[type];
|
|
3686
|
+
if (exists && passive != !exists.handlers.length) {
|
|
3687
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3688
|
+
exists = null;
|
|
3726
3689
|
}
|
|
3690
|
+
if (!exists)
|
|
3691
|
+
dom.addEventListener(type, this.handleEvent, { passive });
|
|
3727
3692
|
}
|
|
3728
|
-
|
|
3693
|
+
for (let type in prev)
|
|
3694
|
+
if (type != "scroll" && !handlers[type])
|
|
3695
|
+
dom.removeEventListener(type, this.handleEvent);
|
|
3696
|
+
this.handlers = handlers;
|
|
3729
3697
|
}
|
|
3730
|
-
keydown(
|
|
3698
|
+
keydown(event) {
|
|
3731
3699
|
// Must always run, even if a custom handler handled the event
|
|
3732
3700
|
this.lastKeyCode = event.keyCode;
|
|
3733
3701
|
this.lastKeyTime = Date.now();
|
|
3734
3702
|
if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
|
3735
3703
|
return true;
|
|
3736
3704
|
if (event.keyCode != 27 && modifierCodes.indexOf(event.keyCode) < 0)
|
|
3737
|
-
view.inputState.lastEscPress = 0;
|
|
3705
|
+
this.view.inputState.lastEscPress = 0;
|
|
3738
3706
|
// Chrome for Android usually doesn't fire proper key events, but
|
|
3739
3707
|
// occasionally does, usually surrounded by a bunch of complicated
|
|
3740
3708
|
// composition changes. When an enter or backspace key event is
|
|
@@ -3742,10 +3710,10 @@ class InputState {
|
|
|
3742
3710
|
// dispatch it.
|
|
3743
3711
|
if (browser.android && browser.chrome && !event.synthetic &&
|
|
3744
3712
|
(event.keyCode == 13 || event.keyCode == 8)) {
|
|
3745
|
-
view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3713
|
+
this.view.observer.delayAndroidKey(event.key, event.keyCode);
|
|
3746
3714
|
return true;
|
|
3747
3715
|
}
|
|
3748
|
-
//
|
|
3716
|
+
// Preventing the default behavior of Enter on iOS makes the
|
|
3749
3717
|
// virtual keyboard get stuck in the wrong (lowercase)
|
|
3750
3718
|
// state. So we let it go through, and then, in
|
|
3751
3719
|
// applyDOMChange, notify key handlers of it and reset to
|
|
@@ -3755,17 +3723,19 @@ class InputState {
|
|
|
3755
3723
|
((pending = PendingKeys.find(key => key.keyCode == event.keyCode)) && !event.ctrlKey ||
|
|
3756
3724
|
EmacsyPendingKeys.indexOf(event.key) > -1 && event.ctrlKey && !event.shiftKey)) {
|
|
3757
3725
|
this.pendingIOSKey = pending || event;
|
|
3758
|
-
setTimeout(() => this.flushIOSKey(
|
|
3726
|
+
setTimeout(() => this.flushIOSKey(), 250);
|
|
3759
3727
|
return true;
|
|
3760
3728
|
}
|
|
3729
|
+
if (event.keyCode != 229)
|
|
3730
|
+
this.view.observer.forceFlush();
|
|
3761
3731
|
return false;
|
|
3762
3732
|
}
|
|
3763
|
-
flushIOSKey(
|
|
3733
|
+
flushIOSKey() {
|
|
3764
3734
|
let key = this.pendingIOSKey;
|
|
3765
3735
|
if (!key)
|
|
3766
3736
|
return false;
|
|
3767
3737
|
this.pendingIOSKey = undefined;
|
|
3768
|
-
return dispatchKey(view.contentDOM, key.key, key.keyCode);
|
|
3738
|
+
return dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
|
3769
3739
|
}
|
|
3770
3740
|
ignoreDuringComposition(event) {
|
|
3771
3741
|
if (!/^key/.test(event.type))
|
|
@@ -3784,9 +3754,6 @@ class InputState {
|
|
|
3784
3754
|
}
|
|
3785
3755
|
return false;
|
|
3786
3756
|
}
|
|
3787
|
-
mustFlushObserver(event) {
|
|
3788
|
-
return event.type == "keydown" && event.keyCode != 229;
|
|
3789
|
-
}
|
|
3790
3757
|
startMouseSelection(mouseSelection) {
|
|
3791
3758
|
if (this.mouseSelection)
|
|
3792
3759
|
this.mouseSelection.destroy();
|
|
@@ -3803,6 +3770,42 @@ class InputState {
|
|
|
3803
3770
|
this.mouseSelection.destroy();
|
|
3804
3771
|
}
|
|
3805
3772
|
}
|
|
3773
|
+
function bindHandler(plugin, handler) {
|
|
3774
|
+
return (view, event) => {
|
|
3775
|
+
try {
|
|
3776
|
+
return handler.call(plugin, event, view);
|
|
3777
|
+
}
|
|
3778
|
+
catch (e) {
|
|
3779
|
+
logException(view.state, e);
|
|
3780
|
+
}
|
|
3781
|
+
};
|
|
3782
|
+
}
|
|
3783
|
+
function computeHandlers(plugins) {
|
|
3784
|
+
let result = Object.create(null);
|
|
3785
|
+
function record(type) {
|
|
3786
|
+
return result[type] || (result[type] = { observers: [], handlers: [] });
|
|
3787
|
+
}
|
|
3788
|
+
for (let plugin of plugins) {
|
|
3789
|
+
let spec = plugin.spec;
|
|
3790
|
+
if (spec && spec.domEventHandlers)
|
|
3791
|
+
for (let type in spec.domEventHandlers) {
|
|
3792
|
+
let f = spec.domEventHandlers[type];
|
|
3793
|
+
if (f)
|
|
3794
|
+
record(type).handlers.push(bindHandler(plugin.value, f));
|
|
3795
|
+
}
|
|
3796
|
+
if (spec && spec.domEventObservers)
|
|
3797
|
+
for (let type in spec.domEventObservers) {
|
|
3798
|
+
let f = spec.domEventObservers[type];
|
|
3799
|
+
if (f)
|
|
3800
|
+
record(type).observers.push(bindHandler(plugin.value, f));
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
for (let type in handlers)
|
|
3804
|
+
record(type).handlers.push(handlers[type]);
|
|
3805
|
+
for (let type in observers)
|
|
3806
|
+
record(type).observers.push(observers[type]);
|
|
3807
|
+
return result;
|
|
3808
|
+
}
|
|
3806
3809
|
const PendingKeys = [
|
|
3807
3810
|
{ key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
|
3808
3811
|
{ key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
|
@@ -3840,10 +3843,8 @@ class MouseSelection {
|
|
|
3840
3843
|
start(event) {
|
|
3841
3844
|
// When clicking outside of the selection, immediately apply the
|
|
3842
3845
|
// effect of starting the selection
|
|
3843
|
-
if (this.dragging === false)
|
|
3844
|
-
event.preventDefault();
|
|
3846
|
+
if (this.dragging === false)
|
|
3845
3847
|
this.select(event);
|
|
3846
|
-
}
|
|
3847
3848
|
}
|
|
3848
3849
|
move(event) {
|
|
3849
3850
|
var _a;
|
|
@@ -3979,7 +3980,7 @@ function eventBelongsToEditor(view, event) {
|
|
|
3979
3980
|
return true;
|
|
3980
3981
|
}
|
|
3981
3982
|
const handlers = Object.create(null);
|
|
3982
|
-
const
|
|
3983
|
+
const observers = Object.create(null);
|
|
3983
3984
|
// This is very crude, but unfortunately both these browsers _pretend_
|
|
3984
3985
|
// that they have a clipboard API—all the objects and methods are
|
|
3985
3986
|
// there, they just don't work, and they are hard to test.
|
|
@@ -4029,23 +4030,27 @@ function doPaste(view, input) {
|
|
|
4029
4030
|
scrollIntoView: true
|
|
4030
4031
|
});
|
|
4031
4032
|
}
|
|
4033
|
+
observers.scroll = view => {
|
|
4034
|
+
view.inputState.lastScrollTop = view.scrollDOM.scrollTop;
|
|
4035
|
+
view.inputState.lastScrollLeft = view.scrollDOM.scrollLeft;
|
|
4036
|
+
};
|
|
4032
4037
|
handlers.keydown = (view, event) => {
|
|
4033
4038
|
view.inputState.setSelectionOrigin("select");
|
|
4034
4039
|
if (event.keyCode == 27)
|
|
4035
4040
|
view.inputState.lastEscPress = Date.now();
|
|
4041
|
+
return false;
|
|
4036
4042
|
};
|
|
4037
|
-
|
|
4043
|
+
observers.touchstart = (view, e) => {
|
|
4038
4044
|
view.inputState.lastTouchTime = Date.now();
|
|
4039
4045
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4040
4046
|
};
|
|
4041
|
-
|
|
4047
|
+
observers.touchmove = view => {
|
|
4042
4048
|
view.inputState.setSelectionOrigin("select.pointer");
|
|
4043
4049
|
};
|
|
4044
|
-
handlerOptions.touchstart = handlerOptions.touchmove = { passive: true };
|
|
4045
4050
|
handlers.mousedown = (view, event) => {
|
|
4046
4051
|
view.observer.flush();
|
|
4047
4052
|
if (view.inputState.lastTouchTime > Date.now() - 2000)
|
|
4048
|
-
return; // Ignore touch interaction
|
|
4053
|
+
return false; // Ignore touch interaction
|
|
4049
4054
|
let style = null;
|
|
4050
4055
|
for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
|
4051
4056
|
style = makeStyle(view, event);
|
|
@@ -4059,9 +4064,13 @@ handlers.mousedown = (view, event) => {
|
|
|
4059
4064
|
view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
|
4060
4065
|
if (mustFocus)
|
|
4061
4066
|
view.observer.ignore(() => focusPreventScroll(view.contentDOM));
|
|
4062
|
-
|
|
4063
|
-
|
|
4067
|
+
let mouseSel = view.inputState.mouseSelection;
|
|
4068
|
+
if (mouseSel) {
|
|
4069
|
+
mouseSel.start(event);
|
|
4070
|
+
return !mouseSel.dragging;
|
|
4071
|
+
}
|
|
4064
4072
|
}
|
|
4073
|
+
return false;
|
|
4065
4074
|
};
|
|
4066
4075
|
function rangeForClick(view, pos, bias, type) {
|
|
4067
4076
|
if (type == 1) { // Single click
|
|
@@ -4165,12 +4174,12 @@ handlers.dragstart = (view, event) => {
|
|
|
4165
4174
|
event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to));
|
|
4166
4175
|
event.dataTransfer.effectAllowed = "copyMove";
|
|
4167
4176
|
}
|
|
4177
|
+
return false;
|
|
4168
4178
|
};
|
|
4169
4179
|
function dropText(view, event, text, direct) {
|
|
4170
4180
|
if (!text)
|
|
4171
4181
|
return;
|
|
4172
4182
|
let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
|
4173
|
-
event.preventDefault();
|
|
4174
4183
|
let { mouseSelection } = view.inputState;
|
|
4175
4184
|
let del = direct && mouseSelection && mouseSelection.dragging && dragMovesSelection(view, event) ?
|
|
4176
4185
|
{ from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null;
|
|
@@ -4185,12 +4194,11 @@ function dropText(view, event, text, direct) {
|
|
|
4185
4194
|
}
|
|
4186
4195
|
handlers.drop = (view, event) => {
|
|
4187
4196
|
if (!event.dataTransfer)
|
|
4188
|
-
return;
|
|
4197
|
+
return false;
|
|
4189
4198
|
if (view.state.readOnly)
|
|
4190
|
-
return
|
|
4199
|
+
return true;
|
|
4191
4200
|
let files = event.dataTransfer.files;
|
|
4192
4201
|
if (files && files.length) { // For a file drop, read the file's text.
|
|
4193
|
-
event.preventDefault();
|
|
4194
4202
|
let text = Array(files.length), read = 0;
|
|
4195
4203
|
let finishFile = () => {
|
|
4196
4204
|
if (++read == files.length)
|
|
@@ -4206,22 +4214,29 @@ handlers.drop = (view, event) => {
|
|
|
4206
4214
|
};
|
|
4207
4215
|
reader.readAsText(files[i]);
|
|
4208
4216
|
}
|
|
4217
|
+
return true;
|
|
4209
4218
|
}
|
|
4210
4219
|
else {
|
|
4211
|
-
|
|
4220
|
+
let text = event.dataTransfer.getData("Text");
|
|
4221
|
+
if (text) {
|
|
4222
|
+
dropText(view, event, text, true);
|
|
4223
|
+
return true;
|
|
4224
|
+
}
|
|
4212
4225
|
}
|
|
4226
|
+
return false;
|
|
4213
4227
|
};
|
|
4214
4228
|
handlers.paste = (view, event) => {
|
|
4215
4229
|
if (view.state.readOnly)
|
|
4216
|
-
return
|
|
4230
|
+
return true;
|
|
4217
4231
|
view.observer.flush();
|
|
4218
4232
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4219
4233
|
if (data) {
|
|
4220
4234
|
doPaste(view, data.getData("text/plain") || data.getData("text/uri-text"));
|
|
4221
|
-
|
|
4235
|
+
return true;
|
|
4222
4236
|
}
|
|
4223
4237
|
else {
|
|
4224
4238
|
capturePaste(view);
|
|
4239
|
+
return false;
|
|
4225
4240
|
}
|
|
4226
4241
|
};
|
|
4227
4242
|
function captureCopy(view, text) {
|
|
@@ -4267,23 +4282,24 @@ let lastLinewiseCopy = null;
|
|
|
4267
4282
|
handlers.copy = handlers.cut = (view, event) => {
|
|
4268
4283
|
let { text, ranges, linewise } = copiedRange(view.state);
|
|
4269
4284
|
if (!text && !linewise)
|
|
4270
|
-
return;
|
|
4285
|
+
return false;
|
|
4271
4286
|
lastLinewiseCopy = linewise ? text : null;
|
|
4287
|
+
if (event.type == "cut" && !view.state.readOnly)
|
|
4288
|
+
view.dispatch({
|
|
4289
|
+
changes: ranges,
|
|
4290
|
+
scrollIntoView: true,
|
|
4291
|
+
userEvent: "delete.cut"
|
|
4292
|
+
});
|
|
4272
4293
|
let data = brokenClipboardAPI ? null : event.clipboardData;
|
|
4273
4294
|
if (data) {
|
|
4274
|
-
event.preventDefault();
|
|
4275
4295
|
data.clearData();
|
|
4276
4296
|
data.setData("text/plain", text);
|
|
4297
|
+
return true;
|
|
4277
4298
|
}
|
|
4278
4299
|
else {
|
|
4279
4300
|
captureCopy(view, text);
|
|
4301
|
+
return false;
|
|
4280
4302
|
}
|
|
4281
|
-
if (event.type == "cut" && !view.state.readOnly)
|
|
4282
|
-
view.dispatch({
|
|
4283
|
-
changes: ranges,
|
|
4284
|
-
scrollIntoView: true,
|
|
4285
|
-
userEvent: "delete.cut"
|
|
4286
|
-
});
|
|
4287
4303
|
};
|
|
4288
4304
|
const isFocusChange = state.Annotation.define();
|
|
4289
4305
|
function focusChangeTransaction(state, focus) {
|
|
@@ -4307,7 +4323,7 @@ function updateForFocusChange(view) {
|
|
|
4307
4323
|
}
|
|
4308
4324
|
}, 10);
|
|
4309
4325
|
}
|
|
4310
|
-
|
|
4326
|
+
observers.focus = view => {
|
|
4311
4327
|
view.inputState.lastFocusTime = Date.now();
|
|
4312
4328
|
// When focusing reset the scroll position, move it back to where it was
|
|
4313
4329
|
if (!view.scrollDOM.scrollTop && (view.inputState.lastScrollTop || view.inputState.lastScrollLeft)) {
|
|
@@ -4316,11 +4332,11 @@ handlers.focus = view => {
|
|
|
4316
4332
|
}
|
|
4317
4333
|
updateForFocusChange(view);
|
|
4318
4334
|
};
|
|
4319
|
-
|
|
4335
|
+
observers.blur = view => {
|
|
4320
4336
|
view.observer.clearSelectionRange();
|
|
4321
4337
|
updateForFocusChange(view);
|
|
4322
4338
|
};
|
|
4323
|
-
|
|
4339
|
+
observers.compositionstart = observers.compositionupdate = view => {
|
|
4324
4340
|
if (view.inputState.compositionFirstChange == null)
|
|
4325
4341
|
view.inputState.compositionFirstChange = true;
|
|
4326
4342
|
if (view.inputState.composing < 0) {
|
|
@@ -4328,7 +4344,7 @@ handlers.compositionstart = handlers.compositionupdate = view => {
|
|
|
4328
4344
|
view.inputState.composing = 0;
|
|
4329
4345
|
}
|
|
4330
4346
|
};
|
|
4331
|
-
|
|
4347
|
+
observers.compositionend = view => {
|
|
4332
4348
|
view.inputState.composing = -1;
|
|
4333
4349
|
view.inputState.compositionEndedAt = Date.now();
|
|
4334
4350
|
view.inputState.compositionPendingKey = true;
|
|
@@ -4352,7 +4368,7 @@ handlers.compositionend = view => {
|
|
|
4352
4368
|
}, 50);
|
|
4353
4369
|
}
|
|
4354
4370
|
};
|
|
4355
|
-
|
|
4371
|
+
observers.contextmenu = view => {
|
|
4356
4372
|
view.inputState.lastContextMenu = Date.now();
|
|
4357
4373
|
};
|
|
4358
4374
|
handlers.beforeinput = (view, event) => {
|
|
@@ -4381,6 +4397,7 @@ handlers.beforeinput = (view, event) => {
|
|
|
4381
4397
|
}, 100);
|
|
4382
4398
|
}
|
|
4383
4399
|
}
|
|
4400
|
+
return false;
|
|
4384
4401
|
};
|
|
4385
4402
|
const appliedFirefoxHack = new Set;
|
|
4386
4403
|
// In Firefox, when cut/copy handlers are added to the document, that
|
|
@@ -5051,14 +5068,13 @@ class NodeBuilder {
|
|
|
5051
5068
|
return line;
|
|
5052
5069
|
}
|
|
5053
5070
|
addBlock(block) {
|
|
5054
|
-
var _a;
|
|
5055
5071
|
this.enterLine();
|
|
5056
|
-
let
|
|
5057
|
-
if (
|
|
5072
|
+
let deco = block.deco;
|
|
5073
|
+
if (deco && deco.startSide > 0 && !this.isCovered)
|
|
5058
5074
|
this.ensureLine();
|
|
5059
5075
|
this.nodes.push(block);
|
|
5060
5076
|
this.writtenTo = this.pos = this.pos + block.length;
|
|
5061
|
-
if (
|
|
5077
|
+
if (deco && deco.endSide > 0)
|
|
5062
5078
|
this.covering = block;
|
|
5063
5079
|
}
|
|
5064
5080
|
addLineDeco(height, breaks, length) {
|
|
@@ -6166,7 +6182,7 @@ function applyDOMChange(view, domChange) {
|
|
|
6166
6182
|
change = { from: sel.from, to: sel.to, insert: state.Text.of([" "]) };
|
|
6167
6183
|
}
|
|
6168
6184
|
if (change) {
|
|
6169
|
-
if (browser.ios && view.inputState.flushIOSKey(
|
|
6185
|
+
if (browser.ios && view.inputState.flushIOSKey())
|
|
6170
6186
|
return true;
|
|
6171
6187
|
// Android browsers don't fire reasonable key events for enter,
|
|
6172
6188
|
// backspace, or delete. So this detects changes that look like
|
|
@@ -6420,7 +6436,7 @@ class DOMObserver {
|
|
|
6420
6436
|
this.readSelectionRange();
|
|
6421
6437
|
}
|
|
6422
6438
|
onScrollChanged(e) {
|
|
6423
|
-
this.view.inputState.
|
|
6439
|
+
this.view.inputState.runHandlers("scroll", e);
|
|
6424
6440
|
if (this.intersecting)
|
|
6425
6441
|
this.view.measure();
|
|
6426
6442
|
}
|
|
@@ -6891,7 +6907,7 @@ class EditorView {
|
|
|
6891
6907
|
plugin.update(this);
|
|
6892
6908
|
this.observer = new DOMObserver(this);
|
|
6893
6909
|
this.inputState = new InputState(this);
|
|
6894
|
-
this.inputState.ensureHandlers(this
|
|
6910
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
6895
6911
|
this.docView = new DocView(this);
|
|
6896
6912
|
this.mountStyles();
|
|
6897
6913
|
this.updateAttrs();
|
|
@@ -7033,7 +7049,7 @@ class EditorView {
|
|
|
7033
7049
|
for (let plugin of this.plugins)
|
|
7034
7050
|
plugin.update(this);
|
|
7035
7051
|
this.docView = new DocView(this);
|
|
7036
|
-
this.inputState.ensureHandlers(this
|
|
7052
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7037
7053
|
this.mountStyles();
|
|
7038
7054
|
this.updateAttrs();
|
|
7039
7055
|
this.bidiCache = [];
|
|
@@ -7065,7 +7081,7 @@ class EditorView {
|
|
|
7065
7081
|
plugin.destroy(this);
|
|
7066
7082
|
this.plugins = newPlugins;
|
|
7067
7083
|
this.pluginMap.clear();
|
|
7068
|
-
this.inputState.ensureHandlers(this
|
|
7084
|
+
this.inputState.ensureHandlers(this.plugins);
|
|
7069
7085
|
}
|
|
7070
7086
|
else {
|
|
7071
7087
|
for (let p of this.plugins)
|
|
@@ -7593,6 +7609,17 @@ class EditorView {
|
|
|
7593
7609
|
return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
|
7594
7610
|
}
|
|
7595
7611
|
/**
|
|
7612
|
+
Create an extension that registers DOM event observers. Contrary
|
|
7613
|
+
to event [handlers](https://codemirror.net/6/docs/ref/#view.EditorView^domEventHandlers),
|
|
7614
|
+
observers can't be prevented from running by a higher-precedence
|
|
7615
|
+
handler returning true. They also don't prevent other handlers
|
|
7616
|
+
and observers from running when they return true, and should not
|
|
7617
|
+
call `preventDefault`.
|
|
7618
|
+
*/
|
|
7619
|
+
static domEventObservers(observers) {
|
|
7620
|
+
return ViewPlugin.define(() => ({}), { eventObservers: observers });
|
|
7621
|
+
}
|
|
7622
|
+
/**
|
|
7596
7623
|
Create a theme extension. The first argument can be a
|
|
7597
7624
|
[`style-mod`](https://github.com/marijnh/style-mod#documentation)
|
|
7598
7625
|
style spec providing the styles for the theme. These will be
|
|
@@ -8445,7 +8472,7 @@ const drawDropCursor = ViewPlugin.fromClass(class {
|
|
|
8445
8472
|
this.view.dispatch({ effects: setDropCursorPos.of(pos) });
|
|
8446
8473
|
}
|
|
8447
8474
|
}, {
|
|
8448
|
-
|
|
8475
|
+
eventObservers: {
|
|
8449
8476
|
dragover(event) {
|
|
8450
8477
|
this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
|
|
8451
8478
|
},
|
|
@@ -8955,7 +8982,7 @@ function crosshairCursor(options = {}) {
|
|
|
8955
8982
|
}
|
|
8956
8983
|
}
|
|
8957
8984
|
}, {
|
|
8958
|
-
|
|
8985
|
+
eventObservers: {
|
|
8959
8986
|
keydown(e) {
|
|
8960
8987
|
this.set(e.keyCode == code || getter(e));
|
|
8961
8988
|
},
|
|
@@ -9266,7 +9293,7 @@ const tooltipPlugin = ViewPlugin.fromClass(class {
|
|
|
9266
9293
|
}
|
|
9267
9294
|
}
|
|
9268
9295
|
}, {
|
|
9269
|
-
|
|
9296
|
+
eventObservers: {
|
|
9270
9297
|
scroll() { this.maybeMeasure(); }
|
|
9271
9298
|
}
|
|
9272
9299
|
});
|