@yuneta/gobj-ui 7.25.15 → 7.25.17

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.
@@ -3432,8 +3432,28 @@ function build_dialog(shell, message, buttons, opts) {
3432
3432
  if ($primary) $primary.focus();
3433
3433
  });
3434
3434
  }
3435
+ /***************************************************************
3436
+ * The labels a confirmation shows when the caller names none.
3437
+ *
3438
+ * They are i18n KEYS, lower-case like every key: a button
3439
+ * translates its label with the app's t() -- its text, its title
3440
+ * and its aria-label. Until 7.25.16 they were "OK", "Yes", "No",
3441
+ * "Delete" and "Cancel", keys that no locale carries, so a dialog
3442
+ * that took the defaults read in English in every language.
3443
+ *
3444
+ * Written as `i18n:` entries so the validate-locales script of a
3445
+ * consumer finds them when it scans this module: an app that
3446
+ * mounts these dialogs must define the five keys.
3447
+ ***************************************************************/
3448
+ var DEFAULT_LABEL = Object.freeze({
3449
+ ok: Object.freeze({ i18n: "ok" }),
3450
+ yes: Object.freeze({ i18n: "yes" }),
3451
+ no: Object.freeze({ i18n: "no" }),
3452
+ delete: Object.freeze({ i18n: "delete" }),
3453
+ cancel: Object.freeze({ i18n: "cancel" })
3454
+ });
3435
3455
  function yui_shell_confirm_ok(shell, message, opts) {
3436
- let label = opts && opts.ok_label || "OK";
3456
+ let label = opts && opts.ok_label || DEFAULT_LABEL.ok.i18n;
3437
3457
  if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "success" });
3438
3458
  return build_dialog(shell, message, [{
3439
3459
  label,
@@ -3442,8 +3462,8 @@ function yui_shell_confirm_ok(shell, message, opts) {
3442
3462
  }], opts).then(() => void 0);
3443
3463
  }
3444
3464
  function yui_shell_confirm_yesno(shell, message, opts) {
3445
- let yes_label = opts && opts.yes_label || "Yes";
3446
- let no_label = opts && opts.no_label || "No";
3465
+ let yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes.i18n;
3466
+ let no_label = opts && opts.no_label || DEFAULT_LABEL.no.i18n;
3447
3467
  return build_dialog(shell, message, [{
3448
3468
  label: yes_label,
3449
3469
  value: "yes",
@@ -3468,8 +3488,8 @@ function yui_shell_confirm_yesno(shell, message, opts) {
3468
3488
  * pressed.
3469
3489
  ***************************************************************/
3470
3490
  function yui_shell_confirm_danger(shell, message, opts) {
3471
- let confirm_label = opts && opts.confirm_label || "Delete";
3472
- let cancel_label = opts && opts.cancel_label || "Cancel";
3491
+ let confirm_label = opts && opts.confirm_label || DEFAULT_LABEL.delete.i18n;
3492
+ let cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel.i18n;
3473
3493
  if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "danger" });
3474
3494
  return build_dialog(shell, message, [{
3475
3495
  label: confirm_label,
@@ -3481,9 +3501,9 @@ function yui_shell_confirm_danger(shell, message, opts) {
3481
3501
  }], opts).then((v) => v === "confirm");
3482
3502
  }
3483
3503
  function yui_shell_confirm_yesnocancel(shell, message, opts) {
3484
- let yes_label = opts && opts.yes_label || "Yes";
3485
- let no_label = opts && opts.no_label || "No";
3486
- let cancel_label = opts && opts.cancel_label || "Cancel";
3504
+ let yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes.i18n;
3505
+ let no_label = opts && opts.no_label || DEFAULT_LABEL.no.i18n;
3506
+ let cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel.i18n;
3487
3507
  return build_dialog(shell, message, [
3488
3508
  {
3489
3509
  label: yes_label,
@@ -59227,6 +59247,7 @@ var PRIVATE_DATA$4 = {
59227
59247
  __graphs__: [],
59228
59248
  _graph_properties: {},
59229
59249
  _saved_graph_properties: {},
59250
+ _graphs_writes_owed: {},
59230
59251
  yet_showed: false,
59231
59252
  edit_mode: false,
59232
59253
  operation_mode: null,
@@ -60922,6 +60943,7 @@ function save_topic_graph_properties(gobj, topic_name) {
60922
60943
  if (!topic_arrangement_changed(properties, priv._saved_graph_properties[topic_name])) return;
60923
60944
  properties.__origin__ = gobj_read_str_attr(gobj_yuno(), "node_uuid");
60924
60945
  priv._saved_graph_properties[topic_name] = json_deep_copy(properties);
60946
+ delete priv._graphs_writes_owed[topic_name];
60925
60947
  let kw_update = {
60926
60948
  treedb_name: priv.treedb_name,
60927
60949
  topic_name: "__graphs__",
@@ -61003,8 +61025,13 @@ function update_history_buttons(gobj) {
61003
61025
  } else {
61004
61026
  disableElements($container, ".EV_HISTORY_UNDO");
61005
61027
  set_active_state($container, ".EV_HISTORY_UNDO", false);
61006
- disableElements($container, ".EV_SAVE_GRAPH");
61007
- set_submit_state($container, ".EV_SAVE_GRAPH", false);
61028
+ if (graphs_write_is_owed(gobj)) {
61029
+ enableElements($container, ".EV_SAVE_GRAPH");
61030
+ set_submit_state($container, ".EV_SAVE_GRAPH", true);
61031
+ } else {
61032
+ disableElements($container, ".EV_SAVE_GRAPH");
61033
+ set_submit_state($container, ".EV_SAVE_GRAPH", false);
61034
+ }
61008
61035
  }
61009
61036
  } else {
61010
61037
  disableElements($container, ".EV_HISTORY_REDO");
@@ -61961,6 +61988,15 @@ function run_preview_undo(gobj, key) {
61961
61988
  log_error(`${gobj_short_name(gobj)}: cannot undo the preview: ${e}`);
61962
61989
  }
61963
61990
  }
61991
+ /************************************************************
61992
+ * Is a `__graphs__` write owed? The host said one did not land
61993
+ * (EV_GRAPHS_WRITE_REFUSED), and no Save has written that topic
61994
+ * since. The Save button stays lit while it is: the history
61995
+ * knows nothing of it, so `canUndo()` alone would put it out.
61996
+ ************************************************************/
61997
+ function graphs_write_is_owed(gobj) {
61998
+ return Object.keys(gobj.priv._graphs_writes_owed).length > 0;
61999
+ }
61964
62000
  function mark_graph_dirty(gobj) {
61965
62001
  let $container = gobj_read_attr(gobj, "$container");
61966
62002
  enableElements($container, ".EV_SAVE_GRAPH");
@@ -65701,6 +65737,7 @@ function ac_clear_data(gobj, event, kw, src) {
65701
65737
  deselect_node(gobj);
65702
65738
  hide_create_popover(gobj);
65703
65739
  gobj_write_attr(gobj, "records", {});
65740
+ priv._graphs_writes_owed = {};
65704
65741
  priv._nodes_total = 0;
65705
65742
  priv._nodes_placed = 0;
65706
65743
  priv._fold_model = null;
@@ -65793,11 +65830,9 @@ function ac_save_graph(gobj, event, kw, src) {
65793
65830
  disableElements($container, ".EV_SAVE_GRAPH");
65794
65831
  set_submit_state($container, ".EV_SAVE_GRAPH", false);
65795
65832
  let history = graph_get_plugin(gobj, "history");
65796
- if (history) {
65797
- history.clear();
65798
- update_history_buttons(gobj);
65799
- }
65833
+ if (history) history.clear();
65800
65834
  save_geometry(gobj);
65835
+ update_history_buttons(gobj);
65801
65836
  }
65802
65837
  return 0;
65803
65838
  }
@@ -65820,6 +65855,7 @@ function ac_graphs_write_refused(gobj, event, kw, src) {
65820
65855
  }
65821
65856
  log_warning(`${gobj_short_name(gobj)}: the arrangement of '${topic_name}' was not saved: the next Save writes it again`);
65822
65857
  forget_refused_graphs_write(priv._saved_graph_properties, topic_name);
65858
+ priv._graphs_writes_owed[topic_name] = true;
65823
65859
  if (priv.edit_mode) mark_graph_dirty(gobj);
65824
65860
  return 0;
65825
65861
  }
@@ -68337,6 +68373,7 @@ function treedb_update_node(gobj, treedb_name, topic_name, record, options) {
68337
68373
  options: options || {}
68338
68374
  };
68339
68375
  kw.__md_command__ = { topic_name };
68376
+ if (topic_name === "__graphs__") kw.__md_command__.graph_topic = graph_topic_of(record);
68340
68377
  let ret = gobj_command(priv.gobj_remote_yuno, command, kw, gobj);
68341
68378
  if (ret) {
68342
68379
  log_error(ret);
@@ -68615,7 +68652,7 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
68615
68652
  case "delete-node":
68616
68653
  case "link-nodes":
68617
68654
  case "unlink-nodes":
68618
- if (result < 0 && command === "update-node") graphs_write_refused(gobj, kw_get_str(gobj, kw_command, "topic_name", "", 0), kw_get_dict(gobj, kw_command, "record", {}, 0));
68655
+ if (result < 0 && command === "update-node") graphs_write_refused(gobj, kw_get_str(gobj, kw_command, "topic_name", "", 0), kw_get_str(gobj, kw_command, "graph_topic", "", 0));
68619
68656
  if (result >= 0 && kw_get_str(gobj, kw_command, "topic_name", "", 0) !== "__graphs__") gobj_publish_event(gobj, "EV_RECORD_WRITTEN", {
68620
68657
  treedb_name: kw_get_str(gobj, kw_command, "treedb_name", "", 0),
68621
68658
  topic_name: kw_get_str(gobj, kw_command, "topic_name", "", 0),
@@ -68864,29 +68901,35 @@ function ac_update_node(gobj, event, kw, src) {
68864
68901
  let record = kw.record;
68865
68902
  let options = kw.options || {};
68866
68903
  if (refuse_if_readonly$1(gobj, event)) {
68867
- graphs_write_refused(gobj, topic_name, record);
68904
+ graphs_write_refused(gobj, topic_name, graph_topic_of(record));
68868
68905
  return -1;
68869
68906
  }
68870
68907
  if (topic_name === "__graphs__" && !is_connected(gobj)) {
68871
68908
  log_warning(`${gobj_short_name(gobj)}: no session, the arrangement was not sent`);
68872
- graphs_write_refused(gobj, topic_name, record);
68909
+ graphs_write_refused(gobj, topic_name, graph_topic_of(record));
68873
68910
  return -1;
68874
68911
  }
68875
68912
  let ret = treedb_update_node(gobj, treedb_name, topic_name, record, options);
68876
- if (ret < 0) graphs_write_refused(gobj, topic_name, record);
68913
+ if (ret < 0) graphs_write_refused(gobj, topic_name, graph_topic_of(record));
68877
68914
  return ret;
68878
68915
  }
68879
68916
  /************************************************************
68917
+ * The topic a `__graphs__` record arranges.
68918
+ ************************************************************/
68919
+ function graph_topic_of(record) {
68920
+ if (!record || typeof record !== "object") return "";
68921
+ return record.topic || record.id || "";
68922
+ }
68923
+ /************************************************************
68880
68924
  * A write of `__graphs__` did not land. The engine
68881
68925
  * (C_G6_NODES_TREE) took it for granted when it left -- nothing
68882
68926
  * answers it when it lands -- so it is told, and its next Save
68883
68927
  * writes the topic again. Other topics are the operator's data:
68884
68928
  * the answer's error says what happened to them.
68885
68929
  ************************************************************/
68886
- function graphs_write_refused(gobj, topic_name, record) {
68930
+ function graphs_write_refused(gobj, topic_name, topic) {
68887
68931
  let priv = gobj.priv;
68888
68932
  if (topic_name !== "__graphs__") return;
68889
- let topic = record && typeof record === "object" ? record.topic || record.id : "";
68890
68933
  if (!topic) {
68891
68934
  log_error(`${gobj_short_name(gobj)}: a refused __graphs__ write names no topic`);
68892
68935
  return;
@@ -72329,6 +72372,8 @@ var PRIVATE_DATA$1 = {
72329
72372
  dropped_round: 0,
72330
72373
  dropped_write: 0,
72331
72374
  reload_after_write: false,
72375
+ refresh_after_write: false,
72376
+ reopen_form: null,
72332
72377
  pending_seg: null,
72333
72378
  import_plan: null,
72334
72379
  import_pane: null,
@@ -72443,11 +72488,18 @@ function el_attrs(attrs) {
72443
72488
  return attrs;
72444
72489
  }
72445
72490
  /***************************************************************
72446
- * The body stops answering while a write is in flight.
72491
+ * The body stops answering while a write is in flight. For the
72492
+ * keyboard too: `pointer-events` stops the mouse alone, and the
72493
+ * shell's focus trap puts the focus back on the row control that
72494
+ * had it, where Enter or Delete sent an action ST_SAVING does
72495
+ * not declare. `inert` takes the whole body out of reach.
72447
72496
  ***************************************************************/
72448
72497
  function set_busy(gobj, busy) {
72449
72498
  let $body = $of(gobj, ".SCHEMA_BODY");
72450
- if ($body) $body.classList.toggle("SCHEMA_BUSY", !!busy);
72499
+ if ($body) {
72500
+ $body.classList.toggle("SCHEMA_BUSY", !!busy);
72501
+ $body.toggleAttribute("inert", !!busy);
72502
+ }
72451
72503
  }
72452
72504
  /***************************************************************
72453
72505
  * Shorthands for the three panes of the frame.
@@ -72534,14 +72586,61 @@ function owes_reload(gobj) {
72534
72586
  let state = gobj_current_state(gobj);
72535
72587
  return gobj.priv.reload_on_open && transport_in_session(gobj) && state !== "ST_LOADING" && state !== "ST_SAVING";
72536
72588
  }
72537
- function reload_first(gobj, event) {
72589
+ function reload_first(gobj, event, reopen) {
72590
+ let priv = gobj.priv;
72538
72591
  if (!owes_reload(gobj)) return false;
72539
- gobj.priv.reload_on_open = false;
72592
+ priv.reload_on_open = false;
72593
+ if (reopen && priv.dialog) {
72594
+ priv.reopen_form = Object.assign(json_deep_copy(reopen), {
72595
+ dialog: priv.dialog,
72596
+ treedb_id: priv.treedb_id
72597
+ });
72598
+ log_warning(`${gobj_short_name(gobj)}: ${event} refused, the schemas shown may be out of date: they are read again first, and the form opens again on them with its changes`);
72599
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas shown may be out of date: they are read again, and the form opens again on them with your changes", { t });
72600
+ request_model(gobj, true);
72601
+ return true;
72602
+ }
72540
72603
  log_warning(`${gobj_short_name(gobj)}: ${event} refused, the schemas shown may be out of date: they are read again first`);
72541
72604
  yui_shell_show_error(yui_shell_of(gobj), "the schemas shown may be out of date: they are read again, try again when they are in", { t });
72542
72605
  request_model(gobj, true);
72543
72606
  return true;
72544
72607
  }
72608
+ /***************************************************************
72609
+ * The form reload_first() took down, opened again on the model
72610
+ * the load just made, with the operator's changes on top.
72611
+ *
72612
+ * Only where it can mean the same thing: on the treedb it was
72613
+ * opened on, on the screen whose Save it has, and on a record
72614
+ * that is still there. Otherwise it is not opened, and that is
72615
+ * said -- a form opened on another treedb, or on nothing, would
72616
+ * save somewhere the operator never meant.
72617
+ ***************************************************************/
72618
+ function reopen_form(gobj, r) {
72619
+ let priv = gobj.priv;
72620
+ let state = gobj_current_state(gobj);
72621
+ let treedb = current_treedb(gobj);
72622
+ let topic = null;
72623
+ let col = null;
72624
+ let fits = false;
72625
+ if (treedb && r.treedb_id === priv.treedb_id) {
72626
+ if (r.form === "column" && state === "ST_COLUMNS") {
72627
+ topic = find_topic(priv.model, priv.treedb_id, r.topic);
72628
+ col = topic && !r.creating ? find_col(priv.model, priv.treedb_id, r.topic, r.col) : null;
72629
+ fits = !!topic && (r.creating || !!col);
72630
+ } else if (r.form === "topic" && state === "ST_TOPICS") {
72631
+ topic = r.creating ? null : find_topic(priv.model, priv.treedb_id, r.topic);
72632
+ fits = r.creating || !!topic;
72633
+ }
72634
+ }
72635
+ if (!fits) {
72636
+ log_warning(`${gobj_short_name(gobj)}: the ${r.form} form was not opened again: what it edited is not on the schemas the reload read (${r.treedb_id} ${r.topic}${r.col ? "." + r.col : ""}, now ${state})`);
72637
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again and what the form was editing is not there any more", { t });
72638
+ return -1;
72639
+ }
72640
+ if (r.form === "column") open_column_form(gobj, topic, col, null, r.changed);
72641
+ else open_topic_form(gobj, treedb, topic, r.changed);
72642
+ return 0;
72643
+ }
72545
72644
  function reload_after_move(gobj) {
72546
72645
  if (!owes_reload(gobj)) return 0;
72547
72646
  gobj.priv.reload_on_open = false;
@@ -72616,7 +72715,7 @@ function request_model(gobj, keep_written) {
72616
72715
  priv.records_before = null;
72617
72716
  priv.load_round++;
72618
72717
  priv.reload_on_open = true;
72619
- priv.load_error = t("cannot reach the treedb");
72718
+ priv.load_error = "cannot reach the treedb";
72620
72719
  if (priv.model) yui_shell_show_error(yui_shell_of(gobj), "cannot reach the treedb", { t });
72621
72720
  end_load(gobj);
72622
72721
  return -1;
@@ -72687,7 +72786,7 @@ function build_model(gobj) {
72687
72786
  * measurement of "changed since" can be measured against.
72688
72787
  *
72689
72788
  * `written` is forgotten only by an EV_REFRESH (the view's own
72690
- * Refresh button, or a host that sends one). Since M36 a write moves no
72789
+ * Refresh button, or a host that sends one). Since 7.23.196 a write moves no
72691
72790
  * version, so `written` is the draft chip of what this session
72692
72791
  * wrote and no longer half of a version measurement: a reload of
72693
72792
  * the reconnect, or of a write that turned out done, forgot the
@@ -72827,10 +72926,13 @@ function show_notice(gobj, key, detail) {
72827
72926
  },
72828
72927
  t(key)
72829
72928
  ]));
72830
- if (detail) $notice.appendChild(createElement2([
72929
+ if (detail && detail !== key) $notice.appendChild(createElement2([
72831
72930
  "span",
72832
- { class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2" },
72833
- `${detail}`
72931
+ {
72932
+ class: "SCHEMA_NOTICE_DETAIL yui-text-quiet ml-2",
72933
+ i18n: `${detail}`
72934
+ },
72935
+ t(`${detail}`)
72834
72936
  ]));
72835
72937
  }
72836
72938
  /***************************************************************
@@ -73965,6 +74067,55 @@ function read_form($root) {
73965
74067
  return out;
73966
74068
  }
73967
74069
  /***************************************************************
74070
+ * A column form as its Save sends it: the fields and the flags.
74071
+ ***************************************************************/
74072
+ function column_form_state($form) {
74073
+ let values = read_form($form);
74074
+ values.flag = read_flags($form);
74075
+ return values;
74076
+ }
74077
+ /***************************************************************
74078
+ * The fields the operator CHANGED: those whose value is not the
74079
+ * one the form was opened with.
74080
+ ***************************************************************/
74081
+ function form_changes(initial, values) {
74082
+ let changed = {};
74083
+ for (let name of Object.keys(values)) if (JSON.stringify(values[name]) !== JSON.stringify(initial[name])) changed[name] = values[name];
74084
+ return changed;
74085
+ }
74086
+ /***************************************************************
74087
+ * Put changes back into a form just built (reopen_form()). The
74088
+ * flags are drawn again for the type the changes leave, holding
74089
+ * the flags they name, so none of them is hidden by the type.
74090
+ ***************************************************************/
74091
+ function apply_form_changes(gobj, $form, changes) {
74092
+ for (let name of Object.keys(changes)) {
74093
+ if (name === "flag") continue;
74094
+ let $control = $form.querySelector(`[data-name="${name}"]`);
74095
+ if (!$control) {
74096
+ log_warning(`${gobj_short_name(gobj)}: a change of '${name}' has no field in the form opened again: not put back`);
74097
+ continue;
74098
+ }
74099
+ if ($control.type === "checkbox") $control.checked = !!changes[name];
74100
+ else $control.value = changes[name];
74101
+ }
74102
+ let $type = $form.querySelector("[data-name=\"type\"]");
74103
+ if ($type && $form.querySelector(".SCHEMA_FLAGS")) {
74104
+ let flags = Array.isArray(changes.flag) ? changes.flag : read_flags($form);
74105
+ redraw_flags(gobj, $form, $type.value, flags);
74106
+ }
74107
+ }
74108
+ /***************************************************************
74109
+ * Draw the flags of a column form again, for `type`, with
74110
+ * `current` checked.
74111
+ ***************************************************************/
74112
+ function redraw_flags(gobj, $form, type, current) {
74113
+ let $holder = $form.querySelector(".SCHEMA_FLAGS");
74114
+ let $new = createElement2(flags_field(gobj, type, current));
74115
+ $holder.parentNode.replaceChild($new, $holder);
74116
+ refresh_language($new, t);
74117
+ }
74118
+ /***************************************************************
73968
74119
  * The flags of a column, as checkboxes that say what they do.
73969
74120
  *
73970
74121
  * Grouped the way they act, greyed when they are meaningless on
@@ -74038,7 +74189,7 @@ function read_flags($root) {
74038
74189
  * Offering a field that silently does something else is worse
74039
74190
  * than not offering it.
74040
74191
  ***************************************************************/
74041
- function open_column_form(gobj, topic, col, prefill) {
74192
+ function open_column_form(gobj, topic, col, prefill, changes) {
74042
74193
  let priv = gobj.priv;
74043
74194
  let record = prefill || col && col.record || {};
74044
74195
  let creating = !col;
@@ -74142,11 +74293,7 @@ function open_column_form(gobj, topic, col, prefill) {
74142
74293
  ]);
74143
74294
  let $type = $form.querySelector("[data-name=\"type\"]");
74144
74295
  $type.addEventListener("change", () => {
74145
- let $holder = $form.querySelector(".SCHEMA_FLAGS");
74146
- let current = read_flags($form);
74147
- let $new = createElement2(flags_field(gobj, $type.value, current));
74148
- $holder.parentNode.replaceChild($new, $holder);
74149
- refresh_language($new, t);
74296
+ redraw_flags(gobj, $form, $type.value, read_flags($form));
74150
74297
  });
74151
74298
  $form.addEventListener("change", (evt) => {
74152
74299
  let $box = evt.target.closest(".SCHEMA_FLAG_BOX");
@@ -74158,15 +74305,17 @@ function open_column_form(gobj, topic, col, prefill) {
74158
74305
  evt.stopPropagation();
74159
74306
  close_dialog(gobj);
74160
74307
  });
74308
+ let initial = column_form_state($form);
74309
+ if (changes) apply_form_changes(gobj, $form, changes);
74161
74310
  $form.querySelector(".SCHEMA_COL_FORM_SAVE").addEventListener("click", (evt) => {
74162
74311
  evt.stopPropagation();
74163
- let values = read_form($form);
74164
- values.flag = read_flags($form);
74312
+ let values = column_form_state($form);
74165
74313
  gobj_send_event(gobj, "EV_SAVE_COLUMN", {
74166
74314
  topic: topic.name,
74167
74315
  col: creating ? "" : col.name,
74168
74316
  creating,
74169
74317
  values,
74318
+ changed: creating ? values : form_changes(initial, values),
74170
74319
  model_gen
74171
74320
  }, gobj);
74172
74321
  });
@@ -74186,7 +74335,7 @@ function stringify_field(value) {
74186
74335
  * actually has: a pkey naming no column is a topic that does
74187
74336
  * not open, and it is the first thing the validator looks for.
74188
74337
  ***************************************************************/
74189
- function open_topic_form(gobj, treedb, topic) {
74338
+ function open_topic_form(gobj, treedb, topic, changes) {
74190
74339
  let record = topic && topic.record || {};
74191
74340
  let creating = !topic;
74192
74341
  let col_names = topic ? topic.cols.map((c) => c.name) : [];
@@ -74281,12 +74430,16 @@ function open_topic_form(gobj, treedb, topic) {
74281
74430
  evt.stopPropagation();
74282
74431
  close_dialog(gobj);
74283
74432
  });
74433
+ let initial = read_form($form);
74434
+ if (changes) apply_form_changes(gobj, $form, changes);
74284
74435
  $form.querySelector(".SCHEMA_TOPIC_FORM_SAVE").addEventListener("click", (evt) => {
74285
74436
  evt.stopPropagation();
74437
+ let values = read_form($form);
74286
74438
  gobj_send_event(gobj, "EV_SAVE_TOPIC", {
74287
74439
  topic: creating ? "" : topic.name,
74288
74440
  creating,
74289
- values: read_form($form),
74441
+ values,
74442
+ changed: creating ? values : form_changes(initial, values),
74290
74443
  model_gen
74291
74444
  }, gobj);
74292
74445
  });
@@ -75056,20 +75209,28 @@ function transport_dropped(gobj) {
75056
75209
  function end_load(gobj) {
75057
75210
  let priv = gobj.priv;
75058
75211
  let seg = priv.pending_seg;
75212
+ let reopen = priv.reopen_form;
75059
75213
  priv.pending_seg = null;
75214
+ priv.reopen_form = null;
75060
75215
  if (priv.dialog && priv.dialog_gen !== priv.model_gen) {
75061
- log_warning(`${gobj_short_name(gobj)}: a dialog was open on the schemas the load replaced: closed`);
75216
+ if (!reopen || reopen.dialog !== priv.dialog) {
75217
+ reopen = null;
75218
+ log_warning(`${gobj_short_name(gobj)}: a dialog was open on the schemas the load replaced: closed`);
75219
+ yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t });
75220
+ }
75062
75221
  close_dialog(gobj);
75063
- yui_shell_show_error(yui_shell_of(gobj), "the schemas were read again: open the dialog again", { t });
75064
- }
75222
+ } else reopen = null;
75223
+ let ret = 0;
75065
75224
  if (priv.model) {
75066
- if (seg !== null) return apply_seg(gobj, seg);
75067
- return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
75225
+ if (seg !== null) ret = apply_seg(gobj, seg);
75226
+ else ret = go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
75227
+ } else {
75228
+ if (seg !== null) adopt_seg(gobj, seg);
75229
+ gobj_change_state(gobj, "ST_IDLE");
75230
+ render(gobj);
75068
75231
  }
75069
- if (seg !== null) adopt_seg(gobj, seg);
75070
- gobj_change_state(gobj, "ST_IDLE");
75071
- render(gobj);
75072
- return 0;
75232
+ if (reopen) reopen_form(gobj, reopen);
75233
+ return ret;
75073
75234
  }
75074
75235
  /***************************************************************
75075
75236
  * The queue is done, or gave up. Either way the model is what
@@ -75094,7 +75255,11 @@ function end_writes(gobj, error) {
75094
75255
  render(gobj);
75095
75256
  publish_check(gobj);
75096
75257
  }
75097
- reload_if_owed(gobj);
75258
+ if (priv.refresh_after_write) {
75259
+ priv.refresh_after_write = false;
75260
+ priv.reload_after_write = false;
75261
+ request_model(gobj, false);
75262
+ } else reload_if_owed(gobj);
75098
75263
  return error ? -1 : 0;
75099
75264
  }
75100
75265
  /***************************************************************
@@ -75322,7 +75487,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
75322
75487
  return 0;
75323
75488
  }
75324
75489
  priv.pending--;
75325
- if (result < 0) priv.load_error = comment || t("cannot load the schemas");
75490
+ if (result < 0) priv.load_error = comment || "cannot load the schemas";
75326
75491
  else if (priv.records && Array.isArray(priv.records[topic_name])) priv.records[topic_name] = Array.isArray(data) ? data : [];
75327
75492
  if (priv.pending > 0) return 0;
75328
75493
  if (priv.load_error) {
@@ -75358,9 +75523,10 @@ function ac_mt_command_answer(gobj, event, kw, src) {
75358
75523
  }
75359
75524
  if (result < 0) return end_writes(gobj, comment || t("the treedb refused the write"));
75360
75525
  priv.save_wrote = true;
75526
+ let record = null;
75361
75527
  if (command === "delete-node") forget_record(gobj, topic_name, kw_get_str(gobj, md, "record_id", "", 0));
75362
75528
  else {
75363
- let record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
75529
+ record = is_object(data) ? data : Array.isArray(data) && is_object(data[0]) ? data[0] : null;
75364
75530
  if (record) patch_record(gobj, topic_name, record);
75365
75531
  else {
75366
75532
  let not_sent = priv.save_queue.length - 1;
@@ -75368,20 +75534,22 @@ function ac_mt_command_answer(gobj, event, kw, src) {
75368
75534
  if (not_sent > 0) yui_shell_show_error(yui_shell_of(gobj), "the treedb did not describe a write back: the writes after it were not sent", { t });
75369
75535
  if (topic_name === T_TOPICS || topic_name === T_COLS) {
75370
75536
  let write = priv.save_queue[0];
75371
- mark_written(gobj, topic_name, write ? write.record : null);
75537
+ mark_written(gobj, topic_name, null, write ? write.record : null);
75372
75538
  }
75373
75539
  priv.reload_after_write = false;
75374
75540
  priv.save_queue = [];
75375
75541
  priv.save_return = "";
75376
75542
  priv.save_wrote = false;
75377
75543
  gobj_publish_event(gobj, "EV_RECORD_WRITTEN", { treedb_name: gobj_read_str_attr(gobj, "treedb_name") });
75378
- request_model(gobj, true);
75544
+ let refresh = priv.refresh_after_write;
75545
+ priv.refresh_after_write = false;
75546
+ request_model(gobj, !refresh);
75379
75547
  return 0;
75380
75548
  }
75381
75549
  }
75382
75550
  if (topic_name === T_TOPICS || topic_name === T_COLS) {
75383
75551
  let write = priv.save_queue[0];
75384
- mark_written(gobj, topic_name, write ? write.record : null);
75552
+ mark_written(gobj, topic_name, record, write ? write.record : null);
75385
75553
  }
75386
75554
  priv.save_queue.shift();
75387
75555
  return run_next_write(gobj);
@@ -75438,25 +75606,34 @@ function late_write_done(gobj, command, topic_name, data) {
75438
75606
  ***************************************************************/
75439
75607
  function mark_written_record(gobj, topic_name, record) {
75440
75608
  let priv = gobj.priv;
75441
- if (!record) return;
75609
+ let marked = 0;
75610
+ if (!record) return 0;
75442
75611
  if (topic_name === T_TOPICS && typeof record.id === "string" && record.id) {
75443
75612
  priv.written[record.id] = true;
75444
- return;
75613
+ return 1;
75445
75614
  }
75446
- if (topic_name !== T_COLS) return;
75447
- for (let ref of parse_fkey_ref(record.topics)) priv.written[ref.id] = true;
75615
+ if (topic_name !== T_COLS) return 0;
75616
+ for (let ref of parse_fkey_ref(record.topics)) {
75617
+ priv.written[ref.id] = true;
75618
+ marked++;
75619
+ }
75620
+ return marked;
75448
75621
  }
75449
75622
  /***************************************************************
75450
75623
  * Remember which topic this write belongs to, which is what
75451
75624
  * "its version still has to move" is asked about.
75625
+ *
75626
+ * Asked of the RECORD first: the one the store answered (a new
75627
+ * topic has its id only there), then the one queued (a column
75628
+ * names its topic in its fkey). The screen is the last resort,
75629
+ * and a poor one: an import writes topics the operator is not
75630
+ * on, and from the topics screen there is no topic on it at all.
75452
75631
  ***************************************************************/
75453
- function mark_written(gobj, topic_name, record) {
75632
+ function mark_written(gobj, topic_name, answered, queued) {
75454
75633
  let priv = gobj.priv;
75634
+ if (mark_written_record(gobj, topic_name, answered) > 0) return;
75635
+ if (mark_written_record(gobj, topic_name, queued) > 0) return;
75455
75636
  let topic = current_topic(gobj);
75456
- if (topic_name === T_TOPICS && record && record.id) {
75457
- priv.written[record.id] = true;
75458
- return;
75459
- }
75460
75637
  if (topic) priv.written[topic.id] = true;
75461
75638
  }
75462
75639
  /***************************************************************
@@ -75522,6 +75699,21 @@ function ac_refresh$1(gobj, event, kw, src) {
75522
75699
  return request_model(gobj, false);
75523
75700
  }
75524
75701
  /***************************************************************
75702
+ * EV_REFRESH while writes are in flight: the view's own Refresh
75703
+ * is busy then, so it is a host's (after a Save, say).
75704
+ *
75705
+ * Run when the writes END (end_writes()), not now. Run now, the
75706
+ * load replaced ST_SAVING and what was still queued was never
75707
+ * sent, with no word: nothing but the end of what is in flight
75708
+ * moves this view out of ST_LOADING or ST_SAVING.
75709
+ ***************************************************************/
75710
+ function ac_refresh_after_the_writes(gobj, event, kw, src) {
75711
+ let priv = gobj.priv;
75712
+ log_warning(`${gobj_short_name(gobj)}: ${event} while writes are in flight: the schemas are read again when the writes end`);
75713
+ priv.refresh_after_write = true;
75714
+ return 0;
75715
+ }
75716
+ /***************************************************************
75525
75717
  * What a DIALOG sends while the model is being read again: the
75526
75718
  * Save of a form left open when the reload started, a
75527
75719
  * confirmation, an import. The loading screen took the rest of
@@ -75696,7 +75888,13 @@ function ac_save_column(gobj, event, kw, src) {
75696
75888
  let topic = find_topic(priv.model, priv.treedb_id, kw.topic);
75697
75889
  let col = kw.creating ? null : find_col(priv.model, priv.treedb_id, kw.topic, kw.col);
75698
75890
  if (refuse_if_readonly(gobj, event)) return -1;
75699
- if (reload_first(gobj, event)) return -1;
75891
+ if (reload_first(gobj, event, {
75892
+ form: "column",
75893
+ topic: kw.topic,
75894
+ col: kw.col,
75895
+ creating: !!kw.creating,
75896
+ changed: kw.changed || {}
75897
+ })) return -1;
75700
75898
  if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75701
75899
  if (!topic || !kw.creating && !col) {
75702
75900
  log_error(`${gobj_short_name(gobj)}: ${event} names no column: ${kw.topic}.${kw.col}`);
@@ -75824,7 +76022,13 @@ function ac_save_topic(gobj, event, kw, src) {
75824
76022
  let treedb = current_treedb(gobj);
75825
76023
  let topic = kw.creating ? null : find_topic(priv.model, priv.treedb_id, kw.topic);
75826
76024
  if (refuse_if_readonly(gobj, event)) return -1;
75827
- if (reload_first(gobj, event)) return -1;
76025
+ if (reload_first(gobj, event, {
76026
+ form: "topic",
76027
+ topic: kw.topic,
76028
+ col: "",
76029
+ creating: !!kw.creating,
76030
+ changed: kw.changed || {}
76031
+ })) return -1;
75828
76032
  if (built_on_a_replaced_model(gobj, event, kw)) return -1;
75829
76033
  if (!treedb || !kw.creating && !topic) {
75830
76034
  log_error(`${gobj_short_name(gobj)}: ${event} names no topic: ${kw.topic}`);
@@ -76287,7 +76491,11 @@ function create_gclass$1(gclass_name) {
76287
76491
  null
76288
76492
  ]
76289
76493
  ])],
76290
- ["ST_SAVING", COMMON.slice()]
76494
+ ["ST_SAVING", COMMON.filter((a) => a[0] !== "EV_REFRESH").concat([[
76495
+ "EV_REFRESH",
76496
+ ac_refresh_after_the_writes,
76497
+ null
76498
+ ]])]
76291
76499
  ];
76292
76500
  const event_types = [
76293
76501
  ["EV_MT_COMMAND_ANSWER", event_flag_t.EVF_PUBLIC_EVENT],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.25.15",
3
+ "version": "7.25.17",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -30,7 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@rollup/plugin-terser": "^1.0.0",
32
32
  "@vitest/coverage-v8": "^4.1.10",
33
- "@yuneta/gobj-js": "^7.22.2",
33
+ "@yuneta/gobj-js": "^7.25.3",
34
34
  "vite": "^8.2.1",
35
35
  "vitest": "^4.1.10"
36
36
  },