@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
@@ -19,6 +19,7 @@ import {
19
19
  gobj_write_attr,
20
20
  gobj_short_name,
21
21
  clean_name,
22
+ gobj_send_event,
22
23
  gobj_find_service,
23
24
  createElement2,
24
25
  is_gobj,
@@ -49,6 +50,19 @@ import {get_yesnocancel} from "./c_yui_main.js";
49
50
  ***************************************************************/
50
51
  const GCLASS_NAME = "C_YUI_WINDOW";
51
52
 
53
+ /* Window-control glyphs as inline SVG (currentColor → theme-aware,
54
+ * pixel-consistent). There is no minimize/restore glyph in the
55
+ * yui_icons.css mask set, and chrome affordances read better as
56
+ * crisp SVG than as content icons. */
57
+ const WC_MIN = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="3" y="11" width="10" height="1.6" rx="0.8" fill="currentColor"/></svg>';
58
+ const WC_MAX = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="3.3" y="3.3" width="9.4" height="9.4" rx="1.6" fill="none" stroke="currentColor" stroke-width="1.5"/></svg>';
59
+ const WC_RESTORE = '<svg viewBox="0 0 16 16" aria-hidden="true"><rect x="5.2" y="3" width="7.8" height="7.8" rx="1.3" fill="none" stroke="currentColor" stroke-width="1.4"/><rect x="3" y="5.2" width="7.8" height="7.8" rx="1.3" fill="var(--bulma-scheme-main)" stroke="currentColor" stroke-width="1.4"/></svg>';
60
+ const WC_CLOSE = '<svg viewBox="0 0 16 16" aria-hidden="true"><path d="M4 4 L12 12 M12 4 L4 12" stroke="currentColor" stroke-width="1.7" stroke-linecap="round"/></svg>';
61
+
62
+ /* Bulma mobile breakpoint: at or below this a window becomes a
63
+ * full-screen sheet (no float / drag / resize). */
64
+ const MOBILE_MAX = 768;
65
+
52
66
  /***************************************************************
53
67
  * Data
54
68
  ***************************************************************/
@@ -70,9 +84,13 @@ SDATA(data_type_t.DTP_BOOLEAN, "resizable", 0, true, "Allow resizing"),
70
84
  SDATA(data_type_t.DTP_BOOLEAN, "showFooter", 0, true, "Show footer"),
71
85
  SDATA(data_type_t.DTP_BOOLEAN, "openMaximized",0, false, "Open the window maximized"),
72
86
  SDATA(data_type_t.DTP_BOOLEAN, "showMax", 0, true, "Show maximize button"),
87
+ SDATA(data_type_t.DTP_BOOLEAN, "showMin", 0, true, "Show minimize (roll-up / shade) button"),
73
88
  SDATA(data_type_t.DTP_BOOLEAN, "maximized", 0, false, "Flag to indicate if maximized"),
74
89
  SDATA(data_type_t.DTP_JSON, "window_style", 0, "{}", "Override window style"),
75
90
  SDATA(data_type_t.DTP_POINTER, "on_close", 0, null, "Callback on destroy"),
91
+ SDATA(data_type_t.DTP_POINTER, "manager", 0, null, "Optional C_YUI_WINDOW_MANAGER (gobj or service name) for dock/taskbar"),
92
+ SDATA(data_type_t.DTP_STRING, "title", 0, "", "Window title, shown on the dock chip"),
93
+ SDATA(data_type_t.DTP_STRING, "icon", 0, "", "Dock-chip icon: a yi-* class name or inline SVG (by window type)"),
76
94
  // TODO pendiente focus modal keyboard
77
95
  SDATA(data_type_t.DTP_POINTER, "focus", 0, null, "Brings focus to the element, can be a number or selector"),
78
96
  SDATA(data_type_t.DTP_BOOLEAN, "modal", 0, false, "Enable modal mode"),
@@ -85,6 +103,7 @@ SDATA_END()
85
103
 
86
104
  let PRIVATE_DATA = {
87
105
  prevSize: 0,
106
+ preShadeHeight: 0,
88
107
  };
89
108
 
90
109
  let __gclass__ = null;
@@ -116,6 +135,27 @@ function mt_create(gobj)
116
135
  gobj_write_attr(gobj, "window_id", window_id);
117
136
  build_ui(gobj);
118
137
 
138
+ /* Optional window manager (dock/taskbar): register, and raise/
139
+ * highlight on any pointer press. Absent → the window is a plain
140
+ * floating window and minimize falls back to shade in place. */
141
+ let manager = resolve_manager(gobj);
142
+ if(manager) {
143
+ let $c = gobj_read_attr(gobj, "$container");
144
+ if($c) {
145
+ $c.addEventListener("pointerdown", function() {
146
+ let m = gobj_read_pointer_attr(gobj, "manager");
147
+ if(m) {
148
+ gobj_send_event(m, "EV_FOCUS_WINDOW", {window: gobj}, gobj);
149
+ }
150
+ }, true);
151
+ }
152
+ gobj_send_event(manager, "EV_REGISTER_WINDOW", {
153
+ window: gobj,
154
+ title: gobj_read_attr(gobj, "title") || gobj_short_name(gobj),
155
+ icon: gobj_read_attr(gobj, "icon") || "",
156
+ }, gobj);
157
+ }
158
+
119
159
  /* Keep the window inside the viewport on a breakpoint change.
120
160
  * Wired in mt_create (NOT mt_start) on purpose: windows are
121
161
  * often created via gobj_create_service WITHOUT being started
@@ -159,6 +199,11 @@ function mt_stop(gobj)
159
199
  ***************************************************************/
160
200
  function mt_destroy(gobj)
161
201
  {
202
+ let manager = gobj_read_pointer_attr(gobj, "manager");
203
+ if(manager) {
204
+ gobj_send_event(manager, "EV_UNREGISTER_WINDOW", {window: gobj}, gobj);
205
+ }
206
+
162
207
  let on_win_resize = gobj_read_attr(gobj, "win_resize_handler");
163
208
  if(on_win_resize) {
164
209
  window.removeEventListener("resize", on_win_resize);
@@ -177,11 +222,122 @@ function mt_destroy(gobj)
177
222
 
178
223
 
179
224
 
225
+ /************************************************************
226
+ * Inject the window-chrome stylesheet once. Theme-aware via
227
+ * Bulma scheme vars (flips on <html data-theme>); replaces the
228
+ * old saturated `has-background-info` bar + forced black text.
229
+ ************************************************************/
230
+ function ensure_window_style()
231
+ {
232
+ if(document.getElementById('yui-window-style')) {
233
+ return;
234
+ }
235
+ let css = `
236
+ .yui-window-header {
237
+ background: var(--bulma-scheme-main-bis);
238
+ color: var(--bulma-text-strong);
239
+ -webkit-user-select: none; user-select: none;
240
+ }
241
+ .yui-window-titlebar-controls { display: flex; align-items: center; gap: 2px; padding-left: 6px; }
242
+ .yui-wc {
243
+ width: 30px; height: 26px; display: inline-flex; align-items: center; justify-content: center;
244
+ padding: 0; border: 0; background: transparent; color: var(--bulma-text); cursor: pointer;
245
+ border-radius: 5px; -webkit-tap-highlight-color: transparent;
246
+ }
247
+ .yui-wc:hover { background: var(--bulma-scheme-main-ter); color: var(--bulma-text-strong); }
248
+ .yui-wc.wc-close:hover { background: #e0364a; color: #fff; }
249
+ .yui-wc svg { width: 15px; height: 15px; display: block; }
250
+ .C_YUI_WINDOW.is-shaded .yui-window-body,
251
+ .C_YUI_WINDOW.is-shaded .yui-window-footer { display: none !important; }
252
+ .C_YUI_WINDOW.is-shaded { height: auto !important; }
253
+ .yui-window-resize { color: var(--bulma-text-weak); opacity: 0.55; }
254
+ .yui-window-resize:hover { opacity: 1; color: var(--bulma-text); }
255
+ @media (max-width: ${MOBILE_MAX}px) {
256
+ .C_YUI_WINDOW.is-mobile-sheet { border-radius: 0 !important; box-shadow: none !important; }
257
+ .C_YUI_WINDOW.is-mobile-sheet .yui-window-resize { display: none !important; }
258
+ .yui-wc { width: 42px; height: 38px; }
259
+ .yui-wc.wc-max { display: none !important; }
260
+ .yui-wc svg { width: 18px; height: 18px; }
261
+ }
262
+ `;
263
+ let $style = document.createElement('style');
264
+ $style.id = 'yui-window-style';
265
+ $style.textContent = css;
266
+ document.head.appendChild($style);
267
+ }
268
+
269
+ /************************************************************
270
+ * Below the mobile breakpoint the window is a full-screen
271
+ * sheet (no float / drag / resize).
272
+ ************************************************************/
273
+ function is_mobile()
274
+ {
275
+ let w = window.innerWidth || document.documentElement.offsetWidth;
276
+ return w <= MOBILE_MAX;
277
+ }
278
+
279
+ /************************************************************
280
+ * Resolve the optional `manager` attr (a gobj or a service
281
+ * name) to a gobj, caching the resolution back into the attr.
282
+ ************************************************************/
283
+ function resolve_manager(gobj)
284
+ {
285
+ let m = gobj_read_pointer_attr(gobj, "manager");
286
+ if(!m) {
287
+ return null;
288
+ }
289
+ if(typeof m === "string") {
290
+ m = gobj_find_service(m, false);
291
+ gobj_write_attr(gobj, "manager", m);
292
+ }
293
+ return m;
294
+ }
295
+
296
+ /************************************************************
297
+ * Minimize: with a manager, send the window to the dock;
298
+ * otherwise "shade" it in place. Called by the minimize button.
299
+ ************************************************************/
300
+ function do_minimize(gobj)
301
+ {
302
+ let manager = gobj_read_pointer_attr(gobj, "manager");
303
+ if(manager) {
304
+ gobj_send_event(manager, "EV_MINIMIZE_WINDOW", {window: gobj}, gobj);
305
+ } else {
306
+ toggle_shade(gobj);
307
+ }
308
+ }
309
+
310
+ /************************************************************
311
+ * Minimize as "shade": roll the window up to its title bar
312
+ * in place (self-contained; no window manager needed). Toggles.
313
+ ************************************************************/
314
+ function toggle_shade(gobj)
315
+ {
316
+ let priv = gobj.priv;
317
+ let $container = gobj_read_attr(gobj, "$container");
318
+ if(!$container) {
319
+ return;
320
+ }
321
+ if($container.classList.contains("is-shaded")) {
322
+ $container.classList.remove("is-shaded");
323
+ if(priv.preShadeHeight) {
324
+ $container.style.height = parseInt(priv.preShadeHeight) + 'px';
325
+ }
326
+ } else {
327
+ priv.preShadeHeight = $container.getBoundingClientRect().height;
328
+ $container.classList.add("is-shaded");
329
+ $container.style.height = "auto";
330
+ }
331
+ }
332
+
180
333
  /************************************************************
181
334
  * Build UI
182
335
  ************************************************************/
183
336
  function build_ui(gobj)
184
337
  {
338
+ ensure_window_style();
339
+ let mobile = is_mobile();
340
+
185
341
  let header = gobj_read_attr(gobj, "header");
186
342
  if(is_gobj(header)) {
187
343
  header = gobj_read_attr(header, "$container");
@@ -224,6 +380,16 @@ function build_ui(gobj)
224
380
  rect = do_center(gobj, rect.x, rect.y, rect.width, rect.height);
225
381
  }
226
382
 
383
+ /* On mobile the window is a full-screen sheet: ignore the saved
384
+ * rect / centering and fill the viewport. */
385
+ if(mobile) {
386
+ rect = {
387
+ x: 0, y: 0,
388
+ width: window.innerWidth || document.documentElement.offsetWidth,
389
+ height: window.innerHeight || document.documentElement.offsetHeight,
390
+ };
391
+ }
392
+
227
393
  let window_style = {
228
394
  position: "fixed",
229
395
  "z-index": 3,
@@ -245,14 +411,14 @@ function build_ui(gobj)
245
411
 
246
412
  let $container = createElement2(
247
413
  ['div', {
248
- class: 'yui-window strong-shadow is-flex is-flex-direction-column',
414
+ class: 'C_YUI_WINDOW strong-shadow is-flex is-flex-direction-column' + (mobile ? ' is-mobile-sheet' : ''),
249
415
  style: window_style}, [
250
416
 
251
417
  /*----------------------------*
252
418
  * Header
253
419
  *----------------------------*/
254
420
  ['div', {
255
- class: 'yui-window-header p-1 is-flex-shrink-0 is-flex is-flex-nowrap is-justify-content-space-between is-align-items-flex-start has-text-black has-background-info', style: 'border-bottom:1px solid var(--bulma-border); cursor:move; box-sizing: border-box;'
421
+ class: 'yui-window-header p-1 is-flex-shrink-0 is-flex is-flex-nowrap is-justify-content-space-between is-align-items-center', style: 'border-bottom:1px solid var(--bulma-border); cursor:move; box-sizing: border-box;'
256
422
  }, [
257
423
  /* Custom header content: a single-row, horizontally
258
424
  * scrollable strip. It takes the remaining width and
@@ -272,33 +438,40 @@ function build_ui(gobj)
272
438
  * width and kept wrapping. */
273
439
  ['div', {class: '', style: 'width:max-content; display:flex; flex-wrap:nowrap; align-items:center;'}, header]
274
440
  ]],
275
- /* Max/close: pinned top-right, never shrink, never
276
- * wrap, always on top so the click always lands. */
277
- ['div', {class: 'is-flex-shrink-0 is-flex is-flex-nowrap is-align-items-flex-start', style: 'position:relative; z-index:1; cursor:default;'}, [
441
+ /* Window controls: pinned top-right, never shrink,
442
+ * never wrap, always on top so the click always lands.
443
+ * Minimize (shade) · maximize/restore · close. */
444
+ ['div', {class: 'yui-window-titlebar-controls is-flex-shrink-0', style: 'position:relative; z-index:1; cursor:default;'}, [
278
445
  /*----------------------------*
279
- * Max/min button
446
+ * Minimize (shade)
280
447
  *----------------------------*/
281
448
  ['button', {
282
- class: 'without-border pr-4',
283
- style: {
284
- color: 'var(--bulma-text)',
285
- "font-size": "1.4em",
286
- "cursor": "pointer",
287
- "display": gobj_read_bool_attr(gobj, "showMax")?'inline-block':'none',
449
+ class: 'yui-wc wc-min', type: 'button', 'aria-label': 'minimize',
450
+ style: gobj_read_bool_attr(gobj, "showMin") ? '' : 'display:none;',
451
+ }, WC_MIN, {
452
+ click: (evt) => {
453
+ evt.stopPropagation();
454
+ do_minimize(gobj);
288
455
  }
289
- }, '<i class="yi-square"></i>', {
456
+ }],
457
+ /*----------------------------*
458
+ * Maximize / restore
459
+ *----------------------------*/
460
+ ['button', {
461
+ class: 'yui-wc wc-max', type: 'button', 'aria-label': 'maximize',
462
+ style: gobj_read_bool_attr(gobj, "showMax") ? '' : 'display:none;',
463
+ }, WC_MAX, {
290
464
  click: (evt) => {
291
465
  evt.stopPropagation();
292
466
  toggle(gobj);
293
467
  }
294
468
  }],
295
469
  /*----------------------------*
296
- * Close button
470
+ * Close
297
471
  *----------------------------*/
298
472
  ['button', {
299
- class: 'without-border pr-2',
300
- style: 'color:var(--bulma-text);font-size:1.6em;cursor:pointer;',
301
- }, '<i class="yi-xmark"></i>', {
473
+ class: 'yui-wc wc-close', type: 'button', 'aria-label': 'close',
474
+ }, WC_CLOSE, {
302
475
  click: (evt) => {
303
476
  evt.stopPropagation();
304
477
  close_window(gobj);
@@ -409,7 +582,7 @@ function build_ui(gobj)
409
582
  *----------------------------*/
410
583
  if(gobj_read_bool_attr(gobj, "resizable") && !gobj_read_bool_attr(gobj, "showFooter")) {
411
584
  let $resizable_btn = createElement2(['div', {
412
- class: 'without-border',
585
+ class: 'without-border yui-window-resize',
413
586
  style: {
414
587
  cursor: "nwse-resize",
415
588
  display: "flex",
@@ -447,7 +620,7 @@ function build_ui(gobj)
447
620
 
448
621
  if (gobj_read_bool_attr(gobj, "openMaximized")) {
449
622
  max(gobj);
450
- } else {
623
+ } else if(!mobile) {
451
624
  if(gobj_read_bool_attr(gobj, "content_size")) {
452
625
  $container.style.height = "auto";
453
626
  }
@@ -538,10 +711,27 @@ function max(gobj)
538
711
  $container.style.height = parseInt(rect.height) +'px';
539
712
 
540
713
  gobj_write_bool_attr(gobj, "maximized", true);
714
+ set_max_icon(gobj, true);
541
715
 
542
716
  return rect;
543
717
  }
544
718
 
719
+ /************************************************************
720
+ * Swap the maximize/restore glyph to match the state.
721
+ ************************************************************/
722
+ function set_max_icon(gobj, maximized)
723
+ {
724
+ let $container = gobj_read_attr(gobj, "$container");
725
+ if(!$container) {
726
+ return;
727
+ }
728
+ let $btn = $container.querySelector('.wc-max');
729
+ if($btn) {
730
+ $btn.innerHTML = maximized ? WC_RESTORE : WC_MAX;
731
+ $btn.setAttribute('aria-label', maximized ? 'restore' : 'maximize');
732
+ }
733
+ }
734
+
545
735
  /************************************************************
546
736
  *
547
737
  ************************************************************/
@@ -562,6 +752,7 @@ function min(gobj)
562
752
  $container.style.height = parseInt(rect.height) +'px';
563
753
 
564
754
  gobj_write_bool_attr(gobj, "maximized", false);
755
+ set_max_icon(gobj, false);
565
756
 
566
757
  return rect;
567
758
  }
@@ -571,6 +762,11 @@ function min(gobj)
571
762
  ************************************************************/
572
763
  function mvStart(gobj, evt)
573
764
  {
765
+ /* No window-dragging on a mobile full-screen sheet. */
766
+ if(is_mobile()) {
767
+ return;
768
+ }
769
+
574
770
  let $container = gobj_read_attr(gobj, "$container");
575
771
 
576
772
  let window_rect = $container.getBoundingClientRect();
@@ -776,6 +972,19 @@ function handleResize(gobj)
776
972
  return;
777
973
  }
778
974
 
975
+ /* Mobile: full-screen sheet, refit to the viewport and stop. */
976
+ if(is_mobile()) {
977
+ $container.classList.add("is-mobile-sheet");
978
+ let vw = window.innerWidth || document.documentElement.offsetWidth;
979
+ let vh = window.innerHeight || document.documentElement.offsetHeight;
980
+ $container.style.left = '0px';
981
+ $container.style.top = '0px';
982
+ $container.style.width = vw + 'px';
983
+ $container.style.height = vh + 'px';
984
+ return;
985
+ }
986
+ $container.classList.remove("is-mobile-sheet");
987
+
779
988
  /* Maximized: just refit to the (new) viewport. */
780
989
  if(gobj_read_bool_attr(gobj, "maximized") === true) {
781
990
  let r = do_fix_dimension_to_screen(gobj, 0, 0, 10000, 10000);
@@ -853,6 +1062,16 @@ function ac_hide(gobj, event, kw, src)
853
1062
  return 0;
854
1063
  }
855
1064
 
1065
+ /************************************************************
1066
+ * EV_CLOSE_WINDOW — close from outside (e.g. the dock chip ✕),
1067
+ * the same teardown as the title-bar close button.
1068
+ ************************************************************/
1069
+ function ac_close(gobj, event, kw, src)
1070
+ {
1071
+ close_window(gobj);
1072
+ return 0;
1073
+ }
1074
+
856
1075
 
857
1076
 
858
1077
 
@@ -891,7 +1110,8 @@ function create_gclass(gclass_name)
891
1110
  ["EV_RESIZE", ac_resize, null],
892
1111
  ["EV_REFRESH", ac_refresh, null],
893
1112
  ["EV_SHOW", ac_show, null],
894
- ["EV_HIDE", ac_hide, null]
1113
+ ["EV_HIDE", ac_hide, null],
1114
+ ["EV_CLOSE_WINDOW", ac_close, null]
895
1115
  ]]
896
1116
  ];
897
1117
 
@@ -905,7 +1125,8 @@ function create_gclass(gclass_name)
905
1125
  ["EV_RESIZE", 0],
906
1126
  ["EV_REFRESH", 0],
907
1127
  ["EV_SHOW", 0],
908
- ["EV_HIDE", 0]
1128
+ ["EV_HIDE", 0],
1129
+ ["EV_CLOSE_WINDOW", 0]
909
1130
  ];
910
1131
 
911
1132
  __gclass__ = gclass_create(