@yuneta/gobj-ui 7.23.140 → 7.23.142
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 +123 -37
- package/dist/gobj-ui.cjs.js +412 -140
- package/dist/gobj-ui.es.js +412 -140
- package/package.json +2 -2
- package/src/c_g6_nodes_tree.js +98 -59
- package/src/c_yui_schema_editor.js +16 -0
- package/src/c_yui_treedb_graph.js +153 -23
- package/src/schema_import.js +2 -1
- package/src/schema_model.js +2 -1
- package/src/schema_to_c.js +1 -1
- package/src/schema_validate.js +20 -0
- package/src/schema_validate.test.js +44 -0
- package/src/treedb_fold_model.js +185 -21
- package/src/treedb_fold_model.test.js +120 -5
package/dist/gobj-ui.es.js
CHANGED
|
@@ -13106,7 +13106,7 @@ function ac_find_nodes$3(gobj, event, kw, src) {
|
|
|
13106
13106
|
/************************************************************
|
|
13107
13107
|
* EV_EXPAND_ALL
|
|
13108
13108
|
************************************************************/
|
|
13109
|
-
function ac_expand_all$
|
|
13109
|
+
function ac_expand_all$2(gobj, event, kw, src) {
|
|
13110
13110
|
let priv = gobj.priv;
|
|
13111
13111
|
if (priv.collapsed.size === 0) return 0;
|
|
13112
13112
|
priv.collapsed.clear();
|
|
@@ -13118,7 +13118,7 @@ function ac_expand_all$4(gobj, event, kw, src) {
|
|
|
13118
13118
|
/************************************************************
|
|
13119
13119
|
* EV_COLLAPSE_ALL — fold every card but the root.
|
|
13120
13120
|
************************************************************/
|
|
13121
|
-
function ac_collapse_all$
|
|
13121
|
+
function ac_collapse_all$2(gobj, event, kw, src) {
|
|
13122
13122
|
let priv = gobj.priv;
|
|
13123
13123
|
let json_data = gobj_read_attr(gobj, "json_data");
|
|
13124
13124
|
if (!json_data) return 0;
|
|
@@ -13418,12 +13418,12 @@ function create_gclass$13(gclass_name) {
|
|
|
13418
13418
|
],
|
|
13419
13419
|
[
|
|
13420
13420
|
"EV_EXPAND_ALL",
|
|
13421
|
-
ac_expand_all$
|
|
13421
|
+
ac_expand_all$2,
|
|
13422
13422
|
null
|
|
13423
13423
|
],
|
|
13424
13424
|
[
|
|
13425
13425
|
"EV_COLLAPSE_ALL",
|
|
13426
|
-
ac_collapse_all$
|
|
13426
|
+
ac_collapse_all$2,
|
|
13427
13427
|
null
|
|
13428
13428
|
],
|
|
13429
13429
|
[
|
|
@@ -14495,7 +14495,7 @@ function ac_search$2(gobj, event, kw, src) {
|
|
|
14495
14495
|
/************************************************************
|
|
14496
14496
|
* EV_EXPAND_ALL — expand every already-loaded container
|
|
14497
14497
|
************************************************************/
|
|
14498
|
-
function ac_expand_all$
|
|
14498
|
+
function ac_expand_all$1(gobj, event, kw, src) {
|
|
14499
14499
|
let priv = gobj.priv;
|
|
14500
14500
|
if (priv.root === null || priv.root === void 0) return 0;
|
|
14501
14501
|
let paths = [];
|
|
@@ -14513,7 +14513,7 @@ function ac_expand_all$3(gobj, event, kw, src) {
|
|
|
14513
14513
|
/************************************************************
|
|
14514
14514
|
* EV_COLLAPSE_ALL
|
|
14515
14515
|
************************************************************/
|
|
14516
|
-
function ac_collapse_all$
|
|
14516
|
+
function ac_collapse_all$1(gobj, event, kw, src) {
|
|
14517
14517
|
gobj.priv.expanded.clear();
|
|
14518
14518
|
render_view$1(gobj);
|
|
14519
14519
|
return 0;
|
|
@@ -14698,12 +14698,12 @@ function create_gclass$12(gclass_name) {
|
|
|
14698
14698
|
],
|
|
14699
14699
|
[
|
|
14700
14700
|
"EV_EXPAND_ALL",
|
|
14701
|
-
ac_expand_all$
|
|
14701
|
+
ac_expand_all$1,
|
|
14702
14702
|
null
|
|
14703
14703
|
],
|
|
14704
14704
|
[
|
|
14705
14705
|
"EV_COLLAPSE_ALL",
|
|
14706
|
-
ac_collapse_all$
|
|
14706
|
+
ac_collapse_all$1,
|
|
14707
14707
|
null
|
|
14708
14708
|
],
|
|
14709
14709
|
[
|
|
@@ -19725,7 +19725,7 @@ function ac_toggle_collapse(gobj, event, kw, src) {
|
|
|
19725
19725
|
/************************************************************
|
|
19726
19726
|
* Force every node visible (overrides threshold).
|
|
19727
19727
|
************************************************************/
|
|
19728
|
-
function ac_expand_all
|
|
19728
|
+
function ac_expand_all(gobj, event, kw, src) {
|
|
19729
19729
|
let priv = gobj.priv;
|
|
19730
19730
|
if (!priv.collapse_state) priv.collapse_state = {};
|
|
19731
19731
|
if (priv.node_by_id) for (let id of Object.keys(priv.node_by_id)) {
|
|
@@ -19738,7 +19738,7 @@ function ac_expand_all$2(gobj, event, kw, src) {
|
|
|
19738
19738
|
/************************************************************
|
|
19739
19739
|
* Collapse every node that has children.
|
|
19740
19740
|
************************************************************/
|
|
19741
|
-
function ac_collapse_all
|
|
19741
|
+
function ac_collapse_all(gobj, event, kw, src) {
|
|
19742
19742
|
let priv = gobj.priv;
|
|
19743
19743
|
if (!priv.collapse_state) priv.collapse_state = {};
|
|
19744
19744
|
if (priv.node_by_id) for (let id of Object.keys(priv.node_by_id)) {
|
|
@@ -20090,12 +20090,12 @@ function create_gclass$9(gclass_name) {
|
|
|
20090
20090
|
],
|
|
20091
20091
|
[
|
|
20092
20092
|
"EV_EXPAND_ALL",
|
|
20093
|
-
ac_expand_all
|
|
20093
|
+
ac_expand_all,
|
|
20094
20094
|
null
|
|
20095
20095
|
],
|
|
20096
20096
|
[
|
|
20097
20097
|
"EV_COLLAPSE_ALL",
|
|
20098
|
-
ac_collapse_all
|
|
20098
|
+
ac_collapse_all,
|
|
20099
20099
|
null
|
|
20100
20100
|
],
|
|
20101
20101
|
[
|
|
@@ -27670,7 +27670,9 @@ function fold_build_model(descs, records, opts) {
|
|
|
27670
27670
|
opts = is_object(opts) ? opts : {};
|
|
27671
27671
|
let hidden = new Set(is_array(opts.hidden_topics) ? opts.hidden_topics : []);
|
|
27672
27672
|
let loose_shown = new Set(is_array(opts.loose_topics) ? opts.loose_topics : []);
|
|
27673
|
-
let main_topic = opts.main_topic ||
|
|
27673
|
+
let main_topic = opts.main_topic || "";
|
|
27674
|
+
if (main_topic && !fold_is_hierarchical(descs, main_topic)) main_topic = "";
|
|
27675
|
+
if (!main_topic) main_topic = fold_main_topic(descs);
|
|
27674
27676
|
if (main_topic && (!descs[main_topic] || hidden.has(main_topic))) main_topic = "";
|
|
27675
27677
|
let linked = fold_linked_topics(descs, main_topic);
|
|
27676
27678
|
let totals = {};
|
|
@@ -27734,7 +27736,7 @@ function fold_build_model(descs, records, opts) {
|
|
|
27734
27736
|
for (let k of reach_from(nodes, [node.key])) reached.add(k);
|
|
27735
27737
|
}
|
|
27736
27738
|
for (let topic_name of topics) if (roots[topic_name].length > 0) groups.set(fold_root_group_key(topic_name), roots[topic_name]);
|
|
27737
|
-
|
|
27739
|
+
let model = {
|
|
27738
27740
|
nodes,
|
|
27739
27741
|
groups,
|
|
27740
27742
|
topics,
|
|
@@ -27743,32 +27745,97 @@ function fold_build_model(descs, records, opts) {
|
|
|
27743
27745
|
main_topic,
|
|
27744
27746
|
linked,
|
|
27745
27747
|
loose,
|
|
27746
|
-
loose_shown
|
|
27748
|
+
loose_shown,
|
|
27749
|
+
level_of: null,
|
|
27750
|
+
levels: 0
|
|
27747
27751
|
};
|
|
27752
|
+
count_levels(model);
|
|
27753
|
+
return model;
|
|
27748
27754
|
}
|
|
27749
27755
|
/************************************************************
|
|
27750
|
-
* The
|
|
27751
|
-
*
|
|
27752
|
-
*
|
|
27753
|
-
*
|
|
27754
|
-
*
|
|
27756
|
+
* The LEVELS of the main tree: the roots of the main topic --
|
|
27757
|
+
* and of the topics hung from it, whose roots are the loose
|
|
27758
|
+
* records the reader asked for -- are level 1, their children
|
|
27759
|
+
* level 2, and so on down every hook of every topic that is not
|
|
27760
|
+
* hidden. A node reached by two paths takes the shallowest.
|
|
27761
|
+
*
|
|
27762
|
+
* With no main topic every topic is a tree of its own and all
|
|
27763
|
+
* of them count. A topic the schema does not tie to the main
|
|
27764
|
+
* one is a separate tree, and has no level: the stepper of the
|
|
27765
|
+
* toolbar speaks for the main tree and nothing else, those
|
|
27766
|
+
* trees are opened by their own pills.
|
|
27767
|
+
************************************************************/
|
|
27768
|
+
function count_levels(model) {
|
|
27769
|
+
let level_of = /* @__PURE__ */ new Map();
|
|
27770
|
+
let queue = [];
|
|
27771
|
+
let deepest = 0;
|
|
27772
|
+
for (let topic_name of model.topics) {
|
|
27773
|
+
if (model.main_topic && !model.linked.has(topic_name)) continue;
|
|
27774
|
+
let roots = model.groups.get(fold_root_group_key(topic_name)) || [];
|
|
27775
|
+
for (let key of roots) if (!level_of.has(key)) {
|
|
27776
|
+
level_of.set(key, 1);
|
|
27777
|
+
queue.push(key);
|
|
27778
|
+
}
|
|
27779
|
+
}
|
|
27780
|
+
let head = 0;
|
|
27781
|
+
while (head < queue.length) {
|
|
27782
|
+
let key = queue[head++];
|
|
27783
|
+
let lv = level_of.get(key);
|
|
27784
|
+
if (lv > deepest) deepest = lv;
|
|
27785
|
+
let node = model.nodes.get(key);
|
|
27786
|
+
if (!node) continue;
|
|
27787
|
+
for (let hook of Object.keys(node.hooks)) for (let child of node.hooks[hook]) if (!level_of.has(child)) {
|
|
27788
|
+
level_of.set(child, lv + 1);
|
|
27789
|
+
queue.push(child);
|
|
27790
|
+
}
|
|
27791
|
+
}
|
|
27792
|
+
model.level_of = level_of;
|
|
27793
|
+
model.levels = deepest;
|
|
27794
|
+
}
|
|
27795
|
+
/************************************************************
|
|
27796
|
+
* A HIERARCHICAL topic: one hooked to ITSELF -- places inside
|
|
27797
|
+
* places, groups inside groups, roles inside roles. It is the
|
|
27798
|
+
* only kind of topic a tree can hang from: a topic that only
|
|
27799
|
+
* reaches OTHER topics is a list with children, and making it
|
|
27800
|
+
* the trunk drew the agent's treedb from `yunos` instead of
|
|
27801
|
+
* `realms`.
|
|
27802
|
+
*
|
|
27803
|
+
* (Not the engine's `entity` tier, which is any topic with
|
|
27804
|
+
* hooks AND fkeys: that one sizes a card and says nothing about
|
|
27805
|
+
* where a tree starts.)
|
|
27806
|
+
************************************************************/
|
|
27807
|
+
function fold_is_hierarchical(descs, topic_name) {
|
|
27808
|
+
if (!is_object(descs) || !descs[topic_name]) return false;
|
|
27809
|
+
return hook_targets(descs, topic_name).has(topic_name);
|
|
27810
|
+
}
|
|
27811
|
+
/************************************************************
|
|
27812
|
+
* The topic the tree hangs from. Only a HIERARCHICAL topic can
|
|
27813
|
+
* be it, and in this order:
|
|
27814
|
+
*
|
|
27815
|
+
* the one the schema MARKS (`main_topic: true` on the topic,
|
|
27816
|
+
* sent by the backend in its desc since SDK 7.19; the first
|
|
27817
|
+
* one in schema order if a schema marks two);
|
|
27818
|
+
* else the one whose hooks reach the most OTHER topics,
|
|
27819
|
+
* schema order breaking a tie.
|
|
27820
|
+
*
|
|
27821
|
+
* "" when no topic is hooked to itself: there is no trunk, and
|
|
27822
|
+
* every topic is a tree of its own. (A pick by the reader comes
|
|
27823
|
+
* first of all, and is fold_build_model's business.)
|
|
27755
27824
|
************************************************************/
|
|
27756
27825
|
function fold_main_topic(descs) {
|
|
27757
27826
|
descs = is_object(descs) ? descs : {};
|
|
27827
|
+
let candidates = Object.keys(descs).filter((topic_name) => {
|
|
27828
|
+
return topic_name.substring(0, 2) !== "__" && fold_is_hierarchical(descs, topic_name);
|
|
27829
|
+
});
|
|
27830
|
+
for (let topic_name of candidates) if (descs[topic_name].main_topic === true) return topic_name;
|
|
27758
27831
|
let best = "";
|
|
27759
|
-
let best_score =
|
|
27760
|
-
let
|
|
27761
|
-
for (let topic_name of Object.keys(descs)) {
|
|
27762
|
-
if (topic_name.substring(0, 2) === "__") continue;
|
|
27832
|
+
let best_score = -1;
|
|
27833
|
+
for (let topic_name of candidates) {
|
|
27763
27834
|
let reach = hook_targets(descs, topic_name);
|
|
27764
|
-
let self = reach.has(topic_name);
|
|
27765
27835
|
reach.delete(topic_name);
|
|
27766
|
-
|
|
27767
|
-
if (score === 0) continue;
|
|
27768
|
-
if (score > best_score || score === best_score && self && !best_self) {
|
|
27836
|
+
if (reach.size > best_score) {
|
|
27769
27837
|
best = topic_name;
|
|
27770
|
-
best_score =
|
|
27771
|
-
best_self = self;
|
|
27838
|
+
best_score = reach.size;
|
|
27772
27839
|
}
|
|
27773
27840
|
}
|
|
27774
27841
|
return best;
|
|
@@ -27870,14 +27937,6 @@ function fold_show_more(model, state, group_key) {
|
|
|
27870
27937
|
return n;
|
|
27871
27938
|
}
|
|
27872
27939
|
/************************************************************
|
|
27873
|
-
* Every group open on ALL its children. This is the reader
|
|
27874
|
-
* asking for the whole thing; the pages are for the other way in.
|
|
27875
|
-
************************************************************/
|
|
27876
|
-
function fold_expand_all(model, state) {
|
|
27877
|
-
state.shown.clear();
|
|
27878
|
-
for (let [group_key, list] of model.groups) if (list.length > 0) state.shown.set(group_key, list.length);
|
|
27879
|
-
}
|
|
27880
|
-
/************************************************************
|
|
27881
27940
|
* The roots and nothing else -- the first page of each topic's
|
|
27882
27941
|
* roots, the way the graph looks before anything is opened.
|
|
27883
27942
|
************************************************************/
|
|
@@ -27889,40 +27948,51 @@ function fold_collapse_all(model, state) {
|
|
|
27889
27948
|
}
|
|
27890
27949
|
}
|
|
27891
27950
|
/************************************************************
|
|
27892
|
-
*
|
|
27893
|
-
*
|
|
27894
|
-
*
|
|
27895
|
-
*
|
|
27951
|
+
* The toolbar's STEPPER over the levels of the main tree (see
|
|
27952
|
+
* count_levels): level N shows the roots and N-1 levels under
|
|
27953
|
+
* them. A level is a floor of what is open, not a picture that
|
|
27954
|
+
* replaces it:
|
|
27955
|
+
*
|
|
27956
|
+
* opening to N opens, on its first page, every hook of
|
|
27957
|
+
* every node above level N that is folded;
|
|
27958
|
+
* what the reader opened, and every page
|
|
27959
|
+
* already shown, stays
|
|
27960
|
+
* closing to N folds every hook of every node at level N
|
|
27961
|
+
* or below, and touches nothing above it
|
|
27962
|
+
*
|
|
27963
|
+
* A separate tree (a topic not tied to the main one) has no
|
|
27964
|
+
* level, so neither ever touches it.
|
|
27896
27965
|
************************************************************/
|
|
27897
|
-
function
|
|
27898
|
-
|
|
27899
|
-
|
|
27900
|
-
|
|
27901
|
-
|
|
27902
|
-
|
|
27903
|
-
|
|
27904
|
-
|
|
27905
|
-
|
|
27906
|
-
|
|
27907
|
-
}
|
|
27908
|
-
}
|
|
27909
|
-
while (queue.length) {
|
|
27910
|
-
let key = queue.shift();
|
|
27911
|
-
let lv = level.get(key);
|
|
27912
|
-
if (lv >= depth) continue;
|
|
27966
|
+
function fold_level_clamp(model, level) {
|
|
27967
|
+
let top = model.levels > 0 ? model.levels : 1;
|
|
27968
|
+
level = Math.floor(Number(level)) || 1;
|
|
27969
|
+
if (level < 1) return 1;
|
|
27970
|
+
if (level > top) return top;
|
|
27971
|
+
return level;
|
|
27972
|
+
}
|
|
27973
|
+
function fold_open_levels(model, state, level) {
|
|
27974
|
+
for (let [key, lv] of model.level_of) {
|
|
27975
|
+
if (lv >= level) continue;
|
|
27913
27976
|
let node = model.nodes.get(key);
|
|
27914
27977
|
if (!node) continue;
|
|
27915
27978
|
for (let hook of Object.keys(node.hooks)) {
|
|
27916
|
-
let
|
|
27917
|
-
if (
|
|
27918
|
-
state.shown.set(fold_group_key(key, hook), state.page_size);
|
|
27919
|
-
for (let child of children) if (!level.has(child)) {
|
|
27920
|
-
level.set(child, lv + 1);
|
|
27921
|
-
queue.push(child);
|
|
27922
|
-
}
|
|
27979
|
+
let group_key = fold_group_key(key, hook);
|
|
27980
|
+
if (node.hooks[hook].length > 0 && !fold_is_open(state, group_key)) state.shown.set(group_key, state.page_size);
|
|
27923
27981
|
}
|
|
27924
27982
|
}
|
|
27925
27983
|
}
|
|
27984
|
+
function fold_close_levels(model, state, level) {
|
|
27985
|
+
for (let [key, lv] of model.level_of) {
|
|
27986
|
+
if (lv < level) continue;
|
|
27987
|
+
let node = model.nodes.get(key);
|
|
27988
|
+
if (!node) continue;
|
|
27989
|
+
for (let hook of Object.keys(node.hooks)) state.shown.delete(fold_group_key(key, hook));
|
|
27990
|
+
}
|
|
27991
|
+
}
|
|
27992
|
+
function fold_expand_to_level(model, state, level) {
|
|
27993
|
+
fold_collapse_all(model, state);
|
|
27994
|
+
fold_open_levels(model, state, fold_level_clamp(model, level));
|
|
27995
|
+
}
|
|
27926
27996
|
/************************************************************
|
|
27927
27997
|
* The set of node keys on screen, from the roots down through
|
|
27928
27998
|
* every open group -- and only through open groups whose parent
|
|
@@ -55165,8 +55235,9 @@ function ensure_brush_select_owned() {
|
|
|
55165
55235
|
* The graph opens FOLDED, like a JSON viewer.
|
|
55166
55236
|
*
|
|
55167
55237
|
* Every record of every topic is fetched, but only the ones on
|
|
55168
|
-
* screen become G6 nodes: the roots,
|
|
55169
|
-
*
|
|
55238
|
+
* screen become G6 nodes: the roots, and the MAIN tree open to
|
|
55239
|
+
* the reader's level (`fold_level`, `expand_depth` until they
|
|
55240
|
+
* step it), one page (`fold_page_size`) of children per hook. Each
|
|
55170
55241
|
* card carries a pill per hook that has children -- `▸ devices
|
|
55171
55242
|
* 142` -- which opens or folds that hook; an open hook with more
|
|
55172
55243
|
* children than its page ends in a `+N` chip that opens the next
|
|
@@ -55250,13 +55321,13 @@ var NODE_MODES$1 = [
|
|
|
55250
55321
|
"shape"
|
|
55251
55322
|
];
|
|
55252
55323
|
var PILL_SIZE = {
|
|
55253
|
-
|
|
55324
|
+
entity: [200, 30],
|
|
55254
55325
|
extended: [180, 28],
|
|
55255
55326
|
child: [160, 26]
|
|
55256
55327
|
};
|
|
55257
55328
|
var PORT_R_PILL = 6;
|
|
55258
55329
|
var SHAPE_SIZE = {
|
|
55259
|
-
|
|
55330
|
+
entity: 32,
|
|
55260
55331
|
extended: 28,
|
|
55261
55332
|
child: 22
|
|
55262
55333
|
};
|
|
@@ -55344,7 +55415,8 @@ var attrs_table$4 = [
|
|
|
55344
55415
|
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)"),
|
|
55345
55416
|
SDATA(data_type_t.DTP_STRING, "hook_port_position", 0, "bottom", "Hook port position"),
|
|
55346
55417
|
SDATA(data_type_t.DTP_STRING, "fkey_port_position", 0, "top", "Fkey port position"),
|
|
55347
|
-
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0,
|
|
55418
|
+
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0, 1, "Levels open when a treedb loads, until the reader steps (`fold_level`): 1 = the roots alone (the default), 2 = the roots and their children. Every open hook shows its first page"),
|
|
55419
|
+
SDATA(data_type_t.DTP_INTEGER, "fold_level", 0, 0, "The level of the MAIN tree the toolbar's stepper stands on: 1 = its roots, N = N-1 levels under them; 0 = `expand_depth`. The host persists it and sends EV_SET_FOLD_LEVEL; it is published back in EV_LEGEND_STATE (`fold`) with the levels the tree has"),
|
|
55348
55420
|
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"),
|
|
55349
55421
|
SDATA(data_type_t.DTP_LIST, "hidden_topics", 0, "[]", "Topics left out of the tree: no card, no pill counts them, no edge reaches them"),
|
|
55350
55422
|
SDATA(data_type_t.DTP_STRING, "main_topic", 0, "", "The topic the tree hangs from; empty = deduced (the one whose hooks reach the most others). Its parentless records are the roots; a parentless record of a topic linked to it is LOOSE and shown only on request"),
|
|
@@ -55435,7 +55507,8 @@ var PRIVATE_DATA$4 = {
|
|
|
55435
55507
|
_layout_asked: "",
|
|
55436
55508
|
_nodes_total: 0,
|
|
55437
55509
|
_nodes_placed: 0,
|
|
55438
|
-
expand_depth:
|
|
55510
|
+
expand_depth: 1,
|
|
55511
|
+
fold_level: 0,
|
|
55439
55512
|
fold_page_size: 24,
|
|
55440
55513
|
hidden_topics: null,
|
|
55441
55514
|
main_topic: "",
|
|
@@ -56158,7 +56231,12 @@ function configure_behaviour(gobj) {
|
|
|
56158
56231
|
graph_write_behaviors(gobj, behaviors);
|
|
56159
56232
|
}
|
|
56160
56233
|
/************************************************************
|
|
56161
|
-
* Count hooks and fkeys in topic desc, classify node type
|
|
56234
|
+
* Count hooks and fkeys in topic desc, classify node type:
|
|
56235
|
+
* `child` (no hooks), `extended` (hooks, no fkeys), `entity`
|
|
56236
|
+
* (both). It sizes the card and nothing else. It used to be
|
|
56237
|
+
* called `hierarchical`, and that word means something else now:
|
|
56238
|
+
* a topic hooked to ITSELF, the only kind a tree can hang from
|
|
56239
|
+
* (treedb_fold_model).
|
|
56162
56240
|
************************************************************/
|
|
56163
56241
|
function calculate_hooks_fkeys_counter(desc) {
|
|
56164
56242
|
let cols = desc.cols;
|
|
@@ -56175,7 +56253,7 @@ function calculate_hooks_fkeys_counter(desc) {
|
|
|
56175
56253
|
}
|
|
56176
56254
|
if (desc.hooks_counter === 0) desc.node_treedb_type = "child";
|
|
56177
56255
|
else if (desc.fkeys_counter === 0) desc.node_treedb_type = "extended";
|
|
56178
|
-
else desc.node_treedb_type = "
|
|
56256
|
+
else desc.node_treedb_type = "entity";
|
|
56179
56257
|
}
|
|
56180
56258
|
/************************************************************
|
|
56181
56259
|
* Build ports for a topic desc
|
|
@@ -56548,7 +56626,7 @@ function dress_ports(gobj, style, ports, geometry, topic_defaults, r_default, fi
|
|
|
56548
56626
|
************************************************************/
|
|
56549
56627
|
function pill_shape_of(gobj, desc, record, geometry) {
|
|
56550
56628
|
let priv = gobj.priv;
|
|
56551
|
-
let size = PILL_SIZE[desc.node_treedb_type] || PILL_SIZE.
|
|
56629
|
+
let size = PILL_SIZE[desc.node_treedb_type] || PILL_SIZE.entity;
|
|
56552
56630
|
let ports = build_ports(gobj, desc);
|
|
56553
56631
|
let paint = node_paint_of(gobj, desc, geometry);
|
|
56554
56632
|
let style = {
|
|
@@ -56597,7 +56675,7 @@ function figure_shape_of(gobj, desc, record, geometry, flags) {
|
|
|
56597
56675
|
let dark = priv.theme === "dark";
|
|
56598
56676
|
let f = flags || {};
|
|
56599
56677
|
let tier = desc.node_treedb_type;
|
|
56600
|
-
let side = SHAPE_SIZE[tier] || SHAPE_SIZE.
|
|
56678
|
+
let side = SHAPE_SIZE[tier] || SHAPE_SIZE.entity;
|
|
56601
56679
|
let labels = gobj_read_bool_attr(gobj, "node_labels");
|
|
56602
56680
|
let figure = node_figure_of(gobj, desc, geometry || {});
|
|
56603
56681
|
let paint = node_paint_of(gobj, desc, geometry);
|
|
@@ -59663,7 +59741,7 @@ function show_node_detail_popover(gobj, node_id) {
|
|
|
59663
59741
|
clamp_popover_position(gobj, popover);
|
|
59664
59742
|
}
|
|
59665
59743
|
/************************************************************
|
|
59666
|
-
* Re-render every HTML (
|
|
59744
|
+
* Re-render every HTML (entity) node so its card adopts
|
|
59667
59745
|
* the given theme: entity cards and leaf chips (baked innerHTML,
|
|
59668
59746
|
* not re-themed by setTheme()) are regenerated; structural
|
|
59669
59747
|
* junction diamonds get their neutral fill/stroke re-themed.
|
|
@@ -59782,7 +59860,7 @@ function refresh_minimap(gobj) {
|
|
|
59782
59860
|
}
|
|
59783
59861
|
/************************************************************
|
|
59784
59862
|
* The innerHTML of ONE node, in the given theme and highlight state.
|
|
59785
|
-
* The three treedb tiers (
|
|
59863
|
+
* The three treedb tiers (entity / extended / child) each have
|
|
59786
59864
|
* their own card, and both the theme refresh and the highlight need the
|
|
59787
59865
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
59788
59866
|
* shared now. Returns null for a node that carries no desc.
|
|
@@ -59799,7 +59877,7 @@ function node_innerHTML_of(nd, theme, highlight, selected, anchored, pills_html)
|
|
|
59799
59877
|
switch (desc.node_treedb_type) {
|
|
59800
59878
|
case "child": return build_chip_innerHTML(fill, theme, record.icon, label, record.id, highlight, selected, anchored);
|
|
59801
59879
|
case "extended": return build_node_innerHTML(fill, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected, anchored, pills_html);
|
|
59802
|
-
case "
|
|
59880
|
+
case "entity": return build_node_innerHTML(fill, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected, anchored, pills_html);
|
|
59803
59881
|
}
|
|
59804
59882
|
return null;
|
|
59805
59883
|
}
|
|
@@ -59996,7 +60074,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
59996
60074
|
`;
|
|
59997
60075
|
}
|
|
59998
60076
|
/************************************************************
|
|
59999
|
-
* Build innerHTML for
|
|
60077
|
+
* Build innerHTML for entity (HTML) nodes.
|
|
60000
60078
|
*
|
|
60001
60079
|
* Card style modelled on the documentation schema graphs
|
|
60002
60080
|
* (docs gen_treedb_graphs.py): rounded card, soft tint of the
|
|
@@ -61314,13 +61392,19 @@ function publish_legend_state(gobj, visible) {
|
|
|
61314
61392
|
loose: loose.length,
|
|
61315
61393
|
loose_shown: model.loose_shown.has(topic_name),
|
|
61316
61394
|
hidden: model.hidden.has(topic_name),
|
|
61317
|
-
linked: model.linked.has(topic_name)
|
|
61395
|
+
linked: model.linked.has(topic_name),
|
|
61396
|
+
hierarchical: fold_is_hierarchical(priv.descs, topic_name)
|
|
61318
61397
|
});
|
|
61319
61398
|
}
|
|
61320
61399
|
gobj_publish_event(gobj, "EV_LEGEND_STATE", {
|
|
61321
61400
|
main_topic: model.main_topic,
|
|
61322
|
-
main_chosen: !!gobj_read_str_attr(gobj, "main_topic"),
|
|
61323
|
-
topics
|
|
61401
|
+
main_chosen: !!model.main_topic && gobj_read_str_attr(gobj, "main_topic") === model.main_topic,
|
|
61402
|
+
topics,
|
|
61403
|
+
fold: {
|
|
61404
|
+
topic: model.main_topic,
|
|
61405
|
+
level: current_fold_level(gobj),
|
|
61406
|
+
levels: model.levels
|
|
61407
|
+
}
|
|
61324
61408
|
});
|
|
61325
61409
|
}
|
|
61326
61410
|
async function reconcile_fold_apply(gobj, opts, visible) {
|
|
@@ -61625,7 +61709,7 @@ function ac_load_data(gobj, event, kw, src) {
|
|
|
61625
61709
|
}
|
|
61626
61710
|
if (all_loaded && priv.graph) {
|
|
61627
61711
|
rebuild_fold_model(gobj);
|
|
61628
|
-
|
|
61712
|
+
fold_expand_to_level(priv._fold_model, priv._fold_state, current_fold_level(gobj));
|
|
61629
61713
|
count_placed_records(gobj);
|
|
61630
61714
|
let auto_laid = false;
|
|
61631
61715
|
try {
|
|
@@ -62029,19 +62113,46 @@ function ac_show_more(gobj, event, kw, src) {
|
|
|
62029
62113
|
return 0;
|
|
62030
62114
|
}
|
|
62031
62115
|
/************************************************************
|
|
62032
|
-
* The
|
|
62033
|
-
*
|
|
62034
|
-
* the
|
|
62116
|
+
* The level of the main tree the toolbar's stepper stands on:
|
|
62117
|
+
* `fold_level` once the reader has stepped, `expand_depth`
|
|
62118
|
+
* until then, clamped to the levels the tree has.
|
|
62035
62119
|
************************************************************/
|
|
62036
|
-
function
|
|
62120
|
+
function current_fold_level(gobj) {
|
|
62037
62121
|
let priv = gobj.priv;
|
|
62038
|
-
|
|
62039
|
-
|
|
62122
|
+
let level = gobj_read_integer_attr(gobj, "fold_level");
|
|
62123
|
+
if (!(level > 0)) level = gobj_read_integer_attr(gobj, "expand_depth");
|
|
62124
|
+
if (!priv._fold_model) return level;
|
|
62125
|
+
return fold_level_clamp(priv._fold_model, level);
|
|
62126
|
+
}
|
|
62127
|
+
/************************************************************
|
|
62128
|
+
* The toolbar's stepper: one level more or one less of the
|
|
62129
|
+
* MAIN tree (the host owns the number and persists it; this
|
|
62130
|
+
* applies it). Deeper opens the hooks above the new level,
|
|
62131
|
+
* shallower folds from it down -- a level is a floor, not a
|
|
62132
|
+
* picture, so what the reader opened by its pill stays (see
|
|
62133
|
+
* treedb_fold_model). Replaces expand all / collapse all
|
|
62134
|
+
* (7.23.141): the whole treedb at once was the pile, and
|
|
62135
|
+
* closing threw away everything the reader had opened.
|
|
62136
|
+
************************************************************/
|
|
62137
|
+
function ac_set_fold_level(gobj, event, kw, src) {
|
|
62138
|
+
let priv = gobj.priv;
|
|
62139
|
+
let level = Number(kw && kw.level);
|
|
62140
|
+
if (!(level > 0)) {
|
|
62141
|
+
log_error(`${gobj_short_name(gobj)}: fold level '${kw && kw.level}' is not a level`);
|
|
62040
62142
|
return -1;
|
|
62041
62143
|
}
|
|
62144
|
+
if (!priv._fold_model) {
|
|
62145
|
+
gobj_write_attr(gobj, "fold_level", level);
|
|
62146
|
+
return 0;
|
|
62147
|
+
}
|
|
62148
|
+
let from = current_fold_level(gobj);
|
|
62149
|
+
level = fold_level_clamp(priv._fold_model, level);
|
|
62150
|
+
gobj_write_attr(gobj, "fold_level", level);
|
|
62151
|
+
if (level === from) return 0;
|
|
62042
62152
|
let keep = fold_keep_node(gobj);
|
|
62043
62153
|
let vp = yui_graph_viewport_of(priv.graph, keep);
|
|
62044
|
-
|
|
62154
|
+
if (level > from) fold_open_levels(priv._fold_model, priv._fold_state, level);
|
|
62155
|
+
else fold_close_levels(priv._fold_model, priv._fold_state, level);
|
|
62045
62156
|
reconcile_fold(gobj, {
|
|
62046
62157
|
keep,
|
|
62047
62158
|
keep_vp: vp
|
|
@@ -62069,29 +62180,11 @@ function fold_keep_node(gobj) {
|
|
|
62069
62180
|
return "";
|
|
62070
62181
|
}
|
|
62071
62182
|
/************************************************************
|
|
62072
|
-
* The roots alone.
|
|
62073
|
-
************************************************************/
|
|
62074
|
-
function ac_collapse_all$1(gobj, event, kw, src) {
|
|
62075
|
-
let priv = gobj.priv;
|
|
62076
|
-
if (!priv._fold_model) {
|
|
62077
|
-
log_error(`${gobj_short_name(gobj)}: collapse all with no tree loaded`);
|
|
62078
|
-
return -1;
|
|
62079
|
-
}
|
|
62080
|
-
let keep = fold_keep_node(gobj);
|
|
62081
|
-
let vp = yui_graph_viewport_of(priv.graph, keep);
|
|
62082
|
-
fold_collapse_all(priv._fold_model, priv._fold_state);
|
|
62083
|
-
reconcile_fold(gobj, {
|
|
62084
|
-
keep,
|
|
62085
|
-
keep_vp: vp
|
|
62086
|
-
});
|
|
62087
|
-
return 0;
|
|
62088
|
-
}
|
|
62089
|
-
/************************************************************
|
|
62090
62183
|
* The legend's three settings, from the host, which persists
|
|
62091
62184
|
* them. Each rebuilds the tree; the fold state is kept -- it is
|
|
62092
62185
|
* keyed by group, and a group that is gone is never read -- except
|
|
62093
62186
|
* for a new MAIN topic, whose roots are other roots: the tree
|
|
62094
|
-
* opens again at
|
|
62187
|
+
* opens again at the reader's level, now counted from them.
|
|
62095
62188
|
************************************************************/
|
|
62096
62189
|
function ac_set_hidden_topics(gobj, event, kw, src) {
|
|
62097
62190
|
let priv = gobj.priv;
|
|
@@ -62109,7 +62202,7 @@ function ac_set_main_topic(gobj, event, kw, src) {
|
|
|
62109
62202
|
let keep = fold_keep_node(gobj);
|
|
62110
62203
|
let vp = yui_graph_viewport_of(priv.graph, keep);
|
|
62111
62204
|
rebuild_fold_model(gobj);
|
|
62112
|
-
|
|
62205
|
+
fold_expand_to_level(priv._fold_model, priv._fold_state, current_fold_level(gobj));
|
|
62113
62206
|
reconcile_fold(gobj, {
|
|
62114
62207
|
relayout: true,
|
|
62115
62208
|
keep,
|
|
@@ -62670,13 +62763,8 @@ function create_gclass$4(gclass_name) {
|
|
|
62670
62763
|
null
|
|
62671
62764
|
],
|
|
62672
62765
|
[
|
|
62673
|
-
"
|
|
62674
|
-
|
|
62675
|
-
null
|
|
62676
|
-
],
|
|
62677
|
-
[
|
|
62678
|
-
"EV_COLLAPSE_ALL",
|
|
62679
|
-
ac_collapse_all$1,
|
|
62766
|
+
"EV_SET_FOLD_LEVEL",
|
|
62767
|
+
ac_set_fold_level,
|
|
62680
62768
|
null
|
|
62681
62769
|
],
|
|
62682
62770
|
[
|
|
@@ -62819,8 +62907,7 @@ function create_gclass$4(gclass_name) {
|
|
|
62819
62907
|
["EV_CAMERA_CHANGED", event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],
|
|
62820
62908
|
["EV_TOGGLE_FOLD", 0],
|
|
62821
62909
|
["EV_SHOW_MORE", 0],
|
|
62822
|
-
["
|
|
62823
|
-
["EV_COLLAPSE_ALL", 0],
|
|
62910
|
+
["EV_SET_FOLD_LEVEL", 0],
|
|
62824
62911
|
["EV_SET_HIDDEN_TOPICS", 0],
|
|
62825
62912
|
["EV_SET_MAIN_TOPIC", 0],
|
|
62826
62913
|
["EV_SET_LOOSE_TOPICS", 0],
|
|
@@ -62887,7 +62974,7 @@ var attrs_table$3 = [
|
|
|
62887
62974
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
62888
62975
|
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."),
|
|
62889
62976
|
SDATA(data_type_t.DTP_BOOLEAN, "with_treedb_tables", 0, false, "Include treedb tables"),
|
|
62890
|
-
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0,
|
|
62977
|
+
SDATA(data_type_t.DTP_INTEGER, "expand_depth", 0, 1, "Levels of the treedb open when it loads, until the reader steps (`fold_level`): 1 = the roots alone (the default), 2 = the roots and their children. Forwarded to the G6 child"),
|
|
62891
62978
|
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"),
|
|
62892
62979
|
SDATA(data_type_t.DTP_INTEGER, "minimap_min_nodes", 0, 30, "Show the minimap from this many nodes on (0 = never). Forwarded to the G6 child"),
|
|
62893
62980
|
SDATA(data_type_t.DTP_BOOLEAN, "with_gridline", 0, true, "Draw the grid under the graph. Forwarded to the G6 child"),
|
|
@@ -62904,6 +62991,7 @@ var attrs_table$3 = [
|
|
|
62904
62991
|
SDATA(data_type_t.DTP_STRING, "node_mode", sdata_flag_t.SDF_PERSIST, "expanded", "How the records are drawn: `expanded` = the cards with their pills and ports, `compact` = one-line pills with the name, `shape` = coloured figures, the topology alone. User preference"),
|
|
62905
62992
|
SDATA(data_type_t.DTP_BOOLEAN, "node_labels", sdata_flag_t.SDF_PERSIST, true, "A `shape` node says its name under its figure. User preference"),
|
|
62906
62993
|
SDATA(data_type_t.DTP_DICT, "camera", sdata_flag_t.SDF_PERSIST, "{}", "Where the reader left the viewport: {zoom, x, y}. Handed to the engine on creation and written back when a move settles, so the graph opens where it was left. User preference, per treedb"),
|
|
62994
|
+
SDATA(data_type_t.DTP_INTEGER, "fold_level", sdata_flag_t.SDF_PERSIST, 0, "The level of the MAIN tree the toolbar's stepper stands on: 1 = the main topic's roots, N = N-1 levels under them; 0 = never stepped, `expand_depth`. Handed to the engine on creation, so the graph opens at the level it was left. User preference, per treedb"),
|
|
62907
62995
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
|
|
62908
62996
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote service treedb name"),
|
|
62909
62997
|
SDATA(data_type_t.DTP_DICT, "descs", 0, null, "Descriptions of topics obtained"),
|
|
@@ -62979,6 +63067,7 @@ function mt_create$3(gobj) {
|
|
|
62979
63067
|
hook_port_position: "bottom",
|
|
62980
63068
|
fkey_port_position: "top",
|
|
62981
63069
|
expand_depth: gobj_read_integer_attr(gobj, "expand_depth"),
|
|
63070
|
+
fold_level: gobj_read_integer_attr(gobj, "fold_level"),
|
|
62982
63071
|
fold_page_size: gobj_read_integer_attr(gobj, "fold_page_size"),
|
|
62983
63072
|
minimap_min_nodes: gobj_read_integer_attr(gobj, "minimap_min_nodes"),
|
|
62984
63073
|
with_gridline: gobj_read_bool_attr(gobj, "with_gridline"),
|
|
@@ -63286,6 +63375,127 @@ function refresh_node_shape_buttons(gobj, $root) {
|
|
|
63286
63375
|
$labels.disabled = mode !== "shape";
|
|
63287
63376
|
}
|
|
63288
63377
|
}
|
|
63378
|
+
/************************************************************
|
|
63379
|
+
* The fold STEPPER: one level less, where the tree stands, one
|
|
63380
|
+
* level more.
|
|
63381
|
+
*
|
|
63382
|
+
* It replaces the fold pair (7.23.141). `expand all` opened every
|
|
63383
|
+
* hook of the treedb -- the pile, on purpose, which on a treedb
|
|
63384
|
+
* of thousands is a pile nobody reads -- and `collapse all` threw
|
|
63385
|
+
* away everything the reader had opened. The stepper walks the
|
|
63386
|
+
* MAIN tree a level at a time, the way the frontend view opens
|
|
63387
|
+
* one level per press: `+` opens the next level under the main
|
|
63388
|
+
* topic's roots, through every topic that is not hidden; `-`
|
|
63389
|
+
* folds the deepest one. Pages and pills the reader opened stay.
|
|
63390
|
+
*
|
|
63391
|
+
* The readout says what the two buttons act on, which no chevron
|
|
63392
|
+
* can: the main topic -- its swatch and its name, which is DATA
|
|
63393
|
+
* and never translated -- and `level/levels`. On a phone the name
|
|
63394
|
+
* goes and the numbers stay. The level is the reader's, per
|
|
63395
|
+
* treedb: persisted (`fold_level`) and handed to the engine on
|
|
63396
|
+
* creation, so a reload opens where it was left.
|
|
63397
|
+
*
|
|
63398
|
+
* Both buttons are born disabled: nothing can be stepped until
|
|
63399
|
+
* the engine has said how deep the tree goes (EV_LEGEND_STATE).
|
|
63400
|
+
************************************************************/
|
|
63401
|
+
function fold_level_items(gobj, wide) {
|
|
63402
|
+
let step_button = (cls, icon, key, event_name) => {
|
|
63403
|
+
return [
|
|
63404
|
+
"button",
|
|
63405
|
+
{
|
|
63406
|
+
class: `${cls} button`,
|
|
63407
|
+
type: "button",
|
|
63408
|
+
style: {
|
|
63409
|
+
height: wide,
|
|
63410
|
+
width: "2.5em"
|
|
63411
|
+
},
|
|
63412
|
+
disabled: true,
|
|
63413
|
+
title: t(key),
|
|
63414
|
+
"data-i18n-title": key,
|
|
63415
|
+
"aria-label": t(key),
|
|
63416
|
+
"data-i18n-aria-label": key
|
|
63417
|
+
},
|
|
63418
|
+
yui_toolbar_icon(icon),
|
|
63419
|
+
{ click: (evt) => {
|
|
63420
|
+
evt.stopPropagation();
|
|
63421
|
+
gobj_send_event(gobj, event_name, {}, gobj);
|
|
63422
|
+
} }
|
|
63423
|
+
];
|
|
63424
|
+
};
|
|
63425
|
+
return [[
|
|
63426
|
+
"div",
|
|
63427
|
+
{
|
|
63428
|
+
class: "GRAPH_FOLD_STEPPER buttons has-addons",
|
|
63429
|
+
style: "margin:0; flex:0 0 auto; flex-wrap:nowrap; align-items:stretch;"
|
|
63430
|
+
},
|
|
63431
|
+
[
|
|
63432
|
+
step_button("GRAPH_FOLD_COLLAPSE", "yi-chevron-right", "collapse one level", "EV_COLLAPSE_LEVEL"),
|
|
63433
|
+
[
|
|
63434
|
+
"div",
|
|
63435
|
+
{
|
|
63436
|
+
class: "GRAPH_FOLD_LEVEL button",
|
|
63437
|
+
style: {
|
|
63438
|
+
height: wide,
|
|
63439
|
+
cursor: "default",
|
|
63440
|
+
gap: ".35rem"
|
|
63441
|
+
},
|
|
63442
|
+
role: "status",
|
|
63443
|
+
title: t("fold level"),
|
|
63444
|
+
"data-i18n-title": "fold level"
|
|
63445
|
+
},
|
|
63446
|
+
[
|
|
63447
|
+
["span", {
|
|
63448
|
+
class: "GRAPH_FOLD_SWATCH",
|
|
63449
|
+
style: "display:none; width:.8rem; height:.8rem; border-radius:3px; flex:0 0 auto; border:1px solid rgba(0,0,0,.25);"
|
|
63450
|
+
}],
|
|
63451
|
+
["span", {
|
|
63452
|
+
class: "GRAPH_FOLD_TOPIC is-hidden-mobile",
|
|
63453
|
+
style: "max-width:10em; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-weight:600;"
|
|
63454
|
+
}],
|
|
63455
|
+
[
|
|
63456
|
+
"span",
|
|
63457
|
+
{
|
|
63458
|
+
class: "GRAPH_FOLD_WORD",
|
|
63459
|
+
i18n: "level"
|
|
63460
|
+
},
|
|
63461
|
+
"level"
|
|
63462
|
+
],
|
|
63463
|
+
[
|
|
63464
|
+
"span",
|
|
63465
|
+
{
|
|
63466
|
+
class: "GRAPH_FOLD_COUNT",
|
|
63467
|
+
style: "font-variant-numeric:tabular-nums;"
|
|
63468
|
+
},
|
|
63469
|
+
"–"
|
|
63470
|
+
]
|
|
63471
|
+
]
|
|
63472
|
+
],
|
|
63473
|
+
step_button("GRAPH_FOLD_EXPAND", "yi-chevron-down", "expand one level", "EV_EXPAND_LEVEL")
|
|
63474
|
+
]
|
|
63475
|
+
]];
|
|
63476
|
+
}
|
|
63477
|
+
function refresh_fold_level(gobj) {
|
|
63478
|
+
let priv = gobj.priv;
|
|
63479
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
63480
|
+
if (!$container) return;
|
|
63481
|
+
let $readout = $container.querySelector(".GRAPH_FOLD_LEVEL");
|
|
63482
|
+
if (!$readout) return;
|
|
63483
|
+
let state = priv._legend_state || {};
|
|
63484
|
+
let fold = state.fold || {};
|
|
63485
|
+
let levels = fold.levels > 0 ? fold.levels : 0;
|
|
63486
|
+
let level = fold.level > 0 ? fold.level : 0;
|
|
63487
|
+
let topic = fold.topic || "";
|
|
63488
|
+
let entry = (is_array(state.topics) ? state.topics : []).find((e) => e.topic === topic);
|
|
63489
|
+
let $swatch = $readout.querySelector(".GRAPH_FOLD_SWATCH");
|
|
63490
|
+
$swatch.style.display = topic ? "inline-block" : "none";
|
|
63491
|
+
$swatch.style.background = entry && entry.color || "#94a3b8";
|
|
63492
|
+
$readout.querySelector(".GRAPH_FOLD_TOPIC").textContent = topic;
|
|
63493
|
+
$readout.querySelector(".GRAPH_FOLD_COUNT").textContent = levels ? `${level}/${levels}` : "–";
|
|
63494
|
+
let $collapse = $container.querySelector(".GRAPH_FOLD_COLLAPSE");
|
|
63495
|
+
let $expand = $container.querySelector(".GRAPH_FOLD_EXPAND");
|
|
63496
|
+
if ($collapse) $collapse.disabled = !(levels && level > 1);
|
|
63497
|
+
if ($expand) $expand.disabled = !(levels && level < levels);
|
|
63498
|
+
}
|
|
63289
63499
|
function make_toolbar(gobj) {
|
|
63290
63500
|
let priv = gobj.priv;
|
|
63291
63501
|
let modes = gobj_read_attr(gobj, "operation_modes");
|
|
@@ -63352,7 +63562,7 @@ function make_toolbar(gobj) {
|
|
|
63352
63562
|
} }
|
|
63353
63563
|
]
|
|
63354
63564
|
];
|
|
63355
|
-
let center_items = [...
|
|
63565
|
+
let center_items = [...fold_level_items(gobj, gobj_read_str_attr(gobj, "wide")), ...node_shape_items(gobj, gobj_read_str_attr(gobj, "wide"))];
|
|
63356
63566
|
let backend_items = [[
|
|
63357
63567
|
"button",
|
|
63358
63568
|
{
|
|
@@ -64415,6 +64625,7 @@ function refresh_legend(gobj) {
|
|
|
64415
64625
|
let topics = state.topics.slice().sort((a, b) => {
|
|
64416
64626
|
return String(a.topic).localeCompare(String(b.topic));
|
|
64417
64627
|
});
|
|
64628
|
+
let hierarchical_count = topics.filter((e) => e.hierarchical && !e.hidden).length;
|
|
64418
64629
|
for (let entry of topics) {
|
|
64419
64630
|
let topic_name = entry.topic;
|
|
64420
64631
|
let is_main = topic_name === state.main_topic;
|
|
@@ -64509,7 +64720,7 @@ function refresh_legend(gobj) {
|
|
|
64509
64720
|
"★"
|
|
64510
64721
|
]]
|
|
64511
64722
|
]);
|
|
64512
|
-
else if (!hidden) extras.push([
|
|
64723
|
+
else if (!hidden && entry.hierarchical && hierarchical_count > 1) extras.push([
|
|
64513
64724
|
"button",
|
|
64514
64725
|
{
|
|
64515
64726
|
class: "GRAPH_LEGEND_STAR button",
|
|
@@ -64608,6 +64819,7 @@ function ac_legend_state(gobj, event, kw, src) {
|
|
|
64608
64819
|
let priv = gobj.priv;
|
|
64609
64820
|
priv._legend_state = kw || null;
|
|
64610
64821
|
refresh_legend(gobj);
|
|
64822
|
+
refresh_fold_level(gobj);
|
|
64611
64823
|
return 0;
|
|
64612
64824
|
}
|
|
64613
64825
|
/************************************************************
|
|
@@ -64720,17 +64932,33 @@ function ac_find_nodes(gobj, event, kw, src) {
|
|
|
64720
64932
|
return 0;
|
|
64721
64933
|
}
|
|
64722
64934
|
/************************************************************
|
|
64723
|
-
*
|
|
64724
|
-
*
|
|
64935
|
+
* One press of the fold stepper (EV_EXPAND_LEVEL /
|
|
64936
|
+
* EV_COLLAPSE_LEVEL): the level moves by one, is SAVED (the
|
|
64937
|
+
* reader's, per treedb) and reaches the G6 child, which owns
|
|
64938
|
+
* the tree.
|
|
64939
|
+
*
|
|
64940
|
+
* The readout moves at once, not when the engine speaks again:
|
|
64941
|
+
* a reconcile is asynchronous, and a second press that came
|
|
64942
|
+
* before it would step from the level already left -- two
|
|
64943
|
+
* presses, one level.
|
|
64725
64944
|
************************************************************/
|
|
64726
|
-
function
|
|
64727
|
-
let priv = gobj.priv;
|
|
64728
|
-
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_EXPAND_ALL", {}, gobj);
|
|
64729
|
-
return 0;
|
|
64730
|
-
}
|
|
64731
|
-
function ac_collapse_all(gobj, event, kw, src) {
|
|
64945
|
+
function ac_fold_level_step(gobj, event, kw, src) {
|
|
64732
64946
|
let priv = gobj.priv;
|
|
64733
|
-
|
|
64947
|
+
let fold = priv._legend_state && priv._legend_state.fold;
|
|
64948
|
+
if (!fold || !(fold.levels > 0)) {
|
|
64949
|
+
log_error(`${gobj_short_name(gobj)}: ${event} with no tree to step through`);
|
|
64950
|
+
return -1;
|
|
64951
|
+
}
|
|
64952
|
+
let level = fold.level + (event === "EV_EXPAND_LEVEL" ? 1 : -1);
|
|
64953
|
+
if (level < 1 || level > fold.levels) {
|
|
64954
|
+
log_error(`${gobj_short_name(gobj)}: ${event}: level ${level} out of 1..${fold.levels}`);
|
|
64955
|
+
return -1;
|
|
64956
|
+
}
|
|
64957
|
+
gobj_write_attr(gobj, "fold_level", level);
|
|
64958
|
+
gobj_save_persistent_attrs(gobj, "fold_level");
|
|
64959
|
+
fold.level = level;
|
|
64960
|
+
refresh_fold_level(gobj);
|
|
64961
|
+
if (priv.gobj_nodes_tree) gobj_send_event(priv.gobj_nodes_tree, "EV_SET_FOLD_LEVEL", { level }, gobj);
|
|
64734
64962
|
return 0;
|
|
64735
64963
|
}
|
|
64736
64964
|
/************************************************************
|
|
@@ -64967,13 +65195,13 @@ function create_gclass$3(gclass_name) {
|
|
|
64967
65195
|
null
|
|
64968
65196
|
],
|
|
64969
65197
|
[
|
|
64970
|
-
"
|
|
64971
|
-
|
|
65198
|
+
"EV_EXPAND_LEVEL",
|
|
65199
|
+
ac_fold_level_step,
|
|
64972
65200
|
null
|
|
64973
65201
|
],
|
|
64974
65202
|
[
|
|
64975
|
-
"
|
|
64976
|
-
|
|
65203
|
+
"EV_COLLAPSE_LEVEL",
|
|
65204
|
+
ac_fold_level_step,
|
|
64977
65205
|
null
|
|
64978
65206
|
],
|
|
64979
65207
|
[
|
|
@@ -65058,8 +65286,8 @@ function create_gclass$3(gclass_name) {
|
|
|
65058
65286
|
["EV_SET_OPERATION_MODE", 0],
|
|
65059
65287
|
["EV_SET_FOCUS_TOPIC", 0],
|
|
65060
65288
|
["EV_FIND_NODES", 0],
|
|
65061
|
-
["
|
|
65062
|
-
["
|
|
65289
|
+
["EV_EXPAND_LEVEL", 0],
|
|
65290
|
+
["EV_COLLAPSE_LEVEL", 0],
|
|
65063
65291
|
["EV_SET_NODE_MODE", 0],
|
|
65064
65292
|
["EV_TOGGLE_NODE_LABELS", 0],
|
|
65065
65293
|
["EV_FIND_RESULT", 0],
|
|
@@ -65841,7 +66069,7 @@ function sort_by_order(list) {
|
|
|
65841
66069
|
* schema_version, c_schema_version, system_schema_version,
|
|
65842
66070
|
* topics: [{
|
|
65843
66071
|
* id, name, order, record,
|
|
65844
|
-
* pkey, topic_version, system_topic,
|
|
66072
|
+
* pkey, topic_version, system_topic, main_topic,
|
|
65845
66073
|
* cols: [{id, name, order, record}]
|
|
65846
66074
|
* }]
|
|
65847
66075
|
* }],
|
|
@@ -65890,6 +66118,7 @@ function build_schema_model(records) {
|
|
|
65890
66118
|
tkey: record.tkey || "",
|
|
65891
66119
|
topic_version: record.topic_version,
|
|
65892
66120
|
system_topic: !!record.system_topic,
|
|
66121
|
+
main_topic: !!record.main_topic,
|
|
65893
66122
|
cols: []
|
|
65894
66123
|
};
|
|
65895
66124
|
by_topic_id[entry.id] = entry;
|
|
@@ -66186,6 +66415,12 @@ function validate_schema(treedb, options) {
|
|
|
66186
66415
|
if (is_fkey && FKEY_TYPES.indexOf(type) < 0) add("error", "fkey has a bad type", topic.name, col.name, type);
|
|
66187
66416
|
}
|
|
66188
66417
|
}
|
|
66418
|
+
let marked = treedb.topics.filter((topic) => topic.main_topic);
|
|
66419
|
+
if (marked.length > 1) add("error", "more than one main topic", marked[1].name, "", marked.map((topic) => topic.name).join(", "));
|
|
66420
|
+
for (let topic of marked) if (!topic.cols.some((col) => {
|
|
66421
|
+
let hook = col_hook(col.record);
|
|
66422
|
+
return col_flags(col.record).indexOf("hook") >= 0 && !!hook && Object.prototype.hasOwnProperty.call(hook, topic.name);
|
|
66423
|
+
})) add("error", "main topic not hooked to itself", topic.name, "", "");
|
|
66189
66424
|
let hooked = {};
|
|
66190
66425
|
for (let topic of treedb.topics) for (let col of topic.cols) {
|
|
66191
66426
|
let hook = col_hook(col.record);
|
|
@@ -66377,7 +66612,8 @@ var TOPIC_KEY_ORDER = [
|
|
|
66377
66612
|
"system_flag",
|
|
66378
66613
|
"tkey",
|
|
66379
66614
|
"topic_version",
|
|
66380
|
-
"system_topic"
|
|
66615
|
+
"system_topic",
|
|
66616
|
+
"main_topic"
|
|
66381
66617
|
];
|
|
66382
66618
|
var COL_KEY_ORDER = [
|
|
66383
66619
|
"header",
|
|
@@ -66635,7 +66871,8 @@ var TOPIC_FIELDS = [
|
|
|
66635
66871
|
"system_flag",
|
|
66636
66872
|
"tkey",
|
|
66637
66873
|
"topic_version",
|
|
66638
|
-
"system_topic"
|
|
66874
|
+
"system_topic",
|
|
66875
|
+
"main_topic"
|
|
66639
66876
|
];
|
|
66640
66877
|
var COL_FIELDS = [
|
|
66641
66878
|
"header",
|
|
@@ -68252,6 +68489,20 @@ function render_topics(gobj, $body) {
|
|
|
68252
68489
|
{},
|
|
68253
68490
|
""
|
|
68254
68491
|
],
|
|
68492
|
+
topic.main_topic ? [
|
|
68493
|
+
"span",
|
|
68494
|
+
{
|
|
68495
|
+
class: "SCHEMA_TOPIC_MAIN ml-2",
|
|
68496
|
+
style: "color:#d4a017;",
|
|
68497
|
+
title: t("main topic"),
|
|
68498
|
+
"data-i18n-title": "main topic"
|
|
68499
|
+
},
|
|
68500
|
+
"★"
|
|
68501
|
+
] : [
|
|
68502
|
+
"span",
|
|
68503
|
+
{},
|
|
68504
|
+
""
|
|
68505
|
+
],
|
|
68255
68506
|
ambiguous ? [
|
|
68256
68507
|
"div",
|
|
68257
68508
|
{ class: "SCHEMA_TOPIC_ID is-size-7 yui-text-quiet" },
|
|
@@ -69246,6 +69497,26 @@ function open_topic_form(gobj, treedb, topic) {
|
|
|
69246
69497
|
]]
|
|
69247
69498
|
]]
|
|
69248
69499
|
],
|
|
69500
|
+
[
|
|
69501
|
+
"div",
|
|
69502
|
+
{ class: "SCHEMA_TOPIC_FORM_MAIN field mb-3" },
|
|
69503
|
+
[[
|
|
69504
|
+
"label",
|
|
69505
|
+
{ class: "checkbox" },
|
|
69506
|
+
[["input", el_attrs({
|
|
69507
|
+
type: "checkbox",
|
|
69508
|
+
"data-name": "main_topic",
|
|
69509
|
+
checked: record.main_topic ? "checked" : void 0
|
|
69510
|
+
})], [
|
|
69511
|
+
"span",
|
|
69512
|
+
{
|
|
69513
|
+
class: "ml-1",
|
|
69514
|
+
i18n: "main topic"
|
|
69515
|
+
},
|
|
69516
|
+
t("main topic")
|
|
69517
|
+
]]
|
|
69518
|
+
]]
|
|
69519
|
+
],
|
|
69249
69520
|
[
|
|
69250
69521
|
"div",
|
|
69251
69522
|
{
|
|
@@ -70038,6 +70309,7 @@ function topic_record(gobj, treedb, topic, values) {
|
|
|
70038
70309
|
record.tkey = values.tkey || "";
|
|
70039
70310
|
record.topic_version = values.topic_version === "" ? 1 : Number(values.topic_version);
|
|
70040
70311
|
record.system_topic = !!values.system_topic;
|
|
70312
|
+
record.main_topic = !!values.main_topic;
|
|
70041
70313
|
return record;
|
|
70042
70314
|
}
|
|
70043
70315
|
/***************************
|