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