@yuneta/gobj-ui 7.23.74 → 7.23.75

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.
@@ -27370,10 +27370,10 @@ function fold_reveal(model, state, node_key) {
27370
27370
  /***********************************************************************
27371
27371
  * treedb_layout.js
27372
27372
  *
27373
- * Three layouts made for a treedb, and nothing else.
27373
+ * Two layouts made for a treedb, and nothing else.
27374
27374
  *
27375
27375
  * What a treedb graph IS, once it is folded (treedb_fold_model.js):
27376
- * a forest read left to right. A main topic is a tree (places:
27376
+ * a forest read top to bottom. A main topic is a tree (places:
27377
27377
  * country, region, site, hall), the other topics hang from its
27378
27378
  * nodes through hooks (devices, users, controllers), a record may
27379
27379
  * hang from two parents (a device from its place AND its
@@ -27394,9 +27394,8 @@ function fold_reveal(model, state, node_key) {
27394
27394
  * - the force family scatters a tree, which is the pile with
27395
27395
  * physics.
27396
27396
  *
27397
- * So: a tidy tree (`tree`), an outline (`outline`) and a radial
27398
- * tree (`radial`), all three fed by the SAME spanning tree, chosen
27399
- * deterministically:
27397
+ * So: a tidy tree (`tree`) and a radial tree (`radial`), both fed
27398
+ * by the SAME spanning tree, chosen deterministically:
27400
27399
  *
27401
27400
  * - roots are the nodes with no incoming edge, in node order;
27402
27401
  * - a node belongs to the FIRST parent that reaches it in a
@@ -27408,16 +27407,16 @@ function fold_reveal(model, state, node_key) {
27408
27407
  * and then by node order (record order, the pages' order);
27409
27408
  * - a node nothing reaches (a cycle) is a root too.
27410
27409
  *
27411
- * `tree`: the classic tidy tree, left to right. Each depth is a
27412
- * column as wide as its widest card; a node is centred on the
27413
- * block of its children; siblings stack with `nodesep` between
27414
- * them. O(n), and opening a hook moves NOTHING that is not below
27415
- * or beside it -- the cards keep their order, the eye keeps its
27416
- * place.
27417
- *
27418
- * `outline`: one node per row, indented by depth -- what a JSON
27419
- * viewer draws, and what a treedb is when read as one. Tall, but
27420
- * nothing is ever beside anything: the reader scrolls a list.
27410
+ * `tree`: the classic tidy tree, top to bottom. Each depth is a
27411
+ * row as tall as its tallest card; a node is centred over the
27412
+ * block of its children; siblings sit side by side with `nodesep`
27413
+ * between them. O(n), and opening a hook moves NOTHING that is
27414
+ * not below or beside it -- the cards keep their order, the eye
27415
+ * keeps its place. It reads DOWN because that is the direction a
27416
+ * tree with many children has room in: a hall with a hundred
27417
+ * devices is a wide row, not a tall column beside a card. (The
27418
+ * left-to-right reading is `direction: "LR"`, kept for a host
27419
+ * that wants it; `dagre` reads that way in the graph.)
27421
27420
  *
27422
27421
  * `radial`: the root in the middle and a ring per depth, each
27423
27422
  * subtree owning a sector proportional to its leaves; the radius
@@ -27425,15 +27424,15 @@ function fold_reveal(model, state, node_key) {
27425
27424
  * nothing overlaps by construction (see `layout_radial`).
27426
27425
  *
27427
27426
  * Pure: takes plain nodes and edges, returns positions. The G6
27428
- * classes in c_g6_nodes_tree.js are three thin adapters over it.
27427
+ * classes in c_g6_nodes_tree.js are two thin adapters over it.
27429
27428
  *
27430
27429
  * Copyright (c) 2026, ArtGins.
27431
27430
  * All Rights Reserved.
27432
27431
  ***********************************************************************/
27433
27432
  var DEFAULTS = {
27434
27433
  nodesep: 18,
27435
- ranksep: 110,
27436
- indent: 48
27434
+ ranksep: 90,
27435
+ direction: "TB"
27437
27436
  };
27438
27437
  /************************************************************
27439
27438
  * The spanning tree of a graph, deterministic.
@@ -27520,13 +27519,33 @@ function walk_order(t) {
27520
27519
  return order;
27521
27520
  }
27522
27521
  /************************************************************
27523
- * The tidy tree, left to right.
27522
+ * The tidy tree.
27524
27523
  *
27525
27524
  * Returns Map<id, {x, y}> with the CENTRE of each node, the way G6
27526
27525
  * positions a node.
27526
+ *
27527
+ * The algorithm is written ONCE, reading left to right (depths are
27528
+ * columns, siblings stack down). Top to bottom -- the default -- is
27529
+ * the same tree with the axes swapped: every card is fed in
27530
+ * transposed (its height as its width), and every position comes
27531
+ * back transposed. That is the whole difference, and it is the
27532
+ * reason the code is not duplicated for a second direction.
27527
27533
  ************************************************************/
27528
27534
  function layout_tree(nodes, edges, opts) {
27529
27535
  let o = Object.assign({}, DEFAULTS, opts || {});
27536
+ if (o.direction === "LR") return tidy_tree_lr(nodes, edges, o);
27537
+ let lr = tidy_tree_lr(nodes.map((n) => Object.assign({}, n, {
27538
+ w: n.h,
27539
+ h: n.w
27540
+ })), edges, o);
27541
+ let pos = /* @__PURE__ */ new Map();
27542
+ for (let [id, p] of lr) pos.set(id, {
27543
+ x: p.y,
27544
+ y: p.x
27545
+ });
27546
+ return pos;
27547
+ }
27548
+ function tidy_tree_lr(nodes, edges, o) {
27530
27549
  let t = spanning_tree(nodes, edges);
27531
27550
  let pos = /* @__PURE__ */ new Map();
27532
27551
  let col_w = [];
@@ -27692,37 +27711,6 @@ function layout_radial(nodes, edges, opts) {
27692
27711
  }
27693
27712
  return pos;
27694
27713
  }
27695
- /************************************************************
27696
- * The outline: one node per row, indented by depth, in the
27697
- * pre-order of the spanning tree. Rows are left-aligned on
27698
- * their indent, so a column of chips reads as a list.
27699
- ************************************************************/
27700
- function layout_outline(nodes, edges, opts) {
27701
- let o = Object.assign({}, DEFAULTS, opts || {});
27702
- let t = spanning_tree(nodes, edges);
27703
- let pos = /* @__PURE__ */ new Map();
27704
- let y = 0;
27705
- let visit = (root_id) => {
27706
- let stack = [root_id];
27707
- while (stack.length) {
27708
- let id = stack.pop();
27709
- let n = t.by_id.get(id);
27710
- let d = t.depth.get(id);
27711
- pos.set(id, {
27712
- x: d * o.indent + n.w / 2,
27713
- y: y + n.h / 2
27714
- });
27715
- y += n.h + o.nodesep;
27716
- let kids = t.children.get(id) || [];
27717
- for (let i = kids.length - 1; i >= 0; i--) stack.push(kids[i]);
27718
- }
27719
- };
27720
- for (let root of t.roots) {
27721
- visit(root);
27722
- y += o.nodesep;
27723
- }
27724
- return pos;
27725
- }
27726
27714
  //#endregion
27727
27715
  //#region node_modules/@babel/runtime/helpers/esm/typeof.js
27728
27716
  function _typeof(o) {
@@ -54539,6 +54527,14 @@ var GCLASS_NAME$4 = "C_G6_NODES_TREE";
54539
54527
  var HIGHLIGHT_COLOR = "#f0a020";
54540
54528
  var HIGHLIGHT_HALO = "rgba(240,160,32,0.35)";
54541
54529
  var SELECT_RING = "rgba(59,130,246,0.95)";
54530
+ var PORT_R_ENTITY = 10;
54531
+ var PORT_R_CHILD = 5;
54532
+ var PORT_LINE_WIDTH = 2;
54533
+ var COMPACT_SIZE = {
54534
+ hierarchical: 32,
54535
+ extended: 28,
54536
+ child: 22
54537
+ };
54542
54538
  /***************************************************************
54543
54539
  * Internal layout and operation mode definitions
54544
54540
  ***************************************************************/
@@ -54546,13 +54542,9 @@ var _layouts = {
54546
54542
  "manual": { type: "manual" },
54547
54543
  "treedb-tree": {
54548
54544
  type: "treedb-tree",
54545
+ direction: "TB",
54549
54546
  nodesep: 18,
54550
- ranksep: 110
54551
- },
54552
- "treedb-outline": {
54553
- type: "treedb-outline",
54554
- nodesep: 12,
54555
- indent: 48
54547
+ ranksep: 90
54556
54548
  },
54557
54549
  "dagre": {
54558
54550
  type: "dagre",
@@ -54623,6 +54615,8 @@ var attrs_table$4 = [
54623
54615
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "hidden_topics", 0, "[]", "Topics left out of the tree: no card, no pill counts them, no edge reaches them"),
54624
54616
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "main_topic", 0, "", "The topic the tree hangs from; empty = deduced (the one whose hooks reach the most others). Its parentless records are the roots; a parentless record of a topic linked to it is LOOSE and shown only on request"),
54625
54617
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "loose_topics", 0, "[]", "Topics whose loose records (no parent, in a topic the schema hangs from the main one) are shown as roots"),
54618
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "node_mode", 0, "expanded", "How a record is drawn: `expanded` = the card with its ports (the only shape a link can be edited on); `compact` = a rounded square of the topic's colour, no ports, no text -- the topology alone. One node can be toggled against it (EV_TOGGLE_NODE_MODE)"),
54619
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "node_labels", 0, true, "A compact node says its name under the square. Off, it is a coloured square and nothing else"),
54626
54620
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
54627
54621
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
54628
54622
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
@@ -54706,6 +54700,7 @@ var PRIVATE_DATA$4 = {
54706
54700
  _fold_state: null,
54707
54701
  _fold_listener: null,
54708
54702
  _pill_sig: null,
54703
+ _open_nodes: null,
54709
54704
  _fold_busy: false
54710
54705
  };
54711
54706
  var __gclass__$4 = null;
@@ -54851,7 +54846,6 @@ function register_layouts(gobj) {
54851
54846
  _g6_extensions_registered = true;
54852
54847
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "manual", ManualLayout);
54853
54848
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
54854
- (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-outline", TreedbOutlineLayout);
54855
54849
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
54856
54850
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
54857
54851
  }
@@ -54934,6 +54928,9 @@ function configure_events(gobj) {
54934
54928
  graph.on(_antv_g6.NodeEvent.CONTEXT_MENU, (evt) => {
54935
54929
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_CONTEXT_MENU", { evt }, gobj);
54936
54930
  });
54931
+ graph.on(_antv_g6.NodeEvent.DBLCLICK, (evt) => {
54932
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_DBLCLICK", { evt }, gobj);
54933
+ });
54937
54934
  graph.on(_antv_g6.EdgeEvent.CLICK, (evt) => {
54938
54935
  if (consume_long_press_click(graph)) return;
54939
54936
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_EDGE_CLICK", { evt }, gobj);
@@ -55358,7 +55355,7 @@ function configure_behaviour(gobj) {
55358
55355
  case "writing":
55359
55356
  case "reading":
55360
55357
  priv.edit_mode = false;
55361
- behaviors = ["drag-canvas", "zoom-canvas"];
55358
+ behaviors = ["drag-canvas", ...camera_behaviors()];
55362
55359
  break;
55363
55360
  case "edition":
55364
55361
  priv.edit_mode = true;
@@ -55372,7 +55369,7 @@ function configure_behaviour(gobj) {
55372
55369
  return true;
55373
55370
  }
55374
55371
  },
55375
- "zoom-canvas",
55372
+ ...camera_behaviors(),
55376
55373
  "drag-element",
55377
55374
  {
55378
55375
  type: BRUSH_SELECT_OWNED,
@@ -55390,7 +55387,7 @@ function configure_behaviour(gobj) {
55390
55387
  break;
55391
55388
  case "operation":
55392
55389
  priv.edit_mode = false;
55393
- behaviors = ["drag-canvas", "zoom-canvas"];
55390
+ behaviors = ["drag-canvas", ...camera_behaviors()];
55394
55391
  break;
55395
55392
  default: (0, _yuneta_gobj_js.log_error)(`operation mode unknown: ${operation_mode}`);
55396
55393
  }
@@ -55462,13 +55459,33 @@ function build_ports(gobj, desc) {
55462
55459
  * Which way the graph reads. `dagre` is the left-to-right
55463
55460
  * layout; everything else keeps the top-down reading, `manual`
55464
55461
  * included, because the saved arrangements were made with the
55465
- * ports on the top and bottom edges.
55466
- ************************************************************/
55467
- var LR_LAYOUTS = [
55468
- "dagre",
55469
- "treedb-tree",
55470
- "treedb-outline"
55471
- ];
55462
+ * ports on the top and bottom edges. The treedb tree reads down
55463
+ * too, since 7.23.75: read right it was dagre's twin.
55464
+ ************************************************************/
55465
+ var LR_LAYOUTS = ["dagre"];
55466
+ /************************************************************
55467
+ * The camera behaviors every operation mode shares.
55468
+ *
55469
+ * The wheel SCROLLS, as it does on a map and on every page: a
55470
+ * graph of many nodes is taller than the screen, and a wheel
55471
+ * that zoomed instead made it a thing to be looked at from afar
55472
+ * or read through a keyhole -- never scrolled. Zoom is Ctrl +
55473
+ * wheel (which is also what a trackpad pinch arrives as), the
55474
+ * toolbar's +/-, and the two-finger pinch of g6_touch_gestures.
55475
+ * `enable` on the scroll keeps the two apart: a Ctrl wheel is
55476
+ * the zoom's, so the scroll stands aside for it.
55477
+ ************************************************************/
55478
+ function camera_behaviors() {
55479
+ return [{
55480
+ type: "scroll-canvas",
55481
+ key: "scroll-canvas",
55482
+ enable: (event) => !(event && (event.ctrlKey || event.metaKey))
55483
+ }, {
55484
+ type: "zoom-canvas",
55485
+ key: "zoom-canvas",
55486
+ trigger: ["Control"]
55487
+ }];
55488
+ }
55472
55489
  function layout_direction(gobj) {
55473
55490
  return (0, _yuneta_gobj_js.str_in_list)(LR_LAYOUTS, gobj.priv.layout) ? "LR" : "TB";
55474
55491
  }
@@ -55536,83 +55553,101 @@ function apply_layout_direction(gobj) {
55536
55553
  * Create a topic node in the G6 graph
55537
55554
  ************************************************************/
55538
55555
  function create_topic_node(gobj, desc, record) {
55539
- let priv = gobj.priv;
55540
- const graph = priv.graph;
55556
+ const graph = gobj.priv.graph;
55541
55557
  let node_name = build_node_name(gobj, desc.topic_name, record.id);
55542
55558
  let xy = get_default_ne_xy(gobj);
55543
55559
  let geometry = get_node_graph_props(gobj, desc.topic_name, record.id, record);
55544
55560
  let x = (0, _yuneta_gobj_js.kw_get_int)(gobj, geometry, "x", xy, _yuneta_gobj_js.kw_flag_t.KW_CREATE);
55545
55561
  let y = (0, _yuneta_gobj_js.kw_get_int)(gobj, geometry, "y", xy, _yuneta_gobj_js.kw_flag_t.KW_CREATE);
55546
- let ports = build_ports(gobj, desc);
55547
- let node_graph_type = null;
55562
+ let shape = node_shape_of(gobj, node_name, desc, record, geometry, pills_html_of_key(gobj, fold_node_key(desc.topic_name, String(record.id))));
55563
+ let node_def = {
55564
+ id: node_name,
55565
+ type: shape.type,
55566
+ style: Object.assign({
55567
+ x,
55568
+ y
55569
+ }, shape.style),
55570
+ data: {
55571
+ topic_name: desc.topic_name,
55572
+ desc,
55573
+ record,
55574
+ graph_props: geometry,
55575
+ port_keys: build_ports(gobj, desc).map((p) => p.key)
55576
+ }
55577
+ };
55578
+ graph.addNodeData([node_def]);
55579
+ }
55580
+ /************************************************************
55581
+ * The shape of a record node: OPEN (the card, with its ports)
55582
+ * or CLOSED (a coloured square), by `node_mode` and the nodes
55583
+ * toggled against it.
55584
+ *
55585
+ * Both answer {type, style} WITHOUT x/y, which belong to the node
55586
+ * and not to its shape, and a node moves between the two on the
55587
+ * fly: G6 rebuilds the element when `type` changes, and the
55588
+ * style is MERGED, which is why each shape also writes the keys
55589
+ * the other one would leave behind (`labelText`, `ports`).
55590
+ ************************************************************/
55591
+ function node_shape_of(gobj, node_id, desc, record, geometry, pills_html) {
55592
+ if (node_is_compact(gobj, node_id)) return compact_shape_of(gobj, desc, record, {});
55593
+ return card_shape_of(gobj, desc, record, geometry, pills_html);
55594
+ }
55595
+ function node_is_compact(gobj, node_id) {
55596
+ let priv = gobj.priv;
55597
+ if (!priv._open_nodes) priv._open_nodes = /* @__PURE__ */ new Set();
55598
+ let compact = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact";
55599
+ return priv._open_nodes.has(node_id) ? !compact : compact;
55600
+ }
55601
+ /************************************************************
55602
+ * The CARD: an html node, the tier's size, the ports, the
55603
+ * saved geometry on top. The flags (focus, selection, anchor)
55604
+ * are not painted here: repaint_cards() reads them where they
55605
+ * live and rebuilds the html.
55606
+ ************************************************************/
55607
+ function card_shape_of(gobj, desc, record, geometry, pills_html) {
55608
+ let priv = gobj.priv;
55548
55609
  let node_treedb_type = desc.node_treedb_type;
55610
+ let label = node_label(desc, record);
55611
+ let ports = build_ports(gobj, desc);
55549
55612
  let style = {
55550
- x,
55551
- y,
55552
55613
  fill: desc.color,
55553
55614
  stroke: getStrokeColor(desc.color),
55554
- lineWidth: 1
55615
+ lineWidth: 1,
55616
+ lineDash: [],
55617
+ halo: false,
55618
+ labelText: ""
55555
55619
  };
55556
- let pills_html = pills_html_of_key(gobj, fold_node_key(desc.topic_name, String(record.id)));
55557
55620
  let size = card_size_for(node_treedb_type, !!pills_html);
55558
- if (node_treedb_type === "child") {
55559
- node_graph_type = "html";
55560
- style.size = size;
55561
- style.dx = -size[0] / 2;
55562
- style.dy = -size[1] / 2;
55563
- style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id);
55564
- } else if (node_treedb_type === "extended") {
55565
- node_graph_type = "html";
55566
- style.size = size;
55567
- style.dx = -size[0] / 2;
55568
- style.dy = -size[1] / 2;
55569
- style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id, false, false, false, pills_html);
55570
- } else {
55571
- node_graph_type = "html";
55572
- style.size = size;
55573
- style.dx = -size[0] / 2;
55574
- style.dy = -size[1] / 2;
55575
- style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id, false, false, false, pills_html);
55576
- }
55621
+ style.size = size;
55622
+ style.dx = -size[0] / 2;
55623
+ style.dy = -size[1] / 2;
55624
+ if (node_treedb_type === "child") style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, label, record.id);
55625
+ else if (node_treedb_type === "extended") style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, label, desc.topic_name, true, record.id, false, false, false, pills_html);
55626
+ else style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, label, desc.topic_name, false, record.id, false, false, false, pills_html);
55577
55627
  let topic_props = priv._graph_properties[desc.topic_name];
55578
55628
  let topic_defaults = (0, _yuneta_gobj_js.is_object)(topic_props) && (0, _yuneta_gobj_js.is_object)(topic_props.defaults) ? topic_props.defaults : null;
55579
55629
  if (topic_defaults) {
55580
55630
  let def_size = topic_defaults.size;
55581
55631
  if (!geometry.size && Array.isArray(def_size) && def_size.length > 0) {
55582
55632
  style.size = [...def_size];
55583
- if (node_graph_type === "html") {
55584
- style.dx = -def_size[0] / 2;
55585
- style.dy = -(def_size.length > 1 ? def_size[1] : def_size[0]) / 2;
55586
- }
55633
+ style.dx = -def_size[0] / 2;
55634
+ style.dy = -(def_size.length > 1 ? def_size[1] : def_size[0]) / 2;
55587
55635
  }
55588
55636
  if (!geometry.portR && topic_defaults.portR > 0) style.portR = topic_defaults.portR;
55589
55637
  }
55590
55638
  let saved_size = geometry.size;
55591
55639
  if (Array.isArray(saved_size) && saved_size.length > 0) {
55592
55640
  style.size = saved_size;
55593
- if (node_graph_type === "html") {
55594
- style.dx = -saved_size[0] / 2;
55595
- style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
55596
- }
55641
+ style.dx = -saved_size[0] / 2;
55642
+ style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
55597
55643
  }
55598
55644
  if (geometry.portR > 0) style.portR = geometry.portR;
55599
- let node_def = {
55600
- id: node_name,
55601
- type: node_graph_type,
55602
- style,
55603
- data: {
55604
- topic_name: desc.topic_name,
55605
- desc,
55606
- record,
55607
- graph_props: geometry
55608
- }
55609
- };
55610
55645
  if ((0, _yuneta_gobj_js.json_size)(ports)) {
55611
55646
  (0, _yuneta_gobj_js.json_object_update_missing)(style, {
55612
55647
  port: true,
55613
55648
  ports,
55614
- portR: node_treedb_type === "child" ? 2 : 6,
55615
- portLineWidth: 1
55649
+ portR: node_treedb_type === "child" ? PORT_R_CHILD : PORT_R_ENTITY,
55650
+ portLineWidth: PORT_LINE_WIDTH
55616
55651
  });
55617
55652
  let port_sizes = geometry.port_sizes;
55618
55653
  let default_port_sizes = topic_defaults ? topic_defaults.port_sizes : null;
@@ -55622,8 +55657,117 @@ function create_topic_node(gobj, desc, record) {
55622
55657
  if (r == null && (0, _yuneta_gobj_js.is_object)(default_port_sizes)) r = default_port_sizes[key];
55623
55658
  if (r != null) style.ports[i].r = r;
55624
55659
  }
55660
+ } else {
55661
+ style.port = false;
55662
+ style.ports = [];
55663
+ }
55664
+ return {
55665
+ type: "html",
55666
+ style
55667
+ };
55668
+ }
55669
+ /************************************************************
55670
+ * The SQUARE: a G6 `rect` of the topic's colour, no ports, the
55671
+ * name as a label under it when `node_labels` says so. A native
55672
+ * shape and not html on purpose: G6's own stroke and halo paint
55673
+ * on it, so the focus, the selection and the anchor are three
55674
+ * keys of the style instead of a rebuilt innerHTML.
55675
+ *
55676
+ * flags {highlight, selected, anchored}
55677
+ ************************************************************/
55678
+ function compact_shape_of(gobj, desc, record, flags) {
55679
+ let dark = gobj.priv.theme === "dark";
55680
+ let f = flags || {};
55681
+ let tier = desc.node_treedb_type;
55682
+ let side = COMPACT_SIZE[tier] || COMPACT_SIZE.hierarchical;
55683
+ let labels = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
55684
+ let stroke = getStrokeColor(desc.color);
55685
+ let line_width = 1.5;
55686
+ if (f.selected) {
55687
+ stroke = SELECT_RING;
55688
+ line_width = 3;
55689
+ }
55690
+ if (f.highlight) {
55691
+ stroke = HIGHLIGHT_COLOR;
55692
+ line_width = 3;
55693
+ }
55694
+ let dash = [];
55695
+ if (tier === "extended") dash = [4, 3];
55696
+ if (f.anchored) {
55697
+ dash = [2, 2];
55698
+ line_width = Math.max(line_width, 2.5);
55699
+ }
55700
+ return {
55701
+ type: "rect",
55702
+ style: {
55703
+ size: [side, side],
55704
+ radius: Math.round(side / 5),
55705
+ fill: desc.color,
55706
+ stroke,
55707
+ lineWidth: line_width,
55708
+ lineDash: dash,
55709
+ halo: !!f.highlight,
55710
+ haloStroke: HIGHLIGHT_HALO,
55711
+ haloLineWidth: 8,
55712
+ port: false,
55713
+ ports: [],
55714
+ labelText: labels ? node_label(desc, record) : "",
55715
+ labelPlacement: "bottom",
55716
+ labelFontSize: 11,
55717
+ labelFill: dark ? "#e6e9ef" : "#2e333d",
55718
+ labelMaxWidth: 150,
55719
+ labelWordWrap: true,
55720
+ labelMaxLines: 1,
55721
+ labelTextOverflow: "ellipsis",
55722
+ labelBackground: true,
55723
+ labelBackgroundFill: dark ? "#1b2230" : "#ffffff",
55724
+ labelBackgroundOpacity: .85,
55725
+ labelBackgroundRadius: 3,
55726
+ labelPadding: [1, 3]
55727
+ }
55728
+ };
55729
+ }
55730
+ /************************************************************
55731
+ * Give these record nodes the shape their mode says, then
55732
+ * repaint them with the flags they carry. A `+N` chip is not a
55733
+ * record and keeps its own shape.
55734
+ ************************************************************/
55735
+ function reshape_nodes(gobj, ids) {
55736
+ let graph = gobj.priv.graph;
55737
+ if (!graph) return;
55738
+ let updates = [];
55739
+ let touched = /* @__PURE__ */ new Set();
55740
+ for (let id of ids) {
55741
+ let nd;
55742
+ try {
55743
+ nd = graph.getNodeData(id);
55744
+ } catch (e) {
55745
+ continue;
55746
+ }
55747
+ if (!nd || !nd.data || !nd.data.desc || is_more_node(nd)) continue;
55748
+ let geometry = nd.data.graph_props || {};
55749
+ let shape = node_shape_of(gobj, id, nd.data.desc, nd.data.record || {}, geometry, pills_html_of(gobj, nd));
55750
+ updates.push({
55751
+ id,
55752
+ type: shape.type,
55753
+ style: shape.style
55754
+ });
55755
+ touched.add(id);
55756
+ }
55757
+ if (!updates.length) return;
55758
+ try {
55759
+ graph.updateNodeData(updates);
55760
+ } catch (e) {
55761
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot reshape the nodes: ${e}`);
55762
+ return;
55625
55763
  }
55626
- if (node_graph_type) graph.addNodeData([node_def]);
55764
+ repaint_cards(gobj, touched);
55765
+ }
55766
+ function all_record_node_ids(gobj) {
55767
+ let graph = gobj.priv.graph;
55768
+ let ids = [];
55769
+ for (let nd of graph && graph.getNodeData() || []) if (nd && nd.data && nd.data.desc && !is_more_node(nd)) ids.push(nd.id);
55770
+ return ids;
55627
55771
  }
55628
55772
  /************************************************************
55629
55773
  * Update topic node data
@@ -56470,7 +56614,7 @@ var ManualLayout = class extends _antv_g6.BaseLayout {
56470
56614
  }
56471
56615
  };
56472
56616
  /************************************************************
56473
- * Custom G6 layouts: TreedbTreeLayout / TreedbOutlineLayout.
56617
+ * Custom G6 layouts: TreedbTreeLayout / TreedbRadialLayout.
56474
56618
  *
56475
56619
  * Thin adapters over treedb_layout.js: the nodes with their sizes,
56476
56620
  * the edges with the RANK of the hook they leave by (the position
@@ -56488,7 +56632,8 @@ function treedb_layout_input(data) {
56488
56632
  let w = (0, _yuneta_gobj_js.is_array)(size) ? size[0] : size;
56489
56633
  let h = (0, _yuneta_gobj_js.is_array)(size) ? size.length > 1 ? size[1] : size[0] : size;
56490
56634
  let ports = node.style && (0, _yuneta_gobj_js.is_array)(node.style.ports) ? node.style.ports : [];
56491
- ports_of.set(node.id, ports.map((p) => p.key));
56635
+ let keys = node.data && (0, _yuneta_gobj_js.is_array)(node.data.port_keys) ? node.data.port_keys : ports.map((p) => p.key);
56636
+ ports_of.set(node.id, keys);
56492
56637
  return {
56493
56638
  id: node.id,
56494
56639
  w,
@@ -56524,12 +56669,6 @@ var TreedbTreeLayout = class extends _antv_g6.BaseLayout {
56524
56669
  return treedb_layout_output(layout_tree(input.nodes, input.edges, options));
56525
56670
  }
56526
56671
  };
56527
- var TreedbOutlineLayout = class extends _antv_g6.BaseLayout {
56528
- async execute(data, options) {
56529
- let input = treedb_layout_input(data);
56530
- return treedb_layout_output(layout_outline(input.nodes, input.edges, options));
56531
- }
56532
- };
56533
56672
  var TreedbRadialLayout = class extends _antv_g6.BaseLayout {
56534
56673
  async execute(data, options) {
56535
56674
  let input = treedb_layout_input(data);
@@ -57221,7 +57360,7 @@ function get_port_radius(gobj, node_id, port_key) {
57221
57360
  if (ports[i].r != null) return ports[i].r;
57222
57361
  break;
57223
57362
  }
57224
- return style.portR || 6;
57363
+ return style.portR || PORT_R_ENTITY;
57225
57364
  }
57226
57365
  /************************************************************
57227
57366
  * How much wider than the port itself its hit area is,
@@ -57253,7 +57392,7 @@ function detect_port_click(gobj, node_id, canvasX, canvasY) {
57253
57392
  const style = graph.getNodeData(node_id).style || {};
57254
57393
  const { w, h } = extract_size(style);
57255
57394
  const ports = style.ports || [];
57256
- const defaultR = style.portR || 6;
57395
+ const defaultR = style.portR || PORT_R_ENTITY;
57257
57396
  let best_key = null;
57258
57397
  let best_dist = Infinity;
57259
57398
  let slop = port_hit_slop_world(graph);
@@ -57410,7 +57549,7 @@ function enter_linking_mode(gobj) {
57410
57549
  p.stroke = "#52c41a";
57411
57550
  p.lineWidth = 3;
57412
57551
  if (p.r != null) p.r = p.r + 4;
57413
- else p.r = (style.portR || 6) + 4;
57552
+ else p.r = (style.portR || PORT_R_ENTITY) + 4;
57414
57553
  }
57415
57554
  graph.updateNodeData([{
57416
57555
  id: vh.node_id,
@@ -57562,7 +57701,7 @@ function find_hook_at_point(gobj, canvasX, canvasY) {
57562
57701
  let pl = p.placement || [.5, .5];
57563
57702
  let px = pos[0] + (pl[0] - .5) * w;
57564
57703
  let py = pos[1] + (pl[1] - .5) * h;
57565
- let r = p.r != null ? p.r : style.portR || 6;
57704
+ let r = p.r != null ? p.r : style.portR || PORT_R_ENTITY;
57566
57705
  let dx = canvasX - px;
57567
57706
  let dy = canvasY - py;
57568
57707
  if (Math.sqrt(dx * dx + dy * dy) <= r + 6) return {
@@ -58320,7 +58459,19 @@ function repaint_cards(gobj, ids) {
58320
58459
  } catch (e) {
58321
58460
  continue;
58322
58461
  }
58323
- let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), priv.anchor_state === "on" && id === priv.anchor_id, pills_html_of(gobj, nd));
58462
+ let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58463
+ if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58464
+ updates.push({
58465
+ id,
58466
+ style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58467
+ highlight: focus.has(id),
58468
+ selected: selected.has(id),
58469
+ anchored
58470
+ }).style
58471
+ });
58472
+ continue;
58473
+ }
58474
+ let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58324
58475
  if (html !== null) updates.push({
58325
58476
  id,
58326
58477
  style: { innerHTML: html }
@@ -58357,7 +58508,19 @@ function refresh_html_nodes_theme(gobj, theme) {
58357
58508
  for (let i = 0; i < nodes.length; i++) {
58358
58509
  let id = nodes[i].id;
58359
58510
  let nd = graph.getNodeData(id);
58360
- let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), priv.anchor_state === "on" && id === priv.anchor_id, pills_html_of(gobj, nd));
58511
+ let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58512
+ if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58513
+ updates.push({
58514
+ id,
58515
+ style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58516
+ highlight: highlighted.has(id),
58517
+ selected: selected.has(id),
58518
+ anchored
58519
+ }).style
58520
+ });
58521
+ continue;
58522
+ }
58523
+ let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58361
58524
  if (html === null) html = more_innerHTML_of(gobj, nd, theme);
58362
58525
  if (html !== null) updates.push({
58363
58526
  id,
@@ -58977,8 +59140,10 @@ function ctx_item(icon_id, label, value) {
58977
59140
  ************************************************************/
58978
59141
  function build_node_context_menu(gobj, node_id) {
58979
59142
  let items = [];
58980
- if (gobj.priv.edit_mode) {
58981
- inject_svg_icons();
59143
+ inject_svg_icons();
59144
+ if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", (0, i18next.t)("open node"), "toggle_node_mode"));
59145
+ else items.push(ctx_item("g6-icon-fullscreen-exit", (0, i18next.t)("close node"), "toggle_node_mode"));
59146
+ if (gobj.priv.edit_mode && !node_is_compact(gobj, node_id)) {
58982
59147
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize all"), "resize_all_nodes"));
58983
59148
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize topic nodes"), "resize_topic_nodes"));
58984
59149
  }
@@ -59006,8 +59171,11 @@ function build_edge_context_menu(gobj) {
59006
59171
  * Handle context menu click: dispatch by value.
59007
59172
  ************************************************************/
59008
59173
  function handle_context_menu_click(gobj, value) {
59009
- gobj.priv;
59174
+ let priv = gobj.priv;
59010
59175
  switch (value) {
59176
+ case "toggle_node_mode":
59177
+ if (priv._context_node_id) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_NODE_MODE", { id: priv._context_node_id }, gobj);
59178
+ break;
59011
59179
  case "resize_all_nodes":
59012
59180
  copy_size_to_nodes(gobj, false);
59013
59181
  break;
@@ -59538,7 +59706,7 @@ async function reconcile_fold_apply(gobj, opts, visible) {
59538
59706
  let nd = graph.getNodeData(id);
59539
59707
  let desc = nd && nd.data && nd.data.desc;
59540
59708
  let geometry = nd && nd.data && nd.data.graph_props || {};
59541
- if (desc && !(0, _yuneta_gobj_js.is_array)(geometry.size)) {
59709
+ if (desc && !(0, _yuneta_gobj_js.is_array)(geometry.size) && !node_is_compact(gobj, id)) {
59542
59710
  let size = card_size_for(desc.node_treedb_type, !!sig);
59543
59711
  resize.push({
59544
59712
  id,
@@ -59623,6 +59791,7 @@ function ac_clear_data(gobj, event, kw, src) {
59623
59791
  priv._fold_model = null;
59624
59792
  priv._fold_state = null;
59625
59793
  priv._pill_sig = null;
59794
+ priv._open_nodes = null;
59626
59795
  graph_remove_plugin(gobj, "history");
59627
59796
  update_history_buttons(gobj);
59628
59797
  graph_clear(gobj);
@@ -60121,6 +60290,79 @@ function ac_set_loose_topics(gobj, event, kw, src) {
60121
60290
  return 0;
60122
60291
  }
60123
60292
  /************************************************************
60293
+ * The shape of every record: open cards or closed squares.
60294
+ * A change of mode forgets the nodes toggled against the old
60295
+ * one -- they were exceptions to a rule that no longer holds --
60296
+ * and lays the graph out again, because a square and a card
60297
+ * do not occupy the same room.
60298
+ ************************************************************/
60299
+ function ac_set_node_mode(gobj, event, kw, src) {
60300
+ let priv = gobj.priv;
60301
+ let mode = kw && kw.node_mode === "compact" ? "compact" : "expanded";
60302
+ (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "node_mode", mode);
60303
+ priv._open_nodes = /* @__PURE__ */ new Set();
60304
+ if (!priv.graph || !priv._fold_model) return 0;
60305
+ reshape_nodes(gobj, all_record_node_ids(gobj));
60306
+ reconcile_fold(gobj, {
60307
+ relayout: true,
60308
+ fit: true
60309
+ });
60310
+ return 0;
60311
+ }
60312
+ /************************************************************
60313
+ * The name under a closed square, on or off. Only the closed
60314
+ * nodes change, and nothing moves: the label hangs outside the
60315
+ * square and the layout measures the square.
60316
+ ************************************************************/
60317
+ function ac_set_node_labels(gobj, event, kw, src) {
60318
+ let priv = gobj.priv;
60319
+ (0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "node_labels", !!(kw && kw.node_labels));
60320
+ if (!priv.graph) return 0;
60321
+ reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_is_compact(gobj, id)));
60322
+ return 0;
60323
+ }
60324
+ /************************************************************
60325
+ * ONE node opened or closed against the mode (a double click,
60326
+ * or the context menu). It holds still on screen while the
60327
+ * rest of the graph makes room, as a fold does.
60328
+ ************************************************************/
60329
+ function ac_toggle_node_mode$1(gobj, event, kw, src) {
60330
+ let priv = gobj.priv;
60331
+ let node_id = kw && kw.id || "";
60332
+ if (!priv.graph || !node_id) {
60333
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: toggle node mode without a node`);
60334
+ return -1;
60335
+ }
60336
+ if (!priv._open_nodes) priv._open_nodes = /* @__PURE__ */ new Set();
60337
+ if (priv._open_nodes.has(node_id)) priv._open_nodes.delete(node_id);
60338
+ else priv._open_nodes.add(node_id);
60339
+ let vp = yui_graph_viewport_of(priv.graph, node_id);
60340
+ reshape_nodes(gobj, [node_id]);
60341
+ if (priv._fold_model) reconcile_fold(gobj, {
60342
+ relayout: true,
60343
+ keep: node_id,
60344
+ keep_vp: vp
60345
+ });
60346
+ return 0;
60347
+ }
60348
+ /************************************************************
60349
+ * A double click on a node: open it if closed, close it if open.
60350
+ * A `+N` chip is not a record and has no shape to toggle.
60351
+ ************************************************************/
60352
+ function ac_node_dblclick(gobj, event, kw, src) {
60353
+ let priv = gobj.priv;
60354
+ let node_id = kw && kw.evt && kw.evt.target ? kw.evt.target.id : "";
60355
+ let nd = null;
60356
+ try {
60357
+ nd = priv.graph.getNodeData(node_id);
60358
+ } catch (e) {
60359
+ nd = null;
60360
+ }
60361
+ if (!nd || !nd.data || !nd.data.desc || is_more_node(nd)) return 0;
60362
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_NODE_MODE", { id: node_id }, gobj);
60363
+ return 0;
60364
+ }
60365
+ /************************************************************
60124
60366
  * Tell whoever asked how many nodes the term matched. The count is
60125
60367
  * the answer to the question the box asks; without it "nothing moved"
60126
60368
  * and "nothing matched" look the same.
@@ -60610,6 +60852,26 @@ function create_gclass$4(gclass_name) {
60610
60852
  ac_set_loose_topics,
60611
60853
  null
60612
60854
  ],
60855
+ [
60856
+ "EV_SET_NODE_MODE",
60857
+ ac_set_node_mode,
60858
+ null
60859
+ ],
60860
+ [
60861
+ "EV_SET_NODE_LABELS",
60862
+ ac_set_node_labels,
60863
+ null
60864
+ ],
60865
+ [
60866
+ "EV_TOGGLE_NODE_MODE",
60867
+ ac_toggle_node_mode$1,
60868
+ null
60869
+ ],
60870
+ [
60871
+ "EV_NODE_DBLCLICK",
60872
+ ac_node_dblclick,
60873
+ null
60874
+ ],
60613
60875
  [
60614
60876
  "EV_CENTER",
60615
60877
  ac_center,
@@ -60714,6 +60976,10 @@ function create_gclass$4(gclass_name) {
60714
60976
  ["EV_SET_HIDDEN_TOPICS", 0],
60715
60977
  ["EV_SET_MAIN_TOPIC", 0],
60716
60978
  ["EV_SET_LOOSE_TOPICS", 0],
60979
+ ["EV_SET_NODE_MODE", 0],
60980
+ ["EV_SET_NODE_LABELS", 0],
60981
+ ["EV_TOGGLE_NODE_MODE", 0],
60982
+ ["EV_NODE_DBLCLICK", 0],
60717
60983
  ["EV_LEGEND_STATE", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
60718
60984
  ["EV_CENTER", 0],
60719
60985
  ["EV_FULLSCREEN", 0],
@@ -60779,6 +61045,8 @@ var attrs_table$3 = [
60779
61045
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "hidden_topics", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "[]", "Topics hidden from the graph (legend). User preference, per treedb"),
60780
61046
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "main_topic", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "", "The topic the tree hangs from; empty = deduced by the graph. User preference, per treedb"),
60781
61047
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_LIST, "loose_topics", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "[]", "Topics whose LOOSE records (no parent) are shown. User preference, per treedb"),
61048
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "node_mode", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, "expanded", "How the records are drawn: `expanded` = the cards with their ports, `compact` = coloured squares, the topology alone. User preference"),
61049
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "node_labels", _yuneta_gobj_js.sdata_flag_t.SDF_PERSIST, true, "A compact node says its name under its square. User preference"),
60782
61050
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
60783
61051
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
60784
61052
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
@@ -60856,7 +61124,9 @@ function mt_create$3(gobj) {
60856
61124
  fold_page_size: (0, _yuneta_gobj_js.gobj_read_integer_attr)(gobj, "fold_page_size"),
60857
61125
  hidden_topics: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "hidden_topics") || [],
60858
61126
  main_topic: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "main_topic") || "",
60859
- loose_topics: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "loose_topics") || []
61127
+ loose_topics: (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "loose_topics") || [],
61128
+ node_mode: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") || "expanded",
61129
+ node_labels: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels")
60860
61130
  }, gobj);
60861
61131
  populate_nodes_tree_options(gobj);
60862
61132
  if (priv.with_treedb_tables) {}
@@ -60907,6 +61177,7 @@ function build_ui$3(gobj) {
60907
61177
  let priv = gobj.priv;
60908
61178
  let padding = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "padding");
60909
61179
  let $toolbar = make_toolbar(gobj);
61180
+ refresh_node_shape_buttons(gobj, $toolbar);
60910
61181
  let $back = make_back_to_topics(gobj);
60911
61182
  let $container = (0, _yuneta_gobj_js.createElement2)([
60912
61183
  "div",
@@ -61048,6 +61319,57 @@ function option_label(name) {
61048
61319
  /************************************************************
61049
61320
  *
61050
61321
  ************************************************************/
61322
+ /************************************************************
61323
+ * The two toggles of the nodes' shape.
61324
+ *
61325
+ * Closed nodes: every record a rounded square of its topic's
61326
+ * colour, no ports, no text -- the topology of a graph of many
61327
+ * nodes, which the cards hide behind their own size. Labels:
61328
+ * the name under each square, when the squares alone do not say
61329
+ * enough. Both persist, both are forwarded to the G6 child, and
61330
+ * one node can be opened against the rule with a double click or
61331
+ * its context menu (the child's business).
61332
+ ************************************************************/
61333
+ function node_shape_items(gobj, wide) {
61334
+ let toggle = (cls, icon, event_name, label_key) => {
61335
+ return [
61336
+ "button",
61337
+ {
61338
+ class: `${cls} button`,
61339
+ type: "button",
61340
+ style: {
61341
+ height: wide,
61342
+ width: "2.5em"
61343
+ },
61344
+ title: (0, i18next.t)(label_key),
61345
+ "data-i18n-title": label_key,
61346
+ "aria-label": (0, i18next.t)(label_key),
61347
+ "data-i18n-aria-label": label_key,
61348
+ "aria-pressed": "false"
61349
+ },
61350
+ ["i", {
61351
+ style: "font-size:1.5em; color:inherit;",
61352
+ class: icon
61353
+ }],
61354
+ { click: (evt) => {
61355
+ evt.stopPropagation();
61356
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, event_name, {}, gobj);
61357
+ } }
61358
+ ];
61359
+ };
61360
+ return [toggle("GRAPH_NODE_MODE", "yi-hexagon-nodes", "EV_TOGGLE_NODE_MODE", "closed nodes"), toggle("GRAPH_NODE_LABELS", "yi-font", "EV_TOGGLE_NODE_LABELS", "node labels")];
61361
+ }
61362
+ function refresh_node_shape_buttons(gobj, $root) {
61363
+ if (!$root) return;
61364
+ let compact = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact";
61365
+ let labels = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
61366
+ set_pressed_state($root, ".GRAPH_NODE_MODE", compact);
61367
+ set_pressed_state($root, ".GRAPH_NODE_LABELS", labels);
61368
+ let $mode = $root.querySelector(".GRAPH_NODE_MODE");
61369
+ if ($mode) $mode.setAttribute("aria-pressed", compact ? "true" : "false");
61370
+ let $labels = $root.querySelector(".GRAPH_NODE_LABELS");
61371
+ if ($labels) $labels.setAttribute("aria-pressed", labels ? "true" : "false");
61372
+ }
61051
61373
  function make_toolbar(gobj) {
61052
61374
  let priv = gobj.priv;
61053
61375
  let modes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "operation_modes");
@@ -61118,6 +61440,7 @@ function make_toolbar(gobj) {
61118
61440
  } }
61119
61441
  ],
61120
61442
  ...yui_graph_fold_items(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "wide")),
61443
+ ...node_shape_items(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "wide")),
61121
61444
  [
61122
61445
  "button",
61123
61446
  {
@@ -62432,6 +62755,29 @@ function ac_collapse_all(gobj, event, kw, src) {
62432
62755
  return 0;
62433
62756
  }
62434
62757
  /************************************************************
62758
+ * The shape pair of the toolbar: the attr flips, persists,
62759
+ * shows on the button, and reaches the G6 child, which owns
62760
+ * the nodes.
62761
+ ************************************************************/
62762
+ function ac_toggle_node_mode(gobj, event, kw, src) {
62763
+ let priv = gobj.priv;
62764
+ let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact" ? "expanded" : "compact";
62765
+ (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "node_mode", mode);
62766
+ (0, _yuneta_gobj_js.gobj_save_persistent_attrs)(gobj, "node_mode");
62767
+ refresh_node_shape_buttons(gobj, priv.$container);
62768
+ if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_SET_NODE_MODE", { node_mode: mode }, gobj);
62769
+ return 0;
62770
+ }
62771
+ function ac_toggle_node_labels(gobj, event, kw, src) {
62772
+ let priv = gobj.priv;
62773
+ let labels = !(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
62774
+ (0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "node_labels", labels);
62775
+ (0, _yuneta_gobj_js.gobj_save_persistent_attrs)(gobj, "node_labels");
62776
+ refresh_node_shape_buttons(gobj, priv.$container);
62777
+ if (priv.gobj_nodes_tree) (0, _yuneta_gobj_js.gobj_send_event)(priv.gobj_nodes_tree, "EV_SET_NODE_LABELS", { node_labels: labels }, gobj);
62778
+ return 0;
62779
+ }
62780
+ /************************************************************
62435
62781
  * How many nodes the term matched, from the graph child. Zero with a
62436
62782
  * term typed is an ANSWER and is shown; an empty box shows nothing.
62437
62783
  ************************************************************/
@@ -62645,6 +62991,16 @@ function create_gclass$3(gclass_name) {
62645
62991
  ac_collapse_all,
62646
62992
  null
62647
62993
  ],
62994
+ [
62995
+ "EV_TOGGLE_NODE_MODE",
62996
+ ac_toggle_node_mode,
62997
+ null
62998
+ ],
62999
+ [
63000
+ "EV_TOGGLE_NODE_LABELS",
63001
+ ac_toggle_node_labels,
63002
+ null
63003
+ ],
62648
63004
  [
62649
63005
  "EV_LAYOUT_AUTOSET",
62650
63006
  ac_layout_autoset,
@@ -62709,6 +63065,8 @@ function create_gclass$3(gclass_name) {
62709
63065
  ["EV_FIND_NODES", 0],
62710
63066
  ["EV_EXPAND_ALL", 0],
62711
63067
  ["EV_COLLAPSE_ALL", 0],
63068
+ ["EV_TOGGLE_NODE_MODE", 0],
63069
+ ["EV_TOGGLE_NODE_LABELS", 0],
62712
63070
  ["EV_FIND_RESULT", 0],
62713
63071
  ["EV_LAYOUT_AUTOSET", 0],
62714
63072
  ["EV_LEGEND_TOPIC", 0],