@yuneta/gobj-ui 7.23.156 → 7.23.158

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.
@@ -6,7 +6,7 @@ import { createJSONEditor } from "vanilla-jsoneditor";
6
6
  import { TabulatorFull } from "tabulator-tables";
7
7
  import * as maplibregl from "maplibre-gl";
8
8
  import uPlot from "uplot";
9
- import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, Cubic, CubicHorizontal, DragCanvas, EdgeEvent, ExtensionCategory, Graph, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
9
+ import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, DragCanvas, EdgeEvent, ExtensionCategory, Graph, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
10
10
  //#region \0rolldown/runtime.js
11
11
  var __create = Object.create;
12
12
  var __defProp = Object.defineProperty;
@@ -29309,321 +29309,6 @@ function tidy_tree_lr(nodes, edges, o) {
29309
29309
  }
29310
29310
  return pos;
29311
29311
  }
29312
- /************************************************************
29313
- * The compact tree.
29314
- *
29315
- * The tidy tree above gives every subtree its whole BLOCK: open a
29316
- * hall with twenty-four devices and its block widens, and with it
29317
- * every block above it, so the siblings of its ancestors move apart
29318
- * at depths where nothing of theirs touches. This one keeps the
29319
- * CONTOUR of each subtree instead -- its outline on each side, depth
29320
- * by depth -- and slides every sibling against the outline of the
29321
- * ones before it. A folded region then sits as close to an open one
29322
- * as their cards allow at each depth, which is what a folded treedb
29323
- * is: one branch open among closed ones.
29324
- *
29325
- * Same spanning tree, same order, same rows as the tidy tree: only
29326
- * the packing across the depths differs, so switching between the
29327
- * two moves cards sideways and never reorders them.
29328
- *
29329
- * And a run of three or more LEAF children -- a hall's devices, a
29330
- * region's places when none is open -- is STACKED: two columns
29331
- * under the parent with a corridor between them, row after row.
29332
- * That is what makes it compact when a whole level is open, where
29333
- * the contour alone gains nothing: every parent needed the whole
29334
- * row of its children beside it. The tree grows taller instead of
29335
- * wider. Its elbow edges run down the corridor (elbow_combs).
29336
- *
29337
- * The contour arithmetic is Moen's ("Drawing dynamic trees", IEEE
29338
- * Software, 1990) in the form mxGraph gave it in mxCompactTreeLayout
29339
- * -- Copyright (c) 2006-2015 JGraph Ltd, Apache License 2.0 -- read in
29340
- * maxGraph's CompactTreeLayout.ts: leaf, join, merge, offset and
29341
- * bridge below follow that form. What is ours: it runs on the
29342
- * spanning tree of a FOREST, every depth is a row as wide as its
29343
- * widest card (mxGraph's `alignRanks`), several roots sit side by
29344
- * side, and there is no recursion.
29345
- ************************************************************/
29346
- function layout_compact(nodes, edges, opts) {
29347
- let o = Object.assign({}, DEFAULTS, opts || {});
29348
- if (o.direction === "LR") return compact_tree_lr(nodes, edges, o);
29349
- let lr = compact_tree_lr(nodes.map((n) => Object.assign({}, n, {
29350
- w: n.h,
29351
- h: n.w
29352
- })), edges, o);
29353
- let pos = /* @__PURE__ */ new Map();
29354
- for (let [id, p] of lr) pos.set(id, {
29355
- x: p.y,
29356
- y: p.x
29357
- });
29358
- return pos;
29359
- }
29360
- function contour_line(dx, dy, next) {
29361
- return {
29362
- dx,
29363
- dy,
29364
- next: next || null
29365
- };
29366
- }
29367
- function contour_offset(p1, p2, a1, a2, b1, b2) {
29368
- if (b1 <= p1 || p1 + a1 <= 0) return 0;
29369
- let d;
29370
- if (b1 * a2 - a1 * b2 > 0) {
29371
- if (p1 < 0) d = p1 * a2 / a1 - p2;
29372
- else if (p1 > 0) d = p1 * b2 / b1 - p2;
29373
- else d = -p2;
29374
- } else if (b1 < p1 + a1) d = b2 - (p2 + (b1 - p1) * a2 / a1);
29375
- else if (b1 > p1 + a1) d = (a1 + p1) * b2 / b1 - (p2 + a2);
29376
- else d = b2 - (p2 + a2);
29377
- return d > 0 ? d : 0;
29378
- }
29379
- function contour_bridge(line1, x1, y1, line2, x2, y2) {
29380
- let dx = x2 + line2.dx - x1;
29381
- let dy = line2.dx === 0 ? line2.dy : dx * line2.dy / line2.dx;
29382
- let r = contour_line(dx, dy, line2.next);
29383
- line1.next = contour_line(0, y2 + line2.dy - dy - y1, r);
29384
- return r;
29385
- }
29386
- function contour_merge(p1, p2) {
29387
- let x = 0;
29388
- let y = 0;
29389
- let total = 0;
29390
- let upper = p1.lower_head;
29391
- let lower = p2.upper_head;
29392
- while (lower && upper) {
29393
- let d = contour_offset(x, y, lower.dx, lower.dy, upper.dx, upper.dy);
29394
- y += d;
29395
- total += d;
29396
- if (x + lower.dx <= upper.dx) {
29397
- x += lower.dx;
29398
- y += lower.dy;
29399
- lower = lower.next;
29400
- } else {
29401
- x -= upper.dx;
29402
- y -= upper.dy;
29403
- upper = upper.next;
29404
- }
29405
- }
29406
- if (lower) {
29407
- let b = contour_bridge(p1.upper_tail, 0, 0, lower, x, y);
29408
- p1.upper_tail = b.next ? p2.upper_tail : b;
29409
- p1.lower_tail = p2.lower_tail;
29410
- } else {
29411
- let b = contour_bridge(p2.lower_tail, x, y, upper, 0, 0);
29412
- if (!b.next) p1.lower_tail = b;
29413
- }
29414
- p1.lower_head = p2.lower_head;
29415
- return total;
29416
- }
29417
- function stack_trunk_width(k) {
29418
- let lanes = Math.max(0, k - 2);
29419
- return Math.max(36, 20 + Math.max(0, lanes - 1) * 6);
29420
- }
29421
- /************************************************************
29422
- * The children of every node, with each run of STACK_MIN_RUN or
29423
- * more consecutive LEAF children replaced by one STACK. Runs, not
29424
- * all the leaves of a parent: the children keep their order. A
29425
- * stack's key is an OBJECT, so it can never be taken for a node id,
29426
- * which is a string. Shared by the compact tree and the radial.
29427
- *
29428
- * Returns {kids_of: Map<id, [id | stack]>, stacks: Map<stack, {ids, depth}>}
29429
- ************************************************************/
29430
- function leaf_runs(t) {
29431
- let kids_of = /* @__PURE__ */ new Map();
29432
- let stacks = /* @__PURE__ */ new Map();
29433
- for (let [id, kids] of t.children) {
29434
- let out = [];
29435
- let run = [];
29436
- let flush = () => {
29437
- if (run.length >= 3) {
29438
- let key = { stack: stacks.size };
29439
- stacks.set(key, {
29440
- ids: run,
29441
- depth: t.depth.get(run[0])
29442
- });
29443
- out.push(key);
29444
- } else out.push(...run);
29445
- run = [];
29446
- };
29447
- for (let kid of kids) if ((t.children.get(kid) || []).length === 0) run.push(kid);
29448
- else {
29449
- flush();
29450
- out.push(kid);
29451
- }
29452
- flush();
29453
- kids_of.set(id, out);
29454
- }
29455
- return {
29456
- kids_of,
29457
- stacks
29458
- };
29459
- }
29460
- function stacked_order(t, kids_of) {
29461
- let order = [];
29462
- let todo = t.roots.slice().reverse();
29463
- while (todo.length) {
29464
- let id = todo.pop();
29465
- order.push(id);
29466
- let kids = kids_of.get(id) || [];
29467
- for (let i = kids.length - 1; i >= 0; i--) todo.push(kids[i]);
29468
- }
29469
- return order;
29470
- }
29471
- function stack_geometry(t, st, col_x, col_w) {
29472
- let d = st.depth;
29473
- let k = st.ids.length;
29474
- let rows = Math.ceil(k / 2);
29475
- let side = [0, 0];
29476
- let row_len = [];
29477
- for (let i = 0; i < k; i++) {
29478
- let n = t.by_id.get(st.ids[i]);
29479
- let r = Math.floor(i / 2);
29480
- side[i % 2] = Math.max(side[i % 2], n.h);
29481
- row_len[r] = Math.max(row_len[r] || 0, n.w);
29482
- }
29483
- row_len[0] = col_w[d];
29484
- let trunk = stack_trunk_width(k);
29485
- let starts = [col_x[d]];
29486
- for (let r = 1; r < rows; r++) starts[r] = starts[r - 1] + row_len[r - 1] + 40;
29487
- return {
29488
- side,
29489
- trunk,
29490
- starts,
29491
- row_len,
29492
- len: starts[rows - 1] + row_len[rows - 1] - col_x[d],
29493
- ext: side[0] + trunk + side[1]
29494
- };
29495
- }
29496
- function place_stack(t, st, g, top, pos) {
29497
- for (let i = 0; i < st.ids.length; i++) {
29498
- let n = t.by_id.get(st.ids[i]);
29499
- let r = Math.floor(i / 2);
29500
- let across = i % 2 === 0 ? top + g.side[0] - n.h / 2 : top + g.side[0] + g.trunk + n.h / 2;
29501
- pos.set(st.ids[i], {
29502
- x: g.starts[r] + g.row_len[r] / 2,
29503
- y: across
29504
- });
29505
- }
29506
- }
29507
- function compact_tree_lr(nodes, edges, o) {
29508
- let t = spanning_tree(nodes, edges);
29509
- let pos = /* @__PURE__ */ new Map();
29510
- let { kids_of, stacks } = leaf_runs(t);
29511
- let order = stacked_order(t, kids_of);
29512
- let col_w = [];
29513
- for (let [id, d] of t.depth) col_w[d] = Math.max(col_w[d] || 0, t.by_id.get(id).w);
29514
- let col_x = [];
29515
- let x = 0;
29516
- for (let d = 0; d < col_w.length; d++) {
29517
- col_x[d] = x;
29518
- x += (col_w[d] || 0) + o.ranksep;
29519
- }
29520
- let pad = o.nodesep / 2;
29521
- let dist = o.nodesep;
29522
- let level_distance = o.ranksep - pad;
29523
- let tn = /* @__PURE__ */ new Map();
29524
- for (let id of order) {
29525
- let st = stacks.get(id);
29526
- if (st) {
29527
- let g = stack_geometry(t, st, col_x, col_w);
29528
- tn.set(id, {
29529
- len: g.len,
29530
- ext: g.ext,
29531
- geom: g,
29532
- off_x: 0,
29533
- off_y: 0,
29534
- y: 0,
29535
- contour: null
29536
- });
29537
- } else tn.set(id, {
29538
- len: col_w[t.depth.get(id)],
29539
- ext: t.by_id.get(id).h,
29540
- off_x: 0,
29541
- off_y: 0,
29542
- y: 0,
29543
- contour: null
29544
- });
29545
- }
29546
- for (let i = order.length - 1; i >= 0; i--) {
29547
- let id = order[i];
29548
- let n = tn.get(id);
29549
- let kids = kids_of.get(id) || [];
29550
- if (!kids.length) {
29551
- let upper = contour_line(n.len + dist, 0);
29552
- let lower_tail = contour_line(0, -n.ext - dist);
29553
- n.contour = {
29554
- upper_head: upper,
29555
- upper_tail: upper,
29556
- lower_tail,
29557
- lower_head: contour_line(n.len + dist, 0, lower_tail)
29558
- };
29559
- continue;
29560
- }
29561
- let first = tn.get(kids[0]);
29562
- n.contour = first.contour;
29563
- let h = first.ext + dist;
29564
- let span = h;
29565
- for (let k = 1; k < kids.length; k++) {
29566
- let kid = tn.get(kids[k]);
29567
- let d = contour_merge(n.contour, kid.contour);
29568
- kid.off_y = d + h;
29569
- kid.off_x = 0;
29570
- h = kid.ext + dist;
29571
- span += d + h;
29572
- }
29573
- let gap = pad + level_distance;
29574
- let y2 = (span - n.ext) / 2 - pad;
29575
- let y1 = y2 + n.ext + 2 * pad - span;
29576
- first.off_x = gap + n.len;
29577
- first.off_y = y1;
29578
- n.contour.upper_head = contour_line(n.len, 0, contour_line(gap, y1, n.contour.upper_head));
29579
- n.contour.lower_head = contour_line(n.len, 0, contour_line(gap, y2, n.contour.lower_head));
29580
- }
29581
- let root_of = /* @__PURE__ */ new Map();
29582
- for (let id of order) {
29583
- let n = tn.get(id);
29584
- if (!root_of.has(id)) root_of.set(id, id);
29585
- let kids = kids_of.get(id) || [];
29586
- if (!kids.length) continue;
29587
- let running = n.y + tn.get(kids[0]).off_y;
29588
- tn.get(kids[0]).y = running;
29589
- root_of.set(kids[0], root_of.get(id));
29590
- for (let k = 1; k < kids.length; k++) {
29591
- let kid = tn.get(kids[k]);
29592
- kid.y = running + kid.off_y;
29593
- running = kid.y;
29594
- root_of.set(kids[k], root_of.get(id));
29595
- }
29596
- }
29597
- let lo = /* @__PURE__ */ new Map();
29598
- let hi = /* @__PURE__ */ new Map();
29599
- for (let id of order) {
29600
- let r = root_of.get(id);
29601
- let n = tn.get(id);
29602
- lo.set(r, Math.min(lo.has(r) ? lo.get(r) : Infinity, n.y));
29603
- hi.set(r, Math.max(hi.has(r) ? hi.get(r) : -Infinity, n.y + n.ext));
29604
- }
29605
- let shift = /* @__PURE__ */ new Map();
29606
- let top = 0;
29607
- for (let r of t.roots) {
29608
- shift.set(r, top - lo.get(r));
29609
- top += hi.get(r) - lo.get(r) + o.nodesep * 2;
29610
- }
29611
- for (let id of order) {
29612
- let n = tn.get(id);
29613
- let y = n.y + shift.get(root_of.get(id));
29614
- let st = stacks.get(id);
29615
- if (st) {
29616
- place_stack(t, st, n.geom, y, pos);
29617
- continue;
29618
- }
29619
- let d = t.depth.get(id);
29620
- pos.set(id, {
29621
- x: col_x[d] + col_w[d] / 2,
29622
- y: y + n.ext / 2
29623
- });
29624
- }
29625
- return pos;
29626
- }
29627
29312
  function extent_at(n, a) {
29628
29313
  if (!n) return 0;
29629
29314
  return Math.abs(n.w * Math.cos(a)) + Math.abs(n.h * Math.sin(a));
@@ -29645,103 +29330,56 @@ function extent_at(n, a) {
29645
29330
  *
29646
29331
  * ranksep the step between rings
29647
29332
  * nodesep the gap between neighbours on a ring
29648
- * stack (default true) a run of three or more LEAF children
29649
- * is a STACK, as in the compact tree: it asks its
29650
- * ring for one row of about the square root of its
29651
- * cards, not for every leaf -- a hall with a hundred
29652
- * devices no longer blows the ring up -- and lays
29653
- * them in rows going OUTWARD, each row as full as
29654
- * the room it has: rings round the parent when it is
29655
- * alone, a fan inside its sector when it is not.
29656
- * false keeps every leaf on the ring.
29657
29333
  ************************************************************/
29658
29334
  function layout_radial(nodes, edges, opts) {
29659
- let o = Object.assign({}, DEFAULTS, { stack: true }, opts || {});
29335
+ let o = Object.assign({}, DEFAULTS, opts || {});
29660
29336
  let t = spanning_tree(nodes, edges);
29661
29337
  let pos = /* @__PURE__ */ new Map();
29662
29338
  if (!t.roots.length) return pos;
29663
- let runs = o.stack ? leaf_runs(t) : {
29664
- kids_of: t.children,
29665
- stacks: /* @__PURE__ */ new Map()
29666
- };
29667
- let kids_of = runs.kids_of;
29668
- let stacks = runs.stacks;
29669
- let order = stacked_order(t, kids_of);
29670
- for (let st of stacks.values()) {
29671
- st.per_row = Math.ceil(Math.sqrt(st.ids.length));
29672
- st.cards = st.ids.map((id) => t.by_id.get(id));
29673
- }
29674
- let stack_across = (st, a) => {
29675
- let w = 0;
29676
- for (let c of st.cards) w = Math.max(w, extent_at(c, a + Math.PI / 2));
29677
- return {
29678
- card: w,
29679
- row: st.per_row * w + (st.per_row - 1) * o.nodesep
29680
- };
29681
- };
29682
- let widest_along = (cards, a, half) => {
29683
- let e = 0;
29684
- for (let k = 0; k <= 16; k++) {
29685
- let th = a - half + 2 * half * k / 16;
29686
- for (let c of cards) e = Math.max(e, extent_at(c, th));
29687
- }
29688
- return e;
29689
- };
29690
- let depth_of = (id) => stacks.has(id) ? stacks.get(id).depth : t.depth.get(id);
29691
- let circ = (a, b) => {
29692
- let d = Math.abs(a - b) % (2 * Math.PI);
29693
- return d > Math.PI ? 2 * Math.PI - d : d;
29694
- };
29695
- let weight = /* @__PURE__ */ new Map();
29339
+ let order = walk_order(t);
29340
+ let leaves = /* @__PURE__ */ new Map();
29696
29341
  for (let i = order.length - 1; i >= 0; i--) {
29697
29342
  let id = order[i];
29698
- let st = stacks.get(id);
29699
- if (st) {
29700
- weight.set(id, st.per_row);
29701
- continue;
29702
- }
29703
- let kids = kids_of.get(id) || [];
29343
+ let kids = t.children.get(id) || [];
29704
29344
  if (!kids.length) {
29705
- weight.set(id, 1);
29345
+ leaves.set(id, 1);
29706
29346
  continue;
29707
29347
  }
29708
29348
  let n = 0;
29709
- for (let kid of kids) n += weight.get(kid);
29710
- weight.set(id, n);
29349
+ for (let kid of kids) n += leaves.get(kid);
29350
+ leaves.set(id, n);
29711
29351
  }
29712
29352
  let total = 0;
29713
- for (let root of t.roots) total += weight.get(root);
29353
+ for (let root of t.roots) total += leaves.get(root);
29714
29354
  let single = t.roots.length === 1;
29715
- let ring_of = (id) => depth_of(id) + (single ? 0 : 1);
29355
+ let ring_of = (id) => t.depth.get(id) + (single ? 0 : 1);
29716
29356
  let angle = /* @__PURE__ */ new Map();
29717
29357
  let rings = [];
29718
29358
  let sector = (root_id, root_from, root_span, root_parent) => {
29719
- let todo = [{
29359
+ let stack = [{
29720
29360
  id: root_id,
29721
29361
  from: root_from,
29722
29362
  span: root_span,
29723
29363
  parent: root_parent
29724
29364
  }];
29725
- while (todo.length) {
29726
- let { id, from, span, parent } = todo.pop();
29365
+ while (stack.length) {
29366
+ let { id, from, span, parent } = stack.pop();
29727
29367
  let a = from + span / 2;
29728
29368
  angle.set(id, a);
29729
29369
  let ring = ring_of(id);
29730
29370
  if (!rings[ring]) rings[ring] = [];
29731
- let st = stacks.get(id);
29732
- let n = st ? null : t.by_id.get(id);
29371
+ let n = t.by_id.get(id);
29733
29372
  rings[ring].push({
29734
29373
  id,
29735
29374
  angle: a,
29736
- span,
29737
- diag: st ? stack_across(st, a).row : Math.hypot(n.w, n.h),
29738
- ext: st ? widest_along(st.cards, a, Math.min(span / 2, Math.PI)) : extent_at(n, a),
29739
- parent_ext: !parent ? 0 : st ? widest_along([t.by_id.get(parent)], a, Math.min(span / 2, Math.PI)) : extent_at(t.by_id.get(parent), a)
29375
+ diag: Math.hypot(n.w, n.h),
29376
+ ext: extent_at(n, a),
29377
+ parent_ext: parent ? extent_at(t.by_id.get(parent), a) : 0
29740
29378
  });
29741
29379
  let cursor = from;
29742
- for (let kid of kids_of.get(id) || []) {
29743
- let part = span * weight.get(kid) / weight.get(id);
29744
- todo.push({
29380
+ for (let kid of t.children.get(id) || []) {
29381
+ let part = span * leaves.get(kid) / leaves.get(id);
29382
+ stack.push({
29745
29383
  id: kid,
29746
29384
  from: cursor,
29747
29385
  span: part,
@@ -29755,120 +29393,38 @@ function layout_radial(nodes, edges, opts) {
29755
29393
  let root = t.roots[0];
29756
29394
  angle.set(root, 0);
29757
29395
  let cursor = -Math.PI / 2;
29758
- for (let kid of kids_of.get(root) || []) {
29759
- let part = 2 * Math.PI * weight.get(kid) / weight.get(root);
29396
+ for (let kid of t.children.get(root) || []) {
29397
+ let part = 2 * Math.PI * leaves.get(kid) / leaves.get(root);
29760
29398
  sector(kid, cursor, part, root);
29761
29399
  cursor += part;
29762
29400
  }
29763
29401
  } else {
29764
29402
  let cursor = -Math.PI / 2;
29765
29403
  for (let root of t.roots) {
29766
- let part = 2 * Math.PI * weight.get(root) / total;
29404
+ let part = 2 * Math.PI * leaves.get(root) / total;
29767
29405
  sector(root, cursor, part, null);
29768
29406
  cursor += part;
29769
29407
  }
29770
29408
  }
29771
- let fit = (list, r0) => {
29772
- let r = r0;
29773
- let sorted = list.slice().sort((a, b) => a.angle - b.angle);
29774
- for (let i = 0; i < sorted.length && sorted.length > 1; i++) {
29775
- let a = sorted[i];
29776
- let b = sorted[(i + 1) % sorted.length];
29777
- let gap = i + 1 < sorted.length ? b.angle - a.angle : b.angle + 2 * Math.PI - a.angle;
29778
- if (gap > 1e-9) r = Math.max(r, (a.diag / 2 + b.diag / 2 + o.nodesep) / gap);
29779
- }
29780
- return r;
29781
- };
29782
29409
  let radius = [0];
29783
- let reaching = [];
29784
29410
  for (let ring = 1; ring < rings.length; ring++) {
29785
- let members = rings[ring] || [];
29786
29411
  let r = radius[ring - 1] + o.ranksep;
29787
- let band = 0;
29788
- for (let n of members) {
29789
- r = Math.max(r, radius[ring - 1] + (n.parent_ext + n.ext) / 2 + o.nodesep);
29790
- band = Math.max(band, n.ext);
29791
- }
29792
- r = fit(members, r);
29793
- for (let pass = 0; pass < 2; pass++) for (let g of reaching) {
29794
- if (g.reach < r - band / 2 - o.nodesep) continue;
29795
- for (let m of members) {
29796
- let d = circ(g.angle, m.angle);
29797
- if (d > g.half + 1e-9) r = Math.max(r, (m.diag / 2 + o.nodesep) / (d - g.half));
29798
- else r = Math.max(r, g.reach + m.ext / 2 + o.nodesep);
29799
- }
29412
+ for (let n of rings[ring] || []) r = Math.max(r, radius[ring - 1] + (n.parent_ext + n.ext) / 2 + o.nodesep);
29413
+ let list = (rings[ring] || []).slice().sort((a, b) => a.angle - b.angle);
29414
+ for (let i = 0; i < list.length && list.length > 1; i++) {
29415
+ let a = list[i];
29416
+ let b = list[(i + 1) % list.length];
29417
+ let gap = i + 1 < list.length ? b.angle - a.angle : b.angle + 2 * Math.PI - a.angle;
29418
+ if (gap > 1e-9) r = Math.max(r, (a.diag / 2 + b.diag / 2 + o.nodesep) / gap);
29800
29419
  }
29801
29420
  radius[ring] = r;
29802
- let sorted = members.slice().sort((a, b) => a.angle - b.angle);
29803
- for (let i = 0; i < sorted.length; i++) {
29804
- let m = sorted[i];
29805
- let st = stacks.get(m.id);
29806
- if (!st) continue;
29807
- let room = m.span / 2;
29808
- if (sorted.length > 1) {
29809
- let left = sorted[(i - 1 + sorted.length) % sorted.length];
29810
- let right = sorted[(i + 1) % sorted.length];
29811
- room = Math.min(room, circ(m.angle, left.angle) - (left.diag / 2 + o.nodesep) / r, circ(m.angle, right.angle) - (right.diag / 2 + o.nodesep) / r);
29812
- }
29813
- room = Math.min(room, Math.PI);
29814
- let across = 0;
29815
- let along = 0;
29816
- for (let k = 0; k <= 16; k++) {
29817
- let th = m.angle - room + 2 * room * k / 16;
29818
- for (let c of st.cards) {
29819
- across = Math.max(across, extent_at(c, th + Math.PI / 2));
29820
- along = Math.max(along, extent_at(c, th));
29821
- }
29822
- }
29823
- let rows = [];
29824
- let left_to_place = st.ids.length;
29825
- let rr = r;
29826
- let half = 0;
29827
- while (left_to_place > 0) {
29828
- let fits = Math.floor(2 * room * rr / (across + o.nodesep));
29829
- let cnt = Math.max(1, Math.min(left_to_place, fits));
29830
- rows.push({
29831
- rr,
29832
- cnt
29833
- });
29834
- half = Math.max(half, (cnt * (across + o.nodesep) - o.nodesep) / 2 / rr);
29835
- left_to_place -= cnt;
29836
- rr += along + 40;
29837
- }
29838
- st.plan = {
29839
- angle: m.angle,
29840
- across,
29841
- rows
29842
- };
29843
- reaching.push({
29844
- angle: m.angle,
29845
- half,
29846
- reach: rows[rows.length - 1].rr + along / 2
29847
- });
29848
- }
29849
29421
  }
29850
29422
  for (let [id, a] of angle) {
29851
- let st = stacks.get(id);
29852
- if (!st) {
29853
- let r0 = radius[ring_of(id)] || 0;
29854
- pos.set(id, {
29855
- x: r0 * Math.cos(a),
29856
- y: r0 * Math.sin(a)
29857
- });
29858
- continue;
29859
- }
29860
- let i = 0;
29861
- for (let row of st.plan.rows) {
29862
- let step = (st.plan.across + o.nodesep) / row.rr;
29863
- for (let j = 0; j < row.cnt; j++) {
29864
- let th = a + (j - (row.cnt - 1) / 2) * step;
29865
- pos.set(st.ids[i], {
29866
- x: row.rr * Math.cos(th),
29867
- y: row.rr * Math.sin(th)
29868
- });
29869
- i++;
29870
- }
29871
- }
29423
+ let r = radius[ring_of(id)] || 0;
29424
+ pos.set(id, {
29425
+ x: r * Math.cos(a),
29426
+ y: r * Math.sin(a)
29427
+ });
29872
29428
  }
29873
29429
  return pos;
29874
29430
  }
@@ -29882,23 +29438,6 @@ function elbow_lane(ids, id) {
29882
29438
  if (k <= 0) return 0;
29883
29439
  return (k % 2 ? 1 : -1) * Math.ceil(k / 2);
29884
29440
  }
29885
- /************************************************************
29886
- * The rank of `id` among `items` ([{id, span}]): the forward
29887
- * edges that share one end with it, each with how far it runs
29888
- * ACROSS. Farthest first; a tie goes to the edge made first.
29889
- * Returns {rank, count}.
29890
- ************************************************************/
29891
- function elbow_rank(items, id) {
29892
- let sorted = items.slice().sort((a, b) => {
29893
- if (b.span !== a.span) return b.span - a.span;
29894
- return String(a.id).localeCompare(String(b.id), void 0, { numeric: true });
29895
- });
29896
- let rank = sorted.findIndex((it) => it.id === id);
29897
- return {
29898
- rank: rank < 0 ? 0 : rank,
29899
- count: sorted.length
29900
- };
29901
- }
29902
29441
  function swap(p) {
29903
29442
  return [p[1], p[0]];
29904
29443
  }
@@ -29910,136 +29449,6 @@ function swap_box(b) {
29910
29449
  y2: b.x2
29911
29450
  };
29912
29451
  }
29913
- function staggered_turn(lo, hi, st) {
29914
- let mid = (lo + hi) / 2;
29915
- let group = null;
29916
- let k = 0;
29917
- if (st.dep && st.dep.count > 1) {
29918
- group = st.dep;
29919
- k = st.dep.rank;
29920
- } else if (st.arr && st.arr.count > 1) {
29921
- group = st.arr;
29922
- k = st.arr.count - 1 - st.arr.rank;
29923
- }
29924
- if (group) {
29925
- let room = Math.max(0, hi - lo - 12);
29926
- let step = Math.min(10, room / (group.count - 1));
29927
- mid = mid - (group.count - 1) * step / 2 + k * step;
29928
- }
29929
- return mid;
29930
- }
29931
- /************************************************************
29932
- * The combs of the stacks under one card.
29933
- *
29934
- * treedb_layout.js lays a run of leaf children out as two columns
29935
- * with a corridor between them. A card in the first row is reached
29936
- * from the channel like any other; one in a lower row cannot be --
29937
- * the card above it stands in the way -- so its edge runs down
29938
- * the corridor in a LANE of its own and turns into the gap above
29939
- * its card, which it shares only with the other card of its row,
29940
- * reached from the other side.
29941
- *
29942
- * targets [{id, box}]: the forward edges leaving one card,
29943
- * each with the box of the card it reaches
29944
- * vertical as in elbow_points; false swaps the boxes
29945
- *
29946
- * Returns Map id -> {lane, z, top}: the lane, the height of the
29947
- * gap it turns into, and the top of the stack's first row (where
29948
- * the channel over the stack ends). Only for a card that stands
29949
- * under another of the group, within a stack gap and lined up
29950
- * with it on the corridor side -- what a stack looks like.
29951
- *
29952
- * Lanes go outermost first, row by row: a line into a higher row
29953
- * keeps outside the lines going deeper, and none crosses another.
29954
- ************************************************************/
29955
- function elbow_combs(targets, vertical) {
29956
- let list = vertical ? targets : targets.map((it) => ({
29957
- id: it.id,
29958
- box: swap_box(it.box)
29959
- }));
29960
- let cy = (b) => (b.y1 + b.y2) / 2;
29961
- let near = (a, b) => Math.abs(a - b) < 1.5;
29962
- let under = [];
29963
- for (let it of list) {
29964
- let b = it.box;
29965
- let above = null;
29966
- for (let o of list) {
29967
- let a = o.box;
29968
- if (o === it || a.y2 > b.y1 || b.y1 - a.y2 > 40) continue;
29969
- if (!(near(a.x2, b.x2) || near(a.x1, b.x1))) continue;
29970
- if (!above || a.y2 > above.y2) above = a;
29971
- }
29972
- if (!above) continue;
29973
- let side;
29974
- if (near(above.x2, b.x2) && !near(above.x1, b.x1)) side = 0;
29975
- else if (near(above.x1, b.x1) && !near(above.x2, b.x2)) side = 1;
29976
- else side = list.some((o) => o !== it && near(cy(o.box), cy(b)) && o.box.x2 <= b.x1) ? 1 : 0;
29977
- under.push({
29978
- id: it.id,
29979
- box: b,
29980
- above,
29981
- side
29982
- });
29983
- }
29984
- let corridor = (u) => {
29985
- if (u.side === 0) {
29986
- let l = u.box.x2;
29987
- let col = list.filter((o) => near(o.box.x2, l));
29988
- let r = Infinity;
29989
- for (let c of col) for (let o of list) if (o !== c && near(cy(o.box), cy(c.box)) && o.box.x1 >= l - .5) r = Math.min(r, o.box.x1);
29990
- return {
29991
- l,
29992
- r: isFinite(r) ? r : l + 36,
29993
- col
29994
- };
29995
- }
29996
- let r = u.box.x1;
29997
- let col = list.filter((o) => near(o.box.x1, r));
29998
- let l = -Infinity;
29999
- for (let c of col) for (let o of list) if (o !== c && near(cy(o.box), cy(c.box)) && o.box.x2 <= r + .5) l = Math.max(l, o.box.x2);
30000
- return {
30001
- l: isFinite(l) ? l : r - 36,
30002
- r,
30003
- col
30004
- };
30005
- };
30006
- let groups = /* @__PURE__ */ new Map();
30007
- for (let u of under) {
30008
- let c = corridor(u);
30009
- u.top = Math.min(...c.col.map((o) => o.box.y1));
30010
- let key = `${Math.round(c.l)}|${Math.round(c.r)}`;
30011
- if (!groups.has(key)) groups.set(key, {
30012
- l: c.l,
30013
- r: c.r,
30014
- left: [],
30015
- right: []
30016
- });
30017
- groups.get(key)[u.side === 0 ? "left" : "right"].push(u);
30018
- }
30019
- let out = /* @__PURE__ */ new Map();
30020
- for (let g of groups.values()) {
30021
- g.left.sort((a, b) => a.box.y1 - b.box.y1);
30022
- g.right.sort((a, b) => a.box.y1 - b.box.y1);
30023
- let n = g.left.length + g.right.length;
30024
- let room = g.r - g.l - 20;
30025
- let step = n > 1 ? Math.max(0, Math.min(6, room / (n - 1))) : 0;
30026
- g.left.forEach((u, i) => {
30027
- out.set(u.id, {
30028
- lane: g.l + 10 + i * step,
30029
- z: (u.above.y2 + u.box.y1) / 2,
30030
- top: u.top
30031
- });
30032
- });
30033
- g.right.forEach((u, j) => {
30034
- out.set(u.id, {
30035
- lane: g.r - 10 - j * step,
30036
- z: (u.above.y2 + u.box.y1) / 2,
30037
- top: u.top
30038
- });
30039
- });
30040
- }
30041
- return out;
30042
- }
30043
29452
  /************************************************************
30044
29453
  * The control points of an elbow from the port `s` to the port
30045
29454
  * `t` ([x, y] each), knowing the boxes of the two cards
@@ -30047,33 +29456,13 @@ function elbow_combs(targets, vertical) {
30047
29456
  *
30048
29457
  * vertical the rows are stacked (top to bottom); false
30049
29458
  * when they are side by side (left to right)
30050
- * stagger {dep, arr, comb}: the edge's rank among the
30051
- * forward edges leaving its source card and among
30052
- * those reaching its target card (elbow_rank), and
30053
- * its comb when the target is in a lower row of a
30054
- * stack (elbow_combs). Absent, the channel is the
30055
- * middle.
30056
- ************************************************************/
30057
- function elbow_points(s, t, box_s, box_t, lane, vertical, stagger) {
30058
- if (!vertical) return elbow_points(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, stagger).map(swap);
29459
+ ************************************************************/
29460
+ function elbow_points(s, t, box_s, box_t, lane, vertical) {
29461
+ if (!vertical) return elbow_points(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true).map(swap);
30059
29462
  let shift = lane * 10;
30060
29463
  if (t[1] - s[1] > 20) {
30061
- let st = stagger || {};
30062
- let lo = Math.max(s[1], box_s.y2);
30063
- if (st.comb) {
30064
- let c = st.comb;
30065
- let turn = staggered_turn(lo, c.top, { dep: st.dep }) + shift;
30066
- turn = Math.min(Math.max(turn, lo + 4), c.top - 4);
30067
- return [
30068
- [s[0], turn],
30069
- [c.lane, turn],
30070
- [c.lane, c.z],
30071
- [t[0], c.z]
30072
- ];
30073
- }
30074
- let hi = Math.min(t[1], box_t.y1);
30075
- let mid = staggered_turn(lo, hi, st) + shift;
30076
- mid = Math.min(Math.max(mid, lo + 4), hi - 4);
29464
+ let mid = (s[1] + t[1]) / 2 + shift;
29465
+ mid = Math.min(Math.max(mid, s[1] + 10), t[1] - 10);
30077
29466
  return [[s[0], mid], [t[0], mid]];
30078
29467
  }
30079
29468
  let out = 16 + Math.abs(shift);
@@ -30167,12 +29556,8 @@ function heap_pop(h) {
30167
29556
  /************************************************************
30168
29557
  * The shortest orthogonal line from `a` to `z` that enters none
30169
29558
  * of `boxes` (already expanded by the clearance), a turn costing
30170
- * ROUTE_BEND. The line leaves `a` SIDEWAYS and reaches `z`
30171
- * SIDEWAYS: the column straight under a port and the one straight
30172
- * over it belong to the forward edges that share that port, which
30173
- * run along them to their staggered turns -- a route going down
30174
- * that column lay on top of them. So a routed line shares only
30175
- * the stub between the port and `a` (or `z`).
29559
+ * ROUTE_BEND. The line leaves `a` going down and ends at `z`
29560
+ * going down, since after `z` it drops into a port.
30176
29561
  *
30177
29562
  * The grid is SPARSE: only the lines of the boxes' borders and
30178
29563
  * of the two ends, which is all an orthogonal shortest path ever
@@ -30238,8 +29623,7 @@ function orth_search(a, z, boxes) {
30238
29623
  let k = state >> 2;
30239
29624
  let dir = state & 3;
30240
29625
  if (k === goal) {
30241
- if (dir >= 2) continue;
30242
- let total = cost + 40;
29626
+ let total = cost + (dir === 2 ? 0 : 40);
30243
29627
  if (total < found_cost) {
30244
29628
  found_cost = total;
30245
29629
  found = state;
@@ -30247,7 +29631,6 @@ function orth_search(a, z, boxes) {
30247
29631
  continue;
30248
29632
  }
30249
29633
  for (let [nk, nd, len] of moves(k)) {
30250
- if (k === start && nd >= 2) continue;
30251
29634
  let c = cost + len + (nd === dir ? 0 : 40);
30252
29635
  let ns = nk * 4 + nd;
30253
29636
  if (c < best[ns]) {
@@ -30288,11 +29671,10 @@ function orth_search(a, z, boxes) {
30288
29671
  * coincide. Nearby cards first; all of them if that finds no way;
30289
29672
  * the simple elbow if nothing does.
30290
29673
  ************************************************************/
30291
- function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger) {
29674
+ function elbow_route(s, t, box_s, box_t, lane, vertical, boxes) {
30292
29675
  let others = boxes || [];
30293
- if (!vertical) return elbow_route(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, others.map(swap_box), stagger).map(swap);
30294
- if (stagger && stagger.comb) return elbow_points(s, t, box_s, box_t, lane, true, stagger);
30295
- let simple = elbow_points(s, t, box_s, box_t, lane, true, stagger);
29676
+ if (!vertical) return elbow_route(swap(s), swap(t), swap_box(box_s), swap_box(box_t), lane, true, others.map(swap_box)).map(swap);
29677
+ let simple = elbow_points(s, t, box_s, box_t, lane, true);
30296
29678
  if (!elbow_path_hits([
30297
29679
  s,
30298
29680
  ...simple,
@@ -30312,112 +29694,6 @@ function elbow_route(s, t, box_s, box_t, lane, vertical, boxes, stagger) {
30312
29694
  if (!route && near.length < others.length) route = orth_search(a, z, others.map((b) => box_expand(b, m)));
30313
29695
  return route || simple;
30314
29696
  }
30315
- function path_points(path) {
30316
- let pts = [];
30317
- let cur = null;
30318
- for (let c of path) if (c[0] === "M" || c[0] === "L") {
30319
- cur = [c[1], c[2]];
30320
- pts.push(cur);
30321
- } else if (c[0] === "C" && cur) {
30322
- let [x0, y0] = cur;
30323
- for (let k = 1; k <= 16; k++) {
30324
- let u = k / 16;
30325
- let v = 1 - u;
30326
- pts.push([v * v * v * x0 + 3 * v * v * u * c[1] + 3 * v * u * u * c[3] + u * u * u * c[5], v * v * v * y0 + 3 * v * v * u * c[2] + 3 * v * u * u * c[4] + u * u * u * c[6]]);
30327
- }
30328
- cur = [c[5], c[6]];
30329
- } else if (c[0] === "Q" && cur) {
30330
- let [x0, y0] = cur;
30331
- for (let k = 1; k <= 16; k++) {
30332
- let u = k / 16;
30333
- let v = 1 - u;
30334
- pts.push([v * v * x0 + 2 * v * u * c[1] + u * u * c[3], v * v * y0 + 2 * v * u * c[2] + u * u * c[4]]);
30335
- }
30336
- cur = [c[3], c[4]];
30337
- }
30338
- return pts;
30339
- }
30340
- /************************************************************
30341
- * Does the G6 path `path` of a curved edge cross a card other than
30342
- * its own two? Measured on the curve itself -- the path G6 would
30343
- * draw, sampled -- and not on the rectangle round it, which took
30344
- * every card the curve merely passed near: the ports of a row
30345
- * stick well into the space above it. Its own two cards are left
30346
- * out: the curve starts and ends on their ports.
30347
- ************************************************************/
30348
- function curve_hits(path, boxes, box_s, box_t) {
30349
- let pts = path_points(path);
30350
- if (pts.length < 2) return false;
30351
- let bb = {
30352
- x1: Infinity,
30353
- y1: Infinity,
30354
- x2: -Infinity,
30355
- y2: -Infinity
30356
- };
30357
- for (let p of pts) {
30358
- bb.x1 = Math.min(bb.x1, p[0]);
30359
- bb.y1 = Math.min(bb.y1, p[1]);
30360
- bb.x2 = Math.max(bb.x2, p[0]);
30361
- bb.y2 = Math.max(bb.y2, p[1]);
30362
- }
30363
- for (let b of boxes || []) {
30364
- if (same_box(b, box_s) || same_box(b, box_t) || !box_overlaps(b, box_expand(bb, 1))) continue;
30365
- let inner = box_expand(b, -1);
30366
- for (let k = 0; k + 1 < pts.length; k++) if (segment_hits(pts[k], pts[k + 1], inner)) return true;
30367
- }
30368
- return false;
30369
- }
30370
- /************************************************************
30371
- * A G6 path (['M'|'L'|'Q', ...]) along `points` with every corner
30372
- * rounded -- by `radius`, or by half the shorter of its two
30373
- * segments, so a short run is never overshot. The rounding is the
30374
- * quadratic G6's own polyline uses.
30375
- ************************************************************/
30376
- function rounded_path(points, radius) {
30377
- let path = [[
30378
- "M",
30379
- points[0][0],
30380
- points[0][1]
30381
- ]];
30382
- for (let i = 1; i + 1 < points.length; i++) {
30383
- let a = points[i - 1];
30384
- let m = points[i];
30385
- let b = points[i + 1];
30386
- let len_in = Math.hypot(m[0] - a[0], m[1] - a[1]);
30387
- let len_out = Math.hypot(b[0] - m[0], b[1] - m[1]);
30388
- let r = Math.min(radius, len_in / 2, len_out / 2);
30389
- let collinear = Math.abs((m[0] - a[0]) * (b[1] - m[1]) - (m[1] - a[1]) * (b[0] - m[0])) < 1e-9;
30390
- if (r <= 0 || collinear) {
30391
- path.push([
30392
- "L",
30393
- m[0],
30394
- m[1]
30395
- ]);
30396
- continue;
30397
- }
30398
- let p1 = [m[0] - (m[0] - a[0]) / len_in * r, m[1] - (m[1] - a[1]) / len_in * r];
30399
- let p2 = [m[0] + (b[0] - m[0]) / len_out * r, m[1] + (b[1] - m[1]) / len_out * r];
30400
- path.push([
30401
- "L",
30402
- p1[0],
30403
- p1[1]
30404
- ]);
30405
- path.push([
30406
- "Q",
30407
- m[0],
30408
- m[1],
30409
- p2[0],
30410
- p2[1]
30411
- ]);
30412
- }
30413
- let last = points[points.length - 1];
30414
- path.push([
30415
- "L",
30416
- last[0],
30417
- last[1]
30418
- ]);
30419
- return path;
30420
- }
30421
29697
  //#endregion
30422
29698
  //#region node_modules/@babel/runtime/helpers/esm/typeof.js
30423
29699
  function _typeof(o) {
@@ -55305,7 +54581,7 @@ Easing Functions from anime.js, they are tried and true, so, its better to use t
55305
54581
  var Quad = function Quad(t) {
55306
54582
  return Math.pow(t, 2);
55307
54583
  };
55308
- var Cubic$1 = function Cubic(t) {
54584
+ var Cubic = function Cubic(t) {
55309
54585
  return Math.pow(t, 3);
55310
54586
  };
55311
54587
  var Quart = function Quart(t) {
@@ -55442,10 +54718,10 @@ var EasingFunctions = {
55442
54718
  "out-quad": EaseOut(Quad),
55443
54719
  "in-out-quad": EaseInOut(Quad),
55444
54720
  "out-in-quad": EaseOutIn(Quad),
55445
- "in-cubic": Cubic$1,
55446
- "out-cubic": EaseOut(Cubic$1),
55447
- "in-out-cubic": EaseInOut(Cubic$1),
55448
- "out-in-cubic": EaseOutIn(Cubic$1),
54721
+ "in-cubic": Cubic,
54722
+ "out-cubic": EaseOut(Cubic),
54723
+ "in-out-cubic": EaseInOut(Cubic),
54724
+ "out-in-cubic": EaseOutIn(Cubic),
55449
54725
  "in-quart": Quart,
55450
54726
  "out-quart": EaseOut(Quart),
55451
54727
  "in-out-quart": EaseInOut(Quart),
@@ -57282,12 +56558,6 @@ var _layouts = {
57282
56558
  nodesep: 18,
57283
56559
  ranksep: 90
57284
56560
  },
57285
- "compact-tree": {
57286
- type: "treedb-compact",
57287
- direction: "TB",
57288
- nodesep: 18,
57289
- ranksep: 90
57290
- },
57291
56561
  "dagre": {
57292
56562
  type: "dagre",
57293
56563
  rankdir: "LR",
@@ -57445,8 +56715,9 @@ var PRIVATE_DATA$4 = {
57445
56715
  _selected_paint_ids: [],
57446
56716
  _pending_focus_topic: null,
57447
56717
  _pending_focus_all: false,
57448
- _find_hidden_matches: 0,
57449
- _pending_find: null,
56718
+ _find_term: "",
56719
+ _find_current: "",
56720
+ _find_found: null,
57450
56721
  _layout_asked: "",
57451
56722
  _nodes_total: 0,
57452
56723
  _nodes_placed: 0,
@@ -57615,11 +56886,8 @@ function register_layouts(gobj) {
57615
56886
  _g6_extensions_registered = true;
57616
56887
  register(ExtensionCategory.LAYOUT, "manual", ManualLayout);
57617
56888
  register(ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
57618
- register(ExtensionCategory.LAYOUT, "treedb-compact", TreedbCompactLayout);
57619
56889
  register(ExtensionCategory.EDGE, "treedb-elbow-v", TreedbElbowV);
57620
56890
  register(ExtensionCategory.EDGE, "treedb-elbow-h", TreedbElbowH);
57621
- register(ExtensionCategory.EDGE, "treedb-curve-v", TreedbCurveV);
57622
- register(ExtensionCategory.EDGE, "treedb-curve-h", TreedbCurveH);
57623
56891
  register(ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
57624
56892
  register(ExtensionCategory.NODE, "light", LightNode);
57625
56893
  register(ExtensionCategory.NODE, "treedb-card", TreedbCard);
@@ -58314,9 +57582,7 @@ function layout_direction(gobj) {
58314
57582
  function edge_type_for(gobj) {
58315
57583
  let lr = layout_direction(gobj) === "LR";
58316
57584
  let rowless = gobj_read_attr(gobj, "rowless_layouts") || [];
58317
- let rows = !str_in_list(rowless, gobj.priv.layout);
58318
- if (rows && gobj_read_str_attr(gobj, "edge_shape") === "elbow") return lr ? "treedb-elbow-h" : "treedb-elbow-v";
58319
- if (rows) return lr ? "treedb-curve-h" : "treedb-curve-v";
57585
+ if (gobj_read_str_attr(gobj, "edge_shape") === "elbow" && !str_in_list(rowless, gobj.priv.layout)) return lr ? "treedb-elbow-h" : "treedb-elbow-v";
58320
57586
  return lr ? "cubic-horizontal" : "cubic";
58321
57587
  }
58322
57588
  /************************************************************
@@ -59406,6 +58672,14 @@ function graph_focus_topic(gobj, topic, reveal_all) {
59406
58672
  }
59407
58673
  let model = priv._fold_model;
59408
58674
  let state = priv._fold_state;
58675
+ if (empty_string(topic) && priv._find_term) {
58676
+ priv._focus_topic = null;
58677
+ return;
58678
+ }
58679
+ if (!empty_string(topic)) {
58680
+ priv._find_term = "";
58681
+ priv._find_current = "";
58682
+ }
59409
58683
  let keys = [];
59410
58684
  if (!empty_string(topic)) {
59411
58685
  for (let node of model.nodes.values()) if (node.topic_name === topic) keys.push(node.key);
@@ -59421,17 +58695,17 @@ function graph_focus_topic(gobj, topic, reveal_all) {
59421
58695
  }
59422
58696
  priv._focus_topic = topic || null;
59423
58697
  reconcile_fold(gobj, {}).then(() => {
59424
- apply_focus_ids(gobj, keys, "focus topic");
58698
+ apply_focus_ids(gobj, keys, "focus topic", true);
59425
58699
  });
59426
58700
  }
59427
58701
  /************************************************************
59428
- * Paint the highlight on these records (by model key) and put
59429
- * the first of them in the middle. Shared by the find and the
59430
- * topic focus, after the reconcile that brought them on screen.
59431
- * Keys that are still off screen are skipped: a match beyond the
59432
- * page a reveal opened is counted, not painted.
58702
+ * Paint the highlight on these records (by model key) and, with
58703
+ * `center`, put the first of them in the middle. Shared by the
58704
+ * find and the topic focus. Keys that are not on screen are
58705
+ * skipped: a match beyond the page a reveal opened is counted,
58706
+ * not painted.
59433
58707
  ************************************************************/
59434
- function apply_focus_ids(gobj, keys, what) {
58708
+ function apply_focus_ids(gobj, keys, what, center) {
59435
58709
  let priv = gobj.priv;
59436
58710
  let graph = priv.graph;
59437
58711
  if (!graph) return;
@@ -59456,7 +58730,7 @@ function apply_focus_ids(gobj, keys, what) {
59456
58730
  try {
59457
58731
  if (typeof graph.setElementState === "function") graph.setElementState(states);
59458
58732
  apply_node_highlight(gobj, prev_ids, ids);
59459
- if (ids.length) yui_graph_center_on(graph, ids[0]);
58733
+ if (center && ids.length) yui_graph_center_on(graph, ids[0]);
59460
58734
  } catch (e) {
59461
58735
  log_error(`${gobj_short_name(gobj)}: ${what} apply failed: ${e}`);
59462
58736
  }
@@ -59467,61 +58741,139 @@ function node_id_of_key(gobj, key) {
59467
58741
  return build_node_name(gobj, key.slice(0, i), key.slice(i + 1));
59468
58742
  }
59469
58743
  /************************************************************
59470
- * Find the nodes whose name, id or topic contains `term`, highlight
59471
- * them with the same amber 'active' state the topic focus uses, and
59472
- * centre the viewport on them. Returns how many matched, which is the
59473
- * half the toolbar needs: a search that finds nothing must SAY so,
59474
- * because a graph that did not move is also what a graph looks like
59475
- * when the match is off-screen.
58744
+ * The find box: highlight the cards ON SCREEN whose name, id or
58745
+ * topic contains `term`, and change nothing else -- no group is
58746
+ * opened, no layout runs, the camera does not move. The graph the
58747
+ * reader arranged is the graph they are searching; emptying the
58748
+ * box takes the amber off and leaves it exactly as it was.
58749
+ *
58750
+ * It used to search the whole treedb and unfold a page of what it
58751
+ * found, which re-laid the graph out on every keystroke and left
58752
+ * the unfolded groups behind when the box was cleared. Opening up
58753
+ * to a topic is the legend's focus (graph_focus_topic); this only
58754
+ * LOOKS.
58755
+ *
58756
+ * The term is kept and repainted after every reconcile (see
58757
+ * reconcile_fold_now): a group opened by hand shows its matches
58758
+ * already lit, and the count follows what is on screen.
59476
58759
  *
59477
58760
  * It shares the highlight slot with graph_focus_topic on purpose —
59478
- * two amber sets at once would say nothing about either. An empty
59479
- * term clears it. Matching reads the node's LABEL and not only its
59480
- * id: on a topic keyed by rowid or by a qualified path, the id is a
59481
- * counter and the name a human knows is elsewhere (see node_label).
58761
+ * two amber sets at once would say nothing about either. Matching
58762
+ * reads the node's LABEL and not only its id: on a topic keyed by
58763
+ * rowid or by a qualified path, the id is a counter and the name a
58764
+ * human knows is elsewhere (see node_label).
59482
58765
  ************************************************************/
59483
58766
  function graph_find_nodes(gobj, term) {
59484
58767
  let priv = gobj.priv;
59485
- if (!priv.graph || !priv.graph_rendered || !priv._fold_model) {
59486
- priv._pending_find = term;
59487
- return 0;
58768
+ let next = empty_string(term) ? "" : String(term);
58769
+ let was = priv._find_term;
58770
+ priv._find_term = next;
58771
+ priv._find_current = "";
58772
+ priv._find_found = null;
58773
+ let ready = priv.graph && priv.graph_rendered && priv._fold_model;
58774
+ if (!next) {
58775
+ if (was && ready && !priv._focus_topic) apply_focus_ids(gobj, [], "find", false);
58776
+ publish_find_result(gobj);
58777
+ return;
59488
58778
  }
58779
+ priv._focus_topic = null;
58780
+ if (!ready) return;
58781
+ refresh_find(gobj, fold_visible_set(priv._fold_model, priv._fold_state));
58782
+ }
58783
+ /************************************************************
58784
+ * Repaint the find's highlight over the `visible` set and publish
58785
+ * the count. A no-op while no term is live, so the topic focus
58786
+ * keeps the slot.
58787
+ ************************************************************/
58788
+ function refresh_find(gobj, visible) {
58789
+ let priv = gobj.priv;
58790
+ if (!priv._find_term) return;
58791
+ let found = find_matches(gobj, priv._find_term, visible);
58792
+ apply_focus_ids(gobj, found.keys, "find", false);
58793
+ if (priv._find_current && (priv._focus_ids || []).indexOf(priv._find_current) < 0) priv._find_current = "";
58794
+ priv._find_found = found;
58795
+ publish_find_result(gobj);
58796
+ }
58797
+ /************************************************************
58798
+ * The records matching `term`: the keys ON SCREEN, and how many
58799
+ * more match that are NOT -- folded away in the fold model, or in
58800
+ * a hidden topic. Those two are only counted: "0" alone would read
58801
+ * as "does not exist" when it means "is not on screen".
58802
+ ************************************************************/
58803
+ function find_matches(gobj, term, visible) {
58804
+ let priv = gobj.priv;
59489
58805
  let model = priv._fold_model;
59490
- let state = priv._fold_state;
59491
- let keys = [];
59492
- let hidden_matches = 0;
59493
- if (!empty_string(term)) {
59494
- let needle = String(term).toLowerCase();
59495
- let matches = (topic_name, record) => {
59496
- let label = "";
59497
- try {
59498
- label = node_label(priv.descs[topic_name] || {}, record) || "";
59499
- } catch (e) {
59500
- label = "";
59501
- }
59502
- return [
59503
- label,
59504
- record.id,
59505
- topic_name
59506
- ].filter((v) => typeof v === "string").join(" ").toLowerCase().includes(needle);
59507
- };
59508
- for (let node of model.nodes.values()) if (matches(node.topic_name, node.record || {})) keys.push(node.key);
59509
- for (let topic_name of model.hidden) for (let record of priv.records[topic_name] || []) if (is_object(record) && matches(topic_name, record)) hidden_matches++;
58806
+ let found = {
58807
+ keys: [],
58808
+ folded: 0,
58809
+ hidden: 0
58810
+ };
58811
+ if (!model || empty_string(term)) return found;
58812
+ let needle = String(term).toLowerCase();
58813
+ let matches = (topic_name, record) => {
58814
+ let label = "";
58815
+ try {
58816
+ label = node_label(priv.descs[topic_name] || {}, record) || "";
58817
+ } catch (e) {
58818
+ label = "";
58819
+ }
58820
+ return [
58821
+ label,
58822
+ record.id,
58823
+ topic_name
58824
+ ].filter((v) => typeof v === "string").join(" ").toLowerCase().includes(needle);
58825
+ };
58826
+ for (let node of model.nodes.values()) if (matches(node.topic_name, node.record || {})) {
58827
+ if (visible.has(node.key)) found.keys.push(node.key);
58828
+ else found.folded++;
59510
58829
  }
59511
- priv._find_hidden_matches = hidden_matches;
59512
- let visible = fold_visible_set(model, state);
59513
- let revealed = 0;
59514
- for (let key of keys) {
59515
- if (visible.has(key)) continue;
59516
- if (revealed >= state.page_size) break;
59517
- fold_reveal(model, state, key);
59518
- revealed++;
58830
+ for (let topic_name of model.hidden) for (let record of priv.records[topic_name] || []) if (is_object(record) && matches(topic_name, record)) found.hidden++;
58831
+ return found;
58832
+ }
58833
+ /************************************************************
58834
+ * The lit cards in reading order: top to bottom, then left to
58835
+ * right. The order Enter walks, and the one the "k/N" counts in.
58836
+ ************************************************************/
58837
+ function find_order(gobj) {
58838
+ let priv = gobj.priv;
58839
+ let graph = priv.graph;
58840
+ let ids = (priv._focus_ids || []).slice();
58841
+ if (!graph) return ids;
58842
+ let pos = {};
58843
+ for (let id of ids) {
58844
+ let p = null;
58845
+ try {
58846
+ p = graph.getElementPosition(id);
58847
+ } catch (e) {
58848
+ p = null;
58849
+ }
58850
+ pos[id] = p || [0, 0];
59519
58851
  }
59520
- priv._focus_topic = null;
59521
- reconcile_fold(gobj, {}).then(() => {
59522
- apply_focus_ids(gobj, keys, "find");
59523
- });
59524
- return keys.length;
58852
+ ids.sort((a, b) => pos[a][1] - pos[b][1] || pos[a][0] - pos[b][0]);
58853
+ return ids;
58854
+ }
58855
+ /************************************************************
58856
+ * Enter in the find box: centre the next lit card (`back`: the
58857
+ * previous one). The one camera move of the find, and the reader
58858
+ * asks for it: the highlight alone cannot take anybody to a match
58859
+ * that is outside the frame.
58860
+ ************************************************************/
58861
+ function graph_find_step(gobj, back) {
58862
+ let priv = gobj.priv;
58863
+ let graph = priv.graph;
58864
+ if (!graph || !priv._find_term) return;
58865
+ let ids = find_order(gobj);
58866
+ if (ids.length === 0) return;
58867
+ let i = ids.indexOf(priv._find_current);
58868
+ if (i < 0) i = back ? ids.length - 1 : 0;
58869
+ else i = (i + (back ? ids.length - 1 : 1)) % ids.length;
58870
+ priv._find_current = ids[i];
58871
+ try {
58872
+ yui_graph_center_on(graph, ids[i]);
58873
+ } catch (e) {
58874
+ log_error(`${gobj_short_name(gobj)}: find step failed: ${e}`);
58875
+ }
58876
+ publish_find_result(gobj);
59525
58877
  }
59526
58878
  async function graph_zoom_in(gobj) {
59527
58879
  let graph = gobj.priv.graph;
@@ -59803,9 +59155,8 @@ var TreedbTreeLayout = class extends BaseLayout {
59803
59155
  * dragged card, a fold or a layout needs nothing else. `-v` runs
59804
59156
  * between rows (top to bottom), `-h` between columns. An edge that
59805
59157
  * does not run forward goes round the two cards, the edges joining
59806
- * the same two cards take lanes, the edges sharing an end turn at
59807
- * staggered heights, and a line that would cross any other card is
59808
- * routed round it (treedb_elbow.js).
59158
+ * the same two cards take lanes, and a line that would cross any
59159
+ * other card is routed round it (treedb_elbow.js).
59809
59160
  ************************************************************/
59810
59161
  var ELBOW_RADIUS = 6;
59811
59162
  function elbow_box(node) {
@@ -59857,55 +59208,10 @@ function elbow_lane_of(edge) {
59857
59208
  return 0;
59858
59209
  }
59859
59210
  }
59860
- function elbow_stagger_of(edge, vertical) {
59861
- let graph = edge.context && edge.context.graph;
59862
- let element = edge.context && edge.context.element;
59863
- let s = edge.sourceNode && edge.sourceNode.id;
59864
- let t = edge.targetNode && edge.targetNode.id;
59865
- if (!graph || !element || s === void 0 || t === void 0) return null;
59866
- let across = vertical ? 0 : 1;
59867
- let along = vertical ? 1 : 0;
59868
- let pos = (id) => graph.getElementPosition(id);
59869
- let port_of = (node_id, key) => {
59870
- let node = element.getElement(node_id);
59871
- let ports = node && typeof node.getPorts === "function" ? node.getPorts() : {};
59872
- let port = key ? ports[key] : null;
59873
- return port ? port.getPosition() : pos(node_id);
59874
- };
59875
- try {
59876
- let ps = pos(s);
59877
- let pt = pos(t);
59878
- let leaving = graph.getRelatedEdgesData(s, "out").filter((d) => d.source === s && pos(d.target)[along] > ps[along]);
59879
- let combs = elbow_combs(leaving.map((d) => ({
59880
- id: d.id,
59881
- box: elbow_box(element.getElement(d.target))
59882
- })), vertical);
59883
- let dep = leaving.map((d) => {
59884
- let comb = combs.get(d.id);
59885
- let far = comb ? comb.lane : pos(d.target)[across];
59886
- return {
59887
- id: d.id,
59888
- span: Math.abs(far - port_of(s, d.style && d.style.sourcePort)[across])
59889
- };
59890
- });
59891
- let arr = graph.getRelatedEdgesData(t, "in").filter((d) => d.target === t && pos(d.source)[along] < pt[along]).map((d) => ({
59892
- id: d.id,
59893
- span: Math.abs(port_of(d.source, d.style && d.style.sourcePort)[across] - pt[across])
59894
- }));
59895
- return {
59896
- dep: elbow_rank(dep, edge.id),
59897
- arr: elbow_rank(arr, edge.id),
59898
- comb: combs.get(edge.id) || null
59899
- };
59900
- } catch (e) {
59901
- log_error(`elbow edge ${edge.id}: cannot read the edges sharing its ends: ${e}`);
59902
- return null;
59903
- }
59904
- }
59905
59211
  var TreedbElbowV = class extends Polyline {
59906
59212
  getControlPoints(attributes) {
59907
59213
  let [s, t] = this.getEndpoints(attributes, false);
59908
- return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), true, elbow_obstacles(this), elbow_stagger_of(this, true));
59214
+ return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), true, elbow_obstacles(this));
59909
59215
  }
59910
59216
  getKeyPath(attributes) {
59911
59217
  return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
@@ -59914,52 +59220,12 @@ var TreedbElbowV = class extends Polyline {
59914
59220
  var TreedbElbowH = class extends Polyline {
59915
59221
  getControlPoints(attributes) {
59916
59222
  let [s, t] = this.getEndpoints(attributes, false);
59917
- return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), false, elbow_obstacles(this), elbow_stagger_of(this, false));
59223
+ return elbow_route(s, t, elbow_box(this.sourceNode), elbow_box(this.targetNode), elbow_lane_of(this), false, elbow_obstacles(this));
59918
59224
  }
59919
59225
  getKeyPath(attributes) {
59920
59226
  return super.getKeyPath(Object.assign({}, attributes, { radius: attributes.radius || ELBOW_RADIUS }));
59921
59227
  }
59922
59228
  };
59923
- /************************************************************
59924
- * A CURVED edge that keeps off the cards. G6's cubic, as before,
59925
- * unless that very curve -- sampled, not guessed from the
59926
- * rectangle round it -- would cross a card other than its own two,
59927
- * or when it does not run forward and so would cross its own:
59928
- * the card above a lower row of a stack, a row between a parent
59929
- * and a far child. Then it goes the way an elbow would (the comb,
59930
- * the detour, the route: the same lanes and staggered turns) with
59931
- * round corners, so it still reads as a curve. `-v` for rows
59932
- * stacked top to bottom, `-h` for columns.
59933
- ************************************************************/
59934
- function curve_key_path(edge, attributes, vertical, plain) {
59935
- let [s, t] = edge.getEndpoints(attributes, false);
59936
- let along = vertical ? 1 : 0;
59937
- let box_s = elbow_box(edge.sourceNode);
59938
- let box_t = elbow_box(edge.targetNode);
59939
- let boxes = elbow_obstacles(edge);
59940
- if (t[along] - s[along] > 20 && !curve_hits(plain, boxes, box_s, box_t)) return plain;
59941
- return rounded_path([
59942
- s,
59943
- ...elbow_route(s, t, box_s, box_t, elbow_lane_of(edge), vertical, boxes, elbow_stagger_of(edge, vertical)),
59944
- t
59945
- ], 24);
59946
- }
59947
- var TreedbCurveV = class extends Cubic {
59948
- getKeyPath(attributes) {
59949
- return curve_key_path(this, attributes, true, super.getKeyPath(attributes));
59950
- }
59951
- };
59952
- var TreedbCurveH = class extends CubicHorizontal {
59953
- getKeyPath(attributes) {
59954
- return curve_key_path(this, attributes, false, super.getKeyPath(attributes));
59955
- }
59956
- };
59957
- var TreedbCompactLayout = class extends BaseLayout {
59958
- async execute(data, options) {
59959
- let input = treedb_layout_input(data);
59960
- return treedb_layout_output(layout_compact(input.nodes, input.edges, options));
59961
- }
59962
- };
59963
59229
  var TreedbRadialLayout = class extends BaseLayout {
59964
59230
  async execute(data, options) {
59965
59231
  let input = treedb_layout_input(data);
@@ -63499,6 +62765,7 @@ async function reconcile_fold_now(gobj, opts) {
63499
62765
  history_resume(gobj);
63500
62766
  }
63501
62767
  publish_legend_state(gobj, visible);
62768
+ refresh_find(gobj, visible);
63502
62769
  return changed;
63503
62770
  }
63504
62771
  /************************************************************
@@ -63880,11 +63147,6 @@ function ac_load_data(gobj, event, kw, src) {
63880
63147
  priv._pending_focus_all = false;
63881
63148
  graph_focus_topic(gobj, ft, all);
63882
63149
  }
63883
- if (priv._pending_find !== null) {
63884
- let term = priv._pending_find;
63885
- priv._pending_find = null;
63886
- publish_find_result(gobj, term, graph_find_nodes(gobj, term));
63887
- }
63888
63150
  });
63889
63151
  }
63890
63152
  return 0;
@@ -64453,23 +63715,45 @@ function ac_node_dblclick(gobj, event, kw, src) {
64453
63715
  return 0;
64454
63716
  }
64455
63717
  /************************************************************
64456
- * Tell whoever asked how many nodes the term matched. The count is
64457
- * the answer to the question the box asks; without it "nothing moved"
64458
- * and "nothing matched" look the same.
63718
+ * Tell whoever asked how many cards the term lit. The count is the
63719
+ * answer to the question the box asks; without it "nothing lit" and
63720
+ * "nothing matched" look the same.
63721
+ *
63722
+ * matches lit cards (on screen)
63723
+ * folded_matches matches folded away, not on screen
63724
+ * hidden_matches matches in hidden topics
63725
+ * current 1-based place of the card Enter centred on
63726
+ * among the lit ones (reading order), 0 = none
64459
63727
  ************************************************************/
64460
- function publish_find_result(gobj, term, matches) {
63728
+ function publish_find_result(gobj) {
63729
+ let priv = gobj.priv;
63730
+ let found = priv._find_found || {
63731
+ keys: [],
63732
+ folded: 0,
63733
+ hidden: 0
63734
+ };
63735
+ let current = 0;
63736
+ if (priv._find_term && priv._find_current) current = find_order(gobj).indexOf(priv._find_current) + 1;
64461
63737
  gobj_publish_event(gobj, "EV_FIND_RESULT", {
64462
- term,
64463
- matches,
64464
- hidden_matches: gobj.priv._find_hidden_matches || 0
63738
+ term: priv._find_term,
63739
+ matches: priv._find_term ? (priv._focus_ids || []).length : 0,
63740
+ folded_matches: found.folded,
63741
+ hidden_matches: found.hidden,
63742
+ current
64465
63743
  });
64466
63744
  }
64467
63745
  /************************************************************
64468
63746
  *
64469
63747
  ************************************************************/
64470
63748
  function ac_find_nodes$1(gobj, event, kw, src) {
64471
- let term = kw && kw.text || "";
64472
- publish_find_result(gobj, term, graph_find_nodes(gobj, term));
63749
+ graph_find_nodes(gobj, kw && kw.text || "");
63750
+ return 0;
63751
+ }
63752
+ /************************************************************
63753
+ * Enter in the find box: {back: true} for Shift+Enter.
63754
+ ************************************************************/
63755
+ function ac_find_next$1(gobj, event, kw, src) {
63756
+ graph_find_step(gobj, !!(kw && kw.back));
64473
63757
  return 0;
64474
63758
  }
64475
63759
  function ac_center(gobj, event, kw, src) {
@@ -64930,6 +64214,11 @@ function create_gclass$4(gclass_name) {
64930
64214
  ac_find_nodes$1,
64931
64215
  null
64932
64216
  ],
64217
+ [
64218
+ "EV_FIND_NEXT",
64219
+ ac_find_next$1,
64220
+ null
64221
+ ],
64933
64222
  [
64934
64223
  "EV_TOGGLE_FOLD",
64935
64224
  ac_toggle_fold,
@@ -65085,6 +64374,7 @@ function create_gclass$4(gclass_name) {
65085
64374
  ["EV_ZOOM_SELECTION", 0],
65086
64375
  ["EV_FOCUS_TOPIC", 0],
65087
64376
  ["EV_FIND_NODES", 0],
64377
+ ["EV_FIND_NEXT", 0],
65088
64378
  ["EV_FIND_RESULT", event_flag_t.EVF_OUTPUT_EVENT],
65089
64379
  ["EV_LAYOUT_AUTOSET", event_flag_t.EVF_OUTPUT_EVENT],
65090
64380
  ["EV_CAMERA_CHANGED", event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],
@@ -65453,7 +64743,6 @@ function option_label(name) {
65453
64743
  case "edition": return t("edition");
65454
64744
  case "manual": return t("manual");
65455
64745
  case "treedb-tree": return t("treedb-tree");
65456
- case "compact-tree": return t("compact-tree");
65457
64746
  case "radial": return t("radial");
65458
64747
  case "dagre": return t("dagre");
65459
64748
  case "antv-dagre": return t("antv-dagre");
@@ -65878,19 +65167,34 @@ function make_toolbar(gobj) {
65878
65167
  type: "text",
65879
65168
  placeholder: t("search"),
65880
65169
  "data-i18n-placeholder": "search",
65881
- "aria-label": t("search"),
65882
- "data-i18n-aria-label": "search"
65170
+ title: t("find on screen"),
65171
+ "data-i18n-title": "find on screen",
65172
+ "aria-label": t("find on screen"),
65173
+ "data-i18n-aria-label": "find on screen"
65883
65174
  },
65884
65175
  [],
65885
- { input: (evt) => {
65886
- evt.stopPropagation();
65887
- let text = evt.target.value.trim();
65888
- if (priv.find_timer) clearTimeout(priv.find_timer);
65889
- priv.find_timer = setTimeout(function() {
65890
- priv.find_timer = null;
65891
- gobj_send_event(gobj, "EV_FIND_NODES", { text }, gobj);
65892
- }, 250);
65893
- } }
65176
+ {
65177
+ input: (evt) => {
65178
+ evt.stopPropagation();
65179
+ let text = evt.target.value.trim();
65180
+ if (priv.find_timer) clearTimeout(priv.find_timer);
65181
+ priv.find_timer = setTimeout(function() {
65182
+ priv.find_timer = null;
65183
+ gobj_send_event(gobj, "EV_FIND_NODES", { text }, gobj);
65184
+ }, 250);
65185
+ },
65186
+ keydown: (evt) => {
65187
+ if (evt.key !== "Enter" || evt.isComposing) return;
65188
+ evt.preventDefault();
65189
+ evt.stopPropagation();
65190
+ if (priv.find_timer) {
65191
+ clearTimeout(priv.find_timer);
65192
+ priv.find_timer = null;
65193
+ gobj_send_event(gobj, "EV_FIND_NODES", { text: evt.target.value.trim() }, gobj);
65194
+ }
65195
+ gobj_send_event(gobj, "EV_FIND_NEXT", { back: evt.shiftKey }, gobj);
65196
+ }
65197
+ }
65894
65198
  ]);
65895
65199
  let $find_control = createElement2([
65896
65200
  "div",
@@ -67219,6 +66523,14 @@ function ac_find_nodes(gobj, event, kw, src) {
67219
66523
  return 0;
67220
66524
  }
67221
66525
  /************************************************************
66526
+ * Enter in the find box: forward the step down to the graph child.
66527
+ ************************************************************/
66528
+ function ac_find_next(gobj, event, kw, src) {
66529
+ let priv = gobj.priv;
66530
+ if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_FIND_NEXT", { back: !!(kw && kw.back) }, gobj);
66531
+ return 0;
66532
+ }
66533
+ /************************************************************
67222
66534
  * One press of the fold stepper (EV_EXPAND_LEVEL /
67223
66535
  * EV_COLLAPSE_LEVEL): the level moves by one, is SAVED (the
67224
66536
  * reader's, per treedb) and reaches the G6 child, which owns
@@ -67302,12 +66614,33 @@ function refresh_find_result(gobj) {
67302
66614
  return 0;
67303
66615
  }
67304
66616
  let text = t("matches", { count: kw && kw.matches || 0 });
66617
+ let current = kw && kw.current || 0;
66618
+ if (current > 0) text = `${current}/${text}`;
66619
+ let extra = [];
66620
+ let folded = kw && kw.folded_matches || 0;
66621
+ if (folded > 0) extra.push(`+${folded} ${t("not shown")}`);
67305
66622
  let hidden = kw && kw.hidden_matches || 0;
67306
- if (hidden > 0) text += ` (+${hidden} ${t("hidden topics")})`;
66623
+ if (hidden > 0) extra.push(`+${hidden} ${t("hidden topics")}`);
66624
+ if (extra.length) text += ` (${extra.join(", ")})`;
67307
66625
  $count.textContent = text;
67308
66626
  $result.classList.remove("is-hidden");
67309
66627
  return 0;
67310
66628
  }
66629
+ function clear_find_box(gobj) {
66630
+ let priv = gobj.priv;
66631
+ if (priv.find_timer) {
66632
+ clearTimeout(priv.find_timer);
66633
+ priv.find_timer = null;
66634
+ }
66635
+ let $container = gobj_read_attr(gobj, "$container");
66636
+ let $input = $container ? $container.querySelector(".GRAPH_FIND_INPUT") : null;
66637
+ if ($input) {
66638
+ $input.value = "";
66639
+ refresh_clear($input);
66640
+ }
66641
+ priv._find_result = null;
66642
+ refresh_find_result(gobj);
66643
+ }
67311
66644
  function ac_set_focus_topic(gobj, event, kw, src) {
67312
66645
  let priv = gobj.priv;
67313
66646
  priv.focus_topic = kw && kw.topic || "";
@@ -67318,6 +66651,7 @@ function ac_set_focus_topic(gobj, event, kw, src) {
67318
66651
  set_legend_list_attr(gobj, "hidden_topics", "EV_SET_HIDDEN_TOPICS", hidden);
67319
66652
  }
67320
66653
  }
66654
+ if (priv.focus_topic) clear_find_box(gobj);
67321
66655
  if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_FOCUS_TOPIC", {
67322
66656
  topic: priv.focus_topic,
67323
66657
  reveal: kw && kw.reveal || "page"
@@ -67495,6 +66829,11 @@ function create_gclass$3(gclass_name) {
67495
66829
  ac_find_nodes,
67496
66830
  null
67497
66831
  ],
66832
+ [
66833
+ "EV_FIND_NEXT",
66834
+ ac_find_next,
66835
+ null
66836
+ ],
67498
66837
  [
67499
66838
  "EV_EXPAND_LEVEL",
67500
66839
  ac_fold_level_step,
@@ -67593,6 +66932,7 @@ function create_gclass$3(gclass_name) {
67593
66932
  ["EV_SET_OPERATION_MODE", 0],
67594
66933
  ["EV_SET_FOCUS_TOPIC", 0],
67595
66934
  ["EV_FIND_NODES", 0],
66935
+ ["EV_FIND_NEXT", 0],
67596
66936
  ["EV_EXPAND_LEVEL", 0],
67597
66937
  ["EV_COLLAPSE_LEVEL", 0],
67598
66938
  ["EV_SET_NODE_MODE", 0],