@yuneta/gobj-ui 7.26.27 → 7.26.28
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 +458 -22
- package/dist/gobj-ui.cjs.js +1063 -216
- package/dist/gobj-ui.es.js +1064 -217
- package/package.json +1 -1
- package/scripts/validate-locales.mjs +2269 -316
- package/src/c_g6_nodes_tree.js +1086 -253
- package/src/c_yui_form.js +11 -1
- package/src/c_yui_fsm_graph.js +5 -0
- package/src/c_yui_gclass.js +11 -0
- package/src/c_yui_gobj_tree_js.js +17 -0
- package/src/c_yui_json_graph.js +5 -0
- package/src/c_yui_nav.js +9 -6
- package/src/c_yui_pager.js +1 -1
- package/src/c_yui_period.js +11 -4
- package/src/c_yui_schema_editor.js +19 -7
- package/src/c_yui_shell.js +7 -7
- package/src/c_yui_treedb_graph.js +15 -6
- package/src/c_yui_treedb_schema.js +5 -0
- package/src/c_yui_treedb_topic_with_form.js +10 -10
- package/src/c_yui_treedb_topics.js +6 -6
- package/src/c_yui_window.js +2 -2
- package/src/c_yui_wizard.js +8 -1
- package/src/form_json_field.js +7 -0
- package/src/g6_canvas_tab_order.js +84 -0
- package/src/g6_canvas_tab_order.wiring.test.js +232 -0
- package/src/g6_nodes_tree_controls.test.js +547 -0
- package/src/g6_nodes_tree_focus.wiring.test.js +1360 -0
- package/src/g6_nodes_tree_i18n_keys.test.js +241 -5
- package/src/i18n_key_functions.js +146 -0
- package/src/i18n_key_functions.test.js +1204 -0
- package/src/lib_graph.js +38 -1
- package/src/nav_backbar_name.wiring.test.js +82 -0
- package/src/schema_flags.js +47 -0
- package/src/schema_import.js +7 -0
- package/src/shell_modals.js +20 -16
- package/src/shell_route_map.js +12 -2
- package/src/wizard_helpers.js +8 -0
- package/src/yui_dev.js +16 -3
- package/src/yui_dev_controls.test.js +174 -0
- package/src/yui_gclass_view.js +2 -2
- package/src/yui_graph_camera.js +1 -1
- package/src/yui_install.js +10 -8
- package/src/yui_table_select.js +2 -2
- package/src/yui_time.js +18 -3
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -1848,7 +1848,7 @@ function build_toolbar$1(gobj, config) {
|
|
|
1848
1848
|
}
|
|
1849
1849
|
priv.avatar_nodes = [];
|
|
1850
1850
|
priv.conn_nodes = [];
|
|
1851
|
-
|
|
1851
|
+
const toolbar_aria = tb.aria_label || "toolbar";
|
|
1852
1852
|
let $bar = (0, _yuneta_gobj_js.createElement2)([
|
|
1853
1853
|
"nav",
|
|
1854
1854
|
{
|
|
@@ -2059,8 +2059,8 @@ function build_toolbar_brand_item(gobj, it) {
|
|
|
2059
2059
|
************************************************************/
|
|
2060
2060
|
function build_toolbar_avatar_item(gobj, it) {
|
|
2061
2061
|
let priv = gobj.priv;
|
|
2062
|
-
|
|
2063
|
-
|
|
2062
|
+
const aria_key = it.aria_label || it.name || it.id || "user menu";
|
|
2063
|
+
const i18n_aria = it.aria_label || it.name || "user menu";
|
|
2064
2064
|
let action_type = it.action && it.action.type || "";
|
|
2065
2065
|
let attrs = {
|
|
2066
2066
|
class: "navbar-item yui-toolbar-item yui-toolbar-avatar is-unselectable",
|
|
@@ -2136,8 +2136,8 @@ function attach_context_action(gobj, $item, it) {
|
|
|
2136
2136
|
************************************************************/
|
|
2137
2137
|
function build_toolbar_connection_item(gobj, it) {
|
|
2138
2138
|
let priv = gobj.priv;
|
|
2139
|
-
|
|
2140
|
-
|
|
2139
|
+
const aria_key = it.aria_label || it.name || it.id || "backend connection";
|
|
2140
|
+
const i18n_aria = it.aria_label || it.name || "backend connection";
|
|
2141
2141
|
let attrs = {
|
|
2142
2142
|
class: "navbar-item yui-toolbar-item yui-toolbar-conn is-unselectable is-disconnected",
|
|
2143
2143
|
type: "button",
|
|
@@ -2243,8 +2243,8 @@ function toggle_toolbar_dropdown(gobj, item, action, $trigger) {
|
|
|
2243
2243
|
function open_toolbar_dropdown(gobj, item, action, $trigger) {
|
|
2244
2244
|
let priv = gobj.priv;
|
|
2245
2245
|
if (!priv || !priv.layers || !priv.layers.popup) return;
|
|
2246
|
-
|
|
2247
|
-
|
|
2246
|
+
const aria_key = item && (item.aria_label || item.name || item.id) || "menu";
|
|
2247
|
+
const i18n_aria = item && (item.aria_label || item.name) || "menu";
|
|
2248
2248
|
let $panel = (0, _yuneta_gobj_js.createElement2)(["div", {
|
|
2249
2249
|
class: "yui-toolbar-dropdown-panel",
|
|
2250
2250
|
role: "menu",
|
|
@@ -3781,19 +3781,22 @@ function build_dialog(shell, message, buttons, opts) {
|
|
|
3781
3781
|
* "Delete" and "Cancel", keys that no locale carries, so a dialog
|
|
3782
3782
|
* that took the defaults read in English in every language.
|
|
3783
3783
|
*
|
|
3784
|
-
*
|
|
3785
|
-
* consumer
|
|
3786
|
-
*
|
|
3784
|
+
* An app that mounts these dialogs must define the five keys. A
|
|
3785
|
+
* consumer's validate-locales reads them where build_dialog() gets
|
|
3786
|
+
* them (a const, `DEFAULT_LABEL.ok`, it follows), and in
|
|
3787
|
+
* SHELL_MODALS_I18N_KEYS, which a test holds to this table. (Up to
|
|
3788
|
+
* 7.26.27 they were written as `i18n:` entries, which only a regex
|
|
3789
|
+
* scan of `i18n: "..."` happened to see.)
|
|
3787
3790
|
***************************************************************/
|
|
3788
3791
|
var DEFAULT_LABEL = Object.freeze({
|
|
3789
|
-
ok:
|
|
3790
|
-
yes:
|
|
3791
|
-
no:
|
|
3792
|
-
delete:
|
|
3793
|
-
cancel:
|
|
3792
|
+
ok: "ok",
|
|
3793
|
+
yes: "yes",
|
|
3794
|
+
no: "no",
|
|
3795
|
+
delete: "delete",
|
|
3796
|
+
cancel: "cancel"
|
|
3794
3797
|
});
|
|
3795
3798
|
function yui_shell_confirm_ok(shell, message, opts) {
|
|
3796
|
-
|
|
3799
|
+
const label = opts && opts.ok_label || DEFAULT_LABEL.ok;
|
|
3797
3800
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "success" });
|
|
3798
3801
|
return build_dialog(shell, message, [{
|
|
3799
3802
|
label,
|
|
@@ -3802,8 +3805,8 @@ function yui_shell_confirm_ok(shell, message, opts) {
|
|
|
3802
3805
|
}], opts).then(() => void 0);
|
|
3803
3806
|
}
|
|
3804
3807
|
function yui_shell_confirm_yesno(shell, message, opts) {
|
|
3805
|
-
|
|
3806
|
-
|
|
3808
|
+
const yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes;
|
|
3809
|
+
const no_label = opts && opts.no_label || DEFAULT_LABEL.no;
|
|
3807
3810
|
return build_dialog(shell, message, [{
|
|
3808
3811
|
label: yes_label,
|
|
3809
3812
|
value: "yes",
|
|
@@ -3828,8 +3831,8 @@ function yui_shell_confirm_yesno(shell, message, opts) {
|
|
|
3828
3831
|
* pressed.
|
|
3829
3832
|
***************************************************************/
|
|
3830
3833
|
function yui_shell_confirm_danger(shell, message, opts) {
|
|
3831
|
-
|
|
3832
|
-
|
|
3834
|
+
const confirm_label = opts && opts.confirm_label || DEFAULT_LABEL.delete;
|
|
3835
|
+
const cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel;
|
|
3833
3836
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "danger" });
|
|
3834
3837
|
return build_dialog(shell, message, [{
|
|
3835
3838
|
label: confirm_label,
|
|
@@ -3841,9 +3844,9 @@ function yui_shell_confirm_danger(shell, message, opts) {
|
|
|
3841
3844
|
}], opts).then((v) => v === "confirm");
|
|
3842
3845
|
}
|
|
3843
3846
|
function yui_shell_confirm_yesnocancel(shell, message, opts) {
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
+
const yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes;
|
|
3848
|
+
const no_label = opts && opts.no_label || DEFAULT_LABEL.no;
|
|
3849
|
+
const cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel;
|
|
3847
3850
|
return build_dialog(shell, message, [
|
|
3848
3851
|
{
|
|
3849
3852
|
label: yes_label,
|
|
@@ -4497,7 +4500,7 @@ function set_max_icon(gobj, maximized) {
|
|
|
4497
4500
|
if (!$container) return;
|
|
4498
4501
|
let $btn = $container.querySelector(".wc-max");
|
|
4499
4502
|
if ($btn) {
|
|
4500
|
-
|
|
4503
|
+
const key = maximized ? "restore" : "maximize";
|
|
4501
4504
|
$btn.innerHTML = maximized ? WC_RESTORE : WC_MAX;
|
|
4502
4505
|
$btn.setAttribute("title", (0, i18next.t)(key));
|
|
4503
4506
|
$btn.setAttribute("data-i18n-title", key);
|
|
@@ -5599,7 +5602,7 @@ function render_header(gobj) {
|
|
|
5599
5602
|
let $discard = $container.querySelector(".yui-pager-discard");
|
|
5600
5603
|
$back.classList.toggle("is-hidden", !model.show_back);
|
|
5601
5604
|
let $back_icon = $back.querySelector("i");
|
|
5602
|
-
|
|
5605
|
+
const back_key = model.back_kind === "close" ? "close" : "back";
|
|
5603
5606
|
$back_icon.className = back_key === "close" ? "yi-xmark" : "yi-arrow-left";
|
|
5604
5607
|
$back.setAttribute("title", (0, i18next.t)(back_key));
|
|
5605
5608
|
$back.setAttribute("data-i18n-title", back_key);
|
|
@@ -12754,7 +12757,7 @@ function set_pressed_state($container, selector, set) {
|
|
|
12754
12757
|
*
|
|
12755
12758
|
* Utilities for graph, using Bulma
|
|
12756
12759
|
*
|
|
12757
|
-
* Copyright (c) 2025, ArtGins.
|
|
12760
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
12758
12761
|
* All Rights Reserved.
|
|
12759
12762
|
***********************************************************************/
|
|
12760
12763
|
/************************************************************
|
|
@@ -12783,15 +12786,46 @@ function removeChildElements($element) {
|
|
|
12783
12786
|
}
|
|
12784
12787
|
/************************************************************
|
|
12785
12788
|
* Disable/Enable elements
|
|
12786
|
-
|
|
12789
|
+
*
|
|
12790
|
+
* A disabled control says so to the keyboard and to a screen
|
|
12791
|
+
* reader too, not only to the pointer:
|
|
12792
|
+
* - `disabled`, what the stylesheets and the click guards
|
|
12793
|
+
* read (on a `div` drawn as a button it means nothing to
|
|
12794
|
+
* the browser itself);
|
|
12795
|
+
* - `aria-disabled="true"`, what a reader announces -- without
|
|
12796
|
+
* it a disabled toolbar item was heard as a button that
|
|
12797
|
+
* works;
|
|
12798
|
+
* - `tabindex="-1"`, so Tab does not stop on a control that
|
|
12799
|
+
* does nothing.
|
|
12800
|
+
*
|
|
12801
|
+
* Enabled again, it gets back the tabindex it had, kept in
|
|
12802
|
+
* `data-enabled-tabindex` while it is disabled (empty: it had
|
|
12803
|
+
* none, and it gets none). Whoever BUILDS a control disabled
|
|
12804
|
+
* writes that attribute itself, with the tabindex the control
|
|
12805
|
+
* takes once enabled (see toolbar_item_html in
|
|
12806
|
+
* c_g6_nodes_tree.js). An element that keeps the focus while it
|
|
12807
|
+
* is disabled keeps it: tabindex -1 still takes a focus, it is
|
|
12808
|
+
* only left out of the Tab order.
|
|
12809
|
+
************************************************************/
|
|
12810
|
+
var ENABLED_TABINDEX = "data-enabled-tabindex";
|
|
12787
12811
|
function disableElements($container, selector) {
|
|
12788
12812
|
$container.querySelectorAll(selector).forEach((el) => {
|
|
12789
12813
|
el.setAttribute("disabled", "");
|
|
12814
|
+
el.setAttribute("aria-disabled", "true");
|
|
12815
|
+
if (!el.hasAttribute(ENABLED_TABINDEX)) el.setAttribute(ENABLED_TABINDEX, el.getAttribute("tabindex") ?? "");
|
|
12816
|
+
el.setAttribute("tabindex", "-1");
|
|
12790
12817
|
});
|
|
12791
12818
|
}
|
|
12792
12819
|
function enableElements($container, selector) {
|
|
12793
12820
|
$container.querySelectorAll(selector).forEach((el) => {
|
|
12794
12821
|
if (el.hasAttribute("disabled")) el.removeAttribute("disabled");
|
|
12822
|
+
el.removeAttribute("aria-disabled");
|
|
12823
|
+
if (el.hasAttribute(ENABLED_TABINDEX)) {
|
|
12824
|
+
let tabindex = el.getAttribute(ENABLED_TABINDEX);
|
|
12825
|
+
el.removeAttribute(ENABLED_TABINDEX);
|
|
12826
|
+
if (tabindex === "") el.removeAttribute("tabindex");
|
|
12827
|
+
else el.setAttribute("tabindex", tabindex);
|
|
12828
|
+
}
|
|
12795
12829
|
});
|
|
12796
12830
|
}
|
|
12797
12831
|
/************************************************************
|
|
@@ -13174,7 +13208,7 @@ function yui_graph_update_anchor($container, state) {
|
|
|
13174
13208
|
set_pressed_state($container, ".EV_TOGGLE_ANCHOR", state === "on");
|
|
13175
13209
|
$btn.classList.toggle("color_pending_state", state === "arming");
|
|
13176
13210
|
$btn.setAttribute("aria-pressed", state === "on" ? "true" : "false");
|
|
13177
|
-
|
|
13211
|
+
const key = state === "arming" ? "click the element to centre on" : state === "on" ? "centred: click to release" : "anchor view";
|
|
13178
13212
|
$btn.setAttribute("title", (0, i18next.t)(key));
|
|
13179
13213
|
$btn.setAttribute("data-i18n-title", key);
|
|
13180
13214
|
$btn.setAttribute("aria-label", (0, i18next.t)(key));
|
|
@@ -13788,6 +13822,73 @@ function g6_event_kw(evt) {
|
|
|
13788
13822
|
};
|
|
13789
13823
|
}
|
|
13790
13824
|
//#endregion
|
|
13825
|
+
//#region src/g6_canvas_tab_order.js
|
|
13826
|
+
/***********************************************************************
|
|
13827
|
+
* g6_canvas_tab_order.js
|
|
13828
|
+
*
|
|
13829
|
+
* The canvases of a G6 graph in the page's Tab order: the main
|
|
13830
|
+
* one in its place, the other layers out of it.
|
|
13831
|
+
*
|
|
13832
|
+
* G6 stacks four canvases (background, main, label, transient)
|
|
13833
|
+
* and gives each of them `tabIndex = 1` (configCanvasDom, when it
|
|
13834
|
+
* builds the Canvas and again on a renderer change). A POSITIVE
|
|
13835
|
+
* tabindex goes before every control of the page: Tab from a
|
|
13836
|
+
* graph went to its other canvases, then to the top of the page
|
|
13837
|
+
* and through every control there, and only then to the graph's
|
|
13838
|
+
* own buttons. The main canvas -- the one G6 listens on, and the
|
|
13839
|
+
* one a view puts the keyboard on -- takes 0, so Tab goes from it
|
|
13840
|
+
* to the graph's toolbars and buttons in DOM order; the other
|
|
13841
|
+
* layers receive nothing (`pointer-events: none`) and take -1.
|
|
13842
|
+
*
|
|
13843
|
+
* Every view that creates a G6 Graph calls
|
|
13844
|
+
* keep_canvas_tab_order() right after `new Graph()`: the order is
|
|
13845
|
+
* put right each time G6 writes the 1 -- once the canvas is built
|
|
13846
|
+
* (on the first render(), whichever function of the view calls
|
|
13847
|
+
* it), and after a renderer change. One place, so a view with
|
|
13848
|
+
* several render() calls cannot miss the one that builds the
|
|
13849
|
+
* canvas.
|
|
13850
|
+
*
|
|
13851
|
+
* Copyright (c) 2026, ArtGins.
|
|
13852
|
+
* All Rights Reserved.
|
|
13853
|
+
***********************************************************************/
|
|
13854
|
+
/************************************************************
|
|
13855
|
+
* Main canvas 0, every other layer -1. Returns 0, or -1 with
|
|
13856
|
+
* the cause logged.
|
|
13857
|
+
************************************************************/
|
|
13858
|
+
function set_canvas_tab_order(gobj, graph) {
|
|
13859
|
+
let canvas = graph ? graph.getCanvas() : null;
|
|
13860
|
+
if (!canvas || typeof canvas.getLayers !== "function") {
|
|
13861
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no canvas to set the Tab order of`);
|
|
13862
|
+
return -1;
|
|
13863
|
+
}
|
|
13864
|
+
let ret = 0;
|
|
13865
|
+
let layers = canvas.getLayers() || {};
|
|
13866
|
+
for (let name of Object.keys(layers)) {
|
|
13867
|
+
let $el = null;
|
|
13868
|
+
try {
|
|
13869
|
+
$el = layers[name].getContextService().getDomElement();
|
|
13870
|
+
} catch (e) {
|
|
13871
|
+
$el = null;
|
|
13872
|
+
}
|
|
13873
|
+
if (!$el) {
|
|
13874
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: canvas layer '${name}' has no element`);
|
|
13875
|
+
ret = -1;
|
|
13876
|
+
continue;
|
|
13877
|
+
}
|
|
13878
|
+
$el.tabIndex = name === "main" ? 0 : -1;
|
|
13879
|
+
}
|
|
13880
|
+
return ret;
|
|
13881
|
+
}
|
|
13882
|
+
/************************************************************
|
|
13883
|
+
* Keep the order for the life of `graph`: on every moment G6
|
|
13884
|
+
* writes its own.
|
|
13885
|
+
************************************************************/
|
|
13886
|
+
function keep_canvas_tab_order(gobj, graph) {
|
|
13887
|
+
for (let ev of [_antv_g6.GraphEvent.AFTER_CANVAS_INIT, _antv_g6.GraphEvent.AFTER_RENDERER_CHANGE]) graph.on(ev, () => {
|
|
13888
|
+
set_canvas_tab_order(gobj, graph);
|
|
13889
|
+
});
|
|
13890
|
+
}
|
|
13891
|
+
//#endregion
|
|
13791
13892
|
//#region src/c_yui_json_graph.js
|
|
13792
13893
|
/***********************************************************************
|
|
13793
13894
|
* c_yui_json_graph.js
|
|
@@ -14291,6 +14392,7 @@ function build_graph$4(gobj) {
|
|
|
14291
14392
|
behaviors: BEHAVIORS_READING$1.slice()
|
|
14292
14393
|
});
|
|
14293
14394
|
if (priv.theme) graph.setTheme(priv.theme);
|
|
14395
|
+
keep_canvas_tab_order(gobj, graph);
|
|
14294
14396
|
graph.on(_antv_g6.NodeEvent.CLICK, (evt) => {
|
|
14295
14397
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_NODE_CLICK", g6_event_kw(evt), gobj);
|
|
14296
14398
|
});
|
|
@@ -18208,6 +18310,7 @@ function build_graph$3(gobj) {
|
|
|
18208
18310
|
} catch (e) {
|
|
18209
18311
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the theme was refused: ${e}`);
|
|
18210
18312
|
}
|
|
18313
|
+
keep_canvas_tab_order(gobj, priv.graph);
|
|
18211
18314
|
priv.graph.on("aftertransform", () => {
|
|
18212
18315
|
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
18213
18316
|
});
|
|
@@ -21711,6 +21814,7 @@ function build_graph$2(gobj) {
|
|
|
21711
21814
|
behaviors: BEHAVIORS_READING.slice()
|
|
21712
21815
|
});
|
|
21713
21816
|
if (priv.theme) graph.setTheme(priv.theme);
|
|
21817
|
+
keep_canvas_tab_order(gobj, graph);
|
|
21714
21818
|
graph.on("aftertransform", () => {
|
|
21715
21819
|
yui_graph_update_zoom((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container"), priv.graph);
|
|
21716
21820
|
let z = priv.last_zoom;
|
|
@@ -23527,7 +23631,7 @@ function build_ui$7(gobj) {
|
|
|
23527
23631
|
if (layout !== "drawer") {
|
|
23528
23632
|
$container.setAttribute("role", "navigation");
|
|
23529
23633
|
if (!$container.hasAttribute("aria-label")) {
|
|
23530
|
-
|
|
23634
|
+
const label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "nav_label") || "navigation";
|
|
23531
23635
|
$container.setAttribute("aria-label", (0, i18next.t)(label));
|
|
23532
23636
|
$container.setAttribute("data-i18n-aria-label", label);
|
|
23533
23637
|
}
|
|
@@ -23788,14 +23892,17 @@ function render_backbar(gobj) {
|
|
|
23788
23892
|
let label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "nav_label") || "";
|
|
23789
23893
|
let label_attrs = { class: "yui-nav-label" };
|
|
23790
23894
|
if (label) label_attrs.i18n = label;
|
|
23895
|
+
const name_key = label || "back";
|
|
23791
23896
|
let a_attrs = {
|
|
23792
23897
|
class: "yui-nav-item yui-nav-back",
|
|
23793
23898
|
href: back_route ? "#" + back_route : "#",
|
|
23794
23899
|
"data-item-id": "__index__",
|
|
23795
23900
|
"data-route": back_route,
|
|
23796
|
-
|
|
23901
|
+
title: (0, i18next.t)(name_key),
|
|
23902
|
+
"data-i18n-title": name_key,
|
|
23903
|
+
"aria-label": (0, i18next.t)(name_key),
|
|
23904
|
+
"data-i18n-aria-label": name_key
|
|
23797
23905
|
};
|
|
23798
|
-
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
23799
23906
|
return (0, _yuneta_gobj_js.createElement2)([
|
|
23800
23907
|
"div",
|
|
23801
23908
|
{},
|
|
@@ -23822,7 +23929,7 @@ function render_drawer(gobj, items) {
|
|
|
23822
23929
|
wrap.className = "yui-drawer";
|
|
23823
23930
|
wrap.setAttribute("role", "dialog");
|
|
23824
23931
|
wrap.setAttribute("aria-modal", "true");
|
|
23825
|
-
|
|
23932
|
+
const nav_label = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "nav_label") || "navigation";
|
|
23826
23933
|
wrap.setAttribute("aria-label", (0, i18next.t)(nav_label));
|
|
23827
23934
|
wrap.setAttribute("data-i18n-aria-label", nav_label);
|
|
23828
23935
|
let back = document.createElement("div");
|
|
@@ -25617,7 +25724,7 @@ function show_load_error$1(gobj, message) {
|
|
|
25617
25724
|
$container.insertBefore($err, $container.firstChild);
|
|
25618
25725
|
}
|
|
25619
25726
|
let treedb = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "treedb_name") || "";
|
|
25620
|
-
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
|
|
25727
|
+
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || (0, i18next.t)("cannot load treedb"));
|
|
25621
25728
|
}
|
|
25622
25729
|
/************************************************************
|
|
25623
25730
|
* Destroy UI
|
|
@@ -27995,7 +28102,6 @@ function yui_selection_bar(t, opts) {
|
|
|
27995
28102
|
if (typeof o.on_clear === "function") o.on_clear(e);
|
|
27996
28103
|
} }
|
|
27997
28104
|
]);
|
|
27998
|
-
$clear._yui_label = "clear selection";
|
|
27999
28105
|
let $el = (0, _yuneta_gobj_js.createElement2)([
|
|
28000
28106
|
"div",
|
|
28001
28107
|
{
|
|
@@ -28011,7 +28117,7 @@ function yui_selection_bar(t, opts) {
|
|
|
28011
28117
|
$count.textContent = t("{{n}} selected", { n: count });
|
|
28012
28118
|
for (let $b of $buttons.concat([$clear])) {
|
|
28013
28119
|
let $label = label_of($b);
|
|
28014
|
-
|
|
28120
|
+
const key = $b === $clear ? "clear selection" : $b._yui_label;
|
|
28015
28121
|
if ($label && key) $label.textContent = t(key);
|
|
28016
28122
|
$b.title = key ? t(key) : "";
|
|
28017
28123
|
$b.setAttribute("aria-label", $b.title);
|
|
@@ -30093,7 +30199,7 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
30093
30199
|
return;
|
|
30094
30200
|
}
|
|
30095
30201
|
let pkey = desc.pkey || "id";
|
|
30096
|
-
|
|
30202
|
+
const title = mode === "create" ? "new" : mode === "view" ? "view" : "edit";
|
|
30097
30203
|
let title_prefix = "";
|
|
30098
30204
|
if (mode !== "create") {
|
|
30099
30205
|
let rid = record ? String(record[pkey] ?? "") : "";
|
|
@@ -60774,17 +60880,41 @@ function css_color_or_null(value) {
|
|
|
60774
60880
|
* The markup of one toolbar item. Everything that goes into it is
|
|
60775
60881
|
* escaped, the read-out branch too: its text, title and value are
|
|
60776
60882
|
* values (a zoom figure, a translated title), never markup.
|
|
60883
|
+
*
|
|
60884
|
+
* An item is a BUTTON for the keyboard too: `role="button"` and
|
|
60885
|
+
* `tabindex="0"`, and YuiToolbar presses it on Enter or Space.
|
|
60886
|
+
* `title_key` is the i18n key of `title`: written as
|
|
60887
|
+
* `data-i18n-title` / `data-i18n-aria-label`, so the name carries
|
|
60888
|
+
* its key like every other control's.
|
|
60889
|
+
*
|
|
60890
|
+
* A `disabled` item is born the way disableElements() (lib_graph.js)
|
|
60891
|
+
* leaves one: `aria-disabled`, out of the Tab order, and the
|
|
60892
|
+
* tabindex it takes once enabled kept in `data-enabled-tabindex`,
|
|
60893
|
+
* where enableElements() finds it. A toggle (`pressed` given, true
|
|
60894
|
+
* or false) says its state in `aria-pressed`, as its look says it
|
|
60895
|
+
* with `pressed_state`. `data-control` names the CONTROL the item
|
|
60896
|
+
* is, whatever state it shows: `control` when the item gives one
|
|
60897
|
+
* (full screen is `request-fullscreen` or `exit-fullscreen`, and
|
|
60898
|
+
* one control), its `value` otherwise -- it is what a rebuild puts
|
|
60899
|
+
* the focus back on.
|
|
60777
60900
|
***************************************************************/
|
|
60778
60901
|
function toolbar_item_html(item) {
|
|
60779
60902
|
if (item.separator) return `<div class="g6-toolbar-sep" aria-hidden="true"></div>`;
|
|
60780
60903
|
const extra_class = item.className ? ` ${(0, _yuneta_gobj_js.escapeHtml)(String(item.className))}` : "";
|
|
60781
60904
|
const title = (0, _yuneta_gobj_js.escapeHtml)(String(item.title ?? ""));
|
|
60782
|
-
|
|
60783
|
-
|
|
60905
|
+
let i18n_attrs = "";
|
|
60906
|
+
if (item.title_key) {
|
|
60907
|
+
const key = (0, _yuneta_gobj_js.escapeHtml)(String(item.title_key));
|
|
60908
|
+
i18n_attrs = ` data-i18n-title="${key}" data-i18n-aria-label="${key}"`;
|
|
60909
|
+
}
|
|
60910
|
+
if (item.readout) return `<div class="g6-toolbar-readout${extra_class}" title="${title}" aria-label="${title}"${i18n_attrs}>${(0, _yuneta_gobj_js.escapeHtml)(String(item.text ?? ""))}</div>`;
|
|
60911
|
+
const state = item.disabled ? " tabindex=\"-1\" aria-disabled=\"true\" data-enabled-tabindex=\"0\" disabled" : " tabindex=\"0\"";
|
|
60912
|
+
const pressed = item.pressed === void 0 ? "" : ` aria-pressed="${item.pressed ? "true" : "false"}"`;
|
|
60913
|
+
const control = (0, _yuneta_gobj_js.escapeHtml)(String(item.control ?? item.value));
|
|
60784
60914
|
const is_text = item.text !== void 0;
|
|
60785
60915
|
const kind_class = is_text ? " g6-toolbar-item-text" : "";
|
|
60786
60916
|
const body = is_text ? `<span class="g6-toolbar-text">${(0, _yuneta_gobj_js.escapeHtml)(String(item.text))}</span>` : `<svg aria-hidden="true" focusable="false"><use xlink:href="#${(0, _yuneta_gobj_js.escapeHtml)(String(item.id))}"></use></svg>`;
|
|
60787
|
-
return `<div class="g6-toolbar-item${kind_class}${extra_class}" value="${(0, _yuneta_gobj_js.escapeHtml)(String(item.value))}" title="${title}" aria-label="${title}"${
|
|
60917
|
+
return `<div class="g6-toolbar-item${kind_class}${extra_class}" role="button"${state}${pressed} value="${(0, _yuneta_gobj_js.escapeHtml)(String(item.value))}" data-control="${control}" title="${title}" aria-label="${title}"${i18n_attrs}>${body}</div>`;
|
|
60788
60918
|
}
|
|
60789
60919
|
/***************************************************************
|
|
60790
60920
|
* YuiToolbar — G6 Toolbar subclass that adds per-item className
|
|
@@ -60799,6 +60929,11 @@ function toolbar_item_html(item) {
|
|
|
60799
60929
|
* readout — a text item that REPORTS instead of acting (the
|
|
60800
60930
|
* zoom level); it is not a button
|
|
60801
60931
|
* separator — a group divider, not an item
|
|
60932
|
+
* title_key — the i18n key of `title` (see toolbar_item_html)
|
|
60933
|
+
* pressed — boolean; the item is a TOGGLE, and this is its
|
|
60934
|
+
* state (`aria-pressed`)
|
|
60935
|
+
* control — the identity of the control when its `value`
|
|
60936
|
+
* changes with its state (full screen enter/exit)
|
|
60802
60937
|
*
|
|
60803
60938
|
* The base class fires onClick only for elements whose class list
|
|
60804
60939
|
* contains `g6-toolbar-item`, so a separator and a readout carry
|
|
@@ -60809,12 +60944,117 @@ function toolbar_item_html(item) {
|
|
|
60809
60944
|
* functions (set_submit_state, disableElements, …) work on toolbar
|
|
60810
60945
|
* icons exactly like on regular Bulma/FA buttons — no special
|
|
60811
60946
|
* icon-specific helpers needed.
|
|
60947
|
+
*
|
|
60948
|
+
* The items are buttons for the KEYBOARD as well:
|
|
60949
|
+
* - Enter or Space CLICKS the focused item, and the click bubbles
|
|
60950
|
+
* to the base class's own handler, so the key reaches the same
|
|
60951
|
+
* onClick a pointer does. A `disabled` item takes the key and
|
|
60952
|
+
* does nothing, as its `pointer-events: none` does for a press.
|
|
60953
|
+
* - A POINTER press does not move the focus to an item (it stays
|
|
60954
|
+
* on the canvas, where the graph's keys are heard), the way the
|
|
60955
|
+
* floating buttons keep it (see keep_focus_on_press).
|
|
60956
|
+
* - A disabled item is out of the Tab order and says it is
|
|
60957
|
+
* disabled (`aria-disabled`), from its first render
|
|
60958
|
+
* (toolbar_item_html) and on every change (disableElements /
|
|
60959
|
+
* enableElements in lib_graph.js).
|
|
60960
|
+
* - A rebuild (update) replaces the innerHTML, the focused item
|
|
60961
|
+
* with it: the focus goes back to the item of the same CONTROL
|
|
60962
|
+
* (`data-control`: Enter on "enter full screen" lands on "exit
|
|
60963
|
+
* full screen"), or to the canvas when there is none. And a
|
|
60964
|
+
* toolbar that goes away (destroy) hands it to the canvas
|
|
60965
|
+
* first. A removed element that held the focus leaves it on
|
|
60966
|
+
* <body> in Firefox, which fires no focusout for it, and the
|
|
60967
|
+
* graph goes deaf.
|
|
60812
60968
|
***************************************************************/
|
|
60813
60969
|
var YuiToolbar = class extends _antv_g6.Toolbar {
|
|
60970
|
+
constructor(context, options) {
|
|
60971
|
+
super(context, options);
|
|
60972
|
+
this.$element.addEventListener("pointerdown", keep_focus_on_toolbar_press);
|
|
60973
|
+
this.$element.addEventListener("keydown", press_toolbar_item_on_key);
|
|
60974
|
+
}
|
|
60975
|
+
async update(options) {
|
|
60976
|
+
const control = focused_toolbar_item_control(this.$element);
|
|
60977
|
+
await super.update(options);
|
|
60978
|
+
if (control !== null) refocus_toolbar_item(this.$element, control);
|
|
60979
|
+
}
|
|
60980
|
+
destroy() {
|
|
60981
|
+
if (!this.destroyed && this.$element) {
|
|
60982
|
+
this.$element.removeEventListener("pointerdown", keep_focus_on_toolbar_press);
|
|
60983
|
+
this.$element.removeEventListener("keydown", press_toolbar_item_on_key);
|
|
60984
|
+
if (this.$element.contains(document.activeElement)) focus_main_canvas(this.$element.parentNode);
|
|
60985
|
+
}
|
|
60986
|
+
super.destroy();
|
|
60987
|
+
}
|
|
60814
60988
|
async getDOMContent() {
|
|
60815
60989
|
return (await this.options.getItems()).map(toolbar_item_html).join("");
|
|
60816
60990
|
}
|
|
60817
60991
|
};
|
|
60992
|
+
/***************************************************************
|
|
60993
|
+
* A POINTER press on a button of this view does not take the
|
|
60994
|
+
* focus. The container's capture listener has just put it on the
|
|
60995
|
+
* canvas, where the graph's keys are heard; a press that moved it
|
|
60996
|
+
* on to the button would leave it on something this view removes
|
|
60997
|
+
* -- Escape deselects and takes the floating buttons away, the ✕
|
|
60998
|
+
* closes its popover, a rebuild replaces the toolbar -- and
|
|
60999
|
+
* Firefox fires no focusout for a removed element: the focus falls
|
|
61000
|
+
* to <body> and the graph hears nothing until it is clicked again.
|
|
61001
|
+
* Cancelling the pointerdown cancels the mousedown that moves the
|
|
61002
|
+
* focus; the click still comes, and Tab still reaches the button.
|
|
61003
|
+
***************************************************************/
|
|
61004
|
+
function keep_focus_on_press(el) {
|
|
61005
|
+
el.addEventListener("pointerdown", (e) => {
|
|
61006
|
+
e.preventDefault();
|
|
61007
|
+
});
|
|
61008
|
+
}
|
|
61009
|
+
function keep_focus_on_toolbar_press(e) {
|
|
61010
|
+
let target = e.target;
|
|
61011
|
+
if (target && typeof target.closest === "function" && target.closest(".g6-toolbar-item")) e.preventDefault();
|
|
61012
|
+
}
|
|
61013
|
+
/***************************************************************
|
|
61014
|
+
* The keyboard to the graph: the focus on its main canvas.
|
|
61015
|
+
***************************************************************/
|
|
61016
|
+
function focus_main_canvas($container) {
|
|
61017
|
+
if (!$container) return;
|
|
61018
|
+
let $canvas = main_canvas_of($container);
|
|
61019
|
+
if ($canvas && $canvas.isConnected && typeof $canvas.focus === "function") $canvas.focus({ preventScroll: true });
|
|
61020
|
+
}
|
|
61021
|
+
/***************************************************************
|
|
61022
|
+
* Enter or Space on a toolbar item clicks it; the click bubbles
|
|
61023
|
+
* to G6's toolbar handler, which reads the item's `value`.
|
|
61024
|
+
***************************************************************/
|
|
61025
|
+
function press_toolbar_item_on_key(e) {
|
|
61026
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
61027
|
+
let target = e.target;
|
|
61028
|
+
let item = target && typeof target.closest === "function" ? target.closest(".g6-toolbar-item") : null;
|
|
61029
|
+
if (!item) return;
|
|
61030
|
+
e.preventDefault();
|
|
61031
|
+
e.stopPropagation();
|
|
61032
|
+
if (item.hasAttribute("disabled")) return;
|
|
61033
|
+
item.click();
|
|
61034
|
+
}
|
|
61035
|
+
/***************************************************************
|
|
61036
|
+
* The control (`data-control`) of the toolbar item that has the
|
|
61037
|
+
* focus, or null.
|
|
61038
|
+
***************************************************************/
|
|
61039
|
+
function focused_toolbar_item_control($toolbar) {
|
|
61040
|
+
let active = document.activeElement;
|
|
61041
|
+
if (!$toolbar || !active || active === $toolbar || !$toolbar.contains(active)) return null;
|
|
61042
|
+
if (!active.classList || !active.classList.contains("g6-toolbar-item")) return null;
|
|
61043
|
+
return active.getAttribute("data-control");
|
|
61044
|
+
}
|
|
61045
|
+
/***************************************************************
|
|
61046
|
+
* After a rebuild: the focus on the item of that control, in
|
|
61047
|
+
* whatever state the rebuild shows it, or on the canvas when the
|
|
61048
|
+
* rebuild has none (a fold took it away).
|
|
61049
|
+
***************************************************************/
|
|
61050
|
+
function refocus_toolbar_item($toolbar, control) {
|
|
61051
|
+
let items = $toolbar.querySelectorAll(".g6-toolbar-item");
|
|
61052
|
+
for (let i = 0; i < items.length; i++) if (items[i].getAttribute("data-control") === control) {
|
|
61053
|
+
items[i].focus({ preventScroll: true });
|
|
61054
|
+
return;
|
|
61055
|
+
}
|
|
61056
|
+
focus_main_canvas($toolbar.parentNode);
|
|
61057
|
+
}
|
|
60818
61058
|
(0, _antv_g6.register)(_antv_g6.ExtensionCategory.PLUGIN, "yui-toolbar", YuiToolbar);
|
|
60819
61059
|
ensure_drag_canvas_patch();
|
|
60820
61060
|
ensure_brush_select_owned();
|
|
@@ -60979,6 +61219,7 @@ var PRIVATE_DATA$4 = {
|
|
|
60979
61219
|
_saved_graph_properties: {},
|
|
60980
61220
|
_graphs_writes_owed: {},
|
|
60981
61221
|
_graphs_load: 0,
|
|
61222
|
+
_save_lit: false,
|
|
60982
61223
|
yet_showed: false,
|
|
60983
61224
|
edit_mode: false,
|
|
60984
61225
|
operation_mode: null,
|
|
@@ -61012,6 +61253,7 @@ var PRIVATE_DATA$4 = {
|
|
|
61012
61253
|
_detail_node_id: null,
|
|
61013
61254
|
_delete_confirm_el: null,
|
|
61014
61255
|
_unlink_confirm_el: null,
|
|
61256
|
+
_confirm_questions: {},
|
|
61015
61257
|
_create_popover_el: null,
|
|
61016
61258
|
_context_node_id: null,
|
|
61017
61259
|
_context_port_key: null,
|
|
@@ -61020,6 +61262,7 @@ var PRIVATE_DATA$4 = {
|
|
|
61020
61262
|
_link_source: null,
|
|
61021
61263
|
_link_icon_el: null,
|
|
61022
61264
|
_link_drag_svg: null,
|
|
61265
|
+
_link_drag: null,
|
|
61023
61266
|
_link_valid_hooks: [],
|
|
61024
61267
|
_link_saved_styles: [],
|
|
61025
61268
|
_focus_topic: null,
|
|
@@ -61263,6 +61506,7 @@ function build_graph$1(gobj) {
|
|
|
61263
61506
|
plugins: []
|
|
61264
61507
|
});
|
|
61265
61508
|
graph.setTheme(priv.theme);
|
|
61509
|
+
keep_canvas_tab_order(gobj, graph);
|
|
61266
61510
|
priv._unforward_wheel = yui_graph_forward_wheel(graph, priv.$container, { selector: ".TREEDB_CARD, .TREEDB_PILLS" });
|
|
61267
61511
|
graph.setLayout(layout);
|
|
61268
61512
|
priv.graph_rendered = false;
|
|
@@ -61420,8 +61664,6 @@ function update_toolbar(gobj) {
|
|
|
61420
61664
|
if (graph_get_plugin(gobj, "toolbar")) graph.updatePlugin({ key: "toolbar" });
|
|
61421
61665
|
configure_toolbar_edit(gobj);
|
|
61422
61666
|
if (graph_get_plugin(gobj, "toolbar-edit")) graph.updatePlugin({ key: "toolbar-edit" });
|
|
61423
|
-
update_zoom_selection_button(gobj);
|
|
61424
|
-
update_selection_mode_button(gobj);
|
|
61425
61667
|
}
|
|
61426
61668
|
/************************************************************
|
|
61427
61669
|
* The floating toolbars follow the theme.
|
|
@@ -61472,13 +61714,15 @@ function toolbar_fold_item(gobj) {
|
|
|
61472
61714
|
id: "g6-icon-toolbar-show",
|
|
61473
61715
|
value: "toolbar-toggle",
|
|
61474
61716
|
className: "EV_TOGGLE_TOOLBARS",
|
|
61475
|
-
title: (0, i18next.t)("show toolbar")
|
|
61717
|
+
title: (0, i18next.t)("show toolbar"),
|
|
61718
|
+
title_key: "show toolbar"
|
|
61476
61719
|
};
|
|
61477
61720
|
return {
|
|
61478
61721
|
id: "g6-icon-toolbar-hide",
|
|
61479
61722
|
value: "toolbar-toggle",
|
|
61480
61723
|
className: "EV_TOGGLE_TOOLBARS",
|
|
61481
|
-
title: (0, i18next.t)("hide toolbar")
|
|
61724
|
+
title: (0, i18next.t)("hide toolbar"),
|
|
61725
|
+
title_key: "hide toolbar"
|
|
61482
61726
|
};
|
|
61483
61727
|
}
|
|
61484
61728
|
function toolbar_style(extra) {
|
|
@@ -61544,38 +61788,44 @@ function configure_toolbar(gobj) {
|
|
|
61544
61788
|
id: "g6-icon-zoom-in",
|
|
61545
61789
|
value: "zoom-in",
|
|
61546
61790
|
className: "EV_ZOOM_IN",
|
|
61547
|
-
title: (0, i18next.t)("zoom in")
|
|
61791
|
+
title: (0, i18next.t)("zoom in"),
|
|
61792
|
+
title_key: "zoom in"
|
|
61548
61793
|
},
|
|
61549
61794
|
{
|
|
61550
61795
|
id: "g6-icon-zoom-out",
|
|
61551
61796
|
value: "zoom-out",
|
|
61552
61797
|
className: "EV_ZOOM_OUT",
|
|
61553
|
-
title: (0, i18next.t)("zoom out")
|
|
61798
|
+
title: (0, i18next.t)("zoom out"),
|
|
61799
|
+
title_key: "zoom out"
|
|
61554
61800
|
},
|
|
61555
61801
|
{
|
|
61556
61802
|
readout: true,
|
|
61557
61803
|
className: "G6_ZOOM_LEVEL",
|
|
61558
61804
|
text: zoom_percent_text(gobj),
|
|
61559
|
-
title: (0, i18next.t)("zoom level")
|
|
61805
|
+
title: (0, i18next.t)("zoom level"),
|
|
61806
|
+
title_key: "zoom level"
|
|
61560
61807
|
},
|
|
61561
61808
|
{ separator: true },
|
|
61562
61809
|
{
|
|
61563
61810
|
id: "g6-icon-fit",
|
|
61564
61811
|
value: "auto-fit",
|
|
61565
61812
|
className: "EV_AUTO_FIT",
|
|
61566
|
-
title: (0, i18next.t)("auto fit")
|
|
61813
|
+
title: (0, i18next.t)("auto fit"),
|
|
61814
|
+
title_key: "auto fit"
|
|
61567
61815
|
},
|
|
61568
61816
|
{
|
|
61569
61817
|
text: "1:1",
|
|
61570
61818
|
value: "reset",
|
|
61571
61819
|
className: "EV_ZOOM_RESET",
|
|
61572
|
-
title: (0, i18next.t)("actual size")
|
|
61820
|
+
title: (0, i18next.t)("actual size"),
|
|
61821
|
+
title_key: "actual size"
|
|
61573
61822
|
},
|
|
61574
61823
|
{
|
|
61575
61824
|
id: "g6-icon-anchor",
|
|
61576
61825
|
value: "anchor",
|
|
61577
61826
|
className: "EV_TOGGLE_ANCHOR" + (priv.anchor_state === "on" ? " pressed_state" : "") + (priv.anchor_state === "arming" ? " color_pending_state" : ""),
|
|
61578
|
-
|
|
61827
|
+
pressed: priv.anchor_state === "on",
|
|
61828
|
+
...anchor_title(priv.anchor_state)
|
|
61579
61829
|
}
|
|
61580
61830
|
];
|
|
61581
61831
|
if (priv.edit_mode) items.push({
|
|
@@ -61583,21 +61833,26 @@ function configure_toolbar(gobj) {
|
|
|
61583
61833
|
value: "fit-selection",
|
|
61584
61834
|
className: "EV_ZOOM_SELECTION",
|
|
61585
61835
|
title: (0, i18next.t)("zoom to selection"),
|
|
61586
|
-
|
|
61836
|
+
title_key: "zoom to selection",
|
|
61837
|
+
disabled: !selection_is_painted(gobj)
|
|
61587
61838
|
});
|
|
61588
61839
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_fullscreen")) {
|
|
61589
61840
|
items.push({ separator: true });
|
|
61590
61841
|
if (priv.is_fullscreen) items.push({
|
|
61591
61842
|
id: "g6-icon-fullscreen-exit",
|
|
61592
61843
|
value: "exit-fullscreen",
|
|
61844
|
+
control: "fullscreen",
|
|
61593
61845
|
className: "EV_EXIT_FULLSCREEN",
|
|
61594
|
-
title: (0, i18next.t)("exit full screen")
|
|
61846
|
+
title: (0, i18next.t)("exit full screen"),
|
|
61847
|
+
title_key: "exit full screen"
|
|
61595
61848
|
});
|
|
61596
61849
|
else items.push({
|
|
61597
61850
|
id: "g6-icon-fullscreen",
|
|
61598
61851
|
value: "request-fullscreen",
|
|
61852
|
+
control: "fullscreen",
|
|
61599
61853
|
className: "EV_REQUEST_FULLSCREEN",
|
|
61600
|
-
title: (0, i18next.t)("enter full screen")
|
|
61854
|
+
title: (0, i18next.t)("enter full screen"),
|
|
61855
|
+
title_key: "enter full screen"
|
|
61601
61856
|
});
|
|
61602
61857
|
}
|
|
61603
61858
|
if (toolbars_can_collapse(gobj)) {
|
|
@@ -61658,46 +61913,53 @@ function configure_toolbar_edit(gobj) {
|
|
|
61658
61913
|
position: "left-top",
|
|
61659
61914
|
style: toolbar_style(),
|
|
61660
61915
|
getItems: () => {
|
|
61916
|
+
let lit = edit_buttons_lit(gobj);
|
|
61661
61917
|
return [
|
|
61662
61918
|
{
|
|
61663
61919
|
id: "g6-icon-plus",
|
|
61664
61920
|
value: "create-node",
|
|
61665
61921
|
className: "EV_CREATE_NODE_BTN color_create_state",
|
|
61666
|
-
title: (0, i18next.t)("create node")
|
|
61922
|
+
title: (0, i18next.t)("create node"),
|
|
61923
|
+
title_key: "create node"
|
|
61667
61924
|
},
|
|
61668
61925
|
{
|
|
61669
61926
|
id: "g6-icon-select-mode",
|
|
61670
61927
|
value: "selection-mode",
|
|
61671
61928
|
className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " pressed_state" : ""),
|
|
61672
|
-
|
|
61929
|
+
pressed: !!priv.selection_mode,
|
|
61930
|
+
title: (0, i18next.t)("selection mode"),
|
|
61931
|
+
title_key: "selection mode"
|
|
61673
61932
|
},
|
|
61674
61933
|
{
|
|
61675
61934
|
id: "g6-icon-save",
|
|
61676
61935
|
value: "save",
|
|
61677
|
-
className: "EV_SAVE_GRAPH",
|
|
61936
|
+
className: "EV_SAVE_GRAPH" + (lit.save ? " color_submit_state" : ""),
|
|
61678
61937
|
title: (0, i18next.t)("save"),
|
|
61679
|
-
|
|
61938
|
+
title_key: "save",
|
|
61939
|
+
disabled: !lit.save
|
|
61680
61940
|
},
|
|
61681
61941
|
{
|
|
61682
61942
|
id: "g6-icon-undo",
|
|
61683
61943
|
value: "undo",
|
|
61684
|
-
className: "EV_HISTORY_UNDO",
|
|
61944
|
+
className: "EV_HISTORY_UNDO" + (lit.undo ? " color_active_state" : ""),
|
|
61685
61945
|
title: (0, i18next.t)("undo"),
|
|
61686
|
-
|
|
61946
|
+
title_key: "undo",
|
|
61947
|
+
disabled: !lit.undo
|
|
61687
61948
|
},
|
|
61688
61949
|
{
|
|
61689
61950
|
id: "g6-icon-redo",
|
|
61690
61951
|
value: "redo",
|
|
61691
|
-
className: "EV_HISTORY_REDO",
|
|
61952
|
+
className: "EV_HISTORY_REDO" + (lit.redo ? " color_active_state" : ""),
|
|
61692
61953
|
title: (0, i18next.t)("redo"),
|
|
61693
|
-
|
|
61954
|
+
title_key: "redo",
|
|
61955
|
+
disabled: !lit.redo
|
|
61694
61956
|
}
|
|
61695
61957
|
];
|
|
61696
61958
|
},
|
|
61697
61959
|
onClick: (value) => {
|
|
61698
61960
|
switch (value) {
|
|
61699
61961
|
case "create-node":
|
|
61700
|
-
|
|
61962
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_CREATE_POPOVER", {}, gobj);
|
|
61701
61963
|
break;
|
|
61702
61964
|
case "selection-mode":
|
|
61703
61965
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_TOGGLE_SELECTION_MODE", {}, gobj);
|
|
@@ -62758,28 +63020,50 @@ function update_history_buttons(gobj) {
|
|
|
62758
63020
|
if (history.canUndo()) {
|
|
62759
63021
|
enableElements($container, ".EV_HISTORY_UNDO");
|
|
62760
63022
|
set_active_state($container, ".EV_HISTORY_UNDO", true);
|
|
62761
|
-
|
|
62762
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
63023
|
+
light_save_button(gobj, true);
|
|
62763
63024
|
} else {
|
|
62764
63025
|
disableElements($container, ".EV_HISTORY_UNDO");
|
|
62765
63026
|
set_active_state($container, ".EV_HISTORY_UNDO", false);
|
|
62766
|
-
|
|
62767
|
-
enableElements($container, ".EV_SAVE_GRAPH");
|
|
62768
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
62769
|
-
} else {
|
|
62770
|
-
disableElements($container, ".EV_SAVE_GRAPH");
|
|
62771
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
62772
|
-
}
|
|
63027
|
+
light_save_button(gobj, graphs_write_is_owed(gobj));
|
|
62773
63028
|
}
|
|
62774
63029
|
} else {
|
|
62775
63030
|
disableElements($container, ".EV_HISTORY_REDO");
|
|
62776
63031
|
set_active_state($container, ".EV_HISTORY_REDO", false);
|
|
62777
63032
|
disableElements($container, ".EV_HISTORY_UNDO");
|
|
62778
63033
|
set_active_state($container, ".EV_HISTORY_UNDO", false);
|
|
63034
|
+
light_save_button(gobj, graphs_write_is_owed(gobj));
|
|
62779
63035
|
}
|
|
62780
63036
|
}
|
|
62781
63037
|
}
|
|
62782
63038
|
/************************************************************
|
|
63039
|
+
* What Save, Undo and Redo show when the edit toolbar is
|
|
63040
|
+
* built (its getItems): Undo and Redo what the history can do
|
|
63041
|
+
* now; Save what it was last told (`_save_lit`, see
|
|
63042
|
+
* light_save_button), because more than the history lights
|
|
63043
|
+
* it -- a change the history does not record
|
|
63044
|
+
* (mark_graph_dirty), a write owed -- and update_history_
|
|
63045
|
+
* buttons() is where those are weighed.
|
|
63046
|
+
************************************************************/
|
|
63047
|
+
function edit_buttons_lit(gobj) {
|
|
63048
|
+
let history = graph_get_plugin(gobj, "history");
|
|
63049
|
+
return {
|
|
63050
|
+
undo: !!history && history.canUndo(),
|
|
63051
|
+
redo: !!history && history.canRedo(),
|
|
63052
|
+
save: !!gobj.priv._save_lit
|
|
63053
|
+
};
|
|
63054
|
+
}
|
|
63055
|
+
/************************************************************
|
|
63056
|
+
* Light the Save, or put it out: on the live element, and in
|
|
63057
|
+
* `_save_lit`, where the next rebuild of the toolbar reads it.
|
|
63058
|
+
************************************************************/
|
|
63059
|
+
function light_save_button(gobj, lit) {
|
|
63060
|
+
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
63061
|
+
gobj.priv._save_lit = !!lit;
|
|
63062
|
+
if (lit) enableElements($container, ".EV_SAVE_GRAPH");
|
|
63063
|
+
else disableElements($container, ".EV_SAVE_GRAPH");
|
|
63064
|
+
set_submit_state($container, ".EV_SAVE_GRAPH", !!lit);
|
|
63065
|
+
}
|
|
63066
|
+
/************************************************************
|
|
62783
63067
|
* Graph utility functions
|
|
62784
63068
|
*
|
|
62785
63069
|
* From the G6 documentation:
|
|
@@ -63655,20 +63939,59 @@ function floating_popover_dx() {
|
|
|
63655
63939
|
return 4 + floating_icon_size() + 4;
|
|
63656
63940
|
}
|
|
63657
63941
|
/************************************************************
|
|
63942
|
+
* A key press IS the click on an element drawn as a button.
|
|
63943
|
+
*
|
|
63944
|
+
* Enter or Space clicks it, so the keyboard reaches the very
|
|
63945
|
+
* handler the pointer does, whatever that handler is. Stopped
|
|
63946
|
+
* here, as the click is: this view's container forwards every
|
|
63947
|
+
* keydown to G6 (its shortcuts, and EV_KEY_DOWN), and a key
|
|
63948
|
+
* that pressed a button is not the graph's. Space would scroll
|
|
63949
|
+
* the page as well. Any other key goes on to the graph, so
|
|
63950
|
+
* Escape and Delete keep doing there what they do.
|
|
63951
|
+
************************************************************/
|
|
63952
|
+
function click_on_enter_or_space(el) {
|
|
63953
|
+
el.addEventListener("keydown", (e) => {
|
|
63954
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
63955
|
+
e.preventDefault();
|
|
63956
|
+
e.stopPropagation();
|
|
63957
|
+
el.click();
|
|
63958
|
+
}
|
|
63959
|
+
});
|
|
63960
|
+
}
|
|
63961
|
+
/************************************************************
|
|
63658
63962
|
* Create a floating circular icon button.
|
|
63659
|
-
*
|
|
63660
|
-
*
|
|
63661
|
-
*
|
|
63662
|
-
*
|
|
63663
|
-
*
|
|
63664
|
-
*
|
|
63963
|
+
*
|
|
63964
|
+
* A button for the keyboard too: `role` and `tabindex`, and
|
|
63965
|
+
* Enter or Space click it (click_on_enter_or_space). Its name
|
|
63966
|
+
* carries its KEY, so refresh_language() renames it on a
|
|
63967
|
+
* language switch; a key handed in here goes in
|
|
63968
|
+
* G6_NODES_TREE_I18N_KEYS, because no scan sees it.
|
|
63969
|
+
*
|
|
63970
|
+
* Its click does one thing: it sends `event` to `gobj`, with
|
|
63971
|
+
* `kw` -- the plain identity of what the button belongs to --
|
|
63972
|
+
* and the ACTION does the work, where the `machine` trace sees
|
|
63973
|
+
* it. A pointer press does not take the focus
|
|
63974
|
+
* (keep_focus_on_press).
|
|
63975
|
+
*
|
|
63976
|
+
* @param {string} svgKey - key into SVG_ICONS
|
|
63977
|
+
* @param {string} color - border & text color (e.g. '#1890ff')
|
|
63978
|
+
* @param {number} left - CSS left in px
|
|
63979
|
+
* @param {number} top - CSS top in px
|
|
63980
|
+
* @param {string} title_key - i18n key of its title and aria-label
|
|
63981
|
+
* @param {object} gobj - who hears the click
|
|
63982
|
+
* @param {string} event - an input event of this gclass
|
|
63983
|
+
* @param {object} kw - plain JSON identity, copied per click
|
|
63665
63984
|
* @returns {HTMLElement}
|
|
63666
63985
|
************************************************************/
|
|
63667
|
-
function create_floating_icon(svgKey, color, left, top,
|
|
63986
|
+
function create_floating_icon(svgKey, color, left, top, title_key, gobj, event, kw) {
|
|
63668
63987
|
const size = floating_icon_size();
|
|
63669
63988
|
const el = document.createElement("div");
|
|
63670
|
-
el.
|
|
63671
|
-
el.setAttribute("
|
|
63989
|
+
el.setAttribute("role", "button");
|
|
63990
|
+
el.setAttribute("tabindex", "0");
|
|
63991
|
+
el.setAttribute("title", (0, i18next.t)(title_key));
|
|
63992
|
+
el.setAttribute("data-i18n-title", title_key);
|
|
63993
|
+
el.setAttribute("aria-label", (0, i18next.t)(title_key));
|
|
63994
|
+
el.setAttribute("data-i18n-aria-label", title_key);
|
|
63672
63995
|
el.innerHTML = SVG_ICONS[svgKey] || "";
|
|
63673
63996
|
el.style.cssText = "position:absolute;left:" + left + "px;top:" + top + "px;width:" + size + "px;height:" + size + "px;display:flex;align-items:center;justify-content:center;background:#fff;border:1px solid " + color + ";border-radius:50%;cursor:pointer;pointer-events:all;z-index:11;touch-action:none;box-shadow:0 2px 6px rgba(0,0,0,0.15);color:" + color + ";";
|
|
63674
63997
|
const $svg = el.querySelector("svg");
|
|
@@ -63679,19 +64002,33 @@ function create_floating_icon(svgKey, color, left, top, title, onClick) {
|
|
|
63679
64002
|
}
|
|
63680
64003
|
el.addEventListener("click", (e) => {
|
|
63681
64004
|
e.stopPropagation();
|
|
63682
|
-
|
|
64005
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, event, (0, _yuneta_gobj_js.json_deep_copy)(kw || {}), gobj);
|
|
63683
64006
|
});
|
|
64007
|
+
keep_focus_on_press(el);
|
|
64008
|
+
click_on_enter_or_space(el);
|
|
63684
64009
|
return el;
|
|
63685
64010
|
}
|
|
63686
64011
|
/************************************************************
|
|
63687
64012
|
* Remove one or more overlay elements from priv and the DOM.
|
|
64013
|
+
*
|
|
64014
|
+
* An overlay that holds the focus -- a floating button reached
|
|
64015
|
+
* with Tab, the ✕ of the detail popover, a field of a popover --
|
|
64016
|
+
* gives it back to the canvas BEFORE it goes. Removing the
|
|
64017
|
+
* focused element is a focus loss the browsers do not report
|
|
64018
|
+
* alike: Chromium fires a focusout, which _on_focusout_restore
|
|
64019
|
+
* answers; Firefox fires none and leaves the focus on <body>,
|
|
64020
|
+
* and the graph is deaf to Escape, Delete and ctrl+A until the
|
|
64021
|
+
* next click on it.
|
|
64022
|
+
*
|
|
63688
64023
|
* @param {object} gobj
|
|
63689
64024
|
* @param {...string} keys - priv property names to remove
|
|
63690
64025
|
************************************************************/
|
|
63691
64026
|
function hide_overlay(gobj, ...keys) {
|
|
63692
64027
|
let priv = gobj.priv;
|
|
63693
64028
|
for (let key of keys) if (priv[key]) {
|
|
63694
|
-
priv[key]
|
|
64029
|
+
let el = priv[key];
|
|
64030
|
+
if (el.contains(document.activeElement) && !(0, _yuneta_gobj_js.gobj_is_destroying)(gobj)) focus_main_canvas(priv.$container);
|
|
64031
|
+
el.remove();
|
|
63695
64032
|
priv[key] = null;
|
|
63696
64033
|
}
|
|
63697
64034
|
}
|
|
@@ -63736,9 +64073,7 @@ function graphs_write_is_owed(gobj) {
|
|
|
63736
64073
|
return Object.keys(gobj.priv._graphs_writes_owed).length > 0;
|
|
63737
64074
|
}
|
|
63738
64075
|
function mark_graph_dirty(gobj) {
|
|
63739
|
-
|
|
63740
|
-
enableElements($container, ".EV_SAVE_GRAPH");
|
|
63741
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
64076
|
+
light_save_button(gobj, true);
|
|
63742
64077
|
}
|
|
63743
64078
|
/************************************************************
|
|
63744
64079
|
* Extract width/height from a style's size property.
|
|
@@ -63753,13 +64088,15 @@ function extract_size(style) {
|
|
|
63753
64088
|
}
|
|
63754
64089
|
/************************************************************
|
|
63755
64090
|
* Show a pair of floating icons (gear + trash) next to an
|
|
63756
|
-
* element.
|
|
64091
|
+
* element. The titles are i18n KEYS (see create_floating_icon);
|
|
64092
|
+
* each click sends its event to `gobj` with the same identity
|
|
64093
|
+
* `kw`. Returns {icon_el, delete_el}.
|
|
63757
64094
|
************************************************************/
|
|
63758
|
-
function show_dual_icons(gobj, x, y,
|
|
64095
|
+
function show_dual_icons(gobj, x, y, gear_key, gear_event, trash_key, trash_event, kw) {
|
|
63759
64096
|
let priv = gobj.priv;
|
|
63760
|
-
const icon_el = create_floating_icon("gear", "#1890ff", x, y,
|
|
64097
|
+
const icon_el = create_floating_icon("gear", "#1890ff", x, y, gear_key, gobj, gear_event, kw);
|
|
63761
64098
|
priv.$container.appendChild(icon_el);
|
|
63762
|
-
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y + floating_icon_step(),
|
|
64099
|
+
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y + floating_icon_step(), trash_key, gobj, trash_event, kw);
|
|
63763
64100
|
priv.$container.appendChild(delete_el);
|
|
63764
64101
|
return {
|
|
63765
64102
|
icon_el,
|
|
@@ -63851,10 +64188,22 @@ function create_form_select(parent, options, marginBottom) {
|
|
|
63851
64188
|
return select;
|
|
63852
64189
|
}
|
|
63853
64190
|
var BTN_STYLE_CANCEL = "flex:1;padding:6px;background:var(--bulma-scheme-main-bis, #fff);color:var(--bulma-text-strong, #333);border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;";
|
|
63854
|
-
|
|
64191
|
+
/************************************************************
|
|
64192
|
+
* The buttons of a popover: each one SENDS an input event of
|
|
64193
|
+
* this gclass to `gobj`, and the action does the work, where
|
|
64194
|
+
* the `machine` trace sees it (V20.5 #4). A button is
|
|
64195
|
+
* {i18n, style, event, kw, form}
|
|
64196
|
+
* `kw` is the plain identity of what the popover is about
|
|
64197
|
+
* (copied per click); `form` names the controls whose `value`
|
|
64198
|
+
* goes in the kw too, as the control says it -- a string, the
|
|
64199
|
+
* action parses it. The kw says what was asked for, in the
|
|
64200
|
+
* trace: the identity and what the form held when it was
|
|
64201
|
+
* pressed.
|
|
64202
|
+
************************************************************/
|
|
64203
|
+
function create_form_button_row(parent, buttons, gobj) {
|
|
63855
64204
|
let btnRow = document.createElement("div");
|
|
63856
64205
|
btnRow.style.cssText = "display:flex;gap:8px;";
|
|
63857
|
-
for (let { i18n, style,
|
|
64206
|
+
for (let { i18n, style, event, kw, form } of buttons) {
|
|
63858
64207
|
let btn = document.createElement("button");
|
|
63859
64208
|
btn.textContent = (0, i18next.t)(i18n);
|
|
63860
64209
|
btn.setAttribute("data-i18n", i18n);
|
|
@@ -63865,18 +64214,28 @@ function create_form_button_row(parent, buttons) {
|
|
|
63865
64214
|
btn.style.cssText = style + touch_control_css();
|
|
63866
64215
|
btn.addEventListener("click", (e) => {
|
|
63867
64216
|
e.stopPropagation();
|
|
63868
|
-
|
|
64217
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, event, form_kw(kw, form), gobj);
|
|
63869
64218
|
});
|
|
63870
64219
|
btnRow.appendChild(btn);
|
|
63871
64220
|
}
|
|
63872
64221
|
parent.appendChild(btnRow);
|
|
63873
64222
|
return btnRow;
|
|
63874
64223
|
}
|
|
64224
|
+
function form_kw(kw, form) {
|
|
64225
|
+
let out = (0, _yuneta_gobj_js.json_deep_copy)(kw || {});
|
|
64226
|
+
for (let [name, control] of Object.entries(form || {})) out[name] = String(control.value);
|
|
64227
|
+
return out;
|
|
64228
|
+
}
|
|
63875
64229
|
/************************************************************
|
|
63876
64230
|
* Show a confirmation popover next to a target element.
|
|
63877
|
-
*
|
|
64231
|
+
*
|
|
64232
|
+
* `question` is the plain identity of what is asked, {what,
|
|
64233
|
+
* id|ids}: the confirm button sends it with EV_CONFIRMED and the
|
|
64234
|
+
* cancel button with EV_CANCEL_CONFIRM, and the actions answer.
|
|
64235
|
+
* `priv_key` is where the popover is kept, and it must be the
|
|
64236
|
+
* one CONFIRM_POPOVER_OF names for `question.what`.
|
|
63878
64237
|
************************************************************/
|
|
63879
|
-
function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_color,
|
|
64238
|
+
function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_color, question, priv_key) {
|
|
63880
64239
|
hide_overlay(gobj, priv_key);
|
|
63881
64240
|
let priv = gobj.priv;
|
|
63882
64241
|
let containerRect = priv.$container.getBoundingClientRect();
|
|
@@ -63897,14 +64256,17 @@ function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_co
|
|
|
63897
64256
|
create_form_button_row(popover, [{
|
|
63898
64257
|
i18n: "cancel",
|
|
63899
64258
|
style: BTN_STYLE_CANCEL,
|
|
63900
|
-
|
|
64259
|
+
event: "EV_CANCEL_CONFIRM",
|
|
64260
|
+
kw: question
|
|
63901
64261
|
}, {
|
|
63902
64262
|
i18n: confirm_text,
|
|
63903
64263
|
style: "flex:1;padding:6px;background:" + confirm_color + ";color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
63904
|
-
|
|
63905
|
-
|
|
64264
|
+
event: "EV_CONFIRMED",
|
|
64265
|
+
kw: question
|
|
64266
|
+
}], gobj);
|
|
63906
64267
|
priv.$container.appendChild(popover);
|
|
63907
64268
|
priv[priv_key] = popover;
|
|
64269
|
+
priv._confirm_questions[priv_key] = (0, _yuneta_gobj_js.json_deep_copy)(question);
|
|
63908
64270
|
clamp_popover_position(gobj, popover);
|
|
63909
64271
|
}
|
|
63910
64272
|
/************************************************************
|
|
@@ -63982,27 +64344,30 @@ function paint_selection(gobj, ids) {
|
|
|
63982
64344
|
* Zoom-to-selection can only act on a selection.
|
|
63983
64345
|
*
|
|
63984
64346
|
* The attribute is toggled on the element instead of re-rendering
|
|
63985
|
-
* the toolbar, which would rebuild its innerHTML
|
|
63986
|
-
*
|
|
63987
|
-
*
|
|
64347
|
+
* the toolbar, which would rebuild its whole innerHTML each time a
|
|
64348
|
+
* card is ticked. A rebuild asks the same question
|
|
64349
|
+
* (selection_is_painted) in the toolbar's getItems().
|
|
63988
64350
|
************************************************************/
|
|
64351
|
+
function selection_is_painted(gobj) {
|
|
64352
|
+
return (gobj.priv._selected_paint_ids || []).length > 0;
|
|
64353
|
+
}
|
|
63989
64354
|
function update_zoom_selection_button(gobj) {
|
|
63990
|
-
let priv = gobj.priv;
|
|
63991
64355
|
let $container = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "$container");
|
|
63992
64356
|
if (!$container) return;
|
|
63993
64357
|
if (!$container.querySelector(".EV_ZOOM_SELECTION")) return;
|
|
63994
|
-
if ((
|
|
64358
|
+
if (selection_is_painted(gobj)) enableElements($container, ".EV_ZOOM_SELECTION");
|
|
63995
64359
|
else disableElements($container, ".EV_ZOOM_SELECTION");
|
|
63996
64360
|
}
|
|
63997
64361
|
/************************************************************
|
|
63998
64362
|
* The selection mode is a state, so it has to LOOK like one:
|
|
63999
64363
|
* a PRESSED toggle, not a button wearing one of the palette's
|
|
64000
|
-
* action colours (see `pressed_state` in lib_graph.css).
|
|
64364
|
+
* action colours (see `pressed_state` in lib_graph.css). And
|
|
64365
|
+
* it SAYS it, in `aria-pressed`, for whoever does not see it.
|
|
64001
64366
|
*
|
|
64002
64367
|
* Toggled on the element rather than re-rendered with the
|
|
64003
64368
|
* toolbar, for the same reason as the button above: a
|
|
64004
|
-
* re-render rebuilds the innerHTML
|
|
64005
|
-
*
|
|
64369
|
+
* re-render rebuilds the whole innerHTML. A rebuild draws the
|
|
64370
|
+
* same state, baked in the edit toolbar's getItems().
|
|
64006
64371
|
************************************************************/
|
|
64007
64372
|
function update_selection_mode_button(gobj) {
|
|
64008
64373
|
let priv = gobj.priv;
|
|
@@ -64010,6 +64375,9 @@ function update_selection_mode_button(gobj) {
|
|
|
64010
64375
|
if (!$container) return;
|
|
64011
64376
|
if (!$container.querySelector(".EV_TOGGLE_SELECTION_MODE")) return;
|
|
64012
64377
|
set_pressed_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
|
|
64378
|
+
$container.querySelectorAll(".EV_TOGGLE_SELECTION_MODE").forEach(($el) => {
|
|
64379
|
+
$el.setAttribute("aria-pressed", priv.selection_mode ? "true" : "false");
|
|
64380
|
+
});
|
|
64013
64381
|
}
|
|
64014
64382
|
/************************************************************
|
|
64015
64383
|
* Select a SET of nodes: what a marquee and a shift-click do.
|
|
@@ -64464,13 +64832,18 @@ function show_link_icon_if_fkey(gobj) {
|
|
|
64464
64832
|
let canvasPos = get_port_canvas_position(gobj, priv._selected_node_id, priv._selected_port_key);
|
|
64465
64833
|
if (!canvasPos) return;
|
|
64466
64834
|
let vp = graph.getViewportByCanvas([canvasPos.x, canvasPos.y]);
|
|
64467
|
-
let
|
|
64468
|
-
|
|
64469
|
-
|
|
64835
|
+
let identity = {
|
|
64836
|
+
node_id: priv._selected_node_id,
|
|
64837
|
+
port_key: priv._selected_port_key
|
|
64838
|
+
};
|
|
64839
|
+
let icon = create_floating_icon("link", "#52c41a", vp[0] + floating_icon_size() / 2 + 4, vp[1] + floating_icon_dy(), "link to hook", gobj, "EV_ENTER_LINKING_MODE", identity);
|
|
64470
64840
|
icon.addEventListener("pointerdown", (e) => {
|
|
64471
64841
|
e.stopPropagation();
|
|
64472
64842
|
e.preventDefault();
|
|
64473
|
-
|
|
64843
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_START_LINK_DRAG", Object.assign((0, _yuneta_gobj_js.json_deep_copy)(identity), {
|
|
64844
|
+
client_x: e.clientX,
|
|
64845
|
+
client_y: e.clientY
|
|
64846
|
+
}), gobj);
|
|
64474
64847
|
});
|
|
64475
64848
|
priv.$container.appendChild(icon);
|
|
64476
64849
|
priv._link_icon_el = icon;
|
|
@@ -64520,7 +64893,10 @@ function show_port_icon(gobj) {
|
|
|
64520
64893
|
if (!priv._selected_node_id || !priv._selected_port_key) return;
|
|
64521
64894
|
let xy = port_icon_xy(gobj);
|
|
64522
64895
|
if (!xy) return;
|
|
64523
|
-
let icon = create_floating_icon("gear", "#1890ff", xy.x, xy.y,
|
|
64896
|
+
let icon = create_floating_icon("gear", "#1890ff", xy.x, xy.y, "port properties", gobj, "EV_TOGGLE_PORT_POPOVER", {
|
|
64897
|
+
node_id: priv._selected_node_id,
|
|
64898
|
+
port_key: priv._selected_port_key
|
|
64899
|
+
});
|
|
64524
64900
|
priv.$container.appendChild(icon);
|
|
64525
64901
|
priv._port_icon_el = icon;
|
|
64526
64902
|
}
|
|
@@ -64630,17 +65006,26 @@ function show_port_popover(gobj) {
|
|
|
64630
65006
|
create_form_button_row(popover, [{
|
|
64631
65007
|
i18n: "cancel",
|
|
64632
65008
|
style: BTN_STYLE_CANCEL,
|
|
64633
|
-
|
|
64634
|
-
|
|
65009
|
+
event: "EV_CANCEL_PORT_POPOVER",
|
|
65010
|
+
kw: {
|
|
65011
|
+
node_id,
|
|
65012
|
+
port_key
|
|
64635
65013
|
}
|
|
64636
65014
|
}, {
|
|
64637
65015
|
i18n: "apply",
|
|
64638
65016
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
64639
|
-
|
|
64640
|
-
|
|
64641
|
-
|
|
65017
|
+
event: "EV_APPLY_PORT_POPOVER",
|
|
65018
|
+
kw: {
|
|
65019
|
+
node_id,
|
|
65020
|
+
port_key,
|
|
65021
|
+
r_before: orig_r
|
|
65022
|
+
},
|
|
65023
|
+
form: {
|
|
65024
|
+
shape: shapeSelect,
|
|
65025
|
+
r: rInput,
|
|
65026
|
+
scope: scopeSelect
|
|
64642
65027
|
}
|
|
64643
|
-
}]);
|
|
65028
|
+
}], gobj);
|
|
64644
65029
|
priv.$container.appendChild(popover);
|
|
64645
65030
|
priv._port_popover_el = popover;
|
|
64646
65031
|
set_preview_undo(gobj, "_port_preview_undo", undo_port);
|
|
@@ -64857,8 +65242,16 @@ function try_complete_link(gobj, clicked_node_id, clicked_port_key) {
|
|
|
64857
65242
|
/************************************************************
|
|
64858
65243
|
* Drag-link: drag from link icon to a hook port.
|
|
64859
65244
|
* Draws a temporary SVG line from the fkey port to the cursor.
|
|
65245
|
+
*
|
|
65246
|
+
* Run by ac_start_link_drag. The pointer's MOVES only draw the
|
|
65247
|
+
* line and the cursor -- the drag's own picture, no action, and
|
|
65248
|
+
* one event per move would bury the machine trace -- while the
|
|
65249
|
+
* END of the gesture is an event: EV_LINK_DRAG_END {client_x,
|
|
65250
|
+
* client_y, dragged} on the release, EV_LINK_DRAG_CANCEL when
|
|
65251
|
+
* the browser takes the pointer. Their actions take the drag
|
|
65252
|
+
* down (end_link_drag) and link, or leave the linking mode.
|
|
64860
65253
|
************************************************************/
|
|
64861
|
-
function start_link_drag(gobj,
|
|
65254
|
+
function start_link_drag(gobj, client_x, client_y) {
|
|
64862
65255
|
let priv = gobj.priv;
|
|
64863
65256
|
let graph = priv.graph;
|
|
64864
65257
|
if (!priv._linking_mode) enter_linking_mode(gobj);
|
|
@@ -64872,8 +65265,8 @@ function start_link_drag(gobj, e) {
|
|
|
64872
65265
|
let line = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
64873
65266
|
line.setAttribute("x1", startX);
|
|
64874
65267
|
line.setAttribute("y1", startY);
|
|
64875
|
-
line.setAttribute("x2",
|
|
64876
|
-
line.setAttribute("y2",
|
|
65268
|
+
line.setAttribute("x2", client_x - containerRect.left);
|
|
65269
|
+
line.setAttribute("y2", client_y - containerRect.top);
|
|
64877
65270
|
line.setAttribute("stroke", "#52c41a");
|
|
64878
65271
|
line.setAttribute("stroke-width", "2");
|
|
64879
65272
|
line.setAttribute("stroke-dasharray", "6 3");
|
|
@@ -64892,41 +65285,47 @@ function start_link_drag(gobj, e) {
|
|
|
64892
65285
|
priv.$container.style.cursor = hoverTarget ? "copy" : "not-allowed";
|
|
64893
65286
|
}
|
|
64894
65287
|
function onPointerUp(ev) {
|
|
64895
|
-
|
|
64896
|
-
|
|
64897
|
-
|
|
64898
|
-
|
|
64899
|
-
|
|
64900
|
-
priv._link_drag_svg.remove();
|
|
64901
|
-
priv._link_drag_svg = null;
|
|
64902
|
-
}
|
|
64903
|
-
if (!dragged) return;
|
|
64904
|
-
let cx = ev.clientX - containerRect.left;
|
|
64905
|
-
let cy = ev.clientY - containerRect.top;
|
|
64906
|
-
let canvasPt = graph.getCanvasByViewport([cx, cy]);
|
|
64907
|
-
let target = find_hook_at_point(gobj, canvasPt[0], canvasPt[1]);
|
|
64908
|
-
if (target) try_complete_link(gobj, target.node_id, target.port_key);
|
|
64909
|
-
else exit_linking_mode(gobj);
|
|
65288
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LINK_DRAG_END", {
|
|
65289
|
+
client_x: ev.clientX,
|
|
65290
|
+
client_y: ev.clientY,
|
|
65291
|
+
dragged
|
|
65292
|
+
}, gobj);
|
|
64910
65293
|
}
|
|
64911
65294
|
function onPointerCancel(ev) {
|
|
65295
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_LINK_DRAG_CANCEL", {}, gobj);
|
|
65296
|
+
}
|
|
65297
|
+
function unwire() {
|
|
64912
65298
|
document.removeEventListener("pointermove", onPointerMove);
|
|
64913
65299
|
document.removeEventListener("pointerup", onPointerUp);
|
|
64914
65300
|
document.removeEventListener("pointercancel", onPointerCancel);
|
|
64915
|
-
priv.$container.style.cursor = "";
|
|
64916
|
-
if (priv._link_drag_svg) {
|
|
64917
|
-
priv._link_drag_svg.remove();
|
|
64918
|
-
priv._link_drag_svg = null;
|
|
64919
|
-
}
|
|
64920
|
-
exit_linking_mode(gobj);
|
|
64921
65301
|
}
|
|
64922
65302
|
document.addEventListener("pointermove", onPointerMove);
|
|
64923
65303
|
document.addEventListener("pointerup", onPointerUp);
|
|
64924
65304
|
document.addEventListener("pointercancel", onPointerCancel);
|
|
64925
|
-
|
|
64926
|
-
|
|
64927
|
-
|
|
64928
|
-
|
|
65305
|
+
priv._link_drag = {
|
|
65306
|
+
left: containerRect.left,
|
|
65307
|
+
top: containerRect.top,
|
|
65308
|
+
unwire
|
|
64929
65309
|
};
|
|
65310
|
+
priv._drag_unwire = unwire;
|
|
65311
|
+
}
|
|
65312
|
+
/************************************************************
|
|
65313
|
+
* Take a link drag down: its listeners, its line, its cursor.
|
|
65314
|
+
* What was linked, or not, is the caller's.
|
|
65315
|
+
************************************************************/
|
|
65316
|
+
function end_link_drag(gobj) {
|
|
65317
|
+
let priv = gobj.priv;
|
|
65318
|
+
let drag = priv._link_drag;
|
|
65319
|
+
priv._link_drag = null;
|
|
65320
|
+
if (drag) {
|
|
65321
|
+
drag.unwire();
|
|
65322
|
+
if (priv._drag_unwire === drag.unwire) priv._drag_unwire = null;
|
|
65323
|
+
}
|
|
65324
|
+
priv.$container.style.cursor = "";
|
|
65325
|
+
if (priv._link_drag_svg) {
|
|
65326
|
+
priv._link_drag_svg.remove();
|
|
65327
|
+
priv._link_drag_svg = null;
|
|
65328
|
+
}
|
|
64930
65329
|
}
|
|
64931
65330
|
/************************************************************
|
|
64932
65331
|
* Find if a canvas point hits a valid hook port during
|
|
@@ -65216,7 +65615,7 @@ function show_edge_icon(gobj) {
|
|
|
65216
65615
|
if (!priv._selected_edge_id) return;
|
|
65217
65616
|
let mid = get_edge_viewport_midpoint(gobj, priv._selected_edge_id);
|
|
65218
65617
|
if (!mid) return;
|
|
65219
|
-
let icons = show_dual_icons(gobj, mid.x + 4, mid.y + floating_icon_dy(),
|
|
65618
|
+
let icons = show_dual_icons(gobj, mid.x + 4, mid.y + floating_icon_dy(), "edge properties", "EV_TOGGLE_EDGE_POPOVER", "unlink", "EV_REQUEST_UNLINK_EDGE", { edge_id: priv._selected_edge_id });
|
|
65220
65619
|
priv._edge_icon_el = icons.icon_el;
|
|
65221
65620
|
priv._edge_delete_el = icons.delete_el;
|
|
65222
65621
|
}
|
|
@@ -65326,17 +65725,19 @@ function show_edge_popover(gobj) {
|
|
|
65326
65725
|
create_form_button_row(popover, [{
|
|
65327
65726
|
i18n: "cancel",
|
|
65328
65727
|
style: BTN_STYLE_CANCEL,
|
|
65329
|
-
|
|
65330
|
-
|
|
65331
|
-
}
|
|
65728
|
+
event: "EV_CANCEL_EDGE_POPOVER",
|
|
65729
|
+
kw: { edge_id }
|
|
65332
65730
|
}, {
|
|
65333
65731
|
i18n: "apply",
|
|
65334
65732
|
style: "flex:1;padding:6px;background:#52c41a;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
65335
|
-
|
|
65336
|
-
|
|
65337
|
-
|
|
65338
|
-
|
|
65339
|
-
|
|
65733
|
+
event: "EV_APPLY_EDGE_POPOVER",
|
|
65734
|
+
kw: { edge_id },
|
|
65735
|
+
form: {
|
|
65736
|
+
line_width: lwInput,
|
|
65737
|
+
color: colorInput,
|
|
65738
|
+
scope: scopeSelect
|
|
65739
|
+
}
|
|
65740
|
+
}], gobj);
|
|
65340
65741
|
priv.$container.appendChild(popover);
|
|
65341
65742
|
priv._edge_popover_el = popover;
|
|
65342
65743
|
set_preview_undo(gobj, "_edge_preview_undo", undo_edge);
|
|
@@ -65373,7 +65774,7 @@ function show_node_icon(gobj) {
|
|
|
65373
65774
|
if (!priv._selected_node_id || priv._selected_port_key) return;
|
|
65374
65775
|
let rect = get_node_viewport_rect(gobj, priv._selected_node_id);
|
|
65375
65776
|
if (!rect) return;
|
|
65376
|
-
let icons = show_dual_icons(gobj, rect.right + 4, rect.top + floating_icon_dy(),
|
|
65777
|
+
let icons = show_dual_icons(gobj, rect.right + 4, rect.top + floating_icon_dy(), "node properties", "EV_TOGGLE_NODE_POPOVER", "delete node", "EV_REQUEST_DELETE_NODE", { node_id: priv._selected_node_id });
|
|
65377
65778
|
priv._node_icon_el = icons.icon_el;
|
|
65378
65779
|
priv._node_delete_el = icons.delete_el;
|
|
65379
65780
|
}
|
|
@@ -65487,17 +65888,24 @@ function show_node_popover(gobj) {
|
|
|
65487
65888
|
create_form_button_row(popover, [{
|
|
65488
65889
|
i18n: "cancel",
|
|
65489
65890
|
style: BTN_STYLE_CANCEL,
|
|
65490
|
-
|
|
65491
|
-
|
|
65492
|
-
}
|
|
65891
|
+
event: "EV_CANCEL_NODE_POPOVER",
|
|
65892
|
+
kw: { node_id }
|
|
65493
65893
|
}, {
|
|
65494
65894
|
i18n: "apply",
|
|
65495
65895
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
65496
|
-
|
|
65497
|
-
|
|
65498
|
-
|
|
65896
|
+
event: "EV_APPLY_NODE_POPOVER",
|
|
65897
|
+
kw: {
|
|
65898
|
+
node_id,
|
|
65899
|
+
shape_before: orig_figure
|
|
65900
|
+
},
|
|
65901
|
+
form: {
|
|
65902
|
+
fill: fillInput,
|
|
65903
|
+
stroke: strokeInput,
|
|
65904
|
+
line_width: lwInput,
|
|
65905
|
+
scope: scopeSelect,
|
|
65906
|
+
shape: shapeSelect
|
|
65499
65907
|
}
|
|
65500
|
-
}]);
|
|
65908
|
+
}], gobj);
|
|
65501
65909
|
priv.$container.appendChild(popover);
|
|
65502
65910
|
priv._node_popover_el = popover;
|
|
65503
65911
|
set_preview_undo(gobj, "_node_preview_undo", undo_node);
|
|
@@ -65517,6 +65925,39 @@ function hide_node_detail(gobj) {
|
|
|
65517
65925
|
gobj.priv._detail_node_id = null;
|
|
65518
65926
|
hide_overlay(gobj, "_node_detail_el");
|
|
65519
65927
|
}
|
|
65928
|
+
/************************************************************
|
|
65929
|
+
* The ✕ of the detail popover. Built as an element and not in
|
|
65930
|
+
* the popover's markup, so that it is a whole button: named
|
|
65931
|
+
* with its key (a language switch renames it), reachable by
|
|
65932
|
+
* the keyboard and pressed by Enter or Space as by the pointer.
|
|
65933
|
+
* Its click sends EV_CLOSE_NODE_DETAIL {node_id} and nothing
|
|
65934
|
+
* else; a pointer press does not take the focus.
|
|
65935
|
+
************************************************************/
|
|
65936
|
+
function create_detail_close(gobj, color, node_id) {
|
|
65937
|
+
let el = document.createElement("div");
|
|
65938
|
+
el.className = "g6-detail-close";
|
|
65939
|
+
el.setAttribute("role", "button");
|
|
65940
|
+
el.setAttribute("tabindex", "0");
|
|
65941
|
+
el.setAttribute("title", (0, i18next.t)("close"));
|
|
65942
|
+
el.setAttribute("data-i18n-title", "close");
|
|
65943
|
+
el.setAttribute("aria-label", (0, i18next.t)("close"));
|
|
65944
|
+
el.setAttribute("data-i18n-aria-label", "close");
|
|
65945
|
+
el.style.color = color;
|
|
65946
|
+
el.textContent = "×";
|
|
65947
|
+
el.addEventListener("click", (e) => {
|
|
65948
|
+
e.stopPropagation();
|
|
65949
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CLOSE_NODE_DETAIL", { node_id }, gobj);
|
|
65950
|
+
});
|
|
65951
|
+
keep_focus_on_press(el);
|
|
65952
|
+
click_on_enter_or_space(el);
|
|
65953
|
+
return el;
|
|
65954
|
+
}
|
|
65955
|
+
function detail_div(class_name, text) {
|
|
65956
|
+
let el = document.createElement("div");
|
|
65957
|
+
if (class_name) el.className = class_name;
|
|
65958
|
+
if (text !== void 0) el.textContent = text;
|
|
65959
|
+
return el;
|
|
65960
|
+
}
|
|
65520
65961
|
function show_node_detail_popover(gobj, node_id) {
|
|
65521
65962
|
let priv = gobj.priv;
|
|
65522
65963
|
let graph = priv.graph;
|
|
@@ -65546,7 +65987,19 @@ function show_node_detail_popover(gobj, node_id) {
|
|
|
65546
65987
|
popover.style.overflow = "auto";
|
|
65547
65988
|
popover.style.padding = "0 12px 12px";
|
|
65548
65989
|
popover.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
|
|
65549
|
-
let
|
|
65990
|
+
let head = detail_div("g6-detail-head");
|
|
65991
|
+
head.style.background = bg;
|
|
65992
|
+
let names = detail_div("");
|
|
65993
|
+
names.style.flex = "1 1 auto";
|
|
65994
|
+
names.style.minWidth = "0";
|
|
65995
|
+
names.appendChild(detail_div("g6-detail-id", id));
|
|
65996
|
+
let topic_el = detail_div("g6-detail-topic", topic);
|
|
65997
|
+
topic_el.style.color = sub;
|
|
65998
|
+
names.appendChild(topic_el);
|
|
65999
|
+
head.appendChild(names);
|
|
66000
|
+
head.appendChild(create_detail_close(gobj, sub, node_id));
|
|
66001
|
+
popover.appendChild(head);
|
|
66002
|
+
let n_rows = 0;
|
|
65550
66003
|
for (let key of Object.keys(record)) {
|
|
65551
66004
|
if (key.indexOf("__") === 0) continue;
|
|
65552
66005
|
let v = record[key];
|
|
@@ -65555,14 +66008,21 @@ function show_node_detail_popover(gobj, node_id) {
|
|
|
65555
66008
|
else if (typeof v === "object") vs = JSON.stringify(v);
|
|
65556
66009
|
else vs = String(v);
|
|
65557
66010
|
if (vs.length > 240) vs = vs.slice(0, 240) + "…";
|
|
65558
|
-
|
|
66011
|
+
let row = detail_div("g6-detail-row");
|
|
66012
|
+
row.style.borderTop = `1px solid ${rowbd}`;
|
|
66013
|
+
let key_el = detail_div("g6-detail-key", key);
|
|
66014
|
+
key_el.style.color = sub;
|
|
66015
|
+
row.appendChild(key_el);
|
|
66016
|
+
row.appendChild(detail_div("g6-detail-val", vs));
|
|
66017
|
+
popover.appendChild(row);
|
|
66018
|
+
n_rows++;
|
|
66019
|
+
}
|
|
66020
|
+
if (!n_rows) {
|
|
66021
|
+
let empty = detail_div("g6-detail-empty", (0, i18next.t)("no fields"));
|
|
66022
|
+
empty.setAttribute("data-i18n", "no fields");
|
|
66023
|
+
empty.style.color = sub;
|
|
66024
|
+
popover.appendChild(empty);
|
|
65559
66025
|
}
|
|
65560
|
-
popover.innerHTML = `<div class="g6-detail-head" style="background:${bg};"><div style="flex:1 1 auto;min-width:0;"><div class="g6-detail-id">${(0, _yuneta_gobj_js.escapeHtml)(id)}</div><div class="g6-detail-topic" style="color:${sub};">${(0, _yuneta_gobj_js.escapeHtml)(topic)}</div></div><div class="g6-detail-close" role="button" tabindex="0" aria-label="${(0, _yuneta_gobj_js.escapeHtml)((0, i18next.t)("close"))}" title="${(0, _yuneta_gobj_js.escapeHtml)((0, i18next.t)("close"))}" style="color:${sub};">×</div></div>` + (rows || `<div class="g6-detail-empty" style="color:${sub};">${(0, _yuneta_gobj_js.escapeHtml)((0, i18next.t)("no fields"))}</div>`);
|
|
65561
|
-
let close_el = popover.querySelector(".g6-detail-close");
|
|
65562
|
-
if (close_el) close_el.addEventListener("click", (e) => {
|
|
65563
|
-
e.stopPropagation();
|
|
65564
|
-
hide_node_detail(gobj);
|
|
65565
|
-
});
|
|
65566
66026
|
priv.$container.appendChild(popover);
|
|
65567
66027
|
priv._node_detail_el = popover;
|
|
65568
66028
|
priv._detail_node_id = node_id;
|
|
@@ -66084,10 +66544,10 @@ function request_delete_selection(gobj) {
|
|
|
66084
66544
|
execute_delete_selection(gobj, nodes);
|
|
66085
66545
|
return;
|
|
66086
66546
|
}
|
|
66087
|
-
show_confirm_popover(gobj, null, delete_question(nodes), "delete", "#ff4d4f",
|
|
66547
|
+
show_confirm_popover(gobj, null, delete_question(nodes), "delete", "#ff4d4f", {
|
|
66088
66548
|
what: "delete_selection",
|
|
66089
66549
|
ids: nodes.map((nd) => String(nd.id))
|
|
66090
|
-
},
|
|
66550
|
+
}, "_delete_confirm_el");
|
|
66091
66551
|
}
|
|
66092
66552
|
function execute_delete_selection(gobj, nodes) {
|
|
66093
66553
|
let priv = gobj.priv;
|
|
@@ -66104,10 +66564,10 @@ function execute_delete_selection(gobj, nodes) {
|
|
|
66104
66564
|
************************************************************/
|
|
66105
66565
|
function show_delete_confirm(gobj, nodeData) {
|
|
66106
66566
|
let priv = gobj.priv;
|
|
66107
|
-
show_confirm_popover(gobj, priv._node_delete_el, delete_question([nodeData]), "delete", "#ff4d4f",
|
|
66567
|
+
show_confirm_popover(gobj, priv._node_delete_el, delete_question([nodeData]), "delete", "#ff4d4f", {
|
|
66108
66568
|
what: "delete_node",
|
|
66109
66569
|
id: String(nodeData.id)
|
|
66110
|
-
},
|
|
66570
|
+
}, "_delete_confirm_el");
|
|
66111
66571
|
}
|
|
66112
66572
|
function hide_delete_confirm(gobj) {
|
|
66113
66573
|
hide_overlay(gobj, "_delete_confirm_el");
|
|
@@ -66156,6 +66616,7 @@ function show_create_popover(gobj) {
|
|
|
66156
66616
|
topicLabel.appendChild(document.createTextNode(":"));
|
|
66157
66617
|
popover.appendChild(topicLabel);
|
|
66158
66618
|
let topicSelect = document.createElement("select");
|
|
66619
|
+
topicSelect.className = "G6_CREATE_TOPIC";
|
|
66159
66620
|
topicSelect.setAttribute("title", (0, i18next.t)("topic"));
|
|
66160
66621
|
topicSelect.setAttribute("data-i18n-title", "topic");
|
|
66161
66622
|
topicSelect.setAttribute("aria-label", (0, i18next.t)("topic"));
|
|
@@ -66195,6 +66656,7 @@ function show_create_popover(gobj) {
|
|
|
66195
66656
|
idLabel.appendChild(document.createTextNode(":"));
|
|
66196
66657
|
popover.appendChild(idLabel);
|
|
66197
66658
|
let idInput = document.createElement("input");
|
|
66659
|
+
idInput.className = "G6_CREATE_ID";
|
|
66198
66660
|
idInput.type = "text";
|
|
66199
66661
|
idInput.placeholder = (0, i18next.t)("node id");
|
|
66200
66662
|
idInput.setAttribute("data-i18n-placeholder", "node id");
|
|
@@ -66205,39 +66667,31 @@ function show_create_popover(gobj) {
|
|
|
66205
66667
|
idInput.style.cssText = "width:100%;padding:6px;border:1px solid #d9d9d9;border-radius:4px;font-size:13px;margin-bottom:10px;box-sizing:border-box;" + touch_control_css();
|
|
66206
66668
|
popover.appendChild(idInput);
|
|
66207
66669
|
let errorEl = document.createElement("div");
|
|
66670
|
+
errorEl.className = "G6_CREATE_ERROR";
|
|
66208
66671
|
errorEl.style.cssText = "color:#ff4d4f;font-size:12px;margin-bottom:8px;display:none;";
|
|
66209
66672
|
popover.appendChild(errorEl);
|
|
66210
|
-
let createBtn
|
|
66211
|
-
create_form_button_row(popover, [{
|
|
66673
|
+
let createBtn = create_form_button_row(popover, [{
|
|
66212
66674
|
i18n: "cancel",
|
|
66213
66675
|
style: BTN_STYLE_CANCEL,
|
|
66214
|
-
|
|
66676
|
+
event: "EV_CLOSE_CREATE_POPOVER",
|
|
66677
|
+
kw: {}
|
|
66215
66678
|
}, {
|
|
66216
66679
|
i18n: "create",
|
|
66217
66680
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
66218
|
-
|
|
66219
|
-
|
|
66220
|
-
|
|
66221
|
-
|
|
66222
|
-
|
|
66223
|
-
errorEl.style.display = "block";
|
|
66224
|
-
idInput.focus();
|
|
66225
|
-
return;
|
|
66226
|
-
}
|
|
66227
|
-
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_SUBMIT_NEW_NODE", {
|
|
66228
|
-
topic_name: String(topicSelect.value),
|
|
66229
|
-
id: node_id
|
|
66230
|
-
}, gobj);
|
|
66681
|
+
event: "EV_SUBMIT_NEW_NODE",
|
|
66682
|
+
kw: {},
|
|
66683
|
+
form: {
|
|
66684
|
+
topic_name: topicSelect,
|
|
66685
|
+
id: idInput
|
|
66231
66686
|
}
|
|
66232
|
-
}]);
|
|
66233
|
-
createBtn = popover.querySelector("button:last-child");
|
|
66687
|
+
}], gobj).lastElementChild;
|
|
66234
66688
|
idInput.addEventListener("keydown", (e) => {
|
|
66235
66689
|
if (e.key === "Enter") {
|
|
66236
66690
|
e.preventDefault();
|
|
66237
66691
|
createBtn.click();
|
|
66238
66692
|
} else if (e.key === "Escape") {
|
|
66239
66693
|
e.preventDefault();
|
|
66240
|
-
|
|
66694
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CLOSE_CREATE_POPOVER", {}, gobj);
|
|
66241
66695
|
}
|
|
66242
66696
|
});
|
|
66243
66697
|
priv.$container.appendChild(popover);
|
|
@@ -66287,10 +66741,10 @@ function execute_unlink_edge(gobj, edgeData) {
|
|
|
66287
66741
|
function show_unlink_confirm(gobj, edgeData) {
|
|
66288
66742
|
let priv = gobj.priv;
|
|
66289
66743
|
const d = edgeData.data;
|
|
66290
|
-
show_confirm_popover(gobj, priv._edge_delete_el, (0, i18next.t)("unlink") + " " + d.child_id + " → " + d.parent_id + "?\n" + (0, i18next.t)("neither record is deleted"), "unlink", "#ff4d4f",
|
|
66744
|
+
show_confirm_popover(gobj, priv._edge_delete_el, (0, i18next.t)("unlink") + " " + d.child_id + " → " + d.parent_id + "?\n" + (0, i18next.t)("neither record is deleted"), "unlink", "#ff4d4f", {
|
|
66291
66745
|
what: "unlink_edge",
|
|
66292
66746
|
id: String(edgeData.id)
|
|
66293
|
-
},
|
|
66747
|
+
}, "_unlink_confirm_el");
|
|
66294
66748
|
}
|
|
66295
66749
|
function hide_unlink_confirm(gobj) {
|
|
66296
66750
|
hide_overlay(gobj, "_unlink_confirm_el");
|
|
@@ -67661,9 +68115,7 @@ function ac_load_data(gobj, event, kw, src) {
|
|
|
67661
68115
|
************************************************************/
|
|
67662
68116
|
function ac_save_graph(gobj, event, kw, src) {
|
|
67663
68117
|
if (gobj.priv.edit_mode) {
|
|
67664
|
-
|
|
67665
|
-
disableElements($container, ".EV_SAVE_GRAPH");
|
|
67666
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
68118
|
+
light_save_button(gobj, false);
|
|
67667
68119
|
let history = graph_get_plugin(gobj, "history");
|
|
67668
68120
|
if (history) history.clear();
|
|
67669
68121
|
save_geometry(gobj);
|
|
@@ -67940,12 +68392,22 @@ function ac_center_anchor(gobj, event, kw, src) {
|
|
|
67940
68392
|
return 0;
|
|
67941
68393
|
}
|
|
67942
68394
|
/************************************************************
|
|
67943
|
-
* What the anchor button says it will do next
|
|
68395
|
+
* What the anchor button says it will do next: its `title`,
|
|
68396
|
+
* and the `title_key` it is translated from.
|
|
67944
68397
|
************************************************************/
|
|
67945
68398
|
function anchor_title(state) {
|
|
67946
|
-
if (state === "arming") return
|
|
67947
|
-
|
|
67948
|
-
|
|
68399
|
+
if (state === "arming") return {
|
|
68400
|
+
title: (0, i18next.t)("click the element to centre on"),
|
|
68401
|
+
title_key: "click the element to centre on"
|
|
68402
|
+
};
|
|
68403
|
+
if (state === "on") return {
|
|
68404
|
+
title: (0, i18next.t)("centred: click to release"),
|
|
68405
|
+
title_key: "centred: click to release"
|
|
68406
|
+
};
|
|
68407
|
+
return {
|
|
68408
|
+
title: (0, i18next.t)("anchor view"),
|
|
68409
|
+
title_key: "anchor view"
|
|
68410
|
+
};
|
|
67949
68411
|
}
|
|
67950
68412
|
/************************************************************
|
|
67951
68413
|
* Every camera action ends the same way once an anchor is
|
|
@@ -68361,8 +68823,8 @@ function ac_set_layout$1(gobj, event, kw, src) {
|
|
|
68361
68823
|
function ac_set_operation_mode$1(gobj, event, kw, src) {
|
|
68362
68824
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "operation_mode", kw.operation_mode);
|
|
68363
68825
|
configure_behaviour(gobj);
|
|
68364
|
-
update_toolbar(gobj);
|
|
68365
68826
|
sync_history_plugin(gobj);
|
|
68827
|
+
update_toolbar(gobj);
|
|
68366
68828
|
return 0;
|
|
68367
68829
|
}
|
|
68368
68830
|
/************************************************************
|
|
@@ -68544,25 +69006,134 @@ function ac_context_menu_item(gobj, event, kw, src) {
|
|
|
68544
69006
|
return 0;
|
|
68545
69007
|
}
|
|
68546
69008
|
/************************************************************
|
|
68547
|
-
*
|
|
69009
|
+
* Is the identity a floating button was drawn with still what
|
|
69010
|
+
* is selected?
|
|
69011
|
+
*
|
|
69012
|
+
* The buttons are removed with their selection and drawn again
|
|
69013
|
+
* for the next one, so a click carrying another identity is a
|
|
69014
|
+
* broken invariant -- said loudly, never acted on: it would
|
|
69015
|
+
* delete, unlink or edit what the reader is not looking at.
|
|
69016
|
+
************************************************************/
|
|
69017
|
+
function floating_button_is_current(gobj, event, kw) {
|
|
69018
|
+
let priv = gobj.priv;
|
|
69019
|
+
let want = {
|
|
69020
|
+
node_id: priv._selected_node_id || "",
|
|
69021
|
+
port_key: priv._selected_port_key || "",
|
|
69022
|
+
edge_id: priv._selected_edge_id || ""
|
|
69023
|
+
};
|
|
69024
|
+
let keys = Object.keys(kw || {});
|
|
69025
|
+
let matches = keys.length > 0 && keys.every((k) => {
|
|
69026
|
+
return Object.prototype.hasOwnProperty.call(want, k) && !!kw[k] && kw[k] === want[k];
|
|
69027
|
+
});
|
|
69028
|
+
if (!matches) (0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but the selection is ${JSON.stringify(want)}`);
|
|
69029
|
+
return matches;
|
|
69030
|
+
}
|
|
69031
|
+
/************************************************************
|
|
69032
|
+
* {node_id} -- the delete icon floating beside the selected
|
|
69033
|
+
* node.
|
|
68548
69034
|
************************************************************/
|
|
68549
69035
|
function ac_request_delete_node(gobj, event, kw, src) {
|
|
69036
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
68550
69037
|
request_delete_node(gobj);
|
|
68551
69038
|
return 0;
|
|
68552
69039
|
}
|
|
68553
69040
|
/************************************************************
|
|
68554
|
-
*
|
|
69041
|
+
* {edge_id} -- the unlink icon floating beside the selected
|
|
69042
|
+
* edge.
|
|
68555
69043
|
************************************************************/
|
|
68556
69044
|
function ac_request_unlink_edge(gobj, event, kw, src) {
|
|
69045
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
68557
69046
|
request_unlink_edge(gobj);
|
|
68558
69047
|
return 0;
|
|
68559
69048
|
}
|
|
68560
69049
|
/************************************************************
|
|
69050
|
+
* {node_id} -- the gear beside the selected node: its
|
|
69051
|
+
* properties popover, opened or closed.
|
|
69052
|
+
************************************************************/
|
|
69053
|
+
function ac_toggle_node_popover(gobj, event, kw, src) {
|
|
69054
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69055
|
+
toggle_node_popover(gobj);
|
|
69056
|
+
return 0;
|
|
69057
|
+
}
|
|
69058
|
+
/************************************************************
|
|
69059
|
+
* {edge_id} -- the gear beside the selected edge.
|
|
69060
|
+
************************************************************/
|
|
69061
|
+
function ac_toggle_edge_popover(gobj, event, kw, src) {
|
|
69062
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69063
|
+
toggle_edge_popover(gobj);
|
|
69064
|
+
return 0;
|
|
69065
|
+
}
|
|
69066
|
+
/************************************************************
|
|
69067
|
+
* {node_id, port_key} -- the gear beside the selected port.
|
|
69068
|
+
************************************************************/
|
|
69069
|
+
function ac_toggle_port_popover(gobj, event, kw, src) {
|
|
69070
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69071
|
+
toggle_port_popover(gobj);
|
|
69072
|
+
return 0;
|
|
69073
|
+
}
|
|
69074
|
+
/************************************************************
|
|
69075
|
+
* {node_id, port_key} -- the link icon of a selected fkey port,
|
|
69076
|
+
* CLICKED (a press that drags enters the mode on its own, from
|
|
69077
|
+
* start_link_drag): the compatible hooks light up, and the next
|
|
69078
|
+
* click on one of them links.
|
|
69079
|
+
************************************************************/
|
|
69080
|
+
function ac_enter_linking_mode(gobj, event, kw, src) {
|
|
69081
|
+
let priv = gobj.priv;
|
|
69082
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69083
|
+
if (!priv._linking_mode) enter_linking_mode(gobj);
|
|
69084
|
+
return 0;
|
|
69085
|
+
}
|
|
69086
|
+
/************************************************************
|
|
69087
|
+
* {node_id} -- the ✕ of the detail popover.
|
|
69088
|
+
************************************************************/
|
|
69089
|
+
function ac_close_node_detail(gobj, event, kw, src) {
|
|
69090
|
+
let priv = gobj.priv;
|
|
69091
|
+
let node_id = kw && kw.node_id || "";
|
|
69092
|
+
if (!priv._node_detail_el || !node_id || node_id !== priv._detail_node_id) {
|
|
69093
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} for '${node_id}', but the detail popover shows '${priv._detail_node_id || ""}'`);
|
|
69094
|
+
return -1;
|
|
69095
|
+
}
|
|
69096
|
+
hide_node_detail(gobj);
|
|
69097
|
+
return 0;
|
|
69098
|
+
}
|
|
69099
|
+
/************************************************************
|
|
69100
|
+
* {} -- the create button of the edit toolbar: the create
|
|
69101
|
+
* popover, opened or closed. Only in edition, where that
|
|
69102
|
+
* toolbar is.
|
|
69103
|
+
************************************************************/
|
|
69104
|
+
function ac_toggle_create_popover(gobj, event, kw, src) {
|
|
69105
|
+
if (!gobj.priv.edit_mode) {
|
|
69106
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} outside edition`);
|
|
69107
|
+
return -1;
|
|
69108
|
+
}
|
|
69109
|
+
toggle_create_popover(gobj);
|
|
69110
|
+
return 0;
|
|
69111
|
+
}
|
|
69112
|
+
/************************************************************
|
|
69113
|
+
* {} -- the cancel of the create popover, or Escape in its id.
|
|
69114
|
+
************************************************************/
|
|
69115
|
+
function ac_close_create_popover(gobj, event, kw, src) {
|
|
69116
|
+
if (!gobj.priv._create_popover_el) {
|
|
69117
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no create popover open`);
|
|
69118
|
+
return -1;
|
|
69119
|
+
}
|
|
69120
|
+
hide_create_popover(gobj);
|
|
69121
|
+
return 0;
|
|
69122
|
+
}
|
|
69123
|
+
/************************************************************
|
|
68561
69124
|
* {topic_name, id} -- the create popover was filled in.
|
|
69125
|
+
*
|
|
69126
|
+
* An empty id with the popover open is the person's to fix,
|
|
69127
|
+
* not a fault: it is said IN the popover, where they typed.
|
|
68562
69128
|
************************************************************/
|
|
68563
69129
|
function ac_submit_new_node(gobj, event, kw, src) {
|
|
68564
|
-
let
|
|
68565
|
-
let
|
|
69130
|
+
let priv = gobj.priv;
|
|
69131
|
+
let topic_name = kw && kw.topic_name ? String(kw.topic_name) : "";
|
|
69132
|
+
let node_id = kw && kw.id ? String(kw.id).trim() : "";
|
|
69133
|
+
if (topic_name && !node_id && priv._create_popover_el) {
|
|
69134
|
+
say_node_id_required(gobj);
|
|
69135
|
+
return 0;
|
|
69136
|
+
}
|
|
68566
69137
|
if (!topic_name || !node_id) {
|
|
68567
69138
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} without topic or id`);
|
|
68568
69139
|
return -1;
|
|
@@ -68570,6 +69141,168 @@ function ac_submit_new_node(gobj, event, kw, src) {
|
|
|
68570
69141
|
execute_create_node(gobj, topic_name, node_id);
|
|
68571
69142
|
return 0;
|
|
68572
69143
|
}
|
|
69144
|
+
function say_node_id_required(gobj) {
|
|
69145
|
+
let $popover = gobj.priv._create_popover_el;
|
|
69146
|
+
let $error = $popover.querySelector(".G6_CREATE_ERROR");
|
|
69147
|
+
let $id = $popover.querySelector(".G6_CREATE_ID");
|
|
69148
|
+
if (!$error || !$id) {
|
|
69149
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: the create popover has no id or no error line`);
|
|
69150
|
+
return;
|
|
69151
|
+
}
|
|
69152
|
+
$error.textContent = (0, i18next.t)("node id required");
|
|
69153
|
+
$error.setAttribute("data-i18n", "node id required");
|
|
69154
|
+
$error.style.display = "block";
|
|
69155
|
+
$id.focus();
|
|
69156
|
+
}
|
|
69157
|
+
/************************************************************
|
|
69158
|
+
* Is `popover_key` open, and for the selection `kw` names?
|
|
69159
|
+
* `keys` are the identity in `kw` (the rest is what the form
|
|
69160
|
+
* held). A button of a popover that is not the one open is a
|
|
69161
|
+
* broken invariant -- said loudly, never acted on.
|
|
69162
|
+
************************************************************/
|
|
69163
|
+
function popover_is_current(gobj, event, kw, popover_key, keys) {
|
|
69164
|
+
if (!gobj.priv[popover_key]) {
|
|
69165
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but its popover is not open`);
|
|
69166
|
+
return false;
|
|
69167
|
+
}
|
|
69168
|
+
let identity = {};
|
|
69169
|
+
for (let k of keys) identity[k] = kw ? kw[k] : void 0;
|
|
69170
|
+
return floating_button_is_current(gobj, event, identity);
|
|
69171
|
+
}
|
|
69172
|
+
/************************************************************
|
|
69173
|
+
* {node_id, shape_before, fill, stroke, line_width, scope,
|
|
69174
|
+
* shape} -- apply of the node popover.
|
|
69175
|
+
************************************************************/
|
|
69176
|
+
function ac_apply_node_popover(gobj, event, kw, src) {
|
|
69177
|
+
if (!popover_is_current(gobj, event, kw, "_node_popover_el", ["node_id"])) return -1;
|
|
69178
|
+
let shape = String(kw.shape || "");
|
|
69179
|
+
drop_preview_undo(gobj, "_node_preview_undo");
|
|
69180
|
+
apply_node_properties(gobj, kw.node_id, kw.fill, kw.stroke, parseInt(kw.line_width) || 1, kw.scope, shape !== kw.shape_before ? shape : "");
|
|
69181
|
+
return 0;
|
|
69182
|
+
}
|
|
69183
|
+
/************************************************************
|
|
69184
|
+
* {node_id} -- cancel of the node popover, which undoes the
|
|
69185
|
+
* preview.
|
|
69186
|
+
************************************************************/
|
|
69187
|
+
function ac_cancel_node_popover(gobj, event, kw, src) {
|
|
69188
|
+
if (!popover_is_current(gobj, event, kw, "_node_popover_el", ["node_id"])) return -1;
|
|
69189
|
+
hide_node_popover(gobj);
|
|
69190
|
+
return 0;
|
|
69191
|
+
}
|
|
69192
|
+
/************************************************************
|
|
69193
|
+
* {edge_id, line_width, color, scope} -- apply of the edge
|
|
69194
|
+
* popover.
|
|
69195
|
+
************************************************************/
|
|
69196
|
+
function ac_apply_edge_popover(gobj, event, kw, src) {
|
|
69197
|
+
if (!popover_is_current(gobj, event, kw, "_edge_popover_el", ["edge_id"])) return -1;
|
|
69198
|
+
drop_preview_undo(gobj, "_edge_preview_undo");
|
|
69199
|
+
apply_edge_properties(gobj, kw.edge_id, parseInt(kw.line_width) || 2, kw.color, kw.scope);
|
|
69200
|
+
return 0;
|
|
69201
|
+
}
|
|
69202
|
+
/************************************************************
|
|
69203
|
+
* {edge_id} -- cancel of the edge popover: the edge is let go,
|
|
69204
|
+
* which undoes the preview.
|
|
69205
|
+
************************************************************/
|
|
69206
|
+
function ac_cancel_edge_popover(gobj, event, kw, src) {
|
|
69207
|
+
if (!popover_is_current(gobj, event, kw, "_edge_popover_el", ["edge_id"])) return -1;
|
|
69208
|
+
deselect_edge(gobj);
|
|
69209
|
+
return 0;
|
|
69210
|
+
}
|
|
69211
|
+
/************************************************************
|
|
69212
|
+
* {node_id, port_key, r_before, shape, r, scope} -- apply of
|
|
69213
|
+
* the port popover.
|
|
69214
|
+
************************************************************/
|
|
69215
|
+
function ac_apply_port_popover(gobj, event, kw, src) {
|
|
69216
|
+
if (!popover_is_current(gobj, event, kw, "_port_popover_el", ["node_id", "port_key"])) return -1;
|
|
69217
|
+
drop_preview_undo(gobj, "_port_preview_undo");
|
|
69218
|
+
apply_port_properties(gobj, kw.node_id, kw.port_key, kw.shape, parseInt(kw.r) || kw.r_before, kw.scope);
|
|
69219
|
+
return 0;
|
|
69220
|
+
}
|
|
69221
|
+
/************************************************************
|
|
69222
|
+
* {node_id, port_key} -- cancel of the port popover, which
|
|
69223
|
+
* undoes the preview.
|
|
69224
|
+
************************************************************/
|
|
69225
|
+
function ac_cancel_port_popover(gobj, event, kw, src) {
|
|
69226
|
+
if (!popover_is_current(gobj, event, kw, "_port_popover_el", ["node_id", "port_key"])) return -1;
|
|
69227
|
+
hide_port_popover(gobj);
|
|
69228
|
+
return 0;
|
|
69229
|
+
}
|
|
69230
|
+
var CONFIRM_POPOVER_OF = {
|
|
69231
|
+
delete_selection: "_delete_confirm_el",
|
|
69232
|
+
delete_node: "_delete_confirm_el",
|
|
69233
|
+
unlink_edge: "_unlink_confirm_el"
|
|
69234
|
+
};
|
|
69235
|
+
function same_question(a, b) {
|
|
69236
|
+
return !!a && !!b && a.what === b.what && JSON.stringify(a.id ?? null) === JSON.stringify(b.id ?? null) && JSON.stringify(a.ids ?? null) === JSON.stringify(b.ids ?? null);
|
|
69237
|
+
}
|
|
69238
|
+
/************************************************************
|
|
69239
|
+
* {what, id|ids} -- the person said no in a confirm popover:
|
|
69240
|
+
* the question it carries must be the one open.
|
|
69241
|
+
************************************************************/
|
|
69242
|
+
function ac_cancel_confirm(gobj, event, kw, src) {
|
|
69243
|
+
let priv = gobj.priv;
|
|
69244
|
+
let key = CONFIRM_POPOVER_OF[kw && kw.what || ""];
|
|
69245
|
+
let asked = key ? priv._confirm_questions[key] : null;
|
|
69246
|
+
if (!key || !priv[key] || !same_question(asked, kw)) {
|
|
69247
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but the question open is ${JSON.stringify(priv[key] && asked || {})}`);
|
|
69248
|
+
return -1;
|
|
69249
|
+
}
|
|
69250
|
+
hide_overlay(gobj, key);
|
|
69251
|
+
return 0;
|
|
69252
|
+
}
|
|
69253
|
+
/************************************************************
|
|
69254
|
+
* {node_id, port_key, client_x, client_y} -- a press on the
|
|
69255
|
+
* link icon of the selected fkey port, which may be a drag.
|
|
69256
|
+
************************************************************/
|
|
69257
|
+
function ac_start_link_drag(gobj, event, kw, src) {
|
|
69258
|
+
let priv = gobj.priv;
|
|
69259
|
+
if (!floating_button_is_current(gobj, event, {
|
|
69260
|
+
node_id: kw && kw.node_id,
|
|
69261
|
+
port_key: kw && kw.port_key
|
|
69262
|
+
})) return -1;
|
|
69263
|
+
if (priv._link_drag) {
|
|
69264
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with a link drag still in flight`);
|
|
69265
|
+
end_link_drag(gobj);
|
|
69266
|
+
}
|
|
69267
|
+
start_link_drag(gobj, Number(kw.client_x) || 0, Number(kw.client_y) || 0);
|
|
69268
|
+
return 0;
|
|
69269
|
+
}
|
|
69270
|
+
/************************************************************
|
|
69271
|
+
* {client_x, client_y, dragged} -- the pointer of a link drag
|
|
69272
|
+
* went up. Not dragged, it was a click: the click comes next
|
|
69273
|
+
* (EV_ENTER_LINKING_MODE). Dragged, it links to the hook it was
|
|
69274
|
+
* dropped on, or leaves the linking mode.
|
|
69275
|
+
************************************************************/
|
|
69276
|
+
function ac_link_drag_end(gobj, event, kw, src) {
|
|
69277
|
+
let priv = gobj.priv;
|
|
69278
|
+
let drag = priv._link_drag;
|
|
69279
|
+
if (!drag) {
|
|
69280
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no link drag in flight`);
|
|
69281
|
+
return -1;
|
|
69282
|
+
}
|
|
69283
|
+
end_link_drag(gobj);
|
|
69284
|
+
if (!kw || !kw.dragged) return 0;
|
|
69285
|
+
let cx = Number(kw.client_x) - drag.left;
|
|
69286
|
+
let cy = Number(kw.client_y) - drag.top;
|
|
69287
|
+
let canvasPt = priv.graph.getCanvasByViewport([cx, cy]);
|
|
69288
|
+
let target = find_hook_at_point(gobj, canvasPt[0], canvasPt[1]);
|
|
69289
|
+
if (target) try_complete_link(gobj, target.node_id, target.port_key);
|
|
69290
|
+
else exit_linking_mode(gobj);
|
|
69291
|
+
return 0;
|
|
69292
|
+
}
|
|
69293
|
+
/************************************************************
|
|
69294
|
+
* {} -- the browser took the pointer of a link drag: no drop,
|
|
69295
|
+
* and the linking mode goes.
|
|
69296
|
+
************************************************************/
|
|
69297
|
+
function ac_link_drag_cancel(gobj, event, kw, src) {
|
|
69298
|
+
if (!gobj.priv._link_drag) {
|
|
69299
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: ${event} with no link drag in flight`);
|
|
69300
|
+
return -1;
|
|
69301
|
+
}
|
|
69302
|
+
end_link_drag(gobj);
|
|
69303
|
+
exit_linking_mode(gobj);
|
|
69304
|
+
return 0;
|
|
69305
|
+
}
|
|
68573
69306
|
/************************************************************
|
|
68574
69307
|
* {what, id|ids} -- the person said yes in a confirm popover.
|
|
68575
69308
|
*
|
|
@@ -68826,16 +69559,101 @@ function create_gclass$4(gclass_name) {
|
|
|
68826
69559
|
ac_request_unlink_edge,
|
|
68827
69560
|
null
|
|
68828
69561
|
],
|
|
69562
|
+
[
|
|
69563
|
+
"EV_TOGGLE_NODE_POPOVER",
|
|
69564
|
+
ac_toggle_node_popover,
|
|
69565
|
+
null
|
|
69566
|
+
],
|
|
69567
|
+
[
|
|
69568
|
+
"EV_TOGGLE_EDGE_POPOVER",
|
|
69569
|
+
ac_toggle_edge_popover,
|
|
69570
|
+
null
|
|
69571
|
+
],
|
|
69572
|
+
[
|
|
69573
|
+
"EV_TOGGLE_PORT_POPOVER",
|
|
69574
|
+
ac_toggle_port_popover,
|
|
69575
|
+
null
|
|
69576
|
+
],
|
|
69577
|
+
[
|
|
69578
|
+
"EV_ENTER_LINKING_MODE",
|
|
69579
|
+
ac_enter_linking_mode,
|
|
69580
|
+
null
|
|
69581
|
+
],
|
|
69582
|
+
[
|
|
69583
|
+
"EV_CLOSE_NODE_DETAIL",
|
|
69584
|
+
ac_close_node_detail,
|
|
69585
|
+
null
|
|
69586
|
+
],
|
|
69587
|
+
[
|
|
69588
|
+
"EV_TOGGLE_CREATE_POPOVER",
|
|
69589
|
+
ac_toggle_create_popover,
|
|
69590
|
+
null
|
|
69591
|
+
],
|
|
69592
|
+
[
|
|
69593
|
+
"EV_CLOSE_CREATE_POPOVER",
|
|
69594
|
+
ac_close_create_popover,
|
|
69595
|
+
null
|
|
69596
|
+
],
|
|
68829
69597
|
[
|
|
68830
69598
|
"EV_SUBMIT_NEW_NODE",
|
|
68831
69599
|
ac_submit_new_node,
|
|
68832
69600
|
null
|
|
68833
69601
|
],
|
|
69602
|
+
[
|
|
69603
|
+
"EV_APPLY_NODE_POPOVER",
|
|
69604
|
+
ac_apply_node_popover,
|
|
69605
|
+
null
|
|
69606
|
+
],
|
|
69607
|
+
[
|
|
69608
|
+
"EV_CANCEL_NODE_POPOVER",
|
|
69609
|
+
ac_cancel_node_popover,
|
|
69610
|
+
null
|
|
69611
|
+
],
|
|
69612
|
+
[
|
|
69613
|
+
"EV_APPLY_EDGE_POPOVER",
|
|
69614
|
+
ac_apply_edge_popover,
|
|
69615
|
+
null
|
|
69616
|
+
],
|
|
69617
|
+
[
|
|
69618
|
+
"EV_CANCEL_EDGE_POPOVER",
|
|
69619
|
+
ac_cancel_edge_popover,
|
|
69620
|
+
null
|
|
69621
|
+
],
|
|
69622
|
+
[
|
|
69623
|
+
"EV_APPLY_PORT_POPOVER",
|
|
69624
|
+
ac_apply_port_popover,
|
|
69625
|
+
null
|
|
69626
|
+
],
|
|
69627
|
+
[
|
|
69628
|
+
"EV_CANCEL_PORT_POPOVER",
|
|
69629
|
+
ac_cancel_port_popover,
|
|
69630
|
+
null
|
|
69631
|
+
],
|
|
68834
69632
|
[
|
|
68835
69633
|
"EV_CONFIRMED",
|
|
68836
69634
|
ac_confirmed$1,
|
|
68837
69635
|
null
|
|
68838
69636
|
],
|
|
69637
|
+
[
|
|
69638
|
+
"EV_CANCEL_CONFIRM",
|
|
69639
|
+
ac_cancel_confirm,
|
|
69640
|
+
null
|
|
69641
|
+
],
|
|
69642
|
+
[
|
|
69643
|
+
"EV_START_LINK_DRAG",
|
|
69644
|
+
ac_start_link_drag,
|
|
69645
|
+
null
|
|
69646
|
+
],
|
|
69647
|
+
[
|
|
69648
|
+
"EV_LINK_DRAG_END",
|
|
69649
|
+
ac_link_drag_end,
|
|
69650
|
+
null
|
|
69651
|
+
],
|
|
69652
|
+
[
|
|
69653
|
+
"EV_LINK_DRAG_CANCEL",
|
|
69654
|
+
ac_link_drag_cancel,
|
|
69655
|
+
null
|
|
69656
|
+
],
|
|
68839
69657
|
[
|
|
68840
69658
|
"EV_CANVAS_CLICK",
|
|
68841
69659
|
ac_canvas_click,
|
|
@@ -69056,8 +69874,25 @@ function create_gclass$4(gclass_name) {
|
|
|
69056
69874
|
["EV_CONTEXT_MENU_ITEM", 0],
|
|
69057
69875
|
["EV_REQUEST_DELETE_NODE", 0],
|
|
69058
69876
|
["EV_REQUEST_UNLINK_EDGE", 0],
|
|
69877
|
+
["EV_TOGGLE_NODE_POPOVER", 0],
|
|
69878
|
+
["EV_TOGGLE_EDGE_POPOVER", 0],
|
|
69879
|
+
["EV_TOGGLE_PORT_POPOVER", 0],
|
|
69880
|
+
["EV_ENTER_LINKING_MODE", 0],
|
|
69881
|
+
["EV_CLOSE_NODE_DETAIL", 0],
|
|
69882
|
+
["EV_TOGGLE_CREATE_POPOVER", 0],
|
|
69883
|
+
["EV_CLOSE_CREATE_POPOVER", 0],
|
|
69059
69884
|
["EV_SUBMIT_NEW_NODE", 0],
|
|
69885
|
+
["EV_APPLY_NODE_POPOVER", 0],
|
|
69886
|
+
["EV_CANCEL_NODE_POPOVER", 0],
|
|
69887
|
+
["EV_APPLY_EDGE_POPOVER", 0],
|
|
69888
|
+
["EV_CANCEL_EDGE_POPOVER", 0],
|
|
69889
|
+
["EV_APPLY_PORT_POPOVER", 0],
|
|
69890
|
+
["EV_CANCEL_PORT_POPOVER", 0],
|
|
69060
69891
|
["EV_CONFIRMED", 0],
|
|
69892
|
+
["EV_CANCEL_CONFIRM", 0],
|
|
69893
|
+
["EV_START_LINK_DRAG", 0],
|
|
69894
|
+
["EV_LINK_DRAG_END", 0],
|
|
69895
|
+
["EV_LINK_DRAG_CANCEL", 0],
|
|
69061
69896
|
["EV_CANVAS_CLICK", 0],
|
|
69062
69897
|
["EV_NODE_DRAG_END", 0],
|
|
69063
69898
|
["EV_BRUSH_SELECT", 0],
|
|
@@ -69407,7 +70242,7 @@ function show_load_error(gobj, message) {
|
|
|
69407
70242
|
$container.insertBefore($err, $container.firstChild);
|
|
69408
70243
|
}
|
|
69409
70244
|
let treedb = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "treedb_name") || "";
|
|
69410
|
-
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
|
|
70245
|
+
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || (0, i18next.t)("cannot load treedb"));
|
|
69411
70246
|
}
|
|
69412
70247
|
/************************************************************
|
|
69413
70248
|
* Destroy UI
|
|
@@ -71092,7 +71927,7 @@ function refresh_legend(gobj) {
|
|
|
71092
71927
|
},
|
|
71093
71928
|
hidden ? `${entry.total}` : `${entry.visible}/${entry.total}`
|
|
71094
71929
|
]);
|
|
71095
|
-
|
|
71930
|
+
const body_key = is_main ? "main topic" : hidden ? "show topic" : "hide topic";
|
|
71096
71931
|
let body_attrs = {
|
|
71097
71932
|
class: "GRAPH_LEGEND_ITEM button" + (focused ? " GRAPH_LEGEND_FOCUSED" : "") + (is_main ? " GRAPH_LEGEND_MAIN" : ""),
|
|
71098
71933
|
type: "button",
|
|
@@ -72352,6 +73187,7 @@ function build_graph(gobj) {
|
|
|
72352
73187
|
}
|
|
72353
73188
|
priv.graph = graph;
|
|
72354
73189
|
graph.setTheme(dark ? "dark" : "light");
|
|
73190
|
+
keep_canvas_tab_order(gobj, graph);
|
|
72355
73191
|
graph.on("aftertransform", () => {
|
|
72356
73192
|
yui_graph_update_zoom($container, priv.graph);
|
|
72357
73193
|
});
|
|
@@ -77665,7 +78501,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
77665
78501
|
}
|
|
77666
78502
|
return late_write_done(gobj, command, topic_name, data);
|
|
77667
78503
|
}
|
|
77668
|
-
if (result < 0) return end_writes(gobj, comment ||
|
|
78504
|
+
if (result < 0) return end_writes(gobj, comment || "the treedb refused the write");
|
|
77669
78505
|
priv.save_wrote = true;
|
|
77670
78506
|
let record = null;
|
|
77671
78507
|
if (command === "delete-node") forget_record(gobj, topic_name, (0, _yuneta_gobj_js.kw_get_str)(gobj, md, "record_id", "", 0));
|
|
@@ -78181,7 +79017,8 @@ function confirm_column_delete(gobj, verdict) {
|
|
|
78181
79017
|
capped: "the records read hold no value in this column, but not all were read: the rest may hold values that no reader will show any more",
|
|
78182
79018
|
unknown: "the records of this topic could not be read: if they hold values in this column, they keep them, but no reader shows them any more"
|
|
78183
79019
|
};
|
|
78184
|
-
|
|
79020
|
+
const message = "delete this column?";
|
|
79021
|
+
let $warning = null;
|
|
78185
79022
|
if (NOTES[verdict]) {
|
|
78186
79023
|
let children = [[
|
|
78187
79024
|
"p",
|
|
@@ -78211,13 +79048,13 @@ function confirm_column_delete(gobj, verdict) {
|
|
|
78211
79048
|
String(c.scanned)
|
|
78212
79049
|
]]
|
|
78213
79050
|
]);
|
|
78214
|
-
|
|
79051
|
+
$warning = (0, _yuneta_gobj_js.createElement2)([
|
|
78215
79052
|
"div",
|
|
78216
79053
|
{ class: "SCHEMA_COLUMN_DATA_WARNING" },
|
|
78217
79054
|
children
|
|
78218
79055
|
]);
|
|
78219
79056
|
}
|
|
78220
|
-
confirm_then(gobj, message, `${c.topic}.${c.col}`, {
|
|
79057
|
+
confirm_then(gobj, $warning ? $warning : message, `${c.topic}.${c.col}`, {
|
|
78221
79058
|
what: "column",
|
|
78222
79059
|
topic: c.topic,
|
|
78223
79060
|
col: c.col
|
|
@@ -81782,7 +82619,9 @@ function build_control_bar() {
|
|
|
81782
82619
|
type: "button",
|
|
81783
82620
|
title: (0, i18next.t)("machine trace shape"),
|
|
81784
82621
|
"data-i18n-title": "machine trace shape",
|
|
81785
|
-
"data-i18n": "simple mach"
|
|
82622
|
+
"data-i18n": "simple mach",
|
|
82623
|
+
"aria-label": (0, i18next.t)("simple mach"),
|
|
82624
|
+
"data-i18n-aria-label": "simple mach"
|
|
81786
82625
|
},
|
|
81787
82626
|
(0, i18next.t)("simple mach"),
|
|
81788
82627
|
{ click: (ev) => {
|
|
@@ -81856,7 +82695,9 @@ function build_control_bar() {
|
|
|
81856
82695
|
type: "button",
|
|
81857
82696
|
title: (0, i18next.t)(OUT_TITLES[v]),
|
|
81858
82697
|
"data-i18n-title": OUT_TITLES[v],
|
|
81859
|
-
"data-i18n": label
|
|
82698
|
+
"data-i18n": label,
|
|
82699
|
+
"aria-label": (0, i18next.t)(label),
|
|
82700
|
+
"data-i18n-aria-label": label
|
|
81860
82701
|
},
|
|
81861
82702
|
(0, i18next.t)(label),
|
|
81862
82703
|
{ click: (ev) => {
|
|
@@ -81884,7 +82725,9 @@ function build_control_bar() {
|
|
|
81884
82725
|
type: "button",
|
|
81885
82726
|
title: (0, i18next.t)("show this section in the expanded view"),
|
|
81886
82727
|
"data-i18n-title": "show this section in the expanded view",
|
|
81887
|
-
"data-i18n": label
|
|
82728
|
+
"data-i18n": label,
|
|
82729
|
+
"aria-label": (0, i18next.t)(label),
|
|
82730
|
+
"data-i18n-aria-label": label
|
|
81888
82731
|
},
|
|
81889
82732
|
(0, i18next.t)(label),
|
|
81890
82733
|
{ click: (ev) => {
|
|
@@ -81983,7 +82826,9 @@ function build_control_bar() {
|
|
|
81983
82826
|
type: "button",
|
|
81984
82827
|
title: (0, i18next.t)("copy visible traffic to clipboard"),
|
|
81985
82828
|
"data-i18n-title": "copy visible traffic to clipboard",
|
|
81986
|
-
"data-i18n": "copy"
|
|
82829
|
+
"data-i18n": "copy",
|
|
82830
|
+
"aria-label": (0, i18next.t)("copy"),
|
|
82831
|
+
"data-i18n-aria-label": "copy"
|
|
81987
82832
|
},
|
|
81988
82833
|
(0, i18next.t)("copy"),
|
|
81989
82834
|
{ click: (ev) => {
|
|
@@ -82005,7 +82850,9 @@ function build_control_bar() {
|
|
|
82005
82850
|
type: "button",
|
|
82006
82851
|
title: (0, i18next.t)("clear captured traffic"),
|
|
82007
82852
|
"data-i18n-title": "clear captured traffic",
|
|
82008
|
-
"data-i18n": "clear"
|
|
82853
|
+
"data-i18n": "clear",
|
|
82854
|
+
"aria-label": (0, i18next.t)("clear"),
|
|
82855
|
+
"data-i18n-aria-label": "clear"
|
|
82009
82856
|
},
|
|
82010
82857
|
(0, i18next.t)("clear"),
|
|
82011
82858
|
{ click: (ev) => {
|