1 | import { Text, RangeSet, MapMode, RangeValue, Facet, StateEffect, ChangeSet, findClusterBreak, EditorSelection, EditorState, findColumn, CharCategory, Prec, Transaction, codePointAt, codePointSize, combineConfig, StateField, RangeSetBuilder, countColumn } from '@codemirror/state';
|
2 | import { StyleModule } from 'style-mod';
|
3 | import { keyName, base, shift } from 'w3c-keyname';
|
4 |
|
5 | function getSelection(root) {
|
6 | let target;
|
7 |
|
8 |
|
9 |
|
10 | if (root.nodeType == 11) {
|
11 | target = root.getSelection ? root : root.ownerDocument;
|
12 | }
|
13 | else {
|
14 | target = root;
|
15 | }
|
16 | return target.getSelection();
|
17 | }
|
18 | function contains(dom, node) {
|
19 | return node ? dom == node || dom.contains(node.nodeType != 1 ? node.parentNode : node) : false;
|
20 | }
|
21 | function deepActiveElement() {
|
22 | let elt = document.activeElement;
|
23 | while (elt && elt.shadowRoot)
|
24 | elt = elt.shadowRoot.activeElement;
|
25 | return elt;
|
26 | }
|
27 | function hasSelection(dom, selection) {
|
28 | if (!selection.anchorNode)
|
29 | return false;
|
30 | try {
|
31 |
|
32 |
|
33 |
|
34 | return contains(dom, selection.anchorNode);
|
35 | }
|
36 | catch (_) {
|
37 | return false;
|
38 | }
|
39 | }
|
40 | function clientRectsFor(dom) {
|
41 | if (dom.nodeType == 3)
|
42 | return textRange(dom, 0, dom.nodeValue.length).getClientRects();
|
43 | else if (dom.nodeType == 1)
|
44 | return dom.getClientRects();
|
45 | else
|
46 | return [];
|
47 | }
|
48 |
|
49 |
|
50 |
|
51 | function isEquivalentPosition(node, off, targetNode, targetOff) {
|
52 | return targetNode ? (scanFor(node, off, targetNode, targetOff, -1) ||
|
53 | scanFor(node, off, targetNode, targetOff, 1)) : false;
|
54 | }
|
55 | function domIndex(node) {
|
56 | for (var index = 0;; index++) {
|
57 | node = node.previousSibling;
|
58 | if (!node)
|
59 | return index;
|
60 | }
|
61 | }
|
62 | function scanFor(node, off, targetNode, targetOff, dir) {
|
63 | for (;;) {
|
64 | if (node == targetNode && off == targetOff)
|
65 | return true;
|
66 | if (off == (dir < 0 ? 0 : maxOffset(node))) {
|
67 | if (node.nodeName == "DIV")
|
68 | return false;
|
69 | let parent = node.parentNode;
|
70 | if (!parent || parent.nodeType != 1)
|
71 | return false;
|
72 | off = domIndex(node) + (dir < 0 ? 0 : 1);
|
73 | node = parent;
|
74 | }
|
75 | else if (node.nodeType == 1) {
|
76 | node = node.childNodes[off + (dir < 0 ? -1 : 0)];
|
77 | if (node.nodeType == 1 && node.contentEditable == "false")
|
78 | return false;
|
79 | off = dir < 0 ? maxOffset(node) : 0;
|
80 | }
|
81 | else {
|
82 | return false;
|
83 | }
|
84 | }
|
85 | }
|
86 | function maxOffset(node) {
|
87 | return node.nodeType == 3 ? node.nodeValue.length : node.childNodes.length;
|
88 | }
|
89 | const Rect0 = { left: 0, right: 0, top: 0, bottom: 0 };
|
90 | function flattenRect(rect, left) {
|
91 | let x = left ? rect.left : rect.right;
|
92 | return { left: x, right: x, top: rect.top, bottom: rect.bottom };
|
93 | }
|
94 | function windowRect(win) {
|
95 | return { left: 0, right: win.innerWidth,
|
96 | top: 0, bottom: win.innerHeight };
|
97 | }
|
98 | function scrollRectIntoView(dom, rect, side, x, y, xMargin, yMargin, ltr) {
|
99 | let doc = dom.ownerDocument, win = doc.defaultView;
|
100 | for (let cur = dom; cur;) {
|
101 | if (cur.nodeType == 1) {
|
102 | let bounding, top = cur == doc.body;
|
103 | if (top) {
|
104 | bounding = windowRect(win);
|
105 | }
|
106 | else {
|
107 | if (cur.scrollHeight <= cur.clientHeight && cur.scrollWidth <= cur.clientWidth) {
|
108 | cur = cur.parentNode;
|
109 | continue;
|
110 | }
|
111 | let rect = cur.getBoundingClientRect();
|
112 |
|
113 | bounding = { left: rect.left, right: rect.left + cur.clientWidth,
|
114 | top: rect.top, bottom: rect.top + cur.clientHeight };
|
115 | }
|
116 | let moveX = 0, moveY = 0;
|
117 | if (y == "nearest") {
|
118 | if (rect.top < bounding.top) {
|
119 | moveY = -(bounding.top - rect.top + yMargin);
|
120 | if (side > 0 && rect.bottom > bounding.bottom + moveY)
|
121 | moveY = rect.bottom - bounding.bottom + moveY + yMargin;
|
122 | }
|
123 | else if (rect.bottom > bounding.bottom) {
|
124 | moveY = rect.bottom - bounding.bottom + yMargin;
|
125 | if (side < 0 && (rect.top - moveY) < bounding.top)
|
126 | moveY = -(bounding.top + moveY - rect.top + yMargin);
|
127 | }
|
128 | }
|
129 | else {
|
130 | let rectHeight = rect.bottom - rect.top, boundingHeight = bounding.bottom - bounding.top;
|
131 | let targetTop = y == "center" && rectHeight <= boundingHeight ? rect.top + rectHeight / 2 - boundingHeight / 2 :
|
132 | y == "start" || y == "center" && side < 0 ? rect.top - yMargin :
|
133 | rect.bottom - boundingHeight + yMargin;
|
134 | moveY = targetTop - bounding.top;
|
135 | }
|
136 | if (x == "nearest") {
|
137 | if (rect.left < bounding.left) {
|
138 | moveX = -(bounding.left - rect.left + xMargin);
|
139 | if (side > 0 && rect.right > bounding.right + moveX)
|
140 | moveX = rect.right - bounding.right + moveX + xMargin;
|
141 | }
|
142 | else if (rect.right > bounding.right) {
|
143 | moveX = rect.right - bounding.right + xMargin;
|
144 | if (side < 0 && rect.left < bounding.left + moveX)
|
145 | moveX = -(bounding.left + moveX - rect.left + xMargin);
|
146 | }
|
147 | }
|
148 | else {
|
149 | let targetLeft = x == "center" ? rect.left + (rect.right - rect.left) / 2 - (bounding.right - bounding.left) / 2 :
|
150 | (x == "start") == ltr ? rect.left - xMargin :
|
151 | rect.right - (bounding.right - bounding.left) + xMargin;
|
152 | moveX = targetLeft - bounding.left;
|
153 | }
|
154 | if (moveX || moveY) {
|
155 | if (top) {
|
156 | win.scrollBy(moveX, moveY);
|
157 | }
|
158 | else {
|
159 | if (moveY) {
|
160 | let start = cur.scrollTop;
|
161 | cur.scrollTop += moveY;
|
162 | moveY = cur.scrollTop - start;
|
163 | }
|
164 | if (moveX) {
|
165 | let start = cur.scrollLeft;
|
166 | cur.scrollLeft += moveX;
|
167 | moveX = cur.scrollLeft - start;
|
168 | }
|
169 | rect = { left: rect.left - moveX, top: rect.top - moveY,
|
170 | right: rect.right - moveX, bottom: rect.bottom - moveY };
|
171 | }
|
172 | }
|
173 | if (top)
|
174 | break;
|
175 | cur = cur.assignedSlot || cur.parentNode;
|
176 | x = y = "nearest";
|
177 | }
|
178 | else if (cur.nodeType == 11) {
|
179 | cur = cur.host;
|
180 | }
|
181 | else {
|
182 | break;
|
183 | }
|
184 | }
|
185 | }
|
186 | class DOMSelectionState {
|
187 | constructor() {
|
188 | this.anchorNode = null;
|
189 | this.anchorOffset = 0;
|
190 | this.focusNode = null;
|
191 | this.focusOffset = 0;
|
192 | }
|
193 | eq(domSel) {
|
194 | return this.anchorNode == domSel.anchorNode && this.anchorOffset == domSel.anchorOffset &&
|
195 | this.focusNode == domSel.focusNode && this.focusOffset == domSel.focusOffset;
|
196 | }
|
197 | setRange(range) {
|
198 | this.set(range.anchorNode, range.anchorOffset, range.focusNode, range.focusOffset);
|
199 | }
|
200 | set(anchorNode, anchorOffset, focusNode, focusOffset) {
|
201 | this.anchorNode = anchorNode;
|
202 | this.anchorOffset = anchorOffset;
|
203 | this.focusNode = focusNode;
|
204 | this.focusOffset = focusOffset;
|
205 | }
|
206 | }
|
207 | let preventScrollSupported = null;
|
208 |
|
209 |
|
210 | function focusPreventScroll(dom) {
|
211 | if (dom.setActive)
|
212 | return dom.setActive();
|
213 | if (preventScrollSupported)
|
214 | return dom.focus(preventScrollSupported);
|
215 | let stack = [];
|
216 | for (let cur = dom; cur; cur = cur.parentNode) {
|
217 | stack.push(cur, cur.scrollTop, cur.scrollLeft);
|
218 | if (cur == cur.ownerDocument)
|
219 | break;
|
220 | }
|
221 | dom.focus(preventScrollSupported == null ? {
|
222 | get preventScroll() {
|
223 | preventScrollSupported = { preventScroll: true };
|
224 | return true;
|
225 | }
|
226 | } : undefined);
|
227 | if (!preventScrollSupported) {
|
228 | preventScrollSupported = false;
|
229 | for (let i = 0; i < stack.length;) {
|
230 | let elt = stack[i++], top = stack[i++], left = stack[i++];
|
231 | if (elt.scrollTop != top)
|
232 | elt.scrollTop = top;
|
233 | if (elt.scrollLeft != left)
|
234 | elt.scrollLeft = left;
|
235 | }
|
236 | }
|
237 | }
|
238 | let scratchRange;
|
239 | function textRange(node, from, to = from) {
|
240 | let range = scratchRange || (scratchRange = document.createRange());
|
241 | range.setEnd(node, to);
|
242 | range.setStart(node, from);
|
243 | return range;
|
244 | }
|
245 | function dispatchKey(elt, name, code) {
|
246 | let options = { key: name, code: name, keyCode: code, which: code, cancelable: true };
|
247 | let down = new KeyboardEvent("keydown", options);
|
248 | down.synthetic = true;
|
249 | elt.dispatchEvent(down);
|
250 | let up = new KeyboardEvent("keyup", options);
|
251 | up.synthetic = true;
|
252 | elt.dispatchEvent(up);
|
253 | return down.defaultPrevented || up.defaultPrevented;
|
254 | }
|
255 | function getRoot(node) {
|
256 | while (node) {
|
257 | if (node && (node.nodeType == 9 || node.nodeType == 11 && node.host))
|
258 | return node;
|
259 | node = node.assignedSlot || node.parentNode;
|
260 | }
|
261 | return null;
|
262 | }
|
263 | function clearAttributes(node) {
|
264 | while (node.attributes.length)
|
265 | node.removeAttributeNode(node.attributes[0]);
|
266 | }
|
267 |
|
268 | class DOMPos {
|
269 | constructor(node, offset, precise = true) {
|
270 | this.node = node;
|
271 | this.offset = offset;
|
272 | this.precise = precise;
|
273 | }
|
274 | static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); }
|
275 | static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); }
|
276 | }
|
277 | const noChildren = [];
|
278 | class ContentView {
|
279 | constructor() {
|
280 | this.parent = null;
|
281 | this.dom = null;
|
282 | this.dirty = 2 ;
|
283 | }
|
284 | get editorView() {
|
285 | if (!this.parent)
|
286 | throw new Error("Accessing view in orphan content view");
|
287 | return this.parent.editorView;
|
288 | }
|
289 | get overrideDOMText() { return null; }
|
290 | get posAtStart() {
|
291 | return this.parent ? this.parent.posBefore(this) : 0;
|
292 | }
|
293 | get posAtEnd() {
|
294 | return this.posAtStart + this.length;
|
295 | }
|
296 | posBefore(view) {
|
297 | let pos = this.posAtStart;
|
298 | for (let child of this.children) {
|
299 | if (child == view)
|
300 | return pos;
|
301 | pos += child.length + child.breakAfter;
|
302 | }
|
303 | throw new RangeError("Invalid child in posBefore");
|
304 | }
|
305 | posAfter(view) {
|
306 | return this.posBefore(view) + view.length;
|
307 | }
|
308 |
|
309 |
|
310 |
|
311 | coordsAt(_pos, _side) { return null; }
|
312 | sync(track) {
|
313 | if (this.dirty & 2 ) {
|
314 | let parent = this.dom;
|
315 | let prev = null, next;
|
316 | for (let child of this.children) {
|
317 | if (child.dirty) {
|
318 | if (!child.dom && (next = prev ? prev.nextSibling : parent.firstChild)) {
|
319 | let contentView = ContentView.get(next);
|
320 | if (!contentView || !contentView.parent && contentView.constructor == child.constructor)
|
321 | child.reuseDOM(next);
|
322 | }
|
323 | child.sync(track);
|
324 | child.dirty = 0 ;
|
325 | }
|
326 | next = prev ? prev.nextSibling : parent.firstChild;
|
327 | if (track && !track.written && track.node == parent && next != child.dom)
|
328 | track.written = true;
|
329 | if (child.dom.parentNode == parent) {
|
330 | while (next && next != child.dom)
|
331 | next = rm$1(next);
|
332 | }
|
333 | else {
|
334 | parent.insertBefore(child.dom, next);
|
335 | }
|
336 | prev = child.dom;
|
337 | }
|
338 | next = prev ? prev.nextSibling : parent.firstChild;
|
339 | if (next && track && track.node == parent)
|
340 | track.written = true;
|
341 | while (next)
|
342 | next = rm$1(next);
|
343 | }
|
344 | else if (this.dirty & 1 ) {
|
345 | for (let child of this.children)
|
346 | if (child.dirty) {
|
347 | child.sync(track);
|
348 | child.dirty = 0 ;
|
349 | }
|
350 | }
|
351 | }
|
352 | reuseDOM(_dom) { }
|
353 | localPosFromDOM(node, offset) {
|
354 | let after;
|
355 | if (node == this.dom) {
|
356 | after = this.dom.childNodes[offset];
|
357 | }
|
358 | else {
|
359 | let bias = maxOffset(node) == 0 ? 0 : offset == 0 ? -1 : 1;
|
360 | for (;;) {
|
361 | let parent = node.parentNode;
|
362 | if (parent == this.dom)
|
363 | break;
|
364 | if (bias == 0 && parent.firstChild != parent.lastChild) {
|
365 | if (node == parent.firstChild)
|
366 | bias = -1;
|
367 | else
|
368 | bias = 1;
|
369 | }
|
370 | node = parent;
|
371 | }
|
372 | if (bias < 0)
|
373 | after = node;
|
374 | else
|
375 | after = node.nextSibling;
|
376 | }
|
377 | if (after == this.dom.firstChild)
|
378 | return 0;
|
379 | while (after && !ContentView.get(after))
|
380 | after = after.nextSibling;
|
381 | if (!after)
|
382 | return this.length;
|
383 | for (let i = 0, pos = 0;; i++) {
|
384 | let child = this.children[i];
|
385 | if (child.dom == after)
|
386 | return pos;
|
387 | pos += child.length + child.breakAfter;
|
388 | }
|
389 | }
|
390 | domBoundsAround(from, to, offset = 0) {
|
391 | let fromI = -1, fromStart = -1, toI = -1, toEnd = -1;
|
392 | for (let i = 0, pos = offset, prevEnd = offset; i < this.children.length; i++) {
|
393 | let child = this.children[i], end = pos + child.length;
|
394 | if (pos < from && end > to)
|
395 | return child.domBoundsAround(from, to, pos);
|
396 | if (end >= from && fromI == -1) {
|
397 | fromI = i;
|
398 | fromStart = pos;
|
399 | }
|
400 | if (pos > to && child.dom.parentNode == this.dom) {
|
401 | toI = i;
|
402 | toEnd = prevEnd;
|
403 | break;
|
404 | }
|
405 | prevEnd = end;
|
406 | pos = end + child.breakAfter;
|
407 | }
|
408 | return { from: fromStart, to: toEnd < 0 ? offset + this.length : toEnd,
|
409 | startDOM: (fromI ? this.children[fromI - 1].dom.nextSibling : null) || this.dom.firstChild,
|
410 | endDOM: toI < this.children.length && toI >= 0 ? this.children[toI].dom : null };
|
411 | }
|
412 | markDirty(andParent = false) {
|
413 | this.dirty |= 2 ;
|
414 | this.markParentsDirty(andParent);
|
415 | }
|
416 | markParentsDirty(childList) {
|
417 | for (let parent = this.parent; parent; parent = parent.parent) {
|
418 | if (childList)
|
419 | parent.dirty |= 2 ;
|
420 | if (parent.dirty & 1 )
|
421 | return;
|
422 | parent.dirty |= 1 ;
|
423 | childList = false;
|
424 | }
|
425 | }
|
426 | setParent(parent) {
|
427 | if (this.parent != parent) {
|
428 | this.parent = parent;
|
429 | if (this.dirty)
|
430 | this.markParentsDirty(true);
|
431 | }
|
432 | }
|
433 | setDOM(dom) {
|
434 | if (this.dom)
|
435 | this.dom.cmView = null;
|
436 | this.dom = dom;
|
437 | dom.cmView = this;
|
438 | }
|
439 | get rootView() {
|
440 | for (let v = this;;) {
|
441 | let parent = v.parent;
|
442 | if (!parent)
|
443 | return v;
|
444 | v = parent;
|
445 | }
|
446 | }
|
447 | replaceChildren(from, to, children = noChildren) {
|
448 | this.markDirty();
|
449 | for (let i = from; i < to; i++) {
|
450 | let child = this.children[i];
|
451 | if (child.parent == this)
|
452 | child.destroy();
|
453 | }
|
454 | this.children.splice(from, to - from, ...children);
|
455 | for (let i = 0; i < children.length; i++)
|
456 | children[i].setParent(this);
|
457 | }
|
458 | ignoreMutation(_rec) { return false; }
|
459 | ignoreEvent(_event) { return false; }
|
460 | childCursor(pos = this.length) {
|
461 | return new ChildCursor(this.children, pos, this.children.length);
|
462 | }
|
463 | childPos(pos, bias = 1) {
|
464 | return this.childCursor().findPos(pos, bias);
|
465 | }
|
466 | toString() {
|
467 | let name = this.constructor.name.replace("View", "");
|
468 | return name + (this.children.length ? "(" + this.children.join() + ")" :
|
469 | this.length ? "[" + (name == "Text" ? this.text : this.length) + "]" : "") +
|
470 | (this.breakAfter ? "#" : "");
|
471 | }
|
472 | static get(node) { return node.cmView; }
|
473 | get isEditable() { return true; }
|
474 | merge(from, to, source, hasStart, openStart, openEnd) {
|
475 | return false;
|
476 | }
|
477 | become(other) { return false; }
|
478 |
|
479 |
|
480 |
|
481 | getSide() { return 0; }
|
482 | destroy() {
|
483 | this.parent = null;
|
484 | }
|
485 | }
|
486 | ContentView.prototype.breakAfter = 0;
|
487 |
|
488 | function rm$1(dom) {
|
489 | let next = dom.nextSibling;
|
490 | dom.parentNode.removeChild(dom);
|
491 | return next;
|
492 | }
|
493 | class ChildCursor {
|
494 | constructor(children, pos, i) {
|
495 | this.children = children;
|
496 | this.pos = pos;
|
497 | this.i = i;
|
498 | this.off = 0;
|
499 | }
|
500 | findPos(pos, bias = 1) {
|
501 | for (;;) {
|
502 | if (pos > this.pos || pos == this.pos &&
|
503 | (bias > 0 || this.i == 0 || this.children[this.i - 1].breakAfter)) {
|
504 | this.off = pos - this.pos;
|
505 | return this;
|
506 | }
|
507 | let next = this.children[--this.i];
|
508 | this.pos -= next.length + next.breakAfter;
|
509 | }
|
510 | }
|
511 | }
|
512 | function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) {
|
513 | let { children } = parent;
|
514 | let before = children.length ? children[fromI] : null;
|
515 | let last = insert.length ? insert[insert.length - 1] : null;
|
516 | let breakAtEnd = last ? last.breakAfter : breakAtStart;
|
517 |
|
518 | if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 &&
|
519 | before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd))
|
520 | return;
|
521 | if (toI < children.length) {
|
522 | let after = children[toI];
|
523 |
|
524 | if (after && toOff < after.length) {
|
525 |
|
526 |
|
527 | if (fromI == toI) {
|
528 | after = after.split(toOff);
|
529 | toOff = 0;
|
530 | }
|
531 |
|
532 |
|
533 | if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) {
|
534 | insert[insert.length - 1] = after;
|
535 | }
|
536 | else {
|
537 |
|
538 |
|
539 | if (toOff)
|
540 | after.merge(0, toOff, null, false, 0, openEnd);
|
541 | insert.push(after);
|
542 | }
|
543 | }
|
544 | else if (after === null || after === void 0 ? void 0 : after.breakAfter) {
|
545 |
|
546 |
|
547 | if (last)
|
548 | last.breakAfter = 1;
|
549 | else
|
550 | breakAtStart = 1;
|
551 | }
|
552 |
|
553 |
|
554 | toI++;
|
555 | }
|
556 | if (before) {
|
557 | before.breakAfter = breakAtStart;
|
558 | if (fromOff > 0) {
|
559 | if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) {
|
560 | before.breakAfter = insert.shift().breakAfter;
|
561 | }
|
562 | else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) {
|
563 | before.merge(fromOff, before.length, null, false, openStart, 0);
|
564 | }
|
565 | fromI++;
|
566 | }
|
567 | }
|
568 |
|
569 | while (fromI < toI && insert.length) {
|
570 | if (children[toI - 1].become(insert[insert.length - 1])) {
|
571 | toI--;
|
572 | insert.pop();
|
573 | openEnd = insert.length ? 0 : openStart;
|
574 | }
|
575 | else if (children[fromI].become(insert[0])) {
|
576 | fromI++;
|
577 | insert.shift();
|
578 | openStart = insert.length ? 0 : openEnd;
|
579 | }
|
580 | else {
|
581 | break;
|
582 | }
|
583 | }
|
584 | if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter &&
|
585 | children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd))
|
586 | fromI--;
|
587 | if (fromI < toI || insert.length)
|
588 | parent.replaceChildren(fromI, toI, insert);
|
589 | }
|
590 | function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
|
591 | let cur = parent.childCursor();
|
592 | let { i: toI, off: toOff } = cur.findPos(to, 1);
|
593 | let { i: fromI, off: fromOff } = cur.findPos(from, -1);
|
594 | let dLen = from - to;
|
595 | for (let view of insert)
|
596 | dLen += view.length;
|
597 | parent.length += dLen;
|
598 | replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
|
599 | }
|
600 |
|
601 | let nav = typeof navigator != "undefined" ? navigator : { userAgent: "", vendor: "", platform: "" };
|
602 | let doc = typeof document != "undefined" ? document : { documentElement: { style: {} } };
|
603 | const ie_edge = /Edge\/(\d+)/.exec(nav.userAgent);
|
604 | const ie_upto10 = /MSIE \d/.test(nav.userAgent);
|
605 | const ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(nav.userAgent);
|
606 | const ie = !!(ie_upto10 || ie_11up || ie_edge);
|
607 | const gecko = !ie && /gecko\/(\d+)/i.test(nav.userAgent);
|
608 | const chrome = !ie && /Chrome\/(\d+)/.exec(nav.userAgent);
|
609 | const webkit = "webkitFontSmoothing" in doc.documentElement.style;
|
610 | const safari = !ie && /Apple Computer/.test(nav.vendor);
|
611 | const ios = safari && (/Mobile\/\w+/.test(nav.userAgent) || nav.maxTouchPoints > 2);
|
612 | var browser = {
|
613 | mac: ios || /Mac/.test(nav.platform),
|
614 | windows: /Win/.test(nav.platform),
|
615 | linux: /Linux|X11/.test(nav.platform),
|
616 | ie,
|
617 | ie_version: ie_upto10 ? doc.documentMode || 6 : ie_11up ? +ie_11up[1] : ie_edge ? +ie_edge[1] : 0,
|
618 | gecko,
|
619 | gecko_version: gecko ? +(/Firefox\/(\d+)/.exec(nav.userAgent) || [0, 0])[1] : 0,
|
620 | chrome: !!chrome,
|
621 | chrome_version: chrome ? +chrome[1] : 0,
|
622 | ios,
|
623 | android: /Android\b/.test(nav.userAgent),
|
624 | webkit,
|
625 | safari,
|
626 | webkit_version: webkit ? +(/\bAppleWebKit\/(\d+)/.exec(navigator.userAgent) || [0, 0])[1] : 0,
|
627 | tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
|
628 | };
|
629 |
|
630 | const MaxJoinLen = 256;
|
631 | class TextView extends ContentView {
|
632 | constructor(text) {
|
633 | super();
|
634 | this.text = text;
|
635 | }
|
636 | get length() { return this.text.length; }
|
637 | createDOM(textDOM) {
|
638 | this.setDOM(textDOM || document.createTextNode(this.text));
|
639 | }
|
640 | sync(track) {
|
641 | if (!this.dom)
|
642 | this.createDOM();
|
643 | if (this.dom.nodeValue != this.text) {
|
644 | if (track && track.node == this.dom)
|
645 | track.written = true;
|
646 | this.dom.nodeValue = this.text;
|
647 | }
|
648 | }
|
649 | reuseDOM(dom) {
|
650 | if (dom.nodeType == 3)
|
651 | this.createDOM(dom);
|
652 | }
|
653 | merge(from, to, source) {
|
654 | if (source && (!(source instanceof TextView) || this.length - (to - from) + source.length > MaxJoinLen))
|
655 | return false;
|
656 | this.text = this.text.slice(0, from) + (source ? source.text : "") + this.text.slice(to);
|
657 | this.markDirty();
|
658 | return true;
|
659 | }
|
660 | split(from) {
|
661 | let result = new TextView(this.text.slice(from));
|
662 | this.text = this.text.slice(0, from);
|
663 | this.markDirty();
|
664 | return result;
|
665 | }
|
666 | localPosFromDOM(node, offset) {
|
667 | return node == this.dom ? offset : offset ? this.text.length : 0;
|
668 | }
|
669 | domAtPos(pos) { return new DOMPos(this.dom, pos); }
|
670 | domBoundsAround(_from, _to, offset) {
|
671 | return { from: offset, to: offset + this.length, startDOM: this.dom, endDOM: this.dom.nextSibling };
|
672 | }
|
673 | coordsAt(pos, side) {
|
674 | return textCoords(this.dom, pos, side);
|
675 | }
|
676 | }
|
677 | class MarkView extends ContentView {
|
678 | constructor(mark, children = [], length = 0) {
|
679 | super();
|
680 | this.mark = mark;
|
681 | this.children = children;
|
682 | this.length = length;
|
683 | for (let ch of children)
|
684 | ch.setParent(this);
|
685 | }
|
686 | setAttrs(dom) {
|
687 | clearAttributes(dom);
|
688 | if (this.mark.class)
|
689 | dom.className = this.mark.class;
|
690 | if (this.mark.attrs)
|
691 | for (let name in this.mark.attrs)
|
692 | dom.setAttribute(name, this.mark.attrs[name]);
|
693 | return dom;
|
694 | }
|
695 | reuseDOM(node) {
|
696 | if (node.nodeName == this.mark.tagName.toUpperCase()) {
|
697 | this.setDOM(node);
|
698 | this.dirty |= 4 | 2 ;
|
699 | }
|
700 | }
|
701 | sync(track) {
|
702 | if (!this.dom)
|
703 | this.setDOM(this.setAttrs(document.createElement(this.mark.tagName)));
|
704 | else if (this.dirty & 4 )
|
705 | this.setAttrs(this.dom);
|
706 | super.sync(track);
|
707 | }
|
708 | merge(from, to, source, _hasStart, openStart, openEnd) {
|
709 | if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
|
710 | (from && openStart <= 0) || (to < this.length && openEnd <= 0)))
|
711 | return false;
|
712 | mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1);
|
713 | this.markDirty();
|
714 | return true;
|
715 | }
|
716 | split(from) {
|
717 | let result = [], off = 0, detachFrom = -1, i = 0;
|
718 | for (let elt of this.children) {
|
719 | let end = off + elt.length;
|
720 | if (end > from)
|
721 | result.push(off < from ? elt.split(from - off) : elt);
|
722 | if (detachFrom < 0 && off >= from)
|
723 | detachFrom = i;
|
724 | off = end;
|
725 | i++;
|
726 | }
|
727 | let length = this.length - from;
|
728 | this.length = from;
|
729 | if (detachFrom > -1) {
|
730 | this.children.length = detachFrom;
|
731 | this.markDirty();
|
732 | }
|
733 | return new MarkView(this.mark, result, length);
|
734 | }
|
735 | domAtPos(pos) {
|
736 | return inlineDOMAtPos(this.dom, this.children, pos);
|
737 | }
|
738 | coordsAt(pos, side) {
|
739 | return coordsInChildren(this, pos, side);
|
740 | }
|
741 | }
|
742 | function textCoords(text, pos, side) {
|
743 | let length = text.nodeValue.length;
|
744 | if (pos > length)
|
745 | pos = length;
|
746 | let from = pos, to = pos, flatten = 0;
|
747 | if (pos == 0 && side < 0 || pos == length && side >= 0) {
|
748 | if (!(browser.chrome || browser.gecko)) {
|
749 | if (pos) {
|
750 | from--;
|
751 | flatten = 1;
|
752 | }
|
753 | else if (to < length) {
|
754 | to++;
|
755 | flatten = -1;
|
756 | }
|
757 | }
|
758 | }
|
759 | else {
|
760 | if (side < 0)
|
761 | from--;
|
762 | else if (to < length)
|
763 | to++;
|
764 | }
|
765 | let rects = textRange(text, from, to).getClientRects();
|
766 | if (!rects.length)
|
767 | return Rect0;
|
768 | let rect = rects[(flatten ? flatten < 0 : side >= 0) ? 0 : rects.length - 1];
|
769 | if (browser.safari && !flatten && rect.width == 0)
|
770 | rect = Array.prototype.find.call(rects, r => r.width) || rect;
|
771 | return flatten ? flattenRect(rect, flatten < 0) : rect || null;
|
772 | }
|
773 |
|
774 | class WidgetView extends ContentView {
|
775 | constructor(widget, length, side) {
|
776 | super();
|
777 | this.widget = widget;
|
778 | this.length = length;
|
779 | this.side = side;
|
780 | this.prevWidget = null;
|
781 | }
|
782 | static create(widget, length, side) {
|
783 | return new (widget.customView || WidgetView)(widget, length, side);
|
784 | }
|
785 | split(from) {
|
786 | let result = WidgetView.create(this.widget, this.length - from, this.side);
|
787 | this.length -= from;
|
788 | return result;
|
789 | }
|
790 | sync() {
|
791 | if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
792 | if (this.dom && this.prevWidget)
|
793 | this.prevWidget.destroy(this.dom);
|
794 | this.prevWidget = null;
|
795 | this.setDOM(this.widget.toDOM(this.editorView));
|
796 | this.dom.contentEditable = "false";
|
797 | }
|
798 | }
|
799 | getSide() { return this.side; }
|
800 | merge(from, to, source, hasStart, openStart, openEnd) {
|
801 | if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) ||
|
802 | from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
|
803 | return false;
|
804 | this.length = from + (source ? source.length : 0) + (this.length - to);
|
805 | return true;
|
806 | }
|
807 | become(other) {
|
808 | if (other.length == this.length && other instanceof WidgetView && other.side == this.side) {
|
809 | if (this.widget.constructor == other.widget.constructor) {
|
810 | if (!this.widget.eq(other.widget))
|
811 | this.markDirty(true);
|
812 | if (this.dom && !this.prevWidget)
|
813 | this.prevWidget = this.widget;
|
814 | this.widget = other.widget;
|
815 | return true;
|
816 | }
|
817 | }
|
818 | return false;
|
819 | }
|
820 | ignoreMutation() { return true; }
|
821 | ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
822 | get overrideDOMText() {
|
823 | if (this.length == 0)
|
824 | return Text.empty;
|
825 | let top = this;
|
826 | while (top.parent)
|
827 | top = top.parent;
|
828 | let view = top.editorView, text = view && view.state.doc, start = this.posAtStart;
|
829 | return text ? text.slice(start, start + this.length) : Text.empty;
|
830 | }
|
831 | domAtPos(pos) {
|
832 | return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
|
833 | }
|
834 | domBoundsAround() { return null; }
|
835 | coordsAt(pos, side) {
|
836 | let rects = this.dom.getClientRects(), rect = null;
|
837 | if (!rects.length)
|
838 | return Rect0;
|
839 | for (let i = pos > 0 ? rects.length - 1 : 0;; i += (pos > 0 ? -1 : 1)) {
|
840 | rect = rects[i];
|
841 | if (pos > 0 ? i == 0 : i == rects.length - 1 || rect.top < rect.bottom)
|
842 | break;
|
843 | }
|
844 | return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0);
|
845 | }
|
846 | get isEditable() { return false; }
|
847 | destroy() {
|
848 | super.destroy();
|
849 | if (this.dom)
|
850 | this.widget.destroy(this.dom);
|
851 | }
|
852 | }
|
853 | class CompositionView extends WidgetView {
|
854 | domAtPos(pos) {
|
855 | let { topView, text } = this.widget;
|
856 | if (!topView)
|
857 | return new DOMPos(text, Math.min(pos, text.nodeValue.length));
|
858 | return scanCompositionTree(pos, 0, topView, text, (v, p) => v.domAtPos(p), p => new DOMPos(text, Math.min(p, text.nodeValue.length)));
|
859 | }
|
860 | sync() { this.setDOM(this.widget.toDOM()); }
|
861 | localPosFromDOM(node, offset) {
|
862 | let { topView, text } = this.widget;
|
863 | if (!topView)
|
864 | return Math.min(offset, this.length);
|
865 | return posFromDOMInCompositionTree(node, offset, topView, text);
|
866 | }
|
867 | ignoreMutation() { return false; }
|
868 | get overrideDOMText() { return null; }
|
869 | coordsAt(pos, side) {
|
870 | let { topView, text } = this.widget;
|
871 | if (!topView)
|
872 | return textCoords(text, pos, side);
|
873 | return scanCompositionTree(pos, side, topView, text, (v, pos, side) => v.coordsAt(pos, side), (pos, side) => textCoords(text, pos, side));
|
874 | }
|
875 | destroy() {
|
876 | var _a;
|
877 | super.destroy();
|
878 | (_a = this.widget.topView) === null || _a === void 0 ? void 0 : _a.destroy();
|
879 | }
|
880 | get isEditable() { return true; }
|
881 | }
|
882 |
|
883 |
|
884 |
|
885 | function scanCompositionTree(pos, side, view, text, enterView, fromText) {
|
886 | if (view instanceof MarkView) {
|
887 | for (let child of view.children) {
|
888 | let hasComp = contains(child.dom, text);
|
889 | let len = hasComp ? text.nodeValue.length : child.length;
|
890 | if (pos < len || pos == len && child.getSide() <= 0)
|
891 | return hasComp ? scanCompositionTree(pos, side, child, text, enterView, fromText) : enterView(child, pos, side);
|
892 | pos -= len;
|
893 | }
|
894 | return enterView(view, view.length, -1);
|
895 | }
|
896 | else if (view.dom == text) {
|
897 | return fromText(pos, side);
|
898 | }
|
899 | else {
|
900 | return enterView(view, pos, side);
|
901 | }
|
902 | }
|
903 | function posFromDOMInCompositionTree(node, offset, view, text) {
|
904 | if (view instanceof MarkView) {
|
905 | for (let child of view.children) {
|
906 | let pos = 0, hasComp = contains(child.dom, text);
|
907 | if (contains(child.dom, node))
|
908 | return pos + (hasComp ? posFromDOMInCompositionTree(node, offset, child, text) : child.localPosFromDOM(node, offset));
|
909 | pos += hasComp ? text.nodeValue.length : child.length;
|
910 | }
|
911 | }
|
912 | else if (view.dom == text) {
|
913 | return Math.min(offset, text.nodeValue.length);
|
914 | }
|
915 | return view.localPosFromDOM(node, offset);
|
916 | }
|
917 |
|
918 |
|
919 |
|
920 | class WidgetBufferView extends ContentView {
|
921 | constructor(side) {
|
922 | super();
|
923 | this.side = side;
|
924 | }
|
925 | get length() { return 0; }
|
926 | merge() { return false; }
|
927 | become(other) {
|
928 | return other instanceof WidgetBufferView && other.side == this.side;
|
929 | }
|
930 | split() { return new WidgetBufferView(this.side); }
|
931 | sync() {
|
932 | if (!this.dom) {
|
933 | let dom = document.createElement("img");
|
934 | dom.className = "cm-widgetBuffer";
|
935 | dom.setAttribute("aria-hidden", "true");
|
936 | this.setDOM(dom);
|
937 | }
|
938 | }
|
939 | getSide() { return this.side; }
|
940 | domAtPos(pos) { return DOMPos.before(this.dom); }
|
941 | localPosFromDOM() { return 0; }
|
942 | domBoundsAround() { return null; }
|
943 | coordsAt(pos) {
|
944 | let imgRect = this.dom.getBoundingClientRect();
|
945 |
|
946 |
|
947 | let siblingRect = inlineSiblingRect(this, this.side > 0 ? -1 : 1);
|
948 | return siblingRect && siblingRect.top < imgRect.bottom && siblingRect.bottom > imgRect.top
|
949 | ? { left: imgRect.left, right: imgRect.right, top: siblingRect.top, bottom: siblingRect.bottom } : imgRect;
|
950 | }
|
951 | get overrideDOMText() {
|
952 | return Text.empty;
|
953 | }
|
954 | }
|
955 | TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
|
956 | function inlineSiblingRect(view, side) {
|
957 | let parent = view.parent, index = parent ? parent.children.indexOf(view) : -1;
|
958 | while (parent && index >= 0) {
|
959 | if (side < 0 ? index > 0 : index < parent.children.length) {
|
960 | let next = parent.children[index + side];
|
961 | if (next instanceof TextView) {
|
962 | let nextRect = next.coordsAt(side < 0 ? next.length : 0, side);
|
963 | if (nextRect)
|
964 | return nextRect;
|
965 | }
|
966 | index += side;
|
967 | }
|
968 | else if (parent instanceof MarkView && parent.parent) {
|
969 | index = parent.parent.children.indexOf(parent) + (side < 0 ? 0 : 1);
|
970 | parent = parent.parent;
|
971 | }
|
972 | else {
|
973 | let last = parent.dom.lastChild;
|
974 | if (last && last.nodeName == "BR")
|
975 | return last.getClientRects()[0];
|
976 | break;
|
977 | }
|
978 | }
|
979 | return undefined;
|
980 | }
|
981 | function inlineDOMAtPos(dom, children, pos) {
|
982 | let i = 0;
|
983 | for (let off = 0; i < children.length; i++) {
|
984 | let child = children[i], end = off + child.length;
|
985 | if (end == off && child.getSide() <= 0)
|
986 | continue;
|
987 | if (pos > off && pos < end && child.dom.parentNode == dom)
|
988 | return child.domAtPos(pos - off);
|
989 | if (pos <= off)
|
990 | break;
|
991 | off = end;
|
992 | }
|
993 | for (; i > 0; i--) {
|
994 | let before = children[i - 1].dom;
|
995 | if (before.parentNode == dom)
|
996 | return DOMPos.after(before);
|
997 | }
|
998 | return new DOMPos(dom, 0);
|
999 | }
|
1000 |
|
1001 | function joinInlineInto(parent, view, open) {
|
1002 | let last, { children } = parent;
|
1003 | if (open > 0 && view instanceof MarkView && children.length &&
|
1004 | (last = children[children.length - 1]) instanceof MarkView && last.mark.eq(view.mark)) {
|
1005 | joinInlineInto(last, view.children[0], open - 1);
|
1006 | }
|
1007 | else {
|
1008 | children.push(view);
|
1009 | view.setParent(parent);
|
1010 | }
|
1011 | parent.length += view.length;
|
1012 | }
|
1013 | function coordsInChildren(view, pos, side) {
|
1014 | for (let off = 0, i = 0; i < view.children.length; i++) {
|
1015 | let child = view.children[i], end = off + child.length, next;
|
1016 | if ((side <= 0 || end == view.length || child.getSide() > 0 ? end >= pos : end > pos) &&
|
1017 | (pos < end || i + 1 == view.children.length || (next = view.children[i + 1]).length || next.getSide() > 0)) {
|
1018 | let flatten = 0;
|
1019 | if (end == off) {
|
1020 | if (child.getSide() <= 0)
|
1021 | continue;
|
1022 | flatten = side = -child.getSide();
|
1023 | }
|
1024 | let rect = child.coordsAt(Math.max(0, pos - off), side);
|
1025 | return flatten && rect ? flattenRect(rect, side < 0) : rect;
|
1026 | }
|
1027 | off = end;
|
1028 | }
|
1029 | let last = view.dom.lastChild;
|
1030 | if (!last)
|
1031 | return view.dom.getBoundingClientRect();
|
1032 | let rects = clientRectsFor(last);
|
1033 | return rects[rects.length - 1] || null;
|
1034 | }
|
1035 |
|
1036 | function combineAttrs(source, target) {
|
1037 | for (let name in source) {
|
1038 | if (name == "class" && target.class)
|
1039 | target.class += " " + source.class;
|
1040 | else if (name == "style" && target.style)
|
1041 | target.style += ";" + source.style;
|
1042 | else
|
1043 | target[name] = source[name];
|
1044 | }
|
1045 | return target;
|
1046 | }
|
1047 | function attrsEq(a, b) {
|
1048 | if (a == b)
|
1049 | return true;
|
1050 | if (!a || !b)
|
1051 | return false;
|
1052 | let keysA = Object.keys(a), keysB = Object.keys(b);
|
1053 | if (keysA.length != keysB.length)
|
1054 | return false;
|
1055 | for (let key of keysA) {
|
1056 | if (keysB.indexOf(key) == -1 || a[key] !== b[key])
|
1057 | return false;
|
1058 | }
|
1059 | return true;
|
1060 | }
|
1061 | function updateAttrs(dom, prev, attrs) {
|
1062 | let changed = null;
|
1063 | if (prev)
|
1064 | for (let name in prev)
|
1065 | if (!(attrs && name in attrs))
|
1066 | dom.removeAttribute(changed = name);
|
1067 | if (attrs)
|
1068 | for (let name in attrs)
|
1069 | if (!(prev && prev[name] == attrs[name]))
|
1070 | dom.setAttribute(changed = name, attrs[name]);
|
1071 | return !!changed;
|
1072 | }
|
1073 |
|
1074 |
|
1075 |
|
1076 |
|
1077 |
|
1078 |
|
1079 |
|
1080 |
|
1081 | class WidgetType {
|
1082 | |
1083 |
|
1084 |
|
1085 |
|
1086 |
|
1087 |
|
1088 |
|
1089 |
|
1090 |
|
1091 | eq(widget) { return false; }
|
1092 | |
1093 |
|
1094 |
|
1095 |
|
1096 |
|
1097 |
|
1098 |
|
1099 | updateDOM(dom) { return false; }
|
1100 | |
1101 |
|
1102 |
|
1103 | compare(other) {
|
1104 | return this == other || this.constructor == other.constructor && this.eq(other);
|
1105 | }
|
1106 | |
1107 |
|
1108 |
|
1109 |
|
1110 |
|
1111 |
|
1112 | get estimatedHeight() { return -1; }
|
1113 | |
1114 |
|
1115 |
|
1116 |
|
1117 |
|
1118 | ignoreEvent(event) { return true; }
|
1119 | |
1120 |
|
1121 |
|
1122 | get customView() { return null; }
|
1123 | |
1124 |
|
1125 |
|
1126 |
|
1127 | destroy(dom) { }
|
1128 | }
|
1129 |
|
1130 |
|
1131 |
|
1132 | var BlockType = (function (BlockType) {
|
1133 | |
1134 |
|
1135 |
|
1136 | BlockType[BlockType["Text"] = 0] = "Text";
|
1137 | |
1138 |
|
1139 |
|
1140 | BlockType[BlockType["WidgetBefore"] = 1] = "WidgetBefore";
|
1141 | |
1142 |
|
1143 |
|
1144 | BlockType[BlockType["WidgetAfter"] = 2] = "WidgetAfter";
|
1145 | |
1146 |
|
1147 |
|
1148 | BlockType[BlockType["WidgetRange"] = 3] = "WidgetRange";
|
1149 | return BlockType})(BlockType || (BlockType = {}));
|
1150 |
|
1151 |
|
1152 |
|
1153 |
|
1154 |
|
1155 |
|
1156 | class Decoration extends RangeValue {
|
1157 | constructor(
|
1158 | /**
|
1159 | @internal
|
1160 | */
|
1161 | startSide,
|
1162 | /**
|
1163 | @internal
|
1164 | */
|
1165 | endSide,
|
1166 | /**
|
1167 | @internal
|
1168 | */
|
1169 | widget,
|
1170 | /**
|
1171 | The config object used to create this decoration. You can
|
1172 | include additional properties in there to store metadata about
|
1173 | your decoration.
|
1174 | */
|
1175 | spec) {
|
1176 | super();
|
1177 | this.startSide = startSide;
|
1178 | this.endSide = endSide;
|
1179 | this.widget = widget;
|
1180 | this.spec = spec;
|
1181 | }
|
1182 | |
1183 |
|
1184 |
|
1185 | get heightRelevant() { return false; }
|
1186 | |
1187 |
|
1188 |
|
1189 |
|
1190 |
|
1191 |
|
1192 |
|
1193 |
|
1194 |
|
1195 | static mark(spec) {
|
1196 | return new MarkDecoration(spec);
|
1197 | }
|
1198 | |
1199 |
|
1200 |
|
1201 |
|
1202 | static widget(spec) {
|
1203 | let side = spec.side || 0, block = !!spec.block;
|
1204 | side += block ? (side > 0 ? 300000000 : -400000000 ) : (side > 0 ? 100000000 : -100000000 );
|
1205 | return new PointDecoration(spec, side, side, block, spec.widget || null, false);
|
1206 | }
|
1207 | |
1208 |
|
1209 |
|
1210 |
|
1211 | static replace(spec) {
|
1212 | let block = !!spec.block, startSide, endSide;
|
1213 | if (spec.isBlockGap) {
|
1214 | startSide = -500000000 ;
|
1215 | endSide = 400000000 ;
|
1216 | }
|
1217 | else {
|
1218 | let { start, end } = getInclusive(spec, block);
|
1219 | startSide = (start ? (block ? -300000000 : -1 ) : 500000000 ) - 1;
|
1220 | endSide = (end ? (block ? 200000000 : 1 ) : -600000000 ) + 1;
|
1221 | }
|
1222 | return new PointDecoration(spec, startSide, endSide, block, spec.widget || null, true);
|
1223 | }
|
1224 | |
1225 |
|
1226 |
|
1227 |
|
1228 | static line(spec) {
|
1229 | return new LineDecoration(spec);
|
1230 | }
|
1231 | |
1232 |
|
1233 |
|
1234 |
|
1235 |
|
1236 | static set(of, sort = false) {
|
1237 | return RangeSet.of(of, sort);
|
1238 | }
|
1239 | |
1240 |
|
1241 |
|
1242 | hasHeight() { return this.widget ? this.widget.estimatedHeight > -1 : false; }
|
1243 | }
|
1244 |
|
1245 |
|
1246 |
|
1247 | Decoration.none = RangeSet.empty;
|
1248 | class MarkDecoration extends Decoration {
|
1249 | constructor(spec) {
|
1250 | let { start, end } = getInclusive(spec);
|
1251 | super(start ? -1 : 500000000 , end ? 1 : -600000000 , null, spec);
|
1252 | this.tagName = spec.tagName || "span";
|
1253 | this.class = spec.class || "";
|
1254 | this.attrs = spec.attributes || null;
|
1255 | }
|
1256 | eq(other) {
|
1257 | return this == other ||
|
1258 | other instanceof MarkDecoration &&
|
1259 | this.tagName == other.tagName &&
|
1260 | this.class == other.class &&
|
1261 | attrsEq(this.attrs, other.attrs);
|
1262 | }
|
1263 | range(from, to = from) {
|
1264 | if (from >= to)
|
1265 | throw new RangeError("Mark decorations may not be empty");
|
1266 | return super.range(from, to);
|
1267 | }
|
1268 | }
|
1269 | MarkDecoration.prototype.point = false;
|
1270 | class LineDecoration extends Decoration {
|
1271 | constructor(spec) {
|
1272 | super(-200000000 , -200000000 , null, spec);
|
1273 | }
|
1274 | eq(other) {
|
1275 | return other instanceof LineDecoration && attrsEq(this.spec.attributes, other.spec.attributes);
|
1276 | }
|
1277 | range(from, to = from) {
|
1278 | if (to != from)
|
1279 | throw new RangeError("Line decoration ranges must be zero-length");
|
1280 | return super.range(from, to);
|
1281 | }
|
1282 | }
|
1283 | LineDecoration.prototype.mapMode = MapMode.TrackBefore;
|
1284 | LineDecoration.prototype.point = true;
|
1285 | class PointDecoration extends Decoration {
|
1286 | constructor(spec, startSide, endSide, block, widget, isReplace) {
|
1287 | super(startSide, endSide, widget, spec);
|
1288 | this.block = block;
|
1289 | this.isReplace = isReplace;
|
1290 | this.mapMode = !block ? MapMode.TrackDel : startSide <= 0 ? MapMode.TrackBefore : MapMode.TrackAfter;
|
1291 | }
|
1292 |
|
1293 | get type() {
|
1294 | return this.startSide < this.endSide ? BlockType.WidgetRange
|
1295 | : this.startSide <= 0 ? BlockType.WidgetBefore : BlockType.WidgetAfter;
|
1296 | }
|
1297 | get heightRelevant() { return this.block || !!this.widget && this.widget.estimatedHeight >= 5; }
|
1298 | eq(other) {
|
1299 | return other instanceof PointDecoration &&
|
1300 | widgetsEq(this.widget, other.widget) &&
|
1301 | this.block == other.block &&
|
1302 | this.startSide == other.startSide && this.endSide == other.endSide;
|
1303 | }
|
1304 | range(from, to = from) {
|
1305 | if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
|
1306 | throw new RangeError("Invalid range for replacement decoration");
|
1307 | if (!this.isReplace && to != from)
|
1308 | throw new RangeError("Widget decorations can only have zero-length ranges");
|
1309 | return super.range(from, to);
|
1310 | }
|
1311 | }
|
1312 | PointDecoration.prototype.point = true;
|
1313 | function getInclusive(spec, block = false) {
|
1314 | let { inclusiveStart: start, inclusiveEnd: end } = spec;
|
1315 | if (start == null)
|
1316 | start = spec.inclusive;
|
1317 | if (end == null)
|
1318 | end = spec.inclusive;
|
1319 | return { start: start !== null && start !== void 0 ? start : block, end: end !== null && end !== void 0 ? end : block };
|
1320 | }
|
1321 | function widgetsEq(a, b) {
|
1322 | return a == b || !!(a && b && a.compare(b));
|
1323 | }
|
1324 | function addRange(from, to, ranges, margin = 0) {
|
1325 | let last = ranges.length - 1;
|
1326 | if (last >= 0 && ranges[last] + margin >= from)
|
1327 | ranges[last] = Math.max(ranges[last], to);
|
1328 | else
|
1329 | ranges.push(from, to);
|
1330 | }
|
1331 |
|
1332 | class LineView extends ContentView {
|
1333 | constructor() {
|
1334 | super(...arguments);
|
1335 | this.children = [];
|
1336 | this.length = 0;
|
1337 | this.prevAttrs = undefined;
|
1338 | this.attrs = null;
|
1339 | this.breakAfter = 0;
|
1340 | }
|
1341 |
|
1342 | merge(from, to, source, hasStart, openStart, openEnd) {
|
1343 | if (source) {
|
1344 | if (!(source instanceof LineView))
|
1345 | return false;
|
1346 | if (!this.dom)
|
1347 | source.transferDOM(this);
|
1348 | }
|
1349 | if (hasStart)
|
1350 | this.setDeco(source ? source.attrs : null);
|
1351 | mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
|
1352 | return true;
|
1353 | }
|
1354 | split(at) {
|
1355 | let end = new LineView;
|
1356 | end.breakAfter = this.breakAfter;
|
1357 | if (this.length == 0)
|
1358 | return end;
|
1359 | let { i, off } = this.childPos(at);
|
1360 | if (off) {
|
1361 | end.append(this.children[i].split(off), 0);
|
1362 | this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
|
1363 | i++;
|
1364 | }
|
1365 | for (let j = i; j < this.children.length; j++)
|
1366 | end.append(this.children[j], 0);
|
1367 | while (i > 0 && this.children[i - 1].length == 0)
|
1368 | this.children[--i].destroy();
|
1369 | this.children.length = i;
|
1370 | this.markDirty();
|
1371 | this.length = at;
|
1372 | return end;
|
1373 | }
|
1374 | transferDOM(other) {
|
1375 | if (!this.dom)
|
1376 | return;
|
1377 | this.markDirty();
|
1378 | other.setDOM(this.dom);
|
1379 | other.prevAttrs = this.prevAttrs === undefined ? this.attrs : this.prevAttrs;
|
1380 | this.prevAttrs = undefined;
|
1381 | this.dom = null;
|
1382 | }
|
1383 | setDeco(attrs) {
|
1384 | if (!attrsEq(this.attrs, attrs)) {
|
1385 | if (this.dom) {
|
1386 | this.prevAttrs = this.attrs;
|
1387 | this.markDirty();
|
1388 | }
|
1389 | this.attrs = attrs;
|
1390 | }
|
1391 | }
|
1392 | append(child, openStart) {
|
1393 | joinInlineInto(this, child, openStart);
|
1394 | }
|
1395 |
|
1396 | addLineDeco(deco) {
|
1397 | let attrs = deco.spec.attributes, cls = deco.spec.class;
|
1398 | if (attrs)
|
1399 | this.attrs = combineAttrs(attrs, this.attrs || {});
|
1400 | if (cls)
|
1401 | this.attrs = combineAttrs({ class: cls }, this.attrs || {});
|
1402 | }
|
1403 | domAtPos(pos) {
|
1404 | return inlineDOMAtPos(this.dom, this.children, pos);
|
1405 | }
|
1406 | reuseDOM(node) {
|
1407 | if (node.nodeName == "DIV") {
|
1408 | this.setDOM(node);
|
1409 | this.dirty |= 4 | 2 ;
|
1410 | }
|
1411 | }
|
1412 | sync(track) {
|
1413 | var _a;
|
1414 | if (!this.dom) {
|
1415 | this.setDOM(document.createElement("div"));
|
1416 | this.dom.className = "cm-line";
|
1417 | this.prevAttrs = this.attrs ? null : undefined;
|
1418 | }
|
1419 | else if (this.dirty & 4 ) {
|
1420 | clearAttributes(this.dom);
|
1421 | this.dom.className = "cm-line";
|
1422 | this.prevAttrs = this.attrs ? null : undefined;
|
1423 | }
|
1424 | if (this.prevAttrs !== undefined) {
|
1425 | updateAttrs(this.dom, this.prevAttrs, this.attrs);
|
1426 | this.dom.classList.add("cm-line");
|
1427 | this.prevAttrs = undefined;
|
1428 | }
|
1429 | super.sync(track);
|
1430 | let last = this.dom.lastChild;
|
1431 | while (last && ContentView.get(last) instanceof MarkView)
|
1432 | last = last.lastChild;
|
1433 | if (!last || !this.length ||
|
1434 | last.nodeName != "BR" && ((_a = ContentView.get(last)) === null || _a === void 0 ? void 0 : _a.isEditable) == false &&
|
1435 | (!browser.ios || !this.children.some(ch => ch instanceof TextView))) {
|
1436 | let hack = document.createElement("BR");
|
1437 | hack.cmIgnore = true;
|
1438 | this.dom.appendChild(hack);
|
1439 | }
|
1440 | }
|
1441 | measureTextSize() {
|
1442 | if (this.children.length == 0 || this.length > 20)
|
1443 | return null;
|
1444 | let totalWidth = 0;
|
1445 | for (let child of this.children) {
|
1446 | if (!(child instanceof TextView))
|
1447 | return null;
|
1448 | let rects = clientRectsFor(child.dom);
|
1449 | if (rects.length != 1)
|
1450 | return null;
|
1451 | totalWidth += rects[0].width;
|
1452 | }
|
1453 | return { lineHeight: this.dom.getBoundingClientRect().height,
|
1454 | charWidth: totalWidth / this.length };
|
1455 | }
|
1456 | coordsAt(pos, side) {
|
1457 | return coordsInChildren(this, pos, side);
|
1458 | }
|
1459 | become(_other) { return false; }
|
1460 | get type() { return BlockType.Text; }
|
1461 | static find(docView, pos) {
|
1462 | for (let i = 0, off = 0; i < docView.children.length; i++) {
|
1463 | let block = docView.children[i], end = off + block.length;
|
1464 | if (end >= pos) {
|
1465 | if (block instanceof LineView)
|
1466 | return block;
|
1467 | if (end > pos)
|
1468 | break;
|
1469 | }
|
1470 | off = end + block.breakAfter;
|
1471 | }
|
1472 | return null;
|
1473 | }
|
1474 | }
|
1475 | class BlockWidgetView extends ContentView {
|
1476 | constructor(widget, length, type) {
|
1477 | super();
|
1478 | this.widget = widget;
|
1479 | this.length = length;
|
1480 | this.type = type;
|
1481 | this.breakAfter = 0;
|
1482 | this.prevWidget = null;
|
1483 | }
|
1484 | merge(from, to, source, _takeDeco, openStart, openEnd) {
|
1485 | if (source && (!(source instanceof BlockWidgetView) || !this.widget.compare(source.widget) ||
|
1486 | from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
|
1487 | return false;
|
1488 | this.length = from + (source ? source.length : 0) + (this.length - to);
|
1489 | return true;
|
1490 | }
|
1491 | domAtPos(pos) {
|
1492 | return pos == 0 ? DOMPos.before(this.dom) : DOMPos.after(this.dom, pos == this.length);
|
1493 | }
|
1494 | split(at) {
|
1495 | let len = this.length - at;
|
1496 | this.length = at;
|
1497 | let end = new BlockWidgetView(this.widget, len, this.type);
|
1498 | end.breakAfter = this.breakAfter;
|
1499 | return end;
|
1500 | }
|
1501 | get children() { return noChildren; }
|
1502 | sync() {
|
1503 | if (!this.dom || !this.widget.updateDOM(this.dom)) {
|
1504 | if (this.dom && this.prevWidget)
|
1505 | this.prevWidget.destroy(this.dom);
|
1506 | this.prevWidget = null;
|
1507 | this.setDOM(this.widget.toDOM(this.editorView));
|
1508 | this.dom.contentEditable = "false";
|
1509 | }
|
1510 | }
|
1511 | get overrideDOMText() {
|
1512 | return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : Text.empty;
|
1513 | }
|
1514 | domBoundsAround() { return null; }
|
1515 | become(other) {
|
1516 | if (other instanceof BlockWidgetView && other.type == this.type &&
|
1517 | other.widget.constructor == this.widget.constructor) {
|
1518 | if (!other.widget.eq(this.widget))
|
1519 | this.markDirty(true);
|
1520 | if (this.dom && !this.prevWidget)
|
1521 | this.prevWidget = this.widget;
|
1522 | this.widget = other.widget;
|
1523 | this.length = other.length;
|
1524 | this.breakAfter = other.breakAfter;
|
1525 | return true;
|
1526 | }
|
1527 | return false;
|
1528 | }
|
1529 | ignoreMutation() { return true; }
|
1530 | ignoreEvent(event) { return this.widget.ignoreEvent(event); }
|
1531 | destroy() {
|
1532 | super.destroy();
|
1533 | if (this.dom)
|
1534 | this.widget.destroy(this.dom);
|
1535 | }
|
1536 | }
|
1537 |
|
1538 | class ContentBuilder {
|
1539 | constructor(doc, pos, end, disallowBlockEffectsFor) {
|
1540 | this.doc = doc;
|
1541 | this.pos = pos;
|
1542 | this.end = end;
|
1543 | this.disallowBlockEffectsFor = disallowBlockEffectsFor;
|
1544 | this.content = [];
|
1545 | this.curLine = null;
|
1546 | this.breakAtStart = 0;
|
1547 | this.pendingBuffer = 0 ;
|
1548 |
|
1549 | this.atCursorPos = true;
|
1550 | this.openStart = -1;
|
1551 | this.openEnd = -1;
|
1552 | this.text = "";
|
1553 | this.textOff = 0;
|
1554 | this.cursor = doc.iter();
|
1555 | this.skip = pos;
|
1556 | }
|
1557 | posCovered() {
|
1558 | if (this.content.length == 0)
|
1559 | return !this.breakAtStart && this.doc.lineAt(this.pos).from != this.pos;
|
1560 | let last = this.content[this.content.length - 1];
|
1561 | return !last.breakAfter && !(last instanceof BlockWidgetView && last.type == BlockType.WidgetBefore);
|
1562 | }
|
1563 | getLine() {
|
1564 | if (!this.curLine) {
|
1565 | this.content.push(this.curLine = new LineView);
|
1566 | this.atCursorPos = true;
|
1567 | }
|
1568 | return this.curLine;
|
1569 | }
|
1570 | flushBuffer(active) {
|
1571 | if (this.pendingBuffer) {
|
1572 | this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
|
1573 | this.pendingBuffer = 0 ;
|
1574 | }
|
1575 | }
|
1576 | addBlockWidget(view) {
|
1577 | this.flushBuffer([]);
|
1578 | this.curLine = null;
|
1579 | this.content.push(view);
|
1580 | }
|
1581 | finish(openEnd) {
|
1582 | if (!openEnd)
|
1583 | this.flushBuffer([]);
|
1584 | else
|
1585 | this.pendingBuffer = 0 ;
|
1586 | if (!this.posCovered())
|
1587 | this.getLine();
|
1588 | }
|
1589 | buildText(length, active, openStart) {
|
1590 | while (length > 0) {
|
1591 | if (this.textOff == this.text.length) {
|
1592 | let { value, lineBreak, done } = this.cursor.next(this.skip);
|
1593 | this.skip = 0;
|
1594 | if (done)
|
1595 | throw new Error("Ran out of text content when drawing inline views");
|
1596 | if (lineBreak) {
|
1597 | if (!this.posCovered())
|
1598 | this.getLine();
|
1599 | if (this.content.length)
|
1600 | this.content[this.content.length - 1].breakAfter = 1;
|
1601 | else
|
1602 | this.breakAtStart = 1;
|
1603 | this.flushBuffer([]);
|
1604 | this.curLine = null;
|
1605 | length--;
|
1606 | continue;
|
1607 | }
|
1608 | else {
|
1609 | this.text = value;
|
1610 | this.textOff = 0;
|
1611 | }
|
1612 | }
|
1613 | let take = Math.min(this.text.length - this.textOff, length, 512 );
|
1614 | this.flushBuffer(active.slice(0, openStart));
|
1615 | this.getLine().append(wrapMarks(new TextView(this.text.slice(this.textOff, this.textOff + take)), active), openStart);
|
1616 | this.atCursorPos = true;
|
1617 | this.textOff += take;
|
1618 | length -= take;
|
1619 | openStart = 0;
|
1620 | }
|
1621 | }
|
1622 | span(from, to, active, openStart) {
|
1623 | this.buildText(to - from, active, openStart);
|
1624 | this.pos = to;
|
1625 | if (this.openStart < 0)
|
1626 | this.openStart = openStart;
|
1627 | }
|
1628 | point(from, to, deco, active, openStart, index) {
|
1629 | if (this.disallowBlockEffectsFor[index] && deco instanceof PointDecoration) {
|
1630 | if (deco.block)
|
1631 | throw new RangeError("Block decorations may not be specified via plugins");
|
1632 | if (to > this.doc.lineAt(this.pos).to)
|
1633 | throw new RangeError("Decorations that replace line breaks may not be specified via plugins");
|
1634 | }
|
1635 | let len = to - from;
|
1636 | if (deco instanceof PointDecoration) {
|
1637 | if (deco.block) {
|
1638 | let { type } = deco;
|
1639 | if (type == BlockType.WidgetAfter && !this.posCovered())
|
1640 | this.getLine();
|
1641 | this.addBlockWidget(new BlockWidgetView(deco.widget || new NullWidget("div"), len, type));
|
1642 | }
|
1643 | else {
|
1644 | let view = WidgetView.create(deco.widget || new NullWidget("span"), len, deco.startSide);
|
1645 | let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
|
1646 | let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
|
1647 | let line = this.getLine();
|
1648 | if (this.pendingBuffer == 2 && !cursorBefore)
|
1649 | this.pendingBuffer = 0 ;
|
1650 | this.flushBuffer(active);
|
1651 | if (cursorBefore) {
|
1652 | line.append(wrapMarks(new WidgetBufferView(1), active), openStart);
|
1653 | openStart = active.length + Math.max(0, openStart - active.length);
|
1654 | }
|
1655 | line.append(wrapMarks(view, active), openStart);
|
1656 | this.atCursorPos = cursorAfter;
|
1657 | this.pendingBuffer = !cursorAfter ? 0 : from < to ? 1 : 2 ;
|
1658 | }
|
1659 | }
|
1660 | else if (this.doc.lineAt(this.pos).from == this.pos) {
|
1661 | this.getLine().addLineDeco(deco);
|
1662 | }
|
1663 | if (len) {
|
1664 |
|
1665 | if (this.textOff + len <= this.text.length) {
|
1666 | this.textOff += len;
|
1667 | }
|
1668 | else {
|
1669 | this.skip += len - (this.text.length - this.textOff);
|
1670 | this.text = "";
|
1671 | this.textOff = 0;
|
1672 | }
|
1673 | this.pos = to;
|
1674 | }
|
1675 | if (this.openStart < 0)
|
1676 | this.openStart = openStart;
|
1677 | }
|
1678 | static build(text, from, to, decorations, dynamicDecorationMap) {
|
1679 | let builder = new ContentBuilder(text, from, to, dynamicDecorationMap);
|
1680 | builder.openEnd = RangeSet.spans(decorations, from, to, builder);
|
1681 | if (builder.openStart < 0)
|
1682 | builder.openStart = builder.openEnd;
|
1683 | builder.finish(builder.openEnd);
|
1684 | return builder;
|
1685 | }
|
1686 | }
|
1687 | function wrapMarks(view, active) {
|
1688 | for (let mark of active)
|
1689 | view = new MarkView(mark, [view], view.length);
|
1690 | return view;
|
1691 | }
|
1692 | class NullWidget extends WidgetType {
|
1693 | constructor(tag) {
|
1694 | super();
|
1695 | this.tag = tag;
|
1696 | }
|
1697 | eq(other) { return other.tag == this.tag; }
|
1698 | toDOM() { return document.createElement(this.tag); }
|
1699 | updateDOM(elt) { return elt.nodeName.toLowerCase() == this.tag; }
|
1700 | }
|
1701 |
|
1702 | const clickAddsSelectionRange = Facet.define();
|
1703 | const dragMovesSelection$1 = Facet.define();
|
1704 | const mouseSelectionStyle = Facet.define();
|
1705 | const exceptionSink = Facet.define();
|
1706 | const updateListener = Facet.define();
|
1707 | const inputHandler = Facet.define();
|
1708 | const perLineTextDirection = Facet.define({
|
1709 | combine: values => values.some(x => x)
|
1710 | });
|
1711 | class ScrollTarget {
|
1712 | constructor(range, y = "nearest", x = "nearest", yMargin = 5, xMargin = 5) {
|
1713 | this.range = range;
|
1714 | this.y = y;
|
1715 | this.x = x;
|
1716 | this.yMargin = yMargin;
|
1717 | this.xMargin = xMargin;
|
1718 | }
|
1719 | map(changes) {
|
1720 | return changes.empty ? this : new ScrollTarget(this.range.map(changes), this.y, this.x, this.yMargin, this.xMargin);
|
1721 | }
|
1722 | }
|
1723 | const scrollIntoView = StateEffect.define({ map: (t, ch) => t.map(ch) });
|
1724 |
|
1725 |
|
1726 |
|
1727 |
|
1728 |
|
1729 |
|
1730 |
|
1731 |
|
1732 |
|
1733 |
|
1734 |
|
1735 |
|
1736 | function logException(state, exception, context) {
|
1737 | let handler = state.facet(exceptionSink);
|
1738 | if (handler.length)
|
1739 | handler[0](exception);
|
1740 | else if (window.onerror)
|
1741 | window.onerror(String(exception), context, undefined, undefined, exception);
|
1742 | else if (context)
|
1743 | console.error(context + ":", exception);
|
1744 | else
|
1745 | console.error(exception);
|
1746 | }
|
1747 | const editable = Facet.define({ combine: values => values.length ? values[0] : true });
|
1748 | let nextPluginID = 0;
|
1749 | const viewPlugin = Facet.define();
|
1750 |
|
1751 |
|
1752 |
|
1753 |
|
1754 |
|
1755 | class ViewPlugin {
|
1756 | constructor(
|
1757 | /**
|
1758 | @internal
|
1759 | */
|
1760 | id,
|
1761 | /**
|
1762 | @internal
|
1763 | */
|
1764 | create,
|
1765 | /**
|
1766 | @internal
|
1767 | */
|
1768 | domEventHandlers, buildExtensions) {
|
1769 | this.id = id;
|
1770 | this.create = create;
|
1771 | this.domEventHandlers = domEventHandlers;
|
1772 | this.extension = buildExtensions(this);
|
1773 | }
|
1774 | |
1775 |
|
1776 |
|
1777 |
|
1778 | static define(create, spec) {
|
1779 | const { eventHandlers, provide, decorations: deco } = spec || {};
|
1780 | return new ViewPlugin(nextPluginID++, create, eventHandlers, plugin => {
|
1781 | let ext = [viewPlugin.of(plugin)];
|
1782 | if (deco)
|
1783 | ext.push(decorations.of(view => {
|
1784 | let pluginInst = view.plugin(plugin);
|
1785 | return pluginInst ? deco(pluginInst) : Decoration.none;
|
1786 | }));
|
1787 | if (provide)
|
1788 | ext.push(provide(plugin));
|
1789 | return ext;
|
1790 | });
|
1791 | }
|
1792 | |
1793 |
|
1794 |
|
1795 |
|
1796 | static fromClass(cls, spec) {
|
1797 | return ViewPlugin.define(view => new cls(view), spec);
|
1798 | }
|
1799 | }
|
1800 | class PluginInstance {
|
1801 | constructor(spec) {
|
1802 | this.spec = spec;
|
1803 |
|
1804 |
|
1805 |
|
1806 |
|
1807 | this.mustUpdate = null;
|
1808 |
|
1809 |
|
1810 | this.value = null;
|
1811 | }
|
1812 | update(view) {
|
1813 | if (!this.value) {
|
1814 | if (this.spec) {
|
1815 | try {
|
1816 | this.value = this.spec.create(view);
|
1817 | }
|
1818 | catch (e) {
|
1819 | logException(view.state, e, "CodeMirror plugin crashed");
|
1820 | this.deactivate();
|
1821 | }
|
1822 | }
|
1823 | }
|
1824 | else if (this.mustUpdate) {
|
1825 | let update = this.mustUpdate;
|
1826 | this.mustUpdate = null;
|
1827 | if (this.value.update) {
|
1828 | try {
|
1829 | this.value.update(update);
|
1830 | }
|
1831 | catch (e) {
|
1832 | logException(update.state, e, "CodeMirror plugin crashed");
|
1833 | if (this.value.destroy)
|
1834 | try {
|
1835 | this.value.destroy();
|
1836 | }
|
1837 | catch (_) { }
|
1838 | this.deactivate();
|
1839 | }
|
1840 | }
|
1841 | }
|
1842 | return this;
|
1843 | }
|
1844 | destroy(view) {
|
1845 | var _a;
|
1846 | if ((_a = this.value) === null || _a === void 0 ? void 0 : _a.destroy) {
|
1847 | try {
|
1848 | this.value.destroy();
|
1849 | }
|
1850 | catch (e) {
|
1851 | logException(view.state, e, "CodeMirror plugin crashed");
|
1852 | }
|
1853 | }
|
1854 | }
|
1855 | deactivate() {
|
1856 | this.spec = this.value = null;
|
1857 | }
|
1858 | }
|
1859 | const editorAttributes = Facet.define();
|
1860 | const contentAttributes = Facet.define();
|
1861 |
|
1862 | const decorations = Facet.define();
|
1863 | const atomicRanges = Facet.define();
|
1864 | const scrollMargins = Facet.define();
|
1865 | const styleModule = Facet.define();
|
1866 | class ChangedRange {
|
1867 | constructor(fromA, toA, fromB, toB) {
|
1868 | this.fromA = fromA;
|
1869 | this.toA = toA;
|
1870 | this.fromB = fromB;
|
1871 | this.toB = toB;
|
1872 | }
|
1873 | join(other) {
|
1874 | 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));
|
1875 | }
|
1876 | addToSet(set) {
|
1877 | let i = set.length, me = this;
|
1878 | for (; i > 0; i--) {
|
1879 | let range = set[i - 1];
|
1880 | if (range.fromA > me.toA)
|
1881 | continue;
|
1882 | if (range.toA < me.fromA)
|
1883 | break;
|
1884 | me = me.join(range);
|
1885 | set.splice(i - 1, 1);
|
1886 | }
|
1887 | set.splice(i, 0, me);
|
1888 | return set;
|
1889 | }
|
1890 | static extendWithRanges(diff, ranges) {
|
1891 | if (ranges.length == 0)
|
1892 | return diff;
|
1893 | let result = [];
|
1894 | for (let dI = 0, rI = 0, posA = 0, posB = 0;; dI++) {
|
1895 | let next = dI == diff.length ? null : diff[dI], off = posA - posB;
|
1896 | let end = next ? next.fromB : 1e9;
|
1897 | while (rI < ranges.length && ranges[rI] < end) {
|
1898 | let from = ranges[rI], to = ranges[rI + 1];
|
1899 | let fromB = Math.max(posB, from), toB = Math.min(end, to);
|
1900 | if (fromB <= toB)
|
1901 | new ChangedRange(fromB + off, toB + off, fromB, toB).addToSet(result);
|
1902 | if (to > end)
|
1903 | break;
|
1904 | else
|
1905 | rI += 2;
|
1906 | }
|
1907 | if (!next)
|
1908 | return result;
|
1909 | new ChangedRange(next.fromA, next.toA, next.fromB, next.toB).addToSet(result);
|
1910 | posA = next.toA;
|
1911 | posB = next.toB;
|
1912 | }
|
1913 | }
|
1914 | }
|
1915 |
|
1916 |
|
1917 |
|
1918 |
|
1919 | class ViewUpdate {
|
1920 | constructor(
|
1921 | /**
|
1922 | The editor view that the update is associated with.
|
1923 | */
|
1924 | view,
|
1925 | /**
|
1926 | The new editor state.
|
1927 | */
|
1928 | state,
|
1929 | /**
|
1930 | The transactions involved in the update. May be empty.
|
1931 | */
|
1932 | transactions) {
|
1933 | this.view = view;
|
1934 | this.state = state;
|
1935 | this.transactions = transactions;
|
1936 | |
1937 |
|
1938 |
|
1939 | this.flags = 0;
|
1940 | this.startState = view.state;
|
1941 | this.changes = ChangeSet.empty(this.startState.doc.length);
|
1942 | for (let tr of transactions)
|
1943 | this.changes = this.changes.compose(tr.changes);
|
1944 | let changedRanges = [];
|
1945 | this.changes.iterChangedRanges((fromA, toA, fromB, toB) => changedRanges.push(new ChangedRange(fromA, toA, fromB, toB)));
|
1946 | this.changedRanges = changedRanges;
|
1947 | let focus = view.hasFocus;
|
1948 | if (focus != view.inputState.notifiedFocused) {
|
1949 | view.inputState.notifiedFocused = focus;
|
1950 | this.flags |= 1 ;
|
1951 | }
|
1952 | }
|
1953 | |
1954 |
|
1955 |
|
1956 | static create(view, state, transactions) {
|
1957 | return new ViewUpdate(view, state, transactions);
|
1958 | }
|
1959 | |
1960 |
|
1961 |
|
1962 |
|
1963 |
|
1964 | get viewportChanged() {
|
1965 | return (this.flags & 4 ) > 0;
|
1966 | }
|
1967 | |
1968 |
|
1969 |
|
1970 |
|
1971 | get heightChanged() {
|
1972 | return (this.flags & 2 ) > 0;
|
1973 | }
|
1974 | |
1975 |
|
1976 |
|
1977 |
|
1978 | get geometryChanged() {
|
1979 | return this.docChanged || (this.flags & (8 | 2 )) > 0;
|
1980 | }
|
1981 | |
1982 |
|
1983 |
|
1984 | get focusChanged() {
|
1985 | return (this.flags & 1 ) > 0;
|
1986 | }
|
1987 | |
1988 |
|
1989 |
|
1990 | get docChanged() {
|
1991 | return !this.changes.empty;
|
1992 | }
|
1993 | |
1994 |
|
1995 |
|
1996 | get selectionSet() {
|
1997 | return this.transactions.some(tr => tr.selection);
|
1998 | }
|
1999 | |
2000 |
|
2001 |
|
2002 | get empty() { return this.flags == 0 && this.transactions.length == 0; }
|
2003 | }
|
2004 |
|
2005 |
|
2006 |
|
2007 |
|
2008 | var Direction = (function (Direction) {
|
2009 |
|
2010 |
|
2011 | |
2012 |
|
2013 |
|
2014 | Direction[Direction["LTR"] = 0] = "LTR";
|
2015 | |
2016 |
|
2017 |
|
2018 | Direction[Direction["RTL"] = 1] = "RTL";
|
2019 | return Direction})(Direction || (Direction = {}));
|
2020 | const LTR = Direction.LTR, RTL = Direction.RTL;
|
2021 |
|
2022 | function dec(str) {
|
2023 | let result = [];
|
2024 | for (let i = 0; i < str.length; i++)
|
2025 | result.push(1 << +str[i]);
|
2026 | return result;
|
2027 | }
|
2028 |
|
2029 | const LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
|
2030 |
|
2031 | const ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
|
2032 | const Brackets = Object.create(null), BracketStack = [];
|
2033 |
|
2034 |
|
2035 |
|
2036 | for (let p of ["()", "[]", "{}"]) {
|
2037 | let l = p.charCodeAt(0), r = p.charCodeAt(1);
|
2038 | Brackets[l] = r;
|
2039 | Brackets[r] = -l;
|
2040 | }
|
2041 | function charType(ch) {
|
2042 | return ch <= 0xf7 ? LowTypes[ch] :
|
2043 | 0x590 <= ch && ch <= 0x5f4 ? 2 :
|
2044 | 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] :
|
2045 | 0x6ee <= ch && ch <= 0x8ac ? 4 :
|
2046 | 0x2000 <= ch && ch <= 0x200b ? 256 :
|
2047 | ch == 0x200c ? 256 : 1 ;
|
2048 | }
|
2049 | const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
|
2050 |
|
2051 |
|
2052 |
|
2053 |
|
2054 | class BidiSpan {
|
2055 | |
2056 |
|
2057 |
|
2058 | constructor(
|
2059 | /**
|
2060 | The start of the span (relative to the start of the line).
|
2061 | */
|
2062 | from,
|
2063 | /**
|
2064 | The end of the span.
|
2065 | */
|
2066 | to,
|
2067 | /**
|
2068 | The ["bidi
|
2069 | level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm)
|
2070 | of the span (in this context, 0 means
|
2071 | left-to-right, 1 means right-to-left, 2 means left-to-right
|
2072 | number inside right-to-left text).
|
2073 | */
|
2074 | level) {
|
2075 | this.from = from;
|
2076 | this.to = to;
|
2077 | this.level = level;
|
2078 | }
|
2079 | |
2080 |
|
2081 |
|
2082 | get dir() { return this.level % 2 ? RTL : LTR; }
|
2083 | |
2084 |
|
2085 |
|
2086 | side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; }
|
2087 | |
2088 |
|
2089 |
|
2090 | static find(order, index, level, assoc) {
|
2091 | let maybe = -1;
|
2092 | for (let i = 0; i < order.length; i++) {
|
2093 | let span = order[i];
|
2094 | if (span.from <= index && span.to >= index) {
|
2095 | if (span.level == level)
|
2096 | return i;
|
2097 |
|
2098 |
|
2099 |
|
2100 | if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level))
|
2101 | maybe = i;
|
2102 | }
|
2103 | }
|
2104 | if (maybe < 0)
|
2105 | throw new RangeError("Index out of range");
|
2106 | return maybe;
|
2107 | }
|
2108 | }
|
2109 |
|
2110 | const types = [];
|
2111 | function computeOrder(line, direction) {
|
2112 | let len = line.length, outerType = direction == LTR ? 1 : 2 , oppositeType = direction == LTR ? 2 : 1 ;
|
2113 | if (!line || outerType == 1 && !BidiRE.test(line))
|
2114 | return trivialOrder(len);
|
2115 |
|
2116 |
|
2117 |
|
2118 |
|
2119 |
|
2120 |
|
2121 |
|
2122 |
|
2123 |
|
2124 |
|
2125 | for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
|
2126 | let type = charType(line.charCodeAt(i));
|
2127 | if (type == 512 )
|
2128 | type = prev;
|
2129 | else if (type == 8 && prevStrong == 4 )
|
2130 | type = 16 ;
|
2131 | types[i] = type == 4 ? 2 : type;
|
2132 | if (type & 7 )
|
2133 | prevStrong = type;
|
2134 | prev = type;
|
2135 | }
|
2136 |
|
2137 |
|
2138 |
|
2139 |
|
2140 |
|
2141 |
|
2142 |
|
2143 |
|
2144 | for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
|
2145 | let type = types[i];
|
2146 | if (type == 128 ) {
|
2147 | if (i < len - 1 && prev == types[i + 1] && (prev & 24 ))
|
2148 | type = types[i] = prev;
|
2149 | else
|
2150 | types[i] = 256 ;
|
2151 | }
|
2152 | else if (type == 64 ) {
|
2153 | let end = i + 1;
|
2154 | while (end < len && types[end] == 64 )
|
2155 | end++;
|
2156 | let replace = (i && prev == 8 ) || (end < len && types[end] == 8 ) ? (prevStrong == 1 ? 1 : 8 ) : 256 ;
|
2157 | for (let j = i; j < end; j++)
|
2158 | types[j] = replace;
|
2159 | i = end - 1;
|
2160 | }
|
2161 | else if (type == 8 && prevStrong == 1 ) {
|
2162 | types[i] = 1 ;
|
2163 | }
|
2164 | prev = type;
|
2165 | if (type & 7 )
|
2166 | prevStrong = type;
|
2167 | }
|
2168 |
|
2169 |
|
2170 |
|
2171 |
|
2172 | for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) {
|
2173 |
|
2174 |
|
2175 | if (br = Brackets[ch = line.charCodeAt(i)]) {
|
2176 | if (br < 0) {
|
2177 | for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
|
2178 | if (BracketStack[sJ + 1] == -br) {
|
2179 | let flags = BracketStack[sJ + 2];
|
2180 | let type = (flags & 2 ) ? outerType :
|
2181 | !(flags & 4 ) ? 0 :
|
2182 | (flags & 1 ) ? oppositeType : outerType;
|
2183 | if (type)
|
2184 | types[i] = types[BracketStack[sJ]] = type;
|
2185 | sI = sJ;
|
2186 | break;
|
2187 | }
|
2188 | }
|
2189 | }
|
2190 | else if (BracketStack.length == 189 ) {
|
2191 | break;
|
2192 | }
|
2193 | else {
|
2194 | BracketStack[sI++] = i;
|
2195 | BracketStack[sI++] = ch;
|
2196 | BracketStack[sI++] = context;
|
2197 | }
|
2198 | }
|
2199 | else if ((type = types[i]) == 2 || type == 1 ) {
|
2200 | let embed = type == outerType;
|
2201 | context = embed ? 0 : 1 ;
|
2202 | for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
|
2203 | let cur = BracketStack[sJ + 2];
|
2204 | if (cur & 2 )
|
2205 | break;
|
2206 | if (embed) {
|
2207 | BracketStack[sJ + 2] |= 2 ;
|
2208 | }
|
2209 | else {
|
2210 | if (cur & 4 )
|
2211 | break;
|
2212 | BracketStack[sJ + 2] |= 4 ;
|
2213 | }
|
2214 | }
|
2215 | }
|
2216 | }
|
2217 |
|
2218 |
|
2219 |
|
2220 |
|
2221 |
|
2222 |
|
2223 |
|
2224 | for (let i = 0; i < len; i++) {
|
2225 | if (types[i] == 256 ) {
|
2226 | let end = i + 1;
|
2227 | while (end < len && types[end] == 256 )
|
2228 | end++;
|
2229 | let beforeL = (i ? types[i - 1] : outerType) == 1 ;
|
2230 | let afterL = (end < len ? types[end] : outerType) == 1 ;
|
2231 | let replace = beforeL == afterL ? (beforeL ? 1 : 2 ) : outerType;
|
2232 | for (let j = i; j < end; j++)
|
2233 | types[j] = replace;
|
2234 | i = end - 1;
|
2235 | }
|
2236 | }
|
2237 |
|
2238 |
|
2239 |
|
2240 |
|
2241 |
|
2242 | let order = [];
|
2243 | if (outerType == 1 ) {
|
2244 | for (let i = 0; i < len;) {
|
2245 | let start = i, rtl = types[i++] != 1 ;
|
2246 | while (i < len && rtl == (types[i] != 1 ))
|
2247 | i++;
|
2248 | if (rtl) {
|
2249 | for (let j = i; j > start;) {
|
2250 | let end = j, l = types[--j] != 2 ;
|
2251 | while (j > start && l == (types[j - 1] != 2 ))
|
2252 | j--;
|
2253 | order.push(new BidiSpan(j, end, l ? 2 : 1));
|
2254 | }
|
2255 | }
|
2256 | else {
|
2257 | order.push(new BidiSpan(start, i, 0));
|
2258 | }
|
2259 | }
|
2260 | }
|
2261 | else {
|
2262 | for (let i = 0; i < len;) {
|
2263 | let start = i, rtl = types[i++] == 2 ;
|
2264 | while (i < len && rtl == (types[i] == 2 ))
|
2265 | i++;
|
2266 | order.push(new BidiSpan(start, i, rtl ? 1 : 2));
|
2267 | }
|
2268 | }
|
2269 | return order;
|
2270 | }
|
2271 | function trivialOrder(length) {
|
2272 | return [new BidiSpan(0, length, 0)];
|
2273 | }
|
2274 | let movedOver = "";
|
2275 | function moveVisually(line, order, dir, start, forward) {
|
2276 | var _a;
|
2277 | let startIndex = start.head - line.from, spanI = -1;
|
2278 | if (startIndex == 0) {
|
2279 | if (!forward || !line.length)
|
2280 | return null;
|
2281 | if (order[0].level != dir) {
|
2282 | startIndex = order[0].side(false, dir);
|
2283 | spanI = 0;
|
2284 | }
|
2285 | }
|
2286 | else if (startIndex == line.length) {
|
2287 | if (forward)
|
2288 | return null;
|
2289 | let last = order[order.length - 1];
|
2290 | if (last.level != dir) {
|
2291 | startIndex = last.side(true, dir);
|
2292 | spanI = order.length - 1;
|
2293 | }
|
2294 | }
|
2295 | if (spanI < 0)
|
2296 | spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
|
2297 | let span = order[spanI];
|
2298 |
|
2299 | if (startIndex == span.side(forward, dir)) {
|
2300 | span = order[spanI += forward ? 1 : -1];
|
2301 | startIndex = span.side(!forward, dir);
|
2302 | }
|
2303 | let indexForward = forward == (span.dir == dir);
|
2304 | let nextIndex = findClusterBreak(line.text, startIndex, indexForward);
|
2305 | movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
|
2306 | if (nextIndex != span.side(forward, dir))
|
2307 | return EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
|
2308 | let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
|
2309 | if (!nextSpan && span.level != dir)
|
2310 | return EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir);
|
2311 | if (nextSpan && nextSpan.level < span.level)
|
2312 | return EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level);
|
2313 | return EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
|
2314 | }
|
2315 |
|
2316 | const LineBreakPlaceholder = "\uffff";
|
2317 | class DOMReader {
|
2318 | constructor(points, state) {
|
2319 | this.points = points;
|
2320 | this.text = "";
|
2321 | this.lineSeparator = state.facet(EditorState.lineSeparator);
|
2322 | }
|
2323 | append(text) {
|
2324 | this.text += text;
|
2325 | }
|
2326 | lineBreak() {
|
2327 | this.text += LineBreakPlaceholder;
|
2328 | }
|
2329 | readRange(start, end) {
|
2330 | if (!start)
|
2331 | return this;
|
2332 | let parent = start.parentNode;
|
2333 | for (let cur = start;;) {
|
2334 | this.findPointBefore(parent, cur);
|
2335 | this.readNode(cur);
|
2336 | let next = cur.nextSibling;
|
2337 | if (next == end)
|
2338 | break;
|
2339 | let view = ContentView.get(cur), nextView = ContentView.get(next);
|
2340 | if (view && nextView ? view.breakAfter :
|
2341 | (view ? view.breakAfter : isBlockElement(cur)) ||
|
2342 | (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
|
2343 | this.lineBreak();
|
2344 | cur = next;
|
2345 | }
|
2346 | this.findPointBefore(parent, end);
|
2347 | return this;
|
2348 | }
|
2349 | readTextNode(node) {
|
2350 | let text = node.nodeValue;
|
2351 | for (let point of this.points)
|
2352 | if (point.node == node)
|
2353 | point.pos = this.text.length + Math.min(point.offset, text.length);
|
2354 | for (let off = 0, re = this.lineSeparator ? null : /\r\n?|\n/g;;) {
|
2355 | let nextBreak = -1, breakSize = 1, m;
|
2356 | if (this.lineSeparator) {
|
2357 | nextBreak = text.indexOf(this.lineSeparator, off);
|
2358 | breakSize = this.lineSeparator.length;
|
2359 | }
|
2360 | else if (m = re.exec(text)) {
|
2361 | nextBreak = m.index;
|
2362 | breakSize = m[0].length;
|
2363 | }
|
2364 | this.append(text.slice(off, nextBreak < 0 ? text.length : nextBreak));
|
2365 | if (nextBreak < 0)
|
2366 | break;
|
2367 | this.lineBreak();
|
2368 | if (breakSize > 1)
|
2369 | for (let point of this.points)
|
2370 | if (point.node == node && point.pos > this.text.length)
|
2371 | point.pos -= breakSize - 1;
|
2372 | off = nextBreak + breakSize;
|
2373 | }
|
2374 | }
|
2375 | readNode(node) {
|
2376 | if (node.cmIgnore)
|
2377 | return;
|
2378 | let view = ContentView.get(node);
|
2379 | let fromView = view && view.overrideDOMText;
|
2380 | if (fromView != null) {
|
2381 | this.findPointInside(node, fromView.length);
|
2382 | for (let i = fromView.iter(); !i.next().done;) {
|
2383 | if (i.lineBreak)
|
2384 | this.lineBreak();
|
2385 | else
|
2386 | this.append(i.value);
|
2387 | }
|
2388 | }
|
2389 | else if (node.nodeType == 3) {
|
2390 | this.readTextNode(node);
|
2391 | }
|
2392 | else if (node.nodeName == "BR") {
|
2393 | if (node.nextSibling)
|
2394 | this.lineBreak();
|
2395 | }
|
2396 | else if (node.nodeType == 1) {
|
2397 | this.readRange(node.firstChild, null);
|
2398 | }
|
2399 | }
|
2400 | findPointBefore(node, next) {
|
2401 | for (let point of this.points)
|
2402 | if (point.node == node && node.childNodes[point.offset] == next)
|
2403 | point.pos = this.text.length;
|
2404 | }
|
2405 | findPointInside(node, maxLen) {
|
2406 | for (let point of this.points)
|
2407 | if (node.nodeType == 3 ? point.node == node : node.contains(point.node))
|
2408 | point.pos = this.text.length + Math.min(maxLen, point.offset);
|
2409 | }
|
2410 | }
|
2411 | function isBlockElement(node) {
|
2412 | return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
|
2413 | }
|
2414 | class DOMPoint {
|
2415 | constructor(node, offset) {
|
2416 | this.node = node;
|
2417 | this.offset = offset;
|
2418 | this.pos = -1;
|
2419 | }
|
2420 | }
|
2421 |
|
2422 | class DocView extends ContentView {
|
2423 | constructor(view) {
|
2424 | super();
|
2425 | this.view = view;
|
2426 | this.compositionDeco = Decoration.none;
|
2427 | this.decorations = [];
|
2428 | this.dynamicDecorationMap = [];
|
2429 |
|
2430 |
|
2431 |
|
2432 |
|
2433 |
|
2434 |
|
2435 |
|
2436 | this.minWidth = 0;
|
2437 | this.minWidthFrom = 0;
|
2438 | this.minWidthTo = 0;
|
2439 |
|
2440 |
|
2441 | this.impreciseAnchor = null;
|
2442 | this.impreciseHead = null;
|
2443 | this.forceSelection = false;
|
2444 |
|
2445 |
|
2446 | this.lastUpdate = Date.now();
|
2447 | this.setDOM(view.contentDOM);
|
2448 | this.children = [new LineView];
|
2449 | this.children[0].setParent(this);
|
2450 | this.updateDeco();
|
2451 | this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], 0);
|
2452 | }
|
2453 | get root() { return this.view.root; }
|
2454 | get editorView() { return this.view; }
|
2455 | get length() { return this.view.state.doc.length; }
|
2456 |
|
2457 |
|
2458 |
|
2459 |
|
2460 | update(update) {
|
2461 | let changedRanges = update.changedRanges;
|
2462 | if (this.minWidth > 0 && changedRanges.length) {
|
2463 | if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
|
2464 | this.minWidth = this.minWidthFrom = this.minWidthTo = 0;
|
2465 | }
|
2466 | else {
|
2467 | this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1);
|
2468 | this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
|
2469 | }
|
2470 | }
|
2471 | if (this.view.inputState.composing < 0)
|
2472 | this.compositionDeco = Decoration.none;
|
2473 | else if (update.transactions.length || this.dirty)
|
2474 | this.compositionDeco = computeCompositionDeco(this.view, update.changes);
|
2475 |
|
2476 |
|
2477 |
|
2478 |
|
2479 |
|
2480 | if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update &&
|
2481 | update.state.doc.lines != update.startState.doc.lines)
|
2482 | this.forceSelection = true;
|
2483 | let prevDeco = this.decorations, deco = this.updateDeco();
|
2484 | let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
|
2485 | changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
|
2486 | if (this.dirty == 0 && changedRanges.length == 0) {
|
2487 | return false;
|
2488 | }
|
2489 | else {
|
2490 | this.updateInner(changedRanges, update.startState.doc.length);
|
2491 | if (update.transactions.length)
|
2492 | this.lastUpdate = Date.now();
|
2493 | return true;
|
2494 | }
|
2495 | }
|
2496 |
|
2497 |
|
2498 | updateInner(changes, oldLength) {
|
2499 | this.view.viewState.mustMeasureContent = true;
|
2500 | this.updateChildren(changes, oldLength);
|
2501 | let { observer } = this.view;
|
2502 | observer.ignore(() => {
|
2503 |
|
2504 |
|
2505 |
|
2506 |
|
2507 | this.dom.style.height = this.view.viewState.contentHeight + "px";
|
2508 | this.dom.style.flexBasis = this.minWidth ? this.minWidth + "px" : "";
|
2509 |
|
2510 |
|
2511 |
|
2512 |
|
2513 | let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
|
2514 | this.sync(track);
|
2515 | this.dirty = 0 ;
|
2516 | if (track && (track.written || observer.selectionRange.focusNode != track.node))
|
2517 | this.forceSelection = true;
|
2518 | this.dom.style.height = "";
|
2519 | });
|
2520 | let gaps = [];
|
2521 | if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
|
2522 | for (let child of this.children)
|
2523 | if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget)
|
2524 | gaps.push(child.dom);
|
2525 | observer.updateGaps(gaps);
|
2526 | }
|
2527 | updateChildren(changes, oldLength) {
|
2528 | let cursor = this.childCursor(oldLength);
|
2529 | for (let i = changes.length - 1;; i--) {
|
2530 | let next = i >= 0 ? changes[i] : null;
|
2531 | if (!next)
|
2532 | break;
|
2533 | let { fromA, toA, fromB, toB } = next;
|
2534 | let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, this.decorations, this.dynamicDecorationMap);
|
2535 | let { i: toI, off: toOff } = cursor.findPos(toA, 1);
|
2536 | let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
|
2537 | replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
|
2538 | }
|
2539 | }
|
2540 |
|
2541 | updateSelection(mustRead = false, fromPointer = false) {
|
2542 | if (mustRead || !this.view.observer.selectionRange.focusNode)
|
2543 | this.view.observer.readSelectionRange();
|
2544 | if (!(fromPointer || this.mayControlSelection()) ||
|
2545 | browser.ios && this.view.inputState.rapidCompositionStart)
|
2546 | return;
|
2547 | let force = this.forceSelection;
|
2548 | this.forceSelection = false;
|
2549 | let main = this.view.state.selection.main;
|
2550 |
|
2551 | let anchor = this.domAtPos(main.anchor);
|
2552 | let head = main.empty ? anchor : this.domAtPos(main.head);
|
2553 |
|
2554 |
|
2555 | if (browser.gecko && main.empty && betweenUneditable(anchor)) {
|
2556 | let dummy = document.createTextNode("");
|
2557 | this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
|
2558 | anchor = head = new DOMPos(dummy, 0);
|
2559 | force = true;
|
2560 | }
|
2561 | let domSel = this.view.observer.selectionRange;
|
2562 |
|
2563 | if (force || !domSel.focusNode ||
|
2564 | !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
|
2565 | !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
|
2566 | this.view.observer.ignore(() => {
|
2567 |
|
2568 |
|
2569 |
|
2570 |
|
2571 | if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) &&
|
2572 | inUneditable(domSel.focusNode, this.dom)) {
|
2573 | this.dom.blur();
|
2574 | this.dom.focus({ preventScroll: true });
|
2575 | }
|
2576 | let rawSel = getSelection(this.root);
|
2577 | if (!rawSel) ;
|
2578 | else if (main.empty) {
|
2579 |
|
2580 | if (browser.gecko) {
|
2581 | let nextTo = nextToUneditable(anchor.node, anchor.offset);
|
2582 | if (nextTo && nextTo != (1 | 2 )) {
|
2583 | let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 ? 1 : -1);
|
2584 | if (text)
|
2585 | anchor = new DOMPos(text, nextTo == 1 ? 0 : text.nodeValue.length);
|
2586 | }
|
2587 | }
|
2588 | rawSel.collapse(anchor.node, anchor.offset);
|
2589 | if (main.bidiLevel != null && domSel.cursorBidiLevel != null)
|
2590 | domSel.cursorBidiLevel = main.bidiLevel;
|
2591 | }
|
2592 | else if (rawSel.extend) {
|
2593 |
|
2594 |
|
2595 |
|
2596 | rawSel.collapse(anchor.node, anchor.offset);
|
2597 | rawSel.extend(head.node, head.offset);
|
2598 | }
|
2599 | else {
|
2600 |
|
2601 | let range = document.createRange();
|
2602 | if (main.anchor > main.head)
|
2603 | [anchor, head] = [head, anchor];
|
2604 | range.setEnd(head.node, head.offset);
|
2605 | range.setStart(anchor.node, anchor.offset);
|
2606 | rawSel.removeAllRanges();
|
2607 | rawSel.addRange(range);
|
2608 | }
|
2609 | });
|
2610 | this.view.observer.setSelectionRange(anchor, head);
|
2611 | }
|
2612 | this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset);
|
2613 | this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
|
2614 | }
|
2615 | enforceCursorAssoc() {
|
2616 | if (this.compositionDeco.size)
|
2617 | return;
|
2618 | let cursor = this.view.state.selection.main;
|
2619 | let sel = getSelection(this.root);
|
2620 | if (!sel || !cursor.empty || !cursor.assoc || !sel.modify)
|
2621 | return;
|
2622 | let line = LineView.find(this, cursor.head);
|
2623 | if (!line)
|
2624 | return;
|
2625 | let lineStart = line.posAtStart;
|
2626 | if (cursor.head == lineStart || cursor.head == lineStart + line.length)
|
2627 | return;
|
2628 | let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
|
2629 | if (!before || !after || before.bottom > after.top)
|
2630 | return;
|
2631 | let dom = this.domAtPos(cursor.head + cursor.assoc);
|
2632 | sel.collapse(dom.node, dom.offset);
|
2633 | sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
|
2634 | }
|
2635 | mayControlSelection() {
|
2636 | let active = this.root.activeElement;
|
2637 | return active == this.dom ||
|
2638 | hasSelection(this.dom, this.view.observer.selectionRange) && !(active && this.dom.contains(active));
|
2639 | }
|
2640 | nearest(dom) {
|
2641 | for (let cur = dom; cur;) {
|
2642 | let domView = ContentView.get(cur);
|
2643 | if (domView && domView.rootView == this)
|
2644 | return domView;
|
2645 | cur = cur.parentNode;
|
2646 | }
|
2647 | return null;
|
2648 | }
|
2649 | posFromDOM(node, offset) {
|
2650 | let view = this.nearest(node);
|
2651 | if (!view)
|
2652 | throw new RangeError("Trying to find position for a DOM position outside of the document");
|
2653 | return view.localPosFromDOM(node, offset) + view.posAtStart;
|
2654 | }
|
2655 | domAtPos(pos) {
|
2656 | let { i, off } = this.childCursor().findPos(pos, -1);
|
2657 | for (; i < this.children.length - 1;) {
|
2658 | let child = this.children[i];
|
2659 | if (off < child.length || child instanceof LineView)
|
2660 | break;
|
2661 | i++;
|
2662 | off = 0;
|
2663 | }
|
2664 | return this.children[i].domAtPos(off);
|
2665 | }
|
2666 | coordsAt(pos, side) {
|
2667 | for (let off = this.length, i = this.children.length - 1;; i--) {
|
2668 | let child = this.children[i], start = off - child.breakAfter - child.length;
|
2669 | if (pos > start ||
|
2670 | (pos == start && child.type != BlockType.WidgetBefore && child.type != BlockType.WidgetAfter &&
|
2671 | (!i || side == 2 || this.children[i - 1].breakAfter ||
|
2672 | (this.children[i - 1].type == BlockType.WidgetBefore && side > -2))))
|
2673 | return child.coordsAt(pos - start, side);
|
2674 | off = start;
|
2675 | }
|
2676 | }
|
2677 | measureVisibleLineHeights(viewport) {
|
2678 | let result = [], { from, to } = viewport;
|
2679 | let contentWidth = this.view.contentDOM.clientWidth;
|
2680 | let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
|
2681 | let widest = -1, ltr = this.view.textDirection == Direction.LTR;
|
2682 | for (let pos = 0, i = 0; i < this.children.length; i++) {
|
2683 | let child = this.children[i], end = pos + child.length;
|
2684 | if (end > to)
|
2685 | break;
|
2686 | if (pos >= from) {
|
2687 | let childRect = child.dom.getBoundingClientRect();
|
2688 | result.push(childRect.height);
|
2689 | if (isWider) {
|
2690 | let last = child.dom.lastChild;
|
2691 | let rects = last ? clientRectsFor(last) : [];
|
2692 | if (rects.length) {
|
2693 | let rect = rects[rects.length - 1];
|
2694 | let width = ltr ? rect.right - childRect.left : childRect.right - rect.left;
|
2695 | if (width > widest) {
|
2696 | widest = width;
|
2697 | this.minWidth = contentWidth;
|
2698 | this.minWidthFrom = pos;
|
2699 | this.minWidthTo = end;
|
2700 | }
|
2701 | }
|
2702 | }
|
2703 | }
|
2704 | pos = end + child.breakAfter;
|
2705 | }
|
2706 | return result;
|
2707 | }
|
2708 | textDirectionAt(pos) {
|
2709 | let { i } = this.childPos(pos, 1);
|
2710 | return getComputedStyle(this.children[i].dom).direction == "rtl" ? Direction.RTL : Direction.LTR;
|
2711 | }
|
2712 | measureTextSize() {
|
2713 | for (let child of this.children) {
|
2714 | if (child instanceof LineView) {
|
2715 | let measure = child.measureTextSize();
|
2716 | if (measure)
|
2717 | return measure;
|
2718 | }
|
2719 | }
|
2720 |
|
2721 | let dummy = document.createElement("div"), lineHeight, charWidth;
|
2722 | dummy.className = "cm-line";
|
2723 | dummy.textContent = "abc def ghi jkl mno pqr stu";
|
2724 | this.view.observer.ignore(() => {
|
2725 | this.dom.appendChild(dummy);
|
2726 | let rect = clientRectsFor(dummy.firstChild)[0];
|
2727 | lineHeight = dummy.getBoundingClientRect().height;
|
2728 | charWidth = rect ? rect.width / 27 : 7;
|
2729 | dummy.remove();
|
2730 | });
|
2731 | return { lineHeight, charWidth };
|
2732 | }
|
2733 | childCursor(pos = this.length) {
|
2734 |
|
2735 |
|
2736 |
|
2737 | let i = this.children.length;
|
2738 | if (i)
|
2739 | pos -= this.children[--i].length;
|
2740 | return new ChildCursor(this.children, pos, i);
|
2741 | }
|
2742 | computeBlockGapDeco() {
|
2743 | let deco = [], vs = this.view.viewState;
|
2744 | for (let pos = 0, i = 0;; i++) {
|
2745 | let next = i == vs.viewports.length ? null : vs.viewports[i];
|
2746 | let end = next ? next.from - 1 : this.length;
|
2747 | if (end > pos) {
|
2748 | let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
|
2749 | deco.push(Decoration.replace({
|
2750 | widget: new BlockGapWidget(height),
|
2751 | block: true,
|
2752 | inclusive: true,
|
2753 | isBlockGap: true,
|
2754 | }).range(pos, end));
|
2755 | }
|
2756 | if (!next)
|
2757 | break;
|
2758 | pos = next.to + 1;
|
2759 | }
|
2760 | return Decoration.set(deco);
|
2761 | }
|
2762 | updateDeco() {
|
2763 | let allDeco = this.view.state.facet(decorations).map((d, i) => {
|
2764 | let dynamic = this.dynamicDecorationMap[i] = typeof d == "function";
|
2765 | return dynamic ? d(this.view) : d;
|
2766 | });
|
2767 | for (let i = allDeco.length; i < allDeco.length + 3; i++)
|
2768 | this.dynamicDecorationMap[i] = false;
|
2769 | return this.decorations = [
|
2770 | ...allDeco,
|
2771 | this.compositionDeco,
|
2772 | this.computeBlockGapDeco(),
|
2773 | this.view.viewState.lineGapDeco
|
2774 | ];
|
2775 | }
|
2776 | scrollIntoView(target) {
|
2777 | let { range } = target;
|
2778 | let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
|
2779 | if (!rect)
|
2780 | return;
|
2781 | if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
|
2782 | rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
|
2783 | right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
|
2784 | let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
|
2785 | for (let margins of this.view.state.facet(scrollMargins).map(f => f(this.view)))
|
2786 | if (margins) {
|
2787 | let { left, right, top, bottom } = margins;
|
2788 | if (left != null)
|
2789 | mLeft = Math.max(mLeft, left);
|
2790 | if (right != null)
|
2791 | mRight = Math.max(mRight, right);
|
2792 | if (top != null)
|
2793 | mTop = Math.max(mTop, top);
|
2794 | if (bottom != null)
|
2795 | mBottom = Math.max(mBottom, bottom);
|
2796 | }
|
2797 | let targetRect = {
|
2798 | left: rect.left - mLeft, top: rect.top - mTop,
|
2799 | right: rect.right + mRight, bottom: rect.bottom + mBottom
|
2800 | };
|
2801 | scrollRectIntoView(this.view.scrollDOM, targetRect, range.head < range.anchor ? -1 : 1, target.x, target.y, target.xMargin, target.yMargin, this.view.textDirection == Direction.LTR);
|
2802 | }
|
2803 | }
|
2804 | function betweenUneditable(pos) {
|
2805 | return pos.node.nodeType == 1 && pos.node.firstChild &&
|
2806 | (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") &&
|
2807 | (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false");
|
2808 | }
|
2809 | class BlockGapWidget extends WidgetType {
|
2810 | constructor(height) {
|
2811 | super();
|
2812 | this.height = height;
|
2813 | }
|
2814 | toDOM() {
|
2815 | let elt = document.createElement("div");
|
2816 | this.updateDOM(elt);
|
2817 | return elt;
|
2818 | }
|
2819 | eq(other) { return other.height == this.height; }
|
2820 | updateDOM(elt) {
|
2821 | elt.style.height = this.height + "px";
|
2822 | return true;
|
2823 | }
|
2824 | get estimatedHeight() { return this.height; }
|
2825 | }
|
2826 | function compositionSurroundingNode(view) {
|
2827 | let sel = view.observer.selectionRange;
|
2828 | let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
|
2829 | if (!textNode)
|
2830 | return null;
|
2831 | let cView = view.docView.nearest(textNode);
|
2832 | if (!cView)
|
2833 | return null;
|
2834 | if (cView instanceof LineView) {
|
2835 | let topNode = textNode;
|
2836 | while (topNode.parentNode != cView.dom)
|
2837 | topNode = topNode.parentNode;
|
2838 | let prev = topNode.previousSibling;
|
2839 | while (prev && !ContentView.get(prev))
|
2840 | prev = prev.previousSibling;
|
2841 | let pos = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
|
2842 | return { from: pos, to: pos, node: topNode, text: textNode };
|
2843 | }
|
2844 | else {
|
2845 | for (;;) {
|
2846 | let { parent } = cView;
|
2847 | if (!parent)
|
2848 | return null;
|
2849 | if (parent instanceof LineView)
|
2850 | break;
|
2851 | cView = parent;
|
2852 | }
|
2853 | let from = cView.posAtStart;
|
2854 | return { from, to: from + cView.length, node: cView.dom, text: textNode };
|
2855 | }
|
2856 | }
|
2857 | function computeCompositionDeco(view, changes) {
|
2858 | let surrounding = compositionSurroundingNode(view);
|
2859 | if (!surrounding)
|
2860 | return Decoration.none;
|
2861 | let { from, to, node, text: textNode } = surrounding;
|
2862 | let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1));
|
2863 | let { state } = view, text = node.nodeType == 3 ? node.nodeValue :
|
2864 | new DOMReader([], state).readRange(node.firstChild, null).text;
|
2865 | if (newTo - newFrom < text.length) {
|
2866 | if (state.doc.sliceString(newFrom, Math.min(state.doc.length, newFrom + text.length), LineBreakPlaceholder) == text)
|
2867 | newTo = newFrom + text.length;
|
2868 | else if (state.doc.sliceString(Math.max(0, newTo - text.length), newTo, LineBreakPlaceholder) == text)
|
2869 | newFrom = newTo - text.length;
|
2870 | else
|
2871 | return Decoration.none;
|
2872 | }
|
2873 | else if (state.doc.sliceString(newFrom, newTo, LineBreakPlaceholder) != text) {
|
2874 | return Decoration.none;
|
2875 | }
|
2876 | let topView = ContentView.get(node);
|
2877 | if (topView instanceof CompositionView)
|
2878 | topView = topView.widget.topView;
|
2879 | else if (topView)
|
2880 | topView.parent = null;
|
2881 | return Decoration.set(Decoration.replace({ widget: new CompositionWidget(node, textNode, topView), inclusive: true })
|
2882 | .range(newFrom, newTo));
|
2883 | }
|
2884 | class CompositionWidget extends WidgetType {
|
2885 | constructor(top, text, topView) {
|
2886 | super();
|
2887 | this.top = top;
|
2888 | this.text = text;
|
2889 | this.topView = topView;
|
2890 | }
|
2891 | eq(other) { return this.top == other.top && this.text == other.text; }
|
2892 | toDOM() { return this.top; }
|
2893 | ignoreEvent() { return false; }
|
2894 | get customView() { return CompositionView; }
|
2895 | }
|
2896 | function nearbyTextNode(node, offset, side) {
|
2897 | for (;;) {
|
2898 | if (node.nodeType == 3)
|
2899 | return node;
|
2900 | if (node.nodeType == 1 && offset > 0 && side <= 0) {
|
2901 | node = node.childNodes[offset - 1];
|
2902 | offset = maxOffset(node);
|
2903 | }
|
2904 | else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
|
2905 | node = node.childNodes[offset];
|
2906 | offset = 0;
|
2907 | }
|
2908 | else {
|
2909 | return null;
|
2910 | }
|
2911 | }
|
2912 | }
|
2913 | function nextToUneditable(node, offset) {
|
2914 | if (node.nodeType != 1)
|
2915 | return 0;
|
2916 | return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 : 0) |
|
2917 | (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 : 0);
|
2918 | }
|
2919 | class DecorationComparator$1 {
|
2920 | constructor() {
|
2921 | this.changes = [];
|
2922 | }
|
2923 | compareRange(from, to) { addRange(from, to, this.changes); }
|
2924 | comparePoint(from, to) { addRange(from, to, this.changes); }
|
2925 | }
|
2926 | function findChangedDeco(a, b, diff) {
|
2927 | let comp = new DecorationComparator$1;
|
2928 | RangeSet.compare(a, b, diff, comp);
|
2929 | return comp.changes;
|
2930 | }
|
2931 | function inUneditable(node, inside) {
|
2932 | for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
|
2933 | if (cur.nodeType == 1 && cur.contentEditable == 'false') {
|
2934 | return true;
|
2935 | }
|
2936 | }
|
2937 | return false;
|
2938 | }
|
2939 |
|
2940 | function groupAt(state, pos, bias = 1) {
|
2941 | let categorize = state.charCategorizer(pos);
|
2942 | let line = state.doc.lineAt(pos), linePos = pos - line.from;
|
2943 | if (line.length == 0)
|
2944 | return EditorSelection.cursor(pos);
|
2945 | if (linePos == 0)
|
2946 | bias = 1;
|
2947 | else if (linePos == line.length)
|
2948 | bias = -1;
|
2949 | let from = linePos, to = linePos;
|
2950 | if (bias < 0)
|
2951 | from = findClusterBreak(line.text, linePos, false);
|
2952 | else
|
2953 | to = findClusterBreak(line.text, linePos);
|
2954 | let cat = categorize(line.text.slice(from, to));
|
2955 | while (from > 0) {
|
2956 | let prev = findClusterBreak(line.text, from, false);
|
2957 | if (categorize(line.text.slice(prev, from)) != cat)
|
2958 | break;
|
2959 | from = prev;
|
2960 | }
|
2961 | while (to < line.length) {
|
2962 | let next = findClusterBreak(line.text, to);
|
2963 | if (categorize(line.text.slice(to, next)) != cat)
|
2964 | break;
|
2965 | to = next;
|
2966 | }
|
2967 | return EditorSelection.range(from + line.from, to + line.from);
|
2968 | }
|
2969 |
|
2970 |
|
2971 |
|
2972 | function getdx(x, rect) {
|
2973 | return rect.left > x ? rect.left - x : Math.max(0, x - rect.right);
|
2974 | }
|
2975 | function getdy(y, rect) {
|
2976 | return rect.top > y ? rect.top - y : Math.max(0, y - rect.bottom);
|
2977 | }
|
2978 | function yOverlap(a, b) {
|
2979 | return a.top < b.bottom - 1 && a.bottom > b.top + 1;
|
2980 | }
|
2981 | function upTop(rect, top) {
|
2982 | return top < rect.top ? { top, left: rect.left, right: rect.right, bottom: rect.bottom } : rect;
|
2983 | }
|
2984 | function upBot(rect, bottom) {
|
2985 | return bottom > rect.bottom ? { top: rect.top, left: rect.left, right: rect.right, bottom } : rect;
|
2986 | }
|
2987 | function domPosAtCoords(parent, x, y) {
|
2988 | let closest, closestRect, closestX, closestY;
|
2989 | let above, below, aboveRect, belowRect;
|
2990 | for (let child = parent.firstChild; child; child = child.nextSibling) {
|
2991 | let rects = clientRectsFor(child);
|
2992 | for (let i = 0; i < rects.length; i++) {
|
2993 | let rect = rects[i];
|
2994 | if (closestRect && yOverlap(closestRect, rect))
|
2995 | rect = upTop(upBot(rect, closestRect.bottom), closestRect.top);
|
2996 | let dx = getdx(x, rect), dy = getdy(y, rect);
|
2997 | if (dx == 0 && dy == 0)
|
2998 | return child.nodeType == 3 ? domPosInText(child, x, y) : domPosAtCoords(child, x, y);
|
2999 | if (!closest || closestY > dy || closestY == dy && closestX > dx) {
|
3000 | closest = child;
|
3001 | closestRect = rect;
|
3002 | closestX = dx;
|
3003 | closestY = dy;
|
3004 | }
|
3005 | if (dx == 0) {
|
3006 | if (y > rect.bottom && (!aboveRect || aboveRect.bottom < rect.bottom)) {
|
3007 | above = child;
|
3008 | aboveRect = rect;
|
3009 | }
|
3010 | else if (y < rect.top && (!belowRect || belowRect.top > rect.top)) {
|
3011 | below = child;
|
3012 | belowRect = rect;
|
3013 | }
|
3014 | }
|
3015 | else if (aboveRect && yOverlap(aboveRect, rect)) {
|
3016 | aboveRect = upBot(aboveRect, rect.bottom);
|
3017 | }
|
3018 | else if (belowRect && yOverlap(belowRect, rect)) {
|
3019 | belowRect = upTop(belowRect, rect.top);
|
3020 | }
|
3021 | }
|
3022 | }
|
3023 | if (aboveRect && aboveRect.bottom >= y) {
|
3024 | closest = above;
|
3025 | closestRect = aboveRect;
|
3026 | }
|
3027 | else if (belowRect && belowRect.top <= y) {
|
3028 | closest = below;
|
3029 | closestRect = belowRect;
|
3030 | }
|
3031 | if (!closest)
|
3032 | return { node: parent, offset: 0 };
|
3033 | let clipX = Math.max(closestRect.left, Math.min(closestRect.right, x));
|
3034 | if (closest.nodeType == 3)
|
3035 | return domPosInText(closest, clipX, y);
|
3036 | if (!closestX && closest.contentEditable == "true")
|
3037 | return domPosAtCoords(closest, clipX, y);
|
3038 | let offset = Array.prototype.indexOf.call(parent.childNodes, closest) +
|
3039 | (x >= (closestRect.left + closestRect.right) / 2 ? 1 : 0);
|
3040 | return { node: parent, offset };
|
3041 | }
|
3042 | function domPosInText(node, x, y) {
|
3043 | let len = node.nodeValue.length;
|
3044 | let closestOffset = -1, closestDY = 1e9, generalSide = 0;
|
3045 | for (let i = 0; i < len; i++) {
|
3046 | let rects = textRange(node, i, i + 1).getClientRects();
|
3047 | for (let j = 0; j < rects.length; j++) {
|
3048 | let rect = rects[j];
|
3049 | if (rect.top == rect.bottom)
|
3050 | continue;
|
3051 | if (!generalSide)
|
3052 | generalSide = x - rect.left;
|
3053 | let dy = (rect.top > y ? rect.top - y : y - rect.bottom) - 1;
|
3054 | if (rect.left - 1 <= x && rect.right + 1 >= x && dy < closestDY) {
|
3055 | let right = x >= (rect.left + rect.right) / 2, after = right;
|
3056 | if (browser.chrome || browser.gecko) {
|
3057 |
|
3058 |
|
3059 | let rectBefore = textRange(node, i).getBoundingClientRect();
|
3060 | if (rectBefore.left == rect.right)
|
3061 | after = !right;
|
3062 | }
|
3063 | if (dy <= 0)
|
3064 | return { node, offset: i + (after ? 1 : 0) };
|
3065 | closestOffset = i + (after ? 1 : 0);
|
3066 | closestDY = dy;
|
3067 | }
|
3068 | }
|
3069 | }
|
3070 | return { node, offset: closestOffset > -1 ? closestOffset : generalSide > 0 ? node.nodeValue.length : 0 };
|
3071 | }
|
3072 | function posAtCoords(view, { x, y }, precise, bias = -1) {
|
3073 | var _a;
|
3074 | let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
|
3075 | let block, { docHeight } = view.viewState;
|
3076 | let yOffset = y - docTop;
|
3077 | if (yOffset < 0)
|
3078 | return 0;
|
3079 | if (yOffset > docHeight)
|
3080 | return view.state.doc.length;
|
3081 |
|
3082 | for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
|
3083 | block = view.elementAtHeight(yOffset);
|
3084 | if (block.type == BlockType.Text)
|
3085 | break;
|
3086 | for (;;) {
|
3087 |
|
3088 | yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
|
3089 | if (yOffset >= 0 && yOffset <= docHeight)
|
3090 | break;
|
3091 |
|
3092 |
|
3093 | if (bounced)
|
3094 | return precise ? null : 0;
|
3095 | bounced = true;
|
3096 | bias = -bias;
|
3097 | }
|
3098 | }
|
3099 | y = docTop + yOffset;
|
3100 | let lineStart = block.from;
|
3101 |
|
3102 | if (lineStart < view.viewport.from)
|
3103 | return view.viewport.from == 0 ? 0 : precise ? null : posAtCoordsImprecise(view, content, block, x, y);
|
3104 | if (lineStart > view.viewport.to)
|
3105 | return view.viewport.to == view.state.doc.length ? view.state.doc.length :
|
3106 | precise ? null : posAtCoordsImprecise(view, content, block, x, y);
|
3107 |
|
3108 | let doc = view.dom.ownerDocument;
|
3109 | let root = view.root.elementFromPoint ? view.root : doc;
|
3110 | let element = root.elementFromPoint(x, y);
|
3111 | if (element && !view.contentDOM.contains(element))
|
3112 | element = null;
|
3113 |
|
3114 | if (!element) {
|
3115 | x = Math.max(content.left + 1, Math.min(content.right - 1, x));
|
3116 | element = root.elementFromPoint(x, y);
|
3117 | if (element && !view.contentDOM.contains(element))
|
3118 | element = null;
|
3119 | }
|
3120 |
|
3121 |
|
3122 | let node, offset = -1;
|
3123 | if (element && ((_a = view.docView.nearest(element)) === null || _a === void 0 ? void 0 : _a.isEditable) != false) {
|
3124 | if (doc.caretPositionFromPoint) {
|
3125 | let pos = doc.caretPositionFromPoint(x, y);
|
3126 | if (pos)
|
3127 | ({ offsetNode: node, offset } = pos);
|
3128 | }
|
3129 | else if (doc.caretRangeFromPoint) {
|
3130 | let range = doc.caretRangeFromPoint(x, y);
|
3131 | if (range) {
|
3132 | ({ startContainer: node, startOffset: offset } = range);
|
3133 | if (browser.safari && isSuspiciousCaretResult(node, offset, x))
|
3134 | node = undefined;
|
3135 | }
|
3136 | }
|
3137 | }
|
3138 |
|
3139 | if (!node || !view.docView.dom.contains(node)) {
|
3140 | let line = LineView.find(view.docView, lineStart);
|
3141 | if (!line)
|
3142 | return yOffset > block.top + block.height / 2 ? block.to : block.from;
|
3143 | ({ node, offset } = domPosAtCoords(line.dom, x, y));
|
3144 | }
|
3145 | return view.docView.posFromDOM(node, offset);
|
3146 | }
|
3147 | function posAtCoordsImprecise(view, contentRect, block, x, y) {
|
3148 | let into = Math.round((x - contentRect.left) * view.defaultCharacterWidth);
|
3149 | if (view.lineWrapping && block.height > view.defaultLineHeight * 1.5) {
|
3150 | let line = Math.floor((y - block.top) / view.defaultLineHeight);
|
3151 | into += line * view.viewState.heightOracle.lineLength;
|
3152 | }
|
3153 | let content = view.state.sliceDoc(block.from, block.to);
|
3154 | return block.from + findColumn(content, into, view.state.tabSize);
|
3155 | }
|
3156 |
|
3157 |
|
3158 |
|
3159 |
|
3160 | function isSuspiciousCaretResult(node, offset, x) {
|
3161 | let len;
|
3162 | if (node.nodeType != 3 || offset != (len = node.nodeValue.length))
|
3163 | return false;
|
3164 | for (let next = node.nextSibling; next; next = next.nextSibling)
|
3165 | if (next.nodeType != 1 || next.nodeName != "BR")
|
3166 | return false;
|
3167 | return textRange(node, len - 1, len).getBoundingClientRect().left > x;
|
3168 | }
|
3169 | function moveToLineBoundary(view, start, forward, includeWrap) {
|
3170 | let line = view.state.doc.lineAt(start.head);
|
3171 | let coords = !includeWrap || !view.lineWrapping ? null
|
3172 | : view.coordsAtPos(start.assoc < 0 && start.head > line.from ? start.head - 1 : start.head);
|
3173 | if (coords) {
|
3174 | let editorRect = view.dom.getBoundingClientRect();
|
3175 | let direction = view.textDirectionAt(line.from);
|
3176 | let pos = view.posAtCoords({ x: forward == (direction == Direction.LTR) ? editorRect.right - 1 : editorRect.left + 1,
|
3177 | y: (coords.top + coords.bottom) / 2 });
|
3178 | if (pos != null)
|
3179 | return EditorSelection.cursor(pos, forward ? -1 : 1);
|
3180 | }
|
3181 | let lineView = LineView.find(view.docView, start.head);
|
3182 | let end = lineView ? (forward ? lineView.posAtEnd : lineView.posAtStart) : (forward ? line.to : line.from);
|
3183 | return EditorSelection.cursor(end, forward ? -1 : 1);
|
3184 | }
|
3185 | function moveByChar(view, start, forward, by) {
|
3186 | let line = view.state.doc.lineAt(start.head), spans = view.bidiSpans(line);
|
3187 | let direction = view.textDirectionAt(line.from);
|
3188 | for (let cur = start, check = null;;) {
|
3189 | let next = moveVisually(line, spans, direction, cur, forward), char = movedOver;
|
3190 | if (!next) {
|
3191 | if (line.number == (forward ? view.state.doc.lines : 1))
|
3192 | return cur;
|
3193 | char = "\n";
|
3194 | line = view.state.doc.line(line.number + (forward ? 1 : -1));
|
3195 | spans = view.bidiSpans(line);
|
3196 | next = EditorSelection.cursor(forward ? line.from : line.to);
|
3197 | }
|
3198 | if (!check) {
|
3199 | if (!by)
|
3200 | return next;
|
3201 | check = by(char);
|
3202 | }
|
3203 | else if (!check(char)) {
|
3204 | return cur;
|
3205 | }
|
3206 | cur = next;
|
3207 | }
|
3208 | }
|
3209 | function byGroup(view, pos, start) {
|
3210 | let categorize = view.state.charCategorizer(pos);
|
3211 | let cat = categorize(start);
|
3212 | return (next) => {
|
3213 | let nextCat = categorize(next);
|
3214 | if (cat == CharCategory.Space)
|
3215 | cat = nextCat;
|
3216 | return cat == nextCat;
|
3217 | };
|
3218 | }
|
3219 | function moveVertically(view, start, forward, distance) {
|
3220 | let startPos = start.head, dir = forward ? 1 : -1;
|
3221 | if (startPos == (forward ? view.state.doc.length : 0))
|
3222 | return EditorSelection.cursor(startPos, start.assoc);
|
3223 | let goal = start.goalColumn, startY;
|
3224 | let rect = view.contentDOM.getBoundingClientRect();
|
3225 | let startCoords = view.coordsAtPos(startPos), docTop = view.documentTop;
|
3226 | if (startCoords) {
|
3227 | if (goal == null)
|
3228 | goal = startCoords.left - rect.left;
|
3229 | startY = dir < 0 ? startCoords.top : startCoords.bottom;
|
3230 | }
|
3231 | else {
|
3232 | let line = view.viewState.lineBlockAt(startPos);
|
3233 | if (goal == null)
|
3234 | goal = Math.min(rect.right - rect.left, view.defaultCharacterWidth * (startPos - line.from));
|
3235 | startY = (dir < 0 ? line.top : line.bottom) + docTop;
|
3236 | }
|
3237 | let resolvedGoal = rect.left + goal;
|
3238 | let dist = distance !== null && distance !== void 0 ? distance : (view.defaultLineHeight >> 1);
|
3239 | for (let extra = 0;; extra += 10) {
|
3240 | let curY = startY + (dist + extra) * dir;
|
3241 | let pos = posAtCoords(view, { x: resolvedGoal, y: curY }, false, dir);
|
3242 | if (curY < rect.top || curY > rect.bottom || (dir < 0 ? pos < startPos : pos > startPos))
|
3243 | return EditorSelection.cursor(pos, start.assoc, undefined, goal);
|
3244 | }
|
3245 | }
|
3246 | function skipAtoms(view, oldPos, pos) {
|
3247 | let atoms = view.state.facet(atomicRanges).map(f => f(view));
|
3248 | for (;;) {
|
3249 | let moved = false;
|
3250 | for (let set of atoms) {
|
3251 | set.between(pos.from - 1, pos.from + 1, (from, to, value) => {
|
3252 | if (pos.from > from && pos.from < to) {
|
3253 | pos = oldPos.from > pos.from ? EditorSelection.cursor(from, 1) : EditorSelection.cursor(to, -1);
|
3254 | moved = true;
|
3255 | }
|
3256 | });
|
3257 | }
|
3258 | if (!moved)
|
3259 | return pos;
|
3260 | }
|
3261 | }
|
3262 |
|
3263 |
|
3264 | class InputState {
|
3265 | constructor(view) {
|
3266 | this.lastKeyCode = 0;
|
3267 | this.lastKeyTime = 0;
|
3268 | this.chromeScrollHack = -1;
|
3269 |
|
3270 |
|
3271 |
|
3272 | this.pendingIOSKey = undefined;
|
3273 | this.lastSelectionOrigin = null;
|
3274 | this.lastSelectionTime = 0;
|
3275 | this.lastEscPress = 0;
|
3276 | this.lastContextMenu = 0;
|
3277 | this.scrollHandlers = [];
|
3278 | this.registeredEvents = [];
|
3279 | this.customHandlers = [];
|
3280 |
|
3281 |
|
3282 |
|
3283 |
|
3284 | this.composing = -1;
|
3285 |
|
3286 |
|
3287 |
|
3288 |
|
3289 | this.compositionFirstChange = null;
|
3290 | this.compositionEndedAt = 0;
|
3291 | this.rapidCompositionStart = false;
|
3292 | this.mouseSelection = null;
|
3293 | for (let type in handlers) {
|
3294 | let handler = handlers[type];
|
3295 | view.contentDOM.addEventListener(type, (event) => {
|
3296 | if (!eventBelongsToEditor(view, event) || this.ignoreDuringComposition(event))
|
3297 | return;
|
3298 | if (type == "keydown" && this.keydown(view, event))
|
3299 | return;
|
3300 | if (this.mustFlushObserver(event))
|
3301 | view.observer.forceFlush();
|
3302 | if (this.runCustomHandlers(type, view, event))
|
3303 | event.preventDefault();
|
3304 | else
|
3305 | handler(view, event);
|
3306 | });
|
3307 | this.registeredEvents.push(type);
|
3308 | }
|
3309 | if (browser.chrome && browser.chrome_version >= 102) {
|
3310 |
|
3311 |
|
3312 |
|
3313 | view.scrollDOM.addEventListener("wheel", () => {
|
3314 | if (this.chromeScrollHack < 0)
|
3315 | view.contentDOM.style.pointerEvents = "none";
|
3316 | else
|
3317 | window.clearTimeout(this.chromeScrollHack);
|
3318 | this.chromeScrollHack = setTimeout(() => {
|
3319 | this.chromeScrollHack = -1;
|
3320 | view.contentDOM.style.pointerEvents = "";
|
3321 | }, 100);
|
3322 | }, { passive: true });
|
3323 | }
|
3324 | this.notifiedFocused = view.hasFocus;
|
3325 |
|
3326 |
|
3327 | if (browser.safari)
|
3328 | view.contentDOM.addEventListener("input", () => null);
|
3329 | }
|
3330 | setSelectionOrigin(origin) {
|
3331 | this.lastSelectionOrigin = origin;
|
3332 | this.lastSelectionTime = Date.now();
|
3333 | }
|
3334 | ensureHandlers(view, plugins) {
|
3335 | var _a;
|
3336 | let handlers;
|
3337 | this.customHandlers = [];
|
3338 | for (let plugin of plugins)
|
3339 | if (handlers = (_a = plugin.update(view).spec) === null || _a === void 0 ? void 0 : _a.domEventHandlers) {
|
3340 | this.customHandlers.push({ plugin: plugin.value, handlers });
|
3341 | for (let type in handlers)
|
3342 | if (this.registeredEvents.indexOf(type) < 0 && type != "scroll") {
|
3343 | this.registeredEvents.push(type);
|
3344 | view.contentDOM.addEventListener(type, (event) => {
|
3345 | if (!eventBelongsToEditor(view, event))
|
3346 | return;
|
3347 | if (this.runCustomHandlers(type, view, event))
|
3348 | event.preventDefault();
|
3349 | });
|
3350 | }
|
3351 | }
|
3352 | }
|
3353 | runCustomHandlers(type, view, event) {
|
3354 | for (let set of this.customHandlers) {
|
3355 | let handler = set.handlers[type];
|
3356 | if (handler) {
|
3357 | try {
|
3358 | if (handler.call(set.plugin, event, view) || event.defaultPrevented)
|
3359 | return true;
|
3360 | }
|
3361 | catch (e) {
|
3362 | logException(view.state, e);
|
3363 | }
|
3364 | }
|
3365 | }
|
3366 | return false;
|
3367 | }
|
3368 | runScrollHandlers(view, event) {
|
3369 | for (let set of this.customHandlers) {
|
3370 | let handler = set.handlers.scroll;
|
3371 | if (handler) {
|
3372 | try {
|
3373 | handler.call(set.plugin, event, view);
|
3374 | }
|
3375 | catch (e) {
|
3376 | logException(view.state, e);
|
3377 | }
|
3378 | }
|
3379 | }
|
3380 | }
|
3381 | keydown(view, event) {
|
3382 |
|
3383 | this.lastKeyCode = event.keyCode;
|
3384 | this.lastKeyTime = Date.now();
|
3385 | if (event.keyCode == 9 && Date.now() < this.lastEscPress + 2000)
|
3386 | return true;
|
3387 |
|
3388 |
|
3389 |
|
3390 |
|
3391 |
|
3392 | if (browser.android && browser.chrome && !event.synthetic &&
|
3393 | (event.keyCode == 13 || event.keyCode == 8)) {
|
3394 | view.observer.delayAndroidKey(event.key, event.keyCode);
|
3395 | return true;
|
3396 | }
|
3397 |
|
3398 |
|
3399 |
|
3400 |
|
3401 |
|
3402 | let pending;
|
3403 | if (browser.ios && (pending = PendingKeys.find(key => key.keyCode == event.keyCode)) &&
|
3404 | !(event.ctrlKey || event.altKey || event.metaKey) && !event.synthetic) {
|
3405 | this.pendingIOSKey = pending;
|
3406 | setTimeout(() => this.flushIOSKey(view), 250);
|
3407 | return true;
|
3408 | }
|
3409 | return false;
|
3410 | }
|
3411 | flushIOSKey(view) {
|
3412 | let key = this.pendingIOSKey;
|
3413 | if (!key)
|
3414 | return false;
|
3415 | this.pendingIOSKey = undefined;
|
3416 | return dispatchKey(view.contentDOM, key.key, key.keyCode);
|
3417 | }
|
3418 | ignoreDuringComposition(event) {
|
3419 | if (!/^key/.test(event.type))
|
3420 | return false;
|
3421 | if (this.composing > 0)
|
3422 | return true;
|
3423 |
|
3424 |
|
3425 |
|
3426 |
|
3427 |
|
3428 |
|
3429 | if (browser.safari && Date.now() - this.compositionEndedAt < 100) {
|
3430 | this.compositionEndedAt = 0;
|
3431 | return true;
|
3432 | }
|
3433 | return false;
|
3434 | }
|
3435 | mustFlushObserver(event) {
|
3436 | return (event.type == "keydown" && event.keyCode != 229) ||
|
3437 | event.type == "compositionend" && !browser.ios;
|
3438 | }
|
3439 | startMouseSelection(mouseSelection) {
|
3440 | if (this.mouseSelection)
|
3441 | this.mouseSelection.destroy();
|
3442 | this.mouseSelection = mouseSelection;
|
3443 | }
|
3444 | update(update) {
|
3445 | if (this.mouseSelection)
|
3446 | this.mouseSelection.update(update);
|
3447 | if (update.transactions.length)
|
3448 | this.lastKeyCode = this.lastSelectionTime = 0;
|
3449 | }
|
3450 | destroy() {
|
3451 | if (this.mouseSelection)
|
3452 | this.mouseSelection.destroy();
|
3453 | }
|
3454 | }
|
3455 | const PendingKeys = [
|
3456 | { key: "Backspace", keyCode: 8, inputType: "deleteContentBackward" },
|
3457 | { key: "Enter", keyCode: 13, inputType: "insertParagraph" },
|
3458 | { key: "Delete", keyCode: 46, inputType: "deleteContentForward" }
|
3459 | ];
|
3460 |
|
3461 | const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
|
3462 | class MouseSelection {
|
3463 | constructor(view, startEvent, style, mustSelect) {
|
3464 | this.view = view;
|
3465 | this.style = style;
|
3466 | this.mustSelect = mustSelect;
|
3467 | this.lastEvent = startEvent;
|
3468 | let doc = view.contentDOM.ownerDocument;
|
3469 | doc.addEventListener("mousemove", this.move = this.move.bind(this));
|
3470 | doc.addEventListener("mouseup", this.up = this.up.bind(this));
|
3471 | this.extend = startEvent.shiftKey;
|
3472 | this.multiple = view.state.facet(EditorState.allowMultipleSelections) && addsSelectionRange(view, startEvent);
|
3473 | this.dragMove = dragMovesSelection(view, startEvent);
|
3474 | this.dragging = isInPrimarySelection(view, startEvent) && getClickType(startEvent) == 1 ? null : false;
|
3475 |
|
3476 |
|
3477 | if (this.dragging === false) {
|
3478 | startEvent.preventDefault();
|
3479 | this.select(startEvent);
|
3480 | }
|
3481 | }
|
3482 | move(event) {
|
3483 | if (event.buttons == 0)
|
3484 | return this.destroy();
|
3485 | if (this.dragging !== false)
|
3486 | return;
|
3487 | this.select(this.lastEvent = event);
|
3488 | }
|
3489 | up(event) {
|
3490 | if (this.dragging == null)
|
3491 | this.select(this.lastEvent);
|
3492 | if (!this.dragging)
|
3493 | event.preventDefault();
|
3494 | this.destroy();
|
3495 | }
|
3496 | destroy() {
|
3497 | let doc = this.view.contentDOM.ownerDocument;
|
3498 | doc.removeEventListener("mousemove", this.move);
|
3499 | doc.removeEventListener("mouseup", this.up);
|
3500 | this.view.inputState.mouseSelection = null;
|
3501 | }
|
3502 | select(event) {
|
3503 | let selection = this.style.get(event, this.extend, this.multiple);
|
3504 | if (this.mustSelect || !selection.eq(this.view.state.selection) ||
|
3505 | selection.main.assoc != this.view.state.selection.main.assoc)
|
3506 | this.view.dispatch({
|
3507 | selection,
|
3508 | userEvent: "select.pointer",
|
3509 | scrollIntoView: true
|
3510 | });
|
3511 | this.mustSelect = false;
|
3512 | }
|
3513 | update(update) {
|
3514 | if (update.docChanged && this.dragging)
|
3515 | this.dragging = this.dragging.map(update.changes);
|
3516 | if (this.style.update(update))
|
3517 | setTimeout(() => this.select(this.lastEvent), 20);
|
3518 | }
|
3519 | }
|
3520 | function addsSelectionRange(view, event) {
|
3521 | let facet = view.state.facet(clickAddsSelectionRange);
|
3522 | return facet.length ? facet[0](event) : browser.mac ? event.metaKey : event.ctrlKey;
|
3523 | }
|
3524 | function dragMovesSelection(view, event) {
|
3525 | let facet = view.state.facet(dragMovesSelection$1);
|
3526 | return facet.length ? facet[0](event) : browser.mac ? !event.altKey : !event.ctrlKey;
|
3527 | }
|
3528 | function isInPrimarySelection(view, event) {
|
3529 | let { main } = view.state.selection;
|
3530 | if (main.empty)
|
3531 | return false;
|
3532 |
|
3533 |
|
3534 | let sel = getSelection(view.root);
|
3535 | if (!sel || sel.rangeCount == 0)
|
3536 | return true;
|
3537 | let rects = sel.getRangeAt(0).getClientRects();
|
3538 | for (let i = 0; i < rects.length; i++) {
|
3539 | let rect = rects[i];
|
3540 | if (rect.left <= event.clientX && rect.right >= event.clientX &&
|
3541 | rect.top <= event.clientY && rect.bottom >= event.clientY)
|
3542 | return true;
|
3543 | }
|
3544 | return false;
|
3545 | }
|
3546 | function eventBelongsToEditor(view, event) {
|
3547 | if (!event.bubbles)
|
3548 | return true;
|
3549 | if (event.defaultPrevented)
|
3550 | return false;
|
3551 | for (let node = event.target, cView; node != view.contentDOM; node = node.parentNode)
|
3552 | if (!node || node.nodeType == 11 || ((cView = ContentView.get(node)) && cView.ignoreEvent(event)))
|
3553 | return false;
|
3554 | return true;
|
3555 | }
|
3556 | const handlers = Object.create(null);
|
3557 |
|
3558 |
|
3559 |
|
3560 | const brokenClipboardAPI = (browser.ie && browser.ie_version < 15) ||
|
3561 | (browser.ios && browser.webkit_version < 604);
|
3562 | function capturePaste(view) {
|
3563 | let parent = view.dom.parentNode;
|
3564 | if (!parent)
|
3565 | return;
|
3566 | let target = parent.appendChild(document.createElement("textarea"));
|
3567 | target.style.cssText = "position: fixed; left: -10000px; top: 10px";
|
3568 | target.focus();
|
3569 | setTimeout(() => {
|
3570 | view.focus();
|
3571 | target.remove();
|
3572 | doPaste(view, target.value);
|
3573 | }, 50);
|
3574 | }
|
3575 | function doPaste(view, input) {
|
3576 | let { state } = view, changes, i = 1, text = state.toText(input);
|
3577 | let byLine = text.lines == state.selection.ranges.length;
|
3578 | let linewise = lastLinewiseCopy != null && state.selection.ranges.every(r => r.empty) && lastLinewiseCopy == text.toString();
|
3579 | if (linewise) {
|
3580 | let lastLine = -1;
|
3581 | changes = state.changeByRange(range => {
|
3582 | let line = state.doc.lineAt(range.from);
|
3583 | if (line.from == lastLine)
|
3584 | return { range };
|
3585 | lastLine = line.from;
|
3586 | let insert = state.toText((byLine ? text.line(i++).text : input) + state.lineBreak);
|
3587 | return { changes: { from: line.from, insert },
|
3588 | range: EditorSelection.cursor(range.from + insert.length) };
|
3589 | });
|
3590 | }
|
3591 | else if (byLine) {
|
3592 | changes = state.changeByRange(range => {
|
3593 | let line = text.line(i++);
|
3594 | return { changes: { from: range.from, to: range.to, insert: line.text },
|
3595 | range: EditorSelection.cursor(range.from + line.length) };
|
3596 | });
|
3597 | }
|
3598 | else {
|
3599 | changes = state.replaceSelection(text);
|
3600 | }
|
3601 | view.dispatch(changes, {
|
3602 | userEvent: "input.paste",
|
3603 | scrollIntoView: true
|
3604 | });
|
3605 | }
|
3606 | handlers.keydown = (view, event) => {
|
3607 | view.inputState.setSelectionOrigin("select");
|
3608 | if (event.keyCode == 27)
|
3609 | view.inputState.lastEscPress = Date.now();
|
3610 | else if (modifierCodes.indexOf(event.keyCode) < 0)
|
3611 | view.inputState.lastEscPress = 0;
|
3612 | };
|
3613 | let lastTouch = 0;
|
3614 | handlers.touchstart = (view, e) => {
|
3615 | lastTouch = Date.now();
|
3616 | view.inputState.setSelectionOrigin("select.pointer");
|
3617 | };
|
3618 | handlers.touchmove = view => {
|
3619 | view.inputState.setSelectionOrigin("select.pointer");
|
3620 | };
|
3621 | handlers.mousedown = (view, event) => {
|
3622 | view.observer.flush();
|
3623 | if (lastTouch > Date.now() - 2000 && getClickType(event) == 1)
|
3624 | return;
|
3625 | let style = null;
|
3626 | for (let makeStyle of view.state.facet(mouseSelectionStyle)) {
|
3627 | style = makeStyle(view, event);
|
3628 | if (style)
|
3629 | break;
|
3630 | }
|
3631 | if (!style && event.button == 0)
|
3632 | style = basicMouseSelection(view, event);
|
3633 | if (style) {
|
3634 | let mustFocus = view.root.activeElement != view.contentDOM;
|
3635 | if (mustFocus)
|
3636 | view.observer.ignore(() => focusPreventScroll(view.contentDOM));
|
3637 | view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
|
3638 | }
|
3639 | };
|
3640 | function rangeForClick(view, pos, bias, type) {
|
3641 | if (type == 1) {
|
3642 | return EditorSelection.cursor(pos, bias);
|
3643 | }
|
3644 | else if (type == 2) {
|
3645 | return groupAt(view.state, pos, bias);
|
3646 | }
|
3647 | else {
|
3648 | let visual = LineView.find(view.docView, pos), line = view.state.doc.lineAt(visual ? visual.posAtEnd : pos);
|
3649 | let from = visual ? visual.posAtStart : line.from, to = visual ? visual.posAtEnd : line.to;
|
3650 | if (to < view.state.doc.length && to == line.to)
|
3651 | to++;
|
3652 | return EditorSelection.range(from, to);
|
3653 | }
|
3654 | }
|
3655 | let insideY = (y, rect) => y >= rect.top && y <= rect.bottom;
|
3656 | let inside = (x, y, rect) => insideY(y, rect) && x >= rect.left && x <= rect.right;
|
3657 |
|
3658 |
|
3659 |
|
3660 | function findPositionSide(view, pos, x, y) {
|
3661 | let line = LineView.find(view.docView, pos);
|
3662 | if (!line)
|
3663 | return 1;
|
3664 | let off = pos - line.posAtStart;
|
3665 |
|
3666 | if (off == 0)
|
3667 | return 1;
|
3668 | if (off == line.length)
|
3669 | return -1;
|
3670 |
|
3671 | let before = line.coordsAt(off, -1);
|
3672 | if (before && inside(x, y, before))
|
3673 | return -1;
|
3674 | let after = line.coordsAt(off, 1);
|
3675 | if (after && inside(x, y, after))
|
3676 | return 1;
|
3677 |
|
3678 |
|
3679 | return before && insideY(y, before) ? -1 : 1;
|
3680 | }
|
3681 | function queryPos(view, event) {
|
3682 | let pos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
3683 | return { pos, bias: findPositionSide(view, pos, event.clientX, event.clientY) };
|
3684 | }
|
3685 | const BadMouseDetail = browser.ie && browser.ie_version <= 11;
|
3686 | let lastMouseDown = null, lastMouseDownCount = 0, lastMouseDownTime = 0;
|
3687 | function getClickType(event) {
|
3688 | if (!BadMouseDetail)
|
3689 | return event.detail;
|
3690 | let last = lastMouseDown, lastTime = lastMouseDownTime;
|
3691 | lastMouseDown = event;
|
3692 | lastMouseDownTime = Date.now();
|
3693 | return lastMouseDownCount = !last || (lastTime > Date.now() - 400 && Math.abs(last.clientX - event.clientX) < 2 &&
|
3694 | Math.abs(last.clientY - event.clientY) < 2) ? (lastMouseDownCount + 1) % 3 : 1;
|
3695 | }
|
3696 | function basicMouseSelection(view, event) {
|
3697 | let start = queryPos(view, event), type = getClickType(event);
|
3698 | let startSel = view.state.selection;
|
3699 | let last = start, lastEvent = event;
|
3700 | return {
|
3701 | update(update) {
|
3702 | if (update.docChanged) {
|
3703 | if (start)
|
3704 | start.pos = update.changes.mapPos(start.pos);
|
3705 | startSel = startSel.map(update.changes);
|
3706 | lastEvent = null;
|
3707 | }
|
3708 | },
|
3709 | get(event, extend, multiple) {
|
3710 | let cur;
|
3711 | if (lastEvent && event.clientX == lastEvent.clientX && event.clientY == lastEvent.clientY)
|
3712 | cur = last;
|
3713 | else {
|
3714 | cur = last = queryPos(view, event);
|
3715 | lastEvent = event;
|
3716 | }
|
3717 | if (!cur || !start)
|
3718 | return startSel;
|
3719 | let range = rangeForClick(view, cur.pos, cur.bias, type);
|
3720 | if (start.pos != cur.pos && !extend) {
|
3721 | let startRange = rangeForClick(view, start.pos, start.bias, type);
|
3722 | let from = Math.min(startRange.from, range.from), to = Math.max(startRange.to, range.to);
|
3723 | range = from < range.from ? EditorSelection.range(from, to) : EditorSelection.range(to, from);
|
3724 | }
|
3725 | if (extend)
|
3726 | return startSel.replaceRange(startSel.main.extend(range.from, range.to));
|
3727 | else if (multiple)
|
3728 | return startSel.addRange(range);
|
3729 | else
|
3730 | return EditorSelection.create([range]);
|
3731 | }
|
3732 | };
|
3733 | }
|
3734 | handlers.dragstart = (view, event) => {
|
3735 | let { selection: { main } } = view.state;
|
3736 | let { mouseSelection } = view.inputState;
|
3737 | if (mouseSelection)
|
3738 | mouseSelection.dragging = main;
|
3739 | if (event.dataTransfer) {
|
3740 | event.dataTransfer.setData("Text", view.state.sliceDoc(main.from, main.to));
|
3741 | event.dataTransfer.effectAllowed = "copyMove";
|
3742 | }
|
3743 | };
|
3744 | function dropText(view, event, text, direct) {
|
3745 | if (!text)
|
3746 | return;
|
3747 | let dropPos = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
3748 | event.preventDefault();
|
3749 | let { mouseSelection } = view.inputState;
|
3750 | let del = direct && mouseSelection && mouseSelection.dragging && mouseSelection.dragMove ?
|
3751 | { from: mouseSelection.dragging.from, to: mouseSelection.dragging.to } : null;
|
3752 | let ins = { from: dropPos, insert: text };
|
3753 | let changes = view.state.changes(del ? [del, ins] : ins);
|
3754 | view.focus();
|
3755 | view.dispatch({
|
3756 | changes,
|
3757 | selection: { anchor: changes.mapPos(dropPos, -1), head: changes.mapPos(dropPos, 1) },
|
3758 | userEvent: del ? "move.drop" : "input.drop"
|
3759 | });
|
3760 | }
|
3761 | handlers.drop = (view, event) => {
|
3762 | if (!event.dataTransfer)
|
3763 | return;
|
3764 | if (view.state.readOnly)
|
3765 | return event.preventDefault();
|
3766 | let files = event.dataTransfer.files;
|
3767 | if (files && files.length) {
|
3768 | event.preventDefault();
|
3769 | let text = Array(files.length), read = 0;
|
3770 | let finishFile = () => {
|
3771 | if (++read == files.length)
|
3772 | dropText(view, event, text.filter(s => s != null).join(view.state.lineBreak), false);
|
3773 | };
|
3774 | for (let i = 0; i < files.length; i++) {
|
3775 | let reader = new FileReader;
|
3776 | reader.onerror = finishFile;
|
3777 | reader.onload = () => {
|
3778 | if (!/[\x00-\x08\x0e-\x1f]{2}/.test(reader.result))
|
3779 | text[i] = reader.result;
|
3780 | finishFile();
|
3781 | };
|
3782 | reader.readAsText(files[i]);
|
3783 | }
|
3784 | }
|
3785 | else {
|
3786 | dropText(view, event, event.dataTransfer.getData("Text"), true);
|
3787 | }
|
3788 | };
|
3789 | handlers.paste = (view, event) => {
|
3790 | if (view.state.readOnly)
|
3791 | return event.preventDefault();
|
3792 | view.observer.flush();
|
3793 | let data = brokenClipboardAPI ? null : event.clipboardData;
|
3794 | if (data) {
|
3795 | doPaste(view, data.getData("text/plain"));
|
3796 | event.preventDefault();
|
3797 | }
|
3798 | else {
|
3799 | capturePaste(view);
|
3800 | }
|
3801 | };
|
3802 | function captureCopy(view, text) {
|
3803 |
|
3804 |
|
3805 | let parent = view.dom.parentNode;
|
3806 | if (!parent)
|
3807 | return;
|
3808 | let target = parent.appendChild(document.createElement("textarea"));
|
3809 | target.style.cssText = "position: fixed; left: -10000px; top: 10px";
|
3810 | target.value = text;
|
3811 | target.focus();
|
3812 | target.selectionEnd = text.length;
|
3813 | target.selectionStart = 0;
|
3814 | setTimeout(() => {
|
3815 | target.remove();
|
3816 | view.focus();
|
3817 | }, 50);
|
3818 | }
|
3819 | function copiedRange(state) {
|
3820 | let content = [], ranges = [], linewise = false;
|
3821 | for (let range of state.selection.ranges)
|
3822 | if (!range.empty) {
|
3823 | content.push(state.sliceDoc(range.from, range.to));
|
3824 | ranges.push(range);
|
3825 | }
|
3826 | if (!content.length) {
|
3827 |
|
3828 | let upto = -1;
|
3829 | for (let { from } of state.selection.ranges) {
|
3830 | let line = state.doc.lineAt(from);
|
3831 | if (line.number > upto) {
|
3832 | content.push(line.text);
|
3833 | ranges.push({ from: line.from, to: Math.min(state.doc.length, line.to + 1) });
|
3834 | }
|
3835 | upto = line.number;
|
3836 | }
|
3837 | linewise = true;
|
3838 | }
|
3839 | return { text: content.join(state.lineBreak), ranges, linewise };
|
3840 | }
|
3841 | let lastLinewiseCopy = null;
|
3842 | handlers.copy = handlers.cut = (view, event) => {
|
3843 | let { text, ranges, linewise } = copiedRange(view.state);
|
3844 | if (!text && !linewise)
|
3845 | return;
|
3846 | lastLinewiseCopy = linewise ? text : null;
|
3847 | let data = brokenClipboardAPI ? null : event.clipboardData;
|
3848 | if (data) {
|
3849 | event.preventDefault();
|
3850 | data.clearData();
|
3851 | data.setData("text/plain", text);
|
3852 | }
|
3853 | else {
|
3854 | captureCopy(view, text);
|
3855 | }
|
3856 | if (event.type == "cut" && !view.state.readOnly)
|
3857 | view.dispatch({
|
3858 | changes: ranges,
|
3859 | scrollIntoView: true,
|
3860 | userEvent: "delete.cut"
|
3861 | });
|
3862 | };
|
3863 | function updateForFocusChange(view) {
|
3864 | setTimeout(() => {
|
3865 | if (view.hasFocus != view.inputState.notifiedFocused)
|
3866 | view.update([]);
|
3867 | }, 10);
|
3868 | }
|
3869 | handlers.focus = updateForFocusChange;
|
3870 | handlers.blur = view => {
|
3871 | view.observer.clearSelectionRange();
|
3872 | updateForFocusChange(view);
|
3873 | };
|
3874 | function forceClearComposition(view, rapid) {
|
3875 | if (view.docView.compositionDeco.size) {
|
3876 | view.inputState.rapidCompositionStart = rapid;
|
3877 | try {
|
3878 | view.update([]);
|
3879 | }
|
3880 | finally {
|
3881 | view.inputState.rapidCompositionStart = false;
|
3882 | }
|
3883 | }
|
3884 | }
|
3885 | handlers.compositionstart = handlers.compositionupdate = view => {
|
3886 | if (view.inputState.compositionFirstChange == null)
|
3887 | view.inputState.compositionFirstChange = true;
|
3888 | if (view.inputState.composing < 0) {
|
3889 |
|
3890 | view.inputState.composing = 0;
|
3891 | if (view.docView.compositionDeco.size) {
|
3892 | view.observer.flush();
|
3893 | forceClearComposition(view, true);
|
3894 | }
|
3895 | }
|
3896 | };
|
3897 | handlers.compositionend = view => {
|
3898 | view.inputState.composing = -1;
|
3899 | view.inputState.compositionEndedAt = Date.now();
|
3900 | view.inputState.compositionFirstChange = null;
|
3901 | setTimeout(() => {
|
3902 | if (view.inputState.composing < 0)
|
3903 | forceClearComposition(view, false);
|
3904 | }, 50);
|
3905 | };
|
3906 | handlers.contextmenu = view => {
|
3907 | view.inputState.lastContextMenu = Date.now();
|
3908 | };
|
3909 | handlers.beforeinput = (view, event) => {
|
3910 | var _a;
|
3911 |
|
3912 |
|
3913 |
|
3914 |
|
3915 |
|
3916 |
|
3917 |
|
3918 | let pending;
|
3919 | if (browser.chrome && browser.android && (pending = PendingKeys.find(key => key.inputType == event.inputType))) {
|
3920 | view.observer.delayAndroidKey(pending.key, pending.keyCode);
|
3921 | if (pending.key == "Backspace" || pending.key == "Delete") {
|
3922 | let startViewHeight = ((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0;
|
3923 | setTimeout(() => {
|
3924 | var _a;
|
3925 |
|
3926 |
|
3927 |
|
3928 | if ((((_a = window.visualViewport) === null || _a === void 0 ? void 0 : _a.height) || 0) > startViewHeight + 10 && view.hasFocus) {
|
3929 | view.contentDOM.blur();
|
3930 | view.focus();
|
3931 | }
|
3932 | }, 100);
|
3933 | }
|
3934 | }
|
3935 | };
|
3936 |
|
3937 | const wrappingWhiteSpace = ["pre-wrap", "normal", "pre-line", "break-spaces"];
|
3938 | class HeightOracle {
|
3939 | constructor() {
|
3940 | this.doc = Text.empty;
|
3941 | this.lineWrapping = false;
|
3942 | this.heightSamples = {};
|
3943 | this.lineHeight = 14;
|
3944 | this.charWidth = 7;
|
3945 | this.lineLength = 30;
|
3946 |
|
3947 | this.heightChanged = false;
|
3948 | }
|
3949 | heightForGap(from, to) {
|
3950 | let lines = this.doc.lineAt(to).number - this.doc.lineAt(from).number + 1;
|
3951 | if (this.lineWrapping)
|
3952 | lines += Math.ceil(((to - from) - (lines * this.lineLength * 0.5)) / this.lineLength);
|
3953 | return this.lineHeight * lines;
|
3954 | }
|
3955 | heightForLine(length) {
|
3956 | if (!this.lineWrapping)
|
3957 | return this.lineHeight;
|
3958 | let lines = 1 + Math.max(0, Math.ceil((length - this.lineLength) / (this.lineLength - 5)));
|
3959 | return lines * this.lineHeight;
|
3960 | }
|
3961 | setDoc(doc) { this.doc = doc; return this; }
|
3962 | mustRefreshForWrapping(whiteSpace) {
|
3963 | return (wrappingWhiteSpace.indexOf(whiteSpace) > -1) != this.lineWrapping;
|
3964 | }
|
3965 | mustRefreshForHeights(lineHeights) {
|
3966 | let newHeight = false;
|
3967 | for (let i = 0; i < lineHeights.length; i++) {
|
3968 | let h = lineHeights[i];
|
3969 | if (h < 0) {
|
3970 | i++;
|
3971 | }
|
3972 | else if (!this.heightSamples[Math.floor(h * 10)]) {
|
3973 | newHeight = true;
|
3974 | this.heightSamples[Math.floor(h * 10)] = true;
|
3975 | }
|
3976 | }
|
3977 | return newHeight;
|
3978 | }
|
3979 | refresh(whiteSpace, lineHeight, charWidth, lineLength, knownHeights) {
|
3980 | let lineWrapping = wrappingWhiteSpace.indexOf(whiteSpace) > -1;
|
3981 | let changed = Math.round(lineHeight) != Math.round(this.lineHeight) || this.lineWrapping != lineWrapping;
|
3982 | this.lineWrapping = lineWrapping;
|
3983 | this.lineHeight = lineHeight;
|
3984 | this.charWidth = charWidth;
|
3985 | this.lineLength = lineLength;
|
3986 | if (changed) {
|
3987 | this.heightSamples = {};
|
3988 | for (let i = 0; i < knownHeights.length; i++) {
|
3989 | let h = knownHeights[i];
|
3990 | if (h < 0)
|
3991 | i++;
|
3992 | else
|
3993 | this.heightSamples[Math.floor(h * 10)] = true;
|
3994 | }
|
3995 | }
|
3996 | return changed;
|
3997 | }
|
3998 | }
|
3999 |
|
4000 |
|
4001 |
|
4002 | class MeasuredHeights {
|
4003 | constructor(from, heights) {
|
4004 | this.from = from;
|
4005 | this.heights = heights;
|
4006 | this.index = 0;
|
4007 | }
|
4008 | get more() { return this.index < this.heights.length; }
|
4009 | }
|
4010 |
|
4011 |
|
4012 |
|
4013 |
|
4014 | class BlockInfo {
|
4015 | |
4016 |
|
4017 |
|
4018 | constructor(
|
4019 | /**
|
4020 | The start of the element in the document.
|
4021 | */
|
4022 | from,
|
4023 | /**
|
4024 | The length of the element.
|
4025 | */
|
4026 | length,
|
4027 | /**
|
4028 | The top position of the element (relative to the top of the
|
4029 | document).
|
4030 | */
|
4031 | top,
|
4032 | /**
|
4033 | Its height.
|
4034 | */
|
4035 | height,
|
4036 | /**
|
4037 | The type of element this is. When querying lines, this may be
|
4038 | an array of all the blocks that make up the line.
|
4039 | */
|
4040 | type) {
|
4041 | this.from = from;
|
4042 | this.length = length;
|
4043 | this.top = top;
|
4044 | this.height = height;
|
4045 | this.type = type;
|
4046 | }
|
4047 | |
4048 |
|
4049 |
|
4050 | get to() { return this.from + this.length; }
|
4051 | |
4052 |
|
4053 |
|
4054 | get bottom() { return this.top + this.height; }
|
4055 | |
4056 |
|
4057 |
|
4058 | join(other) {
|
4059 | let detail = (Array.isArray(this.type) ? this.type : [this])
|
4060 | .concat(Array.isArray(other.type) ? other.type : [other]);
|
4061 | return new BlockInfo(this.from, this.length + other.length, this.top, this.height + other.height, detail);
|
4062 | }
|
4063 | }
|
4064 | var QueryType = (function (QueryType) {
|
4065 | QueryType[QueryType["ByPos"] = 0] = "ByPos";
|
4066 | QueryType[QueryType["ByHeight"] = 1] = "ByHeight";
|
4067 | QueryType[QueryType["ByPosNoHeight"] = 2] = "ByPosNoHeight";
|
4068 | return QueryType})(QueryType || (QueryType = {}));
|
4069 | const Epsilon = 1e-3;
|
4070 | class HeightMap {
|
4071 | constructor(length, // The number of characters covered
|
4072 | height, // Height of this part of the document
|
4073 | flags = 2 /* Outdated */) {
|
4074 | this.length = length;
|
4075 | this.height = height;
|
4076 | this.flags = flags;
|
4077 | }
|
4078 | get outdated() { return (this.flags & 2 ) > 0; }
|
4079 | set outdated(value) { this.flags = (value ? 2 : 0) | (this.flags & ~2 ); }
|
4080 | setHeight(oracle, height) {
|
4081 | if (this.height != height) {
|
4082 | if (Math.abs(this.height - height) > Epsilon)
|
4083 | oracle.heightChanged = true;
|
4084 | this.height = height;
|
4085 | }
|
4086 | }
|
4087 |
|
4088 |
|
4089 |
|
4090 | replace(_from, _to, nodes) {
|
4091 | return HeightMap.of(nodes);
|
4092 | }
|
4093 |
|
4094 | decomposeLeft(_to, result) { result.push(this); }
|
4095 | decomposeRight(_from, result) { result.push(this); }
|
4096 | applyChanges(decorations, oldDoc, oracle, changes) {
|
4097 | let me = this;
|
4098 | for (let i = changes.length - 1; i >= 0; i--) {
|
4099 | let { fromA, toA, fromB, toB } = changes[i];
|
4100 | let start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
|
4101 | let end = start.to >= toA ? start : me.lineAt(toA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
|
4102 | toB += end.to - toA;
|
4103 | toA = end.to;
|
4104 | while (i > 0 && start.from <= changes[i - 1].toA) {
|
4105 | fromA = changes[i - 1].fromA;
|
4106 | fromB = changes[i - 1].fromB;
|
4107 | i--;
|
4108 | if (fromA < start.from)
|
4109 | start = me.lineAt(fromA, QueryType.ByPosNoHeight, oldDoc, 0, 0);
|
4110 | }
|
4111 | fromB += start.from - fromA;
|
4112 | fromA = start.from;
|
4113 | let nodes = NodeBuilder.build(oracle, decorations, fromB, toB);
|
4114 | me = me.replace(fromA, toA, nodes);
|
4115 | }
|
4116 | return me.updateHeight(oracle, 0);
|
4117 | }
|
4118 | static empty() { return new HeightMapText(0, 0); }
|
4119 |
|
4120 |
|
4121 |
|
4122 |
|
4123 | static of(nodes) {
|
4124 | if (nodes.length == 1)
|
4125 | return nodes[0];
|
4126 | let i = 0, j = nodes.length, before = 0, after = 0;
|
4127 | for (;;) {
|
4128 | if (i == j) {
|
4129 | if (before > after * 2) {
|
4130 | let split = nodes[i - 1];
|
4131 | if (split.break)
|
4132 | nodes.splice(--i, 1, split.left, null, split.right);
|
4133 | else
|
4134 | nodes.splice(--i, 1, split.left, split.right);
|
4135 | j += 1 + split.break;
|
4136 | before -= split.size;
|
4137 | }
|
4138 | else if (after > before * 2) {
|
4139 | let split = nodes[j];
|
4140 | if (split.break)
|
4141 | nodes.splice(j, 1, split.left, null, split.right);
|
4142 | else
|
4143 | nodes.splice(j, 1, split.left, split.right);
|
4144 | j += 2 + split.break;
|
4145 | after -= split.size;
|
4146 | }
|
4147 | else {
|
4148 | break;
|
4149 | }
|
4150 | }
|
4151 | else if (before < after) {
|
4152 | let next = nodes[i++];
|
4153 | if (next)
|
4154 | before += next.size;
|
4155 | }
|
4156 | else {
|
4157 | let next = nodes[--j];
|
4158 | if (next)
|
4159 | after += next.size;
|
4160 | }
|
4161 | }
|
4162 | let brk = 0;
|
4163 | if (nodes[i - 1] == null) {
|
4164 | brk = 1;
|
4165 | i--;
|
4166 | }
|
4167 | else if (nodes[i] == null) {
|
4168 | brk = 1;
|
4169 | j++;
|
4170 | }
|
4171 | return new HeightMapBranch(HeightMap.of(nodes.slice(0, i)), brk, HeightMap.of(nodes.slice(j)));
|
4172 | }
|
4173 | }
|
4174 | HeightMap.prototype.size = 1;
|
4175 | class HeightMapBlock extends HeightMap {
|
4176 | constructor(length, height, type) {
|
4177 | super(length, height);
|
4178 | this.type = type;
|
4179 | }
|
4180 | blockAt(_height, _doc, top, offset) {
|
4181 | return new BlockInfo(offset, this.length, top, this.height, this.type);
|
4182 | }
|
4183 | lineAt(_value, _type, doc, top, offset) {
|
4184 | return this.blockAt(0, doc, top, offset);
|
4185 | }
|
4186 | forEachLine(from, to, doc, top, offset, f) {
|
4187 | if (from <= offset + this.length && to >= offset)
|
4188 | f(this.blockAt(0, doc, top, offset));
|
4189 | }
|
4190 | updateHeight(oracle, offset = 0, _force = false, measured) {
|
4191 | if (measured && measured.from <= offset && measured.more)
|
4192 | this.setHeight(oracle, measured.heights[measured.index++]);
|
4193 | this.outdated = false;
|
4194 | return this;
|
4195 | }
|
4196 | toString() { return `block(${this.length})`; }
|
4197 | }
|
4198 | class HeightMapText extends HeightMapBlock {
|
4199 | constructor(length, height) {
|
4200 | super(length, height, BlockType.Text);
|
4201 | this.collapsed = 0;
|
4202 | this.widgetHeight = 0;
|
4203 | }
|
4204 | replace(_from, _to, nodes) {
|
4205 | let node = nodes[0];
|
4206 | if (nodes.length == 1 && (node instanceof HeightMapText || node instanceof HeightMapGap && (node.flags & 4 )) &&
|
4207 | Math.abs(this.length - node.length) < 10) {
|
4208 | if (node instanceof HeightMapGap)
|
4209 | node = new HeightMapText(node.length, this.height);
|
4210 | else
|
4211 | node.height = this.height;
|
4212 | if (!this.outdated)
|
4213 | node.outdated = false;
|
4214 | return node;
|
4215 | }
|
4216 | else {
|
4217 | return HeightMap.of(nodes);
|
4218 | }
|
4219 | }
|
4220 | updateHeight(oracle, offset = 0, force = false, measured) {
|
4221 | if (measured && measured.from <= offset && measured.more)
|
4222 | this.setHeight(oracle, measured.heights[measured.index++]);
|
4223 | else if (force || this.outdated)
|
4224 | this.setHeight(oracle, Math.max(this.widgetHeight, oracle.heightForLine(this.length - this.collapsed)));
|
4225 | this.outdated = false;
|
4226 | return this;
|
4227 | }
|
4228 | toString() {
|
4229 | return `line(${this.length}${this.collapsed ? -this.collapsed : ""}${this.widgetHeight ? ":" + this.widgetHeight : ""})`;
|
4230 | }
|
4231 | }
|
4232 | class HeightMapGap extends HeightMap {
|
4233 | constructor(length) { super(length, 0); }
|
4234 | lines(doc, offset) {
|
4235 | let firstLine = doc.lineAt(offset).number, lastLine = doc.lineAt(offset + this.length).number;
|
4236 | return { firstLine, lastLine, lineHeight: this.height / (lastLine - firstLine + 1) };
|
4237 | }
|
4238 | blockAt(height, doc, top, offset) {
|
4239 | let { firstLine, lastLine, lineHeight } = this.lines(doc, offset);
|
4240 | let line = Math.max(0, Math.min(lastLine - firstLine, Math.floor((height - top) / lineHeight)));
|
4241 | let { from, length } = doc.line(firstLine + line);
|
4242 | return new BlockInfo(from, length, top + lineHeight * line, lineHeight, BlockType.Text);
|
4243 | }
|
4244 | lineAt(value, type, doc, top, offset) {
|
4245 | if (type == QueryType.ByHeight)
|
4246 | return this.blockAt(value, doc, top, offset);
|
4247 | if (type == QueryType.ByPosNoHeight) {
|
4248 | let { from, to } = doc.lineAt(value);
|
4249 | return new BlockInfo(from, to - from, 0, 0, BlockType.Text);
|
4250 | }
|
4251 | let { firstLine, lineHeight } = this.lines(doc, offset);
|
4252 | let { from, length, number } = doc.lineAt(value);
|
4253 | return new BlockInfo(from, length, top + lineHeight * (number - firstLine), lineHeight, BlockType.Text);
|
4254 | }
|
4255 | forEachLine(from, to, doc, top, offset, f) {
|
4256 | let { firstLine, lineHeight } = this.lines(doc, offset);
|
4257 | for (let pos = Math.max(from, offset), end = Math.min(offset + this.length, to); pos <= end;) {
|
4258 | let line = doc.lineAt(pos);
|
4259 | if (pos == from)
|
4260 | top += lineHeight * (line.number - firstLine);
|
4261 | f(new BlockInfo(line.from, line.length, top, lineHeight, BlockType.Text));
|
4262 | top += lineHeight;
|
4263 | pos = line.to + 1;
|
4264 | }
|
4265 | }
|
4266 | replace(from, to, nodes) {
|
4267 | let after = this.length - to;
|
4268 | if (after > 0) {
|
4269 | let last = nodes[nodes.length - 1];
|
4270 | if (last instanceof HeightMapGap)
|
4271 | nodes[nodes.length - 1] = new HeightMapGap(last.length + after);
|
4272 | else
|
4273 | nodes.push(null, new HeightMapGap(after - 1));
|
4274 | }
|
4275 | if (from > 0) {
|
4276 | let first = nodes[0];
|
4277 | if (first instanceof HeightMapGap)
|
4278 | nodes[0] = new HeightMapGap(from + first.length);
|
4279 | else
|
4280 | nodes.unshift(new HeightMapGap(from - 1), null);
|
4281 | }
|
4282 | return HeightMap.of(nodes);
|
4283 | }
|
4284 | decomposeLeft(to, result) {
|
4285 | result.push(new HeightMapGap(to - 1), null);
|
4286 | }
|
4287 | decomposeRight(from, result) {
|
4288 | result.push(null, new HeightMapGap(this.length - from - 1));
|
4289 | }
|
4290 | updateHeight(oracle, offset = 0, force = false, measured) {
|
4291 | let end = offset + this.length;
|
4292 | if (measured && measured.from <= offset + this.length && measured.more) {
|
4293 |
|
4294 |
|
4295 |
|
4296 |
|
4297 | let nodes = [], pos = Math.max(offset, measured.from), singleHeight = -1;
|
4298 | let wasChanged = oracle.heightChanged;
|
4299 | if (measured.from > offset)
|
4300 | nodes.push(new HeightMapGap(measured.from - offset - 1).updateHeight(oracle, offset));
|
4301 | while (pos <= end && measured.more) {
|
4302 | let len = oracle.doc.lineAt(pos).length;
|
4303 | if (nodes.length)
|
4304 | nodes.push(null);
|
4305 | let height = measured.heights[measured.index++];
|
4306 | if (singleHeight == -1)
|
4307 | singleHeight = height;
|
4308 | else if (Math.abs(height - singleHeight) >= Epsilon)
|
4309 | singleHeight = -2;
|
4310 | let line = new HeightMapText(len, height);
|
4311 | line.outdated = false;
|
4312 | nodes.push(line);
|
4313 | pos += len + 1;
|
4314 | }
|
4315 | if (pos <= end)
|
4316 | nodes.push(null, new HeightMapGap(end - pos).updateHeight(oracle, pos));
|
4317 | let result = HeightMap.of(nodes);
|
4318 | oracle.heightChanged = wasChanged || singleHeight < 0 || Math.abs(result.height - this.height) >= Epsilon ||
|
4319 | Math.abs(singleHeight - this.lines(oracle.doc, offset).lineHeight) >= Epsilon;
|
4320 | return result;
|
4321 | }
|
4322 | else if (force || this.outdated) {
|
4323 | this.setHeight(oracle, oracle.heightForGap(offset, offset + this.length));
|
4324 | this.outdated = false;
|
4325 | }
|
4326 | return this;
|
4327 | }
|
4328 | toString() { return `gap(${this.length})`; }
|
4329 | }
|
4330 | class HeightMapBranch extends HeightMap {
|
4331 | constructor(left, brk, right) {
|
4332 | super(left.length + brk + right.length, left.height + right.height, brk | (left.outdated || right.outdated ? 2 : 0));
|
4333 | this.left = left;
|
4334 | this.right = right;
|
4335 | this.size = left.size + right.size;
|
4336 | }
|
4337 | get break() { return this.flags & 1 ; }
|
4338 | blockAt(height, doc, top, offset) {
|
4339 | let mid = top + this.left.height;
|
4340 | return height < mid ? this.left.blockAt(height, doc, top, offset)
|
4341 | : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break);
|
4342 | }
|
4343 | lineAt(value, type, doc, top, offset) {
|
4344 | let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
4345 | let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
|
4346 | let base = left ? this.left.lineAt(value, type, doc, top, offset)
|
4347 | : this.right.lineAt(value, type, doc, rightTop, rightOffset);
|
4348 | if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
|
4349 | return base;
|
4350 | let subQuery = type == QueryType.ByPosNoHeight ? QueryType.ByPosNoHeight : QueryType.ByPos;
|
4351 | if (left)
|
4352 | return base.join(this.right.lineAt(rightOffset, subQuery, doc, rightTop, rightOffset));
|
4353 | else
|
4354 | return this.left.lineAt(rightOffset, subQuery, doc, top, offset).join(base);
|
4355 | }
|
4356 | forEachLine(from, to, doc, top, offset, f) {
|
4357 | let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
|
4358 | if (this.break) {
|
4359 | if (from < rightOffset)
|
4360 | this.left.forEachLine(from, to, doc, top, offset, f);
|
4361 | if (to >= rightOffset)
|
4362 | this.right.forEachLine(from, to, doc, rightTop, rightOffset, f);
|
4363 | }
|
4364 | else {
|
4365 | let mid = this.lineAt(rightOffset, QueryType.ByPos, doc, top, offset);
|
4366 | if (from < mid.from)
|
4367 | this.left.forEachLine(from, mid.from - 1, doc, top, offset, f);
|
4368 | if (mid.to >= from && mid.from <= to)
|
4369 | f(mid);
|
4370 | if (to > mid.to)
|
4371 | this.right.forEachLine(mid.to + 1, to, doc, rightTop, rightOffset, f);
|
4372 | }
|
4373 | }
|
4374 | replace(from, to, nodes) {
|
4375 | let rightStart = this.left.length + this.break;
|
4376 | if (to < rightStart)
|
4377 | return this.balanced(this.left.replace(from, to, nodes), this.right);
|
4378 | if (from > this.left.length)
|
4379 | return this.balanced(this.left, this.right.replace(from - rightStart, to - rightStart, nodes));
|
4380 | let result = [];
|
4381 | if (from > 0)
|
4382 | this.decomposeLeft(from, result);
|
4383 | let left = result.length;
|
4384 | for (let node of nodes)
|
4385 | result.push(node);
|
4386 | if (from > 0)
|
4387 | mergeGaps(result, left - 1);
|
4388 | if (to < this.length) {
|
4389 | let right = result.length;
|
4390 | this.decomposeRight(to, result);
|
4391 | mergeGaps(result, right);
|
4392 | }
|
4393 | return HeightMap.of(result);
|
4394 | }
|
4395 | decomposeLeft(to, result) {
|
4396 | let left = this.left.length;
|
4397 | if (to <= left)
|
4398 | return this.left.decomposeLeft(to, result);
|
4399 | result.push(this.left);
|
4400 | if (this.break) {
|
4401 | left++;
|
4402 | if (to >= left)
|
4403 | result.push(null);
|
4404 | }
|
4405 | if (to > left)
|
4406 | this.right.decomposeLeft(to - left, result);
|
4407 | }
|
4408 | decomposeRight(from, result) {
|
4409 | let left = this.left.length, right = left + this.break;
|
4410 | if (from >= right)
|
4411 | return this.right.decomposeRight(from - right, result);
|
4412 | if (from < left)
|
4413 | this.left.decomposeRight(from, result);
|
4414 | if (this.break && from < right)
|
4415 | result.push(null);
|
4416 | result.push(this.right);
|
4417 | }
|
4418 | balanced(left, right) {
|
4419 | if (left.size > 2 * right.size || right.size > 2 * left.size)
|
4420 | return HeightMap.of(this.break ? [left, null, right] : [left, right]);
|
4421 | this.left = left;
|
4422 | this.right = right;
|
4423 | this.height = left.height + right.height;
|
4424 | this.outdated = left.outdated || right.outdated;
|
4425 | this.size = left.size + right.size;
|
4426 | this.length = left.length + this.break + right.length;
|
4427 | return this;
|
4428 | }
|
4429 | updateHeight(oracle, offset = 0, force = false, measured) {
|
4430 | let { left, right } = this, rightStart = offset + left.length + this.break, rebalance = null;
|
4431 | if (measured && measured.from <= offset + left.length && measured.more)
|
4432 | rebalance = left = left.updateHeight(oracle, offset, force, measured);
|
4433 | else
|
4434 | left.updateHeight(oracle, offset, force);
|
4435 | if (measured && measured.from <= rightStart + right.length && measured.more)
|
4436 | rebalance = right = right.updateHeight(oracle, rightStart, force, measured);
|
4437 | else
|
4438 | right.updateHeight(oracle, rightStart, force);
|
4439 | if (rebalance)
|
4440 | return this.balanced(left, right);
|
4441 | this.height = this.left.height + this.right.height;
|
4442 | this.outdated = false;
|
4443 | return this;
|
4444 | }
|
4445 | toString() { return this.left + (this.break ? " " : "-") + this.right; }
|
4446 | }
|
4447 | function mergeGaps(nodes, around) {
|
4448 | let before, after;
|
4449 | if (nodes[around] == null &&
|
4450 | (before = nodes[around - 1]) instanceof HeightMapGap &&
|
4451 | (after = nodes[around + 1]) instanceof HeightMapGap)
|
4452 | nodes.splice(around - 1, 3, new HeightMapGap(before.length + 1 + after.length));
|
4453 | }
|
4454 | const relevantWidgetHeight = 5;
|
4455 | class NodeBuilder {
|
4456 | constructor(pos, oracle) {
|
4457 | this.pos = pos;
|
4458 | this.oracle = oracle;
|
4459 | this.nodes = [];
|
4460 | this.lineStart = -1;
|
4461 | this.lineEnd = -1;
|
4462 | this.covering = null;
|
4463 | this.writtenTo = pos;
|
4464 | }
|
4465 | get isCovered() {
|
4466 | return this.covering && this.nodes[this.nodes.length - 1] == this.covering;
|
4467 | }
|
4468 | span(_from, to) {
|
4469 | if (this.lineStart > -1) {
|
4470 | let end = Math.min(to, this.lineEnd), last = this.nodes[this.nodes.length - 1];
|
4471 | if (last instanceof HeightMapText)
|
4472 | last.length += end - this.pos;
|
4473 | else if (end > this.pos || !this.isCovered)
|
4474 | this.nodes.push(new HeightMapText(end - this.pos, -1));
|
4475 | this.writtenTo = end;
|
4476 | if (to > end) {
|
4477 | this.nodes.push(null);
|
4478 | this.writtenTo++;
|
4479 | this.lineStart = -1;
|
4480 | }
|
4481 | }
|
4482 | this.pos = to;
|
4483 | }
|
4484 | point(from, to, deco) {
|
4485 | if (from < to || deco.heightRelevant) {
|
4486 | let height = deco.widget ? deco.widget.estimatedHeight : 0;
|
4487 | if (height < 0)
|
4488 | height = this.oracle.lineHeight;
|
4489 | let len = to - from;
|
4490 | if (deco.block) {
|
4491 | this.addBlock(new HeightMapBlock(len, height, deco.type));
|
4492 | }
|
4493 | else if (len || height >= relevantWidgetHeight) {
|
4494 | this.addLineDeco(height, len);
|
4495 | }
|
4496 | }
|
4497 | else if (to > from) {
|
4498 | this.span(from, to);
|
4499 | }
|
4500 | if (this.lineEnd > -1 && this.lineEnd < this.pos)
|
4501 | this.lineEnd = this.oracle.doc.lineAt(this.pos).to;
|
4502 | }
|
4503 | enterLine() {
|
4504 | if (this.lineStart > -1)
|
4505 | return;
|
4506 | let { from, to } = this.oracle.doc.lineAt(this.pos);
|
4507 | this.lineStart = from;
|
4508 | this.lineEnd = to;
|
4509 | if (this.writtenTo < from) {
|
4510 | if (this.writtenTo < from - 1 || this.nodes[this.nodes.length - 1] == null)
|
4511 | this.nodes.push(this.blankContent(this.writtenTo, from - 1));
|
4512 | this.nodes.push(null);
|
4513 | }
|
4514 | if (this.pos > from)
|
4515 | this.nodes.push(new HeightMapText(this.pos - from, -1));
|
4516 | this.writtenTo = this.pos;
|
4517 | }
|
4518 | blankContent(from, to) {
|
4519 | let gap = new HeightMapGap(to - from);
|
4520 | if (this.oracle.doc.lineAt(from).to == to)
|
4521 | gap.flags |= 4 ;
|
4522 | return gap;
|
4523 | }
|
4524 | ensureLine() {
|
4525 | this.enterLine();
|
4526 | let last = this.nodes.length ? this.nodes[this.nodes.length - 1] : null;
|
4527 | if (last instanceof HeightMapText)
|
4528 | return last;
|
4529 | let line = new HeightMapText(0, -1);
|
4530 | this.nodes.push(line);
|
4531 | return line;
|
4532 | }
|
4533 | addBlock(block) {
|
4534 | this.enterLine();
|
4535 | if (block.type == BlockType.WidgetAfter && !this.isCovered)
|
4536 | this.ensureLine();
|
4537 | this.nodes.push(block);
|
4538 | this.writtenTo = this.pos = this.pos + block.length;
|
4539 | if (block.type != BlockType.WidgetBefore)
|
4540 | this.covering = block;
|
4541 | }
|
4542 | addLineDeco(height, length) {
|
4543 | let line = this.ensureLine();
|
4544 | line.length += length;
|
4545 | line.collapsed += length;
|
4546 | line.widgetHeight = Math.max(line.widgetHeight, height);
|
4547 | this.writtenTo = this.pos = this.pos + length;
|
4548 | }
|
4549 | finish(from) {
|
4550 | let last = this.nodes.length == 0 ? null : this.nodes[this.nodes.length - 1];
|
4551 | if (this.lineStart > -1 && !(last instanceof HeightMapText) && !this.isCovered)
|
4552 | this.nodes.push(new HeightMapText(0, -1));
|
4553 | else if (this.writtenTo < this.pos || last == null)
|
4554 | this.nodes.push(this.blankContent(this.writtenTo, this.pos));
|
4555 | let pos = from;
|
4556 | for (let node of this.nodes) {
|
4557 | if (node instanceof HeightMapText)
|
4558 | node.updateHeight(this.oracle, pos);
|
4559 | pos += node ? node.length : 1;
|
4560 | }
|
4561 | return this.nodes;
|
4562 | }
|
4563 |
|
4564 |
|
4565 |
|
4566 |
|
4567 |
|
4568 | static build(oracle, decorations, from, to) {
|
4569 | let builder = new NodeBuilder(from, oracle);
|
4570 | RangeSet.spans(decorations, from, to, builder, 0);
|
4571 | return builder.finish(from);
|
4572 | }
|
4573 | }
|
4574 | function heightRelevantDecoChanges(a, b, diff) {
|
4575 | let comp = new DecorationComparator;
|
4576 | RangeSet.compare(a, b, diff, comp, 0);
|
4577 | return comp.changes;
|
4578 | }
|
4579 | class DecorationComparator {
|
4580 | constructor() {
|
4581 | this.changes = [];
|
4582 | }
|
4583 | compareRange() { }
|
4584 | comparePoint(from, to, a, b) {
|
4585 | if (from < to || a && a.heightRelevant || b && b.heightRelevant)
|
4586 | addRange(from, to, this.changes, 5);
|
4587 | }
|
4588 | }
|
4589 |
|
4590 | function visiblePixelRange(dom, paddingTop) {
|
4591 | let rect = dom.getBoundingClientRect();
|
4592 | let left = Math.max(0, rect.left), right = Math.min(innerWidth, rect.right);
|
4593 | let top = Math.max(0, rect.top), bottom = Math.min(innerHeight, rect.bottom);
|
4594 | let body = dom.ownerDocument.body;
|
4595 | for (let parent = dom.parentNode; parent && parent != body;) {
|
4596 | if (parent.nodeType == 1) {
|
4597 | let elt = parent;
|
4598 | let style = window.getComputedStyle(elt);
|
4599 | if ((elt.scrollHeight > elt.clientHeight || elt.scrollWidth > elt.clientWidth) &&
|
4600 | style.overflow != "visible") {
|
4601 | let parentRect = elt.getBoundingClientRect();
|
4602 | left = Math.max(left, parentRect.left);
|
4603 | right = Math.min(right, parentRect.right);
|
4604 | top = Math.max(top, parentRect.top);
|
4605 | bottom = Math.min(bottom, parentRect.bottom);
|
4606 | }
|
4607 | parent = style.position == "absolute" || style.position == "fixed" ? elt.offsetParent : elt.parentNode;
|
4608 | }
|
4609 | else if (parent.nodeType == 11) {
|
4610 | parent = parent.host;
|
4611 | }
|
4612 | else {
|
4613 | break;
|
4614 | }
|
4615 | }
|
4616 | return { left: left - rect.left, right: Math.max(left, right) - rect.left,
|
4617 | top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
|
4618 | }
|
4619 | function fullPixelRange(dom, paddingTop) {
|
4620 | let rect = dom.getBoundingClientRect();
|
4621 | return { left: 0, right: rect.right - rect.left,
|
4622 | top: paddingTop, bottom: rect.bottom - (rect.top + paddingTop) };
|
4623 | }
|
4624 |
|
4625 |
|
4626 |
|
4627 | class LineGap {
|
4628 | constructor(from, to, size) {
|
4629 | this.from = from;
|
4630 | this.to = to;
|
4631 | this.size = size;
|
4632 | }
|
4633 | static same(a, b) {
|
4634 | if (a.length != b.length)
|
4635 | return false;
|
4636 | for (let i = 0; i < a.length; i++) {
|
4637 | let gA = a[i], gB = b[i];
|
4638 | if (gA.from != gB.from || gA.to != gB.to || gA.size != gB.size)
|
4639 | return false;
|
4640 | }
|
4641 | return true;
|
4642 | }
|
4643 | draw(wrapping) {
|
4644 | return Decoration.replace({ widget: new LineGapWidget(this.size, wrapping) }).range(this.from, this.to);
|
4645 | }
|
4646 | }
|
4647 | class LineGapWidget extends WidgetType {
|
4648 | constructor(size, vertical) {
|
4649 | super();
|
4650 | this.size = size;
|
4651 | this.vertical = vertical;
|
4652 | }
|
4653 | eq(other) { return other.size == this.size && other.vertical == this.vertical; }
|
4654 | toDOM() {
|
4655 | let elt = document.createElement("div");
|
4656 | if (this.vertical) {
|
4657 | elt.style.height = this.size + "px";
|
4658 | }
|
4659 | else {
|
4660 | elt.style.width = this.size + "px";
|
4661 | elt.style.height = "2px";
|
4662 | elt.style.display = "inline-block";
|
4663 | }
|
4664 | return elt;
|
4665 | }
|
4666 | get estimatedHeight() { return this.vertical ? this.size : -1; }
|
4667 | }
|
4668 | class ViewState {
|
4669 | constructor(state) {
|
4670 | this.state = state;
|
4671 |
|
4672 | this.pixelViewport = { left: 0, right: window.innerWidth, top: 0, bottom: 0 };
|
4673 | this.inView = true;
|
4674 | this.paddingTop = 0;
|
4675 | this.paddingBottom = 0;
|
4676 | this.contentDOMWidth = 0;
|
4677 | this.contentDOMHeight = 0;
|
4678 | this.editorHeight = 0;
|
4679 | this.editorWidth = 0;
|
4680 | this.heightOracle = new HeightOracle;
|
4681 |
|
4682 | this.scaler = IdScaler;
|
4683 | this.scrollTarget = null;
|
4684 |
|
4685 | this.printing = false;
|
4686 |
|
4687 |
|
4688 | this.mustMeasureContent = true;
|
4689 | this.defaultTextDirection = Direction.RTL;
|
4690 | this.visibleRanges = [];
|
4691 |
|
4692 |
|
4693 |
|
4694 |
|
4695 |
|
4696 |
|
4697 |
|
4698 |
|
4699 | this.mustEnforceCursorAssoc = false;
|
4700 | this.stateDeco = state.facet(decorations).filter(d => typeof d != "function");
|
4701 | this.heightMap = HeightMap.empty().applyChanges(this.stateDeco, Text.empty, this.heightOracle.setDoc(state.doc), [new ChangedRange(0, 0, 0, state.doc.length)]);
|
4702 | this.viewport = this.getViewport(0, null);
|
4703 | this.updateViewportLines();
|
4704 | this.updateForViewport();
|
4705 | this.lineGaps = this.ensureLineGaps([]);
|
4706 | this.lineGapDeco = Decoration.set(this.lineGaps.map(gap => gap.draw(false)));
|
4707 | this.computeVisibleRanges();
|
4708 | }
|
4709 | updateForViewport() {
|
4710 | let viewports = [this.viewport], { main } = this.state.selection;
|
4711 | for (let i = 0; i <= 1; i++) {
|
4712 | let pos = i ? main.head : main.anchor;
|
4713 | if (!viewports.some(({ from, to }) => pos >= from && pos <= to)) {
|
4714 | let { from, to } = this.lineBlockAt(pos);
|
4715 | viewports.push(new Viewport(from, to));
|
4716 | }
|
4717 | }
|
4718 | this.viewports = viewports.sort((a, b) => a.from - b.from);
|
4719 | this.scaler = this.heightMap.height <= 7000000 ? IdScaler :
|
4720 | new BigScaler(this.heightOracle.doc, this.heightMap, this.viewports);
|
4721 | }
|
4722 | updateViewportLines() {
|
4723 | this.viewportLines = [];
|
4724 | this.heightMap.forEachLine(this.viewport.from, this.viewport.to, this.state.doc, 0, 0, block => {
|
4725 | this.viewportLines.push(this.scaler.scale == 1 ? block : scaleBlock(block, this.scaler));
|
4726 | });
|
4727 | }
|
4728 | update(update, scrollTarget = null) {
|
4729 | this.state = update.state;
|
4730 | let prevDeco = this.stateDeco;
|
4731 | this.stateDeco = this.state.facet(decorations).filter(d => typeof d != "function");
|
4732 | let contentChanges = update.changedRanges;
|
4733 | let heightChanges = ChangedRange.extendWithRanges(contentChanges, heightRelevantDecoChanges(prevDeco, this.stateDeco, update ? update.changes : ChangeSet.empty(this.state.doc.length)));
|
4734 | let prevHeight = this.heightMap.height;
|
4735 | this.heightMap = this.heightMap.applyChanges(this.stateDeco, update.startState.doc, this.heightOracle.setDoc(this.state.doc), heightChanges);
|
4736 | if (this.heightMap.height != prevHeight)
|
4737 | update.flags |= 2 ;
|
4738 | let viewport = heightChanges.length ? this.mapViewport(this.viewport, update.changes) : this.viewport;
|
4739 | if (scrollTarget && (scrollTarget.range.head < viewport.from || scrollTarget.range.head > viewport.to) ||
|
4740 | !this.viewportIsAppropriate(viewport))
|
4741 | viewport = this.getViewport(0, scrollTarget);
|
4742 | let updateLines = !update.changes.empty || (update.flags & 2 ) ||
|
4743 | viewport.from != this.viewport.from || viewport.to != this.viewport.to;
|
4744 | this.viewport = viewport;
|
4745 | this.updateForViewport();
|
4746 | if (updateLines)
|
4747 | this.updateViewportLines();
|
4748 | if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 )
|
4749 | this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps, update.changes)));
|
4750 | update.flags |= this.computeVisibleRanges();
|
4751 | if (scrollTarget)
|
4752 | this.scrollTarget = scrollTarget;
|
4753 | if (!this.mustEnforceCursorAssoc && update.selectionSet && update.view.lineWrapping &&
|
4754 | update.state.selection.main.empty && update.state.selection.main.assoc)
|
4755 | this.mustEnforceCursorAssoc = true;
|
4756 | }
|
4757 | measure(view) {
|
4758 | let dom = view.contentDOM, style = window.getComputedStyle(dom);
|
4759 | let oracle = this.heightOracle;
|
4760 | let whiteSpace = style.whiteSpace;
|
4761 | this.defaultTextDirection = style.direction == "rtl" ? Direction.RTL : Direction.LTR;
|
4762 | let refresh = this.heightOracle.mustRefreshForWrapping(whiteSpace);
|
4763 | let measureContent = refresh || this.mustMeasureContent || this.contentDOMHeight != dom.clientHeight;
|
4764 | this.contentDOMHeight = dom.clientHeight;
|
4765 | this.mustMeasureContent = false;
|
4766 | let result = 0, bias = 0;
|
4767 |
|
4768 | let paddingTop = parseInt(style.paddingTop) || 0, paddingBottom = parseInt(style.paddingBottom) || 0;
|
4769 | if (this.paddingTop != paddingTop || this.paddingBottom != paddingBottom) {
|
4770 | this.paddingTop = paddingTop;
|
4771 | this.paddingBottom = paddingBottom;
|
4772 | result |= 8 | 2 ;
|
4773 | }
|
4774 | if (this.editorWidth != view.scrollDOM.clientWidth) {
|
4775 | if (oracle.lineWrapping)
|
4776 | measureContent = true;
|
4777 | this.editorWidth = view.scrollDOM.clientWidth;
|
4778 | result |= 8 ;
|
4779 | }
|
4780 |
|
4781 | let pixelViewport = (this.printing ? fullPixelRange : visiblePixelRange)(dom, this.paddingTop);
|
4782 | let dTop = pixelViewport.top - this.pixelViewport.top, dBottom = pixelViewport.bottom - this.pixelViewport.bottom;
|
4783 | this.pixelViewport = pixelViewport;
|
4784 | let inView = this.pixelViewport.bottom > this.pixelViewport.top && this.pixelViewport.right > this.pixelViewport.left;
|
4785 | if (inView != this.inView) {
|
4786 | this.inView = inView;
|
4787 | if (inView)
|
4788 | measureContent = true;
|
4789 | }
|
4790 | if (!this.inView)
|
4791 | return 0;
|
4792 | let contentWidth = dom.clientWidth;
|
4793 | if (this.contentDOMWidth != contentWidth || this.editorHeight != view.scrollDOM.clientHeight) {
|
4794 | this.contentDOMWidth = contentWidth;
|
4795 | this.editorHeight = view.scrollDOM.clientHeight;
|
4796 | result |= 8 ;
|
4797 | }
|
4798 | if (measureContent) {
|
4799 | let lineHeights = view.docView.measureVisibleLineHeights(this.viewport);
|
4800 | if (oracle.mustRefreshForHeights(lineHeights))
|
4801 | refresh = true;
|
4802 | if (refresh || oracle.lineWrapping && Math.abs(contentWidth - this.contentDOMWidth) > oracle.charWidth) {
|
4803 | let { lineHeight, charWidth } = view.docView.measureTextSize();
|
4804 | refresh = oracle.refresh(whiteSpace, lineHeight, charWidth, contentWidth / charWidth, lineHeights);
|
4805 | if (refresh) {
|
4806 | view.docView.minWidth = 0;
|
4807 | result |= 8 ;
|
4808 | }
|
4809 | }
|
4810 | if (dTop > 0 && dBottom > 0)
|
4811 | bias = Math.max(dTop, dBottom);
|
4812 | else if (dTop < 0 && dBottom < 0)
|
4813 | bias = Math.min(dTop, dBottom);
|
4814 | oracle.heightChanged = false;
|
4815 | for (let vp of this.viewports) {
|
4816 | let heights = vp.from == this.viewport.from ? lineHeights : view.docView.measureVisibleLineHeights(vp);
|
4817 | this.heightMap = this.heightMap.updateHeight(oracle, 0, refresh, new MeasuredHeights(vp.from, heights));
|
4818 | }
|
4819 | if (oracle.heightChanged)
|
4820 | result |= 2 ;
|
4821 | }
|
4822 | let viewportChange = !this.viewportIsAppropriate(this.viewport, bias) ||
|
4823 | this.scrollTarget && (this.scrollTarget.range.head < this.viewport.from || this.scrollTarget.range.head > this.viewport.to);
|
4824 | if (viewportChange)
|
4825 | this.viewport = this.getViewport(bias, this.scrollTarget);
|
4826 | this.updateForViewport();
|
4827 | if ((result & 2 ) || viewportChange)
|
4828 | this.updateViewportLines();
|
4829 | if (this.lineGaps.length || this.viewport.to - this.viewport.from > 4000 )
|
4830 | this.updateLineGaps(this.ensureLineGaps(refresh ? [] : this.lineGaps));
|
4831 | result |= this.computeVisibleRanges();
|
4832 | if (this.mustEnforceCursorAssoc) {
|
4833 | this.mustEnforceCursorAssoc = false;
|
4834 |
|
4835 |
|
4836 |
|
4837 |
|
4838 | view.docView.enforceCursorAssoc();
|
4839 | }
|
4840 | return result;
|
4841 | }
|
4842 | get visibleTop() { return this.scaler.fromDOM(this.pixelViewport.top); }
|
4843 | get visibleBottom() { return this.scaler.fromDOM(this.pixelViewport.bottom); }
|
4844 | getViewport(bias, scrollTarget) {
|
4845 |
|
4846 |
|
4847 |
|
4848 | let marginTop = 0.5 - Math.max(-0.5, Math.min(0.5, bias / 1000 / 2));
|
4849 | let map = this.heightMap, doc = this.state.doc, { visibleTop, visibleBottom } = this;
|
4850 | let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 , QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 , QueryType.ByHeight, doc, 0, 0).to);
|
4851 |
|
4852 | if (scrollTarget) {
|
4853 | let { head } = scrollTarget.range;
|
4854 | if (head < viewport.from || head > viewport.to) {
|
4855 | let viewHeight = Math.min(this.editorHeight, this.pixelViewport.bottom - this.pixelViewport.top);
|
4856 | let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
|
4857 | if (scrollTarget.y == "center")
|
4858 | topPos = (block.top + block.bottom) / 2 - viewHeight / 2;
|
4859 | else if (scrollTarget.y == "start" || scrollTarget.y == "nearest" && head < viewport.from)
|
4860 | topPos = block.top;
|
4861 | else
|
4862 | topPos = block.bottom - viewHeight;
|
4863 | viewport = new Viewport(map.lineAt(topPos - 1000 / 2, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(topPos + viewHeight + 1000 / 2, QueryType.ByHeight, doc, 0, 0).to);
|
4864 | }
|
4865 | }
|
4866 | return viewport;
|
4867 | }
|
4868 | mapViewport(viewport, changes) {
|
4869 | let from = changes.mapPos(viewport.from, -1), to = changes.mapPos(viewport.to, 1);
|
4870 | return new Viewport(this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0).from, this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0).to);
|
4871 | }
|
4872 |
|
4873 |
|
4874 | viewportIsAppropriate({ from, to }, bias = 0) {
|
4875 | if (!this.inView)
|
4876 | return true;
|
4877 | let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0);
|
4878 | let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0);
|
4879 | let { visibleTop, visibleBottom } = this;
|
4880 | return (from == 0 || top <= visibleTop - Math.max(10 , Math.min(-bias, 250 ))) &&
|
4881 | (to == this.state.doc.length ||
|
4882 | bottom >= visibleBottom + Math.max(10 , Math.min(bias, 250 ))) &&
|
4883 | (top > visibleTop - 2 * 1000 && bottom < visibleBottom + 2 * 1000 );
|
4884 | }
|
4885 | mapLineGaps(gaps, changes) {
|
4886 | if (!gaps.length || changes.empty)
|
4887 | return gaps;
|
4888 | let mapped = [];
|
4889 | for (let gap of gaps)
|
4890 | if (!changes.touchesRange(gap.from, gap.to))
|
4891 | mapped.push(new LineGap(changes.mapPos(gap.from), changes.mapPos(gap.to), gap.size));
|
4892 | return mapped;
|
4893 | }
|
4894 |
|
4895 |
|
4896 |
|
4897 |
|
4898 |
|
4899 |
|
4900 |
|
4901 | ensureLineGaps(current) {
|
4902 | let gaps = [];
|
4903 |
|
4904 | if (this.defaultTextDirection != Direction.LTR)
|
4905 | return gaps;
|
4906 | for (let line of this.viewportLines) {
|
4907 | if (line.length < 4000 )
|
4908 | continue;
|
4909 | let structure = lineStructure(line.from, line.to, this.stateDeco);
|
4910 | if (structure.total < 4000 )
|
4911 | continue;
|
4912 | let viewFrom, viewTo;
|
4913 | if (this.heightOracle.lineWrapping) {
|
4914 | let marginHeight = (2000 / this.heightOracle.lineLength) * this.heightOracle.lineHeight;
|
4915 | viewFrom = findPosition(structure, (this.visibleTop - line.top - marginHeight) / line.height);
|
4916 | viewTo = findPosition(structure, (this.visibleBottom - line.top + marginHeight) / line.height);
|
4917 | }
|
4918 | else {
|
4919 | let totalWidth = structure.total * this.heightOracle.charWidth;
|
4920 | let marginWidth = 2000 * this.heightOracle.charWidth;
|
4921 | viewFrom = findPosition(structure, (this.pixelViewport.left - marginWidth) / totalWidth);
|
4922 | viewTo = findPosition(structure, (this.pixelViewport.right + marginWidth) / totalWidth);
|
4923 | }
|
4924 | let outside = [];
|
4925 | if (viewFrom > line.from)
|
4926 | outside.push({ from: line.from, to: viewFrom });
|
4927 | if (viewTo < line.to)
|
4928 | outside.push({ from: viewTo, to: line.to });
|
4929 | let sel = this.state.selection.main;
|
4930 |
|
4931 | if (sel.from >= line.from && sel.from <= line.to)
|
4932 | cutRange(outside, sel.from - 10 , sel.from + 10 );
|
4933 | if (!sel.empty && sel.to >= line.from && sel.to <= line.to)
|
4934 | cutRange(outside, sel.to - 10 , sel.to + 10 );
|
4935 | for (let { from, to } of outside)
|
4936 | if (to - from > 1000 ) {
|
4937 | gaps.push(find(current, gap => gap.from >= line.from && gap.to <= line.to &&
|
4938 | Math.abs(gap.from - from) < 1000 && Math.abs(gap.to - to) < 1000 ) ||
|
4939 | new LineGap(from, to, this.gapSize(line, from, to, structure)));
|
4940 | }
|
4941 | }
|
4942 | return gaps;
|
4943 | }
|
4944 | gapSize(line, from, to, structure) {
|
4945 | let fraction = findFraction(structure, to) - findFraction(structure, from);
|
4946 | if (this.heightOracle.lineWrapping) {
|
4947 | return line.height * fraction;
|
4948 | }
|
4949 | else {
|
4950 | return structure.total * this.heightOracle.charWidth * fraction;
|
4951 | }
|
4952 | }
|
4953 | updateLineGaps(gaps) {
|
4954 | if (!LineGap.same(gaps, this.lineGaps)) {
|
4955 | this.lineGaps = gaps;
|
4956 | this.lineGapDeco = Decoration.set(gaps.map(gap => gap.draw(this.heightOracle.lineWrapping)));
|
4957 | }
|
4958 | }
|
4959 | computeVisibleRanges() {
|
4960 | let deco = this.stateDeco;
|
4961 | if (this.lineGaps.length)
|
4962 | deco = deco.concat(this.lineGapDeco);
|
4963 | let ranges = [];
|
4964 | RangeSet.spans(deco, this.viewport.from, this.viewport.to, {
|
4965 | span(from, to) { ranges.push({ from, to }); },
|
4966 | point() { }
|
4967 | }, 20);
|
4968 | let changed = ranges.length != this.visibleRanges.length ||
|
4969 | this.visibleRanges.some((r, i) => r.from != ranges[i].from || r.to != ranges[i].to);
|
4970 | this.visibleRanges = ranges;
|
4971 | return changed ? 4 : 0;
|
4972 | }
|
4973 | lineBlockAt(pos) {
|
4974 | return (pos >= this.viewport.from && pos <= this.viewport.to && this.viewportLines.find(b => b.from <= pos && b.to >= pos)) ||
|
4975 | scaleBlock(this.heightMap.lineAt(pos, QueryType.ByPos, this.state.doc, 0, 0), this.scaler);
|
4976 | }
|
4977 | lineBlockAtHeight(height) {
|
4978 | return scaleBlock(this.heightMap.lineAt(this.scaler.fromDOM(height), QueryType.ByHeight, this.state.doc, 0, 0), this.scaler);
|
4979 | }
|
4980 | elementAtHeight(height) {
|
4981 | return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
|
4982 | }
|
4983 | get docHeight() {
|
4984 | return this.scaler.toDOM(this.heightMap.height);
|
4985 | }
|
4986 | get contentHeight() {
|
4987 | return this.docHeight + this.paddingTop + this.paddingBottom;
|
4988 | }
|
4989 | }
|
4990 | class Viewport {
|
4991 | constructor(from, to) {
|
4992 | this.from = from;
|
4993 | this.to = to;
|
4994 | }
|
4995 | }
|
4996 | function lineStructure(from, to, stateDeco) {
|
4997 | let ranges = [], pos = from, total = 0;
|
4998 | RangeSet.spans(stateDeco, from, to, {
|
4999 | span() { },
|
5000 | point(from, to) {
|
5001 | if (from > pos) {
|
5002 | ranges.push({ from: pos, to: from });
|
5003 | total += from - pos;
|
5004 | }
|
5005 | pos = to;
|
5006 | }
|
5007 | }, 20);
|
5008 | if (pos < to) {
|
5009 | ranges.push({ from: pos, to });
|
5010 | total += to - pos;
|
5011 | }
|
5012 | return { total, ranges };
|
5013 | }
|
5014 | function findPosition({ total, ranges }, ratio) {
|
5015 | if (ratio <= 0)
|
5016 | return ranges[0].from;
|
5017 | if (ratio >= 1)
|
5018 | return ranges[ranges.length - 1].to;
|
5019 | let dist = Math.floor(total * ratio);
|
5020 | for (let i = 0;; i++) {
|
5021 | let { from, to } = ranges[i], size = to - from;
|
5022 | if (dist <= size)
|
5023 | return from + dist;
|
5024 | dist -= size;
|
5025 | }
|
5026 | }
|
5027 | function findFraction(structure, pos) {
|
5028 | let counted = 0;
|
5029 | for (let { from, to } of structure.ranges) {
|
5030 | if (pos <= to) {
|
5031 | counted += pos - from;
|
5032 | break;
|
5033 | }
|
5034 | counted += to - from;
|
5035 | }
|
5036 | return counted / structure.total;
|
5037 | }
|
5038 | function cutRange(ranges, from, to) {
|
5039 | for (let i = 0; i < ranges.length; i++) {
|
5040 | let r = ranges[i];
|
5041 | if (r.from < to && r.to > from) {
|
5042 | let pieces = [];
|
5043 | if (r.from < from)
|
5044 | pieces.push({ from: r.from, to: from });
|
5045 | if (r.to > to)
|
5046 | pieces.push({ from: to, to: r.to });
|
5047 | ranges.splice(i, 1, ...pieces);
|
5048 | i += pieces.length - 1;
|
5049 | }
|
5050 | }
|
5051 | }
|
5052 | function find(array, f) {
|
5053 | for (let val of array)
|
5054 | if (f(val))
|
5055 | return val;
|
5056 | return undefined;
|
5057 | }
|
5058 |
|
5059 |
|
5060 | const IdScaler = {
|
5061 | toDOM(n) { return n; },
|
5062 | fromDOM(n) { return n; },
|
5063 | scale: 1
|
5064 | };
|
5065 |
|
5066 |
|
5067 |
|
5068 | class BigScaler {
|
5069 | constructor(doc, heightMap, viewports) {
|
5070 | let vpHeight = 0, base = 0, domBase = 0;
|
5071 | this.viewports = viewports.map(({ from, to }) => {
|
5072 | let top = heightMap.lineAt(from, QueryType.ByPos, doc, 0, 0).top;
|
5073 | let bottom = heightMap.lineAt(to, QueryType.ByPos, doc, 0, 0).bottom;
|
5074 | vpHeight += bottom - top;
|
5075 | return { from, to, top, bottom, domTop: 0, domBottom: 0 };
|
5076 | });
|
5077 | this.scale = (7000000 - vpHeight) / (heightMap.height - vpHeight);
|
5078 | for (let obj of this.viewports) {
|
5079 | obj.domTop = domBase + (obj.top - base) * this.scale;
|
5080 | domBase = obj.domBottom = obj.domTop + (obj.bottom - obj.top);
|
5081 | base = obj.bottom;
|
5082 | }
|
5083 | }
|
5084 | toDOM(n) {
|
5085 | for (let i = 0, base = 0, domBase = 0;; i++) {
|
5086 | let vp = i < this.viewports.length ? this.viewports[i] : null;
|
5087 | if (!vp || n < vp.top)
|
5088 | return domBase + (n - base) * this.scale;
|
5089 | if (n <= vp.bottom)
|
5090 | return vp.domTop + (n - vp.top);
|
5091 | base = vp.bottom;
|
5092 | domBase = vp.domBottom;
|
5093 | }
|
5094 | }
|
5095 | fromDOM(n) {
|
5096 | for (let i = 0, base = 0, domBase = 0;; i++) {
|
5097 | let vp = i < this.viewports.length ? this.viewports[i] : null;
|
5098 | if (!vp || n < vp.domTop)
|
5099 | return base + (n - domBase) / this.scale;
|
5100 | if (n <= vp.domBottom)
|
5101 | return vp.top + (n - vp.domTop);
|
5102 | base = vp.bottom;
|
5103 | domBase = vp.domBottom;
|
5104 | }
|
5105 | }
|
5106 | }
|
5107 | function scaleBlock(block, scaler) {
|
5108 | if (scaler.scale == 1)
|
5109 | return block;
|
5110 | let bTop = scaler.toDOM(block.top), bBottom = scaler.toDOM(block.bottom);
|
5111 | return new BlockInfo(block.from, block.length, bTop, bBottom - bTop, Array.isArray(block.type) ? block.type.map(b => scaleBlock(b, scaler)) : block.type);
|
5112 | }
|
5113 |
|
5114 | const theme = Facet.define({ combine: strs => strs.join(" ") });
|
5115 | const darkTheme = Facet.define({ combine: values => values.indexOf(true) > -1 });
|
5116 | const baseThemeID = StyleModule.newName(), baseLightID = StyleModule.newName(), baseDarkID = StyleModule.newName();
|
5117 | const lightDarkIDs = { "&light": "." + baseLightID, "&dark": "." + baseDarkID };
|
5118 | function buildTheme(main, spec, scopes) {
|
5119 | return new StyleModule(spec, {
|
5120 | finish(sel) {
|
5121 | return /&/.test(sel) ? sel.replace(/&\w*/, m => {
|
5122 | if (m == "&")
|
5123 | return main;
|
5124 | if (!scopes || !scopes[m])
|
5125 | throw new RangeError(`Unsupported selector: ${m}`);
|
5126 | return scopes[m];
|
5127 | }) : main + " " + sel;
|
5128 | }
|
5129 | });
|
5130 | }
|
5131 | const baseTheme$1 = buildTheme("." + baseThemeID, {
|
5132 | "&.cm-editor": {
|
5133 | position: "relative !important",
|
5134 | boxSizing: "border-box",
|
5135 | "&.cm-focused": {
|
5136 |
|
5137 |
|
5138 |
|
5139 |
|
5140 |
|
5141 |
|
5142 |
|
5143 |
|
5144 | outline: "1px dotted #212121"
|
5145 | },
|
5146 | display: "flex !important",
|
5147 | flexDirection: "column"
|
5148 | },
|
5149 | ".cm-scroller": {
|
5150 | display: "flex !important",
|
5151 | alignItems: "flex-start !important",
|
5152 | fontFamily: "monospace",
|
5153 | lineHeight: 1.4,
|
5154 | height: "100%",
|
5155 | overflowX: "auto",
|
5156 | position: "relative",
|
5157 | zIndex: 0
|
5158 | },
|
5159 | ".cm-content": {
|
5160 | margin: 0,
|
5161 | flexGrow: 2,
|
5162 | minHeight: "100%",
|
5163 | display: "block",
|
5164 | whiteSpace: "pre",
|
5165 | wordWrap: "normal",
|
5166 | boxSizing: "border-box",
|
5167 | padding: "4px 0",
|
5168 | outline: "none",
|
5169 | "&[contenteditable=true]": {
|
5170 | WebkitUserModify: "read-write-plaintext-only",
|
5171 | }
|
5172 | },
|
5173 | ".cm-lineWrapping": {
|
5174 | whiteSpace_fallback: "pre-wrap",
|
5175 | whiteSpace: "break-spaces",
|
5176 | wordBreak: "break-word",
|
5177 | overflowWrap: "anywhere"
|
5178 | },
|
5179 | "&light .cm-content": { caretColor: "black" },
|
5180 | "&dark .cm-content": { caretColor: "white" },
|
5181 | ".cm-line": {
|
5182 | display: "block",
|
5183 | padding: "0 2px 0 4px"
|
5184 | },
|
5185 | ".cm-selectionLayer": {
|
5186 | zIndex: -1,
|
5187 | contain: "size style"
|
5188 | },
|
5189 | ".cm-selectionBackground": {
|
5190 | position: "absolute",
|
5191 | },
|
5192 | "&light .cm-selectionBackground": {
|
5193 | background: "#d9d9d9"
|
5194 | },
|
5195 | "&dark .cm-selectionBackground": {
|
5196 | background: "#222"
|
5197 | },
|
5198 | "&light.cm-focused .cm-selectionBackground": {
|
5199 | background: "#d7d4f0"
|
5200 | },
|
5201 | "&dark.cm-focused .cm-selectionBackground": {
|
5202 | background: "#233"
|
5203 | },
|
5204 | ".cm-cursorLayer": {
|
5205 | zIndex: 100,
|
5206 | contain: "size style",
|
5207 | pointerEvents: "none"
|
5208 | },
|
5209 | "&.cm-focused .cm-cursorLayer": {
|
5210 | animation: "steps(1) cm-blink 1.2s infinite"
|
5211 | },
|
5212 |
|
5213 |
|
5214 |
|
5215 | "@keyframes cm-blink": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
|
5216 | "@keyframes cm-blink2": { "0%": {}, "50%": { visibility: "hidden" }, "100%": {} },
|
5217 | ".cm-cursor, .cm-dropCursor": {
|
5218 | position: "absolute",
|
5219 | borderLeft: "1.2px solid black",
|
5220 | marginLeft: "-0.6px",
|
5221 | pointerEvents: "none",
|
5222 | },
|
5223 | ".cm-cursor": {
|
5224 | display: "none"
|
5225 | },
|
5226 | "&dark .cm-cursor": {
|
5227 | borderLeftColor: "#444"
|
5228 | },
|
5229 | "&.cm-focused .cm-cursor": {
|
5230 | display: "block"
|
5231 | },
|
5232 | "&light .cm-activeLine": { backgroundColor: "#f3f9ff" },
|
5233 | "&dark .cm-activeLine": { backgroundColor: "#223039" },
|
5234 | "&light .cm-specialChar": { color: "red" },
|
5235 | "&dark .cm-specialChar": { color: "#f78" },
|
5236 | ".cm-gutters": {
|
5237 | display: "flex",
|
5238 | height: "100%",
|
5239 | boxSizing: "border-box",
|
5240 | left: 0,
|
5241 | zIndex: 200
|
5242 | },
|
5243 | "&light .cm-gutters": {
|
5244 | backgroundColor: "#f5f5f5",
|
5245 | color: "#6c6c6c",
|
5246 | borderRight: "1px solid #ddd"
|
5247 | },
|
5248 | "&dark .cm-gutters": {
|
5249 | backgroundColor: "#333338",
|
5250 | color: "#ccc"
|
5251 | },
|
5252 | ".cm-gutter": {
|
5253 | display: "flex !important",
|
5254 | flexDirection: "column",
|
5255 | flexShrink: 0,
|
5256 | boxSizing: "border-box",
|
5257 | minHeight: "100%",
|
5258 | overflow: "hidden"
|
5259 | },
|
5260 | ".cm-gutterElement": {
|
5261 | boxSizing: "border-box"
|
5262 | },
|
5263 | ".cm-lineNumbers .cm-gutterElement": {
|
5264 | padding: "0 3px 0 5px",
|
5265 | minWidth: "20px",
|
5266 | textAlign: "right",
|
5267 | whiteSpace: "nowrap"
|
5268 | },
|
5269 | "&light .cm-activeLineGutter": {
|
5270 | backgroundColor: "#e2f2ff"
|
5271 | },
|
5272 | "&dark .cm-activeLineGutter": {
|
5273 | backgroundColor: "#222227"
|
5274 | },
|
5275 | ".cm-panels": {
|
5276 | boxSizing: "border-box",
|
5277 | position: "sticky",
|
5278 | left: 0,
|
5279 | right: 0
|
5280 | },
|
5281 | "&light .cm-panels": {
|
5282 | backgroundColor: "#f5f5f5",
|
5283 | color: "black"
|
5284 | },
|
5285 | "&light .cm-panels-top": {
|
5286 | borderBottom: "1px solid #ddd"
|
5287 | },
|
5288 | "&light .cm-panels-bottom": {
|
5289 | borderTop: "1px solid #ddd"
|
5290 | },
|
5291 | "&dark .cm-panels": {
|
5292 | backgroundColor: "#333338",
|
5293 | color: "white"
|
5294 | },
|
5295 | ".cm-tab": {
|
5296 | display: "inline-block",
|
5297 | overflow: "hidden",
|
5298 | verticalAlign: "bottom"
|
5299 | },
|
5300 | ".cm-widgetBuffer": {
|
5301 | verticalAlign: "text-top",
|
5302 | height: "1em",
|
5303 | display: "inline"
|
5304 | },
|
5305 | ".cm-placeholder": {
|
5306 | color: "#888",
|
5307 | display: "inline-block",
|
5308 | verticalAlign: "top",
|
5309 | },
|
5310 | ".cm-button": {
|
5311 | verticalAlign: "middle",
|
5312 | color: "inherit",
|
5313 | fontSize: "70%",
|
5314 | padding: ".2em 1em",
|
5315 | borderRadius: "1px"
|
5316 | },
|
5317 | "&light .cm-button": {
|
5318 | backgroundImage: "linear-gradient(#eff1f5, #d9d9df)",
|
5319 | border: "1px solid #888",
|
5320 | "&:active": {
|
5321 | backgroundImage: "linear-gradient(#b4b4b4, #d0d3d6)"
|
5322 | }
|
5323 | },
|
5324 | "&dark .cm-button": {
|
5325 | backgroundImage: "linear-gradient(#393939, #111)",
|
5326 | border: "1px solid #888",
|
5327 | "&:active": {
|
5328 | backgroundImage: "linear-gradient(#111, #333)"
|
5329 | }
|
5330 | },
|
5331 | ".cm-textfield": {
|
5332 | verticalAlign: "middle",
|
5333 | color: "inherit",
|
5334 | fontSize: "70%",
|
5335 | border: "1px solid silver",
|
5336 | padding: ".2em .5em"
|
5337 | },
|
5338 | "&light .cm-textfield": {
|
5339 | backgroundColor: "white"
|
5340 | },
|
5341 | "&dark .cm-textfield": {
|
5342 | border: "1px solid #555",
|
5343 | backgroundColor: "inherit"
|
5344 | }
|
5345 | }, lightDarkIDs);
|
5346 |
|
5347 | const observeOptions = {
|
5348 | childList: true,
|
5349 | characterData: true,
|
5350 | subtree: true,
|
5351 | attributes: true,
|
5352 | characterDataOldValue: true
|
5353 | };
|
5354 |
|
5355 |
|
5356 | const useCharData = browser.ie && browser.ie_version <= 11;
|
5357 | class DOMObserver {
|
5358 | constructor(view, onChange, onScrollChanged) {
|
5359 | this.view = view;
|
5360 | this.onChange = onChange;
|
5361 | this.onScrollChanged = onScrollChanged;
|
5362 | this.active = false;
|
5363 |
|
5364 |
|
5365 |
|
5366 |
|
5367 |
|
5368 |
|
5369 | this.selectionRange = new DOMSelectionState;
|
5370 |
|
5371 | this.selectionChanged = false;
|
5372 | this.delayedFlush = -1;
|
5373 | this.resizeTimeout = -1;
|
5374 | this.queue = [];
|
5375 | this.delayedAndroidKey = null;
|
5376 | this.scrollTargets = [];
|
5377 | this.intersection = null;
|
5378 | this.resize = null;
|
5379 | this.intersecting = false;
|
5380 | this.gapIntersection = null;
|
5381 | this.gaps = [];
|
5382 |
|
5383 | this.parentCheck = -1;
|
5384 | this.dom = view.contentDOM;
|
5385 | this.observer = new MutationObserver(mutations => {
|
5386 | for (let mut of mutations)
|
5387 | this.queue.push(mut);
|
5388 |
|
5389 |
|
5390 |
|
5391 |
|
5392 |
|
5393 |
|
5394 |
|
5395 |
|
5396 |
|
5397 | if ((browser.ie && browser.ie_version <= 11 || browser.ios && view.composing) &&
|
5398 | mutations.some(m => m.type == "childList" && m.removedNodes.length ||
|
5399 | m.type == "characterData" && m.oldValue.length > m.target.nodeValue.length))
|
5400 | this.flushSoon();
|
5401 | else
|
5402 | this.flush();
|
5403 | });
|
5404 | if (useCharData)
|
5405 | this.onCharData = (event) => {
|
5406 | this.queue.push({ target: event.target,
|
5407 | type: "characterData",
|
5408 | oldValue: event.prevValue });
|
5409 | this.flushSoon();
|
5410 | };
|
5411 | this.onSelectionChange = this.onSelectionChange.bind(this);
|
5412 | window.addEventListener("resize", this.onResize = this.onResize.bind(this));
|
5413 | if (typeof ResizeObserver == "function") {
|
5414 | this.resize = new ResizeObserver(() => {
|
5415 | if (this.view.docView.lastUpdate < Date.now() - 75)
|
5416 | this.onResize();
|
5417 | });
|
5418 | this.resize.observe(view.scrollDOM);
|
5419 | }
|
5420 | window.addEventListener("beforeprint", this.onPrint = this.onPrint.bind(this));
|
5421 | this.start();
|
5422 | window.addEventListener("scroll", this.onScroll = this.onScroll.bind(this));
|
5423 | if (typeof IntersectionObserver == "function") {
|
5424 | this.intersection = new IntersectionObserver(entries => {
|
5425 | if (this.parentCheck < 0)
|
5426 | this.parentCheck = setTimeout(this.listenForScroll.bind(this), 1000);
|
5427 | if (entries.length > 0 && (entries[entries.length - 1].intersectionRatio > 0) != this.intersecting) {
|
5428 | this.intersecting = !this.intersecting;
|
5429 | if (this.intersecting != this.view.inView)
|
5430 | this.onScrollChanged(document.createEvent("Event"));
|
5431 | }
|
5432 | }, {});
|
5433 | this.intersection.observe(this.dom);
|
5434 | this.gapIntersection = new IntersectionObserver(entries => {
|
5435 | if (entries.length > 0 && entries[entries.length - 1].intersectionRatio > 0)
|
5436 | this.onScrollChanged(document.createEvent("Event"));
|
5437 | }, {});
|
5438 | }
|
5439 | this.listenForScroll();
|
5440 | this.readSelectionRange();
|
5441 | this.dom.ownerDocument.addEventListener("selectionchange", this.onSelectionChange);
|
5442 | }
|
5443 | onScroll(e) {
|
5444 | if (this.intersecting)
|
5445 | this.flush(false);
|
5446 | this.onScrollChanged(e);
|
5447 | }
|
5448 | onResize() {
|
5449 | if (this.resizeTimeout < 0)
|
5450 | this.resizeTimeout = setTimeout(() => {
|
5451 | this.resizeTimeout = -1;
|
5452 | this.view.requestMeasure();
|
5453 | }, 50);
|
5454 | }
|
5455 | onPrint() {
|
5456 | this.view.viewState.printing = true;
|
5457 | this.view.measure();
|
5458 | setTimeout(() => {
|
5459 | this.view.viewState.printing = false;
|
5460 | this.view.requestMeasure();
|
5461 | }, 500);
|
5462 | }
|
5463 | updateGaps(gaps) {
|
5464 | if (this.gapIntersection && (gaps.length != this.gaps.length || this.gaps.some((g, i) => g != gaps[i]))) {
|
5465 | this.gapIntersection.disconnect();
|
5466 | for (let gap of gaps)
|
5467 | this.gapIntersection.observe(gap);
|
5468 | this.gaps = gaps;
|
5469 | }
|
5470 | }
|
5471 | onSelectionChange(event) {
|
5472 | if (!this.readSelectionRange() || this.delayedAndroidKey)
|
5473 | return;
|
5474 | let { view } = this, sel = this.selectionRange;
|
5475 | if (view.state.facet(editable) ? view.root.activeElement != this.dom : !hasSelection(view.dom, sel))
|
5476 | return;
|
5477 | let context = sel.anchorNode && view.docView.nearest(sel.anchorNode);
|
5478 | if (context && context.ignoreEvent(event))
|
5479 | return;
|
5480 |
|
5481 |
|
5482 |
|
5483 |
|
5484 |
|
5485 | if ((browser.ie && browser.ie_version <= 11 || browser.android && browser.chrome) && !view.state.selection.main.empty &&
|
5486 |
|
5487 | sel.focusNode && isEquivalentPosition(sel.focusNode, sel.focusOffset, sel.anchorNode, sel.anchorOffset))
|
5488 | this.flushSoon();
|
5489 | else
|
5490 | this.flush(false);
|
5491 | }
|
5492 | readSelectionRange() {
|
5493 | let { root } = this.view;
|
5494 |
|
5495 |
|
5496 | let range = browser.safari && root.nodeType == 11 && deepActiveElement() == this.view.contentDOM &&
|
5497 | safariSelectionRangeHack(this.view) || getSelection(root);
|
5498 | if (!range || this.selectionRange.eq(range))
|
5499 | return false;
|
5500 | this.selectionRange.setRange(range);
|
5501 | return this.selectionChanged = true;
|
5502 | }
|
5503 | setSelectionRange(anchor, head) {
|
5504 | this.selectionRange.set(anchor.node, anchor.offset, head.node, head.offset);
|
5505 | this.selectionChanged = false;
|
5506 | }
|
5507 | clearSelectionRange() {
|
5508 | this.selectionRange.set(null, 0, null, 0);
|
5509 | }
|
5510 | listenForScroll() {
|
5511 | this.parentCheck = -1;
|
5512 | let i = 0, changed = null;
|
5513 | for (let dom = this.dom; dom;) {
|
5514 | if (dom.nodeType == 1) {
|
5515 | if (!changed && i < this.scrollTargets.length && this.scrollTargets[i] == dom)
|
5516 | i++;
|
5517 | else if (!changed)
|
5518 | changed = this.scrollTargets.slice(0, i);
|
5519 | if (changed)
|
5520 | changed.push(dom);
|
5521 | dom = dom.assignedSlot || dom.parentNode;
|
5522 | }
|
5523 | else if (dom.nodeType == 11) {
|
5524 | dom = dom.host;
|
5525 | }
|
5526 | else {
|
5527 | break;
|
5528 | }
|
5529 | }
|
5530 | if (i < this.scrollTargets.length && !changed)
|
5531 | changed = this.scrollTargets.slice(0, i);
|
5532 | if (changed) {
|
5533 | for (let dom of this.scrollTargets)
|
5534 | dom.removeEventListener("scroll", this.onScroll);
|
5535 | for (let dom of this.scrollTargets = changed)
|
5536 | dom.addEventListener("scroll", this.onScroll);
|
5537 | }
|
5538 | }
|
5539 | ignore(f) {
|
5540 | if (!this.active)
|
5541 | return f();
|
5542 | try {
|
5543 | this.stop();
|
5544 | return f();
|
5545 | }
|
5546 | finally {
|
5547 | this.start();
|
5548 | this.clear();
|
5549 | }
|
5550 | }
|
5551 | start() {
|
5552 | if (this.active)
|
5553 | return;
|
5554 | this.observer.observe(this.dom, observeOptions);
|
5555 | if (useCharData)
|
5556 | this.dom.addEventListener("DOMCharacterDataModified", this.onCharData);
|
5557 | this.active = true;
|
5558 | }
|
5559 | stop() {
|
5560 | if (!this.active)
|
5561 | return;
|
5562 | this.active = false;
|
5563 | this.observer.disconnect();
|
5564 | if (useCharData)
|
5565 | this.dom.removeEventListener("DOMCharacterDataModified", this.onCharData);
|
5566 | }
|
5567 |
|
5568 | clear() {
|
5569 | this.processRecords();
|
5570 | this.queue.length = 0;
|
5571 | this.selectionChanged = false;
|
5572 | }
|
5573 |
|
5574 |
|
5575 |
|
5576 |
|
5577 |
|
5578 |
|
5579 |
|
5580 |
|
5581 | delayAndroidKey(key, keyCode) {
|
5582 | if (!this.delayedAndroidKey)
|
5583 | requestAnimationFrame(() => {
|
5584 | let key = this.delayedAndroidKey;
|
5585 | this.delayedAndroidKey = null;
|
5586 | this.delayedFlush = -1;
|
5587 | if (!this.flush())
|
5588 | dispatchKey(this.view.contentDOM, key.key, key.keyCode);
|
5589 | });
|
5590 |
|
5591 |
|
5592 | if (!this.delayedAndroidKey || key == "Enter")
|
5593 | this.delayedAndroidKey = { key, keyCode };
|
5594 | }
|
5595 | flushSoon() {
|
5596 | if (this.delayedFlush < 0)
|
5597 | this.delayedFlush = window.setTimeout(() => { this.delayedFlush = -1; this.flush(); }, 20);
|
5598 | }
|
5599 | forceFlush() {
|
5600 | if (this.delayedFlush >= 0) {
|
5601 | window.clearTimeout(this.delayedFlush);
|
5602 | this.delayedFlush = -1;
|
5603 | this.flush();
|
5604 | }
|
5605 | }
|
5606 | processRecords() {
|
5607 | let records = this.queue;
|
5608 | for (let mut of this.observer.takeRecords())
|
5609 | records.push(mut);
|
5610 | if (records.length)
|
5611 | this.queue = [];
|
5612 | let from = -1, to = -1, typeOver = false;
|
5613 | for (let record of records) {
|
5614 | let range = this.readMutation(record);
|
5615 | if (!range)
|
5616 | continue;
|
5617 | if (range.typeOver)
|
5618 | typeOver = true;
|
5619 | if (from == -1) {
|
5620 | ({ from, to } = range);
|
5621 | }
|
5622 | else {
|
5623 | from = Math.min(range.from, from);
|
5624 | to = Math.max(range.to, to);
|
5625 | }
|
5626 | }
|
5627 | return { from, to, typeOver };
|
5628 | }
|
5629 |
|
5630 | flush(readSelection = true) {
|
5631 |
|
5632 |
|
5633 |
|
5634 | if (this.delayedFlush >= 0 || this.delayedAndroidKey)
|
5635 | return;
|
5636 | if (readSelection)
|
5637 | this.readSelectionRange();
|
5638 | let { from, to, typeOver } = this.processRecords();
|
5639 | let newSel = this.selectionChanged && hasSelection(this.dom, this.selectionRange);
|
5640 | if (from < 0 && !newSel)
|
5641 | return;
|
5642 | this.selectionChanged = false;
|
5643 | let startState = this.view.state;
|
5644 | let handled = this.onChange(from, to, typeOver);
|
5645 |
|
5646 | if (this.view.state == startState)
|
5647 | this.view.update([]);
|
5648 | return handled;
|
5649 | }
|
5650 | readMutation(rec) {
|
5651 | let cView = this.view.docView.nearest(rec.target);
|
5652 | if (!cView || cView.ignoreMutation(rec))
|
5653 | return null;
|
5654 | cView.markDirty(rec.type == "attributes");
|
5655 | if (rec.type == "attributes")
|
5656 | cView.dirty |= 4 ;
|
5657 | if (rec.type == "childList") {
|
5658 | let childBefore = findChild(cView, rec.previousSibling || rec.target.previousSibling, -1);
|
5659 | let childAfter = findChild(cView, rec.nextSibling || rec.target.nextSibling, 1);
|
5660 | return { from: childBefore ? cView.posAfter(childBefore) : cView.posAtStart,
|
5661 | to: childAfter ? cView.posBefore(childAfter) : cView.posAtEnd, typeOver: false };
|
5662 | }
|
5663 | else if (rec.type == "characterData") {
|
5664 | return { from: cView.posAtStart, to: cView.posAtEnd, typeOver: rec.target.nodeValue == rec.oldValue };
|
5665 | }
|
5666 | else {
|
5667 | return null;
|
5668 | }
|
5669 | }
|
5670 | destroy() {
|
5671 | var _a, _b, _c;
|
5672 | this.stop();
|
5673 | (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
|
5674 | (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
|
5675 | (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
|
5676 | for (let dom of this.scrollTargets)
|
5677 | dom.removeEventListener("scroll", this.onScroll);
|
5678 | window.removeEventListener("scroll", this.onScroll);
|
5679 | window.removeEventListener("resize", this.onResize);
|
5680 | window.removeEventListener("beforeprint", this.onPrint);
|
5681 | this.dom.ownerDocument.removeEventListener("selectionchange", this.onSelectionChange);
|
5682 | clearTimeout(this.parentCheck);
|
5683 | clearTimeout(this.resizeTimeout);
|
5684 | }
|
5685 | }
|
5686 | function findChild(cView, dom, dir) {
|
5687 | while (dom) {
|
5688 | let curView = ContentView.get(dom);
|
5689 | if (curView && curView.parent == cView)
|
5690 | return curView;
|
5691 | let parent = dom.parentNode;
|
5692 | dom = parent != cView.dom ? parent : dir > 0 ? dom.nextSibling : dom.previousSibling;
|
5693 | }
|
5694 | return null;
|
5695 | }
|
5696 |
|
5697 | function safariSelectionRangeHack(view) {
|
5698 | let found = null;
|
5699 |
|
5700 |
|
5701 |
|
5702 |
|
5703 |
|
5704 | function read(event) {
|
5705 | event.preventDefault();
|
5706 | event.stopImmediatePropagation();
|
5707 | found = event.getTargetRanges()[0];
|
5708 | }
|
5709 | view.contentDOM.addEventListener("beforeinput", read, true);
|
5710 | document.execCommand("indent");
|
5711 | view.contentDOM.removeEventListener("beforeinput", read, true);
|
5712 | if (!found)
|
5713 | return null;
|
5714 | let anchorNode = found.startContainer, anchorOffset = found.startOffset;
|
5715 | let focusNode = found.endContainer, focusOffset = found.endOffset;
|
5716 | let curAnchor = view.docView.domAtPos(view.state.selection.main.anchor);
|
5717 |
|
5718 |
|
5719 |
|
5720 | if (isEquivalentPosition(curAnchor.node, curAnchor.offset, focusNode, focusOffset))
|
5721 | [anchorNode, anchorOffset, focusNode, focusOffset] = [focusNode, focusOffset, anchorNode, anchorOffset];
|
5722 | return { anchorNode, anchorOffset, focusNode, focusOffset };
|
5723 | }
|
5724 |
|
5725 | function applyDOMChange(view, start, end, typeOver) {
|
5726 | let change, newSel;
|
5727 | let sel = view.state.selection.main;
|
5728 | if (start > -1) {
|
5729 | let bounds = view.docView.domBoundsAround(start, end, 0);
|
5730 | if (!bounds || view.state.readOnly)
|
5731 | return false;
|
5732 | let { from, to } = bounds;
|
5733 | let selPoints = view.docView.impreciseHead || view.docView.impreciseAnchor ? [] : selectionPoints(view);
|
5734 | let reader = new DOMReader(selPoints, view.state);
|
5735 | reader.readRange(bounds.startDOM, bounds.endDOM);
|
5736 | let preferredPos = sel.from, preferredSide = null;
|
5737 |
|
5738 |
|
5739 | if (view.inputState.lastKeyCode === 8 && view.inputState.lastKeyTime > Date.now() - 100 ||
|
5740 | browser.android && reader.text.length < to - from) {
|
5741 | preferredPos = sel.to;
|
5742 | preferredSide = "end";
|
5743 | }
|
5744 | let diff = findDiff(view.state.doc.sliceString(from, to, LineBreakPlaceholder), reader.text, preferredPos - from, preferredSide);
|
5745 | if (diff) {
|
5746 |
|
5747 |
|
5748 | if (browser.chrome && view.inputState.lastKeyCode == 13 &&
|
5749 | diff.toB == diff.from + 2 && reader.text.slice(diff.from, diff.toB) == LineBreakPlaceholder + LineBreakPlaceholder)
|
5750 | diff.toB--;
|
5751 | change = { from: from + diff.from, to: from + diff.toA,
|
5752 | insert: Text.of(reader.text.slice(diff.from, diff.toB).split(LineBreakPlaceholder)) };
|
5753 | }
|
5754 | newSel = selectionFromPoints(selPoints, from);
|
5755 | }
|
5756 | else if (view.hasFocus || !view.state.facet(editable)) {
|
5757 | let domSel = view.observer.selectionRange;
|
5758 | let { impreciseHead: iHead, impreciseAnchor: iAnchor } = view.docView;
|
5759 | let head = iHead && iHead.node == domSel.focusNode && iHead.offset == domSel.focusOffset ||
|
5760 | !contains(view.contentDOM, domSel.focusNode)
|
5761 | ? view.state.selection.main.head
|
5762 | : view.docView.posFromDOM(domSel.focusNode, domSel.focusOffset);
|
5763 | let anchor = iAnchor && iAnchor.node == domSel.anchorNode && iAnchor.offset == domSel.anchorOffset ||
|
5764 | !contains(view.contentDOM, domSel.anchorNode)
|
5765 | ? view.state.selection.main.anchor
|
5766 | : view.docView.posFromDOM(domSel.anchorNode, domSel.anchorOffset);
|
5767 | if (head != sel.head || anchor != sel.anchor)
|
5768 | newSel = EditorSelection.single(anchor, head);
|
5769 | }
|
5770 | if (!change && !newSel)
|
5771 | return false;
|
5772 |
|
5773 | if (!change && typeOver && !sel.empty && newSel && newSel.main.empty)
|
5774 | change = { from: sel.from, to: sel.to, insert: view.state.doc.slice(sel.from, sel.to) };
|
5775 |
|
5776 |
|
5777 |
|
5778 | else if (change && change.from >= sel.from && change.to <= sel.to &&
|
5779 | (change.from != sel.from || change.to != sel.to) &&
|
5780 | (sel.to - sel.from) - (change.to - change.from) <= 4)
|
5781 | change = {
|
5782 | from: sel.from, to: sel.to,
|
5783 | insert: view.state.doc.slice(sel.from, change.from).append(change.insert).append(view.state.doc.slice(change.to, sel.to))
|
5784 | };
|
5785 |
|
5786 |
|
5787 | else if ((browser.mac || browser.android) && change && change.from == change.to && change.from == sel.head - 1 &&
|
5788 | change.insert.toString() == ".")
|
5789 | change = { from: sel.from, to: sel.to, insert: Text.of([" "]) };
|
5790 | if (change) {
|
5791 | let startState = view.state;
|
5792 | if (browser.ios && view.inputState.flushIOSKey(view))
|
5793 | return true;
|
5794 |
|
5795 |
|
5796 |
|
5797 |
|
5798 |
|
5799 |
|
5800 | if (browser.android &&
|
5801 | ((change.from == sel.from && change.to == sel.to &&
|
5802 | change.insert.length == 1 && change.insert.lines == 2 &&
|
5803 | dispatchKey(view.contentDOM, "Enter", 13)) ||
|
5804 | (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
|
5805 | dispatchKey(view.contentDOM, "Backspace", 8)) ||
|
5806 | (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
|
5807 | dispatchKey(view.contentDOM, "Delete", 46))))
|
5808 | return true;
|
5809 | let text = change.insert.toString();
|
5810 | if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
|
5811 | return true;
|
5812 | if (view.inputState.composing >= 0)
|
5813 | view.inputState.composing++;
|
5814 | let tr;
|
5815 | if (change.from >= sel.from && change.to <= sel.to && change.to - change.from >= (sel.to - sel.from) / 3 &&
|
5816 | (!newSel || newSel.main.empty && newSel.main.from == change.from + change.insert.length) &&
|
5817 | view.inputState.composing < 0) {
|
5818 | let before = sel.from < change.from ? startState.sliceDoc(sel.from, change.from) : "";
|
5819 | let after = sel.to > change.to ? startState.sliceDoc(change.to, sel.to) : "";
|
5820 | tr = startState.replaceSelection(view.state.toText(before + change.insert.sliceString(0, undefined, view.state.lineBreak) + after));
|
5821 | }
|
5822 | else {
|
5823 | let changes = startState.changes(change);
|
5824 | let mainSel = newSel && !startState.selection.main.eq(newSel.main) && newSel.main.to <= changes.newLength
|
5825 | ? newSel.main : undefined;
|
5826 |
|
5827 | if (startState.selection.ranges.length > 1 && view.inputState.composing >= 0 &&
|
5828 | change.to <= sel.to && change.to >= sel.to - 10) {
|
5829 | let replaced = view.state.sliceDoc(change.from, change.to);
|
5830 | let compositionRange = compositionSurroundingNode(view) || view.state.doc.lineAt(sel.head);
|
5831 | let offset = sel.to - change.to, size = sel.to - sel.from;
|
5832 | tr = startState.changeByRange(range => {
|
5833 | if (range.from == sel.from && range.to == sel.to)
|
5834 | return { changes, range: mainSel || range.map(changes) };
|
5835 | let to = range.to - offset, from = to - replaced.length;
|
5836 | if (range.to - range.from != size || view.state.sliceDoc(from, to) != replaced ||
|
5837 |
|
5838 |
|
5839 |
|
5840 |
|
5841 | compositionRange && range.to >= compositionRange.from && range.from <= compositionRange.to)
|
5842 | return { range };
|
5843 | let rangeChanges = startState.changes({ from, to, insert: change.insert }), selOff = range.to - sel.to;
|
5844 | return {
|
5845 | changes: rangeChanges,
|
5846 | range: !mainSel ? range.map(rangeChanges) :
|
5847 | EditorSelection.range(Math.max(0, mainSel.anchor + selOff), Math.max(0, mainSel.head + selOff))
|
5848 | };
|
5849 | });
|
5850 | }
|
5851 | else {
|
5852 | tr = {
|
5853 | changes,
|
5854 | selection: mainSel && startState.selection.replaceRange(mainSel)
|
5855 | };
|
5856 | }
|
5857 | }
|
5858 | let userEvent = "input.type";
|
5859 | if (view.composing) {
|
5860 | userEvent += ".compose";
|
5861 | if (view.inputState.compositionFirstChange) {
|
5862 | userEvent += ".start";
|
5863 | view.inputState.compositionFirstChange = false;
|
5864 | }
|
5865 | }
|
5866 | view.dispatch(tr, { scrollIntoView: true, userEvent });
|
5867 | return true;
|
5868 | }
|
5869 | else if (newSel && !newSel.main.eq(sel)) {
|
5870 | let scrollIntoView = false, userEvent = "select";
|
5871 | if (view.inputState.lastSelectionTime > Date.now() - 50) {
|
5872 | if (view.inputState.lastSelectionOrigin == "select")
|
5873 | scrollIntoView = true;
|
5874 | userEvent = view.inputState.lastSelectionOrigin;
|
5875 | }
|
5876 | view.dispatch({ selection: newSel, scrollIntoView, userEvent });
|
5877 | return true;
|
5878 | }
|
5879 | else {
|
5880 | return false;
|
5881 | }
|
5882 | }
|
5883 | function findDiff(a, b, preferredPos, preferredSide) {
|
5884 | let minLen = Math.min(a.length, b.length);
|
5885 | let from = 0;
|
5886 | while (from < minLen && a.charCodeAt(from) == b.charCodeAt(from))
|
5887 | from++;
|
5888 | if (from == minLen && a.length == b.length)
|
5889 | return null;
|
5890 | let toA = a.length, toB = b.length;
|
5891 | while (toA > 0 && toB > 0 && a.charCodeAt(toA - 1) == b.charCodeAt(toB - 1)) {
|
5892 | toA--;
|
5893 | toB--;
|
5894 | }
|
5895 | if (preferredSide == "end") {
|
5896 | let adjust = Math.max(0, from - Math.min(toA, toB));
|
5897 | preferredPos -= toA + adjust - from;
|
5898 | }
|
5899 | if (toA < from && a.length < b.length) {
|
5900 | let move = preferredPos <= from && preferredPos >= toA ? from - preferredPos : 0;
|
5901 | from -= move;
|
5902 | toB = from + (toB - toA);
|
5903 | toA = from;
|
5904 | }
|
5905 | else if (toB < from) {
|
5906 | let move = preferredPos <= from && preferredPos >= toB ? from - preferredPos : 0;
|
5907 | from -= move;
|
5908 | toA = from + (toA - toB);
|
5909 | toB = from;
|
5910 | }
|
5911 | return { from, toA, toB };
|
5912 | }
|
5913 | function selectionPoints(view) {
|
5914 | let result = [];
|
5915 | if (view.root.activeElement != view.contentDOM)
|
5916 | return result;
|
5917 | let { anchorNode, anchorOffset, focusNode, focusOffset } = view.observer.selectionRange;
|
5918 | if (anchorNode) {
|
5919 | result.push(new DOMPoint(anchorNode, anchorOffset));
|
5920 | if (focusNode != anchorNode || focusOffset != anchorOffset)
|
5921 | result.push(new DOMPoint(focusNode, focusOffset));
|
5922 | }
|
5923 | return result;
|
5924 | }
|
5925 | function selectionFromPoints(points, base) {
|
5926 | if (points.length == 0)
|
5927 | return null;
|
5928 | let anchor = points[0].pos, head = points.length == 2 ? points[1].pos : anchor;
|
5929 | return anchor > -1 && head > -1 ? EditorSelection.single(anchor + base, head + base) : null;
|
5930 | }
|
5931 |
|
5932 |
|
5933 |
|
5934 |
|
5935 |
|
5936 |
|
5937 |
|
5938 |
|
5939 |
|
5940 |
|
5941 |
|
5942 |
|
5943 |
|
5944 |
|
5945 |
|
5946 |
|
5947 |
|
5948 |
|
5949 |
|
5950 |
|
5951 | class EditorView {
|
5952 | |
5953 |
|
5954 |
|
5955 |
|
5956 |
|
5957 | constructor(config = {}) {
|
5958 | this.plugins = [];
|
5959 | this.pluginMap = new Map;
|
5960 | this.editorAttrs = {};
|
5961 | this.contentAttrs = {};
|
5962 | this.bidiCache = [];
|
5963 | this.destroyed = false;
|
5964 | |
5965 |
|
5966 |
|
5967 | this.updateState = 2 ;
|
5968 | |
5969 |
|
5970 |
|
5971 | this.measureScheduled = -1;
|
5972 | |
5973 |
|
5974 |
|
5975 | this.measureRequests = [];
|
5976 | this.contentDOM = document.createElement("div");
|
5977 | this.scrollDOM = document.createElement("div");
|
5978 | this.scrollDOM.tabIndex = -1;
|
5979 | this.scrollDOM.className = "cm-scroller";
|
5980 | this.scrollDOM.appendChild(this.contentDOM);
|
5981 | this.announceDOM = document.createElement("div");
|
5982 | this.announceDOM.style.cssText = "position: absolute; top: -10000px";
|
5983 | this.announceDOM.setAttribute("aria-live", "polite");
|
5984 | this.dom = document.createElement("div");
|
5985 | this.dom.appendChild(this.announceDOM);
|
5986 | this.dom.appendChild(this.scrollDOM);
|
5987 | this._dispatch = config.dispatch || ((tr) => this.update([tr]));
|
5988 | this.dispatch = this.dispatch.bind(this);
|
5989 | this.root = (config.root || getRoot(config.parent) || document);
|
5990 | this.viewState = new ViewState(config.state || EditorState.create(config));
|
5991 | this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
5992 | for (let plugin of this.plugins)
|
5993 | plugin.update(this);
|
5994 | this.observer = new DOMObserver(this, (from, to, typeOver) => {
|
5995 | return applyDOMChange(this, from, to, typeOver);
|
5996 | }, event => {
|
5997 | this.inputState.runScrollHandlers(this, event);
|
5998 | if (this.observer.intersecting)
|
5999 | this.measure();
|
6000 | });
|
6001 | this.inputState = new InputState(this);
|
6002 | this.inputState.ensureHandlers(this, this.plugins);
|
6003 | this.docView = new DocView(this);
|
6004 | this.mountStyles();
|
6005 | this.updateAttrs();
|
6006 | this.updateState = 0 ;
|
6007 | this.requestMeasure();
|
6008 | if (config.parent)
|
6009 | config.parent.appendChild(this.dom);
|
6010 | }
|
6011 | |
6012 |
|
6013 |
|
6014 | get state() { return this.viewState.state; }
|
6015 | |
6016 |
|
6017 |
|
6018 |
|
6019 |
|
6020 |
|
6021 |
|
6022 | get viewport() { return this.viewState.viewport; }
|
6023 | |
6024 |
|
6025 |
|
6026 |
|
6027 |
|
6028 |
|
6029 |
|
6030 |
|
6031 | get visibleRanges() { return this.viewState.visibleRanges; }
|
6032 | |
6033 |
|
6034 |
|
6035 |
|
6036 | get inView() { return this.viewState.inView; }
|
6037 | |
6038 |
|
6039 |
|
6040 |
|
6041 |
|
6042 | get composing() { return this.inputState.composing > 0; }
|
6043 | |
6044 |
|
6045 |
|
6046 |
|
6047 |
|
6048 |
|
6049 | get compositionStarted() { return this.inputState.composing >= 0; }
|
6050 | dispatch(...input) {
|
6051 | this._dispatch(input.length == 1 && input[0] instanceof Transaction ? input[0]
|
6052 | : this.state.update(...input));
|
6053 | }
|
6054 | |
6055 |
|
6056 |
|
6057 |
|
6058 |
|
6059 |
|
6060 |
|
6061 |
|
6062 | update(transactions) {
|
6063 | if (this.updateState != 0 )
|
6064 | throw new Error("Calls to EditorView.update are not allowed while an update is in progress");
|
6065 | let redrawn = false, attrsChanged = false, update;
|
6066 | let state = this.state;
|
6067 | for (let tr of transactions) {
|
6068 | if (tr.startState != state)
|
6069 | throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");
|
6070 | state = tr.state;
|
6071 | }
|
6072 | if (this.destroyed) {
|
6073 | this.viewState.state = state;
|
6074 | return;
|
6075 | }
|
6076 | this.observer.clear();
|
6077 |
|
6078 | if (state.facet(EditorState.phrases) != this.state.facet(EditorState.phrases))
|
6079 | return this.setState(state);
|
6080 | update = ViewUpdate.create(this, state, transactions);
|
6081 | let scrollTarget = this.viewState.scrollTarget;
|
6082 | try {
|
6083 | this.updateState = 2 ;
|
6084 | for (let tr of transactions) {
|
6085 | if (scrollTarget)
|
6086 | scrollTarget = scrollTarget.map(tr.changes);
|
6087 | if (tr.scrollIntoView) {
|
6088 | let { main } = tr.state.selection;
|
6089 | scrollTarget = new ScrollTarget(main.empty ? main : EditorSelection.cursor(main.head, main.head > main.anchor ? -1 : 1));
|
6090 | }
|
6091 | for (let e of tr.effects)
|
6092 | if (e.is(scrollIntoView))
|
6093 | scrollTarget = e.value;
|
6094 | }
|
6095 | this.viewState.update(update, scrollTarget);
|
6096 | this.bidiCache = CachedOrder.update(this.bidiCache, update.changes);
|
6097 | if (!update.empty) {
|
6098 | this.updatePlugins(update);
|
6099 | this.inputState.update(update);
|
6100 | }
|
6101 | redrawn = this.docView.update(update);
|
6102 | if (this.state.facet(styleModule) != this.styleModules)
|
6103 | this.mountStyles();
|
6104 | attrsChanged = this.updateAttrs();
|
6105 | this.showAnnouncements(transactions);
|
6106 | this.docView.updateSelection(redrawn, transactions.some(tr => tr.isUserEvent("select.pointer")));
|
6107 | }
|
6108 | finally {
|
6109 | this.updateState = 0 ;
|
6110 | }
|
6111 | if (update.startState.facet(theme) != update.state.facet(theme))
|
6112 | this.viewState.mustMeasureContent = true;
|
6113 | if (redrawn || attrsChanged || scrollTarget || this.viewState.mustEnforceCursorAssoc || this.viewState.mustMeasureContent)
|
6114 | this.requestMeasure();
|
6115 | if (!update.empty)
|
6116 | for (let listener of this.state.facet(updateListener))
|
6117 | listener(update);
|
6118 | }
|
6119 | |
6120 |
|
6121 |
|
6122 |
|
6123 |
|
6124 |
|
6125 |
|
6126 | setState(newState) {
|
6127 | if (this.updateState != 0 )
|
6128 | throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");
|
6129 | if (this.destroyed) {
|
6130 | this.viewState.state = newState;
|
6131 | return;
|
6132 | }
|
6133 | this.updateState = 2 ;
|
6134 | let hadFocus = this.hasFocus;
|
6135 | try {
|
6136 | for (let plugin of this.plugins)
|
6137 | plugin.destroy(this);
|
6138 | this.viewState = new ViewState(newState);
|
6139 | this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec));
|
6140 | this.pluginMap.clear();
|
6141 | for (let plugin of this.plugins)
|
6142 | plugin.update(this);
|
6143 | this.docView = new DocView(this);
|
6144 | this.inputState.ensureHandlers(this, this.plugins);
|
6145 | this.mountStyles();
|
6146 | this.updateAttrs();
|
6147 | this.bidiCache = [];
|
6148 | }
|
6149 | finally {
|
6150 | this.updateState = 0 ;
|
6151 | }
|
6152 | if (hadFocus)
|
6153 | this.focus();
|
6154 | this.requestMeasure();
|
6155 | }
|
6156 | updatePlugins(update) {
|
6157 | let prevSpecs = update.startState.facet(viewPlugin), specs = update.state.facet(viewPlugin);
|
6158 | if (prevSpecs != specs) {
|
6159 | let newPlugins = [];
|
6160 | for (let spec of specs) {
|
6161 | let found = prevSpecs.indexOf(spec);
|
6162 | if (found < 0) {
|
6163 | newPlugins.push(new PluginInstance(spec));
|
6164 | }
|
6165 | else {
|
6166 | let plugin = this.plugins[found];
|
6167 | plugin.mustUpdate = update;
|
6168 | newPlugins.push(plugin);
|
6169 | }
|
6170 | }
|
6171 | for (let plugin of this.plugins)
|
6172 | if (plugin.mustUpdate != update)
|
6173 | plugin.destroy(this);
|
6174 | this.plugins = newPlugins;
|
6175 | this.pluginMap.clear();
|
6176 | this.inputState.ensureHandlers(this, this.plugins);
|
6177 | }
|
6178 | else {
|
6179 | for (let p of this.plugins)
|
6180 | p.mustUpdate = update;
|
6181 | }
|
6182 | for (let i = 0; i < this.plugins.length; i++)
|
6183 | this.plugins[i].update(this);
|
6184 | }
|
6185 | |
6186 |
|
6187 |
|
6188 | measure(flush = true) {
|
6189 | if (this.destroyed)
|
6190 | return;
|
6191 | if (this.measureScheduled > -1)
|
6192 | cancelAnimationFrame(this.measureScheduled);
|
6193 | this.measureScheduled = 0;
|
6194 | if (flush)
|
6195 | this.observer.flush();
|
6196 | let updated = null;
|
6197 | try {
|
6198 | for (let i = 0;; i++) {
|
6199 | this.updateState = 1 ;
|
6200 | let oldViewport = this.viewport;
|
6201 | let changed = this.viewState.measure(this);
|
6202 | if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
|
6203 | break;
|
6204 | if (i > 5) {
|
6205 | console.warn(this.measureRequests.length
|
6206 | ? "Measure loop restarted more than 5 times"
|
6207 | : "Viewport failed to stabilize");
|
6208 | break;
|
6209 | }
|
6210 | let measuring = [];
|
6211 |
|
6212 | if (!(changed & 4 ))
|
6213 | [this.measureRequests, measuring] = [measuring, this.measureRequests];
|
6214 | let measured = measuring.map(m => {
|
6215 | try {
|
6216 | return m.read(this);
|
6217 | }
|
6218 | catch (e) {
|
6219 | logException(this.state, e);
|
6220 | return BadMeasure;
|
6221 | }
|
6222 | });
|
6223 | let update = ViewUpdate.create(this, this.state, []), redrawn = false, scrolled = false;
|
6224 | update.flags |= changed;
|
6225 | if (!updated)
|
6226 | updated = update;
|
6227 | else
|
6228 | updated.flags |= changed;
|
6229 | this.updateState = 2 ;
|
6230 | if (!update.empty) {
|
6231 | this.updatePlugins(update);
|
6232 | this.inputState.update(update);
|
6233 | this.updateAttrs();
|
6234 | redrawn = this.docView.update(update);
|
6235 | }
|
6236 | for (let i = 0; i < measuring.length; i++)
|
6237 | if (measured[i] != BadMeasure) {
|
6238 | try {
|
6239 | let m = measuring[i];
|
6240 | if (m.write)
|
6241 | m.write(measured[i], this);
|
6242 | }
|
6243 | catch (e) {
|
6244 | logException(this.state, e);
|
6245 | }
|
6246 | }
|
6247 | if (this.viewState.scrollTarget) {
|
6248 | this.docView.scrollIntoView(this.viewState.scrollTarget);
|
6249 | this.viewState.scrollTarget = null;
|
6250 | scrolled = true;
|
6251 | }
|
6252 | if (redrawn)
|
6253 | this.docView.updateSelection(true);
|
6254 | if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to &&
|
6255 | !scrolled && this.measureRequests.length == 0)
|
6256 | break;
|
6257 | }
|
6258 | }
|
6259 | finally {
|
6260 | this.updateState = 0 ;
|
6261 | this.measureScheduled = -1;
|
6262 | }
|
6263 | if (updated && !updated.empty)
|
6264 | for (let listener of this.state.facet(updateListener))
|
6265 | listener(updated);
|
6266 | }
|
6267 | |
6268 |
|
6269 |
|
6270 | get themeClasses() {
|
6271 | return baseThemeID + " " +
|
6272 | (this.state.facet(darkTheme) ? baseDarkID : baseLightID) + " " +
|
6273 | this.state.facet(theme);
|
6274 | }
|
6275 | updateAttrs() {
|
6276 | let editorAttrs = attrsFromFacet(this, editorAttributes, {
|
6277 | class: "cm-editor" + (this.hasFocus ? " cm-focused " : " ") + this.themeClasses
|
6278 | });
|
6279 | let contentAttrs = {
|
6280 | spellcheck: "false",
|
6281 | autocorrect: "off",
|
6282 | autocapitalize: "off",
|
6283 | translate: "no",
|
6284 | contenteditable: !this.state.facet(editable) ? "false" : "true",
|
6285 | class: "cm-content",
|
6286 | style: `${browser.tabSize}: ${this.state.tabSize}`,
|
6287 | role: "textbox",
|
6288 | "aria-multiline": "true"
|
6289 | };
|
6290 | if (this.state.readOnly)
|
6291 | contentAttrs["aria-readonly"] = "true";
|
6292 | attrsFromFacet(this, contentAttributes, contentAttrs);
|
6293 | let changed = this.observer.ignore(() => {
|
6294 | let changedContent = updateAttrs(this.contentDOM, this.contentAttrs, contentAttrs);
|
6295 | let changedEditor = updateAttrs(this.dom, this.editorAttrs, editorAttrs);
|
6296 | return changedContent || changedEditor;
|
6297 | });
|
6298 | this.editorAttrs = editorAttrs;
|
6299 | this.contentAttrs = contentAttrs;
|
6300 | return changed;
|
6301 | }
|
6302 | showAnnouncements(trs) {
|
6303 | let first = true;
|
6304 | for (let tr of trs)
|
6305 | for (let effect of tr.effects)
|
6306 | if (effect.is(EditorView.announce)) {
|
6307 | if (first)
|
6308 | this.announceDOM.textContent = "";
|
6309 | first = false;
|
6310 | let div = this.announceDOM.appendChild(document.createElement("div"));
|
6311 | div.textContent = effect.value;
|
6312 | }
|
6313 | }
|
6314 | mountStyles() {
|
6315 | this.styleModules = this.state.facet(styleModule);
|
6316 | StyleModule.mount(this.root, this.styleModules.concat(baseTheme$1).reverse());
|
6317 | }
|
6318 | readMeasured() {
|
6319 | if (this.updateState == 2 )
|
6320 | throw new Error("Reading the editor layout isn't allowed during an update");
|
6321 | if (this.updateState == 0 && this.measureScheduled > -1)
|
6322 | this.measure(false);
|
6323 | }
|
6324 | |
6325 |
|
6326 |
|
6327 |
|
6328 |
|
6329 |
|
6330 |
|
6331 |
|
6332 | requestMeasure(request) {
|
6333 | if (this.measureScheduled < 0)
|
6334 | this.measureScheduled = requestAnimationFrame(() => this.measure());
|
6335 | if (request) {
|
6336 | if (request.key != null)
|
6337 | for (let i = 0; i < this.measureRequests.length; i++) {
|
6338 | if (this.measureRequests[i].key === request.key) {
|
6339 | this.measureRequests[i] = request;
|
6340 | return;
|
6341 | }
|
6342 | }
|
6343 | this.measureRequests.push(request);
|
6344 | }
|
6345 | }
|
6346 | |
6347 |
|
6348 |
|
6349 |
|
6350 |
|
6351 |
|
6352 | plugin(plugin) {
|
6353 | let known = this.pluginMap.get(plugin);
|
6354 | if (known === undefined || known && known.spec != plugin)
|
6355 | this.pluginMap.set(plugin, known = this.plugins.find(p => p.spec == plugin) || null);
|
6356 | return known && known.update(this).value;
|
6357 | }
|
6358 | |
6359 |
|
6360 |
|
6361 |
|
6362 |
|
6363 | get documentTop() {
|
6364 | return this.contentDOM.getBoundingClientRect().top + this.viewState.paddingTop;
|
6365 | }
|
6366 | |
6367 |
|
6368 |
|
6369 | get documentPadding() {
|
6370 | return { top: this.viewState.paddingTop, bottom: this.viewState.paddingBottom };
|
6371 | }
|
6372 | |
6373 |
|
6374 |
|
6375 |
|
6376 |
|
6377 | elementAtHeight(height) {
|
6378 | this.readMeasured();
|
6379 | return this.viewState.elementAtHeight(height);
|
6380 | }
|
6381 | |
6382 |
|
6383 |
|
6384 |
|
6385 |
|
6386 | lineBlockAtHeight(height) {
|
6387 | this.readMeasured();
|
6388 | return this.viewState.lineBlockAtHeight(height);
|
6389 | }
|
6390 | |
6391 |
|
6392 |
|
6393 |
|
6394 |
|
6395 |
|
6396 | get viewportLineBlocks() {
|
6397 | return this.viewState.viewportLines;
|
6398 | }
|
6399 | |
6400 |
|
6401 |
|
6402 |
|
6403 |
|
6404 |
|
6405 |
|
6406 |
|
6407 | lineBlockAt(pos) {
|
6408 | return this.viewState.lineBlockAt(pos);
|
6409 | }
|
6410 | |
6411 |
|
6412 |
|
6413 | get contentHeight() {
|
6414 | return this.viewState.contentHeight;
|
6415 | }
|
6416 | |
6417 |
|
6418 |
|
6419 |
|
6420 |
|
6421 |
|
6422 |
|
6423 |
|
6424 |
|
6425 |
|
6426 |
|
6427 |
|
6428 |
|
6429 |
|
6430 |
|
6431 |
|
6432 | moveByChar(start, forward, by) {
|
6433 | return skipAtoms(this, start, moveByChar(this, start, forward, by));
|
6434 | }
|
6435 | |
6436 |
|
6437 |
|
6438 |
|
6439 |
|
6440 | moveByGroup(start, forward) {
|
6441 | return skipAtoms(this, start, moveByChar(this, start, forward, initial => byGroup(this, start.head, initial)));
|
6442 | }
|
6443 | |
6444 |
|
6445 |
|
6446 |
|
6447 |
|
6448 |
|
6449 |
|
6450 | moveToLineBoundary(start, forward, includeWrap = true) {
|
6451 | return moveToLineBoundary(this, start, forward, includeWrap);
|
6452 | }
|
6453 | |
6454 |
|
6455 |
|
6456 |
|
6457 |
|
6458 |
|
6459 |
|
6460 |
|
6461 |
|
6462 |
|
6463 |
|
6464 |
|
6465 |
|
6466 | moveVertically(start, forward, distance) {
|
6467 | return skipAtoms(this, start, moveVertically(this, start, forward, distance));
|
6468 | }
|
6469 | |
6470 |
|
6471 |
|
6472 |
|
6473 |
|
6474 |
|
6475 |
|
6476 |
|
6477 |
|
6478 |
|
6479 | domAtPos(pos) {
|
6480 | return this.docView.domAtPos(pos);
|
6481 | }
|
6482 | |
6483 |
|
6484 |
|
6485 |
|
6486 |
|
6487 | posAtDOM(node, offset = 0) {
|
6488 | return this.docView.posFromDOM(node, offset);
|
6489 | }
|
6490 | posAtCoords(coords, precise = true) {
|
6491 | this.readMeasured();
|
6492 | return posAtCoords(this, coords, precise);
|
6493 | }
|
6494 | |
6495 |
|
6496 |
|
6497 |
|
6498 |
|
6499 |
|
6500 |
|
6501 | coordsAtPos(pos, side = 1) {
|
6502 | this.readMeasured();
|
6503 | let rect = this.docView.coordsAt(pos, side);
|
6504 | if (!rect || rect.left == rect.right)
|
6505 | return rect;
|
6506 | let line = this.state.doc.lineAt(pos), order = this.bidiSpans(line);
|
6507 | let span = order[BidiSpan.find(order, pos - line.from, -1, side)];
|
6508 | return flattenRect(rect, (span.dir == Direction.LTR) == (side > 0));
|
6509 | }
|
6510 | |
6511 |
|
6512 |
|
6513 |
|
6514 |
|
6515 | get defaultCharacterWidth() { return this.viewState.heightOracle.charWidth; }
|
6516 | |
6517 |
|
6518 |
|
6519 |
|
6520 | get defaultLineHeight() { return this.viewState.heightOracle.lineHeight; }
|
6521 | |
6522 |
|
6523 |
|
6524 |
|
6525 |
|
6526 | get textDirection() { return this.viewState.defaultTextDirection; }
|
6527 | |
6528 |
|
6529 |
|
6530 |
|
6531 |
|
6532 |
|
6533 |
|
6534 |
|
6535 |
|
6536 | textDirectionAt(pos) {
|
6537 | let perLine = this.state.facet(perLineTextDirection);
|
6538 | if (!perLine || pos < this.viewport.from || pos > this.viewport.to)
|
6539 | return this.textDirection;
|
6540 | this.readMeasured();
|
6541 | return this.docView.textDirectionAt(pos);
|
6542 | }
|
6543 | |
6544 |
|
6545 |
|
6546 |
|
6547 |
|
6548 |
|
6549 | get lineWrapping() { return this.viewState.heightOracle.lineWrapping; }
|
6550 | |
6551 |
|
6552 |
|
6553 |
|
6554 |
|
6555 |
|
6556 |
|
6557 |
|
6558 | bidiSpans(line) {
|
6559 | if (line.length > MaxBidiLine)
|
6560 | return trivialOrder(line.length);
|
6561 | let dir = this.textDirectionAt(line.from);
|
6562 | for (let entry of this.bidiCache)
|
6563 | if (entry.from == line.from && entry.dir == dir)
|
6564 | return entry.order;
|
6565 | let order = computeOrder(line.text, dir);
|
6566 | this.bidiCache.push(new CachedOrder(line.from, line.to, dir, order));
|
6567 | return order;
|
6568 | }
|
6569 | |
6570 |
|
6571 |
|
6572 | get hasFocus() {
|
6573 | var _a;
|
6574 |
|
6575 |
|
6576 |
|
6577 |
|
6578 | return (document.hasFocus() || browser.safari && ((_a = this.inputState) === null || _a === void 0 ? void 0 : _a.lastContextMenu) > Date.now() - 3e4) &&
|
6579 | this.root.activeElement == this.contentDOM;
|
6580 | }
|
6581 | |
6582 |
|
6583 |
|
6584 | focus() {
|
6585 | this.observer.ignore(() => {
|
6586 | focusPreventScroll(this.contentDOM);
|
6587 | this.docView.updateSelection();
|
6588 | });
|
6589 | }
|
6590 | |
6591 |
|
6592 |
|
6593 |
|
6594 |
|
6595 |
|
6596 | destroy() {
|
6597 | for (let plugin of this.plugins)
|
6598 | plugin.destroy(this);
|
6599 | this.plugins = [];
|
6600 | this.inputState.destroy();
|
6601 | this.dom.remove();
|
6602 | this.observer.destroy();
|
6603 | if (this.measureScheduled > -1)
|
6604 | cancelAnimationFrame(this.measureScheduled);
|
6605 | this.destroyed = true;
|
6606 | }
|
6607 | |
6608 |
|
6609 |
|
6610 |
|
6611 |
|
6612 | static scrollIntoView(pos, options = {}) {
|
6613 | return scrollIntoView.of(new ScrollTarget(typeof pos == "number" ? EditorSelection.cursor(pos) : pos, options.y, options.x, options.yMargin, options.xMargin));
|
6614 | }
|
6615 | |
6616 |
|
6617 |
|
6618 |
|
6619 |
|
6620 |
|
6621 |
|
6622 |
|
6623 |
|
6624 |
|
6625 |
|
6626 |
|
6627 | static domEventHandlers(handlers) {
|
6628 | return ViewPlugin.define(() => ({}), { eventHandlers: handlers });
|
6629 | }
|
6630 | |
6631 |
|
6632 |
|
6633 |
|
6634 |
|
6635 |
|
6636 |
|
6637 |
|
6638 |
|
6639 |
|
6640 |
|
6641 |
|
6642 |
|
6643 |
|
6644 |
|
6645 |
|
6646 |
|
6647 |
|
6648 | static theme(spec, options) {
|
6649 | let prefix = StyleModule.newName();
|
6650 | let result = [theme.of(prefix), styleModule.of(buildTheme(`.${prefix}`, spec))];
|
6651 | if (options && options.dark)
|
6652 | result.push(darkTheme.of(true));
|
6653 | return result;
|
6654 | }
|
6655 | |
6656 |
|
6657 |
|
6658 |
|
6659 |
|
6660 |
|
6661 |
|
6662 | static baseTheme(spec) {
|
6663 | return Prec.lowest(styleModule.of(buildTheme("." + baseThemeID, spec, lightDarkIDs)));
|
6664 | }
|
6665 | |
6666 |
|
6667 |
|
6668 |
|
6669 | static findFromDOM(dom) {
|
6670 | var _a;
|
6671 | let content = dom.querySelector(".cm-content");
|
6672 | let cView = content && ContentView.get(content) || ContentView.get(dom);
|
6673 | return ((_a = cView === null || cView === void 0 ? void 0 : cView.rootView) === null || _a === void 0 ? void 0 : _a.view) || null;
|
6674 | }
|
6675 | }
|
6676 |
|
6677 |
|
6678 |
|
6679 |
|
6680 |
|
6681 |
|
6682 |
|
6683 | EditorView.styleModule = styleModule;
|
6684 |
|
6685 |
|
6686 |
|
6687 |
|
6688 |
|
6689 |
|
6690 |
|
6691 | EditorView.inputHandler = inputHandler;
|
6692 |
|
6693 |
|
6694 |
|
6695 |
|
6696 |
|
6697 |
|
6698 | EditorView.perLineTextDirection = perLineTextDirection;
|
6699 |
|
6700 |
|
6701 |
|
6702 |
|
6703 |
|
6704 |
|
6705 |
|
6706 | EditorView.exceptionSink = exceptionSink;
|
6707 |
|
6708 |
|
6709 |
|
6710 |
|
6711 | EditorView.updateListener = updateListener;
|
6712 |
|
6713 |
|
6714 |
|
6715 |
|
6716 |
|
6717 |
|
6718 |
|
6719 |
|
6720 | EditorView.editable = editable;
|
6721 |
|
6722 |
|
6723 |
|
6724 |
|
6725 |
|
6726 |
|
6727 | EditorView.mouseSelectionStyle = mouseSelectionStyle;
|
6728 |
|
6729 |
|
6730 |
|
6731 |
|
6732 |
|
6733 |
|
6734 | EditorView.dragMovesSelection = dragMovesSelection$1;
|
6735 |
|
6736 |
|
6737 |
|
6738 |
|
6739 |
|
6740 |
|
6741 | EditorView.clickAddsSelectionRange = clickAddsSelectionRange;
|
6742 |
|
6743 |
|
6744 |
|
6745 |
|
6746 |
|
6747 |
|
6748 |
|
6749 |
|
6750 |
|
6751 |
|
6752 |
|
6753 | EditorView.decorations = decorations;
|
6754 |
|
6755 |
|
6756 |
|
6757 |
|
6758 |
|
6759 |
|
6760 |
|
6761 |
|
6762 |
|
6763 |
|
6764 |
|
6765 | EditorView.atomicRanges = atomicRanges;
|
6766 |
|
6767 |
|
6768 |
|
6769 |
|
6770 |
|
6771 |
|
6772 |
|
6773 | EditorView.scrollMargins = scrollMargins;
|
6774 |
|
6775 |
|
6776 |
|
6777 |
|
6778 |
|
6779 |
|
6780 | EditorView.darkTheme = darkTheme;
|
6781 |
|
6782 |
|
6783 |
|
6784 |
|
6785 | EditorView.contentAttributes = contentAttributes;
|
6786 |
|
6787 |
|
6788 |
|
6789 |
|
6790 | EditorView.editorAttributes = editorAttributes;
|
6791 |
|
6792 |
|
6793 |
|
6794 |
|
6795 | EditorView.lineWrapping = EditorView.contentAttributes.of({ "class": "cm-lineWrapping" });
|
6796 |
|
6797 |
|
6798 |
|
6799 |
|
6800 |
|
6801 |
|
6802 |
|
6803 |
|
6804 | EditorView.announce = StateEffect.define();
|
6805 |
|
6806 | const MaxBidiLine = 4096;
|
6807 | const BadMeasure = {};
|
6808 | class CachedOrder {
|
6809 | constructor(from, to, dir, order) {
|
6810 | this.from = from;
|
6811 | this.to = to;
|
6812 | this.dir = dir;
|
6813 | this.order = order;
|
6814 | }
|
6815 | static update(cache, changes) {
|
6816 | if (changes.empty)
|
6817 | return cache;
|
6818 | let result = [], lastDir = cache.length ? cache[cache.length - 1].dir : Direction.LTR;
|
6819 | for (let i = Math.max(0, cache.length - 10); i < cache.length; i++) {
|
6820 | let entry = cache[i];
|
6821 | if (entry.dir == lastDir && !changes.touchesRange(entry.from, entry.to))
|
6822 | result.push(new CachedOrder(changes.mapPos(entry.from, 1), changes.mapPos(entry.to, -1), entry.dir, entry.order));
|
6823 | }
|
6824 | return result;
|
6825 | }
|
6826 | }
|
6827 | function attrsFromFacet(view, facet, base) {
|
6828 | for (let sources = view.state.facet(facet), i = sources.length - 1; i >= 0; i--) {
|
6829 | let source = sources[i], value = typeof source == "function" ? source(view) : source;
|
6830 | if (value)
|
6831 | combineAttrs(value, base);
|
6832 | }
|
6833 | return base;
|
6834 | }
|
6835 |
|
6836 | const currentPlatform = browser.mac ? "mac" : browser.windows ? "win" : browser.linux ? "linux" : "key";
|
6837 | function normalizeKeyName(name, platform) {
|
6838 | const parts = name.split(/-(?!$)/);
|
6839 | let result = parts[parts.length - 1];
|
6840 | if (result == "Space")
|
6841 | result = " ";
|
6842 | let alt, ctrl, shift, meta;
|
6843 | for (let i = 0; i < parts.length - 1; ++i) {
|
6844 | const mod = parts[i];
|
6845 | if (/^(cmd|meta|m)$/i.test(mod))
|
6846 | meta = true;
|
6847 | else if (/^a(lt)?$/i.test(mod))
|
6848 | alt = true;
|
6849 | else if (/^(c|ctrl|control)$/i.test(mod))
|
6850 | ctrl = true;
|
6851 | else if (/^s(hift)?$/i.test(mod))
|
6852 | shift = true;
|
6853 | else if (/^mod$/i.test(mod)) {
|
6854 | if (platform == "mac")
|
6855 | meta = true;
|
6856 | else
|
6857 | ctrl = true;
|
6858 | }
|
6859 | else
|
6860 | throw new Error("Unrecognized modifier name: " + mod);
|
6861 | }
|
6862 | if (alt)
|
6863 | result = "Alt-" + result;
|
6864 | if (ctrl)
|
6865 | result = "Ctrl-" + result;
|
6866 | if (meta)
|
6867 | result = "Meta-" + result;
|
6868 | if (shift)
|
6869 | result = "Shift-" + result;
|
6870 | return result;
|
6871 | }
|
6872 | function modifiers(name, event, shift) {
|
6873 | if (event.altKey)
|
6874 | name = "Alt-" + name;
|
6875 | if (event.ctrlKey)
|
6876 | name = "Ctrl-" + name;
|
6877 | if (event.metaKey)
|
6878 | name = "Meta-" + name;
|
6879 | if (shift !== false && event.shiftKey)
|
6880 | name = "Shift-" + name;
|
6881 | return name;
|
6882 | }
|
6883 | const handleKeyEvents = EditorView.domEventHandlers({
|
6884 | keydown(event, view) {
|
6885 | return runHandlers(getKeymap(view.state), event, view, "editor");
|
6886 | }
|
6887 | });
|
6888 |
|
6889 |
|
6890 |
|
6891 |
|
6892 |
|
6893 |
|
6894 |
|
6895 |
|
6896 | const keymap = Facet.define({ enables: handleKeyEvents });
|
6897 | const Keymaps = new WeakMap();
|
6898 |
|
6899 |
|
6900 | function getKeymap(state) {
|
6901 | let bindings = state.facet(keymap);
|
6902 | let map = Keymaps.get(bindings);
|
6903 | if (!map)
|
6904 | Keymaps.set(bindings, map = buildKeymap(bindings.reduce((a, b) => a.concat(b), [])));
|
6905 | return map;
|
6906 | }
|
6907 |
|
6908 |
|
6909 |
|
6910 |
|
6911 |
|
6912 | function runScopeHandlers(view, event, scope) {
|
6913 | return runHandlers(getKeymap(view.state), event, view, scope);
|
6914 | }
|
6915 | let storedPrefix = null;
|
6916 | const PrefixTimeout = 4000;
|
6917 | function buildKeymap(bindings, platform = currentPlatform) {
|
6918 | let bound = Object.create(null);
|
6919 | let isPrefix = Object.create(null);
|
6920 | let checkPrefix = (name, is) => {
|
6921 | let current = isPrefix[name];
|
6922 | if (current == null)
|
6923 | isPrefix[name] = is;
|
6924 | else if (current != is)
|
6925 | throw new Error("Key binding " + name + " is used both as a regular binding and as a multi-stroke prefix");
|
6926 | };
|
6927 | let add = (scope, key, command, preventDefault) => {
|
6928 | let scopeObj = bound[scope] || (bound[scope] = Object.create(null));
|
6929 | let parts = key.split(/ (?!$)/).map(k => normalizeKeyName(k, platform));
|
6930 | for (let i = 1; i < parts.length; i++) {
|
6931 | let prefix = parts.slice(0, i).join(" ");
|
6932 | checkPrefix(prefix, true);
|
6933 | if (!scopeObj[prefix])
|
6934 | scopeObj[prefix] = {
|
6935 | preventDefault: true,
|
6936 | commands: [(view) => {
|
6937 | let ourObj = storedPrefix = { view, prefix, scope };
|
6938 | setTimeout(() => { if (storedPrefix == ourObj)
|
6939 | storedPrefix = null; }, PrefixTimeout);
|
6940 | return true;
|
6941 | }]
|
6942 | };
|
6943 | }
|
6944 | let full = parts.join(" ");
|
6945 | checkPrefix(full, false);
|
6946 | let binding = scopeObj[full] || (scopeObj[full] = { preventDefault: false, commands: [] });
|
6947 | binding.commands.push(command);
|
6948 | if (preventDefault)
|
6949 | binding.preventDefault = true;
|
6950 | };
|
6951 | for (let b of bindings) {
|
6952 | let name = b[platform] || b.key;
|
6953 | if (!name)
|
6954 | continue;
|
6955 | for (let scope of b.scope ? b.scope.split(" ") : ["editor"]) {
|
6956 | add(scope, name, b.run, b.preventDefault);
|
6957 | if (b.shift)
|
6958 | add(scope, "Shift-" + name, b.shift, b.preventDefault);
|
6959 | }
|
6960 | }
|
6961 | return bound;
|
6962 | }
|
6963 | function runHandlers(map, event, view, scope) {
|
6964 | let name = keyName(event);
|
6965 | let charCode = codePointAt(name, 0), isChar = codePointSize(charCode) == name.length && name != " ";
|
6966 | let prefix = "", fallthrough = false;
|
6967 | if (storedPrefix && storedPrefix.view == view && storedPrefix.scope == scope) {
|
6968 | prefix = storedPrefix.prefix + " ";
|
6969 | if (fallthrough = modifierCodes.indexOf(event.keyCode) < 0)
|
6970 | storedPrefix = null;
|
6971 | }
|
6972 | let runFor = (binding) => {
|
6973 | if (binding) {
|
6974 | for (let cmd of binding.commands)
|
6975 | if (cmd(view))
|
6976 | return true;
|
6977 | if (binding.preventDefault)
|
6978 | fallthrough = true;
|
6979 | }
|
6980 | return false;
|
6981 | };
|
6982 | let scopeObj = map[scope], baseName;
|
6983 | if (scopeObj) {
|
6984 | if (runFor(scopeObj[prefix + modifiers(name, event, !isChar)]))
|
6985 | return true;
|
6986 | if (isChar && (event.shiftKey || event.altKey || event.metaKey || charCode > 127) &&
|
6987 | (baseName = base[event.keyCode]) && baseName != name) {
|
6988 | if (runFor(scopeObj[prefix + modifiers(baseName, event, true)]))
|
6989 | return true;
|
6990 | else if (event.shiftKey && shift[event.keyCode] != baseName &&
|
6991 | runFor(scopeObj[prefix + modifiers(shift[event.keyCode], event, false)]))
|
6992 | return true;
|
6993 | }
|
6994 | else if (isChar && event.shiftKey) {
|
6995 | if (runFor(scopeObj[prefix + modifiers(name, event, true)]))
|
6996 | return true;
|
6997 | }
|
6998 | }
|
6999 | return fallthrough;
|
7000 | }
|
7001 |
|
7002 | const CanHidePrimary = !browser.ios;
|
7003 | const selectionConfig = Facet.define({
|
7004 | combine(configs) {
|
7005 | return combineConfig(configs, {
|
7006 | cursorBlinkRate: 1200,
|
7007 | drawRangeCursor: true
|
7008 | }, {
|
7009 | cursorBlinkRate: (a, b) => Math.min(a, b),
|
7010 | drawRangeCursor: (a, b) => a || b
|
7011 | });
|
7012 | }
|
7013 | });
|
7014 |
|
7015 |
|
7016 |
|
7017 |
|
7018 |
|
7019 |
|
7020 |
|
7021 |
|
7022 |
|
7023 |
|
7024 |
|
7025 |
|
7026 |
|
7027 |
|
7028 |
|
7029 |
|
7030 |
|
7031 |
|
7032 | function drawSelection(config = {}) {
|
7033 | return [
|
7034 | selectionConfig.of(config),
|
7035 | drawSelectionPlugin,
|
7036 | hideNativeSelection
|
7037 | ];
|
7038 | }
|
7039 | class Piece {
|
7040 | constructor(left, top, width, height, className) {
|
7041 | this.left = left;
|
7042 | this.top = top;
|
7043 | this.width = width;
|
7044 | this.height = height;
|
7045 | this.className = className;
|
7046 | }
|
7047 | draw() {
|
7048 | let elt = document.createElement("div");
|
7049 | elt.className = this.className;
|
7050 | this.adjust(elt);
|
7051 | return elt;
|
7052 | }
|
7053 | adjust(elt) {
|
7054 | elt.style.left = this.left + "px";
|
7055 | elt.style.top = this.top + "px";
|
7056 | if (this.width >= 0)
|
7057 | elt.style.width = this.width + "px";
|
7058 | elt.style.height = this.height + "px";
|
7059 | }
|
7060 | eq(p) {
|
7061 | return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height &&
|
7062 | this.className == p.className;
|
7063 | }
|
7064 | }
|
7065 | const drawSelectionPlugin = ViewPlugin.fromClass(class {
|
7066 | constructor(view) {
|
7067 | this.view = view;
|
7068 | this.rangePieces = [];
|
7069 | this.cursors = [];
|
7070 | this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) };
|
7071 | this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div"));
|
7072 | this.selectionLayer.className = "cm-selectionLayer";
|
7073 | this.selectionLayer.setAttribute("aria-hidden", "true");
|
7074 | this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div"));
|
7075 | this.cursorLayer.className = "cm-cursorLayer";
|
7076 | this.cursorLayer.setAttribute("aria-hidden", "true");
|
7077 | view.requestMeasure(this.measureReq);
|
7078 | this.setBlinkRate();
|
7079 | }
|
7080 | setBlinkRate() {
|
7081 | this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms";
|
7082 | }
|
7083 | update(update) {
|
7084 | let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
|
7085 | if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged)
|
7086 | this.view.requestMeasure(this.measureReq);
|
7087 | if (update.transactions.some(tr => tr.scrollIntoView))
|
7088 | this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
|
7089 | if (confChanged)
|
7090 | this.setBlinkRate();
|
7091 | }
|
7092 | readPos() {
|
7093 | let { state } = this.view, conf = state.facet(selectionConfig);
|
7094 | let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b));
|
7095 | let cursors = [];
|
7096 | for (let r of state.selection.ranges) {
|
7097 | let prim = r == state.selection.main;
|
7098 | if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
|
7099 | let piece = measureCursor(this.view, r, prim);
|
7100 | if (piece)
|
7101 | cursors.push(piece);
|
7102 | }
|
7103 | }
|
7104 | return { rangePieces, cursors };
|
7105 | }
|
7106 | drawSel({ rangePieces, cursors }) {
|
7107 | if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) {
|
7108 | this.selectionLayer.textContent = "";
|
7109 | for (let p of rangePieces)
|
7110 | this.selectionLayer.appendChild(p.draw());
|
7111 | this.rangePieces = rangePieces;
|
7112 | }
|
7113 | if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) {
|
7114 | let oldCursors = this.cursorLayer.children;
|
7115 | if (oldCursors.length !== cursors.length) {
|
7116 | this.cursorLayer.textContent = "";
|
7117 | for (const c of cursors)
|
7118 | this.cursorLayer.appendChild(c.draw());
|
7119 | }
|
7120 | else {
|
7121 | cursors.forEach((c, idx) => c.adjust(oldCursors[idx]));
|
7122 | }
|
7123 | this.cursors = cursors;
|
7124 | }
|
7125 | }
|
7126 | destroy() {
|
7127 | this.selectionLayer.remove();
|
7128 | this.cursorLayer.remove();
|
7129 | }
|
7130 | });
|
7131 | const themeSpec = {
|
7132 | ".cm-line": {
|
7133 | "& ::selection": { backgroundColor: "transparent !important" },
|
7134 | "&::selection": { backgroundColor: "transparent !important" }
|
7135 | }
|
7136 | };
|
7137 | if (CanHidePrimary)
|
7138 | themeSpec[".cm-line"].caretColor = "transparent !important";
|
7139 | const hideNativeSelection = Prec.highest(EditorView.theme(themeSpec));
|
7140 | function getBase(view) {
|
7141 | let rect = view.scrollDOM.getBoundingClientRect();
|
7142 | let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
|
7143 | return { left: left - view.scrollDOM.scrollLeft, top: rect.top - view.scrollDOM.scrollTop };
|
7144 | }
|
7145 | function wrappedLine(view, pos, inside) {
|
7146 | let range = EditorSelection.cursor(pos);
|
7147 | return { from: Math.max(inside.from, view.moveToLineBoundary(range, false, true).from),
|
7148 | to: Math.min(inside.to, view.moveToLineBoundary(range, true, true).from),
|
7149 | type: BlockType.Text };
|
7150 | }
|
7151 | function blockAt(view, pos) {
|
7152 | let line = view.lineBlockAt(pos);
|
7153 | if (Array.isArray(line.type))
|
7154 | for (let l of line.type) {
|
7155 | if (l.to > pos || l.to == pos && (l.to == line.to || l.type == BlockType.Text))
|
7156 | return l;
|
7157 | }
|
7158 | return line;
|
7159 | }
|
7160 | function measureRange(view, range) {
|
7161 | if (range.to <= view.viewport.from || range.from >= view.viewport.to)
|
7162 | return [];
|
7163 | let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
|
7164 | let ltr = view.textDirection == Direction.LTR;
|
7165 | let content = view.contentDOM, contentRect = content.getBoundingClientRect(), base = getBase(view);
|
7166 | let lineStyle = window.getComputedStyle(content.firstChild);
|
7167 | let leftSide = contentRect.left + parseInt(lineStyle.paddingLeft) + Math.min(0, parseInt(lineStyle.textIndent));
|
7168 | let rightSide = contentRect.right - parseInt(lineStyle.paddingRight);
|
7169 | let startBlock = blockAt(view, from), endBlock = blockAt(view, to);
|
7170 | let visualStart = startBlock.type == BlockType.Text ? startBlock : null;
|
7171 | let visualEnd = endBlock.type == BlockType.Text ? endBlock : null;
|
7172 | if (view.lineWrapping) {
|
7173 | if (visualStart)
|
7174 | visualStart = wrappedLine(view, from, visualStart);
|
7175 | if (visualEnd)
|
7176 | visualEnd = wrappedLine(view, to, visualEnd);
|
7177 | }
|
7178 | if (visualStart && visualEnd && visualStart.from == visualEnd.from) {
|
7179 | return pieces(drawForLine(range.from, range.to, visualStart));
|
7180 | }
|
7181 | else {
|
7182 | let top = visualStart ? drawForLine(range.from, null, visualStart) : drawForWidget(startBlock, false);
|
7183 | let bottom = visualEnd ? drawForLine(null, range.to, visualEnd) : drawForWidget(endBlock, true);
|
7184 | let between = [];
|
7185 | if ((visualStart || startBlock).to < (visualEnd || endBlock).from - 1)
|
7186 | between.push(piece(leftSide, top.bottom, rightSide, bottom.top));
|
7187 | else if (top.bottom < bottom.top && view.elementAtHeight((top.bottom + bottom.top) / 2).type == BlockType.Text)
|
7188 | top.bottom = bottom.top = (top.bottom + bottom.top) / 2;
|
7189 | return pieces(top).concat(between).concat(pieces(bottom));
|
7190 | }
|
7191 | function piece(left, top, right, bottom) {
|
7192 | return new Piece(left - base.left, top - base.top - 0.01 , right - left, bottom - top + 0.01 , "cm-selectionBackground");
|
7193 | }
|
7194 | function pieces({ top, bottom, horizontal }) {
|
7195 | let pieces = [];
|
7196 | for (let i = 0; i < horizontal.length; i += 2)
|
7197 | pieces.push(piece(horizontal[i], top, horizontal[i + 1], bottom));
|
7198 | return pieces;
|
7199 | }
|
7200 |
|
7201 | function drawForLine(from, to, line) {
|
7202 | let top = 1e9, bottom = -1e9, horizontal = [];
|
7203 | function addSpan(from, fromOpen, to, toOpen, dir) {
|
7204 |
|
7205 |
|
7206 |
|
7207 |
|
7208 | let fromCoords = view.coordsAtPos(from, (from == line.to ? -2 : 2));
|
7209 | let toCoords = view.coordsAtPos(to, (to == line.from ? 2 : -2));
|
7210 | top = Math.min(fromCoords.top, toCoords.top, top);
|
7211 | bottom = Math.max(fromCoords.bottom, toCoords.bottom, bottom);
|
7212 | if (dir == Direction.LTR)
|
7213 | horizontal.push(ltr && fromOpen ? leftSide : fromCoords.left, ltr && toOpen ? rightSide : toCoords.right);
|
7214 | else
|
7215 | horizontal.push(!ltr && toOpen ? leftSide : toCoords.left, !ltr && fromOpen ? rightSide : fromCoords.right);
|
7216 | }
|
7217 | let start = from !== null && from !== void 0 ? from : line.from, end = to !== null && to !== void 0 ? to : line.to;
|
7218 |
|
7219 | for (let r of view.visibleRanges)
|
7220 | if (r.to > start && r.from < end) {
|
7221 | for (let pos = Math.max(r.from, start), endPos = Math.min(r.to, end);;) {
|
7222 | let docLine = view.state.doc.lineAt(pos);
|
7223 | for (let span of view.bidiSpans(docLine)) {
|
7224 | let spanFrom = span.from + docLine.from, spanTo = span.to + docLine.from;
|
7225 | if (spanFrom >= endPos)
|
7226 | break;
|
7227 | if (spanTo > pos)
|
7228 | addSpan(Math.max(spanFrom, pos), from == null && spanFrom <= start, Math.min(spanTo, endPos), to == null && spanTo >= end, span.dir);
|
7229 | }
|
7230 | pos = docLine.to + 1;
|
7231 | if (pos >= endPos)
|
7232 | break;
|
7233 | }
|
7234 | }
|
7235 | if (horizontal.length == 0)
|
7236 | addSpan(start, from == null, end, to == null, view.textDirection);
|
7237 | return { top, bottom, horizontal };
|
7238 | }
|
7239 | function drawForWidget(block, top) {
|
7240 | let y = contentRect.top + (top ? block.top : block.bottom);
|
7241 | return { top: y, bottom: y, horizontal: [] };
|
7242 | }
|
7243 | }
|
7244 | function measureCursor(view, cursor, primary) {
|
7245 | let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
|
7246 | if (!pos)
|
7247 | return null;
|
7248 | let base = getBase(view);
|
7249 | return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary");
|
7250 | }
|
7251 |
|
7252 | const setDropCursorPos = StateEffect.define({
|
7253 | map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
|
7254 | });
|
7255 | const dropCursorPos = StateField.define({
|
7256 | create() { return null; },
|
7257 | update(pos, tr) {
|
7258 | if (pos != null)
|
7259 | pos = tr.changes.mapPos(pos);
|
7260 | return tr.effects.reduce((pos, e) => e.is(setDropCursorPos) ? e.value : pos, pos);
|
7261 | }
|
7262 | });
|
7263 | const drawDropCursor = ViewPlugin.fromClass(class {
|
7264 | constructor(view) {
|
7265 | this.view = view;
|
7266 | this.cursor = null;
|
7267 | this.measureReq = { read: this.readPos.bind(this), write: this.drawCursor.bind(this) };
|
7268 | }
|
7269 | update(update) {
|
7270 | var _a;
|
7271 | let cursorPos = update.state.field(dropCursorPos);
|
7272 | if (cursorPos == null) {
|
7273 | if (this.cursor != null) {
|
7274 | (_a = this.cursor) === null || _a === void 0 ? void 0 : _a.remove();
|
7275 | this.cursor = null;
|
7276 | }
|
7277 | }
|
7278 | else {
|
7279 | if (!this.cursor) {
|
7280 | this.cursor = this.view.scrollDOM.appendChild(document.createElement("div"));
|
7281 | this.cursor.className = "cm-dropCursor";
|
7282 | }
|
7283 | if (update.startState.field(dropCursorPos) != cursorPos || update.docChanged || update.geometryChanged)
|
7284 | this.view.requestMeasure(this.measureReq);
|
7285 | }
|
7286 | }
|
7287 | readPos() {
|
7288 | let pos = this.view.state.field(dropCursorPos);
|
7289 | let rect = pos != null && this.view.coordsAtPos(pos);
|
7290 | if (!rect)
|
7291 | return null;
|
7292 | let outer = this.view.scrollDOM.getBoundingClientRect();
|
7293 | return {
|
7294 | left: rect.left - outer.left + this.view.scrollDOM.scrollLeft,
|
7295 | top: rect.top - outer.top + this.view.scrollDOM.scrollTop,
|
7296 | height: rect.bottom - rect.top
|
7297 | };
|
7298 | }
|
7299 | drawCursor(pos) {
|
7300 | if (this.cursor) {
|
7301 | if (pos) {
|
7302 | this.cursor.style.left = pos.left + "px";
|
7303 | this.cursor.style.top = pos.top + "px";
|
7304 | this.cursor.style.height = pos.height + "px";
|
7305 | }
|
7306 | else {
|
7307 | this.cursor.style.left = "-100000px";
|
7308 | }
|
7309 | }
|
7310 | }
|
7311 | destroy() {
|
7312 | if (this.cursor)
|
7313 | this.cursor.remove();
|
7314 | }
|
7315 | setDropPos(pos) {
|
7316 | if (this.view.state.field(dropCursorPos) != pos)
|
7317 | this.view.dispatch({ effects: setDropCursorPos.of(pos) });
|
7318 | }
|
7319 | }, {
|
7320 | eventHandlers: {
|
7321 | dragover(event) {
|
7322 | this.setDropPos(this.view.posAtCoords({ x: event.clientX, y: event.clientY }));
|
7323 | },
|
7324 | dragleave(event) {
|
7325 | if (event.target == this.view.contentDOM || !this.view.contentDOM.contains(event.relatedTarget))
|
7326 | this.setDropPos(null);
|
7327 | },
|
7328 | dragend() {
|
7329 | this.setDropPos(null);
|
7330 | },
|
7331 | drop() {
|
7332 | this.setDropPos(null);
|
7333 | }
|
7334 | }
|
7335 | });
|
7336 |
|
7337 |
|
7338 |
|
7339 |
|
7340 | function dropCursor() {
|
7341 | return [dropCursorPos, drawDropCursor];
|
7342 | }
|
7343 |
|
7344 | function iterMatches(doc, re, from, to, f) {
|
7345 | re.lastIndex = 0;
|
7346 | for (let cursor = doc.iterRange(from, to), pos = from, m; !cursor.next().done; pos += cursor.value.length) {
|
7347 | if (!cursor.lineBreak)
|
7348 | while (m = re.exec(cursor.value))
|
7349 | f(pos + m.index, pos + m.index + m[0].length, m);
|
7350 | }
|
7351 | }
|
7352 | function matchRanges(view, maxLength) {
|
7353 | let visible = view.visibleRanges;
|
7354 | if (visible.length == 1 && visible[0].from == view.viewport.from &&
|
7355 | visible[0].to == view.viewport.to)
|
7356 | return visible;
|
7357 | let result = [];
|
7358 | for (let { from, to } of visible) {
|
7359 | from = Math.max(view.state.doc.lineAt(from).from, from - maxLength);
|
7360 | to = Math.min(view.state.doc.lineAt(to).to, to + maxLength);
|
7361 | if (result.length && result[result.length - 1].to >= from)
|
7362 | result[result.length - 1].to = to;
|
7363 | else
|
7364 | result.push({ from, to });
|
7365 | }
|
7366 | return result;
|
7367 | }
|
7368 |
|
7369 |
|
7370 |
|
7371 |
|
7372 |
|
7373 |
|
7374 | class MatchDecorator {
|
7375 | |
7376 |
|
7377 |
|
7378 | constructor(config) {
|
7379 | let { regexp, decoration, boundary, maxLength = 1000 } = config;
|
7380 | if (!regexp.global)
|
7381 | throw new RangeError("The regular expression given to MatchDecorator should have its 'g' flag set");
|
7382 | this.regexp = regexp;
|
7383 | this.getDeco = typeof decoration == "function" ? decoration : () => decoration;
|
7384 | this.boundary = boundary;
|
7385 | this.maxLength = maxLength;
|
7386 | }
|
7387 | |
7388 |
|
7389 |
|
7390 |
|
7391 |
|
7392 | createDeco(view) {
|
7393 | let build = new RangeSetBuilder();
|
7394 | for (let { from, to } of matchRanges(view, this.maxLength))
|
7395 | iterMatches(view.state.doc, this.regexp, from, to, (a, b, m) => build.add(a, b, this.getDeco(m, view, a)));
|
7396 | return build.finish();
|
7397 | }
|
7398 | |
7399 |
|
7400 |
|
7401 |
|
7402 |
|
7403 | updateDeco(update, deco) {
|
7404 | let changeFrom = 1e9, changeTo = -1;
|
7405 | if (update.docChanged)
|
7406 | update.changes.iterChanges((_f, _t, from, to) => {
|
7407 | if (to > update.view.viewport.from && from < update.view.viewport.to) {
|
7408 | changeFrom = Math.min(from, changeFrom);
|
7409 | changeTo = Math.max(to, changeTo);
|
7410 | }
|
7411 | });
|
7412 | if (update.viewportChanged || changeTo - changeFrom > 1000)
|
7413 | return this.createDeco(update.view);
|
7414 | if (changeTo > -1)
|
7415 | return this.updateRange(update.view, deco.map(update.changes), changeFrom, changeTo);
|
7416 | return deco;
|
7417 | }
|
7418 | updateRange(view, deco, updateFrom, updateTo) {
|
7419 | for (let r of view.visibleRanges) {
|
7420 | let from = Math.max(r.from, updateFrom), to = Math.min(r.to, updateTo);
|
7421 | if (to > from) {
|
7422 | let fromLine = view.state.doc.lineAt(from), toLine = fromLine.to < to ? view.state.doc.lineAt(to) : fromLine;
|
7423 | let start = Math.max(r.from, fromLine.from), end = Math.min(r.to, toLine.to);
|
7424 | if (this.boundary) {
|
7425 | for (; from > fromLine.from; from--)
|
7426 | if (this.boundary.test(fromLine.text[from - 1 - fromLine.from])) {
|
7427 | start = from;
|
7428 | break;
|
7429 | }
|
7430 | for (; to < toLine.to; to++)
|
7431 | if (this.boundary.test(toLine.text[to - toLine.from])) {
|
7432 | end = to;
|
7433 | break;
|
7434 | }
|
7435 | }
|
7436 | let ranges = [], m;
|
7437 | if (fromLine == toLine) {
|
7438 | this.regexp.lastIndex = start - fromLine.from;
|
7439 | while ((m = this.regexp.exec(fromLine.text)) && m.index < end - fromLine.from) {
|
7440 | let pos = m.index + fromLine.from;
|
7441 | ranges.push(this.getDeco(m, view, pos).range(pos, pos + m[0].length));
|
7442 | }
|
7443 | }
|
7444 | else {
|
7445 | iterMatches(view.state.doc, this.regexp, start, end, (from, to, m) => ranges.push(this.getDeco(m, view, from).range(from, to)));
|
7446 | }
|
7447 | deco = deco.update({ filterFrom: start, filterTo: end, filter: (from, to) => from < start || to > end, add: ranges });
|
7448 | }
|
7449 | }
|
7450 | return deco;
|
7451 | }
|
7452 | }
|
7453 |
|
7454 | const UnicodeRegexpSupport = /x/.unicode != null ? "gu" : "g";
|
7455 | const Specials = new RegExp("[\u0000-\u0008\u000a-\u001f\u007f-\u009f\u00ad\u061c\u200b\u200e\u200f\u2028\u2029\u202d\u202e\ufeff\ufff9-\ufffc]", UnicodeRegexpSupport);
|
7456 | const Names = {
|
7457 | 0: "null",
|
7458 | 7: "bell",
|
7459 | 8: "backspace",
|
7460 | 10: "newline",
|
7461 | 11: "vertical tab",
|
7462 | 13: "carriage return",
|
7463 | 27: "escape",
|
7464 | 8203: "zero width space",
|
7465 | 8204: "zero width non-joiner",
|
7466 | 8205: "zero width joiner",
|
7467 | 8206: "left-to-right mark",
|
7468 | 8207: "right-to-left mark",
|
7469 | 8232: "line separator",
|
7470 | 8237: "left-to-right override",
|
7471 | 8238: "right-to-left override",
|
7472 | 8233: "paragraph separator",
|
7473 | 65279: "zero width no-break space",
|
7474 | 65532: "object replacement"
|
7475 | };
|
7476 | let _supportsTabSize = null;
|
7477 | function supportsTabSize() {
|
7478 | var _a;
|
7479 | if (_supportsTabSize == null && typeof document != "undefined" && document.body) {
|
7480 | let styles = document.body.style;
|
7481 | _supportsTabSize = ((_a = styles.tabSize) !== null && _a !== void 0 ? _a : styles.MozTabSize) != null;
|
7482 | }
|
7483 | return _supportsTabSize || false;
|
7484 | }
|
7485 | const specialCharConfig = Facet.define({
|
7486 | combine(configs) {
|
7487 | let config = combineConfig(configs, {
|
7488 | render: null,
|
7489 | specialChars: Specials,
|
7490 | addSpecialChars: null
|
7491 | });
|
7492 | if (config.replaceTabs = !supportsTabSize())
|
7493 | config.specialChars = new RegExp("\t|" + config.specialChars.source, UnicodeRegexpSupport);
|
7494 | if (config.addSpecialChars)
|
7495 | config.specialChars = new RegExp(config.specialChars.source + "|" + config.addSpecialChars.source, UnicodeRegexpSupport);
|
7496 | return config;
|
7497 | }
|
7498 | });
|
7499 |
|
7500 |
|
7501 |
|
7502 |
|
7503 | function highlightSpecialChars(
|
7504 | /**
|
7505 | Configuration options.
|
7506 | */
|
7507 | config = {}) {
|
7508 | return [specialCharConfig.of(config), specialCharPlugin()];
|
7509 | }
|
7510 | let _plugin = null;
|
7511 | function specialCharPlugin() {
|
7512 | return _plugin || (_plugin = ViewPlugin.fromClass(class {
|
7513 | constructor(view) {
|
7514 | this.view = view;
|
7515 | this.decorations = Decoration.none;
|
7516 | this.decorationCache = Object.create(null);
|
7517 | this.decorator = this.makeDecorator(view.state.facet(specialCharConfig));
|
7518 | this.decorations = this.decorator.createDeco(view);
|
7519 | }
|
7520 | makeDecorator(conf) {
|
7521 | return new MatchDecorator({
|
7522 | regexp: conf.specialChars,
|
7523 | decoration: (m, view, pos) => {
|
7524 | let { doc } = view.state;
|
7525 | let code = codePointAt(m[0], 0);
|
7526 | if (code == 9) {
|
7527 | let line = doc.lineAt(pos);
|
7528 | let size = view.state.tabSize, col = countColumn(line.text, size, pos - line.from);
|
7529 | return Decoration.replace({ widget: new TabWidget((size - (col % size)) * this.view.defaultCharacterWidth) });
|
7530 | }
|
7531 | return this.decorationCache[code] ||
|
7532 | (this.decorationCache[code] = Decoration.replace({ widget: new SpecialCharWidget(conf, code) }));
|
7533 | },
|
7534 | boundary: conf.replaceTabs ? undefined : /[^]/
|
7535 | });
|
7536 | }
|
7537 | update(update) {
|
7538 | let conf = update.state.facet(specialCharConfig);
|
7539 | if (update.startState.facet(specialCharConfig) != conf) {
|
7540 | this.decorator = this.makeDecorator(conf);
|
7541 | this.decorations = this.decorator.createDeco(update.view);
|
7542 | }
|
7543 | else {
|
7544 | this.decorations = this.decorator.updateDeco(update, this.decorations);
|
7545 | }
|
7546 | }
|
7547 | }, {
|
7548 | decorations: v => v.decorations
|
7549 | }));
|
7550 | }
|
7551 | const DefaultPlaceholder = "\u2022";
|
7552 |
|
7553 |
|
7554 | function placeholder$1(code) {
|
7555 | if (code >= 32)
|
7556 | return DefaultPlaceholder;
|
7557 | if (code == 10)
|
7558 | return "\u2424";
|
7559 | return String.fromCharCode(9216 + code);
|
7560 | }
|
7561 | class SpecialCharWidget extends WidgetType {
|
7562 | constructor(options, code) {
|
7563 | super();
|
7564 | this.options = options;
|
7565 | this.code = code;
|
7566 | }
|
7567 | eq(other) { return other.code == this.code; }
|
7568 | toDOM(view) {
|
7569 | let ph = placeholder$1(this.code);
|
7570 | let desc = view.state.phrase("Control character") + " " + (Names[this.code] || "0x" + this.code.toString(16));
|
7571 | let custom = this.options.render && this.options.render(this.code, desc, ph);
|
7572 | if (custom)
|
7573 | return custom;
|
7574 | let span = document.createElement("span");
|
7575 | span.textContent = ph;
|
7576 | span.title = desc;
|
7577 | span.setAttribute("aria-label", desc);
|
7578 | span.className = "cm-specialChar";
|
7579 | return span;
|
7580 | }
|
7581 | ignoreEvent() { return false; }
|
7582 | }
|
7583 | class TabWidget extends WidgetType {
|
7584 | constructor(width) {
|
7585 | super();
|
7586 | this.width = width;
|
7587 | }
|
7588 | eq(other) { return other.width == this.width; }
|
7589 | toDOM() {
|
7590 | let span = document.createElement("span");
|
7591 | span.textContent = "\t";
|
7592 | span.className = "cm-tab";
|
7593 | span.style.width = this.width + "px";
|
7594 | return span;
|
7595 | }
|
7596 | ignoreEvent() { return false; }
|
7597 | }
|
7598 |
|
7599 | const plugin = ViewPlugin.fromClass(class {
|
7600 | constructor() {
|
7601 | this.height = 1000;
|
7602 | this.attrs = { style: "padding-bottom: 1000px" };
|
7603 | }
|
7604 | update(update) {
|
7605 | let height = update.view.viewState.editorHeight - update.view.defaultLineHeight;
|
7606 | if (height != this.height) {
|
7607 | this.height = height;
|
7608 | this.attrs = { style: `padding-bottom: ${height}px` };
|
7609 | }
|
7610 | }
|
7611 | });
|
7612 |
|
7613 |
|
7614 |
|
7615 |
|
7616 |
|
7617 |
|
7618 |
|
7619 |
|
7620 |
|
7621 | function scrollPastEnd() {
|
7622 | return [plugin, contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.attrs) || null; })];
|
7623 | }
|
7624 |
|
7625 |
|
7626 |
|
7627 |
|
7628 |
|
7629 | function highlightActiveLine() {
|
7630 | return activeLineHighlighter;
|
7631 | }
|
7632 | const lineDeco = Decoration.line({ class: "cm-activeLine" });
|
7633 | const activeLineHighlighter = ViewPlugin.fromClass(class {
|
7634 | constructor(view) {
|
7635 | this.decorations = this.getDeco(view);
|
7636 | }
|
7637 | update(update) {
|
7638 | if (update.docChanged || update.selectionSet)
|
7639 | this.decorations = this.getDeco(update.view);
|
7640 | }
|
7641 | getDeco(view) {
|
7642 | let lastLineStart = -1, deco = [];
|
7643 | for (let r of view.state.selection.ranges) {
|
7644 | if (!r.empty)
|
7645 | return Decoration.none;
|
7646 | let line = view.lineBlockAt(r.head);
|
7647 | if (line.from > lastLineStart) {
|
7648 | deco.push(lineDeco.range(line.from));
|
7649 | lastLineStart = line.from;
|
7650 | }
|
7651 | }
|
7652 | return Decoration.set(deco);
|
7653 | }
|
7654 | }, {
|
7655 | decorations: v => v.decorations
|
7656 | });
|
7657 |
|
7658 | class Placeholder extends WidgetType {
|
7659 | constructor(content) {
|
7660 | super();
|
7661 | this.content = content;
|
7662 | }
|
7663 | toDOM() {
|
7664 | let wrap = document.createElement("span");
|
7665 | wrap.className = "cm-placeholder";
|
7666 | wrap.style.pointerEvents = "none";
|
7667 | wrap.appendChild(typeof this.content == "string" ? document.createTextNode(this.content) : this.content);
|
7668 | if (typeof this.content == "string")
|
7669 | wrap.setAttribute("aria-label", "placeholder " + this.content);
|
7670 | else
|
7671 | wrap.setAttribute("aria-hidden", "true");
|
7672 | return wrap;
|
7673 | }
|
7674 | ignoreEvent() { return false; }
|
7675 | }
|
7676 |
|
7677 |
|
7678 |
|
7679 |
|
7680 | function placeholder(content) {
|
7681 | return ViewPlugin.fromClass(class {
|
7682 | constructor(view) {
|
7683 | this.view = view;
|
7684 | this.placeholder = Decoration.set([Decoration.widget({ widget: new Placeholder(content), side: 1 }).range(0)]);
|
7685 | }
|
7686 | get decorations() { return this.view.state.doc.length ? Decoration.none : this.placeholder; }
|
7687 | }, { decorations: v => v.decorations });
|
7688 | }
|
7689 |
|
7690 |
|
7691 |
|
7692 | const MaxOff = 2000;
|
7693 | function rectangleFor(state, a, b) {
|
7694 | let startLine = Math.min(a.line, b.line), endLine = Math.max(a.line, b.line);
|
7695 | let ranges = [];
|
7696 | if (a.off > MaxOff || b.off > MaxOff || a.col < 0 || b.col < 0) {
|
7697 | let startOff = Math.min(a.off, b.off), endOff = Math.max(a.off, b.off);
|
7698 | for (let i = startLine; i <= endLine; i++) {
|
7699 | let line = state.doc.line(i);
|
7700 | if (line.length <= endOff)
|
7701 | ranges.push(EditorSelection.range(line.from + startOff, line.to + endOff));
|
7702 | }
|
7703 | }
|
7704 | else {
|
7705 | let startCol = Math.min(a.col, b.col), endCol = Math.max(a.col, b.col);
|
7706 | for (let i = startLine; i <= endLine; i++) {
|
7707 | let line = state.doc.line(i);
|
7708 | let start = findColumn(line.text, startCol, state.tabSize, true);
|
7709 | if (start > -1) {
|
7710 | let end = findColumn(line.text, endCol, state.tabSize);
|
7711 | ranges.push(EditorSelection.range(line.from + start, line.from + end));
|
7712 | }
|
7713 | }
|
7714 | }
|
7715 | return ranges;
|
7716 | }
|
7717 | function absoluteColumn(view, x) {
|
7718 | let ref = view.coordsAtPos(view.viewport.from);
|
7719 | return ref ? Math.round(Math.abs((ref.left - x) / view.defaultCharacterWidth)) : -1;
|
7720 | }
|
7721 | function getPos(view, event) {
|
7722 | let offset = view.posAtCoords({ x: event.clientX, y: event.clientY }, false);
|
7723 | let line = view.state.doc.lineAt(offset), off = offset - line.from;
|
7724 | let col = off > MaxOff ? -1
|
7725 | : off == line.length ? absoluteColumn(view, event.clientX)
|
7726 | : countColumn(line.text, view.state.tabSize, offset - line.from);
|
7727 | return { line: line.number, col, off };
|
7728 | }
|
7729 | function rectangleSelectionStyle(view, event) {
|
7730 | let start = getPos(view, event), startSel = view.state.selection;
|
7731 | if (!start)
|
7732 | return null;
|
7733 | return {
|
7734 | update(update) {
|
7735 | if (update.docChanged) {
|
7736 | let newStart = update.changes.mapPos(update.startState.doc.line(start.line).from);
|
7737 | let newLine = update.state.doc.lineAt(newStart);
|
7738 | start = { line: newLine.number, col: start.col, off: Math.min(start.off, newLine.length) };
|
7739 | startSel = startSel.map(update.changes);
|
7740 | }
|
7741 | },
|
7742 | get(event, _extend, multiple) {
|
7743 | let cur = getPos(view, event);
|
7744 | if (!cur)
|
7745 | return startSel;
|
7746 | let ranges = rectangleFor(view.state, start, cur);
|
7747 | if (!ranges.length)
|
7748 | return startSel;
|
7749 | if (multiple)
|
7750 | return EditorSelection.create(ranges.concat(startSel.ranges));
|
7751 | else
|
7752 | return EditorSelection.create(ranges);
|
7753 | }
|
7754 | };
|
7755 | }
|
7756 |
|
7757 |
|
7758 |
|
7759 |
|
7760 |
|
7761 |
|
7762 |
|
7763 | function rectangularSelection(options) {
|
7764 | let filter = (options === null || options === void 0 ? void 0 : options.eventFilter) || (e => e.altKey && e.button == 0);
|
7765 | return EditorView.mouseSelectionStyle.of((view, event) => filter(event) ? rectangleSelectionStyle(view, event) : null);
|
7766 | }
|
7767 | const keys = {
|
7768 | Alt: [18, e => e.altKey],
|
7769 | Control: [17, e => e.ctrlKey],
|
7770 | Shift: [16, e => e.shiftKey],
|
7771 | Meta: [91, e => e.metaKey]
|
7772 | };
|
7773 | const showCrosshair = { style: "cursor: crosshair" };
|
7774 |
|
7775 |
|
7776 |
|
7777 |
|
7778 |
|
7779 |
|
7780 |
|
7781 | function crosshairCursor(options = {}) {
|
7782 | let [code, getter] = keys[options.key || "Alt"];
|
7783 | let plugin = ViewPlugin.fromClass(class {
|
7784 | constructor(view) {
|
7785 | this.view = view;
|
7786 | this.isDown = false;
|
7787 | }
|
7788 | set(isDown) {
|
7789 | if (this.isDown != isDown) {
|
7790 | this.isDown = isDown;
|
7791 | this.view.update([]);
|
7792 | }
|
7793 | }
|
7794 | }, {
|
7795 | eventHandlers: {
|
7796 | keydown(e) {
|
7797 | this.set(e.keyCode == code || getter(e));
|
7798 | },
|
7799 | keyup(e) {
|
7800 | if (e.keyCode == code || !getter(e))
|
7801 | this.set(false);
|
7802 | }
|
7803 | }
|
7804 | });
|
7805 | return [
|
7806 | plugin,
|
7807 | EditorView.contentAttributes.of(view => { var _a; return ((_a = view.plugin(plugin)) === null || _a === void 0 ? void 0 : _a.isDown) ? showCrosshair : null; })
|
7808 | ];
|
7809 | }
|
7810 |
|
7811 | const Outside = "-10000px";
|
7812 | class TooltipViewManager {
|
7813 | constructor(view, facet, createTooltipView) {
|
7814 | this.facet = facet;
|
7815 | this.createTooltipView = createTooltipView;
|
7816 | this.input = view.state.facet(facet);
|
7817 | this.tooltips = this.input.filter(t => t);
|
7818 | this.tooltipViews = this.tooltips.map(createTooltipView);
|
7819 | }
|
7820 | update(update) {
|
7821 | let input = update.state.facet(this.facet);
|
7822 | let tooltips = input.filter(x => x);
|
7823 | if (input === this.input) {
|
7824 | for (let t of this.tooltipViews)
|
7825 | if (t.update)
|
7826 | t.update(update);
|
7827 | return false;
|
7828 | }
|
7829 | let tooltipViews = [];
|
7830 | for (let i = 0; i < tooltips.length; i++) {
|
7831 | let tip = tooltips[i], known = -1;
|
7832 | if (!tip)
|
7833 | continue;
|
7834 | for (let i = 0; i < this.tooltips.length; i++) {
|
7835 | let other = this.tooltips[i];
|
7836 | if (other && other.create == tip.create)
|
7837 | known = i;
|
7838 | }
|
7839 | if (known < 0) {
|
7840 | tooltipViews[i] = this.createTooltipView(tip);
|
7841 | }
|
7842 | else {
|
7843 | let tooltipView = tooltipViews[i] = this.tooltipViews[known];
|
7844 | if (tooltipView.update)
|
7845 | tooltipView.update(update);
|
7846 | }
|
7847 | }
|
7848 | for (let t of this.tooltipViews)
|
7849 | if (tooltipViews.indexOf(t) < 0)
|
7850 | t.dom.remove();
|
7851 | this.input = input;
|
7852 | this.tooltips = tooltips;
|
7853 | this.tooltipViews = tooltipViews;
|
7854 | return true;
|
7855 | }
|
7856 | }
|
7857 |
|
7858 |
|
7859 |
|
7860 | function tooltips(config = {}) {
|
7861 | return tooltipConfig.of(config);
|
7862 | }
|
7863 | function windowSpace() {
|
7864 | return { top: 0, left: 0, bottom: innerHeight, right: innerWidth };
|
7865 | }
|
7866 | const tooltipConfig = Facet.define({
|
7867 | combine: values => {
|
7868 | var _a, _b, _c;
|
7869 | return ({
|
7870 | position: browser.ios ? "absolute" : ((_a = values.find(conf => conf.position)) === null || _a === void 0 ? void 0 : _a.position) || "fixed",
|
7871 | parent: ((_b = values.find(conf => conf.parent)) === null || _b === void 0 ? void 0 : _b.parent) || null,
|
7872 | tooltipSpace: ((_c = values.find(conf => conf.tooltipSpace)) === null || _c === void 0 ? void 0 : _c.tooltipSpace) || windowSpace,
|
7873 | });
|
7874 | }
|
7875 | });
|
7876 | const tooltipPlugin = ViewPlugin.fromClass(class {
|
7877 | constructor(view) {
|
7878 | var _a;
|
7879 | this.view = view;
|
7880 | this.inView = true;
|
7881 | this.lastTransaction = 0;
|
7882 | this.measureTimeout = -1;
|
7883 | let config = view.state.facet(tooltipConfig);
|
7884 | this.position = config.position;
|
7885 | this.parent = config.parent;
|
7886 | this.classes = view.themeClasses;
|
7887 | this.createContainer();
|
7888 | this.measureReq = { read: this.readMeasure.bind(this), write: this.writeMeasure.bind(this), key: this };
|
7889 | this.manager = new TooltipViewManager(view, showTooltip, t => this.createTooltip(t));
|
7890 | this.intersectionObserver = typeof IntersectionObserver == "function" ? new IntersectionObserver(entries => {
|
7891 | if (Date.now() > this.lastTransaction - 50 &&
|
7892 | entries.length > 0 && entries[entries.length - 1].intersectionRatio < 1)
|
7893 | this.measureSoon();
|
7894 | }, { threshold: [1] }) : null;
|
7895 | this.observeIntersection();
|
7896 | (_a = view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener("resize", this.measureSoon = this.measureSoon.bind(this));
|
7897 | this.maybeMeasure();
|
7898 | }
|
7899 | createContainer() {
|
7900 | if (this.parent) {
|
7901 | this.container = document.createElement("div");
|
7902 | this.container.style.position = "relative";
|
7903 | this.container.className = this.view.themeClasses;
|
7904 | this.parent.appendChild(this.container);
|
7905 | }
|
7906 | else {
|
7907 | this.container = this.view.dom;
|
7908 | }
|
7909 | }
|
7910 | observeIntersection() {
|
7911 | if (this.intersectionObserver) {
|
7912 | this.intersectionObserver.disconnect();
|
7913 | for (let tooltip of this.manager.tooltipViews)
|
7914 | this.intersectionObserver.observe(tooltip.dom);
|
7915 | }
|
7916 | }
|
7917 | measureSoon() {
|
7918 | if (this.measureTimeout < 0)
|
7919 | this.measureTimeout = setTimeout(() => {
|
7920 | this.measureTimeout = -1;
|
7921 | this.maybeMeasure();
|
7922 | }, 50);
|
7923 | }
|
7924 | update(update) {
|
7925 | if (update.transactions.length)
|
7926 | this.lastTransaction = Date.now();
|
7927 | let updated = this.manager.update(update);
|
7928 | if (updated)
|
7929 | this.observeIntersection();
|
7930 | let shouldMeasure = updated || update.geometryChanged;
|
7931 | let newConfig = update.state.facet(tooltipConfig);
|
7932 | if (newConfig.position != this.position) {
|
7933 | this.position = newConfig.position;
|
7934 | for (let t of this.manager.tooltipViews)
|
7935 | t.dom.style.position = this.position;
|
7936 | shouldMeasure = true;
|
7937 | }
|
7938 | if (newConfig.parent != this.parent) {
|
7939 | if (this.parent)
|
7940 | this.container.remove();
|
7941 | this.parent = newConfig.parent;
|
7942 | this.createContainer();
|
7943 | for (let t of this.manager.tooltipViews)
|
7944 | this.container.appendChild(t.dom);
|
7945 | shouldMeasure = true;
|
7946 | }
|
7947 | else if (this.parent && this.view.themeClasses != this.classes) {
|
7948 | this.classes = this.container.className = this.view.themeClasses;
|
7949 | }
|
7950 | if (shouldMeasure)
|
7951 | this.maybeMeasure();
|
7952 | }
|
7953 | createTooltip(tooltip) {
|
7954 | let tooltipView = tooltip.create(this.view);
|
7955 | tooltipView.dom.classList.add("cm-tooltip");
|
7956 | if (tooltip.arrow && !tooltipView.dom.querySelector(".cm-tooltip > .cm-tooltip-arrow")) {
|
7957 | let arrow = document.createElement("div");
|
7958 | arrow.className = "cm-tooltip-arrow";
|
7959 | tooltipView.dom.appendChild(arrow);
|
7960 | }
|
7961 | tooltipView.dom.style.position = this.position;
|
7962 | tooltipView.dom.style.top = Outside;
|
7963 | this.container.appendChild(tooltipView.dom);
|
7964 | if (tooltipView.mount)
|
7965 | tooltipView.mount(this.view);
|
7966 | return tooltipView;
|
7967 | }
|
7968 | destroy() {
|
7969 | var _a, _b;
|
7970 | (_a = this.view.dom.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener("resize", this.measureSoon);
|
7971 | for (let { dom } of this.manager.tooltipViews)
|
7972 | dom.remove();
|
7973 | (_b = this.intersectionObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
|
7974 | clearTimeout(this.measureTimeout);
|
7975 | }
|
7976 | readMeasure() {
|
7977 | let editor = this.view.dom.getBoundingClientRect();
|
7978 | return {
|
7979 | editor,
|
7980 | parent: this.parent ? this.container.getBoundingClientRect() : editor,
|
7981 | pos: this.manager.tooltips.map((t, i) => {
|
7982 | let tv = this.manager.tooltipViews[i];
|
7983 | return tv.getCoords ? tv.getCoords(t.pos) : this.view.coordsAtPos(t.pos);
|
7984 | }),
|
7985 | size: this.manager.tooltipViews.map(({ dom }) => dom.getBoundingClientRect()),
|
7986 | space: this.view.state.facet(tooltipConfig).tooltipSpace(this.view),
|
7987 | };
|
7988 | }
|
7989 | writeMeasure(measured) {
|
7990 | let { editor, space } = measured;
|
7991 | let others = [];
|
7992 | for (let i = 0; i < this.manager.tooltips.length; i++) {
|
7993 | let tooltip = this.manager.tooltips[i], tView = this.manager.tooltipViews[i], { dom } = tView;
|
7994 | let pos = measured.pos[i], size = measured.size[i];
|
7995 |
|
7996 | if (!pos || pos.bottom <= Math.max(editor.top, space.top) ||
|
7997 | pos.top >= Math.min(editor.bottom, space.bottom) ||
|
7998 | pos.right < Math.max(editor.left, space.left) - .1 ||
|
7999 | pos.left > Math.min(editor.right, space.right) + .1) {
|
8000 | dom.style.top = Outside;
|
8001 | continue;
|
8002 | }
|
8003 | let arrow = tooltip.arrow ? tView.dom.querySelector(".cm-tooltip-arrow") : null;
|
8004 | let arrowHeight = arrow ? 7 : 0;
|
8005 | let width = size.right - size.left, height = size.bottom - size.top;
|
8006 | let offset = tView.offset || noOffset, ltr = this.view.textDirection == Direction.LTR;
|
8007 | let left = size.width > space.right - space.left ? (ltr ? space.left : space.right - size.width)
|
8008 | : ltr ? Math.min(pos.left - (arrow ? 14 : 0) + offset.x, space.right - width)
|
8009 | : Math.max(space.left, pos.left - width + (arrow ? 14 : 0) - offset.x);
|
8010 | let above = !!tooltip.above;
|
8011 | if (!tooltip.strictSide && (above
|
8012 | ? pos.top - (size.bottom - size.top) - offset.y < space.top
|
8013 | : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
|
8014 | above == (space.bottom - pos.bottom > pos.top - space.top))
|
8015 | above = !above;
|
8016 | let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
|
8017 | let right = left + width;
|
8018 | if (tView.overlap !== true)
|
8019 | for (let r of others)
|
8020 | if (r.left < right && r.right > left && r.top < top + height && r.bottom > top)
|
8021 | top = above ? r.top - height - 2 - arrowHeight : r.bottom + arrowHeight + 2;
|
8022 | if (this.position == "absolute") {
|
8023 | dom.style.top = (top - measured.parent.top) + "px";
|
8024 | dom.style.left = (left - measured.parent.left) + "px";
|
8025 | }
|
8026 | else {
|
8027 | dom.style.top = top + "px";
|
8028 | dom.style.left = left + "px";
|
8029 | }
|
8030 | if (arrow)
|
8031 | arrow.style.left = `${pos.left + (ltr ? offset.x : -offset.x) - (left + 14 /* Offset */ - 7 /* Size */)}px`;
|
8032 | if (tView.overlap !== true)
|
8033 | others.push({ left, top, right, bottom: top + height });
|
8034 | dom.classList.toggle("cm-tooltip-above", above);
|
8035 | dom.classList.toggle("cm-tooltip-below", !above);
|
8036 | if (tView.positioned)
|
8037 | tView.positioned();
|
8038 | }
|
8039 | }
|
8040 | maybeMeasure() {
|
8041 | if (this.manager.tooltips.length) {
|
8042 | if (this.view.inView)
|
8043 | this.view.requestMeasure(this.measureReq);
|
8044 | if (this.inView != this.view.inView) {
|
8045 | this.inView = this.view.inView;
|
8046 | if (!this.inView)
|
8047 | for (let tv of this.manager.tooltipViews)
|
8048 | tv.dom.style.top = Outside;
|
8049 | }
|
8050 | }
|
8051 | }
|
8052 | }, {
|
8053 | eventHandlers: {
|
8054 | scroll() { this.maybeMeasure(); }
|
8055 | }
|
8056 | });
|
8057 | const baseTheme = EditorView.baseTheme({
|
8058 | ".cm-tooltip": {
|
8059 | zIndex: 100
|
8060 | },
|
8061 | "&light .cm-tooltip": {
|
8062 | border: "1px solid #bbb",
|
8063 | backgroundColor: "#f5f5f5"
|
8064 | },
|
8065 | "&light .cm-tooltip-section:not(:first-child)": {
|
8066 | borderTop: "1px solid #bbb",
|
8067 | },
|
8068 | "&dark .cm-tooltip": {
|
8069 | backgroundColor: "#333338",
|
8070 | color: "white"
|
8071 | },
|
8072 | ".cm-tooltip-arrow": {
|
8073 | height: `${7 /* Size */}px`,
|
8074 | width: `${7 /* Size */ * 2}px`,
|
8075 | position: "absolute",
|
8076 | zIndex: -1,
|
8077 | overflow: "hidden",
|
8078 | "&:before, &:after": {
|
8079 | content: "''",
|
8080 | position: "absolute",
|
8081 | width: 0,
|
8082 | height: 0,
|
8083 | borderLeft: `${7 /* Size */}px solid transparent`,
|
8084 | borderRight: `${7 /* Size */}px solid transparent`,
|
8085 | },
|
8086 | ".cm-tooltip-above &": {
|
8087 | bottom: `-${7 /* Size */}px`,
|
8088 | "&:before": {
|
8089 | borderTop: `${7 /* Size */}px solid #bbb`,
|
8090 | },
|
8091 | "&:after": {
|
8092 | borderTop: `${7 /* Size */}px solid #f5f5f5`,
|
8093 | bottom: "1px"
|
8094 | }
|
8095 | },
|
8096 | ".cm-tooltip-below &": {
|
8097 | top: `-${7 /* Size */}px`,
|
8098 | "&:before": {
|
8099 | borderBottom: `${7 /* Size */}px solid #bbb`,
|
8100 | },
|
8101 | "&:after": {
|
8102 | borderBottom: `${7 /* Size */}px solid #f5f5f5`,
|
8103 | top: "1px"
|
8104 | }
|
8105 | },
|
8106 | },
|
8107 | "&dark .cm-tooltip .cm-tooltip-arrow": {
|
8108 | "&:before": {
|
8109 | borderTopColor: "#333338",
|
8110 | borderBottomColor: "#333338"
|
8111 | },
|
8112 | "&:after": {
|
8113 | borderTopColor: "transparent",
|
8114 | borderBottomColor: "transparent"
|
8115 | }
|
8116 | }
|
8117 | });
|
8118 | const noOffset = { x: 0, y: 0 };
|
8119 |
|
8120 |
|
8121 |
|
8122 | const showTooltip = Facet.define({
|
8123 | enables: [tooltipPlugin, baseTheme]
|
8124 | });
|
8125 | const showHoverTooltip = Facet.define();
|
8126 | class HoverTooltipHost {
|
8127 | constructor(view) {
|
8128 | this.view = view;
|
8129 | this.mounted = false;
|
8130 | this.dom = document.createElement("div");
|
8131 | this.dom.classList.add("cm-tooltip-hover");
|
8132 | this.manager = new TooltipViewManager(view, showHoverTooltip, t => this.createHostedView(t));
|
8133 | }
|
8134 |
|
8135 | static create(view) {
|
8136 | return new HoverTooltipHost(view);
|
8137 | }
|
8138 | createHostedView(tooltip) {
|
8139 | let hostedView = tooltip.create(this.view);
|
8140 | hostedView.dom.classList.add("cm-tooltip-section");
|
8141 | this.dom.appendChild(hostedView.dom);
|
8142 | if (this.mounted && hostedView.mount)
|
8143 | hostedView.mount(this.view);
|
8144 | return hostedView;
|
8145 | }
|
8146 | mount(view) {
|
8147 | for (let hostedView of this.manager.tooltipViews) {
|
8148 | if (hostedView.mount)
|
8149 | hostedView.mount(view);
|
8150 | }
|
8151 | this.mounted = true;
|
8152 | }
|
8153 | positioned() {
|
8154 | for (let hostedView of this.manager.tooltipViews) {
|
8155 | if (hostedView.positioned)
|
8156 | hostedView.positioned();
|
8157 | }
|
8158 | }
|
8159 | update(update) {
|
8160 | this.manager.update(update);
|
8161 | }
|
8162 | }
|
8163 | const showHoverTooltipHost = showTooltip.compute([showHoverTooltip], state => {
|
8164 | let tooltips = state.facet(showHoverTooltip).filter(t => t);
|
8165 | if (tooltips.length === 0)
|
8166 | return null;
|
8167 | return {
|
8168 | pos: Math.min(...tooltips.map(t => t.pos)),
|
8169 | end: Math.max(...tooltips.filter(t => t.end != null).map(t => t.end)),
|
8170 | create: HoverTooltipHost.create,
|
8171 | above: tooltips[0].above,
|
8172 | arrow: tooltips.some(t => t.arrow),
|
8173 | };
|
8174 | });
|
8175 | class HoverPlugin {
|
8176 | constructor(view, source, field, setHover, hoverTime) {
|
8177 | this.view = view;
|
8178 | this.source = source;
|
8179 | this.field = field;
|
8180 | this.setHover = setHover;
|
8181 | this.hoverTime = hoverTime;
|
8182 | this.hoverTimeout = -1;
|
8183 | this.restartTimeout = -1;
|
8184 | this.pending = null;
|
8185 | this.lastMove = { x: 0, y: 0, target: view.dom, time: 0 };
|
8186 | this.checkHover = this.checkHover.bind(this);
|
8187 | view.dom.addEventListener("mouseleave", this.mouseleave = this.mouseleave.bind(this));
|
8188 | view.dom.addEventListener("mousemove", this.mousemove = this.mousemove.bind(this));
|
8189 | }
|
8190 | update() {
|
8191 | if (this.pending) {
|
8192 | this.pending = null;
|
8193 | clearTimeout(this.restartTimeout);
|
8194 | this.restartTimeout = setTimeout(() => this.startHover(), 20);
|
8195 | }
|
8196 | }
|
8197 | get active() {
|
8198 | return this.view.state.field(this.field);
|
8199 | }
|
8200 | checkHover() {
|
8201 | this.hoverTimeout = -1;
|
8202 | if (this.active)
|
8203 | return;
|
8204 | let hovered = Date.now() - this.lastMove.time;
|
8205 | if (hovered < this.hoverTime)
|
8206 | this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime - hovered);
|
8207 | else
|
8208 | this.startHover();
|
8209 | }
|
8210 | startHover() {
|
8211 | clearTimeout(this.restartTimeout);
|
8212 | let { lastMove } = this;
|
8213 | let pos = this.view.contentDOM.contains(lastMove.target) ? this.view.posAtCoords(lastMove) : null;
|
8214 | if (pos == null)
|
8215 | return;
|
8216 | let posCoords = this.view.coordsAtPos(pos);
|
8217 | if (posCoords == null || lastMove.y < posCoords.top || lastMove.y > posCoords.bottom ||
|
8218 | lastMove.x < posCoords.left - this.view.defaultCharacterWidth ||
|
8219 | lastMove.x > posCoords.right + this.view.defaultCharacterWidth)
|
8220 | return;
|
8221 | let bidi = this.view.bidiSpans(this.view.state.doc.lineAt(pos)).find(s => s.from <= pos && s.to >= pos);
|
8222 | let rtl = bidi && bidi.dir == Direction.RTL ? -1 : 1;
|
8223 | let open = this.source(this.view, pos, (lastMove.x < posCoords.left ? -rtl : rtl));
|
8224 | if (open === null || open === void 0 ? void 0 : open.then) {
|
8225 | let pending = this.pending = { pos };
|
8226 | open.then(result => {
|
8227 | if (this.pending == pending) {
|
8228 | this.pending = null;
|
8229 | if (result)
|
8230 | this.view.dispatch({ effects: this.setHover.of(result) });
|
8231 | }
|
8232 | }, e => logException(this.view.state, e, "hover tooltip"));
|
8233 | }
|
8234 | else if (open) {
|
8235 | this.view.dispatch({ effects: this.setHover.of(open) });
|
8236 | }
|
8237 | }
|
8238 | mousemove(event) {
|
8239 | var _a;
|
8240 | this.lastMove = { x: event.clientX, y: event.clientY, target: event.target, time: Date.now() };
|
8241 | if (this.hoverTimeout < 0)
|
8242 | this.hoverTimeout = setTimeout(this.checkHover, this.hoverTime);
|
8243 | let tooltip = this.active;
|
8244 | if (tooltip && !isInTooltip(this.lastMove.target) || this.pending) {
|
8245 | let { pos } = tooltip || this.pending, end = (_a = tooltip === null || tooltip === void 0 ? void 0 : tooltip.end) !== null && _a !== void 0 ? _a : pos;
|
8246 | if ((pos == end ? this.view.posAtCoords(this.lastMove) != pos
|
8247 | : !isOverRange(this.view, pos, end, event.clientX, event.clientY, 6 ))) {
|
8248 | this.view.dispatch({ effects: this.setHover.of(null) });
|
8249 | this.pending = null;
|
8250 | }
|
8251 | }
|
8252 | }
|
8253 | mouseleave() {
|
8254 | clearTimeout(this.hoverTimeout);
|
8255 | this.hoverTimeout = -1;
|
8256 | if (this.active)
|
8257 | this.view.dispatch({ effects: this.setHover.of(null) });
|
8258 | }
|
8259 | destroy() {
|
8260 | clearTimeout(this.hoverTimeout);
|
8261 | this.view.dom.removeEventListener("mouseleave", this.mouseleave);
|
8262 | this.view.dom.removeEventListener("mousemove", this.mousemove);
|
8263 | }
|
8264 | }
|
8265 | function isInTooltip(elt) {
|
8266 | for (let cur = elt; cur; cur = cur.parentNode)
|
8267 | if (cur.nodeType == 1 && cur.classList.contains("cm-tooltip"))
|
8268 | return true;
|
8269 | return false;
|
8270 | }
|
8271 | function isOverRange(view, from, to, x, y, margin) {
|
8272 | let range = document.createRange();
|
8273 | let fromDOM = view.domAtPos(from), toDOM = view.domAtPos(to);
|
8274 | range.setEnd(toDOM.node, toDOM.offset);
|
8275 | range.setStart(fromDOM.node, fromDOM.offset);
|
8276 | let rects = range.getClientRects();
|
8277 | range.detach();
|
8278 | for (let i = 0; i < rects.length; i++) {
|
8279 | let rect = rects[i];
|
8280 | let dist = Math.max(rect.top - y, y - rect.bottom, rect.left - x, x - rect.right);
|
8281 | if (dist <= margin)
|
8282 | return true;
|
8283 | }
|
8284 | return false;
|
8285 | }
|
8286 |
|
8287 |
|
8288 |
|
8289 |
|
8290 |
|
8291 |
|
8292 |
|
8293 |
|
8294 |
|
8295 |
|
8296 |
|
8297 |
|
8298 |
|
8299 | function hoverTooltip(source, options = {}) {
|
8300 | let setHover = StateEffect.define();
|
8301 | let hoverState = StateField.define({
|
8302 | create() { return null; },
|
8303 | update(value, tr) {
|
8304 | if (value && (options.hideOnChange && (tr.docChanged || tr.selection) ||
|
8305 | options.hideOn && options.hideOn(tr, value)))
|
8306 | return null;
|
8307 | if (value && tr.docChanged) {
|
8308 | let newPos = tr.changes.mapPos(value.pos, -1, MapMode.TrackDel);
|
8309 | if (newPos == null)
|
8310 | return null;
|
8311 | let copy = Object.assign(Object.create(null), value);
|
8312 | copy.pos = newPos;
|
8313 | if (value.end != null)
|
8314 | copy.end = tr.changes.mapPos(value.end);
|
8315 | value = copy;
|
8316 | }
|
8317 | for (let effect of tr.effects) {
|
8318 | if (effect.is(setHover))
|
8319 | value = effect.value;
|
8320 | if (effect.is(closeHoverTooltipEffect))
|
8321 | value = null;
|
8322 | }
|
8323 | return value;
|
8324 | },
|
8325 | provide: f => showHoverTooltip.from(f)
|
8326 | });
|
8327 | return [
|
8328 | hoverState,
|
8329 | ViewPlugin.define(view => new HoverPlugin(view, source, hoverState, setHover, options.hoverTime || 300 )),
|
8330 | showHoverTooltipHost
|
8331 | ];
|
8332 | }
|
8333 |
|
8334 |
|
8335 |
|
8336 | function getTooltip(view, tooltip) {
|
8337 | let plugin = view.plugin(tooltipPlugin);
|
8338 | if (!plugin)
|
8339 | return null;
|
8340 | let found = plugin.manager.tooltips.indexOf(tooltip);
|
8341 | return found < 0 ? null : plugin.manager.tooltipViews[found];
|
8342 | }
|
8343 |
|
8344 |
|
8345 |
|
8346 | function hasHoverTooltips(state) {
|
8347 | return state.facet(showHoverTooltip).some(x => x);
|
8348 | }
|
8349 | const closeHoverTooltipEffect = StateEffect.define();
|
8350 |
|
8351 |
|
8352 |
|
8353 | const closeHoverTooltips = closeHoverTooltipEffect.of(null);
|
8354 |
|
8355 |
|
8356 |
|
8357 |
|
8358 |
|
8359 |
|
8360 | function repositionTooltips(view) {
|
8361 | var _a;
|
8362 | (_a = view.plugin(tooltipPlugin)) === null || _a === void 0 ? void 0 : _a.maybeMeasure();
|
8363 | }
|
8364 |
|
8365 | const panelConfig = Facet.define({
|
8366 | combine(configs) {
|
8367 | let topContainer, bottomContainer;
|
8368 | for (let c of configs) {
|
8369 | topContainer = topContainer || c.topContainer;
|
8370 | bottomContainer = bottomContainer || c.bottomContainer;
|
8371 | }
|
8372 | return { topContainer, bottomContainer };
|
8373 | }
|
8374 | });
|
8375 |
|
8376 |
|
8377 |
|
8378 | function panels(config) {
|
8379 | return config ? [panelConfig.of(config)] : [];
|
8380 | }
|
8381 |
|
8382 |
|
8383 |
|
8384 |
|
8385 |
|
8386 | function getPanel(view, panel) {
|
8387 | let plugin = view.plugin(panelPlugin);
|
8388 | let index = plugin ? plugin.specs.indexOf(panel) : -1;
|
8389 | return index > -1 ? plugin.panels[index] : null;
|
8390 | }
|
8391 | const panelPlugin = ViewPlugin.fromClass(class {
|
8392 | constructor(view) {
|
8393 | this.input = view.state.facet(showPanel);
|
8394 | this.specs = this.input.filter(s => s);
|
8395 | this.panels = this.specs.map(spec => spec(view));
|
8396 | let conf = view.state.facet(panelConfig);
|
8397 | this.top = new PanelGroup(view, true, conf.topContainer);
|
8398 | this.bottom = new PanelGroup(view, false, conf.bottomContainer);
|
8399 | this.top.sync(this.panels.filter(p => p.top));
|
8400 | this.bottom.sync(this.panels.filter(p => !p.top));
|
8401 | for (let p of this.panels) {
|
8402 | p.dom.classList.add("cm-panel");
|
8403 | if (p.mount)
|
8404 | p.mount();
|
8405 | }
|
8406 | }
|
8407 | update(update) {
|
8408 | let conf = update.state.facet(panelConfig);
|
8409 | if (this.top.container != conf.topContainer) {
|
8410 | this.top.sync([]);
|
8411 | this.top = new PanelGroup(update.view, true, conf.topContainer);
|
8412 | }
|
8413 | if (this.bottom.container != conf.bottomContainer) {
|
8414 | this.bottom.sync([]);
|
8415 | this.bottom = new PanelGroup(update.view, false, conf.bottomContainer);
|
8416 | }
|
8417 | this.top.syncClasses();
|
8418 | this.bottom.syncClasses();
|
8419 | let input = update.state.facet(showPanel);
|
8420 | if (input != this.input) {
|
8421 | let specs = input.filter(x => x);
|
8422 | let panels = [], top = [], bottom = [], mount = [];
|
8423 | for (let spec of specs) {
|
8424 | let known = this.specs.indexOf(spec), panel;
|
8425 | if (known < 0) {
|
8426 | panel = spec(update.view);
|
8427 | mount.push(panel);
|
8428 | }
|
8429 | else {
|
8430 | panel = this.panels[known];
|
8431 | if (panel.update)
|
8432 | panel.update(update);
|
8433 | }
|
8434 | panels.push(panel);
|
8435 | (panel.top ? top : bottom).push(panel);
|
8436 | }
|
8437 | this.specs = specs;
|
8438 | this.panels = panels;
|
8439 | this.top.sync(top);
|
8440 | this.bottom.sync(bottom);
|
8441 | for (let p of mount) {
|
8442 | p.dom.classList.add("cm-panel");
|
8443 | if (p.mount)
|
8444 | p.mount();
|
8445 | }
|
8446 | }
|
8447 | else {
|
8448 | for (let p of this.panels)
|
8449 | if (p.update)
|
8450 | p.update(update);
|
8451 | }
|
8452 | }
|
8453 | destroy() {
|
8454 | this.top.sync([]);
|
8455 | this.bottom.sync([]);
|
8456 | }
|
8457 | }, {
|
8458 | provide: plugin => EditorView.scrollMargins.of(view => {
|
8459 | let value = view.plugin(plugin);
|
8460 | return value && { top: value.top.scrollMargin(), bottom: value.bottom.scrollMargin() };
|
8461 | })
|
8462 | });
|
8463 | class PanelGroup {
|
8464 | constructor(view, top, container) {
|
8465 | this.view = view;
|
8466 | this.top = top;
|
8467 | this.container = container;
|
8468 | this.dom = undefined;
|
8469 | this.classes = "";
|
8470 | this.panels = [];
|
8471 | this.syncClasses();
|
8472 | }
|
8473 | sync(panels) {
|
8474 | for (let p of this.panels)
|
8475 | if (p.destroy && panels.indexOf(p) < 0)
|
8476 | p.destroy();
|
8477 | this.panels = panels;
|
8478 | this.syncDOM();
|
8479 | }
|
8480 | syncDOM() {
|
8481 | if (this.panels.length == 0) {
|
8482 | if (this.dom) {
|
8483 | this.dom.remove();
|
8484 | this.dom = undefined;
|
8485 | }
|
8486 | return;
|
8487 | }
|
8488 | if (!this.dom) {
|
8489 | this.dom = document.createElement("div");
|
8490 | this.dom.className = this.top ? "cm-panels cm-panels-top" : "cm-panels cm-panels-bottom";
|
8491 | this.dom.style[this.top ? "top" : "bottom"] = "0";
|
8492 | let parent = this.container || this.view.dom;
|
8493 | parent.insertBefore(this.dom, this.top ? parent.firstChild : null);
|
8494 | }
|
8495 | let curDOM = this.dom.firstChild;
|
8496 | for (let panel of this.panels) {
|
8497 | if (panel.dom.parentNode == this.dom) {
|
8498 | while (curDOM != panel.dom)
|
8499 | curDOM = rm(curDOM);
|
8500 | curDOM = curDOM.nextSibling;
|
8501 | }
|
8502 | else {
|
8503 | this.dom.insertBefore(panel.dom, curDOM);
|
8504 | }
|
8505 | }
|
8506 | while (curDOM)
|
8507 | curDOM = rm(curDOM);
|
8508 | }
|
8509 | scrollMargin() {
|
8510 | return !this.dom || this.container ? 0
|
8511 | : Math.max(0, this.top ?
|
8512 | this.dom.getBoundingClientRect().bottom - Math.max(0, this.view.scrollDOM.getBoundingClientRect().top) :
|
8513 | Math.min(innerHeight, this.view.scrollDOM.getBoundingClientRect().bottom) - this.dom.getBoundingClientRect().top);
|
8514 | }
|
8515 | syncClasses() {
|
8516 | if (!this.container || this.classes == this.view.themeClasses)
|
8517 | return;
|
8518 | for (let cls of this.classes.split(" "))
|
8519 | if (cls)
|
8520 | this.container.classList.remove(cls);
|
8521 | for (let cls of (this.classes = this.view.themeClasses).split(" "))
|
8522 | if (cls)
|
8523 | this.container.classList.add(cls);
|
8524 | }
|
8525 | }
|
8526 | function rm(node) {
|
8527 | let next = node.nextSibling;
|
8528 | node.remove();
|
8529 | return next;
|
8530 | }
|
8531 |
|
8532 |
|
8533 |
|
8534 |
|
8535 |
|
8536 | const showPanel = Facet.define({
|
8537 | enables: panelPlugin
|
8538 | });
|
8539 |
|
8540 |
|
8541 |
|
8542 |
|
8543 |
|
8544 |
|
8545 | class GutterMarker extends RangeValue {
|
8546 | |
8547 |
|
8548 |
|
8549 | compare(other) {
|
8550 | return this == other || this.constructor == other.constructor && this.eq(other);
|
8551 | }
|
8552 | |
8553 |
|
8554 |
|
8555 | eq(other) { return false; }
|
8556 | |
8557 |
|
8558 |
|
8559 |
|
8560 | destroy(dom) { }
|
8561 | }
|
8562 | GutterMarker.prototype.elementClass = "";
|
8563 | GutterMarker.prototype.toDOM = undefined;
|
8564 | GutterMarker.prototype.mapMode = MapMode.TrackBefore;
|
8565 | GutterMarker.prototype.startSide = GutterMarker.prototype.endSide = -1;
|
8566 | GutterMarker.prototype.point = true;
|
8567 |
|
8568 |
|
8569 |
|
8570 |
|
8571 |
|
8572 |
|
8573 |
|
8574 | const gutterLineClass = Facet.define();
|
8575 | const defaults = {
|
8576 | class: "",
|
8577 | renderEmptyElements: false,
|
8578 | elementStyle: "",
|
8579 | markers: () => RangeSet.empty,
|
8580 | lineMarker: () => null,
|
8581 | lineMarkerChange: null,
|
8582 | initialSpacer: null,
|
8583 | updateSpacer: null,
|
8584 | domEventHandlers: {}
|
8585 | };
|
8586 | const activeGutters = Facet.define();
|
8587 |
|
8588 |
|
8589 |
|
8590 |
|
8591 | function gutter(config) {
|
8592 | return [gutters(), activeGutters.of(Object.assign(Object.assign({}, defaults), config))];
|
8593 | }
|
8594 | const unfixGutters = Facet.define({
|
8595 | combine: values => values.some(x => x)
|
8596 | });
|
8597 |
|
8598 |
|
8599 |
|
8600 |
|
8601 |
|
8602 |
|
8603 |
|
8604 |
|
8605 |
|
8606 |
|
8607 | function gutters(config) {
|
8608 | let result = [
|
8609 | gutterView,
|
8610 | ];
|
8611 | if (config && config.fixed === false)
|
8612 | result.push(unfixGutters.of(true));
|
8613 | return result;
|
8614 | }
|
8615 | const gutterView = ViewPlugin.fromClass(class {
|
8616 | constructor(view) {
|
8617 | this.view = view;
|
8618 | this.prevViewport = view.viewport;
|
8619 | this.dom = document.createElement("div");
|
8620 | this.dom.className = "cm-gutters";
|
8621 | this.dom.setAttribute("aria-hidden", "true");
|
8622 | this.dom.style.minHeight = this.view.contentHeight + "px";
|
8623 | this.gutters = view.state.facet(activeGutters).map(conf => new SingleGutterView(view, conf));
|
8624 | for (let gutter of this.gutters)
|
8625 | this.dom.appendChild(gutter.dom);
|
8626 | this.fixed = !view.state.facet(unfixGutters);
|
8627 | if (this.fixed) {
|
8628 |
|
8629 |
|
8630 |
|
8631 | this.dom.style.position = "sticky";
|
8632 | }
|
8633 | this.syncGutters(false);
|
8634 | view.scrollDOM.insertBefore(this.dom, view.contentDOM);
|
8635 | }
|
8636 | update(update) {
|
8637 | if (this.updateGutters(update)) {
|
8638 |
|
8639 |
|
8640 |
|
8641 | let vpA = this.prevViewport, vpB = update.view.viewport;
|
8642 | let vpOverlap = Math.min(vpA.to, vpB.to) - Math.max(vpA.from, vpB.from);
|
8643 | this.syncGutters(vpOverlap < (vpB.to - vpB.from) * 0.8);
|
8644 | }
|
8645 | if (update.geometryChanged)
|
8646 | this.dom.style.minHeight = this.view.contentHeight + "px";
|
8647 | if (this.view.state.facet(unfixGutters) != !this.fixed) {
|
8648 | this.fixed = !this.fixed;
|
8649 | this.dom.style.position = this.fixed ? "sticky" : "";
|
8650 | }
|
8651 | this.prevViewport = update.view.viewport;
|
8652 | }
|
8653 | syncGutters(detach) {
|
8654 | let after = this.dom.nextSibling;
|
8655 | if (detach)
|
8656 | this.dom.remove();
|
8657 | let lineClasses = RangeSet.iter(this.view.state.facet(gutterLineClass), this.view.viewport.from);
|
8658 | let classSet = [];
|
8659 | let contexts = this.gutters.map(gutter => new UpdateContext(gutter, this.view.viewport, -this.view.documentPadding.top));
|
8660 | for (let line of this.view.viewportLineBlocks) {
|
8661 | let text;
|
8662 | if (Array.isArray(line.type)) {
|
8663 | for (let b of line.type)
|
8664 | if (b.type == BlockType.Text) {
|
8665 | text = b;
|
8666 | break;
|
8667 | }
|
8668 | }
|
8669 | else {
|
8670 | text = line.type == BlockType.Text ? line : undefined;
|
8671 | }
|
8672 | if (!text)
|
8673 | continue;
|
8674 | if (classSet.length)
|
8675 | classSet = [];
|
8676 | advanceCursor(lineClasses, classSet, line.from);
|
8677 | for (let cx of contexts)
|
8678 | cx.line(this.view, text, classSet);
|
8679 | }
|
8680 | for (let cx of contexts)
|
8681 | cx.finish();
|
8682 | if (detach)
|
8683 | this.view.scrollDOM.insertBefore(this.dom, after);
|
8684 | }
|
8685 | updateGutters(update) {
|
8686 | let prev = update.startState.facet(activeGutters), cur = update.state.facet(activeGutters);
|
8687 | let change = update.docChanged || update.heightChanged || update.viewportChanged ||
|
8688 | !RangeSet.eq(update.startState.facet(gutterLineClass), update.state.facet(gutterLineClass), update.view.viewport.from, update.view.viewport.to);
|
8689 | if (prev == cur) {
|
8690 | for (let gutter of this.gutters)
|
8691 | if (gutter.update(update))
|
8692 | change = true;
|
8693 | }
|
8694 | else {
|
8695 | change = true;
|
8696 | let gutters = [];
|
8697 | for (let conf of cur) {
|
8698 | let known = prev.indexOf(conf);
|
8699 | if (known < 0) {
|
8700 | gutters.push(new SingleGutterView(this.view, conf));
|
8701 | }
|
8702 | else {
|
8703 | this.gutters[known].update(update);
|
8704 | gutters.push(this.gutters[known]);
|
8705 | }
|
8706 | }
|
8707 | for (let g of this.gutters) {
|
8708 | g.dom.remove();
|
8709 | if (gutters.indexOf(g) < 0)
|
8710 | g.destroy();
|
8711 | }
|
8712 | for (let g of gutters)
|
8713 | this.dom.appendChild(g.dom);
|
8714 | this.gutters = gutters;
|
8715 | }
|
8716 | return change;
|
8717 | }
|
8718 | destroy() {
|
8719 | for (let view of this.gutters)
|
8720 | view.destroy();
|
8721 | this.dom.remove();
|
8722 | }
|
8723 | }, {
|
8724 | provide: plugin => EditorView.scrollMargins.of(view => {
|
8725 | let value = view.plugin(plugin);
|
8726 | if (!value || value.gutters.length == 0 || !value.fixed)
|
8727 | return null;
|
8728 | return view.textDirection == Direction.LTR ? { left: value.dom.offsetWidth } : { right: value.dom.offsetWidth };
|
8729 | })
|
8730 | });
|
8731 | function asArray(val) { return (Array.isArray(val) ? val : [val]); }
|
8732 | function advanceCursor(cursor, collect, pos) {
|
8733 | while (cursor.value && cursor.from <= pos) {
|
8734 | if (cursor.from == pos)
|
8735 | collect.push(cursor.value);
|
8736 | cursor.next();
|
8737 | }
|
8738 | }
|
8739 | class UpdateContext {
|
8740 | constructor(gutter, viewport, height) {
|
8741 | this.gutter = gutter;
|
8742 | this.height = height;
|
8743 | this.localMarkers = [];
|
8744 | this.i = 0;
|
8745 | this.cursor = RangeSet.iter(gutter.markers, viewport.from);
|
8746 | }
|
8747 | line(view, line, extraMarkers) {
|
8748 | if (this.localMarkers.length)
|
8749 | this.localMarkers = [];
|
8750 | advanceCursor(this.cursor, this.localMarkers, line.from);
|
8751 | let localMarkers = extraMarkers.length ? this.localMarkers.concat(extraMarkers) : this.localMarkers;
|
8752 | let forLine = this.gutter.config.lineMarker(view, line, localMarkers);
|
8753 | if (forLine)
|
8754 | localMarkers.unshift(forLine);
|
8755 | let gutter = this.gutter;
|
8756 | if (localMarkers.length == 0 && !gutter.config.renderEmptyElements)
|
8757 | return;
|
8758 | let above = line.top - this.height;
|
8759 | if (this.i == gutter.elements.length) {
|
8760 | let newElt = new GutterElement(view, line.height, above, localMarkers);
|
8761 | gutter.elements.push(newElt);
|
8762 | gutter.dom.appendChild(newElt.dom);
|
8763 | }
|
8764 | else {
|
8765 | gutter.elements[this.i].update(view, line.height, above, localMarkers);
|
8766 | }
|
8767 | this.height = line.bottom;
|
8768 | this.i++;
|
8769 | }
|
8770 | finish() {
|
8771 | let gutter = this.gutter;
|
8772 | while (gutter.elements.length > this.i) {
|
8773 | let last = gutter.elements.pop();
|
8774 | gutter.dom.removeChild(last.dom);
|
8775 | last.destroy();
|
8776 | }
|
8777 | }
|
8778 | }
|
8779 | class SingleGutterView {
|
8780 | constructor(view, config) {
|
8781 | this.view = view;
|
8782 | this.config = config;
|
8783 | this.elements = [];
|
8784 | this.spacer = null;
|
8785 | this.dom = document.createElement("div");
|
8786 | this.dom.className = "cm-gutter" + (this.config.class ? " " + this.config.class : "");
|
8787 | for (let prop in config.domEventHandlers) {
|
8788 | this.dom.addEventListener(prop, (event) => {
|
8789 | let line = view.lineBlockAtHeight(event.clientY - view.documentTop);
|
8790 | if (config.domEventHandlers[prop](view, line, event))
|
8791 | event.preventDefault();
|
8792 | });
|
8793 | }
|
8794 | this.markers = asArray(config.markers(view));
|
8795 | if (config.initialSpacer) {
|
8796 | this.spacer = new GutterElement(view, 0, 0, [config.initialSpacer(view)]);
|
8797 | this.dom.appendChild(this.spacer.dom);
|
8798 | this.spacer.dom.style.cssText += "visibility: hidden; pointer-events: none";
|
8799 | }
|
8800 | }
|
8801 | update(update) {
|
8802 | let prevMarkers = this.markers;
|
8803 | this.markers = asArray(this.config.markers(update.view));
|
8804 | if (this.spacer && this.config.updateSpacer) {
|
8805 | let updated = this.config.updateSpacer(this.spacer.markers[0], update);
|
8806 | if (updated != this.spacer.markers[0])
|
8807 | this.spacer.update(update.view, 0, 0, [updated]);
|
8808 | }
|
8809 | let vp = update.view.viewport;
|
8810 | return !RangeSet.eq(this.markers, prevMarkers, vp.from, vp.to) ||
|
8811 | (this.config.lineMarkerChange ? this.config.lineMarkerChange(update) : false);
|
8812 | }
|
8813 | destroy() {
|
8814 | for (let elt of this.elements)
|
8815 | elt.destroy();
|
8816 | }
|
8817 | }
|
8818 | class GutterElement {
|
8819 | constructor(view, height, above, markers) {
|
8820 | this.height = -1;
|
8821 | this.above = 0;
|
8822 | this.markers = [];
|
8823 | this.dom = document.createElement("div");
|
8824 | this.dom.className = "cm-gutterElement";
|
8825 | this.update(view, height, above, markers);
|
8826 | }
|
8827 | update(view, height, above, markers) {
|
8828 | if (this.height != height)
|
8829 | this.dom.style.height = (this.height = height) + "px";
|
8830 | if (this.above != above)
|
8831 | this.dom.style.marginTop = (this.above = above) ? above + "px" : "";
|
8832 | if (!sameMarkers(this.markers, markers))
|
8833 | this.setMarkers(view, markers);
|
8834 | }
|
8835 | setMarkers(view, markers) {
|
8836 | let cls = "cm-gutterElement", domPos = this.dom.firstChild;
|
8837 | for (let iNew = 0, iOld = 0;;) {
|
8838 | let skipTo = iOld, marker = iNew < markers.length ? markers[iNew++] : null, matched = false;
|
8839 | if (marker) {
|
8840 | let c = marker.elementClass;
|
8841 | if (c)
|
8842 | cls += " " + c;
|
8843 | for (let i = iOld; i < this.markers.length; i++)
|
8844 | if (this.markers[i].compare(marker)) {
|
8845 | skipTo = i;
|
8846 | matched = true;
|
8847 | break;
|
8848 | }
|
8849 | }
|
8850 | else {
|
8851 | skipTo = this.markers.length;
|
8852 | }
|
8853 | while (iOld < skipTo) {
|
8854 | let next = this.markers[iOld++];
|
8855 | if (next.toDOM) {
|
8856 | next.destroy(domPos);
|
8857 | let after = domPos.nextSibling;
|
8858 | domPos.remove();
|
8859 | domPos = after;
|
8860 | }
|
8861 | }
|
8862 | if (!marker)
|
8863 | break;
|
8864 | if (marker.toDOM) {
|
8865 | if (matched)
|
8866 | domPos = domPos.nextSibling;
|
8867 | else
|
8868 | this.dom.insertBefore(marker.toDOM(view), domPos);
|
8869 | }
|
8870 | if (matched)
|
8871 | iOld++;
|
8872 | }
|
8873 | this.dom.className = cls;
|
8874 | this.markers = markers;
|
8875 | }
|
8876 | destroy() {
|
8877 | this.setMarkers(null, []);
|
8878 | }
|
8879 | }
|
8880 | function sameMarkers(a, b) {
|
8881 | if (a.length != b.length)
|
8882 | return false;
|
8883 | for (let i = 0; i < a.length; i++)
|
8884 | if (!a[i].compare(b[i]))
|
8885 | return false;
|
8886 | return true;
|
8887 | }
|
8888 |
|
8889 |
|
8890 |
|
8891 | const lineNumberMarkers = Facet.define();
|
8892 | const lineNumberConfig = Facet.define({
|
8893 | combine(values) {
|
8894 | return combineConfig(values, { formatNumber: String, domEventHandlers: {} }, {
|
8895 | domEventHandlers(a, b) {
|
8896 | let result = Object.assign({}, a);
|
8897 | for (let event in b) {
|
8898 | let exists = result[event], add = b[event];
|
8899 | result[event] = exists ? (view, line, event) => exists(view, line, event) || add(view, line, event) : add;
|
8900 | }
|
8901 | return result;
|
8902 | }
|
8903 | });
|
8904 | }
|
8905 | });
|
8906 | class NumberMarker extends GutterMarker {
|
8907 | constructor(number) {
|
8908 | super();
|
8909 | this.number = number;
|
8910 | }
|
8911 | eq(other) { return this.number == other.number; }
|
8912 | toDOM() { return document.createTextNode(this.number); }
|
8913 | }
|
8914 | function formatNumber(view, number) {
|
8915 | return view.state.facet(lineNumberConfig).formatNumber(number, view.state);
|
8916 | }
|
8917 | const lineNumberGutter = activeGutters.compute([lineNumberConfig], state => ({
|
8918 | class: "cm-lineNumbers",
|
8919 | renderEmptyElements: false,
|
8920 | markers(view) { return view.state.facet(lineNumberMarkers); },
|
8921 | lineMarker(view, line, others) {
|
8922 | if (others.some(m => m.toDOM))
|
8923 | return null;
|
8924 | return new NumberMarker(formatNumber(view, view.state.doc.lineAt(line.from).number));
|
8925 | },
|
8926 | lineMarkerChange: update => update.startState.facet(lineNumberConfig) != update.state.facet(lineNumberConfig),
|
8927 | initialSpacer(view) {
|
8928 | return new NumberMarker(formatNumber(view, maxLineNumber(view.state.doc.lines)));
|
8929 | },
|
8930 | updateSpacer(spacer, update) {
|
8931 | let max = formatNumber(update.view, maxLineNumber(update.view.state.doc.lines));
|
8932 | return max == spacer.number ? spacer : new NumberMarker(max);
|
8933 | },
|
8934 | domEventHandlers: state.facet(lineNumberConfig).domEventHandlers
|
8935 | }));
|
8936 |
|
8937 |
|
8938 |
|
8939 | function lineNumbers(config = {}) {
|
8940 | return [
|
8941 | lineNumberConfig.of(config),
|
8942 | gutters(),
|
8943 | lineNumberGutter
|
8944 | ];
|
8945 | }
|
8946 | function maxLineNumber(lines) {
|
8947 | let last = 9;
|
8948 | while (last < lines)
|
8949 | last = last * 10 + 9;
|
8950 | return last;
|
8951 | }
|
8952 | const activeLineGutterMarker = new class extends GutterMarker {
|
8953 | constructor() {
|
8954 | super(...arguments);
|
8955 | this.elementClass = "cm-activeLineGutter";
|
8956 | }
|
8957 | };
|
8958 | const activeLineGutterHighlighter = gutterLineClass.compute(["selection"], state => {
|
8959 | let marks = [], last = -1;
|
8960 | for (let range of state.selection.ranges)
|
8961 | if (range.empty) {
|
8962 | let linePos = state.doc.lineAt(range.head).from;
|
8963 | if (linePos > last) {
|
8964 | last = linePos;
|
8965 | marks.push(activeLineGutterMarker.range(linePos));
|
8966 | }
|
8967 | }
|
8968 | return RangeSet.of(marks);
|
8969 | });
|
8970 |
|
8971 |
|
8972 |
|
8973 |
|
8974 |
|
8975 | function highlightActiveLineGutter() {
|
8976 | return activeLineGutterHighlighter;
|
8977 | }
|
8978 |
|
8979 |
|
8980 |
|
8981 |
|
8982 | const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRange, computeOrder, moveVisually };
|
8983 |
|
8984 | export { BidiSpan, BlockInfo, BlockType, Decoration, Direction, EditorView, GutterMarker, MatchDecorator, ViewPlugin, ViewUpdate, WidgetType, __test, closeHoverTooltips, crosshairCursor, drawSelection, dropCursor, getPanel, getTooltip, gutter, gutterLineClass, gutters, hasHoverTooltips, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, hoverTooltip, keymap, lineNumberMarkers, lineNumbers, logException, panels, placeholder, rectangularSelection, repositionTooltips, runScopeHandlers, scrollPastEnd, showPanel, showTooltip, tooltips };
|