@yuneta/gobj-ui 7.23.73 → 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.
- package/README.md +66 -12
- package/dist/gobj-ui.cjs.js +498 -134
- package/dist/gobj-ui.es.js +498 -134
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +433 -94
- package/src/c_yui_treedb_graph.js +118 -2
- package/src/treedb_layout.js +42 -52
- package/src/treedb_layout.test.js +45 -24
- package/src/yui_icons.css +6 -0
package/dist/gobj-ui.es.js
CHANGED
|
@@ -27368,7 +27368,7 @@ function fold_reveal(model, state, node_key) {
|
|
|
27368
27368
|
* Two layouts made for a treedb, and nothing else.
|
|
27369
27369
|
*
|
|
27370
27370
|
* What a treedb graph IS, once it is folded (treedb_fold_model.js):
|
|
27371
|
-
* a forest read
|
|
27371
|
+
* a forest read top to bottom. A main topic is a tree (places:
|
|
27372
27372
|
* country, region, site, hall), the other topics hang from its
|
|
27373
27373
|
* nodes through hooks (devices, users, controllers), a record may
|
|
27374
27374
|
* hang from two parents (a device from its place AND its
|
|
@@ -27389,8 +27389,8 @@ function fold_reveal(model, state, node_key) {
|
|
|
27389
27389
|
* - the force family scatters a tree, which is the pile with
|
|
27390
27390
|
* physics.
|
|
27391
27391
|
*
|
|
27392
|
-
* So: a tidy tree (`tree`) and
|
|
27393
|
-
* the SAME spanning tree, chosen deterministically:
|
|
27392
|
+
* So: a tidy tree (`tree`) and a radial tree (`radial`), both fed
|
|
27393
|
+
* by the SAME spanning tree, chosen deterministically:
|
|
27394
27394
|
*
|
|
27395
27395
|
* - roots are the nodes with no incoming edge, in node order;
|
|
27396
27396
|
* - a node belongs to the FIRST parent that reaches it in a
|
|
@@ -27402,16 +27402,21 @@ function fold_reveal(model, state, node_key) {
|
|
|
27402
27402
|
* and then by node order (record order, the pages' order);
|
|
27403
27403
|
* - a node nothing reaches (a cycle) is a root too.
|
|
27404
27404
|
*
|
|
27405
|
-
* `tree`: the classic tidy tree,
|
|
27406
|
-
*
|
|
27407
|
-
* block of its children; siblings
|
|
27408
|
-
* them. O(n), and opening a hook moves NOTHING that is
|
|
27409
|
-
* or beside it -- the cards keep their order, the eye
|
|
27410
|
-
* place.
|
|
27411
|
-
*
|
|
27412
|
-
*
|
|
27413
|
-
*
|
|
27414
|
-
*
|
|
27405
|
+
* `tree`: the classic tidy tree, top to bottom. Each depth is a
|
|
27406
|
+
* row as tall as its tallest card; a node is centred over the
|
|
27407
|
+
* block of its children; siblings sit side by side with `nodesep`
|
|
27408
|
+
* between them. O(n), and opening a hook moves NOTHING that is
|
|
27409
|
+
* not below or beside it -- the cards keep their order, the eye
|
|
27410
|
+
* keeps its place. It reads DOWN because that is the direction a
|
|
27411
|
+
* tree with many children has room in: a hall with a hundred
|
|
27412
|
+
* devices is a wide row, not a tall column beside a card. (The
|
|
27413
|
+
* left-to-right reading is `direction: "LR"`, kept for a host
|
|
27414
|
+
* that wants it; `dagre` reads that way in the graph.)
|
|
27415
|
+
*
|
|
27416
|
+
* `radial`: the root in the middle and a ring per depth, each
|
|
27417
|
+
* subtree owning a sector proportional to its leaves; the radius
|
|
27418
|
+
* of a ring grows until its neighbours sit side by side, so
|
|
27419
|
+
* nothing overlaps by construction (see `layout_radial`).
|
|
27415
27420
|
*
|
|
27416
27421
|
* Pure: takes plain nodes and edges, returns positions. The G6
|
|
27417
27422
|
* classes in c_g6_nodes_tree.js are two thin adapters over it.
|
|
@@ -27421,8 +27426,8 @@ function fold_reveal(model, state, node_key) {
|
|
|
27421
27426
|
***********************************************************************/
|
|
27422
27427
|
var DEFAULTS = {
|
|
27423
27428
|
nodesep: 18,
|
|
27424
|
-
ranksep:
|
|
27425
|
-
|
|
27429
|
+
ranksep: 90,
|
|
27430
|
+
direction: "TB"
|
|
27426
27431
|
};
|
|
27427
27432
|
/************************************************************
|
|
27428
27433
|
* The spanning tree of a graph, deterministic.
|
|
@@ -27509,13 +27514,33 @@ function walk_order(t) {
|
|
|
27509
27514
|
return order;
|
|
27510
27515
|
}
|
|
27511
27516
|
/************************************************************
|
|
27512
|
-
* The tidy tree
|
|
27517
|
+
* The tidy tree.
|
|
27513
27518
|
*
|
|
27514
27519
|
* Returns Map<id, {x, y}> with the CENTRE of each node, the way G6
|
|
27515
27520
|
* positions a node.
|
|
27521
|
+
*
|
|
27522
|
+
* The algorithm is written ONCE, reading left to right (depths are
|
|
27523
|
+
* columns, siblings stack down). Top to bottom -- the default -- is
|
|
27524
|
+
* the same tree with the axes swapped: every card is fed in
|
|
27525
|
+
* transposed (its height as its width), and every position comes
|
|
27526
|
+
* back transposed. That is the whole difference, and it is the
|
|
27527
|
+
* reason the code is not duplicated for a second direction.
|
|
27516
27528
|
************************************************************/
|
|
27517
27529
|
function layout_tree(nodes, edges, opts) {
|
|
27518
27530
|
let o = Object.assign({}, DEFAULTS, opts || {});
|
|
27531
|
+
if (o.direction === "LR") return tidy_tree_lr(nodes, edges, o);
|
|
27532
|
+
let lr = tidy_tree_lr(nodes.map((n) => Object.assign({}, n, {
|
|
27533
|
+
w: n.h,
|
|
27534
|
+
h: n.w
|
|
27535
|
+
})), edges, o);
|
|
27536
|
+
let pos = /* @__PURE__ */ new Map();
|
|
27537
|
+
for (let [id, p] of lr) pos.set(id, {
|
|
27538
|
+
x: p.y,
|
|
27539
|
+
y: p.x
|
|
27540
|
+
});
|
|
27541
|
+
return pos;
|
|
27542
|
+
}
|
|
27543
|
+
function tidy_tree_lr(nodes, edges, o) {
|
|
27519
27544
|
let t = spanning_tree(nodes, edges);
|
|
27520
27545
|
let pos = /* @__PURE__ */ new Map();
|
|
27521
27546
|
let col_w = [];
|
|
@@ -27681,37 +27706,6 @@ function layout_radial(nodes, edges, opts) {
|
|
|
27681
27706
|
}
|
|
27682
27707
|
return pos;
|
|
27683
27708
|
}
|
|
27684
|
-
/************************************************************
|
|
27685
|
-
* The outline: one node per row, indented by depth, in the
|
|
27686
|
-
* pre-order of the spanning tree. Rows are left-aligned on
|
|
27687
|
-
* their indent, so a column of chips reads as a list.
|
|
27688
|
-
************************************************************/
|
|
27689
|
-
function layout_outline(nodes, edges, opts) {
|
|
27690
|
-
let o = Object.assign({}, DEFAULTS, opts || {});
|
|
27691
|
-
let t = spanning_tree(nodes, edges);
|
|
27692
|
-
let pos = /* @__PURE__ */ new Map();
|
|
27693
|
-
let y = 0;
|
|
27694
|
-
let visit = (root_id) => {
|
|
27695
|
-
let stack = [root_id];
|
|
27696
|
-
while (stack.length) {
|
|
27697
|
-
let id = stack.pop();
|
|
27698
|
-
let n = t.by_id.get(id);
|
|
27699
|
-
let d = t.depth.get(id);
|
|
27700
|
-
pos.set(id, {
|
|
27701
|
-
x: d * o.indent + n.w / 2,
|
|
27702
|
-
y: y + n.h / 2
|
|
27703
|
-
});
|
|
27704
|
-
y += n.h + o.nodesep;
|
|
27705
|
-
let kids = t.children.get(id) || [];
|
|
27706
|
-
for (let i = kids.length - 1; i >= 0; i--) stack.push(kids[i]);
|
|
27707
|
-
}
|
|
27708
|
-
};
|
|
27709
|
-
for (let root of t.roots) {
|
|
27710
|
-
visit(root);
|
|
27711
|
-
y += o.nodesep;
|
|
27712
|
-
}
|
|
27713
|
-
return pos;
|
|
27714
|
-
}
|
|
27715
27709
|
//#endregion
|
|
27716
27710
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
27717
27711
|
function _typeof(o) {
|
|
@@ -54528,6 +54522,14 @@ var GCLASS_NAME$4 = "C_G6_NODES_TREE";
|
|
|
54528
54522
|
var HIGHLIGHT_COLOR = "#f0a020";
|
|
54529
54523
|
var HIGHLIGHT_HALO = "rgba(240,160,32,0.35)";
|
|
54530
54524
|
var SELECT_RING = "rgba(59,130,246,0.95)";
|
|
54525
|
+
var PORT_R_ENTITY = 10;
|
|
54526
|
+
var PORT_R_CHILD = 5;
|
|
54527
|
+
var PORT_LINE_WIDTH = 2;
|
|
54528
|
+
var COMPACT_SIZE = {
|
|
54529
|
+
hierarchical: 32,
|
|
54530
|
+
extended: 28,
|
|
54531
|
+
child: 22
|
|
54532
|
+
};
|
|
54531
54533
|
/***************************************************************
|
|
54532
54534
|
* Internal layout and operation mode definitions
|
|
54533
54535
|
***************************************************************/
|
|
@@ -54535,13 +54537,9 @@ var _layouts = {
|
|
|
54535
54537
|
"manual": { type: "manual" },
|
|
54536
54538
|
"treedb-tree": {
|
|
54537
54539
|
type: "treedb-tree",
|
|
54540
|
+
direction: "TB",
|
|
54538
54541
|
nodesep: 18,
|
|
54539
|
-
ranksep:
|
|
54540
|
-
},
|
|
54541
|
-
"treedb-outline": {
|
|
54542
|
-
type: "treedb-outline",
|
|
54543
|
-
nodesep: 12,
|
|
54544
|
-
indent: 48
|
|
54542
|
+
ranksep: 90
|
|
54545
54543
|
},
|
|
54546
54544
|
"dagre": {
|
|
54547
54545
|
type: "dagre",
|
|
@@ -54612,6 +54610,8 @@ var attrs_table$4 = [
|
|
|
54612
54610
|
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"),
|
|
54613
54611
|
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"),
|
|
54614
54612
|
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"),
|
|
54615
54615
|
SDATA(data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
|
|
54616
54616
|
SDATA(data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
|
|
54617
54617
|
SDATA(data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
|
|
@@ -54695,6 +54695,7 @@ var PRIVATE_DATA$4 = {
|
|
|
54695
54695
|
_fold_state: null,
|
|
54696
54696
|
_fold_listener: null,
|
|
54697
54697
|
_pill_sig: null,
|
|
54698
|
+
_open_nodes: null,
|
|
54698
54699
|
_fold_busy: false
|
|
54699
54700
|
};
|
|
54700
54701
|
var __gclass__$4 = null;
|
|
@@ -54840,7 +54841,6 @@ function register_layouts(gobj) {
|
|
|
54840
54841
|
_g6_extensions_registered = true;
|
|
54841
54842
|
register(ExtensionCategory.LAYOUT, "manual", ManualLayout);
|
|
54842
54843
|
register(ExtensionCategory.LAYOUT, "treedb-tree", TreedbTreeLayout);
|
|
54843
|
-
register(ExtensionCategory.LAYOUT, "treedb-outline", TreedbOutlineLayout);
|
|
54844
54844
|
register(ExtensionCategory.LAYOUT, "treedb-radial", TreedbRadialLayout);
|
|
54845
54845
|
register(ExtensionCategory.NODE, "light", LightNode);
|
|
54846
54846
|
}
|
|
@@ -54923,6 +54923,9 @@ function configure_events(gobj) {
|
|
|
54923
54923
|
graph.on(NodeEvent.CONTEXT_MENU, (evt) => {
|
|
54924
54924
|
gobj_send_event(gobj, "EV_NODE_CONTEXT_MENU", { evt }, gobj);
|
|
54925
54925
|
});
|
|
54926
|
+
graph.on(NodeEvent.DBLCLICK, (evt) => {
|
|
54927
|
+
gobj_send_event(gobj, "EV_NODE_DBLCLICK", { evt }, gobj);
|
|
54928
|
+
});
|
|
54926
54929
|
graph.on(EdgeEvent.CLICK, (evt) => {
|
|
54927
54930
|
if (consume_long_press_click(graph)) return;
|
|
54928
54931
|
gobj_send_event(gobj, "EV_EDGE_CLICK", { evt }, gobj);
|
|
@@ -55347,7 +55350,7 @@ function configure_behaviour(gobj) {
|
|
|
55347
55350
|
case "writing":
|
|
55348
55351
|
case "reading":
|
|
55349
55352
|
priv.edit_mode = false;
|
|
55350
|
-
behaviors = ["drag-canvas",
|
|
55353
|
+
behaviors = ["drag-canvas", ...camera_behaviors()];
|
|
55351
55354
|
break;
|
|
55352
55355
|
case "edition":
|
|
55353
55356
|
priv.edit_mode = true;
|
|
@@ -55361,7 +55364,7 @@ function configure_behaviour(gobj) {
|
|
|
55361
55364
|
return true;
|
|
55362
55365
|
}
|
|
55363
55366
|
},
|
|
55364
|
-
|
|
55367
|
+
...camera_behaviors(),
|
|
55365
55368
|
"drag-element",
|
|
55366
55369
|
{
|
|
55367
55370
|
type: BRUSH_SELECT_OWNED,
|
|
@@ -55379,7 +55382,7 @@ function configure_behaviour(gobj) {
|
|
|
55379
55382
|
break;
|
|
55380
55383
|
case "operation":
|
|
55381
55384
|
priv.edit_mode = false;
|
|
55382
|
-
behaviors = ["drag-canvas",
|
|
55385
|
+
behaviors = ["drag-canvas", ...camera_behaviors()];
|
|
55383
55386
|
break;
|
|
55384
55387
|
default: log_error(`operation mode unknown: ${operation_mode}`);
|
|
55385
55388
|
}
|
|
@@ -55451,13 +55454,33 @@ function build_ports(gobj, desc) {
|
|
|
55451
55454
|
* Which way the graph reads. `dagre` is the left-to-right
|
|
55452
55455
|
* layout; everything else keeps the top-down reading, `manual`
|
|
55453
55456
|
* included, because the saved arrangements were made with the
|
|
55454
|
-
* ports on the top and bottom edges.
|
|
55455
|
-
|
|
55456
|
-
|
|
55457
|
-
|
|
55458
|
-
|
|
55459
|
-
|
|
55460
|
-
|
|
55457
|
+
* ports on the top and bottom edges. The treedb tree reads down
|
|
55458
|
+
* too, since 7.23.75: read right it was dagre's twin.
|
|
55459
|
+
************************************************************/
|
|
55460
|
+
var LR_LAYOUTS = ["dagre"];
|
|
55461
|
+
/************************************************************
|
|
55462
|
+
* The camera behaviors every operation mode shares.
|
|
55463
|
+
*
|
|
55464
|
+
* The wheel SCROLLS, as it does on a map and on every page: a
|
|
55465
|
+
* graph of many nodes is taller than the screen, and a wheel
|
|
55466
|
+
* that zoomed instead made it a thing to be looked at from afar
|
|
55467
|
+
* or read through a keyhole -- never scrolled. Zoom is Ctrl +
|
|
55468
|
+
* wheel (which is also what a trackpad pinch arrives as), the
|
|
55469
|
+
* toolbar's +/-, and the two-finger pinch of g6_touch_gestures.
|
|
55470
|
+
* `enable` on the scroll keeps the two apart: a Ctrl wheel is
|
|
55471
|
+
* the zoom's, so the scroll stands aside for it.
|
|
55472
|
+
************************************************************/
|
|
55473
|
+
function camera_behaviors() {
|
|
55474
|
+
return [{
|
|
55475
|
+
type: "scroll-canvas",
|
|
55476
|
+
key: "scroll-canvas",
|
|
55477
|
+
enable: (event) => !(event && (event.ctrlKey || event.metaKey))
|
|
55478
|
+
}, {
|
|
55479
|
+
type: "zoom-canvas",
|
|
55480
|
+
key: "zoom-canvas",
|
|
55481
|
+
trigger: ["Control"]
|
|
55482
|
+
}];
|
|
55483
|
+
}
|
|
55461
55484
|
function layout_direction(gobj) {
|
|
55462
55485
|
return str_in_list(LR_LAYOUTS, gobj.priv.layout) ? "LR" : "TB";
|
|
55463
55486
|
}
|
|
@@ -55525,83 +55548,101 @@ function apply_layout_direction(gobj) {
|
|
|
55525
55548
|
* Create a topic node in the G6 graph
|
|
55526
55549
|
************************************************************/
|
|
55527
55550
|
function create_topic_node(gobj, desc, record) {
|
|
55528
|
-
|
|
55529
|
-
const graph = priv.graph;
|
|
55551
|
+
const graph = gobj.priv.graph;
|
|
55530
55552
|
let node_name = build_node_name(gobj, desc.topic_name, record.id);
|
|
55531
55553
|
let xy = get_default_ne_xy(gobj);
|
|
55532
55554
|
let geometry = get_node_graph_props(gobj, desc.topic_name, record.id, record);
|
|
55533
55555
|
let x = kw_get_int(gobj, geometry, "x", xy, kw_flag_t.KW_CREATE);
|
|
55534
55556
|
let y = kw_get_int(gobj, geometry, "y", xy, kw_flag_t.KW_CREATE);
|
|
55535
|
-
let
|
|
55536
|
-
let
|
|
55557
|
+
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))));
|
|
55558
|
+
let node_def = {
|
|
55559
|
+
id: node_name,
|
|
55560
|
+
type: shape.type,
|
|
55561
|
+
style: Object.assign({
|
|
55562
|
+
x,
|
|
55563
|
+
y
|
|
55564
|
+
}, shape.style),
|
|
55565
|
+
data: {
|
|
55566
|
+
topic_name: desc.topic_name,
|
|
55567
|
+
desc,
|
|
55568
|
+
record,
|
|
55569
|
+
graph_props: geometry,
|
|
55570
|
+
port_keys: build_ports(gobj, desc).map((p) => p.key)
|
|
55571
|
+
}
|
|
55572
|
+
};
|
|
55573
|
+
graph.addNodeData([node_def]);
|
|
55574
|
+
}
|
|
55575
|
+
/************************************************************
|
|
55576
|
+
* The shape of a record node: OPEN (the card, with its ports)
|
|
55577
|
+
* or CLOSED (a coloured square), by `node_mode` and the nodes
|
|
55578
|
+
* toggled against it.
|
|
55579
|
+
*
|
|
55580
|
+
* Both answer {type, style} WITHOUT x/y, which belong to the node
|
|
55581
|
+
* and not to its shape, and a node moves between the two on the
|
|
55582
|
+
* fly: G6 rebuilds the element when `type` changes, and the
|
|
55583
|
+
* style is MERGED, which is why each shape also writes the keys
|
|
55584
|
+
* the other one would leave behind (`labelText`, `ports`).
|
|
55585
|
+
************************************************************/
|
|
55586
|
+
function node_shape_of(gobj, node_id, desc, record, geometry, pills_html) {
|
|
55587
|
+
if (node_is_compact(gobj, node_id)) return compact_shape_of(gobj, desc, record, {});
|
|
55588
|
+
return card_shape_of(gobj, desc, record, geometry, pills_html);
|
|
55589
|
+
}
|
|
55590
|
+
function node_is_compact(gobj, node_id) {
|
|
55591
|
+
let priv = gobj.priv;
|
|
55592
|
+
if (!priv._open_nodes) priv._open_nodes = /* @__PURE__ */ new Set();
|
|
55593
|
+
let compact = gobj_read_str_attr(gobj, "node_mode") === "compact";
|
|
55594
|
+
return priv._open_nodes.has(node_id) ? !compact : compact;
|
|
55595
|
+
}
|
|
55596
|
+
/************************************************************
|
|
55597
|
+
* The CARD: an html node, the tier's size, the ports, the
|
|
55598
|
+
* saved geometry on top. The flags (focus, selection, anchor)
|
|
55599
|
+
* are not painted here: repaint_cards() reads them where they
|
|
55600
|
+
* live and rebuilds the html.
|
|
55601
|
+
************************************************************/
|
|
55602
|
+
function card_shape_of(gobj, desc, record, geometry, pills_html) {
|
|
55603
|
+
let priv = gobj.priv;
|
|
55537
55604
|
let node_treedb_type = desc.node_treedb_type;
|
|
55605
|
+
let label = node_label(desc, record);
|
|
55606
|
+
let ports = build_ports(gobj, desc);
|
|
55538
55607
|
let style = {
|
|
55539
|
-
x,
|
|
55540
|
-
y,
|
|
55541
55608
|
fill: desc.color,
|
|
55542
55609
|
stroke: getStrokeColor(desc.color),
|
|
55543
|
-
lineWidth: 1
|
|
55610
|
+
lineWidth: 1,
|
|
55611
|
+
lineDash: [],
|
|
55612
|
+
halo: false,
|
|
55613
|
+
labelText: ""
|
|
55544
55614
|
};
|
|
55545
|
-
let pills_html = pills_html_of_key(gobj, fold_node_key(desc.topic_name, String(record.id)));
|
|
55546
55615
|
let size = card_size_for(node_treedb_type, !!pills_html);
|
|
55547
|
-
|
|
55548
|
-
|
|
55549
|
-
|
|
55550
|
-
|
|
55551
|
-
|
|
55552
|
-
|
|
55553
|
-
} else if (node_treedb_type === "extended") {
|
|
55554
|
-
node_graph_type = "html";
|
|
55555
|
-
style.size = size;
|
|
55556
|
-
style.dx = -size[0] / 2;
|
|
55557
|
-
style.dy = -size[1] / 2;
|
|
55558
|
-
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);
|
|
55559
|
-
} else {
|
|
55560
|
-
node_graph_type = "html";
|
|
55561
|
-
style.size = size;
|
|
55562
|
-
style.dx = -size[0] / 2;
|
|
55563
|
-
style.dy = -size[1] / 2;
|
|
55564
|
-
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);
|
|
55565
|
-
}
|
|
55616
|
+
style.size = size;
|
|
55617
|
+
style.dx = -size[0] / 2;
|
|
55618
|
+
style.dy = -size[1] / 2;
|
|
55619
|
+
if (node_treedb_type === "child") style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, label, record.id);
|
|
55620
|
+
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);
|
|
55621
|
+
else style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, label, desc.topic_name, false, record.id, false, false, false, pills_html);
|
|
55566
55622
|
let topic_props = priv._graph_properties[desc.topic_name];
|
|
55567
55623
|
let topic_defaults = is_object(topic_props) && is_object(topic_props.defaults) ? topic_props.defaults : null;
|
|
55568
55624
|
if (topic_defaults) {
|
|
55569
55625
|
let def_size = topic_defaults.size;
|
|
55570
55626
|
if (!geometry.size && Array.isArray(def_size) && def_size.length > 0) {
|
|
55571
55627
|
style.size = [...def_size];
|
|
55572
|
-
|
|
55573
|
-
|
|
55574
|
-
style.dy = -(def_size.length > 1 ? def_size[1] : def_size[0]) / 2;
|
|
55575
|
-
}
|
|
55628
|
+
style.dx = -def_size[0] / 2;
|
|
55629
|
+
style.dy = -(def_size.length > 1 ? def_size[1] : def_size[0]) / 2;
|
|
55576
55630
|
}
|
|
55577
55631
|
if (!geometry.portR && topic_defaults.portR > 0) style.portR = topic_defaults.portR;
|
|
55578
55632
|
}
|
|
55579
55633
|
let saved_size = geometry.size;
|
|
55580
55634
|
if (Array.isArray(saved_size) && saved_size.length > 0) {
|
|
55581
55635
|
style.size = saved_size;
|
|
55582
|
-
|
|
55583
|
-
|
|
55584
|
-
style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
|
|
55585
|
-
}
|
|
55636
|
+
style.dx = -saved_size[0] / 2;
|
|
55637
|
+
style.dy = -(saved_size.length > 1 ? saved_size[1] : saved_size[0]) / 2;
|
|
55586
55638
|
}
|
|
55587
55639
|
if (geometry.portR > 0) style.portR = geometry.portR;
|
|
55588
|
-
let node_def = {
|
|
55589
|
-
id: node_name,
|
|
55590
|
-
type: node_graph_type,
|
|
55591
|
-
style,
|
|
55592
|
-
data: {
|
|
55593
|
-
topic_name: desc.topic_name,
|
|
55594
|
-
desc,
|
|
55595
|
-
record,
|
|
55596
|
-
graph_props: geometry
|
|
55597
|
-
}
|
|
55598
|
-
};
|
|
55599
55640
|
if (json_size(ports)) {
|
|
55600
55641
|
json_object_update_missing(style, {
|
|
55601
55642
|
port: true,
|
|
55602
55643
|
ports,
|
|
55603
|
-
portR: node_treedb_type === "child" ?
|
|
55604
|
-
portLineWidth:
|
|
55644
|
+
portR: node_treedb_type === "child" ? PORT_R_CHILD : PORT_R_ENTITY,
|
|
55645
|
+
portLineWidth: PORT_LINE_WIDTH
|
|
55605
55646
|
});
|
|
55606
55647
|
let port_sizes = geometry.port_sizes;
|
|
55607
55648
|
let default_port_sizes = topic_defaults ? topic_defaults.port_sizes : null;
|
|
@@ -55611,8 +55652,117 @@ function create_topic_node(gobj, desc, record) {
|
|
|
55611
55652
|
if (r == null && is_object(default_port_sizes)) r = default_port_sizes[key];
|
|
55612
55653
|
if (r != null) style.ports[i].r = r;
|
|
55613
55654
|
}
|
|
55655
|
+
} else {
|
|
55656
|
+
style.port = false;
|
|
55657
|
+
style.ports = [];
|
|
55658
|
+
}
|
|
55659
|
+
return {
|
|
55660
|
+
type: "html",
|
|
55661
|
+
style
|
|
55662
|
+
};
|
|
55663
|
+
}
|
|
55664
|
+
/************************************************************
|
|
55665
|
+
* The SQUARE: a G6 `rect` of the topic's colour, no ports, the
|
|
55666
|
+
* name as a label under it when `node_labels` says so. A native
|
|
55667
|
+
* shape and not html on purpose: G6's own stroke and halo paint
|
|
55668
|
+
* on it, so the focus, the selection and the anchor are three
|
|
55669
|
+
* keys of the style instead of a rebuilt innerHTML.
|
|
55670
|
+
*
|
|
55671
|
+
* flags {highlight, selected, anchored}
|
|
55672
|
+
************************************************************/
|
|
55673
|
+
function compact_shape_of(gobj, desc, record, flags) {
|
|
55674
|
+
let dark = gobj.priv.theme === "dark";
|
|
55675
|
+
let f = flags || {};
|
|
55676
|
+
let tier = desc.node_treedb_type;
|
|
55677
|
+
let side = COMPACT_SIZE[tier] || COMPACT_SIZE.hierarchical;
|
|
55678
|
+
let labels = gobj_read_bool_attr(gobj, "node_labels");
|
|
55679
|
+
let stroke = getStrokeColor(desc.color);
|
|
55680
|
+
let line_width = 1.5;
|
|
55681
|
+
if (f.selected) {
|
|
55682
|
+
stroke = SELECT_RING;
|
|
55683
|
+
line_width = 3;
|
|
55684
|
+
}
|
|
55685
|
+
if (f.highlight) {
|
|
55686
|
+
stroke = HIGHLIGHT_COLOR;
|
|
55687
|
+
line_width = 3;
|
|
55688
|
+
}
|
|
55689
|
+
let dash = [];
|
|
55690
|
+
if (tier === "extended") dash = [4, 3];
|
|
55691
|
+
if (f.anchored) {
|
|
55692
|
+
dash = [2, 2];
|
|
55693
|
+
line_width = Math.max(line_width, 2.5);
|
|
55694
|
+
}
|
|
55695
|
+
return {
|
|
55696
|
+
type: "rect",
|
|
55697
|
+
style: {
|
|
55698
|
+
size: [side, side],
|
|
55699
|
+
radius: Math.round(side / 5),
|
|
55700
|
+
fill: desc.color,
|
|
55701
|
+
stroke,
|
|
55702
|
+
lineWidth: line_width,
|
|
55703
|
+
lineDash: dash,
|
|
55704
|
+
halo: !!f.highlight,
|
|
55705
|
+
haloStroke: HIGHLIGHT_HALO,
|
|
55706
|
+
haloLineWidth: 8,
|
|
55707
|
+
port: false,
|
|
55708
|
+
ports: [],
|
|
55709
|
+
labelText: labels ? node_label(desc, record) : "",
|
|
55710
|
+
labelPlacement: "bottom",
|
|
55711
|
+
labelFontSize: 11,
|
|
55712
|
+
labelFill: dark ? "#e6e9ef" : "#2e333d",
|
|
55713
|
+
labelMaxWidth: 150,
|
|
55714
|
+
labelWordWrap: true,
|
|
55715
|
+
labelMaxLines: 1,
|
|
55716
|
+
labelTextOverflow: "ellipsis",
|
|
55717
|
+
labelBackground: true,
|
|
55718
|
+
labelBackgroundFill: dark ? "#1b2230" : "#ffffff",
|
|
55719
|
+
labelBackgroundOpacity: .85,
|
|
55720
|
+
labelBackgroundRadius: 3,
|
|
55721
|
+
labelPadding: [1, 3]
|
|
55722
|
+
}
|
|
55723
|
+
};
|
|
55724
|
+
}
|
|
55725
|
+
/************************************************************
|
|
55726
|
+
* Give these record nodes the shape their mode says, then
|
|
55727
|
+
* repaint them with the flags they carry. A `+N` chip is not a
|
|
55728
|
+
* record and keeps its own shape.
|
|
55729
|
+
************************************************************/
|
|
55730
|
+
function reshape_nodes(gobj, ids) {
|
|
55731
|
+
let graph = gobj.priv.graph;
|
|
55732
|
+
if (!graph) return;
|
|
55733
|
+
let updates = [];
|
|
55734
|
+
let touched = /* @__PURE__ */ new Set();
|
|
55735
|
+
for (let id of ids) {
|
|
55736
|
+
let nd;
|
|
55737
|
+
try {
|
|
55738
|
+
nd = graph.getNodeData(id);
|
|
55739
|
+
} catch (e) {
|
|
55740
|
+
continue;
|
|
55741
|
+
}
|
|
55742
|
+
if (!nd || !nd.data || !nd.data.desc || is_more_node(nd)) continue;
|
|
55743
|
+
let geometry = nd.data.graph_props || {};
|
|
55744
|
+
let shape = node_shape_of(gobj, id, nd.data.desc, nd.data.record || {}, geometry, pills_html_of(gobj, nd));
|
|
55745
|
+
updates.push({
|
|
55746
|
+
id,
|
|
55747
|
+
type: shape.type,
|
|
55748
|
+
style: shape.style
|
|
55749
|
+
});
|
|
55750
|
+
touched.add(id);
|
|
55751
|
+
}
|
|
55752
|
+
if (!updates.length) return;
|
|
55753
|
+
try {
|
|
55754
|
+
graph.updateNodeData(updates);
|
|
55755
|
+
} catch (e) {
|
|
55756
|
+
log_error(`${gobj_short_name(gobj)}: cannot reshape the nodes: ${e}`);
|
|
55757
|
+
return;
|
|
55614
55758
|
}
|
|
55615
|
-
|
|
55759
|
+
repaint_cards(gobj, touched);
|
|
55760
|
+
}
|
|
55761
|
+
function all_record_node_ids(gobj) {
|
|
55762
|
+
let graph = gobj.priv.graph;
|
|
55763
|
+
let ids = [];
|
|
55764
|
+
for (let nd of graph && graph.getNodeData() || []) if (nd && nd.data && nd.data.desc && !is_more_node(nd)) ids.push(nd.id);
|
|
55765
|
+
return ids;
|
|
55616
55766
|
}
|
|
55617
55767
|
/************************************************************
|
|
55618
55768
|
* Update topic node data
|
|
@@ -56459,7 +56609,7 @@ var ManualLayout = class extends BaseLayout {
|
|
|
56459
56609
|
}
|
|
56460
56610
|
};
|
|
56461
56611
|
/************************************************************
|
|
56462
|
-
* Custom G6 layouts: TreedbTreeLayout /
|
|
56612
|
+
* Custom G6 layouts: TreedbTreeLayout / TreedbRadialLayout.
|
|
56463
56613
|
*
|
|
56464
56614
|
* Thin adapters over treedb_layout.js: the nodes with their sizes,
|
|
56465
56615
|
* the edges with the RANK of the hook they leave by (the position
|
|
@@ -56477,7 +56627,8 @@ function treedb_layout_input(data) {
|
|
|
56477
56627
|
let w = is_array(size) ? size[0] : size;
|
|
56478
56628
|
let h = is_array(size) ? size.length > 1 ? size[1] : size[0] : size;
|
|
56479
56629
|
let ports = node.style && is_array(node.style.ports) ? node.style.ports : [];
|
|
56480
|
-
|
|
56630
|
+
let keys = node.data && is_array(node.data.port_keys) ? node.data.port_keys : ports.map((p) => p.key);
|
|
56631
|
+
ports_of.set(node.id, keys);
|
|
56481
56632
|
return {
|
|
56482
56633
|
id: node.id,
|
|
56483
56634
|
w,
|
|
@@ -56513,12 +56664,6 @@ var TreedbTreeLayout = class extends BaseLayout {
|
|
|
56513
56664
|
return treedb_layout_output(layout_tree(input.nodes, input.edges, options));
|
|
56514
56665
|
}
|
|
56515
56666
|
};
|
|
56516
|
-
var TreedbOutlineLayout = class extends BaseLayout {
|
|
56517
|
-
async execute(data, options) {
|
|
56518
|
-
let input = treedb_layout_input(data);
|
|
56519
|
-
return treedb_layout_output(layout_outline(input.nodes, input.edges, options));
|
|
56520
|
-
}
|
|
56521
|
-
};
|
|
56522
56667
|
var TreedbRadialLayout = class extends BaseLayout {
|
|
56523
56668
|
async execute(data, options) {
|
|
56524
56669
|
let input = treedb_layout_input(data);
|
|
@@ -57210,7 +57355,7 @@ function get_port_radius(gobj, node_id, port_key) {
|
|
|
57210
57355
|
if (ports[i].r != null) return ports[i].r;
|
|
57211
57356
|
break;
|
|
57212
57357
|
}
|
|
57213
|
-
return style.portR ||
|
|
57358
|
+
return style.portR || PORT_R_ENTITY;
|
|
57214
57359
|
}
|
|
57215
57360
|
/************************************************************
|
|
57216
57361
|
* How much wider than the port itself its hit area is,
|
|
@@ -57242,7 +57387,7 @@ function detect_port_click(gobj, node_id, canvasX, canvasY) {
|
|
|
57242
57387
|
const style = graph.getNodeData(node_id).style || {};
|
|
57243
57388
|
const { w, h } = extract_size(style);
|
|
57244
57389
|
const ports = style.ports || [];
|
|
57245
|
-
const defaultR = style.portR ||
|
|
57390
|
+
const defaultR = style.portR || PORT_R_ENTITY;
|
|
57246
57391
|
let best_key = null;
|
|
57247
57392
|
let best_dist = Infinity;
|
|
57248
57393
|
let slop = port_hit_slop_world(graph);
|
|
@@ -57399,7 +57544,7 @@ function enter_linking_mode(gobj) {
|
|
|
57399
57544
|
p.stroke = "#52c41a";
|
|
57400
57545
|
p.lineWidth = 3;
|
|
57401
57546
|
if (p.r != null) p.r = p.r + 4;
|
|
57402
|
-
else p.r = (style.portR ||
|
|
57547
|
+
else p.r = (style.portR || PORT_R_ENTITY) + 4;
|
|
57403
57548
|
}
|
|
57404
57549
|
graph.updateNodeData([{
|
|
57405
57550
|
id: vh.node_id,
|
|
@@ -57551,7 +57696,7 @@ function find_hook_at_point(gobj, canvasX, canvasY) {
|
|
|
57551
57696
|
let pl = p.placement || [.5, .5];
|
|
57552
57697
|
let px = pos[0] + (pl[0] - .5) * w;
|
|
57553
57698
|
let py = pos[1] + (pl[1] - .5) * h;
|
|
57554
|
-
let r = p.r != null ? p.r : style.portR ||
|
|
57699
|
+
let r = p.r != null ? p.r : style.portR || PORT_R_ENTITY;
|
|
57555
57700
|
let dx = canvasX - px;
|
|
57556
57701
|
let dy = canvasY - py;
|
|
57557
57702
|
if (Math.sqrt(dx * dx + dy * dy) <= r + 6) return {
|
|
@@ -58309,7 +58454,19 @@ function repaint_cards(gobj, ids) {
|
|
|
58309
58454
|
} catch (e) {
|
|
58310
58455
|
continue;
|
|
58311
58456
|
}
|
|
58312
|
-
let
|
|
58457
|
+
let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
|
|
58458
|
+
if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
|
|
58459
|
+
updates.push({
|
|
58460
|
+
id,
|
|
58461
|
+
style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
|
|
58462
|
+
highlight: focus.has(id),
|
|
58463
|
+
selected: selected.has(id),
|
|
58464
|
+
anchored
|
|
58465
|
+
}).style
|
|
58466
|
+
});
|
|
58467
|
+
continue;
|
|
58468
|
+
}
|
|
58469
|
+
let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
|
|
58313
58470
|
if (html !== null) updates.push({
|
|
58314
58471
|
id,
|
|
58315
58472
|
style: { innerHTML: html }
|
|
@@ -58346,7 +58503,19 @@ function refresh_html_nodes_theme(gobj, theme) {
|
|
|
58346
58503
|
for (let i = 0; i < nodes.length; i++) {
|
|
58347
58504
|
let id = nodes[i].id;
|
|
58348
58505
|
let nd = graph.getNodeData(id);
|
|
58349
|
-
let
|
|
58506
|
+
let anchored = priv.anchor_state === "on" && id === priv.anchor_id;
|
|
58507
|
+
if (nd && nd.data && nd.data.desc && node_is_compact(gobj, id)) {
|
|
58508
|
+
updates.push({
|
|
58509
|
+
id,
|
|
58510
|
+
style: compact_shape_of(gobj, nd.data.desc, nd.data.record || {}, {
|
|
58511
|
+
highlight: highlighted.has(id),
|
|
58512
|
+
selected: selected.has(id),
|
|
58513
|
+
anchored
|
|
58514
|
+
}).style
|
|
58515
|
+
});
|
|
58516
|
+
continue;
|
|
58517
|
+
}
|
|
58518
|
+
let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), anchored, pills_html_of(gobj, nd));
|
|
58350
58519
|
if (html === null) html = more_innerHTML_of(gobj, nd, theme);
|
|
58351
58520
|
if (html !== null) updates.push({
|
|
58352
58521
|
id,
|
|
@@ -58966,8 +59135,10 @@ function ctx_item(icon_id, label, value) {
|
|
|
58966
59135
|
************************************************************/
|
|
58967
59136
|
function build_node_context_menu(gobj, node_id) {
|
|
58968
59137
|
let items = [];
|
|
58969
|
-
|
|
58970
|
-
|
|
59138
|
+
inject_svg_icons();
|
|
59139
|
+
if (node_is_compact(gobj, node_id)) items.push(ctx_item("g6-icon-fullscreen", t("open node"), "toggle_node_mode"));
|
|
59140
|
+
else items.push(ctx_item("g6-icon-fullscreen-exit", t("close node"), "toggle_node_mode"));
|
|
59141
|
+
if (gobj.priv.edit_mode && !node_is_compact(gobj, node_id)) {
|
|
58971
59142
|
items.push(ctx_item("g6-icon-resize", t("resize all"), "resize_all_nodes"));
|
|
58972
59143
|
items.push(ctx_item("g6-icon-resize", t("resize topic nodes"), "resize_topic_nodes"));
|
|
58973
59144
|
}
|
|
@@ -58995,8 +59166,11 @@ function build_edge_context_menu(gobj) {
|
|
|
58995
59166
|
* Handle context menu click: dispatch by value.
|
|
58996
59167
|
************************************************************/
|
|
58997
59168
|
function handle_context_menu_click(gobj, value) {
|
|
58998
|
-
gobj.priv;
|
|
59169
|
+
let priv = gobj.priv;
|
|
58999
59170
|
switch (value) {
|
|
59171
|
+
case "toggle_node_mode":
|
|
59172
|
+
if (priv._context_node_id) gobj_send_event(gobj, "EV_TOGGLE_NODE_MODE", { id: priv._context_node_id }, gobj);
|
|
59173
|
+
break;
|
|
59000
59174
|
case "resize_all_nodes":
|
|
59001
59175
|
copy_size_to_nodes(gobj, false);
|
|
59002
59176
|
break;
|
|
@@ -59527,7 +59701,7 @@ async function reconcile_fold_apply(gobj, opts, visible) {
|
|
|
59527
59701
|
let nd = graph.getNodeData(id);
|
|
59528
59702
|
let desc = nd && nd.data && nd.data.desc;
|
|
59529
59703
|
let geometry = nd && nd.data && nd.data.graph_props || {};
|
|
59530
|
-
if (desc && !is_array(geometry.size)) {
|
|
59704
|
+
if (desc && !is_array(geometry.size) && !node_is_compact(gobj, id)) {
|
|
59531
59705
|
let size = card_size_for(desc.node_treedb_type, !!sig);
|
|
59532
59706
|
resize.push({
|
|
59533
59707
|
id,
|
|
@@ -59612,6 +59786,7 @@ function ac_clear_data(gobj, event, kw, src) {
|
|
|
59612
59786
|
priv._fold_model = null;
|
|
59613
59787
|
priv._fold_state = null;
|
|
59614
59788
|
priv._pill_sig = null;
|
|
59789
|
+
priv._open_nodes = null;
|
|
59615
59790
|
graph_remove_plugin(gobj, "history");
|
|
59616
59791
|
update_history_buttons(gobj);
|
|
59617
59792
|
graph_clear(gobj);
|
|
@@ -60110,6 +60285,79 @@ function ac_set_loose_topics(gobj, event, kw, src) {
|
|
|
60110
60285
|
return 0;
|
|
60111
60286
|
}
|
|
60112
60287
|
/************************************************************
|
|
60288
|
+
* The shape of every record: open cards or closed squares.
|
|
60289
|
+
* A change of mode forgets the nodes toggled against the old
|
|
60290
|
+
* one -- they were exceptions to a rule that no longer holds --
|
|
60291
|
+
* and lays the graph out again, because a square and a card
|
|
60292
|
+
* do not occupy the same room.
|
|
60293
|
+
************************************************************/
|
|
60294
|
+
function ac_set_node_mode(gobj, event, kw, src) {
|
|
60295
|
+
let priv = gobj.priv;
|
|
60296
|
+
let mode = kw && kw.node_mode === "compact" ? "compact" : "expanded";
|
|
60297
|
+
gobj_write_str_attr(gobj, "node_mode", mode);
|
|
60298
|
+
priv._open_nodes = /* @__PURE__ */ new Set();
|
|
60299
|
+
if (!priv.graph || !priv._fold_model) return 0;
|
|
60300
|
+
reshape_nodes(gobj, all_record_node_ids(gobj));
|
|
60301
|
+
reconcile_fold(gobj, {
|
|
60302
|
+
relayout: true,
|
|
60303
|
+
fit: true
|
|
60304
|
+
});
|
|
60305
|
+
return 0;
|
|
60306
|
+
}
|
|
60307
|
+
/************************************************************
|
|
60308
|
+
* The name under a closed square, on or off. Only the closed
|
|
60309
|
+
* nodes change, and nothing moves: the label hangs outside the
|
|
60310
|
+
* square and the layout measures the square.
|
|
60311
|
+
************************************************************/
|
|
60312
|
+
function ac_set_node_labels(gobj, event, kw, src) {
|
|
60313
|
+
let priv = gobj.priv;
|
|
60314
|
+
gobj_write_bool_attr(gobj, "node_labels", !!(kw && kw.node_labels));
|
|
60315
|
+
if (!priv.graph) return 0;
|
|
60316
|
+
reshape_nodes(gobj, all_record_node_ids(gobj).filter((id) => node_is_compact(gobj, id)));
|
|
60317
|
+
return 0;
|
|
60318
|
+
}
|
|
60319
|
+
/************************************************************
|
|
60320
|
+
* ONE node opened or closed against the mode (a double click,
|
|
60321
|
+
* or the context menu). It holds still on screen while the
|
|
60322
|
+
* rest of the graph makes room, as a fold does.
|
|
60323
|
+
************************************************************/
|
|
60324
|
+
function ac_toggle_node_mode$1(gobj, event, kw, src) {
|
|
60325
|
+
let priv = gobj.priv;
|
|
60326
|
+
let node_id = kw && kw.id || "";
|
|
60327
|
+
if (!priv.graph || !node_id) {
|
|
60328
|
+
log_error(`${gobj_short_name(gobj)}: toggle node mode without a node`);
|
|
60329
|
+
return -1;
|
|
60330
|
+
}
|
|
60331
|
+
if (!priv._open_nodes) priv._open_nodes = /* @__PURE__ */ new Set();
|
|
60332
|
+
if (priv._open_nodes.has(node_id)) priv._open_nodes.delete(node_id);
|
|
60333
|
+
else priv._open_nodes.add(node_id);
|
|
60334
|
+
let vp = yui_graph_viewport_of(priv.graph, node_id);
|
|
60335
|
+
reshape_nodes(gobj, [node_id]);
|
|
60336
|
+
if (priv._fold_model) reconcile_fold(gobj, {
|
|
60337
|
+
relayout: true,
|
|
60338
|
+
keep: node_id,
|
|
60339
|
+
keep_vp: vp
|
|
60340
|
+
});
|
|
60341
|
+
return 0;
|
|
60342
|
+
}
|
|
60343
|
+
/************************************************************
|
|
60344
|
+
* A double click on a node: open it if closed, close it if open.
|
|
60345
|
+
* A `+N` chip is not a record and has no shape to toggle.
|
|
60346
|
+
************************************************************/
|
|
60347
|
+
function ac_node_dblclick(gobj, event, kw, src) {
|
|
60348
|
+
let priv = gobj.priv;
|
|
60349
|
+
let node_id = kw && kw.evt && kw.evt.target ? kw.evt.target.id : "";
|
|
60350
|
+
let nd = null;
|
|
60351
|
+
try {
|
|
60352
|
+
nd = priv.graph.getNodeData(node_id);
|
|
60353
|
+
} catch (e) {
|
|
60354
|
+
nd = null;
|
|
60355
|
+
}
|
|
60356
|
+
if (!nd || !nd.data || !nd.data.desc || is_more_node(nd)) return 0;
|
|
60357
|
+
gobj_send_event(gobj, "EV_TOGGLE_NODE_MODE", { id: node_id }, gobj);
|
|
60358
|
+
return 0;
|
|
60359
|
+
}
|
|
60360
|
+
/************************************************************
|
|
60113
60361
|
* Tell whoever asked how many nodes the term matched. The count is
|
|
60114
60362
|
* the answer to the question the box asks; without it "nothing moved"
|
|
60115
60363
|
* and "nothing matched" look the same.
|
|
@@ -60599,6 +60847,26 @@ function create_gclass$4(gclass_name) {
|
|
|
60599
60847
|
ac_set_loose_topics,
|
|
60600
60848
|
null
|
|
60601
60849
|
],
|
|
60850
|
+
[
|
|
60851
|
+
"EV_SET_NODE_MODE",
|
|
60852
|
+
ac_set_node_mode,
|
|
60853
|
+
null
|
|
60854
|
+
],
|
|
60855
|
+
[
|
|
60856
|
+
"EV_SET_NODE_LABELS",
|
|
60857
|
+
ac_set_node_labels,
|
|
60858
|
+
null
|
|
60859
|
+
],
|
|
60860
|
+
[
|
|
60861
|
+
"EV_TOGGLE_NODE_MODE",
|
|
60862
|
+
ac_toggle_node_mode$1,
|
|
60863
|
+
null
|
|
60864
|
+
],
|
|
60865
|
+
[
|
|
60866
|
+
"EV_NODE_DBLCLICK",
|
|
60867
|
+
ac_node_dblclick,
|
|
60868
|
+
null
|
|
60869
|
+
],
|
|
60602
60870
|
[
|
|
60603
60871
|
"EV_CENTER",
|
|
60604
60872
|
ac_center,
|
|
@@ -60703,6 +60971,10 @@ function create_gclass$4(gclass_name) {
|
|
|
60703
60971
|
["EV_SET_HIDDEN_TOPICS", 0],
|
|
60704
60972
|
["EV_SET_MAIN_TOPIC", 0],
|
|
60705
60973
|
["EV_SET_LOOSE_TOPICS", 0],
|
|
60974
|
+
["EV_SET_NODE_MODE", 0],
|
|
60975
|
+
["EV_SET_NODE_LABELS", 0],
|
|
60976
|
+
["EV_TOGGLE_NODE_MODE", 0],
|
|
60977
|
+
["EV_NODE_DBLCLICK", 0],
|
|
60706
60978
|
["EV_LEGEND_STATE", event_flag_t.EVF_OUTPUT_EVENT],
|
|
60707
60979
|
["EV_CENTER", 0],
|
|
60708
60980
|
["EV_FULLSCREEN", 0],
|
|
@@ -60768,6 +61040,8 @@ var attrs_table$3 = [
|
|
|
60768
61040
|
SDATA(data_type_t.DTP_LIST, "hidden_topics", sdata_flag_t.SDF_PERSIST, "[]", "Topics hidden from the graph (legend). User preference, per treedb"),
|
|
60769
61041
|
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"),
|
|
60770
61042
|
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"),
|
|
61043
|
+
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"),
|
|
61044
|
+
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"),
|
|
60771
61045
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
|
|
60772
61046
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
|
|
60773
61047
|
SDATA(data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
|
|
@@ -60845,7 +61119,9 @@ function mt_create$3(gobj) {
|
|
|
60845
61119
|
fold_page_size: gobj_read_integer_attr(gobj, "fold_page_size"),
|
|
60846
61120
|
hidden_topics: gobj_read_attr(gobj, "hidden_topics") || [],
|
|
60847
61121
|
main_topic: gobj_read_str_attr(gobj, "main_topic") || "",
|
|
60848
|
-
loose_topics: gobj_read_attr(gobj, "loose_topics") || []
|
|
61122
|
+
loose_topics: gobj_read_attr(gobj, "loose_topics") || [],
|
|
61123
|
+
node_mode: gobj_read_str_attr(gobj, "node_mode") || "expanded",
|
|
61124
|
+
node_labels: gobj_read_bool_attr(gobj, "node_labels")
|
|
60849
61125
|
}, gobj);
|
|
60850
61126
|
populate_nodes_tree_options(gobj);
|
|
60851
61127
|
if (priv.with_treedb_tables) {}
|
|
@@ -60896,6 +61172,7 @@ function build_ui$3(gobj) {
|
|
|
60896
61172
|
let priv = gobj.priv;
|
|
60897
61173
|
let padding = gobj_read_attr(gobj, "padding");
|
|
60898
61174
|
let $toolbar = make_toolbar(gobj);
|
|
61175
|
+
refresh_node_shape_buttons(gobj, $toolbar);
|
|
60899
61176
|
let $back = make_back_to_topics(gobj);
|
|
60900
61177
|
let $container = createElement2([
|
|
60901
61178
|
"div",
|
|
@@ -61037,6 +61314,57 @@ function option_label(name) {
|
|
|
61037
61314
|
/************************************************************
|
|
61038
61315
|
*
|
|
61039
61316
|
************************************************************/
|
|
61317
|
+
/************************************************************
|
|
61318
|
+
* The two toggles of the nodes' shape.
|
|
61319
|
+
*
|
|
61320
|
+
* Closed nodes: every record a rounded square of its topic's
|
|
61321
|
+
* colour, no ports, no text -- the topology of a graph of many
|
|
61322
|
+
* nodes, which the cards hide behind their own size. Labels:
|
|
61323
|
+
* the name under each square, when the squares alone do not say
|
|
61324
|
+
* enough. Both persist, both are forwarded to the G6 child, and
|
|
61325
|
+
* one node can be opened against the rule with a double click or
|
|
61326
|
+
* its context menu (the child's business).
|
|
61327
|
+
************************************************************/
|
|
61328
|
+
function node_shape_items(gobj, wide) {
|
|
61329
|
+
let toggle = (cls, icon, event_name, label_key) => {
|
|
61330
|
+
return [
|
|
61331
|
+
"button",
|
|
61332
|
+
{
|
|
61333
|
+
class: `${cls} button`,
|
|
61334
|
+
type: "button",
|
|
61335
|
+
style: {
|
|
61336
|
+
height: wide,
|
|
61337
|
+
width: "2.5em"
|
|
61338
|
+
},
|
|
61339
|
+
title: t(label_key),
|
|
61340
|
+
"data-i18n-title": label_key,
|
|
61341
|
+
"aria-label": t(label_key),
|
|
61342
|
+
"data-i18n-aria-label": label_key,
|
|
61343
|
+
"aria-pressed": "false"
|
|
61344
|
+
},
|
|
61345
|
+
["i", {
|
|
61346
|
+
style: "font-size:1.5em; color:inherit;",
|
|
61347
|
+
class: icon
|
|
61348
|
+
}],
|
|
61349
|
+
{ click: (evt) => {
|
|
61350
|
+
evt.stopPropagation();
|
|
61351
|
+
gobj_send_event(gobj, event_name, {}, gobj);
|
|
61352
|
+
} }
|
|
61353
|
+
];
|
|
61354
|
+
};
|
|
61355
|
+
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")];
|
|
61356
|
+
}
|
|
61357
|
+
function refresh_node_shape_buttons(gobj, $root) {
|
|
61358
|
+
if (!$root) return;
|
|
61359
|
+
let compact = gobj_read_str_attr(gobj, "node_mode") === "compact";
|
|
61360
|
+
let labels = gobj_read_bool_attr(gobj, "node_labels");
|
|
61361
|
+
set_pressed_state($root, ".GRAPH_NODE_MODE", compact);
|
|
61362
|
+
set_pressed_state($root, ".GRAPH_NODE_LABELS", labels);
|
|
61363
|
+
let $mode = $root.querySelector(".GRAPH_NODE_MODE");
|
|
61364
|
+
if ($mode) $mode.setAttribute("aria-pressed", compact ? "true" : "false");
|
|
61365
|
+
let $labels = $root.querySelector(".GRAPH_NODE_LABELS");
|
|
61366
|
+
if ($labels) $labels.setAttribute("aria-pressed", labels ? "true" : "false");
|
|
61367
|
+
}
|
|
61040
61368
|
function make_toolbar(gobj) {
|
|
61041
61369
|
let priv = gobj.priv;
|
|
61042
61370
|
let modes = gobj_read_attr(gobj, "operation_modes");
|
|
@@ -61107,6 +61435,7 @@ function make_toolbar(gobj) {
|
|
|
61107
61435
|
} }
|
|
61108
61436
|
],
|
|
61109
61437
|
...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
61438
|
+
...node_shape_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
61110
61439
|
[
|
|
61111
61440
|
"button",
|
|
61112
61441
|
{
|
|
@@ -62170,9 +62499,9 @@ function refresh_legend(gobj) {
|
|
|
62170
62499
|
hidden ? `${entry.total}` : `${entry.visible}/${entry.total}`
|
|
62171
62500
|
]);
|
|
62172
62501
|
let body_attrs = {
|
|
62173
|
-
class: "GRAPH_LEGEND_ITEM button is-small" + (focused ? "
|
|
62502
|
+
class: "GRAPH_LEGEND_ITEM button is-small" + (focused ? " GRAPH_LEGEND_FOCUSED" : "") + (is_main ? " GRAPH_LEGEND_MAIN" : ""),
|
|
62174
62503
|
type: "button",
|
|
62175
|
-
style: "gap:0; flex:0 0 auto;",
|
|
62504
|
+
style: "gap:0; flex:0 0 auto;" + (focused ? " box-shadow: inset 0 0 0 2px var(--bulma-text, #2e333d);" : ""),
|
|
62176
62505
|
title: is_main ? t("main topic") : hidden ? t("show topic") : t("hide topic"),
|
|
62177
62506
|
"aria-label": topic_name,
|
|
62178
62507
|
"aria-pressed": hidden ? "false" : "true"
|
|
@@ -62421,6 +62750,29 @@ function ac_collapse_all(gobj, event, kw, src) {
|
|
|
62421
62750
|
return 0;
|
|
62422
62751
|
}
|
|
62423
62752
|
/************************************************************
|
|
62753
|
+
* The shape pair of the toolbar: the attr flips, persists,
|
|
62754
|
+
* shows on the button, and reaches the G6 child, which owns
|
|
62755
|
+
* the nodes.
|
|
62756
|
+
************************************************************/
|
|
62757
|
+
function ac_toggle_node_mode(gobj, event, kw, src) {
|
|
62758
|
+
let priv = gobj.priv;
|
|
62759
|
+
let mode = gobj_read_str_attr(gobj, "node_mode") === "compact" ? "expanded" : "compact";
|
|
62760
|
+
gobj_write_str_attr(gobj, "node_mode", mode);
|
|
62761
|
+
gobj_save_persistent_attrs(gobj, "node_mode");
|
|
62762
|
+
refresh_node_shape_buttons(gobj, priv.$container);
|
|
62763
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_SET_NODE_MODE", { node_mode: mode }, gobj);
|
|
62764
|
+
return 0;
|
|
62765
|
+
}
|
|
62766
|
+
function ac_toggle_node_labels(gobj, event, kw, src) {
|
|
62767
|
+
let priv = gobj.priv;
|
|
62768
|
+
let labels = !gobj_read_bool_attr(gobj, "node_labels");
|
|
62769
|
+
gobj_write_bool_attr(gobj, "node_labels", labels);
|
|
62770
|
+
gobj_save_persistent_attrs(gobj, "node_labels");
|
|
62771
|
+
refresh_node_shape_buttons(gobj, priv.$container);
|
|
62772
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_SET_NODE_LABELS", { node_labels: labels }, gobj);
|
|
62773
|
+
return 0;
|
|
62774
|
+
}
|
|
62775
|
+
/************************************************************
|
|
62424
62776
|
* How many nodes the term matched, from the graph child. Zero with a
|
|
62425
62777
|
* term typed is an ANSWER and is shown; an empty box shows nothing.
|
|
62426
62778
|
************************************************************/
|
|
@@ -62634,6 +62986,16 @@ function create_gclass$3(gclass_name) {
|
|
|
62634
62986
|
ac_collapse_all,
|
|
62635
62987
|
null
|
|
62636
62988
|
],
|
|
62989
|
+
[
|
|
62990
|
+
"EV_TOGGLE_NODE_MODE",
|
|
62991
|
+
ac_toggle_node_mode,
|
|
62992
|
+
null
|
|
62993
|
+
],
|
|
62994
|
+
[
|
|
62995
|
+
"EV_TOGGLE_NODE_LABELS",
|
|
62996
|
+
ac_toggle_node_labels,
|
|
62997
|
+
null
|
|
62998
|
+
],
|
|
62637
62999
|
[
|
|
62638
63000
|
"EV_LAYOUT_AUTOSET",
|
|
62639
63001
|
ac_layout_autoset,
|
|
@@ -62698,6 +63060,8 @@ function create_gclass$3(gclass_name) {
|
|
|
62698
63060
|
["EV_FIND_NODES", 0],
|
|
62699
63061
|
["EV_EXPAND_ALL", 0],
|
|
62700
63062
|
["EV_COLLAPSE_ALL", 0],
|
|
63063
|
+
["EV_TOGGLE_NODE_MODE", 0],
|
|
63064
|
+
["EV_TOGGLE_NODE_LABELS", 0],
|
|
62701
63065
|
["EV_FIND_RESULT", 0],
|
|
62702
63066
|
["EV_LAYOUT_AUTOSET", 0],
|
|
62703
63067
|
["EV_LEGEND_TOPIC", 0],
|