@codemirror/view 6.38.8 → 6.39.0-beta.2
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/dist/index.cjs +2215 -2069
- package/dist/index.d.cts +43 -2
- package/dist/index.d.ts +43 -2
- package/dist/index.js +2216 -2071
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -35,1079 +35,6 @@ var browser = {
|
|
|
35
35
|
tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
|
|
36
36
|
};
|
|
37
37
|
|
|
38
|
-
function getSelection(root) {
|
|
39
|
-
let target;
|
|
40
|
-
// Browsers differ on whether shadow roots have a getSelection
|
|
41
|
-
// method. If it exists, use that, otherwise, call it on the
|
|
42
|
-
// document.
|
|
43
|
-
if (root.nodeType == 11) { // Shadow root
|
|
44
|
-
target = root.getSelection ? root : root.ownerDocument;
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
target = root;
|
|
48
|
-
}
|
|
49
|
-
return target.getSelection();
|
|
50
|
-
}
|
|
51
|
-
function contains(dom, node) {
|
|
52
|
-
return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
53
|
-
}
|
|
54
|
-
function hasSelection(dom, selection) {
|
|
55
|
-
if (!selection.anchorNode)
|
|
56
|
-
return false;
|
|
57
|
-
try {
|
|
58
|
-
// Firefox will raise 'permission denied' errors when accessing
|
|
59
|
-
// properties of `sel.anchorNode` when it's in a generated CSS
|
|
60
|
-
// element.
|
|
61
|
-
return contains(dom, selection.anchorNode);
|
|
62
|
-
}
|
|
63
|
-
catch (_) {
|
|
64
|
-
return false;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function clientRectsFor(dom) {
|
|
68
|
-
if (dom.nodeType == 3)
|
|
69
|
-
return textRange(dom, 0, dom.nodeValue.length).getClientRects();
|
|
70
|
-
else if (dom.nodeType == 1)
|
|
71
|
-
return dom.getClientRects();
|
|
72
|
-
else
|
|
73
|
-
return [];
|
|
74
|
-
}
|
|
75
|
-
// Scans forward and backward through DOM positions equivalent to the
|
|
76
|
-
// given one to see if the two are in the same place (i.e. after a
|
|
77
|
-
// text node vs at the end of that text node)
|
|
78
|
-
function isEquivalentPosition(node, off, targetNode, targetOff) {
|
|
79
|
-
return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) ||
|
|
80
|
-
scanFor(node, off, targetNode, targetOff, 1)) : false;
|
|
81
|
-
}
|
|
82
|
-
function domIndex(node) {
|
|
83
|
-
for (var index = 0;; index++) {
|
|
84
|
-
node = node.previousSibling;
|
|
85
|
-
if (!node)
|
|
86
|
-
return index;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
function isBlockElement(node) {
|
|
90
|
-
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
91
|
-
}
|
|
92
|
-
function scanFor(node, off, targetNode, targetOff, dir) {
|
|
93
|
-
for (;;) {
|
|
94
|
-
if (node == targetNode && off == targetOff)
|
|
95
|
-
return true;
|
|
96
|
-
if (off == (dir < 0 ? 0 : maxOffset(node))) {
|
|
97
|
-
if (node.nodeName == "DIV")
|
|
98
|
-
return false;
|
|
99
|
-
let parent = node.parentNode;
|
|
100
|
-
if (!parent || parent.nodeType != 1)
|
|
101
|
-
return false;
|
|
102
|
-
off = domIndex(node) + (dir < 0 ? 0 : 1);
|
|
103
|
-
node = parent;
|
|
104
|
-
}
|
|
105
|
-
else if (node.nodeType == 1) {
|
|
106
|
-
node = node.childNodes[off + (dir < 0 ? -1 : 0)];
|
|
107
|
-
if (node.nodeType == 1 && node.contentEditable == "false")
|
|
108
|
-
return false;
|
|
109
|
-
off = dir < 0 ? maxOffset(node) : 0;
|
|
110
|
-
}
|
|
111
|
-
else {
|
|
112
|
-
return false;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function maxOffset(node) {
|
|
117
|
-
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
118
|
-
}
|
|
119
|
-
function flattenRect(rect, left) {
|
|
120
|
-
let x = left ? rect.left : rect.right;
|
|
121
|
-
return { left: x, right: x, top: rect.top, bottom: rect.bottom };
|
|
122
|
-
}
|
|
123
|
-
function windowRect(win) {
|
|
124
|
-
let vp = win.visualViewport;
|
|
125
|
-
if (vp)
|
|
126
|
-
return {
|
|
127
|
-
left: 0, right: vp.width,
|
|
128
|
-
top: 0, bottom: vp.height
|
|
129
|
-
};
|
|
130
|
-
return { left: 0, right: win.innerWidth,
|
|
131
|
-
top: 0, bottom: win.innerHeight };
|
|
132
|
-
}
|
|
133
|
-
function getScale(elt, rect) {
|
|
134
|
-
let scaleX = rect.width / elt.offsetWidth;
|
|
135
|
-
let scaleY = rect.height / elt.offsetHeight;
|
|
136
|
-
if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1)
|
|
137
|
-
scaleX = 1;
|
|
138
|
-
if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1)
|
|
139
|
-
scaleY = 1;
|
|
140
|
-
return { scaleX, scaleY };
|
|
141
|
-
}
|
|
142
|
-
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
143
|
-
let doc = dom.ownerDocument, win = doc.defaultView || window;
|
|
144
|
-
for (let cur = dom, stop = false; cur && !stop;) {
|
|
145
|
-
if (cur.nodeType == 1) { // Element
|
|
146
|
-
let bounding, top = cur == doc.body;
|
|
147
|
-
let scaleX = 1, scaleY = 1;
|
|
148
|
-
if (top) {
|
|
149
|
-
bounding = windowRect(win);
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
if (/^(fixed|sticky)$/.test(getComputedStyle(cur).position))
|
|
153
|
-
stop = true;
|
|
154
|
-
if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
|
|
155
|
-
cur = cur.assignedSlot || cur.parentNode;
|
|
156
|
-
continue;
|
|
157
|
-
}
|
|
158
|
-
let rect = cur.getBoundingClientRect();
|
|
159
|
-
({ scaleX, scaleY } = getScale(cur, rect));
|
|
160
|
-
// Make sure scrollbar width isn't included in the rectangle
|
|
161
|
-
bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
|
|
162
|
-
top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
|
|
163
|
-
}
|
|
164
|
-
let moveX = 0, moveY = 0;
|
|
165
|
-
if (y == "nearest") {
|
|
166
|
-
if (rect.top < bounding.top) {
|
|
167
|
-
moveY = rect.top - (bounding.top + yMargin);
|
|
168
|
-
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
169
|
-
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
170
|
-
}
|
|
171
|
-
else if (rect.bottom > bounding.bottom) {
|
|
172
|
-
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
173
|
-
if (side < 0 && (rect.top - moveY) < bounding.top)
|
|
174
|
-
moveY = rect.top - (bounding.top + yMargin);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
else {
|
|
178
|
-
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
179
|
-
let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
|
|
180
|
-
y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
|
|
181
|
-
rect.bottom - boundingHeight + yMargin;
|
|
182
|
-
moveY = targetTop - bounding.top;
|
|
183
|
-
}
|
|
184
|
-
if (x == "nearest") {
|
|
185
|
-
if (rect.left < bounding.left) {
|
|
186
|
-
moveX = rect.left - (bounding.left + xMargin);
|
|
187
|
-
if (side > 0 && rect.right > bounding.right + moveX)
|
|
188
|
-
moveX = rect.right - bounding.right + xMargin;
|
|
189
|
-
}
|
|
190
|
-
else if (rect.right > bounding.right) {
|
|
191
|
-
moveX = rect.right - bounding.right + xMargin;
|
|
192
|
-
if (side < 0 && rect.left < bounding.left + moveX)
|
|
193
|
-
moveX = rect.left - (bounding.left + xMargin);
|
|
194
|
-
}
|
|
195
|
-
}
|
|
196
|
-
else {
|
|
197
|
-
let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
|
|
198
|
-
(x == "start") == ltr ? rect.left - xMargin :
|
|
199
|
-
rect.right - (bounding.right - bounding.left) + xMargin;
|
|
200
|
-
moveX = targetLeft - bounding.left;
|
|
201
|
-
}
|
|
202
|
-
if (moveX || moveY) {
|
|
203
|
-
if (top) {
|
|
204
|
-
win.scrollBy(moveX, moveY);
|
|
205
|
-
}
|
|
206
|
-
else {
|
|
207
|
-
let movedX = 0, movedY = 0;
|
|
208
|
-
if (moveY) {
|
|
209
|
-
let start = cur.scrollTop;
|
|
210
|
-
cur.scrollTop += moveY / scaleY;
|
|
211
|
-
movedY = (cur.scrollTop - start) * scaleY;
|
|
212
|
-
}
|
|
213
|
-
if (moveX) {
|
|
214
|
-
let start = cur.scrollLeft;
|
|
215
|
-
cur.scrollLeft += moveX / scaleX;
|
|
216
|
-
movedX = (cur.scrollLeft - start) * scaleX;
|
|
217
|
-
}
|
|
218
|
-
rect = { left: rect.left - movedX, top: rect.top - movedY,
|
|
219
|
-
right: rect.right - movedX, bottom: rect.bottom - movedY };
|
|
220
|
-
if (movedX && Math.abs(movedX - moveX) < 1)
|
|
221
|
-
x = "nearest";
|
|
222
|
-
if (movedY && Math.abs(movedY - moveY) < 1)
|
|
223
|
-
y = "nearest";
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
if (top)
|
|
227
|
-
break;
|
|
228
|
-
if (rect.top < bounding.top || rect.bottom > bounding.bottom ||
|
|
229
|
-
rect.left < bounding.left || rect.right > bounding.right)
|
|
230
|
-
rect = { left: Math.max(rect.left, bounding.left), right: Math.min(rect.right, bounding.right),
|
|
231
|
-
top: Math.max(rect.top, bounding.top), bottom: Math.min(rect.bottom, bounding.bottom) };
|
|
232
|
-
cur = cur.assignedSlot || cur.parentNode;
|
|
233
|
-
}
|
|
234
|
-
else if (cur.nodeType == 11) { // A shadow root
|
|
235
|
-
cur = cur.host;
|
|
236
|
-
}
|
|
237
|
-
else {
|
|
238
|
-
break;
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
function scrollableParents(dom) {
|
|
243
|
-
let doc = dom.ownerDocument, x, y;
|
|
244
|
-
for (let cur = dom.parentNode; cur;) {
|
|
245
|
-
if (cur == doc.body || (x && y)) {
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
else if (cur.nodeType == 1) {
|
|
249
|
-
if (!y && cur.scrollHeight > cur.clientHeight)
|
|
250
|
-
y = cur;
|
|
251
|
-
if (!x && cur.scrollWidth > cur.clientWidth)
|
|
252
|
-
x = cur;
|
|
253
|
-
cur = cur.assignedSlot || cur.parentNode;
|
|
254
|
-
}
|
|
255
|
-
else if (cur.nodeType == 11) {
|
|
256
|
-
cur = cur.host;
|
|
257
|
-
}
|
|
258
|
-
else {
|
|
259
|
-
break;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
return { x, y };
|
|
263
|
-
}
|
|
264
|
-
class DOMSelectionState {
|
|
265
|
-
constructor() {
|
|
266
|
-
this.anchorNode = null;
|
|
267
|
-
this.anchorOffset = 0;
|
|
268
|
-
this.focusNode = null;
|
|
269
|
-
this.focusOffset = 0;
|
|
270
|
-
}
|
|
271
|
-
eq(domSel) {
|
|
272
|
-
return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
|
|
273
|
-
this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
|
|
274
|
-
}
|
|
275
|
-
setRange(range) {
|
|
276
|
-
let { anchorNode, focusNode } = range;
|
|
277
|
-
// Clip offsets to node size to avoid crashes when Safari reports bogus offsets (#1152)
|
|
278
|
-
this.set(anchorNode, Math.min(range.anchorOffset, anchorNode ? maxOffset(anchorNode) : 0), focusNode, Math.min(range.focusOffset, focusNode ? maxOffset(focusNode) : 0));
|
|
279
|
-
}
|
|
280
|
-
set(anchorNode, anchorOffset, focusNode, focusOffset) {
|
|
281
|
-
this.anchorNode = anchorNode;
|
|
282
|
-
this.anchorOffset = anchorOffset;
|
|
283
|
-
this.focusNode = focusNode;
|
|
284
|
-
this.focusOffset = focusOffset;
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
let preventScrollSupported = null;
|
|
288
|
-
// Safari 26 breaks preventScroll support
|
|
289
|
-
if (browser.safari && browser.safari_version >= 26)
|
|
290
|
-
preventScrollSupported = false;
|
|
291
|
-
// Feature-detects support for .focus({preventScroll: true}), and uses
|
|
292
|
-
// a fallback kludge when not supported.
|
|
293
|
-
function focusPreventScroll(dom) {
|
|
294
|
-
if (dom.setActive)
|
|
295
|
-
return dom.setActive(); // in IE
|
|
296
|
-
if (preventScrollSupported)
|
|
297
|
-
return dom.focus(preventScrollSupported);
|
|
298
|
-
let stack = [];
|
|
299
|
-
for (let cur = dom; cur; cur = cur.parentNode) {
|
|
300
|
-
stack.push(cur, cur.scrollTop, cur.scrollLeft);
|
|
301
|
-
if (cur == cur.ownerDocument)
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
304
|
-
dom.focus(preventScrollSupported == null ? {
|
|
305
|
-
get preventScroll() {
|
|
306
|
-
preventScrollSupported = { preventScroll: true };
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
} : undefined);
|
|
310
|
-
if (!preventScrollSupported) {
|
|
311
|
-
preventScrollSupported = false;
|
|
312
|
-
for (let i = 0; i < stack.length;) {
|
|
313
|
-
let elt = stack[i++], top = stack[i++], left = stack[i++];
|
|
314
|
-
if (elt.scrollTop != top)
|
|
315
|
-
elt.scrollTop = top;
|
|
316
|
-
if (elt.scrollLeft != left)
|
|
317
|
-
elt.scrollLeft = left;
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
}
|
|
321
|
-
let scratchRange;
|
|
322
|
-
function textRange(node, from, to = from) {
|
|
323
|
-
let range = scratchRange || (scratchRange = document.createRange());
|
|
324
|
-
range.setEnd(node, to);
|
|
325
|
-
range.setStart(node, from);
|
|
326
|
-
return range;
|
|
327
|
-
}
|
|
328
|
-
function dispatchKey(elt, name, code, mods) {
|
|
329
|
-
let options = { key: name, code: name, keyCode: code, which: code, cancelable: true };
|
|
330
|
-
if (mods)
|
|
331
|
-
({ altKey: options.altKey, ctrlKey: options.ctrlKey, shiftKey: options.shiftKey, metaKey: options.metaKey } = mods);
|
|
332
|
-
let down = new KeyboardEvent("keydown", options);
|
|
333
|
-
down.synthetic = true;
|
|
334
|
-
elt.dispatchEvent(down);
|
|
335
|
-
let up = new KeyboardEvent("keyup", options);
|
|
336
|
-
up.synthetic = true;
|
|
337
|
-
elt.dispatchEvent(up);
|
|
338
|
-
return down.defaultPrevented || up.defaultPrevented;
|
|
339
|
-
}
|
|
340
|
-
function getRoot(node) {
|
|
341
|
-
while (node) {
|
|
342
|
-
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
|
343
|
-
return node;
|
|
344
|
-
node = node.assignedSlot || node.parentNode;
|
|
345
|
-
}
|
|
346
|
-
return null;
|
|
347
|
-
}
|
|
348
|
-
function clearAttributes(node) {
|
|
349
|
-
while (node.attributes.length)
|
|
350
|
-
node.removeAttributeNode(node.attributes[0]);
|
|
351
|
-
}
|
|
352
|
-
function atElementStart(doc, selection) {
|
|
353
|
-
let node = selection.focusNode, offset = selection.focusOffset;
|
|
354
|
-
if (!node || selection.anchorNode != node || selection.anchorOffset != offset)
|
|
355
|
-
return false;
|
|
356
|
-
// Safari can report bogus offsets (#1152)
|
|
357
|
-
offset = Math.min(offset, maxOffset(node));
|
|
358
|
-
for (;;) {
|
|
359
|
-
if (offset) {
|
|
360
|
-
if (node.nodeType != 1)
|
|
361
|
-
return false;
|
|
362
|
-
let prev = node.childNodes[offset - 1];
|
|
363
|
-
if (prev.contentEditable == "false")
|
|
364
|
-
offset--;
|
|
365
|
-
else {
|
|
366
|
-
node = prev;
|
|
367
|
-
offset = maxOffset(node);
|
|
368
|
-
}
|
|
369
|
-
}
|
|
370
|
-
else if (node == doc) {
|
|
371
|
-
return true;
|
|
372
|
-
}
|
|
373
|
-
else {
|
|
374
|
-
offset = domIndex(node);
|
|
375
|
-
node = node.parentNode;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
}
|
|
379
|
-
function isScrolledToBottom(elt) {
|
|
380
|
-
return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
|
|
381
|
-
}
|
|
382
|
-
function textNodeBefore(startNode, startOffset) {
|
|
383
|
-
for (let node = startNode, offset = startOffset;;) {
|
|
384
|
-
if (node.nodeType == 3 && offset > 0) {
|
|
385
|
-
return { node: node, offset: offset };
|
|
386
|
-
}
|
|
387
|
-
else if (node.nodeType == 1 && offset > 0) {
|
|
388
|
-
if (node.contentEditable == "false")
|
|
389
|
-
return null;
|
|
390
|
-
node = node.childNodes[offset - 1];
|
|
391
|
-
offset = maxOffset(node);
|
|
392
|
-
}
|
|
393
|
-
else if (node.parentNode && !isBlockElement(node)) {
|
|
394
|
-
offset = domIndex(node);
|
|
395
|
-
node = node.parentNode;
|
|
396
|
-
}
|
|
397
|
-
else {
|
|
398
|
-
return null;
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
function textNodeAfter(startNode, startOffset) {
|
|
403
|
-
for (let node = startNode, offset = startOffset;;) {
|
|
404
|
-
if (node.nodeType == 3 && offset < node.nodeValue.length) {
|
|
405
|
-
return { node: node, offset: offset };
|
|
406
|
-
}
|
|
407
|
-
else if (node.nodeType == 1 && offset < node.childNodes.length) {
|
|
408
|
-
if (node.contentEditable == "false")
|
|
409
|
-
return null;
|
|
410
|
-
node = node.childNodes[offset];
|
|
411
|
-
offset = 0;
|
|
412
|
-
}
|
|
413
|
-
else if (node.parentNode && !isBlockElement(node)) {
|
|
414
|
-
offset = domIndex(node) + 1;
|
|
415
|
-
node = node.parentNode;
|
|
416
|
-
}
|
|
417
|
-
else {
|
|
418
|
-
return null;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
class DOMPos {
|
|
424
|
-
constructor(node, offset, precise = true) {
|
|
425
|
-
this.node = node;
|
|
426
|
-
this.offset = offset;
|
|
427
|
-
this.precise = precise;
|
|
428
|
-
}
|
|
429
|
-
static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); }
|
|
430
|
-
static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); }
|
|
431
|
-
}
|
|
432
|
-
const noChildren = [];
|
|
433
|
-
class ContentView {
|
|
434
|
-
constructor() {
|
|
435
|
-
this.parent = null;
|
|
436
|
-
this.dom = null;
|
|
437
|
-
this.flags = 2 /* ViewFlag.NodeDirty */;
|
|
438
|
-
}
|
|
439
|
-
get overrideDOMText() { return null; }
|
|
440
|
-
get posAtStart() {
|
|
441
|
-
return this.parent ? this.parent.posBefore(this) : 0;
|
|
442
|
-
}
|
|
443
|
-
get posAtEnd() {
|
|
444
|
-
return this.posAtStart + this.length;
|
|
445
|
-
}
|
|
446
|
-
posBefore(view) {
|
|
447
|
-
let pos = this.posAtStart;
|
|
448
|
-
for (let child of this.children) {
|
|
449
|
-
if (child == view)
|
|
450
|
-
return pos;
|
|
451
|
-
pos += child.length + child.breakAfter;
|
|
452
|
-
}
|
|
453
|
-
throw new RangeError("Invalid child in posBefore");
|
|
454
|
-
}
|
|
455
|
-
posAfter(view) {
|
|
456
|
-
return this.posBefore(view) + view.length;
|
|
457
|
-
}
|
|
458
|
-
sync(view, track) {
|
|
459
|
-
if (this.flags & 2 /* ViewFlag.NodeDirty */) {
|
|
460
|
-
let parent = this.dom;
|
|
461
|
-
let prev = null, next;
|
|
462
|
-
for (let child of this.children) {
|
|
463
|
-
if (child.flags & 7 /* ViewFlag.Dirty */) {
|
|
464
|
-
if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
|
465
|
-
let contentView = ContentView.get(next);
|
|
466
|
-
if (!contentView || !contentView.parent && contentView.canReuseDOM(child))
|
|
467
|
-
child.reuseDOM(next);
|
|
468
|
-
}
|
|
469
|
-
child.sync(view, track);
|
|
470
|
-
child.flags &= ~7 /* ViewFlag.Dirty */;
|
|
471
|
-
}
|
|
472
|
-
next = prev ? prev.nextSibling : parent.firstChild;
|
|
473
|
-
if (track && !track.written && track.node == parent && next != child.dom)
|
|
474
|
-
track.written = true;
|
|
475
|
-
if (child.dom.parentNode == parent) {
|
|
476
|
-
while (next && next != child.dom)
|
|
477
|
-
next = rm$1(next);
|
|
478
|
-
}
|
|
479
|
-
else {
|
|
480
|
-
parent.insertBefore(child.dom, next);
|
|
481
|
-
}
|
|
482
|
-
prev = child.dom;
|
|
483
|
-
}
|
|
484
|
-
next = prev ? prev.nextSibling : parent.firstChild;
|
|
485
|
-
if (next && track && track.node == parent)
|
|
486
|
-
track.written = true;
|
|
487
|
-
while (next)
|
|
488
|
-
next = rm$1(next);
|
|
489
|
-
}
|
|
490
|
-
else if (this.flags & 1 /* ViewFlag.ChildDirty */) {
|
|
491
|
-
for (let child of this.children)
|
|
492
|
-
if (child.flags & 7 /* ViewFlag.Dirty */) {
|
|
493
|
-
child.sync(view, track);
|
|
494
|
-
child.flags &= ~7 /* ViewFlag.Dirty */;
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
reuseDOM(_dom) { }
|
|
499
|
-
localPosFromDOM(node, offset) {
|
|
500
|
-
let after;
|
|
501
|
-
if (node == this.dom) {
|
|
502
|
-
after = this.dom.childNodes[offset];
|
|
503
|
-
}
|
|
504
|
-
else {
|
|
505
|
-
let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
|
|
506
|
-
for (;;) {
|
|
507
|
-
let parent = node.parentNode;
|
|
508
|
-
if (parent == this.dom)
|
|
509
|
-
break;
|
|
510
|
-
if (bias == 0 && parent.firstChild != parent.lastChild) {
|
|
511
|
-
if (node == parent.firstChild)
|
|
512
|
-
bias = -1;
|
|
513
|
-
else
|
|
514
|
-
bias = 1;
|
|
515
|
-
}
|
|
516
|
-
node = parent;
|
|
517
|
-
}
|
|
518
|
-
if (bias < 0)
|
|
519
|
-
after = node;
|
|
520
|
-
else
|
|
521
|
-
after = node.nextSibling;
|
|
522
|
-
}
|
|
523
|
-
if (after == this.dom.firstChild)
|
|
524
|
-
return 0;
|
|
525
|
-
while (after && !ContentView.get(after))
|
|
526
|
-
after = after.nextSibling;
|
|
527
|
-
if (!after)
|
|
528
|
-
return this.length;
|
|
529
|
-
for (let i = 0, pos = 0;; i++) {
|
|
530
|
-
let child = this.children[i];
|
|
531
|
-
if (child.dom == after)
|
|
532
|
-
return pos;
|
|
533
|
-
pos += child.length + child.breakAfter;
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
domBoundsAround(from, to, offset = 0) {
|
|
537
|
-
let fromI = -1, fromStart = -1, toI = -1, toEnd = -1;
|
|
538
|
-
for (let i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) {
|
|
539
|
-
let child = this.children[i], end = pos + child.length;
|
|
540
|
-
if (pos < from && end > to)
|
|
541
|
-
return child.domBoundsAround(from, to, pos);
|
|
542
|
-
if (end >= from && fromI == -1) {
|
|
543
|
-
fromI = i;
|
|
544
|
-
fromStart = pos;
|
|
545
|
-
}
|
|
546
|
-
if (pos > to && child.dom.parentNode == this.dom) {
|
|
547
|
-
toI = i;
|
|
548
|
-
toEnd = prevEnd;
|
|
549
|
-
break;
|
|
550
|
-
}
|
|
551
|
-
prevEnd = end;
|
|
552
|
-
pos = end + child.breakAfter;
|
|
553
|
-
}
|
|
554
|
-
return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd,
|
|
555
|
-
startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild,
|
|
556
|
-
endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null };
|
|
557
|
-
}
|
|
558
|
-
markDirty(andParent = false) {
|
|
559
|
-
this.flags |= 2 /* ViewFlag.NodeDirty */;
|
|
560
|
-
this.markParentsDirty(andParent);
|
|
561
|
-
}
|
|
562
|
-
markParentsDirty(childList) {
|
|
563
|
-
for (let parent = this.parent; parent; parent = parent.parent) {
|
|
564
|
-
if (childList)
|
|
565
|
-
parent.flags |= 2 /* ViewFlag.NodeDirty */;
|
|
566
|
-
if (parent.flags & 1 /* ViewFlag.ChildDirty */)
|
|
567
|
-
return;
|
|
568
|
-
parent.flags |= 1 /* ViewFlag.ChildDirty */;
|
|
569
|
-
childList = false;
|
|
570
|
-
}
|
|
571
|
-
}
|
|
572
|
-
setParent(parent) {
|
|
573
|
-
if (this.parent != parent) {
|
|
574
|
-
this.parent = parent;
|
|
575
|
-
if (this.flags & 7 /* ViewFlag.Dirty */)
|
|
576
|
-
this.markParentsDirty(true);
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
setDOM(dom) {
|
|
580
|
-
if (this.dom == dom)
|
|
581
|
-
return;
|
|
582
|
-
if (this.dom)
|
|
583
|
-
this.dom.cmView = null;
|
|
584
|
-
this.dom = dom;
|
|
585
|
-
dom.cmView = this;
|
|
586
|
-
}
|
|
587
|
-
get rootView() {
|
|
588
|
-
for (let v = this;;) {
|
|
589
|
-
let parent = v.parent;
|
|
590
|
-
if (!parent)
|
|
591
|
-
return v;
|
|
592
|
-
v = parent;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
replaceChildren(from, to, children = noChildren) {
|
|
596
|
-
this.markDirty();
|
|
597
|
-
for (let i = from; i < to; i++) {
|
|
598
|
-
let child = this.children[i];
|
|
599
|
-
if (child.parent == this && children.indexOf(child) < 0)
|
|
600
|
-
child.destroy();
|
|
601
|
-
}
|
|
602
|
-
if (children.length < 250)
|
|
603
|
-
this.children.splice(from, to - from, ...children);
|
|
604
|
-
else
|
|
605
|
-
this.children = [].concat(this.children.slice(0, from), children, this.children.slice(to));
|
|
606
|
-
for (let i = 0; i < children.length; i++)
|
|
607
|
-
children[i].setParent(this);
|
|
608
|
-
}
|
|
609
|
-
ignoreMutation(_rec) { return false; }
|
|
610
|
-
ignoreEvent(_event) { return false; }
|
|
611
|
-
childCursor(pos = this.length) {
|
|
612
|
-
return new ChildCursor(this.children, pos, this.children.length);
|
|
613
|
-
}
|
|
614
|
-
childPos(pos, bias = 1) {
|
|
615
|
-
return this.childCursor().findPos(pos, bias);
|
|
616
|
-
}
|
|
617
|
-
toString() {
|
|
618
|
-
let name = this.constructor.name.replace("View", "");
|
|
619
|
-
return name + (this.children.length ? "(" + this.children.join() + ")" :
|
|
620
|
-
this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") +
|
|
621
|
-
(this.breakAfter ? "#" : "");
|
|
622
|
-
}
|
|
623
|
-
static get(node) { return node.cmView; }
|
|
624
|
-
get isEditable() { return true; }
|
|
625
|
-
get isWidget() { return false; }
|
|
626
|
-
get isHidden() { return false; }
|
|
627
|
-
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
628
|
-
return false;
|
|
629
|
-
}
|
|
630
|
-
become(other) { return false; }
|
|
631
|
-
canReuseDOM(other) {
|
|
632
|
-
return other.constructor == this.constructor && !((this.flags | other.flags) & 8 /* ViewFlag.Composition */);
|
|
633
|
-
}
|
|
634
|
-
// When this is a zero-length view with a side, this should return a
|
|
635
|
-
// number <= 0 to indicate it is before its position, or a
|
|
636
|
-
// number > 0 when after its position.
|
|
637
|
-
getSide() { return 0; }
|
|
638
|
-
destroy() {
|
|
639
|
-
for (let child of this.children)
|
|
640
|
-
if (child.parent == this)
|
|
641
|
-
child.destroy();
|
|
642
|
-
this.parent = null;
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
ContentView.prototype.breakAfter = 0;
|
|
646
|
-
// Remove a DOM node and return its next sibling.
|
|
647
|
-
function rm$1(dom) {
|
|
648
|
-
let next = dom.nextSibling;
|
|
649
|
-
dom.parentNode.removeChild(dom);
|
|
650
|
-
return next;
|
|
651
|
-
}
|
|
652
|
-
class ChildCursor {
|
|
653
|
-
constructor(children, pos, i) {
|
|
654
|
-
this.children = children;
|
|
655
|
-
this.pos = pos;
|
|
656
|
-
this.i = i;
|
|
657
|
-
this.off = 0;
|
|
658
|
-
}
|
|
659
|
-
findPos(pos, bias = 1) {
|
|
660
|
-
for (;;) {
|
|
661
|
-
if (pos > this.pos || pos == this.pos &&
|
|
662
|
-
(bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) {
|
|
663
|
-
this.off = pos - this.pos;
|
|
664
|
-
return this;
|
|
665
|
-
}
|
|
666
|
-
let next = this.children[--this.i];
|
|
667
|
-
this.pos -= next.length + next.breakAfter;
|
|
668
|
-
}
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) {
|
|
672
|
-
let { children } = parent;
|
|
673
|
-
let before = children.length ? children[fromI] : null;
|
|
674
|
-
let last = insert.length ? insert[insert.length - 1] : null;
|
|
675
|
-
let breakAtEnd = last ? last.breakAfter : breakAtStart;
|
|
676
|
-
// Change within a single child
|
|
677
|
-
if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 &&
|
|
678
|
-
before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd))
|
|
679
|
-
return;
|
|
680
|
-
if (toI < children.length) {
|
|
681
|
-
let after = children[toI];
|
|
682
|
-
// Make sure the end of the child after the update is preserved in `after`
|
|
683
|
-
if (after && (toOff < after.length || after.breakAfter && (last === null || last === void 0 ? void 0 : last.breakAfter))) {
|
|
684
|
-
// If we're splitting a child, separate part of it to avoid that
|
|
685
|
-
// being mangled when updating the child before the update.
|
|
686
|
-
if (fromI == toI) {
|
|
687
|
-
after = after.split(toOff);
|
|
688
|
-
toOff = 0;
|
|
689
|
-
}
|
|
690
|
-
// If the element after the replacement should be merged with
|
|
691
|
-
// the last replacing element, update `content`
|
|
692
|
-
if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) {
|
|
693
|
-
insert[insert.length - 1] = after;
|
|
694
|
-
}
|
|
695
|
-
else {
|
|
696
|
-
// Remove the start of the after element, if necessary, and
|
|
697
|
-
// add it to `content`.
|
|
698
|
-
if (toOff || after.children.length && !after.children[0].length)
|
|
699
|
-
after.merge(0, toOff, null, false, 0, openEnd);
|
|
700
|
-
insert.push(after);
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
else if (after === null || after === void 0 ? void 0 : after.breakAfter) {
|
|
704
|
-
// The element at `toI` is entirely covered by this range.
|
|
705
|
-
// Preserve its line break, if any.
|
|
706
|
-
if (last)
|
|
707
|
-
last.breakAfter = 1;
|
|
708
|
-
else
|
|
709
|
-
breakAtStart = 1;
|
|
710
|
-
}
|
|
711
|
-
// Since we've handled the next element from the current elements
|
|
712
|
-
// now, make sure `toI` points after that.
|
|
713
|
-
toI++;
|
|
714
|
-
}
|
|
715
|
-
if (before) {
|
|
716
|
-
before.breakAfter = breakAtStart;
|
|
717
|
-
if (fromOff > 0) {
|
|
718
|
-
if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) {
|
|
719
|
-
before.breakAfter = insert.shift().breakAfter;
|
|
720
|
-
}
|
|
721
|
-
else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) {
|
|
722
|
-
before.merge(fromOff, before.length, null, false, openStart, 0);
|
|
723
|
-
}
|
|
724
|
-
fromI++;
|
|
725
|
-
}
|
|
726
|
-
}
|
|
727
|
-
// Try to merge widgets on the boundaries of the replacement
|
|
728
|
-
while (fromI < toI && insert.length) {
|
|
729
|
-
if (children[toI - 1].become(insert[insert.length - 1])) {
|
|
730
|
-
toI--;
|
|
731
|
-
insert.pop();
|
|
732
|
-
openEnd = insert.length ? 0 : openStart;
|
|
733
|
-
}
|
|
734
|
-
else if (children[fromI].become(insert[0])) {
|
|
735
|
-
fromI++;
|
|
736
|
-
insert.shift();
|
|
737
|
-
openStart = insert.length ? 0 : openEnd;
|
|
738
|
-
}
|
|
739
|
-
else {
|
|
740
|
-
break;
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter &&
|
|
744
|
-
children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd))
|
|
745
|
-
fromI--;
|
|
746
|
-
if (fromI < toI || insert.length)
|
|
747
|
-
parent.replaceChildren(fromI, toI, insert);
|
|
748
|
-
}
|
|
749
|
-
function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
|
750
|
-
let cur = parent.childCursor();
|
|
751
|
-
let { i: toI, off: toOff } = cur.findPos(to, 1);
|
|
752
|
-
let { i: fromI, off: fromOff } = cur.findPos(from, -1);
|
|
753
|
-
let dLen = from - to;
|
|
754
|
-
for (let view of insert)
|
|
755
|
-
dLen += view.length;
|
|
756
|
-
parent.length += dLen;
|
|
757
|
-
replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
|
758
|
-
}
|
|
759
|
-
|
|
760
|
-
const MaxJoinLen = 256;
|
|
761
|
-
class TextView extends ContentView {
|
|
762
|
-
constructor(text) {
|
|
763
|
-
super();
|
|
764
|
-
this.text = text;
|
|
765
|
-
}
|
|
766
|
-
get length() { return this.text.length; }
|
|
767
|
-
createDOM(textDOM) {
|
|
768
|
-
this.setDOM(textDOM || document.createTextNode(this.text));
|
|
769
|
-
}
|
|
770
|
-
sync(view, track) {
|
|
771
|
-
if (!this.dom)
|
|
772
|
-
this.createDOM();
|
|
773
|
-
if (this.dom.nodeValue != this.text) {
|
|
774
|
-
if (track && track.node == this.dom)
|
|
775
|
-
track.written = true;
|
|
776
|
-
this.dom.nodeValue = this.text;
|
|
777
|
-
}
|
|
778
|
-
}
|
|
779
|
-
reuseDOM(dom) {
|
|
780
|
-
if (dom.nodeType == 3)
|
|
781
|
-
this.createDOM(dom);
|
|
782
|
-
}
|
|
783
|
-
merge(from, to, source) {
|
|
784
|
-
if ((this.flags & 8 /* ViewFlag.Composition */) ||
|
|
785
|
-
source && (!(source instanceof TextView) ||
|
|
786
|
-
this.length - (to - from) + source.length > MaxJoinLen ||
|
|
787
|
-
(source.flags & 8 /* ViewFlag.Composition */)))
|
|
788
|
-
return false;
|
|
789
|
-
this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to);
|
|
790
|
-
this.markDirty();
|
|
791
|
-
return true;
|
|
792
|
-
}
|
|
793
|
-
split(from) {
|
|
794
|
-
let result = new TextView(this.text.slice(from));
|
|
795
|
-
this.text = this.text.slice(0, from);
|
|
796
|
-
this.markDirty();
|
|
797
|
-
result.flags |= this.flags & 8 /* ViewFlag.Composition */;
|
|
798
|
-
return result;
|
|
799
|
-
}
|
|
800
|
-
localPosFromDOM(node, offset) {
|
|
801
|
-
return node == this.dom ? offset : offset ? this.text.length : 0;
|
|
802
|
-
}
|
|
803
|
-
domAtPos(pos) { return new DOMPos(this.dom, pos); }
|
|
804
|
-
domBoundsAround(_from, _to, offset) {
|
|
805
|
-
return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling };
|
|
806
|
-
}
|
|
807
|
-
coordsAt(pos, side) {
|
|
808
|
-
return textCoords(this.dom, pos, side);
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
class MarkView extends ContentView {
|
|
812
|
-
constructor(mark, children = [], length = 0) {
|
|
813
|
-
super();
|
|
814
|
-
this.mark = mark;
|
|
815
|
-
this.children = children;
|
|
816
|
-
this.length = length;
|
|
817
|
-
for (let ch of children)
|
|
818
|
-
ch.setParent(this);
|
|
819
|
-
}
|
|
820
|
-
setAttrs(dom) {
|
|
821
|
-
clearAttributes(dom);
|
|
822
|
-
if (this.mark.class)
|
|
823
|
-
dom.className = this.mark.class;
|
|
824
|
-
if (this.mark.attrs)
|
|
825
|
-
for (let name in this.mark.attrs)
|
|
826
|
-
dom.setAttribute(name, this.mark.attrs[name]);
|
|
827
|
-
return dom;
|
|
828
|
-
}
|
|
829
|
-
canReuseDOM(other) {
|
|
830
|
-
return super.canReuseDOM(other) && !((this.flags | other.flags) & 8 /* ViewFlag.Composition */);
|
|
831
|
-
}
|
|
832
|
-
reuseDOM(node) {
|
|
833
|
-
if (node.nodeName == this.mark.tagName.toUpperCase()) {
|
|
834
|
-
this.setDOM(node);
|
|
835
|
-
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
836
|
-
}
|
|
837
|
-
}
|
|
838
|
-
sync(view, track) {
|
|
839
|
-
if (!this.dom)
|
|
840
|
-
this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
|
|
841
|
-
else if (this.flags & 4 /* ViewFlag.AttrsDirty */)
|
|
842
|
-
this.setAttrs(this.dom);
|
|
843
|
-
super.sync(view, track);
|
|
844
|
-
}
|
|
845
|
-
merge(from, to, source, _hasStart, openStart, openEnd) {
|
|
846
|
-
if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
|
|
847
|
-
(from && openStart <= 0) || (to < this.length && openEnd <= 0)))
|
|
848
|
-
return false;
|
|
849
|
-
mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart - 1, openEnd - 1);
|
|
850
|
-
this.markDirty();
|
|
851
|
-
return true;
|
|
852
|
-
}
|
|
853
|
-
split(from) {
|
|
854
|
-
let result = [], off = 0, detachFrom = -1, i = 0;
|
|
855
|
-
for (let elt of this.children) {
|
|
856
|
-
let end = off + elt.length;
|
|
857
|
-
if (end > from)
|
|
858
|
-
result.push(off < from ? elt.split(from - off) : elt);
|
|
859
|
-
if (detachFrom < 0 && off >= from)
|
|
860
|
-
detachFrom = i;
|
|
861
|
-
off = end;
|
|
862
|
-
i++;
|
|
863
|
-
}
|
|
864
|
-
let length = this.length - from;
|
|
865
|
-
this.length = from;
|
|
866
|
-
if (detachFrom > -1) {
|
|
867
|
-
this.children.length = detachFrom;
|
|
868
|
-
this.markDirty();
|
|
869
|
-
}
|
|
870
|
-
return new MarkView(this.mark, result, length);
|
|
871
|
-
}
|
|
872
|
-
domAtPos(pos) {
|
|
873
|
-
return inlineDOMAtPos(this, pos);
|
|
874
|
-
}
|
|
875
|
-
coordsAt(pos, side) {
|
|
876
|
-
return coordsInChildren(this, pos, side);
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
function textCoords(text, pos, side) {
|
|
880
|
-
let length = text.nodeValue.length;
|
|
881
|
-
if (pos > length)
|
|
882
|
-
pos = length;
|
|
883
|
-
let from = pos, to = pos, flatten = 0;
|
|
884
|
-
if (pos == 0 && side < 0 || pos == length && side >= 0) {
|
|
885
|
-
if (!(browser.chrome || browser.gecko)) { // These browsers reliably return valid rectangles for empty ranges
|
|
886
|
-
if (pos) {
|
|
887
|
-
from--;
|
|
888
|
-
flatten = 1;
|
|
889
|
-
} // FIXME this is wrong in RTL text
|
|
890
|
-
else if (to < length) {
|
|
891
|
-
to++;
|
|
892
|
-
flatten = -1;
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
else {
|
|
897
|
-
if (side < 0)
|
|
898
|
-
from--;
|
|
899
|
-
else if (to < length)
|
|
900
|
-
to++;
|
|
901
|
-
}
|
|
902
|
-
let rects = textRange(text, from, to).getClientRects();
|
|
903
|
-
if (!rects.length)
|
|
904
|
-
return null;
|
|
905
|
-
let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
|
|
906
|
-
if (browser.safari && !flatten && rect.width == 0)
|
|
907
|
-
rect = Array.prototype.find.call(rects, r => r.width) || rect;
|
|
908
|
-
return flatten ? flattenRect(rect, flatten < 0) : rect || null;
|
|
909
|
-
}
|
|
910
|
-
// Also used for collapsed ranges that don't have a placeholder widget!
|
|
911
|
-
class WidgetView extends ContentView {
|
|
912
|
-
static create(widget, length, side) {
|
|
913
|
-
return new WidgetView(widget, length, side);
|
|
914
|
-
}
|
|
915
|
-
constructor(widget, length, side) {
|
|
916
|
-
super();
|
|
917
|
-
this.widget = widget;
|
|
918
|
-
this.length = length;
|
|
919
|
-
this.side = side;
|
|
920
|
-
this.prevWidget = null;
|
|
921
|
-
}
|
|
922
|
-
split(from) {
|
|
923
|
-
let result = WidgetView.create(this.widget, this.length - from, this.side);
|
|
924
|
-
this.length -= from;
|
|
925
|
-
return result;
|
|
926
|
-
}
|
|
927
|
-
sync(view) {
|
|
928
|
-
if (!this.dom || !this.widget.updateDOM(this.dom, view)) {
|
|
929
|
-
if (this.dom && this.prevWidget)
|
|
930
|
-
this.prevWidget.destroy(this.dom);
|
|
931
|
-
this.prevWidget = null;
|
|
932
|
-
this.setDOM(this.widget.toDOM(view));
|
|
933
|
-
if (!this.widget.editable)
|
|
934
|
-
this.dom.contentEditable = "false";
|
|
935
|
-
}
|
|
936
|
-
}
|
|
937
|
-
getSide() { return this.side; }
|
|
938
|
-
merge(from, to, source, hasStart, openStart, openEnd) {
|
|
939
|
-
if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) ||
|
|
940
|
-
from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
|
|
941
|
-
return false;
|
|
942
|
-
this.length = from + (source ? source.length : 0) + (this.length - to);
|
|
943
|
-
return true;
|
|
944
|
-
}
|
|
945
|
-
become(other) {
|
|
946
|
-
if (other instanceof WidgetView && other.side == this.side &&
|
|
947
|
-
this.widget.constructor == other.widget.constructor) {
|
|
948
|
-
if (!this.widget.compare(other.widget))
|
|
949
|
-
this.markDirty(true);
|
|
950
|
-
if (this.dom && !this.prevWidget)
|
|
951
|
-
this.prevWidget = this.widget;
|
|
952
|
-
this.widget = other.widget;
|
|
953
|
-
this.length = other.length;
|
|
954
|
-
return true;
|
|
955
|
-
}
|
|
956
|
-
return false;
|
|
957
|
-
}
|
|
958
|
-
ignoreMutation() { return true; }
|
|
959
|
-
ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
|
960
|
-
get overrideDOMText() {
|
|
961
|
-
if (this.length == 0)
|
|
962
|
-
return state.Text.empty;
|
|
963
|
-
let top = this;
|
|
964
|
-
while (top.parent)
|
|
965
|
-
top = top.parent;
|
|
966
|
-
let { view } = top, text = view && view.state.doc, start = this.posAtStart;
|
|
967
|
-
return text ? text.slice(start, start + this.length) : state.Text.empty;
|
|
968
|
-
}
|
|
969
|
-
domAtPos(pos) {
|
|
970
|
-
return (this.length ? pos == 0 : this.side > 0)
|
|
971
|
-
? DOMPos.before(this.dom)
|
|
972
|
-
: DOMPos.after(this.dom, pos == this.length);
|
|
973
|
-
}
|
|
974
|
-
domBoundsAround() { return null; }
|
|
975
|
-
coordsAt(pos, side) {
|
|
976
|
-
let custom = this.widget.coordsAt(this.dom, pos, side);
|
|
977
|
-
if (custom)
|
|
978
|
-
return custom;
|
|
979
|
-
let rects = this.dom.getClientRects(), rect = null;
|
|
980
|
-
if (!rects.length)
|
|
981
|
-
return null;
|
|
982
|
-
let fromBack = this.side ? this.side < 0 : pos > 0;
|
|
983
|
-
for (let i = fromBack ? rects.length - 1 : 0;; i += (fromBack ? -1 : 1)) {
|
|
984
|
-
rect = rects[i];
|
|
985
|
-
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
|
986
|
-
break;
|
|
987
|
-
}
|
|
988
|
-
return flattenRect(rect, !fromBack);
|
|
989
|
-
}
|
|
990
|
-
get isEditable() { return false; }
|
|
991
|
-
get isWidget() { return true; }
|
|
992
|
-
get isHidden() { return this.widget.isHidden; }
|
|
993
|
-
destroy() {
|
|
994
|
-
super.destroy();
|
|
995
|
-
if (this.dom)
|
|
996
|
-
this.widget.destroy(this.dom);
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
// These are drawn around uneditable widgets to avoid a number of
|
|
1000
|
-
// browser bugs that show up when the cursor is directly next to
|
|
1001
|
-
// uneditable inline content.
|
|
1002
|
-
class WidgetBufferView extends ContentView {
|
|
1003
|
-
constructor(side) {
|
|
1004
|
-
super();
|
|
1005
|
-
this.side = side;
|
|
1006
|
-
}
|
|
1007
|
-
get length() { return 0; }
|
|
1008
|
-
merge() { return false; }
|
|
1009
|
-
become(other) {
|
|
1010
|
-
return other instanceof WidgetBufferView && other.side == this.side;
|
|
1011
|
-
}
|
|
1012
|
-
split() { return new WidgetBufferView(this.side); }
|
|
1013
|
-
sync() {
|
|
1014
|
-
if (!this.dom) {
|
|
1015
|
-
let dom = document.createElement("img");
|
|
1016
|
-
dom.className = "cm-widgetBuffer";
|
|
1017
|
-
dom.setAttribute("aria-hidden", "true");
|
|
1018
|
-
this.setDOM(dom);
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
getSide() { return this.side; }
|
|
1022
|
-
domAtPos(pos) { return this.side > 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom); }
|
|
1023
|
-
localPosFromDOM() { return 0; }
|
|
1024
|
-
domBoundsAround() { return null; }
|
|
1025
|
-
coordsAt(pos) {
|
|
1026
|
-
return this.dom.getBoundingClientRect();
|
|
1027
|
-
}
|
|
1028
|
-
get overrideDOMText() {
|
|
1029
|
-
return state.Text.empty;
|
|
1030
|
-
}
|
|
1031
|
-
get isHidden() { return true; }
|
|
1032
|
-
}
|
|
1033
|
-
TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
|
1034
|
-
function inlineDOMAtPos(parent, pos) {
|
|
1035
|
-
let dom = parent.dom, { children } = parent, i = 0;
|
|
1036
|
-
for (let off = 0; i < children.length; i++) {
|
|
1037
|
-
let child = children[i], end = off + child.length;
|
|
1038
|
-
if (end == off && child.getSide() <= 0)
|
|
1039
|
-
continue;
|
|
1040
|
-
if (pos > off && pos < end && child.dom.parentNode == dom)
|
|
1041
|
-
return child.domAtPos(pos - off);
|
|
1042
|
-
if (pos <= off)
|
|
1043
|
-
break;
|
|
1044
|
-
off = end;
|
|
1045
|
-
}
|
|
1046
|
-
for (let j = i; j > 0; j--) {
|
|
1047
|
-
let prev = children[j - 1];
|
|
1048
|
-
if (prev.dom.parentNode == dom)
|
|
1049
|
-
return prev.domAtPos(prev.length);
|
|
1050
|
-
}
|
|
1051
|
-
for (let j = i; j < children.length; j++) {
|
|
1052
|
-
let next = children[j];
|
|
1053
|
-
if (next.dom.parentNode == dom)
|
|
1054
|
-
return next.domAtPos(0);
|
|
1055
|
-
}
|
|
1056
|
-
return new DOMPos(dom, 0);
|
|
1057
|
-
}
|
|
1058
|
-
// Assumes `view`, if a mark view, has precisely 1 child.
|
|
1059
|
-
function joinInlineInto(parent, view, open) {
|
|
1060
|
-
let last, { children } = parent;
|
|
1061
|
-
if (open > 0 && view instanceof MarkView && children.length &&
|
|
1062
|
-
(last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) {
|
|
1063
|
-
joinInlineInto(last, view.children[0], open - 1);
|
|
1064
|
-
}
|
|
1065
|
-
else {
|
|
1066
|
-
children.push(view);
|
|
1067
|
-
view.setParent(parent);
|
|
1068
|
-
}
|
|
1069
|
-
parent.length += view.length;
|
|
1070
|
-
}
|
|
1071
|
-
function coordsInChildren(view, pos, side) {
|
|
1072
|
-
let before = null, beforePos = -1, after = null, afterPos = -1;
|
|
1073
|
-
function scan(view, pos) {
|
|
1074
|
-
for (let i = 0, off = 0; i < view.children.length && off <= pos; i++) {
|
|
1075
|
-
let child = view.children[i], end = off + child.length;
|
|
1076
|
-
if (end >= pos) {
|
|
1077
|
-
if (child.children.length) {
|
|
1078
|
-
scan(child, pos - off);
|
|
1079
|
-
}
|
|
1080
|
-
else if ((!after || after.isHidden && (side > 0 || onSameLine(after, child))) &&
|
|
1081
|
-
(end > pos || off == end && child.getSide() > 0)) {
|
|
1082
|
-
after = child;
|
|
1083
|
-
afterPos = pos - off;
|
|
1084
|
-
}
|
|
1085
|
-
else if (off < pos || (off == end && child.getSide() < 0) && !child.isHidden) {
|
|
1086
|
-
before = child;
|
|
1087
|
-
beforePos = pos - off;
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
off = end;
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
scan(view, pos);
|
|
1094
|
-
let target = (side < 0 ? before : after) || before || after;
|
|
1095
|
-
if (target)
|
|
1096
|
-
return target.coordsAt(Math.max(0, target == before ? beforePos : afterPos), side);
|
|
1097
|
-
return fallbackRect(view);
|
|
1098
|
-
}
|
|
1099
|
-
function fallbackRect(view) {
|
|
1100
|
-
let last = view.dom.lastChild;
|
|
1101
|
-
if (!last)
|
|
1102
|
-
return view.dom.getBoundingClientRect();
|
|
1103
|
-
let rects = clientRectsFor(last);
|
|
1104
|
-
return rects[rects.length - 1] || null;
|
|
1105
|
-
}
|
|
1106
|
-
function onSameLine(a, b) {
|
|
1107
|
-
let posA = a.coordsAt(0, 1), posB = b.coordsAt(0, 1);
|
|
1108
|
-
return posA && posB && posB.top < posA.bottom;
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
38
|
function combineAttrs(source, target) {
|
|
1112
39
|
for (let name in source) {
|
|
1113
40
|
if (name == "class" && target.class)
|
|
@@ -1137,6 +64,20 @@ function attrsEq(a, b, ignore) {
|
|
|
1137
64
|
}
|
|
1138
65
|
return true;
|
|
1139
66
|
}
|
|
67
|
+
function setAttrs(dom, attrs) {
|
|
68
|
+
for (let i = dom.attributes.length - 1; i >= 0; i--) {
|
|
69
|
+
let name = dom.attributes[i].name;
|
|
70
|
+
if (attrs[name] == null)
|
|
71
|
+
dom.removeAttribute(name);
|
|
72
|
+
}
|
|
73
|
+
for (let name in attrs) {
|
|
74
|
+
let value = attrs[name];
|
|
75
|
+
if (name == "style")
|
|
76
|
+
dom.style.cssText = value;
|
|
77
|
+
else if (dom.getAttribute(name) != value)
|
|
78
|
+
dom.setAttribute(name, value);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
1140
81
|
function updateAttrs(dom, prev, attrs) {
|
|
1141
82
|
let changed = false;
|
|
1142
83
|
if (prev)
|
|
@@ -1369,16 +310,11 @@ class MarkDecoration extends Decoration {
|
|
|
1369
310
|
let { start, end } = getInclusive(spec);
|
|
1370
311
|
super(start ? -1 /* Side.InlineIncStart */ : 500000000 /* Side.NonIncStart */, end ? 1 /* Side.InlineIncEnd */ : -600000000 /* Side.NonIncEnd */, null, spec);
|
|
1371
312
|
this.tagName = spec.tagName || "span";
|
|
1372
|
-
this.
|
|
1373
|
-
|
|
313
|
+
this.attrs = spec.class && spec.attributes ? combineAttrs(spec.attributes, { class: spec.class })
|
|
314
|
+
: spec.class ? { class: spec.class } : spec.attributes || noAttrs;
|
|
1374
315
|
}
|
|
1375
316
|
eq(other) {
|
|
1376
|
-
|
|
1377
|
-
return this == other ||
|
|
1378
|
-
other instanceof MarkDecoration &&
|
|
1379
|
-
this.tagName == other.tagName &&
|
|
1380
|
-
(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)) &&
|
|
1381
|
-
attrsEq(this.attrs, other.attrs, "class");
|
|
317
|
+
return this == other || other instanceof MarkDecoration && this.tagName == other.tagName && attrsEq(this.attrs, other.attrs);
|
|
1382
318
|
}
|
|
1383
319
|
range(from, to = from) {
|
|
1384
320
|
if (from >= to)
|
|
@@ -1452,438 +388,427 @@ function addRange(from, to, ranges, margin = 0) {
|
|
|
1452
388
|
else
|
|
1453
389
|
ranges.push(from, to);
|
|
1454
390
|
}
|
|
391
|
+
/**
|
|
392
|
+
A block wrapper defines a DOM node that wraps lines or other block
|
|
393
|
+
wrappers at the top of the document. It affects any line or block
|
|
394
|
+
widget that starts inside its range, including blocks starting
|
|
395
|
+
directly at `from` but not including `to`.
|
|
396
|
+
*/
|
|
397
|
+
class BlockWrapper extends state.RangeValue {
|
|
398
|
+
constructor(tagName, attributes) {
|
|
399
|
+
super();
|
|
400
|
+
this.tagName = tagName;
|
|
401
|
+
this.attributes = attributes;
|
|
402
|
+
}
|
|
403
|
+
eq(other) {
|
|
404
|
+
return other == this ||
|
|
405
|
+
other instanceof BlockWrapper && this.tagName == other.tagName && attrsEq(this.attributes, other.attributes);
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
Create a block wrapper object with the given tag name and
|
|
409
|
+
attributes.
|
|
410
|
+
*/
|
|
411
|
+
static create(spec) {
|
|
412
|
+
return new BlockWrapper(spec.tagName, spec.attributes || noAttrs);
|
|
413
|
+
}
|
|
414
|
+
/**
|
|
415
|
+
Create a range set from the given block wrapper ranges.
|
|
416
|
+
*/
|
|
417
|
+
static set(of, sort = false) {
|
|
418
|
+
return state.RangeSet.of(of, sort);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
BlockWrapper.prototype.startSide = BlockWrapper.prototype.endSide = -1;
|
|
1455
422
|
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
423
|
+
function getSelection(root) {
|
|
424
|
+
let target;
|
|
425
|
+
// Browsers differ on whether shadow roots have a getSelection
|
|
426
|
+
// method. If it exists, use that, otherwise, call it on the
|
|
427
|
+
// document.
|
|
428
|
+
if (root.nodeType == 11) { // Shadow root
|
|
429
|
+
target = root.getSelection ? root : root.ownerDocument;
|
|
430
|
+
}
|
|
431
|
+
else {
|
|
432
|
+
target = root;
|
|
433
|
+
}
|
|
434
|
+
return target.getSelection();
|
|
435
|
+
}
|
|
436
|
+
function contains(dom, node) {
|
|
437
|
+
return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
|
438
|
+
}
|
|
439
|
+
function hasSelection(dom, selection) {
|
|
440
|
+
if (!selection.anchorNode)
|
|
441
|
+
return false;
|
|
442
|
+
try {
|
|
443
|
+
// Firefox will raise 'permission denied' errors when accessing
|
|
444
|
+
// properties of `sel.anchorNode` when it's in a generated CSS
|
|
445
|
+
// element.
|
|
446
|
+
return contains(dom, selection.anchorNode);
|
|
447
|
+
}
|
|
448
|
+
catch (_) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
function clientRectsFor(dom) {
|
|
453
|
+
if (dom.nodeType == 3)
|
|
454
|
+
return textRange(dom, 0, dom.nodeValue.length).getClientRects();
|
|
455
|
+
else if (dom.nodeType == 1)
|
|
456
|
+
return dom.getClientRects();
|
|
457
|
+
else
|
|
458
|
+
return [];
|
|
459
|
+
}
|
|
460
|
+
// Scans forward and backward through DOM positions equivalent to the
|
|
461
|
+
// given one to see if the two are in the same place (i.e. after a
|
|
462
|
+
// text node vs at the end of that text node)
|
|
463
|
+
function isEquivalentPosition(node, off, targetNode, targetOff) {
|
|
464
|
+
return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) ||
|
|
465
|
+
scanFor(node, off, targetNode, targetOff, 1)) : false;
|
|
466
|
+
}
|
|
467
|
+
function domIndex(node) {
|
|
468
|
+
for (var index = 0;; index++) {
|
|
469
|
+
node = node.previousSibling;
|
|
470
|
+
if (!node)
|
|
471
|
+
return index;
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
function isBlockElement(node) {
|
|
475
|
+
return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
|
476
|
+
}
|
|
477
|
+
function scanFor(node, off, targetNode, targetOff, dir) {
|
|
478
|
+
for (;;) {
|
|
479
|
+
if (node == targetNode && off == targetOff)
|
|
480
|
+
return true;
|
|
481
|
+
if (off == (dir < 0 ? 0 : maxOffset(node))) {
|
|
482
|
+
if (node.nodeName == "DIV")
|
|
483
|
+
return false;
|
|
484
|
+
let parent = node.parentNode;
|
|
485
|
+
if (!parent || parent.nodeType != 1)
|
|
1469
486
|
return false;
|
|
1470
|
-
|
|
1471
|
-
|
|
487
|
+
off = domIndex(node) + (dir < 0 ? 0 : 1);
|
|
488
|
+
node = parent;
|
|
489
|
+
}
|
|
490
|
+
else if (node.nodeType == 1) {
|
|
491
|
+
node = node.childNodes[off + (dir < 0 ? -1 : 0)];
|
|
492
|
+
if (node.nodeType == 1 && node.contentEditable == "false")
|
|
493
|
+
return false;
|
|
494
|
+
off = dir < 0 ? maxOffset(node) : 0;
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
return false;
|
|
1472
498
|
}
|
|
1473
|
-
if (hasStart)
|
|
1474
|
-
this.setDeco(source ? source.attrs : null);
|
|
1475
|
-
mergeChildrenInto(this, from, to, source ? source.children.slice() : [], openStart, openEnd);
|
|
1476
|
-
return true;
|
|
1477
499
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if (
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
500
|
+
}
|
|
501
|
+
function maxOffset(node) {
|
|
502
|
+
return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
|
503
|
+
}
|
|
504
|
+
function flattenRect(rect, left) {
|
|
505
|
+
let x = left ? rect.left : rect.right;
|
|
506
|
+
return { left: x, right: x, top: rect.top, bottom: rect.bottom };
|
|
507
|
+
}
|
|
508
|
+
function windowRect(win) {
|
|
509
|
+
let vp = win.visualViewport;
|
|
510
|
+
if (vp)
|
|
511
|
+
return {
|
|
512
|
+
left: 0, right: vp.width,
|
|
513
|
+
top: 0, bottom: vp.height
|
|
514
|
+
};
|
|
515
|
+
return { left: 0, right: win.innerWidth,
|
|
516
|
+
top: 0, bottom: win.innerHeight };
|
|
517
|
+
}
|
|
518
|
+
function getScale(elt, rect) {
|
|
519
|
+
let scaleX = rect.width / elt.offsetWidth;
|
|
520
|
+
let scaleY = rect.height / elt.offsetHeight;
|
|
521
|
+
if (scaleX > 0.995 && scaleX < 1.005 || !isFinite(scaleX) || Math.abs(rect.width - elt.offsetWidth) < 1)
|
|
522
|
+
scaleX = 1;
|
|
523
|
+
if (scaleY > 0.995 && scaleY < 1.005 || !isFinite(scaleY) || Math.abs(rect.height - elt.offsetHeight) < 1)
|
|
524
|
+
scaleY = 1;
|
|
525
|
+
return { scaleX, scaleY };
|
|
526
|
+
}
|
|
527
|
+
function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
|
528
|
+
let doc = dom.ownerDocument, win = doc.defaultView || window;
|
|
529
|
+
for (let cur = dom, stop = false; cur && !stop;) {
|
|
530
|
+
if (cur.nodeType == 1) { // Element
|
|
531
|
+
let bounding, top = cur == doc.body;
|
|
532
|
+
let scaleX = 1, scaleY = 1;
|
|
533
|
+
if (top) {
|
|
534
|
+
bounding = windowRect(win);
|
|
535
|
+
}
|
|
536
|
+
else {
|
|
537
|
+
if (/^(fixed|sticky)$/.test(getComputedStyle(cur).position))
|
|
538
|
+
stop = true;
|
|
539
|
+
if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
|
|
540
|
+
cur = cur.assignedSlot || cur.parentNode;
|
|
541
|
+
continue;
|
|
542
|
+
}
|
|
543
|
+
let rect = cur.getBoundingClientRect();
|
|
544
|
+
({ scaleX, scaleY } = getScale(cur, rect));
|
|
545
|
+
// Make sure scrollbar width isn't included in the rectangle
|
|
546
|
+
bounding = { left: rect.left, right: rect.left + cur.clientWidth * scaleX,
|
|
547
|
+
top: rect.top, bottom: rect.top + cur.clientHeight * scaleY };
|
|
548
|
+
}
|
|
549
|
+
let moveX = 0, moveY = 0;
|
|
550
|
+
if (y == "nearest") {
|
|
551
|
+
if (rect.top < bounding.top) {
|
|
552
|
+
moveY = rect.top - (bounding.top + yMargin);
|
|
553
|
+
if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
|
554
|
+
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
555
|
+
}
|
|
556
|
+
else if (rect.bottom > bounding.bottom) {
|
|
557
|
+
moveY = rect.bottom - bounding.bottom + yMargin;
|
|
558
|
+
if (side < 0 && (rect.top - moveY) < bounding.top)
|
|
559
|
+
moveY = rect.top - (bounding.top + yMargin);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
else {
|
|
563
|
+
let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
|
564
|
+
let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
|
|
565
|
+
y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
|
|
566
|
+
rect.bottom - boundingHeight + yMargin;
|
|
567
|
+
moveY = targetTop - bounding.top;
|
|
568
|
+
}
|
|
569
|
+
if (x == "nearest") {
|
|
570
|
+
if (rect.left < bounding.left) {
|
|
571
|
+
moveX = rect.left - (bounding.left + xMargin);
|
|
572
|
+
if (side > 0 && rect.right > bounding.right + moveX)
|
|
573
|
+
moveX = rect.right - bounding.right + xMargin;
|
|
574
|
+
}
|
|
575
|
+
else if (rect.right > bounding.right) {
|
|
576
|
+
moveX = rect.right - bounding.right + xMargin;
|
|
577
|
+
if (side < 0 && rect.left < bounding.left + moveX)
|
|
578
|
+
moveX = rect.left - (bounding.left + xMargin);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
else {
|
|
582
|
+
let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
|
|
583
|
+
(x == "start") == ltr ? rect.left - xMargin :
|
|
584
|
+
rect.right - (bounding.right - bounding.left) + xMargin;
|
|
585
|
+
moveX = targetLeft - bounding.left;
|
|
586
|
+
}
|
|
587
|
+
if (moveX || moveY) {
|
|
588
|
+
if (top) {
|
|
589
|
+
win.scrollBy(moveX, moveY);
|
|
590
|
+
}
|
|
591
|
+
else {
|
|
592
|
+
let movedX = 0, movedY = 0;
|
|
593
|
+
if (moveY) {
|
|
594
|
+
let start = cur.scrollTop;
|
|
595
|
+
cur.scrollTop += moveY / scaleY;
|
|
596
|
+
movedY = (cur.scrollTop - start) * scaleY;
|
|
597
|
+
}
|
|
598
|
+
if (moveX) {
|
|
599
|
+
let start = cur.scrollLeft;
|
|
600
|
+
cur.scrollLeft += moveX / scaleX;
|
|
601
|
+
movedX = (cur.scrollLeft - start) * scaleX;
|
|
602
|
+
}
|
|
603
|
+
rect = { left: rect.left - movedX, top: rect.top - movedY,
|
|
604
|
+
right: rect.right - movedX, bottom: rect.bottom - movedY };
|
|
605
|
+
if (movedX && Math.abs(movedX - moveX) < 1)
|
|
606
|
+
x = "nearest";
|
|
607
|
+
if (movedY && Math.abs(movedY - moveY) < 1)
|
|
608
|
+
y = "nearest";
|
|
609
|
+
}
|
|
1512
610
|
}
|
|
1513
|
-
|
|
611
|
+
if (top)
|
|
612
|
+
break;
|
|
613
|
+
if (rect.top < bounding.top || rect.bottom > bounding.bottom ||
|
|
614
|
+
rect.left < bounding.left || rect.right > bounding.right)
|
|
615
|
+
rect = { left: Math.max(rect.left, bounding.left), right: Math.min(rect.right, bounding.right),
|
|
616
|
+
top: Math.max(rect.top, bounding.top), bottom: Math.min(rect.bottom, bounding.bottom) };
|
|
617
|
+
cur = cur.assignedSlot || cur.parentNode;
|
|
1514
618
|
}
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
joinInlineInto(this, child, openStart);
|
|
1518
|
-
}
|
|
1519
|
-
// Only called when building a line view in ContentBuilder
|
|
1520
|
-
addLineDeco(deco) {
|
|
1521
|
-
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
1522
|
-
if (attrs)
|
|
1523
|
-
this.attrs = combineAttrs(attrs, this.attrs || {});
|
|
1524
|
-
if (cls)
|
|
1525
|
-
this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
|
1526
|
-
}
|
|
1527
|
-
domAtPos(pos) {
|
|
1528
|
-
return inlineDOMAtPos(this, pos);
|
|
1529
|
-
}
|
|
1530
|
-
reuseDOM(node) {
|
|
1531
|
-
if (node.nodeName == "DIV") {
|
|
1532
|
-
this.setDOM(node);
|
|
1533
|
-
this.flags |= 4 /* ViewFlag.AttrsDirty */ | 2 /* ViewFlag.NodeDirty */;
|
|
619
|
+
else if (cur.nodeType == 11) { // A shadow root
|
|
620
|
+
cur = cur.host;
|
|
1534
621
|
}
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
var _a;
|
|
1538
|
-
if (!this.dom) {
|
|
1539
|
-
this.setDOM(document.createElement("div"));
|
|
1540
|
-
this.dom.className = "cm-line";
|
|
1541
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1542
|
-
}
|
|
1543
|
-
else if (this.flags & 4 /* ViewFlag.AttrsDirty */) {
|
|
1544
|
-
clearAttributes(this.dom);
|
|
1545
|
-
this.dom.className = "cm-line";
|
|
1546
|
-
this.prevAttrs = this.attrs ? null : undefined;
|
|
1547
|
-
}
|
|
1548
|
-
if (this.prevAttrs !== undefined) {
|
|
1549
|
-
updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
|
1550
|
-
this.dom.classList.add("cm-line");
|
|
1551
|
-
this.prevAttrs = undefined;
|
|
1552
|
-
}
|
|
1553
|
-
super.sync(view, track);
|
|
1554
|
-
let last = this.dom.lastChild;
|
|
1555
|
-
while (last && ContentView.get(last) instanceof MarkView)
|
|
1556
|
-
last = last.lastChild;
|
|
1557
|
-
if (!last || !this.length ||
|
|
1558
|
-
last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
|
1559
|
-
(!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
|
1560
|
-
let hack = document.createElement("BR");
|
|
1561
|
-
hack.cmIgnore = true;
|
|
1562
|
-
this.dom.appendChild(hack);
|
|
622
|
+
else {
|
|
623
|
+
break;
|
|
1563
624
|
}
|
|
1564
625
|
}
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
return null;
|
|
1572
|
-
let rects = clientRectsFor(child.dom);
|
|
1573
|
-
if (rects.length != 1)
|
|
1574
|
-
return null;
|
|
1575
|
-
totalWidth += rects[0].width;
|
|
1576
|
-
textHeight = rects[0].height;
|
|
626
|
+
}
|
|
627
|
+
function scrollableParents(dom) {
|
|
628
|
+
let doc = dom.ownerDocument, x, y;
|
|
629
|
+
for (let cur = dom.parentNode; cur;) {
|
|
630
|
+
if (cur == doc.body || (x && y)) {
|
|
631
|
+
break;
|
|
1577
632
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
coordsAt(pos, side) {
|
|
1585
|
-
let rect = coordsInChildren(this, pos, side);
|
|
1586
|
-
// Correct rectangle height for empty lines when the returned
|
|
1587
|
-
// height is larger than the text height.
|
|
1588
|
-
if (!this.children.length && rect && this.parent) {
|
|
1589
|
-
let { heightOracle } = this.parent.view.viewState, height = rect.bottom - rect.top;
|
|
1590
|
-
if (Math.abs(height - heightOracle.lineHeight) < 2 && heightOracle.textHeight < height) {
|
|
1591
|
-
let dist = (height - heightOracle.textHeight) / 2;
|
|
1592
|
-
return { top: rect.top + dist, bottom: rect.bottom - dist, left: rect.left, right: rect.left };
|
|
1593
|
-
}
|
|
633
|
+
else if (cur.nodeType == 1) {
|
|
634
|
+
if (!y && cur.scrollHeight > cur.clientHeight)
|
|
635
|
+
y = cur;
|
|
636
|
+
if (!x && cur.scrollWidth > cur.clientWidth)
|
|
637
|
+
x = cur;
|
|
638
|
+
cur = cur.assignedSlot || cur.parentNode;
|
|
1594
639
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
}
|
|
1601
|
-
covers() { return true; }
|
|
1602
|
-
static find(docView, pos) {
|
|
1603
|
-
for (let i = 0, off = 0; i < docView.children.length; i++) {
|
|
1604
|
-
let block = docView.children[i], end = off + block.length;
|
|
1605
|
-
if (end >= pos) {
|
|
1606
|
-
if (block instanceof LineView)
|
|
1607
|
-
return block;
|
|
1608
|
-
if (end > pos)
|
|
1609
|
-
break;
|
|
1610
|
-
}
|
|
1611
|
-
off = end + block.breakAfter;
|
|
640
|
+
else if (cur.nodeType == 11) {
|
|
641
|
+
cur = cur.host;
|
|
642
|
+
}
|
|
643
|
+
else {
|
|
644
|
+
break;
|
|
1612
645
|
}
|
|
1613
|
-
return null;
|
|
1614
646
|
}
|
|
647
|
+
return { x, y };
|
|
1615
648
|
}
|
|
1616
|
-
class
|
|
1617
|
-
constructor(
|
|
1618
|
-
|
|
1619
|
-
this.
|
|
1620
|
-
this.
|
|
1621
|
-
this.
|
|
1622
|
-
this.breakAfter = 0;
|
|
1623
|
-
this.prevWidget = null;
|
|
649
|
+
class DOMSelectionState {
|
|
650
|
+
constructor() {
|
|
651
|
+
this.anchorNode = null;
|
|
652
|
+
this.anchorOffset = 0;
|
|
653
|
+
this.focusNode = null;
|
|
654
|
+
this.focusOffset = 0;
|
|
1624
655
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
return false;
|
|
1629
|
-
this.length = from + (source ? source.length : 0) + (this.length - to);
|
|
1630
|
-
return true;
|
|
656
|
+
eq(domSel) {
|
|
657
|
+
return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
|
|
658
|
+
this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
|
|
1631
659
|
}
|
|
1632
|
-
|
|
1633
|
-
|
|
660
|
+
setRange(range) {
|
|
661
|
+
let { anchorNode, focusNode } = range;
|
|
662
|
+
// Clip offsets to node size to avoid crashes when Safari reports bogus offsets (#1152)
|
|
663
|
+
this.set(anchorNode, Math.min(range.anchorOffset, anchorNode ? maxOffset(anchorNode) : 0), focusNode, Math.min(range.focusOffset, focusNode ? maxOffset(focusNode) : 0));
|
|
1634
664
|
}
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
this.
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
return end;
|
|
665
|
+
set(anchorNode, anchorOffset, focusNode, focusOffset) {
|
|
666
|
+
this.anchorNode = anchorNode;
|
|
667
|
+
this.anchorOffset = anchorOffset;
|
|
668
|
+
this.focusNode = focusNode;
|
|
669
|
+
this.focusOffset = focusOffset;
|
|
1641
670
|
}
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
671
|
+
}
|
|
672
|
+
let preventScrollSupported = null;
|
|
673
|
+
// Safari 26 breaks preventScroll support
|
|
674
|
+
if (browser.safari && browser.safari_version >= 26)
|
|
675
|
+
preventScrollSupported = false;
|
|
676
|
+
// Feature-detects support for .focus({preventScroll: true}), and uses
|
|
677
|
+
// a fallback kludge when not supported.
|
|
678
|
+
function focusPreventScroll(dom) {
|
|
679
|
+
if (dom.setActive)
|
|
680
|
+
return dom.setActive(); // in IE
|
|
681
|
+
if (preventScrollSupported)
|
|
682
|
+
return dom.focus(preventScrollSupported);
|
|
683
|
+
let stack = [];
|
|
684
|
+
for (let cur = dom; cur; cur = cur.parentNode) {
|
|
685
|
+
stack.push(cur, cur.scrollTop, cur.scrollLeft);
|
|
686
|
+
if (cur == cur.ownerDocument)
|
|
687
|
+
break;
|
|
1652
688
|
}
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
domBoundsAround() { return null; }
|
|
1657
|
-
become(other) {
|
|
1658
|
-
if (other instanceof BlockWidgetView &&
|
|
1659
|
-
other.widget.constructor == this.widget.constructor) {
|
|
1660
|
-
if (!other.widget.compare(this.widget))
|
|
1661
|
-
this.markDirty(true);
|
|
1662
|
-
if (this.dom && !this.prevWidget)
|
|
1663
|
-
this.prevWidget = this.widget;
|
|
1664
|
-
this.widget = other.widget;
|
|
1665
|
-
this.length = other.length;
|
|
1666
|
-
this.deco = other.deco;
|
|
1667
|
-
this.breakAfter = other.breakAfter;
|
|
689
|
+
dom.focus(preventScrollSupported == null ? {
|
|
690
|
+
get preventScroll() {
|
|
691
|
+
preventScrollSupported = { preventScroll: true };
|
|
1668
692
|
return true;
|
|
1669
693
|
}
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
if (this.widget instanceof BlockGapWidget)
|
|
1681
|
-
return null;
|
|
1682
|
-
return flattenRect(this.dom.getBoundingClientRect(), this.length ? pos == 0 : side <= 0);
|
|
1683
|
-
}
|
|
1684
|
-
destroy() {
|
|
1685
|
-
super.destroy();
|
|
1686
|
-
if (this.dom)
|
|
1687
|
-
this.widget.destroy(this.dom);
|
|
1688
|
-
}
|
|
1689
|
-
covers(side) {
|
|
1690
|
-
let { startSide, endSide } = this.deco;
|
|
1691
|
-
return startSide == endSide ? false : side < 0 ? startSide < 0 : endSide > 0;
|
|
694
|
+
} : undefined);
|
|
695
|
+
if (!preventScrollSupported) {
|
|
696
|
+
preventScrollSupported = false;
|
|
697
|
+
for (let i = 0; i < stack.length;) {
|
|
698
|
+
let elt = stack[i++], top = stack[i++], left = stack[i++];
|
|
699
|
+
if (elt.scrollTop != top)
|
|
700
|
+
elt.scrollTop = top;
|
|
701
|
+
if (elt.scrollLeft != left)
|
|
702
|
+
elt.scrollLeft = left;
|
|
703
|
+
}
|
|
1692
704
|
}
|
|
1693
705
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
let elt = document.createElement("div");
|
|
1701
|
-
elt.className = "cm-gap";
|
|
1702
|
-
this.updateDOM(elt);
|
|
1703
|
-
return elt;
|
|
1704
|
-
}
|
|
1705
|
-
eq(other) { return other.height == this.height; }
|
|
1706
|
-
updateDOM(elt) {
|
|
1707
|
-
elt.style.height = this.height + "px";
|
|
1708
|
-
return true;
|
|
1709
|
-
}
|
|
1710
|
-
get editable() { return true; }
|
|
1711
|
-
get estimatedHeight() { return this.height; }
|
|
1712
|
-
ignoreEvent() { return false; }
|
|
706
|
+
let scratchRange;
|
|
707
|
+
function textRange(node, from, to = from) {
|
|
708
|
+
let range = scratchRange || (scratchRange = document.createRange());
|
|
709
|
+
range.setEnd(node, to);
|
|
710
|
+
range.setStart(node, from);
|
|
711
|
+
return range;
|
|
1713
712
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
this.textOff = 0;
|
|
1732
|
-
this.cursor = doc.iter();
|
|
1733
|
-
this.skip = pos;
|
|
1734
|
-
}
|
|
1735
|
-
posCovered() {
|
|
1736
|
-
if (this.content.length == 0)
|
|
1737
|
-
return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos;
|
|
1738
|
-
let last = this.content[this.content.length - 1];
|
|
1739
|
-
return !(last.breakAfter || last instanceof BlockWidgetView && last.deco.endSide < 0);
|
|
713
|
+
function dispatchKey(elt, name, code, mods) {
|
|
714
|
+
let options = { key: name, code: name, keyCode: code, which: code, cancelable: true };
|
|
715
|
+
if (mods)
|
|
716
|
+
({ altKey: options.altKey, ctrlKey: options.ctrlKey, shiftKey: options.shiftKey, metaKey: options.metaKey } = mods);
|
|
717
|
+
let down = new KeyboardEvent("keydown", options);
|
|
718
|
+
down.synthetic = true;
|
|
719
|
+
elt.dispatchEvent(down);
|
|
720
|
+
let up = new KeyboardEvent("keyup", options);
|
|
721
|
+
up.synthetic = true;
|
|
722
|
+
elt.dispatchEvent(up);
|
|
723
|
+
return down.defaultPrevented || up.defaultPrevented;
|
|
724
|
+
}
|
|
725
|
+
function getRoot(node) {
|
|
726
|
+
while (node) {
|
|
727
|
+
if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
|
728
|
+
return node;
|
|
729
|
+
node = node.assignedSlot || node.parentNode;
|
|
1740
730
|
}
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
731
|
+
return null;
|
|
732
|
+
}
|
|
733
|
+
function atElementStart(doc, selection) {
|
|
734
|
+
let node = selection.focusNode, offset = selection.focusOffset;
|
|
735
|
+
if (!node || selection.anchorNode != node || selection.anchorOffset != offset)
|
|
736
|
+
return false;
|
|
737
|
+
// Safari can report bogus offsets (#1152)
|
|
738
|
+
offset = Math.min(offset, maxOffset(node));
|
|
739
|
+
for (;;) {
|
|
740
|
+
if (offset) {
|
|
741
|
+
if (node.nodeType != 1)
|
|
742
|
+
return false;
|
|
743
|
+
let prev = node.childNodes[offset - 1];
|
|
744
|
+
if (prev.contentEditable == "false")
|
|
745
|
+
offset--;
|
|
746
|
+
else {
|
|
747
|
+
node = prev;
|
|
748
|
+
offset = maxOffset(node);
|
|
749
|
+
}
|
|
1745
750
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
751
|
+
else if (node == doc) {
|
|
752
|
+
return true;
|
|
753
|
+
}
|
|
754
|
+
else {
|
|
755
|
+
offset = domIndex(node);
|
|
756
|
+
node = node.parentNode;
|
|
1752
757
|
}
|
|
1753
758
|
}
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
if (
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
if (lineBreak) {
|
|
1776
|
-
if (!this.posCovered())
|
|
1777
|
-
this.getLine();
|
|
1778
|
-
if (this.content.length)
|
|
1779
|
-
this.content[this.content.length - 1].breakAfter = 1;
|
|
1780
|
-
else
|
|
1781
|
-
this.breakAtStart = 1;
|
|
1782
|
-
this.flushBuffer();
|
|
1783
|
-
this.curLine = null;
|
|
1784
|
-
this.atCursorPos = true;
|
|
1785
|
-
length--;
|
|
1786
|
-
continue;
|
|
1787
|
-
}
|
|
1788
|
-
else {
|
|
1789
|
-
this.text = value;
|
|
1790
|
-
this.textOff = 0;
|
|
1791
|
-
}
|
|
1792
|
-
}
|
|
1793
|
-
let remaining = Math.min(this.text.length - this.textOff, length);
|
|
1794
|
-
let take = Math.min(remaining, 512 /* T.Chunk */);
|
|
1795
|
-
this.flushBuffer(active.slice(active.length - openStart));
|
|
1796
|
-
this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
|
1797
|
-
this.atCursorPos = true;
|
|
1798
|
-
this.textOff += take;
|
|
1799
|
-
length -= take;
|
|
1800
|
-
openStart = remaining <= take ? 0 : active.length;
|
|
759
|
+
}
|
|
760
|
+
function isScrolledToBottom(elt) {
|
|
761
|
+
return elt.scrollTop > Math.max(1, elt.scrollHeight - elt.clientHeight - 4);
|
|
762
|
+
}
|
|
763
|
+
function textNodeBefore(startNode, startOffset) {
|
|
764
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
765
|
+
if (node.nodeType == 3 && offset > 0) {
|
|
766
|
+
return { node: node, offset: offset };
|
|
767
|
+
}
|
|
768
|
+
else if (node.nodeType == 1 && offset > 0) {
|
|
769
|
+
if (node.contentEditable == "false")
|
|
770
|
+
return null;
|
|
771
|
+
node = node.childNodes[offset - 1];
|
|
772
|
+
offset = maxOffset(node);
|
|
773
|
+
}
|
|
774
|
+
else if (node.parentNode && !isBlockElement(node)) {
|
|
775
|
+
offset = domIndex(node);
|
|
776
|
+
node = node.parentNode;
|
|
777
|
+
}
|
|
778
|
+
else {
|
|
779
|
+
return null;
|
|
1801
780
|
}
|
|
1802
781
|
}
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
if (
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
this.addBlockWidget(new BlockWidgetView(deco.widget || NullWidget.block, len, deco));
|
|
1822
|
-
}
|
|
1823
|
-
else {
|
|
1824
|
-
let view = WidgetView.create(deco.widget || NullWidget.inline, len, len ? 0 : deco.startSide);
|
|
1825
|
-
let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length &&
|
|
1826
|
-
(from < to || deco.startSide > 0);
|
|
1827
|
-
let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
|
|
1828
|
-
let line = this.getLine();
|
|
1829
|
-
if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore && !view.isEditable)
|
|
1830
|
-
this.pendingBuffer = 0 /* Buf.No */;
|
|
1831
|
-
this.flushBuffer(active);
|
|
1832
|
-
if (cursorBefore) {
|
|
1833
|
-
line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
|
|
1834
|
-
openStart = active.length + Math.max(0, openStart - active.length);
|
|
1835
|
-
}
|
|
1836
|
-
line.append(wrapMarks(view, active), openStart);
|
|
1837
|
-
this.atCursorPos = cursorAfter;
|
|
1838
|
-
this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to || openStart > active.length ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
|
|
1839
|
-
if (this.pendingBuffer)
|
|
1840
|
-
this.bufferMarks = active.slice();
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
|
|
1844
|
-
this.getLine().addLineDeco(deco);
|
|
1845
|
-
}
|
|
1846
|
-
if (len) {
|
|
1847
|
-
// Advance the iterator past the replaced content
|
|
1848
|
-
if (this.textOff + len <= this.text.length) {
|
|
1849
|
-
this.textOff += len;
|
|
1850
|
-
}
|
|
1851
|
-
else {
|
|
1852
|
-
this.skip += len - (this.text.length - this.textOff);
|
|
1853
|
-
this.text = "";
|
|
1854
|
-
this.textOff = 0;
|
|
1855
|
-
}
|
|
1856
|
-
this.pos = to;
|
|
782
|
+
}
|
|
783
|
+
function textNodeAfter(startNode, startOffset) {
|
|
784
|
+
for (let node = startNode, offset = startOffset;;) {
|
|
785
|
+
if (node.nodeType == 3 && offset < node.nodeValue.length) {
|
|
786
|
+
return { node: node, offset: offset };
|
|
787
|
+
}
|
|
788
|
+
else if (node.nodeType == 1 && offset < node.childNodes.length) {
|
|
789
|
+
if (node.contentEditable == "false")
|
|
790
|
+
return null;
|
|
791
|
+
node = node.childNodes[offset];
|
|
792
|
+
offset = 0;
|
|
793
|
+
}
|
|
794
|
+
else if (node.parentNode && !isBlockElement(node)) {
|
|
795
|
+
offset = domIndex(node) + 1;
|
|
796
|
+
node = node.parentNode;
|
|
797
|
+
}
|
|
798
|
+
else {
|
|
799
|
+
return null;
|
|
1857
800
|
}
|
|
1858
|
-
if (this.openStart < 0)
|
|
1859
|
-
this.openStart = openStart;
|
|
1860
|
-
}
|
|
1861
|
-
static build(text, from, to, decorations, dynamicDecorationMap) {
|
|
1862
|
-
let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
|
|
1863
|
-
builder.openEnd = state.RangeSet.spans(decorations, from, to, builder);
|
|
1864
|
-
if (builder.openStart < 0)
|
|
1865
|
-
builder.openStart = builder.openEnd;
|
|
1866
|
-
builder.finish(builder.openEnd);
|
|
1867
|
-
return builder;
|
|
1868
801
|
}
|
|
1869
802
|
}
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
class NullWidget extends WidgetType {
|
|
1876
|
-
constructor(tag) {
|
|
1877
|
-
super();
|
|
1878
|
-
this.tag = tag;
|
|
803
|
+
class DOMPos {
|
|
804
|
+
constructor(node, offset, precise = true) {
|
|
805
|
+
this.node = node;
|
|
806
|
+
this.offset = offset;
|
|
807
|
+
this.precise = precise;
|
|
1879
808
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
|
|
1883
|
-
get isHidden() { return true; }
|
|
809
|
+
static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); }
|
|
810
|
+
static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); }
|
|
1884
811
|
}
|
|
1885
|
-
NullWidget.inline = new NullWidget("span");
|
|
1886
|
-
NullWidget.block = new NullWidget("div");
|
|
1887
812
|
|
|
1888
813
|
/**
|
|
1889
814
|
Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
|
|
@@ -2445,341 +1370,1467 @@ const viewPlugin = state.Facet.define({
|
|
|
2445
1370
|
return true;
|
|
2446
1371
|
});
|
|
2447
1372
|
}
|
|
2448
|
-
});
|
|
1373
|
+
});
|
|
1374
|
+
/**
|
|
1375
|
+
View plugins associate stateful values with a view. They can
|
|
1376
|
+
influence the way the content is drawn, and are notified of things
|
|
1377
|
+
that happen in the view. They optionally take an argument, in
|
|
1378
|
+
which case you need to call [`of`](https://codemirror.net/6/docs/ref/#view.ViewPlugin.of) to create
|
|
1379
|
+
an extension for the plugin. When the argument type is undefined,
|
|
1380
|
+
you can use the plugin instance as an extension directly.
|
|
1381
|
+
*/
|
|
1382
|
+
class ViewPlugin {
|
|
1383
|
+
constructor(
|
|
1384
|
+
/**
|
|
1385
|
+
@internal
|
|
1386
|
+
*/
|
|
1387
|
+
id,
|
|
1388
|
+
/**
|
|
1389
|
+
@internal
|
|
1390
|
+
*/
|
|
1391
|
+
create,
|
|
1392
|
+
/**
|
|
1393
|
+
@internal
|
|
1394
|
+
*/
|
|
1395
|
+
domEventHandlers,
|
|
1396
|
+
/**
|
|
1397
|
+
@internal
|
|
1398
|
+
*/
|
|
1399
|
+
domEventObservers, buildExtensions) {
|
|
1400
|
+
this.id = id;
|
|
1401
|
+
this.create = create;
|
|
1402
|
+
this.domEventHandlers = domEventHandlers;
|
|
1403
|
+
this.domEventObservers = domEventObservers;
|
|
1404
|
+
this.baseExtensions = buildExtensions(this);
|
|
1405
|
+
this.extension = this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg: undefined }));
|
|
1406
|
+
}
|
|
1407
|
+
/**
|
|
1408
|
+
Create an extension for this plugin with the given argument.
|
|
1409
|
+
*/
|
|
1410
|
+
of(arg) {
|
|
1411
|
+
return this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg }));
|
|
1412
|
+
}
|
|
1413
|
+
/**
|
|
1414
|
+
Define a plugin from a constructor function that creates the
|
|
1415
|
+
plugin's value, given an editor view.
|
|
1416
|
+
*/
|
|
1417
|
+
static define(create, spec) {
|
|
1418
|
+
const { eventHandlers, eventObservers, provide, decorations: deco } = spec || {};
|
|
1419
|
+
return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
|
|
1420
|
+
let ext = [];
|
|
1421
|
+
if (deco)
|
|
1422
|
+
ext.push(decorations.of(view => {
|
|
1423
|
+
let pluginInst = view.plugin(plugin);
|
|
1424
|
+
return pluginInst ? deco(pluginInst) : Decoration.none;
|
|
1425
|
+
}));
|
|
1426
|
+
if (provide)
|
|
1427
|
+
ext.push(provide(plugin));
|
|
1428
|
+
return ext;
|
|
1429
|
+
});
|
|
1430
|
+
}
|
|
1431
|
+
/**
|
|
1432
|
+
Create a plugin for a class whose constructor takes a single
|
|
1433
|
+
editor view as argument.
|
|
1434
|
+
*/
|
|
1435
|
+
static fromClass(cls, spec) {
|
|
1436
|
+
return ViewPlugin.define((view, arg) => new cls(view, arg), spec);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
class PluginInstance {
|
|
1440
|
+
constructor(spec) {
|
|
1441
|
+
this.spec = spec;
|
|
1442
|
+
// When starting an update, all plugins have this field set to the
|
|
1443
|
+
// update object, indicating they need to be updated. When finished
|
|
1444
|
+
// updating, it is set to `null`. Retrieving a plugin that needs to
|
|
1445
|
+
// be updated with `view.plugin` forces an eager update.
|
|
1446
|
+
this.mustUpdate = null;
|
|
1447
|
+
// This is null when the plugin is initially created, but
|
|
1448
|
+
// initialized on the first update.
|
|
1449
|
+
this.value = null;
|
|
1450
|
+
}
|
|
1451
|
+
get plugin() { return this.spec && this.spec.plugin; }
|
|
1452
|
+
update(view) {
|
|
1453
|
+
if (!this.value) {
|
|
1454
|
+
if (this.spec) {
|
|
1455
|
+
try {
|
|
1456
|
+
this.value = this.spec.plugin.create(view, this.spec.arg);
|
|
1457
|
+
}
|
|
1458
|
+
catch (e) {
|
|
1459
|
+
logException(view.state, e, "CodeMirror plugin crashed");
|
|
1460
|
+
this.deactivate();
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
}
|
|
1464
|
+
else if (this.mustUpdate) {
|
|
1465
|
+
let update = this.mustUpdate;
|
|
1466
|
+
this.mustUpdate = null;
|
|
1467
|
+
if (this.value.update) {
|
|
1468
|
+
try {
|
|
1469
|
+
this.value.update(update);
|
|
1470
|
+
}
|
|
1471
|
+
catch (e) {
|
|
1472
|
+
logException(update.state, e, "CodeMirror plugin crashed");
|
|
1473
|
+
if (this.value.destroy)
|
|
1474
|
+
try {
|
|
1475
|
+
this.value.destroy();
|
|
1476
|
+
}
|
|
1477
|
+
catch (_) { }
|
|
1478
|
+
this.deactivate();
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
return this;
|
|
1483
|
+
}
|
|
1484
|
+
destroy(view) {
|
|
1485
|
+
var _a;
|
|
1486
|
+
if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) {
|
|
1487
|
+
try {
|
|
1488
|
+
this.value.destroy();
|
|
1489
|
+
}
|
|
1490
|
+
catch (e) {
|
|
1491
|
+
logException(view.state, e, "CodeMirror plugin crashed");
|
|
1492
|
+
}
|
|
1493
|
+
}
|
|
1494
|
+
}
|
|
1495
|
+
deactivate() {
|
|
1496
|
+
this.spec = this.value = null;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
const editorAttributes = state.Facet.define();
|
|
1500
|
+
const contentAttributes = state.Facet.define();
|
|
1501
|
+
// Provide decorations
|
|
1502
|
+
const decorations = state.Facet.define();
|
|
1503
|
+
const blockWrappers = state.Facet.define();
|
|
1504
|
+
const outerDecorations = state.Facet.define();
|
|
1505
|
+
const atomicRanges = state.Facet.define();
|
|
1506
|
+
const bidiIsolatedRanges = state.Facet.define();
|
|
1507
|
+
function getIsolatedRanges(view, line) {
|
|
1508
|
+
let isolates = view.state.facet(bidiIsolatedRanges);
|
|
1509
|
+
if (!isolates.length)
|
|
1510
|
+
return isolates;
|
|
1511
|
+
let sets = isolates.map(i => i instanceof Function ? i(view) : i);
|
|
1512
|
+
let result = [];
|
|
1513
|
+
state.RangeSet.spans(sets, line.from, line.to, {
|
|
1514
|
+
point() { },
|
|
1515
|
+
span(fromDoc, toDoc, active, open) {
|
|
1516
|
+
let from = fromDoc - line.from, to = toDoc - line.from;
|
|
1517
|
+
let level = result;
|
|
1518
|
+
for (let i = active.length - 1; i >= 0; i--, open--) {
|
|
1519
|
+
let direction = active[i].spec.bidiIsolate, update;
|
|
1520
|
+
if (direction == null)
|
|
1521
|
+
direction = autoDirection(line.text, from, to);
|
|
1522
|
+
if (open > 0 && level.length &&
|
|
1523
|
+
(update = level[level.length - 1]).to == from && update.direction == direction) {
|
|
1524
|
+
update.to = to;
|
|
1525
|
+
level = update.inner;
|
|
1526
|
+
}
|
|
1527
|
+
else {
|
|
1528
|
+
let add = { from, to, direction, inner: [] };
|
|
1529
|
+
level.push(add);
|
|
1530
|
+
level = add.inner;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
return result;
|
|
1536
|
+
}
|
|
1537
|
+
const scrollMargins = state.Facet.define();
|
|
1538
|
+
function getScrollMargins(view) {
|
|
1539
|
+
let left = 0, right = 0, top = 0, bottom = 0;
|
|
1540
|
+
for (let source of view.state.facet(scrollMargins)) {
|
|
1541
|
+
let m = source(view);
|
|
1542
|
+
if (m) {
|
|
1543
|
+
if (m.left != null)
|
|
1544
|
+
left = Math.max(left, m.left);
|
|
1545
|
+
if (m.right != null)
|
|
1546
|
+
right = Math.max(right, m.right);
|
|
1547
|
+
if (m.top != null)
|
|
1548
|
+
top = Math.max(top, m.top);
|
|
1549
|
+
if (m.bottom != null)
|
|
1550
|
+
bottom = Math.max(bottom, m.bottom);
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
return { left, right, top, bottom };
|
|
1554
|
+
}
|
|
1555
|
+
const styleModule = state.Facet.define();
|
|
1556
|
+
class ChangedRange {
|
|
1557
|
+
constructor(fromA, toA, fromB, toB) {
|
|
1558
|
+
this.fromA = fromA;
|
|
1559
|
+
this.toA = toA;
|
|
1560
|
+
this.fromB = fromB;
|
|
1561
|
+
this.toB = toB;
|
|
1562
|
+
}
|
|
1563
|
+
join(other) {
|
|
1564
|
+
return new ChangedRange(Math.min(this.fromA, other.fromA), Math.max(this.toA, other.toA), Math.min(this.fromB, other.fromB), Math.max(this.toB, other.toB));
|
|
1565
|
+
}
|
|
1566
|
+
addToSet(set) {
|
|
1567
|
+
let i = set.length, me = this;
|
|
1568
|
+
for (; i > 0; i--) {
|
|
1569
|
+
let range = set[i - 1];
|
|
1570
|
+
if (range.fromA > me.toA)
|
|
1571
|
+
continue;
|
|
1572
|
+
if (range.toA < me.fromA)
|
|
1573
|
+
break;
|
|
1574
|
+
me = me.join(range);
|
|
1575
|
+
set.splice(i - 1, 1);
|
|
1576
|
+
}
|
|
1577
|
+
set.splice(i, 0, me);
|
|
1578
|
+
return set;
|
|
1579
|
+
}
|
|
1580
|
+
// Extend a set to cover all the content in `ranges`, which is a
|
|
1581
|
+
// flat array with each pair of numbers representing fromB/toB
|
|
1582
|
+
// positions. These pairs are generated in unchanged ranges, so the
|
|
1583
|
+
// offset between doc A and doc B is the same for their start and
|
|
1584
|
+
// end points.
|
|
1585
|
+
static extendWithRanges(diff, ranges) {
|
|
1586
|
+
if (ranges.length == 0)
|
|
1587
|
+
return diff;
|
|
1588
|
+
let result = [];
|
|
1589
|
+
for (let dI = 0, rI = 0, off = 0;;) {
|
|
1590
|
+
let nextD = dI < diff.length ? diff[dI].fromB : 1e9;
|
|
1591
|
+
let nextR = rI < ranges.length ? ranges[rI] : 1e9;
|
|
1592
|
+
let fromB = Math.min(nextD, nextR);
|
|
1593
|
+
if (fromB == 1e9)
|
|
1594
|
+
break;
|
|
1595
|
+
let fromA = fromB + off, toB = fromB, toA = fromA;
|
|
1596
|
+
for (;;) {
|
|
1597
|
+
if (rI < ranges.length && ranges[rI] <= toB) {
|
|
1598
|
+
let end = ranges[rI + 1];
|
|
1599
|
+
rI += 2;
|
|
1600
|
+
toB = Math.max(toB, end);
|
|
1601
|
+
toA = Math.max(toA, end + off);
|
|
1602
|
+
}
|
|
1603
|
+
else if (dI < diff.length && diff[dI].fromB <= toB) {
|
|
1604
|
+
let next = diff[dI++];
|
|
1605
|
+
toB = Math.max(toB, next.toB);
|
|
1606
|
+
toA = Math.max(toA, next.toA);
|
|
1607
|
+
off = next.toA - next.toB;
|
|
1608
|
+
}
|
|
1609
|
+
else {
|
|
1610
|
+
break;
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
result.push(new ChangedRange(fromA, toA, fromB, toB));
|
|
1614
|
+
}
|
|
1615
|
+
return result;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
2449
1618
|
/**
|
|
2450
|
-
View plugins
|
|
2451
|
-
|
|
2452
|
-
that happen in the view. They optionally take an argument, in
|
|
2453
|
-
which case you need to call [`of`](https://codemirror.net/6/docs/ref/#view.ViewPlugin.of) to create
|
|
2454
|
-
an extension for the plugin. When the argument type is undefined,
|
|
2455
|
-
you can use the plugin instance as an extension directly.
|
|
1619
|
+
View [plugins](https://codemirror.net/6/docs/ref/#view.ViewPlugin) are given instances of this
|
|
1620
|
+
class, which describe what happened, whenever the view is updated.
|
|
2456
1621
|
*/
|
|
2457
|
-
class
|
|
1622
|
+
class ViewUpdate {
|
|
2458
1623
|
constructor(
|
|
2459
1624
|
/**
|
|
2460
|
-
|
|
1625
|
+
The editor view that the update is associated with.
|
|
2461
1626
|
*/
|
|
2462
|
-
|
|
1627
|
+
view,
|
|
2463
1628
|
/**
|
|
2464
|
-
|
|
1629
|
+
The new editor state.
|
|
2465
1630
|
*/
|
|
2466
|
-
|
|
1631
|
+
state$1,
|
|
2467
1632
|
/**
|
|
2468
|
-
|
|
1633
|
+
The transactions involved in the update. May be empty.
|
|
2469
1634
|
*/
|
|
2470
|
-
|
|
1635
|
+
transactions) {
|
|
1636
|
+
this.view = view;
|
|
1637
|
+
this.state = state$1;
|
|
1638
|
+
this.transactions = transactions;
|
|
1639
|
+
/**
|
|
1640
|
+
@internal
|
|
1641
|
+
*/
|
|
1642
|
+
this.flags = 0;
|
|
1643
|
+
this.startState = view.state;
|
|
1644
|
+
this.changes = state.ChangeSet.empty(this.startState.doc.length);
|
|
1645
|
+
for (let tr of transactions)
|
|
1646
|
+
this.changes = this.changes.compose(tr.changes);
|
|
1647
|
+
let changedRanges = [];
|
|
1648
|
+
this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
|
|
1649
|
+
this.changedRanges = changedRanges;
|
|
1650
|
+
}
|
|
2471
1651
|
/**
|
|
2472
1652
|
@internal
|
|
2473
1653
|
*/
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
this.create = create;
|
|
2477
|
-
this.domEventHandlers = domEventHandlers;
|
|
2478
|
-
this.domEventObservers = domEventObservers;
|
|
2479
|
-
this.baseExtensions = buildExtensions(this);
|
|
2480
|
-
this.extension = this.baseExtensions.concat(viewPlugin.of({ plugin: this, arg: undefined }));
|
|
1654
|
+
static create(view, state, transactions) {
|
|
1655
|
+
return new ViewUpdate(view, state, transactions);
|
|
2481
1656
|
}
|
|
2482
1657
|
/**
|
|
2483
|
-
|
|
1658
|
+
Tells you whether the [viewport](https://codemirror.net/6/docs/ref/#view.EditorView.viewport) or
|
|
1659
|
+
[visible ranges](https://codemirror.net/6/docs/ref/#view.EditorView.visibleRanges) changed in this
|
|
1660
|
+
update.
|
|
2484
1661
|
*/
|
|
2485
|
-
|
|
2486
|
-
return this.
|
|
1662
|
+
get viewportChanged() {
|
|
1663
|
+
return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
|
|
2487
1664
|
}
|
|
2488
1665
|
/**
|
|
2489
|
-
|
|
2490
|
-
|
|
1666
|
+
Returns true when
|
|
1667
|
+
[`viewportChanged`](https://codemirror.net/6/docs/ref/#view.ViewUpdate.viewportChanged) is true
|
|
1668
|
+
and the viewport change is not just the result of mapping it in
|
|
1669
|
+
response to document changes.
|
|
2491
1670
|
*/
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
return new ViewPlugin(nextPluginID++, create, eventHandlers, eventObservers, plugin => {
|
|
2495
|
-
let ext = [];
|
|
2496
|
-
if (deco)
|
|
2497
|
-
ext.push(decorations.of(view => {
|
|
2498
|
-
let pluginInst = view.plugin(plugin);
|
|
2499
|
-
return pluginInst ? deco(pluginInst) : Decoration.none;
|
|
2500
|
-
}));
|
|
2501
|
-
if (provide)
|
|
2502
|
-
ext.push(provide(plugin));
|
|
2503
|
-
return ext;
|
|
2504
|
-
});
|
|
1671
|
+
get viewportMoved() {
|
|
1672
|
+
return (this.flags & 8 /* UpdateFlag.ViewportMoved */) > 0;
|
|
2505
1673
|
}
|
|
2506
1674
|
/**
|
|
2507
|
-
|
|
2508
|
-
|
|
1675
|
+
Indicates whether the height of a block element in the editor
|
|
1676
|
+
changed in this update.
|
|
2509
1677
|
*/
|
|
2510
|
-
|
|
2511
|
-
return
|
|
1678
|
+
get heightChanged() {
|
|
1679
|
+
return (this.flags & 2 /* UpdateFlag.Height */) > 0;
|
|
2512
1680
|
}
|
|
1681
|
+
/**
|
|
1682
|
+
Returns true when the document was modified or the size of the
|
|
1683
|
+
editor, or elements within the editor, changed.
|
|
1684
|
+
*/
|
|
1685
|
+
get geometryChanged() {
|
|
1686
|
+
return this.docChanged || (this.flags & (16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
|
|
1687
|
+
}
|
|
1688
|
+
/**
|
|
1689
|
+
True when this update indicates a focus change.
|
|
1690
|
+
*/
|
|
1691
|
+
get focusChanged() {
|
|
1692
|
+
return (this.flags & 1 /* UpdateFlag.Focus */) > 0;
|
|
1693
|
+
}
|
|
1694
|
+
/**
|
|
1695
|
+
Whether the document changed in this update.
|
|
1696
|
+
*/
|
|
1697
|
+
get docChanged() {
|
|
1698
|
+
return !this.changes.empty;
|
|
1699
|
+
}
|
|
1700
|
+
/**
|
|
1701
|
+
Whether the selection was explicitly set in this update.
|
|
1702
|
+
*/
|
|
1703
|
+
get selectionSet() {
|
|
1704
|
+
return this.transactions.some(tr => tr.selection);
|
|
1705
|
+
}
|
|
1706
|
+
/**
|
|
1707
|
+
@internal
|
|
1708
|
+
*/
|
|
1709
|
+
get empty() { return this.flags == 0 && this.transactions.length == 0; }
|
|
2513
1710
|
}
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
this.
|
|
2522
|
-
|
|
2523
|
-
// initialized on the first update.
|
|
2524
|
-
this.value = null;
|
|
1711
|
+
|
|
1712
|
+
const noChildren = [];
|
|
1713
|
+
class Tile {
|
|
1714
|
+
constructor(dom, length, flags = 0) {
|
|
1715
|
+
this.dom = dom;
|
|
1716
|
+
this.length = length;
|
|
1717
|
+
this.flags = flags;
|
|
1718
|
+
this.parent = null;
|
|
1719
|
+
dom.cmTile = this;
|
|
2525
1720
|
}
|
|
2526
|
-
get
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
1721
|
+
get breakAfter() { return (this.flags & 1 /* TileFlag.BreakAfter */); }
|
|
1722
|
+
get children() { return noChildren; }
|
|
1723
|
+
isWidget() { return false; }
|
|
1724
|
+
get isHidden() { return false; }
|
|
1725
|
+
isComposite() { return false; }
|
|
1726
|
+
isLine() { return false; }
|
|
1727
|
+
isText() { return false; }
|
|
1728
|
+
isBlock() { return false; }
|
|
1729
|
+
get domAttrs() { return null; }
|
|
1730
|
+
sync() {
|
|
1731
|
+
this.flags |= 2 /* TileFlag.Synced */;
|
|
1732
|
+
if (this.flags & 4 /* TileFlag.AttrsDirty */) {
|
|
1733
|
+
this.flags &= ~4 /* TileFlag.AttrsDirty */;
|
|
1734
|
+
let attrs = this.domAttrs;
|
|
1735
|
+
if (attrs)
|
|
1736
|
+
setAttrs(this.dom, attrs);
|
|
1737
|
+
}
|
|
1738
|
+
}
|
|
1739
|
+
toString() {
|
|
1740
|
+
return this.constructor.name + (this.children.length ? `(${this.children})` : "") + (this.breakAfter ? "#" : "");
|
|
1741
|
+
}
|
|
1742
|
+
destroy() { this.parent = null; }
|
|
1743
|
+
setDOM(dom) {
|
|
1744
|
+
this.dom = dom;
|
|
1745
|
+
dom.cmTile = this;
|
|
1746
|
+
}
|
|
1747
|
+
get posAtStart() {
|
|
1748
|
+
return this.parent ? this.parent.posBefore(this) : 0;
|
|
1749
|
+
}
|
|
1750
|
+
get posAtEnd() {
|
|
1751
|
+
return this.posAtStart + this.length;
|
|
1752
|
+
}
|
|
1753
|
+
posBefore(tile) {
|
|
1754
|
+
let pos = this.posAtStart;
|
|
1755
|
+
for (let child of this.children) {
|
|
1756
|
+
if (child == tile)
|
|
1757
|
+
return pos;
|
|
1758
|
+
pos += child.length + child.breakAfter;
|
|
1759
|
+
}
|
|
1760
|
+
throw new RangeError("Invalid child in posBefore");
|
|
1761
|
+
}
|
|
1762
|
+
posAfter(tile) {
|
|
1763
|
+
return this.posBefore(tile) + tile.length;
|
|
1764
|
+
}
|
|
1765
|
+
covers(side) { return true; }
|
|
1766
|
+
coordsIn(pos, side) { return null; }
|
|
1767
|
+
domPosFor(off, side) {
|
|
1768
|
+
let index = domIndex(this.dom);
|
|
1769
|
+
let after = this.length ? off > 0 : side > 0;
|
|
1770
|
+
return new DOMPos(this.parent.dom, index + (after ? 1 : 0), off == 0 || off == this.length);
|
|
1771
|
+
}
|
|
1772
|
+
markDirty(attrs) {
|
|
1773
|
+
this.flags &= ~2 /* TileFlag.Synced */;
|
|
1774
|
+
if (attrs)
|
|
1775
|
+
this.flags |= 4 /* TileFlag.AttrsDirty */;
|
|
1776
|
+
if (this.parent && (this.parent.flags & 2 /* TileFlag.Synced */))
|
|
1777
|
+
this.parent.markDirty(false);
|
|
1778
|
+
}
|
|
1779
|
+
get overrideDOMText() { return null; }
|
|
1780
|
+
get root() {
|
|
1781
|
+
for (let t = this; t; t = t.parent)
|
|
1782
|
+
if (t instanceof DocTile)
|
|
1783
|
+
return t;
|
|
1784
|
+
return null;
|
|
1785
|
+
}
|
|
1786
|
+
static get(dom) {
|
|
1787
|
+
return dom.cmTile;
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
class CompositeTile extends Tile {
|
|
1791
|
+
constructor(dom) {
|
|
1792
|
+
super(dom, 0);
|
|
1793
|
+
this._children = [];
|
|
1794
|
+
}
|
|
1795
|
+
isComposite() { return true; }
|
|
1796
|
+
get children() { return this._children; }
|
|
1797
|
+
get lastChild() { return this.children.length ? this.children[this.children.length - 1] : null; }
|
|
1798
|
+
append(child) {
|
|
1799
|
+
this.children.push(child);
|
|
1800
|
+
child.parent = this;
|
|
1801
|
+
}
|
|
1802
|
+
sync() {
|
|
1803
|
+
if (this.flags & 2 /* TileFlag.Synced */)
|
|
1804
|
+
return;
|
|
1805
|
+
super.sync();
|
|
1806
|
+
let parent = this.dom, prev = null, next;
|
|
1807
|
+
let length = 0;
|
|
1808
|
+
for (let child of this.children) {
|
|
1809
|
+
child.sync();
|
|
1810
|
+
length += child.length + child.breakAfter;
|
|
1811
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
1812
|
+
if (child.dom.parentNode == parent) {
|
|
1813
|
+
while (next && next != child.dom)
|
|
1814
|
+
next = rm$1(next);
|
|
1815
|
+
}
|
|
1816
|
+
else {
|
|
1817
|
+
parent.insertBefore(child.dom, next);
|
|
1818
|
+
}
|
|
1819
|
+
prev = child.dom;
|
|
1820
|
+
}
|
|
1821
|
+
next = prev ? prev.nextSibling : parent.firstChild;
|
|
1822
|
+
while (next)
|
|
1823
|
+
next = rm$1(next);
|
|
1824
|
+
this.length = length;
|
|
1825
|
+
}
|
|
1826
|
+
}
|
|
1827
|
+
// Remove a DOM node and return its next sibling.
|
|
1828
|
+
function rm$1(dom) {
|
|
1829
|
+
let next = dom.nextSibling;
|
|
1830
|
+
dom.parentNode.removeChild(dom);
|
|
1831
|
+
return next;
|
|
1832
|
+
}
|
|
1833
|
+
// The top-level tile. Its dom property equals view.contentDOM.
|
|
1834
|
+
class DocTile extends CompositeTile {
|
|
1835
|
+
constructor(view, dom) {
|
|
1836
|
+
super(dom);
|
|
1837
|
+
this.view = view;
|
|
1838
|
+
}
|
|
1839
|
+
owns(tile) {
|
|
1840
|
+
for (; tile; tile = tile.parent)
|
|
1841
|
+
if (tile == this)
|
|
1842
|
+
return true;
|
|
1843
|
+
return false;
|
|
1844
|
+
}
|
|
1845
|
+
isBlock() { return true; }
|
|
1846
|
+
nearest(dom) {
|
|
1847
|
+
for (;;) {
|
|
1848
|
+
if (!dom)
|
|
1849
|
+
return null;
|
|
1850
|
+
let tile = Tile.get(dom);
|
|
1851
|
+
if (tile && this.owns(tile))
|
|
1852
|
+
return tile;
|
|
1853
|
+
dom = dom.parentNode;
|
|
1854
|
+
}
|
|
1855
|
+
}
|
|
1856
|
+
blockTiles(f) {
|
|
1857
|
+
for (let stack = [], cur = this, i = 0, pos = 0;;) {
|
|
1858
|
+
if (i == cur.children.length) {
|
|
1859
|
+
if (!stack.length)
|
|
1860
|
+
return;
|
|
1861
|
+
cur = cur.parent;
|
|
1862
|
+
if (cur.breakAfter)
|
|
1863
|
+
pos++;
|
|
1864
|
+
i = stack.pop();
|
|
1865
|
+
}
|
|
1866
|
+
else {
|
|
1867
|
+
let next = cur.children[i++];
|
|
1868
|
+
if (next instanceof BlockWrapperTile) {
|
|
1869
|
+
stack.push(i);
|
|
1870
|
+
cur = next;
|
|
1871
|
+
i = 0;
|
|
2532
1872
|
}
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
1873
|
+
else {
|
|
1874
|
+
let end = pos + next.length;
|
|
1875
|
+
let result = f(next, pos);
|
|
1876
|
+
if (result !== undefined)
|
|
1877
|
+
return result;
|
|
1878
|
+
pos = end + next.breakAfter;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
// Find the block at the given position. If side < -1, make sure to
|
|
1884
|
+
// stay before block widgets at that position, if side > 1, after
|
|
1885
|
+
// such widgets (used for selection drawing, which needs to be able
|
|
1886
|
+
// to get coordinates for positions that aren't valid cursor positions).
|
|
1887
|
+
resolveBlock(pos, side) {
|
|
1888
|
+
let before, beforeOff = -1, after, afterOff = -1;
|
|
1889
|
+
this.blockTiles((tile, off) => {
|
|
1890
|
+
let end = off + tile.length;
|
|
1891
|
+
if (pos >= off && pos <= end) {
|
|
1892
|
+
if (tile.isWidget() && side >= -1 && side <= 1) {
|
|
1893
|
+
if (tile.flags & 32 /* TileFlag.After */)
|
|
1894
|
+
return true;
|
|
1895
|
+
if (tile.flags & 16 /* TileFlag.Before */)
|
|
1896
|
+
before = undefined;
|
|
1897
|
+
}
|
|
1898
|
+
if ((off < pos || pos == end && (side < -1 ? tile.length : tile.covers(1))) &&
|
|
1899
|
+
(!before || !tile.isWidget() && before.isWidget())) {
|
|
1900
|
+
before = tile;
|
|
1901
|
+
beforeOff = pos - off;
|
|
1902
|
+
}
|
|
1903
|
+
if ((end > pos || pos == off && (side > 1 ? tile.length : tile.covers(-1))) &&
|
|
1904
|
+
(!after || !tile.isWidget() && after.isWidget())) {
|
|
1905
|
+
after = tile;
|
|
1906
|
+
afterOff = pos - off;
|
|
1907
|
+
}
|
|
1908
|
+
}
|
|
1909
|
+
});
|
|
1910
|
+
if (!before && !after)
|
|
1911
|
+
throw new Error("No tile at position " + pos);
|
|
1912
|
+
return before && side < 0 || !after ? { tile: before, offset: beforeOff } : { tile: after, offset: afterOff };
|
|
1913
|
+
}
|
|
1914
|
+
}
|
|
1915
|
+
class BlockWrapperTile extends CompositeTile {
|
|
1916
|
+
constructor(dom, wrapper) {
|
|
1917
|
+
super(dom);
|
|
1918
|
+
this.wrapper = wrapper;
|
|
1919
|
+
}
|
|
1920
|
+
isBlock() { return true; }
|
|
1921
|
+
covers(side) {
|
|
1922
|
+
if (!this.children.length)
|
|
1923
|
+
return false;
|
|
1924
|
+
return side < 0 ? this.children[0].covers(-1) : this.lastChild.covers(1);
|
|
1925
|
+
}
|
|
1926
|
+
get domAttrs() { return this.wrapper.attributes; }
|
|
1927
|
+
static of(wrapper, dom) {
|
|
1928
|
+
let tile = new BlockWrapperTile(dom || document.createElement(wrapper.tagName), wrapper);
|
|
1929
|
+
if (!dom)
|
|
1930
|
+
tile.flags |= 4 /* TileFlag.AttrsDirty */;
|
|
1931
|
+
return tile;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
class LineTile extends CompositeTile {
|
|
1935
|
+
constructor(dom, attrs) {
|
|
1936
|
+
super(dom);
|
|
1937
|
+
this.attrs = attrs;
|
|
1938
|
+
}
|
|
1939
|
+
isLine() { return true; }
|
|
1940
|
+
static start(attrs, dom, keepAttrs) {
|
|
1941
|
+
let line = new LineTile(dom || document.createElement("div"), attrs);
|
|
1942
|
+
if (!dom || !keepAttrs)
|
|
1943
|
+
line.flags |= 4 /* TileFlag.AttrsDirty */;
|
|
1944
|
+
return line;
|
|
1945
|
+
}
|
|
1946
|
+
get domAttrs() { return this.attrs; }
|
|
1947
|
+
// Find the tile associated with a given position in this line.
|
|
1948
|
+
resolveInline(pos, side, forCoords) {
|
|
1949
|
+
let before = null, beforeOff = -1, after = null, afterOff = -1;
|
|
1950
|
+
function scan(tile, pos) {
|
|
1951
|
+
for (let i = 0, off = 0; i < tile.children.length && off <= pos; i++) {
|
|
1952
|
+
let child = tile.children[i], end = off + child.length;
|
|
1953
|
+
if (end >= pos) {
|
|
1954
|
+
if (child.isComposite()) {
|
|
1955
|
+
scan(child, pos - off);
|
|
1956
|
+
}
|
|
1957
|
+
else if ((!after || after.isHidden && (side > 0 || forCoords && onSameLine(after, child))) &&
|
|
1958
|
+
(end > pos || (child.flags & 32 /* TileFlag.After */))) {
|
|
1959
|
+
after = child;
|
|
1960
|
+
afterOff = pos - off;
|
|
1961
|
+
}
|
|
1962
|
+
else if (off < pos || (child.flags & 16 /* TileFlag.Before */) && !child.isHidden) {
|
|
1963
|
+
before = child;
|
|
1964
|
+
beforeOff = pos - off;
|
|
1965
|
+
}
|
|
1966
|
+
}
|
|
1967
|
+
off = end;
|
|
1968
|
+
}
|
|
1969
|
+
}
|
|
1970
|
+
scan(this, pos);
|
|
1971
|
+
let target = ((side < 0 ? before : after) || before || after);
|
|
1972
|
+
return target ? { tile: target, offset: target == before ? beforeOff : afterOff } : null;
|
|
1973
|
+
}
|
|
1974
|
+
coordsIn(pos, side) {
|
|
1975
|
+
let found = this.resolveInline(pos, side, true);
|
|
1976
|
+
if (!found)
|
|
1977
|
+
return fallbackRect(this);
|
|
1978
|
+
return found.tile.coordsIn(Math.max(0, found.offset), side);
|
|
1979
|
+
}
|
|
1980
|
+
domIn(pos, side) {
|
|
1981
|
+
let found = this.resolveInline(pos, side);
|
|
1982
|
+
if (found) {
|
|
1983
|
+
let { tile, offset } = found;
|
|
1984
|
+
if (this.dom.contains(tile.dom)) {
|
|
1985
|
+
if (tile.isText())
|
|
1986
|
+
return new DOMPos(tile.dom, Math.min(tile.dom.nodeValue.length, offset));
|
|
1987
|
+
return tile.domPosFor(offset, side);
|
|
1988
|
+
}
|
|
1989
|
+
let parent = found.tile.parent, saw = false;
|
|
1990
|
+
for (let ch of parent.children) {
|
|
1991
|
+
if (saw)
|
|
1992
|
+
return new DOMPos(ch.dom, 0);
|
|
1993
|
+
if (ch == found.tile) {
|
|
1994
|
+
saw = true;
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1997
|
+
}
|
|
1998
|
+
return new DOMPos(this.dom, 0);
|
|
1999
|
+
}
|
|
2000
|
+
}
|
|
2001
|
+
function fallbackRect(tile) {
|
|
2002
|
+
let last = tile.dom.lastChild;
|
|
2003
|
+
if (!last)
|
|
2004
|
+
return tile.dom.getBoundingClientRect();
|
|
2005
|
+
let rects = clientRectsFor(last);
|
|
2006
|
+
return rects[rects.length - 1] || null;
|
|
2007
|
+
}
|
|
2008
|
+
function onSameLine(a, b) {
|
|
2009
|
+
let posA = a.coordsIn(0, 1), posB = b.coordsIn(0, 1);
|
|
2010
|
+
return posA && posB && posB.top < posA.bottom;
|
|
2011
|
+
}
|
|
2012
|
+
class MarkTile extends CompositeTile {
|
|
2013
|
+
constructor(dom, mark) {
|
|
2014
|
+
super(dom);
|
|
2015
|
+
this.mark = mark;
|
|
2016
|
+
}
|
|
2017
|
+
get domAttrs() { return this.mark.attrs; }
|
|
2018
|
+
static of(mark, dom) {
|
|
2019
|
+
let tile = new MarkTile(dom || document.createElement(mark.tagName), mark);
|
|
2020
|
+
if (!dom)
|
|
2021
|
+
tile.flags |= 4 /* TileFlag.AttrsDirty */;
|
|
2022
|
+
return tile;
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
class TextTile extends Tile {
|
|
2026
|
+
constructor(dom, text) {
|
|
2027
|
+
super(dom, text.length);
|
|
2028
|
+
this.text = text;
|
|
2029
|
+
}
|
|
2030
|
+
sync() {
|
|
2031
|
+
if (this.flags & 2 /* TileFlag.Synced */)
|
|
2032
|
+
return;
|
|
2033
|
+
super.sync();
|
|
2034
|
+
if (this.dom.nodeValue != this.text)
|
|
2035
|
+
this.dom.nodeValue = this.text;
|
|
2036
|
+
}
|
|
2037
|
+
isText() { return true; }
|
|
2038
|
+
toString() { return JSON.stringify(this.text); }
|
|
2039
|
+
coordsIn(pos, side) {
|
|
2040
|
+
let length = this.dom.nodeValue.length;
|
|
2041
|
+
if (pos > length)
|
|
2042
|
+
pos = length;
|
|
2043
|
+
let from = pos, to = pos, flatten = 0;
|
|
2044
|
+
if (pos == 0 && side < 0 || pos == length && side >= 0) {
|
|
2045
|
+
if (!(browser.chrome || browser.gecko)) { // These browsers reliably return valid rectangles for empty ranges
|
|
2046
|
+
if (pos) {
|
|
2047
|
+
from--;
|
|
2048
|
+
flatten = 1;
|
|
2049
|
+
} // FIXME this is wrong in RTL text
|
|
2050
|
+
else if (to < length) {
|
|
2051
|
+
to++;
|
|
2052
|
+
flatten = -1;
|
|
2536
2053
|
}
|
|
2537
2054
|
}
|
|
2538
2055
|
}
|
|
2539
|
-
else
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
if (
|
|
2543
|
-
|
|
2544
|
-
this.value.update(update);
|
|
2545
|
-
}
|
|
2546
|
-
catch (e) {
|
|
2547
|
-
logException(update.state, e, "CodeMirror plugin crashed");
|
|
2548
|
-
if (this.value.destroy)
|
|
2549
|
-
try {
|
|
2550
|
-
this.value.destroy();
|
|
2551
|
-
}
|
|
2552
|
-
catch (_) { }
|
|
2553
|
-
this.deactivate();
|
|
2554
|
-
}
|
|
2555
|
-
}
|
|
2056
|
+
else {
|
|
2057
|
+
if (side < 0)
|
|
2058
|
+
from--;
|
|
2059
|
+
else if (to < length)
|
|
2060
|
+
to++;
|
|
2556
2061
|
}
|
|
2557
|
-
|
|
2062
|
+
let rects = textRange(this.dom, from, to).getClientRects();
|
|
2063
|
+
if (!rects.length)
|
|
2064
|
+
return null;
|
|
2065
|
+
let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
|
|
2066
|
+
if (browser.safari && !flatten && rect.width == 0)
|
|
2067
|
+
rect = Array.prototype.find.call(rects, r => r.width) || rect;
|
|
2068
|
+
return flatten ? flattenRect(rect, flatten < 0) : rect || null;
|
|
2558
2069
|
}
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
if (
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2070
|
+
static of(text, dom) {
|
|
2071
|
+
let tile = new TextTile(dom || document.createTextNode(text), text);
|
|
2072
|
+
if (!dom)
|
|
2073
|
+
tile.flags |= 2 /* TileFlag.Synced */;
|
|
2074
|
+
return tile;
|
|
2075
|
+
}
|
|
2076
|
+
}
|
|
2077
|
+
class WidgetTile extends Tile {
|
|
2078
|
+
constructor(dom, length, widget, flags) {
|
|
2079
|
+
super(dom, length, flags);
|
|
2080
|
+
this.widget = widget;
|
|
2081
|
+
}
|
|
2082
|
+
isWidget() { return true; }
|
|
2083
|
+
get isHidden() { return this.widget.isHidden; }
|
|
2084
|
+
covers(side) {
|
|
2085
|
+
if (this.flags & 48 /* TileFlag.PointWidget */)
|
|
2086
|
+
return false;
|
|
2087
|
+
return (this.flags & (side < 0 ? 64 /* TileFlag.IncStart */ : 128 /* TileFlag.IncEnd */)) > 0;
|
|
2088
|
+
}
|
|
2089
|
+
coordsIn(pos, side) { return this.coordsInWidget(pos, side, false); }
|
|
2090
|
+
coordsInWidget(pos, side, block) {
|
|
2091
|
+
let custom = this.widget.coordsAt(this.dom, pos, side);
|
|
2092
|
+
if (custom)
|
|
2093
|
+
return custom;
|
|
2094
|
+
if (block) {
|
|
2095
|
+
return flattenRect(this.dom.getBoundingClientRect(), this.length ? pos == 0 : side <= 0);
|
|
2096
|
+
}
|
|
2097
|
+
else {
|
|
2098
|
+
let rects = this.dom.getClientRects(), rect = null;
|
|
2099
|
+
if (!rects.length)
|
|
2100
|
+
return null;
|
|
2101
|
+
let fromBack = (this.flags & 16 /* TileFlag.Before */) ? true : (this.flags & 32 /* TileFlag.After */) ? false : pos > 0;
|
|
2102
|
+
for (let i = fromBack ? rects.length - 1 : 0;; i += (fromBack ? -1 : 1)) {
|
|
2103
|
+
rect = rects[i];
|
|
2104
|
+
if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
|
2105
|
+
break;
|
|
2567
2106
|
}
|
|
2107
|
+
return flattenRect(rect, !fromBack);
|
|
2568
2108
|
}
|
|
2569
2109
|
}
|
|
2570
|
-
|
|
2571
|
-
|
|
2110
|
+
get overrideDOMText() {
|
|
2111
|
+
if (!this.length)
|
|
2112
|
+
return state.Text.empty;
|
|
2113
|
+
let { root } = this;
|
|
2114
|
+
if (!root)
|
|
2115
|
+
return state.Text.empty;
|
|
2116
|
+
let start = this.posAtStart;
|
|
2117
|
+
return root.view.state.doc.slice(start, start + this.length);
|
|
2118
|
+
}
|
|
2119
|
+
destroy() {
|
|
2120
|
+
super.destroy();
|
|
2121
|
+
this.widget.destroy(this.dom);
|
|
2122
|
+
}
|
|
2123
|
+
static of(widget, view, length, flags, dom) {
|
|
2124
|
+
if (!dom) {
|
|
2125
|
+
dom = widget.toDOM(view);
|
|
2126
|
+
if (!widget.editable)
|
|
2127
|
+
dom.contentEditable = "false";
|
|
2128
|
+
}
|
|
2129
|
+
return new WidgetTile(dom, length, widget, flags);
|
|
2572
2130
|
}
|
|
2573
2131
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
//
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2132
|
+
// These are drawn around uneditable widgets to avoid a number of
|
|
2133
|
+
// browser bugs that show up when the cursor is directly next to
|
|
2134
|
+
// uneditable inline content.
|
|
2135
|
+
class WidgetBufferTile extends Tile {
|
|
2136
|
+
constructor(flags) {
|
|
2137
|
+
let img = document.createElement("img");
|
|
2138
|
+
img.className = "cm-widgetBuffer";
|
|
2139
|
+
img.setAttribute("aria-hidden", "true");
|
|
2140
|
+
super(img, 0, flags);
|
|
2141
|
+
}
|
|
2142
|
+
get isHidden() { return false; }
|
|
2143
|
+
get overrideDOMText() { return state.Text.empty; }
|
|
2144
|
+
coordsIn(pos) { return this.dom.getBoundingClientRect(); }
|
|
2145
|
+
}
|
|
2146
|
+
// Represents a position in the tile tree.
|
|
2147
|
+
class TilePointer {
|
|
2148
|
+
constructor(top) {
|
|
2149
|
+
this.index = 0;
|
|
2150
|
+
this.beforeBreak = false;
|
|
2151
|
+
this.parents = [];
|
|
2152
|
+
this.tile = top;
|
|
2153
|
+
}
|
|
2154
|
+
// Advance by the given distance. If side is -1, stop leaving or
|
|
2155
|
+
// entering tiles, or skipping zero-length tiles, once the distance
|
|
2156
|
+
// has been traversed. When side is 1, leave, enter, or skip
|
|
2157
|
+
// everything at the end position.
|
|
2158
|
+
advance(dist, side, walker) {
|
|
2159
|
+
let { tile, index, beforeBreak, parents } = this;
|
|
2160
|
+
while (dist || side > 0) {
|
|
2161
|
+
if (!tile.isComposite()) {
|
|
2162
|
+
if (index == tile.length) {
|
|
2163
|
+
beforeBreak = !!tile.breakAfter;
|
|
2164
|
+
({ tile, index } = parents.pop());
|
|
2165
|
+
index++;
|
|
2166
|
+
}
|
|
2167
|
+
else if (!dist) {
|
|
2168
|
+
break;
|
|
2600
2169
|
}
|
|
2601
2170
|
else {
|
|
2602
|
-
let
|
|
2603
|
-
|
|
2604
|
-
|
|
2171
|
+
let take = Math.min(dist, tile.length - index);
|
|
2172
|
+
if (walker)
|
|
2173
|
+
walker.skip(tile, index, index + take);
|
|
2174
|
+
dist -= take;
|
|
2175
|
+
index += take;
|
|
2176
|
+
}
|
|
2177
|
+
}
|
|
2178
|
+
else if (beforeBreak) {
|
|
2179
|
+
if (!dist)
|
|
2180
|
+
break;
|
|
2181
|
+
if (walker)
|
|
2182
|
+
walker.break();
|
|
2183
|
+
dist--;
|
|
2184
|
+
beforeBreak = false;
|
|
2185
|
+
}
|
|
2186
|
+
else if (index == tile.children.length) {
|
|
2187
|
+
if (!dist && !parents.length)
|
|
2188
|
+
break;
|
|
2189
|
+
if (walker)
|
|
2190
|
+
walker.leave(tile);
|
|
2191
|
+
beforeBreak = !!tile.breakAfter;
|
|
2192
|
+
({ tile, index } = parents.pop());
|
|
2193
|
+
index++;
|
|
2194
|
+
}
|
|
2195
|
+
else {
|
|
2196
|
+
let next = tile.children[index], brk = next.breakAfter;
|
|
2197
|
+
if ((side > 0 ? next.length <= dist : next.length < dist) &&
|
|
2198
|
+
(!walker || walker.skip(next, 0, next.length) !== false || !next.isComposite)) {
|
|
2199
|
+
beforeBreak = !!brk;
|
|
2200
|
+
index++;
|
|
2201
|
+
dist -= next.length;
|
|
2202
|
+
}
|
|
2203
|
+
else {
|
|
2204
|
+
parents.push({ tile, index });
|
|
2205
|
+
tile = next;
|
|
2206
|
+
index = 0;
|
|
2207
|
+
if (walker && next.isComposite())
|
|
2208
|
+
walker.enter(next);
|
|
2605
2209
|
}
|
|
2606
2210
|
}
|
|
2607
2211
|
}
|
|
2608
|
-
|
|
2609
|
-
|
|
2212
|
+
this.tile = tile;
|
|
2213
|
+
this.index = index;
|
|
2214
|
+
this.beforeBreak = beforeBreak;
|
|
2215
|
+
return this;
|
|
2216
|
+
}
|
|
2217
|
+
get root() { return (this.parents.length ? this.parents[0].tile : this.tile); }
|
|
2610
2218
|
}
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
if (m.right != null)
|
|
2620
|
-
right = Math.max(right, m.right);
|
|
2621
|
-
if (m.top != null)
|
|
2622
|
-
top = Math.max(top, m.top);
|
|
2623
|
-
if (m.bottom != null)
|
|
2624
|
-
bottom = Math.max(bottom, m.bottom);
|
|
2625
|
-
}
|
|
2219
|
+
|
|
2220
|
+
// Used to track open block wrappers
|
|
2221
|
+
class OpenWrapper {
|
|
2222
|
+
constructor(from, to, wrapper, rank) {
|
|
2223
|
+
this.from = from;
|
|
2224
|
+
this.to = to;
|
|
2225
|
+
this.wrapper = wrapper;
|
|
2226
|
+
this.rank = rank;
|
|
2626
2227
|
}
|
|
2627
|
-
return { left, right, top, bottom };
|
|
2628
2228
|
}
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2229
|
+
// This class builds up a new document tile using input from either
|
|
2230
|
+
// iteration over the old tree or iteration over the document +
|
|
2231
|
+
// decorations. The add* methods emit elements into the tile
|
|
2232
|
+
// structure. To avoid awkward synchronization issues, marks and block
|
|
2233
|
+
// wrappers are treated as belonging to to their content, rather than
|
|
2234
|
+
// opened/closed independently.
|
|
2235
|
+
//
|
|
2236
|
+
// All composite tiles that are touched by changes are rebuilt,
|
|
2237
|
+
// reusing as much of the old tree (either whole nodes or just DOM
|
|
2238
|
+
// elements) as possible. The new tree is built without the Synced
|
|
2239
|
+
// flag, and then synced (during which DOM parent/child relations are
|
|
2240
|
+
// fixed up, text nodes filled in, and attributes added) in a second
|
|
2241
|
+
// phase.
|
|
2242
|
+
class TileBuilder {
|
|
2243
|
+
constructor(cache, root, blockWrappers) {
|
|
2244
|
+
this.cache = cache;
|
|
2245
|
+
this.root = root;
|
|
2246
|
+
this.blockWrappers = blockWrappers;
|
|
2247
|
+
this.curLine = null;
|
|
2248
|
+
this.lastBlock = null;
|
|
2249
|
+
this.afterWidget = null;
|
|
2250
|
+
this.pos = 0;
|
|
2251
|
+
this.wrappers = [];
|
|
2252
|
+
this.wrapperPos = 0;
|
|
2636
2253
|
}
|
|
2637
|
-
|
|
2638
|
-
|
|
2254
|
+
addText(text, marks, openStart, tile) {
|
|
2255
|
+
var _a;
|
|
2256
|
+
this.flushBuffer();
|
|
2257
|
+
let parent = this.ensureMarks(marks, openStart);
|
|
2258
|
+
let prev = parent.lastChild;
|
|
2259
|
+
if (prev && prev.isText() && !(prev.flags & 8 /* TileFlag.Composition */)) {
|
|
2260
|
+
this.cache.reused.set(prev, 2 /* Reused.DOM */);
|
|
2261
|
+
let tile = parent.children[parent.children.length - 1] = new TextTile(prev.dom, prev.text + text);
|
|
2262
|
+
tile.parent = parent;
|
|
2263
|
+
}
|
|
2264
|
+
else {
|
|
2265
|
+
parent.append(tile || TextTile.of(text, (_a = this.cache.find(TextTile)) === null || _a === void 0 ? void 0 : _a.dom));
|
|
2266
|
+
}
|
|
2267
|
+
this.pos += text.length;
|
|
2268
|
+
this.afterWidget = null;
|
|
2269
|
+
}
|
|
2270
|
+
addComposition(composition, context) {
|
|
2271
|
+
let line = this.curLine;
|
|
2272
|
+
if (line.dom != context.line.dom) {
|
|
2273
|
+
line.setDOM(this.cache.reused.has(context.line) ? freeNode(context.line.dom) : context.line.dom);
|
|
2274
|
+
this.cache.reused.set(context.line, 2 /* Reused.DOM */);
|
|
2275
|
+
}
|
|
2276
|
+
let head = line;
|
|
2277
|
+
for (let i = context.marks.length - 1; i >= 0; i--) {
|
|
2278
|
+
let mark = context.marks[i];
|
|
2279
|
+
let last = head.lastChild;
|
|
2280
|
+
if (last instanceof MarkTile && last.mark.eq(mark.mark)) {
|
|
2281
|
+
if (last.dom != mark.dom)
|
|
2282
|
+
last.setDOM(freeNode(mark.dom));
|
|
2283
|
+
head = last;
|
|
2284
|
+
}
|
|
2285
|
+
else {
|
|
2286
|
+
if (this.cache.reused.get(mark)) {
|
|
2287
|
+
let tile = Tile.get(mark.dom);
|
|
2288
|
+
if (tile)
|
|
2289
|
+
tile.setDOM(freeNode(mark.dom));
|
|
2290
|
+
}
|
|
2291
|
+
let nw = MarkTile.of(mark.mark, mark.dom);
|
|
2292
|
+
head.append(nw);
|
|
2293
|
+
head = nw;
|
|
2294
|
+
}
|
|
2295
|
+
this.cache.reused.set(mark, 2 /* Reused.DOM */);
|
|
2296
|
+
}
|
|
2297
|
+
let text = new TextTile(composition.text, composition.text.nodeValue);
|
|
2298
|
+
text.flags |= 8 /* TileFlag.Composition */;
|
|
2299
|
+
head.append(text);
|
|
2639
2300
|
}
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2301
|
+
addInlineWidget(widget, marks, openStart) {
|
|
2302
|
+
// Adjacent same-side-facing non-replacing widgets don't need buffers between them
|
|
2303
|
+
let noSpace = this.afterWidget && (widget.flags & 48 /* TileFlag.PointWidget */) &&
|
|
2304
|
+
(this.afterWidget.flags & 48 /* TileFlag.PointWidget */) == (widget.flags & 48 /* TileFlag.PointWidget */);
|
|
2305
|
+
if (!noSpace)
|
|
2306
|
+
this.flushBuffer();
|
|
2307
|
+
let parent = this.ensureMarks(marks, openStart);
|
|
2308
|
+
if (!noSpace && !(widget.flags & 16 /* TileFlag.Before */))
|
|
2309
|
+
parent.append(this.getBuffer(1));
|
|
2310
|
+
parent.append(widget);
|
|
2311
|
+
this.pos += widget.length;
|
|
2312
|
+
this.afterWidget = widget;
|
|
2313
|
+
}
|
|
2314
|
+
addMark(tile, marks, openStart) {
|
|
2315
|
+
this.flushBuffer();
|
|
2316
|
+
let parent = this.ensureMarks(marks, openStart);
|
|
2317
|
+
parent.append(tile);
|
|
2318
|
+
this.pos += tile.length;
|
|
2319
|
+
this.afterWidget = null;
|
|
2320
|
+
}
|
|
2321
|
+
addBlockWidget(widget) {
|
|
2322
|
+
this.getBlockPos().append(widget);
|
|
2323
|
+
this.pos += widget.length;
|
|
2324
|
+
this.lastBlock = widget;
|
|
2325
|
+
this.endLine();
|
|
2326
|
+
}
|
|
2327
|
+
continueWidget(length) {
|
|
2328
|
+
let widget = this.afterWidget || this.lastBlock;
|
|
2329
|
+
widget.length += length;
|
|
2330
|
+
this.pos += length;
|
|
2331
|
+
}
|
|
2332
|
+
addLineStart(attrs, dom) {
|
|
2333
|
+
var _a;
|
|
2334
|
+
if (!attrs)
|
|
2335
|
+
attrs = lineBaseAttrs;
|
|
2336
|
+
let tile = LineTile.start(attrs, dom || ((_a = this.cache.find(LineTile)) === null || _a === void 0 ? void 0 : _a.dom), !!dom);
|
|
2337
|
+
this.getBlockPos().append(this.lastBlock = this.curLine = tile);
|
|
2338
|
+
}
|
|
2339
|
+
addLine(tile) {
|
|
2340
|
+
this.getBlockPos().append(tile);
|
|
2341
|
+
this.pos += tile.length;
|
|
2342
|
+
this.lastBlock = tile;
|
|
2343
|
+
this.endLine();
|
|
2344
|
+
}
|
|
2345
|
+
addBreak() {
|
|
2346
|
+
this.lastBlock.flags |= 1 /* TileFlag.BreakAfter */;
|
|
2347
|
+
this.endLine();
|
|
2348
|
+
this.pos++;
|
|
2349
|
+
}
|
|
2350
|
+
addLineStartIfNotCovered(attrs) {
|
|
2351
|
+
if (!this.blockPosCovered())
|
|
2352
|
+
this.addLineStart(attrs);
|
|
2353
|
+
}
|
|
2354
|
+
ensureLine(attrs) {
|
|
2355
|
+
if (!this.curLine)
|
|
2356
|
+
this.addLineStart(attrs);
|
|
2357
|
+
}
|
|
2358
|
+
ensureMarks(marks, openStart) {
|
|
2359
|
+
var _a;
|
|
2360
|
+
let parent = this.curLine;
|
|
2361
|
+
for (let i = marks.length - 1; i >= 0; i--) {
|
|
2362
|
+
let mark = marks[i], last;
|
|
2363
|
+
if (openStart > 0 && (last = parent.lastChild) && last instanceof MarkTile && last.mark.eq(mark)) {
|
|
2364
|
+
parent = last;
|
|
2365
|
+
openStart--;
|
|
2366
|
+
}
|
|
2367
|
+
else {
|
|
2368
|
+
let tile = MarkTile.of(mark, (_a = this.cache.find(MarkTile, m => m.mark.eq(mark))) === null || _a === void 0 ? void 0 : _a.dom);
|
|
2369
|
+
parent.append(tile);
|
|
2370
|
+
parent = tile;
|
|
2371
|
+
openStart = 0;
|
|
2372
|
+
}
|
|
2650
2373
|
}
|
|
2651
|
-
|
|
2652
|
-
return set;
|
|
2374
|
+
return parent;
|
|
2653
2375
|
}
|
|
2654
|
-
|
|
2655
|
-
if (
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2376
|
+
endLine() {
|
|
2377
|
+
if (this.curLine) {
|
|
2378
|
+
this.flushBuffer();
|
|
2379
|
+
let last = this.curLine.lastChild;
|
|
2380
|
+
if (!last || !hasContent(this.curLine, false) ||
|
|
2381
|
+
last.dom.nodeName != "BR" && last.isWidget() && !(browser.ios && hasContent(this.curLine, true)))
|
|
2382
|
+
this.curLine.append(this.cache.findWidget(BreakWidget, 0, 32 /* TileFlag.After */) ||
|
|
2383
|
+
new WidgetTile(BreakWidget.toDOM(), 0, BreakWidget, 32 /* TileFlag.After */));
|
|
2384
|
+
this.curLine = this.afterWidget = null;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
updateBlockWrappers() {
|
|
2388
|
+
if (this.wrapperPos > this.pos + 10000 /* C.WrapperReset */) {
|
|
2389
|
+
this.blockWrappers.goto(this.pos);
|
|
2390
|
+
this.wrappers.length = 0;
|
|
2391
|
+
}
|
|
2392
|
+
for (let i = this.wrappers.length - 1; i >= 0; i--)
|
|
2393
|
+
if (this.wrappers[i].to < this.pos)
|
|
2394
|
+
this.wrappers.splice(i, 1);
|
|
2395
|
+
for (let cur = this.blockWrappers; cur.value && cur.from <= this.pos; cur.next())
|
|
2396
|
+
if (cur.to >= this.pos) {
|
|
2397
|
+
let wrap = new OpenWrapper(cur.from, cur.to, cur.value, cur.rank), i = this.wrappers.length;
|
|
2398
|
+
while (i > 0 && this.wrappers[i - 1].rank < wrap.rank)
|
|
2399
|
+
i--;
|
|
2400
|
+
this.wrappers.splice(i, 0, wrap);
|
|
2401
|
+
}
|
|
2402
|
+
this.wrapperPos = this.pos;
|
|
2403
|
+
}
|
|
2404
|
+
getBlockPos() {
|
|
2405
|
+
var _a;
|
|
2406
|
+
this.updateBlockWrappers();
|
|
2407
|
+
let parent = this.root;
|
|
2408
|
+
for (let wrap of this.wrappers) {
|
|
2409
|
+
let last = parent.lastChild;
|
|
2410
|
+
if (wrap.from < this.pos && last instanceof BlockWrapperTile && last.wrapper.eq(wrap.wrapper)) {
|
|
2411
|
+
parent = last;
|
|
2412
|
+
}
|
|
2413
|
+
else {
|
|
2414
|
+
let tile = BlockWrapperTile.of(wrap.wrapper, (_a = this.cache.find(BlockWrapperTile, t => t.wrapper.eq(wrap.wrapper))) === null || _a === void 0 ? void 0 : _a.dom);
|
|
2415
|
+
parent.append(tile);
|
|
2416
|
+
parent = tile;
|
|
2670
2417
|
}
|
|
2671
|
-
if (!next)
|
|
2672
|
-
return result;
|
|
2673
|
-
new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result);
|
|
2674
|
-
posA = next.toA;
|
|
2675
|
-
posB = next.toB;
|
|
2676
2418
|
}
|
|
2419
|
+
return parent;
|
|
2677
2420
|
}
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
class, which describe what happened, whenever the view is updated.
|
|
2682
|
-
*/
|
|
2683
|
-
class ViewUpdate {
|
|
2684
|
-
constructor(
|
|
2685
|
-
/**
|
|
2686
|
-
The editor view that the update is associated with.
|
|
2687
|
-
*/
|
|
2688
|
-
view,
|
|
2689
|
-
/**
|
|
2690
|
-
The new editor state.
|
|
2691
|
-
*/
|
|
2692
|
-
state$1,
|
|
2693
|
-
/**
|
|
2694
|
-
The transactions involved in the update. May be empty.
|
|
2695
|
-
*/
|
|
2696
|
-
transactions) {
|
|
2697
|
-
this.view = view;
|
|
2698
|
-
this.state = state$1;
|
|
2699
|
-
this.transactions = transactions;
|
|
2700
|
-
/**
|
|
2701
|
-
@internal
|
|
2702
|
-
*/
|
|
2703
|
-
this.flags = 0;
|
|
2704
|
-
this.startState = view.state;
|
|
2705
|
-
this.changes = state.ChangeSet.empty(this.startState.doc.length);
|
|
2706
|
-
for (let tr of transactions)
|
|
2707
|
-
this.changes = this.changes.compose(tr.changes);
|
|
2708
|
-
let changedRanges = [];
|
|
2709
|
-
this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
|
|
2710
|
-
this.changedRanges = changedRanges;
|
|
2421
|
+
blockPosCovered() {
|
|
2422
|
+
let last = this.lastBlock;
|
|
2423
|
+
return last != null && !last.breakAfter && (!last.isWidget() || (last.flags & (32 /* TileFlag.After */ | 128 /* TileFlag.IncEnd */)) > 0);
|
|
2711
2424
|
}
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2425
|
+
getBuffer(side) {
|
|
2426
|
+
let flags = 2 /* TileFlag.Synced */ | (side < 0 ? 16 /* TileFlag.Before */ : 32 /* TileFlag.After */);
|
|
2427
|
+
let found = this.cache.find(WidgetBufferTile, undefined, 1 /* Reused.Full */);
|
|
2428
|
+
if (found)
|
|
2429
|
+
found.flags = flags;
|
|
2430
|
+
return found || new WidgetBufferTile(flags);
|
|
2717
2431
|
}
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
get viewportChanged() {
|
|
2724
|
-
return (this.flags & 4 /* UpdateFlag.Viewport */) > 0;
|
|
2432
|
+
flushBuffer() {
|
|
2433
|
+
if (this.afterWidget && !(this.afterWidget.flags & 32 /* TileFlag.After */)) {
|
|
2434
|
+
this.afterWidget.parent.append(this.getBuffer(-1));
|
|
2435
|
+
this.afterWidget = null;
|
|
2436
|
+
}
|
|
2725
2437
|
}
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2438
|
+
}
|
|
2439
|
+
// Helps getting efficient access to the document text.
|
|
2440
|
+
class TextStream {
|
|
2441
|
+
constructor(doc) {
|
|
2442
|
+
this.skipCount = 0;
|
|
2443
|
+
this.text = "";
|
|
2444
|
+
this.textOff = 0;
|
|
2445
|
+
this.cursor = doc.iter();
|
|
2734
2446
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2447
|
+
skip(len) {
|
|
2448
|
+
// Advance the iterator past the replaced content
|
|
2449
|
+
if (this.textOff + len <= this.text.length) {
|
|
2450
|
+
this.textOff += len;
|
|
2451
|
+
}
|
|
2452
|
+
else {
|
|
2453
|
+
this.skipCount += len - (this.text.length - this.textOff);
|
|
2454
|
+
this.text = "";
|
|
2455
|
+
this.textOff = 0;
|
|
2456
|
+
}
|
|
2457
|
+
}
|
|
2458
|
+
next(maxLen) {
|
|
2459
|
+
if (this.textOff == this.text.length) {
|
|
2460
|
+
let { value, lineBreak, done } = this.cursor.next(this.skipCount);
|
|
2461
|
+
this.skipCount = 0;
|
|
2462
|
+
if (done)
|
|
2463
|
+
throw new Error("Ran out of text content when drawing inline views");
|
|
2464
|
+
this.text = value;
|
|
2465
|
+
let len = this.textOff = Math.min(maxLen, value.length);
|
|
2466
|
+
return lineBreak ? null : value.slice(0, len);
|
|
2467
|
+
}
|
|
2468
|
+
let end = Math.min(this.text.length, this.textOff + maxLen);
|
|
2469
|
+
let chars = this.text.slice(this.textOff, end);
|
|
2470
|
+
this.textOff = end;
|
|
2471
|
+
return chars;
|
|
2472
|
+
}
|
|
2473
|
+
}
|
|
2474
|
+
// Assign the tile classes bucket numbers for caching.
|
|
2475
|
+
const buckets = [WidgetTile, LineTile, TextTile, MarkTile, WidgetBufferTile, BlockWrapperTile, DocTile];
|
|
2476
|
+
for (let i = 0; i < buckets.length; i++)
|
|
2477
|
+
buckets[i].bucket = i;
|
|
2478
|
+
// Leaf tiles and line tiles may be reused in their entirety. All
|
|
2479
|
+
// others will get new tiles allocated, using the old DOM when
|
|
2480
|
+
// possible.
|
|
2481
|
+
class TileCache {
|
|
2482
|
+
constructor(view) {
|
|
2483
|
+
this.view = view;
|
|
2484
|
+
// Buckets are circular buffers, using `index` as the current
|
|
2485
|
+
// position.
|
|
2486
|
+
this.buckets = buckets.map(() => []);
|
|
2487
|
+
this.index = buckets.map(() => 0);
|
|
2488
|
+
this.reused = new Map;
|
|
2489
|
+
}
|
|
2490
|
+
// Put a tile in the cache.
|
|
2491
|
+
add(tile) {
|
|
2492
|
+
let i = tile.constructor.bucket, bucket = this.buckets[i];
|
|
2493
|
+
if (bucket.length < 6 /* C.Bucket */)
|
|
2494
|
+
bucket.push(tile);
|
|
2495
|
+
else
|
|
2496
|
+
bucket[this.index[i] = (this.index[i] + 1) % 6 /* C.Bucket */] = tile;
|
|
2497
|
+
}
|
|
2498
|
+
find(cls, test, type = 2 /* Reused.DOM */) {
|
|
2499
|
+
let i = cls.bucket;
|
|
2500
|
+
let bucket = this.buckets[i], off = this.index[i];
|
|
2501
|
+
for (let j = bucket.length - 1; j >= 0; j--) {
|
|
2502
|
+
// Look at the most recently added items first (last-in, first-out)
|
|
2503
|
+
let index = (j + off) % bucket.length, tile = bucket[index];
|
|
2504
|
+
if ((!test || test(tile)) && !this.reused.has(tile)) {
|
|
2505
|
+
bucket.splice(index, 1);
|
|
2506
|
+
if (index < off)
|
|
2507
|
+
this.index[i]--;
|
|
2508
|
+
this.reused.set(tile, type);
|
|
2509
|
+
return tile;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
return null;
|
|
2513
|
+
}
|
|
2514
|
+
findWidget(widget, length, flags) {
|
|
2515
|
+
let widgets = this.buckets[0];
|
|
2516
|
+
if (widgets.length)
|
|
2517
|
+
for (let i = 0, pass = 0;; i++) {
|
|
2518
|
+
if (i == widgets.length) {
|
|
2519
|
+
if (pass)
|
|
2520
|
+
return null;
|
|
2521
|
+
pass = 1;
|
|
2522
|
+
i = 0;
|
|
2523
|
+
}
|
|
2524
|
+
let tile = widgets[i];
|
|
2525
|
+
if (!this.reused.has(tile) &&
|
|
2526
|
+
(pass == 0 ? tile.widget.compare(widget)
|
|
2527
|
+
: tile.widget.constructor == widget.constructor && widget.updateDOM(tile.dom, this.view))) {
|
|
2528
|
+
widgets.splice(i, 1);
|
|
2529
|
+
if (i < this.index[0])
|
|
2530
|
+
this.index[0]--;
|
|
2531
|
+
this.reused.set(tile, 1 /* Reused.Full */);
|
|
2532
|
+
tile.length = length;
|
|
2533
|
+
tile.flags = (tile.flags & ~(496 /* TileFlag.Widget */ | 1 /* TileFlag.BreakAfter */)) | flags;
|
|
2534
|
+
return tile;
|
|
2535
|
+
}
|
|
2536
|
+
}
|
|
2741
2537
|
}
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
*/
|
|
2746
|
-
get geometryChanged() {
|
|
2747
|
-
return this.docChanged || (this.flags & (16 /* UpdateFlag.Geometry */ | 2 /* UpdateFlag.Height */)) > 0;
|
|
2538
|
+
reuse(tile) {
|
|
2539
|
+
this.reused.set(tile, 1 /* Reused.Full */);
|
|
2540
|
+
return tile;
|
|
2748
2541
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
return
|
|
2542
|
+
maybeReuse(tile, type = 2 /* Reused.DOM */) {
|
|
2543
|
+
if (this.reused.has(tile))
|
|
2544
|
+
return undefined;
|
|
2545
|
+
this.reused.set(tile, type);
|
|
2546
|
+
return tile.dom;
|
|
2754
2547
|
}
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2548
|
+
}
|
|
2549
|
+
// This class organizes a pass over the document, guided by the array
|
|
2550
|
+
// of replaced ranges. For ranges that haven't changed, it iterates
|
|
2551
|
+
// the old tree and copies its content into the new document. For
|
|
2552
|
+
// changed ranges, it runs a decoration iterator to guide generation
|
|
2553
|
+
// of content.
|
|
2554
|
+
class TileUpdate {
|
|
2555
|
+
constructor(view, old, blockWrappers, decorations, disallowBlockEffectsFor) {
|
|
2556
|
+
this.view = view;
|
|
2557
|
+
this.decorations = decorations;
|
|
2558
|
+
this.disallowBlockEffectsFor = disallowBlockEffectsFor;
|
|
2559
|
+
this.openWidget = false;
|
|
2560
|
+
this.openMarks = 0;
|
|
2561
|
+
this.cache = new TileCache(view);
|
|
2562
|
+
this.text = new TextStream(view.state.doc);
|
|
2563
|
+
this.builder = new TileBuilder(this.cache, new DocTile(view, view.contentDOM), state.RangeSet.iter(blockWrappers));
|
|
2564
|
+
this.cache.reused.set(old, 2 /* Reused.DOM */);
|
|
2565
|
+
this.old = new TilePointer(old);
|
|
2566
|
+
}
|
|
2567
|
+
run(changes, composition) {
|
|
2568
|
+
let compositionContext = composition && this.getCompositionContext(composition.text);
|
|
2569
|
+
for (let posA = 0, posB = 0, i = 0;;) {
|
|
2570
|
+
let next = i < changes.length ? changes[i++] : null;
|
|
2571
|
+
let skipA = next ? next.fromA : this.old.root.length;
|
|
2572
|
+
if (skipA > posA) {
|
|
2573
|
+
let len = skipA - posA;
|
|
2574
|
+
this.preserve(len, !i, !next);
|
|
2575
|
+
posA = skipA;
|
|
2576
|
+
posB += len;
|
|
2577
|
+
}
|
|
2578
|
+
if (!next)
|
|
2579
|
+
break;
|
|
2580
|
+
this.forward(next.fromA, next.toA);
|
|
2581
|
+
// Compositions need to be handled specially, forcing the
|
|
2582
|
+
// focused text node and its parent nodes to remain stable at
|
|
2583
|
+
// that point in the document.
|
|
2584
|
+
if (composition && next.fromA <= composition.range.fromA && next.toA >= composition.range.toA) {
|
|
2585
|
+
this.emit(posB, composition.range.fromB);
|
|
2586
|
+
this.builder.addComposition(composition, compositionContext);
|
|
2587
|
+
this.emit(composition.range.toB, next.toB);
|
|
2588
|
+
}
|
|
2589
|
+
else {
|
|
2590
|
+
this.emit(posB, next.toB);
|
|
2591
|
+
}
|
|
2592
|
+
posB = next.toB;
|
|
2593
|
+
posA = next.toA;
|
|
2594
|
+
}
|
|
2595
|
+
if (this.builder.curLine)
|
|
2596
|
+
this.builder.endLine();
|
|
2597
|
+
return this.builder.root;
|
|
2598
|
+
}
|
|
2599
|
+
preserve(length, incStart, incEnd) {
|
|
2600
|
+
let activeMarks = getMarks(this.old), openMarks = this.openMarks;
|
|
2601
|
+
this.old.advance(length, incEnd ? 1 : -1, {
|
|
2602
|
+
skip: (tile, from, to) => {
|
|
2603
|
+
if (tile.isWidget()) {
|
|
2604
|
+
if (this.openWidget) {
|
|
2605
|
+
this.builder.continueWidget(to - from);
|
|
2606
|
+
}
|
|
2607
|
+
else {
|
|
2608
|
+
let widget = to > 0 || from < tile.length
|
|
2609
|
+
? WidgetTile.of(tile.widget, this.view, to - from, tile.flags & 496 /* TileFlag.Widget */, this.cache.maybeReuse(tile))
|
|
2610
|
+
: this.cache.reuse(tile);
|
|
2611
|
+
if (widget.flags & 256 /* TileFlag.Block */) {
|
|
2612
|
+
widget.flags &= ~1 /* TileFlag.BreakAfter */;
|
|
2613
|
+
this.builder.addBlockWidget(widget);
|
|
2614
|
+
}
|
|
2615
|
+
else {
|
|
2616
|
+
this.builder.addInlineWidget(widget, activeMarks, openMarks);
|
|
2617
|
+
openMarks = activeMarks.length;
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
else if (tile.isText()) {
|
|
2622
|
+
if (!from && to == tile.length) {
|
|
2623
|
+
this.builder.addText(tile.text, activeMarks, openMarks, this.cache.reuse(tile));
|
|
2624
|
+
}
|
|
2625
|
+
else {
|
|
2626
|
+
this.cache.add(tile);
|
|
2627
|
+
this.builder.addText(tile.text.slice(from, to), activeMarks, openMarks);
|
|
2628
|
+
}
|
|
2629
|
+
openMarks = activeMarks.length;
|
|
2630
|
+
}
|
|
2631
|
+
else if (tile.isLine()) {
|
|
2632
|
+
tile.flags &= ~1 /* TileFlag.BreakAfter */;
|
|
2633
|
+
this.cache.reused.set(tile, 1 /* Reused.Full */);
|
|
2634
|
+
this.builder.addLine(tile);
|
|
2635
|
+
}
|
|
2636
|
+
else if (tile instanceof WidgetBufferTile) {
|
|
2637
|
+
this.cache.add(tile);
|
|
2638
|
+
}
|
|
2639
|
+
else if (tile instanceof MarkTile) {
|
|
2640
|
+
this.builder.addMark(tile, activeMarks, openMarks);
|
|
2641
|
+
this.cache.reused.set(tile, 1 /* Reused.Full */);
|
|
2642
|
+
}
|
|
2643
|
+
else {
|
|
2644
|
+
return false;
|
|
2645
|
+
}
|
|
2646
|
+
this.openWidget = false;
|
|
2647
|
+
},
|
|
2648
|
+
enter: (tile) => {
|
|
2649
|
+
if (tile.isLine()) {
|
|
2650
|
+
this.builder.addLineStart(tile.attrs, this.cache.maybeReuse(tile));
|
|
2651
|
+
}
|
|
2652
|
+
else {
|
|
2653
|
+
this.cache.add(tile);
|
|
2654
|
+
if (tile instanceof MarkTile)
|
|
2655
|
+
activeMarks.unshift(tile.mark);
|
|
2656
|
+
}
|
|
2657
|
+
this.openWidget = false;
|
|
2658
|
+
},
|
|
2659
|
+
leave: (tile) => {
|
|
2660
|
+
if (tile.isLine()) {
|
|
2661
|
+
if (activeMarks.length)
|
|
2662
|
+
activeMarks.length = openMarks = 0;
|
|
2663
|
+
}
|
|
2664
|
+
else if (tile instanceof MarkTile) {
|
|
2665
|
+
activeMarks.shift();
|
|
2666
|
+
openMarks = Math.min(openMarks, activeMarks.length);
|
|
2667
|
+
}
|
|
2668
|
+
},
|
|
2669
|
+
break: () => {
|
|
2670
|
+
this.builder.addBreak();
|
|
2671
|
+
this.openWidget = false;
|
|
2672
|
+
},
|
|
2673
|
+
});
|
|
2674
|
+
this.text.skip(length);
|
|
2675
|
+
}
|
|
2676
|
+
emit(from, to) {
|
|
2677
|
+
let pendingLineAttrs = null;
|
|
2678
|
+
let b = this.builder, markCount = 0;
|
|
2679
|
+
let openEnd = state.RangeSet.spans(this.decorations, from, to, {
|
|
2680
|
+
point: (from, to, deco, active, openStart, index) => {
|
|
2681
|
+
if (deco instanceof PointDecoration) {
|
|
2682
|
+
if (this.disallowBlockEffectsFor[index]) {
|
|
2683
|
+
if (deco.block)
|
|
2684
|
+
throw new RangeError("Block decorations may not be specified via plugins");
|
|
2685
|
+
if (to > this.view.state.doc.lineAt(from).to)
|
|
2686
|
+
throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
|
2687
|
+
}
|
|
2688
|
+
markCount = active.length;
|
|
2689
|
+
if (openStart > active.length) {
|
|
2690
|
+
b.continueWidget(to - from);
|
|
2691
|
+
}
|
|
2692
|
+
else {
|
|
2693
|
+
let widget = deco.widget || (deco.block ? NullWidget.block : NullWidget.inline);
|
|
2694
|
+
let flags = widgetFlags(deco);
|
|
2695
|
+
let tile = this.cache.findWidget(widget, to - from, flags) || WidgetTile.of(widget, this.view, to - from, flags);
|
|
2696
|
+
if (deco.block) {
|
|
2697
|
+
if (deco.startSide > 0)
|
|
2698
|
+
b.addLineStartIfNotCovered(pendingLineAttrs);
|
|
2699
|
+
b.addBlockWidget(tile);
|
|
2700
|
+
}
|
|
2701
|
+
else {
|
|
2702
|
+
b.ensureLine(pendingLineAttrs);
|
|
2703
|
+
b.addInlineWidget(tile, active, openStart);
|
|
2704
|
+
}
|
|
2705
|
+
}
|
|
2706
|
+
pendingLineAttrs = null;
|
|
2707
|
+
}
|
|
2708
|
+
else {
|
|
2709
|
+
pendingLineAttrs = addLineDeco(pendingLineAttrs, deco);
|
|
2710
|
+
}
|
|
2711
|
+
if (to > from)
|
|
2712
|
+
this.text.skip(to - from);
|
|
2713
|
+
},
|
|
2714
|
+
span: (from, to, active, openStart) => {
|
|
2715
|
+
for (let pos = from; pos < to;) {
|
|
2716
|
+
let chars = this.text.next(Math.min(512 /* C.Chunk */, to - pos));
|
|
2717
|
+
if (chars == null) { // Line break
|
|
2718
|
+
b.addLineStartIfNotCovered(pendingLineAttrs);
|
|
2719
|
+
b.addBreak();
|
|
2720
|
+
pos++;
|
|
2721
|
+
}
|
|
2722
|
+
else {
|
|
2723
|
+
b.ensureLine(pendingLineAttrs);
|
|
2724
|
+
b.addText(chars, active, openStart);
|
|
2725
|
+
pos += chars.length;
|
|
2726
|
+
}
|
|
2727
|
+
pendingLineAttrs = null;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
});
|
|
2731
|
+
b.addLineStartIfNotCovered(pendingLineAttrs);
|
|
2732
|
+
this.openWidget = openEnd > markCount;
|
|
2733
|
+
this.openMarks = openEnd;
|
|
2734
|
+
}
|
|
2735
|
+
forward(from, to) {
|
|
2736
|
+
this.old.advance(to - from, 1, {
|
|
2737
|
+
skip: (tile, from, to) => {
|
|
2738
|
+
if (tile.isText() || to == tile.length)
|
|
2739
|
+
this.cache.add(tile);
|
|
2740
|
+
},
|
|
2741
|
+
enter: tile => this.cache.add(tile),
|
|
2742
|
+
leave: () => { },
|
|
2743
|
+
break: () => { }
|
|
2744
|
+
});
|
|
2760
2745
|
}
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2746
|
+
getCompositionContext(text) {
|
|
2747
|
+
let marks = [], line = null;
|
|
2748
|
+
for (let parent = text.parentNode;; parent = parent.parentNode) {
|
|
2749
|
+
let tile = Tile.get(parent);
|
|
2750
|
+
if (parent == this.view.contentDOM)
|
|
2751
|
+
break;
|
|
2752
|
+
if (tile instanceof MarkTile)
|
|
2753
|
+
marks.push(tile);
|
|
2754
|
+
else if (tile === null || tile === void 0 ? void 0 : tile.isLine())
|
|
2755
|
+
line = tile;
|
|
2756
|
+
else if (parent.nodeName == "DIV" && !line && parent != this.view.contentDOM)
|
|
2757
|
+
line = new LineTile(parent, lineBaseAttrs);
|
|
2758
|
+
else
|
|
2759
|
+
marks.push(MarkTile.of(new MarkDecoration({ tagName: parent.nodeName.toLowerCase(), attributes: getAttrs(parent) }), parent));
|
|
2760
|
+
}
|
|
2761
|
+
return { line: line, marks };
|
|
2766
2762
|
}
|
|
2767
|
-
/**
|
|
2768
|
-
@internal
|
|
2769
|
-
*/
|
|
2770
|
-
get empty() { return this.flags == 0 && this.transactions.length == 0; }
|
|
2771
2763
|
}
|
|
2764
|
+
function hasContent(tile, requireText) {
|
|
2765
|
+
let scan = (tile) => {
|
|
2766
|
+
for (let ch of tile.children)
|
|
2767
|
+
if ((requireText ? ch.isText() : ch.length) || scan(ch))
|
|
2768
|
+
return true;
|
|
2769
|
+
return false;
|
|
2770
|
+
};
|
|
2771
|
+
return scan(tile);
|
|
2772
|
+
}
|
|
2773
|
+
function widgetFlags(deco) {
|
|
2774
|
+
let flags = deco.isReplace ? (deco.startSide < 0 ? 64 /* TileFlag.IncStart */ : 0) | (deco.endSide > 0 ? 128 /* TileFlag.IncEnd */ : 0)
|
|
2775
|
+
: (deco.startSide > 0 ? 32 /* TileFlag.After */ : 16 /* TileFlag.Before */);
|
|
2776
|
+
if (deco.block)
|
|
2777
|
+
flags |= 256 /* TileFlag.Block */;
|
|
2778
|
+
return flags;
|
|
2779
|
+
}
|
|
2780
|
+
const lineBaseAttrs = { class: "cm-line" };
|
|
2781
|
+
function addLineDeco(value, deco) {
|
|
2782
|
+
let attrs = deco.spec.attributes, cls = deco.spec.class;
|
|
2783
|
+
if (!attrs && !cls)
|
|
2784
|
+
return value;
|
|
2785
|
+
if (!value)
|
|
2786
|
+
value = { class: "cm-line" };
|
|
2787
|
+
if (attrs)
|
|
2788
|
+
combineAttrs(attrs, value);
|
|
2789
|
+
if (cls)
|
|
2790
|
+
value.class += " " + cls;
|
|
2791
|
+
return value;
|
|
2792
|
+
}
|
|
2793
|
+
function getMarks(ptr) {
|
|
2794
|
+
let found = [];
|
|
2795
|
+
for (let i = ptr.parents.length; i > 1; i--) {
|
|
2796
|
+
let tile = i == ptr.parents.length ? ptr.tile : ptr.parents[i].tile;
|
|
2797
|
+
if (tile instanceof MarkTile)
|
|
2798
|
+
found.push(tile.mark);
|
|
2799
|
+
}
|
|
2800
|
+
return found;
|
|
2801
|
+
}
|
|
2802
|
+
function freeNode(node) {
|
|
2803
|
+
let tile = Tile.get(node);
|
|
2804
|
+
if (tile)
|
|
2805
|
+
tile.setDOM(node.cloneNode());
|
|
2806
|
+
return node;
|
|
2807
|
+
}
|
|
2808
|
+
class NullWidget extends WidgetType {
|
|
2809
|
+
constructor(tag) {
|
|
2810
|
+
super();
|
|
2811
|
+
this.tag = tag;
|
|
2812
|
+
}
|
|
2813
|
+
eq(other) { return other.tag == this.tag; }
|
|
2814
|
+
toDOM() { return document.createElement(this.tag); }
|
|
2815
|
+
updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
|
|
2816
|
+
get isHidden() { return true; }
|
|
2817
|
+
}
|
|
2818
|
+
NullWidget.inline = new NullWidget("span");
|
|
2819
|
+
NullWidget.block = new NullWidget("div");
|
|
2820
|
+
const BreakWidget = new class extends WidgetType {
|
|
2821
|
+
toDOM() { return document.createElement("br"); }
|
|
2822
|
+
get isHidden() { return true; }
|
|
2823
|
+
get editable() { return true; }
|
|
2824
|
+
};
|
|
2772
2825
|
|
|
2773
|
-
class DocView
|
|
2774
|
-
get length() { return this.view.state.doc.length; }
|
|
2826
|
+
class DocView {
|
|
2775
2827
|
constructor(view) {
|
|
2776
|
-
super();
|
|
2777
2828
|
this.view = view;
|
|
2778
2829
|
this.decorations = [];
|
|
2830
|
+
this.blockWrappers = [];
|
|
2779
2831
|
this.dynamicDecorationMap = [false];
|
|
2780
2832
|
this.domChanged = null;
|
|
2781
2833
|
this.hasComposition = null;
|
|
2782
|
-
this.markedForComposition = new Set;
|
|
2783
2834
|
this.editContextFormatting = Decoration.none;
|
|
2784
2835
|
this.lastCompositionAfterCursor = false;
|
|
2785
2836
|
// Track a minimum width for the editor. When measuring sizes in
|
|
@@ -2800,11 +2851,9 @@ class DocView extends ContentView {
|
|
|
2800
2851
|
// Used by the resize observer to ignore resizes that we caused
|
|
2801
2852
|
// ourselves
|
|
2802
2853
|
this.lastUpdate = Date.now();
|
|
2803
|
-
this.setDOM(view.contentDOM);
|
|
2804
|
-
this.children = [new LineView];
|
|
2805
|
-
this.children[0].setParent(this);
|
|
2806
2854
|
this.updateDeco();
|
|
2807
|
-
this.
|
|
2855
|
+
this.tile = new DocTile(view, view.contentDOM);
|
|
2856
|
+
this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], null);
|
|
2808
2857
|
}
|
|
2809
2858
|
// Update the document view to a given state.
|
|
2810
2859
|
update(update) {
|
|
@@ -2830,7 +2879,6 @@ class DocView extends ContentView {
|
|
|
2830
2879
|
let composition = readCompositionAt > -1 ? findCompositionRange(this.view, update.changes, readCompositionAt) : null;
|
|
2831
2880
|
this.domChanged = null;
|
|
2832
2881
|
if (this.hasComposition) {
|
|
2833
|
-
this.markedForComposition.clear();
|
|
2834
2882
|
let { from, to } = this.hasComposition;
|
|
2835
2883
|
changedRanges = new ChangedRange(from, to, update.changes.mapPos(from, -1), update.changes.mapPos(to, 1))
|
|
2836
2884
|
.addToSet(changedRanges.slice());
|
|
@@ -2844,14 +2892,21 @@ class DocView extends ContentView {
|
|
|
2844
2892
|
if ((browser.ie || browser.chrome) && !composition && update &&
|
|
2845
2893
|
update.state.doc.lines != update.startState.doc.lines)
|
|
2846
2894
|
this.forceSelection = true;
|
|
2847
|
-
let prevDeco = this.decorations,
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
if (
|
|
2895
|
+
let prevDeco = this.decorations, prevWrappers = this.blockWrappers;
|
|
2896
|
+
this.updateDeco();
|
|
2897
|
+
let decoDiff = findChangedDeco(prevDeco, this.decorations, update.changes);
|
|
2898
|
+
if (decoDiff.length)
|
|
2899
|
+
changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
|
2900
|
+
let blockDiff = findChangedWrappers(prevWrappers, this.blockWrappers, update.changes);
|
|
2901
|
+
if (blockDiff.length)
|
|
2902
|
+
changedRanges = ChangedRange.extendWithRanges(changedRanges, blockDiff);
|
|
2903
|
+
if (composition && !changedRanges.some(r => r.fromA <= composition.range.fromA && r.toA >= composition.range.toA))
|
|
2904
|
+
changedRanges = composition.range.addToSet(changedRanges.slice());
|
|
2905
|
+
if ((this.tile.flags & 2 /* TileFlag.Synced */) && changedRanges.length == 0) {
|
|
2851
2906
|
return false;
|
|
2852
2907
|
}
|
|
2853
2908
|
else {
|
|
2854
|
-
this.updateInner(changedRanges,
|
|
2909
|
+
this.updateInner(changedRanges, composition);
|
|
2855
2910
|
if (update.transactions.length)
|
|
2856
2911
|
this.lastUpdate = Date.now();
|
|
2857
2912
|
return true;
|
|
@@ -2859,76 +2914,39 @@ class DocView extends ContentView {
|
|
|
2859
2914
|
}
|
|
2860
2915
|
// Used by update and the constructor do perform the actual DOM
|
|
2861
2916
|
// update
|
|
2862
|
-
updateInner(changes,
|
|
2917
|
+
updateInner(changes, composition) {
|
|
2863
2918
|
this.view.viewState.mustMeasureContent = true;
|
|
2864
|
-
this.updateChildren(changes, oldLength, composition);
|
|
2865
2919
|
let { observer } = this.view;
|
|
2866
2920
|
observer.ignore(() => {
|
|
2921
|
+
if (composition || changes.length) {
|
|
2922
|
+
let oldTile = this.tile;
|
|
2923
|
+
let builder = new TileUpdate(this.view, oldTile, this.blockWrappers, this.decorations, this.dynamicDecorationMap);
|
|
2924
|
+
this.tile = builder.run(changes, composition);
|
|
2925
|
+
destroyDropped(oldTile, builder.cache.reused);
|
|
2926
|
+
}
|
|
2867
2927
|
// Lock the height during redrawing, since Chrome sometimes
|
|
2868
2928
|
// messes with the scroll position during DOM mutation (though
|
|
2869
2929
|
// no relayout is triggered and I cannot imagine how it can
|
|
2870
2930
|
// recompute the scroll position without a layout)
|
|
2871
|
-
this.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
|
|
2872
|
-
this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2931
|
+
this.tile.dom.style.height = this.view.viewState.contentHeight / this.view.scaleY + "px";
|
|
2932
|
+
this.tile.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
|
2873
2933
|
// Chrome will sometimes, when DOM mutations occur directly
|
|
2874
2934
|
// around the selection, get confused and report a different
|
|
2875
2935
|
// selection from the one it displays (issue #218). This tries
|
|
2876
2936
|
// to detect that situation.
|
|
2877
2937
|
let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
|
|
2878
|
-
this.sync(
|
|
2879
|
-
this.flags &= ~7 /* ViewFlag.Dirty */;
|
|
2938
|
+
this.tile.sync();
|
|
2880
2939
|
if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
|
2881
2940
|
this.forceSelection = true;
|
|
2882
|
-
this.dom.style.height = "";
|
|
2941
|
+
this.tile.dom.style.height = "";
|
|
2883
2942
|
});
|
|
2884
|
-
this.markedForComposition.forEach(cView => cView.flags &= ~8 /* ViewFlag.Composition */);
|
|
2885
2943
|
let gaps = [];
|
|
2886
2944
|
if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
|
|
2887
|
-
for (let child of this.children)
|
|
2888
|
-
if (child
|
|
2945
|
+
for (let child of this.tile.children)
|
|
2946
|
+
if (child.isWidget() && child.widget instanceof BlockGapWidget)
|
|
2889
2947
|
gaps.push(child.dom);
|
|
2890
2948
|
observer.updateGaps(gaps);
|
|
2891
2949
|
}
|
|
2892
|
-
updateChildren(changes, oldLength, composition) {
|
|
2893
|
-
let ranges = composition ? composition.range.addToSet(changes.slice()) : changes;
|
|
2894
|
-
let cursor = this.childCursor(oldLength);
|
|
2895
|
-
for (let i = ranges.length - 1;; i--) {
|
|
2896
|
-
let next = i >= 0 ? ranges[i] : null;
|
|
2897
|
-
if (!next)
|
|
2898
|
-
break;
|
|
2899
|
-
let { fromA, toA, fromB, toB } = next, content, breakAtStart, openStart, openEnd;
|
|
2900
|
-
if (composition && composition.range.fromB < toB && composition.range.toB > fromB) {
|
|
2901
|
-
let before = ContentBuilder.build(this.view.state.doc, fromB, composition.range.fromB, this.decorations, this.dynamicDecorationMap);
|
|
2902
|
-
let after = ContentBuilder.build(this.view.state.doc, composition.range.toB, toB, this.decorations, this.dynamicDecorationMap);
|
|
2903
|
-
breakAtStart = before.breakAtStart;
|
|
2904
|
-
openStart = before.openStart;
|
|
2905
|
-
openEnd = after.openEnd;
|
|
2906
|
-
let compLine = this.compositionView(composition);
|
|
2907
|
-
if (after.breakAtStart) {
|
|
2908
|
-
compLine.breakAfter = 1;
|
|
2909
|
-
}
|
|
2910
|
-
else if (after.content.length &&
|
|
2911
|
-
compLine.merge(compLine.length, compLine.length, after.content[0], false, after.openStart, 0)) {
|
|
2912
|
-
compLine.breakAfter = after.content[0].breakAfter;
|
|
2913
|
-
after.content.shift();
|
|
2914
|
-
}
|
|
2915
|
-
if (before.content.length &&
|
|
2916
|
-
compLine.merge(0, 0, before.content[before.content.length - 1], true, 0, before.openEnd)) {
|
|
2917
|
-
before.content.pop();
|
|
2918
|
-
}
|
|
2919
|
-
content = before.content.concat(compLine).concat(after.content);
|
|
2920
|
-
}
|
|
2921
|
-
else {
|
|
2922
|
-
({ content, breakAtStart, openStart, openEnd } =
|
|
2923
|
-
ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap));
|
|
2924
|
-
}
|
|
2925
|
-
let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
|
2926
|
-
let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
|
2927
|
-
replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
|
2928
|
-
}
|
|
2929
|
-
if (composition)
|
|
2930
|
-
this.fixCompositionDOM(composition);
|
|
2931
|
-
}
|
|
2932
2950
|
updateEditContextFormatting(update) {
|
|
2933
2951
|
this.editContextFormatting = this.editContextFormatting.map(update.changes);
|
|
2934
2952
|
for (let tr of update.transactions)
|
|
@@ -2937,47 +2955,26 @@ class DocView extends ContentView {
|
|
|
2937
2955
|
this.editContextFormatting = effect.value;
|
|
2938
2956
|
}
|
|
2939
2957
|
}
|
|
2940
|
-
compositionView(composition) {
|
|
2941
|
-
let cur = new TextView(composition.text.nodeValue);
|
|
2942
|
-
cur.flags |= 8 /* ViewFlag.Composition */;
|
|
2943
|
-
for (let { deco } of composition.marks)
|
|
2944
|
-
cur = new MarkView(deco, [cur], cur.length);
|
|
2945
|
-
let line = new LineView;
|
|
2946
|
-
line.append(cur, 0);
|
|
2947
|
-
return line;
|
|
2948
|
-
}
|
|
2949
|
-
fixCompositionDOM(composition) {
|
|
2950
|
-
let fix = (dom, cView) => {
|
|
2951
|
-
cView.flags |= 8 /* ViewFlag.Composition */ | (cView.children.some(c => c.flags & 7 /* ViewFlag.Dirty */) ? 1 /* ViewFlag.ChildDirty */ : 0);
|
|
2952
|
-
this.markedForComposition.add(cView);
|
|
2953
|
-
let prev = ContentView.get(dom);
|
|
2954
|
-
if (prev && prev != cView)
|
|
2955
|
-
prev.dom = null;
|
|
2956
|
-
cView.setDOM(dom);
|
|
2957
|
-
};
|
|
2958
|
-
let pos = this.childPos(composition.range.fromB, 1);
|
|
2959
|
-
let cView = this.children[pos.i];
|
|
2960
|
-
fix(composition.line, cView);
|
|
2961
|
-
for (let i = composition.marks.length - 1; i >= -1; i--) {
|
|
2962
|
-
pos = cView.childPos(pos.off, 1);
|
|
2963
|
-
cView = cView.children[pos.i];
|
|
2964
|
-
fix(i >= 0 ? composition.marks[i].node : composition.text, cView);
|
|
2965
|
-
}
|
|
2966
|
-
}
|
|
2967
2958
|
// Sync the DOM selection to this.state.selection
|
|
2968
2959
|
updateSelection(mustRead = false, fromPointer = false) {
|
|
2969
2960
|
if (mustRead || !this.view.observer.selectionRange.focusNode)
|
|
2970
2961
|
this.view.observer.readSelectionRange();
|
|
2971
|
-
let
|
|
2972
|
-
let
|
|
2973
|
-
|
|
2962
|
+
let { dom } = this.tile;
|
|
2963
|
+
let activeElt = this.view.root.activeElement, focused = activeElt == dom;
|
|
2964
|
+
let selectionNotFocus = !focused && !(this.view.state.facet(editable) || dom.tabIndex > -1) &&
|
|
2965
|
+
hasSelection(dom, this.view.observer.selectionRange) && !(activeElt && dom.contains(activeElt));
|
|
2974
2966
|
if (!(focused || fromPointer || selectionNotFocus))
|
|
2975
2967
|
return;
|
|
2976
2968
|
let force = this.forceSelection;
|
|
2977
2969
|
this.forceSelection = false;
|
|
2978
|
-
let main = this.view.state.selection.main;
|
|
2979
|
-
|
|
2980
|
-
|
|
2970
|
+
let main = this.view.state.selection.main, anchor, head;
|
|
2971
|
+
if (main.empty) {
|
|
2972
|
+
head = anchor = this.inlineDOMNearPos(main.anchor, main.assoc || 1);
|
|
2973
|
+
}
|
|
2974
|
+
else {
|
|
2975
|
+
head = this.inlineDOMNearPos(main.head, main.head == main.from ? 1 : -1);
|
|
2976
|
+
anchor = this.inlineDOMNearPos(main.anchor, main.anchor == main.from ? 1 : -1);
|
|
2977
|
+
}
|
|
2981
2978
|
// Always reset on Firefox when next to an uneditable node to
|
|
2982
2979
|
// avoid invisible cursor bugs (#111)
|
|
2983
2980
|
if (browser.gecko && main.empty && !this.hasComposition && betweenUneditable(anchor)) {
|
|
@@ -2995,10 +2992,10 @@ class DocView extends ContentView {
|
|
|
2995
2992
|
// inside an uneditable node, and not bring it back when we
|
|
2996
2993
|
// move the cursor to its proper position. This tries to
|
|
2997
2994
|
// restore the keyboard by cycling focus.
|
|
2998
|
-
if (browser.android && browser.chrome &&
|
|
2999
|
-
inUneditable(domSel.focusNode,
|
|
3000
|
-
|
|
3001
|
-
|
|
2995
|
+
if (browser.android && browser.chrome && dom.contains(domSel.focusNode) &&
|
|
2996
|
+
inUneditable(domSel.focusNode, dom)) {
|
|
2997
|
+
dom.blur();
|
|
2998
|
+
dom.focus({ preventScroll: true });
|
|
3002
2999
|
}
|
|
3003
3000
|
let rawSel = getSelection(this.view.root);
|
|
3004
3001
|
if (!rawSel) ;
|
|
@@ -3039,8 +3036,8 @@ class DocView extends ContentView {
|
|
|
3039
3036
|
rawSel.removeAllRanges();
|
|
3040
3037
|
rawSel.addRange(range);
|
|
3041
3038
|
}
|
|
3042
|
-
if (selectionNotFocus && this.view.root.activeElement ==
|
|
3043
|
-
|
|
3039
|
+
if (selectionNotFocus && this.view.root.activeElement == dom) {
|
|
3040
|
+
dom.blur();
|
|
3044
3041
|
if (activeElt)
|
|
3045
3042
|
activeElt.focus();
|
|
3046
3043
|
}
|
|
@@ -3066,7 +3063,7 @@ class DocView extends ContentView {
|
|
|
3066
3063
|
let { anchorNode, anchorOffset } = view.observer.selectionRange;
|
|
3067
3064
|
if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
|
|
3068
3065
|
return;
|
|
3069
|
-
let line =
|
|
3066
|
+
let line = this.lineAt(cursor.head);
|
|
3070
3067
|
if (!line)
|
|
3071
3068
|
return;
|
|
3072
3069
|
let lineStart = line.posAtStart;
|
|
@@ -3075,7 +3072,7 @@ class DocView extends ContentView {
|
|
|
3075
3072
|
let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
|
|
3076
3073
|
if (!before || !after || before.bottom > after.top)
|
|
3077
3074
|
return;
|
|
3078
|
-
let dom = this.domAtPos(cursor.head + cursor.assoc);
|
|
3075
|
+
let dom = this.domAtPos(cursor.head + cursor.assoc, cursor.assoc);
|
|
3079
3076
|
sel.collapse(dom.node, dom.offset);
|
|
3080
3077
|
sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
|
|
3081
3078
|
// This can go wrong in corner cases like single-character lines,
|
|
@@ -3085,143 +3082,213 @@ class DocView extends ContentView {
|
|
|
3085
3082
|
if (view.docView.posFromDOM(newRange.anchorNode, newRange.anchorOffset) != cursor.from)
|
|
3086
3083
|
sel.collapse(anchorNode, anchorOffset);
|
|
3087
3084
|
}
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3085
|
+
posFromDOM(node, offset) {
|
|
3086
|
+
let tile = this.tile.nearest(node);
|
|
3087
|
+
if (!tile)
|
|
3088
|
+
return this.tile.dom.compareDocumentPosition(node) & 2 /* PRECEDING */ ? 0 : this.view.state.doc.length;
|
|
3089
|
+
let start = tile.posAtStart;
|
|
3090
|
+
if (tile.isComposite()) {
|
|
3091
|
+
let after;
|
|
3092
|
+
if (node == tile.dom) {
|
|
3093
|
+
after = tile.dom.childNodes[offset];
|
|
3094
|
+
}
|
|
3095
|
+
else {
|
|
3096
|
+
let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
|
|
3097
|
+
for (;;) {
|
|
3098
|
+
let parent = node.parentNode;
|
|
3099
|
+
if (parent == tile.dom)
|
|
3100
|
+
break;
|
|
3101
|
+
if (bias == 0 && parent.firstChild != parent.lastChild) {
|
|
3102
|
+
if (node == parent.firstChild)
|
|
3103
|
+
bias = -1;
|
|
3104
|
+
else
|
|
3105
|
+
bias = 1;
|
|
3106
|
+
}
|
|
3107
|
+
node = parent;
|
|
3108
|
+
}
|
|
3109
|
+
if (bias < 0)
|
|
3110
|
+
after = node;
|
|
3111
|
+
else
|
|
3112
|
+
after = node.nextSibling;
|
|
3113
|
+
}
|
|
3114
|
+
if (after == tile.dom.firstChild)
|
|
3115
|
+
return start;
|
|
3116
|
+
while (after && !Tile.get(after))
|
|
3117
|
+
after = after.nextSibling;
|
|
3118
|
+
if (!after)
|
|
3119
|
+
return start + tile.length;
|
|
3120
|
+
for (let i = 0, pos = start;; i++) {
|
|
3121
|
+
let child = tile.children[i];
|
|
3122
|
+
if (child.dom == after)
|
|
3123
|
+
return pos;
|
|
3124
|
+
pos += child.length + child.breakAfter;
|
|
3125
|
+
}
|
|
3100
3126
|
}
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
if (view instanceof LineView)
|
|
3104
|
-
newPos = view.domAtPos(view.length);
|
|
3127
|
+
else if (tile.isText()) {
|
|
3128
|
+
return node == tile.dom ? start + offset : start + (offset ? tile.length : 0);
|
|
3105
3129
|
}
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
nearest(dom) {
|
|
3109
|
-
for (let cur = dom; cur;) {
|
|
3110
|
-
let domView = ContentView.get(cur);
|
|
3111
|
-
if (domView && domView.rootView == this)
|
|
3112
|
-
return domView;
|
|
3113
|
-
cur = cur.parentNode;
|
|
3130
|
+
else {
|
|
3131
|
+
return start;
|
|
3114
3132
|
}
|
|
3115
|
-
return null;
|
|
3116
3133
|
}
|
|
3117
|
-
|
|
3118
|
-
let
|
|
3119
|
-
if (
|
|
3120
|
-
|
|
3121
|
-
return
|
|
3122
|
-
}
|
|
3123
|
-
domAtPos(pos) {
|
|
3124
|
-
let { i, off } = this.childCursor().findPos(pos, -1);
|
|
3125
|
-
for (; i < this.children.length - 1;) {
|
|
3126
|
-
let child = this.children[i];
|
|
3127
|
-
if (off < child.length || child instanceof LineView)
|
|
3128
|
-
break;
|
|
3129
|
-
i++;
|
|
3130
|
-
off = 0;
|
|
3131
|
-
}
|
|
3132
|
-
return this.children[i].domAtPos(off);
|
|
3134
|
+
domAtPos(pos, side) {
|
|
3135
|
+
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3136
|
+
if (tile.isWidget())
|
|
3137
|
+
return tile.domPosFor(pos, side);
|
|
3138
|
+
return tile.domIn(offset, side);
|
|
3133
3139
|
}
|
|
3134
|
-
|
|
3135
|
-
let
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
if (
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
bestPos = start;
|
|
3140
|
+
inlineDOMNearPos(pos, side) {
|
|
3141
|
+
let before, beforeOff = -1, beforeBad = false;
|
|
3142
|
+
let after, afterOff = -1, afterBad = false;
|
|
3143
|
+
this.tile.blockTiles((tile, off) => {
|
|
3144
|
+
if (tile.isWidget()) {
|
|
3145
|
+
if ((tile.flags & 32 /* TileFlag.After */) && before)
|
|
3146
|
+
return true;
|
|
3147
|
+
if (tile.flags & 16 /* TileFlag.Before */)
|
|
3148
|
+
beforeBad = true;
|
|
3144
3149
|
}
|
|
3145
|
-
else
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
+
else {
|
|
3151
|
+
let end = off + tile.length;
|
|
3152
|
+
if (off <= pos) {
|
|
3153
|
+
before = tile;
|
|
3154
|
+
beforeOff = pos - off;
|
|
3155
|
+
beforeBad = end < pos;
|
|
3156
|
+
}
|
|
3157
|
+
if (end >= pos && !after) {
|
|
3158
|
+
after = tile;
|
|
3159
|
+
afterOff = pos - off;
|
|
3160
|
+
afterBad = off > pos;
|
|
3161
|
+
}
|
|
3162
|
+
if (off > pos && after)
|
|
3163
|
+
return true;
|
|
3150
3164
|
}
|
|
3151
|
-
|
|
3165
|
+
});
|
|
3166
|
+
if (!before && !after)
|
|
3167
|
+
return this.domAtPos(pos, side);
|
|
3168
|
+
if (beforeBad && after)
|
|
3169
|
+
before = null;
|
|
3170
|
+
else if (afterBad && before)
|
|
3171
|
+
after = null;
|
|
3172
|
+
return before && side < 0 || !after ? before.domIn(beforeOff, side) : after.domIn(afterOff, side);
|
|
3173
|
+
}
|
|
3174
|
+
coordsAt(pos, side) {
|
|
3175
|
+
let { tile, offset } = this.tile.resolveBlock(pos, side);
|
|
3176
|
+
if (tile.isWidget()) {
|
|
3177
|
+
if (tile.widget instanceof BlockGapWidget)
|
|
3178
|
+
return null;
|
|
3179
|
+
return tile.coordsInWidget(offset, side, true);
|
|
3152
3180
|
}
|
|
3153
|
-
return
|
|
3181
|
+
return tile.coordsIn(offset, side);
|
|
3182
|
+
}
|
|
3183
|
+
lineAt(pos) {
|
|
3184
|
+
let { tile } = this.tile.resolveBlock(pos, 1);
|
|
3185
|
+
return tile.isLine() ? tile : null;
|
|
3154
3186
|
}
|
|
3155
3187
|
coordsForChar(pos) {
|
|
3156
|
-
let {
|
|
3157
|
-
if (!(
|
|
3188
|
+
let { tile, offset } = this.tile.resolveBlock(pos, 1);
|
|
3189
|
+
if (!tile.isLine())
|
|
3158
3190
|
return null;
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3191
|
+
function scan(tile, offset) {
|
|
3192
|
+
if (tile.isComposite()) {
|
|
3193
|
+
for (let ch of tile.children) {
|
|
3194
|
+
if (ch.length >= offset) {
|
|
3195
|
+
let found = scan(ch, offset);
|
|
3196
|
+
if (found)
|
|
3197
|
+
return found;
|
|
3198
|
+
}
|
|
3199
|
+
offset -= ch.length;
|
|
3200
|
+
if (offset < 0)
|
|
3201
|
+
break;
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
else if (tile.isText() && offset < tile.length) {
|
|
3205
|
+
let end = state.findClusterBreak(tile.text, offset);
|
|
3206
|
+
if (end == offset)
|
|
3163
3207
|
return null;
|
|
3164
|
-
|
|
3165
|
-
|
|
3208
|
+
let rects = textRange(tile.dom, offset, end).getClientRects();
|
|
3209
|
+
for (let i = 0; i < rects.length; i++) {
|
|
3210
|
+
let rect = rects[i];
|
|
3211
|
+
if (i == rects.length - 1 || rect.top < rect.bottom && rect.left < rect.right)
|
|
3212
|
+
return rect;
|
|
3213
|
+
}
|
|
3166
3214
|
}
|
|
3167
|
-
off = childOff;
|
|
3168
|
-
}
|
|
3169
|
-
if (!(child instanceof TextView))
|
|
3170
3215
|
return null;
|
|
3171
|
-
let end = state.findClusterBreak(child.text, off);
|
|
3172
|
-
if (end == off)
|
|
3173
|
-
return null;
|
|
3174
|
-
let rects = textRange(child.dom, off, end).getClientRects();
|
|
3175
|
-
for (let i = 0; i < rects.length; i++) {
|
|
3176
|
-
let rect = rects[i];
|
|
3177
|
-
if (i == rects.length - 1 || rect.top < rect.bottom && rect.left < rect.right)
|
|
3178
|
-
return rect;
|
|
3179
3216
|
}
|
|
3180
|
-
return
|
|
3217
|
+
return scan(tile, offset);
|
|
3181
3218
|
}
|
|
3182
3219
|
measureVisibleLineHeights(viewport) {
|
|
3183
3220
|
let result = [], { from, to } = viewport;
|
|
3184
3221
|
let contentWidth = this.view.contentDOM.clientWidth;
|
|
3185
3222
|
let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
|
|
3186
3223
|
let widest = -1, ltr = this.view.textDirection == exports.Direction.LTR;
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
let
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3224
|
+
let spaceAbove = 0;
|
|
3225
|
+
let scan = (tile, pos, measureBounds) => {
|
|
3226
|
+
for (let i = 0; i < tile.children.length; i++) {
|
|
3227
|
+
if (pos > to)
|
|
3228
|
+
break;
|
|
3229
|
+
let child = tile.children[i], end = pos + child.length;
|
|
3230
|
+
if (child instanceof BlockWrapperTile) {
|
|
3231
|
+
if (end > from)
|
|
3232
|
+
scan(child, pos, child.dom.getBoundingClientRect());
|
|
3233
|
+
}
|
|
3234
|
+
else if (pos >= from) {
|
|
3235
|
+
let childRect = child.dom.getBoundingClientRect(), { height } = childRect;
|
|
3236
|
+
if (measureBounds && !i)
|
|
3237
|
+
spaceAbove += childRect.top - measureBounds.top;
|
|
3238
|
+
if (spaceAbove > 0)
|
|
3239
|
+
result.push(-spaceAbove);
|
|
3240
|
+
result.push(height + spaceAbove);
|
|
3241
|
+
spaceAbove = 0;
|
|
3242
|
+
if (measureBounds && i == tile.children.length - 1)
|
|
3243
|
+
spaceAbove += measureBounds.bottom - childRect.bottom;
|
|
3244
|
+
if (isWider) {
|
|
3245
|
+
let last = child.dom.lastChild;
|
|
3246
|
+
let rects = last ? clientRectsFor(last) : [];
|
|
3247
|
+
if (rects.length) {
|
|
3248
|
+
let rect = rects[rects.length - 1];
|
|
3249
|
+
let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
|
|
3250
|
+
if (width > widest) {
|
|
3251
|
+
widest = width;
|
|
3252
|
+
this.minWidth = contentWidth;
|
|
3253
|
+
this.minWidthFrom = pos;
|
|
3254
|
+
this.minWidthTo = end;
|
|
3255
|
+
}
|
|
3205
3256
|
}
|
|
3206
3257
|
}
|
|
3207
3258
|
}
|
|
3259
|
+
pos = end + child.breakAfter;
|
|
3208
3260
|
}
|
|
3209
|
-
|
|
3210
|
-
|
|
3261
|
+
};
|
|
3262
|
+
scan(this.tile, 0, null);
|
|
3211
3263
|
return result;
|
|
3212
3264
|
}
|
|
3213
3265
|
textDirectionAt(pos) {
|
|
3214
|
-
let {
|
|
3215
|
-
return getComputedStyle(
|
|
3266
|
+
let { tile } = this.tile.resolveBlock(pos, 1);
|
|
3267
|
+
return getComputedStyle(tile.dom).direction == "rtl" ? exports.Direction.RTL : exports.Direction.LTR;
|
|
3216
3268
|
}
|
|
3217
3269
|
measureTextSize() {
|
|
3218
|
-
|
|
3219
|
-
if (
|
|
3220
|
-
let
|
|
3221
|
-
|
|
3222
|
-
|
|
3270
|
+
let lineMeasure = this.tile.blockTiles(tile => {
|
|
3271
|
+
if (tile.isLine() && tile.children.length && tile.length <= 20) {
|
|
3272
|
+
let totalWidth = 0, textHeight;
|
|
3273
|
+
for (let child of tile.children) {
|
|
3274
|
+
if (!child.isText() || /[^ -~]/.test(child.text))
|
|
3275
|
+
return undefined;
|
|
3276
|
+
let rects = clientRectsFor(child.dom);
|
|
3277
|
+
if (rects.length != 1)
|
|
3278
|
+
return undefined;
|
|
3279
|
+
totalWidth += rects[0].width;
|
|
3280
|
+
textHeight = rects[0].height;
|
|
3281
|
+
}
|
|
3282
|
+
if (totalWidth)
|
|
3283
|
+
return {
|
|
3284
|
+
lineHeight: tile.dom.getBoundingClientRect().height,
|
|
3285
|
+
charWidth: totalWidth / tile.length,
|
|
3286
|
+
textHeight
|
|
3287
|
+
};
|
|
3223
3288
|
}
|
|
3224
|
-
}
|
|
3289
|
+
});
|
|
3290
|
+
if (lineMeasure)
|
|
3291
|
+
return lineMeasure;
|
|
3225
3292
|
// If no workable line exists, force a layout of a measurable element
|
|
3226
3293
|
let dummy = document.createElement("div"), lineHeight, charWidth, textHeight;
|
|
3227
3294
|
dummy.className = "cm-line";
|
|
@@ -3229,7 +3296,7 @@ class DocView extends ContentView {
|
|
|
3229
3296
|
dummy.style.position = "absolute";
|
|
3230
3297
|
dummy.textContent = "abc def ghi jkl mno pqr stu";
|
|
3231
3298
|
this.view.observer.ignore(() => {
|
|
3232
|
-
this.dom.appendChild(dummy);
|
|
3299
|
+
this.tile.dom.appendChild(dummy);
|
|
3233
3300
|
let rect = clientRectsFor(dummy.firstChild)[0];
|
|
3234
3301
|
lineHeight = dummy.getBoundingClientRect().height;
|
|
3235
3302
|
charWidth = rect ? rect.width / 27 : 7;
|
|
@@ -3238,20 +3305,11 @@ class DocView extends ContentView {
|
|
|
3238
3305
|
});
|
|
3239
3306
|
return { lineHeight, charWidth, textHeight };
|
|
3240
3307
|
}
|
|
3241
|
-
childCursor(pos = this.length) {
|
|
3242
|
-
// Move back to start of last element when possible, so that
|
|
3243
|
-
// `ChildCursor.findPos` doesn't have to deal with the edge case
|
|
3244
|
-
// of being after the last element.
|
|
3245
|
-
let i = this.children.length;
|
|
3246
|
-
if (i)
|
|
3247
|
-
pos -= this.children[--i].length;
|
|
3248
|
-
return new ChildCursor(this.children, pos, i);
|
|
3249
|
-
}
|
|
3250
3308
|
computeBlockGapDeco() {
|
|
3251
3309
|
let deco = [], vs = this.view.viewState;
|
|
3252
3310
|
for (let pos = 0, i = 0;; i++) {
|
|
3253
3311
|
let next = i == vs.viewports.length ? null : vs.viewports[i];
|
|
3254
|
-
let end = next ? next.from - 1 : this.length;
|
|
3312
|
+
let end = next ? next.from - 1 : this.view.state.doc.length;
|
|
3255
3313
|
if (end > pos) {
|
|
3256
3314
|
let height = (vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top) / this.view.scaleY;
|
|
3257
3315
|
deco.push(Decoration.replace({
|
|
@@ -3291,7 +3349,7 @@ class DocView extends ContentView {
|
|
|
3291
3349
|
];
|
|
3292
3350
|
while (i < this.decorations.length)
|
|
3293
3351
|
this.dynamicDecorationMap[i++] = false;
|
|
3294
|
-
|
|
3352
|
+
this.blockWrappers = this.view.state.facet(blockWrappers).map(v => typeof v == "function" ? v(this.view) : v);
|
|
3295
3353
|
}
|
|
3296
3354
|
scrollIntoView(target) {
|
|
3297
3355
|
if (target.isSnapshot) {
|
|
@@ -3325,11 +3383,20 @@ class DocView extends ContentView {
|
|
|
3325
3383
|
scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, Math.max(Math.min(target.xMargin, offsetWidth), -offsetWidth), Math.max(Math.min(target.yMargin, offsetHeight), -offsetHeight), this.view.textDirection == exports.Direction.LTR);
|
|
3326
3384
|
}
|
|
3327
3385
|
lineHasWidget(pos) {
|
|
3328
|
-
let
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3386
|
+
let scan = (child) => child.isWidget() || child.children.some(scan);
|
|
3387
|
+
return scan(this.tile.resolveBlock(pos, 1).tile);
|
|
3388
|
+
}
|
|
3389
|
+
destroy() {
|
|
3390
|
+
destroyDropped(this.tile);
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
function destroyDropped(tile, reused) {
|
|
3394
|
+
let r = reused === null || reused === void 0 ? void 0 : reused.get(tile);
|
|
3395
|
+
if (r != 1 /* Reused.Full */) {
|
|
3396
|
+
if (r == null)
|
|
3397
|
+
tile.destroy();
|
|
3398
|
+
for (let ch of tile.children)
|
|
3399
|
+
destroyDropped(ch, reused);
|
|
3333
3400
|
}
|
|
3334
3401
|
}
|
|
3335
3402
|
function betweenUneditable(pos) {
|
|
@@ -3345,13 +3412,13 @@ function findCompositionNode(view, headPos) {
|
|
|
3345
3412
|
let textAfter = textNodeAfter(sel.focusNode, sel.focusOffset);
|
|
3346
3413
|
let textNode = textBefore || textAfter;
|
|
3347
3414
|
if (textAfter && textBefore && textAfter.node != textBefore.node) {
|
|
3348
|
-
let
|
|
3349
|
-
if (!
|
|
3415
|
+
let tileAfter = Tile.get(textAfter.node);
|
|
3416
|
+
if (!tileAfter || tileAfter.isText() && tileAfter.text != textAfter.node.nodeValue) {
|
|
3350
3417
|
textNode = textAfter;
|
|
3351
3418
|
}
|
|
3352
3419
|
else if (view.docView.lastCompositionAfterCursor) {
|
|
3353
|
-
let
|
|
3354
|
-
if (!(!
|
|
3420
|
+
let tileBefore = Tile.get(textBefore.node);
|
|
3421
|
+
if (!(!tileBefore || tileBefore.isText() && tileBefore.text != textBefore.node.nodeValue))
|
|
3355
3422
|
textNode = textAfter;
|
|
3356
3423
|
}
|
|
3357
3424
|
}
|
|
@@ -3372,23 +3439,7 @@ function findCompositionRange(view, changes, headPos) {
|
|
|
3372
3439
|
if (view.state.doc.sliceString(found.from, found.to) != text)
|
|
3373
3440
|
return null;
|
|
3374
3441
|
let inv = changes.invertedDesc;
|
|
3375
|
-
|
|
3376
|
-
let marks = [];
|
|
3377
|
-
for (let parent = textNode.parentNode;; parent = parent.parentNode) {
|
|
3378
|
-
let parentView = ContentView.get(parent);
|
|
3379
|
-
if (parentView instanceof MarkView)
|
|
3380
|
-
marks.push({ node: parent, deco: parentView.mark });
|
|
3381
|
-
else if (parentView instanceof LineView || parent.nodeName == "DIV" && parent.parentNode == view.contentDOM)
|
|
3382
|
-
return { range, text: textNode, marks, line: parent };
|
|
3383
|
-
else if (parent != view.contentDOM)
|
|
3384
|
-
marks.push({ node: parent, deco: new MarkDecoration({
|
|
3385
|
-
inclusive: true,
|
|
3386
|
-
attributes: getAttrs(parent),
|
|
3387
|
-
tagName: parent.tagName.toLowerCase()
|
|
3388
|
-
}) });
|
|
3389
|
-
else
|
|
3390
|
-
return null;
|
|
3391
|
-
}
|
|
3442
|
+
return { range: new ChangedRange(inv.mapPos(from), inv.mapPos(to), from, to), text: textNode };
|
|
3392
3443
|
}
|
|
3393
3444
|
function nextToUneditable(node, offset) {
|
|
3394
3445
|
if (node.nodeType != 1)
|
|
@@ -3409,6 +3460,19 @@ function findChangedDeco(a, b, diff) {
|
|
|
3409
3460
|
state.RangeSet.compare(a, b, diff, comp);
|
|
3410
3461
|
return comp.changes;
|
|
3411
3462
|
}
|
|
3463
|
+
class WrapperComparator {
|
|
3464
|
+
constructor() {
|
|
3465
|
+
this.changes = [];
|
|
3466
|
+
}
|
|
3467
|
+
compareRange(from, to) { addRange(from, to, this.changes); }
|
|
3468
|
+
comparePoint() { }
|
|
3469
|
+
boundChange(pos) { addRange(pos, pos, this.changes); }
|
|
3470
|
+
}
|
|
3471
|
+
function findChangedWrappers(a, b, diff) {
|
|
3472
|
+
let comp = new WrapperComparator;
|
|
3473
|
+
state.RangeSet.compare(a, b, diff, comp);
|
|
3474
|
+
return comp.changes;
|
|
3475
|
+
}
|
|
3412
3476
|
function inUneditable(node, inside) {
|
|
3413
3477
|
for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
|
|
3414
3478
|
if (cur.nodeType == 1 && cur.contentEditable == 'false') {
|
|
@@ -3426,6 +3490,26 @@ function touchesComposition(changes, composition) {
|
|
|
3426
3490
|
});
|
|
3427
3491
|
return touched;
|
|
3428
3492
|
}
|
|
3493
|
+
class BlockGapWidget extends WidgetType {
|
|
3494
|
+
constructor(height) {
|
|
3495
|
+
super();
|
|
3496
|
+
this.height = height;
|
|
3497
|
+
}
|
|
3498
|
+
toDOM() {
|
|
3499
|
+
let elt = document.createElement("div");
|
|
3500
|
+
elt.className = "cm-gap";
|
|
3501
|
+
this.updateDOM(elt);
|
|
3502
|
+
return elt;
|
|
3503
|
+
}
|
|
3504
|
+
eq(other) { return other.height == this.height; }
|
|
3505
|
+
updateDOM(elt) {
|
|
3506
|
+
elt.style.height = this.height + "px";
|
|
3507
|
+
return true;
|
|
3508
|
+
}
|
|
3509
|
+
get editable() { return true; }
|
|
3510
|
+
get estimatedHeight() { return this.height; }
|
|
3511
|
+
ignoreEvent() { return false; }
|
|
3512
|
+
}
|
|
3429
3513
|
|
|
3430
3514
|
function groupAt(state$1, pos, bias = 1) {
|
|
3431
3515
|
let categorize = state$1.charCategorizer(pos);
|
|
@@ -3561,7 +3645,7 @@ function domPosInText(node, x, y) {
|
|
|
3561
3645
|
return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
|
3562
3646
|
}
|
|
3563
3647
|
function posAtCoords(view, coords, precise, bias = -1) {
|
|
3564
|
-
var _a
|
|
3648
|
+
var _a;
|
|
3565
3649
|
let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
|
3566
3650
|
let block, { docHeight } = view.viewState;
|
|
3567
3651
|
let { x, y } = coords, yOffset = y - docTop;
|
|
@@ -3611,7 +3695,7 @@ function posAtCoords(view, coords, precise, bias = -1) {
|
|
|
3611
3695
|
// There's visible editor content under the point, so we can try
|
|
3612
3696
|
// using caret(Position|Range)FromPoint as a shortcut
|
|
3613
3697
|
let node, offset = -1;
|
|
3614
|
-
if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.
|
|
3698
|
+
if (element && !((_a = view.docView.tile.nearest(element)) === null || _a === void 0 ? void 0 : _a.isWidget())) {
|
|
3615
3699
|
if (doc.caretPositionFromPoint) {
|
|
3616
3700
|
let pos = doc.caretPositionFromPoint(x, y);
|
|
3617
3701
|
if (pos)
|
|
@@ -3633,23 +3717,21 @@ function posAtCoords(view, coords, precise, bias = -1) {
|
|
|
3633
3717
|
offset = Math.min(maxOffset(node), offset);
|
|
3634
3718
|
}
|
|
3635
3719
|
// No luck, do our own (potentially expensive) search
|
|
3636
|
-
if (!node || !view.
|
|
3637
|
-
let line =
|
|
3720
|
+
if (!node || !view.contentDOM.contains(node)) {
|
|
3721
|
+
let line = view.docView.lineAt(lineStart);
|
|
3638
3722
|
if (!line)
|
|
3639
3723
|
return yOffset > block.top + block.height / 2 ? block.to : block.from;
|
|
3640
3724
|
({ node, offset } = domPosAtCoords(line.dom, x, y));
|
|
3641
3725
|
}
|
|
3642
|
-
let nearest = view.docView.nearest(node);
|
|
3726
|
+
let nearest = view.docView.tile.nearest(node);
|
|
3643
3727
|
if (!nearest)
|
|
3644
3728
|
return null;
|
|
3645
|
-
if (nearest.isWidget
|
|
3729
|
+
if (nearest.isWidget()) {
|
|
3646
3730
|
let rect = nearest.dom.getBoundingClientRect();
|
|
3647
3731
|
return coords.y < rect.top || coords.y <= rect.bottom && coords.x <= (rect.left + rect.right) / 2
|
|
3648
3732
|
? nearest.posAtStart : nearest.posAtEnd;
|
|
3649
3733
|
}
|
|
3650
|
-
|
|
3651
|
-
return nearest.localPosFromDOM(node, offset) + nearest.posAtStart;
|
|
3652
|
-
}
|
|
3734
|
+
return view.docView.posFromDOM(node, offset);
|
|
3653
3735
|
}
|
|
3654
3736
|
function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
|
3655
3737
|
let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
|
@@ -3865,13 +3947,16 @@ class DOMReader {
|
|
|
3865
3947
|
this.findPointBefore(parent, cur);
|
|
3866
3948
|
let oldLen = this.text.length;
|
|
3867
3949
|
this.readNode(cur);
|
|
3868
|
-
let next = cur.nextSibling;
|
|
3869
|
-
if (next == end)
|
|
3950
|
+
let tile = Tile.get(cur), next = cur.nextSibling;
|
|
3951
|
+
if (next == end) {
|
|
3952
|
+
if ((tile === null || tile === void 0 ? void 0 : tile.breakAfter) && !next)
|
|
3953
|
+
this.lineBreak();
|
|
3870
3954
|
break;
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3955
|
+
}
|
|
3956
|
+
let nextTile = Tile.get(next);
|
|
3957
|
+
if ((tile && nextTile ? tile.breakAfter :
|
|
3958
|
+
(tile ? tile.breakAfter : isBlockElement(cur)) ||
|
|
3959
|
+
(isBlockElement(next) && (cur.nodeName != "BR" || (tile === null || tile === void 0 ? void 0 : tile.isWidget())) && this.text.length > oldLen)) &&
|
|
3875
3960
|
!isEmptyToEnd(next, end))
|
|
3876
3961
|
this.lineBreak();
|
|
3877
3962
|
cur = next;
|
|
@@ -3906,10 +3991,8 @@ class DOMReader {
|
|
|
3906
3991
|
}
|
|
3907
3992
|
}
|
|
3908
3993
|
readNode(node) {
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
let view = ContentView.get(node);
|
|
3912
|
-
let fromView = view && view.overrideDOMText;
|
|
3994
|
+
let tile = Tile.get(node);
|
|
3995
|
+
let fromView = tile && tile.overrideDOMText;
|
|
3913
3996
|
if (fromView != null) {
|
|
3914
3997
|
this.findPointInside(node, fromView.length);
|
|
3915
3998
|
for (let i = fromView.iter(); !i.next().done;) {
|
|
@@ -3956,8 +4039,8 @@ function isEmptyToEnd(node, end) {
|
|
|
3956
4039
|
for (;; node = node.nextSibling) {
|
|
3957
4040
|
if (node == end || !node)
|
|
3958
4041
|
break;
|
|
3959
|
-
let view =
|
|
3960
|
-
if (!(
|
|
4042
|
+
let view = Tile.get(node);
|
|
4043
|
+
if (!(view === null || view === void 0 ? void 0 : view.isWidget()))
|
|
3961
4044
|
return false;
|
|
3962
4045
|
if (view)
|
|
3963
4046
|
(widgets || (widgets = [])).push(view);
|
|
@@ -3989,7 +4072,7 @@ class DOMChange {
|
|
|
3989
4072
|
// Ignore changes when the editor is read-only
|
|
3990
4073
|
this.newSel = null;
|
|
3991
4074
|
}
|
|
3992
|
-
else if (start > -1 && (this.bounds = view.docView.
|
|
4075
|
+
else if (start > -1 && (this.bounds = domBoundsAround(view.docView.tile, start, end, 0))) {
|
|
3993
4076
|
let selPoints = iHead || iAnchor ? [] : selectionPoints(view);
|
|
3994
4077
|
let reader = new DOMReader(selPoints, view.state);
|
|
3995
4078
|
reader.readRange(this.bounds.startDOM, this.bounds.endDOM);
|
|
@@ -4027,6 +4110,36 @@ class DOMChange {
|
|
|
4027
4110
|
}
|
|
4028
4111
|
}
|
|
4029
4112
|
}
|
|
4113
|
+
function domBoundsAround(tile, from, to, offset) {
|
|
4114
|
+
if (tile.isComposite()) {
|
|
4115
|
+
let fromI = -1, fromStart = -1, toI = -1, toEnd = -1;
|
|
4116
|
+
for (let i = 0, pos = offset, prevEnd = offset; i < tile.children.length; i++) {
|
|
4117
|
+
let child = tile.children[i], end = pos + child.length;
|
|
4118
|
+
if (pos < from && end > to)
|
|
4119
|
+
return domBoundsAround(child, from, to, pos);
|
|
4120
|
+
if (end >= from && fromI == -1) {
|
|
4121
|
+
fromI = i;
|
|
4122
|
+
fromStart = pos;
|
|
4123
|
+
}
|
|
4124
|
+
if (pos > to && child.dom.parentNode == tile.dom) {
|
|
4125
|
+
toI = i;
|
|
4126
|
+
toEnd = prevEnd;
|
|
4127
|
+
break;
|
|
4128
|
+
}
|
|
4129
|
+
prevEnd = end;
|
|
4130
|
+
pos = end + child.breakAfter;
|
|
4131
|
+
}
|
|
4132
|
+
return { from: fromStart, to: toEnd < 0 ? offset + tile.length : toEnd,
|
|
4133
|
+
startDOM: (fromI ? tile.children[fromI - 1].dom.nextSibling : null) || tile.dom.firstChild,
|
|
4134
|
+
endDOM: toI < tile.children.length && toI >= 0 ? tile.children[toI].dom : null };
|
|
4135
|
+
}
|
|
4136
|
+
else if (tile.isText()) {
|
|
4137
|
+
return { from: offset, to: offset + tile.length, startDOM: tile.dom, endDOM: tile.dom.nextSibling };
|
|
4138
|
+
}
|
|
4139
|
+
else {
|
|
4140
|
+
return null;
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4030
4143
|
function applyDOMChange(view, domChange) {
|
|
4031
4144
|
let change;
|
|
4032
4145
|
let { newSel } = domChange, sel = view.state.selection.main;
|
|
@@ -4650,8 +4763,8 @@ function eventBelongsToEditor(view, event) {
|
|
|
4650
4763
|
return true;
|
|
4651
4764
|
if (event.defaultPrevented)
|
|
4652
4765
|
return false;
|
|
4653
|
-
for (let node = event.target,
|
|
4654
|
-
if (!node || node.nodeType == 11 || ((
|
|
4766
|
+
for (let node = event.target, tile; node != view.contentDOM; node = node.parentNode)
|
|
4767
|
+
if (!node || node.nodeType == 11 || ((tile = Tile.get(node)) && tile.isWidget() && tile.widget.ignoreEvent(event)))
|
|
4655
4768
|
return false;
|
|
4656
4769
|
return true;
|
|
4657
4770
|
}
|
|
@@ -4770,7 +4883,7 @@ function rangeForClick(view, pos, bias, type) {
|
|
|
4770
4883
|
return groupAt(view.state, pos, bias);
|
|
4771
4884
|
}
|
|
4772
4885
|
else { // Triple click
|
|
4773
|
-
let visual =
|
|
4886
|
+
let visual = view.docView.lineAt(pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos);
|
|
4774
4887
|
let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
|
|
4775
4888
|
if (to < view.state.doc.length && to == line.to)
|
|
4776
4889
|
to++;
|
|
@@ -4782,7 +4895,7 @@ let inside = (x, y, rect) => y >= rect.top && y <= rect.bottom && x >= rect.left
|
|
|
4782
4895
|
// given position, whether they are related to the element before or
|
|
4783
4896
|
// the element after the position.
|
|
4784
4897
|
function findPositionSide(view, pos, x, y) {
|
|
4785
|
-
let line =
|
|
4898
|
+
let line = view.docView.lineAt(pos);
|
|
4786
4899
|
if (!line)
|
|
4787
4900
|
return 1;
|
|
4788
4901
|
let off = pos - line.posAtStart;
|
|
@@ -4792,10 +4905,10 @@ function findPositionSide(view, pos, x, y) {
|
|
|
4792
4905
|
if (off == line.length)
|
|
4793
4906
|
return -1;
|
|
4794
4907
|
// Positions on top of an element point at that element
|
|
4795
|
-
let before = line.
|
|
4908
|
+
let before = line.coordsIn(off, -1);
|
|
4796
4909
|
if (before && inside(x, y, before))
|
|
4797
4910
|
return -1;
|
|
4798
|
-
let after = line.
|
|
4911
|
+
let after = line.coordsIn(off, 1);
|
|
4799
4912
|
if (after && inside(x, y, after))
|
|
4800
4913
|
return 1;
|
|
4801
4914
|
// This is probably a line wrap point. Pick before if the point is
|
|
@@ -4857,9 +4970,9 @@ function removeRangeAround(sel, pos) {
|
|
|
4857
4970
|
handlers.dragstart = (view, event) => {
|
|
4858
4971
|
let { selection: { main: range } } = view.state;
|
|
4859
4972
|
if (event.target.draggable) {
|
|
4860
|
-
let
|
|
4861
|
-
if (
|
|
4862
|
-
let from =
|
|
4973
|
+
let tile = view.docView.tile.nearest(event.target);
|
|
4974
|
+
if (tile && tile.isWidget()) {
|
|
4975
|
+
let from = tile.posAtStart, to = from + tile.length;
|
|
4863
4976
|
if (from >= range.to || to <= range.from)
|
|
4864
4977
|
range = state.EditorSelection.range(from, to);
|
|
4865
4978
|
}
|
|
@@ -5211,7 +5324,7 @@ class HeightOracle {
|
|
|
5211
5324
|
}
|
|
5212
5325
|
}
|
|
5213
5326
|
// This object is used by `updateHeight` to make DOM measurements
|
|
5214
|
-
// arrive at the right
|
|
5327
|
+
// arrive at the right nodes. The `heights` array is a sequence of
|
|
5215
5328
|
// block heights, starting from position `from`.
|
|
5216
5329
|
class MeasuredHeights {
|
|
5217
5330
|
constructor(from, heights) {
|
|
@@ -5250,7 +5363,7 @@ class BlockInfo {
|
|
|
5250
5363
|
/**
|
|
5251
5364
|
@internal Weird packed field that holds an array of children
|
|
5252
5365
|
for composite blocks, a decoration for block widgets, and a
|
|
5253
|
-
number indicating the amount of widget-
|
|
5366
|
+
number indicating the amount of widget-created line breaks for
|
|
5254
5367
|
text blocks.
|
|
5255
5368
|
*/
|
|
5256
5369
|
_content) {
|
|
@@ -5354,7 +5467,7 @@ class HeightMap {
|
|
|
5354
5467
|
}
|
|
5355
5468
|
return me.updateHeight(oracle, 0);
|
|
5356
5469
|
}
|
|
5357
|
-
static empty() { return new HeightMapText(0, 0); }
|
|
5470
|
+
static empty() { return new HeightMapText(0, 0, 0); }
|
|
5358
5471
|
// nodes uses null values to indicate the position of line breaks.
|
|
5359
5472
|
// There are never line breaks at the start or end of the array, or
|
|
5360
5473
|
// two line breaks next to each other, and the array isn't allowed
|
|
@@ -5418,45 +5531,64 @@ function replace(old, val) {
|
|
|
5418
5531
|
return val;
|
|
5419
5532
|
}
|
|
5420
5533
|
HeightMap.prototype.size = 1;
|
|
5534
|
+
const SpaceDeco = Decoration.replace({});
|
|
5421
5535
|
class HeightMapBlock extends HeightMap {
|
|
5422
5536
|
constructor(length, height, deco) {
|
|
5423
5537
|
super(length, height);
|
|
5424
5538
|
this.deco = deco;
|
|
5539
|
+
this.spaceAbove = 0;
|
|
5425
5540
|
}
|
|
5426
|
-
|
|
5427
|
-
return new BlockInfo(offset, this.length, top, this.height, this.deco || 0);
|
|
5541
|
+
mainBlock(top, offset) {
|
|
5542
|
+
return new BlockInfo(offset, this.length, top + this.spaceAbove, this.height - this.spaceAbove, this.deco || 0);
|
|
5543
|
+
}
|
|
5544
|
+
blockAt(height, _oracle, top, offset) {
|
|
5545
|
+
return this.spaceAbove && height < top + this.spaceAbove ? new BlockInfo(offset, 0, top, this.spaceAbove, SpaceDeco)
|
|
5546
|
+
: this.mainBlock(top, offset);
|
|
5428
5547
|
}
|
|
5429
5548
|
lineAt(_value, _type, oracle, top, offset) {
|
|
5430
|
-
|
|
5549
|
+
let main = this.mainBlock(top, offset);
|
|
5550
|
+
return this.spaceAbove ? this.blockAt(0, oracle, top, offset).join(main) : main;
|
|
5431
5551
|
}
|
|
5432
5552
|
forEachLine(from, to, oracle, top, offset, f) {
|
|
5433
5553
|
if (from <= offset + this.length && to >= offset)
|
|
5434
|
-
f(this.
|
|
5554
|
+
f(this.lineAt(0, QueryType.ByPos, oracle, top, offset));
|
|
5555
|
+
}
|
|
5556
|
+
setMeasuredHeight(measured) {
|
|
5557
|
+
let next = measured.heights[measured.index++];
|
|
5558
|
+
if (next < 0) {
|
|
5559
|
+
this.spaceAbove = -next;
|
|
5560
|
+
next = measured.heights[measured.index++];
|
|
5561
|
+
}
|
|
5562
|
+
else {
|
|
5563
|
+
this.spaceAbove = 0;
|
|
5564
|
+
}
|
|
5565
|
+
this.setHeight(next);
|
|
5435
5566
|
}
|
|
5436
5567
|
updateHeight(oracle, offset = 0, _force = false, measured) {
|
|
5437
5568
|
if (measured && measured.from <= offset && measured.more)
|
|
5438
|
-
this.
|
|
5569
|
+
this.setMeasuredHeight(measured);
|
|
5439
5570
|
this.outdated = false;
|
|
5440
5571
|
return this;
|
|
5441
5572
|
}
|
|
5442
5573
|
toString() { return `block(${this.length})`; }
|
|
5443
5574
|
}
|
|
5444
5575
|
class HeightMapText extends HeightMapBlock {
|
|
5445
|
-
constructor(length, height) {
|
|
5576
|
+
constructor(length, height, above) {
|
|
5446
5577
|
super(length, height, null);
|
|
5447
5578
|
this.collapsed = 0; // Amount of collapsed content in the line
|
|
5448
5579
|
this.widgetHeight = 0; // Maximum inline widget height
|
|
5449
5580
|
this.breaks = 0; // Number of widget-introduced line breaks on the line
|
|
5581
|
+
this.spaceAbove = above;
|
|
5450
5582
|
}
|
|
5451
|
-
|
|
5452
|
-
return new BlockInfo(offset, this.length, top, this.height, this.breaks);
|
|
5583
|
+
mainBlock(top, offset) {
|
|
5584
|
+
return new BlockInfo(offset, this.length, top + this.spaceAbove, this.height - this.spaceAbove, this.breaks);
|
|
5453
5585
|
}
|
|
5454
5586
|
replace(_from, _to, nodes) {
|
|
5455
5587
|
let node = nodes[0];
|
|
5456
5588
|
if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && (node.flags & 4 /* Flag.SingleLine */)) &&
|
|
5457
5589
|
Math.abs(this.length - node.length) < 10) {
|
|
5458
5590
|
if (node instanceof HeightMapGap)
|
|
5459
|
-
node = new HeightMapText(node.length, this.height);
|
|
5591
|
+
node = new HeightMapText(node.length, this.height, this.spaceAbove);
|
|
5460
5592
|
else
|
|
5461
5593
|
node.height = this.height;
|
|
5462
5594
|
if (!this.outdated)
|
|
@@ -5468,11 +5600,14 @@ class HeightMapText extends HeightMapBlock {
|
|
|
5468
5600
|
}
|
|
5469
5601
|
}
|
|
5470
5602
|
updateHeight(oracle, offset = 0, force = false, measured) {
|
|
5471
|
-
if (measured && measured.from <= offset && measured.more)
|
|
5472
|
-
this.
|
|
5473
|
-
|
|
5603
|
+
if (measured && measured.from <= offset && measured.more) {
|
|
5604
|
+
this.setMeasuredHeight(measured);
|
|
5605
|
+
}
|
|
5606
|
+
else if (force || this.outdated) {
|
|
5607
|
+
this.spaceAbove = 0;
|
|
5474
5608
|
this.setHeight(Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed)) +
|
|
5475
5609
|
this.breaks * oracle.lineHeight);
|
|
5610
|
+
}
|
|
5476
5611
|
this.outdated = false;
|
|
5477
5612
|
return this;
|
|
5478
5613
|
}
|
|
@@ -5579,12 +5714,16 @@ class HeightMapGap extends HeightMap {
|
|
|
5579
5714
|
let len = oracle.doc.lineAt(pos).length;
|
|
5580
5715
|
if (nodes.length)
|
|
5581
5716
|
nodes.push(null);
|
|
5582
|
-
let height = measured.heights[measured.index++];
|
|
5717
|
+
let height = measured.heights[measured.index++], above = 0;
|
|
5718
|
+
if (height < 0) {
|
|
5719
|
+
above = -height;
|
|
5720
|
+
height = measured.heights[measured.index++];
|
|
5721
|
+
}
|
|
5583
5722
|
if (singleHeight == -1)
|
|
5584
5723
|
singleHeight = height;
|
|
5585
5724
|
else if (Math.abs(height - singleHeight) >= Epsilon)
|
|
5586
5725
|
singleHeight = -2;
|
|
5587
|
-
let line = new HeightMapText(len, height);
|
|
5726
|
+
let line = new HeightMapText(len, height, above);
|
|
5588
5727
|
line.outdated = false;
|
|
5589
5728
|
nodes.push(line);
|
|
5590
5729
|
pos += len + 1;
|
|
@@ -5749,7 +5888,7 @@ class NodeBuilder {
|
|
|
5749
5888
|
if (last instanceof HeightMapText)
|
|
5750
5889
|
last.length += end - this.pos;
|
|
5751
5890
|
else if (end > this.pos || !this.isCovered)
|
|
5752
|
-
this.nodes.push(new HeightMapText(end - this.pos, -1));
|
|
5891
|
+
this.nodes.push(new HeightMapText(end - this.pos, -1, 0));
|
|
5753
5892
|
this.writtenTo = end;
|
|
5754
5893
|
if (to > end) {
|
|
5755
5894
|
this.nodes.push(null);
|
|
@@ -5791,7 +5930,7 @@ class NodeBuilder {
|
|
|
5791
5930
|
this.nodes.push(null);
|
|
5792
5931
|
}
|
|
5793
5932
|
if (this.pos > from)
|
|
5794
|
-
this.nodes.push(new HeightMapText(this.pos - from, -1));
|
|
5933
|
+
this.nodes.push(new HeightMapText(this.pos - from, -1, 0));
|
|
5795
5934
|
this.writtenTo = this.pos;
|
|
5796
5935
|
}
|
|
5797
5936
|
blankContent(from, to) {
|
|
@@ -5805,7 +5944,7 @@ class NodeBuilder {
|
|
|
5805
5944
|
let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null;
|
|
5806
5945
|
if (last instanceof HeightMapText)
|
|
5807
5946
|
return last;
|
|
5808
|
-
let line = new HeightMapText(0, -1);
|
|
5947
|
+
let line = new HeightMapText(0, -1, 0);
|
|
5809
5948
|
this.nodes.push(line);
|
|
5810
5949
|
return line;
|
|
5811
5950
|
}
|
|
@@ -5830,7 +5969,7 @@ class NodeBuilder {
|
|
|
5830
5969
|
finish(from) {
|
|
5831
5970
|
let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1];
|
|
5832
5971
|
if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered)
|
|
5833
|
-
this.nodes.push(new HeightMapText(0, -1));
|
|
5972
|
+
this.nodes.push(new HeightMapText(0, -1, 0));
|
|
5834
5973
|
else if (this.writtenTo < this.pos || last == null)
|
|
5835
5974
|
this.nodes.push(this.blankContent(this.writtenTo, this.pos));
|
|
5836
5975
|
let pos = from;
|
|
@@ -6957,8 +7096,8 @@ class DOMObserver {
|
|
|
6957
7096
|
let { view } = this, sel = this.selectionRange;
|
|
6958
7097
|
if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(this.dom, sel))
|
|
6959
7098
|
return;
|
|
6960
|
-
let context = sel.anchorNode && view.docView.nearest(sel.anchorNode);
|
|
6961
|
-
if (context && context.ignoreEvent(event)) {
|
|
7099
|
+
let context = sel.anchorNode && view.docView.tile.nearest(sel.anchorNode);
|
|
7100
|
+
if (context && context.isWidget() && context.widget.ignoreEvent(event)) {
|
|
6962
7101
|
if (!wasChanged)
|
|
6963
7102
|
this.selectionChanged = false;
|
|
6964
7103
|
return;
|
|
@@ -7188,20 +7327,18 @@ class DOMObserver {
|
|
|
7188
7327
|
return handled;
|
|
7189
7328
|
}
|
|
7190
7329
|
readMutation(rec) {
|
|
7191
|
-
let
|
|
7192
|
-
if (!
|
|
7330
|
+
let tile = this.view.docView.tile.nearest(rec.target);
|
|
7331
|
+
if (!tile || tile.isWidget())
|
|
7193
7332
|
return null;
|
|
7194
|
-
|
|
7195
|
-
if (rec.type == "attributes")
|
|
7196
|
-
cView.flags |= 4 /* ViewFlag.AttrsDirty */;
|
|
7333
|
+
tile.markDirty(rec.type == "attributes");
|
|
7197
7334
|
if (rec.type == "childList") {
|
|
7198
|
-
let childBefore = findChild(
|
|
7199
|
-
let childAfter = findChild(
|
|
7200
|
-
return { from: childBefore ?
|
|
7201
|
-
to: childAfter ?
|
|
7335
|
+
let childBefore = findChild(tile, rec.previousSibling || rec.target.previousSibling, -1);
|
|
7336
|
+
let childAfter = findChild(tile, rec.nextSibling || rec.target.nextSibling, 1);
|
|
7337
|
+
return { from: childBefore ? tile.posAfter(childBefore) : tile.posAtStart,
|
|
7338
|
+
to: childAfter ? tile.posBefore(childAfter) : tile.posAtEnd, typeOver: false };
|
|
7202
7339
|
}
|
|
7203
7340
|
else if (rec.type == "characterData") {
|
|
7204
|
-
return { from:
|
|
7341
|
+
return { from: tile.posAtStart, to: tile.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue };
|
|
7205
7342
|
}
|
|
7206
7343
|
else {
|
|
7207
7344
|
return null;
|
|
@@ -7266,20 +7403,20 @@ class DOMObserver {
|
|
|
7266
7403
|
}
|
|
7267
7404
|
}
|
|
7268
7405
|
}
|
|
7269
|
-
function findChild(
|
|
7406
|
+
function findChild(tile, dom, dir) {
|
|
7270
7407
|
while (dom) {
|
|
7271
|
-
let
|
|
7272
|
-
if (
|
|
7273
|
-
return
|
|
7408
|
+
let curTile = Tile.get(dom);
|
|
7409
|
+
if (curTile && curTile.parent == tile)
|
|
7410
|
+
return curTile;
|
|
7274
7411
|
let parent = dom.parentNode;
|
|
7275
|
-
dom = parent !=
|
|
7412
|
+
dom = parent != tile.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling;
|
|
7276
7413
|
}
|
|
7277
7414
|
return null;
|
|
7278
7415
|
}
|
|
7279
7416
|
function buildSelectionRangeFromRange(view, range) {
|
|
7280
7417
|
let anchorNode = range.startContainer, anchorOffset = range.startOffset;
|
|
7281
7418
|
let focusNode = range.endContainer, focusOffset = range.endOffset;
|
|
7282
|
-
let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor);
|
|
7419
|
+
let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor, 1);
|
|
7283
7420
|
// Since such a range doesn't distinguish between anchor and head,
|
|
7284
7421
|
// use a heuristic that flips it around if its end matches the
|
|
7285
7422
|
// current anchor.
|
|
@@ -8205,8 +8342,8 @@ class EditorView {
|
|
|
8205
8342
|
meaningful (it may just point before or after a placeholder
|
|
8206
8343
|
element).
|
|
8207
8344
|
*/
|
|
8208
|
-
domAtPos(pos) {
|
|
8209
|
-
return this.docView.domAtPos(pos);
|
|
8345
|
+
domAtPos(pos, side = 1) {
|
|
8346
|
+
return this.docView.domAtPos(pos, side);
|
|
8210
8347
|
}
|
|
8211
8348
|
/**
|
|
8212
8349
|
Find the document position at the given DOM node. Can be useful
|
|
@@ -8474,8 +8611,8 @@ class EditorView {
|
|
|
8474
8611
|
static findFromDOM(dom) {
|
|
8475
8612
|
var _a;
|
|
8476
8613
|
let content = dom.querySelector(".cm-content");
|
|
8477
|
-
let
|
|
8478
|
-
return ((_a =
|
|
8614
|
+
let tile = content && Tile.get(content) || Tile.get(dom);
|
|
8615
|
+
return ((_a = tile === null || tile === void 0 ? void 0 : tile.root) === null || _a === void 0 ? void 0 : _a.view) || null;
|
|
8479
8616
|
}
|
|
8480
8617
|
}
|
|
8481
8618
|
/**
|
|
@@ -8587,6 +8724,14 @@ containing the decorations to
|
|
|
8587
8724
|
*/
|
|
8588
8725
|
EditorView.decorations = decorations;
|
|
8589
8726
|
/**
|
|
8727
|
+
[Block wrappers](https://codemirror.net/6/docs/ref/#view.BlockWrapper) provide a way to add DOM
|
|
8728
|
+
structure around editor lines and block widgets. Sets of
|
|
8729
|
+
wrappers are provided in a similar way to decorations, and are
|
|
8730
|
+
nested in a similar way when they overlap. A wrapper affects all
|
|
8731
|
+
lines and block widgets that start inside its range.
|
|
8732
|
+
*/
|
|
8733
|
+
EditorView.blockWrappers = blockWrappers;
|
|
8734
|
+
/**
|
|
8590
8735
|
Facet that works much like
|
|
8591
8736
|
[`decorations`](https://codemirror.net/6/docs/ref/#view.EditorView^decorations), but puts its
|
|
8592
8737
|
inputs at the very bottom of the precedence stack, meaning mark
|
|
@@ -10406,12 +10551,12 @@ class HoverPlugin {
|
|
|
10406
10551
|
startHover() {
|
|
10407
10552
|
clearTimeout(this.restartTimeout);
|
|
10408
10553
|
let { view, lastMove } = this;
|
|
10409
|
-
let
|
|
10410
|
-
if (!
|
|
10554
|
+
let tile = view.docView.tile.nearest(lastMove.target);
|
|
10555
|
+
if (!tile)
|
|
10411
10556
|
return;
|
|
10412
10557
|
let pos, side = 1;
|
|
10413
|
-
if (
|
|
10414
|
-
pos =
|
|
10558
|
+
if (tile.isWidget()) {
|
|
10559
|
+
pos = tile.posAtStart;
|
|
10415
10560
|
}
|
|
10416
10561
|
else {
|
|
10417
10562
|
pos = view.posAtCoords(lastMove);
|
|
@@ -11479,6 +11624,7 @@ const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRan
|
|
|
11479
11624
|
|
|
11480
11625
|
exports.BidiSpan = BidiSpan;
|
|
11481
11626
|
exports.BlockInfo = BlockInfo;
|
|
11627
|
+
exports.BlockWrapper = BlockWrapper;
|
|
11482
11628
|
exports.Decoration = Decoration;
|
|
11483
11629
|
exports.EditorView = EditorView;
|
|
11484
11630
|
exports.GutterMarker = GutterMarker;
|