@yuneta/gobj-ui 7.26.28 → 7.26.30
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 +225 -62
- package/dist/gobj-ui.cjs.js +401 -122
- package/dist/gobj-ui.es.js +401 -123
- package/index.js +1 -0
- package/package.json +4 -2
- package/scripts/validate-locales.mjs +565 -177
- package/src/c_yui_form.js +5 -3
- package/src/c_yui_gobj_tree_js.js +1 -1
- package/src/c_yui_nav.js +164 -29
- package/src/c_yui_period.js +3 -3
- package/src/c_yui_schema_editor.js +22 -18
- package/src/c_yui_shell.css +84 -18
- package/src/c_yui_shell.js +149 -68
- package/src/c_yui_treedb_graph.js +3 -4
- package/src/c_yui_treedb_topic_with_form.js +15 -15
- package/src/c_yui_treedb_topics.js +8 -8
- package/src/c_yui_window_manager.js +5 -2
- package/src/i18n_key_functions.js +112 -23
- package/src/i18n_key_functions.test.js +329 -8
- package/src/nav_cards_helpers.js +21 -5
- package/src/nav_item_badge.wiring.test.js +564 -0
- package/src/shell_route_map.js +2 -2
- package/src/yui_badge.js +145 -0
- package/src/yui_badge.test.js +148 -0
- package/src/yui_gclass_view.js +1 -1
- package/src/yui_time.js +1 -1
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: {},
|
|
@@ -281,7 +290,8 @@ function mt_start(gobj)
|
|
|
281
290
|
|
|
282
291
|
build_item_index(gobj, config);
|
|
283
292
|
instantiate_menus(gobj, config);
|
|
284
|
-
|
|
293
|
+
/* The app's shell declaration: its toolbar's keys are read there */
|
|
294
|
+
build_toolbar(gobj, /* i18n: data */ config);
|
|
285
295
|
|
|
286
296
|
/* lifecycle: "eager" — preinstantiate views that must exist from boot. */
|
|
287
297
|
preinstantiate_eager_views(gobj);
|
|
@@ -1242,6 +1252,7 @@ function instantiate_nav_in_zone(gobj, menu, menu_id, zone_id, level, nav_label)
|
|
|
1242
1252
|
level: level,
|
|
1243
1253
|
show_on: render_cfg.show_on || "",
|
|
1244
1254
|
back_route: render_cfg.back_route || "",
|
|
1255
|
+
badges: Object.assign({}, priv.nav_badges),
|
|
1245
1256
|
shell: gobj
|
|
1246
1257
|
},
|
|
1247
1258
|
gobj
|
|
@@ -1693,6 +1704,7 @@ function navigate_to(gobj, route, depth, no_drain)
|
|
|
1693
1704
|
|
|
1694
1705
|
function build_view_gobj(gobj, entry, route, stage)
|
|
1695
1706
|
{
|
|
1707
|
+
let priv = gobj.priv;
|
|
1696
1708
|
let target = entry.target;
|
|
1697
1709
|
/* The deep-link tail is NOT injected into kw: gobj_create2
|
|
1698
1710
|
* validates kw against the view's SDATA strictly, so an extra
|
|
@@ -1701,6 +1713,11 @@ function build_view_gobj(gobj, entry, route, stage)
|
|
|
1701
1713
|
* mount (and on every later subpath-only change) — that single
|
|
1702
1714
|
* mechanism is how a view owns its dynamic 3rd level. */
|
|
1703
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
|
+
}
|
|
1704
1721
|
let name = target.name || `view_${safe_id(route)}`;
|
|
1705
1722
|
|
|
1706
1723
|
let view;
|
|
@@ -1781,7 +1798,7 @@ function safe_id(s)
|
|
|
1781
1798
|
************************************************************/
|
|
1782
1799
|
function build_toolbar(gobj, config)
|
|
1783
1800
|
{
|
|
1784
|
-
|
|
1801
|
+
const tb = config && config.toolbar;
|
|
1785
1802
|
if(!tb || !is_array(tb.items)) {
|
|
1786
1803
|
return;
|
|
1787
1804
|
}
|
|
@@ -1847,51 +1864,6 @@ function build_toolbar(gobj, config)
|
|
|
1847
1864
|
$zone.appendChild($bar);
|
|
1848
1865
|
}
|
|
1849
1866
|
|
|
1850
|
-
/************************************************************
|
|
1851
|
-
* The badge node of a toolbar item — the little count pinned to
|
|
1852
|
-
* the corner of its icon (unread notifications, active alarms).
|
|
1853
|
-
*
|
|
1854
|
-
* ALWAYS rendered, hidden when empty, so the runtime setter has a
|
|
1855
|
-
* node to write into and does not have to rebuild the button.
|
|
1856
|
-
*
|
|
1857
|
-
* EMPTY IS 0, "" AND null ALIKE: a badge reading "0" is worse than
|
|
1858
|
-
* no badge — it draws the eye to say nothing. A count is only
|
|
1859
|
-
* worth a pixel when there IS something.
|
|
1860
|
-
*
|
|
1861
|
-
* Capped at 99+: the toolbar is a fixed-width row, and a four
|
|
1862
|
-
* digit pill pushes the items next to it off a phone screen.
|
|
1863
|
-
*
|
|
1864
|
-
* role="status" and NOT aria-hidden, deliberately. The button
|
|
1865
|
-
* carries an explicit aria-label, and an explicit label REPLACES
|
|
1866
|
-
* the element's content for a screen reader — so a badge inside
|
|
1867
|
-
* it would be silent. As its own live region it is both read and
|
|
1868
|
-
* announced when the count changes, which is the whole point of a
|
|
1869
|
-
* badge that means "something needs you".
|
|
1870
|
-
************************************************************/
|
|
1871
|
-
function badge_text(value)
|
|
1872
|
-
{
|
|
1873
|
-
if(value === null || value === undefined || value === false) {
|
|
1874
|
-
return "";
|
|
1875
|
-
}
|
|
1876
|
-
if(typeof value === "number") {
|
|
1877
|
-
if(!isFinite(value) || value <= 0) {
|
|
1878
|
-
return "";
|
|
1879
|
-
}
|
|
1880
|
-
return (value > 99) ? "99+" : String(Math.floor(value));
|
|
1881
|
-
}
|
|
1882
|
-
return String(value).trim();
|
|
1883
|
-
}
|
|
1884
|
-
|
|
1885
|
-
function badge_node(value)
|
|
1886
|
-
{
|
|
1887
|
-
let text = badge_text(value);
|
|
1888
|
-
let attrs = {class: "yui-toolbar-badge", role: "status"};
|
|
1889
|
-
if(!text) {
|
|
1890
|
-
attrs.hidden = "hidden";
|
|
1891
|
-
}
|
|
1892
|
-
return ["span", attrs, text];
|
|
1893
|
-
}
|
|
1894
|
-
|
|
1895
1867
|
/************************************************************
|
|
1896
1868
|
* The attributes that turn a toolbar item into a real link, or
|
|
1897
1869
|
* null when this item is not one. Answering null is what keeps
|
|
@@ -1930,11 +1902,14 @@ function build_toolbar_action_item(gobj, it)
|
|
|
1930
1902
|
if(!empty_string(it.icon)) {
|
|
1931
1903
|
/* The badge is anchored to the ICON, not to the button: with a
|
|
1932
1904
|
* label on (desktop) the button is wide, and a badge pinned to
|
|
1933
|
-
* 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. */
|
|
1934
1907
|
children.push(["span", {class: "icon yui-toolbar-icon"},
|
|
1935
1908
|
[
|
|
1936
1909
|
["i", {class: it.icon, "aria-hidden": "true"}],
|
|
1937
|
-
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 || "?"}'`)
|
|
1938
1913
|
]
|
|
1939
1914
|
]);
|
|
1940
1915
|
}
|
|
@@ -2341,7 +2316,7 @@ function open_toolbar_dropdown(gobj, item, action, $trigger)
|
|
|
2341
2316
|
let raw_items = is_array(action.items) ? action.items : [];
|
|
2342
2317
|
for(let i = 0; i < raw_items.length; i++) {
|
|
2343
2318
|
let sub = raw_items[i];
|
|
2344
|
-
let $row = build_dropdown_row(gobj, sub, i);
|
|
2319
|
+
let $row = build_dropdown_row(gobj, /* i18n: data */ sub, i); // the app's shell declaration
|
|
2345
2320
|
if(!$row) {
|
|
2346
2321
|
continue;
|
|
2347
2322
|
}
|
|
@@ -3219,6 +3194,60 @@ function update_secondary_nav_visibility(gobj, entry)
|
|
|
3219
3194
|
}
|
|
3220
3195
|
}
|
|
3221
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
|
+
|
|
3222
3251
|
|
|
3223
3252
|
|
|
3224
3253
|
|
|
@@ -3348,8 +3377,11 @@ function ac_nav_item_close(gobj, event, kw, src)
|
|
|
3348
3377
|
* items of a primary item's submenu (its secondary nav) at runtime
|
|
3349
3378
|
* and re-registers their routes so navigation resolves. Item
|
|
3350
3379
|
* descriptors may carry { id, name, icon, route, class, closable,
|
|
3351
|
-
* target:{stage,gclass,kw,lifecycle} }. Routes
|
|
3352
|
-
* 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`.
|
|
3353
3385
|
************************************************************/
|
|
3354
3386
|
function find_secondary_nav(priv, parent_item_id)
|
|
3355
3387
|
{
|
|
@@ -3470,6 +3502,7 @@ function yui_shell_set_submenu(shell_gobj, parent_item_id, items)
|
|
|
3470
3502
|
};
|
|
3471
3503
|
}
|
|
3472
3504
|
priv.dynamic_routes[parent_item_id] = new_routes;
|
|
3505
|
+
priv.dynamic_items[parent_item_id] = items;
|
|
3473
3506
|
|
|
3474
3507
|
/* Push the new items into the nav (rebuilds its DOM in place), and
|
|
3475
3508
|
* re-apply the translator: the rebuilt labels carry their keys as
|
|
@@ -4232,22 +4265,31 @@ function yui_shell_set_toolbar_item_icon(shell_gobj, item_id, icon_class)
|
|
|
4232
4265
|
* its icon.
|
|
4233
4266
|
*
|
|
4234
4267
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3);
|
|
4268
|
+
* yui_shell_set_toolbar_item_badge(shell, "alarms", 3, "warning");
|
|
4235
4269
|
* yui_shell_set_toolbar_item_badge(shell, "alarms", 0); // hidden
|
|
4236
4270
|
*
|
|
4237
4271
|
* This is the API that matters: a count is a RUNTIME fact. The
|
|
4238
|
-
* `badge`
|
|
4239
|
-
* 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.
|
|
4240
4275
|
*
|
|
4241
4276
|
* 0 / "" / null / false all clear it, and a number over 99 renders
|
|
4242
|
-
* "99+" — see
|
|
4243
|
-
* 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().
|
|
4244
4283
|
*
|
|
4245
4284
|
* Silent no-op on an unknown item id: a toolbar that does not
|
|
4246
4285
|
* declare the item (an app without alarms) must not be an error
|
|
4247
|
-
* 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.
|
|
4248
4288
|
************************************************************/
|
|
4249
|
-
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)
|
|
4250
4290
|
{
|
|
4291
|
+
tone = badge_tone(tone, `C_YUI_SHELL: yui_shell_set_toolbar_item_badge('${item_id}')`);
|
|
4292
|
+
|
|
4251
4293
|
if(!shell_gobj || !is_gobj(shell_gobj) || empty_string(item_id)) {
|
|
4252
4294
|
return;
|
|
4253
4295
|
}
|
|
@@ -4261,21 +4303,59 @@ function yui_shell_set_toolbar_item_badge(shell_gobj, item_id, value)
|
|
|
4261
4303
|
if(!$badge) {
|
|
4262
4304
|
return;
|
|
4263
4305
|
}
|
|
4306
|
+
paint_badge($badge, value, tone);
|
|
4307
|
+
}
|
|
4264
4308
|
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
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)) {
|
|
4269
4346
|
return;
|
|
4270
4347
|
}
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
* reader announce it again on every tick. */
|
|
4274
|
-
if($badge.textContent === text && !$badge.hasAttribute("hidden")) {
|
|
4348
|
+
let priv = shell_gobj.priv;
|
|
4349
|
+
if(!priv || !nav_item_declared(shell_gobj, item_id)) {
|
|
4275
4350
|
return;
|
|
4276
4351
|
}
|
|
4277
|
-
|
|
4278
|
-
|
|
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
|
+
}
|
|
4279
4359
|
}
|
|
4280
4360
|
|
|
4281
4361
|
/************************************************************
|
|
@@ -4329,6 +4409,7 @@ export {
|
|
|
4329
4409
|
yui_shell_set_connection_state,
|
|
4330
4410
|
yui_shell_set_toolbar_item_icon,
|
|
4331
4411
|
yui_shell_set_toolbar_item_badge,
|
|
4412
|
+
yui_shell_set_nav_item_badge,
|
|
4332
4413
|
yui_shell_close_dropdown,
|
|
4333
4414
|
yui_shell_set_submenu
|
|
4334
4415
|
};
|
|
@@ -1361,8 +1361,7 @@ function answer_print_tranger_refused(gobj, path, answer)
|
|
|
1361
1361
|
gobj_send_event(jv, "EV_SUBTREE_ERROR",
|
|
1362
1362
|
Object.assign({path: path}, answer), gobj);
|
|
1363
1363
|
} else {
|
|
1364
|
-
yui_shell_show_error(yui_shell_of(gobj),
|
|
1365
|
-
/* i18n: data */ answer.i18n || answer.error, {t: t});
|
|
1364
|
+
yui_shell_show_error(yui_shell_of(gobj), answer.i18n || answer.error, {t: t});
|
|
1366
1365
|
}
|
|
1367
1366
|
}
|
|
1368
1367
|
|
|
@@ -1413,7 +1412,7 @@ function request_print_tranger(gobj, path)
|
|
|
1413
1412
|
}, gobj);
|
|
1414
1413
|
if(ret) {
|
|
1415
1414
|
log_error(ret);
|
|
1416
|
-
answer_print_tranger_refused(gobj, path, {error: refusal_text(ret)});
|
|
1415
|
+
answer_print_tranger_refused(gobj, path, {error: /* i18n: data */ refusal_text(ret)});
|
|
1417
1416
|
return;
|
|
1418
1417
|
}
|
|
1419
1418
|
if(path) {
|
|
@@ -2193,7 +2192,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2193
2192
|
/* The schema couldn't load (not a treedb, no authz for it, backend
|
|
2194
2193
|
* down…). Show an inline banner in the view rather than a blocking
|
|
2195
2194
|
* app-modal that wedges the whole SPA behind an empty tab. */
|
|
2196
|
-
show_load_error(gobj, t(comment));
|
|
2195
|
+
show_load_error(gobj, t(/* i18n: data */ comment));
|
|
2197
2196
|
} else {
|
|
2198
2197
|
yui_shell_show_error(yui_shell_of(gobj), /* i18n: data */ comment, {t: t});
|
|
2199
2198
|
}
|
|
@@ -325,7 +325,7 @@ function present_json_popup(gobj, $box, opts)
|
|
|
325
325
|
|
|
326
326
|
if(is_mobile()) {
|
|
327
327
|
return {
|
|
328
|
-
modal: yui_shell_show_modal(shell,
|
|
328
|
+
modal: yui_shell_show_modal(shell, $box, {
|
|
329
329
|
dialog: true,
|
|
330
330
|
logical_class: opts.logical_class + "_SHEET",
|
|
331
331
|
title_prefix: opts.title_prefix,
|
|
@@ -1512,7 +1512,7 @@ function create_tabulator(gobj)
|
|
|
1512
1512
|
|
|
1513
1513
|
let colDef = {
|
|
1514
1514
|
title: col_label(col, gobj_read_str_attr(gobj, "topic_name")),
|
|
1515
|
-
titleFormatter: col_title_formatter(gobj, col),
|
|
1515
|
+
titleFormatter: col_title_formatter(gobj, /* i18n: data */ col), // a column of the schema
|
|
1516
1516
|
field: col.id,
|
|
1517
1517
|
sorter: sorter,
|
|
1518
1518
|
hozAlign: hozAlign,
|
|
@@ -2496,7 +2496,7 @@ function open_form_dialog(gobj, mode, record)
|
|
|
2496
2496
|
* are wired by the shell. `before_close` preserves the unsaved-changes
|
|
2497
2497
|
* guard — it vetoes the dismiss and, on confirm, closes the modal
|
|
2498
2498
|
* itself. `on_close` tears the hosted form child down. */
|
|
2499
|
-
priv.form_modal = yui_shell_show_modal(shell,
|
|
2499
|
+
priv.form_modal = yui_shell_show_modal(shell, $body, {
|
|
2500
2500
|
dialog: true,
|
|
2501
2501
|
logical_class: "TREEDB_FORM_SHEET",
|
|
2502
2502
|
title_prefix: title_prefix,
|
|
@@ -2676,7 +2676,7 @@ function open_schema_dialog(gobj)
|
|
|
2676
2676
|
/* Title split in two halves: the topic name is DATA (never
|
|
2677
2677
|
* translated) and "schema" is the kind (carries its i18n key), so
|
|
2678
2678
|
* the header re-translates on a language switch. */
|
|
2679
|
-
let presented = present_json_popup(gobj, $box, {
|
|
2679
|
+
let presented = present_json_popup(gobj, /* i18n: data */ $box, { // the viewer's own DOM
|
|
2680
2680
|
name: "schemawin_" + clean_name(gobj_name(gobj)),
|
|
2681
2681
|
logical_class: "TREEDB_SCHEMA",
|
|
2682
2682
|
title_prefix: gobj_read_str_attr(gobj, "topic_name"),
|
|
@@ -2803,11 +2803,11 @@ function open_cell_json_dialog(gobj, row_id, col_id)
|
|
|
2803
2803
|
* i18n key — the shared `col.id` one, so the header re-translates on a
|
|
2804
2804
|
* language switch and reads as the raw id where the app defines no key
|
|
2805
2805
|
* (exactly what an untranslated column header already shows). */
|
|
2806
|
-
let presented = present_json_popup(gobj, $box, {
|
|
2806
|
+
let presented = present_json_popup(gobj, /* i18n: data */ $box, { // the viewer's own DOM
|
|
2807
2807
|
name: "cellwin_" + clean_name(gobj_name(gobj)),
|
|
2808
2808
|
logical_class: "TREEDB_CELL_JSON",
|
|
2809
2809
|
title_prefix: String(row_id),
|
|
2810
|
-
title:
|
|
2810
|
+
title: col_id,
|
|
2811
2811
|
icon: "yi-js-square",
|
|
2812
2812
|
forget_window: function() {
|
|
2813
2813
|
priv.cell_json_win = null;
|
|
@@ -3019,7 +3019,7 @@ function open_cell_file_dialog(gobj, row_id, col_id)
|
|
|
3019
3019
|
name: "filewin_" + clean_name(gobj_name(gobj)),
|
|
3020
3020
|
logical_class: "TREEDB_CELL_FILE",
|
|
3021
3021
|
title_prefix: String(row_id),
|
|
3022
|
-
title:
|
|
3022
|
+
title: col_id,
|
|
3023
3023
|
icon: "yi-eye",
|
|
3024
3024
|
forget_window: function() {
|
|
3025
3025
|
priv.cell_file_win = null;
|
|
@@ -3167,7 +3167,7 @@ function open_hook_choice_dialog(gobj, targets, parent_id, hook)
|
|
|
3167
3167
|
}];
|
|
3168
3168
|
})]
|
|
3169
3169
|
);
|
|
3170
|
-
priv.hook_choice_modal = yui_shell_show_modal(shell,
|
|
3170
|
+
priv.hook_choice_modal = yui_shell_show_modal(shell, $body, {
|
|
3171
3171
|
dialog: true,
|
|
3172
3172
|
logical_class: "TREEDB_HOOK_CHOICE_SHEET",
|
|
3173
3173
|
title: "choose a topic",
|
|
@@ -4132,7 +4132,7 @@ function ac_delete_rows(gobj, event, kw, src)
|
|
|
4132
4132
|
return 0;
|
|
4133
4133
|
}
|
|
4134
4134
|
|
|
4135
|
-
confirm_then(gobj,
|
|
4135
|
+
confirm_then(gobj, build_delete_question(gobj, rows),
|
|
4136
4136
|
{what: "delete_selection", ids: yui_row_ids(tabulator, rows)});
|
|
4137
4137
|
|
|
4138
4138
|
} else {
|
|
@@ -4140,7 +4140,7 @@ function ac_delete_rows(gobj, event, kw, src)
|
|
|
4140
4140
|
* Delete one row
|
|
4141
4141
|
* {row: }
|
|
4142
4142
|
*----------------------------*/
|
|
4143
|
-
confirm_then(gobj,
|
|
4143
|
+
confirm_then(gobj, build_delete_question(gobj, kw.row),
|
|
4144
4144
|
{what: "delete_row", ids: yui_row_ids(tabulator, [kw.row])});
|
|
4145
4145
|
}
|
|
4146
4146
|
|
|
@@ -4599,7 +4599,7 @@ function ac_show_hook_data(gobj, event, kw, src)
|
|
|
4599
4599
|
String(kw.row_id), kw.col_id);
|
|
4600
4600
|
return 0;
|
|
4601
4601
|
}
|
|
4602
|
-
open_hook_choice_dialog(gobj, targets, String(kw.row_id), kw.col_id);
|
|
4602
|
+
open_hook_choice_dialog(gobj, /* i18n: data */ targets, String(kw.row_id), kw.col_id); // the schema's topics
|
|
4603
4603
|
return 0;
|
|
4604
4604
|
}
|
|
4605
4605
|
|
|
@@ -4681,7 +4681,7 @@ function ac_refresh(gobj, event, kw, src)
|
|
|
4681
4681
|
************************************************************/
|
|
4682
4682
|
function ac_show_cell_json(gobj, event, kw, src)
|
|
4683
4683
|
{
|
|
4684
|
-
open_cell_json_dialog(gobj, kw.row_id, kw.col_id);
|
|
4684
|
+
open_cell_json_dialog(gobj, kw.row_id, /* i18n: data */ kw.col_id);
|
|
4685
4685
|
|
|
4686
4686
|
return 0;
|
|
4687
4687
|
}
|
|
@@ -4695,7 +4695,7 @@ function ac_show_cell_json(gobj, event, kw, src)
|
|
|
4695
4695
|
************************************************************/
|
|
4696
4696
|
function ac_show_cell_file(gobj, event, kw, src)
|
|
4697
4697
|
{
|
|
4698
|
-
open_cell_file_dialog(gobj, kw.row_id, kw.col_id);
|
|
4698
|
+
open_cell_file_dialog(gobj, kw.row_id, /* i18n: data */ kw.col_id);
|
|
4699
4699
|
|
|
4700
4700
|
return 0;
|
|
4701
4701
|
}
|
|
@@ -5078,7 +5078,7 @@ function ac_open_columns(gobj, event, kw, src)
|
|
|
5078
5078
|
));
|
|
5079
5079
|
}
|
|
5080
5080
|
|
|
5081
|
-
yui_shell_show_modal(shell,
|
|
5081
|
+
yui_shell_show_modal(shell, $list, {
|
|
5082
5082
|
dialog: true,
|
|
5083
5083
|
logical_class: "TREEDB_COLUMNS_DIALOG",
|
|
5084
5084
|
title_prefix: gobj_read_str_attr(gobj, "topic_name"),
|
|
@@ -5291,7 +5291,7 @@ function open_table_json_dialog(gobj, records)
|
|
|
5291
5291
|
}
|
|
5292
5292
|
|
|
5293
5293
|
/* The topic is DATA (the prefix), the title carries its key. */
|
|
5294
|
-
let presented = present_json_popup(gobj, $box, {
|
|
5294
|
+
let presented = present_json_popup(gobj, /* i18n: data */ $box, { // the viewer's own DOM
|
|
5295
5295
|
name: "tablejsonwin_" + clean_name(gobj_name(gobj)),
|
|
5296
5296
|
logical_class: "TREEDB_TABLE_JSON",
|
|
5297
5297
|
title_prefix: gobj_read_str_attr(gobj, "topic_name"),
|
|
@@ -1368,8 +1368,9 @@ function process_treedb_descs(gobj)
|
|
|
1368
1368
|
);
|
|
1369
1369
|
|
|
1370
1370
|
// TODO get icon from remote config
|
|
1371
|
-
|
|
1372
|
-
|
|
1371
|
+
/* `key` is a topic of the backend's schema: data */
|
|
1372
|
+
add_tab(gobj, gobj_topic_form, id, /* i18n: data */ key, "yi-table");
|
|
1373
|
+
add_topic_card(gobj, id, /* i18n: data */ key, "yi-table", desc);
|
|
1373
1374
|
|
|
1374
1375
|
gobj_start(gobj_topic_form);
|
|
1375
1376
|
}
|
|
@@ -1390,7 +1391,7 @@ function process_treedb_descs(gobj)
|
|
|
1390
1391
|
if(gobj.priv._pending_info) {
|
|
1391
1392
|
let ti = gobj.priv._pending_info;
|
|
1392
1393
|
gobj.priv._pending_info = null;
|
|
1393
|
-
show_topic_info(gobj, ti);
|
|
1394
|
+
show_topic_info(gobj, /* i18n: data */ ti); // a topic name
|
|
1394
1395
|
} else if(href && href.indexOf("?") >= 0) {
|
|
1395
1396
|
gobj_send_event(gobj, "EV_SHOW", {href: href}, gobj);
|
|
1396
1397
|
} else {
|
|
@@ -2223,8 +2224,7 @@ function answer_print_tranger_refused(gobj, path, answer)
|
|
|
2223
2224
|
gobj_send_event(jv, "EV_SUBTREE_ERROR",
|
|
2224
2225
|
Object.assign({path: path}, answer), gobj);
|
|
2225
2226
|
} else {
|
|
2226
|
-
yui_shell_show_error(yui_shell_of(gobj),
|
|
2227
|
-
/* i18n: data */ answer.i18n || answer.error, {t: t});
|
|
2227
|
+
yui_shell_show_error(yui_shell_of(gobj), answer.i18n || answer.error, {t: t});
|
|
2228
2228
|
}
|
|
2229
2229
|
}
|
|
2230
2230
|
|
|
@@ -2274,7 +2274,7 @@ function request_print_tranger(gobj, path)
|
|
|
2274
2274
|
}, gobj);
|
|
2275
2275
|
if(ret) {
|
|
2276
2276
|
log_error(ret);
|
|
2277
|
-
answer_print_tranger_refused(gobj, path, {error: refusal_text(ret)});
|
|
2277
|
+
answer_print_tranger_refused(gobj, path, {error: /* i18n: data */ refusal_text(ret)});
|
|
2278
2278
|
return;
|
|
2279
2279
|
}
|
|
2280
2280
|
if(path) {
|
|
@@ -2459,7 +2459,7 @@ function ac_mt_command_answer(gobj, event, kw, src)
|
|
|
2459
2459
|
/* The schema couldn't load (not a treedb, no authz for it, backend
|
|
2460
2460
|
* down…). Show an inline banner in the view rather than a blocking
|
|
2461
2461
|
* app-modal that wedges the whole SPA behind an empty tab. */
|
|
2462
|
-
show_load_error(gobj, t(comment));
|
|
2462
|
+
show_load_error(gobj, t(/* i18n: data */ comment));
|
|
2463
2463
|
} else {
|
|
2464
2464
|
yui_shell_show_error(yui_shell_of(gobj), /* i18n: data */ comment, {t: t});
|
|
2465
2465
|
/* A refused write leaves the TABLE showing what the operator
|
|
@@ -2737,7 +2737,7 @@ function ac_show(gobj, event, kw, src)
|
|
|
2737
2737
|
************************************************************/
|
|
2738
2738
|
function ac_show_topic_info(gobj, event, kw, src)
|
|
2739
2739
|
{
|
|
2740
|
-
show_topic_info(gobj, kw && kw.topic);
|
|
2740
|
+
show_topic_info(gobj, /* i18n: data */ kw && kw.topic); // a topic name
|
|
2741
2741
|
return 0;
|
|
2742
2742
|
}
|
|
2743
2743
|
|
|
@@ -510,9 +510,12 @@ function ac_register_window(gobj, event, kw, src)
|
|
|
510
510
|
label_items.push(['span', {class: 'yui-dock-label-prefix'},
|
|
511
511
|
text_node(prefix)]); // data, not markup
|
|
512
512
|
}
|
|
513
|
+
/* An FSM action: what it is given is the kw of EV_REGISTER_WINDOW,
|
|
514
|
+
* which no reader can follow. `title_key` is the window's `title`,
|
|
515
|
+
* a key its HOST chose when it created the window. */
|
|
513
516
|
if(title_key) {
|
|
514
517
|
label_items.push(
|
|
515
|
-
['span', {class: 'yui-dock-label-kind', i18n: title_key},
|
|
518
|
+
['span', {class: 'yui-dock-label-kind', i18n: /* i18n: data */ title_key},
|
|
516
519
|
kind_text || title_key]
|
|
517
520
|
);
|
|
518
521
|
}
|
|
@@ -532,7 +535,7 @@ function ac_register_window(gobj, event, kw, src)
|
|
|
532
535
|
let $chip = createElement2(
|
|
533
536
|
['div', Object.assign(
|
|
534
537
|
{class: 'yui-dock-chip', role: 'button', tabindex: '0', title: title},
|
|
535
|
-
(!prefix && title_key) ? {'data-i18n-title': title_key} : {}
|
|
538
|
+
(!prefix && title_key) ? {'data-i18n-title': /* i18n: data */ title_key} : {}
|
|
536
539
|
), [
|
|
537
540
|
chip_lead(kw.icon),
|
|
538
541
|
['span', {class: 'yui-dock-label'}, label_items],
|