@yuneta/gobj-ui 7.26.29 → 7.26.31
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 +65 -22
- package/dist/gobj-ui.cjs.js +426 -113
- package/dist/gobj-ui.es.js +426 -114
- package/index.js +1 -0
- package/package.json +1 -1
- package/src/c_yui_form.js +12 -0
- package/src/c_yui_nav.js +152 -19
- package/src/c_yui_shell.css +84 -18
- package/src/c_yui_shell.js +145 -65
- package/src/c_yui_window.js +32 -5
- package/src/nav_cards_helpers.js +21 -5
- package/src/nav_item_badge.wiring.test.js +564 -0
- package/src/window_layer.wiring.test.js +106 -0
- package/src/yui_badge.js +145 -0
- package/src/yui_badge.test.js +148 -0
- package/src/yui_tabulator_i18n.js +10 -2
- package/src/yui_tabulator_i18n.test.js +80 -0
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -524,6 +524,127 @@ function text_list_item_formatter(label) {
|
|
|
524
524
|
return span;
|
|
525
525
|
}
|
|
526
526
|
//#endregion
|
|
527
|
+
//#region src/yui_badge.js
|
|
528
|
+
/***********************************************************************
|
|
529
|
+
* yui_badge.js
|
|
530
|
+
*
|
|
531
|
+
* The BADGE: the little count a control carries -- unread
|
|
532
|
+
* notifications, active alarms. The toolbar items of C_YUI_SHELL
|
|
533
|
+
* and the menu items of C_YUI_NAV build and paint theirs here, so
|
|
534
|
+
* the two follow the same rules and cannot drift apart:
|
|
535
|
+
*
|
|
536
|
+
* EMPTY IS 0, "" AND null ALIKE (false and undefined too): a badge
|
|
537
|
+
* reading "0" is worse than no badge -- it draws the eye to say
|
|
538
|
+
* nothing. A count is only worth a pixel when there IS something.
|
|
539
|
+
*
|
|
540
|
+
* CAPPED AT 99+: a badge sits in a row of fixed width (the app bar,
|
|
541
|
+
* a bottom icon bar), and a four digit pill pushes the items next
|
|
542
|
+
* to it off a phone screen. A string passes through, for the
|
|
543
|
+
* states that are not counts ("!", "…").
|
|
544
|
+
*
|
|
545
|
+
* ALWAYS RENDERED, hidden when empty, so the runtime setters have a
|
|
546
|
+
* node to write into and never rebuild the control that holds it.
|
|
547
|
+
*
|
|
548
|
+
* role="status" and NOT aria-hidden, deliberately. The control
|
|
549
|
+
* carries an explicit aria-label, and an explicit label REPLACES
|
|
550
|
+
* the element's content for a screen reader -- so a badge inside
|
|
551
|
+
* it would be silent. As its own live region it is both read and
|
|
552
|
+
* announced when the count changes, which is the whole point of a
|
|
553
|
+
* badge that means "something needs you". For the same reason a
|
|
554
|
+
* write that changes nothing touches no DOM: rewriting the same
|
|
555
|
+
* number would have it announced again on every tick.
|
|
556
|
+
*
|
|
557
|
+
* A TONE, optional: one of BADGE_TONES, drawn as Bulma's
|
|
558
|
+
* `is-<tone>` on the badge. It says HOW BAD the count is -- the
|
|
559
|
+
* alarms of an app coloured by the worst state among them. No
|
|
560
|
+
* tone is the default look (the danger colour: a badge exists to
|
|
561
|
+
* pull the eye). An unknown tone is the caller's error: it is
|
|
562
|
+
* logged, and the default look is drawn instead.
|
|
563
|
+
*
|
|
564
|
+
* The text is a Text node, never a string: a value that came from
|
|
565
|
+
* outside must not reach createElement2() as markup.
|
|
566
|
+
*
|
|
567
|
+
* Copyright (c) 2026, ArtGins.
|
|
568
|
+
* All Rights Reserved.
|
|
569
|
+
***********************************************************************/
|
|
570
|
+
/***************************************************************
|
|
571
|
+
* Constants
|
|
572
|
+
***************************************************************/
|
|
573
|
+
var BADGE_TONES = Object.freeze([
|
|
574
|
+
"danger",
|
|
575
|
+
"warning",
|
|
576
|
+
"info",
|
|
577
|
+
"success",
|
|
578
|
+
"primary",
|
|
579
|
+
"link"
|
|
580
|
+
]);
|
|
581
|
+
/************************************************************
|
|
582
|
+
* The text a badge shows for `value`, "" when it shows none.
|
|
583
|
+
************************************************************/
|
|
584
|
+
function badge_text(value) {
|
|
585
|
+
if (value === null || value === void 0 || value === false) return "";
|
|
586
|
+
if (typeof value === "number") {
|
|
587
|
+
if (!isFinite(value) || value <= 0) return "";
|
|
588
|
+
return value > 99 ? "99+" : String(Math.floor(value));
|
|
589
|
+
}
|
|
590
|
+
return String(value).trim();
|
|
591
|
+
}
|
|
592
|
+
/************************************************************
|
|
593
|
+
* The tone to draw: `tone` when it is one of BADGE_TONES, ""
|
|
594
|
+
* (the default look) when it is empty. Anything else is logged,
|
|
595
|
+
* naming `who`, and answers "".
|
|
596
|
+
************************************************************/
|
|
597
|
+
function badge_tone(tone, who) {
|
|
598
|
+
if (tone === void 0 || tone === null || tone === "") return "";
|
|
599
|
+
if (BADGE_TONES.indexOf(tone) < 0) {
|
|
600
|
+
(0, _yuneta_gobj_js.log_error)(`${who}: unknown badge tone '${tone}', drawn with the default look (the tones: ${BADGE_TONES.join(", ")})`);
|
|
601
|
+
return "";
|
|
602
|
+
}
|
|
603
|
+
return tone;
|
|
604
|
+
}
|
|
605
|
+
/************************************************************
|
|
606
|
+
* The createElement2() description of a badge. `classes` are
|
|
607
|
+
* the host's (its logical name, `yui-badge` for the look, and
|
|
608
|
+
* where it sits); `who` names the item in the log of an unknown
|
|
609
|
+
* tone.
|
|
610
|
+
************************************************************/
|
|
611
|
+
function badge_node(value, tone, classes, who) {
|
|
612
|
+
let text = badge_text(value);
|
|
613
|
+
let known = badge_tone(tone, who);
|
|
614
|
+
let attrs = {
|
|
615
|
+
class: known ? `${classes} is-${known}` : classes,
|
|
616
|
+
role: "status"
|
|
617
|
+
};
|
|
618
|
+
if (!text) attrs.hidden = "hidden";
|
|
619
|
+
return [
|
|
620
|
+
"span",
|
|
621
|
+
attrs,
|
|
622
|
+
text_node(text)
|
|
623
|
+
];
|
|
624
|
+
}
|
|
625
|
+
/************************************************************
|
|
626
|
+
* Write a badge that is already in the DOM, as badge_node()
|
|
627
|
+
* draws it. `tone` is one badge_tone() answered: the setter
|
|
628
|
+
* checks it once for all the badges it paints.
|
|
629
|
+
************************************************************/
|
|
630
|
+
function paint_badge($badge, value, tone) {
|
|
631
|
+
for (let known of BADGE_TONES) {
|
|
632
|
+
let cls = `is-${known}`;
|
|
633
|
+
if (known === tone) {
|
|
634
|
+
if (!$badge.classList.contains(cls)) $badge.classList.add(cls);
|
|
635
|
+
} else if ($badge.classList.contains(cls)) $badge.classList.remove(cls);
|
|
636
|
+
}
|
|
637
|
+
let text = badge_text(value);
|
|
638
|
+
if (!text) {
|
|
639
|
+
$badge.textContent = "";
|
|
640
|
+
$badge.setAttribute("hidden", "hidden");
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
if ($badge.textContent === text && !$badge.hasAttribute("hidden")) return;
|
|
644
|
+
$badge.textContent = text;
|
|
645
|
+
$badge.removeAttribute("hidden");
|
|
646
|
+
}
|
|
647
|
+
//#endregion
|
|
527
648
|
//#region src/route_map_model.js
|
|
528
649
|
/***********************************************************************
|
|
529
650
|
* route_map_model.js
|
|
@@ -962,6 +1083,8 @@ var PRIVATE_DATA$22 = {
|
|
|
962
1083
|
stages: {},
|
|
963
1084
|
navs: [],
|
|
964
1085
|
item_index: {},
|
|
1086
|
+
nav_badges: {},
|
|
1087
|
+
dynamic_items: {},
|
|
965
1088
|
section_pos: {},
|
|
966
1089
|
route_mru: [],
|
|
967
1090
|
sub_routes: {},
|
|
@@ -1585,6 +1708,7 @@ function instantiate_nav_in_zone(gobj, menu, menu_id, zone_id, level, nav_label)
|
|
|
1585
1708
|
level,
|
|
1586
1709
|
show_on: render_cfg.show_on || "",
|
|
1587
1710
|
back_route: render_cfg.back_route || "",
|
|
1711
|
+
badges: Object.assign({}, priv.nav_badges),
|
|
1588
1712
|
shell: gobj
|
|
1589
1713
|
}, gobj);
|
|
1590
1714
|
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(nav, "$container");
|
|
@@ -1774,8 +1898,10 @@ function navigate_to(gobj, route, depth, no_drain) {
|
|
|
1774
1898
|
});
|
|
1775
1899
|
}
|
|
1776
1900
|
function build_view_gobj(gobj, entry, route, stage) {
|
|
1901
|
+
let priv = gobj.priv;
|
|
1777
1902
|
let target = entry.target;
|
|
1778
1903
|
let kw = target.kw || {};
|
|
1904
|
+
if (target.gclass === "C_YUI_NAV") kw = Object.assign({}, kw, { badges: Object.assign({}, priv.nav_badges) });
|
|
1779
1905
|
let name = target.name || `view_${safe_id(route)}`;
|
|
1780
1906
|
let view;
|
|
1781
1907
|
try {
|
|
@@ -1876,48 +2002,6 @@ function build_toolbar$1(gobj, config) {
|
|
|
1876
2002
|
$zone.appendChild($bar);
|
|
1877
2003
|
}
|
|
1878
2004
|
/************************************************************
|
|
1879
|
-
* The badge node of a toolbar item — the little count pinned to
|
|
1880
|
-
* the corner of its icon (unread notifications, active alarms).
|
|
1881
|
-
*
|
|
1882
|
-
* ALWAYS rendered, hidden when empty, so the runtime setter has a
|
|
1883
|
-
* node to write into and does not have to rebuild the button.
|
|
1884
|
-
*
|
|
1885
|
-
* EMPTY IS 0, "" AND null ALIKE: a badge reading "0" is worse than
|
|
1886
|
-
* no badge — it draws the eye to say nothing. A count is only
|
|
1887
|
-
* worth a pixel when there IS something.
|
|
1888
|
-
*
|
|
1889
|
-
* Capped at 99+: the toolbar is a fixed-width row, and a four
|
|
1890
|
-
* digit pill pushes the items next to it off a phone screen.
|
|
1891
|
-
*
|
|
1892
|
-
* role="status" and NOT aria-hidden, deliberately. The button
|
|
1893
|
-
* carries an explicit aria-label, and an explicit label REPLACES
|
|
1894
|
-
* the element's content for a screen reader — so a badge inside
|
|
1895
|
-
* it would be silent. As its own live region it is both read and
|
|
1896
|
-
* announced when the count changes, which is the whole point of a
|
|
1897
|
-
* badge that means "something needs you".
|
|
1898
|
-
************************************************************/
|
|
1899
|
-
function badge_text(value) {
|
|
1900
|
-
if (value === null || value === void 0 || value === false) return "";
|
|
1901
|
-
if (typeof value === "number") {
|
|
1902
|
-
if (!isFinite(value) || value <= 0) return "";
|
|
1903
|
-
return value > 99 ? "99+" : String(Math.floor(value));
|
|
1904
|
-
}
|
|
1905
|
-
return String(value).trim();
|
|
1906
|
-
}
|
|
1907
|
-
function badge_node(value) {
|
|
1908
|
-
let text = badge_text(value);
|
|
1909
|
-
let attrs = {
|
|
1910
|
-
class: "yui-toolbar-badge",
|
|
1911
|
-
role: "status"
|
|
1912
|
-
};
|
|
1913
|
-
if (!text) attrs.hidden = "hidden";
|
|
1914
|
-
return [
|
|
1915
|
-
"span",
|
|
1916
|
-
attrs,
|
|
1917
|
-
text
|
|
1918
|
-
];
|
|
1919
|
-
}
|
|
1920
|
-
/************************************************************
|
|
1921
2005
|
* The attributes that turn a toolbar item into a real link, or
|
|
1922
2006
|
* null when this item is not one. Answering null is what keeps
|
|
1923
2007
|
* every caller's default (a <button> that dispatches an action)
|
|
@@ -1948,7 +2032,7 @@ function build_toolbar_action_item(gobj, it) {
|
|
|
1948
2032
|
[["i", {
|
|
1949
2033
|
class: it.icon,
|
|
1950
2034
|
"aria-hidden": "true"
|
|
1951
|
-
}], badge_node(it.badge)]
|
|
2035
|
+
}], badge_node(it.badge, it.badge_tone, "TOOLBAR_ITEM_BADGE yui-badge yui-toolbar-badge", `C_YUI_SHELL: toolbar item '${it.id || "?"}'`)]
|
|
1952
2036
|
]);
|
|
1953
2037
|
if (!(0, _yuneta_gobj_js.empty_string)(it.name)) children.push([
|
|
1954
2038
|
"span",
|
|
@@ -2759,6 +2843,41 @@ function update_secondary_nav_visibility(gobj, entry) {
|
|
|
2759
2843
|
else $c.classList.add("is-hidden");
|
|
2760
2844
|
}
|
|
2761
2845
|
}
|
|
2846
|
+
/************************************************************
|
|
2847
|
+
* Does a menu of this shell declare an item `item_id`: an item
|
|
2848
|
+
* of a menu of app_config.json, of one of their submenus, or
|
|
2849
|
+
* one given to yui_shell_set_submenu() since.
|
|
2850
|
+
************************************************************/
|
|
2851
|
+
function nav_item_declared(gobj, item_id) {
|
|
2852
|
+
let priv = gobj.priv;
|
|
2853
|
+
let config = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "config") || {};
|
|
2854
|
+
let menus = (0, _yuneta_gobj_js.is_object)(config.menu) ? config.menu : {};
|
|
2855
|
+
let holds = (items) => (0, _yuneta_gobj_js.is_array)(items) && items.some((it) => it && it.id === item_id);
|
|
2856
|
+
for (let menu_id in menus) {
|
|
2857
|
+
let items = menus[menu_id] && menus[menu_id].items;
|
|
2858
|
+
if (!(0, _yuneta_gobj_js.is_array)(items)) continue;
|
|
2859
|
+
if (holds(items)) return true;
|
|
2860
|
+
for (let it of items) if (it && it.submenu && holds(it.submenu.items)) return true;
|
|
2861
|
+
}
|
|
2862
|
+
for (let parent_item_id in priv.dynamic_items) if (holds(priv.dynamic_items[parent_item_id])) return true;
|
|
2863
|
+
return false;
|
|
2864
|
+
}
|
|
2865
|
+
/************************************************************
|
|
2866
|
+
* Every C_YUI_NAV of this shell: the navs of its menus, and the
|
|
2867
|
+
* section-index landings mounted in a stage.
|
|
2868
|
+
************************************************************/
|
|
2869
|
+
function shell_navs(gobj) {
|
|
2870
|
+
let priv = gobj.priv;
|
|
2871
|
+
let navs = priv.navs.slice();
|
|
2872
|
+
for (let stage_name in priv.stages) {
|
|
2873
|
+
let views = priv.stages[stage_name].items || {};
|
|
2874
|
+
for (let route in views) {
|
|
2875
|
+
let view = views[route];
|
|
2876
|
+
if (view && (0, _yuneta_gobj_js.gobj_gclass_name)(view) === "C_YUI_NAV") navs.push(view);
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
return navs;
|
|
2880
|
+
}
|
|
2762
2881
|
/***************************
|
|
2763
2882
|
* Actions
|
|
2764
2883
|
***************************/
|
|
@@ -3255,35 +3374,79 @@ function yui_shell_set_toolbar_item_icon(shell_gobj, item_id, icon_class) {
|
|
|
3255
3374
|
* its icon.
|
|
3256
3375
|
*
|
|
3257
3376
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3);
|
|
3377
|
+
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3, "warning");
|
|
3258
3378
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 0); // hidden
|
|
3259
3379
|
*
|
|
3260
3380
|
* This is the API that matters: a count is a RUNTIME fact. The
|
|
3261
|
-
* `badge`
|
|
3262
|
-
* an app whose number never changes did not need
|
|
3381
|
+
* `badge` / `badge_tone` fields of a toolbar item only seed the
|
|
3382
|
+
* first paint, and an app whose number never changes did not need
|
|
3383
|
+
* a badge.
|
|
3263
3384
|
*
|
|
3264
3385
|
* 0 / "" / null / false all clear it, and a number over 99 renders
|
|
3265
|
-
* "99+" — see
|
|
3266
|
-
* are not counts ("!", "…").
|
|
3386
|
+
* "99+" — see yui_badge.js. Accepts a string for the states that
|
|
3387
|
+
* are not counts ("!", "…"). `tone`, optional, is one of
|
|
3388
|
+
* BADGE_TONES ("danger" | "warning" | "info" | "success" |
|
|
3389
|
+
* "primary" | "link"): Bulma's is-<tone> on the badge. Each call
|
|
3390
|
+
* states the WHOLE badge: no tone is the default look, not the
|
|
3391
|
+
* tone it had. The twin of yui_shell_set_nav_item_badge().
|
|
3267
3392
|
*
|
|
3268
3393
|
* Silent no-op on an unknown item id: a toolbar that does not
|
|
3269
3394
|
* declare the item (an app without alarms) must not be an error
|
|
3270
|
-
* at every tick of whatever feeds the number.
|
|
3395
|
+
* at every tick of whatever feeds the number. An unknown TONE is
|
|
3396
|
+
* the caller's error: logged, and drawn with the default look.
|
|
3271
3397
|
************************************************************/
|
|
3272
|
-
function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value) {
|
|
3398
|
+
function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value, tone) {
|
|
3399
|
+
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_toolbar_item_badge('${item_id}')`);
|
|
3273
3400
|
if (!shell_gobj || !(0, _yuneta_gobj_js.is_gobj)(shell_gobj) || (0, _yuneta_gobj_js.empty_string)(item_id)) return;
|
|
3274
3401
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(shell_gobj, "$container");
|
|
3275
3402
|
if (!$container) return;
|
|
3276
3403
|
let $badge = $container.querySelector(`[data-toolbar-item-id="${item_id}"] .yui-toolbar-badge`);
|
|
3277
3404
|
if (!$badge) return;
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3405
|
+
paint_badge($badge, value, tone);
|
|
3406
|
+
}
|
|
3407
|
+
/************************************************************
|
|
3408
|
+
* Set (or clear) the badge of a MENU item — the twin of
|
|
3409
|
+
* yui_shell_set_toolbar_item_badge(), for an entry of a menu of
|
|
3410
|
+
* app_config.json, of one of their submenus, or one given to
|
|
3411
|
+
* yui_shell_set_submenu().
|
|
3412
|
+
*
|
|
3413
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 3);
|
|
3414
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 3, "warning");
|
|
3415
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 0); // hidden
|
|
3416
|
+
*
|
|
3417
|
+
* The same value, tone and rules as the toolbar's (yui_badge.js),
|
|
3418
|
+
* each call stating the whole badge.
|
|
3419
|
+
*
|
|
3420
|
+
* EVERY instance of the item gets it: the same entry is drawn by
|
|
3421
|
+
* as many navs as there are zones hosting its menu (a rail on
|
|
3422
|
+
* desktop, an icon bar on a phone), and by a drawer that repeats
|
|
3423
|
+
* it. Each nav repaints it in place (EV_SET_ITEM_BADGE), and
|
|
3424
|
+
* KEEPS it: a rebuild of the nav (a yui_shell_set_submenu()) draws
|
|
3425
|
+
* it again. The shell keeps it too, for the navs it creates
|
|
3426
|
+
* afterwards (a section-index landing, mounted when the user walks
|
|
3427
|
+
* into it). From then on it is the badge of that id: the `badge`
|
|
3428
|
+
* field of an item only seeds the paint until this is called.
|
|
3429
|
+
*
|
|
3430
|
+
* Silent no-op on an id no menu declares, as the toolbar's: a menu
|
|
3431
|
+
* without the entry (an app without alarms) must not be an error
|
|
3432
|
+
* at every tick of whatever feeds the number. An unknown TONE is
|
|
3433
|
+
* the caller's error: logged, and drawn with the default look.
|
|
3434
|
+
************************************************************/
|
|
3435
|
+
function yui_shell_set_nav_item_badge(shell_gobj, item_id, value, tone) {
|
|
3436
|
+
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_nav_item_badge('${item_id}')`);
|
|
3437
|
+
if (!shell_gobj || !(0, _yuneta_gobj_js.is_gobj)(shell_gobj) || (0, _yuneta_gobj_js.gobj_is_destroying)(shell_gobj) || (0, _yuneta_gobj_js.empty_string)(item_id)) return;
|
|
3438
|
+
let priv = shell_gobj.priv;
|
|
3439
|
+
if (!priv || !nav_item_declared(shell_gobj, item_id)) return;
|
|
3440
|
+
let badge = value === void 0 ? null : value;
|
|
3441
|
+
priv.nav_badges[item_id] = {
|
|
3442
|
+
badge,
|
|
3443
|
+
badge_tone: tone
|
|
3444
|
+
};
|
|
3445
|
+
for (let nav of shell_navs(shell_gobj)) (0, _yuneta_gobj_js.gobj_send_event)(nav, "EV_SET_ITEM_BADGE", {
|
|
3446
|
+
item_id,
|
|
3447
|
+
badge,
|
|
3448
|
+
badge_tone: tone
|
|
3449
|
+
}, shell_gobj);
|
|
3287
3450
|
}
|
|
3288
3451
|
/************************************************************
|
|
3289
3452
|
* Programmatic close of any open toolbar dropdown. Useful for
|
|
@@ -3887,7 +4050,7 @@ var MOBILE_MAX = 768;
|
|
|
3887
4050
|
***************************************************************/
|
|
3888
4051
|
var attrs_table$21 = [
|
|
3889
4052
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
3890
|
-
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$parent", 0, null, "$container will be appended to $parent if not null, else to document.body"),
|
|
4053
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$parent", 0, null, "$container will be appended to $parent if not null, else to the overlay layer of the shell (document.body when there is none)"),
|
|
3891
4054
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "x", 0, "300", "X position"),
|
|
3892
4055
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "y", 0, "100", "Y position"),
|
|
3893
4056
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_INTEGER, "width", 0, "700", "Width of the window"),
|
|
@@ -4382,8 +4545,8 @@ function build_ui$18(gobj) {
|
|
|
4382
4545
|
}
|
|
4383
4546
|
(0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
|
|
4384
4547
|
let $parent = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$parent");
|
|
4385
|
-
if (
|
|
4386
|
-
|
|
4548
|
+
if (!$parent) $parent = default_parent(gobj);
|
|
4549
|
+
$parent.appendChild($container);
|
|
4387
4550
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "openMaximized")) max$2(gobj);
|
|
4388
4551
|
else if (!mobile) {
|
|
4389
4552
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "content_size")) $container.style.height = "auto";
|
|
@@ -4469,6 +4632,30 @@ function close_window(gobj) {
|
|
|
4469
4632
|
};
|
|
4470
4633
|
}
|
|
4471
4634
|
/************************************************************
|
|
4635
|
+
* Where a window lives when its host names no `$parent`: the
|
|
4636
|
+
* OVERLAY layer of the shell -- above the content, below the
|
|
4637
|
+
* toolbar's dropdowns, the dialogs and the toasts.
|
|
4638
|
+
*
|
|
4639
|
+
* It used to be document.body, and that put every window above
|
|
4640
|
+
* the WHOLE shell: `.yui-shell` is position:fixed, a stacking
|
|
4641
|
+
* context of its own, so the z-index of its modal layer (99)
|
|
4642
|
+
* counted only inside it, and a window at z-index 11 on the body
|
|
4643
|
+
* covered it. The confirmation a window's own close asks ("all
|
|
4644
|
+
* changes will be lost") opened UNDER the window that asked it,
|
|
4645
|
+
* where no click could reach it; a toast, a dropdown of the
|
|
4646
|
+
* toolbar, any dialog opened with a window on screen, the same.
|
|
4647
|
+
*
|
|
4648
|
+
* Inside the layer the dock's z-index still orders the windows
|
|
4649
|
+
* among themselves. No shell (a page with windows and no shell):
|
|
4650
|
+
* the body, as before.
|
|
4651
|
+
************************************************************/
|
|
4652
|
+
function default_parent(gobj) {
|
|
4653
|
+
let shell = yui_shell_of(gobj);
|
|
4654
|
+
let layers = shell && shell.priv && shell.priv.layers;
|
|
4655
|
+
if (layers && layers.overlay) return layers.overlay;
|
|
4656
|
+
return document.body;
|
|
4657
|
+
}
|
|
4658
|
+
/************************************************************
|
|
4472
4659
|
*
|
|
4473
4660
|
************************************************************/
|
|
4474
4661
|
function toggle(gobj) {
|
|
@@ -6571,7 +6758,9 @@ function yui_tabulator_name_filters(table, t) {
|
|
|
6571
6758
|
let $title = $el.querySelector(".tabulator-col-title");
|
|
6572
6759
|
if (!title && $title) title = $title.textContent.trim();
|
|
6573
6760
|
if (!title) continue;
|
|
6574
|
-
|
|
6761
|
+
let name = t("filter by column", { column: title });
|
|
6762
|
+
$input.setAttribute("aria-label", name);
|
|
6763
|
+
$input.setAttribute("title", name);
|
|
6575
6764
|
}
|
|
6576
6765
|
} catch (e) {}
|
|
6577
6766
|
}
|
|
@@ -6602,6 +6791,8 @@ function yui_tabulator_name_row_selects(table, t) {
|
|
|
6602
6791
|
for (let $box of boxes) {
|
|
6603
6792
|
$box.setAttribute("aria-label", t("select row"));
|
|
6604
6793
|
$box.setAttribute("data-i18n-aria-label", "select row");
|
|
6794
|
+
$box.setAttribute("title", t("select row"));
|
|
6795
|
+
$box.setAttribute("data-i18n-title", "select row");
|
|
6605
6796
|
}
|
|
6606
6797
|
} catch (e) {}
|
|
6607
6798
|
}
|
|
@@ -9000,11 +9191,19 @@ function name_form_control$1($field, conf) {
|
|
|
9000
9191
|
$control.setAttribute("aria-label", (0, i18next.t)(key));
|
|
9001
9192
|
$control.setAttribute("data-i18n-aria-label", key);
|
|
9002
9193
|
}
|
|
9194
|
+
if ($control && !$control.getAttribute("title")) {
|
|
9195
|
+
$control.setAttribute("title", (0, i18next.t)(key));
|
|
9196
|
+
$control.setAttribute("data-i18n-title", key);
|
|
9197
|
+
}
|
|
9003
9198
|
let $ts = $field.querySelector(".ts-control input");
|
|
9004
9199
|
if ($ts && !$ts.getAttribute("aria-label")) {
|
|
9005
9200
|
$ts.setAttribute("aria-label", (0, i18next.t)(key));
|
|
9006
9201
|
$ts.setAttribute("data-i18n-aria-label", key);
|
|
9007
9202
|
}
|
|
9203
|
+
if ($ts && !$ts.getAttribute("title")) {
|
|
9204
|
+
$ts.setAttribute("title", (0, i18next.t)(key));
|
|
9205
|
+
$ts.setAttribute("data-i18n-title", key);
|
|
9206
|
+
}
|
|
9008
9207
|
let $clear = $field.querySelector(".ts-wrapper .clear-button");
|
|
9009
9208
|
if ($clear) {
|
|
9010
9209
|
const CLEAR_KEY = "remove all selected options";
|
|
@@ -10094,6 +10293,8 @@ function create_coordinates(gobj, attrs) {
|
|
|
10094
10293
|
type: "text",
|
|
10095
10294
|
placeholder: (0, i18next.t)("coordinates..."),
|
|
10096
10295
|
"data-i18n-placeholder": "coordinates...",
|
|
10296
|
+
title: (0, i18next.t)("coordinates"),
|
|
10297
|
+
"data-i18n-title": "coordinates",
|
|
10097
10298
|
"aria-label": (0, i18next.t)("coordinates"),
|
|
10098
10299
|
"data-i18n-aria-label": "coordinates"
|
|
10099
10300
|
},
|
|
@@ -23365,18 +23566,34 @@ function register_c_yui_service_view() {
|
|
|
23365
23566
|
* contract as every other nav item (data-route/data-item-id/
|
|
23366
23567
|
* data-disabled), so C_YUI_NAV's delegated click handler and
|
|
23367
23568
|
* active-route highlight work unchanged.
|
|
23569
|
+
*
|
|
23570
|
+
* `badge_of(it, pinned)`, optional, answers the description of
|
|
23571
|
+
* the card's badge (C_YUI_NAV's, which knows what was set at
|
|
23572
|
+
* runtime). A card is an icon over its label, so the badge goes
|
|
23573
|
+
* on the corner of the icon (`pinned`), or after the label of a
|
|
23574
|
+
* card that has none. Without it a card has no badge.
|
|
23368
23575
|
************************************************************/
|
|
23369
|
-
function card_descriptor(it, show_label) {
|
|
23576
|
+
function card_descriptor(it, show_label, badge_of) {
|
|
23370
23577
|
let children = [];
|
|
23371
23578
|
let label = it.name || "";
|
|
23372
|
-
|
|
23373
|
-
|
|
23374
|
-
|
|
23375
|
-
["i", {
|
|
23579
|
+
let pinned = !!it.icon;
|
|
23580
|
+
let badge = badge_of ? badge_of(it, pinned) : null;
|
|
23581
|
+
if (it.icon) {
|
|
23582
|
+
let glyph = ["i", {
|
|
23376
23583
|
class: it.icon,
|
|
23377
23584
|
"aria-hidden": "true"
|
|
23378
|
-
}]
|
|
23379
|
-
|
|
23585
|
+
}];
|
|
23586
|
+
if (badge) children.push([
|
|
23587
|
+
"span",
|
|
23588
|
+
{ class: "icon is-medium yui-nav-icon" },
|
|
23589
|
+
[glyph, badge]
|
|
23590
|
+
]);
|
|
23591
|
+
else children.push([
|
|
23592
|
+
"span",
|
|
23593
|
+
{ class: "icon is-medium" },
|
|
23594
|
+
glyph
|
|
23595
|
+
]);
|
|
23596
|
+
}
|
|
23380
23597
|
if (show_label && label) children.push([
|
|
23381
23598
|
"span",
|
|
23382
23599
|
{
|
|
@@ -23385,6 +23602,7 @@ function card_descriptor(it, show_label) {
|
|
|
23385
23602
|
},
|
|
23386
23603
|
text_node(label)
|
|
23387
23604
|
]);
|
|
23605
|
+
if (badge && !pinned) children.push(badge);
|
|
23388
23606
|
let a_attrs = {
|
|
23389
23607
|
class: "yui-nav-item yui-nav-card",
|
|
23390
23608
|
href: it.route ? "#" + it.route : "#",
|
|
@@ -23412,12 +23630,13 @@ function card_descriptor(it, show_label) {
|
|
|
23412
23630
|
/************************************************************
|
|
23413
23631
|
* Descriptor of the whole grid. Decorative items (`header`/
|
|
23414
23632
|
* `divider`) are dropped, same policy as the tabs layout.
|
|
23633
|
+
* `badge_of`: as card_descriptor().
|
|
23415
23634
|
************************************************************/
|
|
23416
|
-
function cards_grid_descriptor(items, show_label) {
|
|
23635
|
+
function cards_grid_descriptor(items, show_label, badge_of) {
|
|
23417
23636
|
let cards = [];
|
|
23418
23637
|
for (let it of items || []) {
|
|
23419
23638
|
if (!it || it.type === "header" || it.type === "divider") continue;
|
|
23420
|
-
cards.push(card_descriptor(it, show_label));
|
|
23639
|
+
cards.push(card_descriptor(it, show_label, badge_of));
|
|
23421
23640
|
}
|
|
23422
23641
|
return [
|
|
23423
23642
|
"div",
|
|
@@ -23462,11 +23681,29 @@ function cards_grid_descriptor(items, show_label) {
|
|
|
23462
23681
|
*
|
|
23463
23682
|
* Each item supports:
|
|
23464
23683
|
* id, name, icon (CSS class or svg id), route, disabled
|
|
23465
|
-
*
|
|
23466
|
-
*
|
|
23467
|
-
*
|
|
23468
|
-
*
|
|
23469
|
-
*
|
|
23684
|
+
* badge — a count, or a short text, carried by the item:
|
|
23685
|
+
* the toolbar badge's rules, helper and live
|
|
23686
|
+
* region (yui_badge.js) -- 0 / "" / null show
|
|
23687
|
+
* none, over 99 reads "99+". It sits on the
|
|
23688
|
+
* corner of the icon where the item is an icon
|
|
23689
|
+
* over its label (icon-bar, cards, a stacked
|
|
23690
|
+
* item) or an icon alone, and after the label
|
|
23691
|
+
* where the item reads as a line (vertical,
|
|
23692
|
+
* drawer, submenu, tabs, an accordion head).
|
|
23693
|
+
* The field only seeds the paint: a count is a
|
|
23694
|
+
* RUNTIME fact, set by
|
|
23695
|
+
* yui_shell_set_nav_item_badge(shell, id, value,
|
|
23696
|
+
* tone), which reaches every nav drawing the id.
|
|
23697
|
+
* Not drawn by "breadcrumb", deliberately: a
|
|
23698
|
+
* crumb names a step of the way in, and the
|
|
23699
|
+
* count belongs to the menu entry that leads
|
|
23700
|
+
* there -- a trail with counts on it reads as a
|
|
23701
|
+
* list of destinations, which is what a
|
|
23702
|
+
* breadcrumb is not. ("backbar" has no items.)
|
|
23703
|
+
* badge_tone — "danger" (the default look), "warning",
|
|
23704
|
+
* "info", "success", "primary" or "link":
|
|
23705
|
+
* Bulma's is-<tone> on the badge. An unknown
|
|
23706
|
+
* one is logged and drawn with the default look.
|
|
23470
23707
|
* class — extra CSS class(es) on the item (tabs layout), e.g.
|
|
23471
23708
|
* a per-item state colour like "yui-nav-disconnected"
|
|
23472
23709
|
* closable — render a trailing ✕ that emits EV_NAV_ITEM_CLOSE
|
|
@@ -23477,6 +23714,13 @@ function cards_grid_descriptor(items, show_label) {
|
|
|
23477
23714
|
* active highlight restored. The app_config path is simply the
|
|
23478
23715
|
* first, startup caller of the same mechanism.
|
|
23479
23716
|
*
|
|
23717
|
+
* One item's badge is set at runtime by sending EV_SET_ITEM_BADGE
|
|
23718
|
+
* {item_id, badge, badge_tone}: painted in place, no rebuild, and
|
|
23719
|
+
* KEPT in the `badges` attr, which wins over the item's own fields
|
|
23720
|
+
* in every later rebuild. The shell sends it to all its navs
|
|
23721
|
+
* (yui_shell_set_nav_item_badge) and hands `badges` to every nav
|
|
23722
|
+
* it creates.
|
|
23723
|
+
*
|
|
23480
23724
|
* In addition to navigable items, secondary navs accept two
|
|
23481
23725
|
* decorative item kinds for in-place visual grouping:
|
|
23482
23726
|
*
|
|
@@ -23524,6 +23768,7 @@ var attrs_table$7 = [
|
|
|
23524
23768
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "level", 0, "primary", "primary|secondary"),
|
|
23525
23769
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "show_on", 0, "", "Breakpoint visibility expr (shell show_on syntax); empty = always"),
|
|
23526
23770
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "back_route", 0, "", "backbar layout: route of the section index the ← returns to"),
|
|
23771
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_DICT, "badges", 0, "{}", "Item id -> {badge, badge_tone} set at runtime (EV_SET_ITEM_BADGE); wins over the item's own fields"),
|
|
23527
23772
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "shell", 0, null, "C_YUI_SHELL gobj (for navigation calls)"),
|
|
23528
23773
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "Root HTMLElement of this nav"),
|
|
23529
23774
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "active_route", 0, "", "Currently active route"),
|
|
@@ -23738,19 +23983,16 @@ function render_tabs(gobj, items) {
|
|
|
23738
23983
|
for (let it of items) {
|
|
23739
23984
|
if (is_decorative(it)) continue;
|
|
23740
23985
|
let children = [];
|
|
23741
|
-
|
|
23742
|
-
|
|
23743
|
-
|
|
23744
|
-
|
|
23745
|
-
|
|
23746
|
-
"aria-hidden": "true"
|
|
23747
|
-
}]
|
|
23748
|
-
]);
|
|
23749
|
-
if (show_label && !(0, _yuneta_gobj_js.empty_string)(it.name)) children.push([
|
|
23986
|
+
let has_label = show_label && !(0, _yuneta_gobj_js.empty_string)(it.name);
|
|
23987
|
+
let pinned = !(0, _yuneta_gobj_js.empty_string)(it.icon) && !has_label;
|
|
23988
|
+
let badge_el = item_badge_node(gobj, it, pinned);
|
|
23989
|
+
if (!(0, _yuneta_gobj_js.empty_string)(it.icon)) children.push(icon_span(it.icon, "icon is-small", pinned ? badge_el : null));
|
|
23990
|
+
if (has_label) children.push([
|
|
23750
23991
|
"span",
|
|
23751
23992
|
{ i18n: it.name },
|
|
23752
23993
|
text_node(it.name)
|
|
23753
23994
|
]);
|
|
23995
|
+
if (!pinned) children.push(badge_el);
|
|
23754
23996
|
if (it.closable) children.push([
|
|
23755
23997
|
"span",
|
|
23756
23998
|
{
|
|
@@ -23808,7 +24050,7 @@ function render_tabs(gobj, items) {
|
|
|
23808
24050
|
}
|
|
23809
24051
|
function render_cards(gobj, items) {
|
|
23810
24052
|
let show_label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "show_label");
|
|
23811
|
-
return (0, _yuneta_gobj_js.createElement2)(cards_grid_descriptor(items, show_label));
|
|
24053
|
+
return (0, _yuneta_gobj_js.createElement2)(cards_grid_descriptor(items, show_label, (it, pinned) => item_badge_node(gobj, it, pinned)));
|
|
23812
24054
|
}
|
|
23813
24055
|
/************************************************************
|
|
23814
24056
|
* "backbar": a single "← <section>" link back to the section
|
|
@@ -23826,6 +24068,9 @@ function render_cards(gobj, items) {
|
|
|
23826
24068
|
* other layout — so the delegated click handler and the active
|
|
23827
24069
|
* highlight work unchanged, and the last crumb marks itself through
|
|
23828
24070
|
* `active_route` like a tab does.
|
|
24071
|
+
*
|
|
24072
|
+
* No badge, deliberately: a crumb names a step of the way in, and a
|
|
24073
|
+
* count belongs to the menu entry that leads there.
|
|
23829
24074
|
************************************************************/
|
|
23830
24075
|
function render_breadcrumb(gobj, items) {
|
|
23831
24076
|
let show_label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "show_label");
|
|
@@ -24004,7 +24249,7 @@ function render_accordion(gobj, items) {
|
|
|
24004
24249
|
let $hdr = (0, _yuneta_gobj_js.createElement2)([
|
|
24005
24250
|
"button",
|
|
24006
24251
|
head_attrs,
|
|
24007
|
-
text_node(head_text)
|
|
24252
|
+
[text_node(head_text), item_badge_node(gobj, it, false)]
|
|
24008
24253
|
]);
|
|
24009
24254
|
$container.appendChild($hdr);
|
|
24010
24255
|
let $ul = (0, _yuneta_gobj_js.createElement2)(["ul", {
|
|
@@ -24051,14 +24296,7 @@ function item_li(gobj, it, opts) {
|
|
|
24051
24296
|
let { icon_pos, show_label, stacked } = opts;
|
|
24052
24297
|
let children = [];
|
|
24053
24298
|
let label = it.name || "";
|
|
24054
|
-
let
|
|
24055
|
-
"span",
|
|
24056
|
-
{ class: "icon" },
|
|
24057
|
-
["i", {
|
|
24058
|
-
class: it.icon,
|
|
24059
|
-
"aria-hidden": "true"
|
|
24060
|
-
}]
|
|
24061
|
-
] : null;
|
|
24299
|
+
let is_stacked = !!(stacked || icon_pos === "top" || icon_pos === "bottom");
|
|
24062
24300
|
let label_el = show_label && !(0, _yuneta_gobj_js.empty_string)(label) ? [
|
|
24063
24301
|
"span",
|
|
24064
24302
|
{
|
|
@@ -24067,14 +24305,19 @@ function item_li(gobj, it, opts) {
|
|
|
24067
24305
|
},
|
|
24068
24306
|
text_node(label)
|
|
24069
24307
|
] : null;
|
|
24308
|
+
let pinned = !(0, _yuneta_gobj_js.empty_string)(it.icon) && (is_stacked || !label_el);
|
|
24309
|
+
let badge_el = item_badge_node(gobj, it, pinned);
|
|
24310
|
+
let icon_el = !(0, _yuneta_gobj_js.empty_string)(it.icon) ? icon_span(it.icon, "icon", pinned ? badge_el : null) : null;
|
|
24070
24311
|
let a_class = "yui-nav-item";
|
|
24071
|
-
if (
|
|
24312
|
+
if (is_stacked) a_class += " yui-nav-stacked";
|
|
24072
24313
|
if (icon_pos === "right" || icon_pos === "bottom") {
|
|
24073
24314
|
if (label_el) children.push(label_el);
|
|
24315
|
+
if (!pinned) children.push(badge_el);
|
|
24074
24316
|
if (icon_el) children.push(icon_el);
|
|
24075
24317
|
} else {
|
|
24076
24318
|
if (icon_el) children.push(icon_el);
|
|
24077
24319
|
if (label_el) children.push(label_el);
|
|
24320
|
+
if (!pinned) children.push(badge_el);
|
|
24078
24321
|
}
|
|
24079
24322
|
let aria_key = label || it.id;
|
|
24080
24323
|
let a_attrs = {
|
|
@@ -24108,14 +24351,9 @@ function item_li(gobj, it, opts) {
|
|
|
24108
24351
|
function item_iconbar(gobj, it, opts) {
|
|
24109
24352
|
let { icon_pos, show_label } = opts;
|
|
24110
24353
|
let label = it.name || "";
|
|
24111
|
-
let
|
|
24112
|
-
|
|
24113
|
-
|
|
24114
|
-
["i", {
|
|
24115
|
-
class: it.icon,
|
|
24116
|
-
"aria-hidden": "true"
|
|
24117
|
-
}]
|
|
24118
|
-
] : null;
|
|
24354
|
+
let pinned = !(0, _yuneta_gobj_js.empty_string)(it.icon);
|
|
24355
|
+
let badge_el = item_badge_node(gobj, it, pinned);
|
|
24356
|
+
let icon_el = pinned ? icon_span(it.icon, "icon is-medium", badge_el) : null;
|
|
24119
24357
|
let label_el = show_label && !(0, _yuneta_gobj_js.empty_string)(label) ? [
|
|
24120
24358
|
"span",
|
|
24121
24359
|
{
|
|
@@ -24132,6 +24370,7 @@ function item_iconbar(gobj, it, opts) {
|
|
|
24132
24370
|
if (icon_el) children.push(icon_el);
|
|
24133
24371
|
if (label_el) children.push(label_el);
|
|
24134
24372
|
}
|
|
24373
|
+
if (!pinned) children.push(badge_el);
|
|
24135
24374
|
let a_attrs = {
|
|
24136
24375
|
class: "yui-nav-item yui-nav-stacked",
|
|
24137
24376
|
href: it.route ? "#" + it.route : "#",
|
|
@@ -24155,6 +24394,40 @@ function item_iconbar(gobj, it, opts) {
|
|
|
24155
24394
|
]
|
|
24156
24395
|
];
|
|
24157
24396
|
}
|
|
24397
|
+
/************************************************************
|
|
24398
|
+
* The badge of an item (yui_badge.js), always drawn -- hidden
|
|
24399
|
+
* when empty -- so EV_SET_ITEM_BADGE has a node to write into.
|
|
24400
|
+
* What was set at runtime for its id (`badges`) wins over the
|
|
24401
|
+
* item's own `badge` / `badge_tone`. `pinned`: on the corner of
|
|
24402
|
+
* the icon instead of after the label.
|
|
24403
|
+
************************************************************/
|
|
24404
|
+
function item_badge_node(gobj, it, pinned) {
|
|
24405
|
+
let badges = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "badges");
|
|
24406
|
+
let state = it;
|
|
24407
|
+
if ((0, _yuneta_gobj_js.is_object)(badges) && (0, _yuneta_gobj_js.is_string)(it.id) && Object.prototype.hasOwnProperty.call(badges, it.id)) state = badges[it.id] || {};
|
|
24408
|
+
let classes = "NAV_ITEM_BADGE yui-badge yui-nav-badge";
|
|
24409
|
+
if (pinned) classes += " yui-nav-badge-pinned";
|
|
24410
|
+
return badge_node(state.badge, state.badge_tone, classes, `C_YUI_NAV '${(0, _yuneta_gobj_js.gobj_read_attr)(gobj, "menu_id") || ""}': item '${it.id}'`);
|
|
24411
|
+
}
|
|
24412
|
+
/************************************************************
|
|
24413
|
+
* An item's icon, with its badge on the corner when given one.
|
|
24414
|
+
************************************************************/
|
|
24415
|
+
function icon_span(icon, classes, badge_el) {
|
|
24416
|
+
let glyph = ["i", {
|
|
24417
|
+
class: icon,
|
|
24418
|
+
"aria-hidden": "true"
|
|
24419
|
+
}];
|
|
24420
|
+
if (!badge_el) return [
|
|
24421
|
+
"span",
|
|
24422
|
+
{ class: classes },
|
|
24423
|
+
glyph
|
|
24424
|
+
];
|
|
24425
|
+
return [
|
|
24426
|
+
"span",
|
|
24427
|
+
{ class: `${classes} yui-nav-icon` },
|
|
24428
|
+
[glyph, badge_el]
|
|
24429
|
+
];
|
|
24430
|
+
}
|
|
24158
24431
|
function wire_clicks(gobj, $container) {
|
|
24159
24432
|
let priv = gobj.priv;
|
|
24160
24433
|
let handler = (ev) => {
|
|
@@ -24231,6 +24504,36 @@ function ac_set_items(gobj, event, kw, src) {
|
|
|
24231
24504
|
return 0;
|
|
24232
24505
|
}
|
|
24233
24506
|
/************************************************************
|
|
24507
|
+
* EV_SET_ITEM_BADGE {item_id, badge, badge_tone} — the badge of
|
|
24508
|
+
* one item, set at runtime (yui_shell_set_nav_item_badge).
|
|
24509
|
+
*
|
|
24510
|
+
* Kept in `badges`, so every later rebuild draws it, and painted
|
|
24511
|
+
* in place: no rebuild for a count that moves on every tick. An
|
|
24512
|
+
* id this nav does not draw is kept all the same — a later
|
|
24513
|
+
* EV_SET_ITEMS may bring the item.
|
|
24514
|
+
************************************************************/
|
|
24515
|
+
function ac_set_item_badge(gobj, event, kw, src) {
|
|
24516
|
+
let item_id = kw.item_id;
|
|
24517
|
+
if ((0, _yuneta_gobj_js.empty_string)(item_id)) {
|
|
24518
|
+
(0, _yuneta_gobj_js.log_error)(`C_YUI_NAV: ${event} without item_id, from ${(0, _yuneta_gobj_js.gobj_short_name)(src)}`);
|
|
24519
|
+
return -1;
|
|
24520
|
+
}
|
|
24521
|
+
let menu_id = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "menu_id") || "";
|
|
24522
|
+
let tone = badge_tone(kw.badge_tone, `C_YUI_NAV '${menu_id}': item '${item_id}'`);
|
|
24523
|
+
let badge = kw.badge === void 0 ? null : kw.badge;
|
|
24524
|
+
let badges = Object.assign({}, (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "badges"));
|
|
24525
|
+
badges[item_id] = {
|
|
24526
|
+
badge,
|
|
24527
|
+
badge_tone: tone
|
|
24528
|
+
};
|
|
24529
|
+
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "badges", badges);
|
|
24530
|
+
let $c = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
24531
|
+
if (!$c) return 0;
|
|
24532
|
+
let $badges = $c.querySelectorAll(`[data-item-id="${css_escape(item_id)}"] .NAV_ITEM_BADGE`);
|
|
24533
|
+
for (let $badge of $badges) paint_badge($badge, badge, tone);
|
|
24534
|
+
return 0;
|
|
24535
|
+
}
|
|
24536
|
+
/************************************************************
|
|
24234
24537
|
* EV_ROUTE_CHANGED from the shell — refresh active highlight
|
|
24235
24538
|
************************************************************/
|
|
24236
24539
|
function ac_route_changed(gobj, event, kw, src) {
|
|
@@ -24286,18 +24589,27 @@ function create_gclass$7(gclass_name) {
|
|
|
24286
24589
|
(0, _yuneta_gobj_js.log_error)(`GClass ALREADY created: ${gclass_name}`);
|
|
24287
24590
|
return -1;
|
|
24288
24591
|
}
|
|
24289
|
-
const states = [["ST_IDLE", [
|
|
24290
|
-
|
|
24291
|
-
|
|
24292
|
-
|
|
24293
|
-
|
|
24294
|
-
|
|
24295
|
-
|
|
24296
|
-
|
|
24297
|
-
|
|
24592
|
+
const states = [["ST_IDLE", [
|
|
24593
|
+
[
|
|
24594
|
+
"EV_ROUTE_CHANGED",
|
|
24595
|
+
ac_route_changed,
|
|
24596
|
+
null
|
|
24597
|
+
],
|
|
24598
|
+
[
|
|
24599
|
+
"EV_SET_ITEMS",
|
|
24600
|
+
ac_set_items,
|
|
24601
|
+
null
|
|
24602
|
+
],
|
|
24603
|
+
[
|
|
24604
|
+
"EV_SET_ITEM_BADGE",
|
|
24605
|
+
ac_set_item_badge,
|
|
24606
|
+
null
|
|
24607
|
+
]
|
|
24608
|
+
]]];
|
|
24298
24609
|
const event_types = [
|
|
24299
24610
|
["EV_ROUTE_CHANGED", 0],
|
|
24300
24611
|
["EV_SET_ITEMS", 0],
|
|
24612
|
+
["EV_SET_ITEM_BADGE", 0],
|
|
24301
24613
|
["EV_NAV_CLICKED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_PUBLIC_EVENT],
|
|
24302
24614
|
["EV_NAV_ITEM_CLOSE", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_PUBLIC_EVENT],
|
|
24303
24615
|
["EV_DRAWER_CLOSE_REQUESTED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_PUBLIC_EVENT]
|
|
@@ -83309,6 +83621,7 @@ exports.yui_shell_register_event_handler = yui_shell_register_event_handler;
|
|
|
83309
83621
|
exports.yui_shell_register_overlay = yui_shell_register_overlay;
|
|
83310
83622
|
exports.yui_shell_set_avatar_provider = yui_shell_set_avatar_provider;
|
|
83311
83623
|
exports.yui_shell_set_connection_state = yui_shell_set_connection_state;
|
|
83624
|
+
exports.yui_shell_set_nav_item_badge = yui_shell_set_nav_item_badge;
|
|
83312
83625
|
exports.yui_shell_set_sub_routes = yui_shell_set_sub_routes;
|
|
83313
83626
|
exports.yui_shell_set_toolbar_item_badge = yui_shell_set_toolbar_item_badge;
|
|
83314
83627
|
exports.yui_shell_set_toolbar_item_icon = yui_shell_set_toolbar_item_icon;
|