@yuneta/gobj-ui 7.13.6 → 7.14.1

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 CHANGED
@@ -866,6 +866,14 @@ id on `.`, which works right up to the first name that carries one),
866
866
  `schema_validate.js`, `schema_descs.js`, `schema_to_c.js`, `schema_import.js`,
867
867
  `schema_flags.js`, `schema_write_options.js`. Since 6.1.0.
868
868
 
869
+ **A drag can be undone.** Reordering a column is a WRITE — `order` is a field —
870
+ so the drop lands in the store the moment you let go. The toolbar grows an
871
+ `Undo the order` button that puts the columns back where they were **before the
872
+ dragging started** (remembered once per topic, before the FIRST drag), shown
873
+ only while there is somewhere to go back to, spent when used, and dropped by a
874
+ refresh. Undoing is another write, like the drag. The host must define the key
875
+ `"undo the order"`.
876
+
869
877
  ### Frontend view — `setup_frontend_view`
870
878
 
871
879
  `setup_frontend_view(self)` opens the **gobj tree of the app's own yuno** in a
@@ -23517,6 +23517,7 @@ var PRIVATE_DATA$2 = {
23517
23517
  diagram: false,
23518
23518
  baseline: null,
23519
23519
  written: null,
23520
+ order_undo: null,
23520
23521
  diagram_gobj: null,
23521
23522
  dialog: null,
23522
23523
  save_queue: null,
@@ -23987,7 +23988,10 @@ function render_toolbar(gobj) {
23987
23988
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
23988
23989
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
23989
23990
  }
23990
- if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23991
+ if (priv.topic_name && !readonly && !priv.diagram) {
23992
+ if (undo_order_writes(gobj, current_topic(gobj)).length > 0) $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left", "undo the order", "EV_UNDO_ORDER", false));
23993
+ $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23994
+ }
23991
23995
  if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
23992
23996
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
23993
23997
  let $bar = (0, _yuneta_gobj_js.createElement2)([
@@ -25818,6 +25822,54 @@ function version_writes(gobj, topic) {
25818
25822
  return writes;
25819
25823
  }
25820
25824
  /***************************************************************
25825
+ * WHERE THE COLUMNS WERE before this session started moving them.
25826
+ *
25827
+ * A drag is a WRITE: the order is a field of the column, so the drop
25828
+ * lands in the store the moment you let go, and the only way back used
25829
+ * to be dragging every row to where you thought it was. The order is
25830
+ * remembered once per topic -- before the FIRST drag, not before each
25831
+ * one -- because the operator who tries three arrangements wants the
25832
+ * one they started from, not the third.
25833
+ *
25834
+ * A reload drops it (see build_model): what it names is what was on
25835
+ * screen, and a reload brings the stored order instead.
25836
+ ***************************************************************/
25837
+ function remember_order(gobj, topic) {
25838
+ let priv = gobj.priv;
25839
+ if (!priv.order_undo) priv.order_undo = {};
25840
+ if (!topic || priv.order_undo[topic.id]) return;
25841
+ priv.order_undo[topic.id] = topic.cols.map((col) => {
25842
+ return {
25843
+ id: col.id,
25844
+ order: col.order
25845
+ };
25846
+ });
25847
+ }
25848
+ /***************************************************************
25849
+ * The writes that would put the remembered order back, or an
25850
+ * empty list when there is nothing to undo (no snapshot, or the
25851
+ * columns are already where they were).
25852
+ ***************************************************************/
25853
+ function undo_order_writes(gobj, topic) {
25854
+ let priv = gobj.priv;
25855
+ let snapshot = topic && priv.order_undo ? priv.order_undo[topic.id] : null;
25856
+ if (!snapshot) return [];
25857
+ let writes = [];
25858
+ for (let was of snapshot) {
25859
+ let col = topic.cols.find((c) => c && c.id === was.id);
25860
+ if (!col || col.order === was.order) continue;
25861
+ writes.push({
25862
+ op: "update",
25863
+ topic_name: T_COLS,
25864
+ record: {
25865
+ id: was.id,
25866
+ order: was.order
25867
+ }
25868
+ });
25869
+ }
25870
+ return writes;
25871
+ }
25872
+ /***************************************************************
25821
25873
  * Run a list of writes, one at a time, and say so while it
25822
25874
  * runs. One at a time because each answer patches the model the
25823
25875
  * next one is computed against, and because a treedb that
@@ -26017,6 +26069,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
26017
26069
  render(gobj);
26018
26070
  return 0;
26019
26071
  }
26072
+ priv.order_undo = {};
26020
26073
  build_model(gobj);
26021
26074
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
26022
26075
  }
@@ -26255,6 +26308,7 @@ function ac_move_column(gobj, event, kw, src) {
26255
26308
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
26256
26309
  return -1;
26257
26310
  }
26311
+ remember_order(gobj, topic);
26258
26312
  let from = kw.from;
26259
26313
  let to = kw.to;
26260
26314
  let list = topic.cols.slice();
@@ -26278,6 +26332,26 @@ function ac_move_column(gobj, event, kw, src) {
26278
26332
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26279
26333
  }
26280
26334
  /***************************************************************
26335
+ * Put the columns back where they were before the dragging
26336
+ * started. Another write, because the drag was one.
26337
+ ***************************************************************/
26338
+ function ac_undo_order(gobj, event, kw, src) {
26339
+ let priv = gobj.priv;
26340
+ let topic = current_topic(gobj);
26341
+ if (refuse_if_readonly(gobj, event)) return -1;
26342
+ if (!topic) {
26343
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
26344
+ return -1;
26345
+ }
26346
+ let writes = undo_order_writes(gobj, topic);
26347
+ if (writes.length === 0) {
26348
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: nothing to undo in ${topic.name}`);
26349
+ return 0;
26350
+ }
26351
+ delete priv.order_undo[topic.id];
26352
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26353
+ }
26354
+ /***************************************************************
26281
26355
  * Editing a topic.
26282
26356
  ***************************************************************/
26283
26357
  function ac_add_topic(gobj, event, kw, src) {
@@ -26705,6 +26779,11 @@ function create_gclass$2(gclass_name) {
26705
26779
  ac_move_column,
26706
26780
  null
26707
26781
  ],
26782
+ [
26783
+ "EV_UNDO_ORDER",
26784
+ ac_undo_order,
26785
+ null
26786
+ ],
26708
26787
  [
26709
26788
  "EV_BUMP_VERSION",
26710
26789
  ac_bump_version,
@@ -26736,6 +26815,7 @@ function create_gclass$2(gclass_name) {
26736
26815
  ["EV_DELETE_COLUMN", 0],
26737
26816
  ["EV_SAVE_COLUMN", 0],
26738
26817
  ["EV_MOVE_COLUMN", 0],
26818
+ ["EV_UNDO_ORDER", 0],
26739
26819
  ["EV_BUMP_VERSION", 0],
26740
26820
  ["EV_VALIDATE", 0],
26741
26821
  ["EV_EXPORT", 0],
@@ -23504,6 +23504,7 @@ var PRIVATE_DATA$2 = {
23504
23504
  diagram: false,
23505
23505
  baseline: null,
23506
23506
  written: null,
23507
+ order_undo: null,
23507
23508
  diagram_gobj: null,
23508
23509
  dialog: null,
23509
23510
  save_queue: null,
@@ -23974,7 +23975,10 @@ function render_toolbar(gobj) {
23974
23975
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
23975
23976
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
23976
23977
  }
23977
- if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23978
+ if (priv.topic_name && !readonly && !priv.diagram) {
23979
+ if (undo_order_writes(gobj, current_topic(gobj)).length > 0) $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left", "undo the order", "EV_UNDO_ORDER", false));
23980
+ $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23981
+ }
23978
23982
  if (priv.treedb_id && !priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_TOPIC_BTN", "yi-plus", "new topic", "EV_ADD_TOPIC", false));
23979
23983
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
23980
23984
  let $bar = createElement2([
@@ -25805,6 +25809,54 @@ function version_writes(gobj, topic) {
25805
25809
  return writes;
25806
25810
  }
25807
25811
  /***************************************************************
25812
+ * WHERE THE COLUMNS WERE before this session started moving them.
25813
+ *
25814
+ * A drag is a WRITE: the order is a field of the column, so the drop
25815
+ * lands in the store the moment you let go, and the only way back used
25816
+ * to be dragging every row to where you thought it was. The order is
25817
+ * remembered once per topic -- before the FIRST drag, not before each
25818
+ * one -- because the operator who tries three arrangements wants the
25819
+ * one they started from, not the third.
25820
+ *
25821
+ * A reload drops it (see build_model): what it names is what was on
25822
+ * screen, and a reload brings the stored order instead.
25823
+ ***************************************************************/
25824
+ function remember_order(gobj, topic) {
25825
+ let priv = gobj.priv;
25826
+ if (!priv.order_undo) priv.order_undo = {};
25827
+ if (!topic || priv.order_undo[topic.id]) return;
25828
+ priv.order_undo[topic.id] = topic.cols.map((col) => {
25829
+ return {
25830
+ id: col.id,
25831
+ order: col.order
25832
+ };
25833
+ });
25834
+ }
25835
+ /***************************************************************
25836
+ * The writes that would put the remembered order back, or an
25837
+ * empty list when there is nothing to undo (no snapshot, or the
25838
+ * columns are already where they were).
25839
+ ***************************************************************/
25840
+ function undo_order_writes(gobj, topic) {
25841
+ let priv = gobj.priv;
25842
+ let snapshot = topic && priv.order_undo ? priv.order_undo[topic.id] : null;
25843
+ if (!snapshot) return [];
25844
+ let writes = [];
25845
+ for (let was of snapshot) {
25846
+ let col = topic.cols.find((c) => c && c.id === was.id);
25847
+ if (!col || col.order === was.order) continue;
25848
+ writes.push({
25849
+ op: "update",
25850
+ topic_name: T_COLS,
25851
+ record: {
25852
+ id: was.id,
25853
+ order: was.order
25854
+ }
25855
+ });
25856
+ }
25857
+ return writes;
25858
+ }
25859
+ /***************************************************************
25808
25860
  * Run a list of writes, one at a time, and say so while it
25809
25861
  * runs. One at a time because each answer patches the model the
25810
25862
  * next one is computed against, and because a treedb that
@@ -26004,6 +26056,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
26004
26056
  render(gobj);
26005
26057
  return 0;
26006
26058
  }
26059
+ priv.order_undo = {};
26007
26060
  build_model(gobj);
26008
26061
  return go(gobj, priv.treedb_id, priv.topic_name, priv.diagram, false);
26009
26062
  }
@@ -26242,6 +26295,7 @@ function ac_move_column(gobj, event, kw, src) {
26242
26295
  log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
26243
26296
  return -1;
26244
26297
  }
26298
+ remember_order(gobj, topic);
26245
26299
  let from = kw.from;
26246
26300
  let to = kw.to;
26247
26301
  let list = topic.cols.slice();
@@ -26265,6 +26319,26 @@ function ac_move_column(gobj, event, kw, src) {
26265
26319
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26266
26320
  }
26267
26321
  /***************************************************************
26322
+ * Put the columns back where they were before the dragging
26323
+ * started. Another write, because the drag was one.
26324
+ ***************************************************************/
26325
+ function ac_undo_order(gobj, event, kw, src) {
26326
+ let priv = gobj.priv;
26327
+ let topic = current_topic(gobj);
26328
+ if (refuse_if_readonly(gobj, event)) return -1;
26329
+ if (!topic) {
26330
+ log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
26331
+ return -1;
26332
+ }
26333
+ let writes = undo_order_writes(gobj, topic);
26334
+ if (writes.length === 0) {
26335
+ log_warning(`${gobj_short_name(gobj)}: nothing to undo in ${topic.name}`);
26336
+ return 0;
26337
+ }
26338
+ delete priv.order_undo[topic.id];
26339
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26340
+ }
26341
+ /***************************************************************
26268
26342
  * Editing a topic.
26269
26343
  ***************************************************************/
26270
26344
  function ac_add_topic(gobj, event, kw, src) {
@@ -26692,6 +26766,11 @@ function create_gclass$2(gclass_name) {
26692
26766
  ac_move_column,
26693
26767
  null
26694
26768
  ],
26769
+ [
26770
+ "EV_UNDO_ORDER",
26771
+ ac_undo_order,
26772
+ null
26773
+ ],
26695
26774
  [
26696
26775
  "EV_BUMP_VERSION",
26697
26776
  ac_bump_version,
@@ -26723,6 +26802,7 @@ function create_gclass$2(gclass_name) {
26723
26802
  ["EV_DELETE_COLUMN", 0],
26724
26803
  ["EV_SAVE_COLUMN", 0],
26725
26804
  ["EV_MOVE_COLUMN", 0],
26805
+ ["EV_UNDO_ORDER", 0],
26726
26806
  ["EV_BUMP_VERSION", 0],
26727
26807
  ["EV_VALIDATE", 0],
26728
26808
  ["EV_EXPORT", 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.13.6",
3
+ "version": "7.14.1",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -202,6 +202,7 @@ let PRIVATE_DATA = {
202
202
  * version still has to move. */
203
203
  baseline: null, /* {topic id: topic_version} at load time */
204
204
  written: null, /* {topic id: true} */
205
+ order_undo: null, /* {topic id: [{id, order}]} before the first drag */
205
206
 
206
207
  /* Children and overlays */
207
208
  diagram_gobj: null,
@@ -768,6 +769,12 @@ function render_toolbar(gobj)
768
769
  }
769
770
  }
770
771
  if(priv.topic_name && !readonly && !priv.diagram) {
772
+ /* Only while there IS somewhere to go back to: a drag is a write,
773
+ * and this is the way back from one. */
774
+ if(undo_order_writes(gobj, current_topic(gobj)).length > 0) {
775
+ $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left",
776
+ "undo the order", "EV_UNDO_ORDER", false));
777
+ }
771
778
  $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus",
772
779
  "new column", "EV_ADD_COLUMN", false));
773
780
  }
@@ -2139,6 +2146,59 @@ function version_writes(gobj, topic)
2139
2146
  return writes;
2140
2147
  }
2141
2148
 
2149
+ /***************************************************************
2150
+ * WHERE THE COLUMNS WERE before this session started moving them.
2151
+ *
2152
+ * A drag is a WRITE: the order is a field of the column, so the drop
2153
+ * lands in the store the moment you let go, and the only way back used
2154
+ * to be dragging every row to where you thought it was. The order is
2155
+ * remembered once per topic -- before the FIRST drag, not before each
2156
+ * one -- because the operator who tries three arrangements wants the
2157
+ * one they started from, not the third.
2158
+ *
2159
+ * A reload drops it (see build_model): what it names is what was on
2160
+ * screen, and a reload brings the stored order instead.
2161
+ ***************************************************************/
2162
+ function remember_order(gobj, topic)
2163
+ {
2164
+ let priv = gobj.priv;
2165
+
2166
+ if(!priv.order_undo) {
2167
+ priv.order_undo = {};
2168
+ }
2169
+ if(!topic || priv.order_undo[topic.id]) {
2170
+ return; /* the first drag already said where we started */
2171
+ }
2172
+ priv.order_undo[topic.id] = topic.cols.map((col) => {
2173
+ return {id: col.id, order: col.order};
2174
+ });
2175
+ }
2176
+
2177
+ /***************************************************************
2178
+ * The writes that would put the remembered order back, or an
2179
+ * empty list when there is nothing to undo (no snapshot, or the
2180
+ * columns are already where they were).
2181
+ ***************************************************************/
2182
+ function undo_order_writes(gobj, topic)
2183
+ {
2184
+ let priv = gobj.priv;
2185
+ let snapshot = (topic && priv.order_undo) ? priv.order_undo[topic.id] : null;
2186
+
2187
+ if(!snapshot) {
2188
+ return [];
2189
+ }
2190
+ let writes = [];
2191
+ for(let was of snapshot) {
2192
+ let col = topic.cols.find((c) => c && c.id === was.id);
2193
+ if(!col || col.order === was.order) {
2194
+ continue;
2195
+ }
2196
+ writes.push({op: "update", topic_name: T_COLS,
2197
+ record: {id: was.id, order: was.order}});
2198
+ }
2199
+ return writes;
2200
+ }
2201
+
2142
2202
  /***************************************************************
2143
2203
  * Run a list of writes, one at a time, and say so while it
2144
2204
  * runs. One at a time because each answer patches the model the
@@ -2468,6 +2528,11 @@ function ac_mt_command_answer(gobj, event, kw, src)
2468
2528
  render(gobj);
2469
2529
  return 0;
2470
2530
  }
2531
+ /* Records straight from the store: what an undo would name is the
2532
+ * order that was ON SCREEN, and this is the stored one arriving.
2533
+ * (NOT in build_model(): that also runs on the patch after every
2534
+ * write, which is exactly when the undo has to survive.) */
2535
+ priv.order_undo = {};
2471
2536
  build_model(gobj);
2472
2537
  /* Back to where the operator was: the load may be a refresh, or
2473
2538
  * the answer to a deep link that arrived before the model. */
@@ -2797,6 +2862,8 @@ function ac_move_column(gobj, event, kw, src)
2797
2862
  return -1;
2798
2863
  }
2799
2864
 
2865
+ remember_order(gobj, topic);
2866
+
2800
2867
  let from = kw.from;
2801
2868
  let to = kw.to;
2802
2869
  let list = topic.cols.slice();
@@ -2817,6 +2884,35 @@ function ac_move_column(gobj, event, kw, src)
2817
2884
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
2818
2885
  }
2819
2886
 
2887
+ /***************************************************************
2888
+ * Put the columns back where they were before the dragging
2889
+ * started. Another write, because the drag was one.
2890
+ ***************************************************************/
2891
+ function ac_undo_order(gobj, event, kw, src)
2892
+ {
2893
+ let priv = gobj.priv;
2894
+ let topic = current_topic(gobj);
2895
+
2896
+ if(refuse_if_readonly(gobj, event)) {
2897
+ return -1;
2898
+ }
2899
+ if(!topic) {
2900
+ log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
2901
+ return -1;
2902
+ }
2903
+
2904
+ let writes = undo_order_writes(gobj, topic);
2905
+ if(writes.length === 0) {
2906
+ /* The button is not there in this case; the event can still
2907
+ * arrive from a keyboard path. */
2908
+ log_warning(`${gobj_short_name(gobj)}: nothing to undo in ${topic.name}`);
2909
+ return 0;
2910
+ }
2911
+ /* Spent: what it named is where the columns are about to be. */
2912
+ delete priv.order_undo[topic.id];
2913
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
2914
+ }
2915
+
2820
2916
  /***************************************************************
2821
2917
  * Editing a topic.
2822
2918
  ***************************************************************/
@@ -3209,6 +3305,7 @@ function create_gclass(gclass_name)
3209
3305
  ["EV_DELETE_COLUMN", ac_delete_column, null],
3210
3306
  ["EV_SAVE_COLUMN", ac_save_column, null],
3211
3307
  ["EV_MOVE_COLUMN", ac_move_column, null],
3308
+ ["EV_UNDO_ORDER", ac_undo_order, null],
3212
3309
  ["EV_BUMP_VERSION", ac_bump_version, null]
3213
3310
  ])],
3214
3311
 
@@ -3251,6 +3348,7 @@ function create_gclass(gclass_name)
3251
3348
  ["EV_DELETE_COLUMN", 0],
3252
3349
  ["EV_SAVE_COLUMN", 0],
3253
3350
  ["EV_MOVE_COLUMN", 0],
3351
+ ["EV_UNDO_ORDER", 0],
3254
3352
  ["EV_BUMP_VERSION", 0],
3255
3353
  ["EV_VALIDATE", 0],
3256
3354
  ["EV_EXPORT", 0],