@codemirror/view 0.19.25 → 0.19.29

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -273,7 +273,7 @@ class DOMPos {
273
273
  static before(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom), precise); }
274
274
  static after(dom, precise) { return new DOMPos(dom.parentNode, domIndex(dom) + 1, precise); }
275
275
  }
276
- const none$3 = [];
276
+ const noChildren = [];
277
277
  class ContentView {
278
278
  constructor() {
279
279
  this.parent = null;
@@ -439,12 +439,12 @@ class ContentView {
439
439
  v = parent;
440
440
  }
441
441
  }
442
- replaceChildren(from, to, children = none$3) {
442
+ replaceChildren(from, to, children = noChildren) {
443
443
  this.markDirty();
444
444
  for (let i = from; i < to; i++) {
445
445
  let child = this.children[i];
446
446
  if (child.parent == this)
447
- child.parent = null;
447
+ child.destroy();
448
448
  }
449
449
  this.children.splice(from, to - from, ...children);
450
450
  for (let i = 0; i < children.length; i++)
@@ -466,6 +466,17 @@ class ContentView {
466
466
  }
467
467
  static get(node) { return node.cmView; }
468
468
  get isEditable() { return true; }
469
+ merge(from, to, source, hasStart, openStart, openEnd) {
470
+ return false;
471
+ }
472
+ become(other) { return false; }
473
+ // When this is a zero-length view with a side, this should return a
474
+ // number <= 0 to indicate it is before its position, or a
475
+ // number > 0 when after its position.
476
+ getSide() { return 0; }
477
+ destroy() {
478
+ this.parent = null;
479
+ }
469
480
  }
470
481
  ContentView.prototype.breakAfter = 0;
471
482
  // Remove a DOM node and return its next sibling.
@@ -493,6 +504,94 @@ class ChildCursor {
493
504
  }
494
505
  }
495
506
  }
507
+ function replaceRange(parent, fromI, fromOff, toI, toOff, insert, breakAtStart, openStart, openEnd) {
508
+ let { children } = parent;
509
+ let before = children.length ? children[fromI] : null;
510
+ let last = insert.length ? insert[insert.length - 1] : null;
511
+ let breakAtEnd = last ? last.breakAfter : breakAtStart;
512
+ // Change within a single child
513
+ if (fromI == toI && before && !breakAtStart && !breakAtEnd && insert.length < 2 &&
514
+ before.merge(fromOff, toOff, insert.length ? last : null, fromOff == 0, openStart, openEnd))
515
+ return;
516
+ if (toI < children.length) {
517
+ let after = children[toI];
518
+ // Make sure the end of the child after the update is preserved in `after`
519
+ if (after && toOff < after.length) {
520
+ // If we're splitting a child, separate part of it to avoid that
521
+ // being mangled when updating the child before the update.
522
+ if (fromI == toI) {
523
+ after = after.split(toOff);
524
+ toOff = 0;
525
+ }
526
+ // If the element after the replacement should be merged with
527
+ // the last replacing element, update `content`
528
+ if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) {
529
+ insert[insert.length - 1] = after;
530
+ }
531
+ else {
532
+ // Remove the start of the after element, if necessary, and
533
+ // add it to `content`.
534
+ if (toOff)
535
+ after.merge(0, toOff, null, false, 0, openEnd);
536
+ insert.push(after);
537
+ }
538
+ }
539
+ else if (after === null || after === void 0 ? void 0 : after.breakAfter) {
540
+ // The element at `toI` is entirely covered by this range.
541
+ // Preserve its line break, if any.
542
+ if (last)
543
+ last.breakAfter = 1;
544
+ else
545
+ breakAtStart = 1;
546
+ }
547
+ // Since we've handled the next element from the current elements
548
+ // now, make sure `toI` points after that.
549
+ toI++;
550
+ }
551
+ if (before) {
552
+ before.breakAfter = breakAtStart;
553
+ if (fromOff > 0) {
554
+ if (!breakAtStart && insert.length && before.merge(fromOff, before.length, insert[0], false, openStart, 0)) {
555
+ before.breakAfter = insert.shift().breakAfter;
556
+ }
557
+ else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) {
558
+ before.merge(fromOff, before.length, null, false, openStart, 0);
559
+ }
560
+ fromI++;
561
+ }
562
+ }
563
+ // Try to merge widgets on the boundaries of the replacement
564
+ while (fromI < toI && insert.length) {
565
+ if (children[toI - 1].become(insert[insert.length - 1])) {
566
+ toI--;
567
+ insert.pop();
568
+ openEnd = insert.length ? 0 : openStart;
569
+ }
570
+ else if (children[fromI].become(insert[0])) {
571
+ fromI++;
572
+ insert.shift();
573
+ openStart = insert.length ? 0 : openEnd;
574
+ }
575
+ else {
576
+ break;
577
+ }
578
+ }
579
+ if (!insert.length && fromI && toI < children.length && !children[fromI - 1].breakAfter &&
580
+ children[toI].merge(0, 0, children[fromI - 1], false, openStart, openEnd))
581
+ fromI--;
582
+ if (fromI < toI || insert.length)
583
+ parent.replaceChildren(fromI, toI, insert);
584
+ }
585
+ function mergeChildrenInto(parent, from, to, insert, openStart, openEnd) {
586
+ let cur = parent.childCursor();
587
+ let { i: toI, off: toOff } = cur.findPos(to, 1);
588
+ let { i: fromI, off: fromOff } = cur.findPos(from, -1);
589
+ let dLen = from - to;
590
+ for (let view of insert)
591
+ dLen += view.length;
592
+ parent.length += dLen;
593
+ replaceRange(parent, fromI, fromOff, toI, toOff, insert, 0, openStart, openEnd);
594
+ }
496
595
 
497
596
  let [nav, doc] = typeof navigator != "undefined"
498
597
  ? [navigator, document]
@@ -524,21 +623,8 @@ var browser = {
524
623
  tabSize: doc.documentElement.style.tabSize != null ? "tab-size" : "-moz-tab-size"
525
624
  };
526
625
 
527
- const none$2 = [];
528
- class InlineView extends ContentView {
529
- /**
530
- Return true when this view is equivalent to `other` and can take
531
- on its role.
532
- */
533
- become(_other) { return false; }
534
- // When this is a zero-length view with a side, this should return a
535
- // negative number to indicate it is before its position, or a
536
- // positive number when after its position.
537
- getSide() { return 0; }
538
- }
539
- InlineView.prototype.children = none$2;
540
626
  const MaxJoinLen = 256;
541
- class TextView extends InlineView {
627
+ class TextView extends ContentView {
542
628
  constructor(text) {
543
629
  super();
544
630
  this.text = text;
@@ -569,7 +655,7 @@ class TextView extends InlineView {
569
655
  this.markDirty();
570
656
  return true;
571
657
  }
572
- slice(from) {
658
+ split(from) {
573
659
  let result = new TextView(this.text.slice(from));
574
660
  this.text = this.text.slice(0, from);
575
661
  return result;
@@ -585,7 +671,7 @@ class TextView extends InlineView {
585
671
  return textCoords(this.dom, pos, side);
586
672
  }
587
673
  }
588
- class MarkView extends InlineView {
674
+ class MarkView extends ContentView {
589
675
  constructor(mark, children = [], length = 0) {
590
676
  super();
591
677
  this.mark = mark;
@@ -608,20 +694,20 @@ class MarkView extends InlineView {
608
694
  this.createDOM();
609
695
  super.sync(track);
610
696
  }
611
- merge(from, to, source, openStart, openEnd) {
697
+ merge(from, to, source, _hasStart, openStart, openEnd) {
612
698
  if (source && (!(source instanceof MarkView && source.mark.eq(this.mark)) ||
613
699
  (from && openStart <= 0) || (to < this.length && openEnd <= 0)))
614
700
  return false;
615
- mergeInlineChildren(this, from, to, source ? source.children : none$2, openStart - 1, openEnd - 1);
701
+ mergeChildrenInto(this, from, to, source ? source.children : [], openStart - 1, openEnd - 1);
616
702
  this.markDirty();
617
703
  return true;
618
704
  }
619
- slice(from) {
705
+ split(from) {
620
706
  let result = [], off = 0, detachFrom = -1, i = 0;
621
707
  for (let elt of this.children) {
622
708
  let end = off + elt.length;
623
709
  if (end > from)
624
- result.push(off < from ? elt.slice(from - off) : elt);
710
+ result.push(off < from ? elt.split(from - off) : elt);
625
711
  if (detachFrom < 0 && off >= from)
626
712
  detachFrom = i;
627
713
  off = end;
@@ -629,8 +715,10 @@ class MarkView extends InlineView {
629
715
  }
630
716
  let length = this.length - from;
631
717
  this.length = from;
632
- if (detachFrom > -1)
633
- this.replaceChildren(detachFrom, this.children.length);
718
+ if (detachFrom > -1) {
719
+ this.children.length = detachFrom;
720
+ this.markDirty();
721
+ }
634
722
  return new MarkView(this.mark, result, length);
635
723
  }
636
724
  domAtPos(pos) {
@@ -672,7 +760,7 @@ function textCoords(text, pos, side) {
672
760
  return flatten ? flattenRect(rect, flatten < 0) : rect || null;
673
761
  }
674
762
  // Also used for collapsed ranges that don't have a placeholder widget!
675
- class WidgetView extends InlineView {
763
+ class WidgetView extends ContentView {
676
764
  constructor(widget, length, side) {
677
765
  super();
678
766
  this.widget = widget;
@@ -682,7 +770,7 @@ class WidgetView extends InlineView {
682
770
  static create(widget, length, side) {
683
771
  return new (widget.customView || WidgetView)(widget, length, side);
684
772
  }
685
- slice(from) {
773
+ split(from) {
686
774
  let result = WidgetView.create(this.widget, this.length - from, this.side);
687
775
  this.length -= from;
688
776
  return result;
@@ -694,7 +782,7 @@ class WidgetView extends InlineView {
694
782
  }
695
783
  }
696
784
  getSide() { return this.side; }
697
- merge(from, to, source, openStart, openEnd) {
785
+ merge(from, to, source, hasStart, openStart, openEnd) {
698
786
  if (source && (!(source instanceof WidgetView) || !this.widget.compare(source.widget) ||
699
787
  from > 0 && openStart <= 0 || to < this.length && openEnd <= 0))
700
788
  return false;
@@ -739,6 +827,11 @@ class WidgetView extends InlineView {
739
827
  return (pos == 0 && side > 0 || pos == this.length && side <= 0) ? rect : flattenRect(rect, pos == 0);
740
828
  }
741
829
  get isEditable() { return false; }
830
+ destroy() {
831
+ super.destroy();
832
+ if (this.dom)
833
+ this.widget.destroy(this.dom);
834
+ }
742
835
  }
743
836
  class CompositionView extends WidgetView {
744
837
  domAtPos(pos) { return new DOMPos(this.widget.text, pos); }
@@ -752,10 +845,13 @@ class CompositionView extends WidgetView {
752
845
  coordsAt(pos, side) { return textCoords(this.widget.text, pos, side); }
753
846
  get isEditable() { return true; }
754
847
  }
848
+ // Use two characters on Android, to prevent Chrome from closing the
849
+ // virtual keyboard when backspacing after a widget (#602).
850
+ const ZeroWidthSpace = browser.android ? "\u200b\u200b" : "\u200b";
755
851
  // These are drawn around uneditable widgets to avoid a number of
756
852
  // browser bugs that show up when the cursor is directly next to
757
853
  // uneditable inline content.
758
- class WidgetBufferView extends InlineView {
854
+ class WidgetBufferView extends ContentView {
759
855
  constructor(side) {
760
856
  super();
761
857
  this.side = side;
@@ -765,15 +861,16 @@ class WidgetBufferView extends InlineView {
765
861
  become(other) {
766
862
  return other instanceof WidgetBufferView && other.side == this.side;
767
863
  }
768
- slice() { return new WidgetBufferView(this.side); }
864
+ split() { return new WidgetBufferView(this.side); }
769
865
  sync() {
770
866
  if (!this.dom)
771
- this.setDOM(document.createTextNode("\u200b"));
772
- else if (this.dirty && this.dom.nodeValue != "\u200b")
773
- this.dom.nodeValue = "\u200b";
867
+ this.setDOM(document.createTextNode(ZeroWidthSpace));
868
+ else if (this.dirty && this.dom.nodeValue != ZeroWidthSpace)
869
+ this.dom.nodeValue = ZeroWidthSpace;
774
870
  }
775
871
  getSide() { return this.side; }
776
872
  domAtPos(pos) { return DOMPos.before(this.dom); }
873
+ localPosFromDOM() { return 0; }
777
874
  domBoundsAround() { return null; }
778
875
  coordsAt(pos) {
779
876
  let rects = clientRectsFor(this.dom);
@@ -783,90 +880,7 @@ class WidgetBufferView extends InlineView {
783
880
  return text.Text.of([this.dom.nodeValue.replace(/\u200b/g, "")]);
784
881
  }
785
882
  }
786
- function mergeInlineChildren(parent, from, to, elts, openStart, openEnd) {
787
- let cur = parent.childCursor();
788
- let { i: toI, off: toOff } = cur.findPos(to, 1);
789
- let { i: fromI, off: fromOff } = cur.findPos(from, -1);
790
- let dLen = from - to;
791
- for (let view of elts)
792
- dLen += view.length;
793
- parent.length += dLen;
794
- let { children } = parent;
795
- // Both from and to point into the same child view
796
- if (fromI == toI && fromOff) {
797
- let start = children[fromI];
798
- // Maybe just update that view and be done
799
- if (elts.length == 1 && start.merge(fromOff, toOff, elts[0], openStart, openEnd))
800
- return;
801
- if (elts.length == 0) {
802
- start.merge(fromOff, toOff, null, openStart, openEnd);
803
- return;
804
- }
805
- // Otherwise split it, so that we don't have to worry about aliasing front/end afterwards
806
- let after = start.slice(toOff);
807
- if (after.merge(0, 0, elts[elts.length - 1], 0, openEnd))
808
- elts[elts.length - 1] = after;
809
- else
810
- elts.push(after);
811
- toI++;
812
- openEnd = toOff = 0;
813
- }
814
- // Make sure start and end positions fall on node boundaries
815
- // (fromOff/toOff are no longer used after this), and that if the
816
- // start or end of the elts can be merged with adjacent nodes,
817
- // this is done
818
- if (toOff) {
819
- let end = children[toI];
820
- if (elts.length && end.merge(0, toOff, elts[elts.length - 1], 0, openEnd)) {
821
- elts.pop();
822
- openEnd = elts.length ? 0 : openStart;
823
- }
824
- else {
825
- end.merge(0, toOff, null, 0, 0);
826
- }
827
- }
828
- else if (toI < children.length && elts.length &&
829
- children[toI].merge(0, 0, elts[elts.length - 1], 0, openEnd)) {
830
- elts.pop();
831
- openEnd = elts.length ? 0 : openStart;
832
- }
833
- if (fromOff) {
834
- let start = children[fromI];
835
- if (elts.length && start.merge(fromOff, start.length, elts[0], openStart, 0)) {
836
- elts.shift();
837
- openStart = elts.length ? 0 : openEnd;
838
- }
839
- else {
840
- start.merge(fromOff, start.length, null, 0, 0);
841
- }
842
- fromI++;
843
- }
844
- else if (fromI && elts.length) {
845
- let end = children[fromI - 1];
846
- if (end.merge(end.length, end.length, elts[0], openStart, 0)) {
847
- elts.shift();
848
- openStart = elts.length ? 0 : openEnd;
849
- }
850
- }
851
- // Then try to merge any mergeable nodes at the start and end of
852
- // the changed range
853
- while (fromI < toI && elts.length && children[toI - 1].become(elts[elts.length - 1])) {
854
- elts.pop();
855
- toI--;
856
- openEnd = elts.length ? 0 : openStart;
857
- }
858
- while (fromI < toI && elts.length && children[fromI].become(elts[0])) {
859
- elts.shift();
860
- fromI++;
861
- openStart = elts.length ? 0 : openEnd;
862
- }
863
- if (!elts.length && fromI && toI < children.length &&
864
- children[toI].merge(0, 0, children[fromI - 1], openStart, openEnd))
865
- fromI--;
866
- // And if anything remains, splice the child array to insert the new elts
867
- if (elts.length || fromI != toI)
868
- parent.replaceChildren(fromI, toI, elts);
869
- }
883
+ TextView.prototype.children = WidgetView.prototype.children = WidgetBufferView.prototype.children = noChildren;
870
884
  function inlineDOMAtPos(dom, children, pos) {
871
885
  let i = 0;
872
886
  for (let off = 0; i < children.length; i++) {
@@ -1007,6 +1021,11 @@ class WidgetType {
1007
1021
  @internal
1008
1022
  */
1009
1023
  get customView() { return null; }
1024
+ /**
1025
+ This is called when the an instance of the widget is removed
1026
+ from the editor view.
1027
+ */
1028
+ destroy(_dom) { }
1010
1029
  }
1011
1030
  /**
1012
1031
  The different types of blocks that can occur in an editor view.
@@ -1167,12 +1186,12 @@ class PointDecoration extends Decoration {
1167
1186
  super(startSide, endSide, widget, spec);
1168
1187
  this.block = block;
1169
1188
  this.isReplace = isReplace;
1170
- this.mapMode = !block ? state.MapMode.TrackDel : startSide < 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter;
1189
+ this.mapMode = !block ? state.MapMode.TrackDel : startSide <= 0 ? state.MapMode.TrackBefore : state.MapMode.TrackAfter;
1171
1190
  }
1172
1191
  // Only relevant when this.block == true
1173
1192
  get type() {
1174
1193
  return this.startSide < this.endSide ? exports.BlockType.WidgetRange
1175
- : this.startSide < 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter;
1194
+ : this.startSide <= 0 ? exports.BlockType.WidgetBefore : exports.BlockType.WidgetAfter;
1176
1195
  }
1177
1196
  get heightRelevant() { return this.block || !!this.widget && this.widget.estimatedHeight >= 5; }
1178
1197
  eq(other) {
@@ -1182,7 +1201,7 @@ class PointDecoration extends Decoration {
1182
1201
  this.startSide == other.startSide && this.endSide == other.endSide;
1183
1202
  }
1184
1203
  range(from, to = from) {
1185
- if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide < 0)))
1204
+ if (this.isReplace && (from > to || (from == to && this.startSide > 0 && this.endSide <= 0)))
1186
1205
  throw new RangeError("Invalid range for replacement decoration");
1187
1206
  if (!this.isReplace && to != from)
1188
1207
  throw new RangeError("Widget decorations can only have zero-length ranges");
@@ -1219,16 +1238,16 @@ class LineView extends ContentView {
1219
1238
  this.breakAfter = 0;
1220
1239
  }
1221
1240
  // Consumes source
1222
- merge(from, to, source, takeDeco, openStart, openEnd) {
1241
+ merge(from, to, source, hasStart, openStart, openEnd) {
1223
1242
  if (source) {
1224
1243
  if (!(source instanceof LineView))
1225
1244
  return false;
1226
1245
  if (!this.dom)
1227
1246
  source.transferDOM(this); // Reuse source.dom when appropriate
1228
1247
  }
1229
- if (takeDeco)
1248
+ if (hasStart)
1230
1249
  this.setDeco(source ? source.attrs : null);
1231
- mergeInlineChildren(this, from, to, source ? source.children : none$1, openStart, openEnd);
1250
+ mergeChildrenInto(this, from, to, source ? source.children : [], openStart, openEnd);
1232
1251
  return true;
1233
1252
  }
1234
1253
  split(at) {
@@ -1238,16 +1257,14 @@ class LineView extends ContentView {
1238
1257
  return end;
1239
1258
  let { i, off } = this.childPos(at);
1240
1259
  if (off) {
1241
- end.append(this.children[i].slice(off), 0);
1242
- this.children[i].merge(off, this.children[i].length, null, 0, 0);
1260
+ end.append(this.children[i].split(off), 0);
1261
+ this.children[i].merge(off, this.children[i].length, null, false, 0, 0);
1243
1262
  i++;
1244
1263
  }
1245
1264
  for (let j = i; j < this.children.length; j++)
1246
1265
  end.append(this.children[j], 0);
1247
- while (i > 0 && this.children[i - 1].length == 0) {
1248
- this.children[i - 1].parent = null;
1249
- i--;
1250
- }
1266
+ while (i > 0 && this.children[i - 1].length == 0)
1267
+ this.children[--i].destroy();
1251
1268
  this.children.length = i;
1252
1269
  this.markDirty();
1253
1270
  this.length = at;
@@ -1270,7 +1287,6 @@ class LineView extends ContentView {
1270
1287
  this.attrs = attrs;
1271
1288
  }
1272
1289
  }
1273
- // Only called when building a line view in ContentBuilder
1274
1290
  append(child, openStart) {
1275
1291
  joinInlineInto(this, child, openStart);
1276
1292
  }
@@ -1327,7 +1343,7 @@ class LineView extends ContentView {
1327
1343
  coordsAt(pos, side) {
1328
1344
  return coordsInChildren(this, pos, side);
1329
1345
  }
1330
- match(_other) { return false; }
1346
+ become(_other) { return false; }
1331
1347
  get type() { return exports.BlockType.Text; }
1332
1348
  static find(docView, pos) {
1333
1349
  for (let i = 0, off = 0;; i++) {
@@ -1342,7 +1358,6 @@ class LineView extends ContentView {
1342
1358
  }
1343
1359
  }
1344
1360
  }
1345
- const none$1 = [];
1346
1361
  class BlockWidgetView extends ContentView {
1347
1362
  constructor(widget, length, type) {
1348
1363
  super();
@@ -1368,7 +1383,7 @@ class BlockWidgetView extends ContentView {
1368
1383
  end.breakAfter = this.breakAfter;
1369
1384
  return end;
1370
1385
  }
1371
- get children() { return none$1; }
1386
+ get children() { return noChildren; }
1372
1387
  sync() {
1373
1388
  if (!this.dom || !this.widget.updateDOM(this.dom)) {
1374
1389
  this.setDOM(this.widget.toDOM(this.editorView));
@@ -1379,7 +1394,7 @@ class BlockWidgetView extends ContentView {
1379
1394
  return this.parent ? this.parent.view.state.doc.slice(this.posAtStart, this.posAtEnd) : state.Text.empty;
1380
1395
  }
1381
1396
  domBoundsAround() { return null; }
1382
- match(other) {
1397
+ become(other) {
1383
1398
  if (other instanceof BlockWidgetView && other.type == this.type &&
1384
1399
  other.widget.constructor == this.widget.constructor) {
1385
1400
  if (!other.widget.eq(this.widget))
@@ -1393,6 +1408,11 @@ class BlockWidgetView extends ContentView {
1393
1408
  }
1394
1409
  ignoreMutation() { return true; }
1395
1410
  ignoreEvent(event) { return this.widget.ignoreEvent(event); }
1411
+ destroy() {
1412
+ super.destroy();
1413
+ if (this.dom)
1414
+ this.widget.destroy(this.dom);
1415
+ }
1396
1416
  }
1397
1417
 
1398
1418
  class ContentBuilder {
@@ -1922,855 +1942,883 @@ class ViewUpdate {
1922
1942
  get empty() { return this.flags == 0 && this.transactions.length == 0; }
1923
1943
  }
1924
1944
 
1925
- class DocView extends ContentView {
1926
- constructor(view) {
1927
- super();
1928
- this.view = view;
1929
- this.compositionDeco = Decoration.none;
1930
- this.decorations = [];
1931
- // Track a minimum width for the editor. When measuring sizes in
1932
- // measureVisibleLineHeights, this is updated to point at the width
1933
- // of a given element and its extent in the document. When a change
1934
- // happens in that range, these are reset. That way, once we've seen
1935
- // a line/element of a given length, we keep the editor wide enough
1936
- // to fit at least that element, until it is changed, at which point
1937
- // we forget it again.
1938
- this.minWidth = 0;
1939
- this.minWidthFrom = 0;
1940
- this.minWidthTo = 0;
1941
- // Track whether the DOM selection was set in a lossy way, so that
1942
- // we don't mess it up when reading it back it
1943
- this.impreciseAnchor = null;
1944
- this.impreciseHead = null;
1945
- this.forceSelection = false;
1946
- // Used by the resize observer to ignore resizes that we caused
1947
- // ourselves
1948
- this.lastUpdate = Date.now();
1949
- this.setDOM(view.contentDOM);
1950
- this.children = [new LineView];
1951
- this.children[0].setParent(this);
1952
- this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], this.updateDeco(), 0);
1945
+ /**
1946
+ Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
1947
+ */
1948
+ exports.Direction = void 0;
1949
+ (function (Direction) {
1950
+ // (These are chosen to match the base levels, in bidi algorithm
1951
+ // terms, of spans in that direction.)
1952
+ /**
1953
+ Left-to-right.
1954
+ */
1955
+ Direction[Direction["LTR"] = 0] = "LTR";
1956
+ /**
1957
+ Right-to-left.
1958
+ */
1959
+ Direction[Direction["RTL"] = 1] = "RTL";
1960
+ })(exports.Direction || (exports.Direction = {}));
1961
+ const LTR = exports.Direction.LTR, RTL = exports.Direction.RTL;
1962
+ // Decode a string with each type encoded as log2(type)
1963
+ function dec(str) {
1964
+ let result = [];
1965
+ for (let i = 0; i < str.length; i++)
1966
+ result.push(1 << +str[i]);
1967
+ return result;
1968
+ }
1969
+ // Character types for codepoints 0 to 0xf8
1970
+ const LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
1971
+ // Character types for codepoints 0x600 to 0x6f9
1972
+ const ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
1973
+ const Brackets = Object.create(null), BracketStack = [];
1974
+ // There's a lot more in
1975
+ // https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt,
1976
+ // which are left out to keep code size down.
1977
+ for (let p of ["()", "[]", "{}"]) {
1978
+ let l = p.charCodeAt(0), r = p.charCodeAt(1);
1979
+ Brackets[l] = r;
1980
+ Brackets[r] = -l;
1981
+ }
1982
+ function charType(ch) {
1983
+ return ch <= 0xf7 ? LowTypes[ch] :
1984
+ 0x590 <= ch && ch <= 0x5f4 ? 2 /* R */ :
1985
+ 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] :
1986
+ 0x6ee <= ch && ch <= 0x8ac ? 4 /* AL */ :
1987
+ 0x2000 <= ch && ch <= 0x200b ? 256 /* NI */ :
1988
+ ch == 0x200c ? 256 /* NI */ : 1 /* L */;
1989
+ }
1990
+ const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
1991
+ /**
1992
+ Represents a contiguous range of text that has a single direction
1993
+ (as in left-to-right or right-to-left).
1994
+ */
1995
+ class BidiSpan {
1996
+ /**
1997
+ @internal
1998
+ */
1999
+ constructor(
2000
+ /**
2001
+ The start of the span (relative to the start of the line).
2002
+ */
2003
+ from,
2004
+ /**
2005
+ The end of the span.
2006
+ */
2007
+ to,
2008
+ /**
2009
+ The ["bidi
2010
+ level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm)
2011
+ of the span (in this context, 0 means
2012
+ left-to-right, 1 means right-to-left, 2 means left-to-right
2013
+ number inside right-to-left text).
2014
+ */
2015
+ level) {
2016
+ this.from = from;
2017
+ this.to = to;
2018
+ this.level = level;
1953
2019
  }
1954
- get root() { return this.view.root; }
1955
- get editorView() { return this.view; }
1956
- get length() { return this.view.state.doc.length; }
1957
- // Update the document view to a given state. scrollIntoView can be
1958
- // used as a hint to compute a new viewport that includes that
1959
- // position, if we know the editor is going to scroll that position
1960
- // into view.
1961
- update(update) {
1962
- let changedRanges = update.changedRanges;
1963
- if (this.minWidth > 0 && changedRanges.length) {
1964
- if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
1965
- this.minWidth = 0;
1966
- }
1967
- else {
1968
- this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1);
1969
- this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
2020
+ /**
2021
+ The direction of this span.
2022
+ */
2023
+ get dir() { return this.level % 2 ? RTL : LTR; }
2024
+ /**
2025
+ @internal
2026
+ */
2027
+ side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; }
2028
+ /**
2029
+ @internal
2030
+ */
2031
+ static find(order, index, level, assoc) {
2032
+ let maybe = -1;
2033
+ for (let i = 0; i < order.length; i++) {
2034
+ let span = order[i];
2035
+ if (span.from <= index && span.to >= index) {
2036
+ if (span.level == level)
2037
+ return i;
2038
+ // When multiple spans match, if assoc != 0, take the one that
2039
+ // covers that side, otherwise take the one with the minimum
2040
+ // level.
2041
+ if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level))
2042
+ maybe = i;
1970
2043
  }
1971
2044
  }
1972
- if (this.view.inputState.composing < 0)
1973
- this.compositionDeco = Decoration.none;
1974
- else if (update.transactions.length)
1975
- this.compositionDeco = computeCompositionDeco(this.view, update.changes);
1976
- // When the DOM nodes around the selection are moved to another
1977
- // parent, Chrome sometimes reports a different selection through
1978
- // getSelection than the one that it actually shows to the user.
1979
- // This forces a selection update when lines are joined to work
1980
- // around that. Issue #54
1981
- if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update &&
1982
- update.state.doc.lines != update.startState.doc.lines)
1983
- this.forceSelection = true;
1984
- let prevDeco = this.decorations, deco = this.updateDeco();
1985
- let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
1986
- changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
1987
- if (this.dirty == 0 /* Not */ && changedRanges.length == 0) {
1988
- return false;
1989
- }
1990
- else {
1991
- this.updateInner(changedRanges, deco, update.startState.doc.length);
1992
- if (update.transactions.length)
1993
- this.lastUpdate = Date.now();
1994
- return true;
1995
- }
2045
+ if (maybe < 0)
2046
+ throw new RangeError("Index out of range");
2047
+ return maybe;
1996
2048
  }
1997
- reset(sel) {
1998
- if (this.dirty) {
1999
- this.view.observer.ignore(() => this.view.docView.sync());
2000
- this.dirty = 0 /* Not */;
2001
- this.updateSelection(true);
2049
+ }
2050
+ // Reused array of character types
2051
+ const types = [];
2052
+ function computeOrder(line, direction) {
2053
+ let len = line.length, outerType = direction == LTR ? 1 /* L */ : 2 /* R */, oppositeType = direction == LTR ? 2 /* R */ : 1 /* L */;
2054
+ if (!line || outerType == 1 /* L */ && !BidiRE.test(line))
2055
+ return trivialOrder(len);
2056
+ // W1. Examine each non-spacing mark (NSM) in the level run, and
2057
+ // change the type of the NSM to the type of the previous
2058
+ // character. If the NSM is at the start of the level run, it will
2059
+ // get the type of sor.
2060
+ // W2. Search backwards from each instance of a European number
2061
+ // until the first strong type (R, L, AL, or sor) is found. If an
2062
+ // AL is found, change the type of the European number to Arabic
2063
+ // number.
2064
+ // W3. Change all ALs to R.
2065
+ // (Left after this: L, R, EN, AN, ET, CS, NI)
2066
+ for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
2067
+ let type = charType(line.charCodeAt(i));
2068
+ if (type == 512 /* NSM */)
2069
+ type = prev;
2070
+ else if (type == 8 /* EN */ && prevStrong == 4 /* AL */)
2071
+ type = 16 /* AN */;
2072
+ types[i] = type == 4 /* AL */ ? 2 /* R */ : type;
2073
+ if (type & 7 /* Strong */)
2074
+ prevStrong = type;
2075
+ prev = type;
2076
+ }
2077
+ // W5. A sequence of European terminators adjacent to European
2078
+ // numbers changes to all European numbers.
2079
+ // W6. Otherwise, separators and terminators change to Other
2080
+ // Neutral.
2081
+ // W7. Search backwards from each instance of a European number
2082
+ // until the first strong type (R, L, or sor) is found. If an L is
2083
+ // found, then change the type of the European number to L.
2084
+ // (Left after this: L, R, EN+AN, NI)
2085
+ for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
2086
+ let type = types[i];
2087
+ if (type == 128 /* CS */) {
2088
+ if (i < len - 1 && prev == types[i + 1] && (prev & 24 /* Num */))
2089
+ type = types[i] = prev;
2090
+ else
2091
+ types[i] = 256 /* NI */;
2002
2092
  }
2003
- else {
2004
- this.updateSelection();
2093
+ else if (type == 64 /* ET */) {
2094
+ let end = i + 1;
2095
+ while (end < len && types[end] == 64 /* ET */)
2096
+ end++;
2097
+ let replace = (i && prev == 8 /* EN */) || (end < len && types[end] == 8 /* EN */) ? (prevStrong == 1 /* L */ ? 1 /* L */ : 8 /* EN */) : 256 /* NI */;
2098
+ for (let j = i; j < end; j++)
2099
+ types[j] = replace;
2100
+ i = end - 1;
2005
2101
  }
2006
- }
2007
- // Used by update and the constructor do perform the actual DOM
2008
- // update
2009
- updateInner(changes, deco, oldLength) {
2010
- this.view.viewState.mustMeasureContent = true;
2011
- this.updateChildren(changes, deco, oldLength);
2012
- let { observer } = this.view;
2013
- observer.ignore(() => {
2014
- // Lock the height during redrawing, since Chrome sometimes
2015
- // messes with the scroll position during DOM mutation (though
2016
- // no relayout is triggered and I cannot imagine how it can
2017
- // recompute the scroll position without a layout)
2018
- this.dom.style.height = this.view.viewState.contentHeight + "px";
2019
- this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : "";
2020
- // Chrome will sometimes, when DOM mutations occur directly
2021
- // around the selection, get confused and report a different
2022
- // selection from the one it displays (issue #218). This tries
2023
- // to detect that situation.
2024
- let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
2025
- this.sync(track);
2026
- this.dirty = 0 /* Not */;
2027
- if (track && (track.written || observer.selectionRange.focusNode != track.node))
2028
- this.forceSelection = true;
2029
- this.dom.style.height = "";
2030
- });
2031
- let gaps = [];
2032
- if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
2033
- for (let child of this.children)
2034
- if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget)
2035
- gaps.push(child.dom);
2036
- observer.updateGaps(gaps);
2037
- }
2038
- updateChildren(changes, deco, oldLength) {
2039
- let cursor = this.childCursor(oldLength);
2040
- for (let i = changes.length - 1;; i--) {
2041
- let next = i >= 0 ? changes[i] : null;
2042
- if (!next)
2043
- break;
2044
- let { fromA, toA, fromB, toB } = next;
2045
- let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, deco);
2046
- let { i: toI, off: toOff } = cursor.findPos(toA, 1);
2047
- let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
2048
- this.replaceRange(fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
2102
+ else if (type == 8 /* EN */ && prevStrong == 1 /* L */) {
2103
+ types[i] = 1 /* L */;
2049
2104
  }
2105
+ prev = type;
2106
+ if (type & 7 /* Strong */)
2107
+ prevStrong = type;
2050
2108
  }
2051
- replaceRange(fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd) {
2052
- let before = this.children[fromI], last = content.length ? content[content.length - 1] : null;
2053
- let breakAtEnd = last ? last.breakAfter : breakAtStart;
2054
- // Change within a single line
2055
- if (fromI == toI && !breakAtStart && !breakAtEnd && content.length < 2 &&
2056
- before.merge(fromOff, toOff, content.length ? last : null, fromOff == 0, openStart, openEnd))
2057
- return;
2058
- let after = this.children[toI];
2059
- // Make sure the end of the line after the update is preserved in `after`
2060
- if (toOff < after.length) {
2061
- // If we're splitting a line, separate part of the start line to
2062
- // avoid that being mangled when updating the start line.
2063
- if (fromI == toI) {
2064
- after = after.split(toOff);
2065
- toOff = 0;
2109
+ // N0. Process bracket pairs in an isolating run sequence
2110
+ // sequentially in the logical order of the text positions of the
2111
+ // opening paired brackets using the logic given below. Within this
2112
+ // scope, bidirectional types EN and AN are treated as R.
2113
+ for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) {
2114
+ // Keeps [startIndex, type, strongSeen] triples for each open
2115
+ // bracket on BracketStack.
2116
+ if (br = Brackets[ch = line.charCodeAt(i)]) {
2117
+ if (br < 0) { // Closing bracket
2118
+ for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
2119
+ if (BracketStack[sJ + 1] == -br) {
2120
+ let flags = BracketStack[sJ + 2];
2121
+ let type = (flags & 2 /* EmbedInside */) ? outerType :
2122
+ !(flags & 4 /* OppositeInside */) ? 0 :
2123
+ (flags & 1 /* OppositeBefore */) ? oppositeType : outerType;
2124
+ if (type)
2125
+ types[i] = types[BracketStack[sJ]] = type;
2126
+ sI = sJ;
2127
+ break;
2128
+ }
2129
+ }
2066
2130
  }
2067
- // If the element after the replacement should be merged with
2068
- // the last replacing element, update `content`
2069
- if (!breakAtEnd && last && after.merge(0, toOff, last, true, 0, openEnd)) {
2070
- content[content.length - 1] = after;
2131
+ else if (BracketStack.length == 189 /* MaxDepth */) {
2132
+ break;
2071
2133
  }
2072
2134
  else {
2073
- // Remove the start of the after element, if necessary, and
2074
- // add it to `content`.
2075
- if (toOff)
2076
- after.merge(0, toOff, null, false, 0, openEnd);
2077
- content.push(after);
2135
+ BracketStack[sI++] = i;
2136
+ BracketStack[sI++] = ch;
2137
+ BracketStack[sI++] = context;
2078
2138
  }
2079
2139
  }
2080
- else if (after.breakAfter) {
2081
- // The element at `toI` is entirely covered by this range.
2082
- // Preserve its line break, if any.
2083
- if (last)
2084
- last.breakAfter = 1;
2085
- else
2086
- breakAtStart = 1;
2140
+ else if ((type = types[i]) == 2 /* R */ || type == 1 /* L */) {
2141
+ let embed = type == outerType;
2142
+ context = embed ? 0 : 1 /* OppositeBefore */;
2143
+ for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
2144
+ let cur = BracketStack[sJ + 2];
2145
+ if (cur & 2 /* EmbedInside */)
2146
+ break;
2147
+ if (embed) {
2148
+ BracketStack[sJ + 2] |= 2 /* EmbedInside */;
2149
+ }
2150
+ else {
2151
+ if (cur & 4 /* OppositeInside */)
2152
+ break;
2153
+ BracketStack[sJ + 2] |= 4 /* OppositeInside */;
2154
+ }
2155
+ }
2087
2156
  }
2088
- // Since we've handled the next element from the current elements
2089
- // now, make sure `toI` points after that.
2090
- toI++;
2091
- before.breakAfter = breakAtStart;
2092
- if (fromOff > 0) {
2093
- if (!breakAtStart && content.length && before.merge(fromOff, before.length, content[0], false, openStart, 0)) {
2094
- before.breakAfter = content.shift().breakAfter;
2157
+ }
2158
+ // N1. A sequence of neutrals takes the direction of the
2159
+ // surrounding strong text if the text on both sides has the same
2160
+ // direction. European and Arabic numbers act as if they were R in
2161
+ // terms of their influence on neutrals. Start-of-level-run (sor)
2162
+ // and end-of-level-run (eor) are used at level run boundaries.
2163
+ // N2. Any remaining neutrals take the embedding direction.
2164
+ // (Left after this: L, R, EN+AN)
2165
+ for (let i = 0; i < len; i++) {
2166
+ if (types[i] == 256 /* NI */) {
2167
+ let end = i + 1;
2168
+ while (end < len && types[end] == 256 /* NI */)
2169
+ end++;
2170
+ let beforeL = (i ? types[i - 1] : outerType) == 1 /* L */;
2171
+ let afterL = (end < len ? types[end] : outerType) == 1 /* L */;
2172
+ let replace = beforeL == afterL ? (beforeL ? 1 /* L */ : 2 /* R */) : outerType;
2173
+ for (let j = i; j < end; j++)
2174
+ types[j] = replace;
2175
+ i = end - 1;
2176
+ }
2177
+ }
2178
+ // Here we depart from the documented algorithm, in order to avoid
2179
+ // building up an actual levels array. Since there are only three
2180
+ // levels (0, 1, 2) in an implementation that doesn't take
2181
+ // explicit embedding into account, we can build up the order on
2182
+ // the fly, without following the level-based algorithm.
2183
+ let order = [];
2184
+ if (outerType == 1 /* L */) {
2185
+ for (let i = 0; i < len;) {
2186
+ let start = i, rtl = types[i++] != 1 /* L */;
2187
+ while (i < len && rtl == (types[i] != 1 /* L */))
2188
+ i++;
2189
+ if (rtl) {
2190
+ for (let j = i; j > start;) {
2191
+ let end = j, l = types[--j] != 2 /* R */;
2192
+ while (j > start && l == (types[j - 1] != 2 /* R */))
2193
+ j--;
2194
+ order.push(new BidiSpan(j, end, l ? 2 : 1));
2195
+ }
2095
2196
  }
2096
- else if (fromOff < before.length || before.children.length && before.children[before.children.length - 1].length == 0) {
2097
- before.merge(fromOff, before.length, null, false, openStart, 0);
2197
+ else {
2198
+ order.push(new BidiSpan(start, i, 0));
2098
2199
  }
2099
- fromI++;
2100
2200
  }
2101
- // Try to merge widgets on the boundaries of the replacement
2102
- while (fromI < toI && content.length) {
2103
- if (this.children[toI - 1].match(content[content.length - 1]))
2104
- toI--, content.pop();
2105
- else if (this.children[fromI].match(content[0]))
2106
- fromI++, content.shift();
2107
- else
2108
- break;
2201
+ }
2202
+ else {
2203
+ for (let i = 0; i < len;) {
2204
+ let start = i, rtl = types[i++] == 2 /* R */;
2205
+ while (i < len && rtl == (types[i] == 2 /* R */))
2206
+ i++;
2207
+ order.push(new BidiSpan(start, i, rtl ? 1 : 2));
2109
2208
  }
2110
- if (fromI < toI || content.length)
2111
- this.replaceChildren(fromI, toI, content);
2112
2209
  }
2113
- // Sync the DOM selection to this.state.selection
2114
- updateSelection(mustRead = false, fromPointer = false) {
2115
- if (mustRead)
2116
- this.view.observer.readSelectionRange();
2117
- if (!(fromPointer || this.mayControlSelection()) ||
2118
- browser.ios && this.view.inputState.rapidCompositionStart)
2119
- return;
2120
- let force = this.forceSelection;
2121
- this.forceSelection = false;
2122
- let main = this.view.state.selection.main;
2123
- // FIXME need to handle the case where the selection falls inside a block range
2124
- let anchor = this.domAtPos(main.anchor);
2125
- let head = main.empty ? anchor : this.domAtPos(main.head);
2126
- // Always reset on Firefox when next to an uneditable node to
2127
- // avoid invisible cursor bugs (#111)
2128
- if (browser.gecko && main.empty && betweenUneditable(anchor)) {
2129
- let dummy = document.createTextNode("");
2130
- this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
2131
- anchor = head = new DOMPos(dummy, 0);
2132
- force = true;
2133
- }
2134
- let domSel = this.view.observer.selectionRange;
2135
- // If the selection is already here, or in an equivalent position, don't touch it
2136
- if (force || !domSel.focusNode ||
2137
- !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
2138
- !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
2139
- this.view.observer.ignore(() => {
2140
- // Chrome Android will hide the virtual keyboard when tapping
2141
- // inside an uneditable node, and not bring it back when we
2142
- // move the cursor to its proper position. This tries to
2143
- // restore the keyboard by cycling focus.
2144
- if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, this.dom)) {
2145
- this.dom.blur();
2146
- this.dom.focus({ preventScroll: true });
2147
- }
2148
- let rawSel = getSelection(this.root);
2149
- if (main.empty) {
2150
- // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
2151
- if (browser.gecko) {
2152
- let nextTo = nextToUneditable(anchor.node, anchor.offset);
2153
- if (nextTo && nextTo != (1 /* Before */ | 2 /* After */)) {
2154
- let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* Before */ ? 1 : -1);
2155
- if (text)
2156
- anchor = new DOMPos(text, nextTo == 1 /* Before */ ? 0 : text.nodeValue.length);
2157
- }
2158
- }
2159
- rawSel.collapse(anchor.node, anchor.offset);
2160
- if (main.bidiLevel != null && domSel.cursorBidiLevel != null)
2161
- domSel.cursorBidiLevel = main.bidiLevel;
2162
- }
2163
- else if (rawSel.extend) {
2164
- // Selection.extend can be used to create an 'inverted' selection
2165
- // (one where the focus is before the anchor), but not all
2166
- // browsers support it yet.
2167
- rawSel.collapse(anchor.node, anchor.offset);
2168
- rawSel.extend(head.node, head.offset);
2169
- }
2170
- else {
2171
- // Primitive (IE) way
2172
- let range = document.createRange();
2173
- if (main.anchor > main.head)
2174
- [anchor, head] = [head, anchor];
2175
- range.setEnd(head.node, head.offset);
2176
- range.setStart(anchor.node, anchor.offset);
2177
- rawSel.removeAllRanges();
2178
- rawSel.addRange(range);
2179
- }
2180
- });
2181
- this.view.observer.setSelectionRange(anchor, head);
2210
+ return order;
2211
+ }
2212
+ function trivialOrder(length) {
2213
+ return [new BidiSpan(0, length, 0)];
2214
+ }
2215
+ let movedOver = "";
2216
+ function moveVisually(line, order, dir, start, forward) {
2217
+ var _a;
2218
+ let startIndex = start.head - line.from, spanI = -1;
2219
+ if (startIndex == 0) {
2220
+ if (!forward || !line.length)
2221
+ return null;
2222
+ if (order[0].level != dir) {
2223
+ startIndex = order[0].side(false, dir);
2224
+ spanI = 0;
2182
2225
  }
2183
- this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset);
2184
- this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
2185
- }
2186
- enforceCursorAssoc() {
2187
- if (this.view.composing)
2188
- return;
2189
- let cursor = this.view.state.selection.main;
2190
- let sel = getSelection(this.root);
2191
- if (!cursor.empty || !cursor.assoc || !sel.modify)
2192
- return;
2193
- let line = LineView.find(this, cursor.head);
2194
- if (!line)
2195
- return;
2196
- let lineStart = line.posAtStart;
2197
- if (cursor.head == lineStart || cursor.head == lineStart + line.length)
2198
- return;
2199
- let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
2200
- if (!before || !after || before.bottom > after.top)
2201
- return;
2202
- let dom = this.domAtPos(cursor.head + cursor.assoc);
2203
- sel.collapse(dom.node, dom.offset);
2204
- sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
2205
2226
  }
2206
- mayControlSelection() {
2207
- return this.view.state.facet(editable) ? this.root.activeElement == this.dom
2208
- : hasSelection(this.dom, this.view.observer.selectionRange);
2209
- }
2210
- nearest(dom) {
2211
- for (let cur = dom; cur;) {
2212
- let domView = ContentView.get(cur);
2213
- if (domView && domView.rootView == this)
2214
- return domView;
2215
- cur = cur.parentNode;
2227
+ else if (startIndex == line.length) {
2228
+ if (forward)
2229
+ return null;
2230
+ let last = order[order.length - 1];
2231
+ if (last.level != dir) {
2232
+ startIndex = last.side(true, dir);
2233
+ spanI = order.length - 1;
2216
2234
  }
2217
- return null;
2218
- }
2219
- posFromDOM(node, offset) {
2220
- let view = this.nearest(node);
2221
- if (!view)
2222
- throw new RangeError("Trying to find position for a DOM position outside of the document");
2223
- return view.localPosFromDOM(node, offset) + view.posAtStart;
2224
2235
  }
2225
- domAtPos(pos) {
2226
- let { i, off } = this.childCursor().findPos(pos, -1);
2227
- for (; i < this.children.length - 1;) {
2228
- let child = this.children[i];
2229
- if (off < child.length || child instanceof LineView)
2230
- break;
2231
- i++;
2232
- off = 0;
2233
- }
2234
- return this.children[i].domAtPos(off);
2236
+ if (spanI < 0)
2237
+ spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
2238
+ let span = order[spanI];
2239
+ // End of span. (But not end of line--that was checked for above.)
2240
+ if (startIndex == span.side(forward, dir)) {
2241
+ span = order[spanI += forward ? 1 : -1];
2242
+ startIndex = span.side(!forward, dir);
2235
2243
  }
2236
- coordsAt(pos, side) {
2237
- for (let off = this.length, i = this.children.length - 1;; i--) {
2238
- let child = this.children[i], start = off - child.breakAfter - child.length;
2239
- if (pos > start ||
2240
- (pos == start && child.type != exports.BlockType.WidgetBefore && child.type != exports.BlockType.WidgetAfter &&
2241
- (!i || side == 2 || this.children[i - 1].breakAfter ||
2242
- (this.children[i - 1].type == exports.BlockType.WidgetBefore && side > -2))))
2243
- return child.coordsAt(pos - start, side);
2244
- off = start;
2245
- }
2244
+ let indexForward = forward == (span.dir == dir);
2245
+ let nextIndex = text.findClusterBreak(line.text, startIndex, indexForward);
2246
+ movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
2247
+ if (nextIndex != span.side(forward, dir))
2248
+ return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
2249
+ let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
2250
+ if (!nextSpan && span.level != dir)
2251
+ return state.EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir);
2252
+ if (nextSpan && nextSpan.level < span.level)
2253
+ return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level);
2254
+ return state.EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
2255
+ }
2256
+
2257
+ class DOMReader {
2258
+ constructor(points, view) {
2259
+ this.points = points;
2260
+ this.view = view;
2261
+ this.text = "";
2262
+ this.lineBreak = view.state.lineBreak;
2246
2263
  }
2247
- measureVisibleLineHeights() {
2248
- let result = [], { from, to } = this.view.viewState.viewport;
2249
- let minWidth = Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
2250
- for (let pos = 0, i = 0; i < this.children.length; i++) {
2251
- let child = this.children[i], end = pos + child.length;
2252
- if (end > to)
2264
+ readRange(start, end) {
2265
+ if (!start)
2266
+ return this;
2267
+ let parent = start.parentNode;
2268
+ for (let cur = start;;) {
2269
+ this.findPointBefore(parent, cur);
2270
+ this.readNode(cur);
2271
+ let next = cur.nextSibling;
2272
+ if (next == end)
2253
2273
  break;
2254
- if (pos >= from) {
2255
- result.push(child.dom.getBoundingClientRect().height);
2256
- let width = child.dom.scrollWidth;
2257
- if (width > minWidth) {
2258
- this.minWidth = minWidth = width;
2259
- this.minWidthFrom = pos;
2260
- this.minWidthTo = end;
2261
- }
2262
- }
2263
- pos = end + child.breakAfter;
2274
+ let view = ContentView.get(cur), nextView = ContentView.get(next);
2275
+ if (view && nextView ? view.breakAfter :
2276
+ (view ? view.breakAfter : isBlockElement(cur)) ||
2277
+ (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
2278
+ this.text += this.lineBreak;
2279
+ cur = next;
2264
2280
  }
2265
- return result;
2281
+ this.findPointBefore(parent, end);
2282
+ return this;
2266
2283
  }
2267
- measureTextSize() {
2268
- for (let child of this.children) {
2269
- if (child instanceof LineView) {
2270
- let measure = child.measureTextSize();
2271
- if (measure)
2272
- return measure;
2273
- }
2284
+ readNode(node) {
2285
+ if (node.cmIgnore)
2286
+ return;
2287
+ let view = ContentView.get(node);
2288
+ let fromView = view && view.overrideDOMText;
2289
+ let text;
2290
+ if (fromView != null)
2291
+ text = fromView.sliceString(0, undefined, this.lineBreak);
2292
+ else if (node.nodeType == 3)
2293
+ text = node.nodeValue;
2294
+ else if (node.nodeName == "BR")
2295
+ text = node.nextSibling ? this.lineBreak : "";
2296
+ else if (node.nodeType == 1)
2297
+ this.readRange(node.firstChild, null);
2298
+ if (text != null) {
2299
+ this.findPointIn(node, text.length);
2300
+ this.text += text;
2301
+ // Chrome inserts two newlines when pressing shift-enter at the
2302
+ // end of a line. This drops one of those.
2303
+ if (browser.chrome && this.view.inputState.lastKeyCode == 13 && !node.nextSibling && /\n\n$/.test(this.text))
2304
+ this.text = this.text.slice(0, -1);
2274
2305
  }
2275
- // If no workable line exists, force a layout of a measurable element
2276
- let dummy = document.createElement("div"), lineHeight, charWidth;
2277
- dummy.className = "cm-line";
2278
- dummy.textContent = "abc def ghi jkl mno pqr stu";
2279
- this.view.observer.ignore(() => {
2280
- this.dom.appendChild(dummy);
2281
- let rect = clientRectsFor(dummy.firstChild)[0];
2282
- lineHeight = dummy.getBoundingClientRect().height;
2283
- charWidth = rect ? rect.width / 27 : 7;
2284
- dummy.remove();
2285
- });
2286
- return { lineHeight, charWidth };
2287
2306
  }
2288
- childCursor(pos = this.length) {
2289
- // Move back to start of last element when possible, so that
2290
- // `ChildCursor.findPos` doesn't have to deal with the edge case
2291
- // of being after the last element.
2292
- let i = this.children.length;
2293
- if (i)
2294
- pos -= this.children[--i].length;
2295
- return new ChildCursor(this.children, pos, i);
2307
+ findPointBefore(node, next) {
2308
+ for (let point of this.points)
2309
+ if (point.node == node && node.childNodes[point.offset] == next)
2310
+ point.pos = this.text.length;
2296
2311
  }
2297
- computeBlockGapDeco() {
2298
- let deco = [], vs = this.view.viewState;
2299
- for (let pos = 0, i = 0;; i++) {
2300
- let next = i == vs.viewports.length ? null : vs.viewports[i];
2301
- let end = next ? next.from - 1 : this.length;
2302
- if (end > pos) {
2303
- let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
2304
- deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end));
2305
- }
2306
- if (!next)
2307
- break;
2308
- pos = next.to + 1;
2309
- }
2310
- return Decoration.set(deco);
2312
+ findPointIn(node, maxLen) {
2313
+ for (let point of this.points)
2314
+ if (point.node == node)
2315
+ point.pos = this.text.length + Math.min(point.offset, maxLen);
2311
2316
  }
2312
- updateDeco() {
2313
- return this.decorations = [
2314
- ...this.view.pluginField(PluginField.decorations),
2315
- ...this.view.state.facet(decorations),
2316
- this.compositionDeco,
2317
- this.computeBlockGapDeco(),
2318
- this.view.viewState.lineGapDeco
2319
- ];
2320
- }
2321
- scrollIntoView({ range, center }) {
2322
- let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
2323
- if (!rect)
2324
- return;
2325
- if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
2326
- rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
2327
- right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
2328
- let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
2329
- for (let margins of this.view.pluginField(PluginField.scrollMargins))
2330
- if (margins) {
2331
- let { left, right, top, bottom } = margins;
2332
- if (left != null)
2333
- mLeft = Math.max(mLeft, left);
2334
- if (right != null)
2335
- mRight = Math.max(mRight, right);
2336
- if (top != null)
2337
- mTop = Math.max(mTop, top);
2338
- if (bottom != null)
2339
- mBottom = Math.max(mBottom, bottom);
2340
- }
2341
- scrollRectIntoView(this.view.scrollDOM, {
2342
- left: rect.left - mLeft, top: rect.top - mTop,
2343
- right: rect.right + mRight, bottom: rect.bottom + mBottom
2344
- }, range.head < range.anchor ? -1 : 1, center);
2345
- }
2346
- }
2347
- function betweenUneditable(pos) {
2348
- return pos.node.nodeType == 1 && pos.node.firstChild &&
2349
- (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") &&
2350
- (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false");
2351
2317
  }
2352
- class BlockGapWidget extends WidgetType {
2353
- constructor(height) {
2354
- super();
2355
- this.height = height;
2356
- }
2357
- toDOM() {
2358
- let elt = document.createElement("div");
2359
- this.updateDOM(elt);
2360
- return elt;
2361
- }
2362
- eq(other) { return other.height == this.height; }
2363
- updateDOM(elt) {
2364
- elt.style.height = this.height + "px";
2365
- return true;
2366
- }
2367
- get estimatedHeight() { return this.height; }
2318
+ function isBlockElement(node) {
2319
+ return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
2368
2320
  }
2369
- function computeCompositionDeco(view, changes) {
2370
- let sel = view.observer.selectionRange;
2371
- let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
2372
- if (!textNode)
2373
- return Decoration.none;
2374
- let cView = view.docView.nearest(textNode);
2375
- let from, to, topNode = textNode;
2376
- if (cView instanceof InlineView) {
2377
- while (cView.parent instanceof InlineView)
2378
- cView = cView.parent;
2379
- from = cView.posAtStart;
2380
- to = from + cView.length;
2381
- topNode = cView.dom;
2382
- }
2383
- else if (cView instanceof LineView) {
2384
- while (topNode.parentNode != cView.dom)
2385
- topNode = topNode.parentNode;
2386
- let prev = topNode.previousSibling;
2387
- while (prev && !ContentView.get(prev))
2388
- prev = prev.previousSibling;
2389
- from = to = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
2390
- }
2391
- else {
2392
- return Decoration.none;
2393
- }
2394
- let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1));
2395
- let text = textNode.nodeValue, { state } = view;
2396
- if (newTo - newFrom < text.length) {
2397
- if (state.sliceDoc(newFrom, Math.min(state.doc.length, newFrom + text.length)) == text)
2398
- newTo = newFrom + text.length;
2399
- else if (state.sliceDoc(Math.max(0, newTo - text.length), newTo) == text)
2400
- newFrom = newTo - text.length;
2401
- else
2402
- return Decoration.none;
2403
- }
2404
- else if (state.sliceDoc(newFrom, newTo) != text) {
2405
- return Decoration.none;
2321
+ class DOMPoint {
2322
+ constructor(node, offset) {
2323
+ this.node = node;
2324
+ this.offset = offset;
2325
+ this.pos = -1;
2406
2326
  }
2407
- return Decoration.set(Decoration.replace({ widget: new CompositionWidget(topNode, textNode) }).range(newFrom, newTo));
2408
2327
  }
2409
- class CompositionWidget extends WidgetType {
2410
- constructor(top, text) {
2328
+
2329
+ class DocView extends ContentView {
2330
+ constructor(view) {
2411
2331
  super();
2412
- this.top = top;
2413
- this.text = text;
2332
+ this.view = view;
2333
+ this.compositionDeco = Decoration.none;
2334
+ this.decorations = [];
2335
+ // Track a minimum width for the editor. When measuring sizes in
2336
+ // measureVisibleLineHeights, this is updated to point at the width
2337
+ // of a given element and its extent in the document. When a change
2338
+ // happens in that range, these are reset. That way, once we've seen
2339
+ // a line/element of a given length, we keep the editor wide enough
2340
+ // to fit at least that element, until it is changed, at which point
2341
+ // we forget it again.
2342
+ this.minWidth = 0;
2343
+ this.minWidthFrom = 0;
2344
+ this.minWidthTo = 0;
2345
+ // Track whether the DOM selection was set in a lossy way, so that
2346
+ // we don't mess it up when reading it back it
2347
+ this.impreciseAnchor = null;
2348
+ this.impreciseHead = null;
2349
+ this.forceSelection = false;
2350
+ // Used by the resize observer to ignore resizes that we caused
2351
+ // ourselves
2352
+ this.lastUpdate = Date.now();
2353
+ this.setDOM(view.contentDOM);
2354
+ this.children = [new LineView];
2355
+ this.children[0].setParent(this);
2356
+ this.updateInner([new ChangedRange(0, 0, 0, view.state.doc.length)], this.updateDeco(), 0);
2414
2357
  }
2415
- eq(other) { return this.top == other.top && this.text == other.text; }
2416
- toDOM() { return this.top; }
2417
- ignoreEvent() { return false; }
2418
- get customView() { return CompositionView; }
2419
- }
2420
- function nearbyTextNode(node, offset, side) {
2421
- for (;;) {
2422
- if (node.nodeType == 3)
2423
- return node;
2424
- if (node.nodeType == 1 && offset > 0 && side <= 0) {
2425
- node = node.childNodes[offset - 1];
2426
- offset = maxOffset(node);
2358
+ get root() { return this.view.root; }
2359
+ get editorView() { return this.view; }
2360
+ get length() { return this.view.state.doc.length; }
2361
+ // Update the document view to a given state. scrollIntoView can be
2362
+ // used as a hint to compute a new viewport that includes that
2363
+ // position, if we know the editor is going to scroll that position
2364
+ // into view.
2365
+ update(update) {
2366
+ let changedRanges = update.changedRanges;
2367
+ if (this.minWidth > 0 && changedRanges.length) {
2368
+ if (!changedRanges.every(({ fromA, toA }) => toA < this.minWidthFrom || fromA > this.minWidthTo)) {
2369
+ this.minWidth = this.minWidthFrom = this.minWidthTo = 0;
2370
+ }
2371
+ else {
2372
+ this.minWidthFrom = update.changes.mapPos(this.minWidthFrom, 1);
2373
+ this.minWidthTo = update.changes.mapPos(this.minWidthTo, 1);
2374
+ }
2427
2375
  }
2428
- else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
2429
- node = node.childNodes[offset];
2430
- offset = 0;
2376
+ if (this.view.inputState.composing < 0)
2377
+ this.compositionDeco = Decoration.none;
2378
+ else if (update.transactions.length || this.dirty)
2379
+ this.compositionDeco = computeCompositionDeco(this.view, update.changes);
2380
+ // When the DOM nodes around the selection are moved to another
2381
+ // parent, Chrome sometimes reports a different selection through
2382
+ // getSelection than the one that it actually shows to the user.
2383
+ // This forces a selection update when lines are joined to work
2384
+ // around that. Issue #54
2385
+ if ((browser.ie || browser.chrome) && !this.compositionDeco.size && update &&
2386
+ update.state.doc.lines != update.startState.doc.lines)
2387
+ this.forceSelection = true;
2388
+ let prevDeco = this.decorations, deco = this.updateDeco();
2389
+ let decoDiff = findChangedDeco(prevDeco, deco, update.changes);
2390
+ changedRanges = ChangedRange.extendWithRanges(changedRanges, decoDiff);
2391
+ if (this.dirty == 0 /* Not */ && changedRanges.length == 0) {
2392
+ return false;
2431
2393
  }
2432
2394
  else {
2433
- return null;
2395
+ this.updateInner(changedRanges, deco, update.startState.doc.length);
2396
+ if (update.transactions.length)
2397
+ this.lastUpdate = Date.now();
2398
+ return true;
2434
2399
  }
2435
2400
  }
2436
- }
2437
- function nextToUneditable(node, offset) {
2438
- if (node.nodeType != 1)
2439
- return 0;
2440
- return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* Before */ : 0) |
2441
- (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* After */ : 0);
2442
- }
2443
- class DecorationComparator$1 {
2444
- constructor() {
2445
- this.changes = [];
2446
- }
2447
- compareRange(from, to) { addRange(from, to, this.changes); }
2448
- comparePoint(from, to) { addRange(from, to, this.changes); }
2449
- }
2450
- function findChangedDeco(a, b, diff) {
2451
- let comp = new DecorationComparator$1;
2452
- rangeset.RangeSet.compare(a, b, diff, comp);
2453
- return comp.changes;
2454
- }
2455
- function inUneditable(node, inside) {
2456
- for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
2457
- if (cur.nodeType == 1 && cur.contentEditable == 'false') {
2458
- return true;
2401
+ reset(sel) {
2402
+ if (this.dirty) {
2403
+ this.view.observer.ignore(() => this.view.docView.sync());
2404
+ this.dirty = 0 /* Not */;
2405
+ this.updateSelection(true);
2406
+ }
2407
+ else {
2408
+ this.updateSelection();
2459
2409
  }
2460
2410
  }
2461
- return false;
2462
- }
2463
-
2464
- /**
2465
- Used to indicate [text direction](https://codemirror.net/6/docs/ref/#view.EditorView.textDirection).
2466
- */
2467
- exports.Direction = void 0;
2468
- (function (Direction) {
2469
- // (These are chosen to match the base levels, in bidi algorithm
2470
- // terms, of spans in that direction.)
2471
- /**
2472
- Left-to-right.
2473
- */
2474
- Direction[Direction["LTR"] = 0] = "LTR";
2475
- /**
2476
- Right-to-left.
2477
- */
2478
- Direction[Direction["RTL"] = 1] = "RTL";
2479
- })(exports.Direction || (exports.Direction = {}));
2480
- const LTR = exports.Direction.LTR, RTL = exports.Direction.RTL;
2481
- // Decode a string with each type encoded as log2(type)
2482
- function dec(str) {
2483
- let result = [];
2484
- for (let i = 0; i < str.length; i++)
2485
- result.push(1 << +str[i]);
2486
- return result;
2487
- }
2488
- // Character types for codepoints 0 to 0xf8
2489
- const LowTypes = dec("88888888888888888888888888888888888666888888787833333333337888888000000000000000000000000008888880000000000000000000000000088888888888888888888888888888888888887866668888088888663380888308888800000000000000000000000800000000000000000000000000000008");
2490
- // Character types for codepoints 0x600 to 0x6f9
2491
- const ArabicTypes = dec("4444448826627288999999999992222222222222222222222222222222222222222222222229999999999999999999994444444444644222822222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222222999999949999999229989999223333333333");
2492
- const Brackets = Object.create(null), BracketStack = [];
2493
- // There's a lot more in
2494
- // https://www.unicode.org/Public/UCD/latest/ucd/BidiBrackets.txt,
2495
- // which are left out to keep code size down.
2496
- for (let p of ["()", "[]", "{}"]) {
2497
- let l = p.charCodeAt(0), r = p.charCodeAt(1);
2498
- Brackets[l] = r;
2499
- Brackets[r] = -l;
2500
- }
2501
- function charType(ch) {
2502
- return ch <= 0xf7 ? LowTypes[ch] :
2503
- 0x590 <= ch && ch <= 0x5f4 ? 2 /* R */ :
2504
- 0x600 <= ch && ch <= 0x6f9 ? ArabicTypes[ch - 0x600] :
2505
- 0x6ee <= ch && ch <= 0x8ac ? 4 /* AL */ :
2506
- 0x2000 <= ch && ch <= 0x200b ? 256 /* NI */ :
2507
- ch == 0x200c ? 256 /* NI */ : 1 /* L */;
2508
- }
2509
- const BidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
2510
- /**
2511
- Represents a contiguous range of text that has a single direction
2512
- (as in left-to-right or right-to-left).
2513
- */
2514
- class BidiSpan {
2515
- /**
2516
- @internal
2517
- */
2518
- constructor(
2519
- /**
2520
- The start of the span (relative to the start of the line).
2521
- */
2522
- from,
2523
- /**
2524
- The end of the span.
2525
- */
2526
- to,
2527
- /**
2528
- The ["bidi
2529
- level"](https://unicode.org/reports/tr9/#Basic_Display_Algorithm)
2530
- of the span (in this context, 0 means
2531
- left-to-right, 1 means right-to-left, 2 means left-to-right
2532
- number inside right-to-left text).
2533
- */
2534
- level) {
2535
- this.from = from;
2536
- this.to = to;
2537
- this.level = level;
2411
+ // Used by update and the constructor do perform the actual DOM
2412
+ // update
2413
+ updateInner(changes, deco, oldLength) {
2414
+ this.view.viewState.mustMeasureContent = true;
2415
+ this.updateChildren(changes, deco, oldLength);
2416
+ let { observer } = this.view;
2417
+ observer.ignore(() => {
2418
+ // Lock the height during redrawing, since Chrome sometimes
2419
+ // messes with the scroll position during DOM mutation (though
2420
+ // no relayout is triggered and I cannot imagine how it can
2421
+ // recompute the scroll position without a layout)
2422
+ this.dom.style.height = this.view.viewState.contentHeight + "px";
2423
+ this.dom.style.minWidth = this.minWidth ? this.minWidth + "px" : "";
2424
+ // Chrome will sometimes, when DOM mutations occur directly
2425
+ // around the selection, get confused and report a different
2426
+ // selection from the one it displays (issue #218). This tries
2427
+ // to detect that situation.
2428
+ let track = browser.chrome || browser.ios ? { node: observer.selectionRange.focusNode, written: false } : undefined;
2429
+ this.sync(track);
2430
+ this.dirty = 0 /* Not */;
2431
+ if (track && (track.written || observer.selectionRange.focusNode != track.node))
2432
+ this.forceSelection = true;
2433
+ this.dom.style.height = "";
2434
+ });
2435
+ let gaps = [];
2436
+ if (this.view.viewport.from || this.view.viewport.to < this.view.state.doc.length)
2437
+ for (let child of this.children)
2438
+ if (child instanceof BlockWidgetView && child.widget instanceof BlockGapWidget)
2439
+ gaps.push(child.dom);
2440
+ observer.updateGaps(gaps);
2538
2441
  }
2539
- /**
2540
- The direction of this span.
2541
- */
2542
- get dir() { return this.level % 2 ? RTL : LTR; }
2543
- /**
2544
- @internal
2545
- */
2546
- side(end, dir) { return (this.dir == dir) == end ? this.to : this.from; }
2547
- /**
2548
- @internal
2549
- */
2550
- static find(order, index, level, assoc) {
2551
- let maybe = -1;
2552
- for (let i = 0; i < order.length; i++) {
2553
- let span = order[i];
2554
- if (span.from <= index && span.to >= index) {
2555
- if (span.level == level)
2556
- return i;
2557
- // When multiple spans match, if assoc != 0, take the one that
2558
- // covers that side, otherwise take the one with the minimum
2559
- // level.
2560
- if (maybe < 0 || (assoc != 0 ? (assoc < 0 ? span.from < index : span.to > index) : order[maybe].level > span.level))
2561
- maybe = i;
2562
- }
2442
+ updateChildren(changes, deco, oldLength) {
2443
+ let cursor = this.childCursor(oldLength);
2444
+ for (let i = changes.length - 1;; i--) {
2445
+ let next = i >= 0 ? changes[i] : null;
2446
+ if (!next)
2447
+ break;
2448
+ let { fromA, toA, fromB, toB } = next;
2449
+ let { content, breakAtStart, openStart, openEnd } = ContentBuilder.build(this.view.state.doc, fromB, toB, deco);
2450
+ let { i: toI, off: toOff } = cursor.findPos(toA, 1);
2451
+ let { i: fromI, off: fromOff } = cursor.findPos(fromA, -1);
2452
+ replaceRange(this, fromI, fromOff, toI, toOff, content, breakAtStart, openStart, openEnd);
2563
2453
  }
2564
- if (maybe < 0)
2565
- throw new RangeError("Index out of range");
2566
- return maybe;
2567
2454
  }
2568
- }
2569
- // Reused array of character types
2570
- const types = [];
2571
- function computeOrder(line, direction) {
2572
- let len = line.length, outerType = direction == LTR ? 1 /* L */ : 2 /* R */, oppositeType = direction == LTR ? 2 /* R */ : 1 /* L */;
2573
- if (!line || outerType == 1 /* L */ && !BidiRE.test(line))
2574
- return trivialOrder(len);
2575
- // W1. Examine each non-spacing mark (NSM) in the level run, and
2576
- // change the type of the NSM to the type of the previous
2577
- // character. If the NSM is at the start of the level run, it will
2578
- // get the type of sor.
2579
- // W2. Search backwards from each instance of a European number
2580
- // until the first strong type (R, L, AL, or sor) is found. If an
2581
- // AL is found, change the type of the European number to Arabic
2582
- // number.
2583
- // W3. Change all ALs to R.
2584
- // (Left after this: L, R, EN, AN, ET, CS, NI)
2585
- for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
2586
- let type = charType(line.charCodeAt(i));
2587
- if (type == 512 /* NSM */)
2588
- type = prev;
2589
- else if (type == 8 /* EN */ && prevStrong == 4 /* AL */)
2590
- type = 16 /* AN */;
2591
- types[i] = type == 4 /* AL */ ? 2 /* R */ : type;
2592
- if (type & 7 /* Strong */)
2593
- prevStrong = type;
2594
- prev = type;
2455
+ // Sync the DOM selection to this.state.selection
2456
+ updateSelection(mustRead = false, fromPointer = false) {
2457
+ if (mustRead)
2458
+ this.view.observer.readSelectionRange();
2459
+ if (!(fromPointer || this.mayControlSelection()) ||
2460
+ browser.ios && this.view.inputState.rapidCompositionStart)
2461
+ return;
2462
+ let force = this.forceSelection;
2463
+ this.forceSelection = false;
2464
+ let main = this.view.state.selection.main;
2465
+ // FIXME need to handle the case where the selection falls inside a block range
2466
+ let anchor = this.domAtPos(main.anchor);
2467
+ let head = main.empty ? anchor : this.domAtPos(main.head);
2468
+ // Always reset on Firefox when next to an uneditable node to
2469
+ // avoid invisible cursor bugs (#111)
2470
+ if (browser.gecko && main.empty && betweenUneditable(anchor)) {
2471
+ let dummy = document.createTextNode("");
2472
+ this.view.observer.ignore(() => anchor.node.insertBefore(dummy, anchor.node.childNodes[anchor.offset] || null));
2473
+ anchor = head = new DOMPos(dummy, 0);
2474
+ force = true;
2475
+ }
2476
+ let domSel = this.view.observer.selectionRange;
2477
+ // If the selection is already here, or in an equivalent position, don't touch it
2478
+ if (force || !domSel.focusNode ||
2479
+ !isEquivalentPosition(anchor.node, anchor.offset, domSel.anchorNode, domSel.anchorOffset) ||
2480
+ !isEquivalentPosition(head.node, head.offset, domSel.focusNode, domSel.focusOffset)) {
2481
+ this.view.observer.ignore(() => {
2482
+ // Chrome Android will hide the virtual keyboard when tapping
2483
+ // inside an uneditable node, and not bring it back when we
2484
+ // move the cursor to its proper position. This tries to
2485
+ // restore the keyboard by cycling focus.
2486
+ if (browser.android && browser.chrome && this.dom.contains(domSel.focusNode) && inUneditable(domSel.focusNode, this.dom)) {
2487
+ this.dom.blur();
2488
+ this.dom.focus({ preventScroll: true });
2489
+ }
2490
+ let rawSel = getSelection(this.root);
2491
+ if (main.empty) {
2492
+ // Work around https://bugzilla.mozilla.org/show_bug.cgi?id=1612076
2493
+ if (browser.gecko) {
2494
+ let nextTo = nextToUneditable(anchor.node, anchor.offset);
2495
+ if (nextTo && nextTo != (1 /* Before */ | 2 /* After */)) {
2496
+ let text = nearbyTextNode(anchor.node, anchor.offset, nextTo == 1 /* Before */ ? 1 : -1);
2497
+ if (text)
2498
+ anchor = new DOMPos(text, nextTo == 1 /* Before */ ? 0 : text.nodeValue.length);
2499
+ }
2500
+ }
2501
+ rawSel.collapse(anchor.node, anchor.offset);
2502
+ if (main.bidiLevel != null && domSel.cursorBidiLevel != null)
2503
+ domSel.cursorBidiLevel = main.bidiLevel;
2504
+ }
2505
+ else if (rawSel.extend) {
2506
+ // Selection.extend can be used to create an 'inverted' selection
2507
+ // (one where the focus is before the anchor), but not all
2508
+ // browsers support it yet.
2509
+ rawSel.collapse(anchor.node, anchor.offset);
2510
+ rawSel.extend(head.node, head.offset);
2511
+ }
2512
+ else {
2513
+ // Primitive (IE) way
2514
+ let range = document.createRange();
2515
+ if (main.anchor > main.head)
2516
+ [anchor, head] = [head, anchor];
2517
+ range.setEnd(head.node, head.offset);
2518
+ range.setStart(anchor.node, anchor.offset);
2519
+ rawSel.removeAllRanges();
2520
+ rawSel.addRange(range);
2521
+ }
2522
+ });
2523
+ this.view.observer.setSelectionRange(anchor, head);
2524
+ }
2525
+ this.impreciseAnchor = anchor.precise ? null : new DOMPos(domSel.anchorNode, domSel.anchorOffset);
2526
+ this.impreciseHead = head.precise ? null : new DOMPos(domSel.focusNode, domSel.focusOffset);
2527
+ }
2528
+ enforceCursorAssoc() {
2529
+ if (this.compositionDeco.size)
2530
+ return;
2531
+ let cursor = this.view.state.selection.main;
2532
+ let sel = getSelection(this.root);
2533
+ if (!cursor.empty || !cursor.assoc || !sel.modify)
2534
+ return;
2535
+ let line = LineView.find(this, cursor.head);
2536
+ if (!line)
2537
+ return;
2538
+ let lineStart = line.posAtStart;
2539
+ if (cursor.head == lineStart || cursor.head == lineStart + line.length)
2540
+ return;
2541
+ let before = this.coordsAt(cursor.head, -1), after = this.coordsAt(cursor.head, 1);
2542
+ if (!before || !after || before.bottom > after.top)
2543
+ return;
2544
+ let dom = this.domAtPos(cursor.head + cursor.assoc);
2545
+ sel.collapse(dom.node, dom.offset);
2546
+ sel.modify("move", cursor.assoc < 0 ? "forward" : "backward", "lineboundary");
2547
+ }
2548
+ mayControlSelection() {
2549
+ return this.view.state.facet(editable) ? this.root.activeElement == this.dom
2550
+ : hasSelection(this.dom, this.view.observer.selectionRange);
2595
2551
  }
2596
- // W5. A sequence of European terminators adjacent to European
2597
- // numbers changes to all European numbers.
2598
- // W6. Otherwise, separators and terminators change to Other
2599
- // Neutral.
2600
- // W7. Search backwards from each instance of a European number
2601
- // until the first strong type (R, L, or sor) is found. If an L is
2602
- // found, then change the type of the European number to L.
2603
- // (Left after this: L, R, EN+AN, NI)
2604
- for (let i = 0, prev = outerType, prevStrong = outerType; i < len; i++) {
2605
- let type = types[i];
2606
- if (type == 128 /* CS */) {
2607
- if (i < len - 1 && prev == types[i + 1] && (prev & 24 /* Num */))
2608
- type = types[i] = prev;
2609
- else
2610
- types[i] = 256 /* NI */;
2552
+ nearest(dom) {
2553
+ for (let cur = dom; cur;) {
2554
+ let domView = ContentView.get(cur);
2555
+ if (domView && domView.rootView == this)
2556
+ return domView;
2557
+ cur = cur.parentNode;
2611
2558
  }
2612
- else if (type == 64 /* ET */) {
2613
- let end = i + 1;
2614
- while (end < len && types[end] == 64 /* ET */)
2615
- end++;
2616
- let replace = (i && prev == 8 /* EN */) || (end < len && types[end] == 8 /* EN */) ? (prevStrong == 1 /* L */ ? 1 /* L */ : 8 /* EN */) : 256 /* NI */;
2617
- for (let j = i; j < end; j++)
2618
- types[j] = replace;
2619
- i = end - 1;
2559
+ return null;
2560
+ }
2561
+ posFromDOM(node, offset) {
2562
+ let view = this.nearest(node);
2563
+ if (!view)
2564
+ throw new RangeError("Trying to find position for a DOM position outside of the document");
2565
+ return view.localPosFromDOM(node, offset) + view.posAtStart;
2566
+ }
2567
+ domAtPos(pos) {
2568
+ let { i, off } = this.childCursor().findPos(pos, -1);
2569
+ for (; i < this.children.length - 1;) {
2570
+ let child = this.children[i];
2571
+ if (off < child.length || child instanceof LineView)
2572
+ break;
2573
+ i++;
2574
+ off = 0;
2620
2575
  }
2621
- else if (type == 8 /* EN */ && prevStrong == 1 /* L */) {
2622
- types[i] = 1 /* L */;
2576
+ return this.children[i].domAtPos(off);
2577
+ }
2578
+ coordsAt(pos, side) {
2579
+ for (let off = this.length, i = this.children.length - 1;; i--) {
2580
+ let child = this.children[i], start = off - child.breakAfter - child.length;
2581
+ if (pos > start ||
2582
+ (pos == start && child.type != exports.BlockType.WidgetBefore && child.type != exports.BlockType.WidgetAfter &&
2583
+ (!i || side == 2 || this.children[i - 1].breakAfter ||
2584
+ (this.children[i - 1].type == exports.BlockType.WidgetBefore && side > -2))))
2585
+ return child.coordsAt(pos - start, side);
2586
+ off = start;
2623
2587
  }
2624
- prev = type;
2625
- if (type & 7 /* Strong */)
2626
- prevStrong = type;
2627
2588
  }
2628
- // N0. Process bracket pairs in an isolating run sequence
2629
- // sequentially in the logical order of the text positions of the
2630
- // opening paired brackets using the logic given below. Within this
2631
- // scope, bidirectional types EN and AN are treated as R.
2632
- for (let i = 0, sI = 0, context = 0, ch, br, type; i < len; i++) {
2633
- // Keeps [startIndex, type, strongSeen] triples for each open
2634
- // bracket on BracketStack.
2635
- if (br = Brackets[ch = line.charCodeAt(i)]) {
2636
- if (br < 0) { // Closing bracket
2637
- for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
2638
- if (BracketStack[sJ + 1] == -br) {
2639
- let flags = BracketStack[sJ + 2];
2640
- let type = (flags & 2 /* EmbedInside */) ? outerType :
2641
- !(flags & 4 /* OppositeInside */) ? 0 :
2642
- (flags & 1 /* OppositeBefore */) ? oppositeType : outerType;
2643
- if (type)
2644
- types[i] = types[BracketStack[sJ]] = type;
2645
- sI = sJ;
2646
- break;
2589
+ measureVisibleLineHeights() {
2590
+ let result = [], { from, to } = this.view.viewState.viewport;
2591
+ let contentWidth = this.view.contentDOM.clientWidth;
2592
+ let isWider = contentWidth > Math.max(this.view.scrollDOM.clientWidth, this.minWidth) + 1;
2593
+ let widest = -1;
2594
+ for (let pos = 0, i = 0; i < this.children.length; i++) {
2595
+ let child = this.children[i], end = pos + child.length;
2596
+ if (end > to)
2597
+ break;
2598
+ if (pos >= from) {
2599
+ let childRect = child.dom.getBoundingClientRect();
2600
+ result.push(childRect.height);
2601
+ if (isWider) {
2602
+ let last = child.dom.lastChild;
2603
+ let rects = last ? clientRectsFor(last) : [];
2604
+ if (rects.length) {
2605
+ let rect = rects[rects.length - 1];
2606
+ let width = this.view.textDirection == exports.Direction.LTR ? rect.right - childRect.left
2607
+ : childRect.right - rect.left;
2608
+ if (width > widest) {
2609
+ widest = width;
2610
+ this.minWidth = contentWidth;
2611
+ this.minWidthFrom = pos;
2612
+ this.minWidthTo = end;
2613
+ }
2647
2614
  }
2648
2615
  }
2649
2616
  }
2650
- else if (BracketStack.length == 189 /* MaxDepth */) {
2651
- break;
2652
- }
2653
- else {
2654
- BracketStack[sI++] = i;
2655
- BracketStack[sI++] = ch;
2656
- BracketStack[sI++] = context;
2657
- }
2617
+ pos = end + child.breakAfter;
2658
2618
  }
2659
- else if ((type = types[i]) == 2 /* R */ || type == 1 /* L */) {
2660
- let embed = type == outerType;
2661
- context = embed ? 0 : 1 /* OppositeBefore */;
2662
- for (let sJ = sI - 3; sJ >= 0; sJ -= 3) {
2663
- let cur = BracketStack[sJ + 2];
2664
- if (cur & 2 /* EmbedInside */)
2665
- break;
2666
- if (embed) {
2667
- BracketStack[sJ + 2] |= 2 /* EmbedInside */;
2668
- }
2669
- else {
2670
- if (cur & 4 /* OppositeInside */)
2671
- break;
2672
- BracketStack[sJ + 2] |= 4 /* OppositeInside */;
2673
- }
2619
+ return result;
2620
+ }
2621
+ measureTextSize() {
2622
+ for (let child of this.children) {
2623
+ if (child instanceof LineView) {
2624
+ let measure = child.measureTextSize();
2625
+ if (measure)
2626
+ return measure;
2674
2627
  }
2675
2628
  }
2629
+ // If no workable line exists, force a layout of a measurable element
2630
+ let dummy = document.createElement("div"), lineHeight, charWidth;
2631
+ dummy.className = "cm-line";
2632
+ dummy.textContent = "abc def ghi jkl mno pqr stu";
2633
+ this.view.observer.ignore(() => {
2634
+ this.dom.appendChild(dummy);
2635
+ let rect = clientRectsFor(dummy.firstChild)[0];
2636
+ lineHeight = dummy.getBoundingClientRect().height;
2637
+ charWidth = rect ? rect.width / 27 : 7;
2638
+ dummy.remove();
2639
+ });
2640
+ return { lineHeight, charWidth };
2676
2641
  }
2677
- // N1. A sequence of neutrals takes the direction of the
2678
- // surrounding strong text if the text on both sides has the same
2679
- // direction. European and Arabic numbers act as if they were R in
2680
- // terms of their influence on neutrals. Start-of-level-run (sor)
2681
- // and end-of-level-run (eor) are used at level run boundaries.
2682
- // N2. Any remaining neutrals take the embedding direction.
2683
- // (Left after this: L, R, EN+AN)
2684
- for (let i = 0; i < len; i++) {
2685
- if (types[i] == 256 /* NI */) {
2686
- let end = i + 1;
2687
- while (end < len && types[end] == 256 /* NI */)
2688
- end++;
2689
- let beforeL = (i ? types[i - 1] : outerType) == 1 /* L */;
2690
- let afterL = (end < len ? types[end] : outerType) == 1 /* L */;
2691
- let replace = beforeL == afterL ? (beforeL ? 1 /* L */ : 2 /* R */) : outerType;
2692
- for (let j = i; j < end; j++)
2693
- types[j] = replace;
2694
- i = end - 1;
2695
- }
2642
+ childCursor(pos = this.length) {
2643
+ // Move back to start of last element when possible, so that
2644
+ // `ChildCursor.findPos` doesn't have to deal with the edge case
2645
+ // of being after the last element.
2646
+ let i = this.children.length;
2647
+ if (i)
2648
+ pos -= this.children[--i].length;
2649
+ return new ChildCursor(this.children, pos, i);
2696
2650
  }
2697
- // Here we depart from the documented algorithm, in order to avoid
2698
- // building up an actual levels array. Since there are only three
2699
- // levels (0, 1, 2) in an implementation that doesn't take
2700
- // explicit embedding into account, we can build up the order on
2701
- // the fly, without following the level-based algorithm.
2702
- let order = [];
2703
- if (outerType == 1 /* L */) {
2704
- for (let i = 0; i < len;) {
2705
- let start = i, rtl = types[i++] != 1 /* L */;
2706
- while (i < len && rtl == (types[i] != 1 /* L */))
2707
- i++;
2708
- if (rtl) {
2709
- for (let j = i; j > start;) {
2710
- let end = j, l = types[--j] != 2 /* R */;
2711
- while (j > start && l == (types[j - 1] != 2 /* R */))
2712
- j--;
2713
- order.push(new BidiSpan(j, end, l ? 2 : 1));
2714
- }
2651
+ computeBlockGapDeco() {
2652
+ let deco = [], vs = this.view.viewState;
2653
+ for (let pos = 0, i = 0;; i++) {
2654
+ let next = i == vs.viewports.length ? null : vs.viewports[i];
2655
+ let end = next ? next.from - 1 : this.length;
2656
+ if (end > pos) {
2657
+ let height = vs.lineBlockAt(end).bottom - vs.lineBlockAt(pos).top;
2658
+ deco.push(Decoration.replace({ widget: new BlockGapWidget(height), block: true, inclusive: true }).range(pos, end));
2715
2659
  }
2716
- else {
2717
- order.push(new BidiSpan(start, i, 0));
2660
+ if (!next)
2661
+ break;
2662
+ pos = next.to + 1;
2663
+ }
2664
+ return Decoration.set(deco);
2665
+ }
2666
+ updateDeco() {
2667
+ return this.decorations = [
2668
+ ...this.view.pluginField(PluginField.decorations),
2669
+ ...this.view.state.facet(decorations),
2670
+ this.compositionDeco,
2671
+ this.computeBlockGapDeco(),
2672
+ this.view.viewState.lineGapDeco
2673
+ ];
2674
+ }
2675
+ scrollIntoView({ range, center }) {
2676
+ let rect = this.coordsAt(range.head, range.empty ? range.assoc : range.head > range.anchor ? -1 : 1), other;
2677
+ if (!rect)
2678
+ return;
2679
+ if (!range.empty && (other = this.coordsAt(range.anchor, range.anchor > range.head ? -1 : 1)))
2680
+ rect = { left: Math.min(rect.left, other.left), top: Math.min(rect.top, other.top),
2681
+ right: Math.max(rect.right, other.right), bottom: Math.max(rect.bottom, other.bottom) };
2682
+ let mLeft = 0, mRight = 0, mTop = 0, mBottom = 0;
2683
+ for (let margins of this.view.pluginField(PluginField.scrollMargins))
2684
+ if (margins) {
2685
+ let { left, right, top, bottom } = margins;
2686
+ if (left != null)
2687
+ mLeft = Math.max(mLeft, left);
2688
+ if (right != null)
2689
+ mRight = Math.max(mRight, right);
2690
+ if (top != null)
2691
+ mTop = Math.max(mTop, top);
2692
+ if (bottom != null)
2693
+ mBottom = Math.max(mBottom, bottom);
2718
2694
  }
2719
- }
2695
+ scrollRectIntoView(this.view.scrollDOM, {
2696
+ left: rect.left - mLeft, top: rect.top - mTop,
2697
+ right: rect.right + mRight, bottom: rect.bottom + mBottom
2698
+ }, range.head < range.anchor ? -1 : 1, center);
2699
+ }
2700
+ }
2701
+ function betweenUneditable(pos) {
2702
+ return pos.node.nodeType == 1 && pos.node.firstChild &&
2703
+ (pos.offset == 0 || pos.node.childNodes[pos.offset - 1].contentEditable == "false") &&
2704
+ (pos.offset == pos.node.childNodes.length || pos.node.childNodes[pos.offset].contentEditable == "false");
2705
+ }
2706
+ class BlockGapWidget extends WidgetType {
2707
+ constructor(height) {
2708
+ super();
2709
+ this.height = height;
2710
+ }
2711
+ toDOM() {
2712
+ let elt = document.createElement("div");
2713
+ this.updateDOM(elt);
2714
+ return elt;
2715
+ }
2716
+ eq(other) { return other.height == this.height; }
2717
+ updateDOM(elt) {
2718
+ elt.style.height = this.height + "px";
2719
+ return true;
2720
+ }
2721
+ get estimatedHeight() { return this.height; }
2722
+ }
2723
+ function computeCompositionDeco(view, changes) {
2724
+ let sel = view.observer.selectionRange;
2725
+ let textNode = sel.focusNode && nearbyTextNode(sel.focusNode, sel.focusOffset, 0);
2726
+ if (!textNode)
2727
+ return Decoration.none;
2728
+ let cView = view.docView.nearest(textNode);
2729
+ if (!cView)
2730
+ return Decoration.none;
2731
+ let from, to, topNode = textNode;
2732
+ if (cView instanceof LineView) {
2733
+ while (topNode.parentNode != cView.dom)
2734
+ topNode = topNode.parentNode;
2735
+ let prev = topNode.previousSibling;
2736
+ while (prev && !ContentView.get(prev))
2737
+ prev = prev.previousSibling;
2738
+ from = to = prev ? ContentView.get(prev).posAtEnd : cView.posAtStart;
2720
2739
  }
2721
2740
  else {
2722
- for (let i = 0; i < len;) {
2723
- let start = i, rtl = types[i++] == 2 /* R */;
2724
- while (i < len && rtl == (types[i] == 2 /* R */))
2725
- i++;
2726
- order.push(new BidiSpan(start, i, rtl ? 1 : 2));
2741
+ for (;;) {
2742
+ let { parent } = cView;
2743
+ if (!parent)
2744
+ return Decoration.none;
2745
+ if (parent instanceof LineView)
2746
+ break;
2747
+ cView = parent;
2727
2748
  }
2749
+ from = cView.posAtStart;
2750
+ to = from + cView.length;
2751
+ topNode = cView.dom;
2728
2752
  }
2729
- return order;
2753
+ let newFrom = changes.mapPos(from, 1), newTo = Math.max(newFrom, changes.mapPos(to, -1));
2754
+ let { state } = view, text = topNode.nodeType == 3 ? topNode.nodeValue :
2755
+ new DOMReader([], view).readRange(topNode.firstChild, null).text;
2756
+ if (newTo - newFrom < text.length) {
2757
+ if (state.sliceDoc(newFrom, Math.min(state.doc.length, newFrom + text.length)) == text)
2758
+ newTo = newFrom + text.length;
2759
+ else if (state.sliceDoc(Math.max(0, newTo - text.length), newTo) == text)
2760
+ newFrom = newTo - text.length;
2761
+ else
2762
+ return Decoration.none;
2763
+ }
2764
+ else if (state.sliceDoc(newFrom, newTo) != text) {
2765
+ return Decoration.none;
2766
+ }
2767
+ return Decoration.set(Decoration.replace({ widget: new CompositionWidget(topNode, textNode) }).range(newFrom, newTo));
2730
2768
  }
2731
- function trivialOrder(length) {
2732
- return [new BidiSpan(0, length, 0)];
2769
+ class CompositionWidget extends WidgetType {
2770
+ constructor(top, text) {
2771
+ super();
2772
+ this.top = top;
2773
+ this.text = text;
2774
+ }
2775
+ eq(other) { return this.top == other.top && this.text == other.text; }
2776
+ toDOM() { return this.top; }
2777
+ ignoreEvent() { return false; }
2778
+ get customView() { return CompositionView; }
2733
2779
  }
2734
- let movedOver = "";
2735
- function moveVisually(line, order, dir, start, forward) {
2736
- var _a;
2737
- let startIndex = start.head - line.from, spanI = -1;
2738
- if (startIndex == 0) {
2739
- if (!forward || !line.length)
2740
- return null;
2741
- if (order[0].level != dir) {
2742
- startIndex = order[0].side(false, dir);
2743
- spanI = 0;
2780
+ function nearbyTextNode(node, offset, side) {
2781
+ for (;;) {
2782
+ if (node.nodeType == 3)
2783
+ return node;
2784
+ if (node.nodeType == 1 && offset > 0 && side <= 0) {
2785
+ node = node.childNodes[offset - 1];
2786
+ offset = maxOffset(node);
2744
2787
  }
2745
- }
2746
- else if (startIndex == line.length) {
2747
- if (forward)
2788
+ else if (node.nodeType == 1 && offset < node.childNodes.length && side >= 0) {
2789
+ node = node.childNodes[offset];
2790
+ offset = 0;
2791
+ }
2792
+ else {
2748
2793
  return null;
2749
- let last = order[order.length - 1];
2750
- if (last.level != dir) {
2751
- startIndex = last.side(true, dir);
2752
- spanI = order.length - 1;
2753
2794
  }
2754
2795
  }
2755
- if (spanI < 0)
2756
- spanI = BidiSpan.find(order, startIndex, (_a = start.bidiLevel) !== null && _a !== void 0 ? _a : -1, start.assoc);
2757
- let span = order[spanI];
2758
- // End of span. (But not end of line--that was checked for above.)
2759
- if (startIndex == span.side(forward, dir)) {
2760
- span = order[spanI += forward ? 1 : -1];
2761
- startIndex = span.side(!forward, dir);
2796
+ }
2797
+ function nextToUneditable(node, offset) {
2798
+ if (node.nodeType != 1)
2799
+ return 0;
2800
+ return (offset && node.childNodes[offset - 1].contentEditable == "false" ? 1 /* Before */ : 0) |
2801
+ (offset < node.childNodes.length && node.childNodes[offset].contentEditable == "false" ? 2 /* After */ : 0);
2802
+ }
2803
+ class DecorationComparator$1 {
2804
+ constructor() {
2805
+ this.changes = [];
2762
2806
  }
2763
- let indexForward = forward == (span.dir == dir);
2764
- let nextIndex = text.findClusterBreak(line.text, startIndex, indexForward);
2765
- movedOver = line.text.slice(Math.min(startIndex, nextIndex), Math.max(startIndex, nextIndex));
2766
- if (nextIndex != span.side(forward, dir))
2767
- return state.EditorSelection.cursor(nextIndex + line.from, indexForward ? -1 : 1, span.level);
2768
- let nextSpan = spanI == (forward ? order.length - 1 : 0) ? null : order[spanI + (forward ? 1 : -1)];
2769
- if (!nextSpan && span.level != dir)
2770
- return state.EditorSelection.cursor(forward ? line.to : line.from, forward ? -1 : 1, dir);
2771
- if (nextSpan && nextSpan.level < span.level)
2772
- return state.EditorSelection.cursor(nextSpan.side(!forward, dir) + line.from, forward ? 1 : -1, nextSpan.level);
2773
- return state.EditorSelection.cursor(nextIndex + line.from, forward ? -1 : 1, span.level);
2807
+ compareRange(from, to) { addRange(from, to, this.changes); }
2808
+ comparePoint(from, to) { addRange(from, to, this.changes); }
2809
+ }
2810
+ function findChangedDeco(a, b, diff) {
2811
+ let comp = new DecorationComparator$1;
2812
+ rangeset.RangeSet.compare(a, b, diff, comp);
2813
+ return comp.changes;
2814
+ }
2815
+ function inUneditable(node, inside) {
2816
+ for (let cur = node; cur && cur != inside; cur = cur.assignedSlot || cur.parentNode) {
2817
+ if (cur.nodeType == 1 && cur.contentEditable == 'false') {
2818
+ return true;
2819
+ }
2820
+ }
2821
+ return false;
2774
2822
  }
2775
2823
 
2776
2824
  function groupAt(state$1, pos, bias = 1) {
@@ -2908,21 +2956,29 @@ function domPosInText(node, x, y) {
2908
2956
  function posAtCoords(view, { x, y }, precise, bias = -1) {
2909
2957
  var _a;
2910
2958
  let content = view.contentDOM.getBoundingClientRect(), docTop = content.top + view.viewState.paddingTop;
2911
- let halfLine = view.defaultLineHeight / 2;
2912
- let block, yOffset = y - docTop;
2913
- for (let bounced = false;;) {
2959
+ let block, yOffset = y - docTop, { docHeight } = view.viewState;
2960
+ if (yOffset < 0 || yOffset > docHeight) {
2961
+ if (precise)
2962
+ return null;
2963
+ yOffset = yOffset < 0 ? 0 : docHeight;
2964
+ }
2965
+ // Scan for a text block near the queried y position
2966
+ for (let halfLine = view.defaultLineHeight / 2, bounced = false;;) {
2914
2967
  block = view.elementAtHeight(yOffset);
2915
- if (block.top > yOffset || block.bottom < yOffset) {
2916
- bias = block.top > yOffset ? -1 : 1;
2917
- yOffset = Math.min(block.bottom - halfLine, Math.max(block.top + halfLine, yOffset));
2968
+ if (block.type == exports.BlockType.Text)
2969
+ break;
2970
+ for (;;) {
2971
+ // Move the y position out of this block
2972
+ yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
2973
+ if (yOffset >= 0 && yOffset <= docHeight)
2974
+ break;
2975
+ // If the document consists entirely of replaced widgets, we
2976
+ // won't find a text block, so return 0
2918
2977
  if (bounced)
2919
2978
  return precise ? null : 0;
2920
- else
2921
- bounced = true;
2979
+ bounced = true;
2980
+ bias = -bias;
2922
2981
  }
2923
- if (block.type == exports.BlockType.Text)
2924
- break;
2925
- yOffset = bias > 0 ? block.bottom + halfLine : block.top - halfLine;
2926
2982
  }
2927
2983
  y = docTop + yOffset;
2928
2984
  let lineStart = block.from;
@@ -3263,10 +3319,10 @@ class InputState {
3263
3319
  return (event.type == "keydown" && event.keyCode != 229) ||
3264
3320
  event.type == "compositionend" && !browser.ios;
3265
3321
  }
3266
- startMouseSelection(view, event, style) {
3322
+ startMouseSelection(mouseSelection) {
3267
3323
  if (this.mouseSelection)
3268
3324
  this.mouseSelection.destroy();
3269
- this.mouseSelection = new MouseSelection(this, view, event, style);
3325
+ this.mouseSelection = mouseSelection;
3270
3326
  }
3271
3327
  update(update) {
3272
3328
  if (this.mouseSelection)
@@ -3287,10 +3343,10 @@ const PendingKeys = [
3287
3343
  // Key codes for modifier keys
3288
3344
  const modifierCodes = [16, 17, 18, 20, 91, 92, 224, 225];
3289
3345
  class MouseSelection {
3290
- constructor(inputState, view, startEvent, style) {
3291
- this.inputState = inputState;
3346
+ constructor(view, startEvent, style, mustSelect) {
3292
3347
  this.view = view;
3293
3348
  this.style = style;
3349
+ this.mustSelect = mustSelect;
3294
3350
  this.lastEvent = startEvent;
3295
3351
  let doc = view.contentDOM.ownerDocument;
3296
3352
  doc.addEventListener("mousemove", this.move = this.move.bind(this));
@@ -3324,16 +3380,18 @@ class MouseSelection {
3324
3380
  let doc = this.view.contentDOM.ownerDocument;
3325
3381
  doc.removeEventListener("mousemove", this.move);
3326
3382
  doc.removeEventListener("mouseup", this.up);
3327
- this.inputState.mouseSelection = null;
3383
+ this.view.inputState.mouseSelection = null;
3328
3384
  }
3329
3385
  select(event) {
3330
3386
  let selection = this.style.get(event, this.extend, this.multiple);
3331
- if (!selection.eq(this.view.state.selection) || selection.main.assoc != this.view.state.selection.main.assoc)
3387
+ if (this.mustSelect || !selection.eq(this.view.state.selection) ||
3388
+ selection.main.assoc != this.view.state.selection.main.assoc)
3332
3389
  this.view.dispatch({
3333
3390
  selection,
3334
3391
  userEvent: "select.pointer",
3335
3392
  scrollIntoView: true
3336
3393
  });
3394
+ this.mustSelect = false;
3337
3395
  }
3338
3396
  update(update) {
3339
3397
  if (update.docChanged && this.dragging)
@@ -3452,9 +3510,10 @@ handlers.mousedown = (view, event) => {
3452
3510
  if (!style && event.button == 0)
3453
3511
  style = basicMouseSelection(view, event);
3454
3512
  if (style) {
3455
- if (view.root.activeElement != view.contentDOM)
3513
+ let mustFocus = view.root.activeElement != view.contentDOM;
3514
+ if (mustFocus)
3456
3515
  view.observer.ignore(() => focusPreventScroll(view.contentDOM));
3457
- view.inputState.startMouseSelection(view, event, style);
3516
+ view.inputState.startMouseSelection(new MouseSelection(view, event, style, mustFocus));
3458
3517
  }
3459
3518
  };
3460
3519
  function rangeForClick(view, pos, bias, type) {
@@ -4170,12 +4229,12 @@ class HeightMapBranch extends HeightMap {
4170
4229
  get break() { return this.flags & 1 /* Break */; }
4171
4230
  blockAt(height, doc, top, offset) {
4172
4231
  let mid = top + this.left.height;
4173
- return height < mid || this.right.height == 0 ? this.left.blockAt(height, doc, top, offset)
4232
+ return height < mid ? this.left.blockAt(height, doc, top, offset)
4174
4233
  : this.right.blockAt(height, doc, mid, offset + this.left.length + this.break);
4175
4234
  }
4176
4235
  lineAt(value, type, doc, top, offset) {
4177
4236
  let rightTop = top + this.left.height, rightOffset = offset + this.left.length + this.break;
4178
- let left = type == QueryType.ByHeight ? value < rightTop || this.right.height == 0 : value < rightOffset;
4237
+ let left = type == QueryType.ByHeight ? value < rightTop : value < rightOffset;
4179
4238
  let base = left ? this.left.lineAt(value, type, doc, top, offset)
4180
4239
  : this.right.lineAt(value, type, doc, rightTop, rightOffset);
4181
4240
  if (this.break || (left ? base.to < rightOffset : base.from > rightOffset))
@@ -4316,7 +4375,9 @@ class NodeBuilder {
4316
4375
  }
4317
4376
  point(from, to, deco) {
4318
4377
  if (from < to || deco.heightRelevant) {
4319
- let height = deco.widget ? Math.max(0, deco.widget.estimatedHeight) : 0;
4378
+ let height = deco.widget ? deco.widget.estimatedHeight : 0;
4379
+ if (height < 0)
4380
+ height = this.oracle.lineHeight;
4320
4381
  let len = to - from;
4321
4382
  if (deco.block) {
4322
4383
  this.addBlock(new HeightMapBlock(len, height, deco.type));
@@ -4444,8 +4505,8 @@ function visiblePixelRange(dom, paddingTop) {
4444
4505
  break;
4445
4506
  }
4446
4507
  }
4447
- return { left: left - rect.left, right: right - rect.left,
4448
- top: top - (rect.top + paddingTop), bottom: bottom - (rect.top + paddingTop) };
4508
+ return { left: left - rect.left, right: Math.max(left, right) - rect.left,
4509
+ top: top - (rect.top + paddingTop), bottom: Math.max(top, bottom) - (rect.top + paddingTop) };
4449
4510
  }
4450
4511
  // Line gaps are placeholder widgets used to hide pieces of overlong
4451
4512
  // lines within the viewport, as a kludge to keep the editor
@@ -4672,7 +4733,7 @@ class ViewState {
4672
4733
  let viewport = new Viewport(map.lineAt(visibleTop - marginTop * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).from, map.lineAt(visibleBottom + (1 - marginTop) * 1000 /* Margin */, QueryType.ByHeight, doc, 0, 0).to);
4673
4734
  // If scrollTarget is given, make sure the viewport includes that position
4674
4735
  if (scrollTarget) {
4675
- let { head } = scrollTarget.range, viewHeight = visibleBottom - visibleTop;
4736
+ let { head } = scrollTarget.range, viewHeight = this.editorHeight;
4676
4737
  if (head < viewport.from || head > viewport.to) {
4677
4738
  let block = map.lineAt(head, QueryType.ByPos, doc, 0, 0), topPos;
4678
4739
  if (scrollTarget.center)
@@ -4693,6 +4754,8 @@ class ViewState {
4693
4754
  // Checks if a given viewport covers the visible part of the
4694
4755
  // document and not too much beyond that.
4695
4756
  viewportIsAppropriate({ from, to }, bias = 0) {
4757
+ if (!this.inView)
4758
+ return true;
4696
4759
  let { top } = this.heightMap.lineAt(from, QueryType.ByPos, this.state.doc, 0, 0);
4697
4760
  let { bottom } = this.heightMap.lineAt(to, QueryType.ByPos, this.state.doc, 0, 0);
4698
4761
  let { visibleTop, visibleBottom } = this;
@@ -4799,8 +4862,11 @@ class ViewState {
4799
4862
  elementAtHeight(height) {
4800
4863
  return scaleBlock(this.heightMap.blockAt(this.scaler.fromDOM(height), this.state.doc, 0, 0), this.scaler);
4801
4864
  }
4865
+ get docHeight() {
4866
+ return this.scaler.toDOM(this.heightMap.height);
4867
+ }
4802
4868
  get contentHeight() {
4803
- return this.scaler.toDOM(this.heightMap.height) + this.paddingTop + this.paddingBottom;
4869
+ return this.docHeight + this.paddingTop + this.paddingBottom;
4804
4870
  }
4805
4871
  }
4806
4872
  class Viewport {
@@ -5054,7 +5120,8 @@ const baseTheme = buildTheme("." + baseThemeID, {
5054
5120
  },
5055
5121
  ".cm-placeholder": {
5056
5122
  color: "#888",
5057
- display: "inline-block"
5123
+ display: "inline-block",
5124
+ verticalAlign: "top",
5058
5125
  },
5059
5126
  ".cm-button": {
5060
5127
  verticalAlign: "middle",
@@ -5352,7 +5419,7 @@ class DOMObserver {
5352
5419
  this.onChange(from, to, typeOver);
5353
5420
  // The view wasn't updated
5354
5421
  if (this.view.state == startState)
5355
- this.view.docView.reset(newSel);
5422
+ this.view.update([]);
5356
5423
  }
5357
5424
  readMutation(rec) {
5358
5425
  let cView = this.view.docView.nearest(rec.target);
@@ -5483,11 +5550,22 @@ function applyDOMChange(view, start, end, typeOver) {
5483
5550
  };
5484
5551
  if (change) {
5485
5552
  let startState = view.state;
5553
+ if (browser.ios && view.inputState.flushIOSKey(view))
5554
+ return;
5486
5555
  // Android browsers don't fire reasonable key events for enter,
5487
5556
  // backspace, or delete. So this detects changes that look like
5488
5557
  // they're caused by those keys, and reinterprets them as key
5489
- // events.
5490
- if (browser.ios && view.inputState.flushIOSKey(view))
5558
+ // events. (Some of these keys are also handled by beforeinput
5559
+ // events and the pendingAndroidKey mechanism, but that's not
5560
+ // reliable in all situations.)
5561
+ if (browser.android &&
5562
+ ((change.from == sel.from && change.to == sel.to &&
5563
+ change.insert.length == 1 && change.insert.lines == 2 &&
5564
+ dispatchKey(view.contentDOM, "Enter", 13)) ||
5565
+ (change.from == sel.from - 1 && change.to == sel.to && change.insert.length == 0 &&
5566
+ dispatchKey(view.contentDOM, "Backspace", 8)) ||
5567
+ (change.from == sel.from && change.to == sel.to + 1 && change.insert.length == 0 &&
5568
+ dispatchKey(view.contentDOM, "Delete", 46))))
5491
5569
  return;
5492
5570
  let text = change.insert.toString();
5493
5571
  if (view.state.facet(inputHandler).some(h => h(view, change.from, change.to, text)))
@@ -5560,76 +5638,6 @@ function findDiff(a, b, preferredPos, preferredSide) {
5560
5638
  }
5561
5639
  return { from, toA, toB };
5562
5640
  }
5563
- class DOMReader {
5564
- constructor(points, view) {
5565
- this.points = points;
5566
- this.view = view;
5567
- this.text = "";
5568
- this.lineBreak = view.state.lineBreak;
5569
- }
5570
- readRange(start, end) {
5571
- if (!start)
5572
- return;
5573
- let parent = start.parentNode;
5574
- for (let cur = start;;) {
5575
- this.findPointBefore(parent, cur);
5576
- this.readNode(cur);
5577
- let next = cur.nextSibling;
5578
- if (next == end)
5579
- break;
5580
- let view = ContentView.get(cur), nextView = ContentView.get(next);
5581
- if (view && nextView ? view.breakAfter :
5582
- (view ? view.breakAfter : isBlockElement(cur)) ||
5583
- (isBlockElement(next) && (cur.nodeName != "BR" || cur.cmIgnore)))
5584
- this.text += this.lineBreak;
5585
- cur = next;
5586
- }
5587
- this.findPointBefore(parent, end);
5588
- }
5589
- readNode(node) {
5590
- if (node.cmIgnore)
5591
- return;
5592
- let view = ContentView.get(node);
5593
- let fromView = view && view.overrideDOMText;
5594
- let text;
5595
- if (fromView != null)
5596
- text = fromView.sliceString(0, undefined, this.lineBreak);
5597
- else if (node.nodeType == 3)
5598
- text = node.nodeValue;
5599
- else if (node.nodeName == "BR")
5600
- text = node.nextSibling ? this.lineBreak : "";
5601
- else if (node.nodeType == 1)
5602
- this.readRange(node.firstChild, null);
5603
- if (text != null) {
5604
- this.findPointIn(node, text.length);
5605
- this.text += text;
5606
- // Chrome inserts two newlines when pressing shift-enter at the
5607
- // end of a line. This drops one of those.
5608
- if (browser.chrome && this.view.inputState.lastKeyCode == 13 && !node.nextSibling && /\n\n$/.test(this.text))
5609
- this.text = this.text.slice(0, -1);
5610
- }
5611
- }
5612
- findPointBefore(node, next) {
5613
- for (let point of this.points)
5614
- if (point.node == node && node.childNodes[point.offset] == next)
5615
- point.pos = this.text.length;
5616
- }
5617
- findPointIn(node, maxLen) {
5618
- for (let point of this.points)
5619
- if (point.node == node)
5620
- point.pos = this.text.length + Math.min(point.offset, maxLen);
5621
- }
5622
- }
5623
- function isBlockElement(node) {
5624
- return node.nodeType == 1 && /^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(node.nodeName);
5625
- }
5626
- class DOMPoint {
5627
- constructor(node, offset) {
5628
- this.node = node;
5629
- this.offset = offset;
5630
- this.pos = -1;
5631
- }
5632
- }
5633
5641
  function selectionPoints(view) {
5634
5642
  let result = [];
5635
5643
  if (view.root.activeElement != view.contentDOM)
@@ -5712,7 +5720,9 @@ class EditorView {
5712
5720
  this.dispatch = this.dispatch.bind(this);
5713
5721
  this.root = (config.root || getRoot(config.parent) || document);
5714
5722
  this.viewState = new ViewState(config.state || state.EditorState.create());
5715
- this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
5723
+ this.plugins = this.state.facet(viewPlugin).map(spec => new PluginInstance(spec));
5724
+ for (let plugin of this.plugins)
5725
+ plugin.update(this);
5716
5726
  this.observer = new DOMObserver(this, (from, to, typeOver) => {
5717
5727
  applyDOMChange(this, from, to, typeOver);
5718
5728
  }, event => {
@@ -5849,8 +5859,10 @@ class EditorView {
5849
5859
  for (let plugin of this.plugins)
5850
5860
  plugin.destroy(this);
5851
5861
  this.viewState = new ViewState(newState);
5852
- this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec).update(this));
5862
+ this.plugins = newState.facet(viewPlugin).map(spec => new PluginInstance(spec));
5853
5863
  this.pluginMap.clear();
5864
+ for (let plugin of this.plugins)
5865
+ plugin.update(this);
5854
5866
  this.docView = new DocView(this);
5855
5867
  this.inputState.ensureHandlers(this);
5856
5868
  this.mountStyles();
@@ -5911,7 +5923,9 @@ class EditorView {
5911
5923
  if (!changed && !this.measureRequests.length && this.viewState.scrollTarget == null)
5912
5924
  break;
5913
5925
  if (i > 5) {
5914
- console.warn(this.measureRequests.length ? "Measure loop restarted more than 5 times" : "Viewport failed to stabilize");
5926
+ console.warn(this.measureRequests.length
5927
+ ? "Measure loop restarted more than 5 times"
5928
+ : "Viewport failed to stabilize");
5915
5929
  break;
5916
5930
  }
5917
5931
  let measuring = [];
@@ -5957,7 +5971,8 @@ class EditorView {
5957
5971
  }
5958
5972
  if (redrawn)
5959
5973
  this.docView.updateSelection(true);
5960
- if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to && this.measureRequests.length == 0)
5974
+ if (this.viewport.from == oldViewport.from && this.viewport.to == oldViewport.to &&
5975
+ this.measureRequests.length == 0)
5961
5976
  break;
5962
5977
  }
5963
5978
  }
@@ -6249,6 +6264,11 @@ class EditorView {
6249
6264
  Find the DOM parent node and offset (child offset if `node` is
6250
6265
  an element, character offset when it is a text node) at the
6251
6266
  given document position.
6267
+
6268
+ Note that for positions that aren't currently in
6269
+ `visibleRanges`, the resulting DOM position isn't necessarily
6270
+ meaningful (it may just point before or after a placeholder
6271
+ element).
6252
6272
  */
6253
6273
  domAtPos(pos) {
6254
6274
  return this.docView.domAtPos(pos);
@@ -7310,9 +7330,7 @@ const __test = { HeightMap, HeightOracle, MeasuredHeights, QueryType, ChangedRan
7310
7330
 
7311
7331
  Object.defineProperty(exports, 'Range', {
7312
7332
  enumerable: true,
7313
- get: function () {
7314
- return rangeset.Range;
7315
- }
7333
+ get: function () { return rangeset.Range; }
7316
7334
  });
7317
7335
  exports.BidiSpan = BidiSpan;
7318
7336
  exports.BlockInfo = BlockInfo;