@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/src/c_yui_shell.js
CHANGED
|
@@ -65,6 +65,7 @@ import {
|
|
|
65
65
|
|
|
66
66
|
import { resolve_route, normalize_route } from "./route_resolver.js";
|
|
67
67
|
import { text_node } from "./yui_text.js";
|
|
68
|
+
import { badge_node, badge_tone, paint_badge } from "./yui_badge.js";
|
|
68
69
|
import { build_nav_map } from "./route_map_model.js";
|
|
69
70
|
import {
|
|
70
71
|
section_index_target,
|
|
@@ -118,6 +119,14 @@ let PRIVATE_DATA = {
|
|
|
118
119
|
stages: {},
|
|
119
120
|
navs: [],
|
|
120
121
|
item_index: {},
|
|
122
|
+
/* Menu item id -> {badge, badge_tone}: what yui_shell_set_nav_item_badge()
|
|
123
|
+
* said last for that id. It wins over the item's own `badge`, and
|
|
124
|
+
* every nav the shell creates is handed it (`badges`), so a nav built
|
|
125
|
+
* or rebuilt after the call draws it too. */
|
|
126
|
+
nav_badges: {},
|
|
127
|
+
/* Parent item id -> the items yui_shell_set_submenu() put in place:
|
|
128
|
+
* menu items as much as the declared ones (nav_item_declared). */
|
|
129
|
+
dynamic_items: {},
|
|
121
130
|
/* Section route -> last position visited inside it. Mirrors the
|
|
122
131
|
* url for the duration of the page; see remember_position(). */
|
|
123
132
|
section_pos: {},
|
|
@@ -1243,6 +1252,7 @@ function instantiate_nav_in_zone(gobj, menu, menu_id, zone_id, level, nav_label)
|
|
|
1243
1252
|
level: level,
|
|
1244
1253
|
show_on: render_cfg.show_on || "",
|
|
1245
1254
|
back_route: render_cfg.back_route || "",
|
|
1255
|
+
badges: Object.assign({}, priv.nav_badges),
|
|
1246
1256
|
shell: gobj
|
|
1247
1257
|
},
|
|
1248
1258
|
gobj
|
|
@@ -1694,6 +1704,7 @@ function navigate_to(gobj, route, depth, no_drain)
|
|
|
1694
1704
|
|
|
1695
1705
|
function build_view_gobj(gobj, entry, route, stage)
|
|
1696
1706
|
{
|
|
1707
|
+
let priv = gobj.priv;
|
|
1697
1708
|
let target = entry.target;
|
|
1698
1709
|
/* The deep-link tail is NOT injected into kw: gobj_create2
|
|
1699
1710
|
* validates kw against the view's SDATA strictly, so an extra
|
|
@@ -1702,6 +1713,11 @@ function build_view_gobj(gobj, entry, route, stage)
|
|
|
1702
1713
|
* mount (and on every later subpath-only change) — that single
|
|
1703
1714
|
* mechanism is how a view owns its dynamic 3rd level. */
|
|
1704
1715
|
let kw = target.kw || {};
|
|
1716
|
+
if(target.gclass === "C_YUI_NAV") {
|
|
1717
|
+
/* A section-index landing is a nav of the shell, mounted when
|
|
1718
|
+
* the user first walks into it: it draws the badges set before. */
|
|
1719
|
+
kw = Object.assign({}, kw, {badges: Object.assign({}, priv.nav_badges)});
|
|
1720
|
+
}
|
|
1705
1721
|
let name = target.name || `view_${safe_id(route)}`;
|
|
1706
1722
|
|
|
1707
1723
|
let view;
|
|
@@ -1848,51 +1864,6 @@ function build_toolbar(gobj, config)
|
|
|
1848
1864
|
$zone.appendChild($bar);
|
|
1849
1865
|
}
|
|
1850
1866
|
|
|
1851
|
-
/************************************************************
|
|
1852
|
-
* The badge node of a toolbar item — the little count pinned to
|
|
1853
|
-
* the corner of its icon (unread notifications, active alarms).
|
|
1854
|
-
*
|
|
1855
|
-
* ALWAYS rendered, hidden when empty, so the runtime setter has a
|
|
1856
|
-
* node to write into and does not have to rebuild the button.
|
|
1857
|
-
*
|
|
1858
|
-
* EMPTY IS 0, "" AND null ALIKE: a badge reading "0" is worse than
|
|
1859
|
-
* no badge — it draws the eye to say nothing. A count is only
|
|
1860
|
-
* worth a pixel when there IS something.
|
|
1861
|
-
*
|
|
1862
|
-
* Capped at 99+: the toolbar is a fixed-width row, and a four
|
|
1863
|
-
* digit pill pushes the items next to it off a phone screen.
|
|
1864
|
-
*
|
|
1865
|
-
* role="status" and NOT aria-hidden, deliberately. The button
|
|
1866
|
-
* carries an explicit aria-label, and an explicit label REPLACES
|
|
1867
|
-
* the element's content for a screen reader — so a badge inside
|
|
1868
|
-
* it would be silent. As its own live region it is both read and
|
|
1869
|
-
* announced when the count changes, which is the whole point of a
|
|
1870
|
-
* badge that means "something needs you".
|
|
1871
|
-
************************************************************/
|
|
1872
|
-
function badge_text(value)
|
|
1873
|
-
{
|
|
1874
|
-
if(value === null || value === undefined || value === false) {
|
|
1875
|
-
return "";
|
|
1876
|
-
}
|
|
1877
|
-
if(typeof value === "number") {
|
|
1878
|
-
if(!isFinite(value) || value <= 0) {
|
|
1879
|
-
return "";
|
|
1880
|
-
}
|
|
1881
|
-
return (value > 99) ? "99+" : String(Math.floor(value));
|
|
1882
|
-
}
|
|
1883
|
-
return String(value).trim();
|
|
1884
|
-
}
|
|
1885
|
-
|
|
1886
|
-
function badge_node(value)
|
|
1887
|
-
{
|
|
1888
|
-
let text = badge_text(value);
|
|
1889
|
-
let attrs = {class: "yui-toolbar-badge", role: "status"};
|
|
1890
|
-
if(!text) {
|
|
1891
|
-
attrs.hidden = "hidden";
|
|
1892
|
-
}
|
|
1893
|
-
return ["span", attrs, text];
|
|
1894
|
-
}
|
|
1895
|
-
|
|
1896
1867
|
/************************************************************
|
|
1897
1868
|
* The attributes that turn a toolbar item into a real link, or
|
|
1898
1869
|
* null when this item is not one. Answering null is what keeps
|
|
@@ -1931,11 +1902,14 @@ function build_toolbar_action_item(gobj, it)
|
|
|
1931
1902
|
if(!empty_string(it.icon)) {
|
|
1932
1903
|
/* The badge is anchored to the ICON, not to the button: with a
|
|
1933
1904
|
* label on (desktop) the button is wide, and a badge pinned to
|
|
1934
|
-
* its corner would float far from the glyph it counts.
|
|
1905
|
+
* its corner would float far from the glyph it counts. The
|
|
1906
|
+
* count, its tone and their rules: yui_badge.js. */
|
|
1935
1907
|
children.push(["span", {class: "icon yui-toolbar-icon"},
|
|
1936
1908
|
[
|
|
1937
1909
|
["i", {class: it.icon, "aria-hidden": "true"}],
|
|
1938
|
-
badge_node(it.badge
|
|
1910
|
+
badge_node(it.badge, it.badge_tone,
|
|
1911
|
+
"TOOLBAR_ITEM_BADGE yui-badge yui-toolbar-badge",
|
|
1912
|
+
`C_YUI_SHELL: toolbar item '${it.id || "?"}'`)
|
|
1939
1913
|
]
|
|
1940
1914
|
]);
|
|
1941
1915
|
}
|
|
@@ -3220,6 +3194,60 @@ function update_secondary_nav_visibility(gobj, entry)
|
|
|
3220
3194
|
}
|
|
3221
3195
|
}
|
|
3222
3196
|
|
|
3197
|
+
/************************************************************
|
|
3198
|
+
* Does a menu of this shell declare an item `item_id`: an item
|
|
3199
|
+
* of a menu of app_config.json, of one of their submenus, or
|
|
3200
|
+
* one given to yui_shell_set_submenu() since.
|
|
3201
|
+
************************************************************/
|
|
3202
|
+
function nav_item_declared(gobj, item_id)
|
|
3203
|
+
{
|
|
3204
|
+
let priv = gobj.priv;
|
|
3205
|
+
let config = gobj_read_attr(gobj, "config") || {};
|
|
3206
|
+
let menus = is_object(config.menu) ? config.menu : {};
|
|
3207
|
+
let holds = (items) => is_array(items) && items.some((it) => it && it.id === item_id);
|
|
3208
|
+
|
|
3209
|
+
for(let menu_id in menus) {
|
|
3210
|
+
let items = menus[menu_id] && menus[menu_id].items;
|
|
3211
|
+
if(!is_array(items)) {
|
|
3212
|
+
continue;
|
|
3213
|
+
}
|
|
3214
|
+
if(holds(items)) {
|
|
3215
|
+
return true;
|
|
3216
|
+
}
|
|
3217
|
+
for(let it of items) {
|
|
3218
|
+
if(it && it.submenu && holds(it.submenu.items)) {
|
|
3219
|
+
return true;
|
|
3220
|
+
}
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
for(let parent_item_id in priv.dynamic_items) {
|
|
3224
|
+
if(holds(priv.dynamic_items[parent_item_id])) {
|
|
3225
|
+
return true;
|
|
3226
|
+
}
|
|
3227
|
+
}
|
|
3228
|
+
return false;
|
|
3229
|
+
}
|
|
3230
|
+
|
|
3231
|
+
/************************************************************
|
|
3232
|
+
* Every C_YUI_NAV of this shell: the navs of its menus, and the
|
|
3233
|
+
* section-index landings mounted in a stage.
|
|
3234
|
+
************************************************************/
|
|
3235
|
+
function shell_navs(gobj)
|
|
3236
|
+
{
|
|
3237
|
+
let priv = gobj.priv;
|
|
3238
|
+
let navs = priv.navs.slice();
|
|
3239
|
+
for(let stage_name in priv.stages) {
|
|
3240
|
+
let views = priv.stages[stage_name].items || {};
|
|
3241
|
+
for(let route in views) {
|
|
3242
|
+
let view = views[route];
|
|
3243
|
+
if(view && gobj_gclass_name(view) === "C_YUI_NAV") {
|
|
3244
|
+
navs.push(view);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
return navs;
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3223
3251
|
|
|
3224
3252
|
|
|
3225
3253
|
|
|
@@ -3349,8 +3377,11 @@ function ac_nav_item_close(gobj, event, kw, src)
|
|
|
3349
3377
|
* items of a primary item's submenu (its secondary nav) at runtime
|
|
3350
3378
|
* and re-registers their routes so navigation resolves. Item
|
|
3351
3379
|
* descriptors may carry { id, name, icon, route, class, closable,
|
|
3352
|
-
* target:{stage,gclass,kw,lifecycle} }. Routes
|
|
3353
|
-
* absent now are pruned (index entry removed,
|
|
3380
|
+
* badge, badge_tone, target:{stage,gclass,kw,lifecycle} }. Routes
|
|
3381
|
+
* present before but absent now are pruned (index entry removed,
|
|
3382
|
+
* mounted view destroyed). A badge set with
|
|
3383
|
+
* yui_shell_set_nav_item_badge() for an id stays on that id here too:
|
|
3384
|
+
* the rebuilt nav draws it, whatever the descriptor's own `badge`.
|
|
3354
3385
|
************************************************************/
|
|
3355
3386
|
function find_secondary_nav(priv, parent_item_id)
|
|
3356
3387
|
{
|
|
@@ -3471,6 +3502,7 @@ function yui_shell_set_submenu(shell_gobj, parent_item_id, items)
|
|
|
3471
3502
|
};
|
|
3472
3503
|
}
|
|
3473
3504
|
priv.dynamic_routes[parent_item_id] = new_routes;
|
|
3505
|
+
priv.dynamic_items[parent_item_id] = items;
|
|
3474
3506
|
|
|
3475
3507
|
/* Push the new items into the nav (rebuilds its DOM in place), and
|
|
3476
3508
|
* re-apply the translator: the rebuilt labels carry their keys as
|
|
@@ -4233,22 +4265,31 @@ function yui_shell_set_toolbar_item_icon(shell_gobj, item_id, icon_class)
|
|
|
4233
4265
|
* its icon.
|
|
4234
4266
|
*
|
|
4235
4267
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3);
|
|
4268
|
+
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3, "warning");
|
|
4236
4269
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 0); // hidden
|
|
4237
4270
|
*
|
|
4238
4271
|
* This is the API that matters: a count is a RUNTIME fact. The
|
|
4239
|
-
* `badge`
|
|
4240
|
-
* an app whose number never changes did not need
|
|
4272
|
+
* `badge` / `badge_tone` fields of a toolbar item only seed the
|
|
4273
|
+
* first paint, and an app whose number never changes did not need
|
|
4274
|
+
* a badge.
|
|
4241
4275
|
*
|
|
4242
4276
|
* 0 / "" / null / false all clear it, and a number over 99 renders
|
|
4243
|
-
* "99+" — see
|
|
4244
|
-
* are not counts ("!", "…").
|
|
4277
|
+
* "99+" — see yui_badge.js. Accepts a string for the states that
|
|
4278
|
+
* are not counts ("!", "…"). `tone`, optional, is one of
|
|
4279
|
+
* BADGE_TONES ("danger" | "warning" | "info" | "success" |
|
|
4280
|
+
* "primary" | "link"): Bulma's is-<tone> on the badge. Each call
|
|
4281
|
+
* states the WHOLE badge: no tone is the default look, not the
|
|
4282
|
+
* tone it had. The twin of yui_shell_set_nav_item_badge().
|
|
4245
4283
|
*
|
|
4246
4284
|
* Silent no-op on an unknown item id: a toolbar that does not
|
|
4247
4285
|
* declare the item (an app without alarms) must not be an error
|
|
4248
|
-
* at every tick of whatever feeds the number.
|
|
4286
|
+
* at every tick of whatever feeds the number. An unknown TONE is
|
|
4287
|
+
* the caller's error: logged, and drawn with the default look.
|
|
4249
4288
|
************************************************************/
|
|
4250
|
-
function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value)
|
|
4289
|
+
function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value, tone)
|
|
4251
4290
|
{
|
|
4291
|
+
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_toolbar_item_badge('${item_id}')`);
|
|
4292
|
+
|
|
4252
4293
|
if(!shell_gobj || !is_gobj(shell_gobj) || empty_string(item_id)) {
|
|
4253
4294
|
return;
|
|
4254
4295
|
}
|
|
@@ -4262,21 +4303,59 @@ function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value)
|
|
|
4262
4303
|
if(!$badge) {
|
|
4263
4304
|
return;
|
|
4264
4305
|
}
|
|
4306
|
+
paint_badge($badge, value, tone);
|
|
4307
|
+
}
|
|
4265
4308
|
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4309
|
+
/************************************************************
|
|
4310
|
+
* Set (or clear) the badge of a MENU item — the twin of
|
|
4311
|
+
* yui_shell_set_toolbar_item_badge(), for an entry of a menu of
|
|
4312
|
+
* app_config.json, of one of their submenus, or one given to
|
|
4313
|
+
* yui_shell_set_submenu().
|
|
4314
|
+
*
|
|
4315
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 3);
|
|
4316
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 3, "warning");
|
|
4317
|
+
* yui_shell_set_nav_item_badge(shell, "alarms", 0); // hidden
|
|
4318
|
+
*
|
|
4319
|
+
* The same value, tone and rules as the toolbar's (yui_badge.js),
|
|
4320
|
+
* each call stating the whole badge.
|
|
4321
|
+
*
|
|
4322
|
+
* EVERY instance of the item gets it: the same entry is drawn by
|
|
4323
|
+
* as many navs as there are zones hosting its menu (a rail on
|
|
4324
|
+
* desktop, an icon bar on a phone), and by a drawer that repeats
|
|
4325
|
+
* it. Each nav repaints it in place (EV_SET_ITEM_BADGE), and
|
|
4326
|
+
* KEEPS it: a rebuild of the nav (a yui_shell_set_submenu()) draws
|
|
4327
|
+
* it again. The shell keeps it too, for the navs it creates
|
|
4328
|
+
* afterwards (a section-index landing, mounted when the user walks
|
|
4329
|
+
* into it). From then on it is the badge of that id: the `badge`
|
|
4330
|
+
* field of an item only seeds the paint until this is called.
|
|
4331
|
+
*
|
|
4332
|
+
* Silent no-op on an id no menu declares, as the toolbar's: a menu
|
|
4333
|
+
* without the entry (an app without alarms) must not be an error
|
|
4334
|
+
* at every tick of whatever feeds the number. An unknown TONE is
|
|
4335
|
+
* the caller's error: logged, and drawn with the default look.
|
|
4336
|
+
************************************************************/
|
|
4337
|
+
function yui_shell_set_nav_item_badge(shell_gobj, item_id, value, tone)
|
|
4338
|
+
{
|
|
4339
|
+
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_nav_item_badge('${item_id}')`);
|
|
4340
|
+
|
|
4341
|
+
/* Silent, as the toolbar's: whatever feeds the number may tick
|
|
4342
|
+
* before the shell exists, after it is gone, and in an app whose
|
|
4343
|
+
* menus have no such entry. */
|
|
4344
|
+
if(!shell_gobj || !is_gobj(shell_gobj) || gobj_is_destroying(shell_gobj) ||
|
|
4345
|
+
empty_string(item_id)) {
|
|
4270
4346
|
return;
|
|
4271
4347
|
}
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
* reader announce it again on every tick. */
|
|
4275
|
-
if($badge.textContent === text && !$badge.hasAttribute("hidden")) {
|
|
4348
|
+
let priv = shell_gobj.priv;
|
|
4349
|
+
if(!priv || !nav_item_declared(shell_gobj, item_id)) {
|
|
4276
4350
|
return;
|
|
4277
4351
|
}
|
|
4278
|
-
|
|
4279
|
-
|
|
4352
|
+
let badge = (value === undefined) ? null : value;
|
|
4353
|
+
priv.nav_badges[item_id] = {badge: badge, badge_tone: tone};
|
|
4354
|
+
|
|
4355
|
+
for(let nav of shell_navs(shell_gobj)) {
|
|
4356
|
+
gobj_send_event(nav, "EV_SET_ITEM_BADGE",
|
|
4357
|
+
{item_id: item_id, badge: badge, badge_tone: tone}, shell_gobj);
|
|
4358
|
+
}
|
|
4280
4359
|
}
|
|
4281
4360
|
|
|
4282
4361
|
/************************************************************
|
|
@@ -4330,6 +4409,7 @@ export {
|
|
|
4330
4409
|
yui_shell_set_connection_state,
|
|
4331
4410
|
yui_shell_set_toolbar_item_icon,
|
|
4332
4411
|
yui_shell_set_toolbar_item_badge,
|
|
4412
|
+
yui_shell_set_nav_item_badge,
|
|
4333
4413
|
yui_shell_close_dropdown,
|
|
4334
4414
|
yui_shell_set_submenu
|
|
4335
4415
|
};
|
package/src/c_yui_window.js
CHANGED
|
@@ -81,7 +81,7 @@ const MOBILE_MAX = 768;
|
|
|
81
81
|
***************************************************************/
|
|
82
82
|
const attrs_table = [
|
|
83
83
|
SDATA(data_type_t.DTP_POINTER, "subscriber", 0, null, "Subscriber of output events"),
|
|
84
|
-
SDATA(data_type_t.DTP_POINTER, "$parent", 0, null, "$container will be appended to $parent if not null, else to document.body"),
|
|
84
|
+
SDATA(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)"),
|
|
85
85
|
SDATA(data_type_t.DTP_INTEGER, "x", 0, "300", "X position"),
|
|
86
86
|
SDATA(data_type_t.DTP_INTEGER, "y", 0, "100", "Y position"),
|
|
87
87
|
SDATA(data_type_t.DTP_INTEGER, "width", 0, "700", "Width of the window"),
|
|
@@ -724,11 +724,10 @@ function build_ui(gobj)
|
|
|
724
724
|
refresh_language($container, t);
|
|
725
725
|
|
|
726
726
|
let $parent = gobj_read_attr(gobj, "$parent");
|
|
727
|
-
if(
|
|
728
|
-
$parent
|
|
729
|
-
} else {
|
|
730
|
-
document.body.appendChild($container);
|
|
727
|
+
if(!$parent) {
|
|
728
|
+
$parent = default_parent(gobj);
|
|
731
729
|
}
|
|
730
|
+
$parent.appendChild($container);
|
|
732
731
|
|
|
733
732
|
if (gobj_read_bool_attr(gobj, "openMaximized")) {
|
|
734
733
|
max(gobj);
|
|
@@ -860,6 +859,34 @@ function close_window(gobj)
|
|
|
860
859
|
return {state: "asking", answer: answer};
|
|
861
860
|
}
|
|
862
861
|
|
|
862
|
+
/************************************************************
|
|
863
|
+
* Where a window lives when its host names no `$parent`: the
|
|
864
|
+
* OVERLAY layer of the shell -- above the content, below the
|
|
865
|
+
* toolbar's dropdowns, the dialogs and the toasts.
|
|
866
|
+
*
|
|
867
|
+
* It used to be document.body, and that put every window above
|
|
868
|
+
* the WHOLE shell: `.yui-shell` is position:fixed, a stacking
|
|
869
|
+
* context of its own, so the z-index of its modal layer (99)
|
|
870
|
+
* counted only inside it, and a window at z-index 11 on the body
|
|
871
|
+
* covered it. The confirmation a window's own close asks ("all
|
|
872
|
+
* changes will be lost") opened UNDER the window that asked it,
|
|
873
|
+
* where no click could reach it; a toast, a dropdown of the
|
|
874
|
+
* toolbar, any dialog opened with a window on screen, the same.
|
|
875
|
+
*
|
|
876
|
+
* Inside the layer the dock's z-index still orders the windows
|
|
877
|
+
* among themselves. No shell (a page with windows and no shell):
|
|
878
|
+
* the body, as before.
|
|
879
|
+
************************************************************/
|
|
880
|
+
function default_parent(gobj)
|
|
881
|
+
{
|
|
882
|
+
let shell = yui_shell_of(gobj);
|
|
883
|
+
let layers = shell && shell.priv && shell.priv.layers;
|
|
884
|
+
if(layers && layers.overlay) {
|
|
885
|
+
return layers.overlay;
|
|
886
|
+
}
|
|
887
|
+
return document.body;
|
|
888
|
+
}
|
|
889
|
+
|
|
863
890
|
/************************************************************
|
|
864
891
|
*
|
|
865
892
|
************************************************************/
|
package/src/nav_cards_helpers.js
CHANGED
|
@@ -18,19 +18,34 @@ import {text_node} from "./yui_text.js";
|
|
|
18
18
|
* contract as every other nav item (data-route/data-item-id/
|
|
19
19
|
* data-disabled), so C_YUI_NAV's delegated click handler and
|
|
20
20
|
* active-route highlight work unchanged.
|
|
21
|
+
*
|
|
22
|
+
* `badge_of(it, pinned)`, optional, answers the description of
|
|
23
|
+
* the card's badge (C_YUI_NAV's, which knows what was set at
|
|
24
|
+
* runtime). A card is an icon over its label, so the badge goes
|
|
25
|
+
* on the corner of the icon (`pinned`), or after the label of a
|
|
26
|
+
* card that has none. Without it a card has no badge.
|
|
21
27
|
************************************************************/
|
|
22
|
-
export function card_descriptor(it, show_label)
|
|
28
|
+
export function card_descriptor(it, show_label, badge_of)
|
|
23
29
|
{
|
|
24
30
|
let children = [];
|
|
25
31
|
let label = it.name || "";
|
|
32
|
+
let pinned = !!it.icon;
|
|
33
|
+
let badge = badge_of ? badge_of(it, pinned) : null;
|
|
26
34
|
|
|
27
35
|
if(it.icon) {
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
let glyph = ["i", {class: it.icon, "aria-hidden": "true"}];
|
|
37
|
+
if(badge) {
|
|
38
|
+
children.push(["span", {class: "icon is-medium yui-nav-icon"}, [glyph, badge]]);
|
|
39
|
+
} else {
|
|
40
|
+
children.push(["span", {class: "icon is-medium"}, glyph]);
|
|
41
|
+
}
|
|
30
42
|
}
|
|
31
43
|
if(show_label && label) {
|
|
32
44
|
children.push(["span", {class: "yui-nav-label", i18n: label}, text_node(label)]);
|
|
33
45
|
}
|
|
46
|
+
if(badge && !pinned) {
|
|
47
|
+
children.push(badge);
|
|
48
|
+
}
|
|
34
49
|
|
|
35
50
|
let a_attrs = {
|
|
36
51
|
class: "yui-nav-item yui-nav-card",
|
|
@@ -58,15 +73,16 @@ export function card_descriptor(it, show_label)
|
|
|
58
73
|
/************************************************************
|
|
59
74
|
* Descriptor of the whole grid. Decorative items (`header`/
|
|
60
75
|
* `divider`) are dropped, same policy as the tabs layout.
|
|
76
|
+
* `badge_of`: as card_descriptor().
|
|
61
77
|
************************************************************/
|
|
62
|
-
export function cards_grid_descriptor(items, show_label)
|
|
78
|
+
export function cards_grid_descriptor(items, show_label, badge_of)
|
|
63
79
|
{
|
|
64
80
|
let cards = [];
|
|
65
81
|
for(let it of (items || [])) {
|
|
66
82
|
if(!it || it.type === "header" || it.type === "divider") {
|
|
67
83
|
continue;
|
|
68
84
|
}
|
|
69
|
-
cards.push(card_descriptor(it, show_label));
|
|
85
|
+
cards.push(card_descriptor(it, show_label, badge_of));
|
|
70
86
|
}
|
|
71
87
|
return ["div", {}, cards];
|
|
72
88
|
}
|