@yuneta/gobj-ui 2.5.0 → 3.0.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/src/c_yui_main.js DELETED
@@ -1,1623 +0,0 @@
1
- /***********************************************************************
2
- * yui_main.js
3
- *
4
- * Yuneta UI Main
5
- *
6
- * Use EV_ON_OPEN/EV_ON_CLOSE (==> show_app_content())
7
- * to show/hide the app ("content-layer", "iframe-layer")
8
- *
9
- * Define the top toolbar
10
- * - login
11
- * - themes
12
- * - languages
13
- * - app menu
14
- * - user menu
15
- *
16
- * In the yui_main.css are the sizes.
17
- *
18
- * Define layers: top-layer
19
- * content-layer
20
- * bottom-layer
21
- * popup-layer
22
- * modal-layer
23
- * iframe-layer
24
- *
25
- * The content-layer is managed in yui_routing.js
26
- *
27
- * The tabs in a content-layer to manage sub-containers can be managed by yui_tabs.js
28
- * or be integrated in each gobj.
29
- *
30
- * Copyright (c) 2025-2026, ArtGins.
31
- * All Rights Reserved.
32
- ***********************************************************************/
33
- /* global ResizeObserver, window, document */
34
-
35
- import {
36
- SDATA,
37
- SDATA_END,
38
- data_type_t,
39
- event_flag_t,
40
- log_error,
41
- gclass_create,
42
- gobj_subscribe_event,
43
- gobj_read_pointer_attr,
44
- kw_get_local_storage_value,
45
- kw_set_local_storage_value,
46
- createElement2,
47
- empty_string,
48
- is_array,
49
- is_string,
50
- createOneHtml,
51
- kw_get_str,
52
- getPositionRelativeToBody,
53
- gobj_find_service,
54
- gobj_read_attr,
55
- gobj_send_event,
56
- gobj_write_attr,
57
- gobj_publish_event,
58
- gobj_default_service,
59
- refresh_language,
60
- debounce,
61
- } from "@yuneta/gobj-js";
62
-
63
- import {setup_dev} from "./yui_dev.js";
64
- import {yui_toolbar} from "./yui_toolbar.js";
65
-
66
- import i18next, {t} from 'i18next';
67
-
68
- import "./c_yui_main.css"; // Must be in index.js ?
69
-
70
- /***************************************************************
71
- * Constants
72
- ***************************************************************/
73
- const GCLASS_NAME = "C_YUI_MAIN";
74
-
75
- /***************************************************************
76
- * Data
77
- ***************************************************************/
78
- const attrs_table = [
79
- SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
80
- SDATA(data_type_t.DTP_STRING, "username", 0, "", "username logged"),
81
- SDATA(data_type_t.DTP_STRING, "publi_page", 0, "publi_page", "Publicity page shown when user is not logged in"),
82
- SDATA(data_type_t.DTP_STRING, "theme", 0, "light", "Theme: light or dark"),
83
- SDATA(data_type_t.DTP_STRING, "logo_wide", 0, "logo-wide.png", "Logo for the app"),
84
- SDATA(data_type_t.DTP_STRING, "logo_wide_svg", 0, "", "SVG string for the app logo"),
85
- SDATA(data_type_t.DTP_POINTER, "flags_of_world", 0, null, "Object with language flags SVG strings"),
86
- SDATA(data_type_t.DTP_REAL, "width", 0, "-1", "Main Window size. -1 -> set full size of the device"),
87
- SDATA(data_type_t.DTP_REAL, "height", 0, "-1", "Main Window size"),
88
- SDATA(data_type_t.DTP_STRING, "color_yuneta_connected",0, "#32CD32", "LimeGreen - connected"),
89
- SDATA(data_type_t.DTP_STRING, "color_yuneta_disconnected",0, "#FF4500", "OrangeRed - disconnected"),
90
- SDATA(data_type_t.DTP_STRING, "color_user_login", 0, "#32CD32", "LimeGreen - user logged in"),
91
- SDATA(data_type_t.DTP_STRING, "color_user_logout", 0, "#FF4500", "OrangeRed - user logged out"),
92
- SDATA_END()
93
- ];
94
-
95
- let PRIVATE_DATA = {};
96
-
97
- let __gclass__ = null;
98
-
99
-
100
-
101
-
102
- /******************************
103
- * Framework Methods
104
- ******************************/
105
-
106
-
107
-
108
-
109
- /***************************************************************
110
- * Framework Method: Create
111
- ***************************************************************/
112
- function mt_create(gobj)
113
- {
114
- build_ui(gobj);
115
-
116
- let current_theme = kw_get_local_storage_value("theme", "light", true);
117
- set_theme(gobj, current_theme);
118
-
119
- /*
120
- * SERVICE subscription model
121
- */
122
- const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
123
- if(subscriber) {
124
- gobj_subscribe_event(gobj, null, {}, subscriber);
125
- }
126
-
127
- }
128
-
129
- /***************************************************************
130
- * Framework Method: Start
131
- ***************************************************************/
132
- function mt_start(gobj)
133
- {
134
- resize_and_subscribe_to_system(gobj);
135
- }
136
-
137
- /***************************************************************
138
- * Framework Method: Stop
139
- ***************************************************************/
140
- function mt_stop(gobj)
141
- {
142
- // TODO gobj.clear_timeout();
143
- }
144
-
145
- /***************************************************************
146
- * Framework Method: Destroy
147
- ***************************************************************/
148
- function mt_destroy(gobj)
149
- {
150
- }
151
-
152
-
153
-
154
-
155
- /***************************
156
- * Local Methods
157
- ***************************/
158
-
159
-
160
-
161
-
162
- /************************************************************
163
- * Build UI
164
- ************************************************************/
165
- function build_ui(gobj)
166
- {
167
- /*----------------------------------------------*
168
- * Layout Schema
169
- *----------------------------------------------*/
170
- const $container = createElement2(
171
- ['div', {id: 'root', class: 'C_YUI_MAIN root'}, [
172
- ['div', {id: 'top-layer', class: 'top-layer'}],
173
- ['div', {id: 'content-layer', class: 'content-layer is-hidden'}],
174
- ['div', {id: 'bottom-layer', class: 'bottom-layer'}],
175
- ['div', {id: 'popup-layer', class: 'popup-layer'}],
176
- ['div', {id: 'modal-layer', class: 'modal-layer'}],
177
- ['div', {id: 'iframe-layer', class: 'iframe-layer'},
178
- `<iframe id="iframe-publi-page" src="./${gobj_read_attr(gobj, "publi_page")}/index.html" width="100%" height="100%"></iframe>`]
179
- ]]
180
- );
181
- document.body.appendChild($container);
182
-
183
- const iframe = document.getElementById('iframe-publi-page');
184
- if(iframe) {
185
- iframe.onload = () => {
186
- const theme = kw_get_local_storage_value("theme", "light", true);
187
- let iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
188
- iframeDocument.documentElement.setAttribute("data-theme", theme);
189
- refresh_language(iframeDocument, t);
190
- };
191
- }
192
-
193
- /*---------------------------------------*
194
- * Top Header toolbar
195
- *---------------------------------------*/
196
- /*
197
- * Left
198
- */
199
- let left_items = [
200
- ['button', {
201
- class: 'button',
202
- style: {
203
- height: `var(--top-layer-size-inside)`,
204
- width: `2.5em`
205
- }
206
- }, [
207
- 'i', {
208
- id: 'icon_yuneta_state',
209
- style: `font-size:1.5em; color:${gobj_read_attr(gobj, "color_yuneta_disconnected")};`,
210
- class: 'yi-bars'
211
- }
212
- ], {
213
- click: (evt) => {
214
- evt.stopPropagation();
215
- gobj_send_event(gobj, "EV_APP_MENU", {evt: evt}, gobj);
216
- },
217
- contextmenu: (evt) => {
218
- evt.stopPropagation();
219
- evt.preventDefault();
220
- gobj_send_event(gobj, "EV_APP_MENU", {evt: evt}, gobj);
221
- }
222
- }]
223
- ];
224
-
225
- /*
226
- * Center
227
- */
228
- let center_items = [
229
- ['img',
230
- {
231
- src: `${gobj_read_attr(gobj, "logo_wide")}`,
232
- alt: `${gobj_read_attr(gobj, "logo_wide")}`,
233
- height: "36",
234
- width: "72",
235
- style: "cursor: pointer;"
236
- },
237
- '',
238
- {
239
- click: (evt) => {
240
- evt.stopPropagation();
241
- gobj_send_event(gobj, "EV_HOME", {evt: evt}, gobj);
242
- }
243
- }
244
- ]
245
-
246
- // ['img', {
247
- // style: {
248
- // height: `var(--top-layer-size-inside)`,
249
- // width: `var(2 * --top-layer-size-inside)`
250
- // }
251
- // },
252
- // `${logo_wide_svg}`,
253
- // {
254
- // click: (evt) => {
255
- // evt.stopPropagation();
256
- // gobj_send_event(gobj, "EV_HOME", {evt: evt}, gobj);
257
- // }
258
- // }]
259
- ];
260
-
261
- /*
262
- * Right
263
- */
264
- let right_items = [
265
- [
266
- 'button', {
267
- id: "EV_SELECT_LANGUAGE",
268
- class: 'button has-text-link',
269
- style: {
270
- 'margin-left': '4px',
271
- height: `var(--top-layer-size-inside)`,
272
- width: `2.5em`,
273
- }
274
- }, [
275
- ['i', {style: 'font-size:1.5em;', class: 'yi-language'}]
276
- ], {
277
- click: (evt) => {
278
- evt.stopPropagation();
279
- gobj_send_event(gobj, "EV_SELECT_LANGUAGE", {evt: evt}, gobj);
280
- }
281
- }
282
- ], [
283
- 'button', {
284
- id: 'theme-change',
285
- class: 'button',
286
- style: {
287
- 'margin-left': '4px',
288
- height: `var(--top-layer-size-inside)`,
289
- width: `2.5em`,
290
- }
291
- }, [
292
- ['i', {
293
- style: 'font-size:1.5em; color:#8156F5; display:none;',
294
- class: 'theme-dark yi-moon'
295
- }],
296
- ['i', {
297
- style: 'font-size:1.5em; color:#FFB70F; display:none;',
298
- class: 'theme-light yi-sun'
299
- }]
300
- ], {
301
- click: (evt) => {
302
- evt.stopPropagation();
303
- gobj_send_event(gobj, "EV_SELECT_THEME", {evt: evt}, gobj);
304
- }
305
- }
306
- ], [
307
- 'button',
308
- {
309
- id: "EV_USER_MENU",
310
- class: 'button',
311
- style: {
312
- 'margin-left': '4px',
313
- display: 'flex',
314
- height: `var(--top-layer-size-inside)`
315
- }
316
- }, [
317
- ['span', {id: 'tag_username', class: 'tag is-hidden-mobile', i18n: 'login'}, 'login'],
318
- ['i', {
319
- id: 'icon_username',
320
- style: `font-size:1.5em; color:${gobj_read_attr(gobj, "color_user_logout")};`,
321
- class: 'yi-user'
322
- }]
323
- ], {
324
- click: (evt) => {
325
- evt.stopPropagation();
326
- gobj_send_event(gobj, "EV_USER_MENU", {evt: evt}, gobj);
327
- }
328
- }
329
- ]
330
- ];
331
-
332
- const $toolbar_header = yui_toolbar({}, [
333
- ['div', {class: 'yui-horizontal-toolbar-section left'}, left_items],
334
- ['div', {class: 'yui-horizontal-toolbar-section center is-hidden-mobile'}, center_items],
335
- ['div', {class: 'yui-horizontal-toolbar-section right'}, right_items]
336
- ]);
337
-
338
- document.getElementById('top-layer').appendChild($toolbar_header);
339
-
340
- refresh_language($toolbar_header, t);
341
-
342
- /*---------------------------------------*
343
- * Top Breadcrumb toolbar
344
- *---------------------------------------*/
345
-
346
- /*---------------------------------------*
347
- * Work area
348
- *---------------------------------------*/
349
- // build_work_area(gobj);
350
-
351
- /*---------------------------------------*
352
- * Add menu items
353
- *---------------------------------------*/
354
- // add_menu_item("EV_HOME", t("Home"), "fas fa-home", false);
355
- // add_menu_item("EV_USER", t("Profile"), "fas fa-user", false);
356
- // add_menu_item("EV_MESSAGE", t("Messages"), "yi-envelope", false);
357
- // add_menu_item("EV_SETTING", t("Settings"), "yi-gear", false);
358
- // add_menu_item("EV_XXX", t("Home"), "fas fa-home", false);
359
- //
360
- // set_active_menu_item("EV_USER", true);
361
-
362
- /*
363
- * Important to adjust some elements
364
- */
365
- window.dispatchEvent(new Event('resize'));
366
- }
367
-
368
- /************************************************************
369
- * Set theme
370
- ************************************************************/
371
- function set_theme(gobj, theme)
372
- {
373
- gobj_write_attr(gobj, "theme", theme);
374
-
375
- let elm = document.querySelectorAll("#theme-change i");
376
- elm.forEach(function (element) {
377
- element.style.display = 'none';
378
- });
379
-
380
- switch (theme) {
381
- case 'dark':
382
- elm = document.querySelector("#theme-change i.theme-dark");
383
- break;
384
- case 'light':
385
- default:
386
- elm = document.querySelector("#theme-change i.theme-light");
387
- break;
388
- }
389
- document.documentElement.setAttribute("data-theme", theme);
390
- if(elm) {
391
- elm.style.display = 'flex';
392
- }
393
-
394
- const iframe = document.getElementById('iframe-publi-page');
395
- if(iframe && iframe.contentWindow) {
396
- iframe.contentWindow.document.documentElement.setAttribute("data-theme", theme);
397
- }
398
- gobj_publish_event(gobj, "EV_THEME", {theme: theme});
399
- }
400
-
401
- /************************************************************
402
- *
403
- ************************************************************/
404
- function change_language(new_language)
405
- {
406
- kw_set_local_storage_value("locale", new_language?new_language:"es");
407
- i18next.changeLanguage(new_language);
408
- refresh_language(null, t);
409
-
410
- const iframe = document.getElementById('iframe-publi-page');
411
- if(iframe && iframe.contentWindow) {
412
- let iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
413
- refresh_language(iframeDocument, t);
414
- }
415
-
416
- window.dispatchEvent(new Event('resize'));
417
- }
418
-
419
- /************************************************************
420
- *
421
- ************************************************************/
422
- function show_select_language(gobj, show)
423
- {
424
- let $element = document.getElementById('popup-select-language');
425
- if(!$element) {
426
- let flags = gobj_read_attr(gobj, "flags_of_world") || {};
427
- $element = createElement2([
428
- 'div', { id: 'popup-select-language', class: 'dropdown is-right popup' }, [
429
- ['div', { class: 'dropdown-menu', role: 'menu', style: 'min-width:4rem;' }, [
430
- ['div', { class: 'dropdown-content', style: 'padding: 0;' }, [
431
- ['a', {class: 'dropdown-item flex-horizontal-section', 'data-value':'es'}, [
432
- ['span', {style: 'width:1.5em; height:1.5em;'}, flags['es'] || ''],
433
- ['span', {i18n: 'es'}, 'Español']
434
-
435
- ]],
436
- ['a', {class: 'dropdown-item flex-horizontal-section', 'data-value':'en'}, [
437
- ['span', {style: 'width:1.5em; height:1.5em;'}, flags['en'] || ''],
438
- ['span', {i18n: 'en'}, 'Inglés']
439
- ]]
440
- ]]
441
- ]]
442
- ], {
443
- 'click': (event) => {
444
- //////////////////////////////////////////////////////////////////////
445
- // WARNING
446
- // if do not stop propagation, the event will arrive until body,
447
- // and an auto-closing function will remove is-active class
448
- // and this popup will not open
449
- // (Bulma components that it opens with toggling "is-active" class)
450
- //////////////////////////////////////////////////////////////////////
451
- event.stopPropagation();
452
- event.currentTarget.classList.toggle("is-active");
453
- const target = event.target.closest('.dropdown-item');
454
- change_language(target.dataset.value);
455
- }
456
- }
457
- ]);
458
- document.getElementById("popup-layer").appendChild($element);
459
- }
460
-
461
- let pos = getPositionRelativeToBody(document.getElementById("EV_SELECT_LANGUAGE"));
462
- $element.style.position = "absolute";
463
- $element.style.top = pos.bottom + "px";
464
- $element.style.left = pos.right + "px";
465
- if(show) {
466
- let locale = kw_get_local_storage_value("locale", "es", true);
467
-
468
- let $items = $element.querySelectorAll('a[data-value]');
469
- $items.forEach(function($item) {
470
- $item.classList.remove('is-active');
471
- });
472
-
473
- let $item = $element.querySelector(`a[data-value="${locale}"]`);
474
- $item.classList.add('is-active');
475
-
476
- $element.classList.add('is-active');
477
- } else {
478
- $element.classList.remove('is-active');
479
- }
480
- }
481
-
482
- /************************************************************
483
- *
484
- ************************************************************/
485
- // <!-- aqui va forgot password -->
486
- // <div class="field">
487
- // <a class="button is-text is-size-7 forgot-password" data-i18n="forgot password?">Forgot Password?</a>
488
- // </div>
489
-
490
- function get_login_html(logo_wide_svg) { return `
491
- <div id="modal-login" class="modal">
492
- <div class="modal-background">
493
- </div>
494
- <div class="modal-content" style="max-width:400px;">
495
- <div class="box">
496
- <div class = "is-flex is-flex-direction-row is-justify-content-center mb-5">
497
- <figure class="image" style="width: 60%;">
498
- ${logo_wide_svg}
499
- </figure>
500
- </div>
501
- <!-- Form -->
502
- <form>
503
- <div class="field">
504
- <label class="label" data-i18n="email">Email</label>
505
- <div class="control has-icons-left">
506
- <input class="input with-focus input-email" type="email" placeholder="name@example.com" required>
507
- <span class="icon is-small is-left">
508
- <i class="yi-envelope"></i>
509
- </span>
510
- </div>
511
- </div>
512
-
513
- <div class="field">
514
- <label class="label" data-i18n="password">Password</label>
515
- <div class="control has-icons-left has-icons-right">
516
- <input class="input input-password" type="password" placeholder="********" required>
517
- <span class="icon is-small is-left">
518
- <i class="yi-lock"></i>
519
- </span>
520
- <span class="icon is-small is-right is-clickable toggle-password">
521
- <i class="yi-eye"></i>
522
- </span>
523
- </div>
524
- <!-- aqui va forgot password -->
525
- </div>
526
-
527
- <!-- Warning Message is-hidden -->
528
- <article class="message is-danger is-hidden invalid-username-password">
529
- <div style="padding: 0.5em 1em;" class="message-body" data-i18n="invalid-username-password">
530
- Invalid username or password.
531
- </div>
532
- </article>
533
-
534
- <div class="pt-4"></div>
535
- <div class="control">
536
- <button type="submit" class="button is-link full-width-button process-form" data-i18n="login">Login</button>
537
- </div>
538
- <div class="pb-4"></div>
539
- </form>
540
- </div>
541
- </div>
542
- <button class="modal-close is-large" aria-label="close"></button>
543
- </div>
544
- `; }
545
-
546
- /************************************************************
547
- *
548
- ************************************************************/
549
- function show_login_form(gobj)
550
- {
551
- let $element = document.getElementById("modal-login");
552
- if(!$element) {
553
- let logo_wide_svg = gobj_read_attr(gobj, "logo_wide_svg") || "";
554
- $element = createOneHtml(get_login_html(logo_wide_svg));
555
- refresh_language($element, t);
556
-
557
- /*------------------------*
558
- * Add events
559
- *------------------------*/
560
- /*
561
- * Don't propagate click
562
- */
563
- $element.addEventListener('click', function(event) {
564
- event.stopPropagation();
565
- });
566
-
567
- /*
568
- * Button close
569
- */
570
- $element.querySelector('.modal-close').addEventListener('click', function(event) {
571
- event.stopPropagation();
572
- $element.classList.remove('is-active');
573
- });
574
-
575
- /*
576
- * Forgot password
577
- */
578
- // $element.querySelector('.forgot-password').addEventListener('click', function(event) {
579
- // event.stopPropagation();
580
- // $element.classList.remove('is-active');
581
- // show_recovery_password(gobj, true);
582
- // });
583
-
584
- /*
585
- * Button password visibility
586
- */
587
- let $input_password = $element.querySelector('.input-password');
588
- let $toggle_password = $element.querySelector('.toggle-password');
589
- $toggle_password.addEventListener('click', function(event) {
590
- event.stopPropagation();
591
- let icon = $toggle_password.querySelector('i');
592
- if ($input_password.type === 'password') {
593
- $input_password.type = 'text';
594
- icon.classList.replace('fa-eye', 'fa-eye-slash');
595
- } else {
596
- $input_password.type = 'password';
597
- icon.classList.replace('fa-eye-slash', 'fa-eye');
598
- }
599
- $input_password.focus();
600
- });
601
-
602
- /*
603
- * Submit
604
- */
605
- $element.addEventListener('submit', function(event) {
606
- const email = $element.querySelector('.input-email').value;
607
- const password = $element.querySelector('.input-password').value;
608
-
609
- event.stopPropagation();
610
- event.preventDefault(); // if not set in mobiles refresh the page
611
- let kw = {
612
- username: email,
613
- password: password
614
- };
615
- gobj_send_event(gobj, "EV_DO_LOGIN", kw, gobj);
616
- });
617
-
618
- /*
619
- * Add to popup layer
620
- */
621
- document.getElementById("popup-layer").appendChild($element);
622
- }
623
-
624
- $element.querySelector('.invalid-username-password').classList.add('is-hidden');
625
- $element.classList.add('is-active');
626
- $element.querySelector('.with-focus').focus();
627
- }
628
-
629
- /************************************************************
630
- *
631
- ************************************************************/
632
- function hide_login_form(gobj)
633
- {
634
- let $element = document.getElementById("modal-login");
635
- if($element) {
636
- $element.classList.remove('is-active');
637
- }
638
- }
639
-
640
- /************************************************************
641
- *
642
- ************************************************************/
643
- function set_error_login_message(gobj, message)
644
- {
645
- let $element = document.querySelector("#modal-login .invalid-username-password");
646
- if($element) {
647
- let $content = $element.querySelector(".message-body");
648
- if($content) {
649
- $content.textContent = `${message}`;
650
- }
651
-
652
- if(empty_string(message)) {
653
- $element.classList.add('is-hidden');
654
- } else {
655
- $element.classList.remove('is-hidden');
656
- }
657
- }
658
- }
659
-
660
- /************************************************************
661
- *
662
- ************************************************************/
663
- function get_recovery_password_html(logo_wide_svg) { return `
664
- <div id="modal-recovery-password" class="modal">
665
- <div class="modal-background">
666
- </div>
667
- <div class="modal-content" style="max-width:600px;">
668
- <div class="box" >
669
- <div class = "is-flex is-flex-direction-row is-justify-content-center mb-5">
670
- <figure class="image" style="width: 60%;">
671
- ${logo_wide_svg}
672
- </figure>
673
- </div>
674
- <!-- Form -->
675
- <div class="mb-5" data-i18n="instructions password recovery">instructions password recovery</div>
676
- <form>
677
- <div class="field">
678
- <label class="label" for="recovery-email" data-i18n="email">Email</label>
679
- <div class="control has-icons-left">
680
- <input id="recovery-email" class="input with-focus" type="email" placeholder="name@example.com" required aria-required="true">
681
- <span class="icon is-small is-left">
682
- <i class="yi-envelope"></i>
683
- </span>
684
- </div>
685
- </div>
686
- <div class="field">
687
- <div class="control has-text-centered">
688
- <button type="submit" class="button is-info" data-i18n="submit">Submit</button>
689
- </div>
690
- </div>
691
- </form>
692
- </div>
693
- </div>
694
- <button class="modal-close is-large" aria-label="close"></button>
695
- </div>
696
- `; }
697
-
698
- /************************************************************
699
- *
700
- ************************************************************/
701
- function show_recovery_password(gobj, show)
702
- {
703
- let $element = document.getElementById("modal-recovery-password");
704
- if(!$element) {
705
- let logo_wide_svg = gobj_read_attr(gobj, "logo_wide_svg") || "";
706
- $element = createOneHtml(get_recovery_password_html(logo_wide_svg));
707
- refresh_language($element, t);
708
-
709
- /*
710
- * Don't propagate click
711
- */
712
- $element.addEventListener('click', function(event) {
713
- event.stopPropagation();
714
- });
715
-
716
- /*------------------------*
717
- * Add events
718
- *------------------------*/
719
- /*
720
- * Button close
721
- */
722
- $element.querySelector('.modal-close').addEventListener('click', function(event){
723
- event.stopPropagation();
724
- $element.classList.remove('is-active');
725
- });
726
-
727
- /*
728
- * Submit
729
- */
730
- $element.addEventListener('submit', function(event) {
731
- event.stopPropagation();
732
- event.preventDefault(); // if not set in mobiles refresh the page
733
- $element.classList.remove('is-active');
734
- let kw = {
735
- username: "username"
736
- };
737
- gobj_send_event(gobj, "EV_DO_RECOVERY_PASSWORD", kw, gobj);
738
- });
739
-
740
- /*
741
- * Add to popup layer
742
- */
743
- document.getElementById("popup-layer").appendChild($element);
744
- }
745
-
746
- if(show) {
747
- $element.classList.add('is-active');
748
- $element.querySelector('.with-focus').focus();
749
- } else {
750
- $element.classList.remove('is-active');
751
- }
752
- }
753
-
754
- /************************************************************
755
- *
756
- ************************************************************/
757
- function show_user_menu(gobj, show, pos)
758
- {
759
- let $element = document.getElementById('popup-user-menu');
760
- if(!$element) {
761
- $element = createElement2([
762
- 'div', { id: 'popup-user-menu', style: 'position=absolute;', class: 'dropdown is-right popup' }, [
763
- ['div', { class: 'dropdown-menu', role: 'menu', style: 'min-width:4rem;' }, [
764
- ['div', { class: 'dropdown-content', style: 'padding: 0;' }, [
765
- // ['hr', {class: 'dropdown-divider'}],
766
- ['a', {class: 'dropdown-item flex-horizontal-section'}, [
767
- ['span', {class:'pr-2', i18n: 'logout'}, 'logout'],
768
- ['i', {style: `color: ${gobj_read_attr(gobj, "color_user_logout")}`, class: 'yi-right-from-bracket'}]
769
- ],
770
- {
771
- click: (evt) => {
772
- evt.stopPropagation();
773
- evt.currentTarget.closest('.popup').classList.toggle("is-active");
774
- gobj_send_event(gobj, "EV_DO_LOGOUT", {evt: evt}, gobj);
775
- }
776
- }]
777
- ]]
778
- ]]
779
- ]
780
- ]);
781
- document.getElementById("popup-layer").appendChild($element);
782
- }
783
-
784
- // $element.style.position = "absolute";
785
- $element.style.top = pos.bottom + "px";
786
- $element.style.left = pos.right + "px";
787
- if(show) {
788
- $element.classList.add('is-active');
789
- } else {
790
- $element.classList.remove('is-active');
791
- }
792
- }
793
-
794
- /************************************************
795
- *
796
- ************************************************/
797
- function set_username(gobj, username)
798
- {
799
- gobj_write_attr(gobj, "username", username);
800
-
801
- /*
802
- * Change color user icon
803
- */
804
- document.getElementById("icon_username").style.color = username?
805
- gobj_read_attr(gobj, "color_user_login") : gobj_read_attr(gobj, "color_user_logout");
806
-
807
- /*
808
- * Change text user label
809
- */
810
- let $element = document.getElementById("tag_username");
811
- $element.textContent = username?username:t('login');
812
- if(username) {
813
- $element.setAttribute('data-i18n', '');
814
- } else {
815
- $element.setAttribute('data-i18n', 'login');
816
- }
817
- }
818
-
819
- /************************************************************
820
- *
821
- ************************************************************/
822
- let modal_message_html = `
823
- <div id="modal-message" class="modal is-active">
824
- <div class="modal-background"></div>
825
- <div class="modal-content">
826
- <!-- Any other Bulma elements you want can go here -->
827
- <div class="box notification is-warning">
828
- <h1 class="title has-text-centered"></h1>
829
- <div class="content"></div>
830
- <button class="button is-large delete"></button>
831
- </div>
832
- </div>
833
- </div>
834
- `;
835
-
836
- /************************************************************
837
- * type: 'info', 'success', 'warning', 'danger'
838
- * buttons: [{content, callback}]
839
- * content can be:
840
- * string -> createOneHtml()
841
- * [] -> createElement2()
842
- *
843
- * callback:
844
- * function()
845
- *
846
- * Add class 'with-focus' to the element you want the focus
847
- * Add class 'to-close' to the buttons INSIDE msg, that you want to close the modal
848
-
849
- Example:
850
- display_volatil_modal({
851
- title: "Info",
852
- type: "info",
853
- x_close: true,
854
- msg: `<div class="">
855
- <p class="title">Are you sure you want to proceed?</p>
856
- <div class="buttons is-centered">
857
- <button class="button to-close is-success" id="yesButton">Yes</button>
858
- <button class="button to-close is-danger" id="noButton">No</button>
859
- <button class="button to-close" id="cancelButton">Cancel</button>
860
- </div>
861
- </div>`,
862
- buttons: [
863
- {
864
- content:
865
- `<button class="button is-success px-6 with-focus">${t('accept')}</button>`,
866
- callback: function(evt) {
867
- console.dir(evt)
868
- console.log("BUTTON callback");
869
- }
870
- }
871
- ],
872
- callback: function(evt) {
873
- console.log("GLOBAL callback");
874
- }
875
- });
876
-
877
- ************************************************************/
878
- function display_volatil_modal(
879
- {title, msg, callback, type, x_close, buttons}
880
- ) {
881
- const callback_ = callback; // ✅ Assign to a constant
882
-
883
- /* Normalize the type: it picks the tinted icon and the accent
884
- * color (see the .yui-volatil rules in c_yui_main.css). */
885
- let type_ = (type || "info").toLowerCase();
886
- if(type_ === "danger") {
887
- type_ = "error";
888
- }
889
- const TYPE_ICONS = {
890
- "info": "yi-circle-info",
891
- "question": "yi-question",
892
- "success": "yi-square-check",
893
- "warning": "yi-triangle-exclamation",
894
- "error": "yi-circle-exclamation",
895
- };
896
- let icon = TYPE_ICONS[type_] || TYPE_ICONS["info"];
897
-
898
- let $element = createElement2([
899
- 'div', {class: `modal yui-volatil is-${type_}`}, [
900
- ['div', {class: 'modal-background'}, ''],
901
- ['div', {class: 'modal-card'}, []]
902
- ]
903
- ]);
904
-
905
- const destroyModal = ()=> {
906
- document.removeEventListener('keydown', on_keydown, true);
907
- $element.classList.remove('is-active');
908
- $element.parentNode.removeChild($element);
909
- };
910
-
911
- /* Escape = cancel. Capture phase on document, so Escape handlers
912
- * beneath the modal (e.g. the treedb edit dialog's own) don't also
913
- * fire and stack a second confirm. Only the top-most open modal
914
- * reacts; the cancel/x click path carries the callback semantics,
915
- * a buttonless modal just dismisses. */
916
- const on_keydown = (evt)=> {
917
- if(evt.key !== "Escape") {
918
- return;
919
- }
920
- let $modals = document.querySelectorAll('.modal.is-active');
921
- if($modals.length && $modals[$modals.length - 1] !== $element) {
922
- return;
923
- }
924
- evt.stopPropagation();
925
- evt.preventDefault();
926
- let $cancel = $element.querySelector('.cancelButton, .delete');
927
- if($cancel) {
928
- $cancel.click();
929
- } else {
930
- destroyModal();
931
- }
932
- };
933
- document.addEventListener('keydown', on_keydown, true);
934
-
935
- let $modal_card = $element.querySelector('.modal-card');
936
-
937
- /* Icon-centric layout (no colored header bar): a tinted round
938
- * icon of the type, an optional title, an optional top-right x. */
939
- $modal_card.appendChild(createElement2(
940
- ['div', {class: 'yui-volatil-icon'}, [
941
- ['i', {class: icon, 'aria-hidden': 'true'}]
942
- ]]
943
- ));
944
- if(title) {
945
- $modal_card.appendChild(createElement2(
946
- ['p', {class: 'yui-volatil-title has-text-centered'}, title]
947
- ));
948
- }
949
- if(x_close) {
950
- $modal_card.appendChild(createElement2(
951
- ['button', {class: 'delete yui-volatil-x', 'aria-label': 'close'}]
952
- ));
953
- }
954
-
955
- let $section = createElement2(
956
- ['section', {class: 'modal-card-body has-text-centered'}, createOneHtml(msg)]
957
- );
958
- $modal_card.appendChild($section);
959
-
960
- if(buttons && buttons.length) {
961
- let $footer = createElement2(
962
- ['footer', {class: 'modal-card-foot p-3'}, [
963
- ['div', {class: 'buttons', style: 'justify-content:center; width:100%;'}]
964
- ]]
965
- );
966
- $modal_card.appendChild($footer);
967
-
968
- let $buttons = $footer.querySelector('.buttons');
969
-
970
- for(let button of buttons) {
971
- let content = button.content;
972
- const btn_callback = button.callback;
973
- let $button = null;
974
-
975
- if(is_string(content)) {
976
- $button = createOneHtml(content);
977
- } else if(is_array(content)) {
978
- $button = createElement2(content);
979
- }
980
-
981
- if($button) {
982
- const clickHandler = (evt)=> {
983
- evt.stopPropagation();
984
- destroyModal();
985
- if(btn_callback) {
986
- btn_callback(evt);
987
- } else if(callback_) {
988
- callback_(evt);
989
- }
990
- };
991
-
992
- $button.addEventListener('click', clickHandler);
993
- $buttons.appendChild($button);
994
- }
995
- }
996
- }
997
-
998
- refresh_language($element, t);
999
-
1000
- /*------------------------*
1001
- * Add events
1002
- *------------------------*/
1003
- $element.querySelectorAll('.delete, .to-close').forEach((element)=> {
1004
- element.addEventListener('click', (evt)=> {
1005
- evt.stopPropagation();
1006
- destroyModal();
1007
- if(callback_) {
1008
- callback_(evt);
1009
- }
1010
- });
1011
- });
1012
-
1013
- /*
1014
- * Add to popup layer
1015
- */
1016
- let $popup_layer = document.getElementById("popup-layer");
1017
- if(!$popup_layer) {
1018
- $popup_layer = document.body;
1019
- }
1020
- $popup_layer.appendChild($element);
1021
- $element.classList.add('is-active');
1022
-
1023
- /*
1024
- * Set focus
1025
- */
1026
- let $with_focus = $element.querySelector('.with-focus');
1027
- if($with_focus) {
1028
- $with_focus.focus();
1029
- }
1030
- }
1031
-
1032
- /************************************************************
1033
- *
1034
- ************************************************************/
1035
- function display_info_message(title, msg, callback)
1036
- {
1037
- if(!title) {
1038
- title = t("info");
1039
- }
1040
- display_volatil_modal({
1041
- title: title,
1042
- msg: msg,
1043
- callback: callback,
1044
- type: 'info',
1045
- buttons: [{
1046
- content:
1047
- `<button class="button is-info px-6 with-focus">${t('accept')}</button>`,
1048
- }]
1049
- });
1050
- }
1051
-
1052
- /************************************************************
1053
- *
1054
- ************************************************************/
1055
- function display_warning_message(title, msg, callback)
1056
- {
1057
- if(!title) {
1058
- title = t("warning");
1059
- }
1060
- display_volatil_modal({
1061
- title: title,
1062
- msg: msg,
1063
- callback: callback,
1064
- type: 'warning',
1065
- buttons: [{
1066
- content:
1067
- `<button class="button is-warning px-6 with-focus">${t('accept')}</button>`,
1068
- }]
1069
- });
1070
- }
1071
-
1072
- /************************************************************
1073
- *
1074
- ************************************************************/
1075
- function display_error_message(title, msg, callback, without_buttons)
1076
- {
1077
- if(!title) {
1078
- title = t("error");
1079
- }
1080
- display_volatil_modal({
1081
- title: title,
1082
- msg: msg,
1083
- callback: callback,
1084
- type: 'error',
1085
- buttons: without_buttons? []: [{
1086
- content:
1087
- `<button class="button is-danger px-6 with-focus">${t('accept')}</button>`,
1088
- }]
1089
- });
1090
- }
1091
-
1092
- /************************************************************
1093
- *
1094
- ************************************************************/
1095
- function get_yesnocancel(msg, callback)
1096
- {
1097
- let content =
1098
- `<div class="">
1099
- <p class="yui-volatil-msg">${t(msg)}</p>
1100
- <div class="buttons is-centered">
1101
- <button class="button to-close is-success px-6 with-focus yesButton">${t('yes')}</button>
1102
- <button class="button to-close is-danger px-6 noButton">${t('no')}</button>
1103
- <button class="button to-close px-5 cancelButton">${t('cancel')}</button>
1104
- </div>
1105
- </div>`;
1106
-
1107
- const callback_ = (evt) => {
1108
- if (evt.currentTarget.classList.contains('yesButton')) {
1109
- callback("yes", evt);
1110
- } else if (evt.currentTarget.classList.contains('noButton')) {
1111
- callback("no", evt);
1112
- } else if (evt.currentTarget.classList.contains('cancelButton')) {
1113
- callback("cancel", evt);
1114
- }
1115
- };
1116
-
1117
- display_volatil_modal({
1118
- title: null,
1119
- msg: content,
1120
- callback: callback_,
1121
- type: 'question'
1122
- });
1123
- }
1124
-
1125
- /************************************************************
1126
- *
1127
- ************************************************************/
1128
- function get_yesno(msg, callback)
1129
- {
1130
- let content =
1131
- `<div class="">
1132
- <p class="yui-volatil-msg">${msg}</p>
1133
- <div class="buttons is-centered">
1134
- <button class="button to-close is-success px-6 with-focus yesButton">${t('yes')}</button>
1135
- <button class="button to-close is-danger px-6 noButton">${t('no')}</button>
1136
- </div>
1137
- </div>`;
1138
-
1139
- const callback_ = (evt) => {
1140
- if (evt.currentTarget.classList.contains('yesButton')) {
1141
- callback("yes", evt);
1142
- } else if (evt.currentTarget.classList.contains('noButton')) {
1143
- callback("no", evt);
1144
- } else if (evt.currentTarget.classList.contains('cancelButton')) {
1145
- callback("cancel", evt);
1146
- }
1147
- };
1148
-
1149
- display_volatil_modal({
1150
- title: null,
1151
- msg: content,
1152
- callback: callback_,
1153
- type: 'question'
1154
- });
1155
- }
1156
-
1157
- /************************************************************
1158
- *
1159
- ************************************************************/
1160
- function get_ok(msg, callback)
1161
- {
1162
- let content =
1163
- `<div class="">
1164
- <p class="yui-volatil-msg">${msg}</p>
1165
- <div class="buttons is-centered">
1166
- <button class="button to-close is-success px-6 with-focus yesButton">${t('accept')}</button>
1167
- </div>
1168
- </div>`;
1169
-
1170
- const callback_ = (evt) => {
1171
- if (evt.currentTarget.classList.contains('yesButton')) {
1172
- callback("yes", evt);
1173
- } else if (evt.currentTarget.classList.contains('noButton')) {
1174
- callback("no", evt);
1175
- } else if (evt.currentTarget.classList.contains('cancelButton')) {
1176
- callback("cancel", evt);
1177
- }
1178
- };
1179
-
1180
- display_volatil_modal({
1181
- title: null,
1182
- msg: content,
1183
- callback: callback_,
1184
- type: 'success'
1185
- });
1186
- }
1187
-
1188
- /************************************************************
1189
- * Switch between app and publi
1190
- ************************************************************/
1191
- function show_app_content(gobj, show)
1192
- {
1193
- /*
1194
- * Activate layers
1195
- */
1196
- let $content_layer = document.getElementById("content-layer");
1197
- let $iframe_layer = document.getElementById("iframe-layer");
1198
- if(show) {
1199
- // Activate own content
1200
- $content_layer.classList.remove('is-hidden');
1201
- if($iframe_layer) {
1202
- $iframe_layer.classList.add('is-hidden');
1203
- }
1204
- } else {
1205
- // Activate publi content
1206
- $content_layer.classList.add('is-hidden');
1207
- if($iframe_layer) {
1208
- $iframe_layer.classList.remove('is-hidden');
1209
- }
1210
- }
1211
- }
1212
-
1213
- /************************************************************
1214
- *
1215
- ************************************************************/
1216
- function resize_and_subscribe_to_system(gobj)
1217
- {
1218
- let last_w = 0;
1219
- let last_h = 0;
1220
- let scheduled = false;
1221
-
1222
- function get_viewport_size()
1223
- {
1224
- if(window.visualViewport) {
1225
- return {
1226
- width: window.visualViewport.width,
1227
- height: window.visualViewport.height
1228
- };
1229
- }
1230
-
1231
- return {
1232
- width: window.innerWidth,
1233
- height: window.innerHeight
1234
- };
1235
- }
1236
-
1237
- function resize()
1238
- {
1239
- scheduled = false;
1240
-
1241
- const {width, height} = get_viewport_size();
1242
-
1243
- if(width === 0 || height === 0) {
1244
- requestAnimationFrame(schedule_resize);
1245
- return;
1246
- }
1247
-
1248
- if(width === last_w && height === last_h) {
1249
- return;
1250
- }
1251
-
1252
- last_w = width;
1253
- last_h = height;
1254
-
1255
- gobj_write_attr(gobj, "width", width);
1256
- gobj_write_attr(gobj, "height", height);
1257
-
1258
- gobj_publish_event(gobj, "EV_RESIZE", {width, height});
1259
- }
1260
-
1261
- function schedule_resize()
1262
- {
1263
- if(scheduled) {
1264
- return;
1265
- }
1266
-
1267
- scheduled = true;
1268
- requestAnimationFrame(resize);
1269
- }
1270
-
1271
- const debouncedResize = debounce(schedule_resize, 100);
1272
-
1273
- if(window.visualViewport) {
1274
- window.visualViewport.addEventListener("resize", debouncedResize);
1275
- window.visualViewport.addEventListener("scroll", debouncedResize);
1276
- } else {
1277
- window.addEventListener("resize", debouncedResize);
1278
- }
1279
- }
1280
-
1281
-
1282
-
1283
-
1284
- /***************************
1285
- * Actions
1286
- ***************************/
1287
-
1288
-
1289
-
1290
-
1291
- /************************************************
1292
- * {
1293
- * username:
1294
- * password:
1295
- * }
1296
- ************************************************/
1297
- function ac_do_login(gobj, event, kw, src)
1298
- {
1299
- set_error_login_message(gobj, "");
1300
-
1301
- let __login__ = gobj_find_service("__login__", true);
1302
- gobj_send_event(__login__, "EV_DO_LOGIN", kw, gobj);
1303
- return 0;
1304
- }
1305
-
1306
- /************************************************
1307
- *
1308
- ************************************************/
1309
- function ac_do_logout(gobj, event, kw, src)
1310
- {
1311
- let __login__ = gobj_find_service("__login__", true);
1312
- gobj_send_event(__login__, "EV_DO_LOGOUT", kw, gobj);
1313
- return 0;
1314
- }
1315
-
1316
- function ac_do_recovery_password(gobj, event, kw, src)
1317
- {
1318
- // TODO
1319
- return 0;
1320
- }
1321
-
1322
- /************************************************
1323
- * {
1324
- * username:
1325
- * jwt:
1326
- * }
1327
- ************************************************/
1328
- function ac_login_accepted(gobj, event, kw, src)
1329
- {
1330
- hide_login_form(gobj);
1331
- set_username(gobj, kw.username);
1332
- return 0;
1333
- }
1334
-
1335
- /************************************************
1336
- *
1337
- ************************************************/
1338
- function ac_login_refreshed(gobj, event, kw, src)
1339
- {
1340
- return 0;
1341
- }
1342
-
1343
- /************************************************
1344
- * EV_LOGIN_DENIED payload contract (from c_login.js):
1345
- * {
1346
- * error_code: "invalid_credentials" | "account_disabled" | ...,
1347
- * error: "<english developer fallback>"
1348
- * }
1349
- * `error_code` is the stable i18n key published by the auth_bff; see
1350
- * the catalogue in kernel/c/root-linux/src/c_auth_bff.h. We look up
1351
- * the translation with t(error_code); if the key is missing from the
1352
- * locale file t() returns it verbatim, so we then fall back to t() on
1353
- * the english `error` string to keep something readable on screen.
1354
- ************************************************/
1355
- function ac_login_denied(gobj, event, kw, src)
1356
- {
1357
- set_username(gobj, "");
1358
- let error_code = kw_get_str(gobj, kw, "error_code", "", 0);
1359
- let error = kw_get_str(gobj, kw, "error", "login denied", 0);
1360
-
1361
- let translated;
1362
- if(error_code) {
1363
- translated = t(error_code);
1364
- if(translated === error_code) {
1365
- // key missing from locale — fall back to the english text
1366
- translated = t(error);
1367
- }
1368
- } else {
1369
- translated = t(error);
1370
- }
1371
- set_error_login_message(gobj, translated);
1372
- return 0;
1373
- }
1374
-
1375
- /************************************************
1376
- *
1377
- ************************************************/
1378
- function ac_logout_done(gobj, event, kw, src)
1379
- {
1380
- set_username(gobj, "");
1381
- return 0;
1382
- }
1383
-
1384
- /************************************************
1385
- *
1386
- ************************************************/
1387
- function ac_select_language(gobj, event, kw, src)
1388
- {
1389
- show_select_language(gobj, true);
1390
- return 0;
1391
- }
1392
-
1393
- /************************************************
1394
- *
1395
- ************************************************/
1396
- function ac_app_menu(gobj, event, kw, src)
1397
- {
1398
- if(kw.evt.type === 'click') {
1399
- gobj_publish_event(gobj, event, {});
1400
- } else if(kw.evt.type === 'contextmenu') {
1401
- if(!gobj_find_service("Developer-Window")) {
1402
- setup_dev(gobj, true);
1403
- }
1404
- }
1405
- return 0;
1406
- }
1407
-
1408
- /************************************************
1409
- *
1410
- ************************************************/
1411
- function ac_home(gobj, event, kw, src)
1412
- {
1413
- let home = gobj_read_attr(gobj_default_service(), "home");
1414
- if(home) {
1415
- gobj_send_event(gobj_find_service("__yui_routing__"),
1416
- "EV_SELECT",
1417
- {
1418
- id: home
1419
- },
1420
- gobj
1421
- );
1422
- }
1423
-
1424
- return 0;
1425
- }
1426
-
1427
- /************************************************
1428
- *
1429
- ************************************************/
1430
- function ac_select_theme(gobj, event, kw, src)
1431
- {
1432
- let current_theme = kw_get_local_storage_value("theme", "light", true);
1433
-
1434
- let new_theme;
1435
- switch (current_theme) {
1436
- case 'dark':
1437
- new_theme = 'light';
1438
- break;
1439
- case 'light':
1440
- default:
1441
- new_theme = 'dark';
1442
- break;
1443
- }
1444
-
1445
- set_theme(gobj, new_theme);
1446
- kw_set_local_storage_value("theme", new_theme);
1447
-
1448
- return 0;
1449
- }
1450
-
1451
- /************************************************
1452
- *
1453
- ************************************************/
1454
- function ac_user_menu(gobj, event, kw, src)
1455
- {
1456
- if(empty_string(gobj_read_attr(gobj, "username"))) {
1457
- show_login_form(gobj);
1458
- } else {
1459
- let element = kw.evt.currentTarget; // button clicked
1460
- let pos = getPositionRelativeToBody(element);
1461
- show_user_menu(gobj, true, pos);
1462
- }
1463
-
1464
- return 0;
1465
- }
1466
-
1467
- /********************************************
1468
- * Connected to yuneta
1469
- ********************************************/
1470
- function ac_on_open(gobj, event, kw, src)
1471
- {
1472
- /*
1473
- * Change color icon
1474
- */
1475
- document.getElementById("icon_yuneta_state").style.color = gobj_read_attr(gobj, "color_yuneta_connected");
1476
-
1477
- show_app_content(gobj, true);
1478
- return 0;
1479
- }
1480
-
1481
- /********************************************
1482
- * Disconnected from yuneta
1483
- ********************************************/
1484
- function ac_on_close(gobj, event, kw, src)
1485
- {
1486
- /*
1487
- * Change color icon
1488
- */
1489
- document.getElementById("icon_yuneta_state").style.color = gobj_read_attr(gobj, "color_yuneta_disconnected");
1490
-
1491
- show_app_content(gobj, false);
1492
- return 0;
1493
- }
1494
-
1495
- /************************************************
1496
- *
1497
- ************************************************/
1498
- function ac_timeout(gobj, event, kw, src)
1499
- {
1500
- if (empty_string(gobj_read_attr(gobj, "username"))) {
1501
- show_login_form(gobj);
1502
- }
1503
- return 0;
1504
- }
1505
-
1506
-
1507
-
1508
-
1509
- /***************************
1510
- * FSM
1511
- ***************************/
1512
-
1513
-
1514
-
1515
-
1516
- /*---------------------------------------------*
1517
- * Global methods table
1518
- *---------------------------------------------*/
1519
- const gmt = {
1520
- mt_create: mt_create,
1521
- mt_start: mt_start,
1522
- mt_stop: mt_stop,
1523
- mt_destroy: mt_destroy
1524
- };
1525
-
1526
- /***************************************************************
1527
- * Create the GClass
1528
- ***************************************************************/
1529
- function create_gclass(gclass_name)
1530
- {
1531
- if (__gclass__) {
1532
- log_error(`GClass ALREADY created: ${gclass_name}`);
1533
- return -1;
1534
- }
1535
-
1536
- /***************************************************************
1537
- * FSM
1538
- ***************************************************************/
1539
- /*---------------------------------------------*
1540
- * States
1541
- *---------------------------------------------*/
1542
- const states = [
1543
- ["ST_IDLE", [
1544
- ["EV_LOGIN_ACCEPTED", ac_login_accepted, null],
1545
- ["EV_LOGIN_DENIED", ac_login_denied, null],
1546
- ["EV_LOGIN_REFRESHED", ac_login_refreshed, null],
1547
- ["EV_LOGOUT_DONE", ac_logout_done, null],
1548
- ["EV_DO_LOGIN", ac_do_login, null],
1549
- ["EV_DO_LOGOUT", ac_do_logout, null],
1550
- ["EV_SELECT_LANGUAGE", ac_select_language, null],
1551
- ["EV_APP_MENU", ac_app_menu, null],
1552
- ["EV_HOME", ac_home, null],
1553
- ["EV_SELECT_THEME", ac_select_theme, null],
1554
- ["EV_USER_MENU", ac_user_menu, null],
1555
- ["EV_ON_OPEN", ac_on_open, null],
1556
- ["EV_ON_CLOSE", ac_on_close, null],
1557
- ["EV_DO_RECOVERY_PASSWORD", ac_do_recovery_password,null],
1558
- ["EV_TIMEOUT", ac_timeout, null]
1559
- ]]
1560
- ];
1561
-
1562
- /*---------------------------------------------*
1563
- * Events
1564
- *---------------------------------------------*/
1565
- const event_types = [
1566
- ["EV_LOGIN_ACCEPTED", 0],
1567
- ["EV_LOGIN_DENIED", 0],
1568
- ["EV_LOGIN_REFRESHED", 0],
1569
- ["EV_LOGOUT_DONE", 0],
1570
- ["EV_RESIZE", event_flag_t.EVF_OUTPUT_EVENT|event_flag_t.EVF_NO_WARN_SUBS],
1571
- ["EV_THEME", event_flag_t.EVF_OUTPUT_EVENT|event_flag_t.EVF_NO_WARN_SUBS],
1572
- ["EV_DO_LOGIN", 0],
1573
- ["EV_DO_LOGOUT", 0],
1574
- ["EV_SELECT_LANGUAGE", 0],
1575
- ["EV_APP_MENU", event_flag_t.EVF_OUTPUT_EVENT],
1576
- ["EV_HOME", 0],
1577
- ["EV_SELECT_THEME", 0],
1578
- ["EV_USER_MENU", 0],
1579
- ["EV_ON_OPEN", 0],
1580
- ["EV_ON_CLOSE", 0],
1581
- ["EV_DO_RECOVERY_PASSWORD", 0],
1582
- ["EV_TIMEOUT", 0]
1583
- ];
1584
-
1585
- __gclass__ = gclass_create(
1586
- gclass_name,
1587
- event_types,
1588
- states,
1589
- gmt,
1590
- 0, // lmt,
1591
- attrs_table,
1592
- PRIVATE_DATA,
1593
- 0, // authz_table,
1594
- 0, // command_table,
1595
- 0, // s_user_trace_level
1596
- 0 // gclass_flag
1597
- );
1598
- if(!__gclass__) {
1599
- // Error already logged
1600
- return -1;
1601
- }
1602
-
1603
- return 0;
1604
- }
1605
-
1606
- /***************************************************************
1607
- * Register GClass
1608
- ***************************************************************/
1609
- function register_c_yui_main()
1610
- {
1611
- return create_gclass(GCLASS_NAME);
1612
- }
1613
-
1614
- export {
1615
- register_c_yui_main,
1616
- display_volatil_modal,
1617
- display_info_message,
1618
- display_warning_message,
1619
- display_error_message,
1620
- get_yesnocancel,
1621
- get_yesno,
1622
- get_ok,
1623
- };