@yuneta/gobj-ui 2.0.0 → 2.2.3

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.
Files changed (58) hide show
  1. package/README.md +25 -20
  2. package/dist/gobj-ui.cjs.js +2340 -528
  3. package/dist/gobj-ui.es.js +2340 -530
  4. package/index.js +32 -31
  5. package/package.json +6 -7
  6. package/{c_g6_nodes_tree.js → src/c_g6_nodes_tree.js} +6 -1
  7. package/{c_yui_form.js → src/c_yui_form.js} +1 -1
  8. package/{c_yui_gobj_tree_js.js → src/c_yui_gobj_tree_js.js} +1 -1
  9. package/{c_yui_json_graph.js → src/c_yui_json_graph.js} +1 -1
  10. package/{c_yui_main.js → src/c_yui_main.js} +3 -3
  11. package/{c_yui_map.js → src/c_yui_map.js} +6 -1
  12. package/{c_yui_nav.js → src/c_yui_nav.js} +134 -26
  13. package/{c_yui_pager.js → src/c_yui_pager.js} +1 -1
  14. package/{c_yui_routing.css → src/c_yui_routing.css} +1 -1
  15. package/{c_yui_routing.js → src/c_yui_routing.js} +1 -1
  16. package/{c_yui_shell.css → src/c_yui_shell.css} +110 -0
  17. package/{c_yui_shell.js → src/c_yui_shell.js} +175 -13
  18. package/{c_yui_tabs.js → src/c_yui_tabs.js} +1 -1
  19. package/{c_yui_treedb_graph.js → src/c_yui_treedb_graph.js} +35 -9
  20. package/{c_yui_treedb_topic_with_form.js → src/c_yui_treedb_topic_with_form.js} +1 -1
  21. package/{c_yui_treedb_topics.js → src/c_yui_treedb_topics.js} +36 -8
  22. package/{c_yui_uplot.js → src/c_yui_uplot.js} +1 -1
  23. package/{c_yui_window.js → src/c_yui_window.js} +242 -21
  24. package/src/c_yui_window_manager.js +602 -0
  25. package/{c_yui_wizard.js → src/c_yui_wizard.js} +1 -1
  26. package/{shell_modals.js → src/shell_modals.js} +53 -13
  27. package/src/tabulator.css +53 -0
  28. package/src/yui_dev.js +1484 -0
  29. package/{yui_icons.css → src/yui_icons.css} +5 -0
  30. package/src/yui_inputs.css +32 -0
  31. package/src/yui_inputs.js +71 -0
  32. package/vite.config.js +0 -131
  33. package/yui_dev.js +0 -583
  34. /package/{c_yui_main.css → src/c_yui_main.css} +0 -0
  35. /package/{c_yui_map.css → src/c_yui_map.css} +0 -0
  36. /package/{c_yui_treedb_topic_with_form.css → src/c_yui_treedb_topic_with_form.css} +0 -0
  37. /package/{g6_drag_canvas_touch.js → src/g6_drag_canvas_touch.js} +0 -0
  38. /package/{lib_graph.css → src/lib_graph.css} +0 -0
  39. /package/{lib_graph.js → src/lib_graph.js} +0 -0
  40. /package/{lib_icons.js → src/lib_icons.js} +0 -0
  41. /package/{lib_maplibre.js → src/lib_maplibre.js} +0 -0
  42. /package/{pager_helpers.js → src/pager_helpers.js} +0 -0
  43. /package/{pager_helpers.test.js → src/pager_helpers.test.js} +0 -0
  44. /package/{route_resolver.js → src/route_resolver.js} +0 -0
  45. /package/{route_resolver.test.js → src/route_resolver.test.js} +0 -0
  46. /package/{shell_focus_trap.js → src/shell_focus_trap.js} +0 -0
  47. /package/{shell_focus_trap.test.js → src/shell_focus_trap.test.js} +0 -0
  48. /package/{shell_show_on.js → src/shell_show_on.js} +0 -0
  49. /package/{shell_show_on.test.js → src/shell_show_on.test.js} +0 -0
  50. /package/{shell_toolbar_helpers.js → src/shell_toolbar_helpers.js} +0 -0
  51. /package/{shell_toolbar_helpers.test.js → src/shell_toolbar_helpers.test.js} +0 -0
  52. /package/{themes.js → src/themes.js} +0 -0
  53. /package/{wizard_helpers.js → src/wizard_helpers.js} +0 -0
  54. /package/{wizard_helpers.test.js → src/wizard_helpers.test.js} +0 -0
  55. /package/{ytable.css → src/ytable.css} +0 -0
  56. /package/{ytable.js → src/ytable.js} +0 -0
  57. /package/{yui_toolbar.css → src/yui_toolbar.css} +0 -0
  58. /package/{yui_toolbar.js → src/yui_toolbar.js} +0 -0
@@ -30,6 +30,7 @@ import {
30
30
  gobj_create, gobj_destroy,
31
31
  gobj_start, gobj_stop,
32
32
  gobj_publish_event,
33
+ gobj_send_event,
33
34
  gobj_subscribe_event,
34
35
  gobj_read_attr, gobj_read_pointer_attr, gobj_write_attr,
35
36
  createElement2, empty_string, is_object, is_array, is_string,
@@ -495,8 +496,8 @@ function build_ui(gobj)
495
496
  let shell_cfg = config.shell || {};
496
497
 
497
498
  /* Root */
498
- let $root = createElement2(
499
- ["div", {class: "yui-shell"}]
499
+ let $container = createElement2(
500
+ ["div", {class: "C_YUI_SHELL yui-shell"}]
500
501
  );
501
502
 
502
503
  /* Build layers */
@@ -504,7 +505,7 @@ function build_ui(gobj)
504
505
  let $layer = createElement2(
505
506
  ["div", {class: `yui-layer yui-layer-${id}`, style: `z-index:${z};`}]
506
507
  );
507
- $root.appendChild($layer);
508
+ $container.appendChild($layer);
508
509
  priv.layers[id] = $layer;
509
510
  }
510
511
 
@@ -561,9 +562,9 @@ function build_ui(gobj)
561
562
 
562
563
  /* Mount */
563
564
  let $mount = gobj_read_attr(gobj, "mount_element") || document.body;
564
- $mount.appendChild($root);
565
+ $mount.appendChild($container);
565
566
 
566
- gobj_write_attr(gobj, "$container", $root);
567
+ gobj_write_attr(gobj, "$container", $container);
567
568
  }
568
569
 
569
570
  /************************************************************
@@ -1049,10 +1050,11 @@ function navigate_to(gobj, route)
1049
1050
  let prev_route = stage.active_route;
1050
1051
  if(prev_route && prev_route !== matched_route) {
1051
1052
  let prev_gobj = stage.items[prev_route];
1053
+ let $prev = null;
1052
1054
  if(prev_gobj) {
1053
- let $c = gobj_read_attr(prev_gobj, "$container");
1054
- if($c) {
1055
- $c.classList.add("is-hidden");
1055
+ $prev = gobj_read_attr(prev_gobj, "$container");
1056
+ if($prev) {
1057
+ $prev.classList.add("is-hidden");
1056
1058
  }
1057
1059
  }
1058
1060
  /* lazy_destroy: drop previous on exit */
@@ -1064,6 +1066,14 @@ function navigate_to(gobj, route)
1064
1066
  } catch(e) {
1065
1067
  log_warning(`C_YUI_SHELL: lazy_destroy of '${prev_route}' failed: ${e}`);
1066
1068
  }
1069
+ /* The shell appended $container on mount (build_view_gobj), so
1070
+ * remove it symmetrically here: a view that doesn't remove its
1071
+ * own container in mt_destroy would otherwise leak a hidden
1072
+ * copy in the stage on every revisit — and any fixed DOM id
1073
+ * inside it then shadows the fresh instance's. */
1074
+ if($prev && $prev.parentNode) {
1075
+ $prev.parentNode.removeChild($prev);
1076
+ }
1067
1077
  delete stage.items[prev_route];
1068
1078
  }
1069
1079
  }
@@ -2085,6 +2095,151 @@ function ac_drawer_close_requested(gobj, event, kw, src)
2085
2095
  return 0;
2086
2096
  }
2087
2097
 
2098
+ /************************************************************
2099
+ * Close 'x' on a closable tab (from a C_YUI_NAV child). The
2100
+ * shell does not own the item set — re-publish so the app (which
2101
+ * owns the underlying data, e.g. the selected-nodes list) removes
2102
+ * the item and calls yui_shell_set_submenu() with the new list.
2103
+ ************************************************************/
2104
+ function ac_nav_item_close(gobj, event, kw, src)
2105
+ {
2106
+ gobj_publish_event(gobj, "EV_NAV_ITEM_CLOSE", {
2107
+ item_id: (kw && kw.item_id) || "",
2108
+ route: (kw && kw.route) || "",
2109
+ menu_id: (kw && kw.menu_id) || "",
2110
+ zone: (kw && kw.zone) || ""
2111
+ });
2112
+ return 0;
2113
+ }
2114
+
2115
+ /************************************************************
2116
+ * Runtime nav API (Yuneta philosophy: the app_config path is the
2117
+ * first, startup caller of the very same machinery — build_item_index
2118
+ * + instantiate + set items; this is its dynamic counterpart).
2119
+ *
2120
+ * yui_shell_set_submenu(shell, parent_item_id, items) replaces the
2121
+ * items of a primary item's submenu (its secondary nav) at runtime
2122
+ * and re-registers their routes so navigation resolves. Item
2123
+ * descriptors may carry { id, name, icon, route, class, closable,
2124
+ * target:{stage,gclass,kw,lifecycle} }. Routes present before but
2125
+ * absent now are pruned (index entry removed, mounted view destroyed).
2126
+ ************************************************************/
2127
+ function find_secondary_nav(priv, parent_item_id)
2128
+ {
2129
+ let suffix = "." + parent_item_id;
2130
+ for(let nav of priv.navs) {
2131
+ let menu_id = gobj_read_attr(nav, "menu_id") || "";
2132
+ if(menu_id.startsWith("secondary.") && menu_id.endsWith(suffix)) {
2133
+ return nav;
2134
+ }
2135
+ }
2136
+ return null;
2137
+ }
2138
+
2139
+ function find_primary_item(shell_gobj, menu_id, item_id)
2140
+ {
2141
+ let config = gobj_read_attr(shell_gobj, "config") || {};
2142
+ let menu = (config.menu && config.menu[menu_id]) || null;
2143
+ if(menu && is_array(menu.items)) {
2144
+ for(let it of menu.items) {
2145
+ if(it && it.id === item_id) {
2146
+ return it;
2147
+ }
2148
+ }
2149
+ }
2150
+ return null;
2151
+ }
2152
+
2153
+ /* Drop a route from the index and destroy any mounted view for it. */
2154
+ function prune_route(shell_gobj, route)
2155
+ {
2156
+ let priv = gobj_read_attr(shell_gobj, "priv");
2157
+ delete priv.item_index[route];
2158
+ for(let stage_name in priv.stages) {
2159
+ let stage = priv.stages[stage_name];
2160
+ let view = stage.items && stage.items[route];
2161
+ if(!view) {
2162
+ continue;
2163
+ }
2164
+ let $c = gobj_read_attr(view, "$container");
2165
+ if($c) {
2166
+ $c.classList.add("is-hidden");
2167
+ }
2168
+ try {
2169
+ gobj_stop(view);
2170
+ gobj_destroy(view);
2171
+ } catch(e) {
2172
+ log_warning(`C_YUI_SHELL: prune_route destroy '${route}' failed: ${e}`);
2173
+ }
2174
+ delete stage.items[route];
2175
+ if(stage.active_route === route) {
2176
+ stage.active_route = "";
2177
+ }
2178
+ }
2179
+ }
2180
+
2181
+ function yui_shell_set_submenu(shell_gobj, parent_item_id, items)
2182
+ {
2183
+ let priv = gobj_read_attr(shell_gobj, "priv");
2184
+ if(!priv) {
2185
+ return -1;
2186
+ }
2187
+ let nav = find_secondary_nav(priv, parent_item_id);
2188
+ if(!nav) {
2189
+ log_warning(
2190
+ `C_YUI_SHELL: yui_shell_set_submenu — no secondary nav for '${parent_item_id}'`
2191
+ );
2192
+ return -1;
2193
+ }
2194
+ items = is_array(items) ? items : [];
2195
+
2196
+ /* Resolve owning menu_id + primary item from the nav's synthesized
2197
+ * id "secondary.<menu_id>.<parent_item_id>", so registered routes
2198
+ * highlight correctly and keep this secondary nav visible. */
2199
+ let nav_menu_id = gobj_read_attr(nav, "menu_id") || "";
2200
+ let m = /^secondary\.(.+)\.([^.]+)$/.exec(nav_menu_id);
2201
+ let owning_menu_id = m ? m[1] : "";
2202
+ let parent_item = find_primary_item(shell_gobj, owning_menu_id, parent_item_id);
2203
+
2204
+ /* Track the routes THIS submenu owns dynamically, so we only prune
2205
+ * our own previous routes — never the static config routes (e.g. a
2206
+ * base "/console/agent" landing declared in app_config). */
2207
+ priv.dynamic_routes = priv.dynamic_routes || {};
2208
+ let prev_routes = priv.dynamic_routes[parent_item_id] || [];
2209
+ let new_routes = [];
2210
+ let new_set = {};
2211
+ for(let it of items) {
2212
+ if(it && it.route) {
2213
+ new_routes.push(it.route);
2214
+ new_set[it.route] = true;
2215
+ }
2216
+ }
2217
+ for(let route of prev_routes) {
2218
+ if(!new_set[route]) {
2219
+ prune_route(shell_gobj, route);
2220
+ }
2221
+ }
2222
+
2223
+ /* Register / refresh routes for the new items. */
2224
+ for(let it of items) {
2225
+ if(!it || !it.route) {
2226
+ continue;
2227
+ }
2228
+ priv.item_index[it.route] = {
2229
+ item: it,
2230
+ parent_item: parent_item,
2231
+ stage: (it.target && it.target.stage) || null,
2232
+ target: it.target || null,
2233
+ menu_id: owning_menu_id
2234
+ };
2235
+ }
2236
+ priv.dynamic_routes[parent_item_id] = new_routes;
2237
+
2238
+ /* Push the new items into the nav (rebuilds its DOM in place). */
2239
+ gobj_send_event(nav, "EV_SET_ITEMS", {items: items}, shell_gobj);
2240
+ return 0;
2241
+ }
2242
+
2088
2243
  /***************************************************************
2089
2244
  * FSM
2090
2245
  ***************************************************************/
@@ -2113,13 +2268,19 @@ function create_gclass(gclass_name)
2113
2268
  ["EV_NAV_CLICKED", ac_nav_clicked, null],
2114
2269
  /* Drawer backdrop close (from a C_YUI_NAV child whose
2115
2270
  * layout is "drawer"). */
2116
- ["EV_DRAWER_CLOSE_REQUESTED", ac_drawer_close_requested, null]
2271
+ ["EV_DRAWER_CLOSE_REQUESTED", ac_drawer_close_requested, null],
2272
+ /* Close 'x' on a closable tab (from a child C_YUI_NAV);
2273
+ * re-published for the app. */
2274
+ ["EV_NAV_ITEM_CLOSE", ac_nav_item_close, null]
2117
2275
  ]]
2118
2276
  ];
2119
2277
 
2120
2278
  const event_types = [
2121
2279
  ["EV_NAV_CLICKED", 0],
2122
2280
  ["EV_DRAWER_CLOSE_REQUESTED", 0],
2281
+ ["EV_NAV_ITEM_CLOSE", event_flag_t.EVF_OUTPUT_EVENT
2282
+ |event_flag_t.EVF_PUBLIC_EVENT
2283
+ |event_flag_t.EVF_NO_WARN_SUBS],
2123
2284
  /* Audit witness: every navigation attempt publishes this BEFORE
2124
2285
  * any work is done, so the FSM trace records intent regardless
2125
2286
  * of whether the route resolves successfully. Pairs with
@@ -2269,11 +2430,11 @@ function yui_shell_set_connection_state(shell_gobj, connected)
2269
2430
  ************************************************************/
2270
2431
  function yui_shell_set_toolbar_item_icon(shell_gobj, item_id, icon_class)
2271
2432
  {
2272
- let $root = gobj_read_attr(shell_gobj, "$container");
2273
- if(!$root || empty_string(item_id) || empty_string(icon_class)) {
2433
+ let $container = gobj_read_attr(shell_gobj, "$container");
2434
+ if(!$container || empty_string(item_id) || empty_string(icon_class)) {
2274
2435
  return;
2275
2436
  }
2276
- let $i = $root.querySelector(
2437
+ let $i = $container.querySelector(
2277
2438
  `[data-toolbar-item-id="${item_id}"] .icon i`
2278
2439
  );
2279
2440
  if($i) {
@@ -2317,5 +2478,6 @@ export {
2317
2478
  yui_shell_set_translator,
2318
2479
  yui_shell_set_connection_state,
2319
2480
  yui_shell_set_toolbar_item_icon,
2320
- yui_shell_close_dropdown
2481
+ yui_shell_close_dropdown,
2482
+ yui_shell_set_submenu
2321
2483
  };
@@ -183,7 +183,7 @@ function build_ui(gobj)
183
183
  let tabs_style = gobj_read_attr(gobj, "tabs_style");
184
184
  let $container = createElement2(
185
185
  // Don't use is-flex, don't work well with is-hidden
186
- ['div', {class: `yui_tabs`, style: 'height:100%; display:flex; flex-direction:column;'}, [
186
+ ['div', {class: `C_YUI_TABS`, style: 'height:100%; display:flex; flex-direction:column;'}, [
187
187
  ['div', {class: 'is-flex-grow-0'}, [
188
188
  ['div', {class: `tabs ${tabs_style}`, style: ''}, [
189
189
  ['ul', {}]
@@ -319,7 +319,7 @@ function build_ui(gobj)
319
319
 
320
320
  let $container = createElement2(
321
321
  // Don't use is-flex, don't work well with is-hidden
322
- ['div', {class: 'graphs', style: `height:100%; display:flex; flex-direction:column;`}, [
322
+ ['div', {class: 'C_YUI_TREEDB_GRAPH', style: `height:100%; display:flex; flex-direction:column;`}, [
323
323
  ['div', {class: 'is-flex-grow-0 is-flex is-align-items-center toolbar_yui_treedb_graph'}, $toolbar],
324
324
  ['div', {class: `is-flex-grow-1 ${padding}`, style: 'height:100%; min-height:0; overflow:hidden;'}, [
325
325
  ['div', {id: priv.canvas_id, class: `graph-container`, style: 'height:100%; min-height:0;border: 1px solid var(--bulma-border-weak);border-radius:0.2rem;'}, [
@@ -333,6 +333,28 @@ function build_ui(gobj)
333
333
  return $container;
334
334
  }
335
335
 
336
+ /************************************************************
337
+ * Show a non-blocking inline error banner at the top of the view
338
+ * (used when the treedb schema `descs` cannot load). Reuses a single
339
+ * banner so retries don't stack.
340
+ ************************************************************/
341
+ function show_load_error(gobj, message)
342
+ {
343
+ let $container = gobj_read_attr(gobj, "$container");
344
+ if(!$container) {
345
+ return;
346
+ }
347
+ let $err = $container.querySelector(".treedb-load-error");
348
+ if(!$err) {
349
+ $err = createElement2(
350
+ ["div", {class: "notification is-danger is-light m-3 treedb-load-error"}, []]
351
+ );
352
+ $container.insertBefore($err, $container.firstChild);
353
+ }
354
+ let treedb = gobj_read_attr(gobj, "treedb_name") || "";
355
+ $err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
356
+ }
357
+
336
358
  /************************************************************
337
359
  * Destroy UI
338
360
  ************************************************************/
@@ -908,18 +930,22 @@ function ac_mt_command_answer(gobj, event, kw, src)
908
930
  log_error(e);
909
931
  return;
910
932
  }
911
- if(result < 0) {
912
- display_error_message(
913
- "Error",
914
- t(comment)
915
- );
916
- // HACK don't return, pass errors when need it.
917
- }
918
-
919
933
  let __command__ = msg_iev_get_stack(gobj, kw, "command_stack", true);
920
934
  let command = kw_get_str(gobj, __command__, "command", "", kw_flag_t.KW_REQUIRED);
921
935
  let kw_command = kw_get_dict(gobj, __command__, "kw", {}, kw_flag_t.KW_REQUIRED);
922
936
 
937
+ if(result < 0) {
938
+ if(command === "descs") {
939
+ /* The schema couldn't load (not a treedb, no authz for it, backend
940
+ * down…). Show an inline banner in the view rather than a blocking
941
+ * app-modal that wedges the whole SPA behind an empty tab. */
942
+ show_load_error(gobj, t(comment));
943
+ } else {
944
+ display_error_message("Error", t(comment));
945
+ }
946
+ // HACK don't return for non-descs, pass errors when need it.
947
+ }
948
+
923
949
  switch(command) {
924
950
  case "descs":
925
951
  if(result >= 0) {
@@ -506,7 +506,7 @@ function build_ui(gobj)
506
506
  *----------------------------------------------*/
507
507
  let table_id = gobj_read_str_attr(gobj, "table_id");
508
508
  let $container = createElement2(
509
- ['div', {class: 'container-treedb-topic-with-form', style: 'height:100%;'}, [
509
+ ['div', {class: 'C_YUI_TREEDB_TOPIC_WITH_FORM', style: 'height:100%;'}, [
510
510
  ['div', {class: 'toolbar_tabulator_table m-1', style: 'display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;'}],
511
511
  ['div',
512
512
  {
@@ -216,7 +216,7 @@ function build_ui(gobj)
216
216
  * Layout Schema
217
217
  *----------------------------------------------*/
218
218
  let $container = createElement2(
219
- ['div', {class: `${gobj_read_attr(gobj, "treedb_name")}`, style: 'height:100%; display:flex; flex-direction:column;'}, [
219
+ ['div', {class: `C_YUI_TREEDB_TOPICS ${gobj_read_attr(gobj, "treedb_name")}`, style: 'height:100%; display:flex; flex-direction:column;'}, [
220
220
  ['div', {class: 'is-flex-grow-0'}, [
221
221
  ['div', {class: `tabs ${gobj_read_attr(gobj, "tabs_style")}`, style: ''}, [
222
222
  ['ul', {}]
@@ -229,6 +229,28 @@ function build_ui(gobj)
229
229
  gobj_write_attr(gobj, "$container", $container);
230
230
  }
231
231
 
232
+ /************************************************************
233
+ * Show a non-blocking inline error banner at the top of the view
234
+ * (used when the treedb schema `descs` cannot load). Reuses a single
235
+ * banner so retries don't stack.
236
+ ************************************************************/
237
+ function show_load_error(gobj, message)
238
+ {
239
+ let $container = gobj_read_attr(gobj, "$container");
240
+ if(!$container) {
241
+ return;
242
+ }
243
+ let $err = $container.querySelector(".treedb-load-error");
244
+ if(!$err) {
245
+ $err = createElement2(
246
+ ["div", {class: "notification is-danger is-light m-3 treedb-load-error"}, []]
247
+ );
248
+ $container.insertBefore($err, $container.firstChild);
249
+ }
250
+ let treedb = gobj_read_attr(gobj, "treedb_name") || "";
251
+ $err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
252
+ }
253
+
232
254
  /************************************************************
233
255
  * Destroy UI
234
256
  ************************************************************/
@@ -786,16 +808,22 @@ function ac_mt_command_answer(gobj, event, kw, src)
786
808
  log_error(e);
787
809
  return;
788
810
  }
789
- if(result < 0) {
790
- display_error_message(
791
- "Error",
792
- t(comment)
793
- );
794
- }
795
-
796
811
  let __command__ = msg_iev_get_stack(gobj, kw, "command_stack", true);
797
812
  let command = kw_get_str(gobj, __command__, "command", "", kw_flag_t.KW_REQUIRED);
798
813
  let kw_command = kw_get_dict(gobj, __command__, "kw", {}, kw_flag_t.KW_REQUIRED);
814
+
815
+ if(result < 0) {
816
+ if(command === "descs") {
817
+ /* The schema couldn't load (not a treedb, no authz for it, backend
818
+ * down…). Show an inline banner in the view rather than a blocking
819
+ * app-modal that wedges the whole SPA behind an empty tab. */
820
+ show_load_error(gobj, t(comment));
821
+ } else {
822
+ display_error_message("Error", t(comment));
823
+ }
824
+ return 0;
825
+ }
826
+
799
827
  switch(command) {
800
828
  case "descs":
801
829
  if(result >= 0) {
@@ -145,7 +145,7 @@ function build_ui(gobj)
145
145
  $container = createElement2(
146
146
  ['div',
147
147
  {
148
- class: '',
148
+ class: 'C_YUI_UPLOT',
149
149
  style: 'overflow:auto;'
150
150
  }
151
151
  ]