@yuneta/gobj-ui 5.3.3 → 5.4.0
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 +40 -1
- package/package.json +1 -1
- package/src/c_yui_node.js +108 -4
- package/src/node_tree_model.js +67 -0
- package/src/node_tree_model.test.js +70 -0
package/README.md
CHANGED
|
@@ -162,7 +162,11 @@ seen*:
|
|
|
162
162
|
"content": {"gclass": "C_MY_LANDING", "kw": {}},
|
|
163
163
|
"children": [
|
|
164
164
|
{"id": "energy", "label": "Energy", "icon": "yi-bolt",
|
|
165
|
-
"projection": {
|
|
165
|
+
"projection": {
|
|
166
|
+
"index": {"layout": "cards"},
|
|
167
|
+
"chrome": [{"layout": "tabs", "show_on": ">=tablet"},
|
|
168
|
+
{"layout": "backbar", "show_on": "<tablet"}]
|
|
169
|
+
},
|
|
166
170
|
"children": [ /* … any depth … */ ]}
|
|
167
171
|
]
|
|
168
172
|
}
|
|
@@ -173,6 +177,16 @@ seen*:
|
|
|
173
177
|
icon-bar/backbar and `show_on` all work unchanged) in two modes: `index`
|
|
174
178
|
when the node is the tip of the path — the projection IS the page — and
|
|
175
179
|
`chrome` when a child is showing — the projection is the strip around it.
|
|
180
|
+
- **Chrome belongs to the node that declares it — so every branch declares its
|
|
181
|
+
own.** A node's `chrome` strip lists *that* node's children, and its backbar
|
|
182
|
+
goes back to *that* node's route (`back_route = my_route`). A branch that
|
|
183
|
+
declares no `chrome` therefore contributes no strip, and the only ← the user
|
|
184
|
+
can reach is the nearest ancestor that did declare one. Declaring the pair
|
|
185
|
+
**only at the root** is the mistake this rule exists to name: the whole
|
|
186
|
+
subtree then shows one "← root" that says the same thing at every depth,
|
|
187
|
+
instead of one ← per level going up exactly one level. Repeat the same
|
|
188
|
+
`chrome` on every branch that can have a tip below it — that is what
|
|
189
|
+
`test-app`'s `/cards` does, and what makes its ← hierarchical.
|
|
176
190
|
- **`content` and `children` are not exclusive**: a section with its own page
|
|
177
191
|
and sub-pages is one node.
|
|
178
192
|
- **The route table does not grow.** The host declares ONE route; everything
|
|
@@ -187,6 +201,30 @@ seen*:
|
|
|
187
201
|
`projection.path`) while the rest of the tree keeps its tabs. Note the
|
|
188
202
|
asymmetry that makes it a third mode and not a layout: `index` and `chrome`
|
|
189
203
|
project a node's CHILDREN; `path` projects the way in.
|
|
204
|
+
- **`nav_mode` — the three shapes as one runtime knob.** The two bullets above
|
|
205
|
+
describe what a tree *declares*; `nav_mode` is how a user *chooses* between
|
|
206
|
+
the shapes without the app rewriting anything:
|
|
207
|
+
|
|
208
|
+
| mode | what it shows | equivalent declaration |
|
|
209
|
+
|---|---|---|
|
|
210
|
+
| `"stack"` (default) | one strip per ancestor | whatever each branch declares |
|
|
211
|
+
| `"back"` | only the tip's parent, as a `← parent` | `chrome: {"layout":"backbar"}` everywhere + `chrome_depth: 1` |
|
|
212
|
+
| `"path"` | the trail as ONE line | `path: {"layout":"breadcrumb"}` on the root + `chrome_depth: 0` |
|
|
213
|
+
|
|
214
|
+
It belongs to the **root** (`yui_node_set_nav_mode(root, "path")`, or
|
|
215
|
+
`"nav_mode"` in its declaration) and the whole tree reads it from there —
|
|
216
|
+
ancestors stacking strips while a descendant drew a breadcrumb would be
|
|
217
|
+
saying the same thing twice in two languages. Set on a middle node it is
|
|
218
|
+
refused, loudly, rather than accepted and ignored.
|
|
219
|
+
|
|
220
|
+
A mode **filters the renders as they are asked for; it never rewrites what
|
|
221
|
+
the app declared.** That is what makes `"stack"` an exact restore: a branch
|
|
222
|
+
that declared `vertical` chrome comes back as `vertical`, not as the tabs a
|
|
223
|
+
canonical "stacked" shape would have imposed. The `index` projection is
|
|
224
|
+
never touched by a mode — how a node shows its own children when it IS the
|
|
225
|
+
page is not a statement about depth. Modes are per tree, so an app can run
|
|
226
|
+
`/admin` as a breadcrumb and `/alarms` as a backbar; `test-app`'s node lab
|
|
227
|
+
cycles all three on the live tree.
|
|
190
228
|
- **`chrome_depth`** caps the stacked chrome: with every ancestor painting its
|
|
191
229
|
own strip, depth N shows N-1 of them. A node declares how many its corner of
|
|
192
230
|
the tree deserves (`0` = none, omit = all), the **deepest declaration on the
|
|
@@ -199,6 +237,7 @@ seen*:
|
|
|
199
237
|
yui_node_add(node, spec, index) yui_node_remove(node, node_id)
|
|
200
238
|
yui_node_set_projection(node, proj) yui_node_set_content(node, content)
|
|
201
239
|
yui_node_set_chrome_depth(node, n) yui_node_tree_version(node)
|
|
240
|
+
yui_node_set_nav_mode(root, mode) yui_node_nav_mode(node)
|
|
202
241
|
yui_node_find(node, "energy/north") yui_node_route(node)
|
|
203
242
|
```
|
|
204
243
|
|
package/package.json
CHANGED
package/src/c_yui_node.js
CHANGED
|
@@ -126,6 +126,10 @@ import {
|
|
|
126
126
|
child_nav_items,
|
|
127
127
|
chrome_visible,
|
|
128
128
|
normalize_spec,
|
|
129
|
+
is_nav_mode,
|
|
130
|
+
nav_mode_renders,
|
|
131
|
+
nav_mode_depth,
|
|
132
|
+
NAV_MODES,
|
|
129
133
|
} from "./node_tree_model.js";
|
|
130
134
|
|
|
131
135
|
import {
|
|
@@ -169,6 +173,7 @@ SDATA(data_type_t.DTP_JSON, "children", 0, null, "Declared child spec
|
|
|
169
173
|
|
|
170
174
|
SDATA(data_type_t.DTP_STRING, "base_route", 0, "", "ROOT only: the declared route the whole tree hangs from"),
|
|
171
175
|
SDATA(data_type_t.DTP_STRING, "tree_version", 0, "", "ROOT only: version of the tree CONTRACT (its paths are public urls)"),
|
|
176
|
+
SDATA(data_type_t.DTP_STRING, "nav_mode", 0, "stack","ROOT only: how the way in is shown — stack|back|path"),
|
|
172
177
|
|
|
173
178
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "Root HTMLElement (shell view contract)"),
|
|
174
179
|
SDATA_END()
|
|
@@ -389,6 +394,29 @@ function tree_root_of(gobj)
|
|
|
389
394
|
}
|
|
390
395
|
}
|
|
391
396
|
|
|
397
|
+
/************************************************************
|
|
398
|
+
* The navigation mode in force for this node.
|
|
399
|
+
*
|
|
400
|
+
* It is ONE knob per tree, held by the root: a tree whose ancestors
|
|
401
|
+
* stacked strips while a descendant drew a breadcrumb would be
|
|
402
|
+
* showing the way in twice, in two languages. Descendants read it
|
|
403
|
+
* from the root rather than keeping a copy, so a node added at
|
|
404
|
+
* runtime is born in the mode the tree is already in.
|
|
405
|
+
************************************************************/
|
|
406
|
+
function nav_mode_of(gobj)
|
|
407
|
+
{
|
|
408
|
+
let mode = gobj_read_attr(tree_root_of(gobj), "nav_mode") || "stack";
|
|
409
|
+
|
|
410
|
+
if(!is_nav_mode(mode)) {
|
|
411
|
+
log_error(
|
|
412
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': unknown nav_mode ` +
|
|
413
|
+
`'${mode}' — expected one of ${NAV_MODES.join("|")}`
|
|
414
|
+
);
|
|
415
|
+
return "stack";
|
|
416
|
+
}
|
|
417
|
+
return mode;
|
|
418
|
+
}
|
|
419
|
+
|
|
392
420
|
/************************************************************
|
|
393
421
|
* Node ids from the root DOWN TO this node, root excluded
|
|
394
422
|
* (the root's own segment is already inside base_route).
|
|
@@ -494,12 +522,14 @@ function resolve_path_info(gobj, subpath, inherited)
|
|
|
494
522
|
{
|
|
495
523
|
let effective = (typeof inherited === "number") ? inherited : null;
|
|
496
524
|
|
|
525
|
+
let mode = nav_mode_of(gobj);
|
|
526
|
+
|
|
497
527
|
let own = gobj_read_attr(gobj, "chrome_depth");
|
|
498
528
|
if(typeof own === "number" && own >= 0) {
|
|
499
529
|
effective = own;
|
|
500
530
|
}
|
|
501
531
|
if(has_link(gobj)) {
|
|
502
|
-
return {distance: 0, chrome_depth: effective, chain: []};
|
|
532
|
+
return {distance: 0, chrome_depth: nav_mode_depth(effective, mode), chain: []};
|
|
503
533
|
}
|
|
504
534
|
|
|
505
535
|
/* Distance is counted in STRUCTURAL segments: the tail a viewer
|
|
@@ -524,7 +554,11 @@ function resolve_path_info(gobj, subpath, inherited)
|
|
|
524
554
|
break;
|
|
525
555
|
}
|
|
526
556
|
}
|
|
527
|
-
return {
|
|
557
|
+
return {
|
|
558
|
+
distance: distance,
|
|
559
|
+
chrome_depth: nav_mode_depth(effective, mode),
|
|
560
|
+
chain: chain
|
|
561
|
+
};
|
|
528
562
|
}
|
|
529
563
|
|
|
530
564
|
/************************************************************
|
|
@@ -575,7 +609,8 @@ function render_projection(gobj, mode, $where, active_route, active_id, zones_on
|
|
|
575
609
|
if(!priv.children.length) {
|
|
576
610
|
return;
|
|
577
611
|
}
|
|
578
|
-
let renders =
|
|
612
|
+
let renders = nav_mode_renders(gobj_read_attr(gobj, "projection"),
|
|
613
|
+
nav_mode_of(gobj), mode, priv.is_root);
|
|
579
614
|
if(!renders.length) {
|
|
580
615
|
return;
|
|
581
616
|
}
|
|
@@ -833,7 +868,8 @@ function render_child(gobj, child)
|
|
|
833
868
|
function render_path(gobj, $where)
|
|
834
869
|
{
|
|
835
870
|
let priv = gobj.priv;
|
|
836
|
-
let renders =
|
|
871
|
+
let renders = nav_mode_renders(gobj_read_attr(gobj, "projection"),
|
|
872
|
+
nav_mode_of(gobj), "path", priv.is_root);
|
|
837
873
|
|
|
838
874
|
if(!renders.length) {
|
|
839
875
|
return;
|
|
@@ -1328,6 +1364,54 @@ function ac_set_chrome_depth(gobj, event, kw, src)
|
|
|
1328
1364
|
return 0;
|
|
1329
1365
|
}
|
|
1330
1366
|
|
|
1367
|
+
/************************************************************
|
|
1368
|
+
* Runtime API: change how this TREE shows the way in.
|
|
1369
|
+
*
|
|
1370
|
+
* One knob for the whole tree, and deliberately root-only: the
|
|
1371
|
+
* mode answers "how deep am I and how do I get back", a question
|
|
1372
|
+
* that has one answer per tree. Set on a middle node it would
|
|
1373
|
+
* silently do nothing (descendants read the root's), and a knob
|
|
1374
|
+
* that accepts a call and ignores it is worse than one that
|
|
1375
|
+
* refuses it.
|
|
1376
|
+
*
|
|
1377
|
+
* Nothing declared is rewritten — the mode filters the renders as
|
|
1378
|
+
* they are asked for — so going back to "stack" restores exactly
|
|
1379
|
+
* what the app declared, per branch, including layouts this mode
|
|
1380
|
+
* never mentions.
|
|
1381
|
+
************************************************************/
|
|
1382
|
+
function ac_set_nav_mode(gobj, event, kw, src)
|
|
1383
|
+
{
|
|
1384
|
+
let priv = gobj.priv;
|
|
1385
|
+
let mode = kw.nav_mode || "";
|
|
1386
|
+
|
|
1387
|
+
if(!is_nav_mode(mode)) {
|
|
1388
|
+
log_error(
|
|
1389
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': unknown nav_mode ` +
|
|
1390
|
+
`'${mode}' — expected one of ${NAV_MODES.join("|")}`
|
|
1391
|
+
);
|
|
1392
|
+
return -1;
|
|
1393
|
+
}
|
|
1394
|
+
if(!priv.is_root) {
|
|
1395
|
+
log_error(
|
|
1396
|
+
`${GCLASS_NAME} '${node_path_str(gobj)}': nav_mode belongs to the ` +
|
|
1397
|
+
`tree ROOT — set it there, the whole tree reads it`
|
|
1398
|
+
);
|
|
1399
|
+
return -1;
|
|
1400
|
+
}
|
|
1401
|
+
gobj_write_attr(gobj, "nav_mode", mode);
|
|
1402
|
+
|
|
1403
|
+
/* Same reason as EV_SET_CHROME_DEPTH: what changes is the shape
|
|
1404
|
+
* of the ACTIVE PATH, whose strips are painted by the ancestors,
|
|
1405
|
+
* so the tree is asked to re-apply the current route instead of
|
|
1406
|
+
* repainting one node. */
|
|
1407
|
+
let shell = yui_shell_of(gobj);
|
|
1408
|
+
if(shell) {
|
|
1409
|
+
yui_shell_navigate(shell, gobj_read_attr(shell, "current_route") ||
|
|
1410
|
+
route_of(gobj), {replace: true});
|
|
1411
|
+
}
|
|
1412
|
+
return 0;
|
|
1413
|
+
}
|
|
1414
|
+
|
|
1331
1415
|
/************************************************************
|
|
1332
1416
|
* Runtime API: change (or set) my content.
|
|
1333
1417
|
************************************************************/
|
|
@@ -1402,6 +1486,20 @@ function yui_node_set_chrome_depth(node, depth)
|
|
|
1402
1486
|
{chrome_depth: depth}, node);
|
|
1403
1487
|
}
|
|
1404
1488
|
|
|
1489
|
+
/************************************************************
|
|
1490
|
+
* The tree's navigation mode: "stack" | "back" | "path".
|
|
1491
|
+
* Send it to the ROOT — the whole tree reads it from there.
|
|
1492
|
+
************************************************************/
|
|
1493
|
+
function yui_node_set_nav_mode(node, mode)
|
|
1494
|
+
{
|
|
1495
|
+
return gobj_send_event(node, "EV_SET_NAV_MODE", {nav_mode: mode}, node);
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
function yui_node_nav_mode(node)
|
|
1499
|
+
{
|
|
1500
|
+
return gobj_read_attr(tree_root_of(node), "nav_mode") || "stack";
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1405
1503
|
/************************************************************
|
|
1406
1504
|
* Resolve a path of ids from a node ("" = the node itself).
|
|
1407
1505
|
* Returns null when any segment is missing — callers that mean
|
|
@@ -1484,6 +1582,7 @@ function create_gclass(gclass_name)
|
|
|
1484
1582
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1485
1583
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1486
1584
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1585
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1487
1586
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1488
1587
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1489
1588
|
]],
|
|
@@ -1496,6 +1595,7 @@ function create_gclass(gclass_name)
|
|
|
1496
1595
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1497
1596
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1498
1597
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1598
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1499
1599
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1500
1600
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1501
1601
|
]],
|
|
@@ -1508,6 +1608,7 @@ function create_gclass(gclass_name)
|
|
|
1508
1608
|
["EV_REMOVE_NODE", ac_remove_node, null],
|
|
1509
1609
|
["EV_SET_PROJECTION", ac_set_projection, null],
|
|
1510
1610
|
["EV_SET_CHROME_DEPTH", ac_set_chrome_depth, null],
|
|
1611
|
+
["EV_SET_NAV_MODE", ac_set_nav_mode, null],
|
|
1511
1612
|
["EV_SET_CONTENT", ac_set_content, null],
|
|
1512
1613
|
["EV_NODE_TREE_CHANGED", ac_tree_changed, null]
|
|
1513
1614
|
]]
|
|
@@ -1525,6 +1626,7 @@ function create_gclass(gclass_name)
|
|
|
1525
1626
|
["EV_REMOVE_NODE", 0],
|
|
1526
1627
|
["EV_SET_PROJECTION", 0],
|
|
1527
1628
|
["EV_SET_CHROME_DEPTH", 0],
|
|
1629
|
+
["EV_SET_NAV_MODE", 0],
|
|
1528
1630
|
["EV_SET_CONTENT", 0],
|
|
1529
1631
|
["EV_NODE_TREE_CHANGED", 0]
|
|
1530
1632
|
];
|
|
@@ -1565,6 +1667,8 @@ export {
|
|
|
1565
1667
|
yui_node_set_projection,
|
|
1566
1668
|
yui_node_set_content,
|
|
1567
1669
|
yui_node_set_chrome_depth,
|
|
1670
|
+
yui_node_set_nav_mode,
|
|
1671
|
+
yui_node_nav_mode,
|
|
1568
1672
|
yui_node_find,
|
|
1569
1673
|
yui_node_route,
|
|
1570
1674
|
yui_node_tree_version
|
package/src/node_tree_model.js
CHANGED
|
@@ -211,6 +211,73 @@ export function chrome_visible(distance, depth)
|
|
|
211
211
|
return distance <= depth;
|
|
212
212
|
}
|
|
213
213
|
|
|
214
|
+
/************************************************************
|
|
215
|
+
* NAVIGATION MODES — the three ways a tree can show the way in.
|
|
216
|
+
*
|
|
217
|
+
* "stack" — one chrome strip per ancestor. Whatever each
|
|
218
|
+
* node declared, painted at every level.
|
|
219
|
+
* "back" — only the tip's parent, and only as a "← parent".
|
|
220
|
+
* "path" — no strips at all: the trail as ONE breadcrumb
|
|
221
|
+
* line, drawn by the root.
|
|
222
|
+
*
|
|
223
|
+
* A mode is a FILTER over what the app declared, applied when the
|
|
224
|
+
* renders are asked for — never a rewrite of the declared
|
|
225
|
+
* projections. That is what makes going back to "stack" free and
|
|
226
|
+
* exact: an app that declares `vertical` chrome gets `vertical`
|
|
227
|
+
* back, not the tabs a canonical "stack" shape would have imposed.
|
|
228
|
+
*
|
|
229
|
+
* The index projection is NEVER touched: how a node shows its own
|
|
230
|
+
* children when it IS the page is not a statement about depth.
|
|
231
|
+
************************************************************/
|
|
232
|
+
export const NAV_MODES = ["stack", "back", "path"];
|
|
233
|
+
|
|
234
|
+
export function is_nav_mode(mode)
|
|
235
|
+
{
|
|
236
|
+
return NAV_MODES.indexOf(mode) >= 0;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/************************************************************
|
|
240
|
+
* The renders of one projection slot under a nav mode.
|
|
241
|
+
*
|
|
242
|
+
* `is_root` only matters for "path": the trail is drawn from the
|
|
243
|
+
* tree root down to the tip whoever declares it, so exactly one
|
|
244
|
+
* node must draw it or the same line appears once per ancestor.
|
|
245
|
+
************************************************************/
|
|
246
|
+
export function nav_mode_renders(projection, mode, slot, is_root)
|
|
247
|
+
{
|
|
248
|
+
if(slot === "index" || !is_nav_mode(mode) || mode === "stack") {
|
|
249
|
+
return projection_renders(projection, slot);
|
|
250
|
+
}
|
|
251
|
+
if(mode === "back") {
|
|
252
|
+
return (slot === "chrome") ? [{layout: "backbar"}] : [];
|
|
253
|
+
}
|
|
254
|
+
/* "path" */
|
|
255
|
+
if(slot === "path") {
|
|
256
|
+
return is_root ? [{layout: "breadcrumb"}] : [];
|
|
257
|
+
}
|
|
258
|
+
return [];
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/************************************************************
|
|
262
|
+
* The effective chrome depth under a nav mode.
|
|
263
|
+
*
|
|
264
|
+
* "back" is exactly `chrome_depth: 1` — one strip, the parent's.
|
|
265
|
+
* "path" is `0`: the trail already says everything the strips
|
|
266
|
+
* would, and a strip under it would be the same information twice.
|
|
267
|
+
* Both override what the tree declared, because the user asked for
|
|
268
|
+
* a shape and the declaration is what they asked to change.
|
|
269
|
+
************************************************************/
|
|
270
|
+
export function nav_mode_depth(declared_depth, mode)
|
|
271
|
+
{
|
|
272
|
+
if(mode === "back") {
|
|
273
|
+
return 1;
|
|
274
|
+
}
|
|
275
|
+
if(mode === "path") {
|
|
276
|
+
return 0;
|
|
277
|
+
}
|
|
278
|
+
return declared_depth;
|
|
279
|
+
}
|
|
280
|
+
|
|
214
281
|
/************************************************************
|
|
215
282
|
* Validate + fill one node spec. Returns the normalized spec,
|
|
216
283
|
* or null when it is unusable; every rejection pushes a
|
|
@@ -12,6 +12,9 @@ import {
|
|
|
12
12
|
projection_renders,
|
|
13
13
|
child_nav_items,
|
|
14
14
|
normalize_spec,
|
|
15
|
+
is_nav_mode,
|
|
16
|
+
nav_mode_renders,
|
|
17
|
+
nav_mode_depth,
|
|
15
18
|
} from "./node_tree_model.js";
|
|
16
19
|
|
|
17
20
|
|
|
@@ -280,3 +283,70 @@ test("a link IS the node's content — declaring both is rejected", () => {
|
|
|
280
283
|
}, errors, "/")).toBe(null);
|
|
281
284
|
expect(errors.some((e) => /both 'link' and 'content'/.test(e))).toBe(true);
|
|
282
285
|
});
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
/***************************************************************
|
|
289
|
+
* navigation modes
|
|
290
|
+
***************************************************************/
|
|
291
|
+
const DECLARED = {
|
|
292
|
+
index: {layout: "cards"},
|
|
293
|
+
chrome: [
|
|
294
|
+
{layout: "tabs", show_on: ">=tablet"},
|
|
295
|
+
{layout: "backbar", show_on: "<tablet"}
|
|
296
|
+
]
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
test("only the three modes are modes", () => {
|
|
300
|
+
expect(is_nav_mode("stack")).toBe(true);
|
|
301
|
+
expect(is_nav_mode("back")).toBe(true);
|
|
302
|
+
expect(is_nav_mode("path")).toBe(true);
|
|
303
|
+
expect(is_nav_mode("breadcrumb")).toBe(false); /* that is a LAYOUT */
|
|
304
|
+
expect(is_nav_mode("")).toBe(false);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
test("stack gives back exactly what the node declared", () => {
|
|
308
|
+
expect(nav_mode_renders(DECLARED, "stack", "chrome", true))
|
|
309
|
+
.toEqual(DECLARED.chrome);
|
|
310
|
+
expect(nav_mode_renders("vertical", "stack", "index", false))
|
|
311
|
+
.toEqual([{layout: "vertical"}]);
|
|
312
|
+
/* An unknown mode must not silently reshape a tree */
|
|
313
|
+
expect(nav_mode_renders(DECLARED, "nonsense", "chrome", true))
|
|
314
|
+
.toEqual(DECLARED.chrome);
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("back replaces every chrome with one backbar, and drops the trail", () => {
|
|
318
|
+
expect(nav_mode_renders(DECLARED, "back", "chrome", true))
|
|
319
|
+
.toEqual([{layout: "backbar"}]);
|
|
320
|
+
expect(nav_mode_renders(DECLARED, "back", "chrome", false))
|
|
321
|
+
.toEqual([{layout: "backbar"}]);
|
|
322
|
+
expect(nav_mode_renders({path: {layout: "breadcrumb"}}, "back", "path", true))
|
|
323
|
+
.toEqual([]);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
test("path draws the trail ONCE, at the root, and no strips anywhere", () => {
|
|
327
|
+
expect(nav_mode_renders(DECLARED, "path", "path", true))
|
|
328
|
+
.toEqual([{layout: "breadcrumb"}]);
|
|
329
|
+
expect(nav_mode_renders(DECLARED, "path", "path", false)).toEqual([]);
|
|
330
|
+
expect(nav_mode_renders(DECLARED, "path", "chrome", true)).toEqual([]);
|
|
331
|
+
expect(nav_mode_renders(DECLARED, "path", "chrome", false)).toEqual([]);
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
test("the index projection survives every mode", () => {
|
|
335
|
+
for(const mode of ["stack", "back", "path"]) {
|
|
336
|
+
expect(nav_mode_renders(DECLARED, mode, "index", true))
|
|
337
|
+
.toEqual([{layout: "cards"}]);
|
|
338
|
+
}
|
|
339
|
+
/* and an undeclared projection keeps defaulting to cards */
|
|
340
|
+
expect(nav_mode_renders(null, "path", "index", true))
|
|
341
|
+
.toEqual([{layout: "cards"}]);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
test("back is depth 1 and path is depth 0, whatever the tree declared", () => {
|
|
345
|
+
expect(nav_mode_depth(null, "back")).toBe(1);
|
|
346
|
+
expect(nav_mode_depth(3, "back")).toBe(1);
|
|
347
|
+
expect(nav_mode_depth(null, "path")).toBe(0);
|
|
348
|
+
expect(nav_mode_depth(3, "path")).toBe(0);
|
|
349
|
+
/* stack keeps the declaration, unlimited included */
|
|
350
|
+
expect(nav_mode_depth(null, "stack")).toBe(null);
|
|
351
|
+
expect(nav_mode_depth(2, "stack")).toBe(2);
|
|
352
|
+
});
|