@yuneta/gobj-ui 7.23.81 → 7.23.82

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.
@@ -54525,11 +54525,31 @@ var SELECT_RING = "rgba(59,130,246,0.95)";
54525
54525
  var PORT_R_ENTITY = 14;
54526
54526
  var PORT_R_CHILD = 8;
54527
54527
  var PORT_LINE_WIDTH = 2;
54528
- var COMPACT_SIZE = {
54528
+ var NODE_MODES$1 = [
54529
+ "expanded",
54530
+ "compact",
54531
+ "shape"
54532
+ ];
54533
+ var PILL_SIZE = {
54534
+ hierarchical: [200, 30],
54535
+ extended: [180, 28],
54536
+ child: [160, 26]
54537
+ };
54538
+ var PORT_R_PILL = 6;
54539
+ var SHAPE_SIZE = {
54529
54540
  hierarchical: 32,
54530
54541
  extended: 28,
54531
54542
  child: 22
54532
54543
  };
54544
+ var NODE_SHAPES = [
54545
+ "square",
54546
+ "circle",
54547
+ "diamond",
54548
+ "triangle",
54549
+ "hexagon",
54550
+ "star"
54551
+ ];
54552
+ var DEFAULT_NODE_SHAPE = "square";
54533
54553
  /***************************************************************
54534
54554
  * Internal layout and operation mode definitions
54535
54555
  ***************************************************************/
@@ -54610,8 +54630,8 @@ var attrs_table$4 = [
54610
54630
  SDATA(data_type_t.DTP_LIST, "hidden_topics", 0, "[]", "Topics left out of the tree: no card, no pill counts them, no edge reaches them"),
54611
54631
  SDATA(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"),
54612
54632
  SDATA(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"),
54613
- SDATA(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)"),
54614
- SDATA(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"),
54633
+ SDATA(data_type_t.DTP_STRING, "node_mode", 0, "expanded", "How a record is drawn: `expanded` = the card with its pills and ports; `compact` = a one-line pill with the name and small ports; `shape` = a figure of the topic's colour (square, circle, diamond... per node or topic, from the node properties), no ports, no text -- the topology alone. One node can be toggled against it (EV_TOGGLE_NODE_MODE)"),
54634
+ SDATA(data_type_t.DTP_BOOLEAN, "node_labels", 0, true, "A `shape` node says its name under the figure. Off, it is a coloured figure and nothing else"),
54615
54635
  SDATA(data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
54616
54636
  SDATA(data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
54617
54637
  SDATA(data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
@@ -55589,14 +55609,26 @@ function create_topic_node(gobj, desc, record) {
55589
55609
  * the other one would leave behind (`labelText`, `ports`).
55590
55610
  ************************************************************/
55591
55611
  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);
55612
+ switch (node_mode_of(gobj, node_id)) {
55613
+ case "shape": return figure_shape_of(gobj, desc, record, geometry, {});
55614
+ case "compact": return pill_shape_of(gobj, desc, record, geometry);
55615
+ default: return card_shape_of(gobj, desc, record, geometry, pills_html);
55616
+ }
55594
55617
  }
55595
- function node_is_compact(gobj, node_id) {
55618
+ function node_mode_of(gobj, node_id) {
55596
55619
  let priv = gobj.priv;
55597
55620
  if (!priv._open_nodes) priv._open_nodes = /* @__PURE__ */ new Set();
55598
- let compact = gobj_read_str_attr(gobj, "node_mode") === "compact";
55599
- return priv._open_nodes.has(node_id) ? !compact : compact;
55621
+ let mode = gobj_read_str_attr(gobj, "node_mode");
55622
+ if (!mode || !str_in_list(NODE_MODES$1, mode)) mode = "expanded";
55623
+ if (priv._open_nodes.has(node_id)) return mode === "expanded" ? "compact" : "expanded";
55624
+ return mode;
55625
+ }
55626
+ function node_is_compact(gobj, node_id) {
55627
+ return node_mode_of(gobj, node_id) !== "expanded";
55628
+ }
55629
+ function topic_defaults_of(gobj, topic_name) {
55630
+ let topic_props = gobj.priv._graph_properties[topic_name];
55631
+ return is_object(topic_props) && is_object(topic_props.defaults) ? topic_props.defaults : null;
55600
55632
  }
55601
55633
  /************************************************************
55602
55634
  * The CARD: an html node, the tier's size, the ports, the
@@ -55642,55 +55674,107 @@ function card_shape_of(gobj, desc, record, geometry, pills_html) {
55642
55674
  style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
55643
55675
  }
55644
55676
  if (geometry.portR > 0) style.portR = geometry.portR;
55645
- if (json_size(ports)) {
55646
- json_object_update_missing(style, {
55647
- port: true,
55648
- ports,
55649
- portR: node_treedb_type === "child" ? PORT_R_CHILD : PORT_R_ENTITY,
55650
- portLineWidth: PORT_LINE_WIDTH
55651
- });
55652
- let port_sizes = geometry.port_sizes;
55653
- let default_port_sizes = topic_defaults ? topic_defaults.port_sizes : null;
55654
- if (is_object(port_sizes) || is_object(default_port_sizes)) for (let i = 0; i < style.ports.length; i++) {
55655
- let key = style.ports[i].key;
55656
- let r = is_object(port_sizes) ? port_sizes[key] : null;
55657
- if (r == null && is_object(default_port_sizes)) r = default_port_sizes[key];
55658
- if (r != null) style.ports[i].r = r;
55659
- }
55660
- let port_shapes = geometry.port_shapes;
55661
- let default_port_shapes = topic_defaults ? topic_defaults.port_shapes : null;
55662
- let default_shape = topic_defaults ? topic_defaults.port_shape : null;
55663
- for (let i = 0; i < style.ports.length; i++) {
55664
- let key = style.ports[i].key;
55665
- let shape = is_object(port_shapes) ? port_shapes[key] : null;
55666
- if (!shape && is_object(default_port_shapes)) shape = default_port_shapes[key];
55667
- if (!shape) shape = default_shape;
55668
- if (shape && str_in_list(PORT_SHAPES, shape)) style.ports[i].shape = shape;
55669
- }
55670
- } else {
55677
+ dress_ports(gobj, style, ports, geometry, topic_defaults, node_treedb_type === "child" ? PORT_R_CHILD : PORT_R_ENTITY, false);
55678
+ return {
55679
+ type: "treedb-card",
55680
+ style
55681
+ };
55682
+ }
55683
+ /************************************************************
55684
+ * The ports of a card or a pill, dressed: the node-level radius
55685
+ * (saved, topic default, or the tier's), each port's own radius
55686
+ * and shape (saved first, then the topic's per-port defaults, then
55687
+ * the topic's one shape for every port). `fixed_r` -- the pill --
55688
+ * ignores every saved radius: a pill has one size of port.
55689
+ ************************************************************/
55690
+ function dress_ports(gobj, style, ports, geometry, topic_defaults, r_default, fixed_r) {
55691
+ if (!json_size(ports)) {
55671
55692
  style.port = false;
55672
55693
  style.ports = [];
55694
+ return;
55673
55695
  }
55696
+ json_object_update_missing(style, {
55697
+ port: true,
55698
+ ports,
55699
+ portR: r_default,
55700
+ portLineWidth: PORT_LINE_WIDTH
55701
+ });
55702
+ if (fixed_r) style.portR = r_default;
55703
+ let port_sizes = fixed_r ? null : geometry.port_sizes;
55704
+ let default_port_sizes = !fixed_r && topic_defaults ? topic_defaults.port_sizes : null;
55705
+ let port_shapes = geometry.port_shapes;
55706
+ let default_port_shapes = topic_defaults ? topic_defaults.port_shapes : null;
55707
+ let default_shape = topic_defaults ? topic_defaults.port_shape : null;
55708
+ for (let i = 0; i < style.ports.length; i++) {
55709
+ let key = style.ports[i].key;
55710
+ let r = is_object(port_sizes) ? port_sizes[key] : null;
55711
+ if (r == null && is_object(default_port_sizes)) r = default_port_sizes[key];
55712
+ if (r != null) style.ports[i].r = r;
55713
+ let shape = is_object(port_shapes) ? port_shapes[key] : null;
55714
+ if (!shape && is_object(default_port_shapes)) shape = default_port_shapes[key];
55715
+ if (!shape) shape = default_shape;
55716
+ if (shape && str_in_list(PORT_SHAPES, shape)) style.ports[i].shape = shape;
55717
+ }
55718
+ }
55719
+ /************************************************************
55720
+ * The PILL: one line with the name inside, the tint and the
55721
+ * border of the topic, small ports on its edges -- the half-way
55722
+ * house between the card and the figure, and the same one-line
55723
+ * chip a leaf record already is, at the tier's width. No pills:
55724
+ * a hook is opened from the card (expand the node).
55725
+ ************************************************************/
55726
+ function pill_shape_of(gobj, desc, record, geometry) {
55727
+ let priv = gobj.priv;
55728
+ let size = PILL_SIZE[desc.node_treedb_type] || PILL_SIZE.hierarchical;
55729
+ let ports = build_ports(gobj, desc);
55730
+ let style = {
55731
+ fill: desc.color,
55732
+ stroke: getStrokeColor(desc.color),
55733
+ lineWidth: 1,
55734
+ lineDash: [],
55735
+ halo: false,
55736
+ labelText: "",
55737
+ size: [...size],
55738
+ dx: -size[0] / 2,
55739
+ dy: -size[1] / 2,
55740
+ innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id)
55741
+ };
55742
+ dress_ports(gobj, style, ports, geometry, topic_defaults_of(gobj, desc.topic_name), PORT_R_PILL, true);
55674
55743
  return {
55675
55744
  type: "treedb-card",
55676
55745
  style
55677
55746
  };
55678
55747
  }
55748
+ function pill_innerHTML_of(gobj, nd, theme, highlight, selected, anchored) {
55749
+ let desc = nd.data.desc;
55750
+ let record = nd.data.record || {};
55751
+ return build_chip_innerHTML(desc.color, theme, record.icon, node_label(desc, record), record.id, highlight, selected, anchored);
55752
+ }
55753
+ function node_figure_of(gobj, desc, geometry) {
55754
+ let shape = geometry ? geometry.node_shape : null;
55755
+ if (!shape) {
55756
+ let defaults = topic_defaults_of(gobj, desc.topic_name);
55757
+ shape = defaults ? defaults.node_shape : null;
55758
+ }
55759
+ return shape && str_in_list(NODE_SHAPES, shape) ? shape : DEFAULT_NODE_SHAPE;
55760
+ }
55679
55761
  /************************************************************
55680
- * The SQUARE: a G6 `rect` of the topic's colour, no ports, the
55681
- * name as a label under it when `node_labels` says so. A native
55682
- * shape and not html on purpose: G6's own stroke and halo paint
55683
- * on it, so the focus, the selection and the anchor are three
55684
- * keys of the style instead of a rebuilt innerHTML.
55762
+ * The FIGURE: a native G6 node of the topic's colour -- a square,
55763
+ * a circle, a diamond, a triangle, a hexagon, a star -- no ports,
55764
+ * the name as a label under it when `node_labels` says so. Native
55765
+ * and not html on purpose: G6's own stroke and halo paint on it,
55766
+ * so the focus, the selection and the anchor are three keys of
55767
+ * the style instead of a rebuilt innerHTML.
55685
55768
  *
55686
55769
  * flags {highlight, selected, anchored}
55687
55770
  ************************************************************/
55688
- function compact_shape_of(gobj, desc, record, flags) {
55771
+ function figure_shape_of(gobj, desc, record, geometry, flags) {
55689
55772
  let dark = gobj.priv.theme === "dark";
55690
55773
  let f = flags || {};
55691
55774
  let tier = desc.node_treedb_type;
55692
- let side = COMPACT_SIZE[tier] || COMPACT_SIZE.hierarchical;
55775
+ let side = SHAPE_SIZE[tier] || SHAPE_SIZE.hierarchical;
55693
55776
  let labels = gobj_read_bool_attr(gobj, "node_labels");
55777
+ let figure = node_figure_of(gobj, desc, geometry || {});
55694
55778
  let stroke = getStrokeColor(desc.color);
55695
55779
  let line_width = 1.5;
55696
55780
  if (f.selected) {
@@ -55707,34 +55791,35 @@ function compact_shape_of(gobj, desc, record, flags) {
55707
55791
  dash = [2, 2];
55708
55792
  line_width = Math.max(line_width, 2.5);
55709
55793
  }
55794
+ let style = {
55795
+ size: [side, side],
55796
+ radius: figure === "square" ? Math.round(side / 5) : 0,
55797
+ fill: desc.color,
55798
+ stroke,
55799
+ lineWidth: line_width,
55800
+ lineDash: dash,
55801
+ halo: !!f.highlight,
55802
+ haloStroke: HIGHLIGHT_HALO,
55803
+ haloLineWidth: 8,
55804
+ port: false,
55805
+ ports: [],
55806
+ labelText: labels ? node_label(desc, record) : "",
55807
+ labelPlacement: "bottom",
55808
+ labelFontSize: 11,
55809
+ labelFill: dark ? "#e6e9ef" : "#2e333d",
55810
+ labelMaxWidth: 150,
55811
+ labelWordWrap: true,
55812
+ labelMaxLines: 1,
55813
+ labelTextOverflow: "ellipsis",
55814
+ labelBackground: true,
55815
+ labelBackgroundFill: dark ? "#1b2230" : "#ffffff",
55816
+ labelBackgroundOpacity: .85,
55817
+ labelBackgroundRadius: 3,
55818
+ labelPadding: [1, 3]
55819
+ };
55710
55820
  return {
55711
- type: "rect",
55712
- style: {
55713
- size: [side, side],
55714
- radius: Math.round(side / 5),
55715
- fill: desc.color,
55716
- stroke,
55717
- lineWidth: line_width,
55718
- lineDash: dash,
55719
- halo: !!f.highlight,
55720
- haloStroke: HIGHLIGHT_HALO,
55721
- haloLineWidth: 8,
55722
- port: false,
55723
- ports: [],
55724
- labelText: labels ? node_label(desc, record) : "",
55725
- labelPlacement: "bottom",
55726
- labelFontSize: 11,
55727
- labelFill: dark ? "#e6e9ef" : "#2e333d",
55728
- labelMaxWidth: 150,
55729
- labelWordWrap: true,
55730
- labelMaxLines: 1,
55731
- labelTextOverflow: "ellipsis",
55732
- labelBackground: true,
55733
- labelBackgroundFill: dark ? "#1b2230" : "#ffffff",
55734
- labelBackgroundOpacity: .85,
55735
- labelBackgroundRadius: 3,
55736
- labelPadding: [1, 3]
55737
- }
55821
+ type: figure === "square" ? "rect" : figure,
55822
+ style
55738
55823
  };
55739
55824
  }
55740
55825
  /************************************************************
@@ -58500,6 +58585,14 @@ function show_node_popover(gobj) {
58500
58585
  let strokeInput = create_form_color_input(popover, currentStroke, preview_node);
58501
58586
  create_form_label(popover, "line width");
58502
58587
  let lwInput = create_form_number_input(popover, currentLW, 1, 20, preview_node);
58588
+ create_form_label(popover, "shape");
58589
+ let shapeSelect = create_form_select(popover, NODE_SHAPES.map((shape) => {
58590
+ return {
58591
+ value: shape,
58592
+ label: t(shape)
58593
+ };
58594
+ }));
58595
+ shapeSelect.value = nodeData.data && nodeData.data.desc ? node_figure_of(gobj, nodeData.data.desc, nodeData.data.graph_props || {}) : DEFAULT_NODE_SHAPE;
58503
58596
  create_form_label(popover, "apply to");
58504
58597
  let scopeSelect = create_form_select(popover, [
58505
58598
  {
@@ -58539,7 +58632,7 @@ function show_node_popover(gobj) {
58539
58632
  text: "apply",
58540
58633
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
58541
58634
  onClick: () => {
58542
- apply_node_properties(gobj, node_id, fillInput.value, strokeInput.value, parseInt(lwInput.value) || 1, scopeSelect.value);
58635
+ apply_node_properties(gobj, node_id, fillInput.value, strokeInput.value, parseInt(lwInput.value) || 1, scopeSelect.value, shapeSelect.value);
58543
58636
  }
58544
58637
  }]);
58545
58638
  priv.$container.appendChild(popover);
@@ -58770,10 +58863,11 @@ function repaint_cards(gobj, ids) {
58770
58863
  continue;
58771
58864
  }
58772
58865
  let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58773
- if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58866
+ let mode = nd && nd.data && nd.data.desc ? node_mode_of(gobj, id) : "expanded";
58867
+ if (mode === "shape") {
58774
58868
  updates.push({
58775
58869
  id,
58776
- style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58870
+ style: figure_shape_of(gobj, nd.data.desc, nd.data.record || {}, nd.data.graph_props || {}, {
58777
58871
  highlight: focus.has(id),
58778
58872
  selected: selected.has(id),
58779
58873
  anchored
@@ -58781,7 +58875,7 @@ function repaint_cards(gobj, ids) {
58781
58875
  });
58782
58876
  continue;
58783
58877
  }
58784
- let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58878
+ let html = mode === "compact" ? pill_innerHTML_of(gobj, nd, priv.theme, focus.has(id), selected.has(id), anchored) : node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58785
58879
  if (html !== null) updates.push({
58786
58880
  id,
58787
58881
  style: { innerHTML: html }
@@ -58819,10 +58913,11 @@ function refresh_html_nodes_theme(gobj, theme) {
58819
58913
  let id = nodes[i].id;
58820
58914
  let nd = graph.getNodeData(id);
58821
58915
  let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58822
- if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58916
+ let mode = nd && nd.data && nd.data.desc ? node_mode_of(gobj, id) : "expanded";
58917
+ if (mode === "shape") {
58823
58918
  updates.push({
58824
58919
  id,
58825
- style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58920
+ style: figure_shape_of(gobj, nd.data.desc, nd.data.record || {}, nd.data.graph_props || {}, {
58826
58921
  highlight: highlighted.has(id),
58827
58922
  selected: selected.has(id),
58828
58923
  anchored
@@ -58830,7 +58925,7 @@ function refresh_html_nodes_theme(gobj, theme) {
58830
58925
  });
58831
58926
  continue;
58832
58927
  }
58833
- let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58928
+ let html = mode === "compact" ? pill_innerHTML_of(gobj, nd, theme, highlighted.has(id), selected.has(id), anchored) : node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58834
58929
  if (html === null) html = more_innerHTML_of(gobj, nd, theme);
58835
58930
  if (html !== null) updates.push({
58836
58931
  id,
@@ -59288,7 +59383,7 @@ function hide_unlink_confirm(gobj) {
59288
59383
  * Apply node properties to one or more nodes.
59289
59384
  * scope: 'this', 'same_topic', 'all'
59290
59385
  ************************************************************/
59291
- function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59386
+ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope, shape) {
59292
59387
  let priv = gobj.priv;
59293
59388
  let graph = priv.graph;
59294
59389
  let nodeData = graph.getNodeData(node_id);
@@ -59296,11 +59391,26 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59296
59391
  let source_topic = nodeData.data.desc ? nodeData.data.desc.topic_name : null;
59297
59392
  let updates = [];
59298
59393
  const nodes = graph.getData().nodes;
59394
+ let figure = shape && str_in_list(NODE_SHAPES, shape) ? shape : "";
59395
+ let reshaped = [];
59396
+ if (figure && scope !== "this") {
59397
+ let topics = scope === "same_topic" ? [source_topic] : Object.keys(priv.descs || {});
59398
+ for (let topic_name of topics) {
59399
+ if (!is_object(priv._graph_properties[topic_name])) priv._graph_properties[topic_name] = {};
59400
+ let defaults = priv._graph_properties[topic_name].defaults || {};
59401
+ defaults.node_shape = figure;
59402
+ priv._graph_properties[topic_name].defaults = defaults;
59403
+ }
59404
+ }
59299
59405
  for (let i = 0; i < nodes.length; i++) {
59300
59406
  let nd = graph.getNodeData(nodes[i].id);
59301
59407
  if (!nd || !nd.data || !nd.data.desc) continue;
59302
59408
  if (scope === "this" && nodes[i].id !== node_id) continue;
59303
59409
  if (scope === "same_topic" && nd.data.desc.topic_name !== source_topic) continue;
59410
+ if (figure) {
59411
+ node_props_entry(gobj, nd).node_shape = figure;
59412
+ if (node_mode_of(gobj, nodes[i].id) === "shape") reshaped.push(nodes[i].id);
59413
+ }
59304
59414
  let updateStyle = {
59305
59415
  fill,
59306
59416
  stroke,
@@ -59317,6 +59427,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59317
59427
  }
59318
59428
  if (updates.length > 0) {
59319
59429
  graph.updateNodeData(updates);
59430
+ if (reshaped.length) reshape_nodes(gobj, reshaped);
59320
59431
  graph.draw().then(() => {
59321
59432
  mark_graph_dirty(gobj);
59322
59433
  });
@@ -59324,6 +59435,23 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59324
59435
  hide_node_popover(gobj);
59325
59436
  }
59326
59437
  /************************************************************
59438
+ * The node's entry in `_graph_properties` -- the object Save
59439
+ * reads and writes -- created if it has none yet, and the node's
59440
+ * `data.graph_props` pointed at it, so a key written here is
59441
+ * read by the next reshape and survives the next Save.
59442
+ ************************************************************/
59443
+ function node_props_entry(gobj, nd) {
59444
+ let priv = gobj.priv;
59445
+ let topic_name = nd.data.topic_name;
59446
+ let record = nd.data.record || {};
59447
+ if (!is_object(priv._graph_properties[topic_name])) priv._graph_properties[topic_name] = {};
59448
+ let topic_props = priv._graph_properties[topic_name];
59449
+ if (!is_object(topic_props.nodes)) topic_props.nodes = {};
59450
+ if (!is_object(topic_props.nodes[record.id])) topic_props.nodes[record.id] = is_object(nd.data.graph_props) ? nd.data.graph_props : {};
59451
+ nd.data.graph_props = topic_props.nodes[record.id];
59452
+ return nd.data.graph_props;
59453
+ }
59454
+ /************************************************************
59327
59455
  * Apply edge properties to one or more edges.
59328
59456
  * scope: 'this', 'same_type', 'all'
59329
59457
  ************************************************************/
@@ -59451,8 +59579,8 @@ function ctx_item(icon_id, label, value) {
59451
59579
  function build_node_context_menu(gobj, node_id) {
59452
59580
  let items = [];
59453
59581
  inject_svg_icons();
59454
- if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", t("open node"), "toggle_node_mode"));
59455
- else items.push(ctx_item("g6-icon-fullscreen-exit", t("close node"), "toggle_node_mode"));
59582
+ if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", t("expand node"), "toggle_node_mode"));
59583
+ else items.push(ctx_item("g6-icon-fullscreen-exit", t("collapse node"), "toggle_node_mode"));
59456
59584
  if (gobj.priv.edit_mode && !node_is_compact(gobj, node_id)) {
59457
59585
  items.push(ctx_item("g6-icon-resize", t("resize all"), "resize_all_nodes"));
59458
59586
  items.push(ctx_item("g6-icon-resize", t("resize topic nodes"), "resize_topic_nodes"));
@@ -59691,7 +59819,7 @@ var MORE_CHIP_SIZE_COMPACT = [40, 22];
59691
59819
  function more_chip_is_compact(gobj, nd) {
59692
59820
  let parent_id = nd && nd.data ? nd.data.parent_node : "";
59693
59821
  if (parent_id) return node_is_compact(gobj, parent_id);
59694
- return gobj_read_str_attr(gobj, "node_mode") === "compact";
59822
+ return gobj_read_str_attr(gobj, "node_mode") !== "expanded";
59695
59823
  }
59696
59824
  function more_chip_style(gobj, nd, color, rest) {
59697
59825
  let compact = more_chip_is_compact(gobj, nd);
@@ -60742,9 +60870,9 @@ function ac_set_loose_topics(gobj, event, kw, src) {
60742
60870
  * and lays the graph out again, because a square and a card
60743
60871
  * do not occupy the same room.
60744
60872
  ************************************************************/
60745
- function ac_set_node_mode(gobj, event, kw, src) {
60873
+ function ac_set_node_mode$1(gobj, event, kw, src) {
60746
60874
  let priv = gobj.priv;
60747
- let mode = kw && kw.node_mode === "compact" ? "compact" : "expanded";
60875
+ let mode = kw && kw.node_mode && str_in_list(NODE_MODES$1, kw.node_mode) ? kw.node_mode : "expanded";
60748
60876
  gobj_write_str_attr(gobj, "node_mode", mode);
60749
60877
  priv._open_nodes = /* @__PURE__ */ new Set();
60750
60878
  if (!priv.graph || !priv._fold_model) return 0;
@@ -60757,15 +60885,15 @@ function ac_set_node_mode(gobj, event, kw, src) {
60757
60885
  return 0;
60758
60886
  }
60759
60887
  /************************************************************
60760
- * The name under a closed square, on or off. Only the closed
60761
- * nodes change, and nothing moves: the label hangs outside the
60762
- * square and the layout measures the square.
60888
+ * The name under a figure, on or off. Only the `shape` nodes
60889
+ * change, and nothing moves: the label hangs outside the figure
60890
+ * and the layout measures the figure.
60763
60891
  ************************************************************/
60764
60892
  function ac_set_node_labels(gobj, event, kw, src) {
60765
60893
  let priv = gobj.priv;
60766
60894
  gobj_write_bool_attr(gobj, "node_labels", !!(kw && kw.node_labels));
60767
60895
  if (!priv.graph) return 0;
60768
- reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_is_compact(gobj, id)));
60896
+ reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_mode_of(gobj, id) === "shape"));
60769
60897
  return 0;
60770
60898
  }
60771
60899
  /************************************************************
@@ -60773,7 +60901,7 @@ function ac_set_node_labels(gobj, event, kw, src) {
60773
60901
  * or the context menu). It holds still on screen while the
60774
60902
  * rest of the graph makes room, as a fold does.
60775
60903
  ************************************************************/
60776
- function ac_toggle_node_mode$1(gobj, event, kw, src) {
60904
+ function ac_toggle_node_mode(gobj, event, kw, src) {
60777
60905
  let priv = gobj.priv;
60778
60906
  let node_id = kw && kw.id || "";
60779
60907
  if (!priv.graph || !node_id) {
@@ -61302,7 +61430,7 @@ function create_gclass$4(gclass_name) {
61302
61430
  ],
61303
61431
  [
61304
61432
  "EV_SET_NODE_MODE",
61305
- ac_set_node_mode,
61433
+ ac_set_node_mode$1,
61306
61434
  null
61307
61435
  ],
61308
61436
  [
@@ -61312,7 +61440,7 @@ function create_gclass$4(gclass_name) {
61312
61440
  ],
61313
61441
  [
61314
61442
  "EV_TOGGLE_NODE_MODE",
61315
- ac_toggle_node_mode$1,
61443
+ ac_toggle_node_mode,
61316
61444
  null
61317
61445
  ],
61318
61446
  [
@@ -61493,8 +61621,8 @@ var attrs_table$3 = [
61493
61621
  SDATA(data_type_t.DTP_LIST, "hidden_topics", sdata_flag_t.SDF_PERSIST, "[]", "Topics hidden from the graph (legend). User preference, per treedb"),
61494
61622
  SDATA(data_type_t.DTP_STRING, "main_topic", sdata_flag_t.SDF_PERSIST, "", "The topic the tree hangs from; empty = deduced by the graph. User preference, per treedb"),
61495
61623
  SDATA(data_type_t.DTP_LIST, "loose_topics", sdata_flag_t.SDF_PERSIST, "[]", "Topics whose LOOSE records (no parent) are shown. User preference, per treedb"),
61496
- SDATA(data_type_t.DTP_STRING, "node_mode", 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"),
61497
- SDATA(data_type_t.DTP_BOOLEAN, "node_labels", sdata_flag_t.SDF_PERSIST, true, "A compact node says its name under its square. User preference"),
61624
+ SDATA(data_type_t.DTP_STRING, "node_mode", sdata_flag_t.SDF_PERSIST, "expanded", "How the records are drawn: `expanded` = the cards with their pills and ports, `compact` = one-line pills with the name, `shape` = coloured figures, the topology alone. User preference"),
61625
+ SDATA(data_type_t.DTP_BOOLEAN, "node_labels", sdata_flag_t.SDF_PERSIST, true, "A `shape` node says its name under its figure. User preference"),
61498
61626
  SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
61499
61627
  SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
61500
61628
  SDATA(data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
@@ -61778,44 +61906,92 @@ function option_label(name) {
61778
61906
  * its context menu (the child's business).
61779
61907
  ************************************************************/
61780
61908
  function node_shape_items(gobj, wide) {
61781
- let toggle = (cls, icon, event_name, label_key) => {
61782
- return [
61909
+ let options = NODE_MODES.map((mode) => [
61910
+ "option",
61911
+ {
61912
+ value: mode,
61913
+ "data-i18n": NODE_MODE_LABELS[mode]
61914
+ },
61915
+ t(NODE_MODE_LABELS[mode])
61916
+ ]);
61917
+ return [
61918
+ [
61919
+ "span",
61920
+ {
61921
+ class: "GRAPH_NODE_MODE_LABEL is-hidden-mobile",
61922
+ style: "padding-left:10px; padding-right:5px;",
61923
+ i18n: "nodes"
61924
+ },
61925
+ "nodes"
61926
+ ],
61927
+ [
61928
+ "div",
61929
+ { class: "select" },
61930
+ [[
61931
+ "select",
61932
+ {
61933
+ class: "GRAPH_NODE_MODE_SELECT",
61934
+ title: t("nodes"),
61935
+ "data-i18n-title": "nodes",
61936
+ "aria-label": t("nodes"),
61937
+ "data-i18n-aria-label": "nodes"
61938
+ },
61939
+ options
61940
+ ]],
61941
+ { change: (evt) => {
61942
+ evt.stopPropagation();
61943
+ gobj_send_event(gobj, "EV_SET_NODE_MODE", { node_mode: evt.target.value }, gobj);
61944
+ } }
61945
+ ],
61946
+ [
61783
61947
  "button",
61784
61948
  {
61785
- class: `${cls} button`,
61949
+ class: "GRAPH_NODE_LABELS button",
61786
61950
  type: "button",
61787
61951
  style: {
61788
61952
  height: wide,
61789
61953
  width: "2.5em"
61790
61954
  },
61791
- title: t(label_key),
61792
- "data-i18n-title": label_key,
61793
- "aria-label": t(label_key),
61794
- "data-i18n-aria-label": label_key,
61955
+ title: t("node labels"),
61956
+ "data-i18n-title": "node labels",
61957
+ "aria-label": t("node labels"),
61958
+ "data-i18n-aria-label": "node labels",
61795
61959
  "aria-pressed": "false"
61796
61960
  },
61797
61961
  ["i", {
61798
61962
  style: "font-size:1.5em; color:inherit;",
61799
- class: icon
61963
+ class: "yi-font"
61800
61964
  }],
61801
61965
  { click: (evt) => {
61802
61966
  evt.stopPropagation();
61803
- gobj_send_event(gobj, event_name, {}, gobj);
61967
+ gobj_send_event(gobj, "EV_TOGGLE_NODE_LABELS", {}, gobj);
61804
61968
  } }
61805
- ];
61806
- };
61807
- 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")];
61969
+ ]
61970
+ ];
61808
61971
  }
61972
+ var NODE_MODES = [
61973
+ "expanded",
61974
+ "compact",
61975
+ "shape"
61976
+ ];
61977
+ var NODE_MODE_LABELS = {
61978
+ expanded: "full",
61979
+ compact: "compact",
61980
+ shape: "shape"
61981
+ };
61809
61982
  function refresh_node_shape_buttons(gobj, $root) {
61810
61983
  if (!$root) return;
61811
- let compact = gobj_read_str_attr(gobj, "node_mode") === "compact";
61984
+ let mode = gobj_read_str_attr(gobj, "node_mode");
61985
+ if (!NODE_MODES.includes(mode)) mode = "expanded";
61812
61986
  let labels = gobj_read_bool_attr(gobj, "node_labels");
61813
- set_pressed_state($root, ".GRAPH_NODE_MODE", compact);
61987
+ let $mode = $root.querySelector(".GRAPH_NODE_MODE_SELECT");
61988
+ if ($mode) $mode.value = mode;
61814
61989
  set_pressed_state($root, ".GRAPH_NODE_LABELS", labels);
61815
- let $mode = $root.querySelector(".GRAPH_NODE_MODE");
61816
- if ($mode) $mode.setAttribute("aria-pressed", compact ? "true" : "false");
61817
61990
  let $labels = $root.querySelector(".GRAPH_NODE_LABELS");
61818
- if ($labels) $labels.setAttribute("aria-pressed", labels ? "true" : "false");
61991
+ if ($labels) {
61992
+ $labels.setAttribute("aria-pressed", labels ? "true" : "false");
61993
+ $labels.disabled = mode !== "shape";
61994
+ }
61819
61995
  }
61820
61996
  function make_toolbar(gobj) {
61821
61997
  let priv = gobj.priv;
@@ -63202,13 +63378,13 @@ function ac_collapse_all(gobj, event, kw, src) {
63202
63378
  return 0;
63203
63379
  }
63204
63380
  /************************************************************
63205
- * The shape pair of the toolbar: the attr flips, persists,
63206
- * shows on the button, and reaches the G6 child, which owns
63207
- * the nodes.
63381
+ * The view of the nodes and the labels toggle of the toolbar:
63382
+ * the attr changes, persists, shows on the control, and reaches
63383
+ * the G6 child, which owns the nodes.
63208
63384
  ************************************************************/
63209
- function ac_toggle_node_mode(gobj, event, kw, src) {
63385
+ function ac_set_node_mode(gobj, event, kw, src) {
63210
63386
  let priv = gobj.priv;
63211
- let mode = gobj_read_str_attr(gobj, "node_mode") === "compact" ? "expanded" : "compact";
63387
+ let mode = kw && NODE_MODES.includes(kw.node_mode) ? kw.node_mode : "expanded";
63212
63388
  gobj_write_str_attr(gobj, "node_mode", mode);
63213
63389
  gobj_save_persistent_attrs(gobj, "node_mode");
63214
63390
  refresh_node_shape_buttons(gobj, priv.$container);
@@ -63439,8 +63615,8 @@ function create_gclass$3(gclass_name) {
63439
63615
  null
63440
63616
  ],
63441
63617
  [
63442
- "EV_TOGGLE_NODE_MODE",
63443
- ac_toggle_node_mode,
63618
+ "EV_SET_NODE_MODE",
63619
+ ac_set_node_mode,
63444
63620
  null
63445
63621
  ],
63446
63622
  [
@@ -63512,7 +63688,7 @@ function create_gclass$3(gclass_name) {
63512
63688
  ["EV_FIND_NODES", 0],
63513
63689
  ["EV_EXPAND_ALL", 0],
63514
63690
  ["EV_COLLAPSE_ALL", 0],
63515
- ["EV_TOGGLE_NODE_MODE", 0],
63691
+ ["EV_SET_NODE_MODE", 0],
63516
63692
  ["EV_TOGGLE_NODE_LABELS", 0],
63517
63693
  ["EV_FIND_RESULT", 0],
63518
63694
  ["EV_LAYOUT_AUTOSET", 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.81",
3
+ "version": "7.23.82",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",