sqlui 0.1.54 → 0.1.55

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.
@@ -4124,7 +4124,6 @@
4124
4124
  };
4125
4125
 
4126
4126
  var chrome$1 = typeof navigator != "undefined" && /Chrome\/(\d+)/.exec(navigator.userAgent);
4127
- typeof navigator != "undefined" && /Gecko\/\d+/.test(navigator.userAgent);
4128
4127
  var mac = typeof navigator != "undefined" && /Mac/.test(navigator.platform);
4129
4128
  var ie$1 = typeof navigator != "undefined" && /MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);
4130
4129
  var brokenModifierNames = mac || chrome$1 && +chrome$1[1] < 57;
@@ -5758,6 +5757,7 @@
5758
5757
  this.curLine = null;
5759
5758
  this.breakAtStart = 0;
5760
5759
  this.pendingBuffer = 0 /* Buf.No */;
5760
+ this.bufferMarks = [];
5761
5761
  // Set to false directly after a widget that covers the position after it
5762
5762
  this.atCursorPos = true;
5763
5763
  this.openStart = -1;
@@ -5780,20 +5780,20 @@
5780
5780
  }
5781
5781
  return this.curLine;
5782
5782
  }
5783
- flushBuffer(active) {
5783
+ flushBuffer(active = this.bufferMarks) {
5784
5784
  if (this.pendingBuffer) {
5785
5785
  this.curLine.append(wrapMarks(new WidgetBufferView(-1), active), active.length);
5786
5786
  this.pendingBuffer = 0 /* Buf.No */;
5787
5787
  }
5788
5788
  }
5789
5789
  addBlockWidget(view) {
5790
- this.flushBuffer([]);
5790
+ this.flushBuffer();
5791
5791
  this.curLine = null;
5792
5792
  this.content.push(view);
5793
5793
  }
5794
5794
  finish(openEnd) {
5795
- if (!openEnd)
5796
- this.flushBuffer([]);
5795
+ if (this.pendingBuffer && openEnd <= this.bufferMarks.length)
5796
+ this.flushBuffer();
5797
5797
  else
5798
5798
  this.pendingBuffer = 0 /* Buf.No */;
5799
5799
  if (!this.posCovered())
@@ -5813,8 +5813,9 @@
5813
5813
  this.content[this.content.length - 1].breakAfter = 1;
5814
5814
  else
5815
5815
  this.breakAtStart = 1;
5816
- this.flushBuffer([]);
5816
+ this.flushBuffer();
5817
5817
  this.curLine = null;
5818
+ this.atCursorPos = true;
5818
5819
  length--;
5819
5820
  continue;
5820
5821
  }
@@ -5856,7 +5857,7 @@
5856
5857
  else {
5857
5858
  let view = WidgetView.create(deco.widget || new NullWidget("span"), len, len ? 0 : deco.startSide);
5858
5859
  let cursorBefore = this.atCursorPos && !view.isEditable && openStart <= active.length && (from < to || deco.startSide > 0);
5859
- let cursorAfter = !view.isEditable && (from < to || deco.startSide <= 0);
5860
+ let cursorAfter = !view.isEditable && (from < to || openStart > active.length || deco.startSide <= 0);
5860
5861
  let line = this.getLine();
5861
5862
  if (this.pendingBuffer == 2 /* Buf.IfCursor */ && !cursorBefore)
5862
5863
  this.pendingBuffer = 0 /* Buf.No */;
@@ -5867,7 +5868,9 @@
5867
5868
  }
5868
5869
  line.append(wrapMarks(view, active), openStart);
5869
5870
  this.atCursorPos = cursorAfter;
5870
- this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
5871
+ this.pendingBuffer = !cursorAfter ? 0 /* Buf.No */ : from < to || openStart > active.length ? 1 /* Buf.Yes */ : 2 /* Buf.IfCursor */;
5872
+ if (this.pendingBuffer)
5873
+ this.bufferMarks = active.slice();
5871
5874
  }
5872
5875
  }
5873
5876
  else if (this.doc.lineAt(this.pos).from == this.pos) { // Line decoration
@@ -9444,7 +9447,6 @@
9444
9447
  margin: 0,
9445
9448
  flexGrow: 2,
9446
9449
  flexShrink: 0,
9447
- minHeight: "100%",
9448
9450
  display: "block",
9449
9451
  whiteSpace: "pre",
9450
9452
  wordWrap: "normal",
@@ -9466,14 +9468,13 @@
9466
9468
  "&dark .cm-content": { caretColor: "white" },
9467
9469
  ".cm-line": {
9468
9470
  display: "block",
9469
- padding: "0 2px 0 4px"
9470
- },
9471
- ".cm-selectionLayer": {
9472
- zIndex: -1,
9473
- contain: "size style"
9471
+ padding: "0 2px 0 6px"
9474
9472
  },
9475
- ".cm-selectionBackground": {
9476
- position: "absolute",
9473
+ ".cm-layer": {
9474
+ contain: "size style",
9475
+ "& > *": {
9476
+ position: "absolute"
9477
+ }
9477
9478
  },
9478
9479
  "&light .cm-selectionBackground": {
9479
9480
  background: "#d9d9d9"
@@ -9488,8 +9489,6 @@
9488
9489
  background: "#233"
9489
9490
  },
9490
9491
  ".cm-cursorLayer": {
9491
- zIndex: 100,
9492
- contain: "size style",
9493
9492
  pointerEvents: "none"
9494
9493
  },
9495
9494
  "&.cm-focused .cm-cursorLayer": {
@@ -9501,7 +9500,6 @@
9501
9500
  "@keyframes cm-blink": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
9502
9501
  "@keyframes cm-blink2": { "0%": {}, "50%": { opacity: 0 }, "100%": {} },
9503
9502
  ".cm-cursor, .cm-dropCursor": {
9504
- position: "absolute",
9505
9503
  borderLeft: "1.2px solid black",
9506
9504
  marginLeft: "-0.6px",
9507
9505
  pointerEvents: "none",
@@ -9595,6 +9593,21 @@
9595
9593
  display: "inline-block",
9596
9594
  verticalAlign: "top",
9597
9595
  },
9596
+ ".cm-highlightSpace:before": {
9597
+ content: "attr(data-display)",
9598
+ position: "absolute",
9599
+ pointerEvents: "none",
9600
+ color: "#888"
9601
+ },
9602
+ ".cm-highlightTab": {
9603
+ backgroundImage: `url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="200" height="20"><path stroke="%23888" stroke-width="1" fill="none" d="M1 10H196L190 5M190 15L196 10M197 4L197 16"/></svg>')`,
9604
+ backgroundSize: "auto 100%",
9605
+ backgroundPosition: "right 90%",
9606
+ backgroundRepeat: "no-repeat"
9607
+ },
9608
+ ".cm-trailingSpace": {
9609
+ backgroundColor: "#ff332255"
9610
+ },
9598
9611
  ".cm-button": {
9599
9612
  verticalAlign: "middle",
9600
9613
  color: "inherit",
@@ -9897,7 +9910,8 @@
9897
9910
  this.lastChange = 0;
9898
9911
  this.scrollTargets = [];
9899
9912
  this.intersection = null;
9900
- this.resize = null;
9913
+ this.resizeScroll = null;
9914
+ this.resizeContent = null;
9901
9915
  this.intersecting = false;
9902
9916
  this.gapIntersection = null;
9903
9917
  this.gaps = [];
@@ -9935,12 +9949,14 @@
9935
9949
  this.onPrint = this.onPrint.bind(this);
9936
9950
  this.onScroll = this.onScroll.bind(this);
9937
9951
  if (typeof ResizeObserver == "function") {
9938
- this.resize = new ResizeObserver(() => {
9952
+ this.resizeScroll = new ResizeObserver(() => {
9939
9953
  var _a;
9940
9954
  if (((_a = this.view.docView) === null || _a === void 0 ? void 0 : _a.lastUpdate) < Date.now() - 75)
9941
9955
  this.onResize();
9942
9956
  });
9943
- this.resize.observe(view.scrollDOM);
9957
+ this.resizeScroll.observe(view.scrollDOM);
9958
+ this.resizeContent = new ResizeObserver(() => this.view.requestMeasure());
9959
+ this.resizeContent.observe(view.contentDOM);
9944
9960
  }
9945
9961
  this.addWindowListeners(this.win = view.win);
9946
9962
  this.start();
@@ -10259,11 +10275,12 @@
10259
10275
  win.document.removeEventListener("selectionchange", this.onSelectionChange);
10260
10276
  }
10261
10277
  destroy() {
10262
- var _a, _b, _c;
10278
+ var _a, _b, _c, _d;
10263
10279
  this.stop();
10264
10280
  (_a = this.intersection) === null || _a === void 0 ? void 0 : _a.disconnect();
10265
10281
  (_b = this.gapIntersection) === null || _b === void 0 ? void 0 : _b.disconnect();
10266
- (_c = this.resize) === null || _c === void 0 ? void 0 : _c.disconnect();
10282
+ (_c = this.resizeScroll) === null || _c === void 0 ? void 0 : _c.disconnect();
10283
+ (_d = this.resizeContent) === null || _d === void 0 ? void 0 : _d.disconnect();
10267
10284
  for (let dom of this.scrollTargets)
10268
10285
  dom.removeEventListener("scroll", this.onScroll);
10269
10286
  this.removeWindowListeners(this.win);
@@ -10362,7 +10379,7 @@
10362
10379
  this.scrollDOM.className = "cm-scroller";
10363
10380
  this.scrollDOM.appendChild(this.contentDOM);
10364
10381
  this.announceDOM = document.createElement("div");
10365
- this.announceDOM.style.cssText = "position: absolute; top: -10000px";
10382
+ this.announceDOM.style.cssText = "position: fixed; top: -10000px";
10366
10383
  this.announceDOM.setAttribute("aria-live", "polite");
10367
10384
  this.dom = document.createElement("div");
10368
10385
  this.dom.appendChild(this.announceDOM);
@@ -11447,51 +11464,21 @@
11447
11464
  return fallthrough;
11448
11465
  }
11449
11466
 
11450
- const CanHidePrimary = !browser.ios; // FIXME test IE
11451
- const selectionConfig = /*@__PURE__*/Facet.define({
11452
- combine(configs) {
11453
- return combineConfig(configs, {
11454
- cursorBlinkRate: 1200,
11455
- drawRangeCursor: true
11456
- }, {
11457
- cursorBlinkRate: (a, b) => Math.min(a, b),
11458
- drawRangeCursor: (a, b) => a || b
11459
- });
11460
- }
11461
- });
11462
11467
  /**
11463
- Returns an extension that hides the browser's native selection and
11464
- cursor, replacing the selection with a background behind the text
11465
- (with the `cm-selectionBackground` class), and the
11466
- cursors with elements overlaid over the code (using
11467
- `cm-cursor-primary` and `cm-cursor-secondary`).
11468
-
11469
- This allows the editor to display secondary selection ranges, and
11470
- tends to produce a type of selection more in line with that users
11471
- expect in a text editor (the native selection styling will often
11472
- leave gaps between lines and won't fill the horizontal space after
11473
- a line when the selection continues past it).
11474
-
11475
- It does have a performance cost, in that it requires an extra DOM
11476
- layout cycle for many updates (the selection is drawn based on DOM
11477
- layout information that's only available after laying out the
11478
- content).
11468
+ Implementation of [`LayerMarker`](https://codemirror.net/6/docs/ref/#view.LayerMarker) that creates
11469
+ a rectangle at a given set of coordinates.
11479
11470
  */
11480
- function drawSelection(config = {}) {
11481
- return [
11482
- selectionConfig.of(config),
11483
- drawSelectionPlugin,
11484
- hideNativeSelection,
11485
- nativeSelectionHidden.of(true)
11486
- ];
11487
- }
11488
- class Piece {
11489
- constructor(left, top, width, height, className) {
11471
+ class RectangleMarker {
11472
+ /**
11473
+ Create a marker with the given class and dimensions. If `width`
11474
+ is null, the DOM element will get no width style.
11475
+ */
11476
+ constructor(className, left, top, width, height) {
11477
+ this.className = className;
11490
11478
  this.left = left;
11491
11479
  this.top = top;
11492
11480
  this.width = width;
11493
11481
  this.height = height;
11494
- this.className = className;
11495
11482
  }
11496
11483
  draw() {
11497
11484
  let elt = document.createElement("div");
@@ -11499,10 +11486,16 @@
11499
11486
  this.adjust(elt);
11500
11487
  return elt;
11501
11488
  }
11489
+ update(elt, prev) {
11490
+ if (prev.className != this.className)
11491
+ return false;
11492
+ this.adjust(elt);
11493
+ return true;
11494
+ }
11502
11495
  adjust(elt) {
11503
11496
  elt.style.left = this.left + "px";
11504
11497
  elt.style.top = this.top + "px";
11505
- if (this.width >= 0)
11498
+ if (this.width != null)
11506
11499
  elt.style.width = this.width + "px";
11507
11500
  elt.style.height = this.height + "px";
11508
11501
  }
@@ -11510,82 +11503,26 @@
11510
11503
  return this.left == p.left && this.top == p.top && this.width == p.width && this.height == p.height &&
11511
11504
  this.className == p.className;
11512
11505
  }
11513
- }
11514
- const drawSelectionPlugin = /*@__PURE__*/ViewPlugin.fromClass(class {
11515
- constructor(view) {
11516
- this.view = view;
11517
- this.rangePieces = [];
11518
- this.cursors = [];
11519
- this.measureReq = { read: this.readPos.bind(this), write: this.drawSel.bind(this) };
11520
- this.selectionLayer = view.scrollDOM.appendChild(document.createElement("div"));
11521
- this.selectionLayer.className = "cm-selectionLayer";
11522
- this.selectionLayer.setAttribute("aria-hidden", "true");
11523
- this.cursorLayer = view.scrollDOM.appendChild(document.createElement("div"));
11524
- this.cursorLayer.className = "cm-cursorLayer";
11525
- this.cursorLayer.setAttribute("aria-hidden", "true");
11526
- view.requestMeasure(this.measureReq);
11527
- this.setBlinkRate();
11528
- }
11529
- setBlinkRate() {
11530
- this.cursorLayer.style.animationDuration = this.view.state.facet(selectionConfig).cursorBlinkRate + "ms";
11531
- }
11532
- update(update) {
11533
- let confChanged = update.startState.facet(selectionConfig) != update.state.facet(selectionConfig);
11534
- if (confChanged || update.selectionSet || update.geometryChanged || update.viewportChanged)
11535
- this.view.requestMeasure(this.measureReq);
11536
- if (update.transactions.some(tr => tr.scrollIntoView))
11537
- this.cursorLayer.style.animationName = this.cursorLayer.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
11538
- if (confChanged)
11539
- this.setBlinkRate();
11540
- }
11541
- readPos() {
11542
- let { state } = this.view, conf = state.facet(selectionConfig);
11543
- let rangePieces = state.selection.ranges.map(r => r.empty ? [] : measureRange(this.view, r)).reduce((a, b) => a.concat(b));
11544
- let cursors = [];
11545
- for (let r of state.selection.ranges) {
11546
- let prim = r == state.selection.main;
11547
- if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
11548
- let piece = measureCursor(this.view, r, prim);
11549
- if (piece)
11550
- cursors.push(piece);
11551
- }
11552
- }
11553
- return { rangePieces, cursors };
11554
- }
11555
- drawSel({ rangePieces, cursors }) {
11556
- if (rangePieces.length != this.rangePieces.length || rangePieces.some((p, i) => !p.eq(this.rangePieces[i]))) {
11557
- this.selectionLayer.textContent = "";
11558
- for (let p of rangePieces)
11559
- this.selectionLayer.appendChild(p.draw());
11560
- this.rangePieces = rangePieces;
11506
+ /**
11507
+ Create a set of rectangles for the given selection range,
11508
+ assigning them theclass`className`. Will create a single
11509
+ rectangle for empty ranges, and a set of selection-style
11510
+ rectangles covering the range's content (in a bidi-aware
11511
+ way) for non-empty ones.
11512
+ */
11513
+ static forRange(view, className, range) {
11514
+ if (range.empty) {
11515
+ let pos = view.coordsAtPos(range.head, range.assoc || 1);
11516
+ if (!pos)
11517
+ return [];
11518
+ let base = getBase(view);
11519
+ return [new RectangleMarker(className, pos.left - base.left, pos.top - base.top, null, pos.bottom - pos.top)];
11561
11520
  }
11562
- if (cursors.length != this.cursors.length || cursors.some((c, i) => !c.eq(this.cursors[i]))) {
11563
- let oldCursors = this.cursorLayer.children;
11564
- if (oldCursors.length !== cursors.length) {
11565
- this.cursorLayer.textContent = "";
11566
- for (const c of cursors)
11567
- this.cursorLayer.appendChild(c.draw());
11568
- }
11569
- else {
11570
- cursors.forEach((c, idx) => c.adjust(oldCursors[idx]));
11571
- }
11572
- this.cursors = cursors;
11521
+ else {
11522
+ return rectanglesForRange(view, className, range);
11573
11523
  }
11574
11524
  }
11575
- destroy() {
11576
- this.selectionLayer.remove();
11577
- this.cursorLayer.remove();
11578
- }
11579
- });
11580
- const themeSpec = {
11581
- ".cm-line": {
11582
- "& ::selection": { backgroundColor: "transparent !important" },
11583
- "&::selection": { backgroundColor: "transparent !important" }
11584
- }
11585
- };
11586
- if (CanHidePrimary)
11587
- themeSpec[".cm-line"].caretColor = "transparent !important";
11588
- const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
11525
+ }
11589
11526
  function getBase(view) {
11590
11527
  let rect = view.scrollDOM.getBoundingClientRect();
11591
11528
  let left = view.textDirection == Direction.LTR ? rect.left : rect.right - view.scrollDOM.clientWidth;
@@ -11606,7 +11543,7 @@
11606
11543
  }
11607
11544
  return line;
11608
11545
  }
11609
- function measureRange(view, range) {
11546
+ function rectanglesForRange(view, className, range) {
11610
11547
  if (range.to <= view.viewport.from || range.from >= view.viewport.to)
11611
11548
  return [];
11612
11549
  let from = Math.max(range.from, view.viewport.from), to = Math.min(range.to, view.viewport.to);
@@ -11638,7 +11575,7 @@
11638
11575
  return pieces(top).concat(between).concat(pieces(bottom));
11639
11576
  }
11640
11577
  function piece(left, top, right, bottom) {
11641
- return new Piece(left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */, "cm-selectionBackground");
11578
+ return new RectangleMarker(className, left - base.left, top - base.top - 0.01 /* C.Epsilon */, right - left, bottom - top + 0.01 /* C.Epsilon */);
11642
11579
  }
11643
11580
  function pieces({ top, bottom, horizontal }) {
11644
11581
  let pieces = [];
@@ -11690,13 +11627,174 @@
11690
11627
  return { top: y, bottom: y, horizontal: [] };
11691
11628
  }
11692
11629
  }
11693
- function measureCursor(view, cursor, primary) {
11694
- let pos = view.coordsAtPos(cursor.head, cursor.assoc || 1);
11695
- if (!pos)
11696
- return null;
11697
- let base = getBase(view);
11698
- return new Piece(pos.left - base.left, pos.top - base.top, -1, pos.bottom - pos.top, primary ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary");
11630
+ function sameMarker(a, b) {
11631
+ return a.constructor == b.constructor && a.eq(b);
11632
+ }
11633
+ class LayerView {
11634
+ constructor(view, layer) {
11635
+ this.view = view;
11636
+ this.layer = layer;
11637
+ this.drawn = [];
11638
+ this.measureReq = { read: this.measure.bind(this), write: this.draw.bind(this) };
11639
+ this.dom = view.scrollDOM.appendChild(document.createElement("div"));
11640
+ this.dom.classList.add("cm-layer");
11641
+ if (layer.above)
11642
+ this.dom.classList.add("cm-layer-above");
11643
+ if (layer.class)
11644
+ this.dom.classList.add(layer.class);
11645
+ this.dom.setAttribute("aria-hidden", "true");
11646
+ this.setOrder(view.state);
11647
+ view.requestMeasure(this.measureReq);
11648
+ if (layer.mount)
11649
+ layer.mount(this.dom, view);
11650
+ }
11651
+ update(update) {
11652
+ if (update.startState.facet(layerOrder) != update.state.facet(layerOrder))
11653
+ this.setOrder(update.state);
11654
+ if (this.layer.update(update, this.dom) || update.geometryChanged)
11655
+ update.view.requestMeasure(this.measureReq);
11656
+ }
11657
+ setOrder(state) {
11658
+ let pos = 0, order = state.facet(layerOrder);
11659
+ while (pos < order.length && order[pos] != this.layer)
11660
+ pos++;
11661
+ this.dom.style.zIndex = String((this.layer.above ? 150 : -1) - pos);
11662
+ }
11663
+ measure() {
11664
+ return this.layer.markers(this.view);
11665
+ }
11666
+ draw(markers) {
11667
+ if (markers.length != this.drawn.length || markers.some((p, i) => !sameMarker(p, this.drawn[i]))) {
11668
+ let old = this.dom.firstChild, oldI = 0;
11669
+ for (let marker of markers) {
11670
+ if (marker.update && old && marker.constructor && this.drawn[oldI].constructor &&
11671
+ marker.update(old, this.drawn[oldI])) {
11672
+ old = old.nextSibling;
11673
+ oldI++;
11674
+ }
11675
+ else {
11676
+ this.dom.insertBefore(marker.draw(), old);
11677
+ }
11678
+ }
11679
+ while (old) {
11680
+ let next = old.nextSibling;
11681
+ old.remove();
11682
+ old = next;
11683
+ }
11684
+ this.drawn = markers;
11685
+ }
11686
+ }
11687
+ destroy() {
11688
+ if (this.layer.destroy)
11689
+ this.layer.destroy(this.dom, this.view);
11690
+ this.dom.remove();
11691
+ }
11692
+ }
11693
+ const layerOrder = /*@__PURE__*/Facet.define();
11694
+ /**
11695
+ Define a layer.
11696
+ */
11697
+ function layer(config) {
11698
+ return [
11699
+ ViewPlugin.define(v => new LayerView(v, config)),
11700
+ layerOrder.of(config)
11701
+ ];
11702
+ }
11703
+
11704
+ const CanHidePrimary = !browser.ios; // FIXME test IE
11705
+ const selectionConfig = /*@__PURE__*/Facet.define({
11706
+ combine(configs) {
11707
+ return combineConfig(configs, {
11708
+ cursorBlinkRate: 1200,
11709
+ drawRangeCursor: true
11710
+ }, {
11711
+ cursorBlinkRate: (a, b) => Math.min(a, b),
11712
+ drawRangeCursor: (a, b) => a || b
11713
+ });
11714
+ }
11715
+ });
11716
+ /**
11717
+ Returns an extension that hides the browser's native selection and
11718
+ cursor, replacing the selection with a background behind the text
11719
+ (with the `cm-selectionBackground` class), and the
11720
+ cursors with elements overlaid over the code (using
11721
+ `cm-cursor-primary` and `cm-cursor-secondary`).
11722
+
11723
+ This allows the editor to display secondary selection ranges, and
11724
+ tends to produce a type of selection more in line with that users
11725
+ expect in a text editor (the native selection styling will often
11726
+ leave gaps between lines and won't fill the horizontal space after
11727
+ a line when the selection continues past it).
11728
+
11729
+ It does have a performance cost, in that it requires an extra DOM
11730
+ layout cycle for many updates (the selection is drawn based on DOM
11731
+ layout information that's only available after laying out the
11732
+ content).
11733
+ */
11734
+ function drawSelection(config = {}) {
11735
+ return [
11736
+ selectionConfig.of(config),
11737
+ cursorLayer,
11738
+ selectionLayer,
11739
+ hideNativeSelection,
11740
+ nativeSelectionHidden.of(true)
11741
+ ];
11699
11742
  }
11743
+ function configChanged(update) {
11744
+ return update.startState.facet(selectionConfig) != update.startState.facet(selectionConfig);
11745
+ }
11746
+ const cursorLayer = /*@__PURE__*/layer({
11747
+ above: true,
11748
+ markers(view) {
11749
+ let { state } = view, conf = state.facet(selectionConfig);
11750
+ let cursors = [];
11751
+ for (let r of state.selection.ranges) {
11752
+ let prim = r == state.selection.main;
11753
+ if (r.empty ? !prim || CanHidePrimary : conf.drawRangeCursor) {
11754
+ let className = prim ? "cm-cursor cm-cursor-primary" : "cm-cursor cm-cursor-secondary";
11755
+ let cursor = r.empty ? r : EditorSelection.cursor(r.head, r.head > r.anchor ? -1 : 1);
11756
+ for (let piece of RectangleMarker.forRange(view, className, cursor))
11757
+ cursors.push(piece);
11758
+ }
11759
+ }
11760
+ return cursors;
11761
+ },
11762
+ update(update, dom) {
11763
+ if (update.transactions.some(tr => tr.scrollIntoView))
11764
+ dom.style.animationName = dom.style.animationName == "cm-blink" ? "cm-blink2" : "cm-blink";
11765
+ let confChange = configChanged(update);
11766
+ if (confChange)
11767
+ setBlinkRate(update.state, dom);
11768
+ return update.docChanged || update.selectionSet || confChange;
11769
+ },
11770
+ mount(dom, view) {
11771
+ setBlinkRate(view.state, dom);
11772
+ },
11773
+ class: "cm-cursorLayer"
11774
+ });
11775
+ function setBlinkRate(state, dom) {
11776
+ dom.style.animationDuration = state.facet(selectionConfig).cursorBlinkRate + "ms";
11777
+ }
11778
+ const selectionLayer = /*@__PURE__*/layer({
11779
+ above: false,
11780
+ markers(view) {
11781
+ return view.state.selection.ranges.map(r => r.empty ? [] : RectangleMarker.forRange(view, "cm-selectionBackground", r))
11782
+ .reduce((a, b) => a.concat(b));
11783
+ },
11784
+ update(update, dom) {
11785
+ return update.docChanged || update.selectionSet || update.viewportChanged || configChanged(update);
11786
+ },
11787
+ class: "cm-selectionLayer"
11788
+ });
11789
+ const themeSpec = {
11790
+ ".cm-line": {
11791
+ "& ::selection": { backgroundColor: "transparent !important" },
11792
+ "&::selection": { backgroundColor: "transparent !important" }
11793
+ }
11794
+ };
11795
+ if (CanHidePrimary)
11796
+ themeSpec[".cm-line"].caretColor = "transparent !important";
11797
+ const hideNativeSelection = /*@__PURE__*/Prec.highest(/*@__PURE__*/EditorView.theme(themeSpec));
11700
11798
 
11701
11799
  const setDropCursorPos = /*@__PURE__*/StateEffect.define({
11702
11800
  map(pos, mapping) { return pos == null ? null : mapping.mapPos(pos); }
@@ -12456,6 +12554,17 @@
12456
12554
  : pos.bottom + (size.bottom - size.top) + offset.y > space.bottom) &&
12457
12555
  above == (space.bottom - pos.bottom > pos.top - space.top))
12458
12556
  above = !above;
12557
+ let spaceVert = (above ? pos.top - space.top : space.bottom - pos.bottom) - arrowHeight;
12558
+ if (spaceVert < height && tView.resize !== false) {
12559
+ if (spaceVert < this.view.defaultLineHeight) {
12560
+ dom.style.top = Outside;
12561
+ continue;
12562
+ }
12563
+ dom.style.height = (height = spaceVert) + "px";
12564
+ }
12565
+ else if (dom.style.height) {
12566
+ dom.style.height = "";
12567
+ }
12459
12568
  let top = above ? pos.top - height - arrowHeight - offset.y : pos.bottom + arrowHeight + offset.y;
12460
12569
  let right = left + width;
12461
12570
  if (tView.overlap !== true)
@@ -12499,7 +12608,8 @@
12499
12608
  });
12500
12609
  const baseTheme$4 = /*@__PURE__*/EditorView.baseTheme({
12501
12610
  ".cm-tooltip": {
12502
- zIndex: 100
12611
+ zIndex: 100,
12612
+ boxSizing: "border-box"
12503
12613
  },
12504
12614
  "&light .cm-tooltip": {
12505
12615
  border: "1px solid #bbb",
@@ -13484,8 +13594,8 @@
13484
13594
  /// Define a node type.
13485
13595
  static define(spec) {
13486
13596
  let props = spec.props && spec.props.length ? Object.create(null) : noProps;
13487
- let flags = (spec.top ? 1 /* Top */ : 0) | (spec.skipped ? 2 /* Skipped */ : 0) |
13488
- (spec.error ? 4 /* Error */ : 0) | (spec.name == null ? 8 /* Anonymous */ : 0);
13597
+ let flags = (spec.top ? 1 /* NodeFlag.Top */ : 0) | (spec.skipped ? 2 /* NodeFlag.Skipped */ : 0) |
13598
+ (spec.error ? 4 /* NodeFlag.Error */ : 0) | (spec.name == null ? 8 /* NodeFlag.Anonymous */ : 0);
13489
13599
  let type = new NodeType(spec.name || "", props, spec.id, flags);
13490
13600
  if (spec.props)
13491
13601
  for (let src of spec.props) {
@@ -13503,14 +13613,14 @@
13503
13613
  /// the prop isn't present on this node.
13504
13614
  prop(prop) { return this.props[prop.id]; }
13505
13615
  /// True when this is the top node of a grammar.
13506
- get isTop() { return (this.flags & 1 /* Top */) > 0; }
13616
+ get isTop() { return (this.flags & 1 /* NodeFlag.Top */) > 0; }
13507
13617
  /// True when this node is produced by a skip rule.
13508
- get isSkipped() { return (this.flags & 2 /* Skipped */) > 0; }
13618
+ get isSkipped() { return (this.flags & 2 /* NodeFlag.Skipped */) > 0; }
13509
13619
  /// Indicates whether this is an error node.
13510
- get isError() { return (this.flags & 4 /* Error */) > 0; }
13620
+ get isError() { return (this.flags & 4 /* NodeFlag.Error */) > 0; }
13511
13621
  /// When true, this node type doesn't correspond to a user-declared
13512
13622
  /// named node, for example because it is used to cache repetition.
13513
- get isAnonymous() { return (this.flags & 8 /* Anonymous */) > 0; }
13623
+ get isAnonymous() { return (this.flags & 8 /* NodeFlag.Anonymous */) > 0; }
13514
13624
  /// Returns true when this node's name or one of its
13515
13625
  /// [groups](#common.NodeProp^group) matches the given string.
13516
13626
  is(name) {
@@ -13543,7 +13653,7 @@
13543
13653
  }
13544
13654
  }
13545
13655
  /// An empty dummy node type to use when no actual type is available.
13546
- NodeType.none = new NodeType("", Object.create(null), 0, 8 /* Anonymous */);
13656
+ NodeType.none = new NodeType("", Object.create(null), 0, 8 /* NodeFlag.Anonymous */);
13547
13657
  /// A node set holds a collection of node types. It is used to
13548
13658
  /// compactly represent trees by storing their type ids, rather than a
13549
13659
  /// full pointer to the type object, in a numeric array. Each parser
@@ -13752,7 +13862,7 @@
13752
13862
  /// which may have children grouped into subtrees with type
13753
13863
  /// [`NodeType.none`](#common.NodeType^none).
13754
13864
  balance(config = {}) {
13755
- return this.children.length <= 8 /* BranchFactor */ ? this :
13865
+ return this.children.length <= 8 /* Balance.BranchFactor */ ? this :
13756
13866
  balanceRange(NodeType.none, this.children, this.positions, 0, this.children.length, 0, this.length, (children, positions, length) => new Tree(this.type, children, positions, length, this.propValues), config.makeTree || ((children, positions, length) => new Tree(NodeType.none, children, positions, length)));
13757
13867
  }
13758
13868
  /// Build a tree from a postfix-ordered buffer of node information,
@@ -13831,26 +13941,27 @@
13831
13941
  return pick;
13832
13942
  }
13833
13943
  /// @internal
13834
- slice(startI, endI, from, to) {
13944
+ slice(startI, endI, from) {
13835
13945
  let b = this.buffer;
13836
- let copy = new Uint16Array(endI - startI);
13946
+ let copy = new Uint16Array(endI - startI), len = 0;
13837
13947
  for (let i = startI, j = 0; i < endI;) {
13838
13948
  copy[j++] = b[i++];
13839
13949
  copy[j++] = b[i++] - from;
13840
- copy[j++] = b[i++] - from;
13950
+ let to = copy[j++] = b[i++] - from;
13841
13951
  copy[j++] = b[i++] - startI;
13952
+ len = Math.max(len, to);
13842
13953
  }
13843
- return new TreeBuffer(copy, to - from, this.set);
13954
+ return new TreeBuffer(copy, len, this.set);
13844
13955
  }
13845
13956
  }
13846
13957
  function checkSide(side, pos, from, to) {
13847
13958
  switch (side) {
13848
- case -2 /* Before */: return from < pos;
13849
- case -1 /* AtOrBefore */: return to >= pos && from < pos;
13850
- case 0 /* Around */: return from < pos && to > pos;
13851
- case 1 /* AtOrAfter */: return from <= pos && to > pos;
13852
- case 2 /* After */: return to > pos;
13853
- case 4 /* DontCare */: return true;
13959
+ case -2 /* Side.Before */: return from < pos;
13960
+ case -1 /* Side.AtOrBefore */: return to >= pos && from < pos;
13961
+ case 0 /* Side.Around */: return from < pos && to > pos;
13962
+ case 1 /* Side.AtOrAfter */: return from <= pos && to > pos;
13963
+ case 2 /* Side.After */: return to > pos;
13964
+ case 4 /* Side.DontCare */: return true;
13854
13965
  }
13855
13966
  }
13856
13967
  function enterUnfinishedNodesBefore(node, pos) {
@@ -13940,10 +14051,10 @@
13940
14051
  return null;
13941
14052
  }
13942
14053
  }
13943
- get firstChild() { return this.nextChild(0, 1, 0, 4 /* DontCare */); }
13944
- get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* DontCare */); }
13945
- childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* After */); }
13946
- childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Before */); }
14054
+ get firstChild() { return this.nextChild(0, 1, 0, 4 /* Side.DontCare */); }
14055
+ get lastChild() { return this.nextChild(this._tree.children.length - 1, -1, 0, 4 /* Side.DontCare */); }
14056
+ childAfter(pos) { return this.nextChild(0, 1, pos, 2 /* Side.After */); }
14057
+ childBefore(pos) { return this.nextChild(this._tree.children.length - 1, -1, pos, -2 /* Side.Before */); }
13947
14058
  enter(pos, side, mode = 0) {
13948
14059
  let mounted;
13949
14060
  if (!(mode & IterMode.IgnoreOverlays) && (mounted = this._tree.prop(NodeProp.mounted)) && mounted.overlay) {
@@ -13966,10 +14077,10 @@
13966
14077
  return this._parent ? this._parent.nextSignificantParent() : null;
13967
14078
  }
13968
14079
  get nextSibling() {
13969
- return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* DontCare */) : null;
14080
+ return this._parent && this.index >= 0 ? this._parent.nextChild(this.index + 1, 1, 0, 4 /* Side.DontCare */) : null;
13970
14081
  }
13971
14082
  get prevSibling() {
13972
- return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* DontCare */) : null;
14083
+ return this._parent && this.index >= 0 ? this._parent.nextChild(this.index - 1, -1, 0, 4 /* Side.DontCare */) : null;
13973
14084
  }
13974
14085
  cursor(mode = 0) { return new TreeCursor(this, mode); }
13975
14086
  get tree() { return this._tree; }
@@ -14031,24 +14142,24 @@
14031
14142
  }
14032
14143
  }
14033
14144
  class BufferNode {
14145
+ get name() { return this.type.name; }
14146
+ get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; }
14147
+ get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; }
14034
14148
  constructor(context, _parent, index) {
14035
14149
  this.context = context;
14036
14150
  this._parent = _parent;
14037
14151
  this.index = index;
14038
14152
  this.type = context.buffer.set.types[context.buffer.buffer[index]];
14039
14153
  }
14040
- get name() { return this.type.name; }
14041
- get from() { return this.context.start + this.context.buffer.buffer[this.index + 1]; }
14042
- get to() { return this.context.start + this.context.buffer.buffer[this.index + 2]; }
14043
14154
  child(dir, pos, side) {
14044
14155
  let { buffer } = this.context;
14045
14156
  let index = buffer.findChild(this.index + 4, buffer.buffer[this.index + 3], dir, pos - this.context.start, side);
14046
14157
  return index < 0 ? null : new BufferNode(this.context, this, index);
14047
14158
  }
14048
- get firstChild() { return this.child(1, 0, 4 /* DontCare */); }
14049
- get lastChild() { return this.child(-1, 0, 4 /* DontCare */); }
14050
- childAfter(pos) { return this.child(1, pos, 2 /* After */); }
14051
- childBefore(pos) { return this.child(-1, pos, -2 /* Before */); }
14159
+ get firstChild() { return this.child(1, 0, 4 /* Side.DontCare */); }
14160
+ get lastChild() { return this.child(-1, 0, 4 /* Side.DontCare */); }
14161
+ childAfter(pos) { return this.child(1, pos, 2 /* Side.After */); }
14162
+ childBefore(pos) { return this.child(-1, pos, -2 /* Side.Before */); }
14052
14163
  enter(pos, side, mode = 0) {
14053
14164
  if (mode & IterMode.ExcludeBuffers)
14054
14165
  return null;
@@ -14060,7 +14171,7 @@
14060
14171
  return this._parent || this.context.parent.nextSignificantParent();
14061
14172
  }
14062
14173
  externalSibling(dir) {
14063
- return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* DontCare */);
14174
+ return this._parent ? null : this.context.parent.nextChild(this.context.index + dir, dir, 0, 4 /* Side.DontCare */);
14064
14175
  }
14065
14176
  get nextSibling() {
14066
14177
  let { buffer } = this.context;
@@ -14074,7 +14185,7 @@
14074
14185
  let parentStart = this._parent ? this._parent.index + 4 : 0;
14075
14186
  if (this.index == parentStart)
14076
14187
  return this.externalSibling(-1);
14077
- return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
14188
+ return new BufferNode(this.context, this._parent, buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */));
14078
14189
  }
14079
14190
  cursor(mode = 0) { return new TreeCursor(this, mode); }
14080
14191
  get tree() { return null; }
@@ -14083,8 +14194,8 @@
14083
14194
  let { buffer } = this.context;
14084
14195
  let startI = this.index + 4, endI = buffer.buffer[this.index + 3];
14085
14196
  if (endI > startI) {
14086
- let from = buffer.buffer[this.index + 1], to = buffer.buffer[this.index + 2];
14087
- children.push(buffer.slice(startI, endI, from, to));
14197
+ let from = buffer.buffer[this.index + 1];
14198
+ children.push(buffer.slice(startI, endI, from));
14088
14199
  positions.push(0);
14089
14200
  }
14090
14201
  return new Tree(this.type, children, positions, this.to - this.from);
@@ -14111,6 +14222,8 @@
14111
14222
  /// A tree cursor object focuses on a given node in a syntax tree, and
14112
14223
  /// allows you to move to adjacent nodes.
14113
14224
  class TreeCursor {
14225
+ /// Shorthand for `.type.name`.
14226
+ get name() { return this.type.name; }
14114
14227
  /// @internal
14115
14228
  constructor(node,
14116
14229
  /// @internal
@@ -14134,8 +14247,6 @@
14134
14247
  this.yieldBuf(node.index);
14135
14248
  }
14136
14249
  }
14137
- /// Shorthand for `.type.name`.
14138
- get name() { return this.type.name; }
14139
14250
  yieldNode(node) {
14140
14251
  if (!node)
14141
14252
  return false;
@@ -14180,13 +14291,13 @@
14180
14291
  }
14181
14292
  /// Move the cursor to this node's first child. When this returns
14182
14293
  /// false, the node has no child, and the cursor has not been moved.
14183
- firstChild() { return this.enterChild(1, 0, 4 /* DontCare */); }
14294
+ firstChild() { return this.enterChild(1, 0, 4 /* Side.DontCare */); }
14184
14295
  /// Move the cursor to this node's last child.
14185
- lastChild() { return this.enterChild(-1, 0, 4 /* DontCare */); }
14296
+ lastChild() { return this.enterChild(-1, 0, 4 /* Side.DontCare */); }
14186
14297
  /// Move the cursor to the first child that ends after `pos`.
14187
- childAfter(pos) { return this.enterChild(1, pos, 2 /* After */); }
14298
+ childAfter(pos) { return this.enterChild(1, pos, 2 /* Side.After */); }
14188
14299
  /// Move to the last child that starts before `pos`.
14189
- childBefore(pos) { return this.enterChild(-1, pos, -2 /* Before */); }
14300
+ childBefore(pos) { return this.enterChild(-1, pos, -2 /* Side.Before */); }
14190
14301
  /// Move the cursor to the child around `pos`. If side is -1 the
14191
14302
  /// child may end at that position, when 1 it may start there. This
14192
14303
  /// will also enter [overlaid](#common.MountedTree.overlay)
@@ -14212,19 +14323,19 @@
14212
14323
  if (!this.buffer)
14213
14324
  return !this._tree._parent ? false
14214
14325
  : this.yield(this._tree.index < 0 ? null
14215
- : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* DontCare */, this.mode));
14326
+ : this._tree._parent.nextChild(this._tree.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode));
14216
14327
  let { buffer } = this.buffer, d = this.stack.length - 1;
14217
14328
  if (dir < 0) {
14218
14329
  let parentStart = d < 0 ? 0 : this.stack[d] + 4;
14219
14330
  if (this.index != parentStart)
14220
- return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* DontCare */));
14331
+ return this.yieldBuf(buffer.findChild(parentStart, this.index, -1, 0, 4 /* Side.DontCare */));
14221
14332
  }
14222
14333
  else {
14223
14334
  let after = buffer.buffer[this.index + 3];
14224
14335
  if (after < (d < 0 ? buffer.buffer.length : buffer.buffer[this.stack[d] + 3]))
14225
14336
  return this.yieldBuf(after);
14226
14337
  }
14227
- return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* DontCare */, this.mode)) : false;
14338
+ return d < 0 ? this.yield(this.buffer.parent.nextChild(this.buffer.index + dir, dir, 0, 4 /* Side.DontCare */, this.mode)) : false;
14228
14339
  }
14229
14340
  /// Move to this node's next sibling, if any.
14230
14341
  nextSibling() { return this.sibling(1); }
@@ -14261,7 +14372,7 @@
14261
14372
  return true;
14262
14373
  }
14263
14374
  move(dir, enter) {
14264
- if (enter && this.enterChild(dir, 0, 4 /* DontCare */))
14375
+ if (enter && this.enterChild(dir, 0, 4 /* Side.DontCare */))
14265
14376
  return true;
14266
14377
  for (;;) {
14267
14378
  if (this.sibling(dir))
@@ -14271,7 +14382,7 @@
14271
14382
  }
14272
14383
  }
14273
14384
  /// Move to the next node in a
14274
- /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order_(NLR))
14385
+ /// [pre-order](https://en.wikipedia.org/wiki/Tree_traversal#Pre-order,_NLR)
14275
14386
  /// traversal, going from a node to its first child or, if the
14276
14387
  /// current node is empty or `enter` is false, its next sibling or
14277
14388
  /// the next sibling of the first parent node that has one.
@@ -14387,17 +14498,17 @@
14387
14498
  let lookAheadAtStart = lookAhead;
14388
14499
  while (size < 0) {
14389
14500
  cursor.next();
14390
- if (size == -1 /* Reuse */) {
14501
+ if (size == -1 /* SpecialRecord.Reuse */) {
14391
14502
  let node = reused[id];
14392
14503
  children.push(node);
14393
14504
  positions.push(start - parentStart);
14394
14505
  return;
14395
14506
  }
14396
- else if (size == -3 /* ContextChange */) { // Context change
14507
+ else if (size == -3 /* SpecialRecord.ContextChange */) { // Context change
14397
14508
  contextHash = id;
14398
14509
  return;
14399
14510
  }
14400
- else if (size == -4 /* LookAhead */) {
14511
+ else if (size == -4 /* SpecialRecord.LookAhead */) {
14401
14512
  lookAhead = id;
14402
14513
  return;
14403
14514
  }
@@ -14514,7 +14625,7 @@
14514
14625
  fork.next();
14515
14626
  while (fork.pos > startPos) {
14516
14627
  if (fork.size < 0) {
14517
- if (fork.size == -3 /* ContextChange */)
14628
+ if (fork.size == -3 /* SpecialRecord.ContextChange */)
14518
14629
  localSkipped += 4;
14519
14630
  else
14520
14631
  break scan;
@@ -14550,10 +14661,10 @@
14550
14661
  buffer[--index] = start - bufferStart;
14551
14662
  buffer[--index] = id;
14552
14663
  }
14553
- else if (size == -3 /* ContextChange */) {
14664
+ else if (size == -3 /* SpecialRecord.ContextChange */) {
14554
14665
  contextHash = id;
14555
14666
  }
14556
- else if (size == -4 /* LookAhead */) {
14667
+ else if (size == -4 /* SpecialRecord.LookAhead */) {
14557
14668
  lookAhead = id;
14558
14669
  }
14559
14670
  return index;
@@ -14600,7 +14711,7 @@
14600
14711
  let total = 0;
14601
14712
  for (let i = from; i < to; i++)
14602
14713
  total += nodeSize(balanceType, children[i]);
14603
- let maxChild = Math.ceil((total * 1.5) / 8 /* BranchFactor */);
14714
+ let maxChild = Math.ceil((total * 1.5) / 8 /* Balance.BranchFactor */);
14604
14715
  let localChildren = [], localPositions = [];
14605
14716
  function divide(children, positions, from, to, offset) {
14606
14717
  for (let i = from; i < to;) {
@@ -14661,16 +14772,16 @@
14661
14772
  this.to = to;
14662
14773
  this.tree = tree;
14663
14774
  this.offset = offset;
14664
- this.open = (openStart ? 1 /* Start */ : 0) | (openEnd ? 2 /* End */ : 0);
14775
+ this.open = (openStart ? 1 /* Open.Start */ : 0) | (openEnd ? 2 /* Open.End */ : 0);
14665
14776
  }
14666
14777
  /// Whether the start of the fragment represents the start of a
14667
14778
  /// parse, or the end of a change. (In the second case, it may not
14668
14779
  /// be safe to reuse some nodes at the start, depending on the
14669
14780
  /// parsing algorithm.)
14670
- get openStart() { return (this.open & 1 /* Start */) > 0; }
14781
+ get openStart() { return (this.open & 1 /* Open.Start */) > 0; }
14671
14782
  /// Whether the end of the fragment represents the end of a
14672
14783
  /// full-document parse, or the start of a change.
14673
- get openEnd() { return (this.open & 2 /* End */) > 0; }
14784
+ get openEnd() { return (this.open & 2 /* Open.End */) > 0; }
14674
14785
  /// Create a set of fragments from a freshly parsed tree, or update
14675
14786
  /// an existing set of fragments by replacing the ones that overlap
14676
14787
  /// with a tree with content from the new tree. When `partial` is
@@ -14914,10 +15025,10 @@
14914
15025
  tags = [tags];
14915
15026
  for (let part of prop.split(" "))
14916
15027
  if (part) {
14917
- let pieces = [], mode = 2 /* Normal */, rest = part;
15028
+ let pieces = [], mode = 2 /* Mode.Normal */, rest = part;
14918
15029
  for (let pos = 0;;) {
14919
15030
  if (rest == "..." && pos > 0 && pos + 3 == part.length) {
14920
- mode = 1 /* Inherit */;
15031
+ mode = 1 /* Mode.Inherit */;
14921
15032
  break;
14922
15033
  }
14923
15034
  let m = /^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(rest);
@@ -14929,7 +15040,7 @@
14929
15040
  break;
14930
15041
  let next = part[pos++];
14931
15042
  if (pos == part.length && next == "!") {
14932
- mode = 0 /* Opaque */;
15043
+ mode = 0 /* Mode.Opaque */;
14933
15044
  break;
14934
15045
  }
14935
15046
  if (next != "/")
@@ -14953,8 +15064,8 @@
14953
15064
  this.context = context;
14954
15065
  this.next = next;
14955
15066
  }
14956
- get opaque() { return this.mode == 0 /* Opaque */; }
14957
- get inherit() { return this.mode == 1 /* Inherit */; }
15067
+ get opaque() { return this.mode == 0 /* Mode.Opaque */; }
15068
+ get inherit() { return this.mode == 1 /* Mode.Inherit */; }
14958
15069
  sort(other) {
14959
15070
  if (!other || other.depth < this.depth) {
14960
15071
  this.next = other;
@@ -14965,7 +15076,7 @@
14965
15076
  }
14966
15077
  get depth() { return this.context ? this.context.length : 0; }
14967
15078
  }
14968
- Rule.empty = new Rule([], 2 /* Normal */, null);
15079
+ Rule.empty = new Rule([], 2 /* Mode.Normal */, null);
14969
15080
  /// Define a [highlighter](#highlight.Highlighter) from an array of
14970
15081
  /// tag/class pairs. Classes associated with more specific tags will
14971
15082
  /// take precedence.
@@ -15052,7 +15163,7 @@
15052
15163
  if (cls)
15053
15164
  cls += " ";
15054
15165
  cls += tagCls;
15055
- if (rule.mode == 1 /* Inherit */)
15166
+ if (rule.mode == 1 /* Mode.Inherit */)
15056
15167
  inheritedClass += (inheritedClass ? " " : "") + tagCls;
15057
15168
  }
15058
15169
  this.startSpan(cursor.from, cls);
@@ -15070,7 +15181,7 @@
15070
15181
  if (rangeFrom < rangeTo && hasChild) {
15071
15182
  while (cursor.from < rangeTo) {
15072
15183
  this.highlightRange(cursor, rangeFrom, rangeTo, inheritedClass, highlighters);
15073
- this.startSpan(Math.min(to, cursor.to), cls);
15184
+ this.startSpan(Math.min(rangeTo, cursor.to), cls);
15074
15185
  if (cursor.to >= nextPos || !cursor.nextSibling())
15075
15186
  break;
15076
15187
  }
@@ -20723,6 +20834,7 @@
20723
20834
  maxWidth: "min(700px, 95vw)",
20724
20835
  minWidth: "250px",
20725
20836
  maxHeight: "10em",
20837
+ height: "100%",
20726
20838
  listStyle: "none",
20727
20839
  margin: 0,
20728
20840
  padding: 0,
@@ -20789,7 +20901,8 @@
20789
20901
  display: "inline-block",
20790
20902
  textAlign: "center",
20791
20903
  paddingRight: ".6em",
20792
- opacity: "0.6"
20904
+ opacity: "0.6",
20905
+ boxSizing: "content-box"
20793
20906
  },
20794
20907
  ".cm-completionIcon-function, .cm-completionIcon-method": {
20795
20908
  "&:after": { content: "'ƒ'" }
@@ -24244,9 +24357,9 @@
24244
24357
  });
24245
24358
  let remainingWidth;
24246
24359
  if (scrolled) {
24247
- remainingWidth = (scrollOffset + drag.containerElement.getBoundingClientRect().width) - runningWidth;
24360
+ remainingWidth = (scrollOffset + drag.containerElement.clientWidth) - runningWidth;
24248
24361
  } else {
24249
- remainingWidth = Math.max(10, drag.containerElement.getBoundingClientRect().width - runningWidth);
24362
+ remainingWidth = Math.max(10, drag.containerElement.clientWidth - runningWidth);
24250
24363
  }
24251
24364
  drag.lastColElement.style.width = `${remainingWidth}px`;
24252
24365
  runningWidth += remainingWidth;
@@ -24261,6 +24374,7 @@
24261
24374
  if (!id) throw new Error('missing table id')
24262
24375
 
24263
24376
  const tableElement = document.createElement('table');
24377
+ containerElement.appendChild(tableElement);
24264
24378
  if (id) tableElement.id = id;
24265
24379
 
24266
24380
  const colgroupElement = document.createElement('colgroup');
@@ -24269,9 +24383,6 @@
24269
24383
  const theadElement = document.createElement('thead');
24270
24384
  tableElement.appendChild(theadElement);
24271
24385
 
24272
- const tbodyElement = document.createElement('tbody');
24273
- tableElement.appendChild(tbodyElement);
24274
-
24275
24386
  const headerTrElement = document.createElement('tr');
24276
24387
  theadElement.appendChild(headerTrElement);
24277
24388
 
@@ -24310,7 +24421,7 @@
24310
24421
  nonLastColElements.forEach((element, index) => {
24311
24422
  runningWidth += element.getBoundingClientRect().width;
24312
24423
  });
24313
- const remainingWidth = Math.max(10, containerElement.getBoundingClientRect().width - runningWidth);
24424
+ const remainingWidth = Math.max(10, containerElement.clientWidth - runningWidth);
24314
24425
  colElements[colElements.length - 1].style.width = `${remainingWidth}px`;
24315
24426
  runningWidth += remainingWidth;
24316
24427
  tableElement.style.width = `${runningWidth}px`;
@@ -24328,7 +24439,15 @@
24328
24439
  });
24329
24440
  mutationObserver.observe(containerElement, { childList: true });
24330
24441
  colgroupElement.appendChild(lastColElement);
24442
+
24443
+ createTableBody(rows, tableElement, cellRenderer);
24331
24444
  }
24445
+ }
24446
+
24447
+ function createTableBody (rows, tableElement, cellRenderer) {
24448
+ const tbodyElement = document.createElement('tbody');
24449
+ tableElement.appendChild(tbodyElement);
24450
+
24332
24451
  let highlight = false;
24333
24452
  rows.forEach(function (row) {
24334
24453
  const rowElement = document.createElement('tr');
@@ -24348,11 +24467,12 @@
24348
24467
  });
24349
24468
  rowElement.appendChild(document.createElement('td'));
24350
24469
  });
24351
- containerElement.appendChild(tableElement);
24352
24470
  }
24353
24471
 
24354
24472
  /* global google */
24355
24473
 
24474
+ const PAGE_SIZE = 500;
24475
+
24356
24476
  function getSqlFromUrl (url) {
24357
24477
  const params = url.searchParams;
24358
24478
  if (params.has('file') && params.has('sql')) {
@@ -24418,6 +24538,14 @@
24418
24538
  copyTextToClipboard(toTsv(window.sqlFetch.result.columns, window.sqlFetch.result.rows));
24419
24539
  }
24420
24540
  });
24541
+ addClickListener(document.getElementById('prev-button'), (event) => {
24542
+ window.sqlFetch.page -= 1;
24543
+ displaySqlFetch(window.sqlFetch);
24544
+ });
24545
+ addClickListener(document.getElementById('next-button'), (event) => {
24546
+ window.sqlFetch.page += 1;
24547
+ displaySqlFetch(window.sqlFetch);
24548
+ });
24421
24549
  addClickListener(document.getElementById('submit-dropdown-button-download-csv'), () => {
24422
24550
  if (!window.sqlFetch?.result) return
24423
24551
 
@@ -24707,7 +24835,6 @@
24707
24835
  document.getElementById('query-box').style.display = 'flex';
24708
24836
  document.getElementById('submit-box').style.display = 'flex';
24709
24837
  document.getElementById('graph-box').style.display = 'flex';
24710
- document.getElementById('graph-status').style.display = 'flex';
24711
24838
  document.getElementById('fetch-sql-box').style.display = 'none';
24712
24839
  document.getElementById('cancel-button').style.display = 'none';
24713
24840
  updateDownloadButtons(window?.sqlFetch);
@@ -24720,7 +24847,6 @@
24720
24847
  document.getElementById('query-box').style.display = 'flex';
24721
24848
  document.getElementById('submit-box').style.display = 'flex';
24722
24849
  document.getElementById('result-box').style.display = 'flex';
24723
- document.getElementById('result-status').style.display = 'flex';
24724
24850
  document.getElementById('fetch-sql-box').style.display = 'none';
24725
24851
  document.getElementById('cancel-button').style.display = 'none';
24726
24852
  focus(getSelection());
@@ -24732,17 +24858,15 @@
24732
24858
  selected.style.display = 'flex';
24733
24859
  });
24734
24860
 
24735
- if (window.savedLoaded) {
24736
- return
24737
- }
24738
-
24739
24861
  const savedElement = document.getElementById('saved-box');
24862
+ const saved = window.metadata.saved;
24863
+ const numFiles = Object.keys(saved).length;
24864
+ setStatus(`${numFiles} file${numFiles === 1 ? '' : 's'}`);
24865
+
24740
24866
  if (savedElement.children.length > 0) {
24741
24867
  return
24742
24868
  }
24743
- const saved = window.metadata.saved;
24744
- const numFiles = Object.keys(saved).length;
24745
- setSavedStatus(`${numFiles} file${numFiles === 1 ? '' : 's'}`);
24869
+
24746
24870
  Object.values(saved).forEach(file => {
24747
24871
  const viewUrl = new URL(window.location.origin + window.location.pathname);
24748
24872
  setActionInUrl(viewUrl, 'query');
@@ -24791,7 +24915,6 @@
24791
24915
 
24792
24916
  savedElement.appendChild(divElement);
24793
24917
  });
24794
- window.savedLoaded = true;
24795
24918
  }
24796
24919
 
24797
24920
  function submitAll (target, event) {
@@ -24847,27 +24970,25 @@
24847
24970
 
24848
24971
  function clearResult () {
24849
24972
  if (window.sqlFetch?.state === 'pending' || window.sqlFetch?.spinner === 'always') {
24850
- window.sqlFetch.state = 'aborted';
24851
- window.sqlFetch.spinner = 'never';
24852
- window.sqlFetch.fetchController.abort();
24973
+ window.sqlFetch.abort();
24853
24974
  displaySqlFetch(window.sqlFetch);
24854
24975
  return
24855
24976
  }
24856
24977
  window.sqlFetch = null;
24857
24978
  clearSpinner();
24858
24979
  clearGraphBox();
24859
- clearGraphStatus();
24980
+ clearStatus();
24860
24981
  clearResultBox();
24861
- clearResultStatus();
24862
24982
  disableDownloadButtons();
24863
24983
  }
24864
24984
 
24865
- function clearResultStatus () {
24866
- document.getElementById('result-status').innerText = '';
24985
+ function clearStatus () {
24986
+ document.getElementById('status-message').innerText = '';
24867
24987
  }
24868
24988
 
24869
- function clearGraphStatus () {
24870
- document.getElementById('graph-status').innerText = '';
24989
+ function setStatus (message) {
24990
+ const element = document.getElementById('status-message');
24991
+ element.innerText = message;
24871
24992
  }
24872
24993
 
24873
24994
  function clearResultBox () {
@@ -24924,22 +25045,24 @@
24924
25045
  signal: sqlFetch.fetchController.signal
24925
25046
  })
24926
25047
  .then((response) => {
25048
+ sqlFetch.endedAt = window.performance.now();
24927
25049
  const contentType = response.headers.get('content-type');
24928
25050
  if (contentType && contentType.indexOf('application/json') !== -1) {
24929
25051
  response.json().then((result) => {
24930
25052
  if (result?.query) {
24931
25053
  sqlFetch.state = 'success';
24932
25054
  sqlFetch.result = result;
25055
+ sqlFetch.pageCount = Math.ceil(result.rows.length / sqlFetch.pageSize);
24933
25056
  } else {
24934
25057
  sqlFetch.state = 'error';
24935
25058
  if (result?.error) {
24936
- sqlFetch.error_message = result.error;
24937
- sqlFetch.error_details = result.stacktrace;
25059
+ sqlFetch.errorMessage = result.error;
25060
+ sqlFetch.errorDetails = result.stacktrace;
24938
25061
  } else if (result) {
24939
- sqlFetch.error_message = 'failed to execute query';
24940
- sqlFetch.error_details = result.toString();
25062
+ sqlFetch.errorMessage = 'failed to execute query';
25063
+ sqlFetch.errorDetails = result.toString();
24941
25064
  } else {
24942
- sqlFetch.error_message = 'failed to execute query';
25065
+ sqlFetch.errorMessage = 'failed to execute query';
24943
25066
  }
24944
25067
  }
24945
25068
  displaySqlFetch(sqlFetch);
@@ -24947,17 +25070,18 @@
24947
25070
  } else {
24948
25071
  response.text().then((result) => {
24949
25072
  sqlFetch.state = 'error';
24950
- sqlFetch.error_message = 'failed to execute query';
24951
- sqlFetch.error_details = result;
25073
+ sqlFetch.errorMessage = 'failed to execute query';
25074
+ sqlFetch.errorDetails = result;
24952
25075
  displaySqlFetch(sqlFetch);
24953
25076
  });
24954
25077
  }
24955
25078
  })
24956
25079
  .catch(function (error) {
24957
25080
  if (sqlFetch.state === 'pending') {
25081
+ sqlFetch.endedAt = window.performance.now();
24958
25082
  sqlFetch.state = 'error';
24959
- sqlFetch.error_message = 'failed to execute query';
24960
- sqlFetch.error_details = error;
25083
+ sqlFetch.errorMessage = 'failed to execute query';
25084
+ sqlFetch.errorDetails = error;
24961
25085
  }
24962
25086
  displaySqlFetch(sqlFetch);
24963
25087
  });
@@ -25026,18 +25150,36 @@
25026
25150
  }
25027
25151
  }
25028
25152
 
25153
+ class SqlFetch {
25154
+ constructor (sql, file, variables, selection) {
25155
+ this.sql = sql;
25156
+ this.file = file;
25157
+ this.variables = variables;
25158
+ this.selection = selection;
25159
+ this.startedAt = window.performance.now();
25160
+ this.endedAt = null;
25161
+ this.state = 'pending';
25162
+ this.fetchController = new AbortController();
25163
+ this.spinner = 'never';
25164
+ this.finished = null;
25165
+ this.page = 0;
25166
+ this.pageSize = PAGE_SIZE;
25167
+ this.pageCount = null;
25168
+ }
25169
+
25170
+ abort () {
25171
+ this.state = 'aborted';
25172
+ this.endedAt = window.performance.now();
25173
+ this.spinner = 'never';
25174
+ this.fetchController.abort();
25175
+ }
25176
+
25177
+ getDuration () {
25178
+ return (this.endedAt || window.performance.now()) - this.startedAt
25179
+ }
25180
+ }
25029
25181
  function buildSqlFetch (sql, file, variables, selection) {
25030
- const sqlFetch = {
25031
- fetchController: new AbortController(),
25032
- state: 'pending',
25033
- startedAt: window.performance.now(),
25034
- spinner: 'never',
25035
- finished: null,
25036
- sql,
25037
- file,
25038
- selection,
25039
- variables
25040
- };
25182
+ const sqlFetch = new SqlFetch(sql, file, variables, selection);
25041
25183
 
25042
25184
  if (file) {
25043
25185
  const fileDetails = window.metadata.saved[file];
@@ -25053,6 +25195,50 @@
25053
25195
  return sqlFetch
25054
25196
  }
25055
25197
 
25198
+ const createCellLink = function (link, value) {
25199
+ const linkElement = document.createElement('a');
25200
+ linkElement.href = link.template.replaceAll('{*}', encodeURIComponent(value));
25201
+ linkElement.innerText = link.short_name;
25202
+ linkElement.target = '_blank';
25203
+
25204
+ const abbrElement = document.createElement('abbr');
25205
+ abbrElement.title = link.long_name;
25206
+ abbrElement.appendChild(linkElement);
25207
+
25208
+ return abbrElement
25209
+ };
25210
+
25211
+ const resultCellRenderer = function (rowElement, columnIndex, value) {
25212
+ const column = window.sqlFetch.result.columns[columnIndex];
25213
+ const columnType = window.sqlFetch.result.column_types[columnIndex];
25214
+
25215
+ if (value && window.metadata.columns[column]?.links?.length > 0) {
25216
+ const linksElement = document.createElement('div');
25217
+ window.metadata.columns[column].links.forEach((link) => {
25218
+ linksElement.appendChild(createCellLink(link, value));
25219
+ });
25220
+
25221
+ const textElement = document.createElement('div');
25222
+ textElement.classList.add('cell-value');
25223
+ textElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25224
+ textElement.innerText = value;
25225
+
25226
+ const wrapperElement = document.createElement('div');
25227
+ wrapperElement.classList.add('cell-content-wrapper');
25228
+ wrapperElement.appendChild(linksElement);
25229
+ wrapperElement.appendChild(textElement);
25230
+
25231
+ const columnElement = document.createElement('td');
25232
+ columnElement.appendChild(wrapperElement);
25233
+ rowElement.appendChild(columnElement);
25234
+ } else {
25235
+ const cellElement = document.createElement('td');
25236
+ cellElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25237
+ cellElement.innerText = value;
25238
+ rowElement.appendChild(cellElement);
25239
+ }
25240
+ };
25241
+
25056
25242
  function displaySqlFetchInResultTab (fetch) {
25057
25243
  if (fetch.state === 'pending' || fetch.spinner === 'always') {
25058
25244
  clearResultBox();
@@ -25072,13 +25258,13 @@
25072
25258
 
25073
25259
  if (fetch.state === 'aborted') {
25074
25260
  clearResultBox();
25075
- document.getElementById('result-status').innerText = 'query cancelled';
25261
+ setStatus('query cancelled');
25076
25262
  return
25077
25263
  }
25078
25264
 
25079
25265
  if (fetch.state === 'error') {
25080
25266
  clearResultBox();
25081
- displaySqlFetchError('result-status', fetch.error_message, fetch.error_details);
25267
+ displaySqlFetchError(fetch.errorMessage, fetch.errorDetails);
25082
25268
  return
25083
25269
  }
25084
25270
 
@@ -25086,58 +25272,30 @@
25086
25272
  throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
25087
25273
  }
25088
25274
 
25089
- if (document.getElementById('result-table')) {
25090
- // Results already displayed.
25091
- return
25092
- }
25093
-
25094
- clearResultBox();
25095
- displaySqlFetchResultStatus('result-status', fetch);
25096
-
25097
- const createLink = function (link, value) {
25098
- const linkElement = document.createElement('a');
25099
- linkElement.href = link.template.replaceAll('{*}', encodeURIComponent(value));
25100
- linkElement.innerText = link.short_name;
25101
- linkElement.target = '_blank';
25102
-
25103
- const abbrElement = document.createElement('abbr');
25104
- abbrElement.title = link.long_name;
25105
- abbrElement.appendChild(linkElement);
25275
+ displaySqlFetchResultStatus(fetch);
25106
25276
 
25107
- return abbrElement
25108
- };
25109
-
25110
- const cellRenderer = function (rowElement, columnIndex, value) {
25111
- const column = fetch.result.columns[columnIndex];
25112
- const columnType = fetch.result.column_types[columnIndex];
25113
-
25114
- if (value && window.metadata.columns[column]?.links?.length > 0) {
25115
- const linksElement = document.createElement('div');
25116
- window.metadata.columns[column].links.forEach((link) => {
25117
- linksElement.appendChild(createLink(link, value));
25118
- });
25119
-
25120
- const textElement = document.createElement('div');
25121
- textElement.classList.add('cell-value');
25122
- textElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25123
- textElement.innerText = value;
25124
-
25125
- const wrapperElement = document.createElement('div');
25126
- wrapperElement.classList.add('cell-content-wrapper');
25127
- wrapperElement.appendChild(linksElement);
25128
- wrapperElement.appendChild(textElement);
25129
-
25130
- const columnElement = document.createElement('td');
25131
- columnElement.appendChild(wrapperElement);
25132
- rowElement.appendChild(columnElement);
25133
- } else {
25134
- const cellElement = document.createElement('td');
25135
- cellElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25136
- cellElement.innerText = value;
25137
- rowElement.appendChild(cellElement);
25277
+ const resultBody = document.querySelector('table[id="result-table"] > tbody');
25278
+ const pageStart = fetch.page * fetch.pageSize;
25279
+ const rows = fetch.result.rows.slice(pageStart, pageStart + fetch.pageSize);
25280
+ if (resultBody) {
25281
+ if (resultBody.dataset.page === fetch.page) {
25282
+ // Results already displayed.
25283
+ return
25138
25284
  }
25139
- };
25140
- createTable(document.getElementById('result-box'), fetch.result.columns, fetch.result.rows, 'result-table', cellRenderer);
25285
+ resultBody.parentElement.removeChild(resultBody);
25286
+ createTableBody(rows, document.getElementById('result-table'), resultCellRenderer);
25287
+ } else {
25288
+ clearResultBox();
25289
+ createTable(
25290
+ document.getElementById('result-box'),
25291
+ fetch.result.columns,
25292
+ rows,
25293
+ 'result-table',
25294
+ resultCellRenderer);
25295
+ }
25296
+ document
25297
+ .querySelector('table[id="result-table"] > tbody')
25298
+ .setAttribute('data-page', fetch.page);
25141
25299
  }
25142
25300
 
25143
25301
  function disableDownloadButtons () {
@@ -25169,8 +25327,7 @@
25169
25327
  }
25170
25328
  }
25171
25329
 
25172
- function displaySqlFetchError (statusElementId, message, details) {
25173
- const statusElement = document.getElementById(statusElementId);
25330
+ function displaySqlFetchError (message, details) {
25174
25331
  let statusMessage = 'error: ' + message;
25175
25332
  if (statusMessage.length > 90) {
25176
25333
  statusMessage = statusMessage.substring(0, 90) + '…';
@@ -25179,7 +25336,7 @@
25179
25336
  console.log(`${message}\n${details}`);
25180
25337
  statusMessage += ' (check console)';
25181
25338
  }
25182
- statusElement.innerText = statusMessage;
25339
+ setStatus(statusMessage);
25183
25340
  }
25184
25341
 
25185
25342
  function clearSpinner () {
@@ -25229,13 +25386,13 @@
25229
25386
 
25230
25387
  if (fetch.state === 'aborted') {
25231
25388
  clearGraphBox();
25232
- document.getElementById('graph-status').innerText = 'query cancelled';
25389
+ setStatus('query cancelled');
25233
25390
  return
25234
25391
  }
25235
25392
 
25236
25393
  if (fetch.state === 'error') {
25237
25394
  clearGraphBox();
25238
- displaySqlFetchError('graph-status', fetch.error_message, fetch.error_details);
25395
+ displaySqlFetchError(fetch.errorMessage, fetch.errorDetails);
25239
25396
  return
25240
25397
  }
25241
25398
 
@@ -25243,7 +25400,7 @@
25243
25400
  throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
25244
25401
  }
25245
25402
  clearGraphBox();
25246
- displaySqlFetchResultStatus('graph-status', fetch);
25403
+ displaySqlFetchResultStatus(fetch);
25247
25404
 
25248
25405
  if (!fetch.result.rows) {
25249
25406
  return
@@ -25282,24 +25439,30 @@
25282
25439
  chart.draw(dataTable, options);
25283
25440
  }
25284
25441
 
25285
- function displaySqlFetchResultStatus (statusElementId, sqlFetch) {
25442
+ function displaySqlFetchResultStatus (sqlFetch) {
25286
25443
  const result = sqlFetch.result;
25287
- const statusElement = document.getElementById(statusElementId);
25288
- const elapsed = Math.round(100 * (window.performance.now() - sqlFetch.startedAt) / 1000.0) / 100;
25444
+ const elapsed = Math.round(100 * (sqlFetch.getDuration() / 1000.0)) / 100;
25289
25445
 
25446
+ let message;
25290
25447
  if (result.total_rows === 1) {
25291
- statusElement.innerText = `${result.total_rows} row (${elapsed}s)`;
25448
+ message = `${result.total_rows} row (${elapsed}s)`;
25292
25449
  } else {
25293
- statusElement.innerText = `${result.total_rows.toLocaleString()} rows (${elapsed}s)`;
25450
+ message = `${result.total_rows.toLocaleString()} rows (${elapsed}s)`;
25294
25451
  }
25295
25452
 
25296
25453
  if (result.total_rows > result.rows.length) {
25297
- statusElement.innerText += ` (truncated to ${result.rows.length})`;
25454
+ message += ` (truncated to ${result.rows.length})`;
25455
+ }
25456
+ setStatus(message);
25457
+
25458
+ const pageCountBox = document.getElementById('page-count-box');
25459
+ pageCountBox.style.display = 'flex';
25460
+ pageCountBox.innerText = `${sqlFetch.page + 1} of ${sqlFetch.pageCount}`;
25461
+ if (sqlFetch.pageCount > 1) {
25462
+ document.getElementById('pagination-box').style.display = 'flex';
25463
+ document.getElementById('next-button').disabled = sqlFetch.page + 1 === sqlFetch.pageCount;
25464
+ document.getElementById('prev-button').disabled = sqlFetch.page === 0;
25298
25465
  }
25299
- }
25300
-
25301
- function setSavedStatus (status) {
25302
- document.getElementById('saved-status').innerText = status;
25303
25466
  }
25304
25467
 
25305
25468
  window.addEventListener('popstate', function (event) {