@yuneta/gobj-ui 7.15.0 → 7.17.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 +69 -0
- package/dist/gobj-ui.cjs.js +310 -41
- package/dist/gobj-ui.es.js +310 -41
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +508 -62
package/dist/gobj-ui.es.js
CHANGED
|
@@ -53734,6 +53734,7 @@ ensure_drag_canvas_patch();
|
|
|
53734
53734
|
var GCLASS_NAME$1 = "C_G6_NODES_TREE";
|
|
53735
53735
|
var HIGHLIGHT_COLOR = "#f0a020";
|
|
53736
53736
|
var HIGHLIGHT_HALO = "rgba(240,160,32,0.35)";
|
|
53737
|
+
var SELECT_RING = "rgba(59,130,246,0.95)";
|
|
53737
53738
|
/***************************************************************
|
|
53738
53739
|
* Internal layout and operation mode definitions
|
|
53739
53740
|
***************************************************************/
|
|
@@ -53845,6 +53846,7 @@ var PRIVATE_DATA$1 = {
|
|
|
53845
53846
|
_link_saved_styles: [],
|
|
53846
53847
|
_focus_topic: null,
|
|
53847
53848
|
_focus_ids: [],
|
|
53849
|
+
_selected_paint_ids: [],
|
|
53848
53850
|
_pending_focus_topic: null,
|
|
53849
53851
|
_pending_find: null,
|
|
53850
53852
|
_layout_asked: "",
|
|
@@ -54073,12 +54075,15 @@ function configure_events(gobj) {
|
|
|
54073
54075
|
update_toolbar(gobj);
|
|
54074
54076
|
};
|
|
54075
54077
|
i18next.on("languageChanged", priv._on_language_changed);
|
|
54076
|
-
|
|
54077
|
-
|
|
54078
|
-
|
|
54079
|
-
|
|
54080
|
-
|
|
54081
|
-
|
|
54078
|
+
graph.on("keydown", (evt) => {
|
|
54079
|
+
let ctrl = !!(evt.ctrlKey || evt.metaKey);
|
|
54080
|
+
if (ctrl && (evt.key === "a" || evt.key === "A")) {
|
|
54081
|
+
if (typeof evt.preventDefault === "function") evt.preventDefault();
|
|
54082
|
+
}
|
|
54083
|
+
gobj_send_event(gobj, "EV_KEY_DOWN", {
|
|
54084
|
+
key: evt.key,
|
|
54085
|
+
ctrl
|
|
54086
|
+
}, gobj);
|
|
54082
54087
|
});
|
|
54083
54088
|
}
|
|
54084
54089
|
/************************************************************
|
|
@@ -54365,9 +54370,24 @@ function configure_behaviour(gobj) {
|
|
|
54365
54370
|
case "edition":
|
|
54366
54371
|
priv.edit_mode = true;
|
|
54367
54372
|
behaviors = [
|
|
54368
|
-
|
|
54373
|
+
{
|
|
54374
|
+
type: "drag-canvas",
|
|
54375
|
+
key: "drag-canvas",
|
|
54376
|
+
enable: (event) => !event.shiftKey
|
|
54377
|
+
},
|
|
54369
54378
|
"zoom-canvas",
|
|
54370
|
-
"drag-element"
|
|
54379
|
+
"drag-element",
|
|
54380
|
+
{
|
|
54381
|
+
type: "brush-select",
|
|
54382
|
+
key: "brush-select",
|
|
54383
|
+
trigger: ["shift"],
|
|
54384
|
+
enableElements: ["node"],
|
|
54385
|
+
immediately: false,
|
|
54386
|
+
onSelect: (states) => {
|
|
54387
|
+
let ids = Object.keys(states || {}).filter((id) => (states[id] || []).includes("selected"));
|
|
54388
|
+
gobj_send_event(gobj, "EV_BRUSH_SELECT", { ids }, gobj);
|
|
54389
|
+
}
|
|
54390
|
+
}
|
|
54371
54391
|
];
|
|
54372
54392
|
break;
|
|
54373
54393
|
case "operation":
|
|
@@ -55440,10 +55460,17 @@ function create_form_button_row(parent, buttons) {
|
|
|
55440
55460
|
function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_color, onConfirm, priv_key) {
|
|
55441
55461
|
hide_overlay(gobj, priv_key);
|
|
55442
55462
|
let priv = gobj.priv;
|
|
55443
|
-
if (!target_el) return;
|
|
55444
|
-
let iconRect = target_el.getBoundingClientRect();
|
|
55445
55463
|
let containerRect = priv.$container.getBoundingClientRect();
|
|
55446
|
-
|
|
55464
|
+
let left, top;
|
|
55465
|
+
if (target_el) {
|
|
55466
|
+
let iconRect = target_el.getBoundingClientRect();
|
|
55467
|
+
left = iconRect.right - containerRect.left + 6;
|
|
55468
|
+
top = iconRect.top - containerRect.top - 4;
|
|
55469
|
+
} else {
|
|
55470
|
+
left = Math.round(containerRect.width / 2) - 110;
|
|
55471
|
+
top = Math.round(containerRect.height / 4);
|
|
55472
|
+
}
|
|
55473
|
+
const popover = create_popover_base(left, top, "g6-confirm-popover", "#ff4d4f", 160);
|
|
55447
55474
|
let msg = document.createElement("div");
|
|
55448
55475
|
msg.style.cssText = "margin-bottom:10px;font-weight:500;white-space:pre-line;";
|
|
55449
55476
|
msg.textContent = message;
|
|
@@ -55482,6 +55509,81 @@ function perform_history_op(gobj, is_redo) {
|
|
|
55482
55509
|
sync_history_to_backend(gobj, cmd ? cmd.original : null);
|
|
55483
55510
|
}
|
|
55484
55511
|
}
|
|
55512
|
+
/************************************************************
|
|
55513
|
+
* The selection.
|
|
55514
|
+
*
|
|
55515
|
+
* G6's `selected` element state IS the selection: `drag-element`
|
|
55516
|
+
* reads it (`getElementDataByState`) to decide what a drag moves,
|
|
55517
|
+
* so keeping the set anywhere else would be a second truth the
|
|
55518
|
+
* drag does not consult. What this gclass keeps is what is
|
|
55519
|
+
* PAINTED -- an html node draws no state style at all (its key
|
|
55520
|
+
* shape is a DOM element), so the ring lives in the card's own
|
|
55521
|
+
* html, exactly like the find highlight, and the painted set
|
|
55522
|
+
* exists to diff the repaint.
|
|
55523
|
+
************************************************************/
|
|
55524
|
+
function selected_node_ids(gobj) {
|
|
55525
|
+
let graph = gobj.priv.graph;
|
|
55526
|
+
if (!graph) return [];
|
|
55527
|
+
let data;
|
|
55528
|
+
try {
|
|
55529
|
+
data = graph.getElementDataByState("node", "selected") || [];
|
|
55530
|
+
} catch (e) {
|
|
55531
|
+
return [];
|
|
55532
|
+
}
|
|
55533
|
+
return data.map((nd) => nd.id);
|
|
55534
|
+
}
|
|
55535
|
+
/************************************************************
|
|
55536
|
+
* Move the ring to these nodes and off the ones that had it.
|
|
55537
|
+
************************************************************/
|
|
55538
|
+
function paint_selection(gobj, ids) {
|
|
55539
|
+
let priv = gobj.priv;
|
|
55540
|
+
let prev = priv._selected_paint_ids || [];
|
|
55541
|
+
let next = ids || [];
|
|
55542
|
+
priv._selected_paint_ids = next;
|
|
55543
|
+
repaint_cards(gobj, /* @__PURE__ */ new Set([...prev, ...next]));
|
|
55544
|
+
}
|
|
55545
|
+
/************************************************************
|
|
55546
|
+
* Select a SET of nodes: what a marquee and a shift-click do.
|
|
55547
|
+
*
|
|
55548
|
+
* It leaves `_selected_node_id` null even for a set of one,
|
|
55549
|
+
* because that field is not "the selection", it is "the node
|
|
55550
|
+
* opened for editing" -- the resize handles, the ports and the
|
|
55551
|
+
* popovers hang off it, and none of them means anything over a
|
|
55552
|
+
* set. Clicking a node is what opens one (`select_node`); a
|
|
55553
|
+
* marquee selects, it does not open.
|
|
55554
|
+
************************************************************/
|
|
55555
|
+
function set_selection(gobj, ids) {
|
|
55556
|
+
let graph = gobj.priv.graph;
|
|
55557
|
+
let next = [];
|
|
55558
|
+
for (let id of ids || []) try {
|
|
55559
|
+
if (graph.getNodeData(id)) next.push(id);
|
|
55560
|
+
} catch (e) {}
|
|
55561
|
+
deselect_node(gobj);
|
|
55562
|
+
if (!next.length) return;
|
|
55563
|
+
history_pause(gobj);
|
|
55564
|
+
try {
|
|
55565
|
+
let states = {};
|
|
55566
|
+
for (let id of next) states[id] = ["selected"];
|
|
55567
|
+
graph.setElementState(states);
|
|
55568
|
+
} catch (e) {
|
|
55569
|
+
log_error(`${gobj_short_name(gobj)}: cannot set the selection: ${e}`);
|
|
55570
|
+
}
|
|
55571
|
+
paint_selection(gobj, next);
|
|
55572
|
+
graph_draw(gobj).then(() => {
|
|
55573
|
+
history_resume(gobj);
|
|
55574
|
+
});
|
|
55575
|
+
}
|
|
55576
|
+
/************************************************************
|
|
55577
|
+
* Add a node to the selection, or take it out of it.
|
|
55578
|
+
************************************************************/
|
|
55579
|
+
function toggle_in_selection(gobj, node_id) {
|
|
55580
|
+
let priv = gobj.priv;
|
|
55581
|
+
let current = new Set(selected_node_ids(gobj));
|
|
55582
|
+
for (let id of priv._selected_paint_ids || []) current.add(id);
|
|
55583
|
+
if (current.has(node_id)) current.delete(node_id);
|
|
55584
|
+
else current.add(node_id);
|
|
55585
|
+
set_selection(gobj, [...current]);
|
|
55586
|
+
}
|
|
55485
55587
|
function select_node(gobj, node_id) {
|
|
55486
55588
|
let priv = gobj.priv;
|
|
55487
55589
|
let graph = priv.graph;
|
|
@@ -55491,6 +55593,7 @@ function select_node(gobj, node_id) {
|
|
|
55491
55593
|
graph.setElementState(node_id, ["selected"]);
|
|
55492
55594
|
} catch (e) {}
|
|
55493
55595
|
priv._selected_node_id = node_id;
|
|
55596
|
+
paint_selection(gobj, [node_id]);
|
|
55494
55597
|
show_resize_handles(gobj);
|
|
55495
55598
|
show_node_icon(gobj);
|
|
55496
55599
|
graph_draw(gobj).then(() => {
|
|
@@ -55506,12 +55609,17 @@ function deselect_node(gobj) {
|
|
|
55506
55609
|
hide_node_popover(gobj);
|
|
55507
55610
|
hide_delete_confirm(gobj);
|
|
55508
55611
|
hide_unlink_confirm(gobj);
|
|
55509
|
-
|
|
55612
|
+
let clearing = /* @__PURE__ */ new Set([...selected_node_ids(gobj), ...priv._selected_paint_ids || []]);
|
|
55613
|
+
if (priv._selected_node_id) clearing.add(priv._selected_node_id);
|
|
55614
|
+
if (clearing.size) {
|
|
55510
55615
|
history_pause(gobj);
|
|
55511
55616
|
try {
|
|
55512
|
-
|
|
55617
|
+
let states = {};
|
|
55618
|
+
for (let id of clearing) states[id] = [];
|
|
55619
|
+
graph.setElementState(states);
|
|
55513
55620
|
} catch (e) {}
|
|
55514
55621
|
priv._selected_node_id = null;
|
|
55622
|
+
paint_selection(gobj, []);
|
|
55515
55623
|
graph_draw(gobj).then(() => {
|
|
55516
55624
|
history_resume(gobj);
|
|
55517
55625
|
});
|
|
@@ -56798,33 +56906,36 @@ function refresh_minimap(gobj) {
|
|
|
56798
56906
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
56799
56907
|
* shared now. Returns null for a node that carries no desc.
|
|
56800
56908
|
************************************************************/
|
|
56801
|
-
function node_innerHTML_of(nd, theme, highlight) {
|
|
56909
|
+
function node_innerHTML_of(nd, theme, highlight, selected) {
|
|
56802
56910
|
if (!nd || !nd.data || !nd.data.desc) return null;
|
|
56803
56911
|
let desc = nd.data.desc;
|
|
56804
56912
|
let record = nd.data.record || {};
|
|
56805
56913
|
let label = node_label(desc, record);
|
|
56806
56914
|
switch (desc.node_treedb_type) {
|
|
56807
|
-
case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight);
|
|
56808
|
-
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight);
|
|
56809
|
-
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight);
|
|
56915
|
+
case "child": return build_chip_innerHTML(desc.color, theme, record.icon, label, record.id, highlight, selected);
|
|
56916
|
+
case "extended": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, true, record.id, highlight, selected);
|
|
56917
|
+
case "hierarchical": return build_node_innerHTML(desc.color, theme, record.icon, label, desc.topic_name, false, record.id, highlight, selected);
|
|
56810
56918
|
}
|
|
56811
56919
|
return null;
|
|
56812
56920
|
}
|
|
56813
56921
|
/************************************************************
|
|
56814
|
-
* Repaint
|
|
56815
|
-
*
|
|
56816
|
-
*
|
|
56922
|
+
* Repaint these cards with the flags they carry RIGHT NOW.
|
|
56923
|
+
*
|
|
56924
|
+
* One place, because the flags are independent and each used to
|
|
56925
|
+
* be written by whoever repainted last: a find that repainted its
|
|
56926
|
+
* matches erased the selection ring off them, and a selection
|
|
56927
|
+
* repainted over a match erased the amber. Both are read here
|
|
56928
|
+
* from where they live.
|
|
56817
56929
|
************************************************************/
|
|
56818
|
-
function
|
|
56930
|
+
function repaint_cards(gobj, ids) {
|
|
56819
56931
|
let priv = gobj.priv;
|
|
56820
56932
|
let graph = priv.graph;
|
|
56821
|
-
if (!graph) return;
|
|
56822
|
-
let
|
|
56823
|
-
let
|
|
56824
|
-
if (touched.size === 0) return;
|
|
56933
|
+
if (!graph || !ids || !ids.size) return;
|
|
56934
|
+
let focus = new Set(priv._focus_ids || []);
|
|
56935
|
+
let selected = new Set(priv._selected_paint_ids || []);
|
|
56825
56936
|
let updates = [];
|
|
56826
|
-
for (let id of
|
|
56827
|
-
let html = node_innerHTML_of(graph.getNodeData(id), priv.theme,
|
|
56937
|
+
for (let id of ids) {
|
|
56938
|
+
let html = node_innerHTML_of(graph.getNodeData(id), priv.theme, focus.has(id), selected.has(id));
|
|
56828
56939
|
if (html !== null) updates.push({
|
|
56829
56940
|
id,
|
|
56830
56941
|
style: { innerHTML: html }
|
|
@@ -56835,19 +56946,32 @@ function apply_node_highlight(gobj, prev_ids, next_ids) {
|
|
|
56835
56946
|
graph.updateNodeData(updates);
|
|
56836
56947
|
graph.draw();
|
|
56837
56948
|
} catch (e) {
|
|
56838
|
-
log_error(`${gobj_short_name(gobj)}: cannot repaint the
|
|
56949
|
+
log_error(`${gobj_short_name(gobj)}: cannot repaint the cards: ${e}`);
|
|
56839
56950
|
}
|
|
56840
56951
|
}
|
|
56952
|
+
/************************************************************
|
|
56953
|
+
* Repaint the cards whose highlight state CHANGES: the ones that had it
|
|
56954
|
+
* and lose it, plus the ones that gain it. Only those — a treedb graph
|
|
56955
|
+
* is redrawn per keystroke of the find box otherwise.
|
|
56956
|
+
************************************************************/
|
|
56957
|
+
function apply_node_highlight(gobj, prev_ids, next_ids) {
|
|
56958
|
+
if (!gobj.priv.graph) return;
|
|
56959
|
+
let next = new Set(next_ids || []);
|
|
56960
|
+
let touched = /* @__PURE__ */ new Set([...prev_ids || [], ...next]);
|
|
56961
|
+
if (touched.size === 0) return;
|
|
56962
|
+
repaint_cards(gobj, touched);
|
|
56963
|
+
}
|
|
56841
56964
|
function refresh_html_nodes_theme(gobj, theme) {
|
|
56842
56965
|
let priv = gobj.priv;
|
|
56843
56966
|
let graph = priv.graph;
|
|
56844
56967
|
if (!graph) return;
|
|
56845
56968
|
let nodes = graph.getData().nodes || [];
|
|
56846
56969
|
let highlighted = new Set(priv._focus_ids || []);
|
|
56970
|
+
let selected = new Set(priv._selected_paint_ids || []);
|
|
56847
56971
|
let updates = [];
|
|
56848
56972
|
for (let i = 0; i < nodes.length; i++) {
|
|
56849
56973
|
let id = nodes[i].id;
|
|
56850
|
-
let html = node_innerHTML_of(graph.getNodeData(id), theme, highlighted.has(id));
|
|
56974
|
+
let html = node_innerHTML_of(graph.getNodeData(id), theme, highlighted.has(id), selected.has(id));
|
|
56851
56975
|
if (html !== null) updates.push({
|
|
56852
56976
|
id,
|
|
56853
56977
|
style: { innerHTML: html }
|
|
@@ -56877,12 +57001,29 @@ function refresh_default_edges_theme(gobj, theme) {
|
|
|
56877
57001
|
if (updates.length > 0) graph.updateEdgeData(updates);
|
|
56878
57002
|
}
|
|
56879
57003
|
/************************************************************
|
|
57004
|
+
* The rings a card can wear, composed into one `box-shadow`.
|
|
57005
|
+
*
|
|
57006
|
+
* A node can be a find match and be selected at the same time, so
|
|
57007
|
+
* neither ring may be written by overwriting the other: the amber
|
|
57008
|
+
* halo hugs the card and the blue selection ring is drawn outside
|
|
57009
|
+
* it, which is also the order that reads correctly when only one
|
|
57010
|
+
* of them is on.
|
|
57011
|
+
************************************************************/
|
|
57012
|
+
function ring_shadow(highlight, selected, base_shadow) {
|
|
57013
|
+
let rings = [];
|
|
57014
|
+
if (highlight) rings.push(`0 0 0 4px ${HIGHLIGHT_HALO}`);
|
|
57015
|
+
if (selected) rings.push(`0 0 0 ${highlight ? "7px" : "3px"} ${SELECT_RING}`);
|
|
57016
|
+
if (base_shadow) rings.push(base_shadow);
|
|
57017
|
+
if (!rings.length) return "";
|
|
57018
|
+
return `box-shadow: ${rings.join(", ")};`;
|
|
57019
|
+
}
|
|
57020
|
+
/************************************************************
|
|
56880
57021
|
* Build innerHTML for pure-child (leaf) nodes: a compact
|
|
56881
57022
|
* chip-card. Same colour/typography family as the entity card
|
|
56882
57023
|
* but lighter (1px border, no shadow, single line). The name is
|
|
56883
57024
|
* always legible (ellipsis + native title tooltip on overflow).
|
|
56884
57025
|
************************************************************/
|
|
56885
|
-
function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
|
|
57026
|
+
function build_chip_innerHTML(color, theme, icon, label, key, highlight, selected) {
|
|
56886
57027
|
let title = key || label;
|
|
56887
57028
|
let dark = theme === "dark";
|
|
56888
57029
|
let bg = dark ? `color-mix(in srgb, ${color} 30%, #2c3542)` : `color-mix(in srgb, ${color} 10%, ${dark ? "#1b2230" : "#ffffff"})`;
|
|
@@ -56901,7 +57042,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
|
|
|
56901
57042
|
height: 100%;
|
|
56902
57043
|
background: ${bg};
|
|
56903
57044
|
border: ${highlight ? "3px" : "1px"} solid ${border};
|
|
56904
|
-
${highlight
|
|
57045
|
+
${ring_shadow(highlight, selected, "")}
|
|
56905
57046
|
border-radius: 8px;
|
|
56906
57047
|
color: ${text_color};
|
|
56907
57048
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
@@ -56927,7 +57068,7 @@ function build_chip_innerHTML(color, theme, icon, label, key, highlight) {
|
|
|
56927
57068
|
* colour is kept (per-topic differentiation) but softened via
|
|
56928
57069
|
* color-mix instead of a harsh saturated fill. Theme-aware.
|
|
56929
57070
|
************************************************************/
|
|
56930
|
-
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight) {
|
|
57071
|
+
function build_node_innerHTML(color, theme, icon, label, topic_name, structural, key, highlight, selected) {
|
|
56931
57072
|
let title = key || label;
|
|
56932
57073
|
let dark = theme === "dark";
|
|
56933
57074
|
let surface = dark ? "#1b2230" : "#ffffff";
|
|
@@ -56969,7 +57110,7 @@ function build_node_innerHTML(color, theme, icon, label, topic_name, structural,
|
|
|
56969
57110
|
background: ${bg};
|
|
56970
57111
|
border: ${highlight ? "3px" : "1.5px"} ${border_style} ${border};
|
|
56971
57112
|
border-radius: 10px;
|
|
56972
|
-
|
|
57113
|
+
${ring_shadow(highlight, selected, shadow)}
|
|
56973
57114
|
color: ${title_color};
|
|
56974
57115
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
|
|
56975
57116
|
display: flex;
|
|
@@ -57013,17 +57154,89 @@ function execute_delete_node(gobj, nodeData) {
|
|
|
57013
57154
|
deselect_node(gobj);
|
|
57014
57155
|
}
|
|
57015
57156
|
/************************************************************
|
|
57157
|
+
* Every node in the graph.
|
|
57158
|
+
************************************************************/
|
|
57159
|
+
function select_all_nodes(gobj) {
|
|
57160
|
+
let graph = gobj.priv.graph;
|
|
57161
|
+
if (!graph) return;
|
|
57162
|
+
set_selection(gobj, ((graph.getData() || {}).nodes || []).map((nd) => nd.id));
|
|
57163
|
+
}
|
|
57164
|
+
/************************************************************
|
|
57165
|
+
* The nodes currently selected, as their node data.
|
|
57166
|
+
************************************************************/
|
|
57167
|
+
function selected_nodes_data(gobj) {
|
|
57168
|
+
let priv = gobj.priv;
|
|
57169
|
+
let graph = priv.graph;
|
|
57170
|
+
let ids = new Set(selected_node_ids(gobj));
|
|
57171
|
+
for (let id of priv._selected_paint_ids || []) ids.add(id);
|
|
57172
|
+
if (priv._selected_node_id) ids.add(priv._selected_node_id);
|
|
57173
|
+
let out = [];
|
|
57174
|
+
for (let id of ids) {
|
|
57175
|
+
let nd;
|
|
57176
|
+
try {
|
|
57177
|
+
nd = graph.getNodeData(id);
|
|
57178
|
+
} catch (e) {
|
|
57179
|
+
continue;
|
|
57180
|
+
}
|
|
57181
|
+
if (nd && nd.data && nd.data.desc) out.push(nd);
|
|
57182
|
+
}
|
|
57183
|
+
return out;
|
|
57184
|
+
}
|
|
57185
|
+
/************************************************************
|
|
57186
|
+
* What a delete takes with it, for ONE node or for a set.
|
|
57187
|
+
*
|
|
57188
|
+
* Same sentence in both cases and the same keys, because it is the
|
|
57189
|
+
* same warning: these views delete with `force`, which UNLINKS the
|
|
57190
|
+
* children (they survive, loose) and cleans the node off its
|
|
57191
|
+
* parents. Over a set the two numbers are the sums -- an operator
|
|
57192
|
+
* about to detach eleven records has to read eleven, not "are you
|
|
57193
|
+
* sure".
|
|
57194
|
+
************************************************************/
|
|
57195
|
+
function delete_question(nodes) {
|
|
57196
|
+
let children = 0;
|
|
57197
|
+
let parents = 0;
|
|
57198
|
+
for (let nd of nodes) {
|
|
57199
|
+
let impact = delete_impact(nd.data.desc, nd.data.record || {});
|
|
57200
|
+
children += impact.children;
|
|
57201
|
+
parents += impact.parents;
|
|
57202
|
+
}
|
|
57203
|
+
let question;
|
|
57204
|
+
if (nodes.length === 1) {
|
|
57205
|
+
let nd = nodes[0];
|
|
57206
|
+
question = t("delete") + " " + nd.data.desc.topic_name + ": " + (nd.data.record || {}).id + "?";
|
|
57207
|
+
} else question = t("delete") + " " + nodes.length + " " + t("records") + "?";
|
|
57208
|
+
if (children > 0) question += "\n" + children + " " + t("children will be unlinked, not deleted", { count: children });
|
|
57209
|
+
if (parents > 0) question += "\n" + t("it will be detached from") + " " + parents + " " + t("parents", { count: parents });
|
|
57210
|
+
return question;
|
|
57211
|
+
}
|
|
57212
|
+
/************************************************************
|
|
57213
|
+
* Delete every selected node (the Delete key).
|
|
57214
|
+
************************************************************/
|
|
57215
|
+
function request_delete_selection(gobj) {
|
|
57216
|
+
let nodes = selected_nodes_data(gobj);
|
|
57217
|
+
if (!nodes.length) return;
|
|
57218
|
+
if (!gobj_read_bool_attr(gobj, "confirm_delete_node")) {
|
|
57219
|
+
execute_delete_selection(gobj, nodes);
|
|
57220
|
+
return;
|
|
57221
|
+
}
|
|
57222
|
+
show_confirm_popover(gobj, null, delete_question(nodes), "delete", "#ff4d4f", () => execute_delete_selection(gobj, nodes), "_delete_confirm_el");
|
|
57223
|
+
}
|
|
57224
|
+
function execute_delete_selection(gobj, nodes) {
|
|
57225
|
+
let priv = gobj.priv;
|
|
57226
|
+
hide_delete_confirm(gobj);
|
|
57227
|
+
for (let nd of nodes) gobj_publish_event(gobj, "EV_DELETE_NODE", {
|
|
57228
|
+
treedb_name: priv.treedb_name,
|
|
57229
|
+
topic_name: nd.data.desc.topic_name,
|
|
57230
|
+
record: nd.data.record
|
|
57231
|
+
});
|
|
57232
|
+
deselect_node(gobj);
|
|
57233
|
+
}
|
|
57234
|
+
/************************************************************
|
|
57016
57235
|
* Show a confirmation popover next to the delete icon.
|
|
57017
57236
|
************************************************************/
|
|
57018
57237
|
function show_delete_confirm(gobj, nodeData) {
|
|
57019
57238
|
let priv = gobj.priv;
|
|
57020
|
-
|
|
57021
|
-
let topic_name = nodeData.data.desc.topic_name;
|
|
57022
|
-
let impact = delete_impact(nodeData.data.desc, record);
|
|
57023
|
-
let question = t("delete") + " " + topic_name + ": " + record.id + "?";
|
|
57024
|
-
if (impact.children > 0) question += "\n" + impact.children + " " + t("children will be unlinked, not deleted", { count: impact.children });
|
|
57025
|
-
if (impact.parents > 0) question += "\n" + t("it will be detached from") + " " + impact.parents + " " + t("parents", { count: impact.parents });
|
|
57026
|
-
show_confirm_popover(gobj, priv._node_delete_el, question, "delete", "#ff4d4f", () => execute_delete_node(gobj, nodeData), "_delete_confirm_el");
|
|
57239
|
+
show_confirm_popover(gobj, priv._node_delete_el, delete_question([nodeData]), "delete", "#ff4d4f", () => execute_delete_node(gobj, nodeData), "_delete_confirm_el");
|
|
57027
57240
|
}
|
|
57028
57241
|
function hide_delete_confirm(gobj) {
|
|
57029
57242
|
hide_overlay(gobj, "_delete_confirm_el");
|
|
@@ -57890,6 +58103,49 @@ function ac_node_drag_end(gobj, event, kw, src) {
|
|
|
57890
58103
|
return 0;
|
|
57891
58104
|
}
|
|
57892
58105
|
/************************************************************
|
|
58106
|
+
* A key, while the graph has focus.
|
|
58107
|
+
*
|
|
58108
|
+
* Full screen keeps the two keys it always had. The rest belong to
|
|
58109
|
+
* the selection, so they only mean anything in edition -- outside
|
|
58110
|
+
* it there is nothing selected to clear, select or delete.
|
|
58111
|
+
************************************************************/
|
|
58112
|
+
function ac_key_down(gobj, event, kw, src) {
|
|
58113
|
+
let priv = gobj.priv;
|
|
58114
|
+
let key = kw && kw.key || "";
|
|
58115
|
+
if (gobj_read_bool_attr(gobj, "with_fullscreen")) {
|
|
58116
|
+
let fullscreen = graph_get_plugin(gobj, "fullscreen");
|
|
58117
|
+
if (fullscreen) {
|
|
58118
|
+
if (key === "F" || key === "f") fullscreen.request();
|
|
58119
|
+
else if (key === "Escape") fullscreen.exit();
|
|
58120
|
+
}
|
|
58121
|
+
}
|
|
58122
|
+
if (!priv.edit_mode) return 0;
|
|
58123
|
+
if (key === "Escape") {
|
|
58124
|
+
deselect_node(gobj);
|
|
58125
|
+
return 0;
|
|
58126
|
+
}
|
|
58127
|
+
if (kw.ctrl && (key === "a" || key === "A")) {
|
|
58128
|
+
select_all_nodes(gobj);
|
|
58129
|
+
return 0;
|
|
58130
|
+
}
|
|
58131
|
+
if (key === "Delete" || key === "Backspace") {
|
|
58132
|
+
request_delete_selection(gobj);
|
|
58133
|
+
return 0;
|
|
58134
|
+
}
|
|
58135
|
+
return 0;
|
|
58136
|
+
}
|
|
58137
|
+
/************************************************************
|
|
58138
|
+
* The rubber band let go: these are the nodes it enclosed.
|
|
58139
|
+
*
|
|
58140
|
+
* They arrive in the kw because `onSelect` runs BEFORE G6 writes
|
|
58141
|
+
* the state, so asking the graph here would answer the previous
|
|
58142
|
+
* selection.
|
|
58143
|
+
************************************************************/
|
|
58144
|
+
function ac_brush_select(gobj, event, kw, src) {
|
|
58145
|
+
set_selection(gobj, kw && kw.ids || []);
|
|
58146
|
+
return 0;
|
|
58147
|
+
}
|
|
58148
|
+
/************************************************************
|
|
57893
58149
|
* Node click - publish vertex clicked event
|
|
57894
58150
|
************************************************************/
|
|
57895
58151
|
function ac_node_click(gobj, event, kw, src) {
|
|
@@ -57904,7 +58160,8 @@ function ac_node_click(gobj, event, kw, src) {
|
|
|
57904
58160
|
topic_name: nodedata.data.desc.topic_name,
|
|
57905
58161
|
record: nodedata.data.record
|
|
57906
58162
|
});
|
|
57907
|
-
if (priv.edit_mode)
|
|
58163
|
+
if (priv.edit_mode && kw.evt.shiftKey) toggle_in_selection(gobj, node_id);
|
|
58164
|
+
else if (priv.edit_mode) {
|
|
57908
58165
|
let containerRect = priv.$container.getBoundingClientRect();
|
|
57909
58166
|
let canvasPoint = graph.getCanvasByViewport([kw.evt.client.x - containerRect.left, kw.evt.client.y - containerRect.top]);
|
|
57910
58167
|
let port_key = detect_port_click(gobj, node_id, canvasPoint[0], canvasPoint[1]);
|
|
@@ -58131,6 +58388,16 @@ function create_gclass$1(gclass_name) {
|
|
|
58131
58388
|
ac_node_drag_end,
|
|
58132
58389
|
null
|
|
58133
58390
|
],
|
|
58391
|
+
[
|
|
58392
|
+
"EV_BRUSH_SELECT",
|
|
58393
|
+
ac_brush_select,
|
|
58394
|
+
null
|
|
58395
|
+
],
|
|
58396
|
+
[
|
|
58397
|
+
"EV_KEY_DOWN",
|
|
58398
|
+
ac_key_down,
|
|
58399
|
+
null
|
|
58400
|
+
],
|
|
58134
58401
|
[
|
|
58135
58402
|
"EV_ZOOM_IN",
|
|
58136
58403
|
ac_zoom_in,
|
|
@@ -58239,6 +58506,8 @@ function create_gclass$1(gclass_name) {
|
|
|
58239
58506
|
["EV_NODE_CONTEXT_MENU", 0],
|
|
58240
58507
|
["EV_CANVAS_CLICK", 0],
|
|
58241
58508
|
["EV_NODE_DRAG_END", 0],
|
|
58509
|
+
["EV_BRUSH_SELECT", 0],
|
|
58510
|
+
["EV_KEY_DOWN", 0],
|
|
58242
58511
|
["EV_ZOOM_IN", 0],
|
|
58243
58512
|
["EV_ZOOM_OUT", 0],
|
|
58244
58513
|
["EV_ZOOM_RESET", 0],
|