@yuneta/gobj-ui 7.26.34 → 7.26.36
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 +1109 -143
- package/dist/gobj-ui.es.js +1109 -143
- 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 +250 -46
- 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 +348 -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,15 +5323,15 @@ 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
|
-
mql_handler: null
|
|
5333
|
+
mql_handler: null,
|
|
5334
|
+
lang_shell: null
|
|
5054
5335
|
};
|
|
5055
5336
|
var __gclass__$20 = null;
|
|
5056
5337
|
/******************************
|
|
@@ -5062,7 +5343,6 @@ var __gclass__$20 = null;
|
|
|
5062
5343
|
function mt_create$20(gobj) {
|
|
5063
5344
|
let priv = gobj.priv;
|
|
5064
5345
|
priv.windows = [];
|
|
5065
|
-
priv.z = 10;
|
|
5066
5346
|
if ((gobj_read_attr(gobj, "dock_mode") || "floating") === "responsive") {
|
|
5067
5347
|
let q = gobj_read_attr(gobj, "responsive_query") || "(max-width: 768px)";
|
|
5068
5348
|
priv.mql = window.matchMedia(q);
|
|
@@ -5072,6 +5352,8 @@ function mt_create$20(gobj) {
|
|
|
5072
5352
|
priv.mql.addEventListener("change", priv.mql_handler);
|
|
5073
5353
|
}
|
|
5074
5354
|
build_dock(gobj);
|
|
5355
|
+
yui_shell_watch_changes(gobj);
|
|
5356
|
+
follow_language(gobj);
|
|
5075
5357
|
const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
|
|
5076
5358
|
if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
|
|
5077
5359
|
}
|
|
@@ -5080,6 +5362,11 @@ function mt_create$20(gobj) {
|
|
|
5080
5362
|
***************************************************************/
|
|
5081
5363
|
function mt_destroy$20(gobj) {
|
|
5082
5364
|
let priv = gobj.priv;
|
|
5365
|
+
yui_shell_unwatch_changes(gobj);
|
|
5366
|
+
if (priv.lang_shell) {
|
|
5367
|
+
if (!gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5368
|
+
priv.lang_shell = null;
|
|
5369
|
+
}
|
|
5083
5370
|
if (priv.mql && priv.mql_handler) {
|
|
5084
5371
|
priv.mql.removeEventListener("change", priv.mql_handler);
|
|
5085
5372
|
priv.mql = null;
|
|
@@ -5091,6 +5378,37 @@ function mt_destroy$20(gobj) {
|
|
|
5091
5378
|
* Local Methods
|
|
5092
5379
|
***************************/
|
|
5093
5380
|
/************************************************************
|
|
5381
|
+
* Hear the language of the shell that holds the dock -- the
|
|
5382
|
+
* dock outlives a shell, so it follows them: the dying one's
|
|
5383
|
+
* subscription goes with it, the next one is heard. The
|
|
5384
|
+
* toggle of a chip whose window's title has a DATA half has a
|
|
5385
|
+
* composed title, which no key carries: it is written again in
|
|
5386
|
+
* the new language (ac_language_changed).
|
|
5387
|
+
************************************************************/
|
|
5388
|
+
function follow_language(gobj) {
|
|
5389
|
+
let priv = gobj.priv;
|
|
5390
|
+
let shell = yui_shell_of(gobj);
|
|
5391
|
+
if (shell && gobj_is_destroying(shell)) shell = null;
|
|
5392
|
+
if (shell === priv.lang_shell) return;
|
|
5393
|
+
if (priv.lang_shell && !gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5394
|
+
priv.lang_shell = null;
|
|
5395
|
+
if (shell) {
|
|
5396
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
5397
|
+
priv.lang_shell = shell;
|
|
5398
|
+
}
|
|
5399
|
+
}
|
|
5400
|
+
/************************************************************
|
|
5401
|
+
* The toggle's title and aria-label, in the current language:
|
|
5402
|
+
* the same join as C_YUI_WINDOW's composed_title(), DATA half
|
|
5403
|
+
* first. The title the window registered with when it gave no
|
|
5404
|
+
* halves (a legacy caller).
|
|
5405
|
+
************************************************************/
|
|
5406
|
+
function chip_title(entry) {
|
|
5407
|
+
let kind = entry.title_key ? t(entry.title_key) : "";
|
|
5408
|
+
if (entry.title_prefix && kind) return `${entry.title_prefix} · ${kind}`;
|
|
5409
|
+
return entry.title_prefix || kind || entry.title;
|
|
5410
|
+
}
|
|
5411
|
+
/************************************************************
|
|
5094
5412
|
* Inject the dock stylesheet once (theme-aware).
|
|
5095
5413
|
************************************************************/
|
|
5096
5414
|
function ensure_dock_style() {
|
|
@@ -5129,10 +5447,18 @@ function ensure_dock_style() {
|
|
|
5129
5447
|
}
|
|
5130
5448
|
.yui-dock-chip {
|
|
5131
5449
|
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);
|
|
5450
|
+
padding: 0 5px 0 0; border: 1px solid var(--bulma-border); border-radius: 7px;
|
|
5451
|
+
background: var(--bulma-scheme-main); color: var(--bulma-text); white-space: nowrap;
|
|
5134
5452
|
}
|
|
5135
5453
|
.yui-dock-chip:hover { border-color: var(--bulma-text-weak); }
|
|
5454
|
+
/* The chip is the look; its toggle a button that adds none, and
|
|
5455
|
+
* takes the pill's padding, so the whole label is what a press lands
|
|
5456
|
+
* on and the chip reads as one pill with its ✕ at the end. */
|
|
5457
|
+
.yui-dock-chip-toggle {
|
|
5458
|
+
display: inline-flex; align-items: center; gap: 7px;
|
|
5459
|
+
padding: 4px 0 4px 11px; margin: 0; border: 0; border-radius: 7px 0 0 7px;
|
|
5460
|
+
background: transparent; font: inherit; color: inherit; cursor: pointer; white-space: nowrap;
|
|
5461
|
+
}
|
|
5136
5462
|
/* The BORDER says active, not the text: blue ink on a blue tint is
|
|
5137
5463
|
* the same hue on itself -- 4.49:1 on the light chip, under the 4.5
|
|
5138
5464
|
* its 12px label needs. The label takes the text colour (11:1). */
|
|
@@ -5222,10 +5548,33 @@ function apply_placement(gobj) {
|
|
|
5222
5548
|
"bottom-left",
|
|
5223
5549
|
"bottom-right"
|
|
5224
5550
|
]) $dock.classList.toggle(`yui-dock--${c}`, !inline && c === corner);
|
|
5225
|
-
let target = inline ? $inline : gobj_read_attr(gobj, "$parent") ||
|
|
5551
|
+
let target = inline ? $inline : gobj_read_attr(gobj, "$parent") || dock_place(gobj);
|
|
5226
5552
|
if ($dock.parentNode !== target) target.appendChild($dock);
|
|
5227
5553
|
}
|
|
5228
5554
|
/************************************************************
|
|
5555
|
+
* Where the FLOATING dock lives when the app names no
|
|
5556
|
+
* `$parent`: the popup layer of the shell, at the top of it.
|
|
5557
|
+
*
|
|
5558
|
+
* It was document.body at z-index 1000000, and that put it
|
|
5559
|
+
* above the WHOLE shell -- `.yui-shell` is a stacking context
|
|
5560
|
+
* of its own, so its dialogs (modal layer, 99) and toasts (120)
|
|
5561
|
+
* counted only inside it: the dock stayed clickable over a
|
|
5562
|
+
* dialog's backdrop (a window could be closed from its chip
|
|
5563
|
+
* while its own "all changes will be lost" question was open),
|
|
5564
|
+
* and it covered a toast where they met.
|
|
5565
|
+
*
|
|
5566
|
+
* The popup layer, not the window layer: the dock has to stay
|
|
5567
|
+
* above EVERY window, and windows live in two layers -- the
|
|
5568
|
+
* window layer (no `$parent`) and the popup layer, where the
|
|
5569
|
+
* site map and the JSON windows of the treedb views put theirs.
|
|
5570
|
+
* Above both; below the dialogs, the toasts and the loading
|
|
5571
|
+
* cover. No shell (before the first, between a logout and the
|
|
5572
|
+
* next login): the body.
|
|
5573
|
+
************************************************************/
|
|
5574
|
+
function dock_place(gobj) {
|
|
5575
|
+
return yui_shell_popup_layer(yui_shell_of(gobj)) || document.body;
|
|
5576
|
+
}
|
|
5577
|
+
/************************************************************
|
|
5229
5578
|
* Destroy the dock element.
|
|
5230
5579
|
************************************************************/
|
|
5231
5580
|
function destroy_dock(gobj) {
|
|
@@ -5302,7 +5651,6 @@ function set_active(gobj, entry) {
|
|
|
5302
5651
|
* Bring a window to front and mark it active/visible.
|
|
5303
5652
|
************************************************************/
|
|
5304
5653
|
function focus_entry(gobj, entry) {
|
|
5305
|
-
let priv = gobj.priv;
|
|
5306
5654
|
let $win = gobj_read_attr(entry.gobj, "$container");
|
|
5307
5655
|
if ($win) {
|
|
5308
5656
|
if (entry.minimized) {
|
|
@@ -5310,8 +5658,7 @@ function focus_entry(gobj, entry) {
|
|
|
5310
5658
|
entry.minimized = false;
|
|
5311
5659
|
if (entry.$chip) entry.$chip.classList.remove("is-min");
|
|
5312
5660
|
}
|
|
5313
|
-
|
|
5314
|
-
$win.style.zIndex = priv.z;
|
|
5661
|
+
yui_shell_raise_window($win);
|
|
5315
5662
|
}
|
|
5316
5663
|
set_active(gobj, entry);
|
|
5317
5664
|
}
|
|
@@ -5378,57 +5725,60 @@ function ac_register_window(gobj, event, kw, src) {
|
|
|
5378
5725
|
{ class: "yui-dock-label-kind" },
|
|
5379
5726
|
text_node(title)
|
|
5380
5727
|
]);
|
|
5728
|
+
let chip_seq = ++__chip_seq__;
|
|
5729
|
+
let label_ids = label_items.map(function(item, i) {
|
|
5730
|
+
item[1].id = `yui-dock-chip-${chip_seq}-${i}`;
|
|
5731
|
+
return item[1].id;
|
|
5732
|
+
});
|
|
5381
5733
|
let entry = {
|
|
5382
5734
|
gobj: win,
|
|
5383
5735
|
$chip: null,
|
|
5384
|
-
minimized: false
|
|
5736
|
+
minimized: false,
|
|
5737
|
+
title,
|
|
5738
|
+
title_key,
|
|
5739
|
+
title_prefix: prefix
|
|
5385
5740
|
};
|
|
5741
|
+
let window_name = gobj_full_name(win);
|
|
5386
5742
|
let $chip = createElement2([
|
|
5387
5743
|
"div",
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5744
|
+
{ class: "DOCK_CHIP yui-dock-chip" },
|
|
5745
|
+
[[
|
|
5746
|
+
"button",
|
|
5747
|
+
Object.assign({
|
|
5748
|
+
class: "DOCK_CHIP_TOGGLE yui-dock-chip-toggle",
|
|
5749
|
+
type: "button",
|
|
5750
|
+
title,
|
|
5751
|
+
"aria-label": title,
|
|
5752
|
+
"aria-labelledby": label_ids.join(" ")
|
|
5753
|
+
}, !prefix && title_key ? {
|
|
5754
|
+
"data-i18n-title": title_key,
|
|
5755
|
+
"data-i18n-aria-label": title_key
|
|
5756
|
+
} : {}),
|
|
5757
|
+
[chip_lead(kw.icon), [
|
|
5397
5758
|
"span",
|
|
5398
5759
|
{ class: "yui-dock-label" },
|
|
5399
5760
|
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) => {
|
|
5761
|
+
]],
|
|
5762
|
+
{ click: (evt) => {
|
|
5420
5763
|
evt.stopPropagation();
|
|
5421
|
-
|
|
5764
|
+
gobj_send_event(gobj, "EV_TOGGLE_WINDOW", { window: window_name }, gobj);
|
|
5765
|
+
} }
|
|
5766
|
+
], [
|
|
5767
|
+
"button",
|
|
5768
|
+
{
|
|
5769
|
+
class: "DOCK_CHIP_CLOSE yui-dock-close",
|
|
5770
|
+
type: "button",
|
|
5771
|
+
title: t("close"),
|
|
5772
|
+
"data-i18n-title": "close",
|
|
5773
|
+
"aria-label": t("close"),
|
|
5774
|
+
"data-i18n-aria-label": "close"
|
|
5422
5775
|
},
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
}
|
|
5430
|
-
}
|
|
5431
|
-
}
|
|
5776
|
+
html_markup(WC_X),
|
|
5777
|
+
{ click: (evt) => {
|
|
5778
|
+
evt.stopPropagation();
|
|
5779
|
+
gobj_send_event(entry.gobj, "EV_CLOSE_WINDOW", {}, gobj);
|
|
5780
|
+
} }
|
|
5781
|
+
]]
|
|
5432
5782
|
]);
|
|
5433
5783
|
entry.$chip = $chip;
|
|
5434
5784
|
priv.windows.push(entry);
|
|
@@ -5472,6 +5822,67 @@ function ac_focus_window(gobj, event, kw, src) {
|
|
|
5472
5822
|
if (entry) focus_entry(gobj, entry);
|
|
5473
5823
|
return 0;
|
|
5474
5824
|
}
|
|
5825
|
+
/************************************************************
|
|
5826
|
+
* EV_TOGGLE_WINDOW { window } -- the toggle of a chip of THIS
|
|
5827
|
+
* dock was pressed: bring a minimized or covered window to the
|
|
5828
|
+
* front, send the one in front to the dock. Only the dock's own
|
|
5829
|
+
* chip sends it (src is the dock): the events a window sends
|
|
5830
|
+
* about itself come from the window, and this one from the chip
|
|
5831
|
+
* that names it.
|
|
5832
|
+
************************************************************/
|
|
5833
|
+
function ac_toggle_window(gobj, event, kw, src) {
|
|
5834
|
+
let priv = gobj.priv;
|
|
5835
|
+
if (src !== gobj) {
|
|
5836
|
+
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)}`);
|
|
5837
|
+
return -1;
|
|
5838
|
+
}
|
|
5839
|
+
let name = kw && kw.window;
|
|
5840
|
+
let entry = priv.windows.find((e) => gobj_full_name(e.gobj) === name);
|
|
5841
|
+
if (!entry) {
|
|
5842
|
+
log_error(`${gobj_short_name(gobj)}: ${event}: no window '${name}' in the dock`);
|
|
5843
|
+
return -1;
|
|
5844
|
+
}
|
|
5845
|
+
on_chip_click(gobj, entry);
|
|
5846
|
+
return 0;
|
|
5847
|
+
}
|
|
5848
|
+
/************************************************************
|
|
5849
|
+
* EV_SHELL_CHANGED -- a shell was built, or is being destroyed
|
|
5850
|
+
* (yui_shell_watch_changes()). The dock's place -- the shell's
|
|
5851
|
+
* popup layer, or its zone when inline -- may have gone with
|
|
5852
|
+
* it, or be in the new one: place it again. Up to 7.26.34 an
|
|
5853
|
+
* inline dock stayed in the destroyed shell's zone after a
|
|
5854
|
+
* logout, detached, until a window registered. Its language
|
|
5855
|
+
* is the new shell's too.
|
|
5856
|
+
************************************************************/
|
|
5857
|
+
function ac_shell_changed(gobj, event, kw, src) {
|
|
5858
|
+
apply_placement(gobj);
|
|
5859
|
+
follow_language(gobj);
|
|
5860
|
+
return 0;
|
|
5861
|
+
}
|
|
5862
|
+
/************************************************************
|
|
5863
|
+
* EV_LANGUAGE_CHANGED -- from the shell that holds the dock.
|
|
5864
|
+
* A chip's label re-translates by its key (refresh_language()
|
|
5865
|
+
* reaches its kind half); the toggle's title and aria-label
|
|
5866
|
+
* of a window with a DATA half are COMPOSED, so no key carries
|
|
5867
|
+
* them: written again here. Up to 7.26.35 they stayed in the
|
|
5868
|
+
* language the window was opened in (a reader took the
|
|
5869
|
+
* aria-labelledby, which changed; the tooltip did not).
|
|
5870
|
+
************************************************************/
|
|
5871
|
+
function ac_language_changed$11(gobj, event, kw, src) {
|
|
5872
|
+
let priv = gobj.priv;
|
|
5873
|
+
for (let entry of priv.windows) {
|
|
5874
|
+
if (!entry.title_prefix || !entry.$chip) continue;
|
|
5875
|
+
let $toggle = entry.$chip.querySelector(".DOCK_CHIP_TOGGLE");
|
|
5876
|
+
if (!$toggle) {
|
|
5877
|
+
log_error(`${gobj_short_name(gobj)}: a chip without its toggle`);
|
|
5878
|
+
continue;
|
|
5879
|
+
}
|
|
5880
|
+
let title = chip_title(entry);
|
|
5881
|
+
$toggle.setAttribute("title", title);
|
|
5882
|
+
$toggle.setAttribute("aria-label", title);
|
|
5883
|
+
}
|
|
5884
|
+
return 0;
|
|
5885
|
+
}
|
|
5475
5886
|
/***************************
|
|
5476
5887
|
* FSM
|
|
5477
5888
|
***************************/
|
|
@@ -5491,7 +5902,10 @@ function create_gclass$20(gclass_name) {
|
|
|
5491
5902
|
["EV_REGISTER_WINDOW", 0],
|
|
5492
5903
|
["EV_UNREGISTER_WINDOW", 0],
|
|
5493
5904
|
["EV_MINIMIZE_WINDOW", 0],
|
|
5494
|
-
["EV_FOCUS_WINDOW", 0]
|
|
5905
|
+
["EV_FOCUS_WINDOW", 0],
|
|
5906
|
+
["EV_TOGGLE_WINDOW", 0],
|
|
5907
|
+
["EV_SHELL_CHANGED", 0],
|
|
5908
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
5495
5909
|
], [["ST_IDLE", [
|
|
5496
5910
|
[
|
|
5497
5911
|
"EV_REGISTER_WINDOW",
|
|
@@ -5512,6 +5926,21 @@ function create_gclass$20(gclass_name) {
|
|
|
5512
5926
|
"EV_FOCUS_WINDOW",
|
|
5513
5927
|
ac_focus_window,
|
|
5514
5928
|
null
|
|
5929
|
+
],
|
|
5930
|
+
[
|
|
5931
|
+
"EV_TOGGLE_WINDOW",
|
|
5932
|
+
ac_toggle_window,
|
|
5933
|
+
null
|
|
5934
|
+
],
|
|
5935
|
+
[
|
|
5936
|
+
"EV_SHELL_CHANGED",
|
|
5937
|
+
ac_shell_changed,
|
|
5938
|
+
null
|
|
5939
|
+
],
|
|
5940
|
+
[
|
|
5941
|
+
"EV_LANGUAGE_CHANGED",
|
|
5942
|
+
ac_language_changed$11,
|
|
5943
|
+
null
|
|
5515
5944
|
]
|
|
5516
5945
|
]]], gmt$20, 0, attrs_table$20, PRIVATE_DATA$20, 0, 0, 0, 0);
|
|
5517
5946
|
if (!__gclass__$20) return -1;
|
|
@@ -6791,6 +7220,41 @@ function yui_tabulator_name_row_selects(table, t) {
|
|
|
6791
7220
|
}
|
|
6792
7221
|
} catch (e) {}
|
|
6793
7222
|
}
|
|
7223
|
+
/***************************************************************
|
|
7224
|
+
* Name the EDITOR of an editable column: the box Tabulator draws
|
|
7225
|
+
* in a cell while it is edited (input, number, textarea, list,
|
|
7226
|
+
* tickCross, date...).
|
|
7227
|
+
*
|
|
7228
|
+
* Tabulator gives it nothing -- no label, no aria-label, no title
|
|
7229
|
+
* -- so a reader lands in an anonymous edit box. Its name is the
|
|
7230
|
+
* column's: a cell is edited under its column's title. Asked at
|
|
7231
|
+
* the MOMENT of editing: Tabulator takes `editorParams` as a
|
|
7232
|
+
* function of the cell, and every built-in editor writes the
|
|
7233
|
+
* `elementAttributes` it answers onto the element it draws. So
|
|
7234
|
+
* the name is in the language of that moment, with nothing to
|
|
7235
|
+
* re-apply after a language change or a rebuild of the columns
|
|
7236
|
+
* -- the twin of the header filters above, which have to be
|
|
7237
|
+
* renamed after every render.
|
|
7238
|
+
*
|
|
7239
|
+
* `name_of(cell)` answers the column's title, TRANSLATED (the
|
|
7240
|
+
* view's own label: a cascade, a schema header); "" names
|
|
7241
|
+
* nothing. What `editorParams` the column had is kept, its own
|
|
7242
|
+
* `elementAttributes` too; a name it set itself wins.
|
|
7243
|
+
***************************************************************/
|
|
7244
|
+
function yui_tabulator_name_editor(column_def, name_of) {
|
|
7245
|
+
if (!column_def || !column_def.editor || typeof name_of !== "function") return;
|
|
7246
|
+
let base = column_def.editorParams;
|
|
7247
|
+
column_def.editorParams = function(cell) {
|
|
7248
|
+
let params = typeof base === "function" ? base(cell) : base || {};
|
|
7249
|
+
let name = name_of(cell);
|
|
7250
|
+
if (!name) return params;
|
|
7251
|
+
let attrs = Object.assign({
|
|
7252
|
+
"aria-label": name,
|
|
7253
|
+
title: name
|
|
7254
|
+
}, params.elementAttributes || {});
|
|
7255
|
+
return Object.assign({}, params, { elementAttributes: attrs });
|
|
7256
|
+
};
|
|
7257
|
+
}
|
|
6794
7258
|
function yui_tabulator_relocalize(table, t) {
|
|
6795
7259
|
if (!table) return;
|
|
6796
7260
|
try {
|
|
@@ -7311,6 +7775,7 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
7311
7775
|
{
|
|
7312
7776
|
type: "button",
|
|
7313
7777
|
class: "FILE_PICK button is-small",
|
|
7778
|
+
title: t("choose a file"),
|
|
7314
7779
|
"data-i18n-title": "choose a file",
|
|
7315
7780
|
"aria-label": t("choose a file"),
|
|
7316
7781
|
"data-i18n-aria-label": "choose a file"
|
|
@@ -7329,6 +7794,7 @@ function yui_file_control(gobj, { name, value, readonly, accept, on_pick }) {
|
|
|
7329
7794
|
{
|
|
7330
7795
|
type: "button",
|
|
7331
7796
|
class: "FILE_CLEAR button is-small",
|
|
7797
|
+
title: t("remove the file"),
|
|
7332
7798
|
"data-i18n-title": "remove the file",
|
|
7333
7799
|
"aria-label": t("remove the file"),
|
|
7334
7800
|
"data-i18n-aria-label": "remove the file"
|
|
@@ -8677,6 +9143,293 @@ function json_editor_value(content) {
|
|
|
8677
9143
|
return JSON.stringify(content.json);
|
|
8678
9144
|
}
|
|
8679
9145
|
//#endregion
|
|
9146
|
+
//#region src/form_json_editor_names.js
|
|
9147
|
+
/***********************************************************************
|
|
9148
|
+
* form_json_editor_names.js
|
|
9149
|
+
*
|
|
9150
|
+
* The NAMES of the buttons vanilla-jsoneditor draws in its menu
|
|
9151
|
+
* (a json field of C_YUI_FORM): in the app's language, and with an
|
|
9152
|
+
* aria-label.
|
|
9153
|
+
*
|
|
9154
|
+
* The editor draws them itself, in English, with a `title` and
|
|
9155
|
+
* nothing else: "Format JSON: add proper indentation and new lines
|
|
9156
|
+
* (Ctrl+I)", "Undo (Ctrl+Z)", and three mode buttons whose text is
|
|
9157
|
+
* "text", "tree" and "table" (REV-CLOUD V23.5.6). Two hooks reach
|
|
9158
|
+
* them, and both are needed:
|
|
9159
|
+
*
|
|
9160
|
+
* - json_editor_menu_items(), the editor's `onRenderMenu`: the
|
|
9161
|
+
* items it is about to draw, with each title translated (its
|
|
9162
|
+
* shortcut kept) and the mode buttons' text too. Svelte draws
|
|
9163
|
+
* from these, so a button born in a re-render is born named.
|
|
9164
|
+
* - name_json_editor_menu(), after the render, from the form's
|
|
9165
|
+
* FSM: the aria-label of each button, with its key, so
|
|
9166
|
+
* refresh_language() re-translates it, and the state of the
|
|
9167
|
+
* mode buttons (aria-pressed). A menu item has no field for
|
|
9168
|
+
* either.
|
|
9169
|
+
*
|
|
9170
|
+
* A button is known by the CLASS the editor gives it (`jse-format`,
|
|
9171
|
+
* `jse-undo`...), never by its English title: a class is what the
|
|
9172
|
+
* editor's own stylesheet relies on. A button not listed here keeps
|
|
9173
|
+
* the editor's words.
|
|
9174
|
+
*
|
|
9175
|
+
* Its CONTEXT MENU (`onRenderContextMenu`,
|
|
9176
|
+
* json_editor_context_menu_items()) has no class on its items, so
|
|
9177
|
+
* an item is known by what it IS and where it IS: the icon the
|
|
9178
|
+
* editor draws it with (a FontAwesome name: `paste`, `scissors`),
|
|
9179
|
+
* the column of the menu it stands in, its place in a dropdown
|
|
9180
|
+
* (the main button, the first or the second of its list), the
|
|
9181
|
+
* mode of the editor (tree or table) -- never by its words. Its
|
|
9182
|
+
* text and title go back translated; after the render the same
|
|
9183
|
+
* pass names its buttons, and the arrow of each dropdown, which
|
|
9184
|
+
* the editor draws with no name at all.
|
|
9185
|
+
*
|
|
9186
|
+
* Not reached, because the editor gives them no hook: its search
|
|
9187
|
+
* box, its repair messages, the tip at the foot of the context
|
|
9188
|
+
* menu, and its modals (sort, transform). They stay in its
|
|
9189
|
+
* English.
|
|
9190
|
+
*
|
|
9191
|
+
* Copyright (c) 2026, ArtGins.
|
|
9192
|
+
* All Rights Reserved.
|
|
9193
|
+
***********************************************************************/
|
|
9194
|
+
/***************************************************************
|
|
9195
|
+
* Constants
|
|
9196
|
+
***************************************************************/
|
|
9197
|
+
var JSON_EDITOR_BUTTON_KEYS = {
|
|
9198
|
+
"jse-expand-all": "expand all",
|
|
9199
|
+
"jse-collapse-all": "collapse all",
|
|
9200
|
+
"jse-search": "search",
|
|
9201
|
+
"jse-copy": "copy",
|
|
9202
|
+
"jse-undo": "undo",
|
|
9203
|
+
"jse-redo": "redo",
|
|
9204
|
+
"jse-cancel": "cancel",
|
|
9205
|
+
"jse-format": "format json",
|
|
9206
|
+
"jse-compact": "compact json",
|
|
9207
|
+
"jse-sort": "sort",
|
|
9208
|
+
"jse-transform": "transform",
|
|
9209
|
+
"jse-contextmenu": "open context menu"
|
|
9210
|
+
};
|
|
9211
|
+
var JSON_EDITOR_MODE_NAME_KEYS = {
|
|
9212
|
+
text: "text view",
|
|
9213
|
+
tree: "tree view",
|
|
9214
|
+
table: "table view"
|
|
9215
|
+
};
|
|
9216
|
+
var JSON_EDITOR_MODE_TEXT_KEYS = {
|
|
9217
|
+
text: "text mode",
|
|
9218
|
+
tree: "tree mode",
|
|
9219
|
+
table: "table mode"
|
|
9220
|
+
};
|
|
9221
|
+
var MODE_CLASS = "yui-jse-mode-";
|
|
9222
|
+
var SHORTCUT = /\((?:Ctrl|Cmd|⌘)[^()]*\)\s*$/;
|
|
9223
|
+
var CONTEXT_BUTTON_KEYS = {
|
|
9224
|
+
"pen": "edit key",
|
|
9225
|
+
"paste": "paste",
|
|
9226
|
+
"clone": "duplicate",
|
|
9227
|
+
"crop-simple": "extract",
|
|
9228
|
+
"arrow-down-short-wide": "sort",
|
|
9229
|
+
"filter": "transform",
|
|
9230
|
+
"trash-can": "remove",
|
|
9231
|
+
"square-caret-up": "insert before",
|
|
9232
|
+
"square-caret-down": "insert after"
|
|
9233
|
+
};
|
|
9234
|
+
var CONTEXT_ROW_BUTTON_KEYS = {
|
|
9235
|
+
"pen": "edit row",
|
|
9236
|
+
"clone": "duplicate row",
|
|
9237
|
+
"trash-can": "remove row"
|
|
9238
|
+
};
|
|
9239
|
+
var CONTEXT_DROPDOWN_MAIN_KEYS = {
|
|
9240
|
+
"pen": "edit value",
|
|
9241
|
+
"scissors": "cut",
|
|
9242
|
+
"copy": "copy"
|
|
9243
|
+
};
|
|
9244
|
+
var CONTEXT_DROPDOWN_FIRST_KEYS = {
|
|
9245
|
+
"pen": "edit value",
|
|
9246
|
+
"scissors": "cut formatted",
|
|
9247
|
+
"copy": "copy formatted"
|
|
9248
|
+
};
|
|
9249
|
+
var CONTEXT_DROPDOWN_SECOND_KEYS = {
|
|
9250
|
+
"pen": "enforce string",
|
|
9251
|
+
"scissors": "cut compacted",
|
|
9252
|
+
"copy": "copy compacted"
|
|
9253
|
+
};
|
|
9254
|
+
var CONTEXT_TARGET_KEYS = {
|
|
9255
|
+
"0": "structure",
|
|
9256
|
+
"1": "object",
|
|
9257
|
+
"2": "array",
|
|
9258
|
+
"3": "value"
|
|
9259
|
+
};
|
|
9260
|
+
var TARGET_ICONS = ["arrow-right-arrow-left", "plus"];
|
|
9261
|
+
var CONTEXT_LABEL_KEYS = {
|
|
9262
|
+
convert: "convert to",
|
|
9263
|
+
insert: "insert",
|
|
9264
|
+
cell: "table cell",
|
|
9265
|
+
row: "table row"
|
|
9266
|
+
};
|
|
9267
|
+
/***************************
|
|
9268
|
+
* Local Methods
|
|
9269
|
+
***************************/
|
|
9270
|
+
function has_key(table, name) {
|
|
9271
|
+
return Object.prototype.hasOwnProperty.call(table, name);
|
|
9272
|
+
}
|
|
9273
|
+
function button_class(classes) {
|
|
9274
|
+
return (Array.isArray(classes) ? classes : String(classes || "").split(/\s+/)).find((c) => has_key(JSON_EDITOR_BUTTON_KEYS, c)) || "";
|
|
9275
|
+
}
|
|
9276
|
+
function mode_of_item(item) {
|
|
9277
|
+
if (String(item.className || "").split(/\s+/).indexOf("jse-group-button") < 0) return "";
|
|
9278
|
+
return has_key(JSON_EDITOR_MODE_NAME_KEYS, item.text) ? item.text : "";
|
|
9279
|
+
}
|
|
9280
|
+
function icon_of(item) {
|
|
9281
|
+
return item && item.icon && typeof item.icon.iconName === "string" ? item.icon.iconName : "";
|
|
9282
|
+
}
|
|
9283
|
+
function named_item(item, name) {
|
|
9284
|
+
let m = SHORTCUT.exec(String(item.title || ""));
|
|
9285
|
+
return Object.assign({}, item, {
|
|
9286
|
+
text: name,
|
|
9287
|
+
title: m ? `${name} ${m[0].trim()}` : name
|
|
9288
|
+
});
|
|
9289
|
+
}
|
|
9290
|
+
function context_dropdown(item) {
|
|
9291
|
+
let icon = icon_of(item.main);
|
|
9292
|
+
if (!has_key(CONTEXT_DROPDOWN_MAIN_KEYS, icon)) return item;
|
|
9293
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9294
|
+
return Object.assign({}, item, {
|
|
9295
|
+
main: named_item(item.main, t(CONTEXT_DROPDOWN_MAIN_KEYS[icon])),
|
|
9296
|
+
items: list.map(function(it, i) {
|
|
9297
|
+
if (!it || it.type !== "button") return it;
|
|
9298
|
+
if (i === 0) return named_item(it, t(CONTEXT_DROPDOWN_FIRST_KEYS[icon]));
|
|
9299
|
+
if (i === 1) return named_item(it, t(CONTEXT_DROPDOWN_SECOND_KEYS[icon]));
|
|
9300
|
+
return it;
|
|
9301
|
+
})
|
|
9302
|
+
});
|
|
9303
|
+
}
|
|
9304
|
+
function context_button(item, row_column) {
|
|
9305
|
+
let icon = icon_of(item);
|
|
9306
|
+
if (row_column && has_key(CONTEXT_ROW_BUTTON_KEYS, icon)) return named_item(item, t(CONTEXT_ROW_BUTTON_KEYS[icon]));
|
|
9307
|
+
if (has_key(CONTEXT_BUTTON_KEYS, icon)) return named_item(item, t(CONTEXT_BUTTON_KEYS[icon]));
|
|
9308
|
+
return item;
|
|
9309
|
+
}
|
|
9310
|
+
function context_column(item, table, index) {
|
|
9311
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9312
|
+
let buttons = list.filter((it) => it && it.type === "button");
|
|
9313
|
+
let targets = !table && buttons.length > 0 && buttons.every((it) => TARGET_ICONS.indexOf(icon_of(it)) >= 0);
|
|
9314
|
+
let row_column = table && index === 1;
|
|
9315
|
+
let label_kind = "";
|
|
9316
|
+
if (table) label_kind = index === 0 ? "cell" : index === 1 ? "row" : "";
|
|
9317
|
+
else if (targets) label_kind = icon_of(buttons[0]) === "plus" ? "insert" : "convert";
|
|
9318
|
+
let target = 0;
|
|
9319
|
+
let insert_row = 0;
|
|
9320
|
+
return Object.assign({}, item, { items: list.map(function(it) {
|
|
9321
|
+
if (!it || typeof it !== "object") return it;
|
|
9322
|
+
if (it.type === "label") return label_kind ? Object.assign({}, it, { text: t(CONTEXT_LABEL_KEYS[label_kind]) }) : it;
|
|
9323
|
+
if (it.type === "dropdown-button") return context_dropdown(it);
|
|
9324
|
+
if (it.type !== "button") return it;
|
|
9325
|
+
if (targets) return named_item(it, t(CONTEXT_TARGET_KEYS[String(target++)]));
|
|
9326
|
+
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"]));
|
|
9327
|
+
return context_button(it, row_column);
|
|
9328
|
+
}) });
|
|
9329
|
+
}
|
|
9330
|
+
function context_item(item, table) {
|
|
9331
|
+
if (!item || typeof item !== "object") return item;
|
|
9332
|
+
if (item.type === "row") {
|
|
9333
|
+
let column = 0;
|
|
9334
|
+
let list = Array.isArray(item.items) ? item.items : [];
|
|
9335
|
+
return Object.assign({}, item, { items: list.map(function(it) {
|
|
9336
|
+
if (it && it.type === "column") return context_column(it, table, column++);
|
|
9337
|
+
return context_item(it, table);
|
|
9338
|
+
}) });
|
|
9339
|
+
}
|
|
9340
|
+
if (item.type === "dropdown-button") return context_dropdown(item);
|
|
9341
|
+
if (item.type === "button") return context_button(item, false);
|
|
9342
|
+
return item;
|
|
9343
|
+
}
|
|
9344
|
+
function mode_of_button($b) {
|
|
9345
|
+
for (let c of $b.classList) if (c.indexOf(MODE_CLASS) === 0) {
|
|
9346
|
+
let mode = c.slice(13);
|
|
9347
|
+
if (has_key(JSON_EDITOR_MODE_NAME_KEYS, mode)) return mode;
|
|
9348
|
+
}
|
|
9349
|
+
return "";
|
|
9350
|
+
}
|
|
9351
|
+
/***************************
|
|
9352
|
+
* Public
|
|
9353
|
+
***************************/
|
|
9354
|
+
/************************************************************
|
|
9355
|
+
* The editor's `onRenderMenu`: the items it is about to draw,
|
|
9356
|
+
* translated. A title keeps the editor's shortcut after the
|
|
9357
|
+
* translated name ("Deshacer (Ctrl+Z)"); a mode button gets its
|
|
9358
|
+
* mode's name as title and its short text translated, and a class
|
|
9359
|
+
* that says its mode. Anything else is returned as it came.
|
|
9360
|
+
*
|
|
9361
|
+
* Pure: what it answers is data for the editor to draw.
|
|
9362
|
+
************************************************************/
|
|
9363
|
+
function json_editor_menu_items(items) {
|
|
9364
|
+
if (!Array.isArray(items)) return items;
|
|
9365
|
+
return items.map(function(item) {
|
|
9366
|
+
if (!item || item.type !== "button") return item;
|
|
9367
|
+
let mode = mode_of_item(item);
|
|
9368
|
+
if (mode) return Object.assign({}, item, {
|
|
9369
|
+
className: `${item.className} ${MODE_CLASS}${mode}`,
|
|
9370
|
+
title: t(JSON_EDITOR_MODE_NAME_KEYS[mode]),
|
|
9371
|
+
text: t(JSON_EDITOR_MODE_TEXT_KEYS[mode])
|
|
9372
|
+
});
|
|
9373
|
+
let cls = button_class(item.className);
|
|
9374
|
+
if (!cls) return item;
|
|
9375
|
+
let m = SHORTCUT.exec(String(item.title || ""));
|
|
9376
|
+
let name = t(JSON_EDITOR_BUTTON_KEYS[cls]);
|
|
9377
|
+
return Object.assign({}, item, { title: m ? `${name} ${m[0].trim()}` : name });
|
|
9378
|
+
});
|
|
9379
|
+
}
|
|
9380
|
+
/************************************************************
|
|
9381
|
+
* The editor's `onRenderContextMenu`: the items it is about to
|
|
9382
|
+
* draw, translated -- each known by its icon and its place, never
|
|
9383
|
+
* by its words (context_item()). Anything the module does not
|
|
9384
|
+
* know comes back as it came: a newer editor that moves an item
|
|
9385
|
+
* leaves it in English, it does not mislabel it.
|
|
9386
|
+
*
|
|
9387
|
+
* Pure: what it answers is data for the editor to draw.
|
|
9388
|
+
************************************************************/
|
|
9389
|
+
function json_editor_context_menu_items(items, context) {
|
|
9390
|
+
if (!Array.isArray(items)) return items;
|
|
9391
|
+
let table = !!(context && context.mode === "table");
|
|
9392
|
+
return items.map((item) => context_item(item, table));
|
|
9393
|
+
}
|
|
9394
|
+
/************************************************************
|
|
9395
|
+
* Name the buttons of a rendered editor's menu: an aria-label
|
|
9396
|
+
* with its key (data-i18n-aria-label, so a language change
|
|
9397
|
+
* reaches it), and aria-pressed on the mode buttons -- the
|
|
9398
|
+
* selected one is the mode on screen (`jse-selected`). Run
|
|
9399
|
+
* after every render of the menu: a re-render may draw new
|
|
9400
|
+
* buttons, which carry none of it.
|
|
9401
|
+
************************************************************/
|
|
9402
|
+
function name_json_editor_menu($editor) {
|
|
9403
|
+
if (!$editor || typeof $editor.querySelectorAll !== "function") return 0;
|
|
9404
|
+
let named = 0;
|
|
9405
|
+
for (let $b of $editor.querySelectorAll(".jse-menu button")) {
|
|
9406
|
+
let mode = mode_of_button($b);
|
|
9407
|
+
const key = mode ? JSON_EDITOR_MODE_NAME_KEYS[mode] : JSON_EDITOR_BUTTON_KEYS[button_class([...$b.classList])];
|
|
9408
|
+
if (!key) continue;
|
|
9409
|
+
$b.setAttribute("aria-label", t(key));
|
|
9410
|
+
$b.setAttribute("data-i18n-aria-label", key);
|
|
9411
|
+
if (mode) $b.setAttribute("aria-pressed", $b.classList.contains("jse-selected") ? "true" : "false");
|
|
9412
|
+
named++;
|
|
9413
|
+
}
|
|
9414
|
+
const MORE = "more options";
|
|
9415
|
+
for (let $b of $editor.querySelectorAll("div.jse-contextmenu button")) {
|
|
9416
|
+
if ($b.getAttribute("data-type") === "jse-open-dropdown") {
|
|
9417
|
+
$b.setAttribute("title", t(MORE));
|
|
9418
|
+
$b.setAttribute("data-i18n-title", MORE);
|
|
9419
|
+
$b.setAttribute("aria-label", t(MORE));
|
|
9420
|
+
$b.setAttribute("data-i18n-aria-label", MORE);
|
|
9421
|
+
named++;
|
|
9422
|
+
continue;
|
|
9423
|
+
}
|
|
9424
|
+
let text = ($b.textContent || "").trim();
|
|
9425
|
+
if (text) {
|
|
9426
|
+
$b.setAttribute("aria-label", text);
|
|
9427
|
+
named++;
|
|
9428
|
+
}
|
|
9429
|
+
}
|
|
9430
|
+
return named;
|
|
9431
|
+
}
|
|
9432
|
+
//#endregion
|
|
8680
9433
|
//#region src/c_yui_form.js
|
|
8681
9434
|
/***********************************************************************
|
|
8682
9435
|
* c_yui_form.js
|
|
@@ -8726,7 +9479,9 @@ var attrs_table$17 = [
|
|
|
8726
9479
|
var PRIVATE_DATA$17 = {
|
|
8727
9480
|
rearm_timer: null,
|
|
8728
9481
|
tables: null,
|
|
8729
|
-
table_seq: 0
|
|
9482
|
+
table_seq: 0,
|
|
9483
|
+
json_names_posted: false,
|
|
9484
|
+
lang_shell: null
|
|
8730
9485
|
};
|
|
8731
9486
|
var __gclass__$17 = null;
|
|
8732
9487
|
/***************************
|
|
@@ -8757,13 +9512,23 @@ function mt_destroy$17(gobj) {
|
|
|
8757
9512
|
* Framework Method start
|
|
8758
9513
|
************************************************************/
|
|
8759
9514
|
function mt_start$17(gobj) {
|
|
9515
|
+
let priv = gobj.priv;
|
|
9516
|
+
let shell = yui_shell_of(gobj);
|
|
9517
|
+
if (shell) {
|
|
9518
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
9519
|
+
priv.lang_shell = shell;
|
|
9520
|
+
}
|
|
8760
9521
|
let record = gobj_read_attr(gobj, "record");
|
|
8761
9522
|
if (record) gobj_send_event(gobj, "EV_LOAD_RECORD", record, gobj);
|
|
8762
9523
|
}
|
|
8763
9524
|
/************************************************************
|
|
8764
9525
|
* Framework Method stop
|
|
8765
9526
|
************************************************************/
|
|
8766
|
-
function mt_stop$17(gobj) {
|
|
9527
|
+
function mt_stop$17(gobj) {
|
|
9528
|
+
let priv = gobj.priv;
|
|
9529
|
+
if (priv.lang_shell && !gobj_is_destroying(priv.lang_shell)) gobj_unsubscribe_event(priv.lang_shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
9530
|
+
priv.lang_shell = null;
|
|
9531
|
+
}
|
|
8767
9532
|
/***************************
|
|
8768
9533
|
* Local Methods
|
|
8769
9534
|
***************************/
|
|
@@ -9219,6 +9984,80 @@ function name_form_control$1($field, conf) {
|
|
|
9219
9984
|
$clear.setAttribute("data-i18n-aria-label", CLEAR_KEY);
|
|
9220
9985
|
}
|
|
9221
9986
|
}
|
|
9987
|
+
/************************************************************
|
|
9988
|
+
* The ✕ of ONE selected option of a Tom Select: its
|
|
9989
|
+
* remove_button plugin calls this for every option it draws.
|
|
9990
|
+
*
|
|
9991
|
+
* The plugin's own was a div titled "Remove" in English -- never
|
|
9992
|
+
* translated, no aria-label -- with tabindex -1, and the form
|
|
9993
|
+
* turns Backspace deletion off (no_backspace_delete): a keyboard
|
|
9994
|
+
* could not take one option out at all. Named here through t()
|
|
9995
|
+
* with its key (so a language change reaches it), and pressed by
|
|
9996
|
+
* Enter or Space as the clear button is: the key clicks it, which
|
|
9997
|
+
* runs the plugin's own handler.
|
|
9998
|
+
************************************************************/
|
|
9999
|
+
function remove_option_button() {
|
|
10000
|
+
const KEY = "remove this option";
|
|
10001
|
+
let $b = createElement2([
|
|
10002
|
+
"div",
|
|
10003
|
+
{
|
|
10004
|
+
class: "remove",
|
|
10005
|
+
role: "button",
|
|
10006
|
+
tabindex: "0",
|
|
10007
|
+
title: t(KEY),
|
|
10008
|
+
"data-i18n-title": KEY,
|
|
10009
|
+
"aria-label": t(KEY),
|
|
10010
|
+
"data-i18n-aria-label": KEY
|
|
10011
|
+
},
|
|
10012
|
+
"×"
|
|
10013
|
+
]);
|
|
10014
|
+
$b.addEventListener("keydown", function(evt) {
|
|
10015
|
+
if (evt.key === "Enter" || evt.key === " ") {
|
|
10016
|
+
evt.preventDefault();
|
|
10017
|
+
evt.stopPropagation();
|
|
10018
|
+
$b.click();
|
|
10019
|
+
}
|
|
10020
|
+
});
|
|
10021
|
+
return $b;
|
|
10022
|
+
}
|
|
10023
|
+
/************************************************************
|
|
10024
|
+
* The `onRenderMenu` of a json editor of this form.
|
|
10025
|
+
*
|
|
10026
|
+
* The editor calls it with the items it is about to draw: they go
|
|
10027
|
+
* back translated (json_editor_menu_items(), data for the editor
|
|
10028
|
+
* to draw). What no item can carry -- an aria-label, the state of
|
|
10029
|
+
* the mode buttons -- is written on the drawn buttons, after the
|
|
10030
|
+
* render, by the form's FSM (EV_NAME_JSON_EDITORS): the callback
|
|
10031
|
+
* only posts the event, once until it is handled. Posted, not
|
|
10032
|
+
* sent: when it runs the editor has not drawn the menu yet.
|
|
10033
|
+
*
|
|
10034
|
+
* A new function each call: handing an editor a new one is what
|
|
10035
|
+
* makes it draw its menu again (ac_language_changed).
|
|
10036
|
+
************************************************************/
|
|
10037
|
+
function json_editor_render_menu(gobj) {
|
|
10038
|
+
return function(items) {
|
|
10039
|
+
ask_json_editor_names(gobj);
|
|
10040
|
+
return json_editor_menu_items(items);
|
|
10041
|
+
};
|
|
10042
|
+
}
|
|
10043
|
+
/************************************************************
|
|
10044
|
+
* The `onRenderContextMenu` of a json editor of this form: the
|
|
10045
|
+
* same, for the menu it opens on a right click or Ctrl+Q. It is
|
|
10046
|
+
* built each time it opens, in the language of that moment.
|
|
10047
|
+
************************************************************/
|
|
10048
|
+
function json_editor_render_context_menu(gobj) {
|
|
10049
|
+
return function(items, context) {
|
|
10050
|
+
ask_json_editor_names(gobj);
|
|
10051
|
+
return json_editor_context_menu_items(items, context);
|
|
10052
|
+
};
|
|
10053
|
+
}
|
|
10054
|
+
function ask_json_editor_names(gobj) {
|
|
10055
|
+
let priv = gobj.priv;
|
|
10056
|
+
if (!priv.json_names_posted && !gobj_is_destroying(gobj)) {
|
|
10057
|
+
priv.json_names_posted = true;
|
|
10058
|
+
gobj_post_event(gobj, "EV_NAME_JSON_EDITORS", {}, gobj);
|
|
10059
|
+
}
|
|
10060
|
+
}
|
|
9222
10061
|
function build_form(gobj) {
|
|
9223
10062
|
let form_id = gobj_read_str_attr(gobj, "form_id");
|
|
9224
10063
|
let $form = createElement2(["form", {
|
|
@@ -9250,7 +10089,7 @@ function build_html_form(gobj, $form, prefix, template) {
|
|
|
9250
10089
|
let label_keys = topic_name ? [topic_name + "." + field_desc.name, field_desc.name] : [field_desc.name];
|
|
9251
10090
|
const NO_I18N = "\0";
|
|
9252
10091
|
html_field_conf.label = t(label_keys, { defaultValue: field_desc.header });
|
|
9253
|
-
html_field_conf.label_i18n = t(
|
|
10092
|
+
html_field_conf.label_i18n = label_keys.find((k) => t(k, { defaultValue: NO_I18N }) !== NO_I18N) || null;
|
|
9254
10093
|
html_field_conf.placeholder = field_desc.placeholder ? t(field_desc.placeholder) : "";
|
|
9255
10094
|
let placeholders = gobj_read_attr(gobj, "placeholders");
|
|
9256
10095
|
if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
|
|
@@ -9956,7 +10795,7 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
9956
10795
|
"clear_button": { "title": t("remove all selected options") },
|
|
9957
10796
|
"no_active_items": {},
|
|
9958
10797
|
"no_backspace_delete": {},
|
|
9959
|
-
"remove_button": {}
|
|
10798
|
+
"remove_button": { html: remove_option_button }
|
|
9960
10799
|
}
|
|
9961
10800
|
});
|
|
9962
10801
|
$extend.tom_select.on("change", function() {
|
|
@@ -10025,7 +10864,9 @@ function create_form_field(gobj, $form, prefix, field_desc, { tag, inputType, na
|
|
|
10025
10864
|
},
|
|
10026
10865
|
timestampTag: function({ field, value, path }) {
|
|
10027
10866
|
return is_time_field(field);
|
|
10028
|
-
}
|
|
10867
|
+
},
|
|
10868
|
+
onRenderMenu: json_editor_render_menu(gobj),
|
|
10869
|
+
onRenderContextMenu: json_editor_render_context_menu(gobj)
|
|
10029
10870
|
}
|
|
10030
10871
|
});
|
|
10031
10872
|
break;
|
|
@@ -10557,6 +11398,9 @@ function template2columns(gobj, columns, template, sub_elements) {
|
|
|
10557
11398
|
}
|
|
10558
11399
|
if (column) {
|
|
10559
11400
|
if (readonly) delete column.editor;
|
|
11401
|
+
yui_tabulator_name_editor(column, function() {
|
|
11402
|
+
return t(field_desc.header || field_desc.name);
|
|
11403
|
+
});
|
|
10560
11404
|
columns.push(column);
|
|
10561
11405
|
}
|
|
10562
11406
|
});
|
|
@@ -11317,6 +12161,39 @@ function ac_hide$11(gobj, event, kw, src) {
|
|
|
11317
12161
|
function ac_timeout(gobj, event, kw, src) {
|
|
11318
12162
|
return 0;
|
|
11319
12163
|
}
|
|
12164
|
+
/************************************************************
|
|
12165
|
+
* EV_NAME_JSON_EDITORS {} -- a menu of a json editor of this
|
|
12166
|
+
* form was drawn, its menu or its context menu (posted by
|
|
12167
|
+
* ask_json_editor_names): name its buttons. Every editor of the
|
|
12168
|
+
* form: naming is idempotent, and a kw is plain json, which an
|
|
12169
|
+
* editor is not.
|
|
12170
|
+
************************************************************/
|
|
12171
|
+
function ac_name_json_editors(gobj, event, kw, src) {
|
|
12172
|
+
let priv = gobj.priv;
|
|
12173
|
+
priv.json_names_posted = false;
|
|
12174
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
12175
|
+
if (!$container) {
|
|
12176
|
+
log_error(`${gobj_short_name(gobj)}: ${event} without a container`);
|
|
12177
|
+
return -1;
|
|
12178
|
+
}
|
|
12179
|
+
for (let $editor of $container.querySelectorAll(".jsoneditor")) name_json_editor_menu($editor);
|
|
12180
|
+
return 0;
|
|
12181
|
+
}
|
|
12182
|
+
/************************************************************
|
|
12183
|
+
* EV_LANGUAGE_CHANGED {} -- from the shell. A json editor draws
|
|
12184
|
+
* its menu once: its titles and the text of its mode buttons stay
|
|
12185
|
+
* in the old language until it draws it again, so each is told to
|
|
12186
|
+
* (a new onRenderMenu), and the render names it again.
|
|
12187
|
+
************************************************************/
|
|
12188
|
+
function ac_language_changed$10(gobj, event, kw, src) {
|
|
12189
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
12190
|
+
if (!$container) return 0;
|
|
12191
|
+
for (let $editor of $container.querySelectorAll(".jsoneditor")) {
|
|
12192
|
+
let editor = $editor.jsoneditor;
|
|
12193
|
+
if (editor && typeof editor.updateProps === "function") editor.updateProps({ onRenderMenu: json_editor_render_menu(gobj) });
|
|
12194
|
+
}
|
|
12195
|
+
return 0;
|
|
12196
|
+
}
|
|
11320
12197
|
/***************************
|
|
11321
12198
|
* FSM
|
|
11322
12199
|
***************************/
|
|
@@ -11466,6 +12343,16 @@ function create_gclass$17(gclass_name) {
|
|
|
11466
12343
|
"EV_TIMEOUT",
|
|
11467
12344
|
ac_timeout,
|
|
11468
12345
|
null
|
|
12346
|
+
],
|
|
12347
|
+
[
|
|
12348
|
+
"EV_NAME_JSON_EDITORS",
|
|
12349
|
+
ac_name_json_editors,
|
|
12350
|
+
null
|
|
12351
|
+
],
|
|
12352
|
+
[
|
|
12353
|
+
"EV_LANGUAGE_CHANGED",
|
|
12354
|
+
ac_language_changed$10,
|
|
12355
|
+
null
|
|
11469
12356
|
]
|
|
11470
12357
|
]]];
|
|
11471
12358
|
const event_types = [
|
|
@@ -11484,7 +12371,9 @@ function create_gclass$17(gclass_name) {
|
|
|
11484
12371
|
["EV_REFRESH", 0],
|
|
11485
12372
|
["EV_SHOW", 0],
|
|
11486
12373
|
["EV_HIDE", 0],
|
|
11487
|
-
["EV_TIMEOUT", 0]
|
|
12374
|
+
["EV_TIMEOUT", 0],
|
|
12375
|
+
["EV_NAME_JSON_EDITORS", 0],
|
|
12376
|
+
["EV_LANGUAGE_CHANGED", 0]
|
|
11488
12377
|
];
|
|
11489
12378
|
__gclass__$17 = gclass_create(gclass_name, event_types, states, gmt$17, 0, attrs_table$17, PRIVATE_DATA$17, 0, 0, 0, 0);
|
|
11490
12379
|
if (!__gclass__$17) return -1;
|
|
@@ -11504,7 +12393,7 @@ function register_c_yui_form() {
|
|
|
11504
12393
|
*
|
|
11505
12394
|
* Utilities for maplibre
|
|
11506
12395
|
*
|
|
11507
|
-
* Copyright (c) 2025, ArtGins.
|
|
12396
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
11508
12397
|
* All Rights Reserved.
|
|
11509
12398
|
***********************************************************************/
|
|
11510
12399
|
var EditControl = class {
|
|
@@ -11700,9 +12589,14 @@ function label_ctrl($root, selector, text) {
|
|
|
11700
12589
|
$el.setAttribute("aria-label", text);
|
|
11701
12590
|
}
|
|
11702
12591
|
}
|
|
12592
|
+
function relabel_written($root, selector, was, now) {
|
|
12593
|
+
if (!$root || !now) return;
|
|
12594
|
+
for (const $el of $root.querySelectorAll(selector)) if ($el.getAttribute("aria-label") === was) $el.setAttribute("aria-label", now);
|
|
12595
|
+
}
|
|
11703
12596
|
function yui_maplibre_relocalize(map, t) {
|
|
11704
12597
|
if (!map || typeof map.getContainer !== "function") return;
|
|
11705
12598
|
const strings = yui_maplibre_locale(t);
|
|
12599
|
+
const was = Object.assign({}, map._locale);
|
|
11706
12600
|
try {
|
|
11707
12601
|
map._locale = Object.assign({}, map._locale, strings);
|
|
11708
12602
|
} catch (e) {}
|
|
@@ -11714,6 +12608,8 @@ function yui_maplibre_relocalize(map, t) {
|
|
|
11714
12608
|
label_ctrl($c, ".maplibregl-ctrl-attrib-button", strings["AttributionControl.ToggleAttribution"]);
|
|
11715
12609
|
label_ctrl($c, ".maplibregl-ctrl-fullscreen", strings["FullscreenControl.Enter"]);
|
|
11716
12610
|
label_ctrl($c, ".maplibregl-popup-close-button", strings["Popup.Close"]);
|
|
12611
|
+
relabel_written($c, ".maplibregl-canvas", was["Map.Title"], strings["Map.Title"]);
|
|
12612
|
+
relabel_written($c, ".maplibregl-marker", was["Marker.Title"], strings["Marker.Title"]);
|
|
11717
12613
|
const mac = typeof navigator !== "undefined" && (navigator.userAgent || "").includes("Mac");
|
|
11718
12614
|
const $desktop = $c.querySelector(".maplibregl-desktop-message");
|
|
11719
12615
|
if ($desktop) $desktop.textContent = mac ? strings["CooperativeGesturesHandler.MacHelpText"] : strings["CooperativeGesturesHandler.WindowsHelpText"];
|
|
@@ -14462,6 +15358,8 @@ function make_toolbar$5(gobj) {
|
|
|
14462
15358
|
type: "text",
|
|
14463
15359
|
placeholder: t("search"),
|
|
14464
15360
|
"data-i18n-placeholder": "search",
|
|
15361
|
+
title: t("search"),
|
|
15362
|
+
"data-i18n-title": "search",
|
|
14465
15363
|
"aria-label": t("search"),
|
|
14466
15364
|
"data-i18n-aria-label": "search"
|
|
14467
15365
|
},
|
|
@@ -16002,6 +16900,8 @@ function make_toolbar$4(gobj) {
|
|
|
16002
16900
|
type: "text",
|
|
16003
16901
|
placeholder: t("search"),
|
|
16004
16902
|
"data-i18n-placeholder": "search",
|
|
16903
|
+
title: t("search"),
|
|
16904
|
+
"data-i18n-title": "search",
|
|
16005
16905
|
"aria-label": t("search"),
|
|
16006
16906
|
"data-i18n-aria-label": "search"
|
|
16007
16907
|
},
|
|
@@ -19275,6 +20175,8 @@ function make_toolbar$2(gobj) {
|
|
|
19275
20175
|
type: "text",
|
|
19276
20176
|
placeholder: t("search"),
|
|
19277
20177
|
"data-i18n-placeholder": "search",
|
|
20178
|
+
title: t("search"),
|
|
20179
|
+
"data-i18n-title": "search",
|
|
19278
20180
|
"aria-label": t("search"),
|
|
19279
20181
|
"data-i18n-aria-label": "search"
|
|
19280
20182
|
},
|
|
@@ -21095,7 +21997,7 @@ function open_gclass_view(host, gclass_name, opts) {
|
|
|
21095
21997
|
gobj_start(jv);
|
|
21096
21998
|
return handle;
|
|
21097
21999
|
}
|
|
21098
|
-
let $win_parent = window_layer_of(host
|
|
22000
|
+
let $win_parent = window_layer_of(host);
|
|
21099
22001
|
handle.win = gobj_create_service(`gclass-win-${clean_name(gobj_name(host))}`, "C_YUI_WINDOW", {
|
|
21100
22002
|
$parent: $win_parent,
|
|
21101
22003
|
subscriber: null,
|
|
@@ -21163,14 +22065,19 @@ function close_gclass_view(handle) {
|
|
|
21163
22065
|
* window on `body` and mounted in the shell's popup layer
|
|
21164
22066
|
* lands BEHIND its opener whatever number it is given, and
|
|
21165
22067
|
* the button reads as one that did nothing.
|
|
22068
|
+
*
|
|
22069
|
+
* Opened from no window: null -- the window layer of the
|
|
22070
|
+
* shell, where every window lives (the legacy '#top-layer'
|
|
22071
|
+
* when a page has one). It was the shell's popup layer: above
|
|
22072
|
+
* the drawer, in the way of the toolbar's dropdowns.
|
|
21166
22073
|
************************************************************/
|
|
21167
|
-
function window_layer_of(host
|
|
22074
|
+
function window_layer_of(host) {
|
|
21168
22075
|
let $c = gobj_read_pointer_attr(host, "$container");
|
|
21169
22076
|
if ($c && typeof $c.closest === "function") {
|
|
21170
22077
|
let $win = $c.closest(".C_YUI_WINDOW");
|
|
21171
22078
|
if ($win && $win.parentNode) return $win.parentNode;
|
|
21172
22079
|
}
|
|
21173
|
-
return typeof document !== "undefined" && document.getElementById("top-layer") ||
|
|
22080
|
+
return typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
21174
22081
|
}
|
|
21175
22082
|
/************************************************************
|
|
21176
22083
|
* A window is not a sheet: below this width there is no room
|
|
@@ -21839,6 +22746,8 @@ function make_find_items(gobj) {
|
|
|
21839
22746
|
type: "text",
|
|
21840
22747
|
placeholder: t("search"),
|
|
21841
22748
|
"data-i18n-placeholder": "search",
|
|
22749
|
+
title: t("search"),
|
|
22750
|
+
"data-i18n-title": "search",
|
|
21842
22751
|
"aria-label": t("search"),
|
|
21843
22752
|
"data-i18n-aria-label": "search"
|
|
21844
22753
|
},
|
|
@@ -23624,7 +24533,7 @@ function card_descriptor(it, show_label, badge_of) {
|
|
|
23624
24533
|
"aria-label": label || it.id
|
|
23625
24534
|
};
|
|
23626
24535
|
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
23627
|
-
let tip = it.tooltip || it.aria_label;
|
|
24536
|
+
let tip = it.tooltip || it.aria_label || label;
|
|
23628
24537
|
if (tip) {
|
|
23629
24538
|
a_attrs.title = tip;
|
|
23630
24539
|
a_attrs["data-i18n-title"] = tip;
|
|
@@ -23633,6 +24542,7 @@ function card_descriptor(it, show_label, badge_of) {
|
|
|
23633
24542
|
a_attrs["aria-disabled"] = "true";
|
|
23634
24543
|
a_attrs["tabindex"] = "-1";
|
|
23635
24544
|
}
|
|
24545
|
+
if (badge) name_control_with_badge(a_attrs, badge);
|
|
23636
24546
|
return [
|
|
23637
24547
|
"a",
|
|
23638
24548
|
a_attrs,
|
|
@@ -24035,6 +24945,7 @@ function render_tabs(gobj, items) {
|
|
|
24035
24945
|
a_attrs.title = tip;
|
|
24036
24946
|
a_attrs["data-i18n-title"] = tip;
|
|
24037
24947
|
}
|
|
24948
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24038
24949
|
let li_class = empty_string(it.class) ? "" : String(it.class);
|
|
24039
24950
|
lis.push([
|
|
24040
24951
|
"li",
|
|
@@ -24114,11 +25025,14 @@ function render_breadcrumb(gobj, items) {
|
|
|
24114
25025
|
href: it.route ? "#" + it.route : "#",
|
|
24115
25026
|
"data-item-id": it.id,
|
|
24116
25027
|
"data-route": it.route || "",
|
|
24117
|
-
"data-disabled": it.disabled ? "1" : "0"
|
|
25028
|
+
"data-disabled": it.disabled ? "1" : "0",
|
|
25029
|
+
"aria-label": it.name || it.id
|
|
24118
25030
|
};
|
|
24119
|
-
if (it.name)
|
|
24120
|
-
|
|
24121
|
-
|
|
25031
|
+
if (it.name) a_attrs["data-i18n-aria-label"] = it.name;
|
|
25032
|
+
let tip = it.tooltip || it.aria_label || it.name;
|
|
25033
|
+
if (tip) {
|
|
25034
|
+
a_attrs.title = tip;
|
|
25035
|
+
a_attrs["data-i18n-title"] = tip;
|
|
24122
25036
|
}
|
|
24123
25037
|
lis.push([
|
|
24124
25038
|
"li",
|
|
@@ -24251,17 +25165,19 @@ function render_accordion(gobj, items) {
|
|
|
24251
25165
|
"aria-expanded": "false",
|
|
24252
25166
|
"aria-controls": body_id
|
|
24253
25167
|
};
|
|
25168
|
+
let head_badge = item_badge_node(gobj, it, false);
|
|
24254
25169
|
if (!empty_string(head_text)) {
|
|
24255
25170
|
head_attrs.i18n = head_text;
|
|
24256
25171
|
head_attrs.title = head_text;
|
|
24257
25172
|
head_attrs["data-i18n-title"] = head_text;
|
|
24258
25173
|
head_attrs["aria-label"] = head_text;
|
|
24259
25174
|
head_attrs["data-i18n-aria-label"] = head_text;
|
|
25175
|
+
name_control_with_badge(head_attrs, head_badge);
|
|
24260
25176
|
}
|
|
24261
25177
|
let $hdr = createElement2([
|
|
24262
25178
|
"button",
|
|
24263
25179
|
head_attrs,
|
|
24264
|
-
[text_node(head_text),
|
|
25180
|
+
[text_node(head_text), head_badge]
|
|
24265
25181
|
]);
|
|
24266
25182
|
$container.appendChild($hdr);
|
|
24267
25183
|
let $ul = createElement2(["ul", {
|
|
@@ -24350,6 +25266,7 @@ function item_li(gobj, it, opts) {
|
|
|
24350
25266
|
a_attrs["aria-disabled"] = "true";
|
|
24351
25267
|
a_attrs["tabindex"] = "-1";
|
|
24352
25268
|
}
|
|
25269
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24353
25270
|
return [
|
|
24354
25271
|
"li",
|
|
24355
25272
|
{},
|
|
@@ -24396,6 +25313,7 @@ function item_iconbar(gobj, it, opts) {
|
|
|
24396
25313
|
a_attrs.title = tip;
|
|
24397
25314
|
a_attrs["data-i18n-title"] = tip;
|
|
24398
25315
|
}
|
|
25316
|
+
name_control_with_badge(a_attrs, badge_el);
|
|
24399
25317
|
return [
|
|
24400
25318
|
"div",
|
|
24401
25319
|
{ class: "level-item" },
|
|
@@ -24653,7 +25571,10 @@ function render_node(node) {
|
|
|
24653
25571
|
if (node.icon && /^yi-[a-z0-9-]+$/.test(node.icon)) row.push([
|
|
24654
25572
|
"span",
|
|
24655
25573
|
{ class: "icon ROUTEMAP_ICON" },
|
|
24656
|
-
[["i", {
|
|
25574
|
+
[["i", {
|
|
25575
|
+
class: node.icon,
|
|
25576
|
+
"aria-hidden": "true"
|
|
25577
|
+
}]]
|
|
24657
25578
|
]);
|
|
24658
25579
|
row.push([
|
|
24659
25580
|
"span",
|
|
@@ -24702,16 +25623,23 @@ function render_node(node) {
|
|
|
24702
25623
|
]);
|
|
24703
25624
|
let row_class = (node.current ? " ROUTEMAP_CURRENT" : "") + (node.ref ? " ROUTEMAP_IS_REF" : "");
|
|
24704
25625
|
let $row;
|
|
24705
|
-
if (node.route)
|
|
24706
|
-
|
|
24707
|
-
{
|
|
25626
|
+
if (node.route) {
|
|
25627
|
+
let a_attrs = {
|
|
24708
25628
|
class: "ROUTEMAP_LINK ROUTEMAP_ROW" + row_class,
|
|
24709
25629
|
href: "#" + node.route,
|
|
24710
25630
|
title: node.route
|
|
24711
|
-
}
|
|
24712
|
-
|
|
24713
|
-
|
|
24714
|
-
|
|
25631
|
+
};
|
|
25632
|
+
if (node.label) {
|
|
25633
|
+
a_attrs["aria-label"] = node.label;
|
|
25634
|
+
a_attrs["data-i18n-aria-label"] = node.label;
|
|
25635
|
+
}
|
|
25636
|
+
if (node.current) a_attrs["aria-current"] = "page";
|
|
25637
|
+
$row = createElement2([
|
|
25638
|
+
"a",
|
|
25639
|
+
a_attrs,
|
|
25640
|
+
row
|
|
25641
|
+
]);
|
|
25642
|
+
} else $row = createElement2([
|
|
24715
25643
|
"span",
|
|
24716
25644
|
{ class: "ROUTEMAP_ROW ROUTEMAP_STRUCT" + row_class },
|
|
24717
25645
|
row
|
|
@@ -24995,7 +25923,7 @@ function yui_shell_show_route_map(shell, opts) {
|
|
|
24995
25923
|
if (gclass_find_by_name("C_YUI_WINDOW")) {
|
|
24996
25924
|
let win_ref = { gobj: null };
|
|
24997
25925
|
let $body = build_body(shell, t);
|
|
24998
|
-
let $parent =
|
|
25926
|
+
let $parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
24999
25927
|
let win = gobj_create_service(WIN_NAME$2, "C_YUI_WINDOW", {
|
|
25000
25928
|
$parent,
|
|
25001
25929
|
subscriber: null,
|
|
@@ -26069,7 +26997,13 @@ function add_tab(gobj, gobj2, id, text, icon) {
|
|
|
26069
26997
|
let $item = createElement2([
|
|
26070
26998
|
"li",
|
|
26071
26999
|
{ class: "" },
|
|
26072
|
-
[["a", {
|
|
27000
|
+
[["a", {
|
|
27001
|
+
href: id,
|
|
27002
|
+
title: t(text),
|
|
27003
|
+
"data-i18n-title": text,
|
|
27004
|
+
"aria-label": t(text),
|
|
27005
|
+
"data-i18n-aria-label": text
|
|
27006
|
+
}]]
|
|
26073
27007
|
]);
|
|
26074
27008
|
$tabs.appendChild($item);
|
|
26075
27009
|
$item.gobj = gobj2;
|
|
@@ -26077,7 +27011,10 @@ function add_tab(gobj, gobj2, id, text, icon) {
|
|
|
26077
27011
|
if (icon) $a.appendChild(createElement2([
|
|
26078
27012
|
"span",
|
|
26079
27013
|
{ class: "icon is-small is-hidden-mobile" },
|
|
26080
|
-
["i", {
|
|
27014
|
+
["i", {
|
|
27015
|
+
class: `${icon}`,
|
|
27016
|
+
"aria-hidden": "true"
|
|
27017
|
+
}]
|
|
26081
27018
|
]));
|
|
26082
27019
|
$a.appendChild(createElement2([
|
|
26083
27020
|
"span",
|
|
@@ -26266,7 +27203,9 @@ function add_topic_card(gobj, id, text, icon, desc) {
|
|
|
26266
27203
|
class: "yui-nav-item yui-nav-card TREEDB_TOPIC_CARD",
|
|
26267
27204
|
href: "#",
|
|
26268
27205
|
"data-topic-href": id,
|
|
26269
|
-
|
|
27206
|
+
title: t(text),
|
|
27207
|
+
"data-i18n-title": text,
|
|
27208
|
+
"aria-label": t(text),
|
|
26270
27209
|
"data-i18n-aria-label": text
|
|
26271
27210
|
},
|
|
26272
27211
|
[[
|
|
@@ -27110,7 +28049,7 @@ function open_json_viewer$1(gobj, opts) {
|
|
|
27110
28049
|
}
|
|
27111
28050
|
});
|
|
27112
28051
|
} else {
|
|
27113
|
-
let $win_parent =
|
|
28052
|
+
let $win_parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
27114
28053
|
priv.json_win = gobj_create_service(`treedb-topics-jsonwin-${clean_name(gobj_name(gobj))}`, "C_YUI_WINDOW", {
|
|
27115
28054
|
$parent: $win_parent,
|
|
27116
28055
|
subscriber: null,
|
|
@@ -27237,7 +28176,9 @@ function request_print_tranger$1(gobj, path) {
|
|
|
27237
28176
|
}, gobj);
|
|
27238
28177
|
if (ret) {
|
|
27239
28178
|
log_error(ret);
|
|
27240
|
-
|
|
28179
|
+
const refusal = refusal_text$1(ret);
|
|
28180
|
+
if (refusal) answer_print_tranger_refused$1(gobj, path, { error: refusal });
|
|
28181
|
+
else answer_print_tranger_refused$1(gobj, path, { i18n: "print-tranger failed" });
|
|
27241
28182
|
return;
|
|
27242
28183
|
}
|
|
27243
28184
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -27305,9 +28246,13 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
27305
28246
|
}
|
|
27306
28247
|
} else gobj.priv.drills_in_flight.clear();
|
|
27307
28248
|
if (result < 0) {
|
|
27308
|
-
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
28249
|
+
if (path && comment) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
28250
|
+
path,
|
|
28251
|
+
error: comment
|
|
28252
|
+
}, gobj);
|
|
28253
|
+
else if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
27309
28254
|
path,
|
|
27310
|
-
|
|
28255
|
+
i18n: "print-tranger failed"
|
|
27311
28256
|
}, gobj);
|
|
27312
28257
|
else yui_shell_show_error(yui_shell_of(gobj), comment || "print-tranger failed", { t });
|
|
27313
28258
|
return 0;
|
|
@@ -29092,7 +30037,7 @@ function present_json_popup(gobj, $box, opts) {
|
|
|
29092
30037
|
win: null
|
|
29093
30038
|
};
|
|
29094
30039
|
let win = gobj_create_service(opts.name, "C_YUI_WINDOW", {
|
|
29095
|
-
$parent: popup_mount_layer(
|
|
30040
|
+
$parent: popup_mount_layer(),
|
|
29096
30041
|
subscriber: null,
|
|
29097
30042
|
modal: false,
|
|
29098
30043
|
showMax: true,
|
|
@@ -29146,10 +30091,17 @@ function retire_popup_window(win) {
|
|
|
29146
30091
|
log_warning(`${GCLASS_NAME$5}: json window already gone: ${e}`);
|
|
29147
30092
|
}
|
|
29148
30093
|
}
|
|
29149
|
-
|
|
29150
|
-
|
|
29151
|
-
|
|
29152
|
-
|
|
30094
|
+
/************************************************************
|
|
30095
|
+
* Where a json window of this view lives: null, the WINDOW
|
|
30096
|
+
* layer of the shell, where every window lives -- below the
|
|
30097
|
+
* shell's dialogs, so a confirm asked over it paints above it
|
|
30098
|
+
* (the legacy C_YUI_MAIN '#popup-layer' when a page has one).
|
|
30099
|
+
* It was the shell's popup layer: above the drawer, in the way
|
|
30100
|
+
* of the toolbar's dropdowns, and in an order of its own no
|
|
30101
|
+
* other window could rise above.
|
|
30102
|
+
************************************************************/
|
|
30103
|
+
function popup_mount_layer() {
|
|
30104
|
+
return document.getElementById("popup-layer") || null;
|
|
29153
30105
|
}
|
|
29154
30106
|
/******************************
|
|
29155
30107
|
* Framework Methods
|
|
@@ -29764,7 +30716,10 @@ function col_title_formatter(gobj, col) {
|
|
|
29764
30716
|
let text = col_label(col, topic_name);
|
|
29765
30717
|
let attrs = {};
|
|
29766
30718
|
const NO_I18N = "\0";
|
|
29767
|
-
|
|
30719
|
+
let key = null;
|
|
30720
|
+
if (topic_name && t(topic_name + "." + col.id, { defaultValue: NO_I18N }) !== NO_I18N) key = topic_name + "." + col.id;
|
|
30721
|
+
else if (t(col.id, { defaultValue: NO_I18N }) !== NO_I18N) key = col.id;
|
|
30722
|
+
if (key) attrs.i18n = key;
|
|
29768
30723
|
return createElement2([
|
|
29769
30724
|
"span",
|
|
29770
30725
|
attrs,
|
|
@@ -29858,6 +30813,9 @@ function create_tabulator(gobj) {
|
|
|
29858
30813
|
colDef.editable = function() {
|
|
29859
30814
|
return gobj_read_bool_attr(gobj, "editable") && !gobj_read_bool_attr(gobj, "readonly");
|
|
29860
30815
|
};
|
|
30816
|
+
yui_tabulator_name_editor(colDef, function() {
|
|
30817
|
+
return col_label(col, gobj_read_str_attr(gobj, "topic_name"));
|
|
30818
|
+
});
|
|
29861
30819
|
}
|
|
29862
30820
|
const FILTERABLE = [
|
|
29863
30821
|
"string",
|
|
@@ -71216,7 +72174,7 @@ function open_json_viewer(gobj) {
|
|
|
71216
72174
|
});
|
|
71217
72175
|
gobj_start(jv);
|
|
71218
72176
|
} else {
|
|
71219
|
-
let $win_parent =
|
|
72177
|
+
let $win_parent = typeof document !== "undefined" && document.getElementById("top-layer") || null;
|
|
71220
72178
|
priv.json_win = gobj_create_service(`treedb-jsonwin-${clean_name(gobj_name(gobj))}`, "C_YUI_WINDOW", {
|
|
71221
72179
|
$parent: $win_parent,
|
|
71222
72180
|
subscriber: null,
|
|
@@ -71330,7 +72288,9 @@ function request_print_tranger(gobj, path) {
|
|
|
71330
72288
|
}, gobj);
|
|
71331
72289
|
if (ret) {
|
|
71332
72290
|
log_error(ret);
|
|
71333
|
-
|
|
72291
|
+
const refusal = refusal_text(ret);
|
|
72292
|
+
if (refusal) answer_print_tranger_refused(gobj, path, { error: refusal });
|
|
72293
|
+
else answer_print_tranger_refused(gobj, path, { i18n: "print-tranger failed" });
|
|
71334
72294
|
return;
|
|
71335
72295
|
}
|
|
71336
72296
|
if (path) priv.drills_in_flight.add(path);
|
|
@@ -71735,9 +72695,13 @@ function ac_mt_command_answer$1(gobj, event, kw, src) {
|
|
|
71735
72695
|
}
|
|
71736
72696
|
} else priv.drills_in_flight.clear();
|
|
71737
72697
|
if (result < 0) {
|
|
71738
|
-
if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
72698
|
+
if (path && comment) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
72699
|
+
path,
|
|
72700
|
+
error: comment
|
|
72701
|
+
}, gobj);
|
|
72702
|
+
else if (path) gobj_send_event(jv, "EV_SUBTREE_ERROR", {
|
|
71739
72703
|
path,
|
|
71740
|
-
|
|
72704
|
+
i18n: "print-tranger failed"
|
|
71741
72705
|
}, gobj);
|
|
71742
72706
|
else yui_shell_show_error(yui_shell_of(gobj), comment || "print-tranger failed", { t });
|
|
71743
72707
|
return 0;
|
|
@@ -83329,7 +84293,8 @@ function apply_dev_traces() {
|
|
|
83329
84293
|
* Shell-agnostic: the legacy C_YUI_MAIN shell has a
|
|
83330
84294
|
* '#top-layer' stacking element; the new C_YUI_SHELL does not.
|
|
83331
84295
|
* We pass that element when present, otherwise null — C_YUI_WINDOW
|
|
83332
|
-
*
|
|
84296
|
+
* then takes the window layer of the shell (document.body while
|
|
84297
|
+
* there is none), and follows the shell across a logout.
|
|
83333
84298
|
************************************************************/
|
|
83334
84299
|
function setup_dev(self, show) {
|
|
83335
84300
|
if (show) {
|
|
@@ -83419,7 +84384,8 @@ var WIN_NAME$1 = "Frontend-View-Window";
|
|
|
83419
84384
|
* Shell-agnostic: the legacy C_YUI_MAIN shell has a
|
|
83420
84385
|
* '#top-layer' stacking element; the new C_YUI_SHELL does not.
|
|
83421
84386
|
* We pass that element when present, otherwise null — C_YUI_WINDOW
|
|
83422
|
-
*
|
|
84387
|
+
* then takes the window layer of the shell (document.body while
|
|
84388
|
+
* there is none), and follows the shell across a logout.
|
|
83423
84389
|
*
|
|
83424
84390
|
* Returns the window gobj, or null.
|
|
83425
84391
|
************************************************************/
|