sqlui 0.1.54 → 0.1.56

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ ];
11742
+ }
11743
+ function configChanged(update) {
11744
+ return update.startState.facet(selectionConfig) != update.startState.facet(selectionConfig);
11699
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: "'ƒ'" }
@@ -24182,17 +24295,22 @@
24182
24295
  return match ? match[1] : identifier
24183
24296
  }
24184
24297
 
24185
- const drag = {
24186
- containerElement: null,
24187
- tableElement: null,
24188
- thElement: null,
24189
- colElement: null,
24190
- otherColWidths: null,
24191
- lastColElement: null
24192
- };
24298
+ class Drag {
24299
+ scrolled = null
24300
+ scrollOffset = null
24301
+ containerOffset = null
24302
+ containerWidth = null
24303
+ thElement = null
24304
+ colElement = null
24305
+ otherColWidths = null
24306
+ lastColElement = null
24307
+ }
24308
+
24309
+ let drag = new Drag();
24193
24310
 
24194
24311
  document.addEventListener('mousedown', (event) => {
24195
24312
  if (event.target.classList.contains('col-resizer')) {
24313
+ drag = new Drag();
24196
24314
  event.preventDefault();
24197
24315
  const thElement = event.target.parentElement.parentElement;
24198
24316
  if (thElement.tagName.toLowerCase() !== 'th') {
@@ -24200,57 +24318,43 @@
24200
24318
  }
24201
24319
  const trElement = thElement.parentElement;
24202
24320
  const theadElement = trElement.parentElement;
24203
- drag.tableElement = theadElement.parentElement;
24204
- drag.containerElement = drag.tableElement.parentElement;
24321
+ const tableElement = theadElement.parentElement;
24322
+ const containerElement = tableElement.parentElement;
24323
+ drag.containerWidth = containerElement.clientWidth;
24324
+ drag.scrollOffset = containerElement.scrollLeft;
24325
+ drag.scrolled = drag.scrollOffset > 0;
24326
+ drag.containerOffset = containerElement.offsetLeft;
24205
24327
  drag.thElement = thElement;
24206
24328
  drag.colElement = document.getElementById(event.target.dataset.colId);
24207
24329
 
24208
24330
  const colElements = Array.from(drag.colElement.parentElement.childNodes);
24209
24331
  drag.lastColElement = colElements[colElements.length - 1];
24210
- drag.otherColWidths = [];
24332
+ drag.otherColsWidth = 0;
24211
24333
  for (let i = 0; i < colElements.length - 1; i++) {
24212
24334
  if (colElements[i] !== drag.colElement) {
24213
- drag.otherColWidths.push(colElements[i].getBoundingClientRect().width);
24335
+ drag.otherColsWidth += colElements[i].getBoundingClientRect().width;
24214
24336
  }
24337
+ colElements[i].style.width = `${colElements[i].getBoundingClientRect().width}px`;
24215
24338
  }
24216
- colElements.forEach((element) => {
24217
- element.style.width = `${element.getBoundingClientRect().width}px`;
24218
- });
24219
- drag.tableElement.style.tableLayout = 'fixed';
24339
+ tableElement.style.tableLayout = 'fixed';
24220
24340
  }
24221
24341
  });
24222
24342
 
24223
24343
  document.addEventListener('mouseup', (event) => {
24224
- drag.containerElement = null;
24225
- drag.tableElement = null;
24226
- drag.thElement = null;
24227
- drag.colElement = null;
24228
- drag.otherColWidths = null;
24229
- drag.lastColElement = null;
24344
+ drag = new Drag();
24230
24345
  });
24231
24346
 
24232
24347
  document.addEventListener('mousemove', (event) => {
24233
- if (drag.colElement) {
24234
- const scrollOffset = drag.containerElement.scrollLeft;
24235
- const scrolled = scrollOffset > 0;
24236
- const containerOffset = drag.containerElement.offsetLeft;
24237
- const newColumnWidth = Math.max(0, scrollOffset + (event.clientX - containerOffset) - drag.thElement.offsetLeft);
24238
- if (newColumnWidth < drag.colElement.getBoundingClientRect().width && newColumnWidth < 30) return
24239
-
24240
- drag.colElement.style.width = `${newColumnWidth}px`;
24241
- let runningWidth = newColumnWidth;
24242
- drag.otherColWidths.forEach((width) => {
24243
- runningWidth += width;
24244
- });
24245
- let remainingWidth;
24246
- if (scrolled) {
24247
- remainingWidth = (scrollOffset + drag.containerElement.getBoundingClientRect().width) - runningWidth;
24248
- } else {
24249
- remainingWidth = Math.max(10, drag.containerElement.getBoundingClientRect().width - runningWidth);
24250
- }
24251
- drag.lastColElement.style.width = `${remainingWidth}px`;
24252
- runningWidth += remainingWidth;
24253
- drag.tableElement.style.width = `${runningWidth}px`;
24348
+ if (!drag.colElement) return
24349
+
24350
+ const newColumnWidth = Math.max(0, drag.scrollOffset + (event.clientX - drag.containerOffset) - drag.thElement.offsetLeft);
24351
+ if (newColumnWidth < drag.colElement.getBoundingClientRect().width && newColumnWidth < 30) return
24352
+
24353
+ drag.colElement.style.width = `${newColumnWidth}px`;
24354
+ if (drag.scrolled) {
24355
+ drag.lastColElement.style.width = ((drag.scrollOffset + drag.containerWidth) - (newColumnWidth + drag.otherColsWidth)) + 'px';
24356
+ } else {
24357
+ drag.lastColElement.style.width = (Math.max(10, drag.containerWidth - (newColumnWidth + drag.otherColsWidth))) + 'px';
24254
24358
  }
24255
24359
  });
24256
24360
 
@@ -24261,7 +24365,9 @@
24261
24365
  if (!id) throw new Error('missing table id')
24262
24366
 
24263
24367
  const tableElement = document.createElement('table');
24368
+ containerElement.appendChild(tableElement);
24264
24369
  if (id) tableElement.id = id;
24370
+ tableElement.style.tableLayout = 'auto';
24265
24371
 
24266
24372
  const colgroupElement = document.createElement('colgroup');
24267
24373
  tableElement.appendChild(colgroupElement);
@@ -24269,51 +24375,55 @@
24269
24375
  const theadElement = document.createElement('thead');
24270
24376
  tableElement.appendChild(theadElement);
24271
24377
 
24272
- const tbodyElement = document.createElement('tbody');
24273
- tableElement.appendChild(tbodyElement);
24274
-
24275
24378
  const headerTrElement = document.createElement('tr');
24276
24379
  theadElement.appendChild(headerTrElement);
24277
24380
 
24278
- const nonLastColElements = [];
24279
- columns.forEach(function (column, index) {
24280
- const headerElement = document.createElement('th');
24281
- headerTrElement.appendChild(headerElement);
24282
-
24283
- const contentWrapperElement = document.createElement('div');
24284
- contentWrapperElement.classList.add('col-content-wrapper');
24285
- headerElement.appendChild(contentWrapperElement);
24286
-
24287
- const nameElement = document.createElement('div');
24288
- nameElement.classList.add('col-name');
24289
- contentWrapperElement.appendChild(nameElement);
24290
-
24291
- const colElement = document.createElement('col');
24292
- colElement.id = `${id}-col-${index}`;
24293
- colgroupElement.appendChild(colElement);
24294
- nonLastColElements.push(colElement);
24295
-
24296
- const resizerElement = document.createElement('div');
24297
- resizerElement.classList.add('col-resizer');
24298
- resizerElement.dataset.colId = colElement.id;
24299
- contentWrapperElement.appendChild(resizerElement);
24300
-
24301
- nameElement.innerText = column;
24302
- });
24303
24381
  if (columns.length > 0) {
24382
+ const colElements = [];
24383
+ columns.forEach(function (column, index) {
24384
+ const headerElement = document.createElement('th');
24385
+ headerTrElement.appendChild(headerElement);
24386
+
24387
+ const contentWrapperElement = document.createElement('div');
24388
+ contentWrapperElement.classList.add('col-content-wrapper');
24389
+ headerElement.appendChild(contentWrapperElement);
24390
+
24391
+ const nameElement = document.createElement('div');
24392
+ nameElement.classList.add('col-name');
24393
+ contentWrapperElement.appendChild(nameElement);
24394
+
24395
+ const colElement = document.createElement('col');
24396
+ colElement.id = `${id}-col-${index}`;
24397
+ colgroupElement.appendChild(colElement);
24398
+ colElements.push(colElement);
24399
+
24400
+ const resizerElement = document.createElement('div');
24401
+ resizerElement.classList.add('col-resizer');
24402
+ resizerElement.dataset.colId = colElement.id;
24403
+ contentWrapperElement.appendChild(resizerElement);
24404
+
24405
+ nameElement.innerText = column;
24406
+ });
24407
+
24304
24408
  headerTrElement.appendChild(document.createElement('th'));
24305
24409
  const lastColElement = document.createElement('col');
24306
24410
  lastColElement.style.width = '100%';
24411
+ colElements.push(lastColElement);
24412
+
24413
+ let columnsWidth;
24307
24414
  function resize () {
24308
- let runningWidth = 0;
24309
- const colElements = Array.from(tableElement.getElementsByTagName('col'));
24310
- nonLastColElements.forEach((element, index) => {
24311
- runningWidth += element.getBoundingClientRect().width;
24312
- });
24313
- const remainingWidth = Math.max(10, containerElement.getBoundingClientRect().width - runningWidth);
24314
- colElements[colElements.length - 1].style.width = `${remainingWidth}px`;
24315
- runningWidth += remainingWidth;
24316
- tableElement.style.width = `${runningWidth}px`;
24415
+ if (tableElement.style.tableLayout === 'auto') {
24416
+ return
24417
+ }
24418
+ if (!columnsWidth) {
24419
+ columnsWidth = 0;
24420
+ colElements.slice(0, -1).forEach((element, index) => {
24421
+ columnsWidth += element.getBoundingClientRect().width;
24422
+ });
24423
+ }
24424
+ const remainingWidth = Math.max(10, containerElement.clientWidth - columnsWidth);
24425
+ colElements.slice(-1)[0].style.width = `${remainingWidth}px`;
24426
+ tableElement.style.width = `${columnsWidth + remainingWidth}px`;
24317
24427
  }
24318
24428
 
24319
24429
  const resizeObserver = new ResizeObserver(resize);
@@ -24328,7 +24438,26 @@
24328
24438
  });
24329
24439
  mutationObserver.observe(containerElement, { childList: true });
24330
24440
  colgroupElement.appendChild(lastColElement);
24441
+
24442
+ setTableBody(rows, tableElement, cellRenderer);
24331
24443
  }
24444
+
24445
+ return tableElement
24446
+ }
24447
+
24448
+ function getTableBody (tableElement) {
24449
+ return tableElement.getElementsByTagName('tbody')[0]
24450
+ }
24451
+
24452
+ function setTableBody (rows, tableElement, cellRenderer) {
24453
+ tableElement.style.tableLayout = 'auto';
24454
+
24455
+ let tbodyElement = getTableBody(tableElement);
24456
+ tbodyElement?.parentElement?.removeChild(tbodyElement);
24457
+
24458
+ tbodyElement = document.createElement('tbody');
24459
+ tableElement.appendChild(tbodyElement);
24460
+
24332
24461
  let highlight = false;
24333
24462
  rows.forEach(function (row) {
24334
24463
  const rowElement = document.createElement('tr');
@@ -24348,11 +24477,12 @@
24348
24477
  });
24349
24478
  rowElement.appendChild(document.createElement('td'));
24350
24479
  });
24351
- containerElement.appendChild(tableElement);
24352
24480
  }
24353
24481
 
24354
24482
  /* global google */
24355
24483
 
24484
+ const PAGE_SIZE = 500;
24485
+
24356
24486
  function getSqlFromUrl (url) {
24357
24487
  const params = url.searchParams;
24358
24488
  if (params.has('file') && params.has('sql')) {
@@ -24418,6 +24548,14 @@
24418
24548
  copyTextToClipboard(toTsv(window.sqlFetch.result.columns, window.sqlFetch.result.rows));
24419
24549
  }
24420
24550
  });
24551
+ addClickListener(document.getElementById('prev-button'), (event) => {
24552
+ window.sqlFetch.page -= 1;
24553
+ displaySqlFetch(window.sqlFetch);
24554
+ });
24555
+ addClickListener(document.getElementById('next-button'), (event) => {
24556
+ window.sqlFetch.page += 1;
24557
+ displaySqlFetch(window.sqlFetch);
24558
+ });
24421
24559
  addClickListener(document.getElementById('submit-dropdown-button-download-csv'), () => {
24422
24560
  if (!window.sqlFetch?.result) return
24423
24561
 
@@ -24566,6 +24704,8 @@
24566
24704
  selected.style.display = 'none';
24567
24705
  });
24568
24706
 
24707
+ setStatus('');
24708
+
24569
24709
  switch (window.tab) {
24570
24710
  case 'query':
24571
24711
  selectResultTab(internal);
@@ -24707,7 +24847,6 @@
24707
24847
  document.getElementById('query-box').style.display = 'flex';
24708
24848
  document.getElementById('submit-box').style.display = 'flex';
24709
24849
  document.getElementById('graph-box').style.display = 'flex';
24710
- document.getElementById('graph-status').style.display = 'flex';
24711
24850
  document.getElementById('fetch-sql-box').style.display = 'none';
24712
24851
  document.getElementById('cancel-button').style.display = 'none';
24713
24852
  updateDownloadButtons(window?.sqlFetch);
@@ -24720,7 +24859,6 @@
24720
24859
  document.getElementById('query-box').style.display = 'flex';
24721
24860
  document.getElementById('submit-box').style.display = 'flex';
24722
24861
  document.getElementById('result-box').style.display = 'flex';
24723
- document.getElementById('result-status').style.display = 'flex';
24724
24862
  document.getElementById('fetch-sql-box').style.display = 'none';
24725
24863
  document.getElementById('cancel-button').style.display = 'none';
24726
24864
  focus(getSelection());
@@ -24732,17 +24870,15 @@
24732
24870
  selected.style.display = 'flex';
24733
24871
  });
24734
24872
 
24735
- if (window.savedLoaded) {
24736
- return
24737
- }
24738
-
24739
24873
  const savedElement = document.getElementById('saved-box');
24874
+ const saved = window.metadata.saved;
24875
+ const numFiles = Object.keys(saved).length;
24876
+ setStatus(`${numFiles} file${numFiles === 1 ? '' : 's'}`);
24877
+
24740
24878
  if (savedElement.children.length > 0) {
24741
24879
  return
24742
24880
  }
24743
- const saved = window.metadata.saved;
24744
- const numFiles = Object.keys(saved).length;
24745
- setSavedStatus(`${numFiles} file${numFiles === 1 ? '' : 's'}`);
24881
+
24746
24882
  Object.values(saved).forEach(file => {
24747
24883
  const viewUrl = new URL(window.location.origin + window.location.pathname);
24748
24884
  setActionInUrl(viewUrl, 'query');
@@ -24791,7 +24927,6 @@
24791
24927
 
24792
24928
  savedElement.appendChild(divElement);
24793
24929
  });
24794
- window.savedLoaded = true;
24795
24930
  }
24796
24931
 
24797
24932
  function submitAll (target, event) {
@@ -24847,27 +24982,25 @@
24847
24982
 
24848
24983
  function clearResult () {
24849
24984
  if (window.sqlFetch?.state === 'pending' || window.sqlFetch?.spinner === 'always') {
24850
- window.sqlFetch.state = 'aborted';
24851
- window.sqlFetch.spinner = 'never';
24852
- window.sqlFetch.fetchController.abort();
24985
+ window.sqlFetch.abort();
24853
24986
  displaySqlFetch(window.sqlFetch);
24854
24987
  return
24855
24988
  }
24856
24989
  window.sqlFetch = null;
24857
24990
  clearSpinner();
24858
24991
  clearGraphBox();
24859
- clearGraphStatus();
24992
+ clearStatus();
24860
24993
  clearResultBox();
24861
- clearResultStatus();
24862
24994
  disableDownloadButtons();
24863
24995
  }
24864
24996
 
24865
- function clearResultStatus () {
24866
- document.getElementById('result-status').innerText = '';
24997
+ function clearStatus () {
24998
+ document.getElementById('status-message').innerText = '';
24867
24999
  }
24868
25000
 
24869
- function clearGraphStatus () {
24870
- document.getElementById('graph-status').innerText = '';
25001
+ function setStatus (message) {
25002
+ const element = document.getElementById('status-message');
25003
+ element.innerText = message;
24871
25004
  }
24872
25005
 
24873
25006
  function clearResultBox () {
@@ -24924,22 +25057,24 @@
24924
25057
  signal: sqlFetch.fetchController.signal
24925
25058
  })
24926
25059
  .then((response) => {
25060
+ sqlFetch.endedAt = window.performance.now();
24927
25061
  const contentType = response.headers.get('content-type');
24928
25062
  if (contentType && contentType.indexOf('application/json') !== -1) {
24929
25063
  response.json().then((result) => {
24930
25064
  if (result?.query) {
24931
25065
  sqlFetch.state = 'success';
24932
25066
  sqlFetch.result = result;
25067
+ sqlFetch.pageCount = Math.ceil(result.rows.length / sqlFetch.pageSize);
24933
25068
  } else {
24934
25069
  sqlFetch.state = 'error';
24935
25070
  if (result?.error) {
24936
- sqlFetch.error_message = result.error;
24937
- sqlFetch.error_details = result.stacktrace;
25071
+ sqlFetch.errorMessage = result.error;
25072
+ sqlFetch.errorDetails = result.stacktrace;
24938
25073
  } else if (result) {
24939
- sqlFetch.error_message = 'failed to execute query';
24940
- sqlFetch.error_details = result.toString();
25074
+ sqlFetch.errorMessage = 'failed to execute query';
25075
+ sqlFetch.errorDetails = result.toString();
24941
25076
  } else {
24942
- sqlFetch.error_message = 'failed to execute query';
25077
+ sqlFetch.errorMessage = 'failed to execute query';
24943
25078
  }
24944
25079
  }
24945
25080
  displaySqlFetch(sqlFetch);
@@ -24947,17 +25082,18 @@
24947
25082
  } else {
24948
25083
  response.text().then((result) => {
24949
25084
  sqlFetch.state = 'error';
24950
- sqlFetch.error_message = 'failed to execute query';
24951
- sqlFetch.error_details = result;
25085
+ sqlFetch.errorMessage = 'failed to execute query';
25086
+ sqlFetch.errorDetails = result;
24952
25087
  displaySqlFetch(sqlFetch);
24953
25088
  });
24954
25089
  }
24955
25090
  })
24956
25091
  .catch(function (error) {
24957
25092
  if (sqlFetch.state === 'pending') {
25093
+ sqlFetch.endedAt = window.performance.now();
24958
25094
  sqlFetch.state = 'error';
24959
- sqlFetch.error_message = 'failed to execute query';
24960
- sqlFetch.error_details = error;
25095
+ sqlFetch.errorMessage = 'failed to execute query';
25096
+ sqlFetch.errorDetails = error;
24961
25097
  }
24962
25098
  displaySqlFetch(sqlFetch);
24963
25099
  });
@@ -25026,18 +25162,36 @@
25026
25162
  }
25027
25163
  }
25028
25164
 
25165
+ class SqlFetch {
25166
+ constructor (sql, file, variables, selection) {
25167
+ this.sql = sql;
25168
+ this.file = file;
25169
+ this.variables = variables;
25170
+ this.selection = selection;
25171
+ this.startedAt = window.performance.now();
25172
+ this.endedAt = null;
25173
+ this.state = 'pending';
25174
+ this.fetchController = new AbortController();
25175
+ this.spinner = 'never';
25176
+ this.finished = null;
25177
+ this.page = 0;
25178
+ this.pageSize = PAGE_SIZE;
25179
+ this.pageCount = null;
25180
+ }
25181
+
25182
+ abort () {
25183
+ this.state = 'aborted';
25184
+ this.endedAt = window.performance.now();
25185
+ this.spinner = 'never';
25186
+ this.fetchController.abort();
25187
+ }
25188
+
25189
+ getDuration () {
25190
+ return (this.endedAt || window.performance.now()) - this.startedAt
25191
+ }
25192
+ }
25029
25193
  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
- };
25194
+ const sqlFetch = new SqlFetch(sql, file, variables, selection);
25041
25195
 
25042
25196
  if (file) {
25043
25197
  const fileDetails = window.metadata.saved[file];
@@ -25053,6 +25207,50 @@
25053
25207
  return sqlFetch
25054
25208
  }
25055
25209
 
25210
+ const createCellLink = function (link, value) {
25211
+ const linkElement = document.createElement('a');
25212
+ linkElement.href = link.template.replaceAll('{*}', encodeURIComponent(value));
25213
+ linkElement.innerText = link.short_name;
25214
+ linkElement.target = '_blank';
25215
+
25216
+ const abbrElement = document.createElement('abbr');
25217
+ abbrElement.title = link.long_name;
25218
+ abbrElement.appendChild(linkElement);
25219
+
25220
+ return abbrElement
25221
+ };
25222
+
25223
+ const resultCellRenderer = function (rowElement, columnIndex, value) {
25224
+ const column = window.sqlFetch.result.columns[columnIndex];
25225
+ const columnType = window.sqlFetch.result.column_types[columnIndex];
25226
+
25227
+ if (value && window.metadata.columns[column]?.links?.length > 0) {
25228
+ const linksElement = document.createElement('div');
25229
+ window.metadata.columns[column].links.forEach((link) => {
25230
+ linksElement.appendChild(createCellLink(link, value));
25231
+ });
25232
+
25233
+ const textElement = document.createElement('div');
25234
+ textElement.classList.add('cell-value');
25235
+ textElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25236
+ textElement.innerText = value;
25237
+
25238
+ const wrapperElement = document.createElement('div');
25239
+ wrapperElement.classList.add('cell-content-wrapper');
25240
+ wrapperElement.appendChild(linksElement);
25241
+ wrapperElement.appendChild(textElement);
25242
+
25243
+ const columnElement = document.createElement('td');
25244
+ columnElement.appendChild(wrapperElement);
25245
+ rowElement.appendChild(columnElement);
25246
+ } else {
25247
+ const cellElement = document.createElement('td');
25248
+ cellElement.style.textAlign = columnType === 'string' ? 'left' : 'right';
25249
+ cellElement.innerText = value;
25250
+ rowElement.appendChild(cellElement);
25251
+ }
25252
+ };
25253
+
25056
25254
  function displaySqlFetchInResultTab (fetch) {
25057
25255
  if (fetch.state === 'pending' || fetch.spinner === 'always') {
25058
25256
  clearResultBox();
@@ -25072,13 +25270,13 @@
25072
25270
 
25073
25271
  if (fetch.state === 'aborted') {
25074
25272
  clearResultBox();
25075
- document.getElementById('result-status').innerText = 'query cancelled';
25273
+ setStatus('query cancelled');
25076
25274
  return
25077
25275
  }
25078
25276
 
25079
25277
  if (fetch.state === 'error') {
25080
25278
  clearResultBox();
25081
- displaySqlFetchError('result-status', fetch.error_message, fetch.error_details);
25279
+ displaySqlFetchError(fetch.errorMessage, fetch.errorDetails);
25082
25280
  return
25083
25281
  }
25084
25282
 
@@ -25086,58 +25284,29 @@
25086
25284
  throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
25087
25285
  }
25088
25286
 
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);
25106
-
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;
25287
+ displaySqlFetchResultStatus(fetch);
25124
25288
 
25125
- const wrapperElement = document.createElement('div');
25126
- wrapperElement.classList.add('cell-content-wrapper');
25127
- wrapperElement.appendChild(linksElement);
25128
- wrapperElement.appendChild(textElement);
25289
+ const pageStart = fetch.page * fetch.pageSize;
25290
+ const rows = fetch.result.rows.slice(pageStart, pageStart + fetch.pageSize);
25129
25291
 
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);
25292
+ let tableElement = document.getElementById('result-table');
25293
+ if (tableElement) {
25294
+ const resultBody = getTableBody(tableElement);
25295
+ if (resultBody.dataset.page === fetch.page) {
25296
+ // Results already displayed.
25297
+ return
25138
25298
  }
25139
- };
25140
- createTable(document.getElementById('result-box'), fetch.result.columns, fetch.result.rows, 'result-table', cellRenderer);
25299
+ setTableBody(rows, tableElement, resultCellRenderer);
25300
+ } else {
25301
+ clearResultBox();
25302
+ tableElement = createTable(
25303
+ document.getElementById('result-box'),
25304
+ fetch.result.columns,
25305
+ rows,
25306
+ 'result-table',
25307
+ resultCellRenderer);
25308
+ }
25309
+ tableElement.setAttribute('data-page', fetch.page);
25141
25310
  }
25142
25311
 
25143
25312
  function disableDownloadButtons () {
@@ -25169,8 +25338,7 @@
25169
25338
  }
25170
25339
  }
25171
25340
 
25172
- function displaySqlFetchError (statusElementId, message, details) {
25173
- const statusElement = document.getElementById(statusElementId);
25341
+ function displaySqlFetchError (message, details) {
25174
25342
  let statusMessage = 'error: ' + message;
25175
25343
  if (statusMessage.length > 90) {
25176
25344
  statusMessage = statusMessage.substring(0, 90) + '…';
@@ -25179,7 +25347,7 @@
25179
25347
  console.log(`${message}\n${details}`);
25180
25348
  statusMessage += ' (check console)';
25181
25349
  }
25182
- statusElement.innerText = statusMessage;
25350
+ setStatus(statusMessage);
25183
25351
  }
25184
25352
 
25185
25353
  function clearSpinner () {
@@ -25229,13 +25397,13 @@
25229
25397
 
25230
25398
  if (fetch.state === 'aborted') {
25231
25399
  clearGraphBox();
25232
- document.getElementById('graph-status').innerText = 'query cancelled';
25400
+ setStatus('query cancelled');
25233
25401
  return
25234
25402
  }
25235
25403
 
25236
25404
  if (fetch.state === 'error') {
25237
25405
  clearGraphBox();
25238
- displaySqlFetchError('graph-status', fetch.error_message, fetch.error_details);
25406
+ displaySqlFetchError(fetch.errorMessage, fetch.errorDetails);
25239
25407
  return
25240
25408
  }
25241
25409
 
@@ -25243,7 +25411,7 @@
25243
25411
  throw new Error(`unexpected fetch sql request status: ${fetch.status}`)
25244
25412
  }
25245
25413
  clearGraphBox();
25246
- displaySqlFetchResultStatus('graph-status', fetch);
25414
+ displaySqlFetchResultStatus(fetch);
25247
25415
 
25248
25416
  if (!fetch.result.rows) {
25249
25417
  return
@@ -25282,24 +25450,30 @@
25282
25450
  chart.draw(dataTable, options);
25283
25451
  }
25284
25452
 
25285
- function displaySqlFetchResultStatus (statusElementId, sqlFetch) {
25453
+ function displaySqlFetchResultStatus (sqlFetch) {
25286
25454
  const result = sqlFetch.result;
25287
- const statusElement = document.getElementById(statusElementId);
25288
- const elapsed = Math.round(100 * (window.performance.now() - sqlFetch.startedAt) / 1000.0) / 100;
25455
+ const elapsed = Math.round(100 * (sqlFetch.getDuration() / 1000.0)) / 100;
25289
25456
 
25457
+ let message;
25290
25458
  if (result.total_rows === 1) {
25291
- statusElement.innerText = `${result.total_rows} row (${elapsed}s)`;
25459
+ message = `${result.total_rows} row (${elapsed}s)`;
25292
25460
  } else {
25293
- statusElement.innerText = `${result.total_rows.toLocaleString()} rows (${elapsed}s)`;
25461
+ message = `${result.total_rows.toLocaleString()} rows (${elapsed}s)`;
25294
25462
  }
25295
25463
 
25296
25464
  if (result.total_rows > result.rows.length) {
25297
- statusElement.innerText += ` (truncated to ${result.rows.length})`;
25465
+ message += ` (truncated to ${result.rows.length})`;
25466
+ }
25467
+ setStatus(message);
25468
+
25469
+ const pageCountBox = document.getElementById('page-count-box');
25470
+ pageCountBox.style.display = 'flex';
25471
+ pageCountBox.innerText = `${sqlFetch.page + 1} of ${sqlFetch.pageCount}`;
25472
+ if (sqlFetch.pageCount > 1) {
25473
+ document.getElementById('pagination-box').style.display = 'flex';
25474
+ document.getElementById('next-button').disabled = sqlFetch.page + 1 === sqlFetch.pageCount;
25475
+ document.getElementById('prev-button').disabled = sqlFetch.page === 0;
25298
25476
  }
25299
- }
25300
-
25301
- function setSavedStatus (status) {
25302
- document.getElementById('saved-status').innerText = status;
25303
25477
  }
25304
25478
 
25305
25479
  window.addEventListener('popstate', function (event) {