@yuneta/gobj-ui 7.23.65 → 7.23.67
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 +58 -0
- package/dist/gobj-ui.cjs.js +1330 -186
- package/dist/gobj-ui.es.js +1330 -186
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +1193 -256
- package/src/c_yui_treedb_graph.js +45 -2
- package/src/treedb_fold_model.js +592 -0
- package/src/treedb_fold_model.test.js +308 -0
package/dist/gobj-ui.es.js
CHANGED
|
@@ -11249,7 +11249,7 @@ function ensure_drag_canvas_patch() {
|
|
|
11249
11249
|
* Constants
|
|
11250
11250
|
***************************************************************/
|
|
11251
11251
|
var GCLASS_NAME$13 = "C_YUI_JSON_GRAPH";
|
|
11252
|
-
var FOLD_SWALLOWED_EVENTS = [
|
|
11252
|
+
var FOLD_SWALLOWED_EVENTS$1 = [
|
|
11253
11253
|
"pointerdown",
|
|
11254
11254
|
"pointerup",
|
|
11255
11255
|
"mousedown",
|
|
@@ -11557,7 +11557,7 @@ function build_ui$12(gobj) {
|
|
|
11557
11557
|
keep: $card ? $card.getAttribute("data-json-path") : ""
|
|
11558
11558
|
}, gobj);
|
|
11559
11559
|
};
|
|
11560
|
-
for (let type of FOLD_SWALLOWED_EVENTS) $mount.addEventListener(type, priv.fold_listener, true);
|
|
11560
|
+
for (let type of FOLD_SWALLOWED_EVENTS$1) $mount.addEventListener(type, priv.fold_listener, true);
|
|
11561
11561
|
} else log_error(`${gobj_short_name(gobj)}: no canvas mount, fold handles are dead`);
|
|
11562
11562
|
priv.$layout_select = $container.querySelector(".JSON_GRAPH_LAYOUT");
|
|
11563
11563
|
priv.$find_input = $container.querySelector(".JSON_GRAPH_FIND_INPUT");
|
|
@@ -11573,7 +11573,7 @@ function destroy_ui$8(gobj) {
|
|
|
11573
11573
|
let $container = gobj_read_attr(gobj, "$container");
|
|
11574
11574
|
if (priv.fold_listener) {
|
|
11575
11575
|
let $mount = $container ? $container.querySelector("#" + priv.canvas_id) : null;
|
|
11576
|
-
if ($mount) for (let type of FOLD_SWALLOWED_EVENTS) $mount.removeEventListener(type, priv.fold_listener, true);
|
|
11576
|
+
if ($mount) for (let type of FOLD_SWALLOWED_EVENTS$1) $mount.removeEventListener(type, priv.fold_listener, true);
|
|
11577
11577
|
priv.fold_listener = null;
|
|
11578
11578
|
}
|
|
11579
11579
|
if ($container) {
|
|
@@ -12424,7 +12424,7 @@ function ac_change_layout$2(gobj, event, kw, src) {
|
|
|
12424
12424
|
* would throw away where the reader was looking. The toolbar
|
|
12425
12425
|
* pair, which changes everything at once, does refit.
|
|
12426
12426
|
************************************************************/
|
|
12427
|
-
function ac_toggle_fold(gobj, event, kw, src) {
|
|
12427
|
+
function ac_toggle_fold$1(gobj, event, kw, src) {
|
|
12428
12428
|
let priv = gobj.priv;
|
|
12429
12429
|
let path = kw && kw.path || "";
|
|
12430
12430
|
if (empty_string(path)) {
|
|
@@ -12463,7 +12463,7 @@ function ac_find_nodes$3(gobj, event, kw, src) {
|
|
|
12463
12463
|
/************************************************************
|
|
12464
12464
|
* EV_EXPAND_ALL
|
|
12465
12465
|
************************************************************/
|
|
12466
|
-
function ac_expand_all$
|
|
12466
|
+
function ac_expand_all$4(gobj, event, kw, src) {
|
|
12467
12467
|
let priv = gobj.priv;
|
|
12468
12468
|
if (priv.collapsed.size === 0) return 0;
|
|
12469
12469
|
priv.collapsed.clear();
|
|
@@ -12475,7 +12475,7 @@ function ac_expand_all$2(gobj, event, kw, src) {
|
|
|
12475
12475
|
/************************************************************
|
|
12476
12476
|
* EV_COLLAPSE_ALL — fold every card but the root.
|
|
12477
12477
|
************************************************************/
|
|
12478
|
-
function ac_collapse_all$
|
|
12478
|
+
function ac_collapse_all$4(gobj, event, kw, src) {
|
|
12479
12479
|
let priv = gobj.priv;
|
|
12480
12480
|
let json_data = gobj_read_attr(gobj, "json_data");
|
|
12481
12481
|
if (!json_data) return 0;
|
|
@@ -12765,7 +12765,7 @@ function create_gclass$13(gclass_name) {
|
|
|
12765
12765
|
],
|
|
12766
12766
|
[
|
|
12767
12767
|
"EV_TOGGLE_FOLD",
|
|
12768
|
-
ac_toggle_fold,
|
|
12768
|
+
ac_toggle_fold$1,
|
|
12769
12769
|
null
|
|
12770
12770
|
],
|
|
12771
12771
|
[
|
|
@@ -12775,12 +12775,12 @@ function create_gclass$13(gclass_name) {
|
|
|
12775
12775
|
],
|
|
12776
12776
|
[
|
|
12777
12777
|
"EV_EXPAND_ALL",
|
|
12778
|
-
ac_expand_all$
|
|
12778
|
+
ac_expand_all$4,
|
|
12779
12779
|
null
|
|
12780
12780
|
],
|
|
12781
12781
|
[
|
|
12782
12782
|
"EV_COLLAPSE_ALL",
|
|
12783
|
-
ac_collapse_all$
|
|
12783
|
+
ac_collapse_all$4,
|
|
12784
12784
|
null
|
|
12785
12785
|
],
|
|
12786
12786
|
[
|
|
@@ -13845,7 +13845,7 @@ function ac_search$2(gobj, event, kw, src) {
|
|
|
13845
13845
|
/************************************************************
|
|
13846
13846
|
* EV_EXPAND_ALL — expand every already-loaded container
|
|
13847
13847
|
************************************************************/
|
|
13848
|
-
function ac_expand_all$
|
|
13848
|
+
function ac_expand_all$3(gobj, event, kw, src) {
|
|
13849
13849
|
let priv = gobj.priv;
|
|
13850
13850
|
if (priv.root === null || priv.root === void 0) return 0;
|
|
13851
13851
|
let paths = [];
|
|
@@ -13863,7 +13863,7 @@ function ac_expand_all$1(gobj, event, kw, src) {
|
|
|
13863
13863
|
/************************************************************
|
|
13864
13864
|
* EV_COLLAPSE_ALL
|
|
13865
13865
|
************************************************************/
|
|
13866
|
-
function ac_collapse_all$
|
|
13866
|
+
function ac_collapse_all$3(gobj, event, kw, src) {
|
|
13867
13867
|
gobj.priv.expanded.clear();
|
|
13868
13868
|
render_view$1(gobj);
|
|
13869
13869
|
return 0;
|
|
@@ -14048,12 +14048,12 @@ function create_gclass$12(gclass_name) {
|
|
|
14048
14048
|
],
|
|
14049
14049
|
[
|
|
14050
14050
|
"EV_EXPAND_ALL",
|
|
14051
|
-
ac_expand_all$
|
|
14051
|
+
ac_expand_all$3,
|
|
14052
14052
|
null
|
|
14053
14053
|
],
|
|
14054
14054
|
[
|
|
14055
14055
|
"EV_COLLAPSE_ALL",
|
|
14056
|
-
ac_collapse_all$
|
|
14056
|
+
ac_collapse_all$3,
|
|
14057
14057
|
null
|
|
14058
14058
|
],
|
|
14059
14059
|
[
|
|
@@ -19056,7 +19056,7 @@ function ac_toggle_collapse(gobj, event, kw, src) {
|
|
|
19056
19056
|
/************************************************************
|
|
19057
19057
|
* Force every node visible (overrides threshold).
|
|
19058
19058
|
************************************************************/
|
|
19059
|
-
function ac_expand_all(gobj, event, kw, src) {
|
|
19059
|
+
function ac_expand_all$2(gobj, event, kw, src) {
|
|
19060
19060
|
let priv = gobj.priv;
|
|
19061
19061
|
if (!priv.collapse_state) priv.collapse_state = {};
|
|
19062
19062
|
if (priv.node_by_id) for (let id of Object.keys(priv.node_by_id)) {
|
|
@@ -19069,7 +19069,7 @@ function ac_expand_all(gobj, event, kw, src) {
|
|
|
19069
19069
|
/************************************************************
|
|
19070
19070
|
* Collapse every node that has children.
|
|
19071
19071
|
************************************************************/
|
|
19072
|
-
function ac_collapse_all(gobj, event, kw, src) {
|
|
19072
|
+
function ac_collapse_all$2(gobj, event, kw, src) {
|
|
19073
19073
|
let priv = gobj.priv;
|
|
19074
19074
|
if (!priv.collapse_state) priv.collapse_state = {};
|
|
19075
19075
|
if (priv.node_by_id) for (let id of Object.keys(priv.node_by_id)) {
|
|
@@ -19421,12 +19421,12 @@ function create_gclass$9(gclass_name) {
|
|
|
19421
19421
|
],
|
|
19422
19422
|
[
|
|
19423
19423
|
"EV_EXPAND_ALL",
|
|
19424
|
-
ac_expand_all,
|
|
19424
|
+
ac_expand_all$2,
|
|
19425
19425
|
null
|
|
19426
19426
|
],
|
|
19427
19427
|
[
|
|
19428
19428
|
"EV_COLLAPSE_ALL",
|
|
19429
|
-
ac_collapse_all,
|
|
19429
|
+
ac_collapse_all$2,
|
|
19430
19430
|
null
|
|
19431
19431
|
],
|
|
19432
19432
|
[
|
|
@@ -26795,6 +26795,429 @@ function node_label(desc, record) {
|
|
|
26795
26795
|
return id;
|
|
26796
26796
|
}
|
|
26797
26797
|
//#endregion
|
|
26798
|
+
//#region src/treedb_fold_model.js
|
|
26799
|
+
/***********************************************************************
|
|
26800
|
+
* treedb_fold_model.js
|
|
26801
|
+
*
|
|
26802
|
+
* A treedb read as a TREE, and which part of it is on screen.
|
|
26803
|
+
*
|
|
26804
|
+
* A treedb is a graph: a record hangs from every parent one of its
|
|
26805
|
+
* fkeys names, and a parent reaches its children through a hook.
|
|
26806
|
+
* Drawn whole it is a pile -- a nave with a hundred and forty
|
|
26807
|
+
* devices is a row of a hundred and forty cards -- so the graph
|
|
26808
|
+
* opens FOLDED, the way a JSON viewer opens: the roots, a level or
|
|
26809
|
+
* two under them, and a count on every cut saying what went with it.
|
|
26810
|
+
*
|
|
26811
|
+
* This module is the arithmetic of that, and nothing else: no G6,
|
|
26812
|
+
* no DOM, no gobj. The graph engine (c_g6_nodes_tree.js) asks it
|
|
26813
|
+
* what is visible and draws exactly that.
|
|
26814
|
+
*
|
|
26815
|
+
* Vocabulary
|
|
26816
|
+
*
|
|
26817
|
+
* node key "topic^id" -- one record
|
|
26818
|
+
* group the children of ONE node through ONE hook,
|
|
26819
|
+
* keyed "topic^id|hook"; the roots of a topic are
|
|
26820
|
+
* a group of their own, keyed "|topic"
|
|
26821
|
+
* shown how many of a group's children are on screen:
|
|
26822
|
+
* absent means folded, a number means the first
|
|
26823
|
+
* N, in record order, a page at a time
|
|
26824
|
+
*
|
|
26825
|
+
* Two rules that are not obvious:
|
|
26826
|
+
*
|
|
26827
|
+
* - A node is visible when SOME visible parent shows it, or it is
|
|
26828
|
+
* a shown root. A record with two parents (a device hangs from
|
|
26829
|
+
* its place AND its controller) is drawn ONCE, under whichever
|
|
26830
|
+
* opened first, and folding one of the two leaves it where the
|
|
26831
|
+
* other one shows it. The union, never the intersection.
|
|
26832
|
+
*
|
|
26833
|
+
* - A parent that the engine does not draw an edge to is not a
|
|
26834
|
+
* parent here either: the `extended` tier (hooks and no fkeys)
|
|
26835
|
+
* gets no edges in draw_link(), so its children are roots. The
|
|
26836
|
+
* tree on screen and the tree in this model have to agree, or a
|
|
26837
|
+
* pill counts children that no line reaches.
|
|
26838
|
+
*
|
|
26839
|
+
* Copyright (c) 2026, ArtGins.
|
|
26840
|
+
* All Rights Reserved.
|
|
26841
|
+
***********************************************************************/
|
|
26842
|
+
var PAGE_SIZE_DEFAULT = 24;
|
|
26843
|
+
/************************************************************
|
|
26844
|
+
* Keys
|
|
26845
|
+
************************************************************/
|
|
26846
|
+
function fold_node_key(topic_name, id) {
|
|
26847
|
+
return `${topic_name}^${id}`;
|
|
26848
|
+
}
|
|
26849
|
+
function fold_group_key(node_key, hook_name) {
|
|
26850
|
+
return `${node_key}|${hook_name}`;
|
|
26851
|
+
}
|
|
26852
|
+
function fold_root_group_key(topic_name) {
|
|
26853
|
+
return `|${topic_name}`;
|
|
26854
|
+
}
|
|
26855
|
+
function fold_split_group_key(group_key) {
|
|
26856
|
+
let i = group_key.lastIndexOf("|");
|
|
26857
|
+
if (i < 0) return null;
|
|
26858
|
+
return {
|
|
26859
|
+
node_key: group_key.slice(0, i),
|
|
26860
|
+
hook: group_key.slice(i + 1)
|
|
26861
|
+
};
|
|
26862
|
+
}
|
|
26863
|
+
/************************************************************
|
|
26864
|
+
* Every parent a record names, decoded, in column order.
|
|
26865
|
+
*
|
|
26866
|
+
* Only the parents that will be DRAWN: a topic missing from
|
|
26867
|
+
* `descs` (a system topic such as `__assets__`, never fetched)
|
|
26868
|
+
* and an `extended` parent (no edge is drawn to one, see the
|
|
26869
|
+
* header) are left out, so a child of nothing else is a root.
|
|
26870
|
+
************************************************************/
|
|
26871
|
+
function parents_of(descs, desc, record) {
|
|
26872
|
+
let out = [];
|
|
26873
|
+
let cols = desc.cols || [];
|
|
26874
|
+
for (let i = 0; i < cols.length; i++) {
|
|
26875
|
+
let col = cols[i];
|
|
26876
|
+
if (!col.fkey) continue;
|
|
26877
|
+
let fkeys = record[col.id];
|
|
26878
|
+
if (!fkeys) continue;
|
|
26879
|
+
let list = is_array(fkeys) ? fkeys : [fkeys];
|
|
26880
|
+
for (let j = 0; j < list.length; j++) {
|
|
26881
|
+
let ref = treedb_decoder_fkey(col, list[j]);
|
|
26882
|
+
if (!ref || !ref.topic_name || !ref.hook_name) continue;
|
|
26883
|
+
let parent_desc = descs[ref.topic_name];
|
|
26884
|
+
if (!parent_desc) continue;
|
|
26885
|
+
if (parent_desc.node_treedb_type === "extended") continue;
|
|
26886
|
+
out.push({
|
|
26887
|
+
node_key: fold_node_key(ref.topic_name, String(ref.id)),
|
|
26888
|
+
hook: ref.hook_name,
|
|
26889
|
+
fkey_name: col.id
|
|
26890
|
+
});
|
|
26891
|
+
}
|
|
26892
|
+
}
|
|
26893
|
+
return out;
|
|
26894
|
+
}
|
|
26895
|
+
/************************************************************
|
|
26896
|
+
* Build the model from the topic descriptions and their records.
|
|
26897
|
+
*
|
|
26898
|
+
* descs {topic_name: desc}, system topics included (skipped)
|
|
26899
|
+
* records {topic_name: [record, ...]}, in the order the
|
|
26900
|
+
* backend returned them -- that order is the order of
|
|
26901
|
+
* the children on screen, and of the pages
|
|
26902
|
+
*
|
|
26903
|
+
* Returns
|
|
26904
|
+
* {
|
|
26905
|
+
* nodes: Map<node_key, {key, topic_name, id, record,
|
|
26906
|
+
* parents: [{node_key, hook, fkey_name}],
|
|
26907
|
+
* hooks: {hook: [child_key, ...]}}>
|
|
26908
|
+
* groups: Map<group_key, [child_key, ...]> (roots included)
|
|
26909
|
+
* topics: [topic_name, ...] topics with records, in desc order
|
|
26910
|
+
* }
|
|
26911
|
+
************************************************************/
|
|
26912
|
+
function fold_build_model(descs, records) {
|
|
26913
|
+
let nodes = /* @__PURE__ */ new Map();
|
|
26914
|
+
let groups = /* @__PURE__ */ new Map();
|
|
26915
|
+
let topics = [];
|
|
26916
|
+
descs = is_object(descs) ? descs : {};
|
|
26917
|
+
records = is_object(records) ? records : {};
|
|
26918
|
+
for (let topic_name of Object.keys(descs)) {
|
|
26919
|
+
if (topic_name.substring(0, 2) === "__") continue;
|
|
26920
|
+
descs[topic_name];
|
|
26921
|
+
let list = records[topic_name];
|
|
26922
|
+
if (!is_array(list)) continue;
|
|
26923
|
+
topics.push(topic_name);
|
|
26924
|
+
for (let i = 0; i < list.length; i++) {
|
|
26925
|
+
let record = list[i];
|
|
26926
|
+
if (!is_object(record) || record.id === void 0 || record.id === null) continue;
|
|
26927
|
+
let key = fold_node_key(topic_name, String(record.id));
|
|
26928
|
+
nodes.set(key, {
|
|
26929
|
+
key,
|
|
26930
|
+
topic_name,
|
|
26931
|
+
id: String(record.id),
|
|
26932
|
+
record,
|
|
26933
|
+
parents: [],
|
|
26934
|
+
hooks: {}
|
|
26935
|
+
});
|
|
26936
|
+
}
|
|
26937
|
+
}
|
|
26938
|
+
for (let node of nodes.values()) {
|
|
26939
|
+
let desc = descs[node.topic_name];
|
|
26940
|
+
let parents = parents_of(descs, desc, node.record);
|
|
26941
|
+
for (let p of parents) {
|
|
26942
|
+
let parent = nodes.get(p.node_key);
|
|
26943
|
+
if (!parent) continue;
|
|
26944
|
+
node.parents.push(p);
|
|
26945
|
+
if (!parent.hooks[p.hook]) parent.hooks[p.hook] = [];
|
|
26946
|
+
parent.hooks[p.hook].push(node.key);
|
|
26947
|
+
}
|
|
26948
|
+
}
|
|
26949
|
+
for (let node of nodes.values()) for (let hook of Object.keys(node.hooks)) groups.set(fold_group_key(node.key, hook), node.hooks[hook]);
|
|
26950
|
+
let roots = {};
|
|
26951
|
+
for (let topic_name of topics) roots[topic_name] = [];
|
|
26952
|
+
for (let node of nodes.values()) if (node.parents.length === 0) roots[node.topic_name].push(node.key);
|
|
26953
|
+
let reached = reach_from(nodes, [].concat(...Object.values(roots)));
|
|
26954
|
+
for (let node of nodes.values()) if (!reached.has(node.key)) {
|
|
26955
|
+
roots[node.topic_name].push(node.key);
|
|
26956
|
+
for (let k of reach_from(nodes, [node.key])) reached.add(k);
|
|
26957
|
+
}
|
|
26958
|
+
for (let topic_name of topics) if (roots[topic_name].length > 0) groups.set(fold_root_group_key(topic_name), roots[topic_name]);
|
|
26959
|
+
return {
|
|
26960
|
+
nodes,
|
|
26961
|
+
groups,
|
|
26962
|
+
topics
|
|
26963
|
+
};
|
|
26964
|
+
}
|
|
26965
|
+
/************************************************************
|
|
26966
|
+
* Everything reachable downwards from `start`, cycles included.
|
|
26967
|
+
************************************************************/
|
|
26968
|
+
function reach_from(nodes, start) {
|
|
26969
|
+
let seen = /* @__PURE__ */ new Set();
|
|
26970
|
+
let queue = start.slice();
|
|
26971
|
+
while (queue.length) {
|
|
26972
|
+
let key = queue.shift();
|
|
26973
|
+
if (seen.has(key)) continue;
|
|
26974
|
+
seen.add(key);
|
|
26975
|
+
let node = nodes.get(key);
|
|
26976
|
+
if (!node) continue;
|
|
26977
|
+
for (let hook of Object.keys(node.hooks)) for (let child of node.hooks[hook]) if (!seen.has(child)) queue.push(child);
|
|
26978
|
+
}
|
|
26979
|
+
return seen;
|
|
26980
|
+
}
|
|
26981
|
+
/************************************************************
|
|
26982
|
+
* Fold state: which groups are open, and how far.
|
|
26983
|
+
************************************************************/
|
|
26984
|
+
function fold_new_state(page_size) {
|
|
26985
|
+
return {
|
|
26986
|
+
page_size: page_size > 0 ? page_size : PAGE_SIZE_DEFAULT,
|
|
26987
|
+
shown: /* @__PURE__ */ new Map()
|
|
26988
|
+
};
|
|
26989
|
+
}
|
|
26990
|
+
function fold_group_total(model, group_key) {
|
|
26991
|
+
let list = model.groups.get(group_key);
|
|
26992
|
+
return list ? list.length : 0;
|
|
26993
|
+
}
|
|
26994
|
+
function fold_group_shown(model, state, group_key) {
|
|
26995
|
+
let total = fold_group_total(model, group_key);
|
|
26996
|
+
let n = state.shown.get(group_key) || 0;
|
|
26997
|
+
return Math.min(n, total);
|
|
26998
|
+
}
|
|
26999
|
+
function fold_is_open(state, group_key) {
|
|
27000
|
+
return (state.shown.get(group_key) || 0) > 0;
|
|
27001
|
+
}
|
|
27002
|
+
function page_ceiling(state, n) {
|
|
27003
|
+
let p = state.page_size;
|
|
27004
|
+
return Math.ceil(n / p) * p;
|
|
27005
|
+
}
|
|
27006
|
+
/************************************************************
|
|
27007
|
+
* Open a group on its first page, or close it.
|
|
27008
|
+
* Returns true when it ends OPEN.
|
|
27009
|
+
************************************************************/
|
|
27010
|
+
function fold_toggle(model, state, group_key) {
|
|
27011
|
+
if (fold_is_open(state, group_key)) {
|
|
27012
|
+
state.shown.delete(group_key);
|
|
27013
|
+
return false;
|
|
27014
|
+
}
|
|
27015
|
+
if (fold_group_total(model, group_key) === 0) return false;
|
|
27016
|
+
state.shown.set(group_key, state.page_size);
|
|
27017
|
+
return true;
|
|
27018
|
+
}
|
|
27019
|
+
/************************************************************
|
|
27020
|
+
* One more page of a group. Returns how many are shown now.
|
|
27021
|
+
************************************************************/
|
|
27022
|
+
function fold_show_more(model, state, group_key) {
|
|
27023
|
+
let total = fold_group_total(model, group_key);
|
|
27024
|
+
let n = fold_group_shown(model, state, group_key) + state.page_size;
|
|
27025
|
+
n = Math.min(n, total);
|
|
27026
|
+
if (n > 0) state.shown.set(group_key, n);
|
|
27027
|
+
return n;
|
|
27028
|
+
}
|
|
27029
|
+
/************************************************************
|
|
27030
|
+
* Every group open on ALL its children. This is the reader
|
|
27031
|
+
* asking for the whole thing; the pages are for the other way in.
|
|
27032
|
+
************************************************************/
|
|
27033
|
+
function fold_expand_all(model, state) {
|
|
27034
|
+
state.shown.clear();
|
|
27035
|
+
for (let [group_key, list] of model.groups) if (list.length > 0) state.shown.set(group_key, list.length);
|
|
27036
|
+
}
|
|
27037
|
+
/************************************************************
|
|
27038
|
+
* The roots and nothing else -- the first page of each topic's
|
|
27039
|
+
* roots, the way the graph looks before anything is opened.
|
|
27040
|
+
************************************************************/
|
|
27041
|
+
function fold_collapse_all(model, state) {
|
|
27042
|
+
state.shown.clear();
|
|
27043
|
+
for (let topic_name of model.topics) {
|
|
27044
|
+
let key = fold_root_group_key(topic_name);
|
|
27045
|
+
if (fold_group_total(model, key) > 0) state.shown.set(key, state.page_size);
|
|
27046
|
+
}
|
|
27047
|
+
}
|
|
27048
|
+
/************************************************************
|
|
27049
|
+
* Open the tree down to `depth` levels: the roots are level 1,
|
|
27050
|
+
* their children level 2. A node reached by two paths takes the
|
|
27051
|
+
* shallowest. Each group opens on its first page. `depth` of 1
|
|
27052
|
+
* is the roots alone; anything below that is treated as 1.
|
|
27053
|
+
************************************************************/
|
|
27054
|
+
function fold_expand_to_depth(model, state, depth) {
|
|
27055
|
+
fold_collapse_all(model, state);
|
|
27056
|
+
if (!(depth > 1)) return;
|
|
27057
|
+
let level = /* @__PURE__ */ new Map();
|
|
27058
|
+
let queue = [];
|
|
27059
|
+
for (let topic_name of model.topics) {
|
|
27060
|
+
let roots = model.groups.get(fold_root_group_key(topic_name)) || [];
|
|
27061
|
+
for (let key of roots) if (!level.has(key)) {
|
|
27062
|
+
level.set(key, 1);
|
|
27063
|
+
queue.push(key);
|
|
27064
|
+
}
|
|
27065
|
+
}
|
|
27066
|
+
while (queue.length) {
|
|
27067
|
+
let key = queue.shift();
|
|
27068
|
+
let lv = level.get(key);
|
|
27069
|
+
if (lv >= depth) continue;
|
|
27070
|
+
let node = model.nodes.get(key);
|
|
27071
|
+
if (!node) continue;
|
|
27072
|
+
for (let hook of Object.keys(node.hooks)) {
|
|
27073
|
+
let children = node.hooks[hook];
|
|
27074
|
+
if (children.length === 0) continue;
|
|
27075
|
+
state.shown.set(fold_group_key(key, hook), state.page_size);
|
|
27076
|
+
for (let child of children) if (!level.has(child)) {
|
|
27077
|
+
level.set(child, lv + 1);
|
|
27078
|
+
queue.push(child);
|
|
27079
|
+
}
|
|
27080
|
+
}
|
|
27081
|
+
}
|
|
27082
|
+
}
|
|
27083
|
+
/************************************************************
|
|
27084
|
+
* The set of node keys on screen, from the roots down through
|
|
27085
|
+
* every open group -- and only through open groups whose parent
|
|
27086
|
+
* is itself on screen: a group remembered open under a folded
|
|
27087
|
+
* ancestor stays remembered, not shown.
|
|
27088
|
+
************************************************************/
|
|
27089
|
+
function fold_visible_set(model, state) {
|
|
27090
|
+
let visible = /* @__PURE__ */ new Set();
|
|
27091
|
+
let queue = [];
|
|
27092
|
+
let push_group = (group_key, children) => {
|
|
27093
|
+
let n = fold_group_shown(model, state, group_key);
|
|
27094
|
+
for (let i = 0; i < n; i++) {
|
|
27095
|
+
let key = children[i];
|
|
27096
|
+
if (!visible.has(key)) {
|
|
27097
|
+
visible.add(key);
|
|
27098
|
+
queue.push(key);
|
|
27099
|
+
}
|
|
27100
|
+
}
|
|
27101
|
+
};
|
|
27102
|
+
for (let topic_name of model.topics) {
|
|
27103
|
+
let key = fold_root_group_key(topic_name);
|
|
27104
|
+
let roots = model.groups.get(key);
|
|
27105
|
+
if (roots) push_group(key, roots);
|
|
27106
|
+
}
|
|
27107
|
+
while (queue.length) {
|
|
27108
|
+
let key = queue.shift();
|
|
27109
|
+
let node = model.nodes.get(key);
|
|
27110
|
+
if (!node) continue;
|
|
27111
|
+
for (let hook of Object.keys(node.hooks)) push_group(fold_group_key(key, hook), node.hooks[hook]);
|
|
27112
|
+
}
|
|
27113
|
+
return visible;
|
|
27114
|
+
}
|
|
27115
|
+
/************************************************************
|
|
27116
|
+
* The open groups that still have children off screen, with the
|
|
27117
|
+
* parent that owns each -- what the "+N" chips are drawn for.
|
|
27118
|
+
* Only groups whose parent is visible (or root groups).
|
|
27119
|
+
*
|
|
27120
|
+
* Returns [{group_key, node_key, hook, shown, total, rest}]
|
|
27121
|
+
************************************************************/
|
|
27122
|
+
function fold_pending_groups(model, state, visible) {
|
|
27123
|
+
let out = [];
|
|
27124
|
+
for (let [group_key, list] of model.groups) {
|
|
27125
|
+
let shown = fold_group_shown(model, state, group_key);
|
|
27126
|
+
if (shown === 0 || shown >= list.length) continue;
|
|
27127
|
+
let g = fold_split_group_key(group_key);
|
|
27128
|
+
if (g.node_key && !visible.has(g.node_key)) continue;
|
|
27129
|
+
out.push({
|
|
27130
|
+
group_key,
|
|
27131
|
+
node_key: g.node_key,
|
|
27132
|
+
hook: g.hook,
|
|
27133
|
+
shown,
|
|
27134
|
+
total: list.length,
|
|
27135
|
+
rest: list.length - shown
|
|
27136
|
+
});
|
|
27137
|
+
}
|
|
27138
|
+
return out;
|
|
27139
|
+
}
|
|
27140
|
+
/************************************************************
|
|
27141
|
+
* The pills of one card: one per hook that has children.
|
|
27142
|
+
*
|
|
27143
|
+
* Returns [{hook, group_key, total, shown, open, child_topic}]
|
|
27144
|
+
* `child_topic` is the topic of the first child, which is what
|
|
27145
|
+
* the pill is coloured with (a hook can name several topics in
|
|
27146
|
+
* the schema, but the children it has are what it links).
|
|
27147
|
+
************************************************************/
|
|
27148
|
+
function fold_pills_of(model, state, node_key) {
|
|
27149
|
+
let node = model.nodes.get(node_key);
|
|
27150
|
+
if (!node) return [];
|
|
27151
|
+
let out = [];
|
|
27152
|
+
for (let hook of Object.keys(node.hooks)) {
|
|
27153
|
+
let children = node.hooks[hook];
|
|
27154
|
+
if (children.length === 0) continue;
|
|
27155
|
+
let group_key = fold_group_key(node_key, hook);
|
|
27156
|
+
let first = model.nodes.get(children[0]);
|
|
27157
|
+
out.push({
|
|
27158
|
+
hook,
|
|
27159
|
+
group_key,
|
|
27160
|
+
total: children.length,
|
|
27161
|
+
shown: fold_group_shown(model, state, group_key),
|
|
27162
|
+
open: fold_is_open(state, group_key),
|
|
27163
|
+
child_topic: first ? first.topic_name : ""
|
|
27164
|
+
});
|
|
27165
|
+
}
|
|
27166
|
+
return out;
|
|
27167
|
+
}
|
|
27168
|
+
/************************************************************
|
|
27169
|
+
* Make ONE node visible, opening the groups on a path from a
|
|
27170
|
+
* root to it, and as many pages of each as it takes for the
|
|
27171
|
+
* node to be inside the shown prefix. Prefers the shortest path
|
|
27172
|
+
* (breadth-first upwards). Returns false if no root reaches it,
|
|
27173
|
+
* which cannot happen with a model built here (see roots) but
|
|
27174
|
+
* is the honest answer for a key the model does not know.
|
|
27175
|
+
************************************************************/
|
|
27176
|
+
function fold_reveal(model, state, node_key) {
|
|
27177
|
+
if (!model.nodes.get(node_key)) return false;
|
|
27178
|
+
let root_group_of = (key) => {
|
|
27179
|
+
let rg = fold_root_group_key(model.nodes.get(key).topic_name);
|
|
27180
|
+
return (model.groups.get(rg) || []).indexOf(key) >= 0 ? rg : null;
|
|
27181
|
+
};
|
|
27182
|
+
let via = /* @__PURE__ */ new Map();
|
|
27183
|
+
let queue = [node_key];
|
|
27184
|
+
via.set(node_key, null);
|
|
27185
|
+
let root_key = null;
|
|
27186
|
+
while (queue.length) {
|
|
27187
|
+
let key = queue.shift();
|
|
27188
|
+
if (root_group_of(key)) {
|
|
27189
|
+
root_key = key;
|
|
27190
|
+
break;
|
|
27191
|
+
}
|
|
27192
|
+
let n = model.nodes.get(key);
|
|
27193
|
+
for (let p of n.parents) {
|
|
27194
|
+
if (!model.nodes.has(p.node_key) || via.has(p.node_key)) continue;
|
|
27195
|
+
via.set(p.node_key, {
|
|
27196
|
+
child_key: key,
|
|
27197
|
+
hook: p.hook
|
|
27198
|
+
});
|
|
27199
|
+
queue.push(p.node_key);
|
|
27200
|
+
}
|
|
27201
|
+
}
|
|
27202
|
+
if (root_key === null) return false;
|
|
27203
|
+
let open_up_to = (group_key, child_key) => {
|
|
27204
|
+
let list = model.groups.get(group_key) || [];
|
|
27205
|
+
let idx = list.indexOf(child_key);
|
|
27206
|
+
if (idx < 0) return;
|
|
27207
|
+
let need = page_ceiling(state, idx + 1);
|
|
27208
|
+
if (need > (state.shown.get(group_key) || 0)) state.shown.set(group_key, Math.min(need, list.length));
|
|
27209
|
+
};
|
|
27210
|
+
open_up_to(root_group_of(root_key), root_key);
|
|
27211
|
+
let key = root_key;
|
|
27212
|
+
while (true) {
|
|
27213
|
+
let step = via.get(key);
|
|
27214
|
+
if (!step) break;
|
|
27215
|
+
open_up_to(fold_group_key(key, step.hook), step.child_key);
|
|
27216
|
+
key = step.child_key;
|
|
27217
|
+
}
|
|
27218
|
+
return true;
|
|
27219
|
+
}
|
|
27220
|
+
//#endregion
|
|
26798
27221
|
//#region node_modules/@babel/runtime/helpers/esm/typeof.js
|
|
26799
27222
|
function _typeof(o) {
|
|
26800
27223
|
"@babel/helpers - typeof";
|
|
@@ -53539,6 +53962,23 @@ function ensure_brush_select_owned() {
|
|
|
53539
53962
|
* record: null, // Data of node
|
|
53540
53963
|
* }
|
|
53541
53964
|
*
|
|
53965
|
+
* The graph opens FOLDED, like a JSON viewer.
|
|
53966
|
+
*
|
|
53967
|
+
* Every record of every topic is fetched, but only the ones on
|
|
53968
|
+
* screen become G6 nodes: the roots, `expand_depth` levels under
|
|
53969
|
+
* them, one page (`fold_page_size`) of children per hook. Each
|
|
53970
|
+
* card carries a pill per hook that has children -- `▸ devices
|
|
53971
|
+
* 142` -- which opens or folds that hook; an open hook with more
|
|
53972
|
+
* children than its page ends in a `+N` chip that opens the next
|
|
53973
|
+
* page. The arithmetic lives in treedb_fold_model.js; this file
|
|
53974
|
+
* reconciles the G6 data with what that model says is visible
|
|
53975
|
+
* (see reconcile_fold) and lays it out again.
|
|
53976
|
+
*
|
|
53977
|
+
* `dagre` reads LEFT TO RIGHT: the children of a node are a
|
|
53978
|
+
* column beside it, the ports move to the sides with it, and
|
|
53979
|
+
* the edges are horizontal beziers. `antv-dagre` keeps the
|
|
53980
|
+
* top-down reading.
|
|
53981
|
+
*
|
|
53542
53982
|
* Copyright (c) 2020-2021 Niyamaka.
|
|
53543
53983
|
* Copyright (c) 2025-2026, ArtGins.
|
|
53544
53984
|
* All Rights Reserved.
|
|
@@ -53598,8 +54038,18 @@ var SELECT_RING = "rgba(59,130,246,0.95)";
|
|
|
53598
54038
|
***************************************************************/
|
|
53599
54039
|
var _layouts = {
|
|
53600
54040
|
"manual": { type: "manual" },
|
|
53601
|
-
"dagre": {
|
|
53602
|
-
|
|
54041
|
+
"dagre": {
|
|
54042
|
+
type: "dagre",
|
|
54043
|
+
rankdir: "LR",
|
|
54044
|
+
nodesep: 18,
|
|
54045
|
+
ranksep: 110
|
|
54046
|
+
},
|
|
54047
|
+
"antv-dagre": {
|
|
54048
|
+
type: "antv-dagre",
|
|
54049
|
+
rankdir: "TB",
|
|
54050
|
+
nodesep: 30,
|
|
54051
|
+
ranksep: 80
|
|
54052
|
+
},
|
|
53603
54053
|
"d3-force": {
|
|
53604
54054
|
type: "d3-force",
|
|
53605
54055
|
link: {
|
|
@@ -53647,6 +54097,8 @@ var attrs_table$4 = [
|
|
|
53647
54097
|
SDATA(data_type_t.DTP_LIST, "layout_names", sdata_flag_t.SDF_RD, JSON.stringify(Object.keys(_layouts)), "Available layout names (read-only, for parent to query)"),
|
|
53648
54098
|
SDATA(data_type_t.DTP_STRING, "hook_port_position", 0, "bottom", "Hook port position"),
|
|
53649
54099
|
SDATA(data_type_t.DTP_STRING, "fkey_port_position", 0, "top", "Fkey port position"),
|
|
54100
|
+
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0, 2, "Levels open when a treedb loads: 1 = the roots alone, 2 = the roots and their children. Every open hook shows its first page"),
|
|
54101
|
+
SDATA(data_type_t.DTP_INTEGER, "fold_page_size", 0, 24, "Children of one hook shown per page; the `+N` chip after the page opens the next one"),
|
|
53650
54102
|
SDATA(data_type_t.DTP_BOOLEAN, "confirm_delete_node", 0, true, "Ask confirmation before deleting a node"),
|
|
53651
54103
|
SDATA(data_type_t.DTP_BOOLEAN, "confirm_unlink_edge", 0, true, "Ask confirmation before unlinking an edge"),
|
|
53652
54104
|
SDATA(data_type_t.DTP_STRING, "wide", 0, "40px", "Height of header"),
|
|
@@ -53715,10 +54167,18 @@ var PRIVATE_DATA$4 = {
|
|
|
53715
54167
|
selection_mode: false,
|
|
53716
54168
|
_selected_paint_ids: [],
|
|
53717
54169
|
_pending_focus_topic: null,
|
|
54170
|
+
_pending_focus_all: false,
|
|
53718
54171
|
_pending_find: null,
|
|
53719
54172
|
_layout_asked: "",
|
|
53720
54173
|
_nodes_total: 0,
|
|
53721
|
-
_nodes_placed: 0
|
|
54174
|
+
_nodes_placed: 0,
|
|
54175
|
+
expand_depth: 2,
|
|
54176
|
+
fold_page_size: 24,
|
|
54177
|
+
_fold_model: null,
|
|
54178
|
+
_fold_state: null,
|
|
54179
|
+
_fold_listener: null,
|
|
54180
|
+
_pill_sig: null,
|
|
54181
|
+
_fold_busy: false
|
|
53722
54182
|
};
|
|
53723
54183
|
var __gclass__$4 = null;
|
|
53724
54184
|
/******************************
|
|
@@ -53738,6 +54198,7 @@ function mt_create$4(gobj) {
|
|
|
53738
54198
|
build_ui$4(gobj);
|
|
53739
54199
|
register_layouts(gobj);
|
|
53740
54200
|
build_graph$1(gobj);
|
|
54201
|
+
install_fold_listener(gobj);
|
|
53741
54202
|
if (typeof ResizeObserver !== "undefined" && priv.$container) {
|
|
53742
54203
|
let ro = new ResizeObserver(() => {
|
|
53743
54204
|
if (priv._resize_raf) cancelAnimationFrame(priv._resize_raf);
|
|
@@ -53777,6 +54238,7 @@ function mt_destroy$4(gobj) {
|
|
|
53777
54238
|
i18next.off("languageChanged", priv._on_language_changed);
|
|
53778
54239
|
priv._on_language_changed = null;
|
|
53779
54240
|
}
|
|
54241
|
+
uninstall_fold_listener(gobj);
|
|
53780
54242
|
if (priv._on_pointerdown_focus) {
|
|
53781
54243
|
priv.$container.removeEventListener("pointerdown", priv._on_pointerdown_focus, true);
|
|
53782
54244
|
priv._on_pointerdown_focus = null;
|
|
@@ -53964,6 +54426,7 @@ function configure_events(gobj) {
|
|
|
53964
54426
|
});
|
|
53965
54427
|
priv._on_language_changed = () => {
|
|
53966
54428
|
update_toolbar(gobj);
|
|
54429
|
+
repaint_more_chips(gobj);
|
|
53967
54430
|
};
|
|
53968
54431
|
i18next.on("languageChanged", priv._on_language_changed);
|
|
53969
54432
|
priv._on_pointerdown_focus = (ev) => {
|
|
@@ -54461,15 +54924,79 @@ function build_ports(gobj, desc) {
|
|
|
54461
54924
|
top_ports.push(port);
|
|
54462
54925
|
}
|
|
54463
54926
|
}
|
|
54464
|
-
|
|
54465
|
-
for (let i = 0; i < bottom_ports.length; i++) {
|
|
54466
|
-
let point = getPointPosition(bottom_ports.length, i);
|
|
54467
|
-
if (top_ports.length === 0) bottom_ports[i].placement = [0, .5];
|
|
54468
|
-
else bottom_ports[i].placement = [point, 1];
|
|
54469
|
-
}
|
|
54927
|
+
place_ports(gobj, top_ports, bottom_ports);
|
|
54470
54928
|
return [...top_ports, ...bottom_ports];
|
|
54471
54929
|
}
|
|
54472
54930
|
/************************************************************
|
|
54931
|
+
* Which way the graph reads. `dagre` is the left-to-right
|
|
54932
|
+
* layout; everything else keeps the top-down reading, `manual`
|
|
54933
|
+
* included, because the saved arrangements were made with the
|
|
54934
|
+
* ports on the top and bottom edges.
|
|
54935
|
+
************************************************************/
|
|
54936
|
+
function layout_direction(gobj) {
|
|
54937
|
+
return gobj.priv.layout === "dagre" ? "LR" : "TB";
|
|
54938
|
+
}
|
|
54939
|
+
function edge_type_for(gobj) {
|
|
54940
|
+
return layout_direction(gobj) === "LR" ? "cubic-horizontal" : "cubic";
|
|
54941
|
+
}
|
|
54942
|
+
/************************************************************
|
|
54943
|
+
* Where the ports sit, by direction: fkeys (the way in from a
|
|
54944
|
+
* parent) all on one point of the leading edge, hooks (the way
|
|
54945
|
+
* out to the children) spread along the trailing edge. Left and
|
|
54946
|
+
* right when the graph reads left to right; top and bottom
|
|
54947
|
+
* otherwise.
|
|
54948
|
+
************************************************************/
|
|
54949
|
+
function place_ports(gobj, fkey_ports, hook_ports) {
|
|
54950
|
+
let lr = layout_direction(gobj) === "LR";
|
|
54951
|
+
for (let i = 0; i < fkey_ports.length; i++) fkey_ports[i].placement = lr ? [0, .5] : [.5, 0];
|
|
54952
|
+
for (let i = 0; i < hook_ports.length; i++) {
|
|
54953
|
+
let point = getPointPosition(hook_ports.length, i);
|
|
54954
|
+
if (fkey_ports.length === 0 && !lr) hook_ports[i].placement = [0, .5];
|
|
54955
|
+
else if (lr) hook_ports[i].placement = [1, point];
|
|
54956
|
+
else hook_ports[i].placement = [point, 1];
|
|
54957
|
+
}
|
|
54958
|
+
}
|
|
54959
|
+
/************************************************************
|
|
54960
|
+
* The layout changed direction: move every port to the edge
|
|
54961
|
+
* the new reading needs, and give every edge the curve that
|
|
54962
|
+
* goes with it. Called before the layout runs, so the lines
|
|
54963
|
+
* are drawn once, in the right place.
|
|
54964
|
+
************************************************************/
|
|
54965
|
+
function apply_layout_direction(gobj) {
|
|
54966
|
+
let graph = gobj.priv.graph;
|
|
54967
|
+
if (!graph) return;
|
|
54968
|
+
let node_updates = [];
|
|
54969
|
+
for (let nd of graph.getNodeData() || []) {
|
|
54970
|
+
if (!nd || !nd.data || !nd.data.desc || !nd.style || !is_array(nd.style.ports)) continue;
|
|
54971
|
+
let desc = nd.data.desc;
|
|
54972
|
+
let fkey_ports = [];
|
|
54973
|
+
let hook_ports = [];
|
|
54974
|
+
for (let port of nd.style.ports) {
|
|
54975
|
+
let col = get_col_by_id(desc, port.key);
|
|
54976
|
+
let copy = Object.assign({}, port);
|
|
54977
|
+
if (col && col.fkey) fkey_ports.push(copy);
|
|
54978
|
+
else hook_ports.push(copy);
|
|
54979
|
+
}
|
|
54980
|
+
place_ports(gobj, fkey_ports, hook_ports);
|
|
54981
|
+
node_updates.push({
|
|
54982
|
+
id: nd.id,
|
|
54983
|
+
style: { ports: [...fkey_ports, ...hook_ports] }
|
|
54984
|
+
});
|
|
54985
|
+
}
|
|
54986
|
+
let type = edge_type_for(gobj);
|
|
54987
|
+
let edge_updates = [];
|
|
54988
|
+
for (let ed of graph.getEdgeData() || []) if (ed && ed.type !== type) edge_updates.push({
|
|
54989
|
+
id: ed.id,
|
|
54990
|
+
type
|
|
54991
|
+
});
|
|
54992
|
+
try {
|
|
54993
|
+
if (node_updates.length) graph.updateNodeData(node_updates);
|
|
54994
|
+
if (edge_updates.length) graph.updateEdgeData(edge_updates);
|
|
54995
|
+
} catch (e) {
|
|
54996
|
+
log_error(`${gobj_short_name(gobj)}: cannot turn the ports: ${e}`);
|
|
54997
|
+
}
|
|
54998
|
+
}
|
|
54999
|
+
/************************************************************
|
|
54473
55000
|
* Create a topic node in the G6 graph
|
|
54474
55001
|
************************************************************/
|
|
54475
55002
|
function create_topic_node(gobj, desc, record) {
|
|
@@ -54478,8 +55005,6 @@ function create_topic_node(gobj, desc, record) {
|
|
|
54478
55005
|
let node_name = build_node_name(gobj, desc.topic_name, record.id);
|
|
54479
55006
|
let xy = get_default_ne_xy(gobj);
|
|
54480
55007
|
let geometry = get_node_graph_props(gobj, desc.topic_name, record.id, record);
|
|
54481
|
-
priv._nodes_total++;
|
|
54482
|
-
if (geometry_has_position(geometry)) priv._nodes_placed++;
|
|
54483
55008
|
let x = kw_get_int(gobj, geometry, "x", xy, kw_flag_t.KW_CREATE);
|
|
54484
55009
|
let y = kw_get_int(gobj, geometry, "y", xy, kw_flag_t.KW_CREATE);
|
|
54485
55010
|
let ports = build_ports(gobj, desc);
|
|
@@ -54492,24 +55017,26 @@ function create_topic_node(gobj, desc, record) {
|
|
|
54492
55017
|
stroke: getStrokeColor(desc.color),
|
|
54493
55018
|
lineWidth: 1
|
|
54494
55019
|
};
|
|
55020
|
+
let pills_html = pills_html_of_key(gobj, fold_node_key(desc.topic_name, String(record.id)));
|
|
55021
|
+
let size = card_size_for(node_treedb_type, !!pills_html);
|
|
54495
55022
|
if (node_treedb_type === "child") {
|
|
54496
55023
|
node_graph_type = "html";
|
|
54497
|
-
style.size =
|
|
54498
|
-
style.dx = -
|
|
54499
|
-
style.dy = -
|
|
55024
|
+
style.size = size;
|
|
55025
|
+
style.dx = -size[0] / 2;
|
|
55026
|
+
style.dy = -size[1] / 2;
|
|
54500
55027
|
style.innerHTML = build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id);
|
|
54501
55028
|
} else if (node_treedb_type === "extended") {
|
|
54502
55029
|
node_graph_type = "html";
|
|
54503
|
-
style.size =
|
|
54504
|
-
style.dx = -
|
|
54505
|
-
style.dy = -
|
|
54506
|
-
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id);
|
|
55030
|
+
style.size = size;
|
|
55031
|
+
style.dx = -size[0] / 2;
|
|
55032
|
+
style.dy = -size[1] / 2;
|
|
55033
|
+
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);
|
|
54507
55034
|
} else {
|
|
54508
55035
|
node_graph_type = "html";
|
|
54509
|
-
style.size =
|
|
54510
|
-
style.dx = -
|
|
54511
|
-
style.dy = -
|
|
54512
|
-
style.innerHTML = build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id);
|
|
55036
|
+
style.size = size;
|
|
55037
|
+
style.dx = -size[0] / 2;
|
|
55038
|
+
style.dy = -size[1] / 2;
|
|
55039
|
+
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);
|
|
54513
55040
|
}
|
|
54514
55041
|
let topic_props = priv._graph_properties[desc.topic_name];
|
|
54515
55042
|
let topic_defaults = is_object(topic_props) && is_object(topic_props.defaults) ? topic_props.defaults : null;
|
|
@@ -54566,8 +55093,7 @@ function create_topic_node(gobj, desc, record) {
|
|
|
54566
55093
|
* Update topic node data
|
|
54567
55094
|
************************************************************/
|
|
54568
55095
|
function update_topic_node(gobj, desc, node_name, record) {
|
|
54569
|
-
let
|
|
54570
|
-
let graph = priv.graph;
|
|
55096
|
+
let graph = gobj.priv.graph;
|
|
54571
55097
|
try {
|
|
54572
55098
|
let nodedata = graph.getNodeData(node_name);
|
|
54573
55099
|
if (!nodedata) {
|
|
@@ -54575,18 +55101,7 @@ function update_topic_node(gobj, desc, node_name, record) {
|
|
|
54575
55101
|
return;
|
|
54576
55102
|
}
|
|
54577
55103
|
nodedata.data.record = record;
|
|
54578
|
-
|
|
54579
|
-
id: node_name,
|
|
54580
|
-
style: { innerHTML: build_chip_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), record.id) }
|
|
54581
|
-
}]);
|
|
54582
|
-
else if (desc.node_treedb_type === "extended") graph.updateNodeData([{
|
|
54583
|
-
id: node_name,
|
|
54584
|
-
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, true, record.id) }
|
|
54585
|
-
}]);
|
|
54586
|
-
else if (desc.node_treedb_type === "hierarchical") graph.updateNodeData([{
|
|
54587
|
-
id: node_name,
|
|
54588
|
-
style: { innerHTML: build_node_innerHTML(desc.color, priv.theme, record.icon, node_label(desc, record), desc.topic_name, false, record.id) }
|
|
54589
|
-
}]);
|
|
55104
|
+
repaint_cards(gobj, /* @__PURE__ */ new Set([node_name]));
|
|
54590
55105
|
} catch (e) {
|
|
54591
55106
|
log_error(e.message);
|
|
54592
55107
|
}
|
|
@@ -54625,19 +55140,6 @@ function remove_local_node(gobj, topic_name, node) {
|
|
|
54625
55140
|
}
|
|
54626
55141
|
}
|
|
54627
55142
|
/************************************************************
|
|
54628
|
-
* Create all links from records, initial load from parent
|
|
54629
|
-
************************************************************/
|
|
54630
|
-
function create_links(gobj) {
|
|
54631
|
-
let priv = gobj.priv;
|
|
54632
|
-
for (const [topic_name, records] of Object.entries(priv.records)) {
|
|
54633
|
-
let desc = priv.descs[topic_name];
|
|
54634
|
-
for (let i = 0; i < records.length; i++) {
|
|
54635
|
-
let record = records[i];
|
|
54636
|
-
draw_links(gobj, desc, record, true);
|
|
54637
|
-
}
|
|
54638
|
-
}
|
|
54639
|
-
}
|
|
54640
|
-
/************************************************************
|
|
54641
55143
|
* Collect all fkey references from a record as a Set.
|
|
54642
55144
|
*
|
|
54643
55145
|
* Each entry is a string: "col_id\tcol_idx\tfkey_value"
|
|
@@ -54717,6 +55219,17 @@ function draw_link(gobj, child_topic, child_id, source_col, fkey, verbose) {
|
|
|
54717
55219
|
return;
|
|
54718
55220
|
}
|
|
54719
55221
|
let child_node = build_node_name(gobj, child_topic, child_id);
|
|
55222
|
+
let child_cell = null;
|
|
55223
|
+
try {
|
|
55224
|
+
child_cell = graph.getNodeData(child_node);
|
|
55225
|
+
} catch (e) {
|
|
55226
|
+
child_cell = null;
|
|
55227
|
+
}
|
|
55228
|
+
if (!child_cell) {
|
|
55229
|
+
if (verbose) log_error(`${gobj_short_name(gobj)}: child node NOT FOUND: ${child_node}`);
|
|
55230
|
+
return;
|
|
55231
|
+
}
|
|
55232
|
+
if (get_edge_by_link(gobj, parent_topic, parent_id, hook_name, child_topic, child_id, fkey_name)) return;
|
|
54720
55233
|
let dark = priv.theme === "dark";
|
|
54721
55234
|
let is_tree = parent_topic === child_topic;
|
|
54722
55235
|
let saved_lineWidth = is_tree ? 2 : 1.6;
|
|
@@ -54755,7 +55268,7 @@ function draw_link(gobj, child_topic, child_id, source_col, fkey, verbose) {
|
|
|
54755
55268
|
}
|
|
54756
55269
|
let edge = {
|
|
54757
55270
|
id: build_edge_id(gobj),
|
|
54758
|
-
type:
|
|
55271
|
+
type: edge_type_for(gobj),
|
|
54759
55272
|
source: parent_node,
|
|
54760
55273
|
target: child_node,
|
|
54761
55274
|
style: {
|
|
@@ -54886,7 +55399,10 @@ function save_geometry(gobj) {
|
|
|
54886
55399
|
let priv = gobj.priv;
|
|
54887
55400
|
let graph = priv.graph;
|
|
54888
55401
|
const nodes = graph.getData().nodes;
|
|
54889
|
-
for (let i = 0; i < nodes.length; i++)
|
|
55402
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
55403
|
+
if (!nodes[i].data || !nodes[i].data.desc) continue;
|
|
55404
|
+
update_geometry(gobj, nodes[i].id);
|
|
55405
|
+
}
|
|
54890
55406
|
const edges = graph.getData().edges;
|
|
54891
55407
|
for (let i = 0; i < edges.length; i++) update_edge_geometry(gobj, edges[i].id);
|
|
54892
55408
|
let origin = gobj_read_str_attr(gobj_yuno(), "node_uuid");
|
|
@@ -55141,40 +55657,75 @@ async function graph_fit_selection(gobj, ids) {
|
|
|
55141
55657
|
* once the data loads (see ac_load_data). Guarded end-to-end — a
|
|
55142
55658
|
* missing G6 API or an unknown topic logs and no-ops, never throws.
|
|
55143
55659
|
************************************************************/
|
|
55144
|
-
function graph_focus_topic(gobj, topic) {
|
|
55660
|
+
function graph_focus_topic(gobj, topic, reveal_all) {
|
|
55145
55661
|
let priv = gobj.priv;
|
|
55146
|
-
|
|
55147
|
-
if (!graph || !priv.graph_rendered) {
|
|
55662
|
+
if (!priv.graph || !priv.graph_rendered || !priv._fold_model) {
|
|
55148
55663
|
priv._pending_focus_topic = topic;
|
|
55664
|
+
priv._pending_focus_all = !!reveal_all;
|
|
55149
55665
|
return;
|
|
55150
55666
|
}
|
|
55151
|
-
let
|
|
55152
|
-
|
|
55153
|
-
|
|
55154
|
-
|
|
55155
|
-
|
|
55156
|
-
|
|
55667
|
+
let model = priv._fold_model;
|
|
55668
|
+
let state = priv._fold_state;
|
|
55669
|
+
let keys = [];
|
|
55670
|
+
if (!empty_string(topic)) {
|
|
55671
|
+
for (let node of model.nodes.values()) if (node.topic_name === topic) keys.push(node.key);
|
|
55672
|
+
if (keys.length === 0) log_warning(`${gobj_short_name(gobj)}: focus topic '${topic}' has no nodes`);
|
|
55673
|
+
let visible = fold_visible_set(model, state);
|
|
55674
|
+
let revealed = 0;
|
|
55675
|
+
for (let key of keys) {
|
|
55676
|
+
if (visible.has(key)) continue;
|
|
55677
|
+
if (!reveal_all && revealed >= state.page_size) break;
|
|
55678
|
+
fold_reveal(model, state, key);
|
|
55679
|
+
revealed++;
|
|
55680
|
+
}
|
|
55157
55681
|
}
|
|
55158
|
-
|
|
55682
|
+
priv._focus_topic = topic || null;
|
|
55683
|
+
reconcile_fold(gobj, {}).then(() => {
|
|
55684
|
+
apply_focus_ids(gobj, keys, "focus topic");
|
|
55685
|
+
});
|
|
55686
|
+
}
|
|
55687
|
+
/************************************************************
|
|
55688
|
+
* Paint the highlight on these records (by model key) and put
|
|
55689
|
+
* the first of them in the middle. Shared by the find and the
|
|
55690
|
+
* topic focus, after the reconcile that brought them on screen.
|
|
55691
|
+
* Keys that are still off screen are skipped: a match beyond the
|
|
55692
|
+
* page a reveal opened is counted, not painted.
|
|
55693
|
+
************************************************************/
|
|
55694
|
+
function apply_focus_ids(gobj, keys, what) {
|
|
55695
|
+
let priv = gobj.priv;
|
|
55696
|
+
let graph = priv.graph;
|
|
55697
|
+
if (!graph) return;
|
|
55159
55698
|
let states = {};
|
|
55160
55699
|
for (let id of priv._focus_ids || []) states[id] = [];
|
|
55161
55700
|
let ids = [];
|
|
55162
|
-
|
|
55163
|
-
|
|
55164
|
-
|
|
55165
|
-
|
|
55701
|
+
for (let key of keys) {
|
|
55702
|
+
let id = node_id_of_key(gobj, key);
|
|
55703
|
+
let nd = null;
|
|
55704
|
+
try {
|
|
55705
|
+
nd = graph.getNodeData(id);
|
|
55706
|
+
} catch (e) {
|
|
55707
|
+
nd = null;
|
|
55708
|
+
}
|
|
55709
|
+
if (nd) {
|
|
55710
|
+
ids.push(id);
|
|
55711
|
+
states[id] = ["active"];
|
|
55712
|
+
}
|
|
55166
55713
|
}
|
|
55167
55714
|
let prev_ids = priv._focus_ids || [];
|
|
55168
55715
|
priv._focus_ids = ids;
|
|
55169
|
-
priv._focus_topic = topic || null;
|
|
55170
55716
|
try {
|
|
55171
55717
|
if (typeof graph.setElementState === "function") graph.setElementState(states);
|
|
55172
55718
|
apply_node_highlight(gobj, prev_ids, ids);
|
|
55173
|
-
if (ids.length
|
|
55719
|
+
if (ids.length) yui_graph_center_on(graph, ids[0]);
|
|
55174
55720
|
} catch (e) {
|
|
55175
|
-
log_error(`${gobj_short_name(gobj)}:
|
|
55721
|
+
log_error(`${gobj_short_name(gobj)}: ${what} apply failed: ${e}`);
|
|
55176
55722
|
}
|
|
55177
55723
|
}
|
|
55724
|
+
function node_id_of_key(gobj, key) {
|
|
55725
|
+
let i = key.indexOf("^");
|
|
55726
|
+
if (i < 0) return "";
|
|
55727
|
+
return build_node_name(gobj, key.slice(0, i), key.slice(i + 1));
|
|
55728
|
+
}
|
|
55178
55729
|
/************************************************************
|
|
55179
55730
|
* Find the nodes whose name, id or topic contains `term`, highlight
|
|
55180
55731
|
* them with the same amber 'active' state the topic focus uses, and
|
|
@@ -55191,52 +55742,43 @@ function graph_focus_topic(gobj, topic) {
|
|
|
55191
55742
|
************************************************************/
|
|
55192
55743
|
function graph_find_nodes(gobj, term) {
|
|
55193
55744
|
let priv = gobj.priv;
|
|
55194
|
-
|
|
55195
|
-
if (!graph || !priv.graph_rendered) {
|
|
55745
|
+
if (!priv.graph || !priv.graph_rendered || !priv._fold_model) {
|
|
55196
55746
|
priv._pending_find = term;
|
|
55197
55747
|
return 0;
|
|
55198
55748
|
}
|
|
55199
|
-
let
|
|
55200
|
-
|
|
55201
|
-
|
|
55202
|
-
} catch (e) {
|
|
55203
|
-
log_error(`${gobj_short_name(gobj)}: graph.getData() failed: ${e}`);
|
|
55204
|
-
return 0;
|
|
55205
|
-
}
|
|
55206
|
-
let nodes = is_array(data.nodes) ? data.nodes : [];
|
|
55207
|
-
let states = {};
|
|
55208
|
-
for (let id of priv._focus_ids || []) states[id] = [];
|
|
55209
|
-
let ids = [];
|
|
55749
|
+
let model = priv._fold_model;
|
|
55750
|
+
let state = priv._fold_state;
|
|
55751
|
+
let keys = [];
|
|
55210
55752
|
if (!empty_string(term)) {
|
|
55211
55753
|
let needle = String(term).toLowerCase();
|
|
55212
|
-
for (let
|
|
55213
|
-
|
|
55214
|
-
let record = n.data.record || {};
|
|
55754
|
+
for (let node of model.nodes.values()) {
|
|
55755
|
+
let record = node.record || {};
|
|
55215
55756
|
let label = "";
|
|
55216
55757
|
try {
|
|
55217
|
-
label = node_label(
|
|
55758
|
+
label = node_label(priv.descs[node.topic_name] || {}, record) || "";
|
|
55218
55759
|
} catch (e) {
|
|
55219
55760
|
label = "";
|
|
55220
55761
|
}
|
|
55221
55762
|
if ([
|
|
55222
55763
|
label,
|
|
55223
55764
|
record.id,
|
|
55224
|
-
|
|
55225
|
-
].filter((v) => typeof v === "string").join(" ").toLowerCase().includes(needle))
|
|
55765
|
+
node.topic_name
|
|
55766
|
+
].filter((v) => typeof v === "string").join(" ").toLowerCase().includes(needle)) keys.push(node.key);
|
|
55226
55767
|
}
|
|
55227
|
-
for (let id of ids) states[id] = ["active"];
|
|
55228
55768
|
}
|
|
55229
|
-
let
|
|
55230
|
-
|
|
55231
|
-
|
|
55232
|
-
|
|
55233
|
-
if (
|
|
55234
|
-
|
|
55235
|
-
|
|
55236
|
-
} catch (e) {
|
|
55237
|
-
log_error(`${gobj_short_name(gobj)}: find apply failed: ${e}`);
|
|
55769
|
+
let visible = fold_visible_set(model, state);
|
|
55770
|
+
let revealed = 0;
|
|
55771
|
+
for (let key of keys) {
|
|
55772
|
+
if (visible.has(key)) continue;
|
|
55773
|
+
if (revealed >= state.page_size) break;
|
|
55774
|
+
fold_reveal(model, state, key);
|
|
55775
|
+
revealed++;
|
|
55238
55776
|
}
|
|
55239
|
-
|
|
55777
|
+
priv._focus_topic = null;
|
|
55778
|
+
reconcile_fold(gobj, {}).then(() => {
|
|
55779
|
+
apply_focus_ids(gobj, keys, "find");
|
|
55780
|
+
});
|
|
55781
|
+
return keys.length;
|
|
55240
55782
|
}
|
|
55241
55783
|
async function graph_zoom_in(gobj) {
|
|
55242
55784
|
let graph = gobj.priv.graph;
|
|
@@ -55349,20 +55891,43 @@ var LightNode = class extends Circle {
|
|
|
55349
55891
|
************************************************************/
|
|
55350
55892
|
var ManualLayout = class extends BaseLayout {
|
|
55351
55893
|
async execute(data, options) {
|
|
55352
|
-
const { nodes = [] } = data;
|
|
55353
|
-
|
|
55354
|
-
|
|
55355
|
-
|
|
55894
|
+
const { nodes = [], edges = [] } = data;
|
|
55895
|
+
let placed = {};
|
|
55896
|
+
let out = [];
|
|
55897
|
+
let chips = [];
|
|
55898
|
+
for (let node of nodes) {
|
|
55899
|
+
let d = node.data || {};
|
|
55900
|
+
if (d.more) {
|
|
55901
|
+
chips.push(node);
|
|
55902
|
+
continue;
|
|
55903
|
+
}
|
|
55904
|
+
let gp = d.graph_props;
|
|
55905
|
+
let geo = d.record ? d.record._geometry : null;
|
|
55356
55906
|
let x = gp && gp.x != null ? gp.x : geo && geo.x != null ? geo.x : 0;
|
|
55357
55907
|
let y = gp && gp.y != null ? gp.y : geo && geo.y != null ? geo.y : 0;
|
|
55358
|
-
|
|
55908
|
+
placed[node.id] = [x, y];
|
|
55909
|
+
out.push({
|
|
55359
55910
|
id: node.id,
|
|
55360
55911
|
style: {
|
|
55361
55912
|
x,
|
|
55362
55913
|
y
|
|
55363
55914
|
}
|
|
55364
|
-
};
|
|
55365
|
-
}
|
|
55915
|
+
});
|
|
55916
|
+
}
|
|
55917
|
+
for (let node of chips) {
|
|
55918
|
+
let edge = edges.find((e) => e.target === node.id);
|
|
55919
|
+
let p = edge ? placed[edge.source] : null;
|
|
55920
|
+
let x = p ? p[0] : node.style && node.style.x || 0;
|
|
55921
|
+
let y = p ? p[1] + 80 : node.style && node.style.y || 0;
|
|
55922
|
+
out.push({
|
|
55923
|
+
id: node.id,
|
|
55924
|
+
style: {
|
|
55925
|
+
x,
|
|
55926
|
+
y
|
|
55927
|
+
}
|
|
55928
|
+
});
|
|
55929
|
+
}
|
|
55930
|
+
return { nodes: out };
|
|
55366
55931
|
}
|
|
55367
55932
|
};
|
|
55368
55933
|
/************************************************************
|
|
@@ -56866,7 +57431,7 @@ function show_node_popover(gobj) {
|
|
|
56866
57431
|
};
|
|
56867
57432
|
if (node_graph_type === "hierarchical") {
|
|
56868
57433
|
let record = nodeData.data.record || {};
|
|
56869
|
-
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
|
|
57434
|
+
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id, false, false, false, pills_html_of(gobj, nodeData));
|
|
56870
57435
|
}
|
|
56871
57436
|
graph.updateNodeData([{
|
|
56872
57437
|
id: node_id,
|
|
@@ -56906,7 +57471,7 @@ function show_node_popover(gobj) {
|
|
|
56906
57471
|
};
|
|
56907
57472
|
if (node_graph_type === "hierarchical") {
|
|
56908
57473
|
let record = nodeData.data.record || {};
|
|
56909
|
-
restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id);
|
|
57474
|
+
restoreStyle.innerHTML = build_node_innerHTML(origFill, priv.theme, record.icon, node_label(nodeData.data.desc, record), nodeData.data.desc.topic_name, false, record.id, false, false, false, pills_html_of(gobj, nodeData));
|
|
56910
57475
|
}
|
|
56911
57476
|
graph.updateNodeData([{
|
|
56912
57477
|
id: node_id,
|
|
@@ -57091,6 +57656,7 @@ function refresh_minimap(gobj) {
|
|
|
57091
57656
|
let nd = graph.getNodeData(id);
|
|
57092
57657
|
let size = nd && nd.style && nd.style.size || [120, 60];
|
|
57093
57658
|
let color = nd && nd.data && nd.data.desc && nd.data.desc.color || "#94a3b8";
|
|
57659
|
+
if (is_more_node(nd)) color = "rgba(148, 163, 184, 0.35)";
|
|
57094
57660
|
return new Rect({ style: {
|
|
57095
57661
|
x: -size[0] / 2,
|
|
57096
57662
|
y: -size[1] / 2,
|
|
@@ -57113,15 +57679,15 @@ function refresh_minimap(gobj) {
|
|
|
57113
57679
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
57114
57680
|
* shared now. Returns null for a node that carries no desc.
|
|
57115
57681
|
************************************************************/
|
|
57116
|
-
function node_innerHTML_of(nd, theme, highlight, selected, anchored) {
|
|
57682
|
+
function node_innerHTML_of(nd, theme, highlight, selected, anchored, pills_html) {
|
|
57117
57683
|
if (!nd || !nd.data || !nd.data.desc) return null;
|
|
57118
57684
|
let desc = nd.data.desc;
|
|
57119
57685
|
let record = nd.data.record || {};
|
|
57120
57686
|
let label = node_label(desc, record);
|
|
57121
57687
|
switch (desc.node_treedb_type) {
|
|
57122
57688
|
case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight, selected, anchored);
|
|
57123
|
-
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected, anchored);
|
|
57124
|
-
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected, anchored);
|
|
57689
|
+
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected, anchored, pills_html);
|
|
57690
|
+
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected, anchored, pills_html);
|
|
57125
57691
|
}
|
|
57126
57692
|
return null;
|
|
57127
57693
|
}
|
|
@@ -57142,7 +57708,13 @@ function repaint_cards(gobj, ids) {
|
|
|
57142
57708
|
let selected = new Set(priv._selected_paint_ids || []);
|
|
57143
57709
|
let updates = [];
|
|
57144
57710
|
for (let id of ids) {
|
|
57145
|
-
let
|
|
57711
|
+
let nd;
|
|
57712
|
+
try {
|
|
57713
|
+
nd = graph.getNodeData(id);
|
|
57714
|
+
} catch (e) {
|
|
57715
|
+
continue;
|
|
57716
|
+
}
|
|
57717
|
+
let html = node_innerHTML_of(nd, priv.theme, focus.has(id), selected.has(id), priv.anchor_state === "on" && id === priv.anchor_id, pills_html_of(gobj, nd));
|
|
57146
57718
|
if (html !== null) updates.push({
|
|
57147
57719
|
id,
|
|
57148
57720
|
style: { innerHTML: html }
|
|
@@ -57178,7 +57750,9 @@ function refresh_html_nodes_theme(gobj, theme) {
|
|
|
57178
57750
|
let updates = [];
|
|
57179
57751
|
for (let i = 0; i < nodes.length; i++) {
|
|
57180
57752
|
let id = nodes[i].id;
|
|
57181
|
-
let
|
|
57753
|
+
let nd = graph.getNodeData(id);
|
|
57754
|
+
let html = node_innerHTML_of(nd, theme, highlighted.has(id), selected.has(id), priv.anchor_state === "on" && id === priv.anchor_id, pills_html_of(gobj, nd));
|
|
57755
|
+
if (html === null) html = more_innerHTML_of(gobj, nd, theme);
|
|
57182
57756
|
if (html !== null) updates.push({
|
|
57183
57757
|
id,
|
|
57184
57758
|
style: { innerHTML: html }
|
|
@@ -57293,7 +57867,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
57293
57867
|
* colour is kept (per-topic differentiation) but softened via
|
|
57294
57868
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
57295
57869
|
************************************************************/
|
|
57296
|
-
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected, anchored) {
|
|
57870
|
+
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected, anchored, pills_html) {
|
|
57297
57871
|
let title = key || label;
|
|
57298
57872
|
let dark = theme === "dark";
|
|
57299
57873
|
let surface = dark ? "#1b2230" : "#ffffff";
|
|
@@ -57327,6 +57901,12 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
57327
57901
|
margin-top: 2px; max-width: 100%;
|
|
57328
57902
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
57329
57903
|
">${escapeHtml(topic_name)}</div>`;
|
|
57904
|
+
let pills_row = "";
|
|
57905
|
+
if (pills_html) pills_row = `
|
|
57906
|
+
<div class="TREEDB_PILLS" style="
|
|
57907
|
+
display: flex; flex-wrap: nowrap; gap: 4px; justify-content: center;
|
|
57908
|
+
margin-top: 6px; max-width: 100%; overflow: hidden;
|
|
57909
|
+
">${pills_html}</div>`;
|
|
57330
57910
|
return `
|
|
57331
57911
|
<div class="TREEDB_CARD" title="${escapeHtml(title)}" style="
|
|
57332
57912
|
box-sizing: border-box;
|
|
@@ -57352,7 +57932,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
57352
57932
|
max-width: 100%; overflow: hidden; text-overflow: ellipsis;
|
|
57353
57933
|
display: -webkit-box; -webkit-line-clamp: 2;
|
|
57354
57934
|
-webkit-box-orient: vertical; word-break: break-word;
|
|
57355
|
-
">${escapeHtml(label)}</div>${sub_html}
|
|
57935
|
+
">${escapeHtml(label)}</div>${sub_html}${pills_row}
|
|
57356
57936
|
</div>
|
|
57357
57937
|
`;
|
|
57358
57938
|
}
|
|
@@ -57385,7 +57965,7 @@ function execute_delete_node(gobj, nodeData) {
|
|
|
57385
57965
|
function select_all_nodes(gobj) {
|
|
57386
57966
|
let graph = gobj.priv.graph;
|
|
57387
57967
|
if (!graph) return;
|
|
57388
|
-
set_selection(gobj, ((graph.getData() || {}).nodes || []).map((nd) => nd.id));
|
|
57968
|
+
set_selection(gobj, ((graph.getData() || {}).nodes || []).filter((nd) => nd.data && nd.data.desc).map((nd) => nd.id));
|
|
57389
57969
|
}
|
|
57390
57970
|
/************************************************************
|
|
57391
57971
|
* The nodes currently selected, as their node data.
|
|
@@ -57649,7 +58229,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope) {
|
|
|
57649
58229
|
};
|
|
57650
58230
|
if (nd.data.desc.node_treedb_type === "hierarchical") {
|
|
57651
58231
|
let record = nd.data.record || {};
|
|
57652
|
-
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id);
|
|
58232
|
+
updateStyle.innerHTML = build_node_innerHTML(fill, priv.theme, record.icon, node_label(nd.data.desc, record), nd.data.desc.topic_name, false, record.id, false, false, false, pills_html_of(gobj, nd));
|
|
57653
58233
|
}
|
|
57654
58234
|
updates.push({
|
|
57655
58235
|
id: nodes[i].id,
|
|
@@ -57725,7 +58305,7 @@ function apply_edge_properties(gobj, edge_id, lineWidth, stroke, scope) {
|
|
|
57725
58305
|
function update_edge_geometry(gobj, edge_id) {
|
|
57726
58306
|
let priv = gobj.priv;
|
|
57727
58307
|
let edgeData = priv.graph.getEdgeData(edge_id);
|
|
57728
|
-
if (!edgeData || !edgeData.data) return;
|
|
58308
|
+
if (!edgeData || !edgeData.data || !edgeData.data.parent_topic) return;
|
|
57729
58309
|
let style = edgeData.style || {};
|
|
57730
58310
|
let lineWidth = style.lineWidth;
|
|
57731
58311
|
let stroke = style.stroke;
|
|
@@ -57866,7 +58446,7 @@ function copy_size_to_nodes(gobj, same_topic_only) {
|
|
|
57866
58446
|
const nodes = graph.getData().nodes;
|
|
57867
58447
|
for (let i = 0; i < nodes.length; i++) {
|
|
57868
58448
|
let nd = graph.getNodeData(nodes[i].id);
|
|
57869
|
-
if (!nd || !nd.data) continue;
|
|
58449
|
+
if (!nd || !nd.data || !nd.data.desc) continue;
|
|
57870
58450
|
if (same_topic_only && nd.data.topic_name !== source_topic) continue;
|
|
57871
58451
|
if (nodes[i].id === node_id) continue;
|
|
57872
58452
|
let updateStyle = { size: [...source_size] };
|
|
@@ -57954,6 +58534,415 @@ function copy_size_to_ports(gobj, same_topic_only) {
|
|
|
57954
58534
|
}
|
|
57955
58535
|
}
|
|
57956
58536
|
/***************************
|
|
58537
|
+
* Folding
|
|
58538
|
+
***************************/
|
|
58539
|
+
var PILL_ROW_HEIGHT = 24;
|
|
58540
|
+
var MORE_CHIP_SIZE = [76, 26];
|
|
58541
|
+
/************************************************************
|
|
58542
|
+
* The three card sizes, with room for the pill row when there
|
|
58543
|
+
* is one. A chip (pure child) never has pills: it has no hooks.
|
|
58544
|
+
************************************************************/
|
|
58545
|
+
function card_size_for(node_treedb_type, has_pills) {
|
|
58546
|
+
let extra = has_pills ? PILL_ROW_HEIGHT : 0;
|
|
58547
|
+
switch (node_treedb_type) {
|
|
58548
|
+
case "child": return [116, 40];
|
|
58549
|
+
case "extended": return [144, 66 + extra];
|
|
58550
|
+
default: return [172, 96 + extra];
|
|
58551
|
+
}
|
|
58552
|
+
}
|
|
58553
|
+
/************************************************************
|
|
58554
|
+
* The model's key of a G6 record node, or "" for anything else.
|
|
58555
|
+
************************************************************/
|
|
58556
|
+
function node_key_of(nd) {
|
|
58557
|
+
if (!nd || !nd.data || !nd.data.desc || !nd.data.record) return "";
|
|
58558
|
+
return fold_node_key(nd.data.desc.topic_name, String(nd.data.record.id));
|
|
58559
|
+
}
|
|
58560
|
+
function is_more_node(nd) {
|
|
58561
|
+
return !!(nd && nd.data && nd.data.more);
|
|
58562
|
+
}
|
|
58563
|
+
function more_node_id(gobj, group_key) {
|
|
58564
|
+
return sprintf("more-%s-%s", gobj.priv.treedb_name, group_key);
|
|
58565
|
+
}
|
|
58566
|
+
function more_edge_id(gobj, group_key) {
|
|
58567
|
+
return sprintf("more-edge-%s-%s", gobj.priv.treedb_name, group_key);
|
|
58568
|
+
}
|
|
58569
|
+
/************************************************************
|
|
58570
|
+
* The colours of a pill or a chip, from the topic colour it
|
|
58571
|
+
* stands for -- the CHILD topic, the same colour its hook port
|
|
58572
|
+
* wears, so the pill and the port say the same thing.
|
|
58573
|
+
************************************************************/
|
|
58574
|
+
function pill_colors(color, theme) {
|
|
58575
|
+
let dark = theme === "dark";
|
|
58576
|
+
return {
|
|
58577
|
+
bg: dark ? `color-mix(in srgb, ${color} 45%, #1b2230)` : `color-mix(in srgb, ${color} 22%, #ffffff)`,
|
|
58578
|
+
fg: dark ? `color-mix(in srgb, ${color} 35%, #ffffff)` : `color-mix(in srgb, ${color} 55%, #0f172a)`,
|
|
58579
|
+
border: dark ? `color-mix(in srgb, ${color} 80%, #ffffff)` : color
|
|
58580
|
+
};
|
|
58581
|
+
}
|
|
58582
|
+
/************************************************************
|
|
58583
|
+
* One pill: `▸ devices 142` folded, `▾ devices 24/142` open on a
|
|
58584
|
+
* page, `▾ devices 142` open whole. A glyph and numbers on
|
|
58585
|
+
* purpose: the card is an innerHTML string where a WORD could
|
|
58586
|
+
* carry no i18n key, and the hook name is a schema identifier,
|
|
58587
|
+
* like the topic subtitle above it.
|
|
58588
|
+
************************************************************/
|
|
58589
|
+
function build_pill_html(pill, color, theme) {
|
|
58590
|
+
let c = pill_colors(color, theme);
|
|
58591
|
+
let glyph = pill.open ? "▾" : "▸";
|
|
58592
|
+
let count = pill.open && pill.shown < pill.total ? `${pill.shown}/${pill.total}` : `${pill.total}`;
|
|
58593
|
+
return `<span class="TREEDB_PILL" data-fold-group="${escapeHtml(pill.group_key)}"
|
|
58594
|
+
title="${escapeHtml(pill.hook)}" style="
|
|
58595
|
+
display: inline-flex; align-items: center; gap: 3px; flex: 0 1 auto;
|
|
58596
|
+
height: 16px; padding: 0 6px; border-radius: 8px;
|
|
58597
|
+
background: ${c.bg}; color: ${c.fg}; border: 1px solid ${c.border};
|
|
58598
|
+
font-size: 10px; font-weight: 700; line-height: 1; white-space: nowrap;
|
|
58599
|
+
overflow: hidden; text-overflow: ellipsis;
|
|
58600
|
+
cursor: pointer; user-select: none;
|
|
58601
|
+
"><span style="font-size: 9px;">${glyph}</span>${escapeHtml(pill.hook)}<span style="opacity: .75; font-weight: 600;">${count}</span></span>`;
|
|
58602
|
+
}
|
|
58603
|
+
/************************************************************
|
|
58604
|
+
* The pill row of one node, as html; "" when it has nothing to
|
|
58605
|
+
* fold or the model is not built yet.
|
|
58606
|
+
************************************************************/
|
|
58607
|
+
function pills_html_of_key(gobj, node_key) {
|
|
58608
|
+
let priv = gobj.priv;
|
|
58609
|
+
if (!priv._fold_model || !priv._fold_state || !node_key) return "";
|
|
58610
|
+
let pills = fold_pills_of(priv._fold_model, priv._fold_state, node_key);
|
|
58611
|
+
if (!pills.length) return "";
|
|
58612
|
+
let out = [];
|
|
58613
|
+
for (let pill of pills) {
|
|
58614
|
+
let child_desc = priv.descs ? priv.descs[pill.child_topic] : null;
|
|
58615
|
+
let color = child_desc && child_desc.color || "#94a3b8";
|
|
58616
|
+
out.push(build_pill_html(pill, color, priv.theme));
|
|
58617
|
+
}
|
|
58618
|
+
return out.join("");
|
|
58619
|
+
}
|
|
58620
|
+
function pills_html_of(gobj, nd) {
|
|
58621
|
+
return pills_html_of_key(gobj, node_key_of(nd));
|
|
58622
|
+
}
|
|
58623
|
+
function pills_signature(gobj, node_key) {
|
|
58624
|
+
let priv = gobj.priv;
|
|
58625
|
+
if (!priv._fold_model || !priv._fold_state) return "";
|
|
58626
|
+
return fold_pills_of(priv._fold_model, priv._fold_state, node_key).map((p) => `${p.hook}:${p.open ? p.shown : "-"}/${p.total}`).join(",");
|
|
58627
|
+
}
|
|
58628
|
+
/************************************************************
|
|
58629
|
+
* The `+N` chip at the end of a page: the rest of the group,
|
|
58630
|
+
* in the child topic's colour, dashed like a cut. Its title is
|
|
58631
|
+
* the one WORD of the folding, and it is translated at build
|
|
58632
|
+
* time: the chips are rebuilt on a language change.
|
|
58633
|
+
************************************************************/
|
|
58634
|
+
function build_more_innerHTML(color, theme, rest) {
|
|
58635
|
+
let c = pill_colors(color, theme);
|
|
58636
|
+
return `
|
|
58637
|
+
<div class="TREEDB_MORE" title="${escapeHtml(t("show more"))}" style="
|
|
58638
|
+
box-sizing: border-box; width: 100%; height: 100%;
|
|
58639
|
+
display: flex; align-items: center; justify-content: center; gap: 4px;
|
|
58640
|
+
background: ${c.bg}; color: ${c.fg}; border: 1px dashed ${c.border};
|
|
58641
|
+
border-radius: 13px;
|
|
58642
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
58643
|
+
font-size: 12px; font-weight: 700; line-height: 1;
|
|
58644
|
+
cursor: pointer; user-select: none;
|
|
58645
|
+
">+${rest}<span style="font-size: 10px; opacity: .8;">…</span></div>
|
|
58646
|
+
`;
|
|
58647
|
+
}
|
|
58648
|
+
function more_innerHTML_of(gobj, nd, theme) {
|
|
58649
|
+
if (!is_more_node(nd)) return null;
|
|
58650
|
+
let priv = gobj.priv;
|
|
58651
|
+
let child_desc = priv.descs ? priv.descs[nd.data.child_topic] : null;
|
|
58652
|
+
return build_more_innerHTML(child_desc && child_desc.color || "#94a3b8", theme, nd.data.rest);
|
|
58653
|
+
}
|
|
58654
|
+
/************************************************************
|
|
58655
|
+
* The pills live inside an `innerHTML` string, so no handler can
|
|
58656
|
+
* be attached to them: the click is delegated from the container
|
|
58657
|
+
* in the CAPTURE phase over four event types -- the same door the
|
|
58658
|
+
* JSON graph opens for its fold handles, for the same reasons: G6
|
|
58659
|
+
* binds on the html node element, a descendant, so only capture
|
|
58660
|
+
* runs first; and G6 never reads the DOM `click`, it builds its
|
|
58661
|
+
* own from the pointer pair, so `pointerdown`/`pointerup` are the
|
|
58662
|
+
* ones that have to be cut or the card is ALSO clicked.
|
|
58663
|
+
************************************************************/
|
|
58664
|
+
var FOLD_SWALLOWED_EVENTS = [
|
|
58665
|
+
"pointerdown",
|
|
58666
|
+
"pointerup",
|
|
58667
|
+
"mousedown",
|
|
58668
|
+
"click"
|
|
58669
|
+
];
|
|
58670
|
+
function install_fold_listener(gobj) {
|
|
58671
|
+
let priv = gobj.priv;
|
|
58672
|
+
if (!priv.$container) {
|
|
58673
|
+
log_error(`${gobj_short_name(gobj)}: no container, the fold pills are dead`);
|
|
58674
|
+
return;
|
|
58675
|
+
}
|
|
58676
|
+
priv._fold_listener = function(evt) {
|
|
58677
|
+
let $pill = evt.target && evt.target.closest ? evt.target.closest("[data-fold-group]") : null;
|
|
58678
|
+
if (!$pill) return;
|
|
58679
|
+
evt.stopPropagation();
|
|
58680
|
+
evt.preventDefault();
|
|
58681
|
+
if (evt.type !== "click") return;
|
|
58682
|
+
gobj_send_event(gobj, "EV_TOGGLE_FOLD", { group: $pill.getAttribute("data-fold-group") }, gobj);
|
|
58683
|
+
};
|
|
58684
|
+
for (let type of FOLD_SWALLOWED_EVENTS) priv.$container.addEventListener(type, priv._fold_listener, true);
|
|
58685
|
+
}
|
|
58686
|
+
function uninstall_fold_listener(gobj) {
|
|
58687
|
+
let priv = gobj.priv;
|
|
58688
|
+
if (priv._fold_listener && priv.$container) for (let type of FOLD_SWALLOWED_EVENTS) priv.$container.removeEventListener(type, priv._fold_listener, true);
|
|
58689
|
+
priv._fold_listener = null;
|
|
58690
|
+
}
|
|
58691
|
+
/************************************************************
|
|
58692
|
+
* (Re)build the tree of the records. Cheap -- one pass over the
|
|
58693
|
+
* records -- so it runs again on every create/update/delete
|
|
58694
|
+
* rather than being patched. The fold state survives: it is
|
|
58695
|
+
* keyed by group, and a group that is gone is simply never read.
|
|
58696
|
+
************************************************************/
|
|
58697
|
+
function rebuild_fold_model(gobj) {
|
|
58698
|
+
let priv = gobj.priv;
|
|
58699
|
+
priv._fold_model = fold_build_model(priv.descs || {}, priv.records || {});
|
|
58700
|
+
if (!priv._fold_state) priv._fold_state = fold_new_state(gobj_read_integer_attr(gobj, "fold_page_size"));
|
|
58701
|
+
if (!priv._pill_sig) priv._pill_sig = /* @__PURE__ */ new Map();
|
|
58702
|
+
}
|
|
58703
|
+
/************************************************************
|
|
58704
|
+
* How many records there are, and how many carry a saved
|
|
58705
|
+
* position -- what auto_layout decides on. Counted over the
|
|
58706
|
+
* RECORDS, because the nodes on screen are a fraction of them.
|
|
58707
|
+
************************************************************/
|
|
58708
|
+
function count_placed_records(gobj) {
|
|
58709
|
+
let priv = gobj.priv;
|
|
58710
|
+
priv._nodes_total = 0;
|
|
58711
|
+
priv._nodes_placed = 0;
|
|
58712
|
+
for (const [topic_name, records] of Object.entries(priv.records || {})) {
|
|
58713
|
+
if (topic_name.substring(0, 2) === "__" || !is_array(records)) continue;
|
|
58714
|
+
for (let record of records) {
|
|
58715
|
+
priv._nodes_total++;
|
|
58716
|
+
if (geometry_has_position(get_node_graph_props(gobj, topic_name, record.id, record))) priv._nodes_placed++;
|
|
58717
|
+
}
|
|
58718
|
+
}
|
|
58719
|
+
}
|
|
58720
|
+
/************************************************************
|
|
58721
|
+
* Make the G6 data say what the fold model says is visible.
|
|
58722
|
+
*
|
|
58723
|
+
* Record nodes not visible any more are removed (their edges go
|
|
58724
|
+
* with them), the visible ones missing are created, the links
|
|
58725
|
+
* between visible nodes are drawn, the `+N` chips are placed or
|
|
58726
|
+
* taken away, and every card whose pills changed is repainted.
|
|
58727
|
+
* Then a draw, a layout if the set of nodes changed, and the
|
|
58728
|
+
* camera: fit the whole thing on the first load, or put `keep`
|
|
58729
|
+
* back where it was on screen before the change.
|
|
58730
|
+
*
|
|
58731
|
+
* Serialised: one reconcile at a time, in order. Two pills tapped
|
|
58732
|
+
* quickly would otherwise interleave their draws.
|
|
58733
|
+
*
|
|
58734
|
+
* opts.relayout run the layout even if no node came or went
|
|
58735
|
+
* opts.fit fit the viewport afterwards
|
|
58736
|
+
* opts.keep node id to hold still on screen
|
|
58737
|
+
* opts.keep_vp where it was ([x, y] viewport px)
|
|
58738
|
+
************************************************************/
|
|
58739
|
+
function reconcile_fold(gobj, opts) {
|
|
58740
|
+
let priv = gobj.priv;
|
|
58741
|
+
let run = () => reconcile_fold_now(gobj, opts || {}).catch((e) => {
|
|
58742
|
+
log_error(`${gobj_short_name(gobj)}: reconcile failed: ${e}`);
|
|
58743
|
+
});
|
|
58744
|
+
priv._fold_chain = (priv._fold_chain || Promise.resolve()).then(run, run);
|
|
58745
|
+
return priv._fold_chain;
|
|
58746
|
+
}
|
|
58747
|
+
async function reconcile_fold_now(gobj, opts) {
|
|
58748
|
+
let priv = gobj.priv;
|
|
58749
|
+
let graph = priv.graph;
|
|
58750
|
+
let model = priv._fold_model;
|
|
58751
|
+
let state = priv._fold_state;
|
|
58752
|
+
if (!graph || !model || !state || gobj_is_destroying(gobj)) return;
|
|
58753
|
+
let visible = fold_visible_set(model, state);
|
|
58754
|
+
let changed = false;
|
|
58755
|
+
history_pause(gobj);
|
|
58756
|
+
try {
|
|
58757
|
+
changed = await reconcile_fold_apply(gobj, opts, visible);
|
|
58758
|
+
} finally {
|
|
58759
|
+
history_resume(gobj);
|
|
58760
|
+
}
|
|
58761
|
+
return changed;
|
|
58762
|
+
}
|
|
58763
|
+
async function reconcile_fold_apply(gobj, opts, visible) {
|
|
58764
|
+
let priv = gobj.priv;
|
|
58765
|
+
let graph = priv.graph;
|
|
58766
|
+
let model = priv._fold_model;
|
|
58767
|
+
let state = priv._fold_state;
|
|
58768
|
+
let changed = false;
|
|
58769
|
+
let present = /* @__PURE__ */ new Map();
|
|
58770
|
+
let more_present = /* @__PURE__ */ new Map();
|
|
58771
|
+
for (let nd of graph.getNodeData() || []) {
|
|
58772
|
+
if (is_more_node(nd)) {
|
|
58773
|
+
more_present.set(nd.data.more, nd.id);
|
|
58774
|
+
continue;
|
|
58775
|
+
}
|
|
58776
|
+
let key = node_key_of(nd);
|
|
58777
|
+
if (key) present.set(key, nd.id);
|
|
58778
|
+
}
|
|
58779
|
+
let to_remove = [];
|
|
58780
|
+
for (let [key, id] of present) if (!visible.has(key)) to_remove.push(id);
|
|
58781
|
+
if (to_remove.length) {
|
|
58782
|
+
let gone = new Set(to_remove);
|
|
58783
|
+
if (priv._selected_node_id && gone.has(priv._selected_node_id)) deselect_node(gobj);
|
|
58784
|
+
if (priv._detail_node_id && gone.has(priv._detail_node_id)) hide_node_detail(gobj);
|
|
58785
|
+
priv._focus_ids = (priv._focus_ids || []).filter((id) => !gone.has(id));
|
|
58786
|
+
priv._selected_paint_ids = (priv._selected_paint_ids || []).filter((id) => !gone.has(id));
|
|
58787
|
+
if (priv.anchor_state === "on" && gone.has(priv.anchor_id)) {
|
|
58788
|
+
priv.anchor_id = "";
|
|
58789
|
+
priv.anchor_state = "off";
|
|
58790
|
+
update_toolbar(gobj);
|
|
58791
|
+
}
|
|
58792
|
+
for (let id of to_remove) priv._pill_sig.delete(id);
|
|
58793
|
+
graph.removeNodeData(to_remove);
|
|
58794
|
+
changed = true;
|
|
58795
|
+
}
|
|
58796
|
+
for (let key of visible) {
|
|
58797
|
+
if (present.has(key)) continue;
|
|
58798
|
+
let node = model.nodes.get(key);
|
|
58799
|
+
let desc = priv.descs[node.topic_name];
|
|
58800
|
+
if (!desc) {
|
|
58801
|
+
log_error(`${gobj_short_name(gobj)}: no desc for ${key}`);
|
|
58802
|
+
continue;
|
|
58803
|
+
}
|
|
58804
|
+
create_topic_node(gobj, desc, node.record);
|
|
58805
|
+
priv._pill_sig.set(build_node_name(gobj, node.topic_name, node.id), pills_signature(gobj, key));
|
|
58806
|
+
changed = true;
|
|
58807
|
+
}
|
|
58808
|
+
for (let key of visible) {
|
|
58809
|
+
let node = model.nodes.get(key);
|
|
58810
|
+
let desc = priv.descs[node.topic_name];
|
|
58811
|
+
if (desc) draw_links(gobj, desc, node.record, false);
|
|
58812
|
+
}
|
|
58813
|
+
let pending = fold_pending_groups(model, state, visible);
|
|
58814
|
+
let wanted = /* @__PURE__ */ new Map();
|
|
58815
|
+
for (let p of pending) wanted.set(p.group_key, p);
|
|
58816
|
+
let more_gone = [];
|
|
58817
|
+
for (let [group_key, id] of more_present) if (!wanted.has(group_key)) more_gone.push(id);
|
|
58818
|
+
if (more_gone.length) {
|
|
58819
|
+
graph.removeNodeData(more_gone);
|
|
58820
|
+
changed = true;
|
|
58821
|
+
}
|
|
58822
|
+
for (let p of pending) {
|
|
58823
|
+
let first = model.nodes.get((model.groups.get(p.group_key) || [])[0]);
|
|
58824
|
+
let child_topic = first ? first.topic_name : "";
|
|
58825
|
+
let child_desc = priv.descs[child_topic];
|
|
58826
|
+
let color = child_desc && child_desc.color || "#94a3b8";
|
|
58827
|
+
let id = more_node_id(gobj, p.group_key);
|
|
58828
|
+
if (more_present.has(p.group_key)) {
|
|
58829
|
+
let nd = graph.getNodeData(id);
|
|
58830
|
+
if (nd && nd.data.rest !== p.rest) {
|
|
58831
|
+
nd.data.rest = p.rest;
|
|
58832
|
+
graph.updateNodeData([{
|
|
58833
|
+
id,
|
|
58834
|
+
style: { innerHTML: build_more_innerHTML(color, priv.theme, p.rest) }
|
|
58835
|
+
}]);
|
|
58836
|
+
}
|
|
58837
|
+
continue;
|
|
58838
|
+
}
|
|
58839
|
+
let xy = get_default_ne_xy(gobj);
|
|
58840
|
+
graph.addNodeData([{
|
|
58841
|
+
id,
|
|
58842
|
+
type: "html",
|
|
58843
|
+
style: {
|
|
58844
|
+
x: xy,
|
|
58845
|
+
y: xy,
|
|
58846
|
+
size: [...MORE_CHIP_SIZE],
|
|
58847
|
+
dx: -MORE_CHIP_SIZE[0] / 2,
|
|
58848
|
+
dy: -MORE_CHIP_SIZE[1] / 2,
|
|
58849
|
+
innerHTML: build_more_innerHTML(color, priv.theme, p.rest)
|
|
58850
|
+
},
|
|
58851
|
+
data: {
|
|
58852
|
+
more: p.group_key,
|
|
58853
|
+
child_topic,
|
|
58854
|
+
rest: p.rest
|
|
58855
|
+
}
|
|
58856
|
+
}]);
|
|
58857
|
+
if (p.node_key) {
|
|
58858
|
+
let parent = model.nodes.get(p.node_key);
|
|
58859
|
+
let dark = priv.theme === "dark";
|
|
58860
|
+
graph.addEdgeData([{
|
|
58861
|
+
id: more_edge_id(gobj, p.group_key),
|
|
58862
|
+
type: edge_type_for(gobj),
|
|
58863
|
+
source: build_node_name(gobj, parent.topic_name, parent.id),
|
|
58864
|
+
target: id,
|
|
58865
|
+
style: {
|
|
58866
|
+
sourcePort: p.hook,
|
|
58867
|
+
lineWidth: 1,
|
|
58868
|
+
lineDash: [4, 3],
|
|
58869
|
+
stroke: dark ? "#8b94a3" : "#94a3b8",
|
|
58870
|
+
startArrow: false,
|
|
58871
|
+
endArrow: false
|
|
58872
|
+
},
|
|
58873
|
+
data: { more: p.group_key }
|
|
58874
|
+
}]);
|
|
58875
|
+
}
|
|
58876
|
+
changed = true;
|
|
58877
|
+
}
|
|
58878
|
+
let repaint = /* @__PURE__ */ new Set();
|
|
58879
|
+
let resize = [];
|
|
58880
|
+
for (let key of visible) {
|
|
58881
|
+
let node = model.nodes.get(key);
|
|
58882
|
+
let id = build_node_name(gobj, node.topic_name, node.id);
|
|
58883
|
+
let sig = pills_signature(gobj, key);
|
|
58884
|
+
if (priv._pill_sig.get(id) === sig) continue;
|
|
58885
|
+
let had = !!priv._pill_sig.get(id);
|
|
58886
|
+
priv._pill_sig.set(id, sig);
|
|
58887
|
+
repaint.add(id);
|
|
58888
|
+
if (had !== !!sig) {
|
|
58889
|
+
let nd = graph.getNodeData(id);
|
|
58890
|
+
let desc = nd && nd.data && nd.data.desc;
|
|
58891
|
+
let geometry = nd && nd.data && nd.data.graph_props || {};
|
|
58892
|
+
if (desc && !is_array(geometry.size)) {
|
|
58893
|
+
let size = card_size_for(desc.node_treedb_type, !!sig);
|
|
58894
|
+
resize.push({
|
|
58895
|
+
id,
|
|
58896
|
+
style: {
|
|
58897
|
+
size,
|
|
58898
|
+
dx: -size[0] / 2,
|
|
58899
|
+
dy: -size[1] / 2
|
|
58900
|
+
}
|
|
58901
|
+
});
|
|
58902
|
+
}
|
|
58903
|
+
}
|
|
58904
|
+
}
|
|
58905
|
+
if (resize.length) graph.updateNodeData(resize);
|
|
58906
|
+
if (repaint.size) repaint_cards(gobj, repaint);
|
|
58907
|
+
try {
|
|
58908
|
+
refresh_minimap(gobj);
|
|
58909
|
+
} catch (e) {
|
|
58910
|
+
log_error(`${gobj_short_name(gobj)}: refresh_minimap failed: ${e}`);
|
|
58911
|
+
}
|
|
58912
|
+
await graph_draw(gobj);
|
|
58913
|
+
if (changed || opts.relayout) await graph_layout(gobj);
|
|
58914
|
+
if (opts.fit) await graph_fit_readable(gobj);
|
|
58915
|
+
else if (opts.keep && opts.keep_vp) await yui_graph_place_at(graph, opts.keep, opts.keep_vp);
|
|
58916
|
+
update_resize_handles_position(gobj);
|
|
58917
|
+
update_port_resize_handles_position(gobj);
|
|
58918
|
+
update_edge_icon_position(gobj);
|
|
58919
|
+
update_node_icon_position(gobj);
|
|
58920
|
+
update_link_icon_position(gobj);
|
|
58921
|
+
return changed;
|
|
58922
|
+
}
|
|
58923
|
+
/************************************************************
|
|
58924
|
+
* Repaint the `+N` chips (theme or language changed).
|
|
58925
|
+
************************************************************/
|
|
58926
|
+
function repaint_more_chips(gobj) {
|
|
58927
|
+
let priv = gobj.priv;
|
|
58928
|
+
let graph = priv.graph;
|
|
58929
|
+
if (!graph) return;
|
|
58930
|
+
let updates = [];
|
|
58931
|
+
for (let nd of graph.getNodeData() || []) {
|
|
58932
|
+
let html = more_innerHTML_of(gobj, nd, priv.theme);
|
|
58933
|
+
if (html !== null) updates.push({
|
|
58934
|
+
id: nd.id,
|
|
58935
|
+
style: { innerHTML: html }
|
|
58936
|
+
});
|
|
58937
|
+
}
|
|
58938
|
+
if (updates.length) try {
|
|
58939
|
+
graph.updateNodeData(updates);
|
|
58940
|
+
graph.draw();
|
|
58941
|
+
} catch (e) {
|
|
58942
|
+
log_error(`${gobj_short_name(gobj)}: cannot repaint the chips: ${e}`);
|
|
58943
|
+
}
|
|
58944
|
+
}
|
|
58945
|
+
/***************************
|
|
57957
58946
|
* Actions
|
|
57958
58947
|
***************************/
|
|
57959
58948
|
/************************************************************
|
|
@@ -57982,6 +58971,9 @@ function ac_clear_data(gobj, event, kw, src) {
|
|
|
57982
58971
|
gobj_write_attr(gobj, "records", {});
|
|
57983
58972
|
priv._nodes_total = 0;
|
|
57984
58973
|
priv._nodes_placed = 0;
|
|
58974
|
+
priv._fold_model = null;
|
|
58975
|
+
priv._fold_state = null;
|
|
58976
|
+
priv._pill_sig = null;
|
|
57985
58977
|
graph_remove_plugin(gobj, "history");
|
|
57986
58978
|
update_history_buttons(gobj);
|
|
57987
58979
|
graph_clear(gobj);
|
|
@@ -58012,53 +59004,45 @@ function ac_load_data(gobj, event, kw, src) {
|
|
|
58012
59004
|
}
|
|
58013
59005
|
return 0;
|
|
58014
59006
|
}
|
|
58015
|
-
|
|
59007
|
+
priv.descs[topic_name];
|
|
58016
59008
|
priv.records[topic_name] = data;
|
|
58017
59009
|
priv.descs[topic_name].loaded = true;
|
|
58018
|
-
|
|
58019
|
-
let record = data[i];
|
|
58020
|
-
create_topic_node(gobj, desc, record);
|
|
58021
|
-
}
|
|
58022
|
-
let do_links = true;
|
|
59010
|
+
let all_loaded = true;
|
|
58023
59011
|
for (const [topic_name, desc] of Object.entries(priv.descs)) {
|
|
58024
59012
|
if (topic_name.substring(0, 2) === "__") continue;
|
|
58025
59013
|
if (!desc.loaded) {
|
|
58026
|
-
|
|
59014
|
+
all_loaded = false;
|
|
58027
59015
|
break;
|
|
58028
59016
|
}
|
|
58029
59017
|
}
|
|
58030
|
-
if (
|
|
59018
|
+
if (all_loaded && priv.graph) {
|
|
59019
|
+
rebuild_fold_model(gobj);
|
|
59020
|
+
fold_expand_to_depth(priv._fold_model, priv._fold_state, gobj_read_integer_attr(gobj, "expand_depth"));
|
|
59021
|
+
count_placed_records(gobj);
|
|
59022
|
+
let auto_laid = false;
|
|
58031
59023
|
try {
|
|
58032
|
-
|
|
59024
|
+
auto_laid = auto_layout(gobj);
|
|
58033
59025
|
} catch (e) {
|
|
58034
|
-
log_error(`${gobj_short_name(gobj)}:
|
|
58035
|
-
}
|
|
58036
|
-
|
|
58037
|
-
|
|
58038
|
-
|
|
58039
|
-
|
|
58040
|
-
|
|
58041
|
-
|
|
58042
|
-
|
|
58043
|
-
|
|
58044
|
-
|
|
58045
|
-
|
|
58046
|
-
|
|
58047
|
-
|
|
58048
|
-
|
|
58049
|
-
|
|
58050
|
-
|
|
58051
|
-
|
|
58052
|
-
|
|
58053
|
-
|
|
58054
|
-
}
|
|
58055
|
-
if (priv._pending_find !== null) {
|
|
58056
|
-
let term = priv._pending_find;
|
|
58057
|
-
priv._pending_find = null;
|
|
58058
|
-
publish_find_result(gobj, term, graph_find_nodes(gobj, term));
|
|
58059
|
-
}
|
|
58060
|
-
});
|
|
58061
|
-
});
|
|
59026
|
+
log_error(`${gobj_short_name(gobj)}: auto_layout failed: ${e}`);
|
|
59027
|
+
}
|
|
59028
|
+
apply_layout_direction(gobj);
|
|
59029
|
+
reconcile_fold(gobj, {
|
|
59030
|
+
relayout: true,
|
|
59031
|
+
fit: auto_laid
|
|
59032
|
+
}).then(() => {
|
|
59033
|
+
sync_history_plugin(gobj);
|
|
59034
|
+
if (priv._pending_focus_topic !== null) {
|
|
59035
|
+
let ft = priv._pending_focus_topic;
|
|
59036
|
+
let all = priv._pending_focus_all;
|
|
59037
|
+
priv._pending_focus_topic = null;
|
|
59038
|
+
priv._pending_focus_all = false;
|
|
59039
|
+
graph_focus_topic(gobj, ft, all);
|
|
59040
|
+
}
|
|
59041
|
+
if (priv._pending_find !== null) {
|
|
59042
|
+
let term = priv._pending_find;
|
|
59043
|
+
priv._pending_find = null;
|
|
59044
|
+
publish_find_result(gobj, term, graph_find_nodes(gobj, term));
|
|
59045
|
+
}
|
|
58062
59046
|
});
|
|
58063
59047
|
}
|
|
58064
59048
|
return 0;
|
|
@@ -58094,19 +59078,15 @@ function ac_node_created(gobj, event, kw, src) {
|
|
|
58094
59078
|
build_graph_properties(gobj);
|
|
58095
59079
|
return 0;
|
|
58096
59080
|
}
|
|
58097
|
-
|
|
58098
|
-
if (!desc) {
|
|
59081
|
+
if (!priv.descs[topic_name]) {
|
|
58099
59082
|
log_error(`ac_node_created: unknown topic: ${topic_name}`);
|
|
58100
59083
|
return 0;
|
|
58101
59084
|
}
|
|
58102
59085
|
if (!priv.records[topic_name]) priv.records[topic_name] = [];
|
|
58103
59086
|
priv.records[topic_name].push(node);
|
|
58104
|
-
|
|
58105
|
-
|
|
58106
|
-
|
|
58107
|
-
graph_draw(gobj).then(() => {
|
|
58108
|
-
history_resume(gobj);
|
|
58109
|
-
});
|
|
59087
|
+
rebuild_fold_model(gobj);
|
|
59088
|
+
fold_reveal(priv._fold_model, priv._fold_state, fold_node_key(topic_name, String(node.id)));
|
|
59089
|
+
reconcile_fold(gobj, {});
|
|
58110
59090
|
return 0;
|
|
58111
59091
|
}
|
|
58112
59092
|
/************************************************************
|
|
@@ -58155,8 +59135,14 @@ function ac_node_updated(gobj, event, kw, src) {
|
|
|
58155
59135
|
let [col_idx, fkey_value] = ref.split(" ");
|
|
58156
59136
|
clear_link(gobj, topic_name, node.id, cols[parseInt(col_idx)], fkey_value, false);
|
|
58157
59137
|
}
|
|
58158
|
-
update_topic_node(gobj, desc, node_name, node);
|
|
58159
59138
|
update_local_node(gobj, topic_name, node);
|
|
59139
|
+
let on_screen = false;
|
|
59140
|
+
try {
|
|
59141
|
+
on_screen = !!graph.getNodeData(node_name);
|
|
59142
|
+
} catch (e) {
|
|
59143
|
+
on_screen = false;
|
|
59144
|
+
}
|
|
59145
|
+
if (on_screen) update_topic_node(gobj, desc, node_name, node);
|
|
58160
59146
|
for (let ref of new_refs) if (!old_refs.has(ref)) {
|
|
58161
59147
|
let [col_idx, fkey_value] = ref.split(" ");
|
|
58162
59148
|
draw_link(gobj, topic_name, node.id, cols[parseInt(col_idx)], fkey_value, false);
|
|
@@ -58164,6 +59150,8 @@ function ac_node_updated(gobj, event, kw, src) {
|
|
|
58164
59150
|
graph_draw(gobj).then(() => {
|
|
58165
59151
|
history_resume(gobj);
|
|
58166
59152
|
});
|
|
59153
|
+
rebuild_fold_model(gobj);
|
|
59154
|
+
reconcile_fold(gobj, {});
|
|
58167
59155
|
return 0;
|
|
58168
59156
|
}
|
|
58169
59157
|
/************************************************************
|
|
@@ -58189,9 +59177,12 @@ function ac_node_deleted(gobj, event, kw, src) {
|
|
|
58189
59177
|
clear_links(gobj, desc, node, false);
|
|
58190
59178
|
remove_topic_node(gobj, node_name);
|
|
58191
59179
|
remove_local_node(gobj, topic_name, node);
|
|
59180
|
+
if (priv._pill_sig) priv._pill_sig.delete(node_name);
|
|
58192
59181
|
graph_draw(gobj).then(() => {
|
|
58193
59182
|
history_resume(gobj);
|
|
58194
59183
|
});
|
|
59184
|
+
rebuild_fold_model(gobj);
|
|
59185
|
+
reconcile_fold(gobj, {});
|
|
58195
59186
|
return 0;
|
|
58196
59187
|
}
|
|
58197
59188
|
/************************************************************
|
|
@@ -58250,6 +59241,7 @@ function ac_theme$1(gobj, event, kw, src) {
|
|
|
58250
59241
|
});
|
|
58251
59242
|
refresh_html_nodes_theme(gobj, theme);
|
|
58252
59243
|
refresh_default_edges_theme(gobj, theme);
|
|
59244
|
+
repaint_more_chips(gobj);
|
|
58253
59245
|
graph_draw(gobj).then(() => {
|
|
58254
59246
|
update_history_buttons(gobj);
|
|
58255
59247
|
});
|
|
@@ -58360,7 +59352,86 @@ function ac_zoom_selection(gobj, event, kw, src) {
|
|
|
58360
59352
|
return 0;
|
|
58361
59353
|
}
|
|
58362
59354
|
function ac_focus_topic(gobj, event, kw, src) {
|
|
58363
|
-
graph_focus_topic(gobj, kw && kw.topic);
|
|
59355
|
+
graph_focus_topic(gobj, kw && kw.topic, !!(kw && kw.reveal === "all"));
|
|
59356
|
+
return 0;
|
|
59357
|
+
}
|
|
59358
|
+
/************************************************************
|
|
59359
|
+
* A pill was tapped: open that hook on its first page, or fold
|
|
59360
|
+
* it. The card the pill is on stays where it was on screen --
|
|
59361
|
+
* the layout moves everything else around it.
|
|
59362
|
+
************************************************************/
|
|
59363
|
+
function ac_toggle_fold(gobj, event, kw, src) {
|
|
59364
|
+
let priv = gobj.priv;
|
|
59365
|
+
let group = kw && kw.group || "";
|
|
59366
|
+
if (!priv._fold_model || !group) {
|
|
59367
|
+
log_error(`${gobj_short_name(gobj)}: fold of '${group}' with no tree loaded`);
|
|
59368
|
+
return -1;
|
|
59369
|
+
}
|
|
59370
|
+
let g = fold_split_group_key(group);
|
|
59371
|
+
if (!g) {
|
|
59372
|
+
log_error(`${gobj_short_name(gobj)}: bad fold group '${group}'`);
|
|
59373
|
+
return -1;
|
|
59374
|
+
}
|
|
59375
|
+
let node_id = g.node_key ? node_id_of_key(gobj, g.node_key) : "";
|
|
59376
|
+
let vp = node_id ? yui_graph_viewport_of(priv.graph, node_id) : null;
|
|
59377
|
+
fold_toggle(priv._fold_model, priv._fold_state, group);
|
|
59378
|
+
reconcile_fold(gobj, {
|
|
59379
|
+
keep: node_id,
|
|
59380
|
+
keep_vp: vp
|
|
59381
|
+
});
|
|
59382
|
+
return 0;
|
|
59383
|
+
}
|
|
59384
|
+
/************************************************************
|
|
59385
|
+
* A `+N` chip was tapped: the next page of its group. The
|
|
59386
|
+
* parent holds still; the chip itself moves down the column.
|
|
59387
|
+
************************************************************/
|
|
59388
|
+
function ac_show_more(gobj, event, kw, src) {
|
|
59389
|
+
let priv = gobj.priv;
|
|
59390
|
+
let group = kw && kw.group || "";
|
|
59391
|
+
if (!priv._fold_model || !group) {
|
|
59392
|
+
log_error(`${gobj_short_name(gobj)}: show more of '${group}' with no tree loaded`);
|
|
59393
|
+
return -1;
|
|
59394
|
+
}
|
|
59395
|
+
let g = fold_split_group_key(group);
|
|
59396
|
+
if (!g) {
|
|
59397
|
+
log_error(`${gobj_short_name(gobj)}: bad fold group '${group}'`);
|
|
59398
|
+
return -1;
|
|
59399
|
+
}
|
|
59400
|
+
let node_id = g.node_key ? node_id_of_key(gobj, g.node_key) : "";
|
|
59401
|
+
let vp = node_id ? yui_graph_viewport_of(priv.graph, node_id) : null;
|
|
59402
|
+
fold_show_more(priv._fold_model, priv._fold_state, group);
|
|
59403
|
+
reconcile_fold(gobj, {
|
|
59404
|
+
keep: node_id,
|
|
59405
|
+
keep_vp: vp
|
|
59406
|
+
});
|
|
59407
|
+
return 0;
|
|
59408
|
+
}
|
|
59409
|
+
/************************************************************
|
|
59410
|
+
* The whole treedb, every hook open on all its children. This
|
|
59411
|
+
* is the reader asking for the pile on purpose; the pages are
|
|
59412
|
+
* the other way in.
|
|
59413
|
+
************************************************************/
|
|
59414
|
+
function ac_expand_all$1(gobj, event, kw, src) {
|
|
59415
|
+
let priv = gobj.priv;
|
|
59416
|
+
if (!priv._fold_model) {
|
|
59417
|
+
log_error(`${gobj_short_name(gobj)}: expand all with no tree loaded`);
|
|
59418
|
+
return -1;
|
|
59419
|
+
}
|
|
59420
|
+
fold_expand_all(priv._fold_model, priv._fold_state);
|
|
59421
|
+
reconcile_fold(gobj, { fit: true });
|
|
59422
|
+
return 0;
|
|
59423
|
+
}
|
|
59424
|
+
/************************************************************
|
|
59425
|
+
* The roots alone.
|
|
59426
|
+
************************************************************/
|
|
59427
|
+
function ac_collapse_all$1(gobj, event, kw, src) {
|
|
59428
|
+
let priv = gobj.priv;
|
|
59429
|
+
if (!priv._fold_model) {
|
|
59430
|
+
log_error(`${gobj_short_name(gobj)}: collapse all with no tree loaded`);
|
|
59431
|
+
return -1;
|
|
59432
|
+
}
|
|
59433
|
+
fold_collapse_all(priv._fold_model, priv._fold_state);
|
|
59434
|
+
reconcile_fold(gobj, { fit: true });
|
|
58364
59435
|
return 0;
|
|
58365
59436
|
}
|
|
58366
59437
|
/************************************************************
|
|
@@ -58394,7 +59465,9 @@ function ac_fullscreen(gobj, event, kw, src) {
|
|
|
58394
59465
|
************************************************************/
|
|
58395
59466
|
function ac_set_layout$1(gobj, event, kw, src) {
|
|
58396
59467
|
gobj.priv;
|
|
58397
|
-
|
|
59468
|
+
let layout = select_layout(gobj, kw.layout);
|
|
59469
|
+
apply_layout_direction(gobj);
|
|
59470
|
+
graph_set_layout(gobj, layout).then(() => {
|
|
58398
59471
|
configure_behaviour(gobj);
|
|
58399
59472
|
update_toolbar(gobj);
|
|
58400
59473
|
});
|
|
@@ -58501,6 +59574,16 @@ function ac_node_click$2(gobj, event, kw, src) {
|
|
|
58501
59574
|
let priv = gobj.priv;
|
|
58502
59575
|
let graph = priv.graph;
|
|
58503
59576
|
let node_id = kw.evt.target.id;
|
|
59577
|
+
let more_nd = null;
|
|
59578
|
+
try {
|
|
59579
|
+
more_nd = graph.getNodeData(node_id);
|
|
59580
|
+
} catch (e) {
|
|
59581
|
+
more_nd = null;
|
|
59582
|
+
}
|
|
59583
|
+
if (is_more_node(more_nd)) {
|
|
59584
|
+
gobj_send_event(gobj, "EV_SHOW_MORE", { group: more_nd.data.more }, gobj);
|
|
59585
|
+
return 0;
|
|
59586
|
+
}
|
|
58504
59587
|
if (priv.anchor_state === "arming") {
|
|
58505
59588
|
priv.anchor_id = node_id;
|
|
58506
59589
|
priv.anchor_state = "on";
|
|
@@ -58805,6 +59888,26 @@ function create_gclass$4(gclass_name) {
|
|
|
58805
59888
|
ac_find_nodes$1,
|
|
58806
59889
|
null
|
|
58807
59890
|
],
|
|
59891
|
+
[
|
|
59892
|
+
"EV_TOGGLE_FOLD",
|
|
59893
|
+
ac_toggle_fold,
|
|
59894
|
+
null
|
|
59895
|
+
],
|
|
59896
|
+
[
|
|
59897
|
+
"EV_SHOW_MORE",
|
|
59898
|
+
ac_show_more,
|
|
59899
|
+
null
|
|
59900
|
+
],
|
|
59901
|
+
[
|
|
59902
|
+
"EV_EXPAND_ALL",
|
|
59903
|
+
ac_expand_all$1,
|
|
59904
|
+
null
|
|
59905
|
+
],
|
|
59906
|
+
[
|
|
59907
|
+
"EV_COLLAPSE_ALL",
|
|
59908
|
+
ac_collapse_all$1,
|
|
59909
|
+
null
|
|
59910
|
+
],
|
|
58808
59911
|
[
|
|
58809
59912
|
"EV_CENTER",
|
|
58810
59913
|
ac_center,
|
|
@@ -58902,6 +60005,10 @@ function create_gclass$4(gclass_name) {
|
|
|
58902
60005
|
["EV_FIND_NODES", 0],
|
|
58903
60006
|
["EV_FIND_RESULT", event_flag_t.EVF_OUTPUT_EVENT],
|
|
58904
60007
|
["EV_LAYOUT_AUTOSET", event_flag_t.EVF_OUTPUT_EVENT],
|
|
60008
|
+
["EV_TOGGLE_FOLD", 0],
|
|
60009
|
+
["EV_SHOW_MORE", 0],
|
|
60010
|
+
["EV_EXPAND_ALL", 0],
|
|
60011
|
+
["EV_COLLAPSE_ALL", 0],
|
|
58905
60012
|
["EV_CENTER", 0],
|
|
58906
60013
|
["EV_FULLSCREEN", 0],
|
|
58907
60014
|
["EV_SET_LAYOUT", 0],
|
|
@@ -58959,6 +60066,8 @@ var attrs_table$3 = [
|
|
|
58959
60066
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
58960
60067
|
SDATA(data_type_t.DTP_LIST, "operation_modes", 0, "[\"reading\", \"operation\", \"writing\", \"edition\"]", "Available **permission** or behaviour modes. These operation modes are required to be accomplish by the graph handler (G6 child). TODO permissions must match treedb permissions."),
|
|
58961
60068
|
SDATA(data_type_t.DTP_BOOLEAN, "with_treedb_tables", 0, false, "Include treedb tables"),
|
|
60069
|
+
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0, 2, "Levels of the treedb open when it loads: 1 = the roots alone, 2 = the roots and their children. Forwarded to the G6 child"),
|
|
60070
|
+
SDATA(data_type_t.DTP_INTEGER, "fold_page_size", 0, 24, "Children of one hook shown per page in the graph; a `+N` chip opens the next page. Forwarded to the G6 child"),
|
|
58962
60071
|
SDATA(data_type_t.DTP_STRING, "operation_mode", sdata_flag_t.SDF_PERSIST, "reading", "Current operation mode (internal behaviour or role). Changed by the user trough the gui."),
|
|
58963
60072
|
SDATA(data_type_t.DTP_STRING, "layout", sdata_flag_t.SDF_PERSIST, "", "Current graph layout. User preference. Changed by the user through the gui."),
|
|
58964
60073
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
|
|
@@ -59032,7 +60141,9 @@ function mt_create$3(gobj) {
|
|
|
59032
60141
|
layout: priv.layout,
|
|
59033
60142
|
with_treedb_tables: priv.with_treedb_tables,
|
|
59034
60143
|
hook_port_position: "bottom",
|
|
59035
|
-
fkey_port_position: "top"
|
|
60144
|
+
fkey_port_position: "top",
|
|
60145
|
+
expand_depth: gobj_read_integer_attr(gobj, "expand_depth"),
|
|
60146
|
+
fold_page_size: gobj_read_integer_attr(gobj, "fold_page_size")
|
|
59036
60147
|
}, gobj);
|
|
59037
60148
|
populate_nodes_tree_options(gobj);
|
|
59038
60149
|
if (priv.with_treedb_tables) {}
|
|
@@ -59290,6 +60401,7 @@ function make_toolbar(gobj) {
|
|
|
59290
60401
|
gobj_send_event(gobj, "EV_REFRESH_TREEDB", { evt }, gobj);
|
|
59291
60402
|
} }
|
|
59292
60403
|
],
|
|
60404
|
+
...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
59293
60405
|
[
|
|
59294
60406
|
"button",
|
|
59295
60407
|
{
|
|
@@ -60403,7 +61515,10 @@ function ac_legend_topic(gobj, event, kw, src) {
|
|
|
60403
61515
|
return -1;
|
|
60404
61516
|
}
|
|
60405
61517
|
let next = priv.focus_topic === topic ? "" : topic;
|
|
60406
|
-
gobj_send_event(gobj, "EV_SET_FOCUS_TOPIC", {
|
|
61518
|
+
gobj_send_event(gobj, "EV_SET_FOCUS_TOPIC", {
|
|
61519
|
+
topic: next,
|
|
61520
|
+
reveal: "all"
|
|
61521
|
+
}, gobj);
|
|
60407
61522
|
gobj_publish_event(gobj, "EV_TOPIC_SELECTED", { topic: next });
|
|
60408
61523
|
return 0;
|
|
60409
61524
|
}
|
|
@@ -60431,6 +61546,20 @@ function ac_find_nodes(gobj, event, kw, src) {
|
|
|
60431
61546
|
return 0;
|
|
60432
61547
|
}
|
|
60433
61548
|
/************************************************************
|
|
61549
|
+
* The fold pair of the toolbar, forwarded to the G6 child,
|
|
61550
|
+
* which owns the tree.
|
|
61551
|
+
************************************************************/
|
|
61552
|
+
function ac_expand_all(gobj, event, kw, src) {
|
|
61553
|
+
let priv = gobj.priv;
|
|
61554
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_EXPAND_ALL", {}, gobj);
|
|
61555
|
+
return 0;
|
|
61556
|
+
}
|
|
61557
|
+
function ac_collapse_all(gobj, event, kw, src) {
|
|
61558
|
+
let priv = gobj.priv;
|
|
61559
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_COLLAPSE_ALL", {}, gobj);
|
|
61560
|
+
return 0;
|
|
61561
|
+
}
|
|
61562
|
+
/************************************************************
|
|
60434
61563
|
* How many nodes the term matched, from the graph child. Zero with a
|
|
60435
61564
|
* term typed is an ANSWER and is shown; an empty box shows nothing.
|
|
60436
61565
|
************************************************************/
|
|
@@ -60452,7 +61581,10 @@ function ac_find_result(gobj, event, kw, src) {
|
|
|
60452
61581
|
function ac_set_focus_topic(gobj, event, kw, src) {
|
|
60453
61582
|
let priv = gobj.priv;
|
|
60454
61583
|
priv.focus_topic = kw && kw.topic || "";
|
|
60455
|
-
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_FOCUS_TOPIC", {
|
|
61584
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_FOCUS_TOPIC", {
|
|
61585
|
+
topic: priv.focus_topic,
|
|
61586
|
+
reveal: kw && kw.reveal || "page"
|
|
61587
|
+
}, gobj);
|
|
60456
61588
|
let $container = gobj_read_attr(gobj, "$container");
|
|
60457
61589
|
let $legend = $container ? $container.querySelector(".GRAPH_LEGEND") : null;
|
|
60458
61590
|
if ($legend && !$legend.classList.contains("is-hidden")) refresh_legend(gobj);
|
|
@@ -60623,6 +61755,16 @@ function create_gclass$3(gclass_name) {
|
|
|
60623
61755
|
ac_find_nodes,
|
|
60624
61756
|
null
|
|
60625
61757
|
],
|
|
61758
|
+
[
|
|
61759
|
+
"EV_EXPAND_ALL",
|
|
61760
|
+
ac_expand_all,
|
|
61761
|
+
null
|
|
61762
|
+
],
|
|
61763
|
+
[
|
|
61764
|
+
"EV_COLLAPSE_ALL",
|
|
61765
|
+
ac_collapse_all,
|
|
61766
|
+
null
|
|
61767
|
+
],
|
|
60626
61768
|
[
|
|
60627
61769
|
"EV_LAYOUT_AUTOSET",
|
|
60628
61770
|
ac_layout_autoset,
|
|
@@ -60685,6 +61827,8 @@ function create_gclass$3(gclass_name) {
|
|
|
60685
61827
|
["EV_SET_OPERATION_MODE", 0],
|
|
60686
61828
|
["EV_SET_FOCUS_TOPIC", 0],
|
|
60687
61829
|
["EV_FIND_NODES", 0],
|
|
61830
|
+
["EV_EXPAND_ALL", 0],
|
|
61831
|
+
["EV_COLLAPSE_ALL", 0],
|
|
60688
61832
|
["EV_FIND_RESULT", 0],
|
|
60689
61833
|
["EV_LAYOUT_AUTOSET", 0],
|
|
60690
61834
|
["EV_TOGGLE_LEGEND", 0],
|