@yuneta/gobj-ui 7.23.157 → 7.23.158
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 +32 -14
- package/dist/gobj-ui.cjs.js +244 -82
- package/dist/gobj-ui.es.js +244 -82
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +217 -93
- package/src/c_yui_treedb_graph.js +91 -11
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -543,8 +543,9 @@ let PRIVATE_DATA = {
|
|
|
543
543
|
// it exists to diff the repaint)
|
|
544
544
|
_pending_focus_topic: null, // focus requested before data was loaded
|
|
545
545
|
_pending_focus_all: false, // ...and whether it reveals the whole topic
|
|
546
|
-
|
|
547
|
-
|
|
546
|
+
_find_term: "", // the find box's term, repainted after every reconcile
|
|
547
|
+
_find_current: "", // node id the last Enter of the find centred on
|
|
548
|
+
_find_found: null, // ...and its last count (see find_matches)
|
|
548
549
|
_layout_asked: "", // layout the host asked for at create (see mt_create)
|
|
549
550
|
_nodes_total: 0, // records of the treedb (auto_layout)
|
|
550
551
|
_nodes_placed: 0, // ...of which carry a saved position
|
|
@@ -3654,6 +3655,18 @@ function graph_focus_topic(gobj, topic, reveal_all)
|
|
|
3654
3655
|
let model = priv._fold_model;
|
|
3655
3656
|
let state = priv._fold_state;
|
|
3656
3657
|
|
|
3658
|
+
/* The two share the highlight slot. A topic takes it from the
|
|
3659
|
+
* find; an EMPTY topic (nothing focused) leaves a live find
|
|
3660
|
+
* alone, or clearing the legend's mark would wipe the find. */
|
|
3661
|
+
if(empty_string(topic) && priv._find_term) {
|
|
3662
|
+
priv._focus_topic = null;
|
|
3663
|
+
return;
|
|
3664
|
+
}
|
|
3665
|
+
if(!empty_string(topic)) {
|
|
3666
|
+
priv._find_term = "";
|
|
3667
|
+
priv._find_current = "";
|
|
3668
|
+
}
|
|
3669
|
+
|
|
3657
3670
|
/* "Show me these": the ones on screen are highlighted, and the
|
|
3658
3671
|
* hidden ones are opened up to. How many depends on who asks.
|
|
3659
3672
|
* A click on the LEGEND (`reveal_all`) means every record of the
|
|
@@ -3689,18 +3702,18 @@ function graph_focus_topic(gobj, topic, reveal_all)
|
|
|
3689
3702
|
priv._focus_topic = topic || null;
|
|
3690
3703
|
|
|
3691
3704
|
reconcile_fold(gobj, {}).then(() => {
|
|
3692
|
-
apply_focus_ids(gobj, keys, "focus topic");
|
|
3705
|
+
apply_focus_ids(gobj, keys, "focus topic", true);
|
|
3693
3706
|
});
|
|
3694
3707
|
}
|
|
3695
3708
|
|
|
3696
3709
|
/************************************************************
|
|
3697
|
-
* Paint the highlight on these records (by model key) and
|
|
3698
|
-
* the first of them in the middle. Shared by the
|
|
3699
|
-
* topic focus
|
|
3700
|
-
*
|
|
3701
|
-
*
|
|
3710
|
+
* Paint the highlight on these records (by model key) and, with
|
|
3711
|
+
* `center`, put the first of them in the middle. Shared by the
|
|
3712
|
+
* find and the topic focus. Keys that are not on screen are
|
|
3713
|
+
* skipped: a match beyond the page a reveal opened is counted,
|
|
3714
|
+
* not painted.
|
|
3702
3715
|
************************************************************/
|
|
3703
|
-
function apply_focus_ids(gobj, keys, what)
|
|
3716
|
+
function apply_focus_ids(gobj, keys, what, center)
|
|
3704
3717
|
{
|
|
3705
3718
|
let priv = gobj.priv;
|
|
3706
3719
|
let graph = priv.graph;
|
|
@@ -3734,7 +3747,7 @@ function apply_focus_ids(gobj, keys, what)
|
|
|
3734
3747
|
graph.setElementState(states);
|
|
3735
3748
|
}
|
|
3736
3749
|
apply_node_highlight(gobj, prev_ids, ids);
|
|
3737
|
-
if(ids.length) {
|
|
3750
|
+
if(center && ids.length) {
|
|
3738
3751
|
yui_graph_center_on(graph, ids[0]);
|
|
3739
3752
|
}
|
|
3740
3753
|
} catch(e) {
|
|
@@ -3753,94 +3766,186 @@ function node_id_of_key(gobj, key)
|
|
|
3753
3766
|
}
|
|
3754
3767
|
|
|
3755
3768
|
/************************************************************
|
|
3756
|
-
*
|
|
3757
|
-
*
|
|
3758
|
-
*
|
|
3759
|
-
*
|
|
3760
|
-
*
|
|
3761
|
-
*
|
|
3769
|
+
* The find box: highlight the cards ON SCREEN whose name, id or
|
|
3770
|
+
* topic contains `term`, and change nothing else -- no group is
|
|
3771
|
+
* opened, no layout runs, the camera does not move. The graph the
|
|
3772
|
+
* reader arranged is the graph they are searching; emptying the
|
|
3773
|
+
* box takes the amber off and leaves it exactly as it was.
|
|
3774
|
+
*
|
|
3775
|
+
* It used to search the whole treedb and unfold a page of what it
|
|
3776
|
+
* found, which re-laid the graph out on every keystroke and left
|
|
3777
|
+
* the unfolded groups behind when the box was cleared. Opening up
|
|
3778
|
+
* to a topic is the legend's focus (graph_focus_topic); this only
|
|
3779
|
+
* LOOKS.
|
|
3780
|
+
*
|
|
3781
|
+
* The term is kept and repainted after every reconcile (see
|
|
3782
|
+
* reconcile_fold_now): a group opened by hand shows its matches
|
|
3783
|
+
* already lit, and the count follows what is on screen.
|
|
3762
3784
|
*
|
|
3763
3785
|
* It shares the highlight slot with graph_focus_topic on purpose —
|
|
3764
|
-
* two amber sets at once would say nothing about either.
|
|
3765
|
-
*
|
|
3766
|
-
*
|
|
3767
|
-
*
|
|
3786
|
+
* two amber sets at once would say nothing about either. Matching
|
|
3787
|
+
* reads the node's LABEL and not only its id: on a topic keyed by
|
|
3788
|
+
* rowid or by a qualified path, the id is a counter and the name a
|
|
3789
|
+
* human knows is elsewhere (see node_label).
|
|
3768
3790
|
************************************************************/
|
|
3769
3791
|
function graph_find_nodes(gobj, term)
|
|
3770
3792
|
{
|
|
3771
3793
|
let priv = gobj.priv;
|
|
3772
|
-
let
|
|
3773
|
-
|
|
3774
|
-
|
|
3775
|
-
|
|
3794
|
+
let next = empty_string(term)? "" : String(term);
|
|
3795
|
+
let was = priv._find_term;
|
|
3796
|
+
|
|
3797
|
+
priv._find_term = next;
|
|
3798
|
+
priv._find_current = "";
|
|
3799
|
+
priv._find_found = null;
|
|
3800
|
+
|
|
3801
|
+
let ready = priv.graph && priv.graph_rendered && priv._fold_model;
|
|
3802
|
+
if(!next) {
|
|
3803
|
+
/* Only a find that HELD the slot is taken off: an empty box
|
|
3804
|
+
* that was already empty must not wipe a topic focus. */
|
|
3805
|
+
if(was && ready && !priv._focus_topic) {
|
|
3806
|
+
apply_focus_ids(gobj, [], "find", false);
|
|
3807
|
+
}
|
|
3808
|
+
publish_find_result(gobj);
|
|
3809
|
+
return;
|
|
3810
|
+
}
|
|
3811
|
+
|
|
3812
|
+
priv._focus_topic = null; /* a find takes over the highlight */
|
|
3813
|
+
if(!ready) {
|
|
3814
|
+
/* Painted by the first reconcile, when the data arrives. */
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3817
|
+
refresh_find(gobj, fold_visible_set(priv._fold_model, priv._fold_state));
|
|
3818
|
+
}
|
|
3819
|
+
|
|
3820
|
+
/************************************************************
|
|
3821
|
+
* Repaint the find's highlight over the `visible` set and publish
|
|
3822
|
+
* the count. A no-op while no term is live, so the topic focus
|
|
3823
|
+
* keeps the slot.
|
|
3824
|
+
************************************************************/
|
|
3825
|
+
function refresh_find(gobj, visible)
|
|
3826
|
+
{
|
|
3827
|
+
let priv = gobj.priv;
|
|
3828
|
+
if(!priv._find_term) {
|
|
3829
|
+
return;
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
let found = find_matches(gobj, priv._find_term, visible);
|
|
3833
|
+
apply_focus_ids(gobj, found.keys, "find", false);
|
|
3834
|
+
if(priv._find_current && (priv._focus_ids || []).indexOf(priv._find_current) < 0) {
|
|
3835
|
+
priv._find_current = "";
|
|
3776
3836
|
}
|
|
3837
|
+
priv._find_found = found;
|
|
3838
|
+
publish_find_result(gobj);
|
|
3839
|
+
}
|
|
3777
3840
|
|
|
3841
|
+
/************************************************************
|
|
3842
|
+
* The records matching `term`: the keys ON SCREEN, and how many
|
|
3843
|
+
* more match that are NOT -- folded away in the fold model, or in
|
|
3844
|
+
* a hidden topic. Those two are only counted: "0" alone would read
|
|
3845
|
+
* as "does not exist" when it means "is not on screen".
|
|
3846
|
+
************************************************************/
|
|
3847
|
+
function find_matches(gobj, term, visible)
|
|
3848
|
+
{
|
|
3849
|
+
let priv = gobj.priv;
|
|
3778
3850
|
let model = priv._fold_model;
|
|
3779
|
-
let
|
|
3851
|
+
let found = {keys: [], folded: 0, hidden: 0};
|
|
3852
|
+
if(!model || empty_string(term)) {
|
|
3853
|
+
return found;
|
|
3854
|
+
}
|
|
3780
3855
|
|
|
3781
|
-
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
|
|
3786
|
-
|
|
3787
|
-
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
3792
|
-
|
|
3793
|
-
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
|
|
3797
|
-
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
if(matches(node.topic_name, node.record || {})) {
|
|
3804
|
-
keys.push(node.key);
|
|
3856
|
+
let needle = String(term).toLowerCase();
|
|
3857
|
+
let matches = (topic_name, record) => {
|
|
3858
|
+
let label = "";
|
|
3859
|
+
try {
|
|
3860
|
+
label = node_label(priv.descs[topic_name] || {}, record) || "";
|
|
3861
|
+
} catch(e) {
|
|
3862
|
+
label = "";
|
|
3863
|
+
}
|
|
3864
|
+
let haystack = [
|
|
3865
|
+
label,
|
|
3866
|
+
record.id,
|
|
3867
|
+
topic_name
|
|
3868
|
+
].filter((v) => typeof v === "string").join(" ").toLowerCase();
|
|
3869
|
+
return haystack.includes(needle);
|
|
3870
|
+
};
|
|
3871
|
+
|
|
3872
|
+
for(let node of model.nodes.values()) {
|
|
3873
|
+
if(matches(node.topic_name, node.record || {})) {
|
|
3874
|
+
if(visible.has(node.key)) {
|
|
3875
|
+
found.keys.push(node.key);
|
|
3876
|
+
} else {
|
|
3877
|
+
found.folded++;
|
|
3805
3878
|
}
|
|
3806
3879
|
}
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
if(is_object(record) && matches(topic_name, record)) {
|
|
3813
|
-
hidden_matches++;
|
|
3814
|
-
}
|
|
3880
|
+
}
|
|
3881
|
+
for(let topic_name of model.hidden) {
|
|
3882
|
+
for(let record of (priv.records[topic_name] || [])) {
|
|
3883
|
+
if(is_object(record) && matches(topic_name, record)) {
|
|
3884
|
+
found.hidden++;
|
|
3815
3885
|
}
|
|
3816
3886
|
}
|
|
3817
3887
|
}
|
|
3818
|
-
|
|
3888
|
+
return found;
|
|
3889
|
+
}
|
|
3819
3890
|
|
|
3820
|
-
|
|
3821
|
-
|
|
3822
|
-
|
|
3823
|
-
|
|
3824
|
-
|
|
3825
|
-
|
|
3826
|
-
|
|
3827
|
-
|
|
3828
|
-
|
|
3829
|
-
|
|
3830
|
-
|
|
3831
|
-
break;
|
|
3832
|
-
}
|
|
3833
|
-
fold_reveal(model, state, key);
|
|
3834
|
-
revealed++;
|
|
3891
|
+
/************************************************************
|
|
3892
|
+
* The lit cards in reading order: top to bottom, then left to
|
|
3893
|
+
* right. The order Enter walks, and the one the "k/N" counts in.
|
|
3894
|
+
************************************************************/
|
|
3895
|
+
function find_order(gobj)
|
|
3896
|
+
{
|
|
3897
|
+
let priv = gobj.priv;
|
|
3898
|
+
let graph = priv.graph;
|
|
3899
|
+
let ids = (priv._focus_ids || []).slice();
|
|
3900
|
+
if(!graph) {
|
|
3901
|
+
return ids;
|
|
3835
3902
|
}
|
|
3836
3903
|
|
|
3837
|
-
|
|
3904
|
+
let pos = {};
|
|
3905
|
+
for(let id of ids) {
|
|
3906
|
+
let p = null;
|
|
3907
|
+
try {
|
|
3908
|
+
p = graph.getElementPosition(id);
|
|
3909
|
+
} catch(e) {
|
|
3910
|
+
p = null;
|
|
3911
|
+
}
|
|
3912
|
+
pos[id] = p || [0, 0];
|
|
3913
|
+
}
|
|
3914
|
+
ids.sort((a, b) => (pos[a][1] - pos[b][1]) || (pos[a][0] - pos[b][0]));
|
|
3915
|
+
return ids;
|
|
3916
|
+
}
|
|
3838
3917
|
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3918
|
+
/************************************************************
|
|
3919
|
+
* Enter in the find box: centre the next lit card (`back`: the
|
|
3920
|
+
* previous one). The one camera move of the find, and the reader
|
|
3921
|
+
* asks for it: the highlight alone cannot take anybody to a match
|
|
3922
|
+
* that is outside the frame.
|
|
3923
|
+
************************************************************/
|
|
3924
|
+
function graph_find_step(gobj, back)
|
|
3925
|
+
{
|
|
3926
|
+
let priv = gobj.priv;
|
|
3927
|
+
let graph = priv.graph;
|
|
3928
|
+
if(!graph || !priv._find_term) {
|
|
3929
|
+
return;
|
|
3930
|
+
}
|
|
3931
|
+
let ids = find_order(gobj);
|
|
3932
|
+
if(ids.length === 0) {
|
|
3933
|
+
return;
|
|
3934
|
+
}
|
|
3842
3935
|
|
|
3843
|
-
|
|
3936
|
+
let i = ids.indexOf(priv._find_current);
|
|
3937
|
+
if(i < 0) {
|
|
3938
|
+
i = back? ids.length - 1 : 0;
|
|
3939
|
+
} else {
|
|
3940
|
+
i = (i + (back? ids.length - 1 : 1)) % ids.length;
|
|
3941
|
+
}
|
|
3942
|
+
priv._find_current = ids[i];
|
|
3943
|
+
try {
|
|
3944
|
+
yui_graph_center_on(graph, ids[i]);
|
|
3945
|
+
} catch(e) {
|
|
3946
|
+
log_error(`${gobj_short_name(gobj)}: find step failed: ${e}`);
|
|
3947
|
+
}
|
|
3948
|
+
publish_find_result(gobj);
|
|
3844
3949
|
}
|
|
3845
3950
|
|
|
3846
3951
|
async function graph_zoom_in(gobj)
|
|
@@ -9648,6 +9753,7 @@ async function reconcile_fold_now(gobj, opts)
|
|
|
9648
9753
|
history_resume(gobj);
|
|
9649
9754
|
}
|
|
9650
9755
|
publish_legend_state(gobj, visible);
|
|
9756
|
+
refresh_find(gobj, visible);
|
|
9651
9757
|
return changed;
|
|
9652
9758
|
}
|
|
9653
9759
|
|
|
@@ -10223,11 +10329,6 @@ function ac_load_data(gobj, event, kw, src)
|
|
|
10223
10329
|
priv._pending_focus_all = false;
|
|
10224
10330
|
graph_focus_topic(gobj, ft, all);
|
|
10225
10331
|
}
|
|
10226
|
-
if(priv._pending_find !== null) {
|
|
10227
|
-
let term = priv._pending_find;
|
|
10228
|
-
priv._pending_find = null;
|
|
10229
|
-
publish_find_result(gobj, term, graph_find_nodes(gobj, term));
|
|
10230
|
-
}
|
|
10231
10332
|
});
|
|
10232
10333
|
}
|
|
10233
10334
|
|
|
@@ -11054,16 +11155,30 @@ function ac_node_dblclick(gobj, event, kw, src)
|
|
|
11054
11155
|
}
|
|
11055
11156
|
|
|
11056
11157
|
/************************************************************
|
|
11057
|
-
* Tell whoever asked how many
|
|
11058
|
-
*
|
|
11059
|
-
*
|
|
11158
|
+
* Tell whoever asked how many cards the term lit. The count is the
|
|
11159
|
+
* answer to the question the box asks; without it "nothing lit" and
|
|
11160
|
+
* "nothing matched" look the same.
|
|
11161
|
+
*
|
|
11162
|
+
* matches lit cards (on screen)
|
|
11163
|
+
* folded_matches matches folded away, not on screen
|
|
11164
|
+
* hidden_matches matches in hidden topics
|
|
11165
|
+
* current 1-based place of the card Enter centred on
|
|
11166
|
+
* among the lit ones (reading order), 0 = none
|
|
11060
11167
|
************************************************************/
|
|
11061
|
-
function publish_find_result(gobj
|
|
11168
|
+
function publish_find_result(gobj)
|
|
11062
11169
|
{
|
|
11170
|
+
let priv = gobj.priv;
|
|
11171
|
+
let found = priv._find_found || {keys: [], folded: 0, hidden: 0};
|
|
11172
|
+
let current = 0;
|
|
11173
|
+
if(priv._find_term && priv._find_current) {
|
|
11174
|
+
current = find_order(gobj).indexOf(priv._find_current) + 1;
|
|
11175
|
+
}
|
|
11063
11176
|
gobj_publish_event(gobj, "EV_FIND_RESULT", {
|
|
11064
|
-
term:
|
|
11065
|
-
matches:
|
|
11066
|
-
|
|
11177
|
+
term: priv._find_term,
|
|
11178
|
+
matches: priv._find_term? (priv._focus_ids || []).length : 0,
|
|
11179
|
+
folded_matches: found.folded,
|
|
11180
|
+
hidden_matches: found.hidden,
|
|
11181
|
+
current: current,
|
|
11067
11182
|
});
|
|
11068
11183
|
}
|
|
11069
11184
|
|
|
@@ -11072,9 +11187,16 @@ function publish_find_result(gobj, term, matches)
|
|
|
11072
11187
|
************************************************************/
|
|
11073
11188
|
function ac_find_nodes(gobj, event, kw, src)
|
|
11074
11189
|
{
|
|
11075
|
-
|
|
11076
|
-
|
|
11077
|
-
|
|
11190
|
+
graph_find_nodes(gobj, (kw && kw.text) || "");
|
|
11191
|
+
return 0;
|
|
11192
|
+
}
|
|
11193
|
+
|
|
11194
|
+
/************************************************************
|
|
11195
|
+
* Enter in the find box: {back: true} for Shift+Enter.
|
|
11196
|
+
************************************************************/
|
|
11197
|
+
function ac_find_next(gobj, event, kw, src)
|
|
11198
|
+
{
|
|
11199
|
+
graph_find_step(gobj, !!(kw && kw.back));
|
|
11078
11200
|
return 0;
|
|
11079
11201
|
}
|
|
11080
11202
|
|
|
@@ -11636,6 +11758,7 @@ function create_gclass(gclass_name)
|
|
|
11636
11758
|
["EV_ZOOM_SELECTION", ac_zoom_selection, null],
|
|
11637
11759
|
["EV_FOCUS_TOPIC", ac_focus_topic, null],
|
|
11638
11760
|
["EV_FIND_NODES", ac_find_nodes, null],
|
|
11761
|
+
["EV_FIND_NEXT", ac_find_next, null],
|
|
11639
11762
|
["EV_TOGGLE_FOLD", ac_toggle_fold, null],
|
|
11640
11763
|
["EV_SHOW_MORE", ac_show_more, null],
|
|
11641
11764
|
["EV_SET_FOLD_LEVEL", ac_set_fold_level, null],
|
|
@@ -11699,6 +11822,7 @@ function create_gclass(gclass_name)
|
|
|
11699
11822
|
["EV_ZOOM_SELECTION", 0],
|
|
11700
11823
|
["EV_FOCUS_TOPIC", 0],
|
|
11701
11824
|
["EV_FIND_NODES", 0],
|
|
11825
|
+
["EV_FIND_NEXT", 0],
|
|
11702
11826
|
["EV_FIND_RESULT", event_flag_t.EVF_OUTPUT_EVENT],
|
|
11703
11827
|
["EV_LAYOUT_AUTOSET", event_flag_t.EVF_OUTPUT_EVENT],
|
|
11704
11828
|
/* Optional: a host that does not persist the viewport is not
|
|
@@ -80,7 +80,7 @@ import {
|
|
|
80
80
|
} from "@yuneta/gobj-js";
|
|
81
81
|
|
|
82
82
|
|
|
83
|
-
import {attach_clear} from "./yui_inputs.js";
|
|
83
|
+
import {attach_clear, refresh_clear} from "./yui_inputs.js";
|
|
84
84
|
import {register_c_g6_nodes_tree} from "./c_g6_nodes_tree.js";
|
|
85
85
|
import {yui_toolbar, yui_toolbar_icon, YUI_TOOLBAR_ICON_SIZE} from "./yui_toolbar.js";
|
|
86
86
|
import {
|
|
@@ -982,11 +982,13 @@ function make_toolbar(gobj)
|
|
|
982
982
|
* Right: find a node.
|
|
983
983
|
*
|
|
984
984
|
* A graph of a few hundred records has no other way in: the only way
|
|
985
|
-
* to locate one was to read every card. The box
|
|
986
|
-
*
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
985
|
+
* to locate one was to read every card. The box lights every match
|
|
986
|
+
* ON SCREEN with the same amber the topic focus uses and changes
|
|
987
|
+
* nothing else (no unfold, no layout, no camera); Enter centres the
|
|
988
|
+
* next lit card, Shift+Enter the previous. It SAYS how many it found,
|
|
989
|
+
* and how many more are folded away or in hidden topics — a graph
|
|
990
|
+
* with no amber looks the same whether nothing matched or the matches
|
|
991
|
+
* are not on screen.
|
|
990
992
|
*/
|
|
991
993
|
/* Materialised, not a spec: attach_clear() hangs the NORM clear (✕)
|
|
992
994
|
* on a real element. Clearing dispatches a synthetic `input`, which
|
|
@@ -1000,8 +1002,12 @@ function make_toolbar(gobj)
|
|
|
1000
1002
|
* cannot reach it: it needs its own key. */
|
|
1001
1003
|
placeholder: t('search'),
|
|
1002
1004
|
'data-i18n-placeholder': 'search',
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
+
/* The title is where Enter is told: nothing else on the
|
|
1006
|
+
* box says it can step through the matches. */
|
|
1007
|
+
title: t('find on screen'),
|
|
1008
|
+
'data-i18n-title': 'find on screen',
|
|
1009
|
+
'aria-label': t('find on screen'),
|
|
1010
|
+
'data-i18n-aria-label': 'find on screen'
|
|
1005
1011
|
}, [], {
|
|
1006
1012
|
/* Rate-limited, not delayed for effect: a match repaints the
|
|
1007
1013
|
* cards it lands on, and on a large treedb the first letter
|
|
@@ -1018,6 +1024,24 @@ function make_toolbar(gobj)
|
|
|
1018
1024
|
priv.find_timer = null;
|
|
1019
1025
|
gobj_send_event(gobj, "EV_FIND_NODES", {text: text}, gobj);
|
|
1020
1026
|
}, 250);
|
|
1027
|
+
},
|
|
1028
|
+
/* Enter steps through the lit cards. A term still waiting
|
|
1029
|
+
* on the rate limit is sent first, or Enter would step
|
|
1030
|
+
* through the matches of the term before it. */
|
|
1031
|
+
keydown: (evt) => {
|
|
1032
|
+
if(evt.key !== 'Enter' || evt.isComposing) {
|
|
1033
|
+
return;
|
|
1034
|
+
}
|
|
1035
|
+
evt.preventDefault();
|
|
1036
|
+
evt.stopPropagation();
|
|
1037
|
+
if(priv.find_timer) {
|
|
1038
|
+
clearTimeout(priv.find_timer);
|
|
1039
|
+
priv.find_timer = null;
|
|
1040
|
+
gobj_send_event(
|
|
1041
|
+
gobj, "EV_FIND_NODES", {text: evt.target.value.trim()}, gobj
|
|
1042
|
+
);
|
|
1043
|
+
}
|
|
1044
|
+
gobj_send_event(gobj, "EV_FIND_NEXT", {back: evt.shiftKey}, gobj);
|
|
1021
1045
|
}
|
|
1022
1046
|
}]);
|
|
1023
1047
|
|
|
@@ -3188,6 +3212,23 @@ function ac_find_nodes(gobj, event, kw, src)
|
|
|
3188
3212
|
return 0;
|
|
3189
3213
|
}
|
|
3190
3214
|
|
|
3215
|
+
/************************************************************
|
|
3216
|
+
* Enter in the find box: forward the step down to the graph child.
|
|
3217
|
+
************************************************************/
|
|
3218
|
+
function ac_find_next(gobj, event, kw, src)
|
|
3219
|
+
{
|
|
3220
|
+
let priv = gobj.priv;
|
|
3221
|
+
if(priv.gobj_nodes_tree) {
|
|
3222
|
+
gobj_send_event(
|
|
3223
|
+
priv.gobj_nodes_tree,
|
|
3224
|
+
"EV_FIND_NEXT",
|
|
3225
|
+
{back: !!(kw && kw.back)},
|
|
3226
|
+
gobj
|
|
3227
|
+
);
|
|
3228
|
+
}
|
|
3229
|
+
return 0;
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3191
3232
|
/************************************************************
|
|
3192
3233
|
* One press of the fold stepper (EV_EXPAND_LEVEL /
|
|
3193
3234
|
* EV_COLLAPSE_LEVEL): the level moves by one, is SAVED (the
|
|
@@ -3307,17 +3348,47 @@ function refresh_find_result(gobj)
|
|
|
3307
3348
|
}
|
|
3308
3349
|
|
|
3309
3350
|
let text = t("matches", {count: (kw && kw.matches) || 0});
|
|
3310
|
-
/*
|
|
3311
|
-
|
|
3351
|
+
/* Where Enter stands among the lit cards: "3/12 matches". */
|
|
3352
|
+
let current = (kw && kw.current) || 0;
|
|
3353
|
+
if(current > 0) {
|
|
3354
|
+
text = `${current}/${text}`;
|
|
3355
|
+
}
|
|
3356
|
+
/* Matches NOT lit, counted apart: "0" alone reads as "does not
|
|
3357
|
+
* exist" when it means "is folded away" or "is hidden". */
|
|
3358
|
+
let extra = [];
|
|
3359
|
+
let folded = (kw && kw.folded_matches) || 0;
|
|
3360
|
+
if(folded > 0) {
|
|
3361
|
+
extra.push(`+${folded} ${t("not shown")}`);
|
|
3362
|
+
}
|
|
3312
3363
|
let hidden = (kw && kw.hidden_matches) || 0;
|
|
3313
3364
|
if(hidden > 0) {
|
|
3314
|
-
|
|
3365
|
+
extra.push(`+${hidden} ${t("hidden topics")}`);
|
|
3366
|
+
}
|
|
3367
|
+
if(extra.length) {
|
|
3368
|
+
text += ` (${extra.join(", ")})`;
|
|
3315
3369
|
}
|
|
3316
3370
|
$count.textContent = text;
|
|
3317
3371
|
$result.classList.remove("is-hidden");
|
|
3318
3372
|
return 0;
|
|
3319
3373
|
}
|
|
3320
3374
|
|
|
3375
|
+
function clear_find_box(gobj)
|
|
3376
|
+
{
|
|
3377
|
+
let priv = gobj.priv;
|
|
3378
|
+
if(priv.find_timer) {
|
|
3379
|
+
clearTimeout(priv.find_timer);
|
|
3380
|
+
priv.find_timer = null;
|
|
3381
|
+
}
|
|
3382
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
3383
|
+
let $input = $container? $container.querySelector(".GRAPH_FIND_INPUT") : null;
|
|
3384
|
+
if($input) {
|
|
3385
|
+
$input.value = "";
|
|
3386
|
+
refresh_clear($input);
|
|
3387
|
+
}
|
|
3388
|
+
priv._find_result = null;
|
|
3389
|
+
refresh_find_result(gobj);
|
|
3390
|
+
}
|
|
3391
|
+
|
|
3321
3392
|
function ac_set_focus_topic(gobj, event, kw, src)
|
|
3322
3393
|
{
|
|
3323
3394
|
let priv = gobj.priv;
|
|
@@ -3334,6 +3405,13 @@ function ac_set_focus_topic(gobj, event, kw, src)
|
|
|
3334
3405
|
}
|
|
3335
3406
|
}
|
|
3336
3407
|
|
|
3408
|
+
/* A topic focus takes the highlight from the find (the engine
|
|
3409
|
+
* drops its term), so the box must not go on showing a term
|
|
3410
|
+
* nothing is lit for. */
|
|
3411
|
+
if(priv.focus_topic) {
|
|
3412
|
+
clear_find_box(gobj);
|
|
3413
|
+
}
|
|
3414
|
+
|
|
3337
3415
|
if(priv.gobj_nodes_tree) {
|
|
3338
3416
|
gobj_send_event(
|
|
3339
3417
|
priv.gobj_nodes_tree,
|
|
@@ -3435,6 +3513,7 @@ function create_gclass(gclass_name)
|
|
|
3435
3513
|
["EV_SET_OPERATION_MODE", ac_set_operation_mode, null],
|
|
3436
3514
|
["EV_SET_FOCUS_TOPIC", ac_set_focus_topic, null],
|
|
3437
3515
|
["EV_FIND_NODES", ac_find_nodes, null],
|
|
3516
|
+
["EV_FIND_NEXT", ac_find_next, null],
|
|
3438
3517
|
["EV_EXPAND_LEVEL", ac_fold_level_step, null],
|
|
3439
3518
|
["EV_COLLAPSE_LEVEL", ac_fold_level_step, null],
|
|
3440
3519
|
["EV_SET_NODE_MODE", ac_set_node_mode, null],
|
|
@@ -3482,6 +3561,7 @@ function create_gclass(gclass_name)
|
|
|
3482
3561
|
["EV_SET_OPERATION_MODE", 0],
|
|
3483
3562
|
["EV_SET_FOCUS_TOPIC", 0],
|
|
3484
3563
|
["EV_FIND_NODES", 0],
|
|
3564
|
+
["EV_FIND_NEXT", 0],
|
|
3485
3565
|
["EV_EXPAND_LEVEL", 0],
|
|
3486
3566
|
["EV_COLLAPSE_LEVEL", 0],
|
|
3487
3567
|
["EV_SET_NODE_MODE", 0],
|