@yuneta/gobj-ui 7.23.32 → 7.23.34

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.
@@ -32,6 +32,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
32
32
  }) : target, mod));
33
33
  //#endregion
34
34
  let _yuneta_gobj_js = require("@yuneta/gobj-js");
35
+ _yuneta_gobj_js = __toESM(_yuneta_gobj_js, 1);
35
36
  let i18next = require("i18next");
36
37
  i18next = __toESM(i18next, 1);
37
38
  let tom_select = require("tom-select");
@@ -64309,6 +64310,10 @@ function dev_view() {
64309
64310
  return v === "compact" || v === "name" || v === "full" ? v : "detailed";
64310
64311
  }
64311
64312
  var HIDE_PERIODIC_DEFAULT = 1;
64313
+ var SIMPLE_MACH_DEFAULT = 1;
64314
+ function dev_simple_mach() {
64315
+ return dev_num("dev_automata_simple", SIMPLE_MACH_DEFAULT) ? 1 : 0;
64316
+ }
64312
64317
  function dev_hide_periodic() {
64313
64318
  return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
64314
64319
  }
@@ -64318,7 +64323,16 @@ function dev_route() {
64318
64323
  }
64319
64324
  function apply_console_route() {
64320
64325
  (0, _yuneta_gobj_js.set_console_log_enabled)(dev_route() !== "window");
64326
+ if (typeof _yuneta_gobj_js.set_console_log_filter === "function") _yuneta_gobj_js.set_console_log_filter((level, msg) => {
64327
+ if (!dev_hide_periodic()) return true;
64328
+ return !log_is_periodic(level, (0, _yuneta_gobj_js.is_string)(msg) ? msg : String(msg));
64329
+ });
64330
+ else if (!__console_filter_warned__) {
64331
+ __console_filter_warned__ = true;
64332
+ console.warn("yui_dev: gobj-js has no set_console_log_filter (needs >= 7.13.6): the Periodic filter applies to this window only, not to the console");
64333
+ }
64321
64334
  }
64335
+ var __console_filter_warned__ = false;
64322
64336
  function console_traffic(title, jn, direction, size) {
64323
64337
  let event = jn && jn.event ? String(jn.event) : "(no event)";
64324
64338
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : jn;
@@ -64348,6 +64362,7 @@ function set_output_route(v) {
64348
64362
  function toggle_pref(key, def) {
64349
64363
  let v = dev_num(key, def) ? 0 : 1;
64350
64364
  (0, _yuneta_gobj_js.kw_set_local_storage_value)(key, v);
64365
+ apply_console_route();
64351
64366
  rerender_all();
64352
64367
  refresh_dev_chrome();
64353
64368
  }
@@ -64876,7 +64891,7 @@ function render_name(e) {
64876
64891
  ]);
64877
64892
  }
64878
64893
  function render_log(e) {
64879
- return (0, _yuneta_gobj_js.createElement2)([
64894
+ let $row = (0, _yuneta_gobj_js.createElement2)([
64880
64895
  "div",
64881
64896
  {
64882
64897
  class: "YDEV_LOGROW YDEV_LOG_" + e.level,
@@ -64891,7 +64906,7 @@ function render_log(e) {
64891
64906
  [
64892
64907
  "span",
64893
64908
  { class: "YDEV_LOG_TXT" },
64894
- e.text
64909
+ ""
64895
64910
  ],
64896
64911
  [
64897
64912
  "span",
@@ -64900,6 +64915,9 @@ function render_log(e) {
64900
64915
  ]
64901
64916
  ]
64902
64917
  ]);
64918
+ let $txt = $row.querySelector(".YDEV_LOG_TXT");
64919
+ if ($txt) $txt.textContent = e.text;
64920
+ return $row;
64903
64921
  }
64904
64922
  function render_entry(e) {
64905
64923
  if (e.kind === "log") return render_log(e);
@@ -64938,15 +64956,28 @@ function rerender_all() {
64938
64956
  }
64939
64957
  }
64940
64958
  logger.replaceChildren(frag);
64941
- if (shown === 0) {
64942
- let $empty = document.createElement("div");
64943
- $empty.className = "YDEV_EMPTY";
64944
- $empty.textContent = TRAFFIC_LOG.length ? "No messages match the current filters." : "Waiting for activity — console logs and errors show automatically; enable Traffic or Automata for more.";
64945
- logger.appendChild($empty);
64946
- }
64959
+ if (shown === 0) logger.appendChild(make_placeholder());
64947
64960
  logger.scrollTop = logger.scrollHeight;
64948
64961
  update_stats();
64949
64962
  }
64963
+ function make_placeholder() {
64964
+ let $empty = document.createElement("div");
64965
+ $empty.className = "YDEV_EMPTY";
64966
+ $empty.textContent = placeholder_text();
64967
+ return $empty;
64968
+ }
64969
+ function placeholder_text() {
64970
+ if (TRAFFIC_LOG.length) return "No messages match the current filters.";
64971
+ return "Waiting for activity — console logs and errors show automatically; enable Traffic or Automata for more.";
64972
+ }
64973
+ function refresh_placeholder() {
64974
+ let logger = document.getElementById("developer-traffic-logger");
64975
+ if (!logger) return;
64976
+ let ph = logger.querySelector(".YDEV_EMPTY");
64977
+ if (!ph) return;
64978
+ let text = placeholder_text();
64979
+ if (ph.textContent !== text) ph.textContent = text;
64980
+ }
64950
64981
  function update_stats() {
64951
64982
  let $s = document.getElementById("ydev-stats");
64952
64983
  if (!$s) return;
@@ -65050,7 +65081,7 @@ function info_traffic(title, msg, direction, size) {
65050
65081
  let ph = logger.querySelector(".YDEV_EMPTY");
65051
65082
  if (ph) ph.remove();
65052
65083
  append_and_follow(logger, node);
65053
- }
65084
+ } else refresh_placeholder();
65054
65085
  update_stats();
65055
65086
  }
65056
65087
  var __in_info_log__ = false;
@@ -65111,7 +65142,7 @@ function info_log(level, msg, hora) {
65111
65142
  let ph = logger.querySelector(".YDEV_EMPTY");
65112
65143
  if (ph) ph.remove();
65113
65144
  append_and_follow(logger, node);
65114
- }
65145
+ } else refresh_placeholder();
65115
65146
  update_stats();
65116
65147
  } finally {
65117
65148
  __in_info_log__ = false;
@@ -65208,7 +65239,7 @@ function refresh_dev_chrome() {
65208
65239
  $b.classList.toggle("is-active", dev_hide_periodic());
65209
65240
  });
65210
65241
  document.querySelectorAll(".YDEV_CHIP[data-toggle=\"automata-simple\"]").forEach(($b) => {
65211
- $b.classList.toggle("is-active", !!dev_num("dev_automata_simple", 0));
65242
+ $b.classList.toggle("is-active", !!dev_simple_mach());
65212
65243
  });
65213
65244
  let $m = document.getElementById("ydev-muted");
65214
65245
  if ($m) {
@@ -65300,12 +65331,12 @@ function build_control_bar() {
65300
65331
  class: "YDEV_CHIP",
65301
65332
  "data-toggle": "automata-simple",
65302
65333
  type: "button",
65303
- title: "Compact automata format (one line per transition, like C)"
65334
+ title: "Machine trace shape. On (default): one line per transition, event first, like the C kernel. Off: the legacy three-line shape (the call, the state change and the return)"
65304
65335
  },
65305
65336
  "Simple mach",
65306
65337
  { click: (ev) => {
65307
65338
  ev.stopPropagation();
65308
- let v = dev_num("dev_automata_simple", 0) ? 0 : 1;
65339
+ let v = dev_simple_mach() ? 0 : 1;
65309
65340
  (0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_automata_simple", v);
65310
65341
  (0, _yuneta_gobj_js.gobj_set_trace_machine_format)(v);
65311
65342
  refresh_dev_chrome();
@@ -65595,7 +65626,7 @@ function apply_dev_traces() {
65595
65626
  (0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "trace_subscriptions", subscriptions);
65596
65627
  (0, _yuneta_gobj_js.gobj_write_attr)((0, _yuneta_gobj_js.gobj_yuno)(), "no_poll", no_poll);
65597
65628
  i18next.default.options.debug = i18n ? true : false;
65598
- (0, _yuneta_gobj_js.gobj_set_trace_machine_format)(Number((0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_automata_simple", 0, false)) ? 1 : 0);
65629
+ (0, _yuneta_gobj_js.gobj_set_trace_machine_format)(dev_simple_mach());
65599
65630
  (0, _yuneta_gobj_js.set_log_callback)(info_log);
65600
65631
  apply_console_route();
65601
65632
  }
@@ -1,3 +1,4 @@
1
+ import * as gobj_js from "@yuneta/gobj-js";
1
2
  import { SDATA, SDATA_END, clean_name, createElement2, createOneHtml, create_template_record, data_type_t, debounce, duplicate_objects, empty_string, escapeHtml, event_flag_t, gclass_create, gclass_find_by_name, gclass_flag_t, getPositionRelativeToBody, gobj_bottom_gobj, gobj_change_state, gobj_command, gobj_create, gobj_create_pure_child, gobj_create_service, gobj_current_state, gobj_destroy, gobj_find_child, gobj_find_service, gobj_full_name, gobj_gclass_name, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_match_children, gobj_name, gobj_parent, gobj_post_event, gobj_publish_event, gobj_read_attr, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_save_persistent_attrs, gobj_send_event, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_tree, gobj_stop, gobj_stop_children, gobj_subscribe_event, gobj_unsubscribe_event, gobj_write_attr, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_name, is_array, is_boolean, is_date, is_gobj, is_null, is_number, is_object, is_string, json_deep_copy, json_object_size, json_object_update, json_object_update_missing, json_size, kw_clone_by_keys, kw_flag_t, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_local_storage_value, kw_get_str, kw_has_key, kw_set_dict_value, kw_set_local_storage_value, kwid_find_one_record, kwid_get_ids, kwid_new_dict, log_error, log_warning, msg_iev_get_stack, parseBoolean, parseSVG, refresh_language, safeSrc, sdata_flag_t, set_console_log_enabled, set_log_callback, sprintf, str_in_list, template_get_field_desc, trace_msg, treedb_decoder_fkey, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size } from "@yuneta/gobj-js";
2
3
  import i18next, { t } from "i18next";
3
4
  import TomSelect from "tom-select";
@@ -64304,6 +64305,10 @@ function dev_view() {
64304
64305
  return v === "compact" || v === "name" || v === "full" ? v : "detailed";
64305
64306
  }
64306
64307
  var HIDE_PERIODIC_DEFAULT = 1;
64308
+ var SIMPLE_MACH_DEFAULT = 1;
64309
+ function dev_simple_mach() {
64310
+ return dev_num("dev_automata_simple", SIMPLE_MACH_DEFAULT) ? 1 : 0;
64311
+ }
64307
64312
  function dev_hide_periodic() {
64308
64313
  return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
64309
64314
  }
@@ -64313,7 +64318,16 @@ function dev_route() {
64313
64318
  }
64314
64319
  function apply_console_route() {
64315
64320
  set_console_log_enabled(dev_route() !== "window");
64321
+ if (typeof gobj_js.set_console_log_filter === "function") gobj_js.set_console_log_filter((level, msg) => {
64322
+ if (!dev_hide_periodic()) return true;
64323
+ return !log_is_periodic(level, is_string(msg) ? msg : String(msg));
64324
+ });
64325
+ else if (!__console_filter_warned__) {
64326
+ __console_filter_warned__ = true;
64327
+ console.warn("yui_dev: gobj-js has no set_console_log_filter (needs >= 7.13.6): the Periodic filter applies to this window only, not to the console");
64328
+ }
64316
64329
  }
64330
+ var __console_filter_warned__ = false;
64317
64331
  function console_traffic(title, jn, direction, size) {
64318
64332
  let event = jn && jn.event ? String(jn.event) : "(no event)";
64319
64333
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : jn;
@@ -64343,6 +64357,7 @@ function set_output_route(v) {
64343
64357
  function toggle_pref(key, def) {
64344
64358
  let v = dev_num(key, def) ? 0 : 1;
64345
64359
  kw_set_local_storage_value(key, v);
64360
+ apply_console_route();
64346
64361
  rerender_all();
64347
64362
  refresh_dev_chrome();
64348
64363
  }
@@ -64871,7 +64886,7 @@ function render_name(e) {
64871
64886
  ]);
64872
64887
  }
64873
64888
  function render_log(e) {
64874
- return createElement2([
64889
+ let $row = createElement2([
64875
64890
  "div",
64876
64891
  {
64877
64892
  class: "YDEV_LOGROW YDEV_LOG_" + e.level,
@@ -64886,7 +64901,7 @@ function render_log(e) {
64886
64901
  [
64887
64902
  "span",
64888
64903
  { class: "YDEV_LOG_TXT" },
64889
- e.text
64904
+ ""
64890
64905
  ],
64891
64906
  [
64892
64907
  "span",
@@ -64895,6 +64910,9 @@ function render_log(e) {
64895
64910
  ]
64896
64911
  ]
64897
64912
  ]);
64913
+ let $txt = $row.querySelector(".YDEV_LOG_TXT");
64914
+ if ($txt) $txt.textContent = e.text;
64915
+ return $row;
64898
64916
  }
64899
64917
  function render_entry(e) {
64900
64918
  if (e.kind === "log") return render_log(e);
@@ -64933,15 +64951,28 @@ function rerender_all() {
64933
64951
  }
64934
64952
  }
64935
64953
  logger.replaceChildren(frag);
64936
- if (shown === 0) {
64937
- let $empty = document.createElement("div");
64938
- $empty.className = "YDEV_EMPTY";
64939
- $empty.textContent = TRAFFIC_LOG.length ? "No messages match the current filters." : "Waiting for activity — console logs and errors show automatically; enable Traffic or Automata for more.";
64940
- logger.appendChild($empty);
64941
- }
64954
+ if (shown === 0) logger.appendChild(make_placeholder());
64942
64955
  logger.scrollTop = logger.scrollHeight;
64943
64956
  update_stats();
64944
64957
  }
64958
+ function make_placeholder() {
64959
+ let $empty = document.createElement("div");
64960
+ $empty.className = "YDEV_EMPTY";
64961
+ $empty.textContent = placeholder_text();
64962
+ return $empty;
64963
+ }
64964
+ function placeholder_text() {
64965
+ if (TRAFFIC_LOG.length) return "No messages match the current filters.";
64966
+ return "Waiting for activity — console logs and errors show automatically; enable Traffic or Automata for more.";
64967
+ }
64968
+ function refresh_placeholder() {
64969
+ let logger = document.getElementById("developer-traffic-logger");
64970
+ if (!logger) return;
64971
+ let ph = logger.querySelector(".YDEV_EMPTY");
64972
+ if (!ph) return;
64973
+ let text = placeholder_text();
64974
+ if (ph.textContent !== text) ph.textContent = text;
64975
+ }
64945
64976
  function update_stats() {
64946
64977
  let $s = document.getElementById("ydev-stats");
64947
64978
  if (!$s) return;
@@ -65045,7 +65076,7 @@ function info_traffic(title, msg, direction, size) {
65045
65076
  let ph = logger.querySelector(".YDEV_EMPTY");
65046
65077
  if (ph) ph.remove();
65047
65078
  append_and_follow(logger, node);
65048
- }
65079
+ } else refresh_placeholder();
65049
65080
  update_stats();
65050
65081
  }
65051
65082
  var __in_info_log__ = false;
@@ -65106,7 +65137,7 @@ function info_log(level, msg, hora) {
65106
65137
  let ph = logger.querySelector(".YDEV_EMPTY");
65107
65138
  if (ph) ph.remove();
65108
65139
  append_and_follow(logger, node);
65109
- }
65140
+ } else refresh_placeholder();
65110
65141
  update_stats();
65111
65142
  } finally {
65112
65143
  __in_info_log__ = false;
@@ -65203,7 +65234,7 @@ function refresh_dev_chrome() {
65203
65234
  $b.classList.toggle("is-active", dev_hide_periodic());
65204
65235
  });
65205
65236
  document.querySelectorAll(".YDEV_CHIP[data-toggle=\"automata-simple\"]").forEach(($b) => {
65206
- $b.classList.toggle("is-active", !!dev_num("dev_automata_simple", 0));
65237
+ $b.classList.toggle("is-active", !!dev_simple_mach());
65207
65238
  });
65208
65239
  let $m = document.getElementById("ydev-muted");
65209
65240
  if ($m) {
@@ -65295,12 +65326,12 @@ function build_control_bar() {
65295
65326
  class: "YDEV_CHIP",
65296
65327
  "data-toggle": "automata-simple",
65297
65328
  type: "button",
65298
- title: "Compact automata format (one line per transition, like C)"
65329
+ title: "Machine trace shape. On (default): one line per transition, event first, like the C kernel. Off: the legacy three-line shape (the call, the state change and the return)"
65299
65330
  },
65300
65331
  "Simple mach",
65301
65332
  { click: (ev) => {
65302
65333
  ev.stopPropagation();
65303
- let v = dev_num("dev_automata_simple", 0) ? 0 : 1;
65334
+ let v = dev_simple_mach() ? 0 : 1;
65304
65335
  kw_set_local_storage_value("dev_automata_simple", v);
65305
65336
  gobj_set_trace_machine_format(v);
65306
65337
  refresh_dev_chrome();
@@ -65590,7 +65621,7 @@ function apply_dev_traces() {
65590
65621
  gobj_write_attr(gobj_yuno(), "trace_subscriptions", subscriptions);
65591
65622
  gobj_write_attr(gobj_yuno(), "no_poll", no_poll);
65592
65623
  i18next.options.debug = i18n ? true : false;
65593
- gobj_set_trace_machine_format(Number(kw_get_local_storage_value("dev_automata_simple", 0, false)) ? 1 : 0);
65624
+ gobj_set_trace_machine_format(dev_simple_mach());
65594
65625
  set_log_callback(info_log);
65595
65626
  apply_console_route();
65596
65627
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.32",
3
+ "version": "7.23.34",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
package/src/yui_dev.js CHANGED
@@ -21,6 +21,14 @@ import {
21
21
  gobj_set_trace_machine_format,
22
22
  } from "@yuneta/gobj-js";
23
23
 
24
+ /* A NAMESPACE import, deliberately, for one optional API.
25
+ *
26
+ * `set_console_log_filter` arrived in gobj-js 7.13.6, and a NAMED import of
27
+ * an export the installed copy does not have is a hard module-load error --
28
+ * it would take the whole app down instead of degrading. Read off the
29
+ * namespace, a missing export is plain `undefined` and can be tested for. */
30
+ import * as gobj_js from "@yuneta/gobj-js";
31
+
24
32
  import {log_signature, log_is_periodic} from "./dev_machine_trace.js";
25
33
 
26
34
  import i18next from 'i18next';
@@ -177,6 +185,25 @@ function dev_view()
177
185
  * chip writes the value it already had and appears to do nothing. */
178
186
  const HIDE_PERIODIC_DEFAULT = 1;
179
187
 
188
+ /* Which SHAPE the machine trace is written in — the two the C kernel
189
+ * offers, and the chip that swaps them:
190
+ *
191
+ * 1 (default) one line per transition, event first
192
+ * 0 the legacy three-line shape: the call, the state
193
+ * change, and the `<- … ret: N` return
194
+ *
195
+ * 1 because that is what the C kernel defaults to, so a browser yuno and
196
+ * a node read alike. Like HIDE_PERIODIC_DEFAULT, a CONSTANT and not a
197
+ * literal in each of the three places that read it (the chip, the chrome
198
+ * and start up): they have to agree on what "unset" means, or the chip
199
+ * is born showing the wrong state and its first click does nothing. */
200
+ const SIMPLE_MACH_DEFAULT = 1;
201
+
202
+ function dev_simple_mach()
203
+ {
204
+ return dev_num("dev_automata_simple", SIMPLE_MACH_DEFAULT) ? 1 : 0;
205
+ }
206
+
180
207
  function dev_hide_periodic()
181
208
  {
182
209
  return dev_num("dev_hide_periodic", HIDE_PERIODIC_DEFAULT) ? true : false;
@@ -195,12 +222,46 @@ function dev_route()
195
222
  }
196
223
 
197
224
  /* Push the current route's console decision down to gobj-js. Called from
198
- * apply_dev_traces (startup) and whenever the Output selector changes. */
225
+ * apply_dev_traces (startup), whenever the Output selector changes, and
226
+ * whenever a filter that the console also obeys is toggled. */
199
227
  function apply_console_route()
200
228
  {
201
229
  set_console_log_enabled(dev_route() !== "window");
230
+
231
+ /* ONE rule, TWO sinks.
232
+ *
233
+ * The window's Periodic filter used to end at the window, so with the
234
+ * Output on "Both" the timers were gone from the panel and still
235
+ * arriving in the browser console, two lines a second — the same flood,
236
+ * one pane over. It cannot be fixed from this side alone: gobj-js writes
237
+ * the console line BEFORE it calls the log sink, so nothing here can
238
+ * un-print it. It hands out a say instead (`set_console_log_filter`,
239
+ * gobj-js >= 7.13.6), and this is the same predicate `entry_hidden()`
240
+ * uses, so the two panes cannot disagree about what is noise.
241
+ *
242
+ * Feature-detected rather than required: against an older gobj-js the
243
+ * window still filters and the console still floods, exactly as before,
244
+ * and the reason is logged once instead of failing. */
245
+ if(typeof gobj_js.set_console_log_filter === "function") {
246
+ gobj_js.set_console_log_filter((level, msg) => {
247
+ if(!dev_hide_periodic()) {
248
+ return true;
249
+ }
250
+ return !log_is_periodic(level, is_string(msg) ? msg : String(msg));
251
+ });
252
+ } else if(!__console_filter_warned__) {
253
+ __console_filter_warned__ = true;
254
+ console.warn(
255
+ "yui_dev: gobj-js has no set_console_log_filter (needs >= 7.13.6): " +
256
+ "the Periodic filter applies to this window only, not to the console"
257
+ );
258
+ }
202
259
  }
203
260
 
261
+ /* The warning above is worth saying, and worth saying ONCE: this runs on
262
+ * every Output change and every filter toggle. */
263
+ let __console_filter_warned__ = false;
264
+
204
265
  /* Emit one inter-event traffic line to the browser console (routes
205
266
  * "console" and "both"). gobj-js only knows about framework logs, not this
206
267
  * traffic feed, so the console mirror is produced here. */
@@ -253,6 +314,12 @@ function toggle_pref(key, def)
253
314
  {
254
315
  let v = dev_num(key, def) ? 0 : 1;
255
316
  kw_set_local_storage_value(key, v);
317
+ /* The console filter closes over dev_hide_periodic(), which reads the
318
+ * stored value on each call, so it follows this on its own. Re-pushed
319
+ * anyway: a filter installed before this module reached apply_dev_traces
320
+ * is the difference between the console obeying the chip and ignoring
321
+ * it, and one assignment is cheaper than that class of bug. */
322
+ apply_console_route();
256
323
  rerender_all();
257
324
  refresh_dev_chrome();
258
325
  }
@@ -773,13 +840,29 @@ function render_name(e)
773
840
  /* A mirrored framework log line (error/warning/info/debug/msg). */
774
841
  function render_log(e)
775
842
  {
776
- return createElement2(
843
+ let $row = createElement2(
777
844
  ['div', {class: 'YDEV_LOGROW YDEV_LOG_' + e.level, title: e.level}, [
778
845
  ['span', {class: 'YDEV_LOG_LVL'}, e.level],
779
- ['span', {class: 'YDEV_LOG_TXT'}, e.text],
846
+ ['span', {class: 'YDEV_LOG_TXT'}, ''],
780
847
  ['span', {class: 'TRAFFIC_META'}, e.ts],
781
848
  ]]
782
849
  );
850
+
851
+ /* The text is assigned AFTER, and that is the whole point.
852
+ *
853
+ * createElement2() TRIMS a string content -- it has to, to decide
854
+ * whether the string is HTML by looking at its first character -- and
855
+ * the machine trace's leading spaces are its NESTING: gobj-js prefixes
856
+ * every line with `tab()`, two spaces per level of __inside__, so an
857
+ * event sent from inside another one's action is indented under it.
858
+ * Passed through createElement2 that indentation was eaten, and the
859
+ * window showed a flat column where the console showed a tree. */
860
+ let $txt = $row.querySelector('.YDEV_LOG_TXT');
861
+ if($txt) {
862
+ $txt.textContent = e.text;
863
+ }
864
+
865
+ return $row;
783
866
  }
784
867
 
785
868
  function render_entry(e)
@@ -841,17 +924,55 @@ function rerender_all()
841
924
  }
842
925
  logger.replaceChildren(frag);
843
926
  if(shown === 0) {
844
- let $empty = document.createElement('div');
845
- $empty.className = 'YDEV_EMPTY';
846
- $empty.textContent = TRAFFIC_LOG.length
847
- ? "No messages match the current filters."
848
- : "Waiting for activity — console logs and errors show automatically; enable Traffic or Automata for more.";
849
- logger.appendChild($empty);
927
+ logger.appendChild(make_placeholder());
850
928
  }
851
929
  logger.scrollTop = logger.scrollHeight;
852
930
  update_stats();
853
931
  }
854
932
 
933
+ /* The empty state, which has to say WHICH empty it is. */
934
+ function make_placeholder()
935
+ {
936
+ let $empty = document.createElement('div');
937
+ $empty.className = 'YDEV_EMPTY';
938
+ $empty.textContent = placeholder_text();
939
+ return $empty;
940
+ }
941
+
942
+ function placeholder_text()
943
+ {
944
+ if(TRAFFIC_LOG.length) {
945
+ return "No messages match the current filters.";
946
+ }
947
+ return "Waiting for activity — console logs and errors show automatically; " +
948
+ "enable Traffic or Automata for more.";
949
+ }
950
+
951
+ /* Keep whatever placeholder is on screen TRUTHFUL.
952
+ *
953
+ * A line that arrives and is filtered out changes the answer without
954
+ * changing the screen: the buffer stops being empty, so "Waiting for
955
+ * activity — enable Automata for more" becomes a lie, and the window reads
956
+ * as "nothing is happening, your traces are off" while it is in fact hiding
957
+ * 36 of them. Measured on a yuno with one timer and the Periodic filter on,
958
+ * which is now the default: the status line said `0/36 shown · 36 hidden`
959
+ * and the panel said there was no activity. */
960
+ function refresh_placeholder()
961
+ {
962
+ let logger = document.getElementById('developer-traffic-logger');
963
+ if(!logger) {
964
+ return;
965
+ }
966
+ let ph = logger.querySelector('.YDEV_EMPTY');
967
+ if(!ph) {
968
+ return;
969
+ }
970
+ let text = placeholder_text();
971
+ if(ph.textContent !== text) {
972
+ ph.textContent = text;
973
+ }
974
+ }
975
+
855
976
  /* Live counters in the status strip. */
856
977
  function update_stats()
857
978
  {
@@ -1002,6 +1123,8 @@ function info_traffic(title, msg, direction, size)
1002
1123
  ph.remove();
1003
1124
  }
1004
1125
  append_and_follow(logger, node);
1126
+ } else {
1127
+ refresh_placeholder(); /* hidden, but the buffer is no longer empty */
1005
1128
  }
1006
1129
  update_stats();
1007
1130
  }
@@ -1092,6 +1215,8 @@ function info_log(level, msg, hora)
1092
1215
  ph.remove();
1093
1216
  }
1094
1217
  append_and_follow(logger, node);
1218
+ } else {
1219
+ refresh_placeholder(); /* hidden, but the buffer is no longer empty */
1095
1220
  }
1096
1221
  update_stats();
1097
1222
  } finally {
@@ -1228,7 +1353,7 @@ function refresh_dev_chrome()
1228
1353
  });
1229
1354
 
1230
1355
  document.querySelectorAll('.YDEV_CHIP[data-toggle="automata-simple"]').forEach(($b) => {
1231
- $b.classList.toggle('is-active', !!dev_num('dev_automata_simple', 0));
1356
+ $b.classList.toggle('is-active', !!dev_simple_mach());
1232
1357
  });
1233
1358
 
1234
1359
  let $m = document.getElementById('ydev-muted');
@@ -1336,11 +1461,13 @@ function build_control_bar()
1336
1461
  * emitted while Automata is on. */
1337
1462
  let simple_mach = ['button', {
1338
1463
  class: 'YDEV_CHIP', 'data-toggle': 'automata-simple', type: 'button',
1339
- title: 'Compact automata format (one line per transition, like C)',
1464
+ title: 'Machine trace shape. On (default): one line per transition, ' +
1465
+ 'event first, like the C kernel. Off: the legacy three-line shape ' +
1466
+ '(the call, the state change and the return)',
1340
1467
  }, 'Simple mach', {
1341
1468
  click: (ev) => {
1342
1469
  ev.stopPropagation();
1343
- let v = dev_num('dev_automata_simple', 0) ? 0 : 1;
1470
+ let v = dev_simple_mach() ? 0 : 1;
1344
1471
  kw_set_local_storage_value('dev_automata_simple', v);
1345
1472
  gobj_set_trace_machine_format(v);
1346
1473
  refresh_dev_chrome();
@@ -1533,9 +1660,8 @@ function apply_dev_traces()
1533
1660
  gobj_write_attr(gobj_yuno(), "no_poll", no_poll);
1534
1661
  i18next.options.debug = i18n ? true : false;
1535
1662
 
1536
- /* Compact vs verbose automata trace format (persisted). */
1537
- gobj_set_trace_machine_format(
1538
- Number(kw_get_local_storage_value("dev_automata_simple", 0, false)) ? 1 : 0);
1663
+ /* Which shape the machine trace is written in (persisted). */
1664
+ gobj_set_trace_machine_format(dev_simple_mach());
1539
1665
 
1540
1666
  /* Mirror the browser console (log_error/warning/info/debug/msg — the
1541
1667
  * automata FSM trace arrives as debug) into the monitor. info_log no-ops