@yuneta/gobj-ui 7.23.136 → 7.23.138
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/dist/gobj-ui.cjs.js +118 -61
- package/dist/gobj-ui.es.js +118 -61
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +69 -1
- package/src/c_yui_treedb_graph.js +31 -15
- package/src/c_yui_treedb_topics.js +38 -9
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -21908,6 +21908,31 @@ function cmd_get_topic_data$1(gobj, cmd, kw, src) {
|
|
|
21908
21908
|
************************************************************/
|
|
21909
21909
|
function build_ui$6(gobj) {
|
|
21910
21910
|
let source_url = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "source_url") || "";
|
|
21911
|
+
let routes = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "card_action_routes");
|
|
21912
|
+
let graph_tpl = (0, _yuneta_gobj_js.is_object)(routes) && typeof routes.graph === "string" ? routes.graph : "";
|
|
21913
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl) ? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
21914
|
+
let graph_items = [];
|
|
21915
|
+
if (graph_href) graph_items.push([
|
|
21916
|
+
"a",
|
|
21917
|
+
{
|
|
21918
|
+
class: "button TREEDB_GRAPH_BTN",
|
|
21919
|
+
href: graph_href,
|
|
21920
|
+
style: "margin-left:auto;",
|
|
21921
|
+
title: (0, i18next.t)("graph"),
|
|
21922
|
+
"aria-label": (0, i18next.t)("graph"),
|
|
21923
|
+
"data-i18n-title": "graph",
|
|
21924
|
+
"data-i18n-aria-label": "graph"
|
|
21925
|
+
},
|
|
21926
|
+
[[
|
|
21927
|
+
"span",
|
|
21928
|
+
{ class: "icon" },
|
|
21929
|
+
[yui_toolbar_icon("yi-hexagon-nodes")]
|
|
21930
|
+
], [
|
|
21931
|
+
"span",
|
|
21932
|
+
{ i18n: "graph" },
|
|
21933
|
+
"graph"
|
|
21934
|
+
]]
|
|
21935
|
+
]);
|
|
21911
21936
|
let $container = (0, _yuneta_gobj_js.createElement2)([
|
|
21912
21937
|
"div",
|
|
21913
21938
|
{
|
|
@@ -21988,11 +22013,12 @@ function build_ui$6(gobj) {
|
|
|
21988
22013
|
source_url
|
|
21989
22014
|
]]
|
|
21990
22015
|
],
|
|
22016
|
+
...graph_items,
|
|
21991
22017
|
[
|
|
21992
22018
|
"button",
|
|
21993
22019
|
{
|
|
21994
22020
|
class: "button TREEDB_JSON_BTN",
|
|
21995
|
-
style: "margin-left:auto;",
|
|
22021
|
+
style: graph_href ? "" : "margin-left:auto;",
|
|
21996
22022
|
title: (0, i18next.t)("raw json"),
|
|
21997
22023
|
"aria-label": (0, i18next.t)("raw json"),
|
|
21998
22024
|
"data-i18n-title": "raw json",
|
|
@@ -57017,12 +57043,41 @@ var MIN_READABLE_ZOOM = .5;
|
|
|
57017
57043
|
* G6 reports them.
|
|
57018
57044
|
************************************************************/
|
|
57019
57045
|
var CAMERA_SETTLE_MS = 700;
|
|
57046
|
+
function node_nearest_view_centre(gobj) {
|
|
57047
|
+
let graph = gobj.priv.graph;
|
|
57048
|
+
let size;
|
|
57049
|
+
try {
|
|
57050
|
+
size = graph.getSize();
|
|
57051
|
+
} catch (e) {
|
|
57052
|
+
return "";
|
|
57053
|
+
}
|
|
57054
|
+
if (!(0, _yuneta_gobj_js.is_array)(size) || !(size[0] > 0) || !(size[1] > 0)) return "";
|
|
57055
|
+
let [w, h] = size;
|
|
57056
|
+
let best = "";
|
|
57057
|
+
let best_d = Infinity;
|
|
57058
|
+
for (let nd of graph.getNodeData() || []) {
|
|
57059
|
+
let vp = yui_graph_viewport_of(graph, nd.id);
|
|
57060
|
+
if (!vp || !(0, _yuneta_gobj_js.is_number)(vp[0]) || !(0, _yuneta_gobj_js.is_number)(vp[1])) continue;
|
|
57061
|
+
if (vp[0] < 0 || vp[1] < 0 || vp[0] > w || vp[1] > h) continue;
|
|
57062
|
+
let d = (vp[0] - w / 2) ** 2 + (vp[1] - h / 2) ** 2;
|
|
57063
|
+
if (d < best_d) {
|
|
57064
|
+
best_d = d;
|
|
57065
|
+
best = nd.id;
|
|
57066
|
+
}
|
|
57067
|
+
}
|
|
57068
|
+
return best;
|
|
57069
|
+
}
|
|
57070
|
+
function camera_anchor_node(gobj) {
|
|
57071
|
+
let priv = gobj.priv;
|
|
57072
|
+
if (priv.anchor_state === "on" && priv.anchor_id) return priv.anchor_id;
|
|
57073
|
+
return node_nearest_view_centre(gobj) || fold_keep_node(gobj);
|
|
57074
|
+
}
|
|
57020
57075
|
function read_camera(gobj) {
|
|
57021
57076
|
let graph = gobj.priv.graph;
|
|
57022
57077
|
if (!graph || typeof graph.getZoom !== "function") return null;
|
|
57023
57078
|
try {
|
|
57024
57079
|
let z = graph.getZoom();
|
|
57025
|
-
let node =
|
|
57080
|
+
let node = camera_anchor_node(gobj);
|
|
57026
57081
|
let vp = node ? yui_graph_viewport_of(graph, node) : null;
|
|
57027
57082
|
if (!(0, _yuneta_gobj_js.is_number)(z) || !node || !vp || !(0, _yuneta_gobj_js.is_number)(vp[0]) || !(0, _yuneta_gobj_js.is_number)(vp[1])) return null;
|
|
57028
57083
|
return {
|
|
@@ -57041,6 +57096,8 @@ async function restore_camera(gobj) {
|
|
|
57041
57096
|
let cam = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "camera");
|
|
57042
57097
|
if (!graph || (0, _yuneta_gobj_js.empty_json)(cam) || !(0, _yuneta_gobj_js.is_number)(cam.zoom) || !cam.node || !(0, _yuneta_gobj_js.is_number)(cam.x) || !(0, _yuneta_gobj_js.is_number)(cam.y)) return false;
|
|
57043
57098
|
if (!yui_graph_viewport_of(graph, cam.node)) return false;
|
|
57099
|
+
let size = graph.getSize() || [0, 0];
|
|
57100
|
+
if (cam.x < 0 || cam.y < 0 || cam.x > size[0] || cam.y > size[1]) return false;
|
|
57044
57101
|
priv._camera_restoring = true;
|
|
57045
57102
|
try {
|
|
57046
57103
|
await graph.zoomTo(cam.zoom);
|
|
@@ -61262,6 +61319,7 @@ async function reconcile_fold_apply(gobj, opts, visible) {
|
|
|
61262
61319
|
if (opts.fit) await graph_fit_readable(gobj);
|
|
61263
61320
|
else if (opts.keep && opts.keep_vp) await yui_graph_place_at(graph, opts.keep, opts.keep_vp);
|
|
61264
61321
|
}
|
|
61322
|
+
if ((graph.getNodeData() || []).length > 0 && !node_nearest_view_centre(gobj)) await graph_fit_readable(gobj);
|
|
61265
61323
|
priv._camera_placed = true;
|
|
61266
61324
|
update_resize_handles_position(gobj);
|
|
61267
61325
|
update_port_resize_handles_position(gobj);
|
|
@@ -63130,56 +63188,54 @@ function make_toolbar(gobj) {
|
|
|
63130
63188
|
evt.stopPropagation();
|
|
63131
63189
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SET_OPERATION_MODE", { operation_mode: evt.target.value }, gobj);
|
|
63132
63190
|
} }
|
|
63133
|
-
]
|
|
63134
|
-
|
|
63135
|
-
|
|
63191
|
+
]
|
|
63192
|
+
];
|
|
63193
|
+
let center_items = [...yui_graph_fold_items(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "wide")), ...node_shape_items(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "wide"))];
|
|
63194
|
+
let backend_items = [[
|
|
63195
|
+
"button",
|
|
63196
|
+
{
|
|
63197
|
+
class: "GRAPH_REFRESH button",
|
|
63198
|
+
title: (0, i18next.t)("refresh"),
|
|
63199
|
+
"data-i18n-title": "refresh",
|
|
63200
|
+
"aria-label": (0, i18next.t)("refresh"),
|
|
63201
|
+
"data-i18n-aria-label": "refresh"
|
|
63202
|
+
},
|
|
63203
|
+
[yui_toolbar_icon("yi-arrows-rotate"), [
|
|
63204
|
+
"span",
|
|
63136
63205
|
{
|
|
63137
|
-
class: "
|
|
63138
|
-
|
|
63139
|
-
|
|
63140
|
-
"aria-label": (0, i18next.t)("refresh"),
|
|
63141
|
-
"data-i18n-aria-label": "refresh"
|
|
63206
|
+
class: "is-hidden-mobile",
|
|
63207
|
+
style: "padding-left:5px;",
|
|
63208
|
+
i18n: "refresh"
|
|
63142
63209
|
},
|
|
63143
|
-
|
|
63144
|
-
|
|
63145
|
-
|
|
63146
|
-
|
|
63147
|
-
|
|
63148
|
-
|
|
63149
|
-
|
|
63150
|
-
|
|
63151
|
-
|
|
63152
|
-
|
|
63153
|
-
|
|
63154
|
-
|
|
63155
|
-
|
|
63156
|
-
|
|
63157
|
-
|
|
63158
|
-
|
|
63159
|
-
|
|
63160
|
-
"button",
|
|
63210
|
+
"refresh"
|
|
63211
|
+
]],
|
|
63212
|
+
{ click: (evt) => {
|
|
63213
|
+
evt.stopPropagation();
|
|
63214
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TREEDB", { evt }, gobj);
|
|
63215
|
+
} }
|
|
63216
|
+
], [
|
|
63217
|
+
"button",
|
|
63218
|
+
{
|
|
63219
|
+
class: "button ml-2 TREEDB_JSON_BTN",
|
|
63220
|
+
title: (0, i18next.t)("raw json"),
|
|
63221
|
+
"aria-label": (0, i18next.t)("raw json"),
|
|
63222
|
+
"data-i18n-title": "raw json",
|
|
63223
|
+
"data-i18n-aria-label": "raw json"
|
|
63224
|
+
},
|
|
63225
|
+
[yui_toolbar_icon("yi-eye"), [
|
|
63226
|
+
"span",
|
|
63161
63227
|
{
|
|
63162
|
-
class: "
|
|
63163
|
-
|
|
63164
|
-
|
|
63165
|
-
"data-i18n-title": "raw json",
|
|
63166
|
-
"data-i18n-aria-label": "raw json"
|
|
63228
|
+
class: "is-hidden-mobile",
|
|
63229
|
+
style: "padding-left:5px;",
|
|
63230
|
+
i18n: "raw json"
|
|
63167
63231
|
},
|
|
63168
|
-
|
|
63169
|
-
|
|
63170
|
-
|
|
63171
|
-
|
|
63172
|
-
|
|
63173
|
-
|
|
63174
|
-
|
|
63175
|
-
"raw json"
|
|
63176
|
-
]],
|
|
63177
|
-
{ click: (evt) => {
|
|
63178
|
-
evt.stopPropagation();
|
|
63179
|
-
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_OPEN_JSON", {}, gobj);
|
|
63180
|
-
} }
|
|
63181
|
-
]
|
|
63182
|
-
];
|
|
63232
|
+
"raw json"
|
|
63233
|
+
]],
|
|
63234
|
+
{ click: (evt) => {
|
|
63235
|
+
evt.stopPropagation();
|
|
63236
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_OPEN_JSON", {}, gobj);
|
|
63237
|
+
} }
|
|
63238
|
+
]];
|
|
63183
63239
|
let $find_input = (0, _yuneta_gobj_js.createElement2)([
|
|
63184
63240
|
"input",
|
|
63185
63241
|
{
|
|
@@ -63214,6 +63270,18 @@ function make_toolbar(gobj) {
|
|
|
63214
63270
|
]]
|
|
63215
63271
|
]);
|
|
63216
63272
|
attach_clear($find_control, $find_input);
|
|
63273
|
+
let right_items = [...[$find_control, [
|
|
63274
|
+
"div",
|
|
63275
|
+
{
|
|
63276
|
+
class: "GRAPH_FIND_RESULT is-hidden",
|
|
63277
|
+
style: "display:flex; align-items:center; gap:.3rem; margin-right:.5rem; font-size:.85rem;"
|
|
63278
|
+
},
|
|
63279
|
+
[[
|
|
63280
|
+
"span",
|
|
63281
|
+
{ class: "GRAPH_FIND_COUNT" },
|
|
63282
|
+
""
|
|
63283
|
+
]]
|
|
63284
|
+
]], ...backend_items];
|
|
63217
63285
|
const $toolbar_header = yui_toolbar({}, [
|
|
63218
63286
|
[
|
|
63219
63287
|
"div",
|
|
@@ -63223,23 +63291,12 @@ function make_toolbar(gobj) {
|
|
|
63223
63291
|
[
|
|
63224
63292
|
"div",
|
|
63225
63293
|
{ class: "yui-horizontal-toolbar-section center" },
|
|
63226
|
-
|
|
63227
|
-
"div",
|
|
63228
|
-
{
|
|
63229
|
-
class: "GRAPH_FIND_RESULT is-hidden",
|
|
63230
|
-
style: "display:flex; align-items:center; gap:.3rem; margin-right:.5rem; font-size:.85rem;"
|
|
63231
|
-
},
|
|
63232
|
-
[[
|
|
63233
|
-
"span",
|
|
63234
|
-
{ class: "GRAPH_FIND_COUNT" },
|
|
63235
|
-
""
|
|
63236
|
-
]]
|
|
63237
|
-
]]
|
|
63294
|
+
center_items
|
|
63238
63295
|
],
|
|
63239
63296
|
[
|
|
63240
63297
|
"div",
|
|
63241
63298
|
{ class: "GRAPH_MODE_BUTTONS yui-horizontal-toolbar-section right" },
|
|
63242
|
-
|
|
63299
|
+
right_items
|
|
63243
63300
|
]
|
|
63244
63301
|
]);
|
|
63245
63302
|
(0, _yuneta_gobj_js.refresh_language)($toolbar_header, i18next.t);
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -21903,6 +21903,31 @@ function cmd_get_topic_data$1(gobj, cmd, kw, src) {
|
|
|
21903
21903
|
************************************************************/
|
|
21904
21904
|
function build_ui$6(gobj) {
|
|
21905
21905
|
let source_url = gobj_read_str_attr(gobj, "source_url") || "";
|
|
21906
|
+
let routes = gobj_read_attr(gobj, "card_action_routes");
|
|
21907
|
+
let graph_tpl = is_object(routes) && typeof routes.graph === "string" ? routes.graph : "";
|
|
21908
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl) ? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
21909
|
+
let graph_items = [];
|
|
21910
|
+
if (graph_href) graph_items.push([
|
|
21911
|
+
"a",
|
|
21912
|
+
{
|
|
21913
|
+
class: "button TREEDB_GRAPH_BTN",
|
|
21914
|
+
href: graph_href,
|
|
21915
|
+
style: "margin-left:auto;",
|
|
21916
|
+
title: t("graph"),
|
|
21917
|
+
"aria-label": t("graph"),
|
|
21918
|
+
"data-i18n-title": "graph",
|
|
21919
|
+
"data-i18n-aria-label": "graph"
|
|
21920
|
+
},
|
|
21921
|
+
[[
|
|
21922
|
+
"span",
|
|
21923
|
+
{ class: "icon" },
|
|
21924
|
+
[yui_toolbar_icon("yi-hexagon-nodes")]
|
|
21925
|
+
], [
|
|
21926
|
+
"span",
|
|
21927
|
+
{ i18n: "graph" },
|
|
21928
|
+
"graph"
|
|
21929
|
+
]]
|
|
21930
|
+
]);
|
|
21906
21931
|
let $container = createElement2([
|
|
21907
21932
|
"div",
|
|
21908
21933
|
{
|
|
@@ -21983,11 +22008,12 @@ function build_ui$6(gobj) {
|
|
|
21983
22008
|
source_url
|
|
21984
22009
|
]]
|
|
21985
22010
|
],
|
|
22011
|
+
...graph_items,
|
|
21986
22012
|
[
|
|
21987
22013
|
"button",
|
|
21988
22014
|
{
|
|
21989
22015
|
class: "button TREEDB_JSON_BTN",
|
|
21990
|
-
style: "margin-left:auto;",
|
|
22016
|
+
style: graph_href ? "" : "margin-left:auto;",
|
|
21991
22017
|
title: t("raw json"),
|
|
21992
22018
|
"aria-label": t("raw json"),
|
|
21993
22019
|
"data-i18n-title": "raw json",
|
|
@@ -57012,12 +57038,41 @@ var MIN_READABLE_ZOOM = .5;
|
|
|
57012
57038
|
* G6 reports them.
|
|
57013
57039
|
************************************************************/
|
|
57014
57040
|
var CAMERA_SETTLE_MS = 700;
|
|
57041
|
+
function node_nearest_view_centre(gobj) {
|
|
57042
|
+
let graph = gobj.priv.graph;
|
|
57043
|
+
let size;
|
|
57044
|
+
try {
|
|
57045
|
+
size = graph.getSize();
|
|
57046
|
+
} catch (e) {
|
|
57047
|
+
return "";
|
|
57048
|
+
}
|
|
57049
|
+
if (!is_array(size) || !(size[0] > 0) || !(size[1] > 0)) return "";
|
|
57050
|
+
let [w, h] = size;
|
|
57051
|
+
let best = "";
|
|
57052
|
+
let best_d = Infinity;
|
|
57053
|
+
for (let nd of graph.getNodeData() || []) {
|
|
57054
|
+
let vp = yui_graph_viewport_of(graph, nd.id);
|
|
57055
|
+
if (!vp || !is_number(vp[0]) || !is_number(vp[1])) continue;
|
|
57056
|
+
if (vp[0] < 0 || vp[1] < 0 || vp[0] > w || vp[1] > h) continue;
|
|
57057
|
+
let d = (vp[0] - w / 2) ** 2 + (vp[1] - h / 2) ** 2;
|
|
57058
|
+
if (d < best_d) {
|
|
57059
|
+
best_d = d;
|
|
57060
|
+
best = nd.id;
|
|
57061
|
+
}
|
|
57062
|
+
}
|
|
57063
|
+
return best;
|
|
57064
|
+
}
|
|
57065
|
+
function camera_anchor_node(gobj) {
|
|
57066
|
+
let priv = gobj.priv;
|
|
57067
|
+
if (priv.anchor_state === "on" && priv.anchor_id) return priv.anchor_id;
|
|
57068
|
+
return node_nearest_view_centre(gobj) || fold_keep_node(gobj);
|
|
57069
|
+
}
|
|
57015
57070
|
function read_camera(gobj) {
|
|
57016
57071
|
let graph = gobj.priv.graph;
|
|
57017
57072
|
if (!graph || typeof graph.getZoom !== "function") return null;
|
|
57018
57073
|
try {
|
|
57019
57074
|
let z = graph.getZoom();
|
|
57020
|
-
let node =
|
|
57075
|
+
let node = camera_anchor_node(gobj);
|
|
57021
57076
|
let vp = node ? yui_graph_viewport_of(graph, node) : null;
|
|
57022
57077
|
if (!is_number(z) || !node || !vp || !is_number(vp[0]) || !is_number(vp[1])) return null;
|
|
57023
57078
|
return {
|
|
@@ -57036,6 +57091,8 @@ async function restore_camera(gobj) {
|
|
|
57036
57091
|
let cam = gobj_read_attr(gobj, "camera");
|
|
57037
57092
|
if (!graph || empty_json(cam) || !is_number(cam.zoom) || !cam.node || !is_number(cam.x) || !is_number(cam.y)) return false;
|
|
57038
57093
|
if (!yui_graph_viewport_of(graph, cam.node)) return false;
|
|
57094
|
+
let size = graph.getSize() || [0, 0];
|
|
57095
|
+
if (cam.x < 0 || cam.y < 0 || cam.x > size[0] || cam.y > size[1]) return false;
|
|
57039
57096
|
priv._camera_restoring = true;
|
|
57040
57097
|
try {
|
|
57041
57098
|
await graph.zoomTo(cam.zoom);
|
|
@@ -61257,6 +61314,7 @@ async function reconcile_fold_apply(gobj, opts, visible) {
|
|
|
61257
61314
|
if (opts.fit) await graph_fit_readable(gobj);
|
|
61258
61315
|
else if (opts.keep && opts.keep_vp) await yui_graph_place_at(graph, opts.keep, opts.keep_vp);
|
|
61259
61316
|
}
|
|
61317
|
+
if ((graph.getNodeData() || []).length > 0 && !node_nearest_view_centre(gobj)) await graph_fit_readable(gobj);
|
|
61260
61318
|
priv._camera_placed = true;
|
|
61261
61319
|
update_resize_handles_position(gobj);
|
|
61262
61320
|
update_port_resize_handles_position(gobj);
|
|
@@ -63125,56 +63183,54 @@ function make_toolbar(gobj) {
|
|
|
63125
63183
|
evt.stopPropagation();
|
|
63126
63184
|
gobj_send_event(gobj, "EV_SET_OPERATION_MODE", { operation_mode: evt.target.value }, gobj);
|
|
63127
63185
|
} }
|
|
63128
|
-
]
|
|
63129
|
-
|
|
63130
|
-
|
|
63186
|
+
]
|
|
63187
|
+
];
|
|
63188
|
+
let center_items = [...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")), ...node_shape_items(gobj, gobj_read_str_attr(gobj, "wide"))];
|
|
63189
|
+
let backend_items = [[
|
|
63190
|
+
"button",
|
|
63191
|
+
{
|
|
63192
|
+
class: "GRAPH_REFRESH button",
|
|
63193
|
+
title: t("refresh"),
|
|
63194
|
+
"data-i18n-title": "refresh",
|
|
63195
|
+
"aria-label": t("refresh"),
|
|
63196
|
+
"data-i18n-aria-label": "refresh"
|
|
63197
|
+
},
|
|
63198
|
+
[yui_toolbar_icon("yi-arrows-rotate"), [
|
|
63199
|
+
"span",
|
|
63131
63200
|
{
|
|
63132
|
-
class: "
|
|
63133
|
-
|
|
63134
|
-
|
|
63135
|
-
"aria-label": t("refresh"),
|
|
63136
|
-
"data-i18n-aria-label": "refresh"
|
|
63201
|
+
class: "is-hidden-mobile",
|
|
63202
|
+
style: "padding-left:5px;",
|
|
63203
|
+
i18n: "refresh"
|
|
63137
63204
|
},
|
|
63138
|
-
|
|
63139
|
-
|
|
63140
|
-
|
|
63141
|
-
|
|
63142
|
-
|
|
63143
|
-
|
|
63144
|
-
|
|
63145
|
-
|
|
63146
|
-
|
|
63147
|
-
|
|
63148
|
-
|
|
63149
|
-
|
|
63150
|
-
|
|
63151
|
-
|
|
63152
|
-
|
|
63153
|
-
|
|
63154
|
-
|
|
63155
|
-
"button",
|
|
63205
|
+
"refresh"
|
|
63206
|
+
]],
|
|
63207
|
+
{ click: (evt) => {
|
|
63208
|
+
evt.stopPropagation();
|
|
63209
|
+
gobj_send_event(gobj, "EV_REFRESH_TREEDB", { evt }, gobj);
|
|
63210
|
+
} }
|
|
63211
|
+
], [
|
|
63212
|
+
"button",
|
|
63213
|
+
{
|
|
63214
|
+
class: "button ml-2 TREEDB_JSON_BTN",
|
|
63215
|
+
title: t("raw json"),
|
|
63216
|
+
"aria-label": t("raw json"),
|
|
63217
|
+
"data-i18n-title": "raw json",
|
|
63218
|
+
"data-i18n-aria-label": "raw json"
|
|
63219
|
+
},
|
|
63220
|
+
[yui_toolbar_icon("yi-eye"), [
|
|
63221
|
+
"span",
|
|
63156
63222
|
{
|
|
63157
|
-
class: "
|
|
63158
|
-
|
|
63159
|
-
|
|
63160
|
-
"data-i18n-title": "raw json",
|
|
63161
|
-
"data-i18n-aria-label": "raw json"
|
|
63223
|
+
class: "is-hidden-mobile",
|
|
63224
|
+
style: "padding-left:5px;",
|
|
63225
|
+
i18n: "raw json"
|
|
63162
63226
|
},
|
|
63163
|
-
|
|
63164
|
-
|
|
63165
|
-
|
|
63166
|
-
|
|
63167
|
-
|
|
63168
|
-
|
|
63169
|
-
|
|
63170
|
-
"raw json"
|
|
63171
|
-
]],
|
|
63172
|
-
{ click: (evt) => {
|
|
63173
|
-
evt.stopPropagation();
|
|
63174
|
-
gobj_send_event(gobj, "EV_OPEN_JSON", {}, gobj);
|
|
63175
|
-
} }
|
|
63176
|
-
]
|
|
63177
|
-
];
|
|
63227
|
+
"raw json"
|
|
63228
|
+
]],
|
|
63229
|
+
{ click: (evt) => {
|
|
63230
|
+
evt.stopPropagation();
|
|
63231
|
+
gobj_send_event(gobj, "EV_OPEN_JSON", {}, gobj);
|
|
63232
|
+
} }
|
|
63233
|
+
]];
|
|
63178
63234
|
let $find_input = createElement2([
|
|
63179
63235
|
"input",
|
|
63180
63236
|
{
|
|
@@ -63209,6 +63265,18 @@ function make_toolbar(gobj) {
|
|
|
63209
63265
|
]]
|
|
63210
63266
|
]);
|
|
63211
63267
|
attach_clear($find_control, $find_input);
|
|
63268
|
+
let right_items = [...[$find_control, [
|
|
63269
|
+
"div",
|
|
63270
|
+
{
|
|
63271
|
+
class: "GRAPH_FIND_RESULT is-hidden",
|
|
63272
|
+
style: "display:flex; align-items:center; gap:.3rem; margin-right:.5rem; font-size:.85rem;"
|
|
63273
|
+
},
|
|
63274
|
+
[[
|
|
63275
|
+
"span",
|
|
63276
|
+
{ class: "GRAPH_FIND_COUNT" },
|
|
63277
|
+
""
|
|
63278
|
+
]]
|
|
63279
|
+
]], ...backend_items];
|
|
63212
63280
|
const $toolbar_header = yui_toolbar({}, [
|
|
63213
63281
|
[
|
|
63214
63282
|
"div",
|
|
@@ -63218,23 +63286,12 @@ function make_toolbar(gobj) {
|
|
|
63218
63286
|
[
|
|
63219
63287
|
"div",
|
|
63220
63288
|
{ class: "yui-horizontal-toolbar-section center" },
|
|
63221
|
-
|
|
63222
|
-
"div",
|
|
63223
|
-
{
|
|
63224
|
-
class: "GRAPH_FIND_RESULT is-hidden",
|
|
63225
|
-
style: "display:flex; align-items:center; gap:.3rem; margin-right:.5rem; font-size:.85rem;"
|
|
63226
|
-
},
|
|
63227
|
-
[[
|
|
63228
|
-
"span",
|
|
63229
|
-
{ class: "GRAPH_FIND_COUNT" },
|
|
63230
|
-
""
|
|
63231
|
-
]]
|
|
63232
|
-
]]
|
|
63289
|
+
center_items
|
|
63233
63290
|
],
|
|
63234
63291
|
[
|
|
63235
63292
|
"div",
|
|
63236
63293
|
{ class: "GRAPH_MODE_BUTTONS yui-horizontal-toolbar-section right" },
|
|
63237
|
-
|
|
63294
|
+
right_items
|
|
63238
63295
|
]
|
|
63239
63296
|
]);
|
|
63240
63297
|
refresh_language($toolbar_header, t);
|
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -3382,6 +3382,58 @@ const CAMERA_SETTLE_MS = 700;
|
|
|
3382
3382
|
*
|
|
3383
3383
|
* A node and a pixel is also the SAME thing the folds keep across a
|
|
3384
3384
|
* rebuild. One idea, used twice. */
|
|
3385
|
+
/* The drawn node nearest the middle of the VIEWPORT, among the ones
|
|
3386
|
+
* inside it; "" when there is none -- which is a blank view. */
|
|
3387
|
+
function node_nearest_view_centre(gobj)
|
|
3388
|
+
{
|
|
3389
|
+
let graph = gobj.priv.graph;
|
|
3390
|
+
let size;
|
|
3391
|
+
try {
|
|
3392
|
+
size = graph.getSize();
|
|
3393
|
+
} catch(e) {
|
|
3394
|
+
return ""; /* between renders: nothing is drawn */
|
|
3395
|
+
}
|
|
3396
|
+
if(!is_array(size) || !(size[0] > 0) || !(size[1] > 0)) {
|
|
3397
|
+
return "";
|
|
3398
|
+
}
|
|
3399
|
+
let [w, h] = size;
|
|
3400
|
+
let best = "";
|
|
3401
|
+
let best_d = Infinity;
|
|
3402
|
+
for(let nd of (graph.getNodeData() || [])) {
|
|
3403
|
+
let vp = yui_graph_viewport_of(graph, nd.id);
|
|
3404
|
+
if(!vp || !is_number(vp[0]) || !is_number(vp[1])) {
|
|
3405
|
+
continue;
|
|
3406
|
+
}
|
|
3407
|
+
if(vp[0] < 0 || vp[1] < 0 || vp[0] > w || vp[1] > h) {
|
|
3408
|
+
continue;
|
|
3409
|
+
}
|
|
3410
|
+
let d = (vp[0] - w / 2) ** 2 + (vp[1] - h / 2) ** 2;
|
|
3411
|
+
if(d < best_d) {
|
|
3412
|
+
best_d = d;
|
|
3413
|
+
best = nd.id;
|
|
3414
|
+
}
|
|
3415
|
+
}
|
|
3416
|
+
return best;
|
|
3417
|
+
}
|
|
3418
|
+
|
|
3419
|
+
/* The node a camera is SAVED by: the anchor when one is set, else the
|
|
3420
|
+
* node nearest the middle of the viewport.
|
|
3421
|
+
*
|
|
3422
|
+
* It used to be fold_keep_node() -- the first root of the tree,
|
|
3423
|
+
* wherever it was. A reader who had panned away saved a node OFF
|
|
3424
|
+
* screen at a pixel off screen, and a reload whose layout had moved
|
|
3425
|
+
* by a hair put that one node back at that pixel and nothing else in
|
|
3426
|
+
* view: a blank graph, with the whole tree sitting in the minimap. */
|
|
3427
|
+
function camera_anchor_node(gobj)
|
|
3428
|
+
{
|
|
3429
|
+
let priv = gobj.priv;
|
|
3430
|
+
|
|
3431
|
+
if(priv.anchor_state === "on" && priv.anchor_id) {
|
|
3432
|
+
return priv.anchor_id;
|
|
3433
|
+
}
|
|
3434
|
+
return node_nearest_view_centre(gobj) || fold_keep_node(gobj);
|
|
3435
|
+
}
|
|
3436
|
+
|
|
3385
3437
|
function read_camera(gobj)
|
|
3386
3438
|
{
|
|
3387
3439
|
let priv = gobj.priv;
|
|
@@ -3392,7 +3444,7 @@ function read_camera(gobj)
|
|
|
3392
3444
|
}
|
|
3393
3445
|
try {
|
|
3394
3446
|
let z = graph.getZoom();
|
|
3395
|
-
let node =
|
|
3447
|
+
let node = camera_anchor_node(gobj);
|
|
3396
3448
|
let vp = node? yui_graph_viewport_of(graph, node) : null;
|
|
3397
3449
|
if(!is_number(z) || !node || !vp || !is_number(vp[0]) || !is_number(vp[1])) {
|
|
3398
3450
|
return null;
|
|
@@ -3422,6 +3474,13 @@ async function restore_camera(gobj)
|
|
|
3422
3474
|
if(!yui_graph_viewport_of(graph, cam.node)) {
|
|
3423
3475
|
return false;
|
|
3424
3476
|
}
|
|
3477
|
+
/* A camera saved by a node OFF screen (before 7.23.137 the node was
|
|
3478
|
+
* the first root, wherever it was) frames nothing it can promise:
|
|
3479
|
+
* the opening fit instead. */
|
|
3480
|
+
let size = graph.getSize() || [0, 0];
|
|
3481
|
+
if(cam.x < 0 || cam.y < 0 || cam.x > size[0] || cam.y > size[1]) {
|
|
3482
|
+
return false;
|
|
3483
|
+
}
|
|
3425
3484
|
priv._camera_restoring = true;
|
|
3426
3485
|
try {
|
|
3427
3486
|
await graph.zoomTo(cam.zoom);
|
|
@@ -9709,6 +9768,15 @@ async function reconcile_fold_apply(gobj, opts, visible)
|
|
|
9709
9768
|
await yui_graph_place_at(graph, opts.keep, opts.keep_vp);
|
|
9710
9769
|
}
|
|
9711
9770
|
}
|
|
9771
|
+
/* And never a BLANK viewport. Every branch above can leave one: a
|
|
9772
|
+
* restore by a node whose surroundings moved, a refresh or a global
|
|
9773
|
+
* fold holding the first root still at a pixel off screen, a saved
|
|
9774
|
+
* arrangement opened with no camera (no fit: its owner's view is
|
|
9775
|
+
* part of it) far from where G6 starts looking. A view with nothing
|
|
9776
|
+
* in it is not a place anybody chose to be. */
|
|
9777
|
+
if((graph.getNodeData() || []).length > 0 && !node_nearest_view_centre(gobj)) {
|
|
9778
|
+
await graph_fit_readable(gobj);
|
|
9779
|
+
}
|
|
9712
9780
|
/* Whichever branch ran -- including none of them, which is a
|
|
9713
9781
|
* graph somebody had arranged and left where it was -- the
|
|
9714
9782
|
* opening viewport is decided from here on, and every move after
|
|
@@ -694,6 +694,11 @@ function make_toolbar(gobj)
|
|
|
694
694
|
);
|
|
695
695
|
|
|
696
696
|
/*
|
|
697
|
+
* Three sections, by what the control is ABOUT:
|
|
698
|
+
* left how the graph is built: layout and operation mode
|
|
699
|
+
* center how it is SHOWN: the fold pair and the node views
|
|
700
|
+
* right what it is asked: find, refresh, the raw json
|
|
701
|
+
*
|
|
697
702
|
* Left: layout and mode selectors
|
|
698
703
|
* Layout options are empty — populated after child creation
|
|
699
704
|
* via populate_nodes_tree_options()
|
|
@@ -730,6 +735,28 @@ function make_toolbar(gobj)
|
|
|
730
735
|
}
|
|
731
736
|
}],
|
|
732
737
|
|
|
738
|
+
];
|
|
739
|
+
|
|
740
|
+
/*
|
|
741
|
+
* Center: how the graph is SHOWN.
|
|
742
|
+
*/
|
|
743
|
+
let center_items = [
|
|
744
|
+
/* The fold pair, the same two chevrons the JSON graph and the
|
|
745
|
+
* lazy tree use: the graph opens folded (see the G6 child), and
|
|
746
|
+
* these are the whole thing and the roots alone. Refresh is the
|
|
747
|
+
* way back to the default depth. */
|
|
748
|
+
...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
749
|
+
|
|
750
|
+
/* The view of the nodes -- full cards, one-line pills or
|
|
751
|
+
* figures -- and the name under a figure. */
|
|
752
|
+
...node_shape_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
753
|
+
];
|
|
754
|
+
|
|
755
|
+
/*
|
|
756
|
+
* Right, after the find box: ask the backend again, and read its
|
|
757
|
+
* raw json.
|
|
758
|
+
*/
|
|
759
|
+
let backend_items = [
|
|
733
760
|
/* Icon + label, and the label is `is-hidden-mobile`: on a phone
|
|
734
761
|
* this is a bare icon, so the name has to be on the button. */
|
|
735
762
|
['button', {class: 'GRAPH_REFRESH button',
|
|
@@ -744,16 +771,6 @@ function make_toolbar(gobj)
|
|
|
744
771
|
}
|
|
745
772
|
}],
|
|
746
773
|
|
|
747
|
-
/* The fold pair, the same two chevrons the JSON graph and the
|
|
748
|
-
* lazy tree use: the graph opens folded (see the G6 child), and
|
|
749
|
-
* these are the whole thing and the roots alone. Refresh is the
|
|
750
|
-
* way back to the default depth. */
|
|
751
|
-
...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
752
|
-
|
|
753
|
-
/* The view of the nodes -- full cards, one-line pills or
|
|
754
|
-
* figures -- and the name under a figure. */
|
|
755
|
-
...node_shape_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
756
|
-
|
|
757
774
|
/* Inspect the treedb's raw tranger json in the lazy tree viewer
|
|
758
775
|
* (print-tranger on the C_NODE service). A treedb can be huge, so
|
|
759
776
|
* the viewer drills in on demand — see open_json_viewer. */
|
|
@@ -771,7 +788,7 @@ function make_toolbar(gobj)
|
|
|
771
788
|
];
|
|
772
789
|
|
|
773
790
|
/*
|
|
774
|
-
*
|
|
791
|
+
* Right: find a node.
|
|
775
792
|
*
|
|
776
793
|
* A graph of a few hundred records has no other way in: the only way
|
|
777
794
|
* to locate one was to read every card. The box highlights every
|
|
@@ -821,7 +838,7 @@ function make_toolbar(gobj)
|
|
|
821
838
|
]]);
|
|
822
839
|
attach_clear($find_control, $find_input);
|
|
823
840
|
|
|
824
|
-
let
|
|
841
|
+
let find_items = [
|
|
825
842
|
$find_control,
|
|
826
843
|
/* ONE counted span, not a number beside a word: "1 matches" is
|
|
827
844
|
* what two spans always produce, because nothing there can see
|
|
@@ -844,10 +861,9 @@ function make_toolbar(gobj)
|
|
|
844
861
|
]]
|
|
845
862
|
];
|
|
846
863
|
|
|
847
|
-
/*
|
|
848
|
-
* Right, fill in set_mode
|
|
849
|
-
*/
|
|
850
864
|
let right_items = [
|
|
865
|
+
...find_items,
|
|
866
|
+
...backend_items,
|
|
851
867
|
];
|
|
852
868
|
|
|
853
869
|
const $toolbar_header = yui_toolbar({}, [
|
|
@@ -254,6 +254,29 @@ function build_ui(gobj)
|
|
|
254
254
|
{
|
|
255
255
|
let source_url = gobj_read_str_attr(gobj, "source_url") || "";
|
|
256
256
|
|
|
257
|
+
/* The whole treedb as a graph, with NO topic focused. A card's graph
|
|
258
|
+
* icon lands on `<graph route>/<topic>`, and that segment is a
|
|
259
|
+
* FOCUS: going through a card was the only way in, and it always
|
|
260
|
+
* arrived with that topic highlighted. The route is the card's
|
|
261
|
+
* template without its `/{topic}`; a host whose template does not
|
|
262
|
+
* end in it, or gives none, gets no button. */
|
|
263
|
+
let routes = gobj_read_attr(gobj, "card_action_routes");
|
|
264
|
+
let graph_tpl = is_object(routes) && typeof routes.graph === "string"? routes.graph : "";
|
|
265
|
+
let graph_href = /\/\{topic\}$/.test(graph_tpl)? graph_tpl.replace(/\/\{topic\}$/, "") : "";
|
|
266
|
+
let graph_items = [];
|
|
267
|
+
if(graph_href) {
|
|
268
|
+
graph_items.push(
|
|
269
|
+
['a', {class: 'button TREEDB_GRAPH_BTN',
|
|
270
|
+
href: graph_href,
|
|
271
|
+
style: 'margin-left:auto;',
|
|
272
|
+
title: t('graph'), 'aria-label': t('graph'),
|
|
273
|
+
'data-i18n-title': 'graph', 'data-i18n-aria-label': 'graph'}, [
|
|
274
|
+
['span', {class: 'icon'}, [yui_toolbar_icon('yi-hexagon-nodes')]],
|
|
275
|
+
['span', {i18n: 'graph'}, 'graph']
|
|
276
|
+
]]
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
|
|
257
280
|
/*----------------------------------------------*
|
|
258
281
|
* Layout Schema
|
|
259
282
|
*----------------------------------------------*/
|
|
@@ -262,12 +285,15 @@ function build_ui(gobj)
|
|
|
262
285
|
['div', {class: 'is-flex-grow-0'}, [
|
|
263
286
|
['div', {class: 'is-flex is-align-items-center TREEDB_TOPICS_TOOLBAR',
|
|
264
287
|
style: 'gap:.25rem; padding:.25rem .25rem;'}, [
|
|
265
|
-
/* This toolbar never holds more than
|
|
266
|
-
* (back|toggle on the left, json on the right),
|
|
267
|
-
* labels stay on mobile — a deliberate exception
|
|
268
|
-
* icon-only-on-mobile rule:
|
|
269
|
-
* read as the same control
|
|
270
|
-
*
|
|
288
|
+
/* This toolbar never holds more than THREE buttons at once
|
|
289
|
+
* (back|toggle on the left, graph and json on the right),
|
|
290
|
+
* so the labels stay on mobile — a deliberate exception
|
|
291
|
+
* to the icon-only-on-mobile rule: bare squares side by
|
|
292
|
+
* side read as the same control, and the toggle and the
|
|
293
|
+
* graph wear the same icon. They fit at 360px because the
|
|
294
|
+
* source url between them gives way down to its icon. The
|
|
295
|
+
* graph's toolbar has many more, so it keeps
|
|
296
|
+
* is-hidden-mobile. */
|
|
271
297
|
|
|
272
298
|
/* Back to the topic-cards grid (cards-landing mode only);
|
|
273
299
|
* hidden until a topic is open. */
|
|
@@ -309,11 +335,14 @@ function build_ui(gobj)
|
|
|
309
335
|
['span', {class: 'icon'}, [yui_toolbar_icon('yi-cloudversify')]],
|
|
310
336
|
['span', {class: 'TREEDB_TOPICS_SOURCE_URL'}, source_url]
|
|
311
337
|
]],
|
|
338
|
+
...graph_items,
|
|
312
339
|
/* Inspect the treedb's raw tranger json (whole service,
|
|
313
|
-
* print-tranger, lazy drill). Last
|
|
314
|
-
*
|
|
340
|
+
* print-tranger, lazy drill). Last and flush right, away
|
|
341
|
+
* from the back arrow it sat next to: the `margin-left:
|
|
342
|
+
* auto` goes on the first button of the right group,
|
|
343
|
+
* which is the graph one when there is one. */
|
|
315
344
|
['button', {class: 'button TREEDB_JSON_BTN',
|
|
316
|
-
style: 'margin-left:auto;',
|
|
345
|
+
style: graph_href? '' : 'margin-left:auto;',
|
|
317
346
|
title: t('raw json'), 'aria-label': t('raw json'),
|
|
318
347
|
'data-i18n-title': 'raw json', 'data-i18n-aria-label': 'raw json'}, [
|
|
319
348
|
['span', {class: 'icon'}, [yui_toolbar_icon('yi-eye')]],
|