@yuneta/gobj-ui 5.12.0 → 5.13.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.
@@ -16142,7 +16142,9 @@ var PRIVATE_DATA$4 = {
16142
16142
  form: null,
16143
16143
  form_modal: null,
16144
16144
  schema_gobj: null,
16145
- schema_modal: null
16145
+ schema_modal: null,
16146
+ cell_json_gobj: null,
16147
+ cell_json_modal: null
16146
16148
  };
16147
16149
  var __gclass__$4 = null;
16148
16150
  function popup_mount_layer(gobj) {
@@ -16182,6 +16184,7 @@ function mt_stop$4(gobj) {
16182
16184
  if (shell) (0, _yuneta_gobj_js.gobj_unsubscribe_event)(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
16183
16185
  close_form_dialog(gobj);
16184
16186
  close_schema_dialog(gobj);
16187
+ close_cell_json_dialog(gobj);
16185
16188
  table__destroy(gobj);
16186
16189
  }
16187
16190
  /***************************************************************
@@ -16190,6 +16193,7 @@ function mt_stop$4(gobj) {
16190
16193
  function mt_destroy$4(gobj) {
16191
16194
  close_form_dialog(gobj);
16192
16195
  close_schema_dialog(gobj);
16196
+ close_cell_json_dialog(gobj);
16193
16197
  destroy_ui$1(gobj);
16194
16198
  }
16195
16199
  /************************************************************
@@ -16595,6 +16599,20 @@ function create_tabulator(gobj) {
16595
16599
  if (col) return transform__treedb_value_2_table_value(gobj, col, value, row, field);
16596
16600
  return "???";
16597
16601
  }
16602
+ function json_cell_click(e, cell) {
16603
+ if (!cell.getElement().querySelector(".JSON_CELL")) return;
16604
+ e.stopPropagation();
16605
+ let pkey = desc.pkey || "id";
16606
+ let row_id = cell.getData()[pkey];
16607
+ if (row_id === void 0 || row_id === null) {
16608
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row without pkey '${pkey}', cannot open the json of '${cell.getField()}'`);
16609
+ return;
16610
+ }
16611
+ (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SHOW_CELL_JSON", {
16612
+ row_id,
16613
+ col_id: cell.getField()
16614
+ }, gobj);
16615
+ }
16598
16616
  for (let i = 0; i < desc.cols.length; i++) {
16599
16617
  let col = desc.cols[i];
16600
16618
  if (!col.id || col.id[0] === "_") continue;
@@ -16648,7 +16666,10 @@ function create_tabulator(gobj) {
16648
16666
  case "array":
16649
16667
  case "list":
16650
16668
  case "coordinates":
16651
- case "blob": break;
16669
+ case "blob":
16670
+ case "gbuffer":
16671
+ cellClick = json_cell_click;
16672
+ break;
16652
16673
  case "boolean":
16653
16674
  hozAlign = "center";
16654
16675
  vertAlign = "middle";
@@ -16773,6 +16794,36 @@ function table__destroy(gobj) {
16773
16794
  }
16774
16795
  }
16775
16796
  /************************************************************
16797
+ * Cell of a col holding a JSON document (dict/list/blob/
16798
+ * template/coordinates/…): a one-line truncated preview,
16799
+ * marked as a link because the click opens the whole value
16800
+ * in a viewer (json_cell_click -> EV_SHOW_CELL_JSON).
16801
+ *
16802
+ * An empty document gets no link — there is nothing to open,
16803
+ * and json_cell_click uses its absence to ignore the click.
16804
+ *
16805
+ * Built as a DOM node and not as an HTML string: the preview
16806
+ * is raw record data, so it must never be parsed as markup.
16807
+ ************************************************************/
16808
+ function build_json_cell_preview(value) {
16809
+ if (value === null || value === void 0 || (0, _yuneta_gobj_js.json_size)(value) === 0) return "";
16810
+ let text = JSON.stringify(value);
16811
+ if (text && text.length > 20) text = text.substring(0, 20) + "…";
16812
+ return (0, _yuneta_gobj_js.createElement2)([
16813
+ "a",
16814
+ {
16815
+ class: "JSON_CELL",
16816
+ title: (0, i18next.t)("show json"),
16817
+ "data-i18n-title": "show json"
16818
+ },
16819
+ [["span", { class: "JSON_CELL_ICON icon yi-eye" }], [
16820
+ "span",
16821
+ { class: "JSON_CELL_PREVIEW" },
16822
+ text
16823
+ ]]
16824
+ ]);
16825
+ }
16826
+ /************************************************************
16776
16827
  * Convert a record column value from backend to frontend
16777
16828
  ************************************************************/
16778
16829
  function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
@@ -16794,8 +16845,7 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
16794
16845
  case "coordinates":
16795
16846
  case "blob":
16796
16847
  case "gbuffer":
16797
- value = JSON.stringify(value);
16798
- if (value && value.length > 20) value = value.substring(0, 20) + "…";
16848
+ value = build_json_cell_preview(value);
16799
16849
  break;
16800
16850
  case "enum":
16801
16851
  switch (field_desc.real_type) {
@@ -17099,6 +17149,94 @@ function close_schema_dialog(gobj) {
17099
17149
  teardown_schema_child(gobj);
17100
17150
  }
17101
17151
  /************************************************************
17152
+ * Show the JSON document held by ONE CELL — the value of a
17153
+ * dict/list/object/array/blob/template/coordinates col — in
17154
+ * the standardized adaptive dialog, rendered by a C_YUI_JSON
17155
+ * child. The cell can only show a 20-char preview; this is
17156
+ * where the value is actually readable (collapsed, searchable).
17157
+ *
17158
+ * Read-only and offline: the record is already in the table,
17159
+ * so no command is issued and nothing can be edited here (the
17160
+ * edit form remains the way to change the value).
17161
+ ************************************************************/
17162
+ function open_cell_json_dialog(gobj, row_id, col_id) {
17163
+ close_cell_json_dialog(gobj);
17164
+ let priv = gobj.priv;
17165
+ let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
17166
+ if (!tabulator) {
17167
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no table, no cell to show`);
17168
+ return;
17169
+ }
17170
+ let row = tabulator.getRow(row_id);
17171
+ if (!row) {
17172
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row '${row_id}' not found in the table`);
17173
+ return;
17174
+ }
17175
+ let value = row.getData()[col_id];
17176
+ if (value === void 0) {
17177
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: row '${row_id}' has no col '${col_id}'`);
17178
+ return;
17179
+ }
17180
+ let shell = yui_shell_of(gobj);
17181
+ if (!shell) {
17182
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no shell, cannot open the cell json`);
17183
+ return;
17184
+ }
17185
+ let json_view = (0, _yuneta_gobj_js.gobj_create_pure_child)("cell_" + (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj)), "C_YUI_JSON", {}, gobj);
17186
+ if (!json_view) {
17187
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot create the cell json viewer`);
17188
+ return;
17189
+ }
17190
+ priv.cell_json_gobj = json_view;
17191
+ (0, _yuneta_gobj_js.gobj_start)(json_view);
17192
+ let $box = (0, _yuneta_gobj_js.gobj_read_attr)(json_view, "$container");
17193
+ if (!$box) {
17194
+ (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the cell json viewer built no $container`);
17195
+ teardown_cell_json_child(gobj);
17196
+ return;
17197
+ }
17198
+ priv.cell_json_modal = yui_shell_show_modal(shell, $box, {
17199
+ dialog: true,
17200
+ logical_class: "TREEDB_CELL_JSON_SHEET",
17201
+ title_prefix: String(row_id),
17202
+ title: col_id,
17203
+ t: i18next.t,
17204
+ on_close: function() {
17205
+ teardown_cell_json_child(gobj);
17206
+ }
17207
+ });
17208
+ (0, _yuneta_gobj_js.gobj_send_event)(json_view, "EV_SET_JSON", { json: value }, gobj);
17209
+ }
17210
+ /************************************************************
17211
+ * Destroy the hosted C_YUI_JSON child. Called from the cell
17212
+ * modal's on_close — the shell has already removed the dialog
17213
+ * DOM and retired its Escape / history entries.
17214
+ ************************************************************/
17215
+ function teardown_cell_json_child(gobj) {
17216
+ let priv = gobj.priv;
17217
+ if (priv.cell_json_gobj) {
17218
+ if ((0, _yuneta_gobj_js.gobj_is_running)(priv.cell_json_gobj)) (0, _yuneta_gobj_js.gobj_stop)(priv.cell_json_gobj);
17219
+ (0, _yuneta_gobj_js.gobj_destroy)(priv.cell_json_gobj);
17220
+ priv.cell_json_gobj = null;
17221
+ }
17222
+ priv.cell_json_modal = null;
17223
+ }
17224
+ /************************************************************
17225
+ * Close the cell json dialog (teardown, or a second open).
17226
+ * Closing the modal runs its on_close, which tears the
17227
+ * viewer child down.
17228
+ ************************************************************/
17229
+ function close_cell_json_dialog(gobj) {
17230
+ let priv = gobj.priv;
17231
+ if (priv.cell_json_modal) {
17232
+ let modal = priv.cell_json_modal;
17233
+ priv.cell_json_modal = null;
17234
+ modal.close();
17235
+ return;
17236
+ }
17237
+ teardown_cell_json_child(gobj);
17238
+ }
17239
+ /************************************************************
17102
17240
  * True if the topic's pkey col carries the "rowid" flag.
17103
17241
  ************************************************************/
17104
17242
  function pkey_is_rowid(gobj) {
@@ -17701,6 +17839,17 @@ function ac_refresh$1(gobj, event, kw, src) {
17701
17839
  return 0;
17702
17840
  }
17703
17841
  /************************************************************
17842
+ * Show the JSON document of one cell
17843
+ * {
17844
+ * row_id:
17845
+ * col_id:
17846
+ * }
17847
+ ************************************************************/
17848
+ function ac_show_cell_json(gobj, event, kw, src) {
17849
+ open_cell_json_dialog(gobj, kw.row_id, kw.col_id);
17850
+ return 0;
17851
+ }
17852
+ /************************************************************
17704
17853
  * Show the schema (desc) of this topic
17705
17854
  ************************************************************/
17706
17855
  function ac_show_schema(gobj, event, kw, src) {
@@ -17811,6 +17960,11 @@ function create_gclass$4(gclass_name) {
17811
17960
  ac_show_hook_data$1,
17812
17961
  null
17813
17962
  ],
17963
+ [
17964
+ "EV_SHOW_CELL_JSON",
17965
+ ac_show_cell_json,
17966
+ null
17967
+ ],
17814
17968
  [
17815
17969
  "EV_CHANGE_LOCALE",
17816
17970
  ac_change_locale,
@@ -17852,6 +18006,7 @@ function create_gclass$4(gclass_name) {
17852
18006
  ["EV_SELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
17853
18007
  ["EV_UNSELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
17854
18008
  ["EV_SHOW_HOOK_DATA", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
18009
+ ["EV_SHOW_CELL_JSON", 0],
17855
18010
  ["EV_CHANGE_LOCALE", 0],
17856
18011
  ["EV_REFRESH", 0],
17857
18012
  ["EV_SHOW_SCHEMA", 0],
@@ -16137,7 +16137,9 @@ var PRIVATE_DATA$4 = {
16137
16137
  form: null,
16138
16138
  form_modal: null,
16139
16139
  schema_gobj: null,
16140
- schema_modal: null
16140
+ schema_modal: null,
16141
+ cell_json_gobj: null,
16142
+ cell_json_modal: null
16141
16143
  };
16142
16144
  var __gclass__$4 = null;
16143
16145
  function popup_mount_layer(gobj) {
@@ -16177,6 +16179,7 @@ function mt_stop$4(gobj) {
16177
16179
  if (shell) gobj_unsubscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
16178
16180
  close_form_dialog(gobj);
16179
16181
  close_schema_dialog(gobj);
16182
+ close_cell_json_dialog(gobj);
16180
16183
  table__destroy(gobj);
16181
16184
  }
16182
16185
  /***************************************************************
@@ -16185,6 +16188,7 @@ function mt_stop$4(gobj) {
16185
16188
  function mt_destroy$4(gobj) {
16186
16189
  close_form_dialog(gobj);
16187
16190
  close_schema_dialog(gobj);
16191
+ close_cell_json_dialog(gobj);
16188
16192
  destroy_ui$1(gobj);
16189
16193
  }
16190
16194
  /************************************************************
@@ -16590,6 +16594,20 @@ function create_tabulator(gobj) {
16590
16594
  if (col) return transform__treedb_value_2_table_value(gobj, col, value, row, field);
16591
16595
  return "???";
16592
16596
  }
16597
+ function json_cell_click(e, cell) {
16598
+ if (!cell.getElement().querySelector(".JSON_CELL")) return;
16599
+ e.stopPropagation();
16600
+ let pkey = desc.pkey || "id";
16601
+ let row_id = cell.getData()[pkey];
16602
+ if (row_id === void 0 || row_id === null) {
16603
+ log_error(`${gobj_short_name(gobj)}: row without pkey '${pkey}', cannot open the json of '${cell.getField()}'`);
16604
+ return;
16605
+ }
16606
+ gobj_send_event(gobj, "EV_SHOW_CELL_JSON", {
16607
+ row_id,
16608
+ col_id: cell.getField()
16609
+ }, gobj);
16610
+ }
16593
16611
  for (let i = 0; i < desc.cols.length; i++) {
16594
16612
  let col = desc.cols[i];
16595
16613
  if (!col.id || col.id[0] === "_") continue;
@@ -16643,7 +16661,10 @@ function create_tabulator(gobj) {
16643
16661
  case "array":
16644
16662
  case "list":
16645
16663
  case "coordinates":
16646
- case "blob": break;
16664
+ case "blob":
16665
+ case "gbuffer":
16666
+ cellClick = json_cell_click;
16667
+ break;
16647
16668
  case "boolean":
16648
16669
  hozAlign = "center";
16649
16670
  vertAlign = "middle";
@@ -16768,6 +16789,36 @@ function table__destroy(gobj) {
16768
16789
  }
16769
16790
  }
16770
16791
  /************************************************************
16792
+ * Cell of a col holding a JSON document (dict/list/blob/
16793
+ * template/coordinates/…): a one-line truncated preview,
16794
+ * marked as a link because the click opens the whole value
16795
+ * in a viewer (json_cell_click -> EV_SHOW_CELL_JSON).
16796
+ *
16797
+ * An empty document gets no link — there is nothing to open,
16798
+ * and json_cell_click uses its absence to ignore the click.
16799
+ *
16800
+ * Built as a DOM node and not as an HTML string: the preview
16801
+ * is raw record data, so it must never be parsed as markup.
16802
+ ************************************************************/
16803
+ function build_json_cell_preview(value) {
16804
+ if (value === null || value === void 0 || json_size(value) === 0) return "";
16805
+ let text = JSON.stringify(value);
16806
+ if (text && text.length > 20) text = text.substring(0, 20) + "…";
16807
+ return createElement2([
16808
+ "a",
16809
+ {
16810
+ class: "JSON_CELL",
16811
+ title: t("show json"),
16812
+ "data-i18n-title": "show json"
16813
+ },
16814
+ [["span", { class: "JSON_CELL_ICON icon yi-eye" }], [
16815
+ "span",
16816
+ { class: "JSON_CELL_PREVIEW" },
16817
+ text
16818
+ ]]
16819
+ ]);
16820
+ }
16821
+ /************************************************************
16771
16822
  * Convert a record column value from backend to frontend
16772
16823
  ************************************************************/
16773
16824
  function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
@@ -16789,8 +16840,7 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
16789
16840
  case "coordinates":
16790
16841
  case "blob":
16791
16842
  case "gbuffer":
16792
- value = JSON.stringify(value);
16793
- if (value && value.length > 20) value = value.substring(0, 20) + "…";
16843
+ value = build_json_cell_preview(value);
16794
16844
  break;
16795
16845
  case "enum":
16796
16846
  switch (field_desc.real_type) {
@@ -17094,6 +17144,94 @@ function close_schema_dialog(gobj) {
17094
17144
  teardown_schema_child(gobj);
17095
17145
  }
17096
17146
  /************************************************************
17147
+ * Show the JSON document held by ONE CELL — the value of a
17148
+ * dict/list/object/array/blob/template/coordinates col — in
17149
+ * the standardized adaptive dialog, rendered by a C_YUI_JSON
17150
+ * child. The cell can only show a 20-char preview; this is
17151
+ * where the value is actually readable (collapsed, searchable).
17152
+ *
17153
+ * Read-only and offline: the record is already in the table,
17154
+ * so no command is issued and nothing can be edited here (the
17155
+ * edit form remains the way to change the value).
17156
+ ************************************************************/
17157
+ function open_cell_json_dialog(gobj, row_id, col_id) {
17158
+ close_cell_json_dialog(gobj);
17159
+ let priv = gobj.priv;
17160
+ let tabulator = gobj_read_attr(gobj, "tabulator");
17161
+ if (!tabulator) {
17162
+ log_error(`${gobj_short_name(gobj)}: no table, no cell to show`);
17163
+ return;
17164
+ }
17165
+ let row = tabulator.getRow(row_id);
17166
+ if (!row) {
17167
+ log_error(`${gobj_short_name(gobj)}: row '${row_id}' not found in the table`);
17168
+ return;
17169
+ }
17170
+ let value = row.getData()[col_id];
17171
+ if (value === void 0) {
17172
+ log_error(`${gobj_short_name(gobj)}: row '${row_id}' has no col '${col_id}'`);
17173
+ return;
17174
+ }
17175
+ let shell = yui_shell_of(gobj);
17176
+ if (!shell) {
17177
+ log_error(`${gobj_short_name(gobj)}: no shell, cannot open the cell json`);
17178
+ return;
17179
+ }
17180
+ let json_view = gobj_create_pure_child("cell_" + clean_name(gobj_name(gobj)), "C_YUI_JSON", {}, gobj);
17181
+ if (!json_view) {
17182
+ log_error(`${gobj_short_name(gobj)}: cannot create the cell json viewer`);
17183
+ return;
17184
+ }
17185
+ priv.cell_json_gobj = json_view;
17186
+ gobj_start(json_view);
17187
+ let $box = gobj_read_attr(json_view, "$container");
17188
+ if (!$box) {
17189
+ log_error(`${gobj_short_name(gobj)}: the cell json viewer built no $container`);
17190
+ teardown_cell_json_child(gobj);
17191
+ return;
17192
+ }
17193
+ priv.cell_json_modal = yui_shell_show_modal(shell, $box, {
17194
+ dialog: true,
17195
+ logical_class: "TREEDB_CELL_JSON_SHEET",
17196
+ title_prefix: String(row_id),
17197
+ title: col_id,
17198
+ t,
17199
+ on_close: function() {
17200
+ teardown_cell_json_child(gobj);
17201
+ }
17202
+ });
17203
+ gobj_send_event(json_view, "EV_SET_JSON", { json: value }, gobj);
17204
+ }
17205
+ /************************************************************
17206
+ * Destroy the hosted C_YUI_JSON child. Called from the cell
17207
+ * modal's on_close — the shell has already removed the dialog
17208
+ * DOM and retired its Escape / history entries.
17209
+ ************************************************************/
17210
+ function teardown_cell_json_child(gobj) {
17211
+ let priv = gobj.priv;
17212
+ if (priv.cell_json_gobj) {
17213
+ if (gobj_is_running(priv.cell_json_gobj)) gobj_stop(priv.cell_json_gobj);
17214
+ gobj_destroy(priv.cell_json_gobj);
17215
+ priv.cell_json_gobj = null;
17216
+ }
17217
+ priv.cell_json_modal = null;
17218
+ }
17219
+ /************************************************************
17220
+ * Close the cell json dialog (teardown, or a second open).
17221
+ * Closing the modal runs its on_close, which tears the
17222
+ * viewer child down.
17223
+ ************************************************************/
17224
+ function close_cell_json_dialog(gobj) {
17225
+ let priv = gobj.priv;
17226
+ if (priv.cell_json_modal) {
17227
+ let modal = priv.cell_json_modal;
17228
+ priv.cell_json_modal = null;
17229
+ modal.close();
17230
+ return;
17231
+ }
17232
+ teardown_cell_json_child(gobj);
17233
+ }
17234
+ /************************************************************
17097
17235
  * True if the topic's pkey col carries the "rowid" flag.
17098
17236
  ************************************************************/
17099
17237
  function pkey_is_rowid(gobj) {
@@ -17696,6 +17834,17 @@ function ac_refresh$1(gobj, event, kw, src) {
17696
17834
  return 0;
17697
17835
  }
17698
17836
  /************************************************************
17837
+ * Show the JSON document of one cell
17838
+ * {
17839
+ * row_id:
17840
+ * col_id:
17841
+ * }
17842
+ ************************************************************/
17843
+ function ac_show_cell_json(gobj, event, kw, src) {
17844
+ open_cell_json_dialog(gobj, kw.row_id, kw.col_id);
17845
+ return 0;
17846
+ }
17847
+ /************************************************************
17699
17848
  * Show the schema (desc) of this topic
17700
17849
  ************************************************************/
17701
17850
  function ac_show_schema(gobj, event, kw, src) {
@@ -17806,6 +17955,11 @@ function create_gclass$4(gclass_name) {
17806
17955
  ac_show_hook_data$1,
17807
17956
  null
17808
17957
  ],
17958
+ [
17959
+ "EV_SHOW_CELL_JSON",
17960
+ ac_show_cell_json,
17961
+ null
17962
+ ],
17809
17963
  [
17810
17964
  "EV_CHANGE_LOCALE",
17811
17965
  ac_change_locale,
@@ -17847,6 +18001,7 @@ function create_gclass$4(gclass_name) {
17847
18001
  ["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
17848
18002
  ["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
17849
18003
  ["EV_SHOW_HOOK_DATA", event_flag_t.EVF_OUTPUT_EVENT],
18004
+ ["EV_SHOW_CELL_JSON", 0],
17850
18005
  ["EV_CHANGE_LOCALE", 0],
17851
18006
  ["EV_REFRESH", 0],
17852
18007
  ["EV_SHOW_SCHEMA", 0],
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "5.12.0",
3
+ "version": "5.13.0",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
@@ -82,6 +82,24 @@
82
82
  }
83
83
  }
84
84
 
85
+ /* Cell of a col holding a JSON document: a truncated preview that opens
86
+ * the whole value in a viewer. Bulma already paints an <a> as a link
87
+ * (colour + pointer cursor, href or not — the click is an FSM event,
88
+ * not a navigation), so the only thing to state here is that a preview
89
+ * of a JSON fragment must stay on ONE line: wrapped, it would make the
90
+ * row of every structured record three lines tall. */
91
+ .JSON_CELL {
92
+ white-space: nowrap;
93
+ }
94
+ .JSON_CELL .JSON_CELL_ICON {
95
+ margin-right: 0.25rem;
96
+ vertical-align: middle;
97
+ }
98
+ .JSON_CELL .JSON_CELL_PREVIEW {
99
+ text-decoration: underline;
100
+ vertical-align: middle;
101
+ }
102
+
85
103
  .without-border {
86
104
  border: none !important;
87
105
  box-shadow: none !important;
@@ -147,6 +147,8 @@ let PRIVATE_DATA = {
147
147
  form_modal: null, // { close } handle of the adaptive dialog
148
148
  schema_gobj: null, // hosted C_YUI_JSON child (while schema open)
149
149
  schema_modal: null, // { close } handle of the schema dialog
150
+ cell_json_gobj: null, // hosted C_YUI_JSON child (while a cell is open)
151
+ cell_json_modal: null, // { close } handle of the cell dialog
150
152
  };
151
153
 
152
154
  let __gclass__ = null;
@@ -226,6 +228,7 @@ function mt_stop(gobj)
226
228
  }
227
229
  close_form_dialog(gobj);
228
230
  close_schema_dialog(gobj);
231
+ close_cell_json_dialog(gobj);
229
232
  table__destroy(gobj);
230
233
  }
231
234
 
@@ -240,6 +243,7 @@ function mt_destroy(gobj)
240
243
  * listener) and removes the dialog DOM. */
241
244
  close_form_dialog(gobj);
242
245
  close_schema_dialog(gobj);
246
+ close_cell_json_dialog(gobj);
243
247
  destroy_ui(gobj);
244
248
  }
245
249
 
@@ -731,6 +735,36 @@ function create_tabulator(gobj)
731
735
  return "???";
732
736
  }
733
737
 
738
+ /*
739
+ * Click on a JSON-document cell (dict/list/blob/template/…): the cell
740
+ * can only ever show a truncated preview, so open the whole value in
741
+ * the viewer. The kw carries the IDENTITY of the cell (row id + col
742
+ * id), never the value itself — the machine trace dumps the kw.
743
+ */
744
+ function json_cell_click(e, cell)
745
+ {
746
+ if(!cell.getElement().querySelector('.JSON_CELL')) {
747
+ return; // empty document: nothing to open
748
+ }
749
+ e.stopPropagation();
750
+
751
+ let pkey = desc.pkey || "id";
752
+ let row_id = cell.getData()[pkey];
753
+ if(row_id === undefined || row_id === null) {
754
+ log_error(
755
+ `${gobj_short_name(gobj)}: row without pkey '${pkey}',` +
756
+ ` cannot open the json of '${cell.getField()}'`
757
+ );
758
+ return;
759
+ }
760
+ gobj_send_event(
761
+ gobj,
762
+ "EV_SHOW_CELL_JSON",
763
+ {row_id: row_id, col_id: cell.getField()},
764
+ gobj
765
+ );
766
+ }
767
+
734
768
  for (let i = 0; i < desc.cols.length; i++) {
735
769
  let col = desc.cols[i];
736
770
  if(!col.id || col.id[0]==='_') {
@@ -794,6 +828,8 @@ function create_tabulator(gobj)
794
828
  case "list":
795
829
  case "coordinates":
796
830
  case "blob":
831
+ case "gbuffer":
832
+ cellClick = json_cell_click;
797
833
  break;
798
834
  case "boolean":
799
835
  hozAlign = "center";
@@ -984,6 +1020,41 @@ function table__destroy(gobj)
984
1020
  }
985
1021
  }
986
1022
 
1023
+ /************************************************************
1024
+ * Cell of a col holding a JSON document (dict/list/blob/
1025
+ * template/coordinates/…): a one-line truncated preview,
1026
+ * marked as a link because the click opens the whole value
1027
+ * in a viewer (json_cell_click -> EV_SHOW_CELL_JSON).
1028
+ *
1029
+ * An empty document gets no link — there is nothing to open,
1030
+ * and json_cell_click uses its absence to ignore the click.
1031
+ *
1032
+ * Built as a DOM node and not as an HTML string: the preview
1033
+ * is raw record data, so it must never be parsed as markup.
1034
+ ************************************************************/
1035
+ function build_json_cell_preview(value)
1036
+ {
1037
+ if(value === null || value === undefined || json_size(value) === 0) {
1038
+ return "";
1039
+ }
1040
+
1041
+ let text = JSON.stringify(value);
1042
+ if(text && text.length > 20) {
1043
+ text = text.substring(0, 20) + "…";
1044
+ }
1045
+
1046
+ return createElement2(
1047
+ ['a', {
1048
+ class: 'JSON_CELL',
1049
+ title: t('show json'),
1050
+ 'data-i18n-title': 'show json'
1051
+ }, [
1052
+ ['span', {class: 'JSON_CELL_ICON icon yi-eye'}],
1053
+ ['span', {class: 'JSON_CELL_PREVIEW'}, text]
1054
+ ]]
1055
+ );
1056
+ }
1057
+
987
1058
  /************************************************************
988
1059
  * Convert a record column value from backend to frontend
989
1060
  ************************************************************/
@@ -1013,10 +1084,7 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field)
1013
1084
  case "coordinates":
1014
1085
  case "blob":
1015
1086
  case "gbuffer":
1016
- value = JSON.stringify(value);
1017
- if(value && value.length > 20) {
1018
- value = value.substring(0, 20) + "…";
1019
- }
1087
+ value = build_json_cell_preview(value);
1020
1088
  break;
1021
1089
 
1022
1090
  case "enum":
@@ -1462,6 +1530,124 @@ function close_schema_dialog(gobj)
1462
1530
  teardown_schema_child(gobj);
1463
1531
  }
1464
1532
 
1533
+ /************************************************************
1534
+ * Show the JSON document held by ONE CELL — the value of a
1535
+ * dict/list/object/array/blob/template/coordinates col — in
1536
+ * the standardized adaptive dialog, rendered by a C_YUI_JSON
1537
+ * child. The cell can only show a 20-char preview; this is
1538
+ * where the value is actually readable (collapsed, searchable).
1539
+ *
1540
+ * Read-only and offline: the record is already in the table,
1541
+ * so no command is issued and nothing can be edited here (the
1542
+ * edit form remains the way to change the value).
1543
+ ************************************************************/
1544
+ function open_cell_json_dialog(gobj, row_id, col_id)
1545
+ {
1546
+ close_cell_json_dialog(gobj); // only one at a time
1547
+
1548
+ let priv = gobj.priv;
1549
+
1550
+ let tabulator = gobj_read_attr(gobj, "tabulator");
1551
+ if(!tabulator) {
1552
+ log_error(`${gobj_short_name(gobj)}: no table, no cell to show`);
1553
+ return;
1554
+ }
1555
+ let row = tabulator.getRow(row_id);
1556
+ if(!row) {
1557
+ log_error(`${gobj_short_name(gobj)}: row '${row_id}' not found in the table`);
1558
+ return;
1559
+ }
1560
+ let value = row.getData()[col_id];
1561
+ if(value === undefined) {
1562
+ log_error(`${gobj_short_name(gobj)}: row '${row_id}' has no col '${col_id}'`);
1563
+ return;
1564
+ }
1565
+
1566
+ let shell = yui_shell_of(gobj);
1567
+ if(!shell) {
1568
+ log_error(`${gobj_short_name(gobj)}: no shell, cannot open the cell json`);
1569
+ return;
1570
+ }
1571
+
1572
+ let json_view = gobj_create_pure_child(
1573
+ "cell_" + clean_name(gobj_name(gobj)),
1574
+ "C_YUI_JSON",
1575
+ {
1576
+ /* No `title`: the dialog header already titles it. */
1577
+ },
1578
+ gobj
1579
+ );
1580
+ if(!json_view) {
1581
+ log_error(`${gobj_short_name(gobj)}: cannot create the cell json viewer`);
1582
+ return;
1583
+ }
1584
+ priv.cell_json_gobj = json_view;
1585
+ gobj_start(json_view);
1586
+
1587
+ let $box = gobj_read_attr(json_view, "$container");
1588
+ if(!$box) {
1589
+ log_error(`${gobj_short_name(gobj)}: the cell json viewer built no $container`);
1590
+ teardown_cell_json_child(gobj);
1591
+ return;
1592
+ }
1593
+
1594
+ /* Title split in two halves, same contract as the schema dialog: the
1595
+ * record id is DATA (never translated) and the column carries its own
1596
+ * i18n key — the shared `col.id` one, so the header re-translates on a
1597
+ * language switch and reads as the raw id where the app defines no key
1598
+ * (exactly what an untranslated column header already shows). */
1599
+ priv.cell_json_modal = yui_shell_show_modal(shell, $box, {
1600
+ dialog: true,
1601
+ logical_class: "TREEDB_CELL_JSON_SHEET",
1602
+ title_prefix: String(row_id),
1603
+ title: col_id,
1604
+ t: t,
1605
+ on_close: function() {
1606
+ teardown_cell_json_child(gobj);
1607
+ }
1608
+ });
1609
+
1610
+ /* EV_SET_JSON and not the `json_data` attr: the attr renders the
1611
+ * tree but leaves the viewer in ST_IDLE, where a click to expand a
1612
+ * node is an event nobody handles. */
1613
+ gobj_send_event(json_view, "EV_SET_JSON", {json: value}, gobj);
1614
+ }
1615
+
1616
+ /************************************************************
1617
+ * Destroy the hosted C_YUI_JSON child. Called from the cell
1618
+ * modal's on_close — the shell has already removed the dialog
1619
+ * DOM and retired its Escape / history entries.
1620
+ ************************************************************/
1621
+ function teardown_cell_json_child(gobj)
1622
+ {
1623
+ let priv = gobj.priv;
1624
+ if(priv.cell_json_gobj) {
1625
+ if(gobj_is_running(priv.cell_json_gobj)) {
1626
+ gobj_stop(priv.cell_json_gobj);
1627
+ }
1628
+ gobj_destroy(priv.cell_json_gobj);
1629
+ priv.cell_json_gobj = null;
1630
+ }
1631
+ priv.cell_json_modal = null;
1632
+ }
1633
+
1634
+ /************************************************************
1635
+ * Close the cell json dialog (teardown, or a second open).
1636
+ * Closing the modal runs its on_close, which tears the
1637
+ * viewer child down.
1638
+ ************************************************************/
1639
+ function close_cell_json_dialog(gobj)
1640
+ {
1641
+ let priv = gobj.priv;
1642
+ if(priv.cell_json_modal) {
1643
+ let modal = priv.cell_json_modal;
1644
+ priv.cell_json_modal = null;
1645
+ modal.close(); // -> on_close -> teardown_cell_json_child
1646
+ return;
1647
+ }
1648
+ teardown_cell_json_child(gobj);
1649
+ }
1650
+
1465
1651
  /************************************************************
1466
1652
  * True if the topic's pkey col carries the "rowid" flag.
1467
1653
  ************************************************************/
@@ -2418,6 +2604,20 @@ function ac_refresh(gobj, event, kw, src)
2418
2604
  return 0;
2419
2605
  }
2420
2606
 
2607
+ /************************************************************
2608
+ * Show the JSON document of one cell
2609
+ * {
2610
+ * row_id:
2611
+ * col_id:
2612
+ * }
2613
+ ************************************************************/
2614
+ function ac_show_cell_json(gobj, event, kw, src)
2615
+ {
2616
+ open_cell_json_dialog(gobj, kw.row_id, kw.col_id);
2617
+
2618
+ return 0;
2619
+ }
2620
+
2421
2621
  /************************************************************
2422
2622
  * Show the schema (desc) of this topic
2423
2623
  ************************************************************/
@@ -2500,6 +2700,7 @@ function create_gclass(gclass_name)
2500
2700
  ["EV_COPY_ROWS", ac_copy_rows, null],
2501
2701
  ["EV_PASTE_ROWS", ac_paste_rows, null],
2502
2702
  ["EV_SHOW_HOOK_DATA", ac_show_hook_data, null],
2703
+ ["EV_SHOW_CELL_JSON", ac_show_cell_json, null],
2503
2704
  ["EV_CHANGE_LOCALE", ac_change_locale, null],
2504
2705
  ["EV_REFRESH", ac_refresh, null],
2505
2706
  ["EV_SHOW_SCHEMA", ac_show_schema, null],
@@ -2527,6 +2728,7 @@ function create_gclass(gclass_name)
2527
2728
  ["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
2528
2729
  ["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
2529
2730
  ["EV_SHOW_HOOK_DATA", event_flag_t.EVF_OUTPUT_EVENT],
2731
+ ["EV_SHOW_CELL_JSON", 0],
2530
2732
  ["EV_CHANGE_LOCALE", 0],
2531
2733
  ["EV_REFRESH", 0],
2532
2734
  ["EV_SHOW_SCHEMA", 0],