@yuneta/gobj-ui 7.23.80 → 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.
@@ -43159,7 +43159,7 @@ var _excluded$5 = ["style"];
43159
43159
  * HTML container
43160
43160
  * @see https://github.com/pmndrs/drei#html
43161
43161
  */
43162
- var HTML = /*#__PURE__*/ function(_DisplayObject) {
43162
+ var HTML$1 = /*#__PURE__*/ function(_DisplayObject) {
43163
43163
  function HTML() {
43164
43164
  var _this;
43165
43165
  var _ref = arguments.length > 0 && arguments[0] !== void 0 ? arguments[0] : {}, style = _ref.style, rest = _objectWithoutProperties(_ref, _excluded$5);
@@ -43207,7 +43207,7 @@ var HTML = /*#__PURE__*/ function(_DisplayObject) {
43207
43207
  }
43208
43208
  ]);
43209
43209
  }(DisplayObject);
43210
- HTML.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(DisplayObject.PARSED_STYLE_LIST), [
43210
+ HTML$1.PARSED_STYLE_LIST = new Set([].concat(_toConsumableArray(DisplayObject.PARSED_STYLE_LIST), [
43211
43211
  "x",
43212
43212
  "y",
43213
43213
  "$el",
@@ -54530,11 +54530,31 @@ var SELECT_RING = "rgba(59,130,246,0.95)";
54530
54530
  var PORT_R_ENTITY = 14;
54531
54531
  var PORT_R_CHILD = 8;
54532
54532
  var PORT_LINE_WIDTH = 2;
54533
- var COMPACT_SIZE = {
54533
+ var NODE_MODES$1 = [
54534
+ "expanded",
54535
+ "compact",
54536
+ "shape"
54537
+ ];
54538
+ var PILL_SIZE = {
54539
+ hierarchical: [200, 30],
54540
+ extended: [180, 28],
54541
+ child: [160, 26]
54542
+ };
54543
+ var PORT_R_PILL = 6;
54544
+ var SHAPE_SIZE = {
54534
54545
  hierarchical: 32,
54535
54546
  extended: 28,
54536
54547
  child: 22
54537
54548
  };
54549
+ var NODE_SHAPES = [
54550
+ "square",
54551
+ "circle",
54552
+ "diamond",
54553
+ "triangle",
54554
+ "hexagon",
54555
+ "star"
54556
+ ];
54557
+ var DEFAULT_NODE_SHAPE = "square";
54538
54558
  /***************************************************************
54539
54559
  * Internal layout and operation mode definitions
54540
54560
  ***************************************************************/
@@ -54615,8 +54635,8 @@ var attrs_table$4 = [
54615
54635
  (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"),
54616
54636
  (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"),
54617
54637
  (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"),
54638
+ (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 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)"),
54639
+ (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.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"),
54620
54640
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
54621
54641
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
54622
54642
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
@@ -54658,6 +54678,8 @@ var PRIVATE_DATA$4 = {
54658
54678
  _edge_icon_el: null,
54659
54679
  _edge_delete_el: null,
54660
54680
  _edge_popover_el: null,
54681
+ _port_icon_el: null,
54682
+ _port_popover_el: null,
54661
54683
  _node_icon_el: null,
54662
54684
  _node_delete_el: null,
54663
54685
  _node_popover_el: null,
@@ -54848,6 +54870,7 @@ function register_layouts(gobj) {
54848
54870
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
54849
54871
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
54850
54872
  (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "light", LightNode);
54873
+ (0, _antv_g6.register)(_antv_g6.ExtensionCategory.NODE, "treedb-card", TreedbCard);
54851
54874
  }
54852
54875
  }
54853
54876
  /************************************************************
@@ -54917,6 +54940,7 @@ function configure_events(gobj) {
54917
54940
  update_edge_icon_position(gobj);
54918
54941
  update_node_icon_position(gobj);
54919
54942
  update_link_icon_position(gobj);
54943
+ update_port_icon_position(gobj);
54920
54944
  });
54921
54945
  graph.on(_antv_g6.NodeEvent.DRAG_END, (evt) => {
54922
54946
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_DRAG_END", { evt }, gobj);
@@ -54941,6 +54965,7 @@ function configure_events(gobj) {
54941
54965
  update_edge_icon_position(gobj);
54942
54966
  update_node_icon_position(gobj);
54943
54967
  update_link_icon_position(gobj);
54968
+ update_port_icon_position(gobj);
54944
54969
  update_zoom_readout(gobj);
54945
54970
  let z = priv.last_zoom;
54946
54971
  try {
@@ -55589,14 +55614,26 @@ function create_topic_node(gobj, desc, record) {
55589
55614
  * the other one would leave behind (`labelText`, `ports`).
55590
55615
  ************************************************************/
55591
55616
  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);
55617
+ switch (node_mode_of(gobj, node_id)) {
55618
+ case "shape": return figure_shape_of(gobj, desc, record, geometry, {});
55619
+ case "compact": return pill_shape_of(gobj, desc, record, geometry);
55620
+ default: return card_shape_of(gobj, desc, record, geometry, pills_html);
55621
+ }
55594
55622
  }
55595
- function node_is_compact(gobj, node_id) {
55623
+ function node_mode_of(gobj, node_id) {
55596
55624
  let priv = gobj.priv;
55597
55625
  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;
55626
+ let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode");
55627
+ if (!mode || !(0, _yuneta_gobj_js.str_in_list)(NODE_MODES$1, mode)) mode = "expanded";
55628
+ if (priv._open_nodes.has(node_id)) return mode === "expanded" ? "compact" : "expanded";
55629
+ return mode;
55630
+ }
55631
+ function node_is_compact(gobj, node_id) {
55632
+ return node_mode_of(gobj, node_id) !== "expanded";
55633
+ }
55634
+ function topic_defaults_of(gobj, topic_name) {
55635
+ let topic_props = gobj.priv._graph_properties[topic_name];
55636
+ return (0, _yuneta_gobj_js.is_object)(topic_props) && (0, _yuneta_gobj_js.is_object)(topic_props.defaults) ? topic_props.defaults : null;
55600
55637
  }
55601
55638
  /************************************************************
55602
55639
  * The CARD: an html node, the tier's size, the ports, the
@@ -55642,45 +55679,107 @@ function card_shape_of(gobj, desc, record, geometry, pills_html) {
55642
55679
  style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
55643
55680
  }
55644
55681
  if (geometry.portR > 0) style.portR = geometry.portR;
55645
- if ((0, _yuneta_gobj_js.json_size)(ports)) {
55646
- (0, _yuneta_gobj_js.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 ((0, _yuneta_gobj_js.is_object)(port_sizes) || (0, _yuneta_gobj_js.is_object)(default_port_sizes)) for (let i = 0; i < style.ports.length; i++) {
55655
- let key = style.ports[i].key;
55656
- let r = (0, _yuneta_gobj_js.is_object)(port_sizes) ? port_sizes[key] : null;
55657
- if (r == null && (0, _yuneta_gobj_js.is_object)(default_port_sizes)) r = default_port_sizes[key];
55658
- if (r != null) style.ports[i].r = r;
55659
- }
55660
- } else {
55682
+ dress_ports(gobj, style, ports, geometry, topic_defaults, node_treedb_type === "child" ? PORT_R_CHILD : PORT_R_ENTITY, false);
55683
+ return {
55684
+ type: "treedb-card",
55685
+ style
55686
+ };
55687
+ }
55688
+ /************************************************************
55689
+ * The ports of a card or a pill, dressed: the node-level radius
55690
+ * (saved, topic default, or the tier's), each port's own radius
55691
+ * and shape (saved first, then the topic's per-port defaults, then
55692
+ * the topic's one shape for every port). `fixed_r` -- the pill --
55693
+ * ignores every saved radius: a pill has one size of port.
55694
+ ************************************************************/
55695
+ function dress_ports(gobj, style, ports, geometry, topic_defaults, r_default, fixed_r) {
55696
+ if (!(0, _yuneta_gobj_js.json_size)(ports)) {
55661
55697
  style.port = false;
55662
55698
  style.ports = [];
55699
+ return;
55663
55700
  }
55701
+ (0, _yuneta_gobj_js.json_object_update_missing)(style, {
55702
+ port: true,
55703
+ ports,
55704
+ portR: r_default,
55705
+ portLineWidth: PORT_LINE_WIDTH
55706
+ });
55707
+ if (fixed_r) style.portR = r_default;
55708
+ let port_sizes = fixed_r ? null : geometry.port_sizes;
55709
+ let default_port_sizes = !fixed_r && topic_defaults ? topic_defaults.port_sizes : null;
55710
+ let port_shapes = geometry.port_shapes;
55711
+ let default_port_shapes = topic_defaults ? topic_defaults.port_shapes : null;
55712
+ let default_shape = topic_defaults ? topic_defaults.port_shape : null;
55713
+ for (let i = 0; i < style.ports.length; i++) {
55714
+ let key = style.ports[i].key;
55715
+ let r = (0, _yuneta_gobj_js.is_object)(port_sizes) ? port_sizes[key] : null;
55716
+ if (r == null && (0, _yuneta_gobj_js.is_object)(default_port_sizes)) r = default_port_sizes[key];
55717
+ if (r != null) style.ports[i].r = r;
55718
+ let shape = (0, _yuneta_gobj_js.is_object)(port_shapes) ? port_shapes[key] : null;
55719
+ if (!shape && (0, _yuneta_gobj_js.is_object)(default_port_shapes)) shape = default_port_shapes[key];
55720
+ if (!shape) shape = default_shape;
55721
+ if (shape && (0, _yuneta_gobj_js.str_in_list)(PORT_SHAPES, shape)) style.ports[i].shape = shape;
55722
+ }
55723
+ }
55724
+ /************************************************************
55725
+ * The PILL: one line with the name inside, the tint and the
55726
+ * border of the topic, small ports on its edges -- the half-way
55727
+ * house between the card and the figure, and the same one-line
55728
+ * chip a leaf record already is, at the tier's width. No pills:
55729
+ * a hook is opened from the card (expand the node).
55730
+ ************************************************************/
55731
+ function pill_shape_of(gobj, desc, record, geometry) {
55732
+ let priv = gobj.priv;
55733
+ let size = PILL_SIZE[desc.node_treedb_type] || PILL_SIZE.hierarchical;
55734
+ let ports = build_ports(gobj, desc);
55735
+ let style = {
55736
+ fill: desc.color,
55737
+ stroke: getStrokeColor(desc.color),
55738
+ lineWidth: 1,
55739
+ lineDash: [],
55740
+ halo: false,
55741
+ labelText: "",
55742
+ size: [...size],
55743
+ dx: -size[0] / 2,
55744
+ dy: -size[1] / 2,
55745
+ innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id)
55746
+ };
55747
+ dress_ports(gobj, style, ports, geometry, topic_defaults_of(gobj, desc.topic_name), PORT_R_PILL, true);
55664
55748
  return {
55665
- type: "html",
55749
+ type: "treedb-card",
55666
55750
  style
55667
55751
  };
55668
55752
  }
55753
+ function pill_innerHTML_of(gobj, nd, theme, highlight, selected, anchored) {
55754
+ let desc = nd.data.desc;
55755
+ let record = nd.data.record || {};
55756
+ return build_chip_innerHTML(desc.color, theme, record.icon, node_label(desc, record), record.id, highlight, selected, anchored);
55757
+ }
55758
+ function node_figure_of(gobj, desc, geometry) {
55759
+ let shape = geometry ? geometry.node_shape : null;
55760
+ if (!shape) {
55761
+ let defaults = topic_defaults_of(gobj, desc.topic_name);
55762
+ shape = defaults ? defaults.node_shape : null;
55763
+ }
55764
+ return shape && (0, _yuneta_gobj_js.str_in_list)(NODE_SHAPES, shape) ? shape : DEFAULT_NODE_SHAPE;
55765
+ }
55669
55766
  /************************************************************
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.
55767
+ * The FIGURE: a native G6 node of the topic's colour -- a square,
55768
+ * a circle, a diamond, a triangle, a hexagon, a star -- no ports,
55769
+ * the name as a label under it when `node_labels` says so. Native
55770
+ * and not html on purpose: G6's own stroke and halo paint on it,
55771
+ * so the focus, the selection and the anchor are three keys of
55772
+ * the style instead of a rebuilt innerHTML.
55675
55773
  *
55676
55774
  * flags {highlight, selected, anchored}
55677
55775
  ************************************************************/
55678
- function compact_shape_of(gobj, desc, record, flags) {
55776
+ function figure_shape_of(gobj, desc, record, geometry, flags) {
55679
55777
  let dark = gobj.priv.theme === "dark";
55680
55778
  let f = flags || {};
55681
55779
  let tier = desc.node_treedb_type;
55682
- let side = COMPACT_SIZE[tier] || COMPACT_SIZE.hierarchical;
55780
+ let side = SHAPE_SIZE[tier] || SHAPE_SIZE.hierarchical;
55683
55781
  let labels = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
55782
+ let figure = node_figure_of(gobj, desc, geometry || {});
55684
55783
  let stroke = getStrokeColor(desc.color);
55685
55784
  let line_width = 1.5;
55686
55785
  if (f.selected) {
@@ -55697,34 +55796,35 @@ function compact_shape_of(gobj, desc, record, flags) {
55697
55796
  dash = [2, 2];
55698
55797
  line_width = Math.max(line_width, 2.5);
55699
55798
  }
55799
+ let style = {
55800
+ size: [side, side],
55801
+ radius: figure === "square" ? Math.round(side / 5) : 0,
55802
+ fill: desc.color,
55803
+ stroke,
55804
+ lineWidth: line_width,
55805
+ lineDash: dash,
55806
+ halo: !!f.highlight,
55807
+ haloStroke: HIGHLIGHT_HALO,
55808
+ haloLineWidth: 8,
55809
+ port: false,
55810
+ ports: [],
55811
+ labelText: labels ? node_label(desc, record) : "",
55812
+ labelPlacement: "bottom",
55813
+ labelFontSize: 11,
55814
+ labelFill: dark ? "#e6e9ef" : "#2e333d",
55815
+ labelMaxWidth: 150,
55816
+ labelWordWrap: true,
55817
+ labelMaxLines: 1,
55818
+ labelTextOverflow: "ellipsis",
55819
+ labelBackground: true,
55820
+ labelBackgroundFill: dark ? "#1b2230" : "#ffffff",
55821
+ labelBackgroundOpacity: .85,
55822
+ labelBackgroundRadius: 3,
55823
+ labelPadding: [1, 3]
55824
+ };
55700
55825
  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
- }
55826
+ type: figure === "square" ? "rect" : figure,
55827
+ style
55728
55828
  };
55729
55829
  }
55730
55830
  /************************************************************
@@ -56086,6 +56186,10 @@ function update_geometry(gobj, node_id) {
56086
56186
  for (let i = 0; i < ports.length; i++) if (ports[i].r != null) port_sizes[ports[i].key] = ports[i].r;
56087
56187
  if (Object.keys(port_sizes).length > 0) node_props.port_sizes = port_sizes;
56088
56188
  else delete node_props.port_sizes;
56189
+ let port_shapes = {};
56190
+ for (let i = 0; i < ports.length; i++) if (ports[i].shape && ports[i].shape !== "circle") port_shapes[ports[i].key] = ports[i].shape;
56191
+ if (Object.keys(port_shapes).length > 0) node_props.port_shapes = port_shapes;
56192
+ else delete node_props.port_shapes;
56089
56193
  }
56090
56194
  topic_props.nodes[record.id] = node_props;
56091
56195
  nodedata.data.graph_props = node_props;
@@ -56568,11 +56672,74 @@ function graph_resize(gobj, width, height) {
56568
56672
  update_port_resize_handles_position(gobj);
56569
56673
  update_node_icon_position(gobj);
56570
56674
  update_link_icon_position(gobj);
56675
+ update_port_icon_position(gobj);
56571
56676
  }
56572
56677
  function graph_write_behaviors(gobj, behaviors) {
56573
56678
  gobj.priv.graph.setOptions({ behaviors });
56574
56679
  }
56575
56680
  /************************************************************
56681
+ * Custom G6 node: TreedbCard -- G6's html node with ports that
56682
+ * have a SHAPE.
56683
+ *
56684
+ * G6 draws every port as a circle (`drawPortShapes` upserts a
56685
+ * `Circle`, nothing in the port style says otherwise). A port's
56686
+ * `shape` -- `circle`, `square`, `diamond`, `triangle` -- picks
56687
+ * the G shape here, by the names G6 registers itself, and `r`
56688
+ * stays the one size: the half-side of the square, the half-
56689
+ * diagonal of the diamond, the half-height of the triangle. The
56690
+ * hit test, the resize handles and the edge's landing point all
56691
+ * read `r` and none of them care about the outline.
56692
+ ************************************************************/
56693
+ var PORT_SHAPES = [
56694
+ "circle",
56695
+ "square",
56696
+ "diamond",
56697
+ "triangle"
56698
+ ];
56699
+ var TreedbCard = class extends _antv_g6.HTML {
56700
+ drawPortShapes(attributes, container) {
56701
+ const portsStyle = this.getPortsStyle(attributes);
56702
+ Object.keys(portsStyle).forEach((key) => {
56703
+ const style = portsStyle[key];
56704
+ const shapeKey = `port-${key}`;
56705
+ if (style === false) {
56706
+ this.upsert(shapeKey, "circle", false, container);
56707
+ return;
56708
+ }
56709
+ let r = Number(style.r) || 0;
56710
+ switch (style.shape) {
56711
+ case "square":
56712
+ this.upsert(shapeKey, "rect", Object.assign({}, style, {
56713
+ x: -r,
56714
+ y: -r,
56715
+ width: 2 * r,
56716
+ height: 2 * r
56717
+ }), container);
56718
+ break;
56719
+ case "diamond":
56720
+ this.upsert(shapeKey, "polygon", Object.assign({}, style, { points: [
56721
+ [0, -r],
56722
+ [r, 0],
56723
+ [0, r],
56724
+ [-r, 0]
56725
+ ] }), container);
56726
+ break;
56727
+ case "triangle":
56728
+ this.upsert(shapeKey, "polygon", Object.assign({}, style, { points: [
56729
+ [0, -r],
56730
+ [r, r],
56731
+ [-r, r]
56732
+ ] }), container);
56733
+ break;
56734
+ default: this.upsert(shapeKey, "circle", style, container);
56735
+ }
56736
+ });
56737
+ }
56738
+ };
56739
+ function is_card_type(type) {
56740
+ return type === "treedb-card" || type === "html";
56741
+ }
56742
+ /************************************************************
56576
56743
  * Custom G6 node: LightNode (circle with status indicator)
56577
56744
  ************************************************************/
56578
56745
  var LightNode = class extends _antv_g6.Circle {
@@ -57318,7 +57485,7 @@ function start_node_resize(gobj, e, mx, my) {
57318
57485
  };
57319
57486
  if (nodeType === "circle") updateStyle.size = [Math.max(newW, newH)];
57320
57487
  else updateStyle.size = [newW, newH];
57321
- if (nodeType === "html") {
57488
+ if (is_card_type(nodeType)) {
57322
57489
  updateStyle.dx = -newW / 2;
57323
57490
  updateStyle.dy = -newH / 2;
57324
57491
  }
@@ -57443,6 +57610,7 @@ function select_port(gobj, node_id, port_key) {
57443
57610
  priv._selected_port_key = port_key;
57444
57611
  show_port_resize_handles(gobj);
57445
57612
  show_link_icon_if_fkey(gobj);
57613
+ show_port_icon(gobj);
57446
57614
  }
57447
57615
  /************************************************************
57448
57616
  * Deselect port: clear port state, return to node selection.
@@ -57451,6 +57619,8 @@ function deselect_port(gobj) {
57451
57619
  let priv = gobj.priv;
57452
57620
  exit_linking_mode(gobj);
57453
57621
  hide_link_icon(gobj);
57622
+ hide_port_icon(gobj);
57623
+ hide_port_popover(gobj);
57454
57624
  hide_port_resize_handles(gobj);
57455
57625
  priv._selected_port_key = null;
57456
57626
  }
@@ -57503,6 +57673,217 @@ function update_link_icon_position(gobj) {
57503
57673
  }
57504
57674
  }
57505
57675
  /************************************************************
57676
+ * Port properties icon and popover: the gear beside a selected
57677
+ * port, as the node has its own. The popover has the two things
57678
+ * a port IS on screen -- its shape and its radius -- and the
57679
+ * scope: this port, the same port of every card of the topic
57680
+ * (the hook or fkey column), or every port there is.
57681
+ ************************************************************/
57682
+ function port_icon_xy(gobj) {
57683
+ let priv = gobj.priv;
57684
+ let graph = priv.graph;
57685
+ let canvasPos = get_port_canvas_position(gobj, priv._selected_node_id, priv._selected_port_key);
57686
+ if (!canvasPos) return null;
57687
+ let vp = graph.getViewportByCanvas([canvasPos.x, canvasPos.y]);
57688
+ let below = priv._link_icon_el ? floating_icon_step() : 0;
57689
+ return {
57690
+ x: vp[0] + floating_icon_size() / 2 + 4,
57691
+ y: vp[1] + floating_icon_dy() + below
57692
+ };
57693
+ }
57694
+ function show_port_icon(gobj) {
57695
+ hide_port_icon(gobj);
57696
+ let priv = gobj.priv;
57697
+ if (!priv._selected_node_id || !priv._selected_port_key) return;
57698
+ let xy = port_icon_xy(gobj);
57699
+ if (!xy) return;
57700
+ let icon = create_floating_icon("gear", "#1890ff", xy.x, xy.y, (0, i18next.t)("port properties"), () => toggle_port_popover(gobj));
57701
+ priv.$container.appendChild(icon);
57702
+ priv._port_icon_el = icon;
57703
+ }
57704
+ function hide_port_icon(gobj) {
57705
+ hide_overlay(gobj, "_port_icon_el");
57706
+ }
57707
+ function update_port_icon_position(gobj) {
57708
+ let priv = gobj.priv;
57709
+ if (!priv._port_icon_el || !priv._selected_node_id || !priv._selected_port_key) return;
57710
+ try {
57711
+ let xy = port_icon_xy(gobj);
57712
+ if (!xy) {
57713
+ hide_port_icon(gobj);
57714
+ hide_port_popover(gobj);
57715
+ return;
57716
+ }
57717
+ priv._port_icon_el.style.left = xy.x + "px";
57718
+ priv._port_icon_el.style.top = xy.y + "px";
57719
+ if (priv._port_popover_el) {
57720
+ priv._port_popover_el.style.left = xy.x + floating_popover_dx() + "px";
57721
+ priv._port_popover_el.style.top = xy.y + "px";
57722
+ clamp_popover_position(gobj, priv._port_popover_el);
57723
+ }
57724
+ } catch (e) {
57725
+ hide_port_icon(gobj);
57726
+ hide_port_popover(gobj);
57727
+ }
57728
+ }
57729
+ function toggle_port_popover(gobj) {
57730
+ if (gobj.priv._port_popover_el) hide_port_popover(gobj);
57731
+ else show_port_popover(gobj);
57732
+ }
57733
+ function hide_port_popover(gobj) {
57734
+ hide_overlay(gobj, "_port_popover_el");
57735
+ }
57736
+ function ports_with(ports, port_key, changes) {
57737
+ return (ports || []).map((p) => p.key === port_key ? Object.assign({}, p, changes) : p);
57738
+ }
57739
+ function show_port_popover(gobj) {
57740
+ hide_port_popover(gobj);
57741
+ let priv = gobj.priv;
57742
+ let graph = priv.graph;
57743
+ let node_id = priv._selected_node_id;
57744
+ let port_key = priv._selected_port_key;
57745
+ if (!node_id || !port_key) return;
57746
+ let nodeData = graph.getNodeData(node_id);
57747
+ if (!nodeData || !nodeData.style) return;
57748
+ let port = (nodeData.style.ports || []).find((p) => p.key === port_key);
57749
+ if (!port) return;
57750
+ let orig_shape = port.shape || "circle";
57751
+ let orig_r = get_port_radius(gobj, node_id, port_key);
57752
+ let xy = port_icon_xy(gobj);
57753
+ if (!xy) return;
57754
+ const popover = create_popover_base(xy.x + floating_popover_dx(), xy.y, "g6-port-popover", "#d9d9d9", 180);
57755
+ function preview_port() {
57756
+ let r = parseInt(rInput.value) || orig_r;
57757
+ graph.updateNodeData([{
57758
+ id: node_id,
57759
+ style: { ports: ports_with(nodeData.style.ports, port_key, {
57760
+ shape: shapeSelect.value,
57761
+ r
57762
+ }) }
57763
+ }]);
57764
+ graph.draw().then(() => {
57765
+ update_port_resize_handles_position(gobj);
57766
+ });
57767
+ }
57768
+ create_form_label(popover, "shape");
57769
+ let shapeSelect = create_form_select(popover, PORT_SHAPES.map((shape) => {
57770
+ return {
57771
+ value: shape,
57772
+ label: (0, i18next.t)(shape)
57773
+ };
57774
+ }));
57775
+ shapeSelect.value = orig_shape;
57776
+ shapeSelect.addEventListener("change", preview_port);
57777
+ create_form_label(popover, "radius");
57778
+ let rInput = create_form_number_input(popover, orig_r, 2, 40, preview_port);
57779
+ create_form_label(popover, "apply to");
57780
+ let scopeSelect = create_form_select(popover, [
57781
+ {
57782
+ value: "this",
57783
+ label: (0, i18next.t)("this port")
57784
+ },
57785
+ {
57786
+ value: "same_topic",
57787
+ label: (0, i18next.t)("same port in topic")
57788
+ },
57789
+ {
57790
+ value: "all",
57791
+ label: (0, i18next.t)("all ports")
57792
+ }
57793
+ ]);
57794
+ create_form_button_row(popover, [{
57795
+ text: "cancel",
57796
+ style: BTN_STYLE_CANCEL,
57797
+ onClick: () => {
57798
+ graph.updateNodeData([{
57799
+ id: node_id,
57800
+ style: { ports: ports_with(nodeData.style.ports, port_key, {
57801
+ shape: orig_shape,
57802
+ r: orig_r
57803
+ }) }
57804
+ }]);
57805
+ graph.draw().then(() => {
57806
+ update_port_resize_handles_position(gobj);
57807
+ });
57808
+ hide_port_popover(gobj);
57809
+ }
57810
+ }, {
57811
+ text: "apply",
57812
+ style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
57813
+ onClick: () => {
57814
+ apply_port_properties(gobj, node_id, port_key, shapeSelect.value, parseInt(rInput.value) || orig_r, scopeSelect.value);
57815
+ }
57816
+ }]);
57817
+ priv.$container.appendChild(popover);
57818
+ priv._port_popover_el = popover;
57819
+ clamp_popover_position(gobj, popover);
57820
+ }
57821
+ /************************************************************
57822
+ * Apply a port's shape and radius to one port, to the same port
57823
+ * of every card of the topic, or to every port -- and remember
57824
+ * the choice as the topic's default, the way `resize all ports`
57825
+ * does, so a card that arrives later is born with it.
57826
+ * scope: 'this', 'same_topic', 'all'
57827
+ ************************************************************/
57828
+ function apply_port_properties(gobj, node_id, port_key, shape, r, scope) {
57829
+ let priv = gobj.priv;
57830
+ let graph = priv.graph;
57831
+ let nodeData = graph.getNodeData(node_id);
57832
+ if (!nodeData || !nodeData.data) return;
57833
+ let source_topic = nodeData.data.topic_name;
57834
+ if (scope === "same_topic") {
57835
+ if (!(0, _yuneta_gobj_js.is_object)(priv._graph_properties[source_topic])) priv._graph_properties[source_topic] = {};
57836
+ let defaults = priv._graph_properties[source_topic].defaults || {};
57837
+ defaults.port_sizes = Object.assign({}, defaults.port_sizes, { [port_key]: r });
57838
+ defaults.port_shapes = Object.assign({}, defaults.port_shapes, { [port_key]: shape });
57839
+ priv._graph_properties[source_topic].defaults = defaults;
57840
+ } else if (scope === "all") for (const topic_name of Object.keys(priv.descs || {})) {
57841
+ if (!(0, _yuneta_gobj_js.is_object)(priv._graph_properties[topic_name])) priv._graph_properties[topic_name] = {};
57842
+ let defaults = priv._graph_properties[topic_name].defaults || {};
57843
+ defaults.portR = r;
57844
+ defaults.port_shape = shape;
57845
+ delete defaults.port_sizes;
57846
+ delete defaults.port_shapes;
57847
+ priv._graph_properties[topic_name].defaults = defaults;
57848
+ }
57849
+ let updates = [];
57850
+ for (let nd of graph.getNodeData() || []) {
57851
+ if (!nd || !nd.data || !nd.data.desc || !nd.style || !(0, _yuneta_gobj_js.is_array)(nd.style.ports)) continue;
57852
+ let new_ports;
57853
+ if (scope === "this") {
57854
+ if (nd.id !== node_id) continue;
57855
+ new_ports = ports_with(nd.style.ports, port_key, {
57856
+ shape,
57857
+ r
57858
+ });
57859
+ } else if (scope === "same_topic") {
57860
+ if (nd.data.topic_name !== source_topic) continue;
57861
+ new_ports = ports_with(nd.style.ports, port_key, {
57862
+ shape,
57863
+ r
57864
+ });
57865
+ } else new_ports = nd.style.ports.map((p) => Object.assign({}, p, {
57866
+ shape,
57867
+ r
57868
+ }));
57869
+ let upd = { ports: new_ports };
57870
+ if (scope === "all") upd.portR = r;
57871
+ updates.push({
57872
+ id: nd.id,
57873
+ style: upd
57874
+ });
57875
+ }
57876
+ if (updates.length > 0) {
57877
+ graph.updateNodeData(updates);
57878
+ graph.draw().then(() => {
57879
+ update_port_resize_handles_position(gobj);
57880
+ update_port_icon_position(gobj);
57881
+ mark_graph_dirty(gobj);
57882
+ });
57883
+ }
57884
+ hide_port_popover(gobj);
57885
+ }
57886
+ /************************************************************
57506
57887
  * Get a column descriptor by field id from a topic desc.
57507
57888
  ************************************************************/
57508
57889
  function get_col_by_id(desc, col_id) {
@@ -58209,6 +58590,14 @@ function show_node_popover(gobj) {
58209
58590
  let strokeInput = create_form_color_input(popover, currentStroke, preview_node);
58210
58591
  create_form_label(popover, "line width");
58211
58592
  let lwInput = create_form_number_input(popover, currentLW, 1, 20, preview_node);
58593
+ create_form_label(popover, "shape");
58594
+ let shapeSelect = create_form_select(popover, NODE_SHAPES.map((shape) => {
58595
+ return {
58596
+ value: shape,
58597
+ label: (0, i18next.t)(shape)
58598
+ };
58599
+ }));
58600
+ shapeSelect.value = nodeData.data && nodeData.data.desc ? node_figure_of(gobj, nodeData.data.desc, nodeData.data.graph_props || {}) : DEFAULT_NODE_SHAPE;
58212
58601
  create_form_label(popover, "apply to");
58213
58602
  let scopeSelect = create_form_select(popover, [
58214
58603
  {
@@ -58248,7 +58637,7 @@ function show_node_popover(gobj) {
58248
58637
  text: "apply",
58249
58638
  style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
58250
58639
  onClick: () => {
58251
- apply_node_properties(gobj, node_id, fillInput.value, strokeInput.value, parseInt(lwInput.value) || 1, scopeSelect.value);
58640
+ apply_node_properties(gobj, node_id, fillInput.value, strokeInput.value, parseInt(lwInput.value) || 1, scopeSelect.value, shapeSelect.value);
58252
58641
  }
58253
58642
  }]);
58254
58643
  priv.$container.appendChild(popover);
@@ -58479,10 +58868,11 @@ function repaint_cards(gobj, ids) {
58479
58868
  continue;
58480
58869
  }
58481
58870
  let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58482
- if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58871
+ let mode = nd && nd.data && nd.data.desc ? node_mode_of(gobj, id) : "expanded";
58872
+ if (mode === "shape") {
58483
58873
  updates.push({
58484
58874
  id,
58485
- style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58875
+ style: figure_shape_of(gobj, nd.data.desc, nd.data.record || {}, nd.data.graph_props || {}, {
58486
58876
  highlight: focus.has(id),
58487
58877
  selected: selected.has(id),
58488
58878
  anchored
@@ -58490,7 +58880,7 @@ function repaint_cards(gobj, ids) {
58490
58880
  });
58491
58881
  continue;
58492
58882
  }
58493
- let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58883
+ 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));
58494
58884
  if (html !== null) updates.push({
58495
58885
  id,
58496
58886
  style: { innerHTML: html }
@@ -58528,10 +58918,11 @@ function refresh_html_nodes_theme(gobj, theme) {
58528
58918
  let id = nodes[i].id;
58529
58919
  let nd = graph.getNodeData(id);
58530
58920
  let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
58531
- if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
58921
+ let mode = nd && nd.data && nd.data.desc ? node_mode_of(gobj, id) : "expanded";
58922
+ if (mode === "shape") {
58532
58923
  updates.push({
58533
58924
  id,
58534
- style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
58925
+ style: figure_shape_of(gobj, nd.data.desc, nd.data.record || {}, nd.data.graph_props || {}, {
58535
58926
  highlight: highlighted.has(id),
58536
58927
  selected: selected.has(id),
58537
58928
  anchored
@@ -58539,7 +58930,7 @@ function refresh_html_nodes_theme(gobj, theme) {
58539
58930
  });
58540
58931
  continue;
58541
58932
  }
58542
- let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
58933
+ 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));
58543
58934
  if (html === null) html = more_innerHTML_of(gobj, nd, theme);
58544
58935
  if (html !== null) updates.push({
58545
58936
  id,
@@ -58997,7 +59388,7 @@ function hide_unlink_confirm(gobj) {
58997
59388
  * Apply node properties to one or more nodes.
58998
59389
  * scope: 'this', 'same_topic', 'all'
58999
59390
  ************************************************************/
59000
- function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59391
+ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope, shape) {
59001
59392
  let priv = gobj.priv;
59002
59393
  let graph = priv.graph;
59003
59394
  let nodeData = graph.getNodeData(node_id);
@@ -59005,11 +59396,26 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59005
59396
  let source_topic = nodeData.data.desc ? nodeData.data.desc.topic_name : null;
59006
59397
  let updates = [];
59007
59398
  const nodes = graph.getData().nodes;
59399
+ let figure = shape && (0, _yuneta_gobj_js.str_in_list)(NODE_SHAPES, shape) ? shape : "";
59400
+ let reshaped = [];
59401
+ if (figure && scope !== "this") {
59402
+ let topics = scope === "same_topic" ? [source_topic] : Object.keys(priv.descs || {});
59403
+ for (let topic_name of topics) {
59404
+ if (!(0, _yuneta_gobj_js.is_object)(priv._graph_properties[topic_name])) priv._graph_properties[topic_name] = {};
59405
+ let defaults = priv._graph_properties[topic_name].defaults || {};
59406
+ defaults.node_shape = figure;
59407
+ priv._graph_properties[topic_name].defaults = defaults;
59408
+ }
59409
+ }
59008
59410
  for (let i = 0; i < nodes.length; i++) {
59009
59411
  let nd = graph.getNodeData(nodes[i].id);
59010
59412
  if (!nd || !nd.data || !nd.data.desc) continue;
59011
59413
  if (scope === "this" && nodes[i].id !== node_id) continue;
59012
59414
  if (scope === "same_topic" && nd.data.desc.topic_name !== source_topic) continue;
59415
+ if (figure) {
59416
+ node_props_entry(gobj, nd).node_shape = figure;
59417
+ if (node_mode_of(gobj, nodes[i].id) === "shape") reshaped.push(nodes[i].id);
59418
+ }
59013
59419
  let updateStyle = {
59014
59420
  fill,
59015
59421
  stroke,
@@ -59026,6 +59432,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59026
59432
  }
59027
59433
  if (updates.length > 0) {
59028
59434
  graph.updateNodeData(updates);
59435
+ if (reshaped.length) reshape_nodes(gobj, reshaped);
59029
59436
  graph.draw().then(() => {
59030
59437
  mark_graph_dirty(gobj);
59031
59438
  });
@@ -59033,6 +59440,23 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
59033
59440
  hide_node_popover(gobj);
59034
59441
  }
59035
59442
  /************************************************************
59443
+ * The node's entry in `_graph_properties` -- the object Save
59444
+ * reads and writes -- created if it has none yet, and the node's
59445
+ * `data.graph_props` pointed at it, so a key written here is
59446
+ * read by the next reshape and survives the next Save.
59447
+ ************************************************************/
59448
+ function node_props_entry(gobj, nd) {
59449
+ let priv = gobj.priv;
59450
+ let topic_name = nd.data.topic_name;
59451
+ let record = nd.data.record || {};
59452
+ if (!(0, _yuneta_gobj_js.is_object)(priv._graph_properties[topic_name])) priv._graph_properties[topic_name] = {};
59453
+ let topic_props = priv._graph_properties[topic_name];
59454
+ if (!(0, _yuneta_gobj_js.is_object)(topic_props.nodes)) topic_props.nodes = {};
59455
+ if (!(0, _yuneta_gobj_js.is_object)(topic_props.nodes[record.id])) topic_props.nodes[record.id] = (0, _yuneta_gobj_js.is_object)(nd.data.graph_props) ? nd.data.graph_props : {};
59456
+ nd.data.graph_props = topic_props.nodes[record.id];
59457
+ return nd.data.graph_props;
59458
+ }
59459
+ /************************************************************
59036
59460
  * Apply edge properties to one or more edges.
59037
59461
  * scope: 'this', 'same_type', 'all'
59038
59462
  ************************************************************/
@@ -59160,8 +59584,8 @@ function ctx_item(icon_id, label, value) {
59160
59584
  function build_node_context_menu(gobj, node_id) {
59161
59585
  let items = [];
59162
59586
  inject_svg_icons();
59163
- if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", (0, i18next.t)("open node"), "toggle_node_mode"));
59164
- else items.push(ctx_item("g6-icon-fullscreen-exit", (0, i18next.t)("close node"), "toggle_node_mode"));
59587
+ if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", (0, i18next.t)("expand node"), "toggle_node_mode"));
59588
+ else items.push(ctx_item("g6-icon-fullscreen-exit", (0, i18next.t)("collapse node"), "toggle_node_mode"));
59165
59589
  if (gobj.priv.edit_mode && !node_is_compact(gobj, node_id)) {
59166
59590
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize all"), "resize_all_nodes"));
59167
59591
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize topic nodes"), "resize_topic_nodes"));
@@ -59177,6 +59601,7 @@ function build_port_context_menu(gobj, node_id, port_key) {
59177
59601
  let items = [];
59178
59602
  if (gobj.priv.edit_mode) {
59179
59603
  inject_svg_icons();
59604
+ items.push(ctx_item("g6-icon-edit", (0, i18next.t)("port properties"), "port_properties"));
59180
59605
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize all ports"), "resize_all_ports"));
59181
59606
  items.push(ctx_item("g6-icon-resize", (0, i18next.t)("resize topic ports"), "resize_topic_ports"));
59182
59607
  }
@@ -59209,6 +59634,12 @@ function handle_context_menu_click(gobj, value) {
59209
59634
  case "reset_topic_sizes":
59210
59635
  reset_sizes(gobj, true);
59211
59636
  break;
59637
+ case "port_properties":
59638
+ if (priv._context_node_id && priv._context_port_key) {
59639
+ select_port(gobj, priv._context_node_id, priv._context_port_key);
59640
+ show_port_popover(gobj);
59641
+ }
59642
+ break;
59212
59643
  case "resize_all_ports":
59213
59644
  copy_size_to_ports(gobj, false);
59214
59645
  break;
@@ -59252,7 +59683,7 @@ function copy_size_to_nodes(gobj, same_topic_only) {
59252
59683
  if (nodes[i].id === node_id) continue;
59253
59684
  let updateStyle = { size: [...source_size] };
59254
59685
  if (source_portR != null) updateStyle.portR = source_portR;
59255
- if (nd.type === "html") {
59686
+ if (is_card_type(nd.type)) {
59256
59687
  updateStyle.dx = -source_size[0] / 2;
59257
59688
  updateStyle.dy = -(source_size.length > 1 ? source_size[1] : source_size[0]) / 2;
59258
59689
  }
@@ -59393,7 +59824,7 @@ var MORE_CHIP_SIZE_COMPACT = [40, 22];
59393
59824
  function more_chip_is_compact(gobj, nd) {
59394
59825
  let parent_id = nd && nd.data ? nd.data.parent_node : "";
59395
59826
  if (parent_id) return node_is_compact(gobj, parent_id);
59396
- return (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact";
59827
+ return (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") !== "expanded";
59397
59828
  }
59398
59829
  function more_chip_style(gobj, nd, color, rest) {
59399
59830
  let compact = more_chip_is_compact(gobj, nd);
@@ -59852,6 +60283,7 @@ async function reconcile_fold_apply(gobj, opts, visible) {
59852
60283
  update_edge_icon_position(gobj);
59853
60284
  update_node_icon_position(gobj);
59854
60285
  update_link_icon_position(gobj);
60286
+ update_port_icon_position(gobj);
59855
60287
  return changed;
59856
60288
  }
59857
60289
  /************************************************************
@@ -60443,9 +60875,9 @@ function ac_set_loose_topics(gobj, event, kw, src) {
60443
60875
  * and lays the graph out again, because a square and a card
60444
60876
  * do not occupy the same room.
60445
60877
  ************************************************************/
60446
- function ac_set_node_mode(gobj, event, kw, src) {
60878
+ function ac_set_node_mode$1(gobj, event, kw, src) {
60447
60879
  let priv = gobj.priv;
60448
- let mode = kw && kw.node_mode === "compact" ? "compact" : "expanded";
60880
+ let mode = kw && kw.node_mode && (0, _yuneta_gobj_js.str_in_list)(NODE_MODES$1, kw.node_mode) ? kw.node_mode : "expanded";
60449
60881
  (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "node_mode", mode);
60450
60882
  priv._open_nodes = /* @__PURE__ */ new Set();
60451
60883
  if (!priv.graph || !priv._fold_model) return 0;
@@ -60458,15 +60890,15 @@ function ac_set_node_mode(gobj, event, kw, src) {
60458
60890
  return 0;
60459
60891
  }
60460
60892
  /************************************************************
60461
- * The name under a closed square, on or off. Only the closed
60462
- * nodes change, and nothing moves: the label hangs outside the
60463
- * square and the layout measures the square.
60893
+ * The name under a figure, on or off. Only the `shape` nodes
60894
+ * change, and nothing moves: the label hangs outside the figure
60895
+ * and the layout measures the figure.
60464
60896
  ************************************************************/
60465
60897
  function ac_set_node_labels(gobj, event, kw, src) {
60466
60898
  let priv = gobj.priv;
60467
60899
  (0, _yuneta_gobj_js.gobj_write_bool_attr)(gobj, "node_labels", !!(kw && kw.node_labels));
60468
60900
  if (!priv.graph) return 0;
60469
- reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_is_compact(gobj, id)));
60901
+ reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_mode_of(gobj, id) === "shape"));
60470
60902
  return 0;
60471
60903
  }
60472
60904
  /************************************************************
@@ -60474,7 +60906,7 @@ function ac_set_node_labels(gobj, event, kw, src) {
60474
60906
  * or the context menu). It holds still on screen while the
60475
60907
  * rest of the graph makes room, as a fold does.
60476
60908
  ************************************************************/
60477
- function ac_toggle_node_mode$1(gobj, event, kw, src) {
60909
+ function ac_toggle_node_mode(gobj, event, kw, src) {
60478
60910
  let priv = gobj.priv;
60479
60911
  let node_id = kw && kw.id || "";
60480
60912
  if (!priv.graph || !node_id) {
@@ -61003,7 +61435,7 @@ function create_gclass$4(gclass_name) {
61003
61435
  ],
61004
61436
  [
61005
61437
  "EV_SET_NODE_MODE",
61006
- ac_set_node_mode,
61438
+ ac_set_node_mode$1,
61007
61439
  null
61008
61440
  ],
61009
61441
  [
@@ -61013,7 +61445,7 @@ function create_gclass$4(gclass_name) {
61013
61445
  ],
61014
61446
  [
61015
61447
  "EV_TOGGLE_NODE_MODE",
61016
- ac_toggle_node_mode$1,
61448
+ ac_toggle_node_mode,
61017
61449
  null
61018
61450
  ],
61019
61451
  [
@@ -61194,8 +61626,8 @@ var attrs_table$3 = [
61194
61626
  (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"),
61195
61627
  (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"),
61196
61628
  (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"),
61197
- (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"),
61198
- (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"),
61629
+ (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 pills and ports, `compact` = one-line pills with the name, `shape` = coloured figures, the topology alone. User preference"),
61630
+ (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 `shape` node says its name under its figure. User preference"),
61199
61631
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
61200
61632
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
61201
61633
  (0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
@@ -61479,44 +61911,92 @@ function option_label(name) {
61479
61911
  * its context menu (the child's business).
61480
61912
  ************************************************************/
61481
61913
  function node_shape_items(gobj, wide) {
61482
- let toggle = (cls, icon, event_name, label_key) => {
61483
- return [
61914
+ let options = NODE_MODES.map((mode) => [
61915
+ "option",
61916
+ {
61917
+ value: mode,
61918
+ "data-i18n": NODE_MODE_LABELS[mode]
61919
+ },
61920
+ (0, i18next.t)(NODE_MODE_LABELS[mode])
61921
+ ]);
61922
+ return [
61923
+ [
61924
+ "span",
61925
+ {
61926
+ class: "GRAPH_NODE_MODE_LABEL is-hidden-mobile",
61927
+ style: "padding-left:10px; padding-right:5px;",
61928
+ i18n: "nodes"
61929
+ },
61930
+ "nodes"
61931
+ ],
61932
+ [
61933
+ "div",
61934
+ { class: "select" },
61935
+ [[
61936
+ "select",
61937
+ {
61938
+ class: "GRAPH_NODE_MODE_SELECT",
61939
+ title: (0, i18next.t)("nodes"),
61940
+ "data-i18n-title": "nodes",
61941
+ "aria-label": (0, i18next.t)("nodes"),
61942
+ "data-i18n-aria-label": "nodes"
61943
+ },
61944
+ options
61945
+ ]],
61946
+ { change: (evt) => {
61947
+ evt.stopPropagation();
61948
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SET_NODE_MODE", { node_mode: evt.target.value }, gobj);
61949
+ } }
61950
+ ],
61951
+ [
61484
61952
  "button",
61485
61953
  {
61486
- class: `${cls} button`,
61954
+ class: "GRAPH_NODE_LABELS button",
61487
61955
  type: "button",
61488
61956
  style: {
61489
61957
  height: wide,
61490
61958
  width: "2.5em"
61491
61959
  },
61492
- title: (0, i18next.t)(label_key),
61493
- "data-i18n-title": label_key,
61494
- "aria-label": (0, i18next.t)(label_key),
61495
- "data-i18n-aria-label": label_key,
61960
+ title: (0, i18next.t)("node labels"),
61961
+ "data-i18n-title": "node labels",
61962
+ "aria-label": (0, i18next.t)("node labels"),
61963
+ "data-i18n-aria-label": "node labels",
61496
61964
  "aria-pressed": "false"
61497
61965
  },
61498
61966
  ["i", {
61499
61967
  style: "font-size:1.5em; color:inherit;",
61500
- class: icon
61968
+ class: "yi-font"
61501
61969
  }],
61502
61970
  { click: (evt) => {
61503
61971
  evt.stopPropagation();
61504
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, event_name, {}, gobj);
61972
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_NODE_LABELS", {}, gobj);
61505
61973
  } }
61506
- ];
61507
- };
61508
- 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")];
61974
+ ]
61975
+ ];
61509
61976
  }
61977
+ var NODE_MODES = [
61978
+ "expanded",
61979
+ "compact",
61980
+ "shape"
61981
+ ];
61982
+ var NODE_MODE_LABELS = {
61983
+ expanded: "full",
61984
+ compact: "compact",
61985
+ shape: "shape"
61986
+ };
61510
61987
  function refresh_node_shape_buttons(gobj, $root) {
61511
61988
  if (!$root) return;
61512
- let compact = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact";
61989
+ let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode");
61990
+ if (!NODE_MODES.includes(mode)) mode = "expanded";
61513
61991
  let labels = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "node_labels");
61514
- set_pressed_state($root, ".GRAPH_NODE_MODE", compact);
61992
+ let $mode = $root.querySelector(".GRAPH_NODE_MODE_SELECT");
61993
+ if ($mode) $mode.value = mode;
61515
61994
  set_pressed_state($root, ".GRAPH_NODE_LABELS", labels);
61516
- let $mode = $root.querySelector(".GRAPH_NODE_MODE");
61517
- if ($mode) $mode.setAttribute("aria-pressed", compact ? "true" : "false");
61518
61995
  let $labels = $root.querySelector(".GRAPH_NODE_LABELS");
61519
- if ($labels) $labels.setAttribute("aria-pressed", labels ? "true" : "false");
61996
+ if ($labels) {
61997
+ $labels.setAttribute("aria-pressed", labels ? "true" : "false");
61998
+ $labels.disabled = mode !== "shape";
61999
+ }
61520
62000
  }
61521
62001
  function make_toolbar(gobj) {
61522
62002
  let priv = gobj.priv;
@@ -62903,13 +63383,13 @@ function ac_collapse_all(gobj, event, kw, src) {
62903
63383
  return 0;
62904
63384
  }
62905
63385
  /************************************************************
62906
- * The shape pair of the toolbar: the attr flips, persists,
62907
- * shows on the button, and reaches the G6 child, which owns
62908
- * the nodes.
63386
+ * The view of the nodes and the labels toggle of the toolbar:
63387
+ * the attr changes, persists, shows on the control, and reaches
63388
+ * the G6 child, which owns the nodes.
62909
63389
  ************************************************************/
62910
- function ac_toggle_node_mode(gobj, event, kw, src) {
63390
+ function ac_set_node_mode(gobj, event, kw, src) {
62911
63391
  let priv = gobj.priv;
62912
- let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "node_mode") === "compact" ? "expanded" : "compact";
63392
+ let mode = kw && NODE_MODES.includes(kw.node_mode) ? kw.node_mode : "expanded";
62913
63393
  (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "node_mode", mode);
62914
63394
  (0, _yuneta_gobj_js.gobj_save_persistent_attrs)(gobj, "node_mode");
62915
63395
  refresh_node_shape_buttons(gobj, priv.$container);
@@ -63140,8 +63620,8 @@ function create_gclass$3(gclass_name) {
63140
63620
  null
63141
63621
  ],
63142
63622
  [
63143
- "EV_TOGGLE_NODE_MODE",
63144
- ac_toggle_node_mode,
63623
+ "EV_SET_NODE_MODE",
63624
+ ac_set_node_mode,
63145
63625
  null
63146
63626
  ],
63147
63627
  [
@@ -63213,7 +63693,7 @@ function create_gclass$3(gclass_name) {
63213
63693
  ["EV_FIND_NODES", 0],
63214
63694
  ["EV_EXPAND_ALL", 0],
63215
63695
  ["EV_COLLAPSE_ALL", 0],
63216
- ["EV_TOGGLE_NODE_MODE", 0],
63696
+ ["EV_SET_NODE_MODE", 0],
63217
63697
  ["EV_TOGGLE_NODE_LABELS", 0],
63218
63698
  ["EV_FIND_RESULT", 0],
63219
63699
  ["EV_LAYOUT_AUTOSET", 0],