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