@yuneta/gobj-ui 7.26.34 → 7.26.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -53
- package/dist/gobj-ui.cjs.js +1035 -141
- package/dist/gobj-ui.es.js +1035 -141
- package/package.json +2 -2
- package/scripts/validate-locales.mjs +672 -96
- package/src/c_yui_form.js +186 -9
- package/src/c_yui_gclass.js +2 -0
- package/src/c_yui_gobj_tree_js.js +2 -0
- package/src/c_yui_json.js +2 -0
- package/src/c_yui_json_graph.js +2 -0
- package/src/c_yui_nav.js +23 -5
- package/src/c_yui_shell.css +16 -0
- package/src/c_yui_shell.js +282 -26
- package/src/c_yui_treedb_graph.js +26 -8
- package/src/c_yui_treedb_topic_with_form.js +40 -18
- package/src/c_yui_treedb_topics.js +34 -11
- package/src/c_yui_window.js +132 -32
- package/src/c_yui_window_manager.js +156 -44
- package/src/form_json_editor_names.js +448 -0
- package/src/form_json_editor_names.wiring.test.js +595 -0
- package/src/form_label_i18n.wiring.test.js +169 -0
- package/src/i18n_key_functions.js +14 -6
- package/src/i18n_key_functions.test.js +124 -2
- package/src/lib_maplibre.js +26 -2
- package/src/lib_maplibre_relocalize.test.js +78 -0
- package/src/named_controls.wiring.test.js +468 -0
- package/src/nav_cards_helpers.js +9 -1
- package/src/nav_item_badge.wiring.test.js +182 -1
- package/src/shell_route_map.js +25 -8
- package/src/table_editor_name.wiring.test.js +201 -0
- package/src/treedb_column_title.wiring.test.js +151 -0
- package/src/treedb_json_drill.wiring.test.js +41 -1
- package/src/window_layer.wiring.test.js +308 -43
- package/src/window_show.wiring.test.js +6 -2
- package/src/window_stacking.wiring.test.js +334 -0
- package/src/yui_badge.js +58 -13
- package/src/yui_badge.test.js +40 -3
- package/src/yui_dev.js +2 -1
- package/src/yui_file_field.js +2 -0
- package/src/yui_frontend_view.js +2 -1
- package/src/yui_gclass_view.js +9 -6
- package/src/yui_tabulator_i18n.js +42 -0
- package/src/yui_tabulator_i18n.test.js +48 -1
package/dist/gobj-ui.es.js
CHANGED
|
@@ -540,14 +540,26 @@ function text_list_item_formatter(label) {
|
|
|
540
540
|
* ALWAYS RENDERED, hidden when empty, so the runtime setters have a
|
|
541
541
|
* node to write into and never rebuild the control that holds it.
|
|
542
542
|
*
|
|
543
|
-
*
|
|
544
|
-
* carries an explicit aria-label, and an explicit label
|
|
545
|
-
* the element's content for a screen reader -- so a badge
|
|
546
|
-
* it
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
*
|
|
550
|
-
*
|
|
543
|
+
* PART OF THE CONTROL'S NAME (name_control_with_badge()). The
|
|
544
|
+
* control carries an explicit aria-label, and an explicit label
|
|
545
|
+
* REPLACES the element's content for a screen reader -- so a badge
|
|
546
|
+
* inside it is silent, and inside a <button> (the toolbar, an
|
|
547
|
+
* accordion head) its children are not even in the tree. The
|
|
548
|
+
* control is labelled by ITSELF (its aria-label, which
|
|
549
|
+
* refresh_language() re-translates) and by the badge: the name is
|
|
550
|
+
* "Alarms 3" while there is a count, "Alarms" while there is none,
|
|
551
|
+
* with nothing composed in javascript that a language switch would
|
|
552
|
+
* leave behind.
|
|
553
|
+
*
|
|
554
|
+
* NOT a live region any more. Up to 7.26.34 the badge was its own
|
|
555
|
+
* role="status", and that said "3" with no word of what has three;
|
|
556
|
+
* hidden while empty, it was not in the tree when the first count
|
|
557
|
+
* arrived, so 0 -> 1 was most likely never said; and inside a
|
|
558
|
+
* <button> it was not there at all. The change is said by the
|
|
559
|
+
* shell, in one live region of its own that is always there, with
|
|
560
|
+
* the name of the item: "Alarms, 3" (yui_shell_set_nav_item_badge,
|
|
561
|
+
* yui_shell_set_toolbar_item_badge). A write that changes nothing
|
|
562
|
+
* still touches no DOM.
|
|
551
563
|
*
|
|
552
564
|
* A TONE, optional: one of BADGE_TONES, drawn as Bulma's
|
|
553
565
|
* `is-<tone>` on the badge. It says HOW BAD the count is -- the
|
|
@@ -573,6 +585,7 @@ var BADGE_TONES = Object.freeze([
|
|
|
573
585
|
"primary",
|
|
574
586
|
"link"
|
|
575
587
|
]);
|
|
588
|
+
var __badge_seq__ = 0;
|
|
576
589
|
/************************************************************
|
|
577
590
|
* The text a badge shows for `value`, "" when it shows none.
|
|
578
591
|
************************************************************/
|
|
@@ -606,10 +619,7 @@ function badge_tone(tone, who) {
|
|
|
606
619
|
function badge_node(value, tone, classes, who) {
|
|
607
620
|
let text = badge_text(value);
|
|
608
621
|
let known = badge_tone(tone, who);
|
|
609
|
-
let attrs = {
|
|
610
|
-
class: known ? `${classes} is-${known}` : classes,
|
|
611
|
-
role: "status"
|
|
612
|
-
};
|
|
622
|
+
let attrs = { class: known ? `${classes} is-${known}` : classes };
|
|
613
623
|
if (!text) attrs.hidden = "hidden";
|
|
614
624
|
return [
|
|
615
625
|
"span",
|
|
@@ -618,6 +628,31 @@ function badge_node(value, tone, classes, who) {
|
|
|
618
628
|
];
|
|
619
629
|
}
|
|
620
630
|
/************************************************************
|
|
631
|
+
* Make the count part of the NAME of the control that carries
|
|
632
|
+
* the badge: its `aria-labelledby` points at the control itself
|
|
633
|
+
* and at the badge.
|
|
634
|
+
*
|
|
635
|
+
* The control keeps its `aria-label` and its
|
|
636
|
+
* data-i18n-aria-label: a self-reference reads the aria-label,
|
|
637
|
+
* so the name is the translated label followed by the badge's
|
|
638
|
+
* text -- "Alarms 3" -- or the label alone while the badge is
|
|
639
|
+
* empty. A painted count is in the name at once, and a language
|
|
640
|
+
* switch re-translates the label as it always did.
|
|
641
|
+
*
|
|
642
|
+
* Both are createElement2() descriptions, before anything is
|
|
643
|
+
* built: `control_attrs` (the attrs of the <a> or <button>, which
|
|
644
|
+
* must carry its aria-label) gets an `id` when it has none, and
|
|
645
|
+
* the `aria-labelledby`; `badge` (what badge_node() answered)
|
|
646
|
+
* gets its `id`.
|
|
647
|
+
************************************************************/
|
|
648
|
+
function name_control_with_badge(control_attrs, badge) {
|
|
649
|
+
let seq = ++__badge_seq__;
|
|
650
|
+
if (!control_attrs.id) control_attrs.id = `yui-badged-${seq}`;
|
|
651
|
+
let badge_attrs = badge[1];
|
|
652
|
+
badge_attrs.id = `yui-badge-${seq}`;
|
|
653
|
+
control_attrs["aria-labelledby"] = `${control_attrs.id} ${badge_attrs.id}`;
|
|
654
|
+
}
|
|
655
|
+
/************************************************************
|
|
621
656
|
* Write a badge that is already in the DOM, as badge_node()
|
|
622
657
|
* draws it. `tone` is one badge_tone() answered: the setter
|
|
623
658
|
* checks it once for all the badges it paints.
|
|
@@ -1014,6 +1049,8 @@ function secondary_nav_renders(item, layout) {
|
|
|
1014
1049
|
*
|
|
1015
1050
|
* Parses a JSON config to build:
|
|
1016
1051
|
* - Layers (z-stacked): base, overlay, popup, modal, notification, loading
|
|
1052
|
+
* (the overlay holds the WINDOW layer, where the windows live,
|
|
1053
|
+
* under the drawer: yui_shell_window_layer())
|
|
1017
1054
|
* - Zones (inside base layer): top, top-sub, left, center, right,
|
|
1018
1055
|
* bottom-sub, bottom
|
|
1019
1056
|
* - Menus (primary + submenus) rendered via C_YUI_NAV — one nav
|
|
@@ -1041,6 +1078,8 @@ function secondary_nav_renders(item, layout) {
|
|
|
1041
1078
|
***************************************************************/
|
|
1042
1079
|
var GCLASS_NAME$22 = "C_YUI_SHELL";
|
|
1043
1080
|
var __last_shell__ = null;
|
|
1081
|
+
var __shell_watchers__ = [];
|
|
1082
|
+
var __window_z__ = 10;
|
|
1044
1083
|
var ZONE_IDS = [
|
|
1045
1084
|
"top",
|
|
1046
1085
|
"top-sub",
|
|
@@ -1075,10 +1114,12 @@ var attrs_table$22 = [
|
|
|
1075
1114
|
var PRIVATE_DATA$22 = {
|
|
1076
1115
|
zones: {},
|
|
1077
1116
|
layers: {},
|
|
1117
|
+
window_layer: null,
|
|
1078
1118
|
stages: {},
|
|
1079
1119
|
navs: [],
|
|
1080
1120
|
item_index: {},
|
|
1081
1121
|
nav_badges: {},
|
|
1122
|
+
badge_status: null,
|
|
1082
1123
|
dynamic_items: {},
|
|
1083
1124
|
section_pos: {},
|
|
1084
1125
|
route_mru: [],
|
|
@@ -1119,6 +1160,7 @@ function mt_create$22(gobj) {
|
|
|
1119
1160
|
if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
1120
1161
|
__last_shell__ = gobj;
|
|
1121
1162
|
build_ui$19(gobj);
|
|
1163
|
+
tell_shell_watchers(gobj);
|
|
1122
1164
|
}
|
|
1123
1165
|
/***************************************************************
|
|
1124
1166
|
* Framework Method: Start
|
|
@@ -1302,10 +1344,11 @@ function mt_stop$20(gobj) {
|
|
|
1302
1344
|
***************************************************************/
|
|
1303
1345
|
function mt_destroy$22(gobj) {
|
|
1304
1346
|
close_toolbar_dropdown(gobj);
|
|
1347
|
+
if (__last_shell__ === gobj) __last_shell__ = null;
|
|
1305
1348
|
let $container = gobj_read_attr(gobj, "$container");
|
|
1306
1349
|
if ($container && $container.parentNode) $container.parentNode.removeChild($container);
|
|
1350
|
+
tell_shell_watchers(gobj);
|
|
1307
1351
|
gobj_write_attr(gobj, "$container", null);
|
|
1308
|
-
if (__last_shell__ === gobj) __last_shell__ = null;
|
|
1309
1352
|
}
|
|
1310
1353
|
/***************************
|
|
1311
1354
|
* Local Methods
|
|
@@ -1428,6 +1471,17 @@ function build_ui$19(gobj) {
|
|
|
1428
1471
|
$container.appendChild($layer);
|
|
1429
1472
|
priv.layers[id] = $layer;
|
|
1430
1473
|
}
|
|
1474
|
+
let $windows = createElement2(["div", { class: "SHELL_WINDOW_LAYER yui-window-layer" }]);
|
|
1475
|
+
priv.layers.overlay.appendChild($windows);
|
|
1476
|
+
priv.window_layer = $windows;
|
|
1477
|
+
let $status = createElement2(["div", {
|
|
1478
|
+
class: "SHELL_BADGE_STATUS is-sr-only",
|
|
1479
|
+
role: "status",
|
|
1480
|
+
"aria-live": "polite",
|
|
1481
|
+
"aria-atomic": "true"
|
|
1482
|
+
}]);
|
|
1483
|
+
$container.appendChild($status);
|
|
1484
|
+
priv.badge_status = $status;
|
|
1431
1485
|
let $base = priv.layers.base;
|
|
1432
1486
|
$base.classList.add("yui-base-grid");
|
|
1433
1487
|
let zones_cfg = shell_cfg.zones || {};
|
|
@@ -2021,14 +2075,18 @@ function toolbar_link_attrs(it) {
|
|
|
2021
2075
|
************************************************************/
|
|
2022
2076
|
function build_toolbar_action_item(gobj, it) {
|
|
2023
2077
|
let children = [];
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
[
|
|
2028
|
-
|
|
2029
|
-
"
|
|
2030
|
-
|
|
2031
|
-
|
|
2078
|
+
let badge = null;
|
|
2079
|
+
if (!empty_string(it.icon)) {
|
|
2080
|
+
badge = badge_node(it.badge, it.badge_tone, "TOOLBAR_ITEM_BADGE yui-badge yui-toolbar-badge", `C_YUI_SHELL: toolbar item '${it.id || "?"}'`);
|
|
2081
|
+
children.push([
|
|
2082
|
+
"span",
|
|
2083
|
+
{ class: "icon yui-toolbar-icon" },
|
|
2084
|
+
[["i", {
|
|
2085
|
+
class: it.icon,
|
|
2086
|
+
"aria-hidden": "true"
|
|
2087
|
+
}], badge]
|
|
2088
|
+
]);
|
|
2089
|
+
}
|
|
2032
2090
|
if (!empty_string(it.name)) children.push([
|
|
2033
2091
|
"span",
|
|
2034
2092
|
{
|
|
@@ -2055,6 +2113,7 @@ function build_toolbar_action_item(gobj, it) {
|
|
|
2055
2113
|
btn_attrs.title = tip;
|
|
2056
2114
|
btn_attrs["data-i18n-title"] = tip;
|
|
2057
2115
|
}
|
|
2116
|
+
if (badge && !empty_string(aria_key)) name_control_with_badge(btn_attrs, badge);
|
|
2058
2117
|
let link = toolbar_link_attrs(it);
|
|
2059
2118
|
if (link) {
|
|
2060
2119
|
delete btn_attrs.type;
|
|
@@ -2839,23 +2898,32 @@ function update_secondary_nav_visibility(gobj, entry) {
|
|
|
2839
2898
|
}
|
|
2840
2899
|
}
|
|
2841
2900
|
/************************************************************
|
|
2842
|
-
*
|
|
2843
|
-
* of a menu of app_config.json, of one of
|
|
2844
|
-
* one given to yui_shell_set_submenu() since
|
|
2901
|
+
* The item `item_id` a menu of this shell declares, null when
|
|
2902
|
+
* none does: an item of a menu of app_config.json, of one of
|
|
2903
|
+
* their submenus, or one given to yui_shell_set_submenu() since
|
|
2904
|
+
* -- which comes first, because it replaced what the submenu
|
|
2905
|
+
* declared and is what the navs draw.
|
|
2845
2906
|
************************************************************/
|
|
2846
|
-
function
|
|
2907
|
+
function nav_item_of(gobj, item_id) {
|
|
2847
2908
|
let priv = gobj.priv;
|
|
2848
2909
|
let config = gobj_read_attr(gobj, "config") || {};
|
|
2849
2910
|
let menus = is_object(config.menu) ? config.menu : {};
|
|
2850
|
-
let
|
|
2911
|
+
let find = (items) => is_array(items) && items.find((it) => it && it.id === item_id) || null;
|
|
2912
|
+
for (let parent_item_id in priv.dynamic_items) {
|
|
2913
|
+
let it = find(priv.dynamic_items[parent_item_id]);
|
|
2914
|
+
if (it) return it;
|
|
2915
|
+
}
|
|
2851
2916
|
for (let menu_id in menus) {
|
|
2852
2917
|
let items = menus[menu_id] && menus[menu_id].items;
|
|
2853
2918
|
if (!is_array(items)) continue;
|
|
2854
|
-
|
|
2855
|
-
|
|
2919
|
+
let it = find(items);
|
|
2920
|
+
if (it) return it;
|
|
2921
|
+
for (let parent of items) {
|
|
2922
|
+
let sub = parent && parent.submenu && find(parent.submenu.items);
|
|
2923
|
+
if (sub) return sub;
|
|
2924
|
+
}
|
|
2856
2925
|
}
|
|
2857
|
-
|
|
2858
|
-
return false;
|
|
2926
|
+
return null;
|
|
2859
2927
|
}
|
|
2860
2928
|
/************************************************************
|
|
2861
2929
|
* Every C_YUI_NAV of this shell: the navs of its menus, and the
|
|
@@ -2873,6 +2941,61 @@ function shell_navs(gobj) {
|
|
|
2873
2941
|
}
|
|
2874
2942
|
return navs;
|
|
2875
2943
|
}
|
|
2944
|
+
/************************************************************
|
|
2945
|
+
* Say a badge that changed, with the name of what it counts:
|
|
2946
|
+
* "Alarms, 3", in the shell's live region (build_ui()).
|
|
2947
|
+
*
|
|
2948
|
+
* The badge itself is no live region (yui_badge.js): its number
|
|
2949
|
+
* alone said nothing, hidden while empty it missed the first
|
|
2950
|
+
* count, and inside a <button> it was not there at all. The
|
|
2951
|
+
* setters call this only when the text a reader would see
|
|
2952
|
+
* changes and is not empty: a count going away is not news, and
|
|
2953
|
+
* the same count again is not either.
|
|
2954
|
+
*
|
|
2955
|
+
* `name_key` is the key of the control's name; the phrase is a
|
|
2956
|
+
* key of its own, so a language orders and punctuates it its
|
|
2957
|
+
* way. Said once: a live region needs no re-translation.
|
|
2958
|
+
************************************************************/
|
|
2959
|
+
function announce_badge(gobj, name_key, text) {
|
|
2960
|
+
let priv = gobj.priv;
|
|
2961
|
+
let $status = priv.badge_status;
|
|
2962
|
+
if (!$status) {
|
|
2963
|
+
log_error(`C_YUI_SHELL: no live region to say badge '${name_key}': ${text}`);
|
|
2964
|
+
return;
|
|
2965
|
+
}
|
|
2966
|
+
let message;
|
|
2967
|
+
if (typeof priv.translator === "function") {
|
|
2968
|
+
const tr = priv.translator;
|
|
2969
|
+
message = tr("{{name}}, {{n}}", {
|
|
2970
|
+
name: tr(name_key),
|
|
2971
|
+
n: text
|
|
2972
|
+
});
|
|
2973
|
+
} else message = `${name_key}, ${text}`;
|
|
2974
|
+
$status.textContent = message;
|
|
2975
|
+
}
|
|
2976
|
+
/************************************************************
|
|
2977
|
+
* A shell was built (mt_create) or is being destroyed
|
|
2978
|
+
* (mt_destroy): tell every gobj that keeps DOM in a shell's
|
|
2979
|
+
* layers without being its child (yui_shell_watch_changes()).
|
|
2980
|
+
* Each one decides in its own action what it means for it --
|
|
2981
|
+
* the trace shows EV_SHELL_CHANGED arriving, from a `!!` shell
|
|
2982
|
+
* when it is the one going.
|
|
2983
|
+
*
|
|
2984
|
+
* An event, not a call into the window's module: the shell does
|
|
2985
|
+
* not import its watchers, and the move is work, so it crosses
|
|
2986
|
+
* their FSM. A watcher that is being destroyed is one whose
|
|
2987
|
+
* mt_destroy did not unwatch: it is dropped, and said.
|
|
2988
|
+
************************************************************/
|
|
2989
|
+
function tell_shell_watchers(gobj) {
|
|
2990
|
+
for (let watcher of __shell_watchers__.slice()) {
|
|
2991
|
+
if (gobj_is_destroying(watcher)) {
|
|
2992
|
+
log_error(`C_YUI_SHELL: a destroyed gobj still watches the shell (${gobj_short_name(watcher)}): it must call yui_shell_unwatch_changes() in its mt_destroy`);
|
|
2993
|
+
yui_shell_unwatch_changes(watcher);
|
|
2994
|
+
continue;
|
|
2995
|
+
}
|
|
2996
|
+
gobj_send_event(watcher, "EV_SHELL_CHANGED", {}, gobj);
|
|
2997
|
+
}
|
|
2998
|
+
}
|
|
2876
2999
|
/***************************
|
|
2877
3000
|
* Actions
|
|
2878
3001
|
***************************/
|
|
@@ -3142,6 +3265,81 @@ function yui_shell_of(gobj) {
|
|
|
3142
3265
|
return __last_shell__;
|
|
3143
3266
|
}
|
|
3144
3267
|
/************************************************************
|
|
3268
|
+
* The DOM where a C_YUI_WINDOW lives when its host names no
|
|
3269
|
+
* `$parent`: the WINDOW layer, a stacking context of its own
|
|
3270
|
+
* inside the overlay layer -- above the content, below the
|
|
3271
|
+
* drawer, the toolbar's dropdowns, the dialogs and the toasts,
|
|
3272
|
+
* whatever z-index a window takes there. Null with no shell (the
|
|
3273
|
+
* window then lives in document.body).
|
|
3274
|
+
************************************************************/
|
|
3275
|
+
function yui_shell_window_layer(shell_gobj) {
|
|
3276
|
+
if (!shell_gobj || !shell_gobj.priv) return null;
|
|
3277
|
+
let priv = shell_gobj.priv;
|
|
3278
|
+
return priv.window_layer || priv.layers && priv.layers.overlay || null;
|
|
3279
|
+
}
|
|
3280
|
+
/************************************************************
|
|
3281
|
+
* Put a window on top of the others: the next number of ONE
|
|
3282
|
+
* counter, the same for a window of the dock and for a floating
|
|
3283
|
+
* one.
|
|
3284
|
+
*
|
|
3285
|
+
* Up to 7.26.34 there were two orders: the dock raised its windows
|
|
3286
|
+
* to a counter of its own (11, 12, ...), and a window without a
|
|
3287
|
+
* dock sat at 3 and was raised by being moved to the end of its
|
|
3288
|
+
* parent -- so a window opened LATER without a dock (a treedb's
|
|
3289
|
+
* raw json) opened UNDER any docked one, and no click could bring
|
|
3290
|
+
* it up. They share the window layer, and this one number orders
|
|
3291
|
+
* them all. It grows for ever, and it can: nothing else lives in
|
|
3292
|
+
* the window layer's stacking context.
|
|
3293
|
+
*
|
|
3294
|
+
* A number, not a move in the DOM: moving an element takes its
|
|
3295
|
+
* focus, its scroll positions and the pointer press that started
|
|
3296
|
+
* on it.
|
|
3297
|
+
************************************************************/
|
|
3298
|
+
function yui_shell_raise_window($el) {
|
|
3299
|
+
if (!$el || !$el.style) {
|
|
3300
|
+
log_error("C_YUI_SHELL: yui_shell_raise_window() needs an element");
|
|
3301
|
+
return;
|
|
3302
|
+
}
|
|
3303
|
+
__window_z__ += 1;
|
|
3304
|
+
$el.style.zIndex = String(__window_z__);
|
|
3305
|
+
}
|
|
3306
|
+
/************************************************************
|
|
3307
|
+
* Ask to be told (EV_SHELL_CHANGED, an INPUT event the gclass of
|
|
3308
|
+
* `gobj` must take in its FSM) when a shell is built or
|
|
3309
|
+
* destroyed.
|
|
3310
|
+
*
|
|
3311
|
+
* For a gobj that keeps DOM in a shell's layers without being
|
|
3312
|
+
* its child -- a window parented to the app, the dock. A shell's
|
|
3313
|
+
* children are destroyed with it; such a gobj is not, and its
|
|
3314
|
+
* place goes with the shell: a logout destroys the shell, the
|
|
3315
|
+
* login builds another. Told, it takes its place again in the
|
|
3316
|
+
* action.
|
|
3317
|
+
*
|
|
3318
|
+
* Idempotent. Pair it with yui_shell_unwatch_changes() in
|
|
3319
|
+
* mt_destroy, or the next shell sends the event to a destroyed
|
|
3320
|
+
* gobj.
|
|
3321
|
+
*
|
|
3322
|
+
* function mt_create(gobj) {
|
|
3323
|
+
* ...
|
|
3324
|
+
* yui_shell_watch_changes(gobj);
|
|
3325
|
+
* }
|
|
3326
|
+
* function mt_destroy(gobj) {
|
|
3327
|
+
* yui_shell_unwatch_changes(gobj);
|
|
3328
|
+
* ...
|
|
3329
|
+
* }
|
|
3330
|
+
************************************************************/
|
|
3331
|
+
function yui_shell_watch_changes(gobj) {
|
|
3332
|
+
if (!is_gobj(gobj)) {
|
|
3333
|
+
log_error("C_YUI_SHELL: yui_shell_watch_changes() needs a gobj");
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
if (__shell_watchers__.indexOf(gobj) < 0) __shell_watchers__.push(gobj);
|
|
3337
|
+
}
|
|
3338
|
+
function yui_shell_unwatch_changes(gobj) {
|
|
3339
|
+
let idx = __shell_watchers__.indexOf(gobj);
|
|
3340
|
+
if (idx >= 0) __shell_watchers__.splice(idx, 1);
|
|
3341
|
+
}
|
|
3342
|
+
/************************************************************
|
|
3145
3343
|
* Programmatic navigation.
|
|
3146
3344
|
*
|
|
3147
3345
|
* Default — PUSH: the user MOVED somewhere new, so change the URL via
|
|
@@ -3397,7 +3595,13 @@ function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value, tone) {
|
|
|
3397
3595
|
if (!$container) return;
|
|
3398
3596
|
let $badge = $container.querySelector(`[data-toolbar-item-id="${item_id}"] .yui-toolbar-badge`);
|
|
3399
3597
|
if (!$badge) return;
|
|
3598
|
+
let before = $badge.hasAttribute("hidden") ? "" : $badge.textContent;
|
|
3400
3599
|
paint_badge($badge, value, tone);
|
|
3600
|
+
let now = badge_text(value);
|
|
3601
|
+
if (now && now !== before) {
|
|
3602
|
+
let $item = $badge.closest("[data-toolbar-item-id]");
|
|
3603
|
+
announce_badge(shell_gobj, $item && $item.getAttribute("data-i18n-aria-label") || item_id, now);
|
|
3604
|
+
}
|
|
3401
3605
|
}
|
|
3402
3606
|
/************************************************************
|
|
3403
3607
|
* Set (or clear) the badge of a MENU item — the twin of
|
|
@@ -3431,8 +3635,11 @@ function yui_shell_set_nav_item_badge(shell_gobj, item_id, value, tone) {
|
|
|
3431
3635
|
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_nav_item_badge('${item_id}')`);
|
|
3432
3636
|
if (!shell_gobj || !is_gobj(shell_gobj) || gobj_is_destroying(shell_gobj) || empty_string(item_id)) return;
|
|
3433
3637
|
let priv = shell_gobj.priv;
|
|
3434
|
-
|
|
3638
|
+
let item = priv ? nav_item_of(shell_gobj, item_id) : null;
|
|
3639
|
+
if (!item) return;
|
|
3435
3640
|
let badge = value === void 0 ? null : value;
|
|
3641
|
+
let was = priv.nav_badges[item_id];
|
|
3642
|
+
let before = badge_text(was ? was.badge : item.badge);
|
|
3436
3643
|
priv.nav_badges[item_id] = {
|
|
3437
3644
|
badge,
|
|
3438
3645
|
badge_tone: tone
|
|
@@ -3442,6 +3649,8 @@ function yui_shell_set_nav_item_badge(shell_gobj, item_id, value, tone) {
|
|
|
3442
3649
|
badge,
|
|
3443
3650
|
badge_tone: tone
|
|
3444
3651
|
}, shell_gobj);
|
|
3652
|
+
let now = badge_text(badge);
|
|
3653
|
+
if (now && now !== before) announce_badge(shell_gobj, item.name || item_id, now);
|
|
3445
3654
|
}
|
|
3446
3655
|
/************************************************************
|
|
3447
3656
|
* Programmatic close of any open toolbar dropdown. Useful for
|
|
@@ -4045,7 +4254,7 @@ var MOBILE_MAX = 768;
|
|
|
4045
4254
|
***************************************************************/
|
|
4046
4255
|
var attrs_table$21 = [
|
|
4047
4256
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
4048
|
-
SDATA(data_type_t.DTP_POINTER, "$parent", 0, null, "$container will be appended to $parent if not null, else to the
|
|
4257
|
+
SDATA(data_type_t.DTP_POINTER, "$parent", 0, null, "$container will be appended to $parent if not null, else to the window layer of the shell (document.body while there is none), following the shell when it is destroyed or another is built"),
|
|
4049
4258
|
SDATA(data_type_t.DTP_INTEGER, "x", 0, "300", "X position"),
|
|
4050
4259
|
SDATA(data_type_t.DTP_INTEGER, "y", 0, "100", "Y position"),
|
|
4051
4260
|
SDATA(data_type_t.DTP_INTEGER, "width", 0, "700", "Width of the window"),
|
|
@@ -4081,7 +4290,11 @@ var attrs_table$21 = [
|
|
|
4081
4290
|
SDATA(data_type_t.DTP_POINTER, "win_resize_handler", 0, null, "Internal: native window 'resize' listener"),
|
|
4082
4291
|
SDATA_END()
|
|
4083
4292
|
];
|
|
4084
|
-
var PRIVATE_DATA$21 = {
|
|
4293
|
+
var PRIVATE_DATA$21 = {
|
|
4294
|
+
prevSize: 0,
|
|
4295
|
+
placed_by_shell: false,
|
|
4296
|
+
back_shell: null
|
|
4297
|
+
};
|
|
4085
4298
|
var __gclass__$21 = null;
|
|
4086
4299
|
/******************************
|
|
4087
4300
|
* Framework Methods
|
|
@@ -4096,6 +4309,7 @@ function mt_create$21(gobj) {
|
|
|
4096
4309
|
gobj_write_attr(gobj, "window_id", window_id);
|
|
4097
4310
|
let manager = resolve_manager(gobj);
|
|
4098
4311
|
build_ui$18(gobj);
|
|
4312
|
+
yui_shell_watch_changes(gobj);
|
|
4099
4313
|
if (manager) {
|
|
4100
4314
|
let $c = gobj_read_attr(gobj, "$container");
|
|
4101
4315
|
if ($c) $c.addEventListener("pointerdown", function() {
|
|
@@ -4111,7 +4325,16 @@ function mt_create$21(gobj) {
|
|
|
4111
4325
|
title_prefix: gobj_read_str_attr(gobj, "title_prefix") || "",
|
|
4112
4326
|
icon: gobj_read_attr(gobj, "icon") || ""
|
|
4113
4327
|
}, gobj);
|
|
4114
|
-
} else
|
|
4328
|
+
} else {
|
|
4329
|
+
let $c = gobj_read_attr(gobj, "$container");
|
|
4330
|
+
if ($c) {
|
|
4331
|
+
yui_shell_raise_window($c);
|
|
4332
|
+
$c.addEventListener("pointerdown", function() {
|
|
4333
|
+
if (!gobj_is_destroying(gobj)) gobj_send_event(gobj, "EV_SHOW", {}, gobj);
|
|
4334
|
+
}, true);
|
|
4335
|
+
}
|
|
4336
|
+
if (gobj_read_bool_attr(gobj, "back_dismissable")) register_back_overlay(gobj);
|
|
4337
|
+
}
|
|
4115
4338
|
let on_win_resize = function() {
|
|
4116
4339
|
handleResize(gobj);
|
|
4117
4340
|
};
|
|
@@ -4122,13 +4345,15 @@ function mt_create$21(gobj) {
|
|
|
4122
4345
|
* Framework Method: Destroy
|
|
4123
4346
|
***************************************************************/
|
|
4124
4347
|
function mt_destroy$21(gobj) {
|
|
4348
|
+
let priv = gobj.priv;
|
|
4349
|
+
yui_shell_unwatch_changes(gobj);
|
|
4125
4350
|
let manager = gobj_read_pointer_attr(gobj, "manager");
|
|
4126
4351
|
if (manager) gobj_send_event(manager, "EV_UNREGISTER_WINDOW", { window: gobj_full_name(gobj) }, gobj);
|
|
4127
4352
|
let back_overlay = gobj_read_attr(gobj, "back_overlay");
|
|
4128
4353
|
if (back_overlay) {
|
|
4129
|
-
|
|
4130
|
-
if (shell) yui_shell_overlay_dismissed(shell, back_overlay);
|
|
4354
|
+
if (priv.back_shell) yui_shell_overlay_dismissed(priv.back_shell, back_overlay);
|
|
4131
4355
|
gobj_write_attr(gobj, "back_overlay", null);
|
|
4356
|
+
priv.back_shell = null;
|
|
4132
4357
|
}
|
|
4133
4358
|
let on_win_resize = gobj_read_attr(gobj, "win_resize_handler");
|
|
4134
4359
|
if (on_win_resize) {
|
|
@@ -4540,7 +4765,8 @@ function build_ui$18(gobj) {
|
|
|
4540
4765
|
}
|
|
4541
4766
|
refresh_language($container, t);
|
|
4542
4767
|
let $parent = gobj_read_attr(gobj, "$parent");
|
|
4543
|
-
|
|
4768
|
+
gobj.priv.placed_by_shell = !$parent;
|
|
4769
|
+
if (!$parent) $parent = window_place(gobj);
|
|
4544
4770
|
$parent.appendChild($container);
|
|
4545
4771
|
if (gobj_read_bool_attr(gobj, "openMaximized")) max$2(gobj);
|
|
4546
4772
|
else if (!mobile) {
|
|
@@ -4582,11 +4808,13 @@ function register_back_overlay(gobj) {
|
|
|
4582
4808
|
};
|
|
4583
4809
|
let overlay = yui_shell_register_overlay(shell, function() {
|
|
4584
4810
|
gobj_write_attr(gobj, "back_overlay", null);
|
|
4811
|
+
gobj.priv.back_shell = null;
|
|
4585
4812
|
const closing = close_window(gobj);
|
|
4586
4813
|
if (closing.state === "vetoed") rearm();
|
|
4587
4814
|
else if (closing.state === "asking") closing.answer.then(rearm);
|
|
4588
4815
|
}, { keep_on_navigate: gobj_read_bool_attr(gobj, "keep_on_navigate") });
|
|
4589
4816
|
gobj_write_attr(gobj, "back_overlay", overlay);
|
|
4817
|
+
gobj.priv.back_shell = overlay ? shell : null;
|
|
4590
4818
|
}
|
|
4591
4819
|
/************************************************************
|
|
4592
4820
|
* Ask to close the window. Answers what happened:
|
|
@@ -4628,7 +4856,8 @@ function close_window(gobj) {
|
|
|
4628
4856
|
}
|
|
4629
4857
|
/************************************************************
|
|
4630
4858
|
* Where a window lives when its host names no `$parent`: the
|
|
4631
|
-
*
|
|
4859
|
+
* WINDOW layer of its shell (yui_shell_window_layer()), inside
|
|
4860
|
+
* the overlay layer -- above the content, below the drawer, the
|
|
4632
4861
|
* toolbar's dropdowns, the dialogs and the toasts.
|
|
4633
4862
|
*
|
|
4634
4863
|
* It used to be document.body, and that put every window above
|
|
@@ -4641,14 +4870,17 @@ function close_window(gobj) {
|
|
|
4641
4870
|
* toolbar, any dialog opened with a window on screen, the same.
|
|
4642
4871
|
*
|
|
4643
4872
|
* Inside the layer the dock's z-index still orders the windows
|
|
4644
|
-
* among themselves
|
|
4645
|
-
* the
|
|
4873
|
+
* among themselves, and no number it gives them reaches the
|
|
4874
|
+
* drawer (7.26.31 put them in the overlay layer itself, beside
|
|
4875
|
+
* it). No shell (a page with windows and no shell, or the time
|
|
4876
|
+
* between a logout and the next login): the body.
|
|
4877
|
+
*
|
|
4878
|
+
* The place is the shell's, and a window parented to the app
|
|
4879
|
+
* outlives it: ac_shell_changed() moves it when a shell goes or
|
|
4880
|
+
* comes.
|
|
4646
4881
|
************************************************************/
|
|
4647
|
-
function
|
|
4648
|
-
|
|
4649
|
-
let layers = shell && shell.priv && shell.priv.layers;
|
|
4650
|
-
if (layers && layers.overlay) return layers.overlay;
|
|
4651
|
-
return document.body;
|
|
4882
|
+
function window_place(gobj) {
|
|
4883
|
+
return yui_shell_window_layer(yui_shell_of(gobj)) || document.body;
|
|
4652
4884
|
}
|
|
4653
4885
|
/************************************************************
|
|
4654
4886
|
*
|
|
@@ -4920,8 +5152,7 @@ function ac_show$15(gobj, event, kw, src) {
|
|
|
4920
5152
|
return -1;
|
|
4921
5153
|
}
|
|
4922
5154
|
$container.style.removeProperty("display");
|
|
4923
|
-
|
|
4924
|
-
if ($parent && $parent.lastChild !== $container) $parent.appendChild($container);
|
|
5155
|
+
yui_shell_raise_window($container);
|
|
4925
5156
|
return 0;
|
|
4926
5157
|
}
|
|
4927
5158
|
/************************************************************
|
|
@@ -4938,6 +5169,49 @@ function ac_close(gobj, event, kw, src) {
|
|
|
4938
5169
|
close_window(gobj);
|
|
4939
5170
|
return 0;
|
|
4940
5171
|
}
|
|
5172
|
+
/************************************************************
|
|
5173
|
+
* EV_SHELL_CHANGED -- a shell was built, or is being destroyed
|
|
5174
|
+
* (`src`, then destroying): the place this window lives in may
|
|
5175
|
+
* have gone with it, or be in the new one
|
|
5176
|
+
* (yui_shell_watch_changes()).
|
|
5177
|
+
*
|
|
5178
|
+
* - A window whose host named no `$parent` takes the window place
|
|
5179
|
+
* again: the window layer of the shell that governs it NOW,
|
|
5180
|
+
* document.body while there is none. So the developer window
|
|
5181
|
+
* outlives a logout in the body, and the login's shell takes it
|
|
5182
|
+
* in -- above its content, under its dialogs. From 7.26.31 to
|
|
5183
|
+
* 7.26.34 it stayed in the destroyed shell's layer: alive,
|
|
5184
|
+
* detached, invisible.
|
|
5185
|
+
* - A window its host placed stays where it was put, unless that
|
|
5186
|
+
* element was inside the shell being destroyed: then no place
|
|
5187
|
+
* is left, and it takes the window place from now on.
|
|
5188
|
+
* - Its Back entry, when the shell being destroyed held it, went
|
|
5189
|
+
* with that shell's history and is forgotten. The next shell
|
|
5190
|
+
* does not get one: a history entry pushed while a shell is
|
|
5191
|
+
* still being built would sit under its first route. Back no
|
|
5192
|
+
* longer closes such a window; its ✕ does, as before 7.26.31.
|
|
5193
|
+
************************************************************/
|
|
5194
|
+
function ac_shell_changed$1(gobj, event, kw, src) {
|
|
5195
|
+
let priv = gobj.priv;
|
|
5196
|
+
let going = gobj_is_destroying(src);
|
|
5197
|
+
if (going && priv.back_shell === src) {
|
|
5198
|
+
gobj_write_attr(gobj, "back_overlay", null);
|
|
5199
|
+
priv.back_shell = null;
|
|
5200
|
+
}
|
|
5201
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
5202
|
+
if (!$container) {
|
|
5203
|
+
log_error(`${gobj_short_name(gobj)}: EV_SHELL_CHANGED without a container`);
|
|
5204
|
+
return -1;
|
|
5205
|
+
}
|
|
5206
|
+
if (!priv.placed_by_shell) {
|
|
5207
|
+
let $shell = going ? gobj_read_attr(src, "$container") : null;
|
|
5208
|
+
if (!$shell || !$shell.contains($container)) return 0;
|
|
5209
|
+
priv.placed_by_shell = true;
|
|
5210
|
+
}
|
|
5211
|
+
let $place = window_place(gobj);
|
|
5212
|
+
if ($container.parentNode !== $place) $place.appendChild($container);
|
|
5213
|
+
return 0;
|
|
5214
|
+
}
|
|
4941
5215
|
/***************************
|
|
4942
5216
|
* FSM
|
|
4943
5217
|
***************************/
|
|
@@ -4973,6 +5247,11 @@ function create_gclass$21(gclass_name) {
|
|
|
4973
5247
|
"EV_CLOSE_WINDOW",
|
|
4974
5248
|
ac_close,
|
|
4975
5249
|
null
|
|
5250
|
+
],
|
|
5251
|
+
[
|
|
5252
|
+
"EV_SHELL_CHANGED",
|
|
5253
|
+
ac_shell_changed$1,
|
|
5254
|
+
null
|
|
4976
5255
|
]
|
|
4977
5256
|
]]];
|
|
4978
5257
|
const event_types = [
|
|
@@ -4982,7 +5261,8 @@ function create_gclass$21(gclass_name) {
|
|
|
4982
5261
|
["EV_REFRESH", 0],
|
|
4983
5262
|
["EV_SHOW", 0],
|
|
4984
5263
|
["EV_HIDE", 0],
|
|
4985
|
-
["EV_CLOSE_WINDOW", 0]
|
|
5264
|
+
["EV_CLOSE_WINDOW", 0],
|
|
5265
|
+
["EV_SHELL_CHANGED", 0]
|
|
4986
5266
|
];
|
|
4987
5267
|
__gclass__$21 = gclass_create(gclass_name, event_types, states, gmt$21, 0, attrs_table$21, PRIVATE_DATA$21, 0, 0, 0, 0);
|
|
4988
5268
|
if (!__gclass__$21) return -1;
|
|
@@ -5033,6 +5313,7 @@ function register_c_yui_window() {
|
|
|
5033
5313
|
var GCLASS_NAME$20 = "C_YUI_WINDOW_MANAGER";
|
|
5034
5314
|
var DOCK_Z = 1e6;
|
|
5035
5315
|
var WC_X = "<svg viewBox=\"0 0 16 16\" aria-hidden=\"true\"><path d=\"M4.5 4.5 L11.5 11.5 M11.5 4.5 L4.5 11.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/></svg>";
|
|
5316
|
+
var __chip_seq__ = 0;
|
|
5036
5317
|
/***************************************************************
|
|
5037
5318
|
* Data
|
|
5038
5319
|
***************************************************************/
|
|
@@ -5042,13 +5323,12 @@ var attrs_table$20 = [
|
|
|
5042
5323
|
SDATA(data_type_t.DTP_STRING, "dock_corner", 0, "bottom-left", "Floating placement: top-left | top-right | bottom-left | bottom-right"),
|
|
5043
5324
|
SDATA(data_type_t.DTP_STRING, "inline_selector", 0, "", "CSS selector of the container the dock mounts into when inline (e.g. a shell zone)"),
|
|
5044
5325
|
SDATA(data_type_t.DTP_STRING, "responsive_query", 0, "(max-width: 768px)", "Media query that selects inline placement when dock_mode is 'responsive'"),
|
|
5045
|
-
SDATA(data_type_t.DTP_POINTER, "$parent", 0, null, "Where the floating dock mounts (default document.body)"),
|
|
5326
|
+
SDATA(data_type_t.DTP_POINTER, "$parent", 0, null, "Where the floating dock mounts (default: the popup layer of the shell, document.body while there is none)"),
|
|
5046
5327
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "Internal: the dock element"),
|
|
5047
5328
|
SDATA_END()
|
|
5048
5329
|
];
|
|
5049
5330
|
var PRIVATE_DATA$20 = {
|
|
5050
5331
|
windows: null,
|
|
5051
|
-
z: 0,
|
|
5052
5332
|
mql: null,
|
|
5053
5333
|
mql_handler: null
|
|
5054
5334
|
};
|
|
@@ -5062,7 +5342,6 @@ var __gclass__$20 = null;
|
|
|
5062
5342
|
function mt_create$20(gobj) {
|
|
5063
5343
|
let priv = gobj.priv;
|
|
5064
5344
|
priv.windows = [];
|
|
5065
|
-
priv.z = 10;
|
|
5066
5345
|
if ((gobj_read_attr(gobj, "dock_mode") || "floating") === "responsive") {
|
|
5067
5346
|
let q = gobj_read_attr(gobj, "responsive_query") || "(max-width: 768px)";
|
|
5068
5347
|
priv.mql = window.matchMedia(q);
|
|
@@ -5072,6 +5351,7 @@ function mt_create$20(gobj) {
|
|
|
5072
5351
|
priv.mql.addEventListener("change", priv.mql_handler);
|
|
5073
5352
|
}
|
|
5074
5353
|
build_dock(gobj);
|
|
5354
|
+
yui_shell_watch_changes(gobj);
|
|
5075
5355
|
const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
5076
5356
|
if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
5077
5357
|
}
|
|
@@ -5080,6 +5360,7 @@ function mt_create$20(gobj) {
|
|
|
5080
5360
|
***************************************************************/
|
|
5081
5361
|
function mt_destroy$20(gobj) {
|
|
5082
5362
|
let priv = gobj.priv;
|
|
5363
|
+
yui_shell_unwatch_changes(gobj);
|
|
5083
5364
|
if (priv.mql && priv.mql_handler) {
|
|
5084
5365
|
priv.mql.removeEventListener("change", priv.mql_handler);
|
|
5085
5366
|
priv.mql = null;
|
|
@@ -5129,10 +5410,18 @@ function ensure_dock_style() {
|
|
|
5129
5410
|
}
|
|
5130
5411
|
.yui-dock-chip {
|
|
5131
5412
|
display: inline-flex; align-items: center; gap: 7px; font: inherit; font-size: 12px;
|
|
5132
|
-
padding:
|
|
5133
|
-
background: var(--bulma-scheme-main); color: var(--bulma-text);
|
|
5413
|
+
padding: 0 5px 0 0; border: 1px solid var(--bulma-border); border-radius: 7px;
|
|
5414
|
+
background: var(--bulma-scheme-main); color: var(--bulma-text); white-space: nowrap;
|
|
5134
5415
|
}
|
|
5135
5416
|
.yui-dock-chip:hover { border-color: var(--bulma-text-weak); }
|
|
5417
|
+
/* The chip is the look; its toggle a button that adds none, and
|
|
5418
|
+
* takes the pill's padding, so the whole label is what a press lands
|
|
5419
|
+
* on and the chip reads as one pill with its ✕ at the end. */
|
|
5420
|
+
.yui-dock-chip-toggle {
|
|
5421
|
+
display: inline-flex; align-items: center; gap: 7px;
|
|
5422
|
+
padding: 4px 0 4px 11px; margin: 0; border: 0; border-radius: 7px 0 0 7px;
|
|
5423
|
+
background: transparent; font: inherit; color: inherit; cursor: pointer; white-space: nowrap;
|
|
5424
|
+
}
|
|
5136
5425
|
/* The BORDER says active, not the text: blue ink on a blue tint is
|
|
5137
5426
|
* the same hue on itself -- 4.49:1 on the light chip, under the 4.5
|
|
5138
5427
|
* its 12px label needs. The label takes the text colour (11:1). */
|
|
@@ -5222,10 +5511,33 @@ function apply_placement(gobj) {
|
|
|
5222
5511
|
"bottom-left",
|
|
5223
5512
|
"bottom-right"
|
|
5224
5513
|
]) $dock.classList.toggle(`yui-dock--${c}`, !inline && c === corner);
|
|
5225
|
-
let target = inline ? $inline : gobj_read_attr(gobj, "$parent") ||
|
|
5514
|
+
let target = inline ? $inline : gobj_read_attr(gobj, "$parent") || dock_place(gobj);
|
|
5226
5515
|
if ($dock.parentNode !== target) target.appendChild($dock);
|
|
5227
5516
|
}
|
|
5228
5517
|
/************************************************************
|
|
5518
|
+
* Where the FLOATING dock lives when the app names no
|
|
5519
|
+
* `$parent`: the popup layer of the shell, at the top of it.
|
|
5520
|
+
*
|
|
5521
|
+
* It was document.body at z-index 1000000, and that put it
|
|
5522
|
+
* above the WHOLE shell -- `.yui-shell` is a stacking context
|
|
5523
|
+
* of its own, so its dialogs (modal layer, 99) and toasts (120)
|
|
5524
|
+
* counted only inside it: the dock stayed clickable over a
|
|
5525
|
+
* dialog's backdrop (a window could be closed from its chip
|
|
5526
|
+
* while its own "all changes will be lost" question was open),
|
|
5527
|
+
* and it covered a toast where they met.
|
|
5528
|
+
*
|
|
5529
|
+
* The popup layer, not the window layer: the dock has to stay
|
|
5530
|
+
* above EVERY window, and windows live in two layers -- the
|
|
5531
|
+
* window layer (no `$parent`) and the popup layer, where the
|
|
5532
|
+
* site map and the JSON windows of the treedb views put theirs.
|
|
5533
|
+
* Above both; below the dialogs, the toasts and the loading
|
|
5534
|
+
* cover. No shell (before the first, between a logout and the
|
|
5535
|
+
* next login): the body.
|
|
5536
|
+
************************************************************/
|
|
5537
|
+
function dock_place(gobj) {
|
|
5538
|
+
return yui_shell_popup_layer(yui_shell_of(gobj)) || document.body;
|
|
5539
|
+
}
|
|
5540
|
+
/************************************************************
|
|
5229
5541
|
* Destroy the dock element.
|
|
5230
5542
|
************************************************************/
|
|
5231
5543
|
function destroy_dock(gobj) {
|
|
@@ -5302,7 +5614,6 @@ function set_active(gobj, entry) {
|
|
|
5302
5614
|
* Bring a window to front and mark it active/visible.
|
|
5303
5615
|
************************************************************/
|
|
5304
5616
|
function focus_entry(gobj, entry) {
|
|
5305
|
-
let priv = gobj.priv;
|
|
5306
5617
|
let $win = gobj_read_attr(entry.gobj, "$container");
|
|
5307
5618
|
if ($win) {
|
|
5308
5619
|
if (entry.minimized) {
|
|
@@ -5310,8 +5621,7 @@ function focus_entry(gobj, entry) {
|
|
|
5310
5621
|
entry.minimized = false;
|
|
5311
5622
|
if (entry.$chip) entry.$chip.classList.remove("is-min");
|
|
5312
5623
|
}
|
|
5313
|
-
|
|
5314
|
-
$win.style.zIndex = priv.z;
|
|
5624
|
+
yui_shell_raise_window($win);
|
|
5315
5625
|
}
|
|
5316
5626
|
set_active(gobj, entry);
|
|
5317
5627
|
}
|
|
@@ -5378,57 +5688,57 @@ function ac_register_window(gobj, event, kw, src) {
|
|
|
5378
5688
|
{ class: "yui-dock-label-kind" },
|
|
5379
5689
|
text_node(title)
|
|
5380
5690
|
]);
|
|
5691
|
+
let chip_seq = ++__chip_seq__;
|
|
5692
|
+
let label_ids = label_items.map(function(item, i) {
|
|
5693
|
+
item[1].id = `yui-dock-chip-${chip_seq}-${i}`;
|
|
5694
|
+
return item[1].id;
|
|
5695
|
+
});
|
|
5381
5696
|
let entry = {
|
|
5382
5697
|
gobj: win,
|
|
5383
5698
|
$chip: null,
|
|
5384
5699
|
minimized: false
|
|
5385
5700
|
};
|
|
5701
|
+
let window_name = gobj_full_name(win);
|
|
5386
5702
|
let $chip = createElement2([
|
|
5387
5703
|
"div",
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5704
|
+
{ class: "DOCK_CHIP yui-dock-chip" },
|
|
5705
|
+
[[
|
|
5706
|
+
"button",
|
|
5707
|
+
Object.assign({
|
|
5708
|
+
class: "DOCK_CHIP_TOGGLE yui-dock-chip-toggle",
|
|
5709
|
+
type: "button",
|
|
5710
|
+
title,
|
|
5711
|
+
"aria-label": title,
|
|
5712
|
+
"aria-labelledby": label_ids.join(" ")
|
|
5713
|
+
}, !prefix && title_key ? {
|
|
5714
|
+
"data-i18n-title": title_key,
|
|
5715
|
+
"data-i18n-aria-label": title_key
|
|
5716
|
+
} : {}),
|
|
5717
|
+
[chip_lead(kw.icon), [
|
|
5397
5718
|
"span",
|
|
5398
5719
|
{ class: "yui-dock-label" },
|
|
5399
5720
|
label_items
|
|
5400
|
-
],
|
|
5401
|
-
|
|
5402
|
-
"button",
|
|
5403
|
-
{
|
|
5404
|
-
class: "yui-dock-close",
|
|
5405
|
-
type: "button",
|
|
5406
|
-
title: t("close"),
|
|
5407
|
-
"data-i18n-title": "close",
|
|
5408
|
-
"aria-label": t("close"),
|
|
5409
|
-
"data-i18n-aria-label": "close"
|
|
5410
|
-
},
|
|
5411
|
-
html_markup(WC_X),
|
|
5412
|
-
{ click: (evt) => {
|
|
5413
|
-
evt.stopPropagation();
|
|
5414
|
-
gobj_send_event(entry.gobj, "EV_CLOSE_WINDOW", {}, gobj);
|
|
5415
|
-
} }
|
|
5416
|
-
]
|
|
5417
|
-
],
|
|
5418
|
-
{
|
|
5419
|
-
click: (evt) => {
|
|
5721
|
+
]],
|
|
5722
|
+
{ click: (evt) => {
|
|
5420
5723
|
evt.stopPropagation();
|
|
5421
|
-
|
|
5724
|
+
gobj_send_event(gobj, "EV_TOGGLE_WINDOW", { window: window_name }, gobj);
|
|
5725
|
+
} }
|
|
5726
|
+
], [
|
|
5727
|
+
"button",
|
|
5728
|
+
{
|
|
5729
|
+
class: "DOCK_CHIP_CLOSE yui-dock-close",
|
|
5730
|
+
type: "button",
|
|
5731
|
+
title: t("close"),
|
|
5732
|
+
"data-i18n-title": "close",
|
|
5733
|
+
"aria-label": t("close"),
|
|
5734
|
+
"data-i18n-aria-label": "close"
|
|
5422
5735
|
},
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
}
|
|
5430
|
-
}
|
|
5431
|
-
}
|
|
5736
|
+
html_markup(WC_X),
|
|
5737
|
+
{ click: (evt) => {
|
|
5738
|
+
evt.stopPropagation();
|
|
5739
|
+
gobj_send_event(entry.gobj, "EV_CLOSE_WINDOW", {}, gobj);
|
|
5740
|
+
} }
|
|
5741
|
+
]]
|
|
5432
5742
|
]);
|
|
5433
5743
|
entry.$chip = $chip;
|
|
5434
5744
|
priv.windows.push(entry);
|
|
@@ -5472,6 +5782,41 @@ function ac_focus_window(gobj, event, kw, src) {
|
|
|
5472
5782
|
if (entry) focus_entry(gobj, entry);
|
|
5473
5783
|
return 0;
|
|
5474
5784
|
}
|
|
5785
|
+
/************************************************************
|
|
5786
|
+
* EV_TOGGLE_WINDOW { window } -- the toggle of a chip of THIS
|
|
5787
|
+
* dock was pressed: bring a minimized or covered window to the
|
|
5788
|
+
* front, send the one in front to the dock. Only the dock's own
|
|
5789
|
+
* chip sends it (src is the dock): the events a window sends
|
|
5790
|
+
* about itself come from the window, and this one from the chip
|
|
5791
|
+
* that names it.
|
|
5792
|
+
************************************************************/
|
|
5793
|
+
function ac_toggle_window(gobj, event, kw, src) {
|
|
5794
|
+
let priv = gobj.priv;
|
|
5795
|
+
if (src !== gobj) {
|
|
5796
|
+
log_error(`${gobj_short_name(gobj)}: ${event} comes from the dock's own chip, not from ${is_gobj(src) ? gobj_full_name(src) : String(src)}`);
|
|
5797
|
+
return -1;
|
|
5798
|
+
}
|
|
5799
|
+
let name = kw && kw.window;
|
|
5800
|
+
let entry = priv.windows.find((e) => gobj_full_name(e.gobj) === name);
|
|
5801
|
+
if (!entry) {
|
|
5802
|
+
log_error(`${gobj_short_name(gobj)}: ${event}: no window '${name}' in the dock`);
|
|
5803
|
+
return -1;
|
|
5804
|
+
}
|
|
5805
|
+
on_chip_click(gobj, entry);
|
|
5806
|
+
return 0;
|
|
5807
|
+
}
|
|
5808
|
+
/************************************************************
|
|
5809
|
+
* EV_SHELL_CHANGED -- a shell was built, or is being destroyed
|
|
5810
|
+
* (yui_shell_watch_changes()). The dock's place -- the shell's
|
|
5811
|
+
* popup layer, or its zone when inline -- may have gone with
|
|
5812
|
+
* it, or be in the new one: place it again. Up to 7.26.34 an
|
|
5813
|
+
* inline dock stayed in the destroyed shell's zone after a
|
|
5814
|
+
* logout, detached, until a window registered.
|
|
5815
|
+
************************************************************/
|
|
5816
|
+
function ac_shell_changed(gobj, event, kw, src) {
|
|
5817
|
+
apply_placement(gobj);
|
|
5818
|
+
return 0;
|
|
5819
|
+
}
|
|
5475
5820
|
/***************************
|
|
5476
5821
|
* FSM
|
|
5477
5822
|
***************************/
|
|
@@ -5491,7 +5836,9 @@ function create_gclass$20(gclass_name) {
|
|
|
5491
5836
|
["EV_REGISTER_WINDOW", 0],
|
|
5492
5837
|
["EV_UNREGISTER_WINDOW", 0],
|
|
5493
5838
|
["EV_MINIMIZE_WINDOW", 0],
|
|
5494
|
-
["EV_FOCUS_WINDOW", 0]
|
|
5839
|
+
["EV_FOCUS_WINDOW", 0],
|
|
5840
|
+
["EV_TOGGLE_WINDOW", 0],
|
|
5841
|
+
["EV_SHELL_CHANGED", 0]
|
|
5495
5842
|
], [["ST_IDLE", [
|
|
5496
5843
|
[
|
|
5497
5844
|
"EV_REGISTER_WINDOW",
|
|
@@ -5512,6 +5859,16 @@ function create_gclass$20(gclass_name) {
|
|
|
5512
5859
|
"EV_FOCUS_WINDOW",
|
|
5513
5860
|
ac_focus_window,
|
|
5514
5861
|
null
|
|
5862
|
+
],
|
|
5863
|
+
[
|
|
5864
|
+
"EV_TOGGLE_WINDOW",
|
|
5865
|
+
ac_toggle_window,
|
|
5866
|
+
null
|
|
5867
|
+
],
|
|
5868
|
+
[
|
|
5869
|
+
"EV_SHELL_CHANGED",
|
|
5870
|
+
ac_shell_changed,
|
|
5871
|
+
null
|
|
5515
5872
|
]
|
|
5516
5873
|
]]], gmt$20, 0, attrs_table$20, PRIVATE_DATA$20, 0, 0, 0, 0);
|
|
5517
5874
|
if (!__gclass__$20) return -1;
|
|
@@ -6791,6 +7148,41 @@ function yui_tabulator_name_row_selects(table, t) {
|
|
|
6791
7148
|
}
|
|
6792
7149
|
} catch (e) {}
|
|
6793
7150
|
}
|
|
7151
|
+
/***************************************************************
|
|
7152
|
+
* Name the EDITOR of an editable column: the box Tabulator draws
|
|
7153
|
+
* in a cell while it is edited (input, number, textarea, list,
|
|
7154
|
+
* tickCross, date...).
|
|
7155
|
+
*
|
|
7156
|
+
* Tabulator gives it nothing -- no label, no aria-label, no title
|
|
7157
|
+
* -- so a reader lands in an anonymous edit box. Its name is the
|
|
7158
|
+
* column's: a cell is edited under its column's title. Asked at
|
|
7159
|
+
* the MOMENT of editing: Tabulator takes `editorParams` as a
|
|
7160
|
+
* function of the cell, and every built-in editor writes the
|
|
7161
|
+
* `elementAttributes` it answers onto the element it draws. So
|
|
7162
|
+
* the name is in the language of that moment, with nothing to
|
|
7163
|
+
* re-apply after a language change or a rebuild of the columns
|
|
7164
|
+
* -- the twin of the header filters above, which have to be
|
|
7165
|
+
* renamed after every render.
|
|
7166
|
+
*
|
|
7167
|
+
* `name_of(cell)` answers the column's title, TRANSLATED (the
|
|
7168
|
+
* view's own label: a cascade, a schema header); "" names
|
|
7169
|
+
* nothing. What `editorParams` the column had is kept, its own
|
|
7170
|
+
* `elementAttributes` too; a name it set itself wins.
|
|
7171
|
+
***************************************************************/
|
|
7172
|
+
function yui_tabulator_name_editor(column_def, name_of) {
|
|
7173
|
+
if (!column_def || !column_def.editor || typeof name_of !== "function") return;
|
|
7174
|
+
let base = column_def.editorParams;
|
|
7175
|
+
column_def.editorParams = function(cell) {
|
|
7176
|
+
let params = typeof base === "function" ? base(cell) : base || {};
|
|
7177
|
+
let name = name_of(cell);
|
|
7178
|
+
if (!name) return params;
|
|
7179
|
+
let attrs = Object.assign({
|
|
7180
|
+
"aria-label": name,
|
|
7181
|
+
title: name
|
|
7182
|
+
}, params.elementAttributes || {});
|
|
7183
|
+
return Object.assign({}, params, { elementAttributes: attrs });
|
|
7184
|
+
};
|
|
7185
|
+
}
|
|
6794
7186
|
function yui_tabulator_relocalize(table, t) {
|
|
6795
7187
|
if (!table) return;
|
|
6796
7188
|
try {
|
|
@@ -7311,6 +7703,7 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
7311
7703
|
{
|
|
7312
7704
|
type: "button",
|
|
7313
7705
|
class: "FILE_PICK button is-small",
|
|
7706
|
+
title: t("choose a file"),
|
|
7314
7707
|
"data-i18n-title": "choose a file",
|
|
7315
7708
|
"aria-label": t("choose a file"),
|
|
7316
7709
|
"data-i18n-aria-label": "choose a file"
|
|
@@ -7329,6 +7722,7 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
7329
7722
|
{
|
|
7330
7723
|
type: "button",
|
|
7331
7724
|
class: "FILE_CLEAR button is-small",
|
|
7725
|
+
title: t("remove the file"),
|
|
7332
7726
|
"data-i18n-title": "remove the file",
|
|
7333
7727
|
"aria-label": t("remove the file"),
|
|
7334
7728
|
"data-i18n-aria-label": "remove the file"
|
|
@@ -8677,6 +9071,293 @@ function json_editor_value(content) {
|
|
|
8677
9071
|
return JSON.stringify(content.json);
|
|
8678
9072
|
}
|
|
8679
9073
|
//#endregion
|
|
9074
|
+
//#region src/form_json_editor_names.js
|
|
9075
|
+
/***********************************************************************
|
|
9076
|
+
* form_json_editor_names.js
|
|
9077
|
+
*
|
|
9078
|
+
* The NAMES of the buttons vanilla-jsoneditor draws in its menu
|
|
9079
|
+
* (a json field of C_YUI_FORM): in the app's language, and with an
|
|
9080
|
+
* aria-label.
|
|
9081
|
+
*
|
|
9082
|
+
* The editor draws them itself, in English, with a `title` and
|
|
9083
|
+
* nothing else: "Format JSON: add proper indentation and new lines
|
|
9084
|
+
* (Ctrl+I)", "Undo (Ctrl+Z)", and three mode buttons whose text is
|
|
9085
|
+
* "text", "tree" and "table" (REV-CLOUD V23.5.6). Two hooks reach
|
|
9086
|
+
* them, and both are needed:
|
|
9087
|
+
*
|
|
9088
|
+
* - json_editor_menu_items(), the editor's `onRenderMenu`: the
|
|
9089
|
+
* items it is about to draw, with each title translated (its
|
|
9090
|
+
* shortcut kept) and the mode buttons' text too. Svelte draws
|
|
9091
|
+
* from these, so a button born in a re-render is born named.
|
|
9092
|
+
* - name_json_editor_menu(), after the render, from the form's
|
|
9093
|
+
* FSM: the aria-label of each button, with its key, so
|
|
9094
|
+
* refresh_language() re-translates it, and the state of the
|
|
9095
|
+
* mode buttons (aria-pressed). A menu item has no field for
|
|
9096
|
+
* either.
|
|
9097
|
+
*
|
|
9098
|
+
* A button is known by the CLASS the editor gives it (`jse-format`,
|
|
9099
|
+
* `jse-undo`...), never by its English title: a class is what the
|
|
9100
|
+
* editor's own stylesheet relies on. A button not listed here keeps
|
|
9101
|
+
* the editor's words.
|
|
9102
|
+
*
|
|
9103
|
+
* Its CONTEXT MENU (`onRenderContextMenu`,
|
|
9104
|
+
* json_editor_context_menu_items()) has no class on its items, so
|
|
9105
|
+
* an item is known by what it IS and where it IS: the icon the
|
|
9106
|
+
* editor draws it with (a FontAwesome name: `paste`, `scissors`),
|
|
9107
|
+
* the column of the menu it stands in, its place in a dropdown
|
|
9108
|
+
* (the main button, the first or the second of its list), the
|
|
9109
|
+
* mode of the editor (tree or table) -- never by its words. Its
|
|
9110
|
+
* text and title go back translated; after the render the same
|
|
9111
|
+
* pass names its buttons, and the arrow of each dropdown, which
|
|
9112
|
+
* the editor draws with no name at all.
|
|
9113
|
+
*
|
|
9114
|
+
* Not reached, because the editor gives them no hook: its search
|
|
9115
|
+
* box, its repair messages, the tip at the foot of the context
|
|
9116
|
+
* menu, and its modals (sort, transform). They stay in its
|
|
9117
|
+
* English.
|
|
9118
|
+
*
|
|
9119
|
+
* Copyright (c) 2026, ArtGins.
|
|
9120
|
+
* All Rights Reserved.
|
|
9121
|
+
***********************************************************************/
|
|
9122
|
+
/***************************************************************
|
|
9123
|
+
* Constants
|
|
9124
|
+
***************************************************************/
|
|
9125
|
+
var JSON_EDITOR_BUTTON_KEYS = {
|
|
9126
|
+
"jse-expand-all": "expand all",
|
|
9127
|
+
"jse-collapse-all": "collapse all",
|
|
9128
|
+
"jse-search": "search",
|
|
9129
|
+
"jse-copy": "copy",
|
|
9130
|
+
"jse-undo": "undo",
|
|
9131
|
+
"jse-redo": "redo",
|
|
9132
|
+
"jse-cancel": "cancel",
|
|
9133
|
+
"jse-format": "format json",
|
|
9134
|
+
"jse-compact": "compact json",
|
|
9135
|
+
"jse-sort": "sort",
|
|
9136
|
+
"jse-transform": "transform",
|
|
9137
|
+
"jse-contextmenu": "open context menu"
|
|
9138
|
+
};
|
|
9139
|
+
var JSON_EDITOR_MODE_NAME_KEYS = {
|
|
9140
|
+
text: "text view",
|
|
9141
|
+
tree: "tree view",
|
|
9142
|
+
table: "table view"
|
|
9143
|
+
};
|
|
9144
|
+
var JSON_EDITOR_MODE_TEXT_KEYS = {
|
|
9145
|
+
text: "text mode",
|
|
9146
|
+
tree: "tree mode",
|
|
9147
|
+
table: "table mode"
|
|
9148
|
+
};
|
|
9149
|
+
var MODE_CLASS = "yui-jse-mode-";
|
|
9150
|
+
var SHORTCUT = /\((?:Ctrl|Cmd|⌘)[^()]*\)\s*$/;
|
|
9151
|
+
var CONTEXT_BUTTON_KEYS = {
|
|
9152
|
+
"pen": "edit key",
|
|
9153
|
+
"paste": "paste",
|
|
9154
|
+
"clone": "duplicate",
|
|
9155
|
+
"crop-simple": "extract",
|
|
9156
|
+
"arrow-down-short-wide": "sort",
|
|
9157
|
+
"filter": "transform",
|
|
9158
|
+
"trash-can": "remove",
|
|
9159
|
+
"square-caret-up": "insert before",
|
|
9160
|
+
"square-caret-down": "insert after"
|
|
9161
|
+
};
|
|
9162
|
+
var CONTEXT_ROW_BUTTON_KEYS = {
|
|
9163
|
+
"pen": "edit row",
|
|
9164
|
+
"clone": "duplicate row",
|
|
9165
|
+
"trash-can": "remove row"
|
|
9166
|
+
};
|
|
9167
|
+
var CONTEXT_DROPDOWN_MAIN_KEYS = {
|
|
9168
|
+
"pen": "edit value",
|
|
9169
|
+
"scissors": "cut",
|
|
9170
|
+
"copy": "copy"
|
|
9171
|
+
};
|
|
9172
|
+
var CONTEXT_DROPDOWN_FIRST_KEYS = {
|
|
9173
|
+
"pen": "edit value",
|
|
9174
|
+
"scissors": "cut formatted",
|
|
9175
|
+
"copy": "copy formatted"
|
|
9176
|
+
};
|
|
9177
|
+
var CONTEXT_DROPDOWN_SECOND_KEYS = {
|
|
9178
|
+
"pen": "enforce string",
|
|
9179
|
+
"scissors": "cut compacted",
|
|
9180
|
+
"copy": "copy compacted"
|
|
9181
|
+
};
|
|
9182
|
+
var CONTEXT_TARGET_KEYS = {
|
|
9183
|
+
"0": "structure",
|
|
9184
|
+
"1": "object",
|
|
9185
|
+
"2": "array",
|
|
9186
|
+
"3": "value"
|
|
9187
|
+
};
|
|
9188
|
+
var TARGET_ICONS = ["arrow-right-arrow-left", "plus"];
|
|
9189
|
+
var CONTEXT_LABEL_KEYS = {
|
|
9190
|
+
convert: "convert to",
|
|
9191
|
+
insert: "insert",
|
|
9192
|
+
cell: "table cell",
|
|
9193
|
+
row: "table row"
|
|
9194
|
+
};
|
|
9195
|
+
/***************************
|
|
9196
|
+
* Local Methods
|
|
9197
|
+
***************************/
|
|
9198
|
+
function has_key(table, name) {
|
|
9199
|
+
return Object.prototype.hasOwnProperty.call(table, name);
|
|
9200
|
+
}
|
|
9201
|
+
function button_class(classes) {
|
|
9202
|
+
return (Array.isArray(classes) ? classes : String(classes || "").split(/\s+/)).find((c) => has_key(JSON_EDITOR_BUTTON_KEYS, c)) || "";
|
|
9203
|
+
}
|
|
9204
|
+
function mode_of_item(item) {
|
|
9205
|
+
if (String(item.className || "").split(/\s+/).indexOf("jse-group-button") < 0) return "";
|
|
9206
|
+
return has_key(JSON_EDITOR_MODE_NAME_KEYS, item.text) ? item.text : "";
|
|
9207
|
+
}
|
|
9208
|
+
function icon_of(item) {
|
|
9209
|
+
return item && item.icon && typeof item.icon.iconName === "string" ? item.icon.iconName : "";
|
|
9210
|
+
}
|
|
9211
|
+
function named_item(item, name) {
|
|
9212
|
+
let m = SHORTCUT.exec(String(item.title || ""));
|
|
9213
|
+
return Object.assign({}, item, {
|
|
9214
|
+
text: name,
|
|
9215
|
+
title: m ? `${name} ${m[0].trim()}` : name
|
|
9216
|
+
});
|
|
9217
|
+
}
|
|
9218
|
+
function context_dropdown(item) {
|
|
9219
|
+
let icon = icon_of(item.main);
|
|
9220
|
+
if (!has_key(CONTEXT_DROPDOWN_MAIN_KEYS, icon)) return item;
|
|
9221
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9222
|
+
return Object.assign({}, item, {
|
|
9223
|
+
main: named_item(item.main, t(CONTEXT_DROPDOWN_MAIN_KEYS[icon])),
|
|
9224
|
+
items: list.map(function(it, i) {
|
|
9225
|
+
if (!it || it.type !== "button") return it;
|
|
9226
|
+
if (i === 0) return named_item(it, t(CONTEXT_DROPDOWN_FIRST_KEYS[icon]));
|
|
9227
|
+
if (i === 1) return named_item(it, t(CONTEXT_DROPDOWN_SECOND_KEYS[icon]));
|
|
9228
|
+
return it;
|
|
9229
|
+
})
|
|
9230
|
+
});
|
|
9231
|
+
}
|
|
9232
|
+
function context_button(item, row_column) {
|
|
9233
|
+
let icon = icon_of(item);
|
|
9234
|
+
if (row_column && has_key(CONTEXT_ROW_BUTTON_KEYS, icon)) return named_item(item, t(CONTEXT_ROW_BUTTON_KEYS[icon]));
|
|
9235
|
+
if (has_key(CONTEXT_BUTTON_KEYS, icon)) return named_item(item, t(CONTEXT_BUTTON_KEYS[icon]));
|
|
9236
|
+
return item;
|
|
9237
|
+
}
|
|
9238
|
+
function context_column(item, table, index) {
|
|
9239
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9240
|
+
let buttons = list.filter((it) => it && it.type === "button");
|
|
9241
|
+
let targets = !table && buttons.length > 0 && buttons.every((it) => TARGET_ICONS.indexOf(icon_of(it)) >= 0);
|
|
9242
|
+
let row_column = table && index === 1;
|
|
9243
|
+
let label_kind = "";
|
|
9244
|
+
if (table) label_kind = index === 0 ? "cell" : index === 1 ? "row" : "";
|
|
9245
|
+
else if (targets) label_kind = icon_of(buttons[0]) === "plus" ? "insert" : "convert";
|
|
9246
|
+
let target = 0;
|
|
9247
|
+
let insert_row = 0;
|
|
9248
|
+
return Object.assign({}, item, { items: list.map(function(it) {
|
|
9249
|
+
if (!it || typeof it !== "object") return it;
|
|
9250
|
+
if (it.type === "label") return label_kind ? Object.assign({}, it, { text: t(CONTEXT_LABEL_KEYS[label_kind]) }) : it;
|
|
9251
|
+
if (it.type === "dropdown-button") return context_dropdown(it);
|
|
9252
|
+
if (it.type !== "button") return it;
|
|
9253
|
+
if (targets) return named_item(it, t(CONTEXT_TARGET_KEYS[String(target++)]));
|
|
9254
|
+
if (row_column && icon_of(it) === "plus") return named_item(it, t(insert_row++ === 0 ? CONTEXT_BUTTON_KEYS["square-caret-up"] : CONTEXT_BUTTON_KEYS["square-caret-down"]));
|
|
9255
|
+
return context_button(it, row_column);
|
|
9256
|
+
}) });
|
|
9257
|
+
}
|
|
9258
|
+
function context_item(item, table) {
|
|
9259
|
+
if (!item || typeof item !== "object") return item;
|
|
9260
|
+
if (item.type === "row") {
|
|
9261
|
+
let column = 0;
|
|
9262
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9263
|
+
return Object.assign({}, item, { items: list.map(function(it) {
|
|
9264
|
+
if (it && it.type === "column") return context_column(it, table, column++);
|
|
9265
|
+
return context_item(it, table);
|
|
9266
|
+
}) });
|
|
9267
|
+
}
|
|
9268
|
+
if (item.type === "dropdown-button") return context_dropdown(item);
|
|
9269
|
+
if (item.type === "button") return context_button(item, false);
|
|
9270
|
+
return item;
|
|
9271
|
+
}
|
|
9272
|
+
function mode_of_button($b) {
|
|
9273
|
+
for (let c of $b.classList) if (c.indexOf(MODE_CLASS) === 0) {
|
|
9274
|
+
let mode = c.slice(13);
|
|
9275
|
+
if (has_key(JSON_EDITOR_MODE_NAME_KEYS, mode)) return mode;
|
|
9276
|
+
}
|
|
9277
|
+
return "";
|
|
9278
|
+
}
|
|
9279
|
+
/***************************
|
|
9280
|
+
* Public
|
|
9281
|
+
***************************/
|
|
9282
|
+
/************************************************************
|
|
9283
|
+
* The editor's `onRenderMenu`: the items it is about to draw,
|
|
9284
|
+
* translated. A title keeps the editor's shortcut after the
|
|
9285
|
+
* translated name ("Deshacer (Ctrl+Z)"); a mode button gets its
|
|
9286
|
+
* mode's name as title and its short text translated, and a class
|
|
9287
|
+
* that says its mode. Anything else is returned as it came.
|
|
9288
|
+
*
|
|
9289
|
+
* Pure: what it answers is data for the editor to draw.
|
|
9290
|
+
************************************************************/
|
|
9291
|
+
function json_editor_menu_items(items) {
|
|
9292
|
+
if (!Array.isArray(items)) return items;
|
|
9293
|
+
return items.map(function(item) {
|
|
9294
|
+
if (!item || item.type !== "button") return item;
|
|
9295
|
+
let mode = mode_of_item(item);
|
|
9296
|
+
if (mode) return Object.assign({}, item, {
|
|
9297
|
+
className: `${item.className} ${MODE_CLASS}${mode}`,
|
|
9298
|
+
title: t(JSON_EDITOR_MODE_NAME_KEYS[mode]),
|
|
9299
|
+
text: t(JSON_EDITOR_MODE_TEXT_KEYS[mode])
|
|
9300
|
+
});
|
|
9301
|
+
let cls = button_class(item.className);
|
|
9302
|
+
if (!cls) return item;
|
|
9303
|
+
let m = SHORTCUT.exec(String(item.title || ""));
|
|
9304
|
+
let name = t(JSON_EDITOR_BUTTON_KEYS[cls]);
|
|
9305
|
+
return Object.assign({}, item, { title: m ? `${name} ${m[0].trim()}` : name });
|
|
9306
|
+
});
|
|
9307
|
+
}
|
|
9308
|
+
/************************************************************
|
|
9309
|
+
* The editor's `onRenderContextMenu`: the items it is about to
|
|
9310
|
+
* draw, translated -- each known by its icon and its place, never
|
|
9311
|
+
* by its words (context_item()). Anything the module does not
|
|
9312
|
+
* know comes back as it came: a newer editor that moves an item
|
|
9313
|
+
* leaves it in English, it does not mislabel it.
|
|
9314
|
+
*
|
|
9315
|
+
* Pure: what it answers is data for the editor to draw.
|
|
9316
|
+
************************************************************/
|
|
9317
|
+
function json_editor_context_menu_items(items, context) {
|
|
9318
|
+
if (!Array.isArray(items)) return items;
|
|
9319
|
+
let table = !!(context && context.mode === "table");
|
|
9320
|
+
return items.map((item) => context_item(item, table));
|
|
9321
|
+
}
|
|
9322
|
+
/************************************************************
|
|
9323
|
+
* Name the buttons of a rendered editor's menu: an aria-label
|
|
9324
|
+
* with its key (data-i18n-aria-label, so a language change
|
|
9325
|
+
* reaches it), and aria-pressed on the mode buttons -- the
|
|
9326
|
+
* selected one is the mode on screen (`jse-selected`). Run
|
|
9327
|
+
* after every render of the menu: a re-render may draw new
|
|
9328
|
+
* buttons, which carry none of it.
|
|
9329
|
+
************************************************************/
|
|
9330
|
+
function name_json_editor_menu($editor) {
|
|
9331
|
+
if (!$editor || typeof $editor.querySelectorAll !== "function") return 0;
|
|
9332
|
+
let named = 0;
|
|
9333
|
+
for (let $b of $editor.querySelectorAll(".jse-menu button")) {
|
|
9334
|
+
let mode = mode_of_button($b);
|
|
9335
|
+
const key = mode ? JSON_EDITOR_MODE_NAME_KEYS[mode] : JSON_EDITOR_BUTTON_KEYS[button_class([...$b.classList])];
|
|
9336
|
+
if (!key) continue;
|
|
9337
|
+
$b.setAttribute("aria-label", t(key));
|
|
9338
|
+
$b.setAttribute("data-i18n-aria-label", key);
|
|
9339
|
+
if (mode) $b.setAttribute("aria-pressed", $b.classList.contains("jse-selected") ? "true" : "false");
|
|
9340
|
+
named++;
|
|
9341
|
+
}
|
|
9342
|
+
const MORE = "more options";
|
|
9343
|
+
for (let $b of $editor.querySelectorAll("div.jse-contextmenu button")) {
|
|
9344
|
+
if ($b.getAttribute("data-type") === "jse-open-dropdown") {
|
|
9345
|
+
$b.setAttribute("title", t(MORE));
|
|
9346
|
+
$b.setAttribute("data-i18n-title", MORE);
|
|
9347
|
+
$b.setAttribute("aria-label", t(MORE));
|
|
9348
|
+
$b.setAttribute("data-i18n-aria-label", MORE);
|
|
9349
|
+
named++;
|
|
9350
|
+
continue;
|
|
9351
|
+
}
|
|
9352
|
+
let text = ($b.textContent || "").trim();
|
|
9353
|
+
if (text) {
|
|
9354
|
+
$b.setAttribute("aria-label", text);
|
|
9355
|
+
named++;
|
|
9356
|
+
}
|
|
9357
|
+
}
|
|
9358
|
+
return named;
|
|
9359
|
+
}
|
|
9360
|
+
//#endregion
|
|
8680
9361
|
//#region src/c_yui_form.js
|
|
8681
9362
|
/***********************************************************************
|
|
8682
9363
|
* c_yui_form.js
|
|
@@ -8726,7 +9407,9 @@ var attrs_table$17 = [
|
|
|
8726
9407
|
var PRIVATE_DATA$17 = {
|
|
8727
9408
|
rearm_timer: null,
|
|
8728
9409
|
tables: null,
|
|
8729
|
-
table_seq: 0
|
|
9410
|
+
table_seq: 0,
|
|
9411
|
+
json_names_posted: false,
|
|
9412
|
+
lang_shell: null
|
|
8730
9413
|
};
|
|
8731
9414
|
var __gclass__$17 = null;
|
|
8732
9415
|
/***************************
|
|
@@ -8757,13 +9440,23 @@ function mt_destroy$17(gobj) {
|
|
|
8757
9440
|
* Framework Method start
|
|
8758
9441
|
************************************************************/
|
|
8759
9442
|
function mt_start$17(gobj) {
|
|
9443
|
+
let priv = gobj.priv;
|
|
9444
|
+
let shell = yui_shell_of(gobj);
|
|
9445
|
+
if (shell) {
|
|
9446
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
9447
|
+
priv.lang_shell = shell;
|
|
9448
|
+
}
|
|
8760
9449
|
let record = gobj_read_attr(gobj, "record");
|
|
8761
9450
|
if (record) gobj_send_event(gobj, "EV_LOAD_RECORD", record, gobj);
|
|
8762
9451
|
}
|
|
8763
9452
|
/************************************************************
|
|
8764
9453
|
* Framework Method stop
|
|
8765
9454
|
************************************************************/
|
|
8766
|
-
function mt_stop$17(gobj) {
|
|
9455
|
+
function mt_stop$17(gobj) {
|
|
9456
|
+
let priv = gobj.priv;
|
|
9457
|
+
if (priv.lang_shell && !gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
9458
|
+
priv.lang_shell = null;
|
|
9459
|
+
}
|
|
8767
9460
|
/***************************
|
|
8768
9461
|
* Local Methods
|
|
8769
9462
|
***************************/
|
|
@@ -9219,6 +9912,80 @@ function name_form_control$1($field, conf) {
|
|
|
9219
9912
|
$clear.setAttribute("data-i18n-aria-label", CLEAR_KEY);
|
|
9220
9913
|
}
|
|
9221
9914
|
}
|
|
9915
|
+
/************************************************************
|
|
9916
|
+
* The ✕ of ONE selected option of a Tom Select: its
|
|
9917
|
+
* remove_button plugin calls this for every option it draws.
|
|
9918
|
+
*
|
|
9919
|
+
* The plugin's own was a div titled "Remove" in English -- never
|
|
9920
|
+
* translated, no aria-label -- with tabindex -1, and the form
|
|
9921
|
+
* turns Backspace deletion off (no_backspace_delete): a keyboard
|
|
9922
|
+
* could not take one option out at all. Named here through t()
|
|
9923
|
+
* with its key (so a language change reaches it), and pressed by
|
|
9924
|
+
* Enter or Space as the clear button is: the key clicks it, which
|
|
9925
|
+
* runs the plugin's own handler.
|
|
9926
|
+
************************************************************/
|
|
9927
|
+
function remove_option_button() {
|
|
9928
|
+
const KEY = "remove this option";
|
|
9929
|
+
let $b = createElement2([
|
|
9930
|
+
"div",
|
|
9931
|
+
{
|
|
9932
|
+
class: "remove",
|
|
9933
|
+
role: "button",
|
|
9934
|
+
tabindex: "0",
|
|
9935
|
+
title: t(KEY),
|
|
9936
|
+
"data-i18n-title": KEY,
|
|
9937
|
+
"aria-label": t(KEY),
|
|
9938
|
+
"data-i18n-aria-label": KEY
|
|
9939
|
+
},
|
|
9940
|
+
"×"
|
|
9941
|
+
]);
|
|
9942
|
+
$b.addEventListener("keydown", function(evt) {
|
|
9943
|
+
if (evt.key === "Enter" || evt.key === " ") {
|
|
9944
|
+
evt.preventDefault();
|
|
9945
|
+
evt.stopPropagation();
|
|
9946
|
+
$b.click();
|
|
9947
|
+
}
|
|
9948
|
+
});
|
|
9949
|
+
return $b;
|
|
9950
|
+
}
|
|
9951
|
+
/************************************************************
|
|
9952
|
+
* The `onRenderMenu` of a json editor of this form.
|
|
9953
|
+
*
|
|
9954
|
+
* The editor calls it with the items it is about to draw: they go
|
|
9955
|
+
* back translated (json_editor_menu_items(), data for the editor
|
|
9956
|
+
* to draw). What no item can carry -- an aria-label, the state of
|
|
9957
|
+
* the mode buttons -- is written on the drawn buttons, after the
|
|
9958
|
+
* render, by the form's FSM (EV_NAME_JSON_EDITORS): the callback
|
|
9959
|
+
* only posts the event, once until it is handled. Posted, not
|
|
9960
|
+
* sent: when it runs the editor has not drawn the menu yet.
|
|
9961
|
+
*
|
|
9962
|
+
* A new function each call: handing an editor a new one is what
|
|
9963
|
+
* makes it draw its menu again (ac_language_changed).
|
|
9964
|
+
************************************************************/
|
|
9965
|
+
function json_editor_render_menu(gobj) {
|
|
9966
|
+
return function(items) {
|
|
9967
|
+
ask_json_editor_names(gobj);
|
|
9968
|
+
return json_editor_menu_items(items);
|
|
9969
|
+
};
|
|
9970
|
+
}
|
|
9971
|
+
/************************************************************
|
|
9972
|
+
* The `onRenderContextMenu` of a json editor of this form: the
|
|
9973
|
+
* same, for the menu it opens on a right click or Ctrl+Q. It is
|
|
9974
|
+
* built each time it opens, in the language of that moment.
|
|
9975
|
+
************************************************************/
|
|
9976
|
+
function json_editor_render_context_menu(gobj) {
|
|
9977
|
+
return function(items, context) {
|
|
9978
|
+
ask_json_editor_names(gobj);
|
|
9979
|
+
return json_editor_context_menu_items(items, context);
|
|
9980
|
+
};
|
|
9981
|
+
}
|
|
9982
|
+
function ask_json_editor_names(gobj) {
|
|
9983
|
+
let priv = gobj.priv;
|
|
9984
|
+
if (!priv.json_names_posted && !gobj_is_destroying(gobj)) {
|
|
9985
|
+
priv.json_names_posted = true;
|
|
9986
|
+
gobj_post_event(gobj, "EV_NAME_JSON_EDITORS", {}, gobj);
|
|
9987
|
+
}
|
|
9988
|
+
}
|
|
9222
9989
|
function build_form(gobj) {
|
|
9223
9990
|
let form_id = gobj_read_str_attr(gobj, "form_id");
|
|
9224
9991
|
let $form = createElement2(["form", {
|
|
@@ -9250,7 +10017,7 @@ function build_html_form(gobj, $form, prefix, template) {
|
|
|
9250
10017
|
let label_keys = topic_name ? [topic_name + "." + field_desc.name, field_desc.name] : [field_desc.name];
|
|
9251
10018
|
const NO_I18N = "\0";
|
|
9252
10019
|
html_field_conf.label = t(label_keys, { defaultValue: field_desc.header });
|
|
9253
|
-
html_field_conf.label_i18n = t(
|
|
10020
|
+
html_field_conf.label_i18n = label_keys.find((k) => t(k, { defaultValue: NO_I18N }) !== NO_I18N) || null;
|
|
9254
10021
|
html_field_conf.placeholder = field_desc.placeholder ? t(field_desc.placeholder) : "";
|
|
9255
10022
|
let placeholders = gobj_read_attr(gobj, "placeholders");
|
|
9256
10023
|
if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
|
|
@@ -9956,7 +10723,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
9956
10723
|
"clear_button": { "title": t("remove all selected options") },
|
|
9957
10724
|
"no_active_items": {},
|
|
9958
10725
|
"no_backspace_delete": {},
|
|
9959
|
-
"remove_button": {}
|
|
10726
|
+
"remove_button": { html: remove_option_button }
|
|
9960
10727
|
}
|
|
9961
10728
|
});
|
|
9962
10729
|
$extend.tom_select.on("change", function() {
|
|
@@ -10025,7 +10792,9 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
10025
10792
|
},
|
|
10026
10793
|
timestampTag: function({ field, value, path }) {
|
|
10027
10794
|
return is_time_field(field);
|
|
10028
|
-
}
|
|
10795
|
+
},
|
|
10796
|
+
onRenderMenu: json_editor_render_menu(gobj),
|
|
10797
|
+
onRenderContextMenu: json_editor_render_context_menu(gobj)
|
|
10029
10798
|
}
|
|
10030
10799
|
});
|
|
10031
10800
|
break;
|
|
@@ -10557,6 +11326,9 @@ function template2columns(gobj, columns, template, sub_elements) {
|
|
|
10557
11326
|
}
|
|
10558
11327
|
if (column) {
|
|
10559
11328
|
if (readonly) delete column.editor;
|
|
11329
|
+
yui_tabulator_name_editor(column, function() {
|
|
11330
|
+
return t(field_desc.header || field_desc.name);
|
|
11331
|
+
});
|
|
10560
11332
|
columns.push(column);
|
|
10561
11333
|
}
|
|
10562
11334
|
});
|
|
@@ -11317,6 +12089,39 @@ function ac_hide$11(gobj, event, kw, src) {
|
|
|
11317
12089
|
function ac_timeout(gobj, event, kw, src) {
|
|
11318
12090
|
return 0;
|
|
11319
12091
|
}
|
|
12092
|
+
/************************************************************
|
|
12093
|
+
* EV_NAME_JSON_EDITORS {} -- a menu of a json editor of this
|
|
12094
|
+
* form was drawn, its menu or its context menu (posted by
|
|
12095
|
+
* ask_json_editor_names): name its buttons. Every editor of the
|
|
12096
|
+
* form: naming is idempotent, and a kw is plain json, which an
|
|
12097
|
+
* editor is not.
|
|
12098
|
+
************************************************************/
|
|
12099
|
+
function ac_name_json_editors(gobj, event, kw, src) {
|
|
12100
|
+
let priv = gobj.priv;
|
|
12101
|
+
priv.json_names_posted = false;
|
|
12102
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
12103
|
+
if (!$container) {
|
|
12104
|
+
log_error(`${gobj_short_name(gobj)}: ${event} without a container`);
|
|
12105
|
+
return -1;
|
|
12106
|
+
}
|
|
12107
|
+
for (let $editor of $container.querySelectorAll(".jsoneditor")) name_json_editor_menu($editor);
|
|
12108
|
+
return 0;
|
|
12109
|
+
}
|
|
12110
|
+
/************************************************************
|
|
12111
|
+
* EV_LANGUAGE_CHANGED {} -- from the shell. A json editor draws
|
|
12112
|
+
* its menu once: its titles and the text of its mode buttons stay
|
|
12113
|
+
* in the old language until it draws it again, so each is told to
|
|
12114
|
+
* (a new onRenderMenu), and the render names it again.
|
|
12115
|
+
************************************************************/
|
|
12116
|
+
function ac_language_changed$10(gobj, event, kw, src) {
|
|
12117
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
12118
|
+
if (!$container) return 0;
|
|
12119
|
+
for (let $editor of $container.querySelectorAll(".jsoneditor")) {
|
|
12120
|
+
let editor = $editor.jsoneditor;
|
|
12121
|
+
if (editor && typeof editor.updateProps === "function") editor.updateProps({ onRenderMenu: json_editor_render_menu(gobj) });
|
|
12122
|
+
}
|
|
12123
|
+
return 0;
|
|
12124
|
+
}
|
|
11320
12125
|
/***************************
|
|
11321
12126
|
* FSM
|
|
11322
12127
|
***************************/
|
|
@@ -11466,6 +12271,16 @@ function create_gclass$17(gclass_name) {
|
|
|
11466
12271
|
"EV_TIMEOUT",
|
|
11467
12272
|
ac_timeout,
|
|
11468
12273
|
null
|
|
12274
|
+
],
|
|
12275
|
+
[
|
|
12276
|
+
"EV_NAME_JSON_EDITORS",
|
|
12277
|
+
ac_name_json_editors,
|
|
12278
|
+
null
|
|
12279
|
+
],
|
|
12280
|
+
[
|
|
12281
|
+
"EV_LANGUAGE_CHANGED",
|
|
12282
|
+
ac_language_changed$10,
|
|
12283
|
+
null
|
|
11469
12284
|
]
|
|
11470
12285
|
]]];
|
|
11471
12286
|
const event_types = [
|
|
@@ -11484,7 +12299,9 @@ function create_gclass$17(gclass_name) {
|
|
|
11484
12299
|
["EV_REFRESH", 0],
|
|
11485
12300
|
["EV_SHOW", 0],
|
|
11486
12301
|
["EV_HIDE", 0],
|
|
11487
|
-
["EV_TIMEOUT", 0]
|
|
12302
|
+
["EV_TIMEOUT", 0],
|
|
12303
|
+
["EV_NAME_JSON_EDITORS", 0],
|
|
12304
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
11488
12305
|
];
|
|
11489
12306
|
__gclass__$17 = gclass_create(gclass_name, event_types, states, gmt$17, 0, attrs_table$17, PRIVATE_DATA$17, 0, 0, 0, 0);
|
|
11490
12307
|
if (!__gclass__$17) return -1;
|
|
@@ -11504,7 +12321,7 @@ function register_c_yui_form() {
|
|
|
11504
12321
|
*
|
|
11505
12322
|
* Utilities for maplibre
|
|
11506
12323
|
*
|
|
11507
|
-
* Copyright (c) 2025, ArtGins.
|
|
12324
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
11508
12325
|
* All Rights Reserved.
|
|
11509
12326
|
***********************************************************************/
|
|
11510
12327
|
var EditControl = class {
|
|
@@ -11700,9 +12517,14 @@ function label_ctrl($root, selector, text) {
|
|
|
11700
12517
|
$el.setAttribute("aria-label", text);
|
|
11701
12518
|
}
|
|
11702
12519
|
}
|
|
12520
|
+
function relabel_written($root, selector, was, now) {
|
|
12521
|
+
if (!$root || !now) return;
|
|
12522
|
+
for (const $el of $root.querySelectorAll(selector)) if ($el.getAttribute("aria-label") === was) $el.setAttribute("aria-label", now);
|
|
12523
|
+
}
|
|
11703
12524
|
function yui_maplibre_relocalize(map, t) {
|
|
11704
12525
|
if (!map || typeof map.getContainer !== "function") return;
|
|
11705
12526
|
const strings = yui_maplibre_locale(t);
|
|
12527
|
+
const was = Object.assign({}, map._locale);
|
|
11706
12528
|
try {
|
|
11707
12529
|
map._locale = Object.assign({}, map._locale, strings);
|
|
11708
12530
|
} catch (e) {}
|
|
@@ -11714,6 +12536,8 @@ function yui_maplibre_relocalize(map, t) {
|
|
|
11714
12536
|
label_ctrl($c, ".maplibregl-ctrl-attrib-button", strings["AttributionControl.ToggleAttribution"]);
|
|
11715
12537
|
label_ctrl($c, ".maplibregl-ctrl-fullscreen", strings["FullscreenControl.Enter"]);
|
|
11716
12538
|
label_ctrl($c, ".maplibregl-popup-close-button", strings["Popup.Close"]);
|
|
12539
|
+
relabel_written($c, ".maplibregl-canvas", was["Map.Title"], strings["Map.Title"]);
|
|
12540
|
+
relabel_written($c, ".maplibregl-marker", was["Marker.Title"], strings["Marker.Title"]);
|
|
11717
12541
|
const mac = typeof navigator !== "undefined" && (navigator.userAgent || "").includes("Mac");
|
|
11718
12542
|
const $desktop = $c.querySelector(".maplibregl-desktop-message");
|
|
11719
12543
|
if ($desktop) $desktop.textContent = mac ? strings["CooperativeGesturesHandler.MacHelpText"] : strings["CooperativeGesturesHandler.WindowsHelpText"];
|
|
@@ -14462,6 +15286,8 @@ function make_toolbar$5(gobj) {
|
|
|
14462
15286
|
type: "text",
|
|
14463
15287
|
placeholder: t("search"),
|
|
14464
15288
|
"data-i18n-placeholder": "search",
|
|
15289
|
+
title: t("search"),
|
|
15290
|
+
"data-i18n-title": "search",
|
|
14465
15291
|
"aria-label": t("search"),
|
|
14466
15292
|
"data-i18n-aria-label": "search"
|
|
14467
15293
|
},
|
|
@@ -16002,6 +16828,8 @@ function make_toolbar$4(gobj) {
|
|
|
16002
16828
|
type: "text",
|
|
16003
16829
|
placeholder: t("search"),
|
|
16004
16830
|
"data-i18n-placeholder": "search",
|
|
16831
|
+
title: t("search"),
|
|
16832
|
+
"data-i18n-title": "search",
|
|
16005
16833
|
"aria-label": t("search"),
|
|
16006
16834
|
"data-i18n-aria-label": "search"
|
|
16007
16835
|
},
|
|
@@ -19275,6 +20103,8 @@ function make_toolbar$2(gobj) {
|
|
|
19275
20103
|
type: "text",
|
|
19276
20104
|
placeholder: t("search"),
|
|
19277
20105
|
"data-i18n-placeholder": "search",
|
|
20106
|
+
title: t("search"),
|
|
20107
|
+
"data-i18n-title": "search",
|
|
19278
20108
|
"aria-label": t("search"),
|
|
19279
20109
|
"data-i18n-aria-label": "search"
|
|
19280
20110
|
},
|
|
@@ -21095,7 +21925,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
21095
21925
|
gobj_start(jv);
|
|
21096
21926
|
return handle;
|
|
21097
21927
|
}
|
|
21098
|
-
let $win_parent = window_layer_of(host
|
|
21928
|
+
let $win_parent = window_layer_of(host);
|
|
21099
21929
|
handle.win = gobj_create_service(`gclass-win-${clean_name(gobj_name(host))}`, "C_YUI_WINDOW", {
|
|
21100
21930
|
$parent: $win_parent,
|
|
21101
21931
|
subscriber: null,
|
|
@@ -21163,14 +21993,19 @@ function close_gclass_view(handle) {
|
|
|
21163
21993
|
* window on `body` and mounted in the shell's popup layer
|
|
21164
21994
|
* lands BEHIND its opener whatever number it is given, and
|
|
21165
21995
|
* the button reads as one that did nothing.
|
|
21996
|
+
*
|
|
21997
|
+
* Opened from no window: null -- the window layer of the
|
|
21998
|
+
* shell, where every window lives (the legacy '#top-layer'
|
|
21999
|
+
* when a page has one). It was the shell's popup layer: above
|
|
22000
|
+
* the drawer, in the way of the toolbar's dropdowns.
|
|
21166
22001
|
************************************************************/
|
|
21167
|
-
function window_layer_of(host
|
|
22002
|
+
function window_layer_of(host) {
|
|
21168
22003
|
let $c = gobj_read_pointer_attr(host, "$container");
|
|
21169
22004
|
if ($c && typeof $c.closest === "function") {
|
|
21170
22005
|
let $win = $c.closest(".C_YUI_WINDOW");
|
|
21171
22006
|
if ($win && $win.parentNode) return $win.parentNode;
|
|
21172
22007
|
}
|
|
21173
|
-
return typeof document !== "undefined" && document.getElementById("top-layer") ||
|
|
22008
|
+
return typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
21174
22009
|
}
|
|
21175
22010
|
/************************************************************
|
|
21176
22011
|
* A window is not a sheet: below this width there is no room
|
|
@@ -21839,6 +22674,8 @@ function make_find_items(gobj) {
|
|
|
21839
22674
|
type: "text",
|
|
21840
22675
|
placeholder: t("search"),
|
|
21841
22676
|
"data-i18n-placeholder": "search",
|
|
22677
|
+
title: t("search"),
|
|
22678
|
+
"data-i18n-title": "search",
|
|
21842
22679
|
"aria-label": t("search"),
|
|
21843
22680
|
"data-i18n-aria-label": "search"
|
|
21844
22681
|
},
|
|
@@ -23624,7 +24461,7 @@ function card_descriptor(it, show_label, badge_of) {
|
|
|
23624
24461
|
"aria-label": label || it.id
|
|
23625
24462
|
};
|
|
23626
24463
|
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
23627
|
-
let tip = it.tooltip || it.aria_label;
|
|
24464
|
+
let tip = it.tooltip || it.aria_label || label;
|
|
23628
24465
|
if (tip) {
|
|
23629
24466
|
a_attrs.title = tip;
|
|
23630
24467
|
a_attrs["data-i18n-title"] = tip;
|
|
@@ -23633,6 +24470,7 @@ function card_descriptor(it, show_label, badge_of) {
|
|
|
23633
24470
|
a_attrs["aria-disabled"] = "true";
|
|
23634
24471
|
a_attrs["tabindex"] = "-1";
|
|
23635
24472
|
}
|
|
24473
|
+
if (badge) name_control_with_badge(a_attrs, badge);
|
|
23636
24474
|
return [
|
|
23637
24475
|
"a",
|
|
23638
24476
|
a_attrs,
|
|
@@ -24035,6 +24873,7 @@ function render_tabs(gobj, items) {
|
|
|
24035
24873
|
a_attrs.title = tip;
|
|
24036
24874
|
a_attrs["data-i18n-title"] = tip;
|
|
24037
24875
|
}
|
|
24876
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24038
24877
|
let li_class = empty_string(it.class) ? "" : String(it.class);
|
|
24039
24878
|
lis.push([
|
|
24040
24879
|
"li",
|
|
@@ -24114,11 +24953,14 @@ function render_breadcrumb(gobj, items) {
|
|
|
24114
24953
|
href: it.route ? "#" + it.route : "#",
|
|
24115
24954
|
"data-item-id": it.id,
|
|
24116
24955
|
"data-route": it.route || "",
|
|
24117
|
-
"data-disabled": it.disabled ? "1" : "0"
|
|
24956
|
+
"data-disabled": it.disabled ? "1" : "0",
|
|
24957
|
+
"aria-label": it.name || it.id
|
|
24118
24958
|
};
|
|
24119
|
-
if (it.name)
|
|
24120
|
-
|
|
24121
|
-
|
|
24959
|
+
if (it.name) a_attrs["data-i18n-aria-label"] = it.name;
|
|
24960
|
+
let tip = it.tooltip || it.aria_label || it.name;
|
|
24961
|
+
if (tip) {
|
|
24962
|
+
a_attrs.title = tip;
|
|
24963
|
+
a_attrs["data-i18n-title"] = tip;
|
|
24122
24964
|
}
|
|
24123
24965
|
lis.push([
|
|
24124
24966
|
"li",
|
|
@@ -24251,17 +25093,19 @@ function render_accordion(gobj, items) {
|
|
|
24251
25093
|
"aria-expanded": "false",
|
|
24252
25094
|
"aria-controls": body_id
|
|
24253
25095
|
};
|
|
25096
|
+
let head_badge = item_badge_node(gobj, it, false);
|
|
24254
25097
|
if (!empty_string(head_text)) {
|
|
24255
25098
|
head_attrs.i18n = head_text;
|
|
24256
25099
|
head_attrs.title = head_text;
|
|
24257
25100
|
head_attrs["data-i18n-title"] = head_text;
|
|
24258
25101
|
head_attrs["aria-label"] = head_text;
|
|
24259
25102
|
head_attrs["data-i18n-aria-label"] = head_text;
|
|
25103
|
+
name_control_with_badge(head_attrs, head_badge);
|
|
24260
25104
|
}
|
|
24261
25105
|
let $hdr = createElement2([
|
|
24262
25106
|
"button",
|
|
24263
25107
|
head_attrs,
|
|
24264
|
-
[text_node(head_text),
|
|
25108
|
+
[text_node(head_text), head_badge]
|
|
24265
25109
|
]);
|
|
24266
25110
|
$container.appendChild($hdr);
|
|
24267
25111
|
let $ul = createElement2(["ul", {
|
|
@@ -24350,6 +25194,7 @@ function item_li(gobj, it, opts) {
|
|
|
24350
25194
|
a_attrs["aria-disabled"] = "true";
|
|
24351
25195
|
a_attrs["tabindex"] = "-1";
|
|
24352
25196
|
}
|
|
25197
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24353
25198
|
return [
|
|
24354
25199
|
"li",
|
|
24355
25200
|
{},
|
|
@@ -24396,6 +25241,7 @@ function item_iconbar(gobj, it, opts) {
|
|
|
24396
25241
|
a_attrs.title = tip;
|
|
24397
25242
|
a_attrs["data-i18n-title"] = tip;
|
|
24398
25243
|
}
|
|
25244
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24399
25245
|
return [
|
|
24400
25246
|
"div",
|
|
24401
25247
|
{ class: "level-item" },
|
|
@@ -24653,7 +25499,10 @@ function render_node(node) {
|
|
|
24653
25499
|
if (node.icon && /^yi-[a-z0-9-]+$/.test(node.icon)) row.push([
|
|
24654
25500
|
"span",
|
|
24655
25501
|
{ class: "icon ROUTEMAP_ICON" },
|
|
24656
|
-
[["i", {
|
|
25502
|
+
[["i", {
|
|
25503
|
+
class: node.icon,
|
|
25504
|
+
"aria-hidden": "true"
|
|
25505
|
+
}]]
|
|
24657
25506
|
]);
|
|
24658
25507
|
row.push([
|
|
24659
25508
|
"span",
|
|
@@ -24702,16 +25551,23 @@ function render_node(node) {
|
|
|
24702
25551
|
]);
|
|
24703
25552
|
let row_class = (node.current ? " ROUTEMAP_CURRENT" : "") + (node.ref ? " ROUTEMAP_IS_REF" : "");
|
|
24704
25553
|
let $row;
|
|
24705
|
-
if (node.route)
|
|
24706
|
-
|
|
24707
|
-
{
|
|
25554
|
+
if (node.route) {
|
|
25555
|
+
let a_attrs = {
|
|
24708
25556
|
class: "ROUTEMAP_LINK ROUTEMAP_ROW" + row_class,
|
|
24709
25557
|
href: "#" + node.route,
|
|
24710
25558
|
title: node.route
|
|
24711
|
-
}
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
25559
|
+
};
|
|
25560
|
+
if (node.label) {
|
|
25561
|
+
a_attrs["aria-label"] = node.label;
|
|
25562
|
+
a_attrs["data-i18n-aria-label"] = node.label;
|
|
25563
|
+
}
|
|
25564
|
+
if (node.current) a_attrs["aria-current"] = "page";
|
|
25565
|
+
$row = createElement2([
|
|
25566
|
+
"a",
|
|
25567
|
+
a_attrs,
|
|
25568
|
+
row
|
|
25569
|
+
]);
|
|
25570
|
+
} else $row = createElement2([
|
|
24715
25571
|
"span",
|
|
24716
25572
|
{ class: "ROUTEMAP_ROW ROUTEMAP_STRUCT" + row_class },
|
|
24717
25573
|
row
|
|
@@ -24995,7 +25851,7 @@ function yui_shell_show_route_map(shell, opts) {
|
|
|
24995
25851
|
if (gclass_find_by_name("C_YUI_WINDOW")) {
|
|
24996
25852
|
let win_ref = { gobj: null };
|
|
24997
25853
|
let $body = build_body(shell, t);
|
|
24998
|
-
let $parent =
|
|
25854
|
+
let $parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
24999
25855
|
let win = gobj_create_service(WIN_NAME$2, "C_YUI_WINDOW", {
|
|
25000
25856
|
$parent,
|
|
25001
25857
|
subscriber: null,
|
|
@@ -26069,7 +26925,13 @@ function add_tab(gobj, gobj2, id, text, icon) {
|
|
|
26069
26925
|
let $item = createElement2([
|
|
26070
26926
|
"li",
|
|
26071
26927
|
{ class: "" },
|
|
26072
|
-
[["a", {
|
|
26928
|
+
[["a", {
|
|
26929
|
+
href: id,
|
|
26930
|
+
title: t(text),
|
|
26931
|
+
"data-i18n-title": text,
|
|
26932
|
+
"aria-label": t(text),
|
|
26933
|
+
"data-i18n-aria-label": text
|
|
26934
|
+
}]]
|
|
26073
26935
|
]);
|
|
26074
26936
|
$tabs.appendChild($item);
|
|
26075
26937
|
$item.gobj = gobj2;
|
|
@@ -26077,7 +26939,10 @@ function add_tab(gobj, gobj2, id, text, icon) {
|
|
|
26077
26939
|
if (icon) $a.appendChild(createElement2([
|
|
26078
26940
|
"span",
|
|
26079
26941
|
{ class: "icon is-small is-hidden-mobile" },
|
|
26080
|
-
["i", {
|
|
26942
|
+
["i", {
|
|
26943
|
+
class: `${icon}`,
|
|
26944
|
+
"aria-hidden": "true"
|
|
26945
|
+
}]
|
|
26081
26946
|
]));
|
|
26082
26947
|
$a.appendChild(createElement2([
|
|
26083
26948
|
"span",
|
|
@@ -26266,7 +27131,9 @@ function add_topic_card(gobj, id, text, icon, desc) {
|
|
|
26266
27131
|
class: "yui-nav-item yui-nav-card TREEDB_TOPIC_CARD",
|
|
26267
27132
|
href: "#",
|
|
26268
27133
|
"data-topic-href": id,
|
|
26269
|
-
|
|
27134
|
+
title: t(text),
|
|
27135
|
+
"data-i18n-title": text,
|
|
27136
|
+
"aria-label": t(text),
|
|
26270
27137
|
"data-i18n-aria-label": text
|
|
26271
27138
|
},
|
|
26272
27139
|
[[
|
|
@@ -27110,7 +27977,7 @@ function open_json_viewer$1(gobj, opts) {
|
|
|
27110
27977
|
}
|
|
27111
27978
|
});
|
|
27112
27979
|
} else {
|
|
27113
|
-
let $win_parent =
|
|
27980
|
+
let $win_parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
27114
27981
|
priv.json_win = gobj_create_service(`treedb-topics-jsonwin-${clean_name(gobj_name(gobj))}`, "C_YUI_WINDOW", {
|
|
27115
27982
|
$parent: $win_parent,
|
|
27116
27983
|
subscriber: null,
|
|
@@ -27237,7 +28104,9 @@ function request_print_tranger$1(gobj, path) {
|
|
|
27237
28104
|
}, gobj);
|
|
27238
28105
|
if (ret) {
|
|
27239
28106
|
log_error(ret);
|
|
27240
|
-
|
|
28107
|
+
const refusal = refusal_text$1(ret);
|
|
28108
|
+
if (refusal) answer_print_tranger_refused$1(gobj, path, { error: refusal });
|
|
28109
|
+
else answer_print_tranger_refused$1(gobj, path, { i18n: "print-tranger failed" });
|
|
27241
28110
|
return;
|
|
27242
28111
|
}
|
|
27243
28112
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -27305,9 +28174,13 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
27305
28174
|
}
|
|
27306
28175
|
} else gobj.priv.drills_in_flight.clear();
|
|
27307
28176
|
if (result < 0) {
|
|
27308
|
-
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
28177
|
+
if (path && comment) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
27309
28178
|
path,
|
|
27310
|
-
error: comment
|
|
28179
|
+
error: comment
|
|
28180
|
+
}, gobj);
|
|
28181
|
+
else if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
28182
|
+
path,
|
|
28183
|
+
i18n: "print-tranger failed"
|
|
27311
28184
|
}, gobj);
|
|
27312
28185
|
else yui_shell_show_error(yui_shell_of(gobj), comment || "print-tranger failed", { t });
|
|
27313
28186
|
return 0;
|
|
@@ -29092,7 +29965,7 @@ function present_json_popup(gobj, $box, opts) {
|
|
|
29092
29965
|
win: null
|
|
29093
29966
|
};
|
|
29094
29967
|
let win = gobj_create_service(opts.name, "C_YUI_WINDOW", {
|
|
29095
|
-
$parent: popup_mount_layer(
|
|
29968
|
+
$parent: popup_mount_layer(),
|
|
29096
29969
|
subscriber: null,
|
|
29097
29970
|
modal: false,
|
|
29098
29971
|
showMax: true,
|
|
@@ -29146,10 +30019,17 @@ function retire_popup_window(win) {
|
|
|
29146
30019
|
log_warning(`${GCLASS_NAME$5}: json window already gone: ${e}`);
|
|
29147
30020
|
}
|
|
29148
30021
|
}
|
|
29149
|
-
|
|
29150
|
-
|
|
29151
|
-
|
|
29152
|
-
|
|
30022
|
+
/************************************************************
|
|
30023
|
+
* Where a json window of this view lives: null, the WINDOW
|
|
30024
|
+
* layer of the shell, where every window lives -- below the
|
|
30025
|
+
* shell's dialogs, so a confirm asked over it paints above it
|
|
30026
|
+
* (the legacy C_YUI_MAIN '#popup-layer' when a page has one).
|
|
30027
|
+
* It was the shell's popup layer: above the drawer, in the way
|
|
30028
|
+
* of the toolbar's dropdowns, and in an order of its own no
|
|
30029
|
+
* other window could rise above.
|
|
30030
|
+
************************************************************/
|
|
30031
|
+
function popup_mount_layer() {
|
|
30032
|
+
return document.getElementById("popup-layer") || null;
|
|
29153
30033
|
}
|
|
29154
30034
|
/******************************
|
|
29155
30035
|
* Framework Methods
|
|
@@ -29764,7 +30644,10 @@ function col_title_formatter(gobj, col) {
|
|
|
29764
30644
|
let text = col_label(col, topic_name);
|
|
29765
30645
|
let attrs = {};
|
|
29766
30646
|
const NO_I18N = "\0";
|
|
29767
|
-
|
|
30647
|
+
let key = null;
|
|
30648
|
+
if (topic_name && t(topic_name + "." + col.id, { defaultValue: NO_I18N }) !== NO_I18N) key = topic_name + "." + col.id;
|
|
30649
|
+
else if (t(col.id, { defaultValue: NO_I18N }) !== NO_I18N) key = col.id;
|
|
30650
|
+
if (key) attrs.i18n = key;
|
|
29768
30651
|
return createElement2([
|
|
29769
30652
|
"span",
|
|
29770
30653
|
attrs,
|
|
@@ -29858,6 +30741,9 @@ function create_tabulator(gobj) {
|
|
|
29858
30741
|
colDef.editable = function() {
|
|
29859
30742
|
return gobj_read_bool_attr(gobj, "editable") && !gobj_read_bool_attr(gobj, "readonly");
|
|
29860
30743
|
};
|
|
30744
|
+
yui_tabulator_name_editor(colDef, function() {
|
|
30745
|
+
return col_label(col, gobj_read_str_attr(gobj, "topic_name"));
|
|
30746
|
+
});
|
|
29861
30747
|
}
|
|
29862
30748
|
const FILTERABLE = [
|
|
29863
30749
|
"string",
|
|
@@ -71216,7 +72102,7 @@ function open_json_viewer(gobj) {
|
|
|
71216
72102
|
});
|
|
71217
72103
|
gobj_start(jv);
|
|
71218
72104
|
} else {
|
|
71219
|
-
let $win_parent =
|
|
72105
|
+
let $win_parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
71220
72106
|
priv.json_win = gobj_create_service(`treedb-jsonwin-${clean_name(gobj_name(gobj))}`, "C_YUI_WINDOW", {
|
|
71221
72107
|
$parent: $win_parent,
|
|
71222
72108
|
subscriber: null,
|
|
@@ -71330,7 +72216,9 @@ function request_print_tranger(gobj, path) {
|
|
|
71330
72216
|
}, gobj);
|
|
71331
72217
|
if (ret) {
|
|
71332
72218
|
log_error(ret);
|
|
71333
|
-
|
|
72219
|
+
const refusal = refusal_text(ret);
|
|
72220
|
+
if (refusal) answer_print_tranger_refused(gobj, path, { error: refusal });
|
|
72221
|
+
else answer_print_tranger_refused(gobj, path, { i18n: "print-tranger failed" });
|
|
71334
72222
|
return;
|
|
71335
72223
|
}
|
|
71336
72224
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -71735,9 +72623,13 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
71735
72623
|
}
|
|
71736
72624
|
} else priv.drills_in_flight.clear();
|
|
71737
72625
|
if (result < 0) {
|
|
71738
|
-
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
72626
|
+
if (path && comment) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
72627
|
+
path,
|
|
72628
|
+
error: comment
|
|
72629
|
+
}, gobj);
|
|
72630
|
+
else if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
71739
72631
|
path,
|
|
71740
|
-
|
|
72632
|
+
i18n: "print-tranger failed"
|
|
71741
72633
|
}, gobj);
|
|
71742
72634
|
else yui_shell_show_error(yui_shell_of(gobj), comment || "print-tranger failed", { t });
|
|
71743
72635
|
return 0;
|
|
@@ -83329,7 +84221,8 @@ function apply_dev_traces() {
|
|
|
83329
84221
|
* Shell-agnostic: the legacy C_YUI_MAIN shell has a
|
|
83330
84222
|
* '#top-layer' stacking element; the new C_YUI_SHELL does not.
|
|
83331
84223
|
* We pass that element when present, otherwise null — C_YUI_WINDOW
|
|
83332
|
-
*
|
|
84224
|
+
* then takes the window layer of the shell (document.body while
|
|
84225
|
+
* there is none), and follows the shell across a logout.
|
|
83333
84226
|
************************************************************/
|
|
83334
84227
|
function setup_dev(self, show) {
|
|
83335
84228
|
if (show) {
|
|
@@ -83419,7 +84312,8 @@ var WIN_NAME$1 = "Frontend-View-Window";
|
|
|
83419
84312
|
* Shell-agnostic: the legacy C_YUI_MAIN shell has a
|
|
83420
84313
|
* '#top-layer' stacking element; the new C_YUI_SHELL does not.
|
|
83421
84314
|
* We pass that element when present, otherwise null — C_YUI_WINDOW
|
|
83422
|
-
*
|
|
84315
|
+
* then takes the window layer of the shell (document.body while
|
|
84316
|
+
* there is none), and follows the shell across a logout.
|
|
83423
84317
|
*
|
|
83424
84318
|
* Returns the window gobj, or null.
|
|
83425
84319
|
************************************************************/
|