@yuneta/gobj-ui 7.23.63 → 7.23.64

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.
@@ -23812,6 +23812,8 @@ function popup_mount_layer(gobj) {
23812
23812
  * Framework Method: Create
23813
23813
  ***************************************************************/
23814
23814
  function mt_create$5(gobj) {
23815
+ gobj.priv.reading_files = 0;
23816
+ gobj.priv.read_serial = 0;
23815
23817
  let name = (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj));
23816
23818
  (0, _yuneta_gobj_js.gobj_write_attr)(gobj, "table_id", "table" + name);
23817
23819
  (0, _yuneta_gobj_js.gobj_write_attr)(gobj, "toolbar_id", "toolbar" + name);
@@ -25060,6 +25062,7 @@ function form_may_close(gobj) {
25060
25062
  ************************************************************/
25061
25063
  function teardown_form_child(gobj) {
25062
25064
  let priv = gobj.priv;
25065
+ priv.reading_files = 0;
25063
25066
  if (priv.form) {
25064
25067
  if ((0, _yuneta_gobj_js.gobj_is_running)(priv.form)) (0, _yuneta_gobj_js.gobj_stop)(priv.form);
25065
25068
  (0, _yuneta_gobj_js.gobj_destroy)(priv.form);
@@ -25867,6 +25870,10 @@ function ac_paste_rows(gobj, event, kw, src) {
25867
25870
  function ac_form_save_record(gobj, event, kw, src) {
25868
25871
  if (refuse_if_readonly$2(gobj, event)) return -1;
25869
25872
  let mode = (0, _yuneta_gobj_js.gobj_read_str_attr)(src, "form_mode");
25873
+ if (priv.reading_files) {
25874
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: save ignored, still reading the picked files`);
25875
+ return -1;
25876
+ }
25870
25877
  let picked = {};
25871
25878
  const answer = (0, _yuneta_gobj_js.gobj_command)(src, "get_picked_files", {}, gobj);
25872
25879
  if (answer && answer.result >= 0 && answer.data) picked = answer.data;
@@ -25878,6 +25885,9 @@ function ac_form_save_record(gobj, event, kw, src) {
25878
25885
  }, 0);
25879
25886
  return 0;
25880
25887
  }
25888
+ const serial = ++priv.read_serial;
25889
+ priv.reading_files = serial;
25890
+ set_form_busy(gobj, true);
25881
25891
  Promise.all(cols.map((col) => {
25882
25892
  return yui_file_read(picked[col]).then((read) => {
25883
25893
  return {
@@ -25891,16 +25901,54 @@ function ac_form_save_record(gobj, event, kw, src) {
25891
25901
  picks[r.col] = r.read;
25892
25902
  });
25893
25903
  (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_FILES_READ", {
25904
+ serial,
25894
25905
  mode,
25895
25906
  record: kw,
25896
25907
  picks
25897
25908
  }, gobj);
25898
25909
  }).catch((e) => {
25899
- (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_FILES_FAILED", { reason: e && e.message ? e.message : String(e) }, gobj);
25910
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_FILES_FAILED", {
25911
+ serial,
25912
+ reason: e && e.message ? e.message : String(e)
25913
+ }, gobj);
25900
25914
  });
25901
25915
  return 0;
25902
25916
  }
25903
25917
  /************************************************************
25918
+ * The form's toolbar while a read is in flight: every button
25919
+ * disabled, the save button spinning. Bulma's `is-loading` is the
25920
+ * spinner; `disabled` is what stops the second click.
25921
+ ************************************************************/
25922
+ function set_form_busy(gobj, busy) {
25923
+ let priv = gobj.priv;
25924
+ if (!priv.form) return;
25925
+ const $container = (0, _yuneta_gobj_js.gobj_read_attr)(priv.form, "$container");
25926
+ if (!$container) return;
25927
+ $container.querySelectorAll(".yui-toolbar-form button").forEach(($b) => {
25928
+ if (busy) {
25929
+ $b.dataset.was_disabled = $b.disabled ? "1" : "0";
25930
+ $b.disabled = true;
25931
+ } else if ($b.dataset.was_disabled !== void 0) {
25932
+ $b.disabled = $b.dataset.was_disabled === "1";
25933
+ delete $b.dataset.was_disabled;
25934
+ }
25935
+ });
25936
+ const $save = $container.querySelector(".yui-toolbar-form .button-save");
25937
+ if ($save) $save.classList.toggle("is-loading", !!busy);
25938
+ }
25939
+ /************************************************************
25940
+ * Is this the read the view is waiting for? A read whose form was
25941
+ * closed (teardown zeroes the serial) or replaced lands on nobody.
25942
+ ************************************************************/
25943
+ function read_is_current(gobj, kw) {
25944
+ let priv = gobj.priv;
25945
+ if (!priv.form || !priv.reading_files || kw.serial !== priv.reading_files) {
25946
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: files read for a form that is gone, dropped`);
25947
+ return false;
25948
+ }
25949
+ return true;
25950
+ }
25951
+ /************************************************************
25904
25952
  * The one place a write of this view leaves for the app.
25905
25953
  ************************************************************/
25906
25954
  function publish_treedb_write(gobj, mode, record, jn_files) {
@@ -25915,6 +25963,8 @@ function publish_treedb_write(gobj, mode, record, jn_files) {
25915
25963
  * {mode, record, picks} -- the bytes are here now
25916
25964
  ************************************************************/
25917
25965
  function ac_files_read(gobj, event, kw, src) {
25966
+ if (!read_is_current(gobj, kw)) return -1;
25967
+ gobj.priv.reading_files = 0;
25918
25968
  const { record, __files__ } = yui_files_manifest(kw.picks, kw.record);
25919
25969
  publish_treedb_write(gobj, kw.mode, record, __files__);
25920
25970
  close_form_dialog(gobj);
@@ -25927,6 +25977,9 @@ function ac_files_read(gobj, event, kw, src) {
25927
25977
  * throw away what the person typed for a failure that is not theirs.
25928
25978
  ************************************************************/
25929
25979
  function ac_files_failed(gobj, event, kw, src) {
25980
+ if (!read_is_current(gobj, kw)) return -1;
25981
+ gobj.priv.reading_files = 0;
25982
+ set_form_busy(gobj, false);
25930
25983
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot read the picked file: ${kw.reason}`);
25931
25984
  yui_shell_confirm_ok(yui_shell_of(gobj), "cannot read the picked file", {
25932
25985
  t: i18next.t,
@@ -23807,6 +23807,8 @@ function popup_mount_layer(gobj) {
23807
23807
  * Framework Method: Create
23808
23808
  ***************************************************************/
23809
23809
  function mt_create$5(gobj) {
23810
+ gobj.priv.reading_files = 0;
23811
+ gobj.priv.read_serial = 0;
23810
23812
  let name = clean_name(gobj_name(gobj));
23811
23813
  gobj_write_attr(gobj, "table_id", "table" + name);
23812
23814
  gobj_write_attr(gobj, "toolbar_id", "toolbar" + name);
@@ -25055,6 +25057,7 @@ function form_may_close(gobj) {
25055
25057
  ************************************************************/
25056
25058
  function teardown_form_child(gobj) {
25057
25059
  let priv = gobj.priv;
25060
+ priv.reading_files = 0;
25058
25061
  if (priv.form) {
25059
25062
  if (gobj_is_running(priv.form)) gobj_stop(priv.form);
25060
25063
  gobj_destroy(priv.form);
@@ -25862,6 +25865,10 @@ function ac_paste_rows(gobj, event, kw, src) {
25862
25865
  function ac_form_save_record(gobj, event, kw, src) {
25863
25866
  if (refuse_if_readonly$2(gobj, event)) return -1;
25864
25867
  let mode = gobj_read_str_attr(src, "form_mode");
25868
+ if (priv.reading_files) {
25869
+ log_warning(`${gobj_short_name(gobj)}: save ignored, still reading the picked files`);
25870
+ return -1;
25871
+ }
25865
25872
  let picked = {};
25866
25873
  const answer = gobj_command(src, "get_picked_files", {}, gobj);
25867
25874
  if (answer && answer.result >= 0 && answer.data) picked = answer.data;
@@ -25873,6 +25880,9 @@ function ac_form_save_record(gobj, event, kw, src) {
25873
25880
  }, 0);
25874
25881
  return 0;
25875
25882
  }
25883
+ const serial = ++priv.read_serial;
25884
+ priv.reading_files = serial;
25885
+ set_form_busy(gobj, true);
25876
25886
  Promise.all(cols.map((col) => {
25877
25887
  return yui_file_read(picked[col]).then((read) => {
25878
25888
  return {
@@ -25886,16 +25896,54 @@ function ac_form_save_record(gobj, event, kw, src) {
25886
25896
  picks[r.col] = r.read;
25887
25897
  });
25888
25898
  gobj_send_event(gobj, "EV_FILES_READ", {
25899
+ serial,
25889
25900
  mode,
25890
25901
  record: kw,
25891
25902
  picks
25892
25903
  }, gobj);
25893
25904
  }).catch((e) => {
25894
- gobj_send_event(gobj, "EV_FILES_FAILED", { reason: e && e.message ? e.message : String(e) }, gobj);
25905
+ gobj_send_event(gobj, "EV_FILES_FAILED", {
25906
+ serial,
25907
+ reason: e && e.message ? e.message : String(e)
25908
+ }, gobj);
25895
25909
  });
25896
25910
  return 0;
25897
25911
  }
25898
25912
  /************************************************************
25913
+ * The form's toolbar while a read is in flight: every button
25914
+ * disabled, the save button spinning. Bulma's `is-loading` is the
25915
+ * spinner; `disabled` is what stops the second click.
25916
+ ************************************************************/
25917
+ function set_form_busy(gobj, busy) {
25918
+ let priv = gobj.priv;
25919
+ if (!priv.form) return;
25920
+ const $container = gobj_read_attr(priv.form, "$container");
25921
+ if (!$container) return;
25922
+ $container.querySelectorAll(".yui-toolbar-form button").forEach(($b) => {
25923
+ if (busy) {
25924
+ $b.dataset.was_disabled = $b.disabled ? "1" : "0";
25925
+ $b.disabled = true;
25926
+ } else if ($b.dataset.was_disabled !== void 0) {
25927
+ $b.disabled = $b.dataset.was_disabled === "1";
25928
+ delete $b.dataset.was_disabled;
25929
+ }
25930
+ });
25931
+ const $save = $container.querySelector(".yui-toolbar-form .button-save");
25932
+ if ($save) $save.classList.toggle("is-loading", !!busy);
25933
+ }
25934
+ /************************************************************
25935
+ * Is this the read the view is waiting for? A read whose form was
25936
+ * closed (teardown zeroes the serial) or replaced lands on nobody.
25937
+ ************************************************************/
25938
+ function read_is_current(gobj, kw) {
25939
+ let priv = gobj.priv;
25940
+ if (!priv.form || !priv.reading_files || kw.serial !== priv.reading_files) {
25941
+ log_warning(`${gobj_short_name(gobj)}: files read for a form that is gone, dropped`);
25942
+ return false;
25943
+ }
25944
+ return true;
25945
+ }
25946
+ /************************************************************
25899
25947
  * The one place a write of this view leaves for the app.
25900
25948
  ************************************************************/
25901
25949
  function publish_treedb_write(gobj, mode, record, jn_files) {
@@ -25910,6 +25958,8 @@ function publish_treedb_write(gobj, mode, record, jn_files) {
25910
25958
  * {mode, record, picks} -- the bytes are here now
25911
25959
  ************************************************************/
25912
25960
  function ac_files_read(gobj, event, kw, src) {
25961
+ if (!read_is_current(gobj, kw)) return -1;
25962
+ gobj.priv.reading_files = 0;
25913
25963
  const { record, __files__ } = yui_files_manifest(kw.picks, kw.record);
25914
25964
  publish_treedb_write(gobj, kw.mode, record, __files__);
25915
25965
  close_form_dialog(gobj);
@@ -25922,6 +25972,9 @@ function ac_files_read(gobj, event, kw, src) {
25922
25972
  * throw away what the person typed for a failure that is not theirs.
25923
25973
  ************************************************************/
25924
25974
  function ac_files_failed(gobj, event, kw, src) {
25975
+ if (!read_is_current(gobj, kw)) return -1;
25976
+ gobj.priv.reading_files = 0;
25977
+ set_form_busy(gobj, false);
25925
25978
  log_error(`${gobj_short_name(gobj)}: cannot read the picked file: ${kw.reason}`);
25926
25979
  yui_shell_confirm_ok(yui_shell_of(gobj), "cannot read the picked file", {
25927
25980
  t,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.63",
3
+ "version": "7.23.64",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -394,6 +394,12 @@ function popup_mount_layer(gobj)
394
394
  ***************************************************************/
395
395
  function mt_create(gobj)
396
396
  {
397
+ /* 0 = not reading; otherwise the serial of the read in flight. A
398
+ * serial and not a flag, so that a read whose form was closed and
399
+ * reopened cannot land on the new form. */
400
+ gobj.priv.reading_files = 0;
401
+ gobj.priv.read_serial = 0;
402
+
397
403
  let name = clean_name(gobj_name(gobj));
398
404
  gobj_write_attr(gobj, "table_id", "table" + name);
399
405
  gobj_write_attr(gobj, "toolbar_id", "toolbar" + name);
@@ -2219,6 +2225,7 @@ function form_may_close(gobj)
2219
2225
  function teardown_form_child(gobj)
2220
2226
  {
2221
2227
  let priv = gobj.priv;
2228
+ priv.reading_files = 0; // a read in flight lands on nobody
2222
2229
  if(priv.form) {
2223
2230
  if(gobj_is_running(priv.form)) {
2224
2231
  gobj_stop(priv.form);
@@ -3484,6 +3491,13 @@ function ac_form_save_record(gobj, event, kw, src)
3484
3491
  * files never came with the record: the form KEPT them and this is
3485
3492
  * where they are asked for. Nothing picked is the ordinary case.
3486
3493
  *------------------------------------------------------*/
3494
+ if(priv.reading_files) {
3495
+ /* The toolbar is disabled while a read is in flight, so this is
3496
+ * a keyboard shortcut or a script: said, and not a second write. */
3497
+ log_warning(`${gobj_short_name(gobj)}: save ignored, still reading the picked files`);
3498
+ return -1;
3499
+ }
3500
+
3487
3501
  let picked = {};
3488
3502
  const answer = gobj_command(src, "get_picked_files", {}, gobj);
3489
3503
  if(answer && answer.result >= 0 && answer.data) {
@@ -3508,8 +3522,16 @@ function ac_form_save_record(gobj, event, kw, src)
3508
3522
  * notification: it enters the machine as an EVENT, never as a
3509
3523
  * chain of callbacks that the trace cannot see. The dialog stays
3510
3524
  * open until it lands, which is what tells the person that 40 MB
3511
- * are still going up.
3525
+ * are still going up -- and stays open BUSY: its toolbar is
3526
+ * disabled and the save button spins, because a second Save
3527
+ * during the read was a second write, and a Cancel was a save
3528
+ * lost without a word. The serial travels with the read: a read
3529
+ * whose form was closed meanwhile lands on nobody (ac_files_read).
3512
3530
  *------------------------------------------------------*/
3531
+ const serial = ++priv.read_serial;
3532
+ priv.reading_files = serial;
3533
+ set_form_busy(gobj, true);
3534
+
3513
3535
  Promise.all(cols.map((col) => {
3514
3536
  return yui_file_read(picked[col]).then((read) => {
3515
3537
  return {col: col, read: read};
@@ -3520,17 +3542,61 @@ function ac_form_save_record(gobj, event, kw, src)
3520
3542
  picks[r.col] = r.read;
3521
3543
  });
3522
3544
  gobj_send_event(gobj, "EV_FILES_READ",
3523
- {mode: mode, record: kw, picks: picks}, gobj
3545
+ {serial: serial, mode: mode, record: kw, picks: picks}, gobj
3524
3546
  );
3525
3547
  }).catch((e) => {
3526
3548
  gobj_send_event(gobj, "EV_FILES_FAILED",
3527
- {reason: (e && e.message)? e.message: String(e)}, gobj
3549
+ {serial: serial, reason: (e && e.message)? e.message: String(e)}, gobj
3528
3550
  );
3529
3551
  });
3530
3552
 
3531
3553
  return 0;
3532
3554
  }
3533
3555
 
3556
+ /************************************************************
3557
+ * The form's toolbar while a read is in flight: every button
3558
+ * disabled, the save button spinning. Bulma's `is-loading` is the
3559
+ * spinner; `disabled` is what stops the second click.
3560
+ ************************************************************/
3561
+ function set_form_busy(gobj, busy)
3562
+ {
3563
+ let priv = gobj.priv;
3564
+ if(!priv.form) {
3565
+ return;
3566
+ }
3567
+ const $container = gobj_read_attr(priv.form, "$container");
3568
+ if(!$container) {
3569
+ return;
3570
+ }
3571
+ $container.querySelectorAll('.yui-toolbar-form button').forEach(($b) => {
3572
+ if(busy) {
3573
+ $b.dataset.was_disabled = $b.disabled? "1": "0";
3574
+ $b.disabled = true;
3575
+ } else if($b.dataset.was_disabled !== undefined) {
3576
+ $b.disabled = ($b.dataset.was_disabled === "1");
3577
+ delete $b.dataset.was_disabled;
3578
+ }
3579
+ });
3580
+ const $save = $container.querySelector('.yui-toolbar-form .button-save');
3581
+ if($save) {
3582
+ $save.classList.toggle('is-loading', !!busy);
3583
+ }
3584
+ }
3585
+
3586
+ /************************************************************
3587
+ * Is this the read the view is waiting for? A read whose form was
3588
+ * closed (teardown zeroes the serial) or replaced lands on nobody.
3589
+ ************************************************************/
3590
+ function read_is_current(gobj, kw)
3591
+ {
3592
+ let priv = gobj.priv;
3593
+ if(!priv.form || !priv.reading_files || kw.serial !== priv.reading_files) {
3594
+ log_warning(`${gobj_short_name(gobj)}: files read for a form that is gone, dropped`);
3595
+ return false;
3596
+ }
3597
+ return true;
3598
+ }
3599
+
3534
3600
  /************************************************************
3535
3601
  * The one place a write of this view leaves for the app.
3536
3602
  ************************************************************/
@@ -3557,6 +3623,10 @@ function publish_treedb_write(gobj, mode, record, jn_files)
3557
3623
  ************************************************************/
3558
3624
  function ac_files_read(gobj, event, kw, src)
3559
3625
  {
3626
+ if(!read_is_current(gobj, kw)) {
3627
+ return -1; /* Warning already logged */
3628
+ }
3629
+ gobj.priv.reading_files = 0;
3560
3630
  const {record, __files__} = yui_files_manifest(kw.picks, kw.record);
3561
3631
  publish_treedb_write(gobj, kw.mode, record, __files__);
3562
3632
  close_form_dialog(gobj);
@@ -3571,6 +3641,11 @@ function ac_files_read(gobj, event, kw, src)
3571
3641
  ************************************************************/
3572
3642
  function ac_files_failed(gobj, event, kw, src)
3573
3643
  {
3644
+ if(!read_is_current(gobj, kw)) {
3645
+ return -1; /* Warning already logged */
3646
+ }
3647
+ gobj.priv.reading_files = 0;
3648
+ set_form_busy(gobj, false);
3574
3649
  log_error(`${gobj_short_name(gobj)}: cannot read the picked file: ${kw.reason}`);
3575
3650
  /* An i18n KEY, not a sentence: the dialog renders it with `i18n`, so
3576
3651
  * a sentence here would be a key nobody defined and would render as