@yuneta/gobj-ui 7.23.28 → 7.23.30
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 +163 -2
- package/dist/gobj-ui.cjs.js +1278 -202
- package/dist/gobj-ui.es.js +1279 -203
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +40 -10
- package/src/c_yui_gobj_tree_js.js +630 -245
- package/src/c_yui_json_graph.js +245 -4
- package/src/gclass_describe.js +234 -0
- package/src/gclass_describe.test.js +125 -0
- package/src/gobj_tree_model.js +436 -0
- package/src/gobj_tree_model.test.js +184 -0
- package/src/lib_graph.css +38 -2
- package/src/yui_gclass_view.js +277 -0
- package/src/yui_graph_camera.js +60 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -3518,7 +3518,7 @@ function composed_title(gobj) {
|
|
|
3518
3518
|
* Below the mobile breakpoint the window is a full-screen
|
|
3519
3519
|
* sheet (no float / drag / resize).
|
|
3520
3520
|
************************************************************/
|
|
3521
|
-
function is_mobile$
|
|
3521
|
+
function is_mobile$4() {
|
|
3522
3522
|
return (window.innerWidth || document.documentElement.offsetWidth) <= MOBILE_MAX;
|
|
3523
3523
|
}
|
|
3524
3524
|
/************************************************************
|
|
@@ -3551,7 +3551,7 @@ function do_minimize(gobj) {
|
|
|
3551
3551
|
************************************************************/
|
|
3552
3552
|
function build_ui$15(gobj) {
|
|
3553
3553
|
ensure_window_style();
|
|
3554
|
-
let mobile = is_mobile$
|
|
3554
|
+
let mobile = is_mobile$4();
|
|
3555
3555
|
let header = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "header");
|
|
3556
3556
|
if ((0, _yuneta_gobj_js.is_gobj)(header)) header = (0, _yuneta_gobj_js.gobj_read_attr)(header, "$container");
|
|
3557
3557
|
if (!header) header = build_default_header(gobj);
|
|
@@ -3889,7 +3889,7 @@ function min$1(gobj) {
|
|
|
3889
3889
|
* handlers moving
|
|
3890
3890
|
************************************************************/
|
|
3891
3891
|
function mvStart(gobj, evt) {
|
|
3892
|
-
if (is_mobile$
|
|
3892
|
+
if (is_mobile$4()) return;
|
|
3893
3893
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
3894
3894
|
let window_rect = $container.getBoundingClientRect();
|
|
3895
3895
|
let x = evt.screenX;
|
|
@@ -4048,7 +4048,7 @@ function do_center(gobj, x, y, width, height) {
|
|
|
4048
4048
|
function handleResize(gobj) {
|
|
4049
4049
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
4050
4050
|
if (!$container) return;
|
|
4051
|
-
if (is_mobile$
|
|
4051
|
+
if (is_mobile$4()) {
|
|
4052
4052
|
$container.classList.add("is-mobile-sheet");
|
|
4053
4053
|
let vw = window.innerWidth || document.documentElement.offsetWidth;
|
|
4054
4054
|
let vh = window.innerHeight || document.documentElement.offsetHeight;
|
|
@@ -9711,6 +9711,42 @@ function yui_graph_update_anchor($container, state) {
|
|
|
9711
9711
|
* nothing to centre right now".
|
|
9712
9712
|
************************************************************/
|
|
9713
9713
|
var __centring__ = /* @__PURE__ */ new WeakMap();
|
|
9714
|
+
/************************************************************
|
|
9715
|
+
* Put `node_id` at a GIVEN point of the viewport.
|
|
9716
|
+
*
|
|
9717
|
+
* What "the graph does not jump when I fold something" is
|
|
9718
|
+
* made of: read where the card is, rebuild the layout, put
|
|
9719
|
+
* that card back where it was. Everything that did not move
|
|
9720
|
+
* in the layout stays put with it.
|
|
9721
|
+
************************************************************/
|
|
9722
|
+
async function yui_graph_place_at(graph, node_id, viewport_xy) {
|
|
9723
|
+
if (!graph || !node_id || !viewport_xy) return false;
|
|
9724
|
+
try {
|
|
9725
|
+
if (typeof graph.getElementPosition !== "function" || typeof graph.getCanvasCenter !== "function" || typeof graph.translateTo !== "function") return false;
|
|
9726
|
+
let z = graph.getZoom() || 1;
|
|
9727
|
+
let c = graph.getCanvasCenter();
|
|
9728
|
+
let n = graph.getElementPosition(node_id);
|
|
9729
|
+
await graph.translateTo([(c[0] - n[0]) * z + (viewport_xy[0] - c[0]), (c[1] - n[1]) * z + (viewport_xy[1] - c[1])]);
|
|
9730
|
+
return true;
|
|
9731
|
+
} catch (e) {
|
|
9732
|
+
return false;
|
|
9733
|
+
}
|
|
9734
|
+
}
|
|
9735
|
+
/************************************************************
|
|
9736
|
+
* Where `node_id` is right now, in viewport pixels.
|
|
9737
|
+
*
|
|
9738
|
+
* The pair of the call above: read it before a rebuild, hand
|
|
9739
|
+
* it back after, and the node has not moved on screen even
|
|
9740
|
+
* though the layout under it changed.
|
|
9741
|
+
************************************************************/
|
|
9742
|
+
function yui_graph_viewport_of(graph, node_id) {
|
|
9743
|
+
if (!graph || !node_id) return null;
|
|
9744
|
+
try {
|
|
9745
|
+
return graph.getViewportByCanvas(graph.getElementPosition(node_id));
|
|
9746
|
+
} catch (e) {
|
|
9747
|
+
return null;
|
|
9748
|
+
}
|
|
9749
|
+
}
|
|
9714
9750
|
async function yui_graph_center_on(graph, node_id) {
|
|
9715
9751
|
if (!graph || !node_id) return false;
|
|
9716
9752
|
let st = __centring__.get(graph);
|
|
@@ -10581,6 +10617,7 @@ var PRIVATE_DATA$11 = {
|
|
|
10581
10617
|
_resize_raf: 0,
|
|
10582
10618
|
search: "",
|
|
10583
10619
|
collapsed: null,
|
|
10620
|
+
reserved: null,
|
|
10584
10621
|
match_count: 0,
|
|
10585
10622
|
find_timer: null,
|
|
10586
10623
|
fold_listener: null,
|
|
@@ -10592,7 +10629,8 @@ var PRIVATE_DATA$11 = {
|
|
|
10592
10629
|
anchor_path: "",
|
|
10593
10630
|
anchor_state: "off",
|
|
10594
10631
|
last_zoom: 1,
|
|
10595
|
-
center_posted: false
|
|
10632
|
+
center_posted: false,
|
|
10633
|
+
pending_keep: null
|
|
10596
10634
|
};
|
|
10597
10635
|
var __gclass__$11 = null;
|
|
10598
10636
|
var __layout_registered__$1 = false;
|
|
@@ -10702,6 +10740,7 @@ function type_color(type, dark) {
|
|
|
10702
10740
|
function mt_create$11(gobj) {
|
|
10703
10741
|
let priv = gobj.priv;
|
|
10704
10742
|
priv.collapsed = /* @__PURE__ */ new Set();
|
|
10743
|
+
priv.reserved = /* @__PURE__ */ new Map();
|
|
10705
10744
|
priv.search = "";
|
|
10706
10745
|
priv.canvas_id = "json-canvas-" + (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj));
|
|
10707
10746
|
(0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "canvas_id", priv.canvas_id);
|
|
@@ -10801,7 +10840,11 @@ function build_ui$10(gobj) {
|
|
|
10801
10840
|
evt.stopPropagation();
|
|
10802
10841
|
evt.preventDefault();
|
|
10803
10842
|
if (evt.type !== "click") return;
|
|
10804
|
-
|
|
10843
|
+
let $card = $handle.closest ? $handle.closest(".JSON_CARD") : null;
|
|
10844
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_FOLD", {
|
|
10845
|
+
path: $handle.getAttribute("data-fold-path"),
|
|
10846
|
+
keep: $card ? $card.getAttribute("data-json-path") : ""
|
|
10847
|
+
}, gobj);
|
|
10805
10848
|
};
|
|
10806
10849
|
for (let type of FOLD_SWALLOWED_EVENTS) $mount.addEventListener(type, priv.fold_listener, true);
|
|
10807
10850
|
} else (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no canvas mount, fold handles are dead`);
|
|
@@ -11082,6 +11125,8 @@ var BEHAVIORS_READING$1 = [
|
|
|
11082
11125
|
var BEHAVIORS_PICKING$1 = ["drag-canvas", ZOOM_CANVAS$1];
|
|
11083
11126
|
var CARD_HEADER_H$1 = 24;
|
|
11084
11127
|
var CARD_ROW_H$1 = 22;
|
|
11128
|
+
var H_GAP = 60;
|
|
11129
|
+
var V_GAP = 50;
|
|
11085
11130
|
function fold_toggle_html(path, foldable, folded, branches, colors) {
|
|
11086
11131
|
if (!foldable) return FOLD_SPACER;
|
|
11087
11132
|
let label = folded ? "+" + branches : "−";
|
|
@@ -11203,7 +11248,10 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id, parent_port)
|
|
|
11203
11248
|
lines.push(build_cell_html(key, value, type, dark, matched, fold));
|
|
11204
11249
|
}
|
|
11205
11250
|
if (parent_id && is_pure_collection(kw)) {
|
|
11206
|
-
if (priv.collapsed.has(path))
|
|
11251
|
+
if (priv.collapsed.has(path)) {
|
|
11252
|
+
push_fold_phantom(gobj, path, parent_id, parent_port, nodes, edges);
|
|
11253
|
+
return parent_id;
|
|
11254
|
+
}
|
|
11207
11255
|
for (let pending of pending_complex) build_json_nodes(gobj, add_segment(path, pending.key), pending.value, nodes, edges, parent_id, parent_port);
|
|
11208
11256
|
return parent_id;
|
|
11209
11257
|
}
|
|
@@ -11289,7 +11337,10 @@ function build_json_nodes(gobj, path, kw, nodes, edges, parent_id, parent_port)
|
|
|
11289
11337
|
if (parent_port) edge.style.sourcePort = parent_port;
|
|
11290
11338
|
edges.push(edge);
|
|
11291
11339
|
}
|
|
11292
|
-
if (folded)
|
|
11340
|
+
if (folded) {
|
|
11341
|
+
push_fold_phantom(gobj, path, group_id, "", nodes, edges);
|
|
11342
|
+
return group_id;
|
|
11343
|
+
}
|
|
11293
11344
|
for (let pending of pending_complex) build_json_nodes(gobj, add_segment(path, pending.key), pending.value, nodes, edges, group_id, pending.port);
|
|
11294
11345
|
return group_id;
|
|
11295
11346
|
}
|
|
@@ -11320,8 +11371,16 @@ function load_json(gobj) {
|
|
|
11320
11371
|
});
|
|
11321
11372
|
graph.render().then(() => {
|
|
11322
11373
|
reanchor$1(gobj);
|
|
11323
|
-
paint_anchor_mark(gobj);
|
|
11374
|
+
paint_anchor_mark$1(gobj);
|
|
11324
11375
|
if (preserve_view) {
|
|
11376
|
+
let keep = priv.pending_keep;
|
|
11377
|
+
priv.pending_keep = null;
|
|
11378
|
+
if (keep) {
|
|
11379
|
+
for (let n of nodes) if (n.data && n.data.path === keep.path) {
|
|
11380
|
+
yui_graph_place_at(graph, n.id, [keep.x, keep.y]);
|
|
11381
|
+
break;
|
|
11382
|
+
}
|
|
11383
|
+
}
|
|
11325
11384
|
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
11326
11385
|
return;
|
|
11327
11386
|
}
|
|
@@ -11373,6 +11432,108 @@ function update_find_result(gobj) {
|
|
|
11373
11432
|
priv.$find_result.classList.remove("is-hidden");
|
|
11374
11433
|
}
|
|
11375
11434
|
/************************************************************
|
|
11435
|
+
* The invisible child a fold leaves behind.
|
|
11436
|
+
*
|
|
11437
|
+
* It is the whole of "nothing moves when I fold": the layout
|
|
11438
|
+
* is a plain tree that centres a parent over its children, so
|
|
11439
|
+
* the only way to keep the survivors still is to leave the
|
|
11440
|
+
* space where it was, in the order it was, as a CHILD. A width
|
|
11441
|
+
* reserved as a number would still have to be placed, and
|
|
11442
|
+
* appending it moves every sibling by half of it.
|
|
11443
|
+
*
|
|
11444
|
+
* A `rect` and not an `html` node: nothing is drawn, and a
|
|
11445
|
+
* DOM element per fold would be a card nobody can see but the
|
|
11446
|
+
* Inspector would show.
|
|
11447
|
+
************************************************************/
|
|
11448
|
+
function push_fold_phantom(gobj, path, parent_id, parent_port, nodes, edges) {
|
|
11449
|
+
let width = gobj.priv.reserved.get(path) || 0;
|
|
11450
|
+
if (!(width > 0) || !parent_id) return;
|
|
11451
|
+
let id = gen_node_id$1(gobj);
|
|
11452
|
+
nodes.push({
|
|
11453
|
+
id,
|
|
11454
|
+
type: "rect",
|
|
11455
|
+
data: {
|
|
11456
|
+
path,
|
|
11457
|
+
phantom: true
|
|
11458
|
+
},
|
|
11459
|
+
style: {
|
|
11460
|
+
size: [width, 1],
|
|
11461
|
+
fill: "transparent",
|
|
11462
|
+
stroke: "transparent",
|
|
11463
|
+
opacity: 0,
|
|
11464
|
+
pointerEvents: "none"
|
|
11465
|
+
}
|
|
11466
|
+
});
|
|
11467
|
+
edges.push({
|
|
11468
|
+
source: parent_id,
|
|
11469
|
+
target: id,
|
|
11470
|
+
style: {
|
|
11471
|
+
opacity: 0,
|
|
11472
|
+
endArrow: false,
|
|
11473
|
+
sourcePort: parent_port || void 0
|
|
11474
|
+
}
|
|
11475
|
+
});
|
|
11476
|
+
}
|
|
11477
|
+
/************************************************************
|
|
11478
|
+
* The width the children a fold is about to hide are taking
|
|
11479
|
+
* RIGHT NOW, measured with the layout's own numbers.
|
|
11480
|
+
*
|
|
11481
|
+
* `card_path` is the card that will lose them; `under` limits
|
|
11482
|
+
* it to the ones hanging from one key of that card, which is
|
|
11483
|
+
* the case of a container that has no card of its own -- its
|
|
11484
|
+
* children hang from the parent, so its fold is a hole in the
|
|
11485
|
+
* PARENT.
|
|
11486
|
+
************************************************************/
|
|
11487
|
+
function group_width_of(gobj, card_path, under) {
|
|
11488
|
+
let priv = gobj.priv;
|
|
11489
|
+
if (!priv.graph) return 0;
|
|
11490
|
+
try {
|
|
11491
|
+
let by_id = {};
|
|
11492
|
+
let card_id = "";
|
|
11493
|
+
for (let node of priv.graph.getNodeData()) {
|
|
11494
|
+
if (!node || !node.data) continue;
|
|
11495
|
+
by_id[node.id] = node;
|
|
11496
|
+
if (node.data.path === card_path) card_id = node.id;
|
|
11497
|
+
}
|
|
11498
|
+
if (!card_id) return 0;
|
|
11499
|
+
let prefix = under ? under + "`" : "";
|
|
11500
|
+
let sum = 0;
|
|
11501
|
+
let n = 0;
|
|
11502
|
+
for (let edge of priv.graph.getEdgeData()) {
|
|
11503
|
+
if (!edge || edge.source !== card_id) continue;
|
|
11504
|
+
let kid = by_id[edge.target];
|
|
11505
|
+
if (!kid) continue;
|
|
11506
|
+
if (prefix && String(kid.data.path).indexOf(prefix) !== 0) continue;
|
|
11507
|
+
sum += kid.data.subtree_width || 0;
|
|
11508
|
+
n++;
|
|
11509
|
+
}
|
|
11510
|
+
return n ? sum + H_GAP * (n - 1) : 0;
|
|
11511
|
+
} catch (e) {
|
|
11512
|
+
return 0;
|
|
11513
|
+
}
|
|
11514
|
+
}
|
|
11515
|
+
/************************************************************
|
|
11516
|
+
* The screen spot of the card at `path`, to be given back
|
|
11517
|
+
* after the rebuild. Null when it has no card of its own --
|
|
11518
|
+
* a pure collection -- and then nothing anchors and the
|
|
11519
|
+
* camera simply stays where it was.
|
|
11520
|
+
************************************************************/
|
|
11521
|
+
function keep_of(gobj, path) {
|
|
11522
|
+
let priv = gobj.priv;
|
|
11523
|
+
if ((0, _yuneta_gobj_js.empty_string)(path) || !priv.graph) return null;
|
|
11524
|
+
try {
|
|
11525
|
+
for (let node of priv.graph.getNodeData()) if (node && node.data && node.data.path === path) {
|
|
11526
|
+
let vp = yui_graph_viewport_of(priv.graph, node.id);
|
|
11527
|
+
return vp ? {
|
|
11528
|
+
path,
|
|
11529
|
+
x: vp[0],
|
|
11530
|
+
y: vp[1]
|
|
11531
|
+
} : null;
|
|
11532
|
+
}
|
|
11533
|
+
} catch (e) {}
|
|
11534
|
+
return null;
|
|
11535
|
+
}
|
|
11536
|
+
/************************************************************
|
|
11376
11537
|
* Clear and reload.
|
|
11377
11538
|
* {preserve_view: true}
|
|
11378
11539
|
* keep the current zoom and translate (no fitView) —
|
|
@@ -11414,8 +11575,6 @@ var JsonTreeLayout = class extends _antv_g6.BaseLayout {
|
|
|
11414
11575
|
h
|
|
11415
11576
|
};
|
|
11416
11577
|
}
|
|
11417
|
-
const H_GAP = 60;
|
|
11418
|
-
const V_GAP = 50;
|
|
11419
11578
|
let subtree_widths = {};
|
|
11420
11579
|
function calc_subtree_width(node_id) {
|
|
11421
11580
|
let kids = children_map[node_id] || [];
|
|
@@ -11432,6 +11591,7 @@ var JsonTreeLayout = class extends _antv_g6.BaseLayout {
|
|
|
11432
11591
|
return subtree_widths[node_id];
|
|
11433
11592
|
}
|
|
11434
11593
|
for (let root of roots) calc_subtree_width(root.id);
|
|
11594
|
+
for (let node of nodes) if (node.data) node.data.subtree_width = subtree_widths[node.id];
|
|
11435
11595
|
let positions = {};
|
|
11436
11596
|
function position_node(node_id, x, y) {
|
|
11437
11597
|
positions[node_id] = {
|
|
@@ -11479,9 +11639,16 @@ var JsonTreeLayout = class extends _antv_g6.BaseLayout {
|
|
|
11479
11639
|
/************************************************************
|
|
11480
11640
|
*
|
|
11481
11641
|
************************************************************/
|
|
11642
|
+
function priv_reset_folds(gobj) {
|
|
11643
|
+
gobj.priv.collapsed.clear();
|
|
11644
|
+
gobj.priv.reserved.clear();
|
|
11645
|
+
}
|
|
11482
11646
|
function ac_load_data$1(gobj, event, kw, src) {
|
|
11483
11647
|
if (kw.path !== void 0) (0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "path", kw.path);
|
|
11484
|
-
if (kw.data !== void 0)
|
|
11648
|
+
if (kw.data !== void 0) {
|
|
11649
|
+
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "json_data", kw.data);
|
|
11650
|
+
priv_reset_folds(gobj);
|
|
11651
|
+
}
|
|
11485
11652
|
refresh_json(gobj);
|
|
11486
11653
|
return 0;
|
|
11487
11654
|
}
|
|
@@ -11536,8 +11703,16 @@ function ac_toggle_fold(gobj, event, kw, src) {
|
|
|
11536
11703
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: EV_TOGGLE_FOLD with no path`);
|
|
11537
11704
|
return -1;
|
|
11538
11705
|
}
|
|
11539
|
-
|
|
11540
|
-
|
|
11706
|
+
let card = kw && kw.keep || path;
|
|
11707
|
+
if (priv.collapsed.has(path)) {
|
|
11708
|
+
priv.collapsed.delete(path);
|
|
11709
|
+
priv.reserved.delete(path);
|
|
11710
|
+
} else {
|
|
11711
|
+
let w = group_width_of(gobj, card, card === path ? "" : path);
|
|
11712
|
+
priv.collapsed.add(path);
|
|
11713
|
+
if (w > 0) priv.reserved.set(path, w);
|
|
11714
|
+
}
|
|
11715
|
+
priv.pending_keep = keep_of(gobj, kw && kw.keep || path);
|
|
11541
11716
|
refresh_json(gobj, { preserve_view: true });
|
|
11542
11717
|
update_find_result(gobj);
|
|
11543
11718
|
return 0;
|
|
@@ -11564,6 +11739,7 @@ function ac_expand_all$2(gobj, event, kw, src) {
|
|
|
11564
11739
|
let priv = gobj.priv;
|
|
11565
11740
|
if (priv.collapsed.size === 0) return 0;
|
|
11566
11741
|
priv.collapsed.clear();
|
|
11742
|
+
priv.reserved.clear();
|
|
11567
11743
|
refresh_json(gobj);
|
|
11568
11744
|
update_find_result(gobj);
|
|
11569
11745
|
return 0;
|
|
@@ -11580,6 +11756,7 @@ function ac_collapse_all$2(gobj, event, kw, src) {
|
|
|
11580
11756
|
if ((0, _yuneta_gobj_js.empty_string)(path)) path = "`";
|
|
11581
11757
|
collect_foldable_paths(json_data, path, paths, true);
|
|
11582
11758
|
priv.collapsed = new Set(paths);
|
|
11759
|
+
priv.reserved.clear();
|
|
11583
11760
|
refresh_json(gobj);
|
|
11584
11761
|
update_find_result(gobj);
|
|
11585
11762
|
return 0;
|
|
@@ -11669,7 +11846,7 @@ function set_picking_mode$1(gobj, picking) {
|
|
|
11669
11846
|
* each time and the mark would otherwise survive only until the
|
|
11670
11847
|
* next fold.
|
|
11671
11848
|
************************************************************/
|
|
11672
|
-
function paint_anchor_mark(gobj) {
|
|
11849
|
+
function paint_anchor_mark$1(gobj) {
|
|
11673
11850
|
let priv = gobj.priv;
|
|
11674
11851
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
11675
11852
|
if (!$container) return;
|
|
@@ -11684,7 +11861,7 @@ function paint_anchor_mark(gobj) {
|
|
|
11684
11861
|
function ac_center_anchor$2(gobj, event, kw, src) {
|
|
11685
11862
|
let priv = gobj.priv;
|
|
11686
11863
|
priv.center_posted = false;
|
|
11687
|
-
paint_anchor_mark(gobj);
|
|
11864
|
+
paint_anchor_mark$1(gobj);
|
|
11688
11865
|
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
11689
11866
|
return 0;
|
|
11690
11867
|
}
|
|
@@ -11705,7 +11882,7 @@ function ac_toggle_anchor$2(gobj, event, kw, src) {
|
|
|
11705
11882
|
priv.anchor_path = "";
|
|
11706
11883
|
}
|
|
11707
11884
|
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
11708
|
-
paint_anchor_mark(gobj);
|
|
11885
|
+
paint_anchor_mark$1(gobj);
|
|
11709
11886
|
set_picking_mode$1(gobj, priv.anchor_state === "arming");
|
|
11710
11887
|
return 0;
|
|
11711
11888
|
}
|
|
@@ -13028,7 +13205,7 @@ function ac_json_item_clicked(gobj, event, kw, src) {
|
|
|
13028
13205
|
/************************************************************
|
|
13029
13206
|
* EV_LANGUAGE_CHANGED — re-translate chrome + re-render
|
|
13030
13207
|
************************************************************/
|
|
13031
|
-
function ac_language_changed$
|
|
13208
|
+
function ac_language_changed$4(gobj, event, kw, src) {
|
|
13032
13209
|
let priv = gobj.priv;
|
|
13033
13210
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
13034
13211
|
if ($container) {
|
|
@@ -13089,7 +13266,7 @@ function create_gclass$10(gclass_name) {
|
|
|
13089
13266
|
],
|
|
13090
13267
|
[
|
|
13091
13268
|
"EV_LANGUAGE_CHANGED",
|
|
13092
|
-
ac_language_changed$
|
|
13269
|
+
ac_language_changed$4,
|
|
13093
13270
|
null
|
|
13094
13271
|
],
|
|
13095
13272
|
[
|
|
@@ -13165,7 +13342,7 @@ function create_gclass$10(gclass_name) {
|
|
|
13165
13342
|
],
|
|
13166
13343
|
[
|
|
13167
13344
|
"EV_LANGUAGE_CHANGED",
|
|
13168
|
-
ac_language_changed$
|
|
13345
|
+
ac_language_changed$4,
|
|
13169
13346
|
null
|
|
13170
13347
|
],
|
|
13171
13348
|
[
|
|
@@ -13215,6 +13392,567 @@ function register_c_yui_json() {
|
|
|
13215
13392
|
return create_gclass$10(GCLASS_NAME$10);
|
|
13216
13393
|
}
|
|
13217
13394
|
//#endregion
|
|
13395
|
+
//#region src/gobj_tree_model.js
|
|
13396
|
+
/***********************************************************************
|
|
13397
|
+
* gobj_tree_model.js
|
|
13398
|
+
*
|
|
13399
|
+
* The gobj tree of a yuno, as plain data.
|
|
13400
|
+
*
|
|
13401
|
+
* The view (C_YUI_GOBJ_TREE_JS) draws NODE DESCRIPTORS, never
|
|
13402
|
+
* gobjs. There are two producers of a descriptor, because the
|
|
13403
|
+
* view has to show the gobjs of the BACKEND too:
|
|
13404
|
+
*
|
|
13405
|
+
* - describe_js_gobj() the gobj tree of THIS browser yuno
|
|
13406
|
+
* - describe_backend_tree() the answer of the backend command
|
|
13407
|
+
* `view-gobj-tree` of another yuno
|
|
13408
|
+
*
|
|
13409
|
+
* Both answer the SAME shape, and that shape is the backend's:
|
|
13410
|
+
* the field names are the ones `gobj2json()` writes in
|
|
13411
|
+
* `kernel/c/gobj-c/src/gobj.c` (fullname, shortname, gclass,
|
|
13412
|
+
* name, parent, state, running, playing, service, disabled,
|
|
13413
|
+
* volatil, bottom_gobj, gobj_flags, commands, gobj_trace_level).
|
|
13414
|
+
* Anything the browser runtime cannot answer is simply absent,
|
|
13415
|
+
* and every reader here treats absent as "not known", never as
|
|
13416
|
+
* false.
|
|
13417
|
+
*
|
|
13418
|
+
* Copyright (c) 2026, ArtGins.
|
|
13419
|
+
* All Rights Reserved.
|
|
13420
|
+
***********************************************************************/
|
|
13421
|
+
/************************************************************
|
|
13422
|
+
* The role of a node: "yuno" | "service" | "volatil" | "pure" | "child"
|
|
13423
|
+
************************************************************/
|
|
13424
|
+
function node_role(d) {
|
|
13425
|
+
if (!d) return "child";
|
|
13426
|
+
if (d.is_yuno) return "yuno";
|
|
13427
|
+
if (d.service) return "service";
|
|
13428
|
+
if (d.volatil) return "volatil";
|
|
13429
|
+
if (d.pure_child) return "pure";
|
|
13430
|
+
return "child";
|
|
13431
|
+
}
|
|
13432
|
+
/************************************************************
|
|
13433
|
+
* What the node is doing: "stopped" | "running" | "playing"
|
|
13434
|
+
************************************************************/
|
|
13435
|
+
function node_status(d) {
|
|
13436
|
+
if (!d || !d.running) return "stopped";
|
|
13437
|
+
return d.playing ? "playing" : "running";
|
|
13438
|
+
}
|
|
13439
|
+
/************************************************************
|
|
13440
|
+
* The i18n key of the status, which is NOT the status itself:
|
|
13441
|
+
* a gobj that runs and does not play is PAUSED to the reader,
|
|
13442
|
+
* and "running" alone never said which of the two it was.
|
|
13443
|
+
************************************************************/
|
|
13444
|
+
function node_status_key(d) {
|
|
13445
|
+
switch (node_status(d)) {
|
|
13446
|
+
case "playing": return "playing";
|
|
13447
|
+
case "running": return "running (paused)";
|
|
13448
|
+
default: return "stopped";
|
|
13449
|
+
}
|
|
13450
|
+
}
|
|
13451
|
+
/******************************
|
|
13452
|
+
* Producers
|
|
13453
|
+
******************************/
|
|
13454
|
+
/************************************************************
|
|
13455
|
+
* A descriptor of a LIVE gobj of this browser yuno, children
|
|
13456
|
+
* included (the whole subtree, depth-first).
|
|
13457
|
+
*
|
|
13458
|
+
* `is_root` marks the yuno itself: the JS runtime has no
|
|
13459
|
+
* gobj_flag_yuno test of its own.
|
|
13460
|
+
************************************************************/
|
|
13461
|
+
function describe_js_gobj(target_gobj, is_root) {
|
|
13462
|
+
if (!target_gobj) return null;
|
|
13463
|
+
let parent_gobj = (0, _yuneta_gobj_js.gobj_parent)(target_gobj);
|
|
13464
|
+
let bottom = (0, _yuneta_gobj_js.gobj_bottom_gobj)(target_gobj);
|
|
13465
|
+
let d = {
|
|
13466
|
+
gclass: (0, _yuneta_gobj_js.gobj_gclass_name)(target_gobj) || "",
|
|
13467
|
+
name: (0, _yuneta_gobj_js.gobj_name)(target_gobj) || "",
|
|
13468
|
+
shortname: (0, _yuneta_gobj_js.gobj_short_name)(target_gobj) || "",
|
|
13469
|
+
fullname: (0, _yuneta_gobj_js.gobj_full_name)(target_gobj) || "",
|
|
13470
|
+
parent: parent_gobj ? (0, _yuneta_gobj_js.gobj_short_name)(parent_gobj) || "" : "",
|
|
13471
|
+
state: (0, _yuneta_gobj_js.gobj_current_state)(target_gobj) || "",
|
|
13472
|
+
running: !!(0, _yuneta_gobj_js.gobj_is_running)(target_gobj),
|
|
13473
|
+
playing: !!(0, _yuneta_gobj_js.gobj_is_playing)(target_gobj),
|
|
13474
|
+
service: !!(0, _yuneta_gobj_js.gobj_is_service)(target_gobj),
|
|
13475
|
+
volatil: !!(0, _yuneta_gobj_js.gobj_is_volatil)(target_gobj),
|
|
13476
|
+
pure_child: !!(0, _yuneta_gobj_js.gobj_is_pure_child)(target_gobj),
|
|
13477
|
+
disabled: !!target_gobj.disabled,
|
|
13478
|
+
bottom_gobj: bottom ? (0, _yuneta_gobj_js.gobj_short_name)(bottom) || "" : "",
|
|
13479
|
+
commands: !!(target_gobj.gclass && target_gobj.gclass.command_table),
|
|
13480
|
+
is_yuno: !!is_root,
|
|
13481
|
+
children: []
|
|
13482
|
+
};
|
|
13483
|
+
let children = target_gobj.dl_children || [];
|
|
13484
|
+
for (let child of children) {
|
|
13485
|
+
let cd = describe_js_gobj(child, false);
|
|
13486
|
+
if (cd) d.children.push(cd);
|
|
13487
|
+
}
|
|
13488
|
+
return d;
|
|
13489
|
+
}
|
|
13490
|
+
/******************************
|
|
13491
|
+
* Readouts
|
|
13492
|
+
******************************/
|
|
13493
|
+
/************************************************************
|
|
13494
|
+
* The i18n key of a role. Two of the five roles are not the
|
|
13495
|
+
* word the reader wants ("pure" and "volatil" alone say
|
|
13496
|
+
* nothing), so the map is explicit.
|
|
13497
|
+
************************************************************/
|
|
13498
|
+
function role_i18n_key(role) {
|
|
13499
|
+
switch (role) {
|
|
13500
|
+
case "yuno": return "yuno";
|
|
13501
|
+
case "service": return "service";
|
|
13502
|
+
case "volatil": return "volatil child";
|
|
13503
|
+
case "pure": return "pure child";
|
|
13504
|
+
default: return "child";
|
|
13505
|
+
}
|
|
13506
|
+
}
|
|
13507
|
+
/************************************************************
|
|
13508
|
+
* The marks a node carries besides its role: what the reader
|
|
13509
|
+
* would otherwise have to open the popover to learn.
|
|
13510
|
+
*
|
|
13511
|
+
* Returns i18n KEYS, in a fixed order, so the card and the
|
|
13512
|
+
* popover cannot disagree about what a node is.
|
|
13513
|
+
************************************************************/
|
|
13514
|
+
function node_badge_keys(d) {
|
|
13515
|
+
let badges = [];
|
|
13516
|
+
if (!d) return badges;
|
|
13517
|
+
let role = node_role(d);
|
|
13518
|
+
if (role !== "child") badges.push(role_i18n_key(role));
|
|
13519
|
+
if (d.disabled) badges.push("disabled");
|
|
13520
|
+
if (d.bottom_gobj) badges.push("bottom");
|
|
13521
|
+
if (d.commands) badges.push("commands");
|
|
13522
|
+
return badges;
|
|
13523
|
+
}
|
|
13524
|
+
/************************************************************
|
|
13525
|
+
* The vocabulary of this view, translated.
|
|
13526
|
+
*
|
|
13527
|
+
* Written as literal t("...") calls and not as t(key): a key
|
|
13528
|
+
* reached through a variable is invisible to the locale
|
|
13529
|
+
* validator, which is how a fixed vocabulary ships in one
|
|
13530
|
+
* language and never changes it.
|
|
13531
|
+
************************************************************/
|
|
13532
|
+
function node_labels(t) {
|
|
13533
|
+
if (typeof t !== "function") t = (k) => k;
|
|
13534
|
+
return {
|
|
13535
|
+
role: {
|
|
13536
|
+
"yuno": t("yuno"),
|
|
13537
|
+
"service": t("service"),
|
|
13538
|
+
"volatil child": t("volatil child"),
|
|
13539
|
+
"pure child": t("pure child"),
|
|
13540
|
+
"child": t("child")
|
|
13541
|
+
},
|
|
13542
|
+
status: {
|
|
13543
|
+
"playing": t("playing"),
|
|
13544
|
+
"running (paused)": t("running (paused)"),
|
|
13545
|
+
"stopped": t("stopped")
|
|
13546
|
+
},
|
|
13547
|
+
status_short: {
|
|
13548
|
+
"playing": t("playing"),
|
|
13549
|
+
"running": t("running"),
|
|
13550
|
+
"stopped": t("stopped")
|
|
13551
|
+
},
|
|
13552
|
+
badge: {
|
|
13553
|
+
"yuno": t("yuno"),
|
|
13554
|
+
"service": t("service"),
|
|
13555
|
+
"volatil child": t("volatil child"),
|
|
13556
|
+
"pure child": t("pure child"),
|
|
13557
|
+
"disabled": t("disabled"),
|
|
13558
|
+
"bottom": t("bottom"),
|
|
13559
|
+
"commands": t("commands")
|
|
13560
|
+
},
|
|
13561
|
+
field: {
|
|
13562
|
+
gclass: t("gclass"),
|
|
13563
|
+
name: t("name"),
|
|
13564
|
+
full_name: t("full name"),
|
|
13565
|
+
role: t("role"),
|
|
13566
|
+
status: t("status"),
|
|
13567
|
+
state: t("state"),
|
|
13568
|
+
disabled: t("disabled"),
|
|
13569
|
+
parent: t("parent"),
|
|
13570
|
+
bottom_gobj: t("bottom gobj"),
|
|
13571
|
+
commands: t("commands"),
|
|
13572
|
+
traces: t("traces"),
|
|
13573
|
+
flags: t("flags"),
|
|
13574
|
+
children: t("children"),
|
|
13575
|
+
yes: t("yes"),
|
|
13576
|
+
collapsed: t("(collapsed)")
|
|
13577
|
+
}
|
|
13578
|
+
};
|
|
13579
|
+
}
|
|
13580
|
+
/************************************************************
|
|
13581
|
+
* The rows of the popover: [label, value], both translated.
|
|
13582
|
+
*
|
|
13583
|
+
* `t` is the app's translator -- the library has none of its
|
|
13584
|
+
* own. Values that are a fixed vocabulary (the role, the
|
|
13585
|
+
* status, yes) go through it too; free text does not.
|
|
13586
|
+
************************************************************/
|
|
13587
|
+
function node_info_rows(d, t) {
|
|
13588
|
+
let rows = [];
|
|
13589
|
+
if (!d) return rows;
|
|
13590
|
+
let L = node_labels(t);
|
|
13591
|
+
let f = L.field;
|
|
13592
|
+
rows.push([f.gclass, d.gclass || "—"]);
|
|
13593
|
+
rows.push([f.name, d.name || "—"]);
|
|
13594
|
+
if (d.fullname && d.fullname !== d.shortname) rows.push([f.full_name, d.fullname]);
|
|
13595
|
+
rows.push([f.role, L.role[role_i18n_key(node_role(d))]]);
|
|
13596
|
+
rows.push([f.status, L.status[node_status_key(d)]]);
|
|
13597
|
+
rows.push([f.state, d.state || "—"]);
|
|
13598
|
+
if (d.disabled) rows.push([f.disabled, f.yes]);
|
|
13599
|
+
if (d.parent) rows.push([f.parent, d.parent]);
|
|
13600
|
+
if (d.bottom_gobj) rows.push([f.bottom_gobj, d.bottom_gobj]);
|
|
13601
|
+
if (d.commands) rows.push([f.commands, f.yes]);
|
|
13602
|
+
if (Array.isArray(d.gobj_trace_level) && d.gobj_trace_level.length > 0) rows.push([f.traces, d.gobj_trace_level.join(", ")]);
|
|
13603
|
+
if (Array.isArray(d.gobj_flags) && d.gobj_flags.length > 0) rows.push([f.flags, d.gobj_flags.join(", ")]);
|
|
13604
|
+
let kids = Array.isArray(d.children) ? d.children.length : 0;
|
|
13605
|
+
if (kids > 0) rows.push([f.children, d.is_collapsed ? kids + " " + f.collapsed : String(kids)]);
|
|
13606
|
+
return rows;
|
|
13607
|
+
}
|
|
13608
|
+
//#endregion
|
|
13609
|
+
//#region src/gclass_describe.js
|
|
13610
|
+
/***********************************************************************
|
|
13611
|
+
* gclass_describe.js
|
|
13612
|
+
*
|
|
13613
|
+
* A gclass, as plain JSON, in the shape the BACKEND answers.
|
|
13614
|
+
*
|
|
13615
|
+
* There is no gclass viewer in the framework: the C kernel
|
|
13616
|
+
* answers `view-gclass` with `gclass2json()`
|
|
13617
|
+
* (`kernel/c/gobj-c/src/gobj.c`) and nothing draws it. This
|
|
13618
|
+
* module builds the same document for a gclass of the BROWSER
|
|
13619
|
+
* yuno, out of the gobj-js registry, so one viewer can show a
|
|
13620
|
+
* gclass of either side:
|
|
13621
|
+
*
|
|
13622
|
+
* {id, gcflag, attrs, commands, gclass_methods,
|
|
13623
|
+
* internal_methods, FSM: {events, states}}
|
|
13624
|
+
*
|
|
13625
|
+
* Two keys the backend does not carry are added at the end,
|
|
13626
|
+
* because the browser can answer them for free and the reader
|
|
13627
|
+
* asks them first: `instances` and `trace_levels`.
|
|
13628
|
+
*
|
|
13629
|
+
* Copyright (c) 2026, ArtGins.
|
|
13630
|
+
* All Rights Reserved.
|
|
13631
|
+
***********************************************************************/
|
|
13632
|
+
/***************************************************************
|
|
13633
|
+
* Bit tables
|
|
13634
|
+
***************************************************************/
|
|
13635
|
+
var DATA_TYPE_NAMES = {
|
|
13636
|
+
[_yuneta_gobj_js.data_type_t.DTP_STRING]: "DTP_STRING",
|
|
13637
|
+
[_yuneta_gobj_js.data_type_t.DTP_BOOLEAN]: "DTP_BOOLEAN",
|
|
13638
|
+
[_yuneta_gobj_js.data_type_t.DTP_INTEGER]: "DTP_INTEGER",
|
|
13639
|
+
[_yuneta_gobj_js.data_type_t.DTP_REAL]: "DTP_REAL",
|
|
13640
|
+
[_yuneta_gobj_js.data_type_t.DTP_LIST]: "DTP_LIST",
|
|
13641
|
+
[_yuneta_gobj_js.data_type_t.DTP_DICT]: "DTP_DICT",
|
|
13642
|
+
[_yuneta_gobj_js.data_type_t.DTP_JSON]: "DTP_JSON",
|
|
13643
|
+
[_yuneta_gobj_js.data_type_t.DTP_POINTER]: "DTP_POINTER"
|
|
13644
|
+
};
|
|
13645
|
+
/************************************************************
|
|
13646
|
+
* The names of the bits set in `bits`, in table order.
|
|
13647
|
+
************************************************************/
|
|
13648
|
+
function bits2names(table, bits) {
|
|
13649
|
+
let names = [];
|
|
13650
|
+
let value = Number(bits) || 0;
|
|
13651
|
+
for (let name of Object.keys(table)) if ((value & table[name]) !== 0) names.push(name);
|
|
13652
|
+
return names;
|
|
13653
|
+
}
|
|
13654
|
+
/************************************************************
|
|
13655
|
+
* The name of a data type. An unknown type is reported as
|
|
13656
|
+
* the number it is -- silently drawing "DTP_STRING" for a
|
|
13657
|
+
* type nobody registered would be worse than saying "17".
|
|
13658
|
+
************************************************************/
|
|
13659
|
+
function data_type_name(type) {
|
|
13660
|
+
return DATA_TYPE_NAMES[type] || String(type);
|
|
13661
|
+
}
|
|
13662
|
+
/************************************************************
|
|
13663
|
+
* One SDATA descriptor -> one row.
|
|
13664
|
+
*
|
|
13665
|
+
* A DTP_POINTER default is a live object (a DOM node, a
|
|
13666
|
+
* gobj): it is never printed, only named, because a viewer
|
|
13667
|
+
* that serializes it would either throw or dump the page.
|
|
13668
|
+
************************************************************/
|
|
13669
|
+
function sdatadesc2json(it) {
|
|
13670
|
+
let row = {
|
|
13671
|
+
id: it.name,
|
|
13672
|
+
type: data_type_name(it.type),
|
|
13673
|
+
flag: bits2names(_yuneta_gobj_js.sdata_flag_t, it.flag),
|
|
13674
|
+
description: it.description || ""
|
|
13675
|
+
};
|
|
13676
|
+
if (it.type === _yuneta_gobj_js.data_type_t.DTP_POINTER) row.default_value = it.default_value === null || it.default_value === void 0 ? null : "<pointer>";
|
|
13677
|
+
else row.default_value = it.default_value === void 0 ? null : it.default_value;
|
|
13678
|
+
return row;
|
|
13679
|
+
}
|
|
13680
|
+
/************************************************************
|
|
13681
|
+
* The attrs table of a gclass.
|
|
13682
|
+
************************************************************/
|
|
13683
|
+
function attrs2json(attrs_table) {
|
|
13684
|
+
let rows = [];
|
|
13685
|
+
if (!Array.isArray(attrs_table)) return rows;
|
|
13686
|
+
for (let it of attrs_table) {
|
|
13687
|
+
if (!it || !it.name) continue;
|
|
13688
|
+
rows.push(sdatadesc2json(it));
|
|
13689
|
+
}
|
|
13690
|
+
return rows;
|
|
13691
|
+
}
|
|
13692
|
+
/************************************************************
|
|
13693
|
+
* The command table of a gclass, with the parameters of
|
|
13694
|
+
* each command (the `schema` slot of SDATACM).
|
|
13695
|
+
************************************************************/
|
|
13696
|
+
function commands2json(command_table) {
|
|
13697
|
+
let rows = [];
|
|
13698
|
+
if (!Array.isArray(command_table)) return rows;
|
|
13699
|
+
for (let it of command_table) {
|
|
13700
|
+
if (!it || !it.name) continue;
|
|
13701
|
+
let row = {
|
|
13702
|
+
id: it.name,
|
|
13703
|
+
alias: it.alias || [],
|
|
13704
|
+
description: it.description || ""
|
|
13705
|
+
};
|
|
13706
|
+
if (Array.isArray(it.schema)) row.parameters = attrs2json(it.schema);
|
|
13707
|
+
rows.push(row);
|
|
13708
|
+
}
|
|
13709
|
+
return rows;
|
|
13710
|
+
}
|
|
13711
|
+
/************************************************************
|
|
13712
|
+
* The methods the gclass actually implements. A table of
|
|
13713
|
+
* every possible one, mostly empty, tells the reader nothing.
|
|
13714
|
+
************************************************************/
|
|
13715
|
+
function methods2json(mt) {
|
|
13716
|
+
let names = [];
|
|
13717
|
+
if (!mt || typeof mt !== "object") return names;
|
|
13718
|
+
for (let key of Object.keys(mt)) if (typeof mt[key] === "function") names.push(key);
|
|
13719
|
+
return names;
|
|
13720
|
+
}
|
|
13721
|
+
/************************************************************
|
|
13722
|
+
* The FSM: the events the gclass declares, and what each
|
|
13723
|
+
* state does with them.
|
|
13724
|
+
************************************************************/
|
|
13725
|
+
function fsm2json(gclass) {
|
|
13726
|
+
let events = [];
|
|
13727
|
+
for (let ev of gclass.dl_events || []) events.push({
|
|
13728
|
+
event_name: ev.event_name,
|
|
13729
|
+
event_flag: bits2names(_yuneta_gobj_js.event_flag_t, ev.event_flag)
|
|
13730
|
+
});
|
|
13731
|
+
let states = {};
|
|
13732
|
+
for (let st of gclass.dl_states || []) {
|
|
13733
|
+
let actions = [];
|
|
13734
|
+
for (let ac of st.dl_actions || []) actions.push({
|
|
13735
|
+
event_name: ac.event_name,
|
|
13736
|
+
action: ac.action ? ac.action.name || "action" : "",
|
|
13737
|
+
next_state: ac.next_state || ""
|
|
13738
|
+
});
|
|
13739
|
+
states[st.state_name] = actions;
|
|
13740
|
+
}
|
|
13741
|
+
return {
|
|
13742
|
+
events,
|
|
13743
|
+
states
|
|
13744
|
+
};
|
|
13745
|
+
}
|
|
13746
|
+
/************************************************************
|
|
13747
|
+
* The description of a gclass REGISTERED IN THIS BROWSER YUNO,
|
|
13748
|
+
* or null when the registry does not know that name.
|
|
13749
|
+
*
|
|
13750
|
+
* Null is the answer for a gclass of a BACKEND yuno too: the
|
|
13751
|
+
* browser registry carries the GUI gclasses and nothing else,
|
|
13752
|
+
* so the caller asks the backend `view-gclass` for those and
|
|
13753
|
+
* shows whatever it answers -- this same shape.
|
|
13754
|
+
************************************************************/
|
|
13755
|
+
function describe_local_gclass(gclass_name) {
|
|
13756
|
+
if (!gclass_name) return null;
|
|
13757
|
+
let gclass = (0, _yuneta_gobj_js.gclass_find_by_name)(gclass_name, false);
|
|
13758
|
+
if (!gclass) return null;
|
|
13759
|
+
return {
|
|
13760
|
+
id: gclass.gclass_name,
|
|
13761
|
+
gcflag: bits2names(_yuneta_gobj_js.gclass_flag_t, gclass.gclass_flag),
|
|
13762
|
+
attrs: attrs2json(gclass.attrs_table),
|
|
13763
|
+
commands: commands2json(gclass.command_table),
|
|
13764
|
+
gclass_methods: methods2json(gclass.gmt),
|
|
13765
|
+
internal_methods: methods2json(gclass.lmt),
|
|
13766
|
+
FSM: fsm2json(gclass),
|
|
13767
|
+
instances: Number(gclass.instances) || 0,
|
|
13768
|
+
trace_levels: Array.isArray(gclass.s_user_trace_level) ? gclass.s_user_trace_level : []
|
|
13769
|
+
};
|
|
13770
|
+
}
|
|
13771
|
+
//#endregion
|
|
13772
|
+
//#region src/yui_gclass_view.js
|
|
13773
|
+
/***********************************************************************
|
|
13774
|
+
* yui_gclass_view.js
|
|
13775
|
+
*
|
|
13776
|
+
* The gclass viewer: what a GClass IS, in a window.
|
|
13777
|
+
*
|
|
13778
|
+
* The framework had no such viewer. The C kernel answers
|
|
13779
|
+
* `view-gclass` with a full description (attrs, commands,
|
|
13780
|
+
* methods, FSM) and the only reader of it was a terminal.
|
|
13781
|
+
* This one draws that same document with C_YUI_JSON, so the
|
|
13782
|
+
* FSM of a gclass is a graph and its attrs table is a tree,
|
|
13783
|
+
* and it takes the document from either side:
|
|
13784
|
+
*
|
|
13785
|
+
* - a gclass of the browser yuno -> describe_local_gclass()
|
|
13786
|
+
* - a gclass of a backend yuno -> `opts.description`, the
|
|
13787
|
+
* answer of `view-gclass`
|
|
13788
|
+
*
|
|
13789
|
+
* One window at a time per host: the caller keeps the handle
|
|
13790
|
+
* and closes it, the way the treedb graph keeps its raw-JSON
|
|
13791
|
+
* viewer.
|
|
13792
|
+
*
|
|
13793
|
+
* Copyright (c) 2026, ArtGins.
|
|
13794
|
+
* All Rights Reserved.
|
|
13795
|
+
***********************************************************************/
|
|
13796
|
+
/************************************************************
|
|
13797
|
+
* Can this app show a gclass at all?
|
|
13798
|
+
*
|
|
13799
|
+
* The viewer is C_YUI_JSON, and an app registers only the
|
|
13800
|
+
* gclasses it mounts. The caller asks this BEFORE drawing a
|
|
13801
|
+
* button, so an app that does not carry the viewer shows no
|
|
13802
|
+
* control instead of a control that fails.
|
|
13803
|
+
************************************************************/
|
|
13804
|
+
function gclass_view_available() {
|
|
13805
|
+
return !!(0, _yuneta_gobj_js.gclass_find_by_name)("C_YUI_JSON", false);
|
|
13806
|
+
}
|
|
13807
|
+
/************************************************************
|
|
13808
|
+
* Open the viewer on `gclass_name`.
|
|
13809
|
+
*
|
|
13810
|
+
* opts:
|
|
13811
|
+
* description the document to draw. Omitted, it is
|
|
13812
|
+
* built from the browser registry.
|
|
13813
|
+
* title_prefix what the window says before the gclass
|
|
13814
|
+
* name (the yuno it belongs to).
|
|
13815
|
+
* on_close called when the reader dismisses it.
|
|
13816
|
+
*
|
|
13817
|
+
* Returns a handle for close_gclass_view(), or null (and a
|
|
13818
|
+
* logged reason) when there is nothing to show.
|
|
13819
|
+
************************************************************/
|
|
13820
|
+
function open_gclass_view(host, gclass_name, opts) {
|
|
13821
|
+
opts = opts || {};
|
|
13822
|
+
if (!host || !gclass_name) {
|
|
13823
|
+
(0, _yuneta_gobj_js.log_error)(`yui_gclass_view: open without a host or a gclass name`);
|
|
13824
|
+
return null;
|
|
13825
|
+
}
|
|
13826
|
+
let shell = yui_shell_of(host);
|
|
13827
|
+
if (!gclass_view_available()) {
|
|
13828
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: C_YUI_JSON not registered by the app`);
|
|
13829
|
+
yui_shell_show_error(shell, "gclass viewer unavailable", { t: i18next.t });
|
|
13830
|
+
return null;
|
|
13831
|
+
}
|
|
13832
|
+
let description = opts.description || describe_local_gclass(gclass_name);
|
|
13833
|
+
if (!description) {
|
|
13834
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: gclass not registered here: ${gclass_name}`);
|
|
13835
|
+
yui_shell_show_error(shell, "gclass not registered in this yuno", { t: i18next.t });
|
|
13836
|
+
return null;
|
|
13837
|
+
}
|
|
13838
|
+
let jv = (0, _yuneta_gobj_js.gobj_create_service)(`gclass-view-${(0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(host))}`, "C_YUI_JSON", {
|
|
13839
|
+
json_data: description,
|
|
13840
|
+
subscriber: null
|
|
13841
|
+
}, host);
|
|
13842
|
+
if (!jv) {
|
|
13843
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: cannot create the gclass viewer`);
|
|
13844
|
+
return null;
|
|
13845
|
+
}
|
|
13846
|
+
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
13847
|
+
let handle = {
|
|
13848
|
+
json_gobj: jv,
|
|
13849
|
+
win: null,
|
|
13850
|
+
modal: null
|
|
13851
|
+
};
|
|
13852
|
+
let $box = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(jv, "$container");
|
|
13853
|
+
let on_close = () => {
|
|
13854
|
+
if (typeof opts.on_close === "function") opts.on_close();
|
|
13855
|
+
};
|
|
13856
|
+
if (is_mobile$3()) {
|
|
13857
|
+
if (!shell) {
|
|
13858
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: no shell, cannot open the gclass sheet`);
|
|
13859
|
+
close_gclass_view(handle);
|
|
13860
|
+
return null;
|
|
13861
|
+
}
|
|
13862
|
+
handle.modal = yui_shell_show_modal(shell, $box, {
|
|
13863
|
+
dialog: true,
|
|
13864
|
+
logical_class: "GCLASS_VIEW_SHEET",
|
|
13865
|
+
title_prefix: opts.title_prefix || "",
|
|
13866
|
+
title: gclass_name,
|
|
13867
|
+
t: i18next.t,
|
|
13868
|
+
on_close
|
|
13869
|
+
});
|
|
13870
|
+
return handle;
|
|
13871
|
+
}
|
|
13872
|
+
let $win_parent = window_layer_of(host, shell);
|
|
13873
|
+
handle.win = (0, _yuneta_gobj_js.gobj_create_service)(`gclass-win-${(0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(host))}`, "C_YUI_WINDOW", {
|
|
13874
|
+
$parent: $win_parent,
|
|
13875
|
+
subscriber: null,
|
|
13876
|
+
modal: false,
|
|
13877
|
+
showMax: true,
|
|
13878
|
+
showFooter: false,
|
|
13879
|
+
resizable: true,
|
|
13880
|
+
center: true,
|
|
13881
|
+
auto_save_size_and_position: true,
|
|
13882
|
+
width: 720,
|
|
13883
|
+
height: 640,
|
|
13884
|
+
logical_class: "GCLASS_VIEW_WINDOW",
|
|
13885
|
+
title_prefix: opts.title_prefix || "",
|
|
13886
|
+
title: gclass_name,
|
|
13887
|
+
icon: "yi-code",
|
|
13888
|
+
body: $box,
|
|
13889
|
+
manager: (0, _yuneta_gobj_js.gobj_find_service)("__window_manager__", false) || null,
|
|
13890
|
+
on_close
|
|
13891
|
+
}, host);
|
|
13892
|
+
if (!handle.win) {
|
|
13893
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: cannot create the gclass window`);
|
|
13894
|
+
close_gclass_view(handle);
|
|
13895
|
+
return null;
|
|
13896
|
+
}
|
|
13897
|
+
(0, _yuneta_gobj_js.gobj_start)(handle.win);
|
|
13898
|
+
return handle;
|
|
13899
|
+
}
|
|
13900
|
+
/************************************************************
|
|
13901
|
+
* Close whatever open_gclass_view() opened. Safe on null and
|
|
13902
|
+
* on a handle whose window the reader already dismissed.
|
|
13903
|
+
************************************************************/
|
|
13904
|
+
function close_gclass_view(handle) {
|
|
13905
|
+
if (!handle) return;
|
|
13906
|
+
let jv = handle.json_gobj;
|
|
13907
|
+
let win = handle.win;
|
|
13908
|
+
let modal = handle.modal;
|
|
13909
|
+
handle.json_gobj = null;
|
|
13910
|
+
handle.win = null;
|
|
13911
|
+
handle.modal = null;
|
|
13912
|
+
if (win && (0, _yuneta_gobj_js.is_gobj)(win)) try {
|
|
13913
|
+
if ((0, _yuneta_gobj_js.gobj_is_running)(win)) (0, _yuneta_gobj_js.gobj_stop)(win);
|
|
13914
|
+
(0, _yuneta_gobj_js.gobj_destroy)(win);
|
|
13915
|
+
} catch (e) {
|
|
13916
|
+
(0, _yuneta_gobj_js.log_warning)(`yui_gclass_view: window already gone: ${e}`);
|
|
13917
|
+
}
|
|
13918
|
+
if (modal && typeof modal.close === "function") try {
|
|
13919
|
+
modal.close();
|
|
13920
|
+
} catch (e) {
|
|
13921
|
+
(0, _yuneta_gobj_js.log_warning)(`yui_gclass_view: modal already gone: ${e}`);
|
|
13922
|
+
}
|
|
13923
|
+
if (jv && (0, _yuneta_gobj_js.is_gobj)(jv)) try {
|
|
13924
|
+
if ((0, _yuneta_gobj_js.gobj_is_running)(jv)) (0, _yuneta_gobj_js.gobj_stop)(jv);
|
|
13925
|
+
(0, _yuneta_gobj_js.gobj_destroy)(jv);
|
|
13926
|
+
} catch (e) {
|
|
13927
|
+
(0, _yuneta_gobj_js.log_warning)(`yui_gclass_view: viewer already gone: ${e}`);
|
|
13928
|
+
}
|
|
13929
|
+
}
|
|
13930
|
+
/************************************************************
|
|
13931
|
+
* Where to mount the window: the SAME element the caller's
|
|
13932
|
+
* own window hangs from.
|
|
13933
|
+
*
|
|
13934
|
+
* Not a preference -- a requirement. z-index only orders
|
|
13935
|
+
* siblings of one stacking context, so a viewer opened from a
|
|
13936
|
+
* window on `body` and mounted in the shell's popup layer
|
|
13937
|
+
* lands BEHIND its opener whatever number it is given, and
|
|
13938
|
+
* the button reads as one that did nothing.
|
|
13939
|
+
************************************************************/
|
|
13940
|
+
function window_layer_of(host, shell) {
|
|
13941
|
+
let $c = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(host, "$container");
|
|
13942
|
+
if ($c && typeof $c.closest === "function") {
|
|
13943
|
+
let $win = $c.closest(".C_YUI_WINDOW");
|
|
13944
|
+
if ($win && $win.parentNode) return $win.parentNode;
|
|
13945
|
+
}
|
|
13946
|
+
return typeof document !== "undefined" && document.getElementById("top-layer") || shell && yui_shell_popup_layer(shell) || null;
|
|
13947
|
+
}
|
|
13948
|
+
/************************************************************
|
|
13949
|
+
* A window is not a sheet: below this width there is no room
|
|
13950
|
+
* for a title bar the reader can drag.
|
|
13951
|
+
************************************************************/
|
|
13952
|
+
function is_mobile$3() {
|
|
13953
|
+
return typeof window !== "undefined" && window.innerWidth <= 768;
|
|
13954
|
+
}
|
|
13955
|
+
//#endregion
|
|
13218
13956
|
//#region src/c_yui_gobj_tree_js.js
|
|
13219
13957
|
/***********************************************************************
|
|
13220
13958
|
* c_yui_gobj_tree_js.js
|
|
@@ -13250,6 +13988,71 @@ var BEHAVIORS_READING = [
|
|
|
13250
13988
|
"drag-element"
|
|
13251
13989
|
];
|
|
13252
13990
|
var BEHAVIORS_PICKING = ["drag-canvas", ZOOM_CANVAS];
|
|
13991
|
+
var VIEW_STORE_PREFIX = "yui_gobj_tree_view:";
|
|
13992
|
+
function view_store_key(gobj) {
|
|
13993
|
+
return VIEW_STORE_PREFIX + (0, _yuneta_gobj_js.gobj_name)(gobj);
|
|
13994
|
+
}
|
|
13995
|
+
function restore_view_shape(gobj) {
|
|
13996
|
+
let priv = gobj.priv;
|
|
13997
|
+
let state = load_view_state(gobj);
|
|
13998
|
+
if (!state) return;
|
|
13999
|
+
if (state.layout && LAYOUTS[state.layout]) {
|
|
14000
|
+
(0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "layout", state.layout);
|
|
14001
|
+
if (priv.$layout_select) priv.$layout_select.value = state.layout;
|
|
14002
|
+
}
|
|
14003
|
+
if (state.collapsed && typeof state.collapsed === "object") priv.collapse_state = Object.assign({}, state.collapsed);
|
|
14004
|
+
}
|
|
14005
|
+
function restore_view_state(gobj) {
|
|
14006
|
+
let priv = gobj.priv;
|
|
14007
|
+
let graph = priv.graph;
|
|
14008
|
+
let state = load_view_state(gobj);
|
|
14009
|
+
if (!graph || !state) return false;
|
|
14010
|
+
let done = false;
|
|
14011
|
+
priv.restoring = true;
|
|
14012
|
+
try {
|
|
14013
|
+
if (typeof state.zoom === "number" && state.zoom > 0) {
|
|
14014
|
+
graph.zoomTo(state.zoom);
|
|
14015
|
+
priv.last_zoom = state.zoom;
|
|
14016
|
+
done = true;
|
|
14017
|
+
}
|
|
14018
|
+
if (Array.isArray(state.position) && state.position.length >= 2) {
|
|
14019
|
+
graph.translateTo([state.position[0], state.position[1]]);
|
|
14020
|
+
done = true;
|
|
14021
|
+
}
|
|
14022
|
+
if (state.anchor) {
|
|
14023
|
+
priv.anchor_name = state.anchor;
|
|
14024
|
+
priv.anchor_state = "on";
|
|
14025
|
+
reanchor(gobj);
|
|
14026
|
+
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
14027
|
+
paint_anchor_mark(gobj);
|
|
14028
|
+
}
|
|
14029
|
+
} catch (e) {
|
|
14030
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot restore the saved view: ${e}`);
|
|
14031
|
+
} finally {
|
|
14032
|
+
priv.restoring = false;
|
|
14033
|
+
}
|
|
14034
|
+
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
14035
|
+
return done;
|
|
14036
|
+
}
|
|
14037
|
+
function save_view_state(gobj) {
|
|
14038
|
+
let priv = gobj.priv;
|
|
14039
|
+
let graph = priv.graph;
|
|
14040
|
+
if (!graph || priv.restoring) return;
|
|
14041
|
+
let state = {
|
|
14042
|
+
layout: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "layout"),
|
|
14043
|
+
collapsed: priv.collapse_state || {},
|
|
14044
|
+
anchor: priv.anchor_state === "on" ? priv.anchor_name : ""
|
|
14045
|
+
};
|
|
14046
|
+
try {
|
|
14047
|
+
state.zoom = graph.getZoom();
|
|
14048
|
+
state.position = graph.getPosition();
|
|
14049
|
+
} catch (e) {}
|
|
14050
|
+
(0, _yuneta_gobj_js.kw_set_local_storage_value)(view_store_key(gobj), state);
|
|
14051
|
+
}
|
|
14052
|
+
function load_view_state(gobj) {
|
|
14053
|
+
let state = (0, _yuneta_gobj_js.kw_get_local_storage_value)(view_store_key(gobj), null, false);
|
|
14054
|
+
return state && typeof state === "object" ? state : null;
|
|
14055
|
+
}
|
|
13253
14056
|
var PRIVATE_DATA$9 = {
|
|
13254
14057
|
canvas_id: "",
|
|
13255
14058
|
graph: null,
|
|
@@ -13260,6 +14063,9 @@ var PRIVATE_DATA$9 = {
|
|
|
13260
14063
|
$popover: null,
|
|
13261
14064
|
$popover_title: null,
|
|
13262
14065
|
$popover_body: null,
|
|
14066
|
+
$popover_gclass: null,
|
|
14067
|
+
popover_node: null,
|
|
14068
|
+
gclass_view: null,
|
|
13263
14069
|
node_by_id: null,
|
|
13264
14070
|
collapse_state: null,
|
|
13265
14071
|
resize_observer: null,
|
|
@@ -13267,39 +14073,99 @@ var PRIVATE_DATA$9 = {
|
|
|
13267
14073
|
anchor_id: "",
|
|
13268
14074
|
anchor_name: "",
|
|
13269
14075
|
anchor_state: "off",
|
|
14076
|
+
restoring: false,
|
|
14077
|
+
restored: false,
|
|
13270
14078
|
last_zoom: 1
|
|
13271
14079
|
};
|
|
13272
14080
|
var __gclass__$9 = null;
|
|
13273
14081
|
var __layout_registered__ = false;
|
|
13274
14082
|
/***************************************************************
|
|
13275
|
-
* Node
|
|
14083
|
+
* Node colours by role.
|
|
14084
|
+
*
|
|
14085
|
+
* Saturated hues, one family apart from the next, and the same
|
|
14086
|
+
* five everywhere the reader meets a gobj. `stroke` draws the
|
|
14087
|
+
* border and the edge; `accent` is the brighter sibling used
|
|
14088
|
+
* for the bar down the left of the card and the toggle badge,
|
|
14089
|
+
* so a card carries its colour twice at two intensities and is
|
|
14090
|
+
* readable at the zoom where the text is not.
|
|
13276
14091
|
***************************************************************/
|
|
13277
14092
|
var ROLE_COLORS = {
|
|
13278
14093
|
yuno: {
|
|
13279
|
-
|
|
13280
|
-
|
|
14094
|
+
stroke: "#0284c7",
|
|
14095
|
+
accent: "#38bdf8"
|
|
13281
14096
|
},
|
|
13282
14097
|
service: {
|
|
13283
|
-
|
|
13284
|
-
|
|
14098
|
+
stroke: "#059669",
|
|
14099
|
+
accent: "#34d399"
|
|
13285
14100
|
},
|
|
13286
14101
|
pure: {
|
|
13287
|
-
|
|
13288
|
-
|
|
14102
|
+
stroke: "#d97706",
|
|
14103
|
+
accent: "#fbbf24"
|
|
13289
14104
|
},
|
|
13290
14105
|
volatil: {
|
|
13291
|
-
|
|
13292
|
-
|
|
14106
|
+
stroke: "#db2777",
|
|
14107
|
+
accent: "#f472b6"
|
|
13293
14108
|
},
|
|
13294
|
-
|
|
13295
|
-
|
|
13296
|
-
|
|
14109
|
+
child: {
|
|
14110
|
+
stroke: "#7c3aed",
|
|
14111
|
+
accent: "#a78bfa"
|
|
13297
14112
|
}
|
|
13298
14113
|
};
|
|
13299
|
-
|
|
13300
|
-
|
|
13301
|
-
|
|
13302
|
-
|
|
14114
|
+
/***************************************************************
|
|
14115
|
+
* Status colours: what the gobj is DOING.
|
|
14116
|
+
*
|
|
14117
|
+
* A pill and not a word: three states of one gobj are told
|
|
14118
|
+
* apart across a whole tree by colour long before anybody
|
|
14119
|
+
* reads them, and the dot alone never said which was which.
|
|
14120
|
+
* `disabled` is a fourth entry and not a status -- a disabled
|
|
14121
|
+
* gobj is still stopped or running -- but it takes the pill,
|
|
14122
|
+
* because it is the fact that explains the other one.
|
|
14123
|
+
***************************************************************/
|
|
14124
|
+
var STATUS_COLORS = {
|
|
14125
|
+
light: {
|
|
14126
|
+
playing: {
|
|
14127
|
+
fg: "#065f46",
|
|
14128
|
+
bg: "#a7f3d0",
|
|
14129
|
+
dot: "#10b981"
|
|
14130
|
+
},
|
|
14131
|
+
running: {
|
|
14132
|
+
fg: "#92400e",
|
|
14133
|
+
bg: "#fde68a",
|
|
14134
|
+
dot: "#f59e0b"
|
|
14135
|
+
},
|
|
14136
|
+
stopped: {
|
|
14137
|
+
fg: "#991b1b",
|
|
14138
|
+
bg: "#fecaca",
|
|
14139
|
+
dot: "#ef4444"
|
|
14140
|
+
},
|
|
14141
|
+
disabled: {
|
|
14142
|
+
fg: "#334155",
|
|
14143
|
+
bg: "#e2e8f0",
|
|
14144
|
+
dot: "#94a3b8"
|
|
14145
|
+
}
|
|
14146
|
+
},
|
|
14147
|
+
dark: {
|
|
14148
|
+
playing: {
|
|
14149
|
+
fg: "#6ee7b7",
|
|
14150
|
+
bg: "rgba(16,185,129,0.28)",
|
|
14151
|
+
dot: "#34d399"
|
|
14152
|
+
},
|
|
14153
|
+
running: {
|
|
14154
|
+
fg: "#fcd34d",
|
|
14155
|
+
bg: "rgba(245,158,11,0.28)",
|
|
14156
|
+
dot: "#fbbf24"
|
|
14157
|
+
},
|
|
14158
|
+
stopped: {
|
|
14159
|
+
fg: "#fca5a5",
|
|
14160
|
+
bg: "rgba(239,68,68,0.28)",
|
|
14161
|
+
dot: "#f87171"
|
|
14162
|
+
},
|
|
14163
|
+
disabled: {
|
|
14164
|
+
fg: "#cbd5e1",
|
|
14165
|
+
bg: "rgba(148,163,184,0.28)",
|
|
14166
|
+
dot: "#94a3b8"
|
|
14167
|
+
}
|
|
14168
|
+
}
|
|
13303
14169
|
};
|
|
13304
14170
|
/***************************************************************
|
|
13305
14171
|
* Fixed node sizes per role (px).
|
|
@@ -13309,16 +14175,16 @@ var STATE_COLORS = {
|
|
|
13309
14175
|
var NODE_SIZES = {
|
|
13310
14176
|
full: {
|
|
13311
14177
|
yuno: {
|
|
13312
|
-
w:
|
|
13313
|
-
h:
|
|
14178
|
+
w: 260,
|
|
14179
|
+
h: 96
|
|
13314
14180
|
},
|
|
13315
14181
|
service: {
|
|
13316
|
-
w:
|
|
13317
|
-
h:
|
|
14182
|
+
w: 232,
|
|
14183
|
+
h: 92
|
|
13318
14184
|
},
|
|
13319
14185
|
child: {
|
|
13320
|
-
w:
|
|
13321
|
-
h:
|
|
14186
|
+
w: 196,
|
|
14187
|
+
h: 86
|
|
13322
14188
|
}
|
|
13323
14189
|
},
|
|
13324
14190
|
compact: {
|
|
@@ -13341,27 +14207,47 @@ var NODE_SIZES = {
|
|
|
13341
14207
|
***************************************************************/
|
|
13342
14208
|
var GT_FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
|
|
13343
14209
|
/***************************************************************
|
|
13344
|
-
*
|
|
13345
|
-
*
|
|
13346
|
-
*
|
|
14210
|
+
* Theme-aware card palette derived from the role colour.
|
|
14211
|
+
*
|
|
14212
|
+
* Brighter than a tint: at 9% of the role colour every card
|
|
14213
|
+
* was the same near-white rectangle and the tree read as a
|
|
14214
|
+
* wireframe. The fill carries enough of the hue to be named
|
|
14215
|
+
* from across the canvas, and the border and the accent bar
|
|
14216
|
+
* carry the rest.
|
|
13347
14217
|
***************************************************************/
|
|
13348
|
-
function role_card_style(
|
|
14218
|
+
function role_card_style(colors, dark) {
|
|
14219
|
+
let stroke = colors.stroke;
|
|
14220
|
+
let accent = colors.accent;
|
|
13349
14221
|
return {
|
|
13350
|
-
bg: dark ? `color-mix(in srgb, ${stroke}
|
|
13351
|
-
border: dark ?
|
|
13352
|
-
|
|
13353
|
-
|
|
13354
|
-
|
|
13355
|
-
|
|
14222
|
+
bg: dark ? `color-mix(in srgb, ${stroke} 34%, #253044)` : `color-mix(in srgb, ${stroke} 13%, #ffffff)`,
|
|
14223
|
+
border: dark ? accent : stroke,
|
|
14224
|
+
accent: dark ? accent : stroke,
|
|
14225
|
+
title: dark ? "#f1f5f9" : "#0f172a",
|
|
14226
|
+
sub: dark ? "#a8b3c2" : "#475569",
|
|
14227
|
+
tagbg: dark ? `color-mix(in srgb, ${stroke} 48%, #253044)` : `color-mix(in srgb, ${stroke} 20%, #ffffff)`,
|
|
14228
|
+
tagfg: dark ? "#f1f5f9" : stroke,
|
|
14229
|
+
shadow: dark ? "0 2px 6px rgba(0,0,0,0.50)" : "0 2px 5px rgba(15,23,42,0.16)"
|
|
13356
14230
|
};
|
|
13357
14231
|
}
|
|
13358
14232
|
/***************************************************************
|
|
13359
|
-
*
|
|
14233
|
+
* The pill colours of a node, for the theme in force.
|
|
13360
14234
|
***************************************************************/
|
|
13361
|
-
function
|
|
13362
|
-
|
|
13363
|
-
if (
|
|
13364
|
-
return
|
|
14235
|
+
function status_card_style(d, dark) {
|
|
14236
|
+
let table = dark ? STATUS_COLORS.dark : STATUS_COLORS.light;
|
|
14237
|
+
if (d.disabled) return table.disabled;
|
|
14238
|
+
return table[node_status(d)] || table.stopped;
|
|
14239
|
+
}
|
|
14240
|
+
/***************************************************************
|
|
14241
|
+
* Map a node to its visual size class. Services are drawn
|
|
14242
|
+
* bigger than plain children so the service boundary of the
|
|
14243
|
+
* hierarchy is visible before anything is read.
|
|
14244
|
+
***************************************************************/
|
|
14245
|
+
function get_node_category(d) {
|
|
14246
|
+
switch (node_role(d)) {
|
|
14247
|
+
case "yuno": return "yuno";
|
|
14248
|
+
case "service": return "service";
|
|
14249
|
+
default: return "child";
|
|
14250
|
+
}
|
|
13365
14251
|
}
|
|
13366
14252
|
/***************************************************************
|
|
13367
14253
|
* Layouts registry.
|
|
@@ -13473,13 +14359,22 @@ function mt_create$9(gobj) {
|
|
|
13473
14359
|
* Framework Method: Start
|
|
13474
14360
|
***************************************************************/
|
|
13475
14361
|
function mt_start$9(gobj) {
|
|
14362
|
+
restore_view_shape(gobj);
|
|
14363
|
+
let shell = yui_shell_of(gobj);
|
|
14364
|
+
if (shell) (0, _yuneta_gobj_js.gobj_subscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
13476
14365
|
build_graph$2(gobj);
|
|
13477
14366
|
load_tree(gobj);
|
|
13478
14367
|
}
|
|
13479
14368
|
/***************************************************************
|
|
13480
14369
|
* Framework Method: Stop
|
|
13481
14370
|
***************************************************************/
|
|
13482
|
-
function mt_stop$9(gobj) {
|
|
14371
|
+
function mt_stop$9(gobj) {
|
|
14372
|
+
let priv = gobj.priv;
|
|
14373
|
+
let shell = yui_shell_of(gobj);
|
|
14374
|
+
if (shell) (0, _yuneta_gobj_js.gobj_unsubscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
14375
|
+
close_gclass_view(priv.gclass_view);
|
|
14376
|
+
priv.gclass_view = null;
|
|
14377
|
+
}
|
|
13483
14378
|
/***************************************************************
|
|
13484
14379
|
* Framework Method: Destroy
|
|
13485
14380
|
***************************************************************/
|
|
@@ -13505,6 +14400,8 @@ function mt_destroy$9(gobj) {
|
|
|
13505
14400
|
priv.$popover = null;
|
|
13506
14401
|
priv.$popover_title = null;
|
|
13507
14402
|
priv.$popover_body = null;
|
|
14403
|
+
priv.$popover_gclass = null;
|
|
14404
|
+
priv.popover_node = null;
|
|
13508
14405
|
priv.$layout_select = null;
|
|
13509
14406
|
priv.node_by_id = null;
|
|
13510
14407
|
priv.collapse_state = null;
|
|
@@ -13608,10 +14505,38 @@ function build_popover(gobj, $container) {
|
|
|
13608
14505
|
text-overflow: ellipsis;
|
|
13609
14506
|
`;
|
|
13610
14507
|
$header.appendChild($title);
|
|
14508
|
+
if (gclass_view_available()) {
|
|
14509
|
+
let $gclass = document.createElement("button");
|
|
14510
|
+
$gclass.type = "button";
|
|
14511
|
+
$gclass.className = "GOBJ_TREE_POPOVER_GCLASS button is-small";
|
|
14512
|
+
$gclass.style.cssText = `
|
|
14513
|
+
margin-right: 6px;
|
|
14514
|
+
padding: 0 8px;
|
|
14515
|
+
height: 22px;
|
|
14516
|
+
font-size: 11px;
|
|
14517
|
+
white-space: nowrap;
|
|
14518
|
+
`;
|
|
14519
|
+
$gclass.textContent = (0, i18next.t)("gclass");
|
|
14520
|
+
$gclass.setAttribute("i18n", "gclass");
|
|
14521
|
+
$gclass.title = (0, i18next.t)("view gclass");
|
|
14522
|
+
$gclass.setAttribute("data-i18n-title", "view gclass");
|
|
14523
|
+
$gclass.setAttribute("aria-label", (0, i18next.t)("view gclass"));
|
|
14524
|
+
$gclass.setAttribute("data-i18n-aria-label", "view gclass");
|
|
14525
|
+
$gclass.addEventListener("click", (evt) => {
|
|
14526
|
+
evt.stopPropagation();
|
|
14527
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_OPEN_GCLASS", {}, gobj);
|
|
14528
|
+
});
|
|
14529
|
+
$header.appendChild($gclass);
|
|
14530
|
+
priv.$popover_gclass = $gclass;
|
|
14531
|
+
} else (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no C_YUI_JSON registered, the gclass viewer is not offered`);
|
|
13611
14532
|
let $close = document.createElement("button");
|
|
13612
14533
|
$close.type = "button";
|
|
14534
|
+
$close.className = "GOBJ_TREE_POPOVER_CLOSE";
|
|
13613
14535
|
$close.textContent = "×";
|
|
13614
14536
|
$close.title = (0, i18next.t)("close");
|
|
14537
|
+
$close.setAttribute("data-i18n-title", "close");
|
|
14538
|
+
$close.setAttribute("aria-label", (0, i18next.t)("close"));
|
|
14539
|
+
$close.setAttribute("data-i18n-aria-label", "close");
|
|
13615
14540
|
$close.style.cssText = `
|
|
13616
14541
|
background: transparent;
|
|
13617
14542
|
border: none;
|
|
@@ -13745,6 +14670,7 @@ function build_graph$2(gobj) {
|
|
|
13745
14670
|
if (z === priv.last_zoom) return;
|
|
13746
14671
|
priv.last_zoom = z;
|
|
13747
14672
|
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
14673
|
+
save_view_state(gobj);
|
|
13748
14674
|
});
|
|
13749
14675
|
graph.on(_antv_g6.NodeEvent.CLICK, (evt) => {
|
|
13750
14676
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_CLICK", { evt }, gobj);
|
|
@@ -13787,22 +14713,20 @@ function apply_layout(gobj) {
|
|
|
13787
14713
|
});
|
|
13788
14714
|
}
|
|
13789
14715
|
/************************************************************
|
|
13790
|
-
*
|
|
13791
|
-
|
|
13792
|
-
|
|
13793
|
-
|
|
13794
|
-
|
|
13795
|
-
if ((0, _yuneta_gobj_js.gobj_is_service)(target_gobj)) return ROLE_COLORS.service;
|
|
13796
|
-
if ((0, _yuneta_gobj_js.gobj_is_pure_child)(target_gobj)) return ROLE_COLORS.pure;
|
|
13797
|
-
return ROLE_COLORS.default;
|
|
13798
|
-
}
|
|
13799
|
-
/************************************************************
|
|
13800
|
-
* Resolve state color
|
|
14716
|
+
* The role colours of a node.
|
|
14717
|
+
*
|
|
14718
|
+
* Note the ORDER: volatil before service. A volatil gobj that
|
|
14719
|
+
* is also a service is drawn volatil, because that is the fact
|
|
14720
|
+
* that decides how long it lives.
|
|
13801
14721
|
************************************************************/
|
|
13802
|
-
function
|
|
13803
|
-
|
|
13804
|
-
|
|
13805
|
-
|
|
14722
|
+
function get_role_colors(d) {
|
|
14723
|
+
switch (node_role(d)) {
|
|
14724
|
+
case "yuno": return ROLE_COLORS.yuno;
|
|
14725
|
+
case "volatil": return ROLE_COLORS.volatil;
|
|
14726
|
+
case "service": return ROLE_COLORS.service;
|
|
14727
|
+
case "pure": return ROLE_COLORS.pure;
|
|
14728
|
+
default: return ROLE_COLORS.child;
|
|
14729
|
+
}
|
|
13806
14730
|
}
|
|
13807
14731
|
/************************************************************
|
|
13808
14732
|
* Generate a unique node id
|
|
@@ -13834,72 +14758,135 @@ function is_node_collapsed(gobj, full_name, num_children) {
|
|
|
13834
14758
|
************************************************************/
|
|
13835
14759
|
function render_toggle_html(node_id, collapsed, num_children, cs) {
|
|
13836
14760
|
let label = collapsed ? "+" + num_children : "−";
|
|
14761
|
+
let title = collapsed ? (0, i18next.t)("expand children") : (0, i18next.t)("collapse children");
|
|
13837
14762
|
return `<span
|
|
13838
14763
|
data-gobj-toggle="true"
|
|
13839
14764
|
data-node-id="${node_id}"
|
|
13840
|
-
title="${
|
|
14765
|
+
title="${(0, _yuneta_gobj_js.escapeHtml)(title)}"
|
|
13841
14766
|
style="
|
|
13842
14767
|
flex: 0 0 auto;
|
|
13843
14768
|
display: inline-flex;
|
|
13844
14769
|
align-items: center;
|
|
13845
14770
|
justify-content: center;
|
|
13846
|
-
min-width:
|
|
13847
|
-
height:
|
|
13848
|
-
padding: 0
|
|
14771
|
+
min-width: 24px;
|
|
14772
|
+
height: 18px;
|
|
14773
|
+
padding: 0 6px;
|
|
13849
14774
|
margin-left: 4px;
|
|
13850
|
-
background: ${cs.
|
|
13851
|
-
color:
|
|
13852
|
-
border: 1px solid ${cs.
|
|
13853
|
-
border-radius:
|
|
14775
|
+
background: ${cs.accent};
|
|
14776
|
+
color: #ffffff;
|
|
14777
|
+
border: 1px solid ${cs.accent};
|
|
14778
|
+
border-radius: 9px;
|
|
13854
14779
|
font-size: 10px;
|
|
13855
|
-
font-weight:
|
|
14780
|
+
font-weight: 700;
|
|
13856
14781
|
line-height: 1;
|
|
13857
14782
|
cursor: pointer;
|
|
13858
14783
|
user-select: none;
|
|
13859
14784
|
">${label}</span>`;
|
|
13860
14785
|
}
|
|
13861
14786
|
/************************************************************
|
|
13862
|
-
*
|
|
14787
|
+
* HTML for the status pill: what the gobj is DOING.
|
|
14788
|
+
*
|
|
14789
|
+
* A dot plus a word, and the word is dropped in the compact
|
|
14790
|
+
* card where there is no room for it -- the colour still
|
|
14791
|
+
* carries it, and the `title` says it in full either way.
|
|
14792
|
+
************************************************************/
|
|
14793
|
+
function render_status_html(d, ss, labels, with_label) {
|
|
14794
|
+
let full = d.disabled ? labels.field.disabled : labels.status[node_status_key(d)] || node_status_key(d);
|
|
14795
|
+
let label = d.disabled ? labels.field.disabled : labels.status_short[node_status(d)] || node_status(d);
|
|
14796
|
+
if (!with_label) return `<span title="${(0, _yuneta_gobj_js.escapeHtml)(full)}" style="
|
|
14797
|
+
flex: 0 0 auto;
|
|
14798
|
+
width: 10px; height: 10px; border-radius: 50%;
|
|
14799
|
+
background: ${ss.dot};
|
|
14800
|
+
box-shadow: 0 0 0 2px ${ss.bg};
|
|
14801
|
+
margin-left: 6px;
|
|
14802
|
+
"></span>`;
|
|
14803
|
+
return `<span title="${(0, _yuneta_gobj_js.escapeHtml)(full)}" style="
|
|
14804
|
+
flex: 0 0 auto;
|
|
14805
|
+
display: inline-flex;
|
|
14806
|
+
align-items: center;
|
|
14807
|
+
gap: 4px;
|
|
14808
|
+
padding: 1px 7px 1px 5px;
|
|
14809
|
+
background: ${ss.bg};
|
|
14810
|
+
color: ${ss.fg};
|
|
14811
|
+
border-radius: 9px;
|
|
14812
|
+
font-size: 10px;
|
|
14813
|
+
font-weight: 700;
|
|
14814
|
+
line-height: 1.45;
|
|
14815
|
+
white-space: nowrap;
|
|
14816
|
+
"><span style="width:7px; height:7px; border-radius:50%; background:${ss.dot};"></span>${(0, _yuneta_gobj_js.escapeHtml)(label)}</span>`;
|
|
14817
|
+
}
|
|
14818
|
+
/************************************************************
|
|
14819
|
+
* HTML for the badges: what the gobj IS, besides its colour.
|
|
14820
|
+
************************************************************/
|
|
14821
|
+
function render_badges_html(d, cs, labels) {
|
|
14822
|
+
let html = "";
|
|
14823
|
+
for (let key of node_badge_keys(d)) {
|
|
14824
|
+
let label = labels.badge[key] || key;
|
|
14825
|
+
html += `<span style="
|
|
14826
|
+
font-size: 10px;
|
|
14827
|
+
font-weight: 600;
|
|
14828
|
+
padding: 0 6px;
|
|
14829
|
+
margin-right: 4px;
|
|
14830
|
+
background: ${cs.tagbg};
|
|
14831
|
+
color: ${cs.tagfg};
|
|
14832
|
+
border: 1px solid ${cs.accent};
|
|
14833
|
+
border-radius: 9px;
|
|
14834
|
+
white-space: nowrap;
|
|
14835
|
+
">${(0, _yuneta_gobj_js.escapeHtml)(label)}</span>`;
|
|
14836
|
+
}
|
|
14837
|
+
return html;
|
|
14838
|
+
}
|
|
14839
|
+
/************************************************************
|
|
14840
|
+
* Recursively build nodes and edges from a NODE DESCRIPTOR
|
|
14841
|
+
* tree (gobj_tree_model.js), never from gobjs: the same
|
|
14842
|
+
* builder draws the browser yuno and a backend one.
|
|
14843
|
+
*
|
|
14844
|
+
* The descriptor is also what the popover reads, so the view
|
|
14845
|
+
* fields it needs are written onto it here (`full_name`,
|
|
14846
|
+
* `short_name`, `num_children`, `is_collapsed`,
|
|
14847
|
+
* `direct_children`) instead of copied into a second object
|
|
14848
|
+
* that can then disagree with the first.
|
|
13863
14849
|
************************************************************/
|
|
13864
|
-
function build_gobj_nodes(gobj,
|
|
14850
|
+
function build_gobj_nodes(gobj, d, nodes, edges, parent_id, compact, labels) {
|
|
13865
14851
|
let priv = gobj.priv;
|
|
13866
14852
|
let node_id = gen_node_id(gobj);
|
|
13867
|
-
let gclass_name = (0, _yuneta_gobj_js.gobj_gclass_name)(target_gobj) || "";
|
|
13868
|
-
let instance_name = (0, _yuneta_gobj_js.gobj_name)(target_gobj) || "";
|
|
13869
|
-
let state = (0, _yuneta_gobj_js.gobj_current_state)(target_gobj) || "";
|
|
13870
|
-
let full_name = (0, _yuneta_gobj_js.gobj_full_name)(target_gobj);
|
|
13871
|
-
let colors = get_role_colors(target_gobj, is_root);
|
|
13872
14853
|
let dark = yui_is_dark();
|
|
13873
|
-
let
|
|
13874
|
-
let
|
|
13875
|
-
let
|
|
13876
|
-
let
|
|
13877
|
-
let status_text = !running ? "stopped" : playing ? "playing" : "running";
|
|
13878
|
-
let category = get_node_category(target_gobj, is_root);
|
|
14854
|
+
let colors = get_role_colors(d);
|
|
14855
|
+
let cs = role_card_style(colors, dark);
|
|
14856
|
+
let ss = status_card_style(d, dark);
|
|
14857
|
+
let category = get_node_category(d);
|
|
13879
14858
|
let size = NODE_SIZES[compact ? "compact" : "full"][category];
|
|
13880
14859
|
let width = size.w;
|
|
13881
14860
|
let height = size.h;
|
|
13882
14861
|
let border_width = category === "yuno" || category === "service" ? 2 : 1;
|
|
13883
|
-
let
|
|
14862
|
+
let border_style = d.disabled ? "dashed" : "solid";
|
|
14863
|
+
let children = d.children || [];
|
|
13884
14864
|
let num_children = children.length;
|
|
13885
14865
|
let has_children = num_children > 0;
|
|
13886
|
-
let collapsed = has_children && is_node_collapsed(gobj,
|
|
14866
|
+
let collapsed = has_children && is_node_collapsed(gobj, d.fullname, num_children);
|
|
13887
14867
|
let direct_children = [];
|
|
13888
14868
|
for (let child of children) direct_children.push({
|
|
13889
|
-
full_name:
|
|
13890
|
-
has_grandchildren: (child.
|
|
14869
|
+
full_name: child.fullname,
|
|
14870
|
+
has_grandchildren: (child.children || []).length > 0
|
|
13891
14871
|
});
|
|
14872
|
+
d.full_name = d.fullname;
|
|
14873
|
+
d.short_name = d.shortname;
|
|
14874
|
+
d.num_children = num_children;
|
|
14875
|
+
d.is_collapsed = collapsed;
|
|
14876
|
+
d.direct_children = direct_children;
|
|
14877
|
+
d.node_id = node_id;
|
|
13892
14878
|
let toggle_html = has_children ? render_toggle_html(node_id, collapsed, num_children, cs) : "";
|
|
14879
|
+
let card_title = d.gclass + (d.name ? "^" + d.name : "");
|
|
13893
14880
|
let node_html;
|
|
13894
14881
|
if (compact) {
|
|
13895
|
-
let compact_label = (0, _yuneta_gobj_js.escapeHtml)(
|
|
14882
|
+
let compact_label = (0, _yuneta_gobj_js.escapeHtml)(card_title);
|
|
13896
14883
|
node_html = `
|
|
13897
|
-
<div style="
|
|
14884
|
+
<div class="GOBJ_CARD" data-gobj-name="${(0, _yuneta_gobj_js.escapeHtml)(d.fullname)}" style="
|
|
13898
14885
|
width: ${width}px;
|
|
13899
14886
|
height: ${height}px;
|
|
13900
14887
|
background: ${cs.bg};
|
|
13901
|
-
border: ${border_width}px
|
|
13902
|
-
border-left:
|
|
14888
|
+
border: ${border_width}px ${border_style} ${cs.border};
|
|
14889
|
+
border-left: 6px solid ${cs.accent};
|
|
13903
14890
|
border-radius: 7px;
|
|
13904
14891
|
box-shadow: ${cs.shadow};
|
|
13905
14892
|
font-family: ${GT_FONT};
|
|
@@ -13908,34 +14895,24 @@ function build_gobj_nodes(gobj, target_gobj, nodes, edges, parent_id, is_root, c
|
|
|
13908
14895
|
padding: 0 8px;
|
|
13909
14896
|
box-sizing: border-box;
|
|
13910
14897
|
overflow: hidden;
|
|
14898
|
+
opacity: ${d.disabled ? "0.72" : "1"};
|
|
13911
14899
|
cursor: pointer;
|
|
13912
14900
|
" title="${compact_label}">
|
|
13913
14901
|
<span style="flex:1 1 auto; min-width:0; font-size:11px; font-weight:600; color:${cs.title}; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${compact_label}</span>
|
|
13914
|
-
|
|
13915
|
-
flex: 0 0 auto;
|
|
13916
|
-
width: 8px; height: 8px; border-radius: 50%;
|
|
13917
|
-
background: ${state_color}; margin-left: 6px;
|
|
13918
|
-
"></span>
|
|
14902
|
+
${render_status_html(d, ss, labels, false)}
|
|
13919
14903
|
${toggle_html}
|
|
13920
14904
|
</div>`;
|
|
13921
14905
|
} else {
|
|
13922
|
-
let header_label = (0, _yuneta_gobj_js.escapeHtml)(
|
|
13923
|
-
let name_label = (0, _yuneta_gobj_js.escapeHtml)(
|
|
13924
|
-
let state_label = (0, _yuneta_gobj_js.escapeHtml)(state);
|
|
13925
|
-
let badges = [];
|
|
13926
|
-
if (is_root) badges.push("yuno");
|
|
13927
|
-
else {
|
|
13928
|
-
if ((0, _yuneta_gobj_js.gobj_is_service)(target_gobj)) badges.push("service");
|
|
13929
|
-
if ((0, _yuneta_gobj_js.gobj_is_pure_child)(target_gobj)) badges.push("pure");
|
|
13930
|
-
if ((0, _yuneta_gobj_js.gobj_is_volatil)(target_gobj)) badges.push("volatil");
|
|
13931
|
-
}
|
|
13932
|
-
let badges_html = badges.map((b) => `<span style="font-size:10px; padding:0 5px; margin-right:4px; background:${cs.tagbg}; color:${cs.border}; border:1px solid ${cs.border}; border-radius:6px; white-space:nowrap;">${b}</span>`).join("");
|
|
14906
|
+
let header_label = (0, _yuneta_gobj_js.escapeHtml)(d.gclass);
|
|
14907
|
+
let name_label = (0, _yuneta_gobj_js.escapeHtml)(d.name);
|
|
14908
|
+
let state_label = (0, _yuneta_gobj_js.escapeHtml)(d.state);
|
|
13933
14909
|
node_html = `
|
|
13934
|
-
<div style="
|
|
14910
|
+
<div class="GOBJ_CARD" data-gobj-name="${(0, _yuneta_gobj_js.escapeHtml)(d.fullname)}" style="
|
|
13935
14911
|
width: ${width}px;
|
|
13936
14912
|
height: ${height}px;
|
|
13937
14913
|
background: ${cs.bg};
|
|
13938
|
-
border: ${border_width}px
|
|
14914
|
+
border: ${border_width}px ${border_style} ${cs.border};
|
|
14915
|
+
border-left: 6px solid ${cs.accent};
|
|
13939
14916
|
border-radius: 9px;
|
|
13940
14917
|
box-shadow: ${cs.shadow};
|
|
13941
14918
|
overflow: hidden;
|
|
@@ -13944,48 +14921,29 @@ function build_gobj_nodes(gobj, target_gobj, nodes, edges, parent_id, is_root, c
|
|
|
13944
14921
|
display: flex;
|
|
13945
14922
|
flex-direction: column;
|
|
13946
14923
|
justify-content: center;
|
|
13947
|
-
padding:
|
|
13948
|
-
gap:
|
|
14924
|
+
padding: 6px 9px;
|
|
14925
|
+
gap: 2px;
|
|
14926
|
+
opacity: ${d.disabled ? "0.72" : "1"};
|
|
13949
14927
|
cursor: pointer;
|
|
13950
|
-
" title="${(0, _yuneta_gobj_js.escapeHtml)(
|
|
14928
|
+
" title="${(0, _yuneta_gobj_js.escapeHtml)(card_title)}">
|
|
13951
14929
|
<div style="flex:0 0 auto; display:flex; align-items:center; gap:6px; overflow:hidden;">
|
|
13952
|
-
<span style="flex:1 1 auto; min-width:0; font-size:12px; line-height:1.25; font-weight:
|
|
14930
|
+
<span style="flex:1 1 auto; min-width:0; font-size:12px; line-height:1.25; font-weight:700; color:${cs.title}; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${header_label}</span>
|
|
13953
14931
|
${toggle_html}
|
|
13954
14932
|
</div>
|
|
13955
14933
|
<div style="flex:0 0 auto; font-size:12px; line-height:1.25; color:${cs.sub}; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${name_label || " "}</div>
|
|
13956
14934
|
<div style="flex:0 0 auto; display:flex; justify-content:space-between; align-items:center; gap:6px; overflow:hidden;">
|
|
13957
|
-
<span style="flex:1 1 auto; min-width:0;
|
|
13958
|
-
|
|
13959
|
-
<span style="width:7px; height:7px; border-radius:50%; background:${state_color};"></span>${state_label || status_text}
|
|
13960
|
-
</span>
|
|
14935
|
+
<span style="flex:1 1 auto; min-width:0; font-size:10px; line-height:1.25; color:${cs.sub}; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">${state_label || " "}</span>
|
|
14936
|
+
${render_status_html(d, ss, labels, true)}
|
|
13961
14937
|
</div>
|
|
14938
|
+
<div style="flex:0 0 auto; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;">${render_badges_html(d, cs, labels)}</div>
|
|
13962
14939
|
</div>`;
|
|
13963
14940
|
}
|
|
13964
|
-
let parent_gobj = (0, _yuneta_gobj_js.gobj_parent)(target_gobj);
|
|
13965
|
-
let node_data = {
|
|
13966
|
-
gclass: gclass_name,
|
|
13967
|
-
name: instance_name,
|
|
13968
|
-
short_name: (0, _yuneta_gobj_js.gobj_short_name)(target_gobj),
|
|
13969
|
-
full_name,
|
|
13970
|
-
parent_short_name: parent_gobj ? (0, _yuneta_gobj_js.gobj_short_name)(parent_gobj) : "",
|
|
13971
|
-
state,
|
|
13972
|
-
category,
|
|
13973
|
-
is_yuno: is_root,
|
|
13974
|
-
is_service: (0, _yuneta_gobj_js.gobj_is_service)(target_gobj),
|
|
13975
|
-
is_pure_child: (0, _yuneta_gobj_js.gobj_is_pure_child)(target_gobj),
|
|
13976
|
-
is_volatil: (0, _yuneta_gobj_js.gobj_is_volatil)(target_gobj),
|
|
13977
|
-
is_running: running,
|
|
13978
|
-
is_playing: playing,
|
|
13979
|
-
num_children,
|
|
13980
|
-
is_collapsed: collapsed,
|
|
13981
|
-
direct_children
|
|
13982
|
-
};
|
|
13983
14941
|
if (!priv.node_by_id) priv.node_by_id = {};
|
|
13984
|
-
priv.node_by_id[node_id] =
|
|
14942
|
+
priv.node_by_id[node_id] = d;
|
|
13985
14943
|
let node = {
|
|
13986
14944
|
id: node_id,
|
|
13987
14945
|
type: "html",
|
|
13988
|
-
data:
|
|
14946
|
+
data: d,
|
|
13989
14947
|
style: {
|
|
13990
14948
|
innerHTML: node_html,
|
|
13991
14949
|
size: [width, height],
|
|
@@ -13998,11 +14956,11 @@ function build_gobj_nodes(gobj, target_gobj, nodes, edges, parent_id, is_root, c
|
|
|
13998
14956
|
source: parent_id,
|
|
13999
14957
|
target: node_id,
|
|
14000
14958
|
style: {
|
|
14001
|
-
stroke: colors.
|
|
14002
|
-
lineWidth: 1
|
|
14959
|
+
stroke: colors.accent,
|
|
14960
|
+
lineWidth: 1.4
|
|
14003
14961
|
}
|
|
14004
14962
|
});
|
|
14005
|
-
if (!collapsed) for (let child of children) build_gobj_nodes(gobj, child, nodes, edges, node_id,
|
|
14963
|
+
if (!collapsed) for (let child of children) build_gobj_nodes(gobj, child, nodes, edges, node_id, compact, labels);
|
|
14006
14964
|
return node_id;
|
|
14007
14965
|
}
|
|
14008
14966
|
/************************************************************
|
|
@@ -14019,9 +14977,13 @@ function load_tree(gobj) {
|
|
|
14019
14977
|
let priv = gobj.priv;
|
|
14020
14978
|
let graph = priv.graph;
|
|
14021
14979
|
if (!graph) return;
|
|
14022
|
-
let
|
|
14023
|
-
if (!
|
|
14980
|
+
let root = describe_js_gobj((0, _yuneta_gobj_js.gobj_yuno)(), true);
|
|
14981
|
+
if (!root) {
|
|
14982
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no yuno to draw`);
|
|
14983
|
+
return;
|
|
14984
|
+
}
|
|
14024
14985
|
let layout_cfg = get_layout_cfg((0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "layout"));
|
|
14986
|
+
let labels = node_labels(i18next.t);
|
|
14025
14987
|
let anchor = priv.pending_anchor || null;
|
|
14026
14988
|
let preserve_view = !!priv.pending_preserve_view;
|
|
14027
14989
|
priv.pending_anchor = null;
|
|
@@ -14030,7 +14992,7 @@ function load_tree(gobj) {
|
|
|
14030
14992
|
priv.node_by_id = {};
|
|
14031
14993
|
let nodes = [];
|
|
14032
14994
|
let edges = [];
|
|
14033
|
-
build_gobj_nodes(gobj,
|
|
14995
|
+
build_gobj_nodes(gobj, root, nodes, edges, null, layout_cfg.compact, labels);
|
|
14034
14996
|
if (nodes.length > 0) {
|
|
14035
14997
|
let root_id = nodes[0].id;
|
|
14036
14998
|
graph.setData({
|
|
@@ -14039,11 +15001,16 @@ function load_tree(gobj) {
|
|
|
14039
15001
|
});
|
|
14040
15002
|
graph.render().then(() => {
|
|
14041
15003
|
reanchor(gobj);
|
|
15004
|
+
paint_anchor_mark(gobj);
|
|
14042
15005
|
if (anchor) {
|
|
14043
15006
|
restore_view_anchored(gobj, anchor);
|
|
14044
15007
|
return;
|
|
14045
15008
|
}
|
|
14046
15009
|
if (preserve_view) return;
|
|
15010
|
+
if (!priv.restored) {
|
|
15011
|
+
priv.restored = true;
|
|
15012
|
+
if (restore_view_state(gobj)) return;
|
|
15013
|
+
}
|
|
14047
15014
|
Promise.resolve(graph.zoomTo(1)).then(() => {
|
|
14048
15015
|
if (!yui_graph_center_on(graph, priv.anchor_id)) yui_graph_center_on(graph, root_id);
|
|
14049
15016
|
priv.last_zoom = 1;
|
|
@@ -14126,46 +15093,17 @@ function refresh_tree(gobj, opts) {
|
|
|
14126
15093
|
}
|
|
14127
15094
|
}
|
|
14128
15095
|
/************************************************************
|
|
14129
|
-
* Rows to show in the popover for a given node data.
|
|
14130
|
-
*
|
|
14131
|
-
* This is the extension point: to surface a new attribute,
|
|
14132
|
-
* collect it into `node_data` in build_gobj_nodes(), then
|
|
14133
|
-
* append a `[label, value]` pair here.
|
|
14134
|
-
************************************************************/
|
|
14135
|
-
function get_node_info_rows(node_data) {
|
|
14136
|
-
let rows = [];
|
|
14137
|
-
rows.push([(0, i18next.t)("gclass"), node_data.gclass || "—"]);
|
|
14138
|
-
rows.push([(0, i18next.t)("name"), node_data.name || "—"]);
|
|
14139
|
-
if (node_data.full_name && node_data.full_name !== node_data.short_name) rows.push([(0, i18next.t)("full name"), node_data.full_name]);
|
|
14140
|
-
let role;
|
|
14141
|
-
if (node_data.is_yuno) role = "yuno";
|
|
14142
|
-
else if (node_data.is_service) role = "service";
|
|
14143
|
-
else if (node_data.is_volatil) role = "volatil child";
|
|
14144
|
-
else if (node_data.is_pure_child) role = "pure child";
|
|
14145
|
-
else role = "child";
|
|
14146
|
-
rows.push([(0, i18next.t)("role"), role]);
|
|
14147
|
-
let status;
|
|
14148
|
-
if (!node_data.is_running) status = "stopped";
|
|
14149
|
-
else if (node_data.is_playing) status = "running + playing";
|
|
14150
|
-
else status = "running";
|
|
14151
|
-
rows.push([(0, i18next.t)("status"), status]);
|
|
14152
|
-
rows.push([(0, i18next.t)("state"), node_data.state || "—"]);
|
|
14153
|
-
if (node_data.parent_short_name) rows.push([(0, i18next.t)("parent"), node_data.parent_short_name]);
|
|
14154
|
-
if (typeof node_data.num_children === "number") {
|
|
14155
|
-
let kids = node_data.num_children;
|
|
14156
|
-
if (kids > 0 && node_data.is_collapsed) rows.push([(0, i18next.t)("children"), kids + " " + (0, i18next.t)("(collapsed)")]);
|
|
14157
|
-
else if (kids > 0) rows.push([(0, i18next.t)("children"), String(kids)]);
|
|
14158
|
-
}
|
|
14159
|
-
return rows;
|
|
14160
|
-
}
|
|
14161
|
-
/************************************************************
|
|
14162
15096
|
* Render popover body from the info rows of a node.
|
|
15097
|
+
*
|
|
15098
|
+
* The rows come from gobj_tree_model.js, so a node of the
|
|
15099
|
+
* browser yuno and a node of a backend one are read out with
|
|
15100
|
+
* the same words in the same order.
|
|
14163
15101
|
************************************************************/
|
|
14164
15102
|
function render_popover_body(gobj, node_data) {
|
|
14165
15103
|
let $body = gobj.priv.$popover_body;
|
|
14166
15104
|
if (!$body) return;
|
|
14167
|
-
$body.innerHTML =
|
|
14168
|
-
<div style="display:grid; grid-template-columns:
|
|
15105
|
+
$body.innerHTML = node_info_rows(node_data, i18next.t).map(([label, value]) => `
|
|
15106
|
+
<div style="display:grid; grid-template-columns: 96px 1fr; column-gap:10px; padding: 2px 0;">
|
|
14169
15107
|
<span style="color:var(--bulma-text-weak, #6B7280); font-weight:500;">${(0, _yuneta_gobj_js.escapeHtml)(String(label))}</span>
|
|
14170
15108
|
<span style="color:var(--bulma-text-strong, #1A1A1A); word-break:break-all;">${(0, _yuneta_gobj_js.escapeHtml)(String(value))}</span>
|
|
14171
15109
|
</div>
|
|
@@ -14182,6 +15120,7 @@ function show_popover(gobj, node_data, client_x, client_y) {
|
|
|
14182
15120
|
let $title = priv.$popover_title;
|
|
14183
15121
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
14184
15122
|
if (!$popover || !$title || !$container) return;
|
|
15123
|
+
priv.popover_node = node_data;
|
|
14185
15124
|
$title.textContent = node_data.short_name || node_data.gclass + (node_data.name ? "^" + node_data.name : "");
|
|
14186
15125
|
$title.title = $title.textContent;
|
|
14187
15126
|
render_popover_body(gobj, node_data);
|
|
@@ -14212,6 +15151,7 @@ function hide_popover(gobj) {
|
|
|
14212
15151
|
if (priv.$popover) priv.$popover.style.display = "none";
|
|
14213
15152
|
if (priv.$popover_body) priv.$popover_body.innerHTML = "";
|
|
14214
15153
|
if (priv.$popover_title) priv.$popover_title.textContent = "";
|
|
15154
|
+
priv.popover_node = null;
|
|
14215
15155
|
}
|
|
14216
15156
|
/************************************************************
|
|
14217
15157
|
* Generic tree layout engine.
|
|
@@ -14474,6 +15414,7 @@ var GobjLanesHLayout = class extends _antv_g6.BaseLayout {
|
|
|
14474
15414
|
*
|
|
14475
15415
|
************************************************************/
|
|
14476
15416
|
function ac_refresh$3(gobj, event, kw, src) {
|
|
15417
|
+
save_view_state(gobj);
|
|
14477
15418
|
refresh_tree(gobj);
|
|
14478
15419
|
return 0;
|
|
14479
15420
|
}
|
|
@@ -14501,6 +15442,8 @@ function ac_change_layout(gobj, event, kw, src) {
|
|
|
14501
15442
|
(0, _yuneta_gobj_js.gobj_write_str_attr)(gobj, "layout", new_key);
|
|
14502
15443
|
if (priv.$layout_select && priv.$layout_select.value !== new_key) priv.$layout_select.value = new_key;
|
|
14503
15444
|
apply_layout(gobj);
|
|
15445
|
+
save_view_state(gobj);
|
|
15446
|
+
save_view_state(gobj);
|
|
14504
15447
|
refresh_tree(gobj);
|
|
14505
15448
|
return 0;
|
|
14506
15449
|
}
|
|
@@ -14520,6 +15463,7 @@ function ac_toggle_collapse(gobj, event, kw, src) {
|
|
|
14520
15463
|
priv.collapse_state[node_data.full_name] = "expanded";
|
|
14521
15464
|
for (let child_info of node_data.direct_children || []) if (child_info.has_grandchildren) priv.collapse_state[child_info.full_name] = "collapsed";
|
|
14522
15465
|
} else priv.collapse_state[node_data.full_name] = "collapsed";
|
|
15466
|
+
save_view_state(gobj);
|
|
14523
15467
|
refresh_tree(gobj, { anchor });
|
|
14524
15468
|
return 0;
|
|
14525
15469
|
}
|
|
@@ -14599,10 +15543,31 @@ function reanchor(gobj) {
|
|
|
14599
15543
|
************************************************************/
|
|
14600
15544
|
function ac_center_anchor$1(gobj, event, kw, src) {
|
|
14601
15545
|
let priv = gobj.priv;
|
|
15546
|
+
paint_anchor_mark(gobj);
|
|
15547
|
+
save_view_state(gobj);
|
|
14602
15548
|
if (priv.anchor_state === "on" && priv.anchor_id) yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
14603
15549
|
return 0;
|
|
14604
15550
|
}
|
|
14605
15551
|
/************************************************************
|
|
15552
|
+
* Mark the card the camera is holding.
|
|
15553
|
+
*
|
|
15554
|
+
* A class on the card's own element and not a G6 node state:
|
|
15555
|
+
* G6 paints no state style on an html node.
|
|
15556
|
+
*
|
|
15557
|
+
* Re-applied after every rebuild, because the cards are new
|
|
15558
|
+
* DOM each time and the mark would otherwise last until the
|
|
15559
|
+
* next expand.
|
|
15560
|
+
************************************************************/
|
|
15561
|
+
function paint_anchor_mark(gobj) {
|
|
15562
|
+
let priv = gobj.priv;
|
|
15563
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
15564
|
+
if (!$container) return;
|
|
15565
|
+
for (let $card of $container.querySelectorAll(".GOBJ_CARD_ANCHORED")) $card.classList.remove("GOBJ_CARD_ANCHORED");
|
|
15566
|
+
if (priv.anchor_state !== "on" || !priv.anchor_name) return;
|
|
15567
|
+
let $it = $container.querySelector(".GOBJ_CARD[data-gobj-name=\"" + CSS.escape(priv.anchor_name) + "\"]");
|
|
15568
|
+
if ($it) $it.classList.add("GOBJ_CARD_ANCHORED");
|
|
15569
|
+
}
|
|
15570
|
+
/************************************************************
|
|
14606
15571
|
* Reading, or picking the node to anchor.
|
|
14607
15572
|
************************************************************/
|
|
14608
15573
|
function set_picking_mode(gobj, picking) {
|
|
@@ -14630,6 +15595,8 @@ function ac_toggle_anchor$1(gobj, event, kw, src) {
|
|
|
14630
15595
|
}
|
|
14631
15596
|
yui_graph_update_anchor((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.anchor_state);
|
|
14632
15597
|
set_picking_mode(gobj, priv.anchor_state === "arming");
|
|
15598
|
+
paint_anchor_mark(gobj);
|
|
15599
|
+
save_view_state(gobj);
|
|
14633
15600
|
return 0;
|
|
14634
15601
|
}
|
|
14635
15602
|
/************************************************************
|
|
@@ -14713,6 +15680,7 @@ function ac_node_click$3(gobj, event, kw, src) {
|
|
|
14713
15680
|
function ac_show$6(gobj, event, kw, src) {
|
|
14714
15681
|
let priv = gobj.priv;
|
|
14715
15682
|
let graph = priv.graph;
|
|
15683
|
+
save_view_state(gobj);
|
|
14716
15684
|
refresh_tree(gobj);
|
|
14717
15685
|
if (graph) {
|
|
14718
15686
|
let $canvas = document.getElementById(priv.canvas_id);
|
|
@@ -14753,6 +15721,68 @@ function ac_hide$5(gobj, event, kw, src) {
|
|
|
14753
15721
|
hide_popover(gobj);
|
|
14754
15722
|
return 0;
|
|
14755
15723
|
}
|
|
15724
|
+
/************************************************************
|
|
15725
|
+
* Open the gclass of the node the popover is showing.
|
|
15726
|
+
*
|
|
15727
|
+
* One window at a time: opening a second gclass replaces the
|
|
15728
|
+
* first rather than stacking windows nobody closes.
|
|
15729
|
+
************************************************************/
|
|
15730
|
+
function ac_open_gclass(gobj, event, kw, src) {
|
|
15731
|
+
let priv = gobj.priv;
|
|
15732
|
+
let node_data = priv.popover_node;
|
|
15733
|
+
if (!node_data || !node_data.gclass) {
|
|
15734
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: EV_OPEN_GCLASS with no node`);
|
|
15735
|
+
return -1;
|
|
15736
|
+
}
|
|
15737
|
+
close_gclass_view(priv.gclass_view);
|
|
15738
|
+
priv.gclass_view = null;
|
|
15739
|
+
priv.gclass_view = open_gclass_view(gobj, node_data.gclass, {
|
|
15740
|
+
title_prefix: (0, _yuneta_gobj_js.gobj_yuno_name)() || "",
|
|
15741
|
+
on_close: () => {
|
|
15742
|
+
if ((0, _yuneta_gobj_js.gobj_is_destroying)(gobj)) return;
|
|
15743
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_GCLASS_CLOSED", {}, gobj);
|
|
15744
|
+
}
|
|
15745
|
+
});
|
|
15746
|
+
return 0;
|
|
15747
|
+
}
|
|
15748
|
+
/************************************************************
|
|
15749
|
+
* The reader dismissed the gclass window (its own ✕).
|
|
15750
|
+
*
|
|
15751
|
+
* C_YUI_WINDOW.close_window() calls on_close and THEN destroys
|
|
15752
|
+
* itself, so here we only drop our reference -- destroying it
|
|
15753
|
+
* again would destroy it twice.
|
|
15754
|
+
************************************************************/
|
|
15755
|
+
function ac_gclass_closed(gobj, event, kw, src) {
|
|
15756
|
+
gobj.priv.gclass_view = null;
|
|
15757
|
+
return 0;
|
|
15758
|
+
}
|
|
15759
|
+
/************************************************************
|
|
15760
|
+
* The gclass viewer asked for a subtree.
|
|
15761
|
+
*
|
|
15762
|
+
* It cannot: the gclass description is a COMPLETE document,
|
|
15763
|
+
* it carries no `__collapsed__` stub, so nothing in it is
|
|
15764
|
+
* fetchable. The event is declared because the viewer is
|
|
15765
|
+
* hosted as a child and subscribes its host to everything it
|
|
15766
|
+
* publishes -- and it is logged, because arriving here means
|
|
15767
|
+
* the document was not the one we built.
|
|
15768
|
+
************************************************************/
|
|
15769
|
+
function ac_gclass_expand_path(gobj, event, kw, src) {
|
|
15770
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: EV_EXPAND_PATH on a complete document: ${kw && kw.path}`);
|
|
15771
|
+
return -1;
|
|
15772
|
+
}
|
|
15773
|
+
/************************************************************
|
|
15774
|
+
* The app switched language.
|
|
15775
|
+
*
|
|
15776
|
+
* A rebuild, not a re-translation: the words live inside the
|
|
15777
|
+
* innerHTML of G6 nodes, where refresh_language() cannot go.
|
|
15778
|
+
************************************************************/
|
|
15779
|
+
function ac_language_changed$3(gobj, event, kw, src) {
|
|
15780
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
15781
|
+
if ($container) (0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
|
|
15782
|
+
hide_popover(gobj);
|
|
15783
|
+
refresh_tree(gobj);
|
|
15784
|
+
return 0;
|
|
15785
|
+
}
|
|
14756
15786
|
/***************************
|
|
14757
15787
|
* FSM
|
|
14758
15788
|
***************************/
|
|
@@ -14786,7 +15816,11 @@ function create_gclass$9(gclass_name) {
|
|
|
14786
15816
|
["EV_CENTER_ANCHOR", 0],
|
|
14787
15817
|
["EV_RESIZE", 0],
|
|
14788
15818
|
["EV_SHOW", 0],
|
|
14789
|
-
["EV_HIDE", 0]
|
|
15819
|
+
["EV_HIDE", 0],
|
|
15820
|
+
["EV_OPEN_GCLASS", 0],
|
|
15821
|
+
["EV_GCLASS_CLOSED", 0],
|
|
15822
|
+
["EV_EXPAND_PATH", 0],
|
|
15823
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
14790
15824
|
], [["ST_IDLE", [
|
|
14791
15825
|
[
|
|
14792
15826
|
"EV_REFRESH",
|
|
@@ -14867,6 +15901,26 @@ function create_gclass$9(gclass_name) {
|
|
|
14867
15901
|
"EV_HIDE",
|
|
14868
15902
|
ac_hide$5,
|
|
14869
15903
|
null
|
|
15904
|
+
],
|
|
15905
|
+
[
|
|
15906
|
+
"EV_OPEN_GCLASS",
|
|
15907
|
+
ac_open_gclass,
|
|
15908
|
+
null
|
|
15909
|
+
],
|
|
15910
|
+
[
|
|
15911
|
+
"EV_GCLASS_CLOSED",
|
|
15912
|
+
ac_gclass_closed,
|
|
15913
|
+
null
|
|
15914
|
+
],
|
|
15915
|
+
[
|
|
15916
|
+
"EV_EXPAND_PATH",
|
|
15917
|
+
ac_gclass_expand_path,
|
|
15918
|
+
null
|
|
15919
|
+
],
|
|
15920
|
+
[
|
|
15921
|
+
"EV_LANGUAGE_CHANGED",
|
|
15922
|
+
ac_language_changed$3,
|
|
15923
|
+
null
|
|
14870
15924
|
]
|
|
14871
15925
|
]]], gmt$9, 0, attrs_table$9, PRIVATE_DATA$9, 0, 0, 0, 0);
|
|
14872
15926
|
if (!__gclass__$9) return -1;
|
|
@@ -49031,7 +50085,7 @@ function configure_toolbar(gobj) {
|
|
|
49031
50085
|
{
|
|
49032
50086
|
id: "g6-icon-anchor",
|
|
49033
50087
|
value: "anchor",
|
|
49034
|
-
className: "EV_TOGGLE_ANCHOR" + (priv.anchor_state
|
|
50088
|
+
className: "EV_TOGGLE_ANCHOR" + (priv.anchor_state === "on" ? " pressed_state" : "") + (priv.anchor_state === "arming" ? " color_pending_state" : ""),
|
|
49035
50089
|
title: anchor_title(priv.anchor_state)
|
|
49036
50090
|
}
|
|
49037
50091
|
];
|
|
@@ -51940,15 +52994,15 @@ function refresh_minimap(gobj) {
|
|
|
51940
52994
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
51941
52995
|
* shared now. Returns null for a node that carries no desc.
|
|
51942
52996
|
************************************************************/
|
|
51943
|
-
function node_innerHTML_of(nd, theme, highlight, selected) {
|
|
52997
|
+
function node_innerHTML_of(nd, theme, highlight, selected, anchored) {
|
|
51944
52998
|
if (!nd || !nd.data || !nd.data.desc) return null;
|
|
51945
52999
|
let desc = nd.data.desc;
|
|
51946
53000
|
let record = nd.data.record || {};
|
|
51947
53001
|
let label = node_label(desc, record);
|
|
51948
53002
|
switch (desc.node_treedb_type) {
|
|
51949
|
-
case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight, selected);
|
|
51950
|
-
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected);
|
|
51951
|
-
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected);
|
|
53003
|
+
case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight, selected, anchored);
|
|
53004
|
+
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected, anchored);
|
|
53005
|
+
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected, anchored);
|
|
51952
53006
|
}
|
|
51953
53007
|
return null;
|
|
51954
53008
|
}
|
|
@@ -51969,7 +53023,7 @@ function repaint_cards(gobj, ids) {
|
|
|
51969
53023
|
let selected = new Set(priv._selected_paint_ids || []);
|
|
51970
53024
|
let updates = [];
|
|
51971
53025
|
for (let id of ids) {
|
|
51972
|
-
let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id));
|
|
53026
|
+
let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id), priv.anchor_state === "on" && id === priv.anchor_id);
|
|
51973
53027
|
if (html !== null) updates.push({
|
|
51974
53028
|
id,
|
|
51975
53029
|
style: { innerHTML: html }
|
|
@@ -52043,6 +53097,23 @@ function refresh_default_edges_theme(gobj, theme) {
|
|
|
52043
53097
|
* it, which is also the order that reads correctly when only one
|
|
52044
53098
|
* of them is on.
|
|
52045
53099
|
************************************************************/
|
|
53100
|
+
/************************************************************
|
|
53101
|
+
* The mark of the card the CAMERA is holding.
|
|
53102
|
+
*
|
|
53103
|
+
* An outline and not another ring, and DASHED: the two rings
|
|
53104
|
+
* already mean things here -- amber is a find match or a
|
|
53105
|
+
* focused topic, blue is the selection -- and a third solid
|
|
53106
|
+
* ring would be a third thing to learn in the same channel.
|
|
53107
|
+
* A dash is a different channel, so it reads beside either of
|
|
53108
|
+
* them, and it says "provisional" the way a camera state is.
|
|
53109
|
+
*
|
|
53110
|
+
* The same dash the other two viewers draw: this is one
|
|
53111
|
+
* feature with one control, and it should not be three
|
|
53112
|
+
* drawings.
|
|
53113
|
+
************************************************************/
|
|
53114
|
+
function anchor_outline(anchored) {
|
|
53115
|
+
return anchored ? "outline: 3px dashed #fa8c16; outline-offset: 2px;" : "";
|
|
53116
|
+
}
|
|
52046
53117
|
function ring_shadow(highlight, selected, base_shadow) {
|
|
52047
53118
|
let rings = [];
|
|
52048
53119
|
if (highlight) rings.push(`0 0 0 4px ${HIGHLIGHT_HALO}`);
|
|
@@ -52057,7 +53128,7 @@ function ring_shadow(highlight, selected, base_shadow) {
|
|
|
52057
53128
|
* but lighter (1px border, no shadow, single line). The name is
|
|
52058
53129
|
* always legible (ellipsis + native title tooltip on overflow).
|
|
52059
53130
|
************************************************************/
|
|
52060
|
-
function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected) {
|
|
53131
|
+
function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected, anchored) {
|
|
52061
53132
|
let title = key || label;
|
|
52062
53133
|
let dark = theme === "dark";
|
|
52063
53134
|
let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
|
|
@@ -52070,13 +53141,14 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
52070
53141
|
margin-right: 6px; flex: 0 0 auto;
|
|
52071
53142
|
"/>`;
|
|
52072
53143
|
return `
|
|
52073
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
53144
|
+
<div class="TREEDB_CARD" title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
52074
53145
|
box-sizing: border-box;
|
|
52075
53146
|
width: 100%;
|
|
52076
53147
|
height: 100%;
|
|
52077
53148
|
background: ${bg};
|
|
52078
53149
|
border: ${highlight ? "3px" : "1px"} solid ${border};
|
|
52079
53150
|
${ring_shadow(highlight, selected, "")}
|
|
53151
|
+
${anchor_outline(anchored)}
|
|
52080
53152
|
border-radius: 8px;
|
|
52081
53153
|
color: ${text_color};
|
|
52082
53154
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
@@ -52102,7 +53174,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
52102
53174
|
* colour is kept (per-topic differentiation) but softened via
|
|
52103
53175
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
52104
53176
|
************************************************************/
|
|
52105
|
-
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected) {
|
|
53177
|
+
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected, anchored) {
|
|
52106
53178
|
let title = key || label;
|
|
52107
53179
|
let dark = theme === "dark";
|
|
52108
53180
|
let surface = dark ? "#1b2230" : "#ffffff";
|
|
@@ -52137,7 +53209,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
52137
53209
|
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
|
52138
53210
|
">${(0, _yuneta_gobj_js.escapeHtml)(topic_name)}</div>`;
|
|
52139
53211
|
return `
|
|
52140
|
-
<div title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
53212
|
+
<div class="TREEDB_CARD" title="${(0, _yuneta_gobj_js.escapeHtml)(title)}" style="
|
|
52141
53213
|
box-sizing: border-box;
|
|
52142
53214
|
width: 100%;
|
|
52143
53215
|
height: 100%;
|
|
@@ -52145,6 +53217,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
52145
53217
|
border: ${highlight ? "3px" : "1.5px"} ${border_style} ${border};
|
|
52146
53218
|
border-radius: 10px;
|
|
52147
53219
|
${ring_shadow(highlight, selected, shadow)}
|
|
53220
|
+
${anchor_outline(anchored)}
|
|
52148
53221
|
color: ${title_color};
|
|
52149
53222
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
52150
53223
|
display: flex;
|
|
@@ -53128,12 +54201,14 @@ function after_camera(gobj, moved) {
|
|
|
53128
54201
|
************************************************************/
|
|
53129
54202
|
function ac_toggle_anchor(gobj, event, kw, src) {
|
|
53130
54203
|
let priv = gobj.priv;
|
|
54204
|
+
let was = priv.anchor_id;
|
|
53131
54205
|
if (priv.anchor_state === "off") priv.anchor_state = "arming";
|
|
53132
54206
|
else {
|
|
53133
54207
|
priv.anchor_state = "off";
|
|
53134
54208
|
priv.anchor_id = "";
|
|
53135
54209
|
}
|
|
53136
54210
|
update_toolbar(gobj);
|
|
54211
|
+
if (was) repaint_cards(gobj, /* @__PURE__ */ new Set([was]));
|
|
53137
54212
|
return 0;
|
|
53138
54213
|
}
|
|
53139
54214
|
/************************************************************
|
|
@@ -53311,6 +54386,7 @@ function ac_node_click$2(gobj, event, kw, src) {
|
|
|
53311
54386
|
priv.anchor_id = node_id;
|
|
53312
54387
|
priv.anchor_state = "on";
|
|
53313
54388
|
update_toolbar(gobj);
|
|
54389
|
+
repaint_cards(gobj, /* @__PURE__ */ new Set([node_id]));
|
|
53314
54390
|
(0, _yuneta_gobj_js.gobj_post_event)(gobj, "EV_CENTER_ANCHOR", {}, gobj);
|
|
53315
54391
|
return 0;
|
|
53316
54392
|
}
|