@yuneta/gobj-ui 7.23.27 → 7.23.29
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/dist/gobj-ui.cjs.js +350 -25
- package/dist/gobj-ui.es.js +350 -25
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +71 -10
- package/src/c_yui_gobj_tree_js.js +197 -2
- package/src/c_yui_json_graph.js +245 -4
- package/src/lib_graph.css +38 -2
- package/src/lib_graph.js +0 -31
- package/src/yui_graph_camera.js +60 -0
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -1273,8 +1273,11 @@ function configure_toolbar(gobj)
|
|
|
1273
1273
|
* the rebuild came back OFF. */
|
|
1274
1274
|
{
|
|
1275
1275
|
id: 'g6-icon-anchor', value: 'anchor',
|
|
1276
|
+
/* PRESSED is "on" and only "on": pressed is the
|
|
1277
|
+
* state the control is IN, and while it is
|
|
1278
|
+
* arming it is asking for something instead. */
|
|
1276
1279
|
className: 'EV_TOGGLE_ANCHOR' +
|
|
1277
|
-
(priv.anchor_state
|
|
1280
|
+
(priv.anchor_state === "on"? ' pressed_state' : '') +
|
|
1278
1281
|
(priv.anchor_state === "arming"? ' color_pending_state' : ''),
|
|
1279
1282
|
title: anchor_title(priv.anchor_state)
|
|
1280
1283
|
},
|
|
@@ -1600,6 +1603,37 @@ function configure_behaviour(gobj)
|
|
|
1600
1603
|
graph_write_behaviors(gobj, behaviors);
|
|
1601
1604
|
}
|
|
1602
1605
|
|
|
1606
|
+
/************************************************************
|
|
1607
|
+
* Count hooks and fkeys in topic desc, classify node type
|
|
1608
|
+
************************************************************/
|
|
1609
|
+
function calculate_hooks_fkeys_counter(desc)
|
|
1610
|
+
{
|
|
1611
|
+
let cols = desc.cols;
|
|
1612
|
+
desc.hooks_counter = 0;
|
|
1613
|
+
desc.fkeys_counter = 0;
|
|
1614
|
+
|
|
1615
|
+
for(let i=0; i<cols.length; i++) {
|
|
1616
|
+
let col = cols[i];
|
|
1617
|
+
const field_desc = treedb_get_field_desc(col);
|
|
1618
|
+
switch(field_desc.type) {
|
|
1619
|
+
case "hook":
|
|
1620
|
+
desc.hooks_counter++;
|
|
1621
|
+
break;
|
|
1622
|
+
case "fkey":
|
|
1623
|
+
desc.fkeys_counter++;
|
|
1624
|
+
break;
|
|
1625
|
+
}
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
if(desc.hooks_counter === 0) {
|
|
1629
|
+
desc.node_treedb_type = 'child';
|
|
1630
|
+
} else if(desc.fkeys_counter === 0) {
|
|
1631
|
+
desc.node_treedb_type = 'extended';
|
|
1632
|
+
} else {
|
|
1633
|
+
desc.node_treedb_type = 'hierarchical';
|
|
1634
|
+
}
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1603
1637
|
/************************************************************
|
|
1604
1638
|
* Build ports for a topic desc
|
|
1605
1639
|
************************************************************/
|
|
@@ -5712,7 +5746,7 @@ function refresh_minimap(gobj)
|
|
|
5712
5746
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
5713
5747
|
* shared now. Returns null for a node that carries no desc.
|
|
5714
5748
|
************************************************************/
|
|
5715
|
-
function node_innerHTML_of(nd, theme, highlight, selected)
|
|
5749
|
+
function node_innerHTML_of(nd, theme, highlight, selected, anchored)
|
|
5716
5750
|
{
|
|
5717
5751
|
if(!nd || !nd.data || !nd.data.desc) {
|
|
5718
5752
|
return null;
|
|
@@ -5725,17 +5759,17 @@ function node_innerHTML_of(nd, theme, highlight, selected)
|
|
|
5725
5759
|
case 'child':
|
|
5726
5760
|
return build_chip_innerHTML(
|
|
5727
5761
|
desc.color, theme, record.icon, label, record.id,
|
|
5728
|
-
highlight, selected
|
|
5762
|
+
highlight, selected, anchored
|
|
5729
5763
|
);
|
|
5730
5764
|
case 'extended':
|
|
5731
5765
|
return build_node_innerHTML(
|
|
5732
5766
|
desc.color, theme, record.icon, label,
|
|
5733
|
-
desc.topic_name, true, record.id, highlight, selected
|
|
5767
|
+
desc.topic_name, true, record.id, highlight, selected, anchored
|
|
5734
5768
|
);
|
|
5735
5769
|
case 'hierarchical':
|
|
5736
5770
|
return build_node_innerHTML(
|
|
5737
5771
|
desc.color, theme, record.icon, label,
|
|
5738
|
-
desc.topic_name, false, record.id, highlight, selected
|
|
5772
|
+
desc.topic_name, false, record.id, highlight, selected, anchored
|
|
5739
5773
|
);
|
|
5740
5774
|
}
|
|
5741
5775
|
return null;
|
|
@@ -5765,7 +5799,8 @@ function repaint_cards(gobj, ids)
|
|
|
5765
5799
|
let updates = [];
|
|
5766
5800
|
for(let id of ids) {
|
|
5767
5801
|
let html = node_innerHTML_of(
|
|
5768
|
-
graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id)
|
|
5802
|
+
graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id),
|
|
5803
|
+
priv.anchor_state === "on" && id === priv.anchor_id
|
|
5769
5804
|
);
|
|
5770
5805
|
if(html !== null) {
|
|
5771
5806
|
updates.push({id: id, style: {innerHTML: html}});
|
|
@@ -5871,6 +5906,25 @@ function refresh_default_edges_theme(gobj, theme)
|
|
|
5871
5906
|
* it, which is also the order that reads correctly when only one
|
|
5872
5907
|
* of them is on.
|
|
5873
5908
|
************************************************************/
|
|
5909
|
+
/************************************************************
|
|
5910
|
+
* The mark of the card the CAMERA is holding.
|
|
5911
|
+
*
|
|
5912
|
+
* An outline and not another ring, and DASHED: the two rings
|
|
5913
|
+
* already mean things here -- amber is a find match or a
|
|
5914
|
+
* focused topic, blue is the selection -- and a third solid
|
|
5915
|
+
* ring would be a third thing to learn in the same channel.
|
|
5916
|
+
* A dash is a different channel, so it reads beside either of
|
|
5917
|
+
* them, and it says "provisional" the way a camera state is.
|
|
5918
|
+
*
|
|
5919
|
+
* The same dash the other two viewers draw: this is one
|
|
5920
|
+
* feature with one control, and it should not be three
|
|
5921
|
+
* drawings.
|
|
5922
|
+
************************************************************/
|
|
5923
|
+
function anchor_outline(anchored)
|
|
5924
|
+
{
|
|
5925
|
+
return anchored? "outline: 3px dashed #fa8c16; outline-offset: 2px;" : "";
|
|
5926
|
+
}
|
|
5927
|
+
|
|
5874
5928
|
function ring_shadow(highlight, selected, base_shadow)
|
|
5875
5929
|
{
|
|
5876
5930
|
let rings = [];
|
|
@@ -5897,7 +5951,7 @@ function ring_shadow(highlight, selected, base_shadow)
|
|
|
5897
5951
|
* but lighter (1px border, no shadow, single line). The name is
|
|
5898
5952
|
* always legible (ellipsis + native title tooltip on overflow).
|
|
5899
5953
|
************************************************************/
|
|
5900
|
-
function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected)
|
|
5954
|
+
function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected, anchored)
|
|
5901
5955
|
{
|
|
5902
5956
|
let title = key || label;
|
|
5903
5957
|
let dark = (theme === "dark");
|
|
@@ -5922,13 +5976,14 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
5922
5976
|
}
|
|
5923
5977
|
|
|
5924
5978
|
return `
|
|
5925
|
-
<div title="${escapeHtml(title)}" style="
|
|
5979
|
+
<div class="TREEDB_CARD" title="${escapeHtml(title)}" style="
|
|
5926
5980
|
box-sizing: border-box;
|
|
5927
5981
|
width: 100%;
|
|
5928
5982
|
height: 100%;
|
|
5929
5983
|
background: ${bg};
|
|
5930
5984
|
border: ${highlight? "3px" : "1px"} solid ${border};
|
|
5931
5985
|
${ring_shadow(highlight, selected, "")}
|
|
5986
|
+
${anchor_outline(anchored)}
|
|
5932
5987
|
border-radius: 8px;
|
|
5933
5988
|
color: ${text_color};
|
|
5934
5989
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
@@ -5955,7 +6010,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight, selecte
|
|
|
5955
6010
|
* colour is kept (per-topic differentiation) but softened via
|
|
5956
6011
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
5957
6012
|
************************************************************/
|
|
5958
|
-
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected)
|
|
6013
|
+
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected, anchored)
|
|
5959
6014
|
{
|
|
5960
6015
|
let title = key || label;
|
|
5961
6016
|
let dark = (theme === "dark");
|
|
@@ -6011,7 +6066,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
6011
6066
|
}
|
|
6012
6067
|
|
|
6013
6068
|
return `
|
|
6014
|
-
<div title="${escapeHtml(title)}" style="
|
|
6069
|
+
<div class="TREEDB_CARD" title="${escapeHtml(title)}" style="
|
|
6015
6070
|
box-sizing: border-box;
|
|
6016
6071
|
width: 100%;
|
|
6017
6072
|
height: 100%;
|
|
@@ -6019,6 +6074,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
6019
6074
|
border: ${highlight? "3px" : "1.5px"} ${border_style} ${border};
|
|
6020
6075
|
border-radius: 10px;
|
|
6021
6076
|
${ring_shadow(highlight, selected, shadow)}
|
|
6077
|
+
${anchor_outline(anchored)}
|
|
6022
6078
|
color: ${title_color};
|
|
6023
6079
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
6024
6080
|
display: flex;
|
|
@@ -7571,6 +7627,7 @@ function after_camera(gobj, moved)
|
|
|
7571
7627
|
function ac_toggle_anchor(gobj, event, kw, src)
|
|
7572
7628
|
{
|
|
7573
7629
|
let priv = gobj.priv;
|
|
7630
|
+
let was = priv.anchor_id;
|
|
7574
7631
|
|
|
7575
7632
|
if(priv.anchor_state === "off") {
|
|
7576
7633
|
priv.anchor_state = "arming";
|
|
@@ -7580,6 +7637,9 @@ function ac_toggle_anchor(gobj, event, kw, src)
|
|
|
7580
7637
|
}
|
|
7581
7638
|
|
|
7582
7639
|
update_toolbar(gobj);
|
|
7640
|
+
if(was) {
|
|
7641
|
+
repaint_cards(gobj, new Set([was]));
|
|
7642
|
+
}
|
|
7583
7643
|
return 0;
|
|
7584
7644
|
}
|
|
7585
7645
|
|
|
@@ -7838,6 +7898,7 @@ function ac_node_click(gobj, event, kw, src)
|
|
|
7838
7898
|
priv.anchor_id = node_id;
|
|
7839
7899
|
priv.anchor_state = "on";
|
|
7840
7900
|
update_toolbar(gobj);
|
|
7901
|
+
repaint_cards(gobj, new Set([node_id]));
|
|
7841
7902
|
|
|
7842
7903
|
/* POSTED, not made here: a camera move issued inside G6's click
|
|
7843
7904
|
* dispatch is swallowed -- see the note in yui_graph_center_on.
|
|
@@ -22,6 +22,8 @@ import {
|
|
|
22
22
|
gobj_write_attr,
|
|
23
23
|
gobj_send_event,
|
|
24
24
|
gobj_post_event,
|
|
25
|
+
kw_get_local_storage_value,
|
|
26
|
+
kw_set_local_storage_value,
|
|
25
27
|
gobj_write_str_attr,
|
|
26
28
|
gobj_read_str_attr,
|
|
27
29
|
gobj_publish_event,
|
|
@@ -120,6 +122,123 @@ const ZOOM_CANVAS = {type: 'zoom-canvas', animation: false};
|
|
|
120
122
|
const BEHAVIORS_READING = ['drag-canvas', ZOOM_CANVAS, 'drag-element'];
|
|
121
123
|
const BEHAVIORS_PICKING = ['drag-canvas', ZOOM_CANVAS];
|
|
122
124
|
|
|
125
|
+
/*
|
|
126
|
+
* Where this view is remembered between visits.
|
|
127
|
+
*
|
|
128
|
+
* In localStorage and not in a persistent attr, for the reason the
|
|
129
|
+
* framework gives itself: only a SERVICE can load or save persistent
|
|
130
|
+
* attrs, and this gclass is hosted as a child. It is also the right
|
|
131
|
+
* place on its own terms -- how somebody left THEIR tree arranged is
|
|
132
|
+
* a fact about that browser, not about the yuno.
|
|
133
|
+
*
|
|
134
|
+
* Keyed by the gobj's name so two trees in one app do not overwrite
|
|
135
|
+
* each other's arrangement.
|
|
136
|
+
*/
|
|
137
|
+
const VIEW_STORE_PREFIX = "yui_gobj_tree_view:";
|
|
138
|
+
|
|
139
|
+
/* What is worth carrying back: the layout, where the camera was, and
|
|
140
|
+
* which branches were folded. The anchor goes too -- it is a camera
|
|
141
|
+
* state like the other two, and coming back to a tree still holding
|
|
142
|
+
* the node you left it on is the point of holding it. */
|
|
143
|
+
function view_store_key(gobj)
|
|
144
|
+
{
|
|
145
|
+
return VIEW_STORE_PREFIX + gobj_name(gobj);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function restore_view_shape(gobj)
|
|
149
|
+
{
|
|
150
|
+
let priv = gobj.priv;
|
|
151
|
+
let state = load_view_state(gobj);
|
|
152
|
+
|
|
153
|
+
if(!state) {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if(state.layout && LAYOUTS[state.layout]) {
|
|
157
|
+
gobj_write_str_attr(gobj, "layout", state.layout);
|
|
158
|
+
/* And the picker with it: the toolbar was built from the
|
|
159
|
+
* attr's default a moment ago, so without this the graph draws
|
|
160
|
+
* the remembered layout while the control names another. */
|
|
161
|
+
if(priv.$layout_select) {
|
|
162
|
+
priv.$layout_select.value = state.layout;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if(state.collapsed && typeof state.collapsed === "object") {
|
|
166
|
+
priv.collapse_state = Object.assign({}, state.collapsed);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function restore_view_state(gobj)
|
|
171
|
+
{
|
|
172
|
+
let priv = gobj.priv;
|
|
173
|
+
let graph = priv.graph;
|
|
174
|
+
let state = load_view_state(gobj);
|
|
175
|
+
|
|
176
|
+
if(!graph || !state) {
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
let done = false;
|
|
181
|
+
priv.restoring = true;
|
|
182
|
+
try {
|
|
183
|
+
if(typeof state.zoom === "number" && state.zoom > 0) {
|
|
184
|
+
graph.zoomTo(state.zoom);
|
|
185
|
+
priv.last_zoom = state.zoom;
|
|
186
|
+
done = true;
|
|
187
|
+
}
|
|
188
|
+
if(Array.isArray(state.position) && state.position.length >= 2) {
|
|
189
|
+
graph.translateTo([state.position[0], state.position[1]]);
|
|
190
|
+
done = true;
|
|
191
|
+
}
|
|
192
|
+
if(state.anchor) {
|
|
193
|
+
/* By NAME, never by node id: ids are generated per build,
|
|
194
|
+
* and this one was written in another session. */
|
|
195
|
+
priv.anchor_name = state.anchor;
|
|
196
|
+
priv.anchor_state = "on";
|
|
197
|
+
reanchor(gobj);
|
|
198
|
+
yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
|
|
199
|
+
paint_anchor_mark(gobj);
|
|
200
|
+
}
|
|
201
|
+
} catch(e) {
|
|
202
|
+
log_error(`${gobj_short_name(gobj)}: cannot restore the saved view: ${e}`);
|
|
203
|
+
} finally {
|
|
204
|
+
priv.restoring = false;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
yui_graph_update_zoom(gobj_read_attr(gobj, "$container"), priv.graph);
|
|
208
|
+
return done;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function save_view_state(gobj)
|
|
212
|
+
{
|
|
213
|
+
let priv = gobj.priv;
|
|
214
|
+
let graph = priv.graph;
|
|
215
|
+
|
|
216
|
+
if(!graph || priv.restoring) {
|
|
217
|
+
return; /* mid-restore: that is our own writing coming back */
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
let state = {
|
|
221
|
+
layout: gobj_read_str_attr(gobj, "layout"),
|
|
222
|
+
collapsed: priv.collapse_state || {},
|
|
223
|
+
anchor: (priv.anchor_state === "on")? priv.anchor_name: "",
|
|
224
|
+
};
|
|
225
|
+
try {
|
|
226
|
+
state.zoom = graph.getZoom();
|
|
227
|
+
state.position = graph.getPosition();
|
|
228
|
+
} catch(e) {
|
|
229
|
+
/* between renders: keep the rest, the camera is not readable */
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
kw_set_local_storage_value(view_store_key(gobj), state);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
function load_view_state(gobj)
|
|
236
|
+
{
|
|
237
|
+
let state = kw_get_local_storage_value(view_store_key(gobj), null, false);
|
|
238
|
+
|
|
239
|
+
return (state && typeof state === "object")? state: null;
|
|
240
|
+
}
|
|
241
|
+
|
|
123
242
|
let PRIVATE_DATA = {
|
|
124
243
|
canvas_id: "",
|
|
125
244
|
graph: null,
|
|
@@ -146,6 +265,8 @@ let PRIVATE_DATA = {
|
|
|
146
265
|
anchor_id: "", // the node the camera keeps in the middle
|
|
147
266
|
anchor_name: "", // its full_name, which survives a rebuild
|
|
148
267
|
anchor_state: "off", // "off" | "arming" | "on"
|
|
268
|
+
restoring: false, // guards the store against its own restore
|
|
269
|
+
restored: false, // the saved arrangement is applied ONCE
|
|
149
270
|
last_zoom: 1, // tells a wheel zoom from a drag in aftertransform
|
|
150
271
|
};
|
|
151
272
|
|
|
@@ -369,6 +490,14 @@ function mt_create(gobj)
|
|
|
369
490
|
***************************************************************/
|
|
370
491
|
function mt_start(gobj)
|
|
371
492
|
{
|
|
493
|
+
/*
|
|
494
|
+
* The layout and the folds go back BEFORE the first build: they
|
|
495
|
+
* decide what is built, so restoring them afterwards would mean
|
|
496
|
+
* building the tree twice and showing the wrong one first.
|
|
497
|
+
* The camera goes back after, once there is something to point at.
|
|
498
|
+
*/
|
|
499
|
+
restore_view_shape(gobj);
|
|
500
|
+
|
|
372
501
|
build_graph(gobj);
|
|
373
502
|
load_tree(gobj);
|
|
374
503
|
}
|
|
@@ -530,8 +659,15 @@ function build_popover(gobj, $container)
|
|
|
530
659
|
|
|
531
660
|
let $close = document.createElement("button");
|
|
532
661
|
$close.type = "button";
|
|
662
|
+
/* Named so a stylesheet can reach it: the size a FINGER needs is a
|
|
663
|
+
* media query, and a media query cannot beat an inline style
|
|
664
|
+
* without one to hang off. See `lib_graph.css`. */
|
|
665
|
+
$close.className = "GOBJ_TREE_POPOVER_CLOSE";
|
|
533
666
|
$close.textContent = "×";
|
|
534
667
|
$close.title = t("close");
|
|
668
|
+
$close.setAttribute("data-i18n-title", "close");
|
|
669
|
+
$close.setAttribute("aria-label", t("close"));
|
|
670
|
+
$close.setAttribute("data-i18n-aria-label", "close");
|
|
535
671
|
$close.style.cssText = `
|
|
536
672
|
background: transparent;
|
|
537
673
|
border: none;
|
|
@@ -710,6 +846,10 @@ function build_graph(gobj)
|
|
|
710
846
|
if(priv.anchor_state === "on" && priv.anchor_id) {
|
|
711
847
|
yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
712
848
|
}
|
|
849
|
+
/* Where the reader left the camera. One hook covers the wheel,
|
|
850
|
+
* the drag and every zoom button, which is why it is not
|
|
851
|
+
* written into each of them. */
|
|
852
|
+
save_view_state(gobj);
|
|
713
853
|
});
|
|
714
854
|
|
|
715
855
|
graph.on(NodeEvent.CLICK, (evt) => {
|
|
@@ -947,7 +1087,7 @@ function build_gobj_nodes(gobj, target_gobj, nodes, edges, parent_id, is_root, c
|
|
|
947
1087
|
);
|
|
948
1088
|
|
|
949
1089
|
node_html = `
|
|
950
|
-
<div style="
|
|
1090
|
+
<div class="GOBJ_CARD" data-gobj-name="${escapeHtml(full_name)}" style="
|
|
951
1091
|
width: ${width}px;
|
|
952
1092
|
height: ${height}px;
|
|
953
1093
|
background: ${cs.bg};
|
|
@@ -999,7 +1139,7 @@ function build_gobj_nodes(gobj, target_gobj, nodes, edges, parent_id, is_root, c
|
|
|
999
1139
|
).join("");
|
|
1000
1140
|
|
|
1001
1141
|
node_html = `
|
|
1002
|
-
<div style="
|
|
1142
|
+
<div class="GOBJ_CARD" data-gobj-name="${escapeHtml(full_name)}" style="
|
|
1003
1143
|
width: ${width}px;
|
|
1004
1144
|
height: ${height}px;
|
|
1005
1145
|
background: ${cs.bg};
|
|
@@ -1145,6 +1285,7 @@ function load_tree(gobj)
|
|
|
1145
1285
|
* there. (`anchor` below is the OTHER one -- see the
|
|
1146
1286
|
* note in PRIVATE_DATA.) */
|
|
1147
1287
|
reanchor(gobj);
|
|
1288
|
+
paint_anchor_mark(gobj);
|
|
1148
1289
|
|
|
1149
1290
|
if(anchor) {
|
|
1150
1291
|
restore_view_anchored(gobj, anchor);
|
|
@@ -1154,6 +1295,19 @@ function load_tree(gobj)
|
|
|
1154
1295
|
return;
|
|
1155
1296
|
}
|
|
1156
1297
|
|
|
1298
|
+
/*
|
|
1299
|
+
* The arrangement this browser was left in, once: after
|
|
1300
|
+
* that the reader's own camera wins, and a restore on
|
|
1301
|
+
* every rebuild would drag them back every time they
|
|
1302
|
+
* folded something.
|
|
1303
|
+
*/
|
|
1304
|
+
if(!priv.restored) {
|
|
1305
|
+
priv.restored = true;
|
|
1306
|
+
if(restore_view_state(gobj)) {
|
|
1307
|
+
return;
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1157
1311
|
/*
|
|
1158
1312
|
* ACTUAL SIZE, not fit. A tree of anything real does not
|
|
1159
1313
|
* fit at a zoom anybody can read, so fitting answered
|
|
@@ -1795,6 +1949,7 @@ class GobjLanesHLayout extends BaseLayout {
|
|
|
1795
1949
|
************************************************************/
|
|
1796
1950
|
function ac_refresh(gobj, event, kw, src)
|
|
1797
1951
|
{
|
|
1952
|
+
save_view_state(gobj);
|
|
1798
1953
|
refresh_tree(gobj);
|
|
1799
1954
|
return 0;
|
|
1800
1955
|
}
|
|
@@ -1841,10 +1996,12 @@ function ac_change_layout(gobj, event, kw, src)
|
|
|
1841
1996
|
}
|
|
1842
1997
|
|
|
1843
1998
|
apply_layout(gobj);
|
|
1999
|
+
save_view_state(gobj);
|
|
1844
2000
|
|
|
1845
2001
|
/*
|
|
1846
2002
|
* Rebuild nodes because compact/full HTML differs per layout
|
|
1847
2003
|
*/
|
|
2004
|
+
save_view_state(gobj);
|
|
1848
2005
|
refresh_tree(gobj);
|
|
1849
2006
|
|
|
1850
2007
|
return 0;
|
|
@@ -1902,6 +2059,7 @@ function ac_toggle_collapse(gobj, event, kw, src)
|
|
|
1902
2059
|
priv.collapse_state[node_data.full_name] = "collapsed";
|
|
1903
2060
|
}
|
|
1904
2061
|
|
|
2062
|
+
save_view_state(gobj);
|
|
1905
2063
|
refresh_tree(gobj, {anchor: anchor});
|
|
1906
2064
|
return 0;
|
|
1907
2065
|
}
|
|
@@ -2022,12 +2180,46 @@ function ac_center_anchor(gobj, event, kw, src)
|
|
|
2022
2180
|
{
|
|
2023
2181
|
let priv = gobj.priv;
|
|
2024
2182
|
|
|
2183
|
+
paint_anchor_mark(gobj);
|
|
2184
|
+
save_view_state(gobj);
|
|
2025
2185
|
if(priv.anchor_state === "on" && priv.anchor_id) {
|
|
2026
2186
|
yui_graph_center_on(priv.graph, priv.anchor_id);
|
|
2027
2187
|
}
|
|
2028
2188
|
return 0;
|
|
2029
2189
|
}
|
|
2030
2190
|
|
|
2191
|
+
/************************************************************
|
|
2192
|
+
* Mark the card the camera is holding.
|
|
2193
|
+
*
|
|
2194
|
+
* A class on the card's own element and not a G6 node state:
|
|
2195
|
+
* G6 paints no state style on an html node.
|
|
2196
|
+
*
|
|
2197
|
+
* Re-applied after every rebuild, because the cards are new
|
|
2198
|
+
* DOM each time and the mark would otherwise last until the
|
|
2199
|
+
* next expand.
|
|
2200
|
+
************************************************************/
|
|
2201
|
+
function paint_anchor_mark(gobj)
|
|
2202
|
+
{
|
|
2203
|
+
let priv = gobj.priv;
|
|
2204
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
2205
|
+
|
|
2206
|
+
if(!$container) {
|
|
2207
|
+
return;
|
|
2208
|
+
}
|
|
2209
|
+
for(let $card of $container.querySelectorAll('.GOBJ_CARD_ANCHORED')) {
|
|
2210
|
+
$card.classList.remove('GOBJ_CARD_ANCHORED');
|
|
2211
|
+
}
|
|
2212
|
+
if(priv.anchor_state !== "on" || !priv.anchor_name) {
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
let $it = $container.querySelector(
|
|
2216
|
+
'.GOBJ_CARD[data-gobj-name="' + CSS.escape(priv.anchor_name) + '"]'
|
|
2217
|
+
);
|
|
2218
|
+
if($it) {
|
|
2219
|
+
$it.classList.add('GOBJ_CARD_ANCHORED');
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2031
2223
|
/************************************************************
|
|
2032
2224
|
* Reading, or picking the node to anchor.
|
|
2033
2225
|
************************************************************/
|
|
@@ -2068,6 +2260,8 @@ function ac_toggle_anchor(gobj, event, kw, src)
|
|
|
2068
2260
|
|
|
2069
2261
|
yui_graph_update_anchor(gobj_read_attr(gobj, "$container"), priv.anchor_state);
|
|
2070
2262
|
set_picking_mode(gobj, priv.anchor_state === "arming");
|
|
2263
|
+
paint_anchor_mark(gobj);
|
|
2264
|
+
save_view_state(gobj);
|
|
2071
2265
|
return 0;
|
|
2072
2266
|
}
|
|
2073
2267
|
|
|
@@ -2202,6 +2396,7 @@ function ac_show(gobj, event, kw, src)
|
|
|
2202
2396
|
/*
|
|
2203
2397
|
* Always refresh on show: the tree may have changed while hidden
|
|
2204
2398
|
*/
|
|
2399
|
+
save_view_state(gobj);
|
|
2205
2400
|
refresh_tree(gobj);
|
|
2206
2401
|
|
|
2207
2402
|
if(graph) {
|