@yuneta/gobj-ui 7.13.5 → 7.14.0

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,
@@ -23751,6 +23752,7 @@ function remote_command(gobj, command, kw) {
23751
23752
  function build_model(gobj) {
23752
23753
  let priv = gobj.priv;
23753
23754
  priv.model = build_schema_model(priv.records);
23755
+ priv.order_undo = {};
23754
23756
  priv.baseline = {};
23755
23757
  for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
23756
23758
  }
@@ -23987,7 +23989,10 @@ function render_toolbar(gobj) {
23987
23989
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
23988
23990
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
23989
23991
  }
23990
- if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23992
+ if (priv.topic_name && !readonly && !priv.diagram) {
23993
+ 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));
23994
+ $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23995
+ }
23991
23996
  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
23997
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
23993
23998
  let $bar = (0, _yuneta_gobj_js.createElement2)([
@@ -25818,6 +25823,53 @@ function version_writes(gobj, topic) {
25818
25823
  return writes;
25819
25824
  }
25820
25825
  /***************************************************************
25826
+ * WHERE THE COLUMNS WERE before this session started moving them.
25827
+ *
25828
+ * A drag is a WRITE: the order is a field of the column, so the drop
25829
+ * lands in the store the moment you let go, and the only way back used
25830
+ * to be dragging every row to where you thought it was. The order is
25831
+ * remembered once per topic -- before the FIRST drag, not before each
25832
+ * one -- because the operator who tries three arrangements wants the
25833
+ * one they started from, not the third.
25834
+ *
25835
+ * A reload drops it (see build_model): what it names is what was on
25836
+ * screen, and a reload brings the stored order instead.
25837
+ ***************************************************************/
25838
+ function remember_order(gobj, topic) {
25839
+ let priv = gobj.priv;
25840
+ if (!topic || !priv.order_undo || 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
@@ -26255,6 +26307,7 @@ function ac_move_column(gobj, event, kw, src) {
26255
26307
  (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
26256
26308
  return -1;
26257
26309
  }
26310
+ remember_order(gobj, topic);
26258
26311
  let from = kw.from;
26259
26312
  let to = kw.to;
26260
26313
  let list = topic.cols.slice();
@@ -26278,6 +26331,26 @@ function ac_move_column(gobj, event, kw, src) {
26278
26331
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26279
26332
  }
26280
26333
  /***************************************************************
26334
+ * Put the columns back where they were before the dragging
26335
+ * started. Another write, because the drag was one.
26336
+ ***************************************************************/
26337
+ function ac_undo_order(gobj, event, kw, src) {
26338
+ let priv = gobj.priv;
26339
+ let topic = current_topic(gobj);
26340
+ if (refuse_if_readonly(gobj, event)) return -1;
26341
+ if (!topic) {
26342
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no topic open`);
26343
+ return -1;
26344
+ }
26345
+ let writes = undo_order_writes(gobj, topic);
26346
+ if (writes.length === 0) {
26347
+ (0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: nothing to undo in ${topic.name}`);
26348
+ return 0;
26349
+ }
26350
+ delete priv.order_undo[topic.id];
26351
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26352
+ }
26353
+ /***************************************************************
26281
26354
  * Editing a topic.
26282
26355
  ***************************************************************/
26283
26356
  function ac_add_topic(gobj, event, kw, src) {
@@ -26705,6 +26778,11 @@ function create_gclass$2(gclass_name) {
26705
26778
  ac_move_column,
26706
26779
  null
26707
26780
  ],
26781
+ [
26782
+ "EV_UNDO_ORDER",
26783
+ ac_undo_order,
26784
+ null
26785
+ ],
26708
26786
  [
26709
26787
  "EV_BUMP_VERSION",
26710
26788
  ac_bump_version,
@@ -26736,6 +26814,7 @@ function create_gclass$2(gclass_name) {
26736
26814
  ["EV_DELETE_COLUMN", 0],
26737
26815
  ["EV_SAVE_COLUMN", 0],
26738
26816
  ["EV_MOVE_COLUMN", 0],
26817
+ ["EV_UNDO_ORDER", 0],
26739
26818
  ["EV_BUMP_VERSION", 0],
26740
26819
  ["EV_VALIDATE", 0],
26741
26820
  ["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,
@@ -23738,6 +23739,7 @@ function remote_command(gobj, command, kw) {
23738
23739
  function build_model(gobj) {
23739
23740
  let priv = gobj.priv;
23740
23741
  priv.model = build_schema_model(priv.records);
23742
+ priv.order_undo = {};
23741
23743
  priv.baseline = {};
23742
23744
  for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
23743
23745
  }
@@ -23974,7 +23976,10 @@ function render_toolbar(gobj) {
23974
23976
  $right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
23975
23977
  if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
23976
23978
  }
23977
- if (priv.topic_name && !readonly && !priv.diagram) $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23979
+ if (priv.topic_name && !readonly && !priv.diagram) {
23980
+ 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));
23981
+ $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus", "new column", "EV_ADD_COLUMN", false));
23982
+ }
23978
23983
  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
23984
  $right.push(toolbar_button("SCHEMA_REFRESH_BTN", "yi-arrows-rotate", "refresh", "EV_REFRESH", state === "ST_LOADING"));
23980
23985
  let $bar = createElement2([
@@ -25805,6 +25810,53 @@ function version_writes(gobj, topic) {
25805
25810
  return writes;
25806
25811
  }
25807
25812
  /***************************************************************
25813
+ * WHERE THE COLUMNS WERE before this session started moving them.
25814
+ *
25815
+ * A drag is a WRITE: the order is a field of the column, so the drop
25816
+ * lands in the store the moment you let go, and the only way back used
25817
+ * to be dragging every row to where you thought it was. The order is
25818
+ * remembered once per topic -- before the FIRST drag, not before each
25819
+ * one -- because the operator who tries three arrangements wants the
25820
+ * one they started from, not the third.
25821
+ *
25822
+ * A reload drops it (see build_model): what it names is what was on
25823
+ * screen, and a reload brings the stored order instead.
25824
+ ***************************************************************/
25825
+ function remember_order(gobj, topic) {
25826
+ let priv = gobj.priv;
25827
+ if (!topic || !priv.order_undo || 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
@@ -26242,6 +26294,7 @@ function ac_move_column(gobj, event, kw, src) {
26242
26294
  log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
26243
26295
  return -1;
26244
26296
  }
26297
+ remember_order(gobj, topic);
26245
26298
  let from = kw.from;
26246
26299
  let to = kw.to;
26247
26300
  let list = topic.cols.slice();
@@ -26265,6 +26318,26 @@ function ac_move_column(gobj, event, kw, src) {
26265
26318
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26266
26319
  }
26267
26320
  /***************************************************************
26321
+ * Put the columns back where they were before the dragging
26322
+ * started. Another write, because the drag was one.
26323
+ ***************************************************************/
26324
+ function ac_undo_order(gobj, event, kw, src) {
26325
+ let priv = gobj.priv;
26326
+ let topic = current_topic(gobj);
26327
+ if (refuse_if_readonly(gobj, event)) return -1;
26328
+ if (!topic) {
26329
+ log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
26330
+ return -1;
26331
+ }
26332
+ let writes = undo_order_writes(gobj, topic);
26333
+ if (writes.length === 0) {
26334
+ log_warning(`${gobj_short_name(gobj)}: nothing to undo in ${topic.name}`);
26335
+ return 0;
26336
+ }
26337
+ delete priv.order_undo[topic.id];
26338
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
26339
+ }
26340
+ /***************************************************************
26268
26341
  * Editing a topic.
26269
26342
  ***************************************************************/
26270
26343
  function ac_add_topic(gobj, event, kw, src) {
@@ -26692,6 +26765,11 @@ function create_gclass$2(gclass_name) {
26692
26765
  ac_move_column,
26693
26766
  null
26694
26767
  ],
26768
+ [
26769
+ "EV_UNDO_ORDER",
26770
+ ac_undo_order,
26771
+ null
26772
+ ],
26695
26773
  [
26696
26774
  "EV_BUMP_VERSION",
26697
26775
  ac_bump_version,
@@ -26723,6 +26801,7 @@ function create_gclass$2(gclass_name) {
26723
26801
  ["EV_DELETE_COLUMN", 0],
26724
26802
  ["EV_SAVE_COLUMN", 0],
26725
26803
  ["EV_MOVE_COLUMN", 0],
26804
+ ["EV_UNDO_ORDER", 0],
26726
26805
  ["EV_BUMP_VERSION", 0],
26727
26806
  ["EV_VALIDATE", 0],
26728
26807
  ["EV_EXPORT", 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.13.5",
3
+ "version": "7.14.0",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -72,12 +72,15 @@
72
72
  cursor: pointer;
73
73
  }
74
74
 
75
- /* ...but they hold NAMES, and a treedb name is long: at the shell's 9rem
76
- * (144px) `treedb_yuneta_agent` breaks into three lines inside its own
77
- * card. Start wider here. The shell default is left alone -- it also
78
- * serves grids of short labels, where 12rem would be a lot of air. */
75
+ /* ...but they hold NAMES, and a treedb name is long. At the shell's 9rem
76
+ * (144px) `treedb_yuneta_agent` broke into THREE lines inside its own
77
+ * card, and at 12rem into two: the name shares its row with the icon and
78
+ * the card's padding, so what it gets is some 60px less than the card.
79
+ * 14rem is what fits that name on one line. The shell default is left
80
+ * alone -- it also serves grids of short labels, where this would be a
81
+ * lot of air. */
79
82
  .C_YUI_SCHEMA_EDITOR .yui-nav-cards {
80
- grid-template-columns: repeat(auto-fill, minmax(12rem, 1fr));
83
+ grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
81
84
  }
82
85
 
83
86
  /* The flag grid: as many columns as fit, never fewer than one. */
@@ -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,
@@ -527,6 +528,9 @@ function build_model(gobj)
527
528
  let priv = gobj.priv;
528
529
 
529
530
  priv.model = build_schema_model(priv.records);
531
+ /* The order to go back to is the one that was on screen; a reload
532
+ * brings the stored one, so what was on screen is gone. */
533
+ priv.order_undo = {};
530
534
  priv.baseline = {};
531
535
  for(let treedb of priv.model.treedbs) {
532
536
  for(let topic of treedb.topics) {
@@ -768,6 +772,12 @@ function render_toolbar(gobj)
768
772
  }
769
773
  }
770
774
  if(priv.topic_name && !readonly && !priv.diagram) {
775
+ /* Only while there IS somewhere to go back to: a drag is a write,
776
+ * and this is the way back from one. */
777
+ if(undo_order_writes(gobj, current_topic(gobj)).length > 0) {
778
+ $right.push(toolbar_button("SCHEMA_UNDO_ORDER_BTN", "yi-arrow-rotate-left",
779
+ "undo the order", "EV_UNDO_ORDER", false));
780
+ }
771
781
  $right.push(toolbar_button("SCHEMA_ADD_COL_BTN", "yi-plus",
772
782
  "new column", "EV_ADD_COLUMN", false));
773
783
  }
@@ -2139,6 +2149,56 @@ function version_writes(gobj, topic)
2139
2149
  return writes;
2140
2150
  }
2141
2151
 
2152
+ /***************************************************************
2153
+ * WHERE THE COLUMNS WERE before this session started moving them.
2154
+ *
2155
+ * A drag is a WRITE: the order is a field of the column, so the drop
2156
+ * lands in the store the moment you let go, and the only way back used
2157
+ * to be dragging every row to where you thought it was. The order is
2158
+ * remembered once per topic -- before the FIRST drag, not before each
2159
+ * one -- because the operator who tries three arrangements wants the
2160
+ * one they started from, not the third.
2161
+ *
2162
+ * A reload drops it (see build_model): what it names is what was on
2163
+ * screen, and a reload brings the stored order instead.
2164
+ ***************************************************************/
2165
+ function remember_order(gobj, topic)
2166
+ {
2167
+ let priv = gobj.priv;
2168
+
2169
+ if(!topic || !priv.order_undo || 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
@@ -2797,6 +2857,8 @@ function ac_move_column(gobj, event, kw, src)
2797
2857
  return -1;
2798
2858
  }
2799
2859
 
2860
+ remember_order(gobj, topic);
2861
+
2800
2862
  let from = kw.from;
2801
2863
  let to = kw.to;
2802
2864
  let list = topic.cols.slice();
@@ -2817,6 +2879,35 @@ function ac_move_column(gobj, event, kw, src)
2817
2879
  return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
2818
2880
  }
2819
2881
 
2882
+ /***************************************************************
2883
+ * Put the columns back where they were before the dragging
2884
+ * started. Another write, because the drag was one.
2885
+ ***************************************************************/
2886
+ function ac_undo_order(gobj, event, kw, src)
2887
+ {
2888
+ let priv = gobj.priv;
2889
+ let topic = current_topic(gobj);
2890
+
2891
+ if(refuse_if_readonly(gobj, event)) {
2892
+ return -1;
2893
+ }
2894
+ if(!topic) {
2895
+ log_error(`${gobj_short_name(gobj)}: ${event} with no topic open`);
2896
+ return -1;
2897
+ }
2898
+
2899
+ let writes = undo_order_writes(gobj, topic);
2900
+ if(writes.length === 0) {
2901
+ /* The button is not there in this case; the event can still
2902
+ * arrive from a keyboard path. */
2903
+ log_warning(`${gobj_short_name(gobj)}: nothing to undo in ${topic.name}`);
2904
+ return 0;
2905
+ }
2906
+ /* Spent: what it named is where the columns are about to be. */
2907
+ delete priv.order_undo[topic.id];
2908
+ return queue_writes(gobj, writes.concat(version_writes(gobj, topic)));
2909
+ }
2910
+
2820
2911
  /***************************************************************
2821
2912
  * Editing a topic.
2822
2913
  ***************************************************************/
@@ -3209,6 +3300,7 @@ function create_gclass(gclass_name)
3209
3300
  ["EV_DELETE_COLUMN", ac_delete_column, null],
3210
3301
  ["EV_SAVE_COLUMN", ac_save_column, null],
3211
3302
  ["EV_MOVE_COLUMN", ac_move_column, null],
3303
+ ["EV_UNDO_ORDER", ac_undo_order, null],
3212
3304
  ["EV_BUMP_VERSION", ac_bump_version, null]
3213
3305
  ])],
3214
3306
 
@@ -3251,6 +3343,7 @@ function create_gclass(gclass_name)
3251
3343
  ["EV_DELETE_COLUMN", 0],
3252
3344
  ["EV_SAVE_COLUMN", 0],
3253
3345
  ["EV_MOVE_COLUMN", 0],
3346
+ ["EV_UNDO_ORDER", 0],
3254
3347
  ["EV_BUMP_VERSION", 0],
3255
3348
  ["EV_VALIDATE", 0],
3256
3349
  ["EV_EXPORT", 0],