@yuneta/gobj-ui 7.23.30 → 7.23.32
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 +13 -1
- package/dist/gobj-ui.cjs.js +149 -24
- package/dist/gobj-ui.es.js +149 -24
- package/package.json +1 -1
- package/src/c_yui_gobj_tree_js.js +30 -4
- package/src/c_yui_json_graph.js +30 -4
- package/src/c_yui_treedb_graph.js +20 -6
- package/src/dev_machine_trace.js +116 -0
- package/src/dev_machine_trace.test.js +98 -0
- package/src/yui_dev.js +39 -5
- package/src/yui_gclass_view.js +14 -1
package/README.md
CHANGED
|
@@ -1430,7 +1430,19 @@ gclass of a **backend** yuno the host passes the answer of `view-gclass` as
|
|
|
1430
1430
|
|
|
1431
1431
|
`gclass_view_available()` reports whether the app registers `C_YUI_JSON` — the
|
|
1432
1432
|
gobj tree asks it before drawing its `gclass` button, so an app that does not
|
|
1433
|
-
carry the viewer shows no control rather than one that fails.
|
|
1433
|
+
carry the viewer shows no control rather than one that fails. **Importing
|
|
1434
|
+
`c_yui_json.js` is not registering it**: an app that only pulls it in
|
|
1435
|
+
transitively (through the treedb graph, say) still has to call
|
|
1436
|
+
`register_c_yui_json()` for the button to appear.
|
|
1437
|
+
|
|
1438
|
+
> **Mount before you start a hosted view.** `mt_create` builds the DOM;
|
|
1439
|
+
> `mt_start` renders it, and a view that measures a canvas or observes its box
|
|
1440
|
+
> needs to be IN the document by then. A host that creates a viewer, reads its
|
|
1441
|
+
> `$container` and hands it to a window as `body` must therefore start the
|
|
1442
|
+
> viewer **after** the window — the window is what puts it in the document.
|
|
1443
|
+
> Started before, a graph viewer measures nothing, attaches no
|
|
1444
|
+
> `ResizeObserver`, and its canvas keeps its birth size for the life of the
|
|
1445
|
+
> window while everything resizes around it (fixed in 7.23.31).
|
|
1434
1446
|
|
|
1435
1447
|
### Toolbar badge — a count pinned to an item's icon
|
|
1436
1448
|
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -10983,6 +10983,26 @@ function make_toolbar$3(gobj) {
|
|
|
10983
10983
|
return $toolbar;
|
|
10984
10984
|
}
|
|
10985
10985
|
/************************************************************
|
|
10986
|
+
* The element G6 mounts its canvas in.
|
|
10987
|
+
*
|
|
10988
|
+
* Read from THIS gclass's own $container, never with
|
|
10989
|
+
* `document.getElementById()`: a view is not always in the
|
|
10990
|
+
* document when it is started -- a host that builds the
|
|
10991
|
+
* viewer and mounts it into a window afterwards starts it
|
|
10992
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
10993
|
+
* a resize that never worked: the ResizeObserver below was
|
|
10994
|
+
* simply never attached, silently, and the canvas kept the
|
|
10995
|
+
* size it was born with for the life of the window.
|
|
10996
|
+
*
|
|
10997
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
10998
|
+
* is logged where it matters rather than skipped.
|
|
10999
|
+
************************************************************/
|
|
11000
|
+
function canvas_mount$1(gobj) {
|
|
11001
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
11002
|
+
if (!$container) return null;
|
|
11003
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
11004
|
+
}
|
|
11005
|
+
/************************************************************
|
|
10986
11006
|
* Build a G6 graph instance
|
|
10987
11007
|
************************************************************/
|
|
10988
11008
|
function build_graph$3(gobj) {
|
|
@@ -11026,8 +11046,9 @@ function build_graph$3(gobj) {
|
|
|
11026
11046
|
});
|
|
11027
11047
|
graph.on(_antv_g6.CanvasEvent.CLICK, (evt) => {});
|
|
11028
11048
|
if (typeof ResizeObserver !== "undefined") {
|
|
11029
|
-
let $canvas =
|
|
11030
|
-
if (
|
|
11049
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11050
|
+
if (!$canvas) (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no canvas mount, the graph will never resize`);
|
|
11051
|
+
else {
|
|
11031
11052
|
let ro = new ResizeObserver(() => {
|
|
11032
11053
|
if (priv._resize_raf) cancelAnimationFrame(priv._resize_raf);
|
|
11033
11054
|
priv._resize_raf = requestAnimationFrame(() => {
|
|
@@ -11964,10 +11985,9 @@ function ac_node_click$4(gobj, event, kw, src) {
|
|
|
11964
11985
|
*
|
|
11965
11986
|
************************************************************/
|
|
11966
11987
|
function ac_show$8(gobj, event, kw, src) {
|
|
11967
|
-
let
|
|
11968
|
-
let graph = priv.graph;
|
|
11988
|
+
let graph = gobj.priv.graph;
|
|
11969
11989
|
if (graph) {
|
|
11970
|
-
let $canvas =
|
|
11990
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11971
11991
|
if ($canvas) {
|
|
11972
11992
|
let cw = $canvas.clientWidth;
|
|
11973
11993
|
let ch = $canvas.clientHeight;
|
|
@@ -11986,10 +12006,9 @@ function ac_show$8(gobj, event, kw, src) {
|
|
|
11986
12006
|
* No fitView: preserve the user's current pan/zoom.
|
|
11987
12007
|
************************************************************/
|
|
11988
12008
|
function ac_resize$2(gobj, event, kw, src) {
|
|
11989
|
-
let
|
|
11990
|
-
let graph = priv.graph;
|
|
12009
|
+
let graph = gobj.priv.graph;
|
|
11991
12010
|
if (graph) {
|
|
11992
|
-
let $canvas =
|
|
12011
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11993
12012
|
if ($canvas) {
|
|
11994
12013
|
let cw = $canvas.clientWidth;
|
|
11995
12014
|
let ch = $canvas.clientHeight;
|
|
@@ -13843,7 +13862,6 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13843
13862
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(host)}: cannot create the gclass viewer`);
|
|
13844
13863
|
return null;
|
|
13845
13864
|
}
|
|
13846
|
-
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
13847
13865
|
let handle = {
|
|
13848
13866
|
json_gobj: jv,
|
|
13849
13867
|
win: null,
|
|
@@ -13867,6 +13885,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13867
13885
|
t: i18next.t,
|
|
13868
13886
|
on_close
|
|
13869
13887
|
});
|
|
13888
|
+
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
13870
13889
|
return handle;
|
|
13871
13890
|
}
|
|
13872
13891
|
let $win_parent = window_layer_of(host, shell);
|
|
@@ -13895,6 +13914,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13895
13914
|
return null;
|
|
13896
13915
|
}
|
|
13897
13916
|
(0, _yuneta_gobj_js.gobj_start)(handle.win);
|
|
13917
|
+
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
13898
13918
|
return handle;
|
|
13899
13919
|
}
|
|
13900
13920
|
/************************************************************
|
|
@@ -14636,6 +14656,26 @@ function make_toolbar$1(gobj) {
|
|
|
14636
14656
|
return $toolbar;
|
|
14637
14657
|
}
|
|
14638
14658
|
/************************************************************
|
|
14659
|
+
* The element G6 mounts its canvas in.
|
|
14660
|
+
*
|
|
14661
|
+
* Read from THIS gclass's own $container, never with
|
|
14662
|
+
* `document.getElementById()`: a view is not always in the
|
|
14663
|
+
* document when it is started -- a host that builds the
|
|
14664
|
+
* viewer and mounts it into a window afterwards starts it
|
|
14665
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
14666
|
+
* a resize that never worked: the ResizeObserver below was
|
|
14667
|
+
* simply never attached, silently, and the canvas kept the
|
|
14668
|
+
* size it was born with for the life of the window.
|
|
14669
|
+
*
|
|
14670
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
14671
|
+
* is logged where it matters rather than skipped.
|
|
14672
|
+
************************************************************/
|
|
14673
|
+
function canvas_mount(gobj) {
|
|
14674
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
14675
|
+
if (!$container) return null;
|
|
14676
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
14677
|
+
}
|
|
14678
|
+
/************************************************************
|
|
14639
14679
|
* Build a G6 graph instance
|
|
14640
14680
|
************************************************************/
|
|
14641
14681
|
function build_graph$2(gobj) {
|
|
@@ -14679,8 +14719,9 @@ function build_graph$2(gobj) {
|
|
|
14679
14719
|
hide_popover(gobj);
|
|
14680
14720
|
});
|
|
14681
14721
|
if (typeof ResizeObserver !== "undefined") {
|
|
14682
|
-
let $canvas =
|
|
14683
|
-
if (
|
|
14722
|
+
let $canvas = canvas_mount(gobj);
|
|
14723
|
+
if (!$canvas) (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no canvas mount, the graph will never resize`);
|
|
14724
|
+
else {
|
|
14684
14725
|
let ro = new ResizeObserver(() => {
|
|
14685
14726
|
if (priv._resize_raf) cancelAnimationFrame(priv._resize_raf);
|
|
14686
14727
|
priv._resize_raf = requestAnimationFrame(() => {
|
|
@@ -15678,12 +15719,11 @@ function ac_node_click$3(gobj, event, kw, src) {
|
|
|
15678
15719
|
*
|
|
15679
15720
|
************************************************************/
|
|
15680
15721
|
function ac_show$6(gobj, event, kw, src) {
|
|
15681
|
-
let
|
|
15682
|
-
let graph = priv.graph;
|
|
15722
|
+
let graph = gobj.priv.graph;
|
|
15683
15723
|
save_view_state(gobj);
|
|
15684
15724
|
refresh_tree(gobj);
|
|
15685
15725
|
if (graph) {
|
|
15686
|
-
let $canvas =
|
|
15726
|
+
let $canvas = canvas_mount(gobj);
|
|
15687
15727
|
if ($canvas) {
|
|
15688
15728
|
let cw = $canvas.clientWidth;
|
|
15689
15729
|
let ch = $canvas.clientHeight;
|
|
@@ -15702,10 +15742,9 @@ function ac_show$6(gobj, event, kw, src) {
|
|
|
15702
15742
|
* No fitView: preserve the user's current pan/zoom.
|
|
15703
15743
|
************************************************************/
|
|
15704
15744
|
function ac_resize$1(gobj, event, kw, src) {
|
|
15705
|
-
let
|
|
15706
|
-
let graph = priv.graph;
|
|
15745
|
+
let graph = gobj.priv.graph;
|
|
15707
15746
|
if (graph) {
|
|
15708
|
-
let $canvas =
|
|
15747
|
+
let $canvas = canvas_mount(gobj);
|
|
15709
15748
|
if ($canvas) {
|
|
15710
15749
|
let cw = $canvas.clientWidth;
|
|
15711
15750
|
let ch = $canvas.clientHeight;
|
|
@@ -55366,7 +55405,6 @@ function open_json_viewer(gobj) {
|
|
|
55366
55405
|
return;
|
|
55367
55406
|
}
|
|
55368
55407
|
priv.json_gobj = jv;
|
|
55369
|
-
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
55370
55408
|
let $box = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(jv, "$container");
|
|
55371
55409
|
if (mobile) {
|
|
55372
55410
|
if (!shell) {
|
|
@@ -55385,6 +55423,7 @@ function open_json_viewer(gobj) {
|
|
|
55385
55423
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_JSON_CLOSED", {}, gobj);
|
|
55386
55424
|
}
|
|
55387
55425
|
});
|
|
55426
|
+
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
55388
55427
|
} else {
|
|
55389
55428
|
let $win_parent = shell && yui_shell_popup_layer(shell) || typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
55390
55429
|
priv.json_win = (0, _yuneta_gobj_js.gobj_create_service)(`treedb-jsonwin-${(0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj))}`, "C_YUI_WINDOW", {
|
|
@@ -55415,6 +55454,7 @@ function open_json_viewer(gobj) {
|
|
|
55415
55454
|
return;
|
|
55416
55455
|
}
|
|
55417
55456
|
(0, _yuneta_gobj_js.gobj_start)(priv.json_win);
|
|
55457
|
+
(0, _yuneta_gobj_js.gobj_start)(jv);
|
|
55418
55458
|
}
|
|
55419
55459
|
request_print_tranger(gobj, "");
|
|
55420
55460
|
}
|
|
@@ -55442,7 +55482,7 @@ function close_json_viewer(gobj) {
|
|
|
55442
55482
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: already gone: ${e}`);
|
|
55443
55483
|
}
|
|
55444
55484
|
if (jv && (0, _yuneta_gobj_js.is_gobj)(jv)) try {
|
|
55445
|
-
(0, _yuneta_gobj_js.gobj_stop)(jv);
|
|
55485
|
+
if ((0, _yuneta_gobj_js.gobj_is_running)(jv)) (0, _yuneta_gobj_js.gobj_stop)(jv);
|
|
55446
55486
|
(0, _yuneta_gobj_js.gobj_destroy)(jv);
|
|
55447
55487
|
} catch (e) {
|
|
55448
55488
|
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: already gone: ${e}`);
|
|
@@ -64052,6 +64092,86 @@ function register_c_yui_period() {
|
|
|
64052
64092
|
return create_gclass(GCLASS_NAME);
|
|
64053
64093
|
}
|
|
64054
64094
|
//#endregion
|
|
64095
|
+
//#region src/dev_machine_trace.js
|
|
64096
|
+
/***********************************************************************
|
|
64097
|
+
* dev_machine_trace.js
|
|
64098
|
+
*
|
|
64099
|
+
* Reading a MACHINE trace line back.
|
|
64100
|
+
*
|
|
64101
|
+
* The developer window mirrors the runtime's log, and the
|
|
64102
|
+
* `machine` trace is most of what lands there once it is on.
|
|
64103
|
+
* Those lines arrive as text, so to the window they were just
|
|
64104
|
+
* "a debug log" -- which is why its `Periodic` filter could
|
|
64105
|
+
* not touch them: the filter works on a signature, and every
|
|
64106
|
+
* mirrored log carried the same one (`log:debug`).
|
|
64107
|
+
*
|
|
64108
|
+
* This gives a machine line back its EVENT, which is the only
|
|
64109
|
+
* thing that says whether it is noise. Both formats gobj-js
|
|
64110
|
+
* emits (`gobj_set_trace_machine_format`):
|
|
64111
|
+
*
|
|
64112
|
+
* 0 verbose "🔄 mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ac: …"
|
|
64113
|
+
* "<- mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ret: 0"
|
|
64114
|
+
* 1 compact "🔄 EV_TIMEOUT C_TIMER^t ST_IDLE from C_TIMER^t"
|
|
64115
|
+
*
|
|
64116
|
+
* Copyright (c) 2026, ArtGins.
|
|
64117
|
+
* All Rights Reserved.
|
|
64118
|
+
***********************************************************************/
|
|
64119
|
+
var MACHINE_MARK_RE = /\bmach\(/;
|
|
64120
|
+
var EVENT_FIELD_RE = /\bev:\s*([A-Za-z0-9_]+)/;
|
|
64121
|
+
var EVENT_HEAD_RE = /^\s*\S{0,4}\s*(EV_[A-Za-z0-9_]+)(?=\s|$)/;
|
|
64122
|
+
var PERIODIC_EVENT_RE = /PERIODIC|TIMEOUT|HEARTBEAT|PING|POLL/i;
|
|
64123
|
+
/************************************************************
|
|
64124
|
+
* The event of a machine trace line, or "" when the line is
|
|
64125
|
+
* not one.
|
|
64126
|
+
*
|
|
64127
|
+
* "" is also the answer for a machine line that carries no
|
|
64128
|
+
* event -- a state change ("new st(…), prev st(…)") -- and
|
|
64129
|
+
* that is right: what it reports is not repetitive.
|
|
64130
|
+
************************************************************/
|
|
64131
|
+
function machine_event_of(text) {
|
|
64132
|
+
if (typeof text !== "string" || text.length === 0) return "";
|
|
64133
|
+
if (MACHINE_MARK_RE.test(text)) {
|
|
64134
|
+
let m = EVENT_FIELD_RE.exec(text);
|
|
64135
|
+
return m ? m[1] : "";
|
|
64136
|
+
}
|
|
64137
|
+
let m = EVENT_HEAD_RE.exec(text);
|
|
64138
|
+
return m ? m[1] : "";
|
|
64139
|
+
}
|
|
64140
|
+
/************************************************************
|
|
64141
|
+
* Is this event one of the ones that arrive by themselves,
|
|
64142
|
+
* for ever, and say nothing about what the app is doing?
|
|
64143
|
+
************************************************************/
|
|
64144
|
+
function is_periodic_event(event_name) {
|
|
64145
|
+
if (!event_name) return false;
|
|
64146
|
+
return PERIODIC_EVENT_RE.test(event_name);
|
|
64147
|
+
}
|
|
64148
|
+
/************************************************************
|
|
64149
|
+
* The signature of a mirrored log line: what the window
|
|
64150
|
+
* counts it under and what its filters match on.
|
|
64151
|
+
*
|
|
64152
|
+
* A machine line is signed by its EVENT, so a hundred
|
|
64153
|
+
* EV_TIMEOUTs are one recurring thing rather than a hundred
|
|
64154
|
+
* anonymous debug lines. Everything else is signed by its
|
|
64155
|
+
* level, as before.
|
|
64156
|
+
************************************************************/
|
|
64157
|
+
function log_signature(level, text) {
|
|
64158
|
+
let event = machine_event_of(text);
|
|
64159
|
+
if (event) return "mach:" + event;
|
|
64160
|
+
return "log:" + (level || "debug");
|
|
64161
|
+
}
|
|
64162
|
+
/************************************************************
|
|
64163
|
+
* May the periodic filter hide this log line?
|
|
64164
|
+
*
|
|
64165
|
+
* Only a machine transition, and only below warning level.
|
|
64166
|
+
* An ERROR that names EV_TIMEOUT -- "Event NOT DEFINED in
|
|
64167
|
+
* state", which is exactly the loud one the framework wants
|
|
64168
|
+
* seen -- must never disappear because of the word in it.
|
|
64169
|
+
************************************************************/
|
|
64170
|
+
function log_is_periodic(level, text) {
|
|
64171
|
+
if (level === "error" || level === "warning") return false;
|
|
64172
|
+
return is_periodic_event(machine_event_of(text));
|
|
64173
|
+
}
|
|
64174
|
+
//#endregion
|
|
64055
64175
|
//#region src/yui_dev.js
|
|
64056
64176
|
/***********************************************************************
|
|
64057
64177
|
* ui_dev.js
|
|
@@ -64188,8 +64308,9 @@ function dev_view() {
|
|
|
64188
64308
|
let v = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_view_mode", "detailed", false);
|
|
64189
64309
|
return v === "compact" || v === "name" || v === "full" ? v : "detailed";
|
|
64190
64310
|
}
|
|
64311
|
+
var HIDE_PERIODIC_DEFAULT = 1;
|
|
64191
64312
|
function dev_hide_periodic() {
|
|
64192
|
-
return dev_num("dev_hide_periodic",
|
|
64313
|
+
return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
|
|
64193
64314
|
}
|
|
64194
64315
|
function dev_route() {
|
|
64195
64316
|
let v = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_output_route", "both", false);
|
|
@@ -64265,7 +64386,10 @@ function build_filter_ctx() {
|
|
|
64265
64386
|
};
|
|
64266
64387
|
}
|
|
64267
64388
|
function entry_hidden(e, ctx) {
|
|
64268
|
-
if (e.kind === "log")
|
|
64389
|
+
if (e.kind === "log") {
|
|
64390
|
+
if (ctx.hide_periodic && e.periodic) return true;
|
|
64391
|
+
return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
|
|
64392
|
+
}
|
|
64269
64393
|
if (e.dir === 1 && !ctx.out) return true;
|
|
64270
64394
|
if (e.dir === 2 && !ctx.inc) return true;
|
|
64271
64395
|
if (e.dir === 3 && !ctx.err) return true;
|
|
@@ -64966,7 +65090,8 @@ function info_log(level, msg, hora) {
|
|
|
64966
65090
|
dir: 0,
|
|
64967
65091
|
size: 0,
|
|
64968
65092
|
ts: traffic_now(),
|
|
64969
|
-
sig:
|
|
65093
|
+
sig: log_signature(lvl, text),
|
|
65094
|
+
periodic: log_is_periodic(lvl, text),
|
|
64970
65095
|
hay: (lvl + " " + text).toLowerCase(),
|
|
64971
65096
|
$node: null
|
|
64972
65097
|
};
|
|
@@ -65299,12 +65424,12 @@ function build_control_bar() {
|
|
|
65299
65424
|
class: "YDEV_CHIP",
|
|
65300
65425
|
"data-toggle": "periodic",
|
|
65301
65426
|
type: "button",
|
|
65302
|
-
title: "Hide
|
|
65427
|
+
title: "Hide the timers: EV_TIMEOUT / PERIODIC / HEARTBEAT / PING transitions, and recurring traffic. On by default"
|
|
65303
65428
|
},
|
|
65304
65429
|
"⊘ Periodic",
|
|
65305
65430
|
{ click: (ev) => {
|
|
65306
65431
|
ev.stopPropagation();
|
|
65307
|
-
toggle_pref("dev_hide_periodic",
|
|
65432
|
+
toggle_pref("dev_hide_periodic", HIDE_PERIODIC_DEFAULT);
|
|
65308
65433
|
} }
|
|
65309
65434
|
];
|
|
65310
65435
|
let search = [
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -10978,6 +10978,26 @@ function make_toolbar$3(gobj) {
|
|
|
10978
10978
|
return $toolbar;
|
|
10979
10979
|
}
|
|
10980
10980
|
/************************************************************
|
|
10981
|
+
* The element G6 mounts its canvas in.
|
|
10982
|
+
*
|
|
10983
|
+
* Read from THIS gclass's own $container, never with
|
|
10984
|
+
* `document.getElementById()`: a view is not always in the
|
|
10985
|
+
* document when it is started -- a host that builds the
|
|
10986
|
+
* viewer and mounts it into a window afterwards starts it
|
|
10987
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
10988
|
+
* a resize that never worked: the ResizeObserver below was
|
|
10989
|
+
* simply never attached, silently, and the canvas kept the
|
|
10990
|
+
* size it was born with for the life of the window.
|
|
10991
|
+
*
|
|
10992
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
10993
|
+
* is logged where it matters rather than skipped.
|
|
10994
|
+
************************************************************/
|
|
10995
|
+
function canvas_mount$1(gobj) {
|
|
10996
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
10997
|
+
if (!$container) return null;
|
|
10998
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
10999
|
+
}
|
|
11000
|
+
/************************************************************
|
|
10981
11001
|
* Build a G6 graph instance
|
|
10982
11002
|
************************************************************/
|
|
10983
11003
|
function build_graph$3(gobj) {
|
|
@@ -11021,8 +11041,9 @@ function build_graph$3(gobj) {
|
|
|
11021
11041
|
});
|
|
11022
11042
|
graph.on(CanvasEvent.CLICK, (evt) => {});
|
|
11023
11043
|
if (typeof ResizeObserver !== "undefined") {
|
|
11024
|
-
let $canvas =
|
|
11025
|
-
if (
|
|
11044
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11045
|
+
if (!$canvas) log_error(`${gobj_short_name(gobj)}: no canvas mount, the graph will never resize`);
|
|
11046
|
+
else {
|
|
11026
11047
|
let ro = new ResizeObserver(() => {
|
|
11027
11048
|
if (priv._resize_raf) cancelAnimationFrame(priv._resize_raf);
|
|
11028
11049
|
priv._resize_raf = requestAnimationFrame(() => {
|
|
@@ -11959,10 +11980,9 @@ function ac_node_click$4(gobj, event, kw, src) {
|
|
|
11959
11980
|
*
|
|
11960
11981
|
************************************************************/
|
|
11961
11982
|
function ac_show$8(gobj, event, kw, src) {
|
|
11962
|
-
let
|
|
11963
|
-
let graph = priv.graph;
|
|
11983
|
+
let graph = gobj.priv.graph;
|
|
11964
11984
|
if (graph) {
|
|
11965
|
-
let $canvas =
|
|
11985
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11966
11986
|
if ($canvas) {
|
|
11967
11987
|
let cw = $canvas.clientWidth;
|
|
11968
11988
|
let ch = $canvas.clientHeight;
|
|
@@ -11981,10 +12001,9 @@ function ac_show$8(gobj, event, kw, src) {
|
|
|
11981
12001
|
* No fitView: preserve the user's current pan/zoom.
|
|
11982
12002
|
************************************************************/
|
|
11983
12003
|
function ac_resize$2(gobj, event, kw, src) {
|
|
11984
|
-
let
|
|
11985
|
-
let graph = priv.graph;
|
|
12004
|
+
let graph = gobj.priv.graph;
|
|
11986
12005
|
if (graph) {
|
|
11987
|
-
let $canvas =
|
|
12006
|
+
let $canvas = canvas_mount$1(gobj);
|
|
11988
12007
|
if ($canvas) {
|
|
11989
12008
|
let cw = $canvas.clientWidth;
|
|
11990
12009
|
let ch = $canvas.clientHeight;
|
|
@@ -13838,7 +13857,6 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13838
13857
|
log_error(`${gobj_short_name(host)}: cannot create the gclass viewer`);
|
|
13839
13858
|
return null;
|
|
13840
13859
|
}
|
|
13841
|
-
gobj_start(jv);
|
|
13842
13860
|
let handle = {
|
|
13843
13861
|
json_gobj: jv,
|
|
13844
13862
|
win: null,
|
|
@@ -13862,6 +13880,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13862
13880
|
t,
|
|
13863
13881
|
on_close
|
|
13864
13882
|
});
|
|
13883
|
+
gobj_start(jv);
|
|
13865
13884
|
return handle;
|
|
13866
13885
|
}
|
|
13867
13886
|
let $win_parent = window_layer_of(host, shell);
|
|
@@ -13890,6 +13909,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
13890
13909
|
return null;
|
|
13891
13910
|
}
|
|
13892
13911
|
gobj_start(handle.win);
|
|
13912
|
+
gobj_start(jv);
|
|
13893
13913
|
return handle;
|
|
13894
13914
|
}
|
|
13895
13915
|
/************************************************************
|
|
@@ -14631,6 +14651,26 @@ function make_toolbar$1(gobj) {
|
|
|
14631
14651
|
return $toolbar;
|
|
14632
14652
|
}
|
|
14633
14653
|
/************************************************************
|
|
14654
|
+
* The element G6 mounts its canvas in.
|
|
14655
|
+
*
|
|
14656
|
+
* Read from THIS gclass's own $container, never with
|
|
14657
|
+
* `document.getElementById()`: a view is not always in the
|
|
14658
|
+
* document when it is started -- a host that builds the
|
|
14659
|
+
* viewer and mounts it into a window afterwards starts it
|
|
14660
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
14661
|
+
* a resize that never worked: the ResizeObserver below was
|
|
14662
|
+
* simply never attached, silently, and the canvas kept the
|
|
14663
|
+
* size it was born with for the life of the window.
|
|
14664
|
+
*
|
|
14665
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
14666
|
+
* is logged where it matters rather than skipped.
|
|
14667
|
+
************************************************************/
|
|
14668
|
+
function canvas_mount(gobj) {
|
|
14669
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
14670
|
+
if (!$container) return null;
|
|
14671
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
14672
|
+
}
|
|
14673
|
+
/************************************************************
|
|
14634
14674
|
* Build a G6 graph instance
|
|
14635
14675
|
************************************************************/
|
|
14636
14676
|
function build_graph$2(gobj) {
|
|
@@ -14674,8 +14714,9 @@ function build_graph$2(gobj) {
|
|
|
14674
14714
|
hide_popover(gobj);
|
|
14675
14715
|
});
|
|
14676
14716
|
if (typeof ResizeObserver !== "undefined") {
|
|
14677
|
-
let $canvas =
|
|
14678
|
-
if (
|
|
14717
|
+
let $canvas = canvas_mount(gobj);
|
|
14718
|
+
if (!$canvas) log_error(`${gobj_short_name(gobj)}: no canvas mount, the graph will never resize`);
|
|
14719
|
+
else {
|
|
14679
14720
|
let ro = new ResizeObserver(() => {
|
|
14680
14721
|
if (priv._resize_raf) cancelAnimationFrame(priv._resize_raf);
|
|
14681
14722
|
priv._resize_raf = requestAnimationFrame(() => {
|
|
@@ -15673,12 +15714,11 @@ function ac_node_click$3(gobj, event, kw, src) {
|
|
|
15673
15714
|
*
|
|
15674
15715
|
************************************************************/
|
|
15675
15716
|
function ac_show$6(gobj, event, kw, src) {
|
|
15676
|
-
let
|
|
15677
|
-
let graph = priv.graph;
|
|
15717
|
+
let graph = gobj.priv.graph;
|
|
15678
15718
|
save_view_state(gobj);
|
|
15679
15719
|
refresh_tree(gobj);
|
|
15680
15720
|
if (graph) {
|
|
15681
|
-
let $canvas =
|
|
15721
|
+
let $canvas = canvas_mount(gobj);
|
|
15682
15722
|
if ($canvas) {
|
|
15683
15723
|
let cw = $canvas.clientWidth;
|
|
15684
15724
|
let ch = $canvas.clientHeight;
|
|
@@ -15697,10 +15737,9 @@ function ac_show$6(gobj, event, kw, src) {
|
|
|
15697
15737
|
* No fitView: preserve the user's current pan/zoom.
|
|
15698
15738
|
************************************************************/
|
|
15699
15739
|
function ac_resize$1(gobj, event, kw, src) {
|
|
15700
|
-
let
|
|
15701
|
-
let graph = priv.graph;
|
|
15740
|
+
let graph = gobj.priv.graph;
|
|
15702
15741
|
if (graph) {
|
|
15703
|
-
let $canvas =
|
|
15742
|
+
let $canvas = canvas_mount(gobj);
|
|
15704
15743
|
if ($canvas) {
|
|
15705
15744
|
let cw = $canvas.clientWidth;
|
|
15706
15745
|
let ch = $canvas.clientHeight;
|
|
@@ -55361,7 +55400,6 @@ function open_json_viewer(gobj) {
|
|
|
55361
55400
|
return;
|
|
55362
55401
|
}
|
|
55363
55402
|
priv.json_gobj = jv;
|
|
55364
|
-
gobj_start(jv);
|
|
55365
55403
|
let $box = gobj_read_pointer_attr(jv, "$container");
|
|
55366
55404
|
if (mobile) {
|
|
55367
55405
|
if (!shell) {
|
|
@@ -55380,6 +55418,7 @@ function open_json_viewer(gobj) {
|
|
|
55380
55418
|
gobj_send_event(gobj, "EV_JSON_CLOSED", {}, gobj);
|
|
55381
55419
|
}
|
|
55382
55420
|
});
|
|
55421
|
+
gobj_start(jv);
|
|
55383
55422
|
} else {
|
|
55384
55423
|
let $win_parent = shell && yui_shell_popup_layer(shell) || typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
55385
55424
|
priv.json_win = gobj_create_service(`treedb-jsonwin-${clean_name(gobj_name(gobj))}`, "C_YUI_WINDOW", {
|
|
@@ -55410,6 +55449,7 @@ function open_json_viewer(gobj) {
|
|
|
55410
55449
|
return;
|
|
55411
55450
|
}
|
|
55412
55451
|
gobj_start(priv.json_win);
|
|
55452
|
+
gobj_start(jv);
|
|
55413
55453
|
}
|
|
55414
55454
|
request_print_tranger(gobj, "");
|
|
55415
55455
|
}
|
|
@@ -55437,7 +55477,7 @@ function close_json_viewer(gobj) {
|
|
|
55437
55477
|
log_warning(`${gobj_short_name(gobj)}: already gone: ${e}`);
|
|
55438
55478
|
}
|
|
55439
55479
|
if (jv && is_gobj(jv)) try {
|
|
55440
|
-
gobj_stop(jv);
|
|
55480
|
+
if (gobj_is_running(jv)) gobj_stop(jv);
|
|
55441
55481
|
gobj_destroy(jv);
|
|
55442
55482
|
} catch (e) {
|
|
55443
55483
|
log_warning(`${gobj_short_name(gobj)}: already gone: ${e}`);
|
|
@@ -64047,6 +64087,86 @@ function register_c_yui_period() {
|
|
|
64047
64087
|
return create_gclass(GCLASS_NAME);
|
|
64048
64088
|
}
|
|
64049
64089
|
//#endregion
|
|
64090
|
+
//#region src/dev_machine_trace.js
|
|
64091
|
+
/***********************************************************************
|
|
64092
|
+
* dev_machine_trace.js
|
|
64093
|
+
*
|
|
64094
|
+
* Reading a MACHINE trace line back.
|
|
64095
|
+
*
|
|
64096
|
+
* The developer window mirrors the runtime's log, and the
|
|
64097
|
+
* `machine` trace is most of what lands there once it is on.
|
|
64098
|
+
* Those lines arrive as text, so to the window they were just
|
|
64099
|
+
* "a debug log" -- which is why its `Periodic` filter could
|
|
64100
|
+
* not touch them: the filter works on a signature, and every
|
|
64101
|
+
* mirrored log carried the same one (`log:debug`).
|
|
64102
|
+
*
|
|
64103
|
+
* This gives a machine line back its EVENT, which is the only
|
|
64104
|
+
* thing that says whether it is noise. Both formats gobj-js
|
|
64105
|
+
* emits (`gobj_set_trace_machine_format`):
|
|
64106
|
+
*
|
|
64107
|
+
* 0 verbose "🔄 mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ac: …"
|
|
64108
|
+
* "<- mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ret: 0"
|
|
64109
|
+
* 1 compact "🔄 EV_TIMEOUT C_TIMER^t ST_IDLE from C_TIMER^t"
|
|
64110
|
+
*
|
|
64111
|
+
* Copyright (c) 2026, ArtGins.
|
|
64112
|
+
* All Rights Reserved.
|
|
64113
|
+
***********************************************************************/
|
|
64114
|
+
var MACHINE_MARK_RE = /\bmach\(/;
|
|
64115
|
+
var EVENT_FIELD_RE = /\bev:\s*([A-Za-z0-9_]+)/;
|
|
64116
|
+
var EVENT_HEAD_RE = /^\s*\S{0,4}\s*(EV_[A-Za-z0-9_]+)(?=\s|$)/;
|
|
64117
|
+
var PERIODIC_EVENT_RE = /PERIODIC|TIMEOUT|HEARTBEAT|PING|POLL/i;
|
|
64118
|
+
/************************************************************
|
|
64119
|
+
* The event of a machine trace line, or "" when the line is
|
|
64120
|
+
* not one.
|
|
64121
|
+
*
|
|
64122
|
+
* "" is also the answer for a machine line that carries no
|
|
64123
|
+
* event -- a state change ("new st(…), prev st(…)") -- and
|
|
64124
|
+
* that is right: what it reports is not repetitive.
|
|
64125
|
+
************************************************************/
|
|
64126
|
+
function machine_event_of(text) {
|
|
64127
|
+
if (typeof text !== "string" || text.length === 0) return "";
|
|
64128
|
+
if (MACHINE_MARK_RE.test(text)) {
|
|
64129
|
+
let m = EVENT_FIELD_RE.exec(text);
|
|
64130
|
+
return m ? m[1] : "";
|
|
64131
|
+
}
|
|
64132
|
+
let m = EVENT_HEAD_RE.exec(text);
|
|
64133
|
+
return m ? m[1] : "";
|
|
64134
|
+
}
|
|
64135
|
+
/************************************************************
|
|
64136
|
+
* Is this event one of the ones that arrive by themselves,
|
|
64137
|
+
* for ever, and say nothing about what the app is doing?
|
|
64138
|
+
************************************************************/
|
|
64139
|
+
function is_periodic_event(event_name) {
|
|
64140
|
+
if (!event_name) return false;
|
|
64141
|
+
return PERIODIC_EVENT_RE.test(event_name);
|
|
64142
|
+
}
|
|
64143
|
+
/************************************************************
|
|
64144
|
+
* The signature of a mirrored log line: what the window
|
|
64145
|
+
* counts it under and what its filters match on.
|
|
64146
|
+
*
|
|
64147
|
+
* A machine line is signed by its EVENT, so a hundred
|
|
64148
|
+
* EV_TIMEOUTs are one recurring thing rather than a hundred
|
|
64149
|
+
* anonymous debug lines. Everything else is signed by its
|
|
64150
|
+
* level, as before.
|
|
64151
|
+
************************************************************/
|
|
64152
|
+
function log_signature(level, text) {
|
|
64153
|
+
let event = machine_event_of(text);
|
|
64154
|
+
if (event) return "mach:" + event;
|
|
64155
|
+
return "log:" + (level || "debug");
|
|
64156
|
+
}
|
|
64157
|
+
/************************************************************
|
|
64158
|
+
* May the periodic filter hide this log line?
|
|
64159
|
+
*
|
|
64160
|
+
* Only a machine transition, and only below warning level.
|
|
64161
|
+
* An ERROR that names EV_TIMEOUT -- "Event NOT DEFINED in
|
|
64162
|
+
* state", which is exactly the loud one the framework wants
|
|
64163
|
+
* seen -- must never disappear because of the word in it.
|
|
64164
|
+
************************************************************/
|
|
64165
|
+
function log_is_periodic(level, text) {
|
|
64166
|
+
if (level === "error" || level === "warning") return false;
|
|
64167
|
+
return is_periodic_event(machine_event_of(text));
|
|
64168
|
+
}
|
|
64169
|
+
//#endregion
|
|
64050
64170
|
//#region src/yui_dev.js
|
|
64051
64171
|
/***********************************************************************
|
|
64052
64172
|
* ui_dev.js
|
|
@@ -64183,8 +64303,9 @@ function dev_view() {
|
|
|
64183
64303
|
let v = kw_get_local_storage_value("dev_view_mode", "detailed", false);
|
|
64184
64304
|
return v === "compact" || v === "name" || v === "full" ? v : "detailed";
|
|
64185
64305
|
}
|
|
64306
|
+
var HIDE_PERIODIC_DEFAULT = 1;
|
|
64186
64307
|
function dev_hide_periodic() {
|
|
64187
|
-
return dev_num("dev_hide_periodic",
|
|
64308
|
+
return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
|
|
64188
64309
|
}
|
|
64189
64310
|
function dev_route() {
|
|
64190
64311
|
let v = kw_get_local_storage_value("dev_output_route", "both", false);
|
|
@@ -64260,7 +64381,10 @@ function build_filter_ctx() {
|
|
|
64260
64381
|
};
|
|
64261
64382
|
}
|
|
64262
64383
|
function entry_hidden(e, ctx) {
|
|
64263
|
-
if (e.kind === "log")
|
|
64384
|
+
if (e.kind === "log") {
|
|
64385
|
+
if (ctx.hide_periodic && e.periodic) return true;
|
|
64386
|
+
return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
|
|
64387
|
+
}
|
|
64264
64388
|
if (e.dir === 1 && !ctx.out) return true;
|
|
64265
64389
|
if (e.dir === 2 && !ctx.inc) return true;
|
|
64266
64390
|
if (e.dir === 3 && !ctx.err) return true;
|
|
@@ -64961,7 +65085,8 @@ function info_log(level, msg, hora) {
|
|
|
64961
65085
|
dir: 0,
|
|
64962
65086
|
size: 0,
|
|
64963
65087
|
ts: traffic_now(),
|
|
64964
|
-
sig:
|
|
65088
|
+
sig: log_signature(lvl, text),
|
|
65089
|
+
periodic: log_is_periodic(lvl, text),
|
|
64965
65090
|
hay: (lvl + " " + text).toLowerCase(),
|
|
64966
65091
|
$node: null
|
|
64967
65092
|
};
|
|
@@ -65294,12 +65419,12 @@ function build_control_bar() {
|
|
|
65294
65419
|
class: "YDEV_CHIP",
|
|
65295
65420
|
"data-toggle": "periodic",
|
|
65296
65421
|
type: "button",
|
|
65297
|
-
title: "Hide
|
|
65422
|
+
title: "Hide the timers: EV_TIMEOUT / PERIODIC / HEARTBEAT / PING transitions, and recurring traffic. On by default"
|
|
65298
65423
|
},
|
|
65299
65424
|
"⊘ Periodic",
|
|
65300
65425
|
{ click: (ev) => {
|
|
65301
65426
|
ev.stopPropagation();
|
|
65302
|
-
toggle_pref("dev_hide_periodic",
|
|
65427
|
+
toggle_pref("dev_hide_periodic", HIDE_PERIODIC_DEFAULT);
|
|
65303
65428
|
} }
|
|
65304
65429
|
];
|
|
65305
65430
|
let search = [
|
package/package.json
CHANGED
|
@@ -903,6 +903,30 @@ function make_toolbar(gobj)
|
|
|
903
903
|
return $toolbar;
|
|
904
904
|
}
|
|
905
905
|
|
|
906
|
+
/************************************************************
|
|
907
|
+
* The element G6 mounts its canvas in.
|
|
908
|
+
*
|
|
909
|
+
* Read from THIS gclass's own $container, never with
|
|
910
|
+
* `document.getElementById()`: a view is not always in the
|
|
911
|
+
* document when it is started -- a host that builds the
|
|
912
|
+
* viewer and mounts it into a window afterwards starts it
|
|
913
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
914
|
+
* a resize that never worked: the ResizeObserver below was
|
|
915
|
+
* simply never attached, silently, and the canvas kept the
|
|
916
|
+
* size it was born with for the life of the window.
|
|
917
|
+
*
|
|
918
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
919
|
+
* is logged where it matters rather than skipped.
|
|
920
|
+
************************************************************/
|
|
921
|
+
function canvas_mount(gobj)
|
|
922
|
+
{
|
|
923
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
924
|
+
if(!$container) {
|
|
925
|
+
return null;
|
|
926
|
+
}
|
|
927
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
928
|
+
}
|
|
929
|
+
|
|
906
930
|
/************************************************************
|
|
907
931
|
* Build a G6 graph instance
|
|
908
932
|
************************************************************/
|
|
@@ -991,8 +1015,10 @@ function build_graph(gobj)
|
|
|
991
1015
|
* the observed box so there is no feedback loop.
|
|
992
1016
|
*/
|
|
993
1017
|
if(typeof ResizeObserver !== "undefined") {
|
|
994
|
-
let $canvas =
|
|
995
|
-
if(
|
|
1018
|
+
let $canvas = canvas_mount(gobj);
|
|
1019
|
+
if(!$canvas) {
|
|
1020
|
+
log_error(`${gobj_short_name(gobj)}: no canvas mount, the graph will never resize`);
|
|
1021
|
+
} else {
|
|
996
1022
|
let ro = new ResizeObserver(() => {
|
|
997
1023
|
if(priv._resize_raf) {
|
|
998
1024
|
cancelAnimationFrame(priv._resize_raf);
|
|
@@ -2501,7 +2527,7 @@ function ac_show(gobj, event, kw, src)
|
|
|
2501
2527
|
refresh_tree(gobj);
|
|
2502
2528
|
|
|
2503
2529
|
if(graph) {
|
|
2504
|
-
let $canvas =
|
|
2530
|
+
let $canvas = canvas_mount(gobj);
|
|
2505
2531
|
if($canvas) {
|
|
2506
2532
|
/*
|
|
2507
2533
|
* Content box (clientWidth/Height), not getBoundingClientRect:
|
|
@@ -2534,7 +2560,7 @@ function ac_resize(gobj, event, kw, src)
|
|
|
2534
2560
|
let graph = priv.graph;
|
|
2535
2561
|
|
|
2536
2562
|
if(graph) {
|
|
2537
|
-
let $canvas =
|
|
2563
|
+
let $canvas = canvas_mount(gobj);
|
|
2538
2564
|
if($canvas) {
|
|
2539
2565
|
let cw = $canvas.clientWidth;
|
|
2540
2566
|
let ch = $canvas.clientHeight;
|
package/src/c_yui_json_graph.js
CHANGED
|
@@ -674,6 +674,30 @@ function make_toolbar(gobj)
|
|
|
674
674
|
return $toolbar;
|
|
675
675
|
}
|
|
676
676
|
|
|
677
|
+
/************************************************************
|
|
678
|
+
* The element G6 mounts its canvas in.
|
|
679
|
+
*
|
|
680
|
+
* Read from THIS gclass's own $container, never with
|
|
681
|
+
* `document.getElementById()`: a view is not always in the
|
|
682
|
+
* document when it is started -- a host that builds the
|
|
683
|
+
* viewer and mounts it into a window afterwards starts it
|
|
684
|
+
* DETACHED -- and a global lookup answers null there. It cost
|
|
685
|
+
* a resize that never worked: the ResizeObserver below was
|
|
686
|
+
* simply never attached, silently, and the canvas kept the
|
|
687
|
+
* size it was born with for the life of the window.
|
|
688
|
+
*
|
|
689
|
+
* Null only if the UI was never built; that is a bug, and it
|
|
690
|
+
* is logged where it matters rather than skipped.
|
|
691
|
+
************************************************************/
|
|
692
|
+
function canvas_mount(gobj)
|
|
693
|
+
{
|
|
694
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
695
|
+
if(!$container) {
|
|
696
|
+
return null;
|
|
697
|
+
}
|
|
698
|
+
return $container.querySelector("#" + gobj.priv.canvas_id);
|
|
699
|
+
}
|
|
700
|
+
|
|
677
701
|
/************************************************************
|
|
678
702
|
* Build a G6 graph instance
|
|
679
703
|
************************************************************/
|
|
@@ -778,8 +802,10 @@ function build_graph(gobj)
|
|
|
778
802
|
* the observed box so there is no feedback loop.
|
|
779
803
|
*/
|
|
780
804
|
if(typeof ResizeObserver !== "undefined") {
|
|
781
|
-
let $canvas =
|
|
782
|
-
if(
|
|
805
|
+
let $canvas = canvas_mount(gobj);
|
|
806
|
+
if(!$canvas) {
|
|
807
|
+
log_error(`${gobj_short_name(gobj)}: no canvas mount, the graph will never resize`);
|
|
808
|
+
} else {
|
|
783
809
|
let ro = new ResizeObserver(() => {
|
|
784
810
|
if(priv._resize_raf) {
|
|
785
811
|
cancelAnimationFrame(priv._resize_raf);
|
|
@@ -2333,7 +2359,7 @@ function ac_show(gobj, event, kw, src)
|
|
|
2333
2359
|
let graph = priv.graph;
|
|
2334
2360
|
|
|
2335
2361
|
if(graph) {
|
|
2336
|
-
let $canvas =
|
|
2362
|
+
let $canvas = canvas_mount(gobj);
|
|
2337
2363
|
if($canvas) {
|
|
2338
2364
|
/*
|
|
2339
2365
|
* Content box (clientWidth/Height), not getBoundingClientRect:
|
|
@@ -2366,7 +2392,7 @@ function ac_resize(gobj, event, kw, src)
|
|
|
2366
2392
|
let graph = priv.graph;
|
|
2367
2393
|
|
|
2368
2394
|
if(graph) {
|
|
2369
|
-
let $canvas =
|
|
2395
|
+
let $canvas = canvas_mount(gobj);
|
|
2370
2396
|
if($canvas) {
|
|
2371
2397
|
let cw = $canvas.clientWidth;
|
|
2372
2398
|
let ch = $canvas.clientHeight;
|
|
@@ -771,7 +771,14 @@ function open_json_viewer(gobj)
|
|
|
771
771
|
return;
|
|
772
772
|
}
|
|
773
773
|
priv.json_gobj = jv;
|
|
774
|
-
|
|
774
|
+
|
|
775
|
+
/* CREATED, not started. `mt_create` builds the DOM; `mt_start`
|
|
776
|
+
* RENDERS it -- and the viewer's graph view measures a canvas and
|
|
777
|
+
* puts a ResizeObserver on it, both of which need the element to be
|
|
778
|
+
* in the document, which the presenter below is what does. Started
|
|
779
|
+
* here it worked only while the reader had last used the tree view;
|
|
780
|
+
* with the graph view remembered it built detached, attached no
|
|
781
|
+
* observer, and the canvas never followed the window again. */
|
|
775
782
|
let $box = gobj_read_pointer_attr(jv, "$container");
|
|
776
783
|
|
|
777
784
|
if(mobile) {
|
|
@@ -793,6 +800,7 @@ function open_json_viewer(gobj)
|
|
|
793
800
|
gobj_send_event(gobj, "EV_JSON_CLOSED", {}, gobj);
|
|
794
801
|
}
|
|
795
802
|
});
|
|
803
|
+
gobj_start(jv); /* mounted: now it can measure itself */
|
|
796
804
|
} else {
|
|
797
805
|
let $win_parent = (shell && yui_shell_popup_layer(shell)) ||
|
|
798
806
|
(typeof document !== "undefined" && document.getElementById("top-layer")) ||
|
|
@@ -833,6 +841,7 @@ function open_json_viewer(gobj)
|
|
|
833
841
|
return;
|
|
834
842
|
}
|
|
835
843
|
gobj_start(priv.json_win);
|
|
844
|
+
gobj_start(jv); /* mounted: now it can measure itself */
|
|
836
845
|
}
|
|
837
846
|
|
|
838
847
|
request_print_tranger(gobj, ""); /* first fetch: whole tranger, collapsed */
|
|
@@ -877,11 +886,16 @@ function close_json_viewer(gobj)
|
|
|
877
886
|
}
|
|
878
887
|
if(jv && is_gobj(jv)) {
|
|
879
888
|
try {
|
|
880
|
-
/* STOP, then destroy
|
|
881
|
-
*
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
|
|
889
|
+
/* STOP, then destroy: gobj_destroy() raises the `destroying`
|
|
890
|
+
* flag before it can stop a running gobj, so destroying it
|
|
891
|
+
* straight logs "Destroying a RUNNING gobj" + "gobj NULL or
|
|
892
|
+
* DESTROYED" and skips its mt_stop. GUARDED, because the
|
|
893
|
+
* viewer is now started AFTER its presenter is up: the two
|
|
894
|
+
* failure paths that get here arrive with it created and
|
|
895
|
+
* never started. */
|
|
896
|
+
if(gobj_is_running(jv)) {
|
|
897
|
+
gobj_stop(jv);
|
|
898
|
+
}
|
|
885
899
|
gobj_destroy(jv);
|
|
886
900
|
} catch(e) {
|
|
887
901
|
log_warning(`${gobj_short_name(gobj)}: already gone: ${e}`);
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/***********************************************************************
|
|
2
|
+
* dev_machine_trace.js
|
|
3
|
+
*
|
|
4
|
+
* Reading a MACHINE trace line back.
|
|
5
|
+
*
|
|
6
|
+
* The developer window mirrors the runtime's log, and the
|
|
7
|
+
* `machine` trace is most of what lands there once it is on.
|
|
8
|
+
* Those lines arrive as text, so to the window they were just
|
|
9
|
+
* "a debug log" -- which is why its `Periodic` filter could
|
|
10
|
+
* not touch them: the filter works on a signature, and every
|
|
11
|
+
* mirrored log carried the same one (`log:debug`).
|
|
12
|
+
*
|
|
13
|
+
* This gives a machine line back its EVENT, which is the only
|
|
14
|
+
* thing that says whether it is noise. Both formats gobj-js
|
|
15
|
+
* emits (`gobj_set_trace_machine_format`):
|
|
16
|
+
*
|
|
17
|
+
* 0 verbose "🔄 mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ac: …"
|
|
18
|
+
* "<- mach(C_TIMER^t), st: ST_IDLE, ev: EV_TIMEOUT, ret: 0"
|
|
19
|
+
* 1 compact "🔄 EV_TIMEOUT C_TIMER^t ST_IDLE from C_TIMER^t"
|
|
20
|
+
*
|
|
21
|
+
* Copyright (c) 2026, ArtGins.
|
|
22
|
+
* All Rights Reserved.
|
|
23
|
+
***********************************************************************/
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
/* The verbose format names itself; the compact one does not. */
|
|
27
|
+
const MACHINE_MARK_RE = /\bmach\(/;
|
|
28
|
+
|
|
29
|
+
/* Verbose: the event is the `ev:` field. */
|
|
30
|
+
const EVENT_FIELD_RE = /\bev:\s*([A-Za-z0-9_]+)/;
|
|
31
|
+
|
|
32
|
+
/* Compact: the event is the first token, behind the emoji. Anchored,
|
|
33
|
+
* so a line that merely MENTIONS an event ("subscribed to EV_X") is
|
|
34
|
+
* not mistaken for a transition. */
|
|
35
|
+
const EVENT_HEAD_RE = /^\s*\S{0,4}\s*(EV_[A-Za-z0-9_]+)(?=\s|$)/;
|
|
36
|
+
|
|
37
|
+
/* What "recurring" means by name. The count-based half of the filter
|
|
38
|
+
* lives in the window, which is the only thing that can count. */
|
|
39
|
+
const PERIODIC_EVENT_RE = /PERIODIC|TIMEOUT|HEARTBEAT|PING|POLL/i;
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
/************************************************************
|
|
43
|
+
* The event of a machine trace line, or "" when the line is
|
|
44
|
+
* not one.
|
|
45
|
+
*
|
|
46
|
+
* "" is also the answer for a machine line that carries no
|
|
47
|
+
* event -- a state change ("new st(…), prev st(…)") -- and
|
|
48
|
+
* that is right: what it reports is not repetitive.
|
|
49
|
+
************************************************************/
|
|
50
|
+
function machine_event_of(text)
|
|
51
|
+
{
|
|
52
|
+
if(typeof text !== "string" || text.length === 0) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if(MACHINE_MARK_RE.test(text)) {
|
|
57
|
+
let m = EVENT_FIELD_RE.exec(text);
|
|
58
|
+
return m? m[1]: "";
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
let m = EVENT_HEAD_RE.exec(text);
|
|
62
|
+
return m? m[1]: "";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/************************************************************
|
|
66
|
+
* Is this event one of the ones that arrive by themselves,
|
|
67
|
+
* for ever, and say nothing about what the app is doing?
|
|
68
|
+
************************************************************/
|
|
69
|
+
function is_periodic_event(event_name)
|
|
70
|
+
{
|
|
71
|
+
if(!event_name) {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
return PERIODIC_EVENT_RE.test(event_name);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/************************************************************
|
|
78
|
+
* The signature of a mirrored log line: what the window
|
|
79
|
+
* counts it under and what its filters match on.
|
|
80
|
+
*
|
|
81
|
+
* A machine line is signed by its EVENT, so a hundred
|
|
82
|
+
* EV_TIMEOUTs are one recurring thing rather than a hundred
|
|
83
|
+
* anonymous debug lines. Everything else is signed by its
|
|
84
|
+
* level, as before.
|
|
85
|
+
************************************************************/
|
|
86
|
+
function log_signature(level, text)
|
|
87
|
+
{
|
|
88
|
+
let event = machine_event_of(text);
|
|
89
|
+
if(event) {
|
|
90
|
+
return "mach:" + event;
|
|
91
|
+
}
|
|
92
|
+
return "log:" + (level || "debug");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/************************************************************
|
|
96
|
+
* May the periodic filter hide this log line?
|
|
97
|
+
*
|
|
98
|
+
* Only a machine transition, and only below warning level.
|
|
99
|
+
* An ERROR that names EV_TIMEOUT -- "Event NOT DEFINED in
|
|
100
|
+
* state", which is exactly the loud one the framework wants
|
|
101
|
+
* seen -- must never disappear because of the word in it.
|
|
102
|
+
************************************************************/
|
|
103
|
+
function log_is_periodic(level, text)
|
|
104
|
+
{
|
|
105
|
+
if(level === "error" || level === "warning") {
|
|
106
|
+
return false;
|
|
107
|
+
}
|
|
108
|
+
return is_periodic_event(machine_event_of(text));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export {
|
|
112
|
+
machine_event_of,
|
|
113
|
+
is_periodic_event,
|
|
114
|
+
log_signature,
|
|
115
|
+
log_is_periodic,
|
|
116
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {describe, it, expect} from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
machine_event_of,
|
|
4
|
+
is_periodic_event,
|
|
5
|
+
log_signature,
|
|
6
|
+
log_is_periodic,
|
|
7
|
+
} from "./dev_machine_trace.js";
|
|
8
|
+
|
|
9
|
+
/* Real lines, copied from the developer window. */
|
|
10
|
+
const VERBOSE_IN =
|
|
11
|
+
"🔄 mach(C_TIMER^demo_yuno), st: ST_IDLE, ev: EV_TIMEOUT, ac: fi(), from(C_TIMER^demo_yuno)";
|
|
12
|
+
const VERBOSE_RET =
|
|
13
|
+
"<- mach(C_YUNO^demo_yuno), st: ST_IDLE, ev: EV_TIMEOUT_PERIODIC, ret: 0";
|
|
14
|
+
const VERBOSE_WORK =
|
|
15
|
+
"🔄 mach(C_YUI_SHELL^shell), st: ST_IDLE, ev: EV_ROUTE_CHANGED, ac: ac_route(), from(C_YUI_NAV^nav)";
|
|
16
|
+
const COMPACT =
|
|
17
|
+
"🔄 EV_TIMEOUT C_TIMER^demo_yuno ST_IDLE from C_TIMER^demo_yuno";
|
|
18
|
+
const STATE_CHANGE =
|
|
19
|
+
"🔀🔀 mach(C_TCP^conn), new st(ST_CONNECTED), prev st(ST_WAIT_CONNECTED)";
|
|
20
|
+
const NOT_DEFINED =
|
|
21
|
+
"📛 mach(C_X^x), st: ST_IDLE, ev: EV_TIMEOUT, 📛📛ERROR Event NOT DEFINED in state📛📛, from(C_TIMER^t)";
|
|
22
|
+
|
|
23
|
+
describe("machine_event_of", () => {
|
|
24
|
+
it("reads the event out of the verbose format, both lines of it", () => {
|
|
25
|
+
expect(machine_event_of(VERBOSE_IN)).toBe("EV_TIMEOUT");
|
|
26
|
+
expect(machine_event_of(VERBOSE_RET)).toBe("EV_TIMEOUT_PERIODIC");
|
|
27
|
+
expect(machine_event_of(VERBOSE_WORK)).toBe("EV_ROUTE_CHANGED");
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it("reads it out of the compact format, where it leads the line", () => {
|
|
31
|
+
expect(machine_event_of(COMPACT)).toBe("EV_TIMEOUT");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("a state change carries no event, and says so", () => {
|
|
35
|
+
expect(machine_event_of(STATE_CHANGE)).toBe("");
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it("a line that merely MENTIONS an event is not a transition", () => {
|
|
39
|
+
expect(machine_event_of("subscribed to EV_TIMEOUT of C_TIMER^t")).toBe("");
|
|
40
|
+
expect(machine_event_of("cannot send EV_ON_OPEN")).toBe("");
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("is safe on anything that is not a line", () => {
|
|
44
|
+
expect(machine_event_of("")).toBe("");
|
|
45
|
+
expect(machine_event_of(null)).toBe("");
|
|
46
|
+
expect(machine_event_of(undefined)).toBe("");
|
|
47
|
+
expect(machine_event_of(42)).toBe("");
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe("is_periodic_event", () => {
|
|
52
|
+
it("names the events that arrive by themselves for ever", () => {
|
|
53
|
+
expect(is_periodic_event("EV_TIMEOUT")).toBe(true);
|
|
54
|
+
expect(is_periodic_event("EV_TIMEOUT_PERIODIC")).toBe(true);
|
|
55
|
+
expect(is_periodic_event("EV_HEARTBEAT")).toBe(true);
|
|
56
|
+
expect(is_periodic_event("EV_PING")).toBe(true);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it("leaves the ones a user caused alone", () => {
|
|
60
|
+
expect(is_periodic_event("EV_ROUTE_CHANGED")).toBe(false);
|
|
61
|
+
expect(is_periodic_event("EV_ON_MESSAGE")).toBe(false);
|
|
62
|
+
expect(is_periodic_event("")).toBe(false);
|
|
63
|
+
expect(is_periodic_event(null)).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
describe("log_signature", () => {
|
|
68
|
+
it("signs a machine line by its EVENT, so a hundred of them are one thing", () => {
|
|
69
|
+
expect(log_signature("debug", VERBOSE_IN)).toBe("mach:EV_TIMEOUT");
|
|
70
|
+
expect(log_signature("debug", VERBOSE_RET)).toBe("mach:EV_TIMEOUT_PERIODIC");
|
|
71
|
+
expect(log_signature("debug", COMPACT)).toBe("mach:EV_TIMEOUT");
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("signs everything else by its level, as before", () => {
|
|
75
|
+
expect(log_signature("error", "connect failed")).toBe("log:error");
|
|
76
|
+
expect(log_signature("debug", "hello")).toBe("log:debug");
|
|
77
|
+
expect(log_signature("", "hello")).toBe("log:debug");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("log_is_periodic", () => {
|
|
82
|
+
it("hides the timer traffic the filter is for", () => {
|
|
83
|
+
expect(log_is_periodic("debug", VERBOSE_IN)).toBe(true);
|
|
84
|
+
expect(log_is_periodic("debug", VERBOSE_RET)).toBe(true);
|
|
85
|
+
expect(log_is_periodic("debug", COMPACT)).toBe(true);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it("NEVER hides an error or a warning that names a timeout", () => {
|
|
89
|
+
expect(log_is_periodic("error", NOT_DEFINED)).toBe(false);
|
|
90
|
+
expect(log_is_periodic("warning", VERBOSE_RET)).toBe(false);
|
|
91
|
+
expect(log_is_periodic("error", "connection timeout")).toBe(false);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("leaves a transition somebody caused alone", () => {
|
|
95
|
+
expect(log_is_periodic("debug", VERBOSE_WORK)).toBe(false);
|
|
96
|
+
expect(log_is_periodic("debug", "just a log line")).toBe(false);
|
|
97
|
+
});
|
|
98
|
+
});
|
package/src/yui_dev.js
CHANGED
|
@@ -21,6 +21,8 @@ import {
|
|
|
21
21
|
gobj_set_trace_machine_format,
|
|
22
22
|
} from "@yuneta/gobj-js";
|
|
23
23
|
|
|
24
|
+
import {log_signature, log_is_periodic} from "./dev_machine_trace.js";
|
|
25
|
+
|
|
24
26
|
import i18next from 'i18next';
|
|
25
27
|
|
|
26
28
|
/***********************************************************************
|
|
@@ -164,9 +166,20 @@ function dev_view()
|
|
|
164
166
|
return (v === "compact" || v === "name" || v === "full") ? v : "detailed";
|
|
165
167
|
}
|
|
166
168
|
|
|
169
|
+
/* ON by default. The machine trace is the reason this window
|
|
170
|
+
* exists, and a yuno with one timer emits two lines a second for
|
|
171
|
+
* ever: leaving the filter off meant the first thing anybody saw
|
|
172
|
+
* after enabling Automata was a wall of EV_TIMEOUT with their own
|
|
173
|
+
* transitions somewhere inside it. The chip turns it back off.
|
|
174
|
+
*
|
|
175
|
+
* A CONSTANT, and not the literal in two places: the reader and the
|
|
176
|
+
* toggle must agree on what "unset" means, or the first click on the
|
|
177
|
+
* chip writes the value it already had and appears to do nothing. */
|
|
178
|
+
const HIDE_PERIODIC_DEFAULT = 1;
|
|
179
|
+
|
|
167
180
|
function dev_hide_periodic()
|
|
168
181
|
{
|
|
169
|
-
return dev_num("dev_hide_periodic",
|
|
182
|
+
return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
|
|
170
183
|
}
|
|
171
184
|
|
|
172
185
|
/* Where dev output (traffic + all logs + automata) is routed:
|
|
@@ -300,7 +313,21 @@ function entry_hidden(e, ctx)
|
|
|
300
313
|
{
|
|
301
314
|
if(e.kind === "log") {
|
|
302
315
|
/* Mirrored console logs respect the search box only — not the
|
|
303
|
-
* in/out/err
|
|
316
|
+
* in/out/err traffic filters, which are about DIRECTION and a
|
|
317
|
+
* log has none.
|
|
318
|
+
*
|
|
319
|
+
* The PERIODIC filter does reach them, and it has to: once
|
|
320
|
+
* Automata is on, the machine trace is what floods this
|
|
321
|
+
* window, and every one of those lines arrives here as a log.
|
|
322
|
+
* It applies to a machine TRANSITION only, and never above
|
|
323
|
+
* debug level — see log_is_periodic(). By NAME and not by
|
|
324
|
+
* count, unlike the traffic half below: a busy FSM crosses
|
|
325
|
+
* the recurrence threshold on almost every event within
|
|
326
|
+
* seconds, so counting here would empty the window of the
|
|
327
|
+
* very transitions somebody turned Automata on to read. */
|
|
328
|
+
if(ctx.hide_periodic && e.periodic) {
|
|
329
|
+
return true;
|
|
330
|
+
}
|
|
304
331
|
return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
|
|
305
332
|
}
|
|
306
333
|
if(e.dir === 1 && !ctx.out) {
|
|
@@ -1031,10 +1058,16 @@ function info_log(level, msg, hora)
|
|
|
1031
1058
|
} else {
|
|
1032
1059
|
text = is_string(msg) ? msg : String(msg);
|
|
1033
1060
|
}
|
|
1061
|
+
/* A machine line is signed by its EVENT, not by "log:debug":
|
|
1062
|
+
* that is what makes a hundred EV_TIMEOUTs ONE recurring
|
|
1063
|
+
* thing the filter and the counter can see, instead of a
|
|
1064
|
+
* hundred anonymous debug lines they cannot tell apart. */
|
|
1034
1065
|
let entry = {
|
|
1035
1066
|
kind: "log", level: lvl, text: text,
|
|
1036
1067
|
dir: 0, size: 0, ts: traffic_now(),
|
|
1037
|
-
sig:
|
|
1068
|
+
sig: log_signature(lvl, text),
|
|
1069
|
+
periodic: log_is_periodic(lvl, text),
|
|
1070
|
+
hay: (lvl + " " + text).toLowerCase(), $node: null,
|
|
1038
1071
|
};
|
|
1039
1072
|
TRAFFIC_LOG.push(entry);
|
|
1040
1073
|
if(TRAFFIC_LOG.length > TRAFFIC_MAX) {
|
|
@@ -1384,11 +1417,12 @@ function build_control_bar()
|
|
|
1384
1417
|
|
|
1385
1418
|
let periodic_chip = ['button', {
|
|
1386
1419
|
class: 'YDEV_CHIP', 'data-toggle': 'periodic', type: 'button',
|
|
1387
|
-
title: 'Hide
|
|
1420
|
+
title: 'Hide the timers: EV_TIMEOUT / PERIODIC / HEARTBEAT / PING ' +
|
|
1421
|
+
'transitions, and recurring traffic. On by default',
|
|
1388
1422
|
}, '⊘ Periodic', {
|
|
1389
1423
|
click: (ev) => {
|
|
1390
1424
|
ev.stopPropagation();
|
|
1391
|
-
toggle_pref('dev_hide_periodic',
|
|
1425
|
+
toggle_pref('dev_hide_periodic', HIDE_PERIODIC_DEFAULT);
|
|
1392
1426
|
}
|
|
1393
1427
|
}];
|
|
1394
1428
|
|
package/src/yui_gclass_view.js
CHANGED
|
@@ -115,8 +115,19 @@ function open_gclass_view(host, gclass_name, opts)
|
|
|
115
115
|
log_error(`${gobj_short_name(host)}: cannot create the gclass viewer`);
|
|
116
116
|
return null;
|
|
117
117
|
}
|
|
118
|
-
gobj_start(jv);
|
|
119
118
|
|
|
119
|
+
/* CREATED, not started. `mt_create` builds the DOM; `mt_start`
|
|
120
|
+
* RENDERS it -- and the viewer's graph view measures a canvas and
|
|
121
|
+
* puts a ResizeObserver on it, both of which need the element to be
|
|
122
|
+
* in the document. The window below is what puts it there, so the
|
|
123
|
+
* start goes after the window, at the bottom of this function.
|
|
124
|
+
*
|
|
125
|
+
* Starting it here worked for as long as the reader had last used
|
|
126
|
+
* the tree view: the graph is built on first entry, which was after
|
|
127
|
+
* the window. The moment the viewer REMEMBERED the graph view, it
|
|
128
|
+
* built it inside mt_start, detached, found no mount, attached no
|
|
129
|
+
* observer -- and the canvas kept its birth size for the life of
|
|
130
|
+
* the window while the window resized around it. */
|
|
120
131
|
let handle = {json_gobj: jv, win: null, modal: null};
|
|
121
132
|
let $box = gobj_read_pointer_attr(jv, "$container");
|
|
122
133
|
|
|
@@ -140,6 +151,7 @@ function open_gclass_view(host, gclass_name, opts)
|
|
|
140
151
|
t: t,
|
|
141
152
|
on_close: on_close,
|
|
142
153
|
});
|
|
154
|
+
gobj_start(jv); /* mounted: now it can measure itself */
|
|
143
155
|
return handle;
|
|
144
156
|
}
|
|
145
157
|
|
|
@@ -180,6 +192,7 @@ function open_gclass_view(host, gclass_name, opts)
|
|
|
180
192
|
return null;
|
|
181
193
|
}
|
|
182
194
|
gobj_start(handle.win);
|
|
195
|
+
gobj_start(jv); /* mounted: now it can measure itself */
|
|
183
196
|
|
|
184
197
|
return handle;
|
|
185
198
|
}
|