@yuneta/gobj-ui 7.23.67 → 7.23.68
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 +57 -0
- package/dist/gobj-ui.cjs.js +438 -84
- package/dist/gobj-ui.es.js +439 -85
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +146 -8
- package/src/c_yui_treedb_graph.js +261 -80
- package/src/treedb_fold_model.js +171 -15
- package/src/treedb_fold_model.test.js +120 -2
|
@@ -115,6 +115,9 @@ SDATA(data_type_t.DTP_INTEGER, "fold_page_size", 0, 24, "Children of one
|
|
|
115
115
|
/*---------------- User last selections ----------------*/
|
|
116
116
|
SDATA(data_type_t.DTP_STRING, "operation_mode", sdata_flag_t.SDF_PERSIST, "reading", "Current operation mode (internal behaviour or role). Changed by the user trough the gui."),
|
|
117
117
|
SDATA(data_type_t.DTP_STRING, "layout", sdata_flag_t.SDF_PERSIST, "", "Current graph layout. User preference. Changed by the user through the gui."),
|
|
118
|
+
SDATA(data_type_t.DTP_LIST, "hidden_topics", sdata_flag_t.SDF_PERSIST, "[]", "Topics hidden from the graph (legend). User preference, per treedb"),
|
|
119
|
+
SDATA(data_type_t.DTP_STRING, "main_topic", sdata_flag_t.SDF_PERSIST, "", "The topic the tree hangs from; empty = deduced by the graph. User preference, per treedb"),
|
|
120
|
+
SDATA(data_type_t.DTP_LIST, "loose_topics", sdata_flag_t.SDF_PERSIST, "[]", "Topics whose LOOSE records (no parent) are shown. User preference, per treedb"),
|
|
118
121
|
|
|
119
122
|
/*---------------- Remote Connection ----------------*/
|
|
120
123
|
SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote Yuno to request data"),
|
|
@@ -165,6 +168,7 @@ let PRIVATE_DATA = {
|
|
|
165
168
|
operation_mode: null,
|
|
166
169
|
layout: null,
|
|
167
170
|
_topics_subscribed: {},
|
|
171
|
+
_legend_state: null, /* the engine's last EV_LEGEND_STATE */
|
|
168
172
|
_links_subscribed: false, /* EV_TREEDB_NODE_LINKED/UNLINKED (treedb-wide) */
|
|
169
173
|
|
|
170
174
|
is_pinhold_window: false, // inherited of v6, todo review
|
|
@@ -246,6 +250,9 @@ function mt_create(gobj)
|
|
|
246
250
|
fkey_port_position: "top",
|
|
247
251
|
expand_depth: gobj_read_integer_attr(gobj, "expand_depth"),
|
|
248
252
|
fold_page_size: gobj_read_integer_attr(gobj, "fold_page_size"),
|
|
253
|
+
hidden_topics: gobj_read_attr(gobj, "hidden_topics") || [],
|
|
254
|
+
main_topic: gobj_read_str_attr(gobj, "main_topic") || "",
|
|
255
|
+
loose_topics: gobj_read_attr(gobj, "loose_topics") || [],
|
|
249
256
|
},
|
|
250
257
|
gobj
|
|
251
258
|
);
|
|
@@ -363,13 +370,18 @@ function build_ui(gobj)
|
|
|
363
370
|
// Don't use is-flex, don't work well with is-hidden
|
|
364
371
|
['div', {class: 'C_YUI_TREEDB_GRAPH', style: `height:100%; display:flex; flex-direction:column;`}, [
|
|
365
372
|
['div', {class: 'GRAPH_TOOLBAR_ROW is-flex-grow-0 is-flex is-align-items-center'}, row_items],
|
|
366
|
-
/*
|
|
367
|
-
*
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
+
/* The legend: a strip under the toolbar, ALWAYS there, one
|
|
374
|
+
* chip per topic. It is the graph's layer control, not a
|
|
375
|
+
* colour key: a chip shows or hides its topic, marks the main
|
|
376
|
+
* one, shows the loose records, highlights. Painted from the
|
|
377
|
+
* engine's EV_LEGEND_STATE, which is the truth about what is
|
|
378
|
+
* drawn. A strip and not an overlay because it is read
|
|
379
|
+
* AGAINST the graph, and an overlay would cover the thing it
|
|
380
|
+
* explains. Scrolls sideways on a narrow screen. */
|
|
381
|
+
['div', {class: 'GRAPH_LEGEND is-flex-grow-0',
|
|
382
|
+
style: 'display:flex; flex-wrap:nowrap; align-items:center; ' +
|
|
383
|
+
'gap:.35rem; padding:.3rem .5rem; overflow-x:auto; ' +
|
|
384
|
+
'min-height:2.2rem;'}, []],
|
|
373
385
|
['div', {class: `GRAPH_BODY is-flex-grow-1 ${padding}`, style: 'height:100%; min-height:0; overflow:hidden;'}, [
|
|
374
386
|
['div', {id: priv.canvas_id, class: `GRAPH_CANVAS graph-container`, style: 'height:100%; min-height:0;border: 1px solid var(--bulma-border-weak);border-radius:0.2rem;'}, [
|
|
375
387
|
]]
|
|
@@ -575,23 +587,6 @@ function make_toolbar(gobj)
|
|
|
575
587
|
* way back to the default depth. */
|
|
576
588
|
...yui_graph_fold_items(gobj, gobj_read_str_attr(gobj, "wide")),
|
|
577
589
|
|
|
578
|
-
/* Which colour is which topic. The port colour of a node encodes
|
|
579
|
-
* the topic it links to, which is the whole point of the graph and
|
|
580
|
-
* which nothing on screen explained. Clicking an entry focuses that
|
|
581
|
-
* topic, so the legend is also the way to say "show me these" —
|
|
582
|
-
* and clicking the focused one again clears it. */
|
|
583
|
-
['button', {class: 'GRAPH_LEGEND_BTN button ml-2',
|
|
584
|
-
title: t('legend'), 'aria-label': t('legend'),
|
|
585
|
-
'data-i18n-title': 'legend', 'data-i18n-aria-label': 'legend'}, [
|
|
586
|
-
['i', {class: 'yi-square'}],
|
|
587
|
-
['span', {class: 'is-hidden-mobile', style: 'padding-left:5px;', i18n: 'legend'}, 'legend']
|
|
588
|
-
], {
|
|
589
|
-
click: (evt) => {
|
|
590
|
-
evt.stopPropagation();
|
|
591
|
-
gobj_send_event(gobj, "EV_TOGGLE_LEGEND", {}, gobj);
|
|
592
|
-
}
|
|
593
|
-
}],
|
|
594
|
-
|
|
595
590
|
/* Inspect the treedb's raw tranger json in the lazy tree viewer
|
|
596
591
|
* (print-tranger on the C_NODE service). A treedb can be huge, so
|
|
597
592
|
* the viewer drills in on demand — see open_json_viewer. */
|
|
@@ -2345,72 +2340,194 @@ function refresh_legend(gobj)
|
|
|
2345
2340
|
return;
|
|
2346
2341
|
}
|
|
2347
2342
|
|
|
2348
|
-
let
|
|
2349
|
-
gobj_read_attr(priv.gobj_nodes_tree, "descs") : null;
|
|
2343
|
+
let state = priv._legend_state;
|
|
2350
2344
|
$legend.textContent = "";
|
|
2351
|
-
if(!
|
|
2352
|
-
return;
|
|
2345
|
+
if(!state || !is_array(state.topics)) {
|
|
2346
|
+
return; /* nothing drawn yet: the engine has not spoken */
|
|
2353
2347
|
}
|
|
2354
2348
|
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2349
|
+
/* The main topic leads the strip: it is the trunk everything else
|
|
2350
|
+
* hangs from, and the eye reads the strip left to right. */
|
|
2351
|
+
let topics = state.topics.slice().sort((a, b) => {
|
|
2352
|
+
let am = (a.topic === state.main_topic)? 0 : 1;
|
|
2353
|
+
let bm = (b.topic === state.main_topic)? 0 : 1;
|
|
2354
|
+
return am - bm;
|
|
2355
|
+
});
|
|
2356
|
+
|
|
2357
|
+
for(let entry of topics) {
|
|
2358
|
+
let topic_name = entry.topic;
|
|
2359
|
+
let is_main = (topic_name === state.main_topic);
|
|
2360
|
+
let focused = (priv.focus_topic === topic_name);
|
|
2361
|
+
let hidden = !!entry.hidden;
|
|
2362
|
+
|
|
2363
|
+
/* A control with a small, named target for each of the things
|
|
2364
|
+
* the strip can do, so a finger lands on ONE of them:
|
|
2365
|
+
* the body show / hide (the main topic cannot be hidden)
|
|
2366
|
+
* ★ make it the main topic
|
|
2367
|
+
* +N show / hide its loose records
|
|
2368
|
+
* ⌖ highlight (the focus)
|
|
2369
|
+
* The names are DATA: a topic name carries no i18n key and is
|
|
2370
|
+
* never translated; the counts are numbers. */
|
|
2371
|
+
let controls = [];
|
|
2372
|
+
|
|
2373
|
+
controls.push(
|
|
2374
|
+
['span', {class: 'GRAPH_LEGEND_SWATCH',
|
|
2375
|
+
style: `display:inline-block; width:.8rem; height:.8rem; ` +
|
|
2376
|
+
`border-radius:3px; margin-right:.35rem; flex:0 0 auto; ` +
|
|
2377
|
+
`background:${entry.color || "#94a3b8"}; ` +
|
|
2378
|
+
`border:1px solid rgba(0,0,0,.25);` +
|
|
2379
|
+
(hidden? 'opacity:.35;' : '')}],
|
|
2380
|
+
['span', {class: 'GRAPH_LEGEND_NAME',
|
|
2381
|
+
style: hidden? 'text-decoration:line-through; opacity:.6;' : ''},
|
|
2382
|
+
topic_name],
|
|
2383
|
+
['span', {class: 'GRAPH_LEGEND_COUNT has-text-grey',
|
|
2384
|
+
style: 'margin-left:.35rem; font-size:.8em;'},
|
|
2385
|
+
hidden? `${entry.total}` : `${entry.visible}/${entry.total}`]
|
|
2386
|
+
);
|
|
2387
|
+
|
|
2388
|
+
/* Built as an object first: an attribute that is `undefined`
|
|
2389
|
+
* is still SET by createElement2 (to the string "undefined"),
|
|
2390
|
+
* and a `disabled="undefined"` button is a disabled button --
|
|
2391
|
+
* every chip was dead except its star. */
|
|
2392
|
+
let body_attrs = {
|
|
2393
|
+
class: 'GRAPH_LEGEND_ITEM button is-small' +
|
|
2394
|
+
(focused? ' is-primary is-light' : '') +
|
|
2395
|
+
(is_main? ' GRAPH_LEGEND_MAIN' : ''),
|
|
2396
|
+
type: 'button',
|
|
2397
|
+
style: 'gap:0; flex:0 0 auto;',
|
|
2398
|
+
title: is_main? t('main topic') : (hidden? t('show topic') : t('hide topic')),
|
|
2399
|
+
'aria-label': topic_name,
|
|
2400
|
+
'aria-pressed': hidden? 'false' : 'true',
|
|
2401
|
+
};
|
|
2402
|
+
if(is_main) {
|
|
2403
|
+
body_attrs.disabled = 'disabled';
|
|
2358
2404
|
}
|
|
2359
|
-
|
|
2360
|
-
|
|
2405
|
+
let $body = createElement2(
|
|
2406
|
+
['button', body_attrs, controls, {
|
|
2407
|
+
click: (evt) => {
|
|
2408
|
+
evt.stopPropagation();
|
|
2409
|
+
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2410
|
+
{topic: topic_name, action: "toggle"}, gobj);
|
|
2411
|
+
}
|
|
2412
|
+
}]
|
|
2413
|
+
);
|
|
2414
|
+
|
|
2415
|
+
let extras = [];
|
|
2416
|
+
|
|
2417
|
+
/* The star: filled on the main one, hollow on the others,
|
|
2418
|
+
* where it moves the star. On a main topic the READER chose it
|
|
2419
|
+
* is a button too: pressing it hands the choice back to the
|
|
2420
|
+
* graph (deduced again). On a deduced one it is a mark. */
|
|
2421
|
+
if(is_main && state.main_chosen) {
|
|
2422
|
+
extras.push(['button', {class: 'GRAPH_LEGEND_STAR button is-small is-warning is-light',
|
|
2423
|
+
type: 'button', style: 'padding:0 .4rem;',
|
|
2424
|
+
title: t('main topic'), 'data-i18n-title': 'main topic',
|
|
2425
|
+
'aria-label': t('main topic'), 'aria-pressed': 'true'},
|
|
2426
|
+
'★', {
|
|
2427
|
+
click: (evt) => {
|
|
2428
|
+
evt.stopPropagation();
|
|
2429
|
+
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2430
|
+
{topic: "", action: "main"}, gobj);
|
|
2431
|
+
}
|
|
2432
|
+
}]);
|
|
2433
|
+
} else if(is_main) {
|
|
2434
|
+
extras.push(['span', {class: 'GRAPH_LEGEND_STAR button is-small is-static',
|
|
2435
|
+
style: 'padding:0 .4rem;',
|
|
2436
|
+
title: t('main topic'), 'data-i18n-title': 'main topic'},
|
|
2437
|
+
'★']);
|
|
2438
|
+
} else if(!hidden) {
|
|
2439
|
+
extras.push(['button', {class: 'GRAPH_LEGEND_STAR button is-small',
|
|
2440
|
+
type: 'button', style: 'padding:0 .4rem;',
|
|
2441
|
+
title: t('main topic'), 'data-i18n-title': 'main topic',
|
|
2442
|
+
'aria-label': t('main topic')},
|
|
2443
|
+
'☆', {
|
|
2444
|
+
click: (evt) => {
|
|
2445
|
+
evt.stopPropagation();
|
|
2446
|
+
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2447
|
+
{topic: topic_name, action: "main"}, gobj);
|
|
2448
|
+
}
|
|
2449
|
+
}]);
|
|
2361
2450
|
}
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
class: '
|
|
2451
|
+
|
|
2452
|
+
/* Loose records: the ones that should hang from the main tree
|
|
2453
|
+
* and do not. Only where there are any, and only for a topic
|
|
2454
|
+
* the schema hangs from the main one. */
|
|
2455
|
+
if(!hidden && entry.linked && entry.loose > 0) {
|
|
2456
|
+
extras.push(['button', {
|
|
2457
|
+
class: 'GRAPH_LEGEND_LOOSE button is-small' +
|
|
2458
|
+
(entry.loose_shown? ' is-warning is-light' : ''),
|
|
2459
|
+
type: 'button', style: 'padding:0 .45rem;',
|
|
2460
|
+
title: t('loose records'), 'data-i18n-title': 'loose records',
|
|
2461
|
+
'aria-label': t('loose records'),
|
|
2462
|
+
'aria-pressed': entry.loose_shown? 'true' : 'false'
|
|
2463
|
+
}, `+${entry.loose}`, {
|
|
2464
|
+
click: (evt) => {
|
|
2465
|
+
evt.stopPropagation();
|
|
2466
|
+
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2467
|
+
{topic: topic_name, action: "loose"}, gobj);
|
|
2468
|
+
}
|
|
2469
|
+
}]);
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
if(!hidden) {
|
|
2473
|
+
extras.push(['button', {
|
|
2474
|
+
class: 'GRAPH_LEGEND_FOCUS button is-small' +
|
|
2369
2475
|
(focused? ' is-primary is-light' : ''),
|
|
2370
|
-
|
|
2371
|
-
'
|
|
2476
|
+
type: 'button', style: 'padding:0 .4rem;',
|
|
2477
|
+
title: t('highlight topic'), 'data-i18n-title': 'highlight topic',
|
|
2478
|
+
'aria-label': t('highlight topic'),
|
|
2372
2479
|
'aria-pressed': focused? 'true' : 'false'
|
|
2373
|
-
}, [
|
|
2374
|
-
['span', {class: 'GRAPH_LEGEND_SWATCH',
|
|
2375
|
-
style: `display:inline-block; width:.8rem; height:.8rem; ` +
|
|
2376
|
-
`border-radius:3px; margin-right:.4rem; ` +
|
|
2377
|
-
`background:${desc.color}; ` +
|
|
2378
|
-
`border:1px solid rgba(0,0,0,.25);`}],
|
|
2379
|
-
/* The topic name is DATA: it carries no i18n key and is
|
|
2380
|
-
* never translated. */
|
|
2381
|
-
['span', {}, topic_name]
|
|
2382
|
-
], {
|
|
2480
|
+
}, [['i', {class: 'yi-location-crosshairs'}]], {
|
|
2383
2481
|
click: (evt) => {
|
|
2384
2482
|
evt.stopPropagation();
|
|
2385
|
-
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2483
|
+
gobj_send_event(gobj, "EV_LEGEND_TOPIC",
|
|
2484
|
+
{topic: topic_name, action: "focus"}, gobj);
|
|
2386
2485
|
}
|
|
2387
|
-
}]
|
|
2486
|
+
}]);
|
|
2487
|
+
}
|
|
2488
|
+
|
|
2489
|
+
let $chip = createElement2(
|
|
2490
|
+
['div', {class: 'GRAPH_LEGEND_CHIP buttons has-addons',
|
|
2491
|
+
style: 'margin:0; flex:0 0 auto; flex-wrap:nowrap;'},
|
|
2492
|
+
[$body].concat(extras.map((spec) => createElement2(spec)))]
|
|
2388
2493
|
);
|
|
2389
|
-
$legend.appendChild($
|
|
2494
|
+
$legend.appendChild($chip);
|
|
2390
2495
|
}
|
|
2391
2496
|
}
|
|
2392
2497
|
|
|
2498
|
+
/************************************************************
|
|
2499
|
+
* The engine said what is drawn: repaint the strip.
|
|
2500
|
+
************************************************************/
|
|
2501
|
+
function ac_legend_state(gobj, event, kw, src)
|
|
2502
|
+
{
|
|
2503
|
+
let priv = gobj.priv;
|
|
2504
|
+
priv._legend_state = kw || null;
|
|
2505
|
+
refresh_legend(gobj);
|
|
2506
|
+
return 0;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2393
2509
|
/************************************************************
|
|
2394
2510
|
*
|
|
2395
2511
|
************************************************************/
|
|
2396
|
-
|
|
2512
|
+
/************************************************************
|
|
2513
|
+
* One of the legend's settings changed: write it, SAVE it (they
|
|
2514
|
+
* are the reader's, per treedb) and tell the engine.
|
|
2515
|
+
************************************************************/
|
|
2516
|
+
function set_legend_list_attr(gobj, name, event_name, topics)
|
|
2397
2517
|
{
|
|
2398
|
-
let
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
log_error(`${gobj_short_name(gobj)}: no legend strip to toggle`);
|
|
2405
|
-
return -1;
|
|
2406
|
-
}
|
|
2407
|
-
if($legend.classList.contains("is-hidden")) {
|
|
2408
|
-
refresh_legend(gobj);
|
|
2409
|
-
$legend.classList.remove("is-hidden");
|
|
2410
|
-
} else {
|
|
2411
|
-
$legend.classList.add("is-hidden");
|
|
2518
|
+
let priv = gobj.priv;
|
|
2519
|
+
|
|
2520
|
+
gobj_write_attr(gobj, name, topics);
|
|
2521
|
+
gobj_save_persistent_attrs(gobj, name);
|
|
2522
|
+
if(priv.gobj_nodes_tree) {
|
|
2523
|
+
gobj_send_event(priv.gobj_nodes_tree, event_name, {topics: topics}, gobj);
|
|
2412
2524
|
}
|
|
2413
|
-
|
|
2525
|
+
}
|
|
2526
|
+
|
|
2527
|
+
function legend_list_attr(gobj, name)
|
|
2528
|
+
{
|
|
2529
|
+
let list = gobj_read_attr(gobj, name);
|
|
2530
|
+
return is_array(list)? list.slice() : [];
|
|
2414
2531
|
}
|
|
2415
2532
|
|
|
2416
2533
|
/************************************************************
|
|
@@ -2422,11 +2539,60 @@ function ac_legend_topic(gobj, event, kw, src)
|
|
|
2422
2539
|
{
|
|
2423
2540
|
let priv = gobj.priv;
|
|
2424
2541
|
let topic = (kw && kw.topic) || "";
|
|
2425
|
-
|
|
2542
|
+
let action = (kw && kw.action) || "focus";
|
|
2543
|
+
if(!topic && action !== "main") {
|
|
2426
2544
|
log_error(`${gobj_short_name(gobj)}: legend click with no topic`);
|
|
2427
2545
|
return -1;
|
|
2428
2546
|
}
|
|
2429
2547
|
|
|
2548
|
+
let state = priv._legend_state || {};
|
|
2549
|
+
|
|
2550
|
+
switch(action) {
|
|
2551
|
+
case "toggle": {
|
|
2552
|
+
/* Show or hide the topic. Never the main one: hiding the
|
|
2553
|
+
* trunk turns everything into roots, which is the pile. */
|
|
2554
|
+
if(topic === state.main_topic) {
|
|
2555
|
+
log_error(`${gobj_short_name(gobj)}: the main topic '${topic}' cannot be hidden`);
|
|
2556
|
+
return -1;
|
|
2557
|
+
}
|
|
2558
|
+
let hidden = legend_list_attr(gobj, "hidden_topics");
|
|
2559
|
+
if(str_in_list(hidden, topic)) {
|
|
2560
|
+
delete_from_list(hidden, topic);
|
|
2561
|
+
} else {
|
|
2562
|
+
hidden.push(topic);
|
|
2563
|
+
}
|
|
2564
|
+
set_legend_list_attr(gobj, "hidden_topics", "EV_SET_HIDDEN_TOPICS", hidden);
|
|
2565
|
+
return 0;
|
|
2566
|
+
}
|
|
2567
|
+
|
|
2568
|
+
case "loose": {
|
|
2569
|
+
let loose = legend_list_attr(gobj, "loose_topics");
|
|
2570
|
+
if(str_in_list(loose, topic)) {
|
|
2571
|
+
delete_from_list(loose, topic);
|
|
2572
|
+
} else {
|
|
2573
|
+
loose.push(topic);
|
|
2574
|
+
}
|
|
2575
|
+
set_legend_list_attr(gobj, "loose_topics", "EV_SET_LOOSE_TOPICS", loose);
|
|
2576
|
+
return 0;
|
|
2577
|
+
}
|
|
2578
|
+
|
|
2579
|
+
case "main": {
|
|
2580
|
+
gobj_write_str_attr(gobj, "main_topic", topic);
|
|
2581
|
+
gobj_save_persistent_attrs(gobj, "main_topic");
|
|
2582
|
+
if(priv.gobj_nodes_tree) {
|
|
2583
|
+
gobj_send_event(priv.gobj_nodes_tree, "EV_SET_MAIN_TOPIC", {topic: topic}, gobj);
|
|
2584
|
+
}
|
|
2585
|
+
return 0;
|
|
2586
|
+
}
|
|
2587
|
+
|
|
2588
|
+
case "focus":
|
|
2589
|
+
break;
|
|
2590
|
+
|
|
2591
|
+
default:
|
|
2592
|
+
log_error(`${gobj_short_name(gobj)}: legend action unknown: ${action}`);
|
|
2593
|
+
return -1;
|
|
2594
|
+
}
|
|
2595
|
+
|
|
2430
2596
|
let next = (priv.focus_topic === topic)? "" : topic;
|
|
2431
2597
|
|
|
2432
2598
|
/* APPLY, then announce — in that order, and both halves are needed.
|
|
@@ -2528,7 +2694,14 @@ function ac_find_result(gobj, event, kw, src)
|
|
|
2528
2694
|
return 0;
|
|
2529
2695
|
}
|
|
2530
2696
|
|
|
2531
|
-
|
|
2697
|
+
let text = t("matches", {count: (kw && kw.matches) || 0});
|
|
2698
|
+
/* Matches in HIDDEN topics, counted apart: "0" alone reads as
|
|
2699
|
+
* "does not exist" when it means "is hidden". */
|
|
2700
|
+
let hidden = (kw && kw.hidden_matches) || 0;
|
|
2701
|
+
if(hidden > 0) {
|
|
2702
|
+
text += ` (+${hidden} ${t("hidden topics")})`;
|
|
2703
|
+
}
|
|
2704
|
+
$count.textContent = text;
|
|
2532
2705
|
$result.classList.remove("is-hidden");
|
|
2533
2706
|
return 0;
|
|
2534
2707
|
}
|
|
@@ -2537,6 +2710,18 @@ function ac_set_focus_topic(gobj, event, kw, src)
|
|
|
2537
2710
|
{
|
|
2538
2711
|
let priv = gobj.priv;
|
|
2539
2712
|
priv.focus_topic = (kw && kw.topic) || "";
|
|
2713
|
+
|
|
2714
|
+
/* The URL wins over the strip: a route that lands on a hidden
|
|
2715
|
+
* topic shows it first, or it would highlight nothing and say
|
|
2716
|
+
* nothing about why. */
|
|
2717
|
+
if(priv.focus_topic) {
|
|
2718
|
+
let hidden = legend_list_attr(gobj, "hidden_topics");
|
|
2719
|
+
if(str_in_list(hidden, priv.focus_topic)) {
|
|
2720
|
+
delete_from_list(hidden, priv.focus_topic);
|
|
2721
|
+
set_legend_list_attr(gobj, "hidden_topics", "EV_SET_HIDDEN_TOPICS", hidden);
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
|
|
2540
2725
|
if(priv.gobj_nodes_tree) {
|
|
2541
2726
|
gobj_send_event(
|
|
2542
2727
|
priv.gobj_nodes_tree,
|
|
@@ -2547,11 +2732,7 @@ function ac_set_focus_topic(gobj, event, kw, src)
|
|
|
2547
2732
|
}
|
|
2548
2733
|
/* Keep the legend's mark on the topic that is actually focused —
|
|
2549
2734
|
* including when the focus arrives from the URL and not from a click. */
|
|
2550
|
-
|
|
2551
|
-
let $legend = $container? $container.querySelector(".GRAPH_LEGEND") : null;
|
|
2552
|
-
if($legend && !$legend.classList.contains("is-hidden")) {
|
|
2553
|
-
refresh_legend(gobj);
|
|
2554
|
-
}
|
|
2735
|
+
refresh_legend(gobj);
|
|
2555
2736
|
return 0;
|
|
2556
2737
|
}
|
|
2557
2738
|
|
|
@@ -2644,8 +2825,8 @@ function create_gclass(gclass_name)
|
|
|
2644
2825
|
["EV_EXPAND_ALL", ac_expand_all, null],
|
|
2645
2826
|
["EV_COLLAPSE_ALL", ac_collapse_all, null],
|
|
2646
2827
|
["EV_LAYOUT_AUTOSET", ac_layout_autoset, null],
|
|
2647
|
-
["EV_TOGGLE_LEGEND", ac_toggle_legend, null],
|
|
2648
2828
|
["EV_LEGEND_TOPIC", ac_legend_topic, null],
|
|
2829
|
+
["EV_LEGEND_STATE", ac_legend_state, null],
|
|
2649
2830
|
["EV_FIND_RESULT", ac_find_result, null],
|
|
2650
2831
|
["EV_SHOW", ac_show, null],
|
|
2651
2832
|
["EV_HIDE", ac_hide, null],
|
|
@@ -2686,8 +2867,8 @@ function create_gclass(gclass_name)
|
|
|
2686
2867
|
["EV_COLLAPSE_ALL", 0],
|
|
2687
2868
|
["EV_FIND_RESULT", 0],
|
|
2688
2869
|
["EV_LAYOUT_AUTOSET", 0],
|
|
2689
|
-
["EV_TOGGLE_LEGEND", 0],
|
|
2690
2870
|
["EV_LEGEND_TOPIC", 0],
|
|
2871
|
+
["EV_LEGEND_STATE", 0],
|
|
2691
2872
|
["EV_TOPIC_SELECTED",
|
|
2692
2873
|
event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],
|
|
2693
2874
|
["EV_OPERATION_MODE_CHANGED",
|