@yuneta/gobj-ui 7.26.26 → 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 +473 -19
- package/dist/gobj-ui.cjs.js +1100 -231
- package/dist/gobj-ui.es.js +1101 -232
- package/package.json +1 -1
- package/scripts/validate-locales.mjs +2334 -275
- package/src/c_g6_nodes_tree.js +1143 -260
- 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 +275 -0
- 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 +44 -33
- 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.es.js
CHANGED
|
@@ -5,7 +5,7 @@ import { createJSONEditor } from "vanilla-jsoneditor";
|
|
|
5
5
|
import { TabulatorFull } from "tabulator-tables";
|
|
6
6
|
import * as maplibregl from "maplibre-gl";
|
|
7
7
|
import uPlot from "uplot";
|
|
8
|
-
import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, DragCanvas, EdgeEvent, ExtensionCategory, Graph, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
|
|
8
|
+
import { BaseLayout, BrushSelect, CanvasEvent, Circle, CommonEvent, DragCanvas, EdgeEvent, ExtensionCategory, Graph, GraphEvent, HTML, HistoryEvent, NodeEvent, Polyline, Toolbar, ZoomCanvas, register } from "@antv/g6";
|
|
9
9
|
//#region \0rolldown/runtime.js
|
|
10
10
|
var __create = Object.create;
|
|
11
11
|
var __defProp = Object.defineProperty;
|
|
@@ -1843,7 +1843,7 @@ function build_toolbar$1(gobj, config) {
|
|
|
1843
1843
|
}
|
|
1844
1844
|
priv.avatar_nodes = [];
|
|
1845
1845
|
priv.conn_nodes = [];
|
|
1846
|
-
|
|
1846
|
+
const toolbar_aria = tb.aria_label || "toolbar";
|
|
1847
1847
|
let $bar = createElement2([
|
|
1848
1848
|
"nav",
|
|
1849
1849
|
{
|
|
@@ -2054,8 +2054,8 @@ function build_toolbar_brand_item(gobj, it) {
|
|
|
2054
2054
|
************************************************************/
|
|
2055
2055
|
function build_toolbar_avatar_item(gobj, it) {
|
|
2056
2056
|
let priv = gobj.priv;
|
|
2057
|
-
|
|
2058
|
-
|
|
2057
|
+
const aria_key = it.aria_label || it.name || it.id || "user menu";
|
|
2058
|
+
const i18n_aria = it.aria_label || it.name || "user menu";
|
|
2059
2059
|
let action_type = it.action && it.action.type || "";
|
|
2060
2060
|
let attrs = {
|
|
2061
2061
|
class: "navbar-item yui-toolbar-item yui-toolbar-avatar is-unselectable",
|
|
@@ -2131,8 +2131,8 @@ function attach_context_action(gobj, $item, it) {
|
|
|
2131
2131
|
************************************************************/
|
|
2132
2132
|
function build_toolbar_connection_item(gobj, it) {
|
|
2133
2133
|
let priv = gobj.priv;
|
|
2134
|
-
|
|
2135
|
-
|
|
2134
|
+
const aria_key = it.aria_label || it.name || it.id || "backend connection";
|
|
2135
|
+
const i18n_aria = it.aria_label || it.name || "backend connection";
|
|
2136
2136
|
let attrs = {
|
|
2137
2137
|
class: "navbar-item yui-toolbar-item yui-toolbar-conn is-unselectable is-disconnected",
|
|
2138
2138
|
type: "button",
|
|
@@ -2238,8 +2238,8 @@ function toggle_toolbar_dropdown(gobj, item, action, $trigger) {
|
|
|
2238
2238
|
function open_toolbar_dropdown(gobj, item, action, $trigger) {
|
|
2239
2239
|
let priv = gobj.priv;
|
|
2240
2240
|
if (!priv || !priv.layers || !priv.layers.popup) return;
|
|
2241
|
-
|
|
2242
|
-
|
|
2241
|
+
const aria_key = item && (item.aria_label || item.name || item.id) || "menu";
|
|
2242
|
+
const i18n_aria = item && (item.aria_label || item.name) || "menu";
|
|
2243
2243
|
let $panel = createElement2(["div", {
|
|
2244
2244
|
class: "yui-toolbar-dropdown-panel",
|
|
2245
2245
|
role: "menu",
|
|
@@ -3776,19 +3776,22 @@ function build_dialog(shell, message, buttons, opts) {
|
|
|
3776
3776
|
* "Delete" and "Cancel", keys that no locale carries, so a dialog
|
|
3777
3777
|
* that took the defaults read in English in every language.
|
|
3778
3778
|
*
|
|
3779
|
-
*
|
|
3780
|
-
* consumer
|
|
3781
|
-
*
|
|
3779
|
+
* An app that mounts these dialogs must define the five keys. A
|
|
3780
|
+
* consumer's validate-locales reads them where build_dialog() gets
|
|
3781
|
+
* them (a const, `DEFAULT_LABEL.ok`, it follows), and in
|
|
3782
|
+
* SHELL_MODALS_I18N_KEYS, which a test holds to this table. (Up to
|
|
3783
|
+
* 7.26.27 they were written as `i18n:` entries, which only a regex
|
|
3784
|
+
* scan of `i18n: "..."` happened to see.)
|
|
3782
3785
|
***************************************************************/
|
|
3783
3786
|
var DEFAULT_LABEL = Object.freeze({
|
|
3784
|
-
ok:
|
|
3785
|
-
yes:
|
|
3786
|
-
no:
|
|
3787
|
-
delete:
|
|
3788
|
-
cancel:
|
|
3787
|
+
ok: "ok",
|
|
3788
|
+
yes: "yes",
|
|
3789
|
+
no: "no",
|
|
3790
|
+
delete: "delete",
|
|
3791
|
+
cancel: "cancel"
|
|
3789
3792
|
});
|
|
3790
3793
|
function yui_shell_confirm_ok(shell, message, opts) {
|
|
3791
|
-
|
|
3794
|
+
const label = opts && opts.ok_label || DEFAULT_LABEL.ok;
|
|
3792
3795
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "success" });
|
|
3793
3796
|
return build_dialog(shell, message, [{
|
|
3794
3797
|
label,
|
|
@@ -3797,8 +3800,8 @@ function yui_shell_confirm_ok(shell, message, opts) {
|
|
|
3797
3800
|
}], opts).then(() => void 0);
|
|
3798
3801
|
}
|
|
3799
3802
|
function yui_shell_confirm_yesno(shell, message, opts) {
|
|
3800
|
-
|
|
3801
|
-
|
|
3803
|
+
const yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes;
|
|
3804
|
+
const no_label = opts && opts.no_label || DEFAULT_LABEL.no;
|
|
3802
3805
|
return build_dialog(shell, message, [{
|
|
3803
3806
|
label: yes_label,
|
|
3804
3807
|
value: "yes",
|
|
@@ -3823,8 +3826,8 @@ function yui_shell_confirm_yesno(shell, message, opts) {
|
|
|
3823
3826
|
* pressed.
|
|
3824
3827
|
***************************************************************/
|
|
3825
3828
|
function yui_shell_confirm_danger(shell, message, opts) {
|
|
3826
|
-
|
|
3827
|
-
|
|
3829
|
+
const confirm_label = opts && opts.confirm_label || DEFAULT_LABEL.delete;
|
|
3830
|
+
const cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel;
|
|
3828
3831
|
if (!opts || !opts.type) opts = Object.assign({}, opts, { type: "danger" });
|
|
3829
3832
|
return build_dialog(shell, message, [{
|
|
3830
3833
|
label: confirm_label,
|
|
@@ -3836,9 +3839,9 @@ function yui_shell_confirm_danger(shell, message, opts) {
|
|
|
3836
3839
|
}], opts).then((v) => v === "confirm");
|
|
3837
3840
|
}
|
|
3838
3841
|
function yui_shell_confirm_yesnocancel(shell, message, opts) {
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
+
const yes_label = opts && opts.yes_label || DEFAULT_LABEL.yes;
|
|
3843
|
+
const no_label = opts && opts.no_label || DEFAULT_LABEL.no;
|
|
3844
|
+
const cancel_label = opts && opts.cancel_label || DEFAULT_LABEL.cancel;
|
|
3842
3845
|
return build_dialog(shell, message, [
|
|
3843
3846
|
{
|
|
3844
3847
|
label: yes_label,
|
|
@@ -4492,7 +4495,7 @@ function set_max_icon(gobj, maximized) {
|
|
|
4492
4495
|
if (!$container) return;
|
|
4493
4496
|
let $btn = $container.querySelector(".wc-max");
|
|
4494
4497
|
if ($btn) {
|
|
4495
|
-
|
|
4498
|
+
const key = maximized ? "restore" : "maximize";
|
|
4496
4499
|
$btn.innerHTML = maximized ? WC_RESTORE : WC_MAX;
|
|
4497
4500
|
$btn.setAttribute("title", t(key));
|
|
4498
4501
|
$btn.setAttribute("data-i18n-title", key);
|
|
@@ -5594,7 +5597,7 @@ function render_header(gobj) {
|
|
|
5594
5597
|
let $discard = $container.querySelector(".yui-pager-discard");
|
|
5595
5598
|
$back.classList.toggle("is-hidden", !model.show_back);
|
|
5596
5599
|
let $back_icon = $back.querySelector("i");
|
|
5597
|
-
|
|
5600
|
+
const back_key = model.back_kind === "close" ? "close" : "back";
|
|
5598
5601
|
$back_icon.className = back_key === "close" ? "yi-xmark" : "yi-arrow-left";
|
|
5599
5602
|
$back.setAttribute("title", t(back_key));
|
|
5600
5603
|
$back.setAttribute("data-i18n-title", back_key);
|
|
@@ -8983,7 +8986,7 @@ function destroy_widgets(gobj, $container) {
|
|
|
8983
8986
|
* ids would break the association for both. The key is the
|
|
8984
8987
|
* label's own, so a language change reaches it.
|
|
8985
8988
|
************************************************************/
|
|
8986
|
-
function name_form_control($field, conf) {
|
|
8989
|
+
function name_form_control$1($field, conf) {
|
|
8987
8990
|
if (!$field || typeof $field.querySelector !== "function" || !conf) return;
|
|
8988
8991
|
let key = conf.label_i18n || conf.label || "";
|
|
8989
8992
|
if (!key) return;
|
|
@@ -9054,7 +9057,7 @@ function build_html_form(gobj, $form, prefix, template) {
|
|
|
9054
9057
|
if (placeholders[key]) html_field_conf.placeholder = placeholders[key];
|
|
9055
9058
|
if (html_field_conf.tag) {
|
|
9056
9059
|
let $field = create_form_field(gobj, $form, prefix, field_desc, html_field_conf);
|
|
9057
|
-
name_form_control($field, html_field_conf);
|
|
9060
|
+
name_form_control$1($field, html_field_conf);
|
|
9058
9061
|
$form.appendChild($field);
|
|
9059
9062
|
}
|
|
9060
9063
|
});
|
|
@@ -12749,7 +12752,7 @@ function set_pressed_state($container, selector, set) {
|
|
|
12749
12752
|
*
|
|
12750
12753
|
* Utilities for graph, using Bulma
|
|
12751
12754
|
*
|
|
12752
|
-
* Copyright (c) 2025, ArtGins.
|
|
12755
|
+
* Copyright (c) 2025-2026, ArtGins.
|
|
12753
12756
|
* All Rights Reserved.
|
|
12754
12757
|
***********************************************************************/
|
|
12755
12758
|
/************************************************************
|
|
@@ -12778,15 +12781,46 @@ function removeChildElements($element) {
|
|
|
12778
12781
|
}
|
|
12779
12782
|
/************************************************************
|
|
12780
12783
|
* Disable/Enable elements
|
|
12781
|
-
|
|
12784
|
+
*
|
|
12785
|
+
* A disabled control says so to the keyboard and to a screen
|
|
12786
|
+
* reader too, not only to the pointer:
|
|
12787
|
+
* - `disabled`, what the stylesheets and the click guards
|
|
12788
|
+
* read (on a `div` drawn as a button it means nothing to
|
|
12789
|
+
* the browser itself);
|
|
12790
|
+
* - `aria-disabled="true"`, what a reader announces -- without
|
|
12791
|
+
* it a disabled toolbar item was heard as a button that
|
|
12792
|
+
* works;
|
|
12793
|
+
* - `tabindex="-1"`, so Tab does not stop on a control that
|
|
12794
|
+
* does nothing.
|
|
12795
|
+
*
|
|
12796
|
+
* Enabled again, it gets back the tabindex it had, kept in
|
|
12797
|
+
* `data-enabled-tabindex` while it is disabled (empty: it had
|
|
12798
|
+
* none, and it gets none). Whoever BUILDS a control disabled
|
|
12799
|
+
* writes that attribute itself, with the tabindex the control
|
|
12800
|
+
* takes once enabled (see toolbar_item_html in
|
|
12801
|
+
* c_g6_nodes_tree.js). An element that keeps the focus while it
|
|
12802
|
+
* is disabled keeps it: tabindex -1 still takes a focus, it is
|
|
12803
|
+
* only left out of the Tab order.
|
|
12804
|
+
************************************************************/
|
|
12805
|
+
var ENABLED_TABINDEX = "data-enabled-tabindex";
|
|
12782
12806
|
function disableElements($container, selector) {
|
|
12783
12807
|
$container.querySelectorAll(selector).forEach((el) => {
|
|
12784
12808
|
el.setAttribute("disabled", "");
|
|
12809
|
+
el.setAttribute("aria-disabled", "true");
|
|
12810
|
+
if (!el.hasAttribute(ENABLED_TABINDEX)) el.setAttribute(ENABLED_TABINDEX, el.getAttribute("tabindex") ?? "");
|
|
12811
|
+
el.setAttribute("tabindex", "-1");
|
|
12785
12812
|
});
|
|
12786
12813
|
}
|
|
12787
12814
|
function enableElements($container, selector) {
|
|
12788
12815
|
$container.querySelectorAll(selector).forEach((el) => {
|
|
12789
12816
|
if (el.hasAttribute("disabled")) el.removeAttribute("disabled");
|
|
12817
|
+
el.removeAttribute("aria-disabled");
|
|
12818
|
+
if (el.hasAttribute(ENABLED_TABINDEX)) {
|
|
12819
|
+
let tabindex = el.getAttribute(ENABLED_TABINDEX);
|
|
12820
|
+
el.removeAttribute(ENABLED_TABINDEX);
|
|
12821
|
+
if (tabindex === "") el.removeAttribute("tabindex");
|
|
12822
|
+
else el.setAttribute("tabindex", tabindex);
|
|
12823
|
+
}
|
|
12790
12824
|
});
|
|
12791
12825
|
}
|
|
12792
12826
|
/************************************************************
|
|
@@ -13169,7 +13203,7 @@ function yui_graph_update_anchor($container, state) {
|
|
|
13169
13203
|
set_pressed_state($container, ".EV_TOGGLE_ANCHOR", state === "on");
|
|
13170
13204
|
$btn.classList.toggle("color_pending_state", state === "arming");
|
|
13171
13205
|
$btn.setAttribute("aria-pressed", state === "on" ? "true" : "false");
|
|
13172
|
-
|
|
13206
|
+
const key = state === "arming" ? "click the element to centre on" : state === "on" ? "centred: click to release" : "anchor view";
|
|
13173
13207
|
$btn.setAttribute("title", t(key));
|
|
13174
13208
|
$btn.setAttribute("data-i18n-title", key);
|
|
13175
13209
|
$btn.setAttribute("aria-label", t(key));
|
|
@@ -13783,6 +13817,73 @@ function g6_event_kw(evt) {
|
|
|
13783
13817
|
};
|
|
13784
13818
|
}
|
|
13785
13819
|
//#endregion
|
|
13820
|
+
//#region src/g6_canvas_tab_order.js
|
|
13821
|
+
/***********************************************************************
|
|
13822
|
+
* g6_canvas_tab_order.js
|
|
13823
|
+
*
|
|
13824
|
+
* The canvases of a G6 graph in the page's Tab order: the main
|
|
13825
|
+
* one in its place, the other layers out of it.
|
|
13826
|
+
*
|
|
13827
|
+
* G6 stacks four canvases (background, main, label, transient)
|
|
13828
|
+
* and gives each of them `tabIndex = 1` (configCanvasDom, when it
|
|
13829
|
+
* builds the Canvas and again on a renderer change). A POSITIVE
|
|
13830
|
+
* tabindex goes before every control of the page: Tab from a
|
|
13831
|
+
* graph went to its other canvases, then to the top of the page
|
|
13832
|
+
* and through every control there, and only then to the graph's
|
|
13833
|
+
* own buttons. The main canvas -- the one G6 listens on, and the
|
|
13834
|
+
* one a view puts the keyboard on -- takes 0, so Tab goes from it
|
|
13835
|
+
* to the graph's toolbars and buttons in DOM order; the other
|
|
13836
|
+
* layers receive nothing (`pointer-events: none`) and take -1.
|
|
13837
|
+
*
|
|
13838
|
+
* Every view that creates a G6 Graph calls
|
|
13839
|
+
* keep_canvas_tab_order() right after `new Graph()`: the order is
|
|
13840
|
+
* put right each time G6 writes the 1 -- once the canvas is built
|
|
13841
|
+
* (on the first render(), whichever function of the view calls
|
|
13842
|
+
* it), and after a renderer change. One place, so a view with
|
|
13843
|
+
* several render() calls cannot miss the one that builds the
|
|
13844
|
+
* canvas.
|
|
13845
|
+
*
|
|
13846
|
+
* Copyright (c) 2026, ArtGins.
|
|
13847
|
+
* All Rights Reserved.
|
|
13848
|
+
***********************************************************************/
|
|
13849
|
+
/************************************************************
|
|
13850
|
+
* Main canvas 0, every other layer -1. Returns 0, or -1 with
|
|
13851
|
+
* the cause logged.
|
|
13852
|
+
************************************************************/
|
|
13853
|
+
function set_canvas_tab_order(gobj, graph) {
|
|
13854
|
+
let canvas = graph ? graph.getCanvas() : null;
|
|
13855
|
+
if (!canvas || typeof canvas.getLayers !== "function") {
|
|
13856
|
+
log_error(`${gobj_short_name(gobj)}: no canvas to set the Tab order of`);
|
|
13857
|
+
return -1;
|
|
13858
|
+
}
|
|
13859
|
+
let ret = 0;
|
|
13860
|
+
let layers = canvas.getLayers() || {};
|
|
13861
|
+
for (let name of Object.keys(layers)) {
|
|
13862
|
+
let $el = null;
|
|
13863
|
+
try {
|
|
13864
|
+
$el = layers[name].getContextService().getDomElement();
|
|
13865
|
+
} catch (e) {
|
|
13866
|
+
$el = null;
|
|
13867
|
+
}
|
|
13868
|
+
if (!$el) {
|
|
13869
|
+
log_error(`${gobj_short_name(gobj)}: canvas layer '${name}' has no element`);
|
|
13870
|
+
ret = -1;
|
|
13871
|
+
continue;
|
|
13872
|
+
}
|
|
13873
|
+
$el.tabIndex = name === "main" ? 0 : -1;
|
|
13874
|
+
}
|
|
13875
|
+
return ret;
|
|
13876
|
+
}
|
|
13877
|
+
/************************************************************
|
|
13878
|
+
* Keep the order for the life of `graph`: on every moment G6
|
|
13879
|
+
* writes its own.
|
|
13880
|
+
************************************************************/
|
|
13881
|
+
function keep_canvas_tab_order(gobj, graph) {
|
|
13882
|
+
for (let ev of [GraphEvent.AFTER_CANVAS_INIT, GraphEvent.AFTER_RENDERER_CHANGE]) graph.on(ev, () => {
|
|
13883
|
+
set_canvas_tab_order(gobj, graph);
|
|
13884
|
+
});
|
|
13885
|
+
}
|
|
13886
|
+
//#endregion
|
|
13786
13887
|
//#region src/c_yui_json_graph.js
|
|
13787
13888
|
/***********************************************************************
|
|
13788
13889
|
* c_yui_json_graph.js
|
|
@@ -14286,6 +14387,7 @@ function build_graph$4(gobj) {
|
|
|
14286
14387
|
behaviors: BEHAVIORS_READING$1.slice()
|
|
14287
14388
|
});
|
|
14288
14389
|
if (priv.theme) graph.setTheme(priv.theme);
|
|
14390
|
+
keep_canvas_tab_order(gobj, graph);
|
|
14289
14391
|
graph.on(NodeEvent.CLICK, (evt) => {
|
|
14290
14392
|
gobj_send_event(gobj, "EV_NODE_CLICK", g6_event_kw(evt), gobj);
|
|
14291
14393
|
});
|
|
@@ -18203,6 +18305,7 @@ function build_graph$3(gobj) {
|
|
|
18203
18305
|
} catch (e) {
|
|
18204
18306
|
log_error(`${gobj_short_name(gobj)}: the theme was refused: ${e}`);
|
|
18205
18307
|
}
|
|
18308
|
+
keep_canvas_tab_order(gobj, priv.graph);
|
|
18206
18309
|
priv.graph.on("aftertransform", () => {
|
|
18207
18310
|
yui_graph_update_zoom(gobj_read_attr(gobj, "$container"), priv.graph);
|
|
18208
18311
|
});
|
|
@@ -21706,6 +21809,7 @@ function build_graph$2(gobj) {
|
|
|
21706
21809
|
behaviors: BEHAVIORS_READING.slice()
|
|
21707
21810
|
});
|
|
21708
21811
|
if (priv.theme) graph.setTheme(priv.theme);
|
|
21812
|
+
keep_canvas_tab_order(gobj, graph);
|
|
21709
21813
|
graph.on("aftertransform", () => {
|
|
21710
21814
|
yui_graph_update_zoom(gobj_read_attr(gobj, "$container"), priv.graph);
|
|
21711
21815
|
let z = priv.last_zoom;
|
|
@@ -23522,7 +23626,7 @@ function build_ui$7(gobj) {
|
|
|
23522
23626
|
if (layout !== "drawer") {
|
|
23523
23627
|
$container.setAttribute("role", "navigation");
|
|
23524
23628
|
if (!$container.hasAttribute("aria-label")) {
|
|
23525
|
-
|
|
23629
|
+
const label = gobj_read_attr(gobj, "nav_label") || "navigation";
|
|
23526
23630
|
$container.setAttribute("aria-label", t(label));
|
|
23527
23631
|
$container.setAttribute("data-i18n-aria-label", label);
|
|
23528
23632
|
}
|
|
@@ -23783,14 +23887,17 @@ function render_backbar(gobj) {
|
|
|
23783
23887
|
let label = gobj_read_attr(gobj, "nav_label") || "";
|
|
23784
23888
|
let label_attrs = { class: "yui-nav-label" };
|
|
23785
23889
|
if (label) label_attrs.i18n = label;
|
|
23890
|
+
const name_key = label || "back";
|
|
23786
23891
|
let a_attrs = {
|
|
23787
23892
|
class: "yui-nav-item yui-nav-back",
|
|
23788
23893
|
href: back_route ? "#" + back_route : "#",
|
|
23789
23894
|
"data-item-id": "__index__",
|
|
23790
23895
|
"data-route": back_route,
|
|
23791
|
-
|
|
23896
|
+
title: t(name_key),
|
|
23897
|
+
"data-i18n-title": name_key,
|
|
23898
|
+
"aria-label": t(name_key),
|
|
23899
|
+
"data-i18n-aria-label": name_key
|
|
23792
23900
|
};
|
|
23793
|
-
if (label) a_attrs["data-i18n-aria-label"] = label;
|
|
23794
23901
|
return createElement2([
|
|
23795
23902
|
"div",
|
|
23796
23903
|
{},
|
|
@@ -23817,7 +23924,7 @@ function render_drawer(gobj, items) {
|
|
|
23817
23924
|
wrap.className = "yui-drawer";
|
|
23818
23925
|
wrap.setAttribute("role", "dialog");
|
|
23819
23926
|
wrap.setAttribute("aria-modal", "true");
|
|
23820
|
-
|
|
23927
|
+
const nav_label = gobj_read_attr(gobj, "nav_label") || "navigation";
|
|
23821
23928
|
wrap.setAttribute("aria-label", t(nav_label));
|
|
23822
23929
|
wrap.setAttribute("data-i18n-aria-label", nav_label);
|
|
23823
23930
|
let back = document.createElement("div");
|
|
@@ -25612,7 +25719,7 @@ function show_load_error$1(gobj, message) {
|
|
|
25612
25719
|
$container.insertBefore($err, $container.firstChild);
|
|
25613
25720
|
}
|
|
25614
25721
|
let treedb = gobj_read_attr(gobj, "treedb_name") || "";
|
|
25615
|
-
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
|
|
25722
|
+
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || t("cannot load treedb"));
|
|
25616
25723
|
}
|
|
25617
25724
|
/************************************************************
|
|
25618
25725
|
* Destroy UI
|
|
@@ -27990,7 +28097,6 @@ function yui_selection_bar(t, opts) {
|
|
|
27990
28097
|
if (typeof o.on_clear === "function") o.on_clear(e);
|
|
27991
28098
|
} }
|
|
27992
28099
|
]);
|
|
27993
|
-
$clear._yui_label = "clear selection";
|
|
27994
28100
|
let $el = createElement2([
|
|
27995
28101
|
"div",
|
|
27996
28102
|
{
|
|
@@ -28006,7 +28112,7 @@ function yui_selection_bar(t, opts) {
|
|
|
28006
28112
|
$count.textContent = t("{{n}} selected", { n: count });
|
|
28007
28113
|
for (let $b of $buttons.concat([$clear])) {
|
|
28008
28114
|
let $label = label_of($b);
|
|
28009
|
-
|
|
28115
|
+
const key = $b === $clear ? "clear selection" : $b._yui_label;
|
|
28010
28116
|
if ($label && key) $label.textContent = t(key);
|
|
28011
28117
|
$b.title = key ? t(key) : "";
|
|
28012
28118
|
$b.setAttribute("aria-label", $b.title);
|
|
@@ -30088,7 +30194,7 @@ function open_form_dialog(gobj, mode, record) {
|
|
|
30088
30194
|
return;
|
|
30089
30195
|
}
|
|
30090
30196
|
let pkey = desc.pkey || "id";
|
|
30091
|
-
|
|
30197
|
+
const title = mode === "create" ? "new" : mode === "view" ? "view" : "edit";
|
|
30092
30198
|
let title_prefix = "";
|
|
30093
30199
|
if (mode !== "create") {
|
|
30094
30200
|
let rid = record ? String(record[pkey] ?? "") : "";
|
|
@@ -60769,17 +60875,41 @@ function css_color_or_null(value) {
|
|
|
60769
60875
|
* The markup of one toolbar item. Everything that goes into it is
|
|
60770
60876
|
* escaped, the read-out branch too: its text, title and value are
|
|
60771
60877
|
* values (a zoom figure, a translated title), never markup.
|
|
60878
|
+
*
|
|
60879
|
+
* An item is a BUTTON for the keyboard too: `role="button"` and
|
|
60880
|
+
* `tabindex="0"`, and YuiToolbar presses it on Enter or Space.
|
|
60881
|
+
* `title_key` is the i18n key of `title`: written as
|
|
60882
|
+
* `data-i18n-title` / `data-i18n-aria-label`, so the name carries
|
|
60883
|
+
* its key like every other control's.
|
|
60884
|
+
*
|
|
60885
|
+
* A `disabled` item is born the way disableElements() (lib_graph.js)
|
|
60886
|
+
* leaves one: `aria-disabled`, out of the Tab order, and the
|
|
60887
|
+
* tabindex it takes once enabled kept in `data-enabled-tabindex`,
|
|
60888
|
+
* where enableElements() finds it. A toggle (`pressed` given, true
|
|
60889
|
+
* or false) says its state in `aria-pressed`, as its look says it
|
|
60890
|
+
* with `pressed_state`. `data-control` names the CONTROL the item
|
|
60891
|
+
* is, whatever state it shows: `control` when the item gives one
|
|
60892
|
+
* (full screen is `request-fullscreen` or `exit-fullscreen`, and
|
|
60893
|
+
* one control), its `value` otherwise -- it is what a rebuild puts
|
|
60894
|
+
* the focus back on.
|
|
60772
60895
|
***************************************************************/
|
|
60773
60896
|
function toolbar_item_html(item) {
|
|
60774
60897
|
if (item.separator) return `<div class="g6-toolbar-sep" aria-hidden="true"></div>`;
|
|
60775
60898
|
const extra_class = item.className ? ` ${escapeHtml(String(item.className))}` : "";
|
|
60776
60899
|
const title = escapeHtml(String(item.title ?? ""));
|
|
60777
|
-
|
|
60778
|
-
|
|
60900
|
+
let i18n_attrs = "";
|
|
60901
|
+
if (item.title_key) {
|
|
60902
|
+
const key = escapeHtml(String(item.title_key));
|
|
60903
|
+
i18n_attrs = ` data-i18n-title="${key}" data-i18n-aria-label="${key}"`;
|
|
60904
|
+
}
|
|
60905
|
+
if (item.readout) return `<div class="g6-toolbar-readout${extra_class}" title="${title}" aria-label="${title}"${i18n_attrs}>${escapeHtml(String(item.text ?? ""))}</div>`;
|
|
60906
|
+
const state = item.disabled ? " tabindex=\"-1\" aria-disabled=\"true\" data-enabled-tabindex=\"0\" disabled" : " tabindex=\"0\"";
|
|
60907
|
+
const pressed = item.pressed === void 0 ? "" : ` aria-pressed="${item.pressed ? "true" : "false"}"`;
|
|
60908
|
+
const control = escapeHtml(String(item.control ?? item.value));
|
|
60779
60909
|
const is_text = item.text !== void 0;
|
|
60780
60910
|
const kind_class = is_text ? " g6-toolbar-item-text" : "";
|
|
60781
60911
|
const body = is_text ? `<span class="g6-toolbar-text">${escapeHtml(String(item.text))}</span>` : `<svg aria-hidden="true" focusable="false"><use xlink:href="#${escapeHtml(String(item.id))}"></use></svg>`;
|
|
60782
|
-
return `<div class="g6-toolbar-item${kind_class}${extra_class}" value="${escapeHtml(String(item.value))}" title="${title}" aria-label="${title}"${
|
|
60912
|
+
return `<div class="g6-toolbar-item${kind_class}${extra_class}" role="button"${state}${pressed} value="${escapeHtml(String(item.value))}" data-control="${control}" title="${title}" aria-label="${title}"${i18n_attrs}>${body}</div>`;
|
|
60783
60913
|
}
|
|
60784
60914
|
/***************************************************************
|
|
60785
60915
|
* YuiToolbar — G6 Toolbar subclass that adds per-item className
|
|
@@ -60794,6 +60924,11 @@ function toolbar_item_html(item) {
|
|
|
60794
60924
|
* readout — a text item that REPORTS instead of acting (the
|
|
60795
60925
|
* zoom level); it is not a button
|
|
60796
60926
|
* separator — a group divider, not an item
|
|
60927
|
+
* title_key — the i18n key of `title` (see toolbar_item_html)
|
|
60928
|
+
* pressed — boolean; the item is a TOGGLE, and this is its
|
|
60929
|
+
* state (`aria-pressed`)
|
|
60930
|
+
* control — the identity of the control when its `value`
|
|
60931
|
+
* changes with its state (full screen enter/exit)
|
|
60797
60932
|
*
|
|
60798
60933
|
* The base class fires onClick only for elements whose class list
|
|
60799
60934
|
* contains `g6-toolbar-item`, so a separator and a readout carry
|
|
@@ -60804,12 +60939,117 @@ function toolbar_item_html(item) {
|
|
|
60804
60939
|
* functions (set_submit_state, disableElements, …) work on toolbar
|
|
60805
60940
|
* icons exactly like on regular Bulma/FA buttons — no special
|
|
60806
60941
|
* icon-specific helpers needed.
|
|
60942
|
+
*
|
|
60943
|
+
* The items are buttons for the KEYBOARD as well:
|
|
60944
|
+
* - Enter or Space CLICKS the focused item, and the click bubbles
|
|
60945
|
+
* to the base class's own handler, so the key reaches the same
|
|
60946
|
+
* onClick a pointer does. A `disabled` item takes the key and
|
|
60947
|
+
* does nothing, as its `pointer-events: none` does for a press.
|
|
60948
|
+
* - A POINTER press does not move the focus to an item (it stays
|
|
60949
|
+
* on the canvas, where the graph's keys are heard), the way the
|
|
60950
|
+
* floating buttons keep it (see keep_focus_on_press).
|
|
60951
|
+
* - A disabled item is out of the Tab order and says it is
|
|
60952
|
+
* disabled (`aria-disabled`), from its first render
|
|
60953
|
+
* (toolbar_item_html) and on every change (disableElements /
|
|
60954
|
+
* enableElements in lib_graph.js).
|
|
60955
|
+
* - A rebuild (update) replaces the innerHTML, the focused item
|
|
60956
|
+
* with it: the focus goes back to the item of the same CONTROL
|
|
60957
|
+
* (`data-control`: Enter on "enter full screen" lands on "exit
|
|
60958
|
+
* full screen"), or to the canvas when there is none. And a
|
|
60959
|
+
* toolbar that goes away (destroy) hands it to the canvas
|
|
60960
|
+
* first. A removed element that held the focus leaves it on
|
|
60961
|
+
* <body> in Firefox, which fires no focusout for it, and the
|
|
60962
|
+
* graph goes deaf.
|
|
60807
60963
|
***************************************************************/
|
|
60808
60964
|
var YuiToolbar = class extends Toolbar {
|
|
60965
|
+
constructor(context, options) {
|
|
60966
|
+
super(context, options);
|
|
60967
|
+
this.$element.addEventListener("pointerdown", keep_focus_on_toolbar_press);
|
|
60968
|
+
this.$element.addEventListener("keydown", press_toolbar_item_on_key);
|
|
60969
|
+
}
|
|
60970
|
+
async update(options) {
|
|
60971
|
+
const control = focused_toolbar_item_control(this.$element);
|
|
60972
|
+
await super.update(options);
|
|
60973
|
+
if (control !== null) refocus_toolbar_item(this.$element, control);
|
|
60974
|
+
}
|
|
60975
|
+
destroy() {
|
|
60976
|
+
if (!this.destroyed && this.$element) {
|
|
60977
|
+
this.$element.removeEventListener("pointerdown", keep_focus_on_toolbar_press);
|
|
60978
|
+
this.$element.removeEventListener("keydown", press_toolbar_item_on_key);
|
|
60979
|
+
if (this.$element.contains(document.activeElement)) focus_main_canvas(this.$element.parentNode);
|
|
60980
|
+
}
|
|
60981
|
+
super.destroy();
|
|
60982
|
+
}
|
|
60809
60983
|
async getDOMContent() {
|
|
60810
60984
|
return (await this.options.getItems()).map(toolbar_item_html).join("");
|
|
60811
60985
|
}
|
|
60812
60986
|
};
|
|
60987
|
+
/***************************************************************
|
|
60988
|
+
* A POINTER press on a button of this view does not take the
|
|
60989
|
+
* focus. The container's capture listener has just put it on the
|
|
60990
|
+
* canvas, where the graph's keys are heard; a press that moved it
|
|
60991
|
+
* on to the button would leave it on something this view removes
|
|
60992
|
+
* -- Escape deselects and takes the floating buttons away, the ✕
|
|
60993
|
+
* closes its popover, a rebuild replaces the toolbar -- and
|
|
60994
|
+
* Firefox fires no focusout for a removed element: the focus falls
|
|
60995
|
+
* to <body> and the graph hears nothing until it is clicked again.
|
|
60996
|
+
* Cancelling the pointerdown cancels the mousedown that moves the
|
|
60997
|
+
* focus; the click still comes, and Tab still reaches the button.
|
|
60998
|
+
***************************************************************/
|
|
60999
|
+
function keep_focus_on_press(el) {
|
|
61000
|
+
el.addEventListener("pointerdown", (e) => {
|
|
61001
|
+
e.preventDefault();
|
|
61002
|
+
});
|
|
61003
|
+
}
|
|
61004
|
+
function keep_focus_on_toolbar_press(e) {
|
|
61005
|
+
let target = e.target;
|
|
61006
|
+
if (target && typeof target.closest === "function" && target.closest(".g6-toolbar-item")) e.preventDefault();
|
|
61007
|
+
}
|
|
61008
|
+
/***************************************************************
|
|
61009
|
+
* The keyboard to the graph: the focus on its main canvas.
|
|
61010
|
+
***************************************************************/
|
|
61011
|
+
function focus_main_canvas($container) {
|
|
61012
|
+
if (!$container) return;
|
|
61013
|
+
let $canvas = main_canvas_of($container);
|
|
61014
|
+
if ($canvas && $canvas.isConnected && typeof $canvas.focus === "function") $canvas.focus({ preventScroll: true });
|
|
61015
|
+
}
|
|
61016
|
+
/***************************************************************
|
|
61017
|
+
* Enter or Space on a toolbar item clicks it; the click bubbles
|
|
61018
|
+
* to G6's toolbar handler, which reads the item's `value`.
|
|
61019
|
+
***************************************************************/
|
|
61020
|
+
function press_toolbar_item_on_key(e) {
|
|
61021
|
+
if (e.key !== "Enter" && e.key !== " ") return;
|
|
61022
|
+
let target = e.target;
|
|
61023
|
+
let item = target && typeof target.closest === "function" ? target.closest(".g6-toolbar-item") : null;
|
|
61024
|
+
if (!item) return;
|
|
61025
|
+
e.preventDefault();
|
|
61026
|
+
e.stopPropagation();
|
|
61027
|
+
if (item.hasAttribute("disabled")) return;
|
|
61028
|
+
item.click();
|
|
61029
|
+
}
|
|
61030
|
+
/***************************************************************
|
|
61031
|
+
* The control (`data-control`) of the toolbar item that has the
|
|
61032
|
+
* focus, or null.
|
|
61033
|
+
***************************************************************/
|
|
61034
|
+
function focused_toolbar_item_control($toolbar) {
|
|
61035
|
+
let active = document.activeElement;
|
|
61036
|
+
if (!$toolbar || !active || active === $toolbar || !$toolbar.contains(active)) return null;
|
|
61037
|
+
if (!active.classList || !active.classList.contains("g6-toolbar-item")) return null;
|
|
61038
|
+
return active.getAttribute("data-control");
|
|
61039
|
+
}
|
|
61040
|
+
/***************************************************************
|
|
61041
|
+
* After a rebuild: the focus on the item of that control, in
|
|
61042
|
+
* whatever state the rebuild shows it, or on the canvas when the
|
|
61043
|
+
* rebuild has none (a fold took it away).
|
|
61044
|
+
***************************************************************/
|
|
61045
|
+
function refocus_toolbar_item($toolbar, control) {
|
|
61046
|
+
let items = $toolbar.querySelectorAll(".g6-toolbar-item");
|
|
61047
|
+
for (let i = 0; i < items.length; i++) if (items[i].getAttribute("data-control") === control) {
|
|
61048
|
+
items[i].focus({ preventScroll: true });
|
|
61049
|
+
return;
|
|
61050
|
+
}
|
|
61051
|
+
focus_main_canvas($toolbar.parentNode);
|
|
61052
|
+
}
|
|
60813
61053
|
register(ExtensionCategory.PLUGIN, "yui-toolbar", YuiToolbar);
|
|
60814
61054
|
ensure_drag_canvas_patch();
|
|
60815
61055
|
ensure_brush_select_owned();
|
|
@@ -60974,6 +61214,7 @@ var PRIVATE_DATA$4 = {
|
|
|
60974
61214
|
_saved_graph_properties: {},
|
|
60975
61215
|
_graphs_writes_owed: {},
|
|
60976
61216
|
_graphs_load: 0,
|
|
61217
|
+
_save_lit: false,
|
|
60977
61218
|
yet_showed: false,
|
|
60978
61219
|
edit_mode: false,
|
|
60979
61220
|
operation_mode: null,
|
|
@@ -61007,6 +61248,7 @@ var PRIVATE_DATA$4 = {
|
|
|
61007
61248
|
_detail_node_id: null,
|
|
61008
61249
|
_delete_confirm_el: null,
|
|
61009
61250
|
_unlink_confirm_el: null,
|
|
61251
|
+
_confirm_questions: {},
|
|
61010
61252
|
_create_popover_el: null,
|
|
61011
61253
|
_context_node_id: null,
|
|
61012
61254
|
_context_port_key: null,
|
|
@@ -61015,6 +61257,7 @@ var PRIVATE_DATA$4 = {
|
|
|
61015
61257
|
_link_source: null,
|
|
61016
61258
|
_link_icon_el: null,
|
|
61017
61259
|
_link_drag_svg: null,
|
|
61260
|
+
_link_drag: null,
|
|
61018
61261
|
_link_valid_hooks: [],
|
|
61019
61262
|
_link_saved_styles: [],
|
|
61020
61263
|
_focus_topic: null,
|
|
@@ -61258,6 +61501,7 @@ function build_graph$1(gobj) {
|
|
|
61258
61501
|
plugins: []
|
|
61259
61502
|
});
|
|
61260
61503
|
graph.setTheme(priv.theme);
|
|
61504
|
+
keep_canvas_tab_order(gobj, graph);
|
|
61261
61505
|
priv._unforward_wheel = yui_graph_forward_wheel(graph, priv.$container, { selector: ".TREEDB_CARD, .TREEDB_PILLS" });
|
|
61262
61506
|
graph.setLayout(layout);
|
|
61263
61507
|
priv.graph_rendered = false;
|
|
@@ -61415,8 +61659,6 @@ function update_toolbar(gobj) {
|
|
|
61415
61659
|
if (graph_get_plugin(gobj, "toolbar")) graph.updatePlugin({ key: "toolbar" });
|
|
61416
61660
|
configure_toolbar_edit(gobj);
|
|
61417
61661
|
if (graph_get_plugin(gobj, "toolbar-edit")) graph.updatePlugin({ key: "toolbar-edit" });
|
|
61418
|
-
update_zoom_selection_button(gobj);
|
|
61419
|
-
update_selection_mode_button(gobj);
|
|
61420
61662
|
}
|
|
61421
61663
|
/************************************************************
|
|
61422
61664
|
* The floating toolbars follow the theme.
|
|
@@ -61467,13 +61709,15 @@ function toolbar_fold_item(gobj) {
|
|
|
61467
61709
|
id: "g6-icon-toolbar-show",
|
|
61468
61710
|
value: "toolbar-toggle",
|
|
61469
61711
|
className: "EV_TOGGLE_TOOLBARS",
|
|
61470
|
-
title: t("show toolbar")
|
|
61712
|
+
title: t("show toolbar"),
|
|
61713
|
+
title_key: "show toolbar"
|
|
61471
61714
|
};
|
|
61472
61715
|
return {
|
|
61473
61716
|
id: "g6-icon-toolbar-hide",
|
|
61474
61717
|
value: "toolbar-toggle",
|
|
61475
61718
|
className: "EV_TOGGLE_TOOLBARS",
|
|
61476
|
-
title: t("hide toolbar")
|
|
61719
|
+
title: t("hide toolbar"),
|
|
61720
|
+
title_key: "hide toolbar"
|
|
61477
61721
|
};
|
|
61478
61722
|
}
|
|
61479
61723
|
function toolbar_style(extra) {
|
|
@@ -61539,38 +61783,44 @@ function configure_toolbar(gobj) {
|
|
|
61539
61783
|
id: "g6-icon-zoom-in",
|
|
61540
61784
|
value: "zoom-in",
|
|
61541
61785
|
className: "EV_ZOOM_IN",
|
|
61542
|
-
title: t("zoom in")
|
|
61786
|
+
title: t("zoom in"),
|
|
61787
|
+
title_key: "zoom in"
|
|
61543
61788
|
},
|
|
61544
61789
|
{
|
|
61545
61790
|
id: "g6-icon-zoom-out",
|
|
61546
61791
|
value: "zoom-out",
|
|
61547
61792
|
className: "EV_ZOOM_OUT",
|
|
61548
|
-
title: t("zoom out")
|
|
61793
|
+
title: t("zoom out"),
|
|
61794
|
+
title_key: "zoom out"
|
|
61549
61795
|
},
|
|
61550
61796
|
{
|
|
61551
61797
|
readout: true,
|
|
61552
61798
|
className: "G6_ZOOM_LEVEL",
|
|
61553
61799
|
text: zoom_percent_text(gobj),
|
|
61554
|
-
title: t("zoom level")
|
|
61800
|
+
title: t("zoom level"),
|
|
61801
|
+
title_key: "zoom level"
|
|
61555
61802
|
},
|
|
61556
61803
|
{ separator: true },
|
|
61557
61804
|
{
|
|
61558
61805
|
id: "g6-icon-fit",
|
|
61559
61806
|
value: "auto-fit",
|
|
61560
61807
|
className: "EV_AUTO_FIT",
|
|
61561
|
-
title: t("auto fit")
|
|
61808
|
+
title: t("auto fit"),
|
|
61809
|
+
title_key: "auto fit"
|
|
61562
61810
|
},
|
|
61563
61811
|
{
|
|
61564
61812
|
text: "1:1",
|
|
61565
61813
|
value: "reset",
|
|
61566
61814
|
className: "EV_ZOOM_RESET",
|
|
61567
|
-
title: t("actual size")
|
|
61815
|
+
title: t("actual size"),
|
|
61816
|
+
title_key: "actual size"
|
|
61568
61817
|
},
|
|
61569
61818
|
{
|
|
61570
61819
|
id: "g6-icon-anchor",
|
|
61571
61820
|
value: "anchor",
|
|
61572
61821
|
className: "EV_TOGGLE_ANCHOR" + (priv.anchor_state === "on" ? " pressed_state" : "") + (priv.anchor_state === "arming" ? " color_pending_state" : ""),
|
|
61573
|
-
|
|
61822
|
+
pressed: priv.anchor_state === "on",
|
|
61823
|
+
...anchor_title(priv.anchor_state)
|
|
61574
61824
|
}
|
|
61575
61825
|
];
|
|
61576
61826
|
if (priv.edit_mode) items.push({
|
|
@@ -61578,21 +61828,26 @@ function configure_toolbar(gobj) {
|
|
|
61578
61828
|
value: "fit-selection",
|
|
61579
61829
|
className: "EV_ZOOM_SELECTION",
|
|
61580
61830
|
title: t("zoom to selection"),
|
|
61581
|
-
|
|
61831
|
+
title_key: "zoom to selection",
|
|
61832
|
+
disabled: !selection_is_painted(gobj)
|
|
61582
61833
|
});
|
|
61583
61834
|
if (gobj_read_bool_attr(gobj, "with_fullscreen")) {
|
|
61584
61835
|
items.push({ separator: true });
|
|
61585
61836
|
if (priv.is_fullscreen) items.push({
|
|
61586
61837
|
id: "g6-icon-fullscreen-exit",
|
|
61587
61838
|
value: "exit-fullscreen",
|
|
61839
|
+
control: "fullscreen",
|
|
61588
61840
|
className: "EV_EXIT_FULLSCREEN",
|
|
61589
|
-
title: t("exit full screen")
|
|
61841
|
+
title: t("exit full screen"),
|
|
61842
|
+
title_key: "exit full screen"
|
|
61590
61843
|
});
|
|
61591
61844
|
else items.push({
|
|
61592
61845
|
id: "g6-icon-fullscreen",
|
|
61593
61846
|
value: "request-fullscreen",
|
|
61847
|
+
control: "fullscreen",
|
|
61594
61848
|
className: "EV_REQUEST_FULLSCREEN",
|
|
61595
|
-
title: t("enter full screen")
|
|
61849
|
+
title: t("enter full screen"),
|
|
61850
|
+
title_key: "enter full screen"
|
|
61596
61851
|
});
|
|
61597
61852
|
}
|
|
61598
61853
|
if (toolbars_can_collapse(gobj)) {
|
|
@@ -61653,46 +61908,53 @@ function configure_toolbar_edit(gobj) {
|
|
|
61653
61908
|
position: "left-top",
|
|
61654
61909
|
style: toolbar_style(),
|
|
61655
61910
|
getItems: () => {
|
|
61911
|
+
let lit = edit_buttons_lit(gobj);
|
|
61656
61912
|
return [
|
|
61657
61913
|
{
|
|
61658
61914
|
id: "g6-icon-plus",
|
|
61659
61915
|
value: "create-node",
|
|
61660
61916
|
className: "EV_CREATE_NODE_BTN color_create_state",
|
|
61661
|
-
title: t("create node")
|
|
61917
|
+
title: t("create node"),
|
|
61918
|
+
title_key: "create node"
|
|
61662
61919
|
},
|
|
61663
61920
|
{
|
|
61664
61921
|
id: "g6-icon-select-mode",
|
|
61665
61922
|
value: "selection-mode",
|
|
61666
61923
|
className: "EV_TOGGLE_SELECTION_MODE" + (priv.selection_mode ? " pressed_state" : ""),
|
|
61667
|
-
|
|
61924
|
+
pressed: !!priv.selection_mode,
|
|
61925
|
+
title: t("selection mode"),
|
|
61926
|
+
title_key: "selection mode"
|
|
61668
61927
|
},
|
|
61669
61928
|
{
|
|
61670
61929
|
id: "g6-icon-save",
|
|
61671
61930
|
value: "save",
|
|
61672
|
-
className: "EV_SAVE_GRAPH",
|
|
61931
|
+
className: "EV_SAVE_GRAPH" + (lit.save ? " color_submit_state" : ""),
|
|
61673
61932
|
title: t("save"),
|
|
61674
|
-
|
|
61933
|
+
title_key: "save",
|
|
61934
|
+
disabled: !lit.save
|
|
61675
61935
|
},
|
|
61676
61936
|
{
|
|
61677
61937
|
id: "g6-icon-undo",
|
|
61678
61938
|
value: "undo",
|
|
61679
|
-
className: "EV_HISTORY_UNDO",
|
|
61939
|
+
className: "EV_HISTORY_UNDO" + (lit.undo ? " color_active_state" : ""),
|
|
61680
61940
|
title: t("undo"),
|
|
61681
|
-
|
|
61941
|
+
title_key: "undo",
|
|
61942
|
+
disabled: !lit.undo
|
|
61682
61943
|
},
|
|
61683
61944
|
{
|
|
61684
61945
|
id: "g6-icon-redo",
|
|
61685
61946
|
value: "redo",
|
|
61686
|
-
className: "EV_HISTORY_REDO",
|
|
61947
|
+
className: "EV_HISTORY_REDO" + (lit.redo ? " color_active_state" : ""),
|
|
61687
61948
|
title: t("redo"),
|
|
61688
|
-
|
|
61949
|
+
title_key: "redo",
|
|
61950
|
+
disabled: !lit.redo
|
|
61689
61951
|
}
|
|
61690
61952
|
];
|
|
61691
61953
|
},
|
|
61692
61954
|
onClick: (value) => {
|
|
61693
61955
|
switch (value) {
|
|
61694
61956
|
case "create-node":
|
|
61695
|
-
|
|
61957
|
+
gobj_send_event(gobj, "EV_TOGGLE_CREATE_POPOVER", {}, gobj);
|
|
61696
61958
|
break;
|
|
61697
61959
|
case "selection-mode":
|
|
61698
61960
|
gobj_send_event(gobj, "EV_TOGGLE_SELECTION_MODE", {}, gobj);
|
|
@@ -62753,28 +63015,50 @@ function update_history_buttons(gobj) {
|
|
|
62753
63015
|
if (history.canUndo()) {
|
|
62754
63016
|
enableElements($container, ".EV_HISTORY_UNDO");
|
|
62755
63017
|
set_active_state($container, ".EV_HISTORY_UNDO", true);
|
|
62756
|
-
|
|
62757
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
63018
|
+
light_save_button(gobj, true);
|
|
62758
63019
|
} else {
|
|
62759
63020
|
disableElements($container, ".EV_HISTORY_UNDO");
|
|
62760
63021
|
set_active_state($container, ".EV_HISTORY_UNDO", false);
|
|
62761
|
-
|
|
62762
|
-
enableElements($container, ".EV_SAVE_GRAPH");
|
|
62763
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
62764
|
-
} else {
|
|
62765
|
-
disableElements($container, ".EV_SAVE_GRAPH");
|
|
62766
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
62767
|
-
}
|
|
63022
|
+
light_save_button(gobj, graphs_write_is_owed(gobj));
|
|
62768
63023
|
}
|
|
62769
63024
|
} else {
|
|
62770
63025
|
disableElements($container, ".EV_HISTORY_REDO");
|
|
62771
63026
|
set_active_state($container, ".EV_HISTORY_REDO", false);
|
|
62772
63027
|
disableElements($container, ".EV_HISTORY_UNDO");
|
|
62773
63028
|
set_active_state($container, ".EV_HISTORY_UNDO", false);
|
|
63029
|
+
light_save_button(gobj, graphs_write_is_owed(gobj));
|
|
62774
63030
|
}
|
|
62775
63031
|
}
|
|
62776
63032
|
}
|
|
62777
63033
|
/************************************************************
|
|
63034
|
+
* What Save, Undo and Redo show when the edit toolbar is
|
|
63035
|
+
* built (its getItems): Undo and Redo what the history can do
|
|
63036
|
+
* now; Save what it was last told (`_save_lit`, see
|
|
63037
|
+
* light_save_button), because more than the history lights
|
|
63038
|
+
* it -- a change the history does not record
|
|
63039
|
+
* (mark_graph_dirty), a write owed -- and update_history_
|
|
63040
|
+
* buttons() is where those are weighed.
|
|
63041
|
+
************************************************************/
|
|
63042
|
+
function edit_buttons_lit(gobj) {
|
|
63043
|
+
let history = graph_get_plugin(gobj, "history");
|
|
63044
|
+
return {
|
|
63045
|
+
undo: !!history && history.canUndo(),
|
|
63046
|
+
redo: !!history && history.canRedo(),
|
|
63047
|
+
save: !!gobj.priv._save_lit
|
|
63048
|
+
};
|
|
63049
|
+
}
|
|
63050
|
+
/************************************************************
|
|
63051
|
+
* Light the Save, or put it out: on the live element, and in
|
|
63052
|
+
* `_save_lit`, where the next rebuild of the toolbar reads it.
|
|
63053
|
+
************************************************************/
|
|
63054
|
+
function light_save_button(gobj, lit) {
|
|
63055
|
+
let $container = gobj_read_attr(gobj, "$container");
|
|
63056
|
+
gobj.priv._save_lit = !!lit;
|
|
63057
|
+
if (lit) enableElements($container, ".EV_SAVE_GRAPH");
|
|
63058
|
+
else disableElements($container, ".EV_SAVE_GRAPH");
|
|
63059
|
+
set_submit_state($container, ".EV_SAVE_GRAPH", !!lit);
|
|
63060
|
+
}
|
|
63061
|
+
/************************************************************
|
|
62778
63062
|
* Graph utility functions
|
|
62779
63063
|
*
|
|
62780
63064
|
* From the G6 documentation:
|
|
@@ -63650,20 +63934,59 @@ function floating_popover_dx() {
|
|
|
63650
63934
|
return 4 + floating_icon_size() + 4;
|
|
63651
63935
|
}
|
|
63652
63936
|
/************************************************************
|
|
63937
|
+
* A key press IS the click on an element drawn as a button.
|
|
63938
|
+
*
|
|
63939
|
+
* Enter or Space clicks it, so the keyboard reaches the very
|
|
63940
|
+
* handler the pointer does, whatever that handler is. Stopped
|
|
63941
|
+
* here, as the click is: this view's container forwards every
|
|
63942
|
+
* keydown to G6 (its shortcuts, and EV_KEY_DOWN), and a key
|
|
63943
|
+
* that pressed a button is not the graph's. Space would scroll
|
|
63944
|
+
* the page as well. Any other key goes on to the graph, so
|
|
63945
|
+
* Escape and Delete keep doing there what they do.
|
|
63946
|
+
************************************************************/
|
|
63947
|
+
function click_on_enter_or_space(el) {
|
|
63948
|
+
el.addEventListener("keydown", (e) => {
|
|
63949
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
63950
|
+
e.preventDefault();
|
|
63951
|
+
e.stopPropagation();
|
|
63952
|
+
el.click();
|
|
63953
|
+
}
|
|
63954
|
+
});
|
|
63955
|
+
}
|
|
63956
|
+
/************************************************************
|
|
63653
63957
|
* Create a floating circular icon button.
|
|
63654
|
-
*
|
|
63655
|
-
*
|
|
63656
|
-
*
|
|
63657
|
-
*
|
|
63658
|
-
*
|
|
63659
|
-
*
|
|
63958
|
+
*
|
|
63959
|
+
* A button for the keyboard too: `role` and `tabindex`, and
|
|
63960
|
+
* Enter or Space click it (click_on_enter_or_space). Its name
|
|
63961
|
+
* carries its KEY, so refresh_language() renames it on a
|
|
63962
|
+
* language switch; a key handed in here goes in
|
|
63963
|
+
* G6_NODES_TREE_I18N_KEYS, because no scan sees it.
|
|
63964
|
+
*
|
|
63965
|
+
* Its click does one thing: it sends `event` to `gobj`, with
|
|
63966
|
+
* `kw` -- the plain identity of what the button belongs to --
|
|
63967
|
+
* and the ACTION does the work, where the `machine` trace sees
|
|
63968
|
+
* it. A pointer press does not take the focus
|
|
63969
|
+
* (keep_focus_on_press).
|
|
63970
|
+
*
|
|
63971
|
+
* @param {string} svgKey - key into SVG_ICONS
|
|
63972
|
+
* @param {string} color - border & text color (e.g. '#1890ff')
|
|
63973
|
+
* @param {number} left - CSS left in px
|
|
63974
|
+
* @param {number} top - CSS top in px
|
|
63975
|
+
* @param {string} title_key - i18n key of its title and aria-label
|
|
63976
|
+
* @param {object} gobj - who hears the click
|
|
63977
|
+
* @param {string} event - an input event of this gclass
|
|
63978
|
+
* @param {object} kw - plain JSON identity, copied per click
|
|
63660
63979
|
* @returns {HTMLElement}
|
|
63661
63980
|
************************************************************/
|
|
63662
|
-
function create_floating_icon(svgKey, color, left, top,
|
|
63981
|
+
function create_floating_icon(svgKey, color, left, top, title_key, gobj, event, kw) {
|
|
63663
63982
|
const size = floating_icon_size();
|
|
63664
63983
|
const el = document.createElement("div");
|
|
63665
|
-
el.
|
|
63666
|
-
el.setAttribute("
|
|
63984
|
+
el.setAttribute("role", "button");
|
|
63985
|
+
el.setAttribute("tabindex", "0");
|
|
63986
|
+
el.setAttribute("title", t(title_key));
|
|
63987
|
+
el.setAttribute("data-i18n-title", title_key);
|
|
63988
|
+
el.setAttribute("aria-label", t(title_key));
|
|
63989
|
+
el.setAttribute("data-i18n-aria-label", title_key);
|
|
63667
63990
|
el.innerHTML = SVG_ICONS[svgKey] || "";
|
|
63668
63991
|
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 + ";";
|
|
63669
63992
|
const $svg = el.querySelector("svg");
|
|
@@ -63674,19 +63997,33 @@ function create_floating_icon(svgKey, color, left, top, title, onClick) {
|
|
|
63674
63997
|
}
|
|
63675
63998
|
el.addEventListener("click", (e) => {
|
|
63676
63999
|
e.stopPropagation();
|
|
63677
|
-
|
|
64000
|
+
gobj_send_event(gobj, event, json_deep_copy(kw || {}), gobj);
|
|
63678
64001
|
});
|
|
64002
|
+
keep_focus_on_press(el);
|
|
64003
|
+
click_on_enter_or_space(el);
|
|
63679
64004
|
return el;
|
|
63680
64005
|
}
|
|
63681
64006
|
/************************************************************
|
|
63682
64007
|
* Remove one or more overlay elements from priv and the DOM.
|
|
64008
|
+
*
|
|
64009
|
+
* An overlay that holds the focus -- a floating button reached
|
|
64010
|
+
* with Tab, the ✕ of the detail popover, a field of a popover --
|
|
64011
|
+
* gives it back to the canvas BEFORE it goes. Removing the
|
|
64012
|
+
* focused element is a focus loss the browsers do not report
|
|
64013
|
+
* alike: Chromium fires a focusout, which _on_focusout_restore
|
|
64014
|
+
* answers; Firefox fires none and leaves the focus on <body>,
|
|
64015
|
+
* and the graph is deaf to Escape, Delete and ctrl+A until the
|
|
64016
|
+
* next click on it.
|
|
64017
|
+
*
|
|
63683
64018
|
* @param {object} gobj
|
|
63684
64019
|
* @param {...string} keys - priv property names to remove
|
|
63685
64020
|
************************************************************/
|
|
63686
64021
|
function hide_overlay(gobj, ...keys) {
|
|
63687
64022
|
let priv = gobj.priv;
|
|
63688
64023
|
for (let key of keys) if (priv[key]) {
|
|
63689
|
-
priv[key]
|
|
64024
|
+
let el = priv[key];
|
|
64025
|
+
if (el.contains(document.activeElement) && !gobj_is_destroying(gobj)) focus_main_canvas(priv.$container);
|
|
64026
|
+
el.remove();
|
|
63690
64027
|
priv[key] = null;
|
|
63691
64028
|
}
|
|
63692
64029
|
}
|
|
@@ -63731,9 +64068,7 @@ function graphs_write_is_owed(gobj) {
|
|
|
63731
64068
|
return Object.keys(gobj.priv._graphs_writes_owed).length > 0;
|
|
63732
64069
|
}
|
|
63733
64070
|
function mark_graph_dirty(gobj) {
|
|
63734
|
-
|
|
63735
|
-
enableElements($container, ".EV_SAVE_GRAPH");
|
|
63736
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", true);
|
|
64071
|
+
light_save_button(gobj, true);
|
|
63737
64072
|
}
|
|
63738
64073
|
/************************************************************
|
|
63739
64074
|
* Extract width/height from a style's size property.
|
|
@@ -63748,13 +64083,15 @@ function extract_size(style) {
|
|
|
63748
64083
|
}
|
|
63749
64084
|
/************************************************************
|
|
63750
64085
|
* Show a pair of floating icons (gear + trash) next to an
|
|
63751
|
-
* element.
|
|
64086
|
+
* element. The titles are i18n KEYS (see create_floating_icon);
|
|
64087
|
+
* each click sends its event to `gobj` with the same identity
|
|
64088
|
+
* `kw`. Returns {icon_el, delete_el}.
|
|
63752
64089
|
************************************************************/
|
|
63753
|
-
function show_dual_icons(gobj, x, y,
|
|
64090
|
+
function show_dual_icons(gobj, x, y, gear_key, gear_event, trash_key, trash_event, kw) {
|
|
63754
64091
|
let priv = gobj.priv;
|
|
63755
|
-
const icon_el = create_floating_icon("gear", "#1890ff", x, y,
|
|
64092
|
+
const icon_el = create_floating_icon("gear", "#1890ff", x, y, gear_key, gobj, gear_event, kw);
|
|
63756
64093
|
priv.$container.appendChild(icon_el);
|
|
63757
|
-
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y + floating_icon_step(),
|
|
64094
|
+
const delete_el = create_floating_icon("trash", "#ff4d4f", x, y + floating_icon_step(), trash_key, gobj, trash_event, kw);
|
|
63758
64095
|
priv.$container.appendChild(delete_el);
|
|
63759
64096
|
return {
|
|
63760
64097
|
icon_el,
|
|
@@ -63788,19 +64125,34 @@ function touch_control_css() {
|
|
|
63788
64125
|
if (!coarse_pointer()) return "";
|
|
63789
64126
|
return "min-height:44px;font-size:16px;";
|
|
63790
64127
|
}
|
|
64128
|
+
var form_control_seq = 0;
|
|
63791
64129
|
function create_form_label(parent, text) {
|
|
63792
64130
|
let label = document.createElement("label");
|
|
63793
64131
|
label.textContent = t(text);
|
|
64132
|
+
label.setAttribute("data-i18n", text);
|
|
63794
64133
|
label.style.cssText = "display:block;margin-bottom:4px;font-weight:500;";
|
|
63795
64134
|
parent.appendChild(label);
|
|
63796
64135
|
return label;
|
|
63797
64136
|
}
|
|
64137
|
+
function name_form_control(parent, control) {
|
|
64138
|
+
let label = parent.lastElementChild;
|
|
64139
|
+
if (!label || label.tagName !== "LABEL") return;
|
|
64140
|
+
let key = label.getAttribute("data-i18n");
|
|
64141
|
+
if (!key) return;
|
|
64142
|
+
control.id = "g6-form-control-" + ++form_control_seq;
|
|
64143
|
+
label.htmlFor = control.id;
|
|
64144
|
+
control.setAttribute("title", t(key));
|
|
64145
|
+
control.setAttribute("data-i18n-title", key);
|
|
64146
|
+
control.setAttribute("aria-label", t(key));
|
|
64147
|
+
control.setAttribute("data-i18n-aria-label", key);
|
|
64148
|
+
}
|
|
63798
64149
|
function create_form_color_input(parent, value, onInput) {
|
|
63799
64150
|
let input = document.createElement("input");
|
|
63800
64151
|
input.type = "color";
|
|
63801
64152
|
input.value = value;
|
|
63802
64153
|
input.style.cssText = "width:100%;height:30px;padding:0;border:1px solid var(--bulma-border-weak, #d9d9d9);border-radius:4px;cursor:pointer;margin-bottom:10px;" + touch_control_css();
|
|
63803
64154
|
if (onInput) input.addEventListener("input", onInput);
|
|
64155
|
+
name_form_control(parent, input);
|
|
63804
64156
|
parent.appendChild(input);
|
|
63805
64157
|
return input;
|
|
63806
64158
|
}
|
|
@@ -63812,6 +64164,7 @@ function create_form_number_input(parent, value, min, max, onInput) {
|
|
|
63812
64164
|
input.value = value;
|
|
63813
64165
|
input.style.cssText = "width:100%;padding:4px 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;box-sizing:border-box;margin-bottom:10px;" + touch_control_css();
|
|
63814
64166
|
if (onInput) input.addEventListener("input", onInput);
|
|
64167
|
+
name_form_control(parent, input);
|
|
63815
64168
|
parent.appendChild(input);
|
|
63816
64169
|
return input;
|
|
63817
64170
|
}
|
|
@@ -63821,17 +64174,31 @@ function create_form_select(parent, options, marginBottom) {
|
|
|
63821
64174
|
for (let opt of options) {
|
|
63822
64175
|
let o = document.createElement("option");
|
|
63823
64176
|
o.value = opt.value;
|
|
63824
|
-
o.textContent = opt.
|
|
64177
|
+
o.textContent = t(opt.i18n);
|
|
64178
|
+
o.setAttribute("data-i18n", opt.i18n);
|
|
63825
64179
|
select.appendChild(o);
|
|
63826
64180
|
}
|
|
64181
|
+
name_form_control(parent, select);
|
|
63827
64182
|
parent.appendChild(select);
|
|
63828
64183
|
return select;
|
|
63829
64184
|
}
|
|
63830
64185
|
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;";
|
|
63831
|
-
|
|
64186
|
+
/************************************************************
|
|
64187
|
+
* The buttons of a popover: each one SENDS an input event of
|
|
64188
|
+
* this gclass to `gobj`, and the action does the work, where
|
|
64189
|
+
* the `machine` trace sees it (V20.5 #4). A button is
|
|
64190
|
+
* {i18n, style, event, kw, form}
|
|
64191
|
+
* `kw` is the plain identity of what the popover is about
|
|
64192
|
+
* (copied per click); `form` names the controls whose `value`
|
|
64193
|
+
* goes in the kw too, as the control says it -- a string, the
|
|
64194
|
+
* action parses it. The kw says what was asked for, in the
|
|
64195
|
+
* trace: the identity and what the form held when it was
|
|
64196
|
+
* pressed.
|
|
64197
|
+
************************************************************/
|
|
64198
|
+
function create_form_button_row(parent, buttons, gobj) {
|
|
63832
64199
|
let btnRow = document.createElement("div");
|
|
63833
64200
|
btnRow.style.cssText = "display:flex;gap:8px;";
|
|
63834
|
-
for (let { i18n, style,
|
|
64201
|
+
for (let { i18n, style, event, kw, form } of buttons) {
|
|
63835
64202
|
let btn = document.createElement("button");
|
|
63836
64203
|
btn.textContent = t(i18n);
|
|
63837
64204
|
btn.setAttribute("data-i18n", i18n);
|
|
@@ -63842,18 +64209,28 @@ function create_form_button_row(parent, buttons) {
|
|
|
63842
64209
|
btn.style.cssText = style + touch_control_css();
|
|
63843
64210
|
btn.addEventListener("click", (e) => {
|
|
63844
64211
|
e.stopPropagation();
|
|
63845
|
-
|
|
64212
|
+
gobj_send_event(gobj, event, form_kw(kw, form), gobj);
|
|
63846
64213
|
});
|
|
63847
64214
|
btnRow.appendChild(btn);
|
|
63848
64215
|
}
|
|
63849
64216
|
parent.appendChild(btnRow);
|
|
63850
64217
|
return btnRow;
|
|
63851
64218
|
}
|
|
64219
|
+
function form_kw(kw, form) {
|
|
64220
|
+
let out = json_deep_copy(kw || {});
|
|
64221
|
+
for (let [name, control] of Object.entries(form || {})) out[name] = String(control.value);
|
|
64222
|
+
return out;
|
|
64223
|
+
}
|
|
63852
64224
|
/************************************************************
|
|
63853
64225
|
* Show a confirmation popover next to a target element.
|
|
63854
|
-
*
|
|
64226
|
+
*
|
|
64227
|
+
* `question` is the plain identity of what is asked, {what,
|
|
64228
|
+
* id|ids}: the confirm button sends it with EV_CONFIRMED and the
|
|
64229
|
+
* cancel button with EV_CANCEL_CONFIRM, and the actions answer.
|
|
64230
|
+
* `priv_key` is where the popover is kept, and it must be the
|
|
64231
|
+
* one CONFIRM_POPOVER_OF names for `question.what`.
|
|
63855
64232
|
************************************************************/
|
|
63856
|
-
function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_color,
|
|
64233
|
+
function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_color, question, priv_key) {
|
|
63857
64234
|
hide_overlay(gobj, priv_key);
|
|
63858
64235
|
let priv = gobj.priv;
|
|
63859
64236
|
let containerRect = priv.$container.getBoundingClientRect();
|
|
@@ -63874,14 +64251,17 @@ function show_confirm_popover(gobj, target_el, message, confirm_text, confirm_co
|
|
|
63874
64251
|
create_form_button_row(popover, [{
|
|
63875
64252
|
i18n: "cancel",
|
|
63876
64253
|
style: BTN_STYLE_CANCEL,
|
|
63877
|
-
|
|
64254
|
+
event: "EV_CANCEL_CONFIRM",
|
|
64255
|
+
kw: question
|
|
63878
64256
|
}, {
|
|
63879
64257
|
i18n: confirm_text,
|
|
63880
64258
|
style: "flex:1;padding:6px;background:" + confirm_color + ";color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
63881
|
-
|
|
63882
|
-
|
|
64259
|
+
event: "EV_CONFIRMED",
|
|
64260
|
+
kw: question
|
|
64261
|
+
}], gobj);
|
|
63883
64262
|
priv.$container.appendChild(popover);
|
|
63884
64263
|
priv[priv_key] = popover;
|
|
64264
|
+
priv._confirm_questions[priv_key] = json_deep_copy(question);
|
|
63885
64265
|
clamp_popover_position(gobj, popover);
|
|
63886
64266
|
}
|
|
63887
64267
|
/************************************************************
|
|
@@ -63959,27 +64339,30 @@ function paint_selection(gobj, ids) {
|
|
|
63959
64339
|
* Zoom-to-selection can only act on a selection.
|
|
63960
64340
|
*
|
|
63961
64341
|
* The attribute is toggled on the element instead of re-rendering
|
|
63962
|
-
* the toolbar, which would rebuild its innerHTML
|
|
63963
|
-
*
|
|
63964
|
-
*
|
|
64342
|
+
* the toolbar, which would rebuild its whole innerHTML each time a
|
|
64343
|
+
* card is ticked. A rebuild asks the same question
|
|
64344
|
+
* (selection_is_painted) in the toolbar's getItems().
|
|
63965
64345
|
************************************************************/
|
|
64346
|
+
function selection_is_painted(gobj) {
|
|
64347
|
+
return (gobj.priv._selected_paint_ids || []).length > 0;
|
|
64348
|
+
}
|
|
63966
64349
|
function update_zoom_selection_button(gobj) {
|
|
63967
|
-
let priv = gobj.priv;
|
|
63968
64350
|
let $container = gobj_read_attr(gobj, "$container");
|
|
63969
64351
|
if (!$container) return;
|
|
63970
64352
|
if (!$container.querySelector(".EV_ZOOM_SELECTION")) return;
|
|
63971
|
-
if ((
|
|
64353
|
+
if (selection_is_painted(gobj)) enableElements($container, ".EV_ZOOM_SELECTION");
|
|
63972
64354
|
else disableElements($container, ".EV_ZOOM_SELECTION");
|
|
63973
64355
|
}
|
|
63974
64356
|
/************************************************************
|
|
63975
64357
|
* The selection mode is a state, so it has to LOOK like one:
|
|
63976
64358
|
* a PRESSED toggle, not a button wearing one of the palette's
|
|
63977
|
-
* action colours (see `pressed_state` in lib_graph.css).
|
|
64359
|
+
* action colours (see `pressed_state` in lib_graph.css). And
|
|
64360
|
+
* it SAYS it, in `aria-pressed`, for whoever does not see it.
|
|
63978
64361
|
*
|
|
63979
64362
|
* Toggled on the element rather than re-rendered with the
|
|
63980
64363
|
* toolbar, for the same reason as the button above: a
|
|
63981
|
-
* re-render rebuilds the innerHTML
|
|
63982
|
-
*
|
|
64364
|
+
* re-render rebuilds the whole innerHTML. A rebuild draws the
|
|
64365
|
+
* same state, baked in the edit toolbar's getItems().
|
|
63983
64366
|
************************************************************/
|
|
63984
64367
|
function update_selection_mode_button(gobj) {
|
|
63985
64368
|
let priv = gobj.priv;
|
|
@@ -63987,6 +64370,9 @@ function update_selection_mode_button(gobj) {
|
|
|
63987
64370
|
if (!$container) return;
|
|
63988
64371
|
if (!$container.querySelector(".EV_TOGGLE_SELECTION_MODE")) return;
|
|
63989
64372
|
set_pressed_state($container, ".EV_TOGGLE_SELECTION_MODE", priv.selection_mode);
|
|
64373
|
+
$container.querySelectorAll(".EV_TOGGLE_SELECTION_MODE").forEach(($el) => {
|
|
64374
|
+
$el.setAttribute("aria-pressed", priv.selection_mode ? "true" : "false");
|
|
64375
|
+
});
|
|
63990
64376
|
}
|
|
63991
64377
|
/************************************************************
|
|
63992
64378
|
* Select a SET of nodes: what a marquee and a shift-click do.
|
|
@@ -64441,13 +64827,18 @@ function show_link_icon_if_fkey(gobj) {
|
|
|
64441
64827
|
let canvasPos = get_port_canvas_position(gobj, priv._selected_node_id, priv._selected_port_key);
|
|
64442
64828
|
if (!canvasPos) return;
|
|
64443
64829
|
let vp = graph.getViewportByCanvas([canvasPos.x, canvasPos.y]);
|
|
64444
|
-
let
|
|
64445
|
-
|
|
64446
|
-
|
|
64830
|
+
let identity = {
|
|
64831
|
+
node_id: priv._selected_node_id,
|
|
64832
|
+
port_key: priv._selected_port_key
|
|
64833
|
+
};
|
|
64834
|
+
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);
|
|
64447
64835
|
icon.addEventListener("pointerdown", (e) => {
|
|
64448
64836
|
e.stopPropagation();
|
|
64449
64837
|
e.preventDefault();
|
|
64450
|
-
|
|
64838
|
+
gobj_send_event(gobj, "EV_START_LINK_DRAG", Object.assign(json_deep_copy(identity), {
|
|
64839
|
+
client_x: e.clientX,
|
|
64840
|
+
client_y: e.clientY
|
|
64841
|
+
}), gobj);
|
|
64451
64842
|
});
|
|
64452
64843
|
priv.$container.appendChild(icon);
|
|
64453
64844
|
priv._link_icon_el = icon;
|
|
@@ -64497,7 +64888,10 @@ function show_port_icon(gobj) {
|
|
|
64497
64888
|
if (!priv._selected_node_id || !priv._selected_port_key) return;
|
|
64498
64889
|
let xy = port_icon_xy(gobj);
|
|
64499
64890
|
if (!xy) return;
|
|
64500
|
-
let icon = create_floating_icon("gear", "#1890ff", xy.x, xy.y,
|
|
64891
|
+
let icon = create_floating_icon("gear", "#1890ff", xy.x, xy.y, "port properties", gobj, "EV_TOGGLE_PORT_POPOVER", {
|
|
64892
|
+
node_id: priv._selected_node_id,
|
|
64893
|
+
port_key: priv._selected_port_key
|
|
64894
|
+
});
|
|
64501
64895
|
priv.$container.appendChild(icon);
|
|
64502
64896
|
priv._port_icon_el = icon;
|
|
64503
64897
|
}
|
|
@@ -64582,7 +64976,7 @@ function show_port_popover(gobj) {
|
|
|
64582
64976
|
let shapeSelect = create_form_select(popover, PORT_SHAPES.map((shape) => {
|
|
64583
64977
|
return {
|
|
64584
64978
|
value: shape,
|
|
64585
|
-
|
|
64979
|
+
i18n: shape
|
|
64586
64980
|
};
|
|
64587
64981
|
}));
|
|
64588
64982
|
shapeSelect.value = orig_shape;
|
|
@@ -64593,31 +64987,40 @@ function show_port_popover(gobj) {
|
|
|
64593
64987
|
let scopeSelect = create_form_select(popover, [
|
|
64594
64988
|
{
|
|
64595
64989
|
value: "this",
|
|
64596
|
-
|
|
64990
|
+
i18n: "this port"
|
|
64597
64991
|
},
|
|
64598
64992
|
{
|
|
64599
64993
|
value: "same_topic",
|
|
64600
|
-
|
|
64994
|
+
i18n: "same port in topic"
|
|
64601
64995
|
},
|
|
64602
64996
|
{
|
|
64603
64997
|
value: "all",
|
|
64604
|
-
|
|
64998
|
+
i18n: "all ports"
|
|
64605
64999
|
}
|
|
64606
65000
|
]);
|
|
64607
65001
|
create_form_button_row(popover, [{
|
|
64608
65002
|
i18n: "cancel",
|
|
64609
65003
|
style: BTN_STYLE_CANCEL,
|
|
64610
|
-
|
|
64611
|
-
|
|
65004
|
+
event: "EV_CANCEL_PORT_POPOVER",
|
|
65005
|
+
kw: {
|
|
65006
|
+
node_id,
|
|
65007
|
+
port_key
|
|
64612
65008
|
}
|
|
64613
65009
|
}, {
|
|
64614
65010
|
i18n: "apply",
|
|
64615
65011
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
64616
|
-
|
|
64617
|
-
|
|
64618
|
-
|
|
65012
|
+
event: "EV_APPLY_PORT_POPOVER",
|
|
65013
|
+
kw: {
|
|
65014
|
+
node_id,
|
|
65015
|
+
port_key,
|
|
65016
|
+
r_before: orig_r
|
|
65017
|
+
},
|
|
65018
|
+
form: {
|
|
65019
|
+
shape: shapeSelect,
|
|
65020
|
+
r: rInput,
|
|
65021
|
+
scope: scopeSelect
|
|
64619
65022
|
}
|
|
64620
|
-
}]);
|
|
65023
|
+
}], gobj);
|
|
64621
65024
|
priv.$container.appendChild(popover);
|
|
64622
65025
|
priv._port_popover_el = popover;
|
|
64623
65026
|
set_preview_undo(gobj, "_port_preview_undo", undo_port);
|
|
@@ -64834,8 +65237,16 @@ function try_complete_link(gobj, clicked_node_id, clicked_port_key) {
|
|
|
64834
65237
|
/************************************************************
|
|
64835
65238
|
* Drag-link: drag from link icon to a hook port.
|
|
64836
65239
|
* Draws a temporary SVG line from the fkey port to the cursor.
|
|
65240
|
+
*
|
|
65241
|
+
* Run by ac_start_link_drag. The pointer's MOVES only draw the
|
|
65242
|
+
* line and the cursor -- the drag's own picture, no action, and
|
|
65243
|
+
* one event per move would bury the machine trace -- while the
|
|
65244
|
+
* END of the gesture is an event: EV_LINK_DRAG_END {client_x,
|
|
65245
|
+
* client_y, dragged} on the release, EV_LINK_DRAG_CANCEL when
|
|
65246
|
+
* the browser takes the pointer. Their actions take the drag
|
|
65247
|
+
* down (end_link_drag) and link, or leave the linking mode.
|
|
64837
65248
|
************************************************************/
|
|
64838
|
-
function start_link_drag(gobj,
|
|
65249
|
+
function start_link_drag(gobj, client_x, client_y) {
|
|
64839
65250
|
let priv = gobj.priv;
|
|
64840
65251
|
let graph = priv.graph;
|
|
64841
65252
|
if (!priv._linking_mode) enter_linking_mode(gobj);
|
|
@@ -64849,8 +65260,8 @@ function start_link_drag(gobj, e) {
|
|
|
64849
65260
|
let line = document.createElementNS("http://www.w3.org/2000/svg", "line");
|
|
64850
65261
|
line.setAttribute("x1", startX);
|
|
64851
65262
|
line.setAttribute("y1", startY);
|
|
64852
|
-
line.setAttribute("x2",
|
|
64853
|
-
line.setAttribute("y2",
|
|
65263
|
+
line.setAttribute("x2", client_x - containerRect.left);
|
|
65264
|
+
line.setAttribute("y2", client_y - containerRect.top);
|
|
64854
65265
|
line.setAttribute("stroke", "#52c41a");
|
|
64855
65266
|
line.setAttribute("stroke-width", "2");
|
|
64856
65267
|
line.setAttribute("stroke-dasharray", "6 3");
|
|
@@ -64869,41 +65280,47 @@ function start_link_drag(gobj, e) {
|
|
|
64869
65280
|
priv.$container.style.cursor = hoverTarget ? "copy" : "not-allowed";
|
|
64870
65281
|
}
|
|
64871
65282
|
function onPointerUp(ev) {
|
|
64872
|
-
|
|
64873
|
-
|
|
64874
|
-
|
|
64875
|
-
|
|
64876
|
-
|
|
64877
|
-
priv._link_drag_svg.remove();
|
|
64878
|
-
priv._link_drag_svg = null;
|
|
64879
|
-
}
|
|
64880
|
-
if (!dragged) return;
|
|
64881
|
-
let cx = ev.clientX - containerRect.left;
|
|
64882
|
-
let cy = ev.clientY - containerRect.top;
|
|
64883
|
-
let canvasPt = graph.getCanvasByViewport([cx, cy]);
|
|
64884
|
-
let target = find_hook_at_point(gobj, canvasPt[0], canvasPt[1]);
|
|
64885
|
-
if (target) try_complete_link(gobj, target.node_id, target.port_key);
|
|
64886
|
-
else exit_linking_mode(gobj);
|
|
65283
|
+
gobj_send_event(gobj, "EV_LINK_DRAG_END", {
|
|
65284
|
+
client_x: ev.clientX,
|
|
65285
|
+
client_y: ev.clientY,
|
|
65286
|
+
dragged
|
|
65287
|
+
}, gobj);
|
|
64887
65288
|
}
|
|
64888
65289
|
function onPointerCancel(ev) {
|
|
65290
|
+
gobj_send_event(gobj, "EV_LINK_DRAG_CANCEL", {}, gobj);
|
|
65291
|
+
}
|
|
65292
|
+
function unwire() {
|
|
64889
65293
|
document.removeEventListener("pointermove", onPointerMove);
|
|
64890
65294
|
document.removeEventListener("pointerup", onPointerUp);
|
|
64891
65295
|
document.removeEventListener("pointercancel", onPointerCancel);
|
|
64892
|
-
priv.$container.style.cursor = "";
|
|
64893
|
-
if (priv._link_drag_svg) {
|
|
64894
|
-
priv._link_drag_svg.remove();
|
|
64895
|
-
priv._link_drag_svg = null;
|
|
64896
|
-
}
|
|
64897
|
-
exit_linking_mode(gobj);
|
|
64898
65296
|
}
|
|
64899
65297
|
document.addEventListener("pointermove", onPointerMove);
|
|
64900
65298
|
document.addEventListener("pointerup", onPointerUp);
|
|
64901
65299
|
document.addEventListener("pointercancel", onPointerCancel);
|
|
64902
|
-
|
|
64903
|
-
|
|
64904
|
-
|
|
64905
|
-
|
|
65300
|
+
priv._link_drag = {
|
|
65301
|
+
left: containerRect.left,
|
|
65302
|
+
top: containerRect.top,
|
|
65303
|
+
unwire
|
|
64906
65304
|
};
|
|
65305
|
+
priv._drag_unwire = unwire;
|
|
65306
|
+
}
|
|
65307
|
+
/************************************************************
|
|
65308
|
+
* Take a link drag down: its listeners, its line, its cursor.
|
|
65309
|
+
* What was linked, or not, is the caller's.
|
|
65310
|
+
************************************************************/
|
|
65311
|
+
function end_link_drag(gobj) {
|
|
65312
|
+
let priv = gobj.priv;
|
|
65313
|
+
let drag = priv._link_drag;
|
|
65314
|
+
priv._link_drag = null;
|
|
65315
|
+
if (drag) {
|
|
65316
|
+
drag.unwire();
|
|
65317
|
+
if (priv._drag_unwire === drag.unwire) priv._drag_unwire = null;
|
|
65318
|
+
}
|
|
65319
|
+
priv.$container.style.cursor = "";
|
|
65320
|
+
if (priv._link_drag_svg) {
|
|
65321
|
+
priv._link_drag_svg.remove();
|
|
65322
|
+
priv._link_drag_svg = null;
|
|
65323
|
+
}
|
|
64907
65324
|
}
|
|
64908
65325
|
/************************************************************
|
|
64909
65326
|
* Find if a canvas point hits a valid hook port during
|
|
@@ -65193,7 +65610,7 @@ function show_edge_icon(gobj) {
|
|
|
65193
65610
|
if (!priv._selected_edge_id) return;
|
|
65194
65611
|
let mid = get_edge_viewport_midpoint(gobj, priv._selected_edge_id);
|
|
65195
65612
|
if (!mid) return;
|
|
65196
|
-
let icons = show_dual_icons(gobj, mid.x + 4, mid.y + floating_icon_dy(),
|
|
65613
|
+
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 });
|
|
65197
65614
|
priv._edge_icon_el = icons.icon_el;
|
|
65198
65615
|
priv._edge_delete_el = icons.delete_el;
|
|
65199
65616
|
}
|
|
@@ -65289,31 +65706,33 @@ function show_edge_popover(gobj) {
|
|
|
65289
65706
|
let scopeSelect = create_form_select(popover, [
|
|
65290
65707
|
{
|
|
65291
65708
|
value: "this",
|
|
65292
|
-
|
|
65709
|
+
i18n: "this edge"
|
|
65293
65710
|
},
|
|
65294
65711
|
{
|
|
65295
65712
|
value: "same_type",
|
|
65296
|
-
|
|
65713
|
+
i18n: "same type edges"
|
|
65297
65714
|
},
|
|
65298
65715
|
{
|
|
65299
65716
|
value: "all",
|
|
65300
|
-
|
|
65717
|
+
i18n: "all edges"
|
|
65301
65718
|
}
|
|
65302
65719
|
]);
|
|
65303
65720
|
create_form_button_row(popover, [{
|
|
65304
65721
|
i18n: "cancel",
|
|
65305
65722
|
style: BTN_STYLE_CANCEL,
|
|
65306
|
-
|
|
65307
|
-
|
|
65308
|
-
}
|
|
65723
|
+
event: "EV_CANCEL_EDGE_POPOVER",
|
|
65724
|
+
kw: { edge_id }
|
|
65309
65725
|
}, {
|
|
65310
65726
|
i18n: "apply",
|
|
65311
65727
|
style: "flex:1;padding:6px;background:#52c41a;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
65312
|
-
|
|
65313
|
-
|
|
65314
|
-
|
|
65315
|
-
|
|
65316
|
-
|
|
65728
|
+
event: "EV_APPLY_EDGE_POPOVER",
|
|
65729
|
+
kw: { edge_id },
|
|
65730
|
+
form: {
|
|
65731
|
+
line_width: lwInput,
|
|
65732
|
+
color: colorInput,
|
|
65733
|
+
scope: scopeSelect
|
|
65734
|
+
}
|
|
65735
|
+
}], gobj);
|
|
65317
65736
|
priv.$container.appendChild(popover);
|
|
65318
65737
|
priv._edge_popover_el = popover;
|
|
65319
65738
|
set_preview_undo(gobj, "_edge_preview_undo", undo_edge);
|
|
@@ -65350,7 +65769,7 @@ function show_node_icon(gobj) {
|
|
|
65350
65769
|
if (!priv._selected_node_id || priv._selected_port_key) return;
|
|
65351
65770
|
let rect = get_node_viewport_rect(gobj, priv._selected_node_id);
|
|
65352
65771
|
if (!rect) return;
|
|
65353
|
-
let icons = show_dual_icons(gobj, rect.right + 4, rect.top + floating_icon_dy(),
|
|
65772
|
+
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 });
|
|
65354
65773
|
priv._node_icon_el = icons.icon_el;
|
|
65355
65774
|
priv._node_delete_el = icons.delete_el;
|
|
65356
65775
|
}
|
|
@@ -65441,7 +65860,7 @@ function show_node_popover(gobj) {
|
|
|
65441
65860
|
let shapeSelect = create_form_select(popover, NODE_SHAPES.map((shape) => {
|
|
65442
65861
|
return {
|
|
65443
65862
|
value: shape,
|
|
65444
|
-
|
|
65863
|
+
i18n: shape
|
|
65445
65864
|
};
|
|
65446
65865
|
}));
|
|
65447
65866
|
shapeSelect.value = nodeData.data && nodeData.data.desc ? node_figure_of(gobj, nodeData.data.desc, nodeData.data.graph_props || {}) : DEFAULT_NODE_SHAPE;
|
|
@@ -65450,31 +65869,38 @@ function show_node_popover(gobj) {
|
|
|
65450
65869
|
let scopeSelect = create_form_select(popover, [
|
|
65451
65870
|
{
|
|
65452
65871
|
value: "this",
|
|
65453
|
-
|
|
65872
|
+
i18n: "this node"
|
|
65454
65873
|
},
|
|
65455
65874
|
{
|
|
65456
65875
|
value: "same_topic",
|
|
65457
|
-
|
|
65876
|
+
i18n: "same topic nodes"
|
|
65458
65877
|
},
|
|
65459
65878
|
{
|
|
65460
65879
|
value: "all",
|
|
65461
|
-
|
|
65880
|
+
i18n: "all nodes"
|
|
65462
65881
|
}
|
|
65463
65882
|
]);
|
|
65464
65883
|
create_form_button_row(popover, [{
|
|
65465
65884
|
i18n: "cancel",
|
|
65466
65885
|
style: BTN_STYLE_CANCEL,
|
|
65467
|
-
|
|
65468
|
-
|
|
65469
|
-
}
|
|
65886
|
+
event: "EV_CANCEL_NODE_POPOVER",
|
|
65887
|
+
kw: { node_id }
|
|
65470
65888
|
}, {
|
|
65471
65889
|
i18n: "apply",
|
|
65472
65890
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
65473
|
-
|
|
65474
|
-
|
|
65475
|
-
|
|
65891
|
+
event: "EV_APPLY_NODE_POPOVER",
|
|
65892
|
+
kw: {
|
|
65893
|
+
node_id,
|
|
65894
|
+
shape_before: orig_figure
|
|
65895
|
+
},
|
|
65896
|
+
form: {
|
|
65897
|
+
fill: fillInput,
|
|
65898
|
+
stroke: strokeInput,
|
|
65899
|
+
line_width: lwInput,
|
|
65900
|
+
scope: scopeSelect,
|
|
65901
|
+
shape: shapeSelect
|
|
65476
65902
|
}
|
|
65477
|
-
}]);
|
|
65903
|
+
}], gobj);
|
|
65478
65904
|
priv.$container.appendChild(popover);
|
|
65479
65905
|
priv._node_popover_el = popover;
|
|
65480
65906
|
set_preview_undo(gobj, "_node_preview_undo", undo_node);
|
|
@@ -65494,6 +65920,39 @@ function hide_node_detail(gobj) {
|
|
|
65494
65920
|
gobj.priv._detail_node_id = null;
|
|
65495
65921
|
hide_overlay(gobj, "_node_detail_el");
|
|
65496
65922
|
}
|
|
65923
|
+
/************************************************************
|
|
65924
|
+
* The ✕ of the detail popover. Built as an element and not in
|
|
65925
|
+
* the popover's markup, so that it is a whole button: named
|
|
65926
|
+
* with its key (a language switch renames it), reachable by
|
|
65927
|
+
* the keyboard and pressed by Enter or Space as by the pointer.
|
|
65928
|
+
* Its click sends EV_CLOSE_NODE_DETAIL {node_id} and nothing
|
|
65929
|
+
* else; a pointer press does not take the focus.
|
|
65930
|
+
************************************************************/
|
|
65931
|
+
function create_detail_close(gobj, color, node_id) {
|
|
65932
|
+
let el = document.createElement("div");
|
|
65933
|
+
el.className = "g6-detail-close";
|
|
65934
|
+
el.setAttribute("role", "button");
|
|
65935
|
+
el.setAttribute("tabindex", "0");
|
|
65936
|
+
el.setAttribute("title", t("close"));
|
|
65937
|
+
el.setAttribute("data-i18n-title", "close");
|
|
65938
|
+
el.setAttribute("aria-label", t("close"));
|
|
65939
|
+
el.setAttribute("data-i18n-aria-label", "close");
|
|
65940
|
+
el.style.color = color;
|
|
65941
|
+
el.textContent = "×";
|
|
65942
|
+
el.addEventListener("click", (e) => {
|
|
65943
|
+
e.stopPropagation();
|
|
65944
|
+
gobj_send_event(gobj, "EV_CLOSE_NODE_DETAIL", { node_id }, gobj);
|
|
65945
|
+
});
|
|
65946
|
+
keep_focus_on_press(el);
|
|
65947
|
+
click_on_enter_or_space(el);
|
|
65948
|
+
return el;
|
|
65949
|
+
}
|
|
65950
|
+
function detail_div(class_name, text) {
|
|
65951
|
+
let el = document.createElement("div");
|
|
65952
|
+
if (class_name) el.className = class_name;
|
|
65953
|
+
if (text !== void 0) el.textContent = text;
|
|
65954
|
+
return el;
|
|
65955
|
+
}
|
|
65497
65956
|
function show_node_detail_popover(gobj, node_id) {
|
|
65498
65957
|
let priv = gobj.priv;
|
|
65499
65958
|
let graph = priv.graph;
|
|
@@ -65523,7 +65982,19 @@ function show_node_detail_popover(gobj, node_id) {
|
|
|
65523
65982
|
popover.style.overflow = "auto";
|
|
65524
65983
|
popover.style.padding = "0 12px 12px";
|
|
65525
65984
|
popover.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif";
|
|
65526
|
-
let
|
|
65985
|
+
let head = detail_div("g6-detail-head");
|
|
65986
|
+
head.style.background = bg;
|
|
65987
|
+
let names = detail_div("");
|
|
65988
|
+
names.style.flex = "1 1 auto";
|
|
65989
|
+
names.style.minWidth = "0";
|
|
65990
|
+
names.appendChild(detail_div("g6-detail-id", id));
|
|
65991
|
+
let topic_el = detail_div("g6-detail-topic", topic);
|
|
65992
|
+
topic_el.style.color = sub;
|
|
65993
|
+
names.appendChild(topic_el);
|
|
65994
|
+
head.appendChild(names);
|
|
65995
|
+
head.appendChild(create_detail_close(gobj, sub, node_id));
|
|
65996
|
+
popover.appendChild(head);
|
|
65997
|
+
let n_rows = 0;
|
|
65527
65998
|
for (let key of Object.keys(record)) {
|
|
65528
65999
|
if (key.indexOf("__") === 0) continue;
|
|
65529
66000
|
let v = record[key];
|
|
@@ -65532,14 +66003,21 @@ function show_node_detail_popover(gobj, node_id) {
|
|
|
65532
66003
|
else if (typeof v === "object") vs = JSON.stringify(v);
|
|
65533
66004
|
else vs = String(v);
|
|
65534
66005
|
if (vs.length > 240) vs = vs.slice(0, 240) + "…";
|
|
65535
|
-
|
|
66006
|
+
let row = detail_div("g6-detail-row");
|
|
66007
|
+
row.style.borderTop = `1px solid ${rowbd}`;
|
|
66008
|
+
let key_el = detail_div("g6-detail-key", key);
|
|
66009
|
+
key_el.style.color = sub;
|
|
66010
|
+
row.appendChild(key_el);
|
|
66011
|
+
row.appendChild(detail_div("g6-detail-val", vs));
|
|
66012
|
+
popover.appendChild(row);
|
|
66013
|
+
n_rows++;
|
|
66014
|
+
}
|
|
66015
|
+
if (!n_rows) {
|
|
66016
|
+
let empty = detail_div("g6-detail-empty", t("no fields"));
|
|
66017
|
+
empty.setAttribute("data-i18n", "no fields");
|
|
66018
|
+
empty.style.color = sub;
|
|
66019
|
+
popover.appendChild(empty);
|
|
65536
66020
|
}
|
|
65537
|
-
popover.innerHTML = `<div class="g6-detail-head" style="background:${bg};"><div style="flex:1 1 auto;min-width:0;"><div class="g6-detail-id">${escapeHtml(id)}</div><div class="g6-detail-topic" style="color:${sub};">${escapeHtml(topic)}</div></div><div class="g6-detail-close" role="button" tabindex="0" aria-label="${escapeHtml(t("close"))}" title="${escapeHtml(t("close"))}" style="color:${sub};">×</div></div>` + (rows || `<div class="g6-detail-empty" style="color:${sub};">${escapeHtml(t("no fields"))}</div>`);
|
|
65538
|
-
let close_el = popover.querySelector(".g6-detail-close");
|
|
65539
|
-
if (close_el) close_el.addEventListener("click", (e) => {
|
|
65540
|
-
e.stopPropagation();
|
|
65541
|
-
hide_node_detail(gobj);
|
|
65542
|
-
});
|
|
65543
66021
|
priv.$container.appendChild(popover);
|
|
65544
66022
|
priv._node_detail_el = popover;
|
|
65545
66023
|
priv._detail_node_id = node_id;
|
|
@@ -66061,10 +66539,10 @@ function request_delete_selection(gobj) {
|
|
|
66061
66539
|
execute_delete_selection(gobj, nodes);
|
|
66062
66540
|
return;
|
|
66063
66541
|
}
|
|
66064
|
-
show_confirm_popover(gobj, null, delete_question(nodes), "delete", "#ff4d4f",
|
|
66542
|
+
show_confirm_popover(gobj, null, delete_question(nodes), "delete", "#ff4d4f", {
|
|
66065
66543
|
what: "delete_selection",
|
|
66066
66544
|
ids: nodes.map((nd) => String(nd.id))
|
|
66067
|
-
},
|
|
66545
|
+
}, "_delete_confirm_el");
|
|
66068
66546
|
}
|
|
66069
66547
|
function execute_delete_selection(gobj, nodes) {
|
|
66070
66548
|
let priv = gobj.priv;
|
|
@@ -66081,10 +66559,10 @@ function execute_delete_selection(gobj, nodes) {
|
|
|
66081
66559
|
************************************************************/
|
|
66082
66560
|
function show_delete_confirm(gobj, nodeData) {
|
|
66083
66561
|
let priv = gobj.priv;
|
|
66084
|
-
show_confirm_popover(gobj, priv._node_delete_el, delete_question([nodeData]), "delete", "#ff4d4f",
|
|
66562
|
+
show_confirm_popover(gobj, priv._node_delete_el, delete_question([nodeData]), "delete", "#ff4d4f", {
|
|
66085
66563
|
what: "delete_node",
|
|
66086
66564
|
id: String(nodeData.id)
|
|
66087
|
-
},
|
|
66565
|
+
}, "_delete_confirm_el");
|
|
66088
66566
|
}
|
|
66089
66567
|
function hide_delete_confirm(gobj) {
|
|
66090
66568
|
hide_overlay(gobj, "_delete_confirm_el");
|
|
@@ -66133,6 +66611,7 @@ function show_create_popover(gobj) {
|
|
|
66133
66611
|
topicLabel.appendChild(document.createTextNode(":"));
|
|
66134
66612
|
popover.appendChild(topicLabel);
|
|
66135
66613
|
let topicSelect = document.createElement("select");
|
|
66614
|
+
topicSelect.className = "G6_CREATE_TOPIC";
|
|
66136
66615
|
topicSelect.setAttribute("title", t("topic"));
|
|
66137
66616
|
topicSelect.setAttribute("data-i18n-title", "topic");
|
|
66138
66617
|
topicSelect.setAttribute("aria-label", t("topic"));
|
|
@@ -66165,9 +66644,14 @@ function show_create_popover(gobj) {
|
|
|
66165
66644
|
});
|
|
66166
66645
|
let idLabel = document.createElement("div");
|
|
66167
66646
|
idLabel.style.cssText = "margin-bottom:4px;font-weight:500;";
|
|
66168
|
-
|
|
66647
|
+
let idWord = document.createElement("span");
|
|
66648
|
+
idWord.textContent = t("node id");
|
|
66649
|
+
idWord.setAttribute("data-i18n", "node id");
|
|
66650
|
+
idLabel.appendChild(idWord);
|
|
66651
|
+
idLabel.appendChild(document.createTextNode(":"));
|
|
66169
66652
|
popover.appendChild(idLabel);
|
|
66170
66653
|
let idInput = document.createElement("input");
|
|
66654
|
+
idInput.className = "G6_CREATE_ID";
|
|
66171
66655
|
idInput.type = "text";
|
|
66172
66656
|
idInput.placeholder = t("node id");
|
|
66173
66657
|
idInput.setAttribute("data-i18n-placeholder", "node id");
|
|
@@ -66178,39 +66662,31 @@ function show_create_popover(gobj) {
|
|
|
66178
66662
|
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();
|
|
66179
66663
|
popover.appendChild(idInput);
|
|
66180
66664
|
let errorEl = document.createElement("div");
|
|
66665
|
+
errorEl.className = "G6_CREATE_ERROR";
|
|
66181
66666
|
errorEl.style.cssText = "color:#ff4d4f;font-size:12px;margin-bottom:8px;display:none;";
|
|
66182
66667
|
popover.appendChild(errorEl);
|
|
66183
|
-
let createBtn
|
|
66184
|
-
create_form_button_row(popover, [{
|
|
66668
|
+
let createBtn = create_form_button_row(popover, [{
|
|
66185
66669
|
i18n: "cancel",
|
|
66186
66670
|
style: BTN_STYLE_CANCEL,
|
|
66187
|
-
|
|
66671
|
+
event: "EV_CLOSE_CREATE_POPOVER",
|
|
66672
|
+
kw: {}
|
|
66188
66673
|
}, {
|
|
66189
66674
|
i18n: "create",
|
|
66190
66675
|
style: "flex:1;padding:6px;background:#1890ff;color:#fff;border:none;border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;",
|
|
66191
|
-
|
|
66192
|
-
|
|
66193
|
-
|
|
66194
|
-
|
|
66195
|
-
|
|
66196
|
-
errorEl.style.display = "block";
|
|
66197
|
-
idInput.focus();
|
|
66198
|
-
return;
|
|
66199
|
-
}
|
|
66200
|
-
gobj_send_event(gobj, "EV_SUBMIT_NEW_NODE", {
|
|
66201
|
-
topic_name: String(topicSelect.value),
|
|
66202
|
-
id: node_id
|
|
66203
|
-
}, gobj);
|
|
66676
|
+
event: "EV_SUBMIT_NEW_NODE",
|
|
66677
|
+
kw: {},
|
|
66678
|
+
form: {
|
|
66679
|
+
topic_name: topicSelect,
|
|
66680
|
+
id: idInput
|
|
66204
66681
|
}
|
|
66205
|
-
}]);
|
|
66206
|
-
createBtn = popover.querySelector("button:last-child");
|
|
66682
|
+
}], gobj).lastElementChild;
|
|
66207
66683
|
idInput.addEventListener("keydown", (e) => {
|
|
66208
66684
|
if (e.key === "Enter") {
|
|
66209
66685
|
e.preventDefault();
|
|
66210
66686
|
createBtn.click();
|
|
66211
66687
|
} else if (e.key === "Escape") {
|
|
66212
66688
|
e.preventDefault();
|
|
66213
|
-
|
|
66689
|
+
gobj_send_event(gobj, "EV_CLOSE_CREATE_POPOVER", {}, gobj);
|
|
66214
66690
|
}
|
|
66215
66691
|
});
|
|
66216
66692
|
priv.$container.appendChild(popover);
|
|
@@ -66260,10 +66736,10 @@ function execute_unlink_edge(gobj, edgeData) {
|
|
|
66260
66736
|
function show_unlink_confirm(gobj, edgeData) {
|
|
66261
66737
|
let priv = gobj.priv;
|
|
66262
66738
|
const d = edgeData.data;
|
|
66263
|
-
show_confirm_popover(gobj, priv._edge_delete_el, t("unlink") + " " + d.child_id + " → " + d.parent_id + "?\n" + t("neither record is deleted"), "unlink", "#ff4d4f",
|
|
66739
|
+
show_confirm_popover(gobj, priv._edge_delete_el, t("unlink") + " " + d.child_id + " → " + d.parent_id + "?\n" + t("neither record is deleted"), "unlink", "#ff4d4f", {
|
|
66264
66740
|
what: "unlink_edge",
|
|
66265
66741
|
id: String(edgeData.id)
|
|
66266
|
-
},
|
|
66742
|
+
}, "_unlink_confirm_el");
|
|
66267
66743
|
}
|
|
66268
66744
|
function hide_unlink_confirm(gobj) {
|
|
66269
66745
|
hide_overlay(gobj, "_unlink_confirm_el");
|
|
@@ -67634,9 +68110,7 @@ function ac_load_data(gobj, event, kw, src) {
|
|
|
67634
68110
|
************************************************************/
|
|
67635
68111
|
function ac_save_graph(gobj, event, kw, src) {
|
|
67636
68112
|
if (gobj.priv.edit_mode) {
|
|
67637
|
-
|
|
67638
|
-
disableElements($container, ".EV_SAVE_GRAPH");
|
|
67639
|
-
set_submit_state($container, ".EV_SAVE_GRAPH", false);
|
|
68113
|
+
light_save_button(gobj, false);
|
|
67640
68114
|
let history = graph_get_plugin(gobj, "history");
|
|
67641
68115
|
if (history) history.clear();
|
|
67642
68116
|
save_geometry(gobj);
|
|
@@ -67913,12 +68387,22 @@ function ac_center_anchor(gobj, event, kw, src) {
|
|
|
67913
68387
|
return 0;
|
|
67914
68388
|
}
|
|
67915
68389
|
/************************************************************
|
|
67916
|
-
* What the anchor button says it will do next
|
|
68390
|
+
* What the anchor button says it will do next: its `title`,
|
|
68391
|
+
* and the `title_key` it is translated from.
|
|
67917
68392
|
************************************************************/
|
|
67918
68393
|
function anchor_title(state) {
|
|
67919
|
-
if (state === "arming") return
|
|
67920
|
-
|
|
67921
|
-
|
|
68394
|
+
if (state === "arming") return {
|
|
68395
|
+
title: t("click the element to centre on"),
|
|
68396
|
+
title_key: "click the element to centre on"
|
|
68397
|
+
};
|
|
68398
|
+
if (state === "on") return {
|
|
68399
|
+
title: t("centred: click to release"),
|
|
68400
|
+
title_key: "centred: click to release"
|
|
68401
|
+
};
|
|
68402
|
+
return {
|
|
68403
|
+
title: t("anchor view"),
|
|
68404
|
+
title_key: "anchor view"
|
|
68405
|
+
};
|
|
67922
68406
|
}
|
|
67923
68407
|
/************************************************************
|
|
67924
68408
|
* Every camera action ends the same way once an anchor is
|
|
@@ -68334,8 +68818,8 @@ function ac_set_layout$1(gobj, event, kw, src) {
|
|
|
68334
68818
|
function ac_set_operation_mode$1(gobj, event, kw, src) {
|
|
68335
68819
|
gobj_write_attr(gobj, "operation_mode", kw.operation_mode);
|
|
68336
68820
|
configure_behaviour(gobj);
|
|
68337
|
-
update_toolbar(gobj);
|
|
68338
68821
|
sync_history_plugin(gobj);
|
|
68822
|
+
update_toolbar(gobj);
|
|
68339
68823
|
return 0;
|
|
68340
68824
|
}
|
|
68341
68825
|
/************************************************************
|
|
@@ -68517,25 +69001,134 @@ function ac_context_menu_item(gobj, event, kw, src) {
|
|
|
68517
69001
|
return 0;
|
|
68518
69002
|
}
|
|
68519
69003
|
/************************************************************
|
|
68520
|
-
*
|
|
69004
|
+
* Is the identity a floating button was drawn with still what
|
|
69005
|
+
* is selected?
|
|
69006
|
+
*
|
|
69007
|
+
* The buttons are removed with their selection and drawn again
|
|
69008
|
+
* for the next one, so a click carrying another identity is a
|
|
69009
|
+
* broken invariant -- said loudly, never acted on: it would
|
|
69010
|
+
* delete, unlink or edit what the reader is not looking at.
|
|
69011
|
+
************************************************************/
|
|
69012
|
+
function floating_button_is_current(gobj, event, kw) {
|
|
69013
|
+
let priv = gobj.priv;
|
|
69014
|
+
let want = {
|
|
69015
|
+
node_id: priv._selected_node_id || "",
|
|
69016
|
+
port_key: priv._selected_port_key || "",
|
|
69017
|
+
edge_id: priv._selected_edge_id || ""
|
|
69018
|
+
};
|
|
69019
|
+
let keys = Object.keys(kw || {});
|
|
69020
|
+
let matches = keys.length > 0 && keys.every((k) => {
|
|
69021
|
+
return Object.prototype.hasOwnProperty.call(want, k) && !!kw[k] && kw[k] === want[k];
|
|
69022
|
+
});
|
|
69023
|
+
if (!matches) log_error(`${gobj_short_name(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but the selection is ${JSON.stringify(want)}`);
|
|
69024
|
+
return matches;
|
|
69025
|
+
}
|
|
69026
|
+
/************************************************************
|
|
69027
|
+
* {node_id} -- the delete icon floating beside the selected
|
|
69028
|
+
* node.
|
|
68521
69029
|
************************************************************/
|
|
68522
69030
|
function ac_request_delete_node(gobj, event, kw, src) {
|
|
69031
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
68523
69032
|
request_delete_node(gobj);
|
|
68524
69033
|
return 0;
|
|
68525
69034
|
}
|
|
68526
69035
|
/************************************************************
|
|
68527
|
-
*
|
|
69036
|
+
* {edge_id} -- the unlink icon floating beside the selected
|
|
69037
|
+
* edge.
|
|
68528
69038
|
************************************************************/
|
|
68529
69039
|
function ac_request_unlink_edge(gobj, event, kw, src) {
|
|
69040
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
68530
69041
|
request_unlink_edge(gobj);
|
|
68531
69042
|
return 0;
|
|
68532
69043
|
}
|
|
68533
69044
|
/************************************************************
|
|
69045
|
+
* {node_id} -- the gear beside the selected node: its
|
|
69046
|
+
* properties popover, opened or closed.
|
|
69047
|
+
************************************************************/
|
|
69048
|
+
function ac_toggle_node_popover(gobj, event, kw, src) {
|
|
69049
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69050
|
+
toggle_node_popover(gobj);
|
|
69051
|
+
return 0;
|
|
69052
|
+
}
|
|
69053
|
+
/************************************************************
|
|
69054
|
+
* {edge_id} -- the gear beside the selected edge.
|
|
69055
|
+
************************************************************/
|
|
69056
|
+
function ac_toggle_edge_popover(gobj, event, kw, src) {
|
|
69057
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69058
|
+
toggle_edge_popover(gobj);
|
|
69059
|
+
return 0;
|
|
69060
|
+
}
|
|
69061
|
+
/************************************************************
|
|
69062
|
+
* {node_id, port_key} -- the gear beside the selected port.
|
|
69063
|
+
************************************************************/
|
|
69064
|
+
function ac_toggle_port_popover(gobj, event, kw, src) {
|
|
69065
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69066
|
+
toggle_port_popover(gobj);
|
|
69067
|
+
return 0;
|
|
69068
|
+
}
|
|
69069
|
+
/************************************************************
|
|
69070
|
+
* {node_id, port_key} -- the link icon of a selected fkey port,
|
|
69071
|
+
* CLICKED (a press that drags enters the mode on its own, from
|
|
69072
|
+
* start_link_drag): the compatible hooks light up, and the next
|
|
69073
|
+
* click on one of them links.
|
|
69074
|
+
************************************************************/
|
|
69075
|
+
function ac_enter_linking_mode(gobj, event, kw, src) {
|
|
69076
|
+
let priv = gobj.priv;
|
|
69077
|
+
if (!floating_button_is_current(gobj, event, kw)) return -1;
|
|
69078
|
+
if (!priv._linking_mode) enter_linking_mode(gobj);
|
|
69079
|
+
return 0;
|
|
69080
|
+
}
|
|
69081
|
+
/************************************************************
|
|
69082
|
+
* {node_id} -- the ✕ of the detail popover.
|
|
69083
|
+
************************************************************/
|
|
69084
|
+
function ac_close_node_detail(gobj, event, kw, src) {
|
|
69085
|
+
let priv = gobj.priv;
|
|
69086
|
+
let node_id = kw && kw.node_id || "";
|
|
69087
|
+
if (!priv._node_detail_el || !node_id || node_id !== priv._detail_node_id) {
|
|
69088
|
+
log_error(`${gobj_short_name(gobj)}: ${event} for '${node_id}', but the detail popover shows '${priv._detail_node_id || ""}'`);
|
|
69089
|
+
return -1;
|
|
69090
|
+
}
|
|
69091
|
+
hide_node_detail(gobj);
|
|
69092
|
+
return 0;
|
|
69093
|
+
}
|
|
69094
|
+
/************************************************************
|
|
69095
|
+
* {} -- the create button of the edit toolbar: the create
|
|
69096
|
+
* popover, opened or closed. Only in edition, where that
|
|
69097
|
+
* toolbar is.
|
|
69098
|
+
************************************************************/
|
|
69099
|
+
function ac_toggle_create_popover(gobj, event, kw, src) {
|
|
69100
|
+
if (!gobj.priv.edit_mode) {
|
|
69101
|
+
log_error(`${gobj_short_name(gobj)}: ${event} outside edition`);
|
|
69102
|
+
return -1;
|
|
69103
|
+
}
|
|
69104
|
+
toggle_create_popover(gobj);
|
|
69105
|
+
return 0;
|
|
69106
|
+
}
|
|
69107
|
+
/************************************************************
|
|
69108
|
+
* {} -- the cancel of the create popover, or Escape in its id.
|
|
69109
|
+
************************************************************/
|
|
69110
|
+
function ac_close_create_popover(gobj, event, kw, src) {
|
|
69111
|
+
if (!gobj.priv._create_popover_el) {
|
|
69112
|
+
log_error(`${gobj_short_name(gobj)}: ${event} with no create popover open`);
|
|
69113
|
+
return -1;
|
|
69114
|
+
}
|
|
69115
|
+
hide_create_popover(gobj);
|
|
69116
|
+
return 0;
|
|
69117
|
+
}
|
|
69118
|
+
/************************************************************
|
|
68534
69119
|
* {topic_name, id} -- the create popover was filled in.
|
|
69120
|
+
*
|
|
69121
|
+
* An empty id with the popover open is the person's to fix,
|
|
69122
|
+
* not a fault: it is said IN the popover, where they typed.
|
|
68535
69123
|
************************************************************/
|
|
68536
69124
|
function ac_submit_new_node(gobj, event, kw, src) {
|
|
68537
|
-
let
|
|
68538
|
-
let
|
|
69125
|
+
let priv = gobj.priv;
|
|
69126
|
+
let topic_name = kw && kw.topic_name ? String(kw.topic_name) : "";
|
|
69127
|
+
let node_id = kw && kw.id ? String(kw.id).trim() : "";
|
|
69128
|
+
if (topic_name && !node_id && priv._create_popover_el) {
|
|
69129
|
+
say_node_id_required(gobj);
|
|
69130
|
+
return 0;
|
|
69131
|
+
}
|
|
68539
69132
|
if (!topic_name || !node_id) {
|
|
68540
69133
|
log_error(`${gobj_short_name(gobj)}: ${event} without topic or id`);
|
|
68541
69134
|
return -1;
|
|
@@ -68543,6 +69136,168 @@ function ac_submit_new_node(gobj, event, kw, src) {
|
|
|
68543
69136
|
execute_create_node(gobj, topic_name, node_id);
|
|
68544
69137
|
return 0;
|
|
68545
69138
|
}
|
|
69139
|
+
function say_node_id_required(gobj) {
|
|
69140
|
+
let $popover = gobj.priv._create_popover_el;
|
|
69141
|
+
let $error = $popover.querySelector(".G6_CREATE_ERROR");
|
|
69142
|
+
let $id = $popover.querySelector(".G6_CREATE_ID");
|
|
69143
|
+
if (!$error || !$id) {
|
|
69144
|
+
log_error(`${gobj_short_name(gobj)}: the create popover has no id or no error line`);
|
|
69145
|
+
return;
|
|
69146
|
+
}
|
|
69147
|
+
$error.textContent = t("node id required");
|
|
69148
|
+
$error.setAttribute("data-i18n", "node id required");
|
|
69149
|
+
$error.style.display = "block";
|
|
69150
|
+
$id.focus();
|
|
69151
|
+
}
|
|
69152
|
+
/************************************************************
|
|
69153
|
+
* Is `popover_key` open, and for the selection `kw` names?
|
|
69154
|
+
* `keys` are the identity in `kw` (the rest is what the form
|
|
69155
|
+
* held). A button of a popover that is not the one open is a
|
|
69156
|
+
* broken invariant -- said loudly, never acted on.
|
|
69157
|
+
************************************************************/
|
|
69158
|
+
function popover_is_current(gobj, event, kw, popover_key, keys) {
|
|
69159
|
+
if (!gobj.priv[popover_key]) {
|
|
69160
|
+
log_error(`${gobj_short_name(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but its popover is not open`);
|
|
69161
|
+
return false;
|
|
69162
|
+
}
|
|
69163
|
+
let identity = {};
|
|
69164
|
+
for (let k of keys) identity[k] = kw ? kw[k] : void 0;
|
|
69165
|
+
return floating_button_is_current(gobj, event, identity);
|
|
69166
|
+
}
|
|
69167
|
+
/************************************************************
|
|
69168
|
+
* {node_id, shape_before, fill, stroke, line_width, scope,
|
|
69169
|
+
* shape} -- apply of the node popover.
|
|
69170
|
+
************************************************************/
|
|
69171
|
+
function ac_apply_node_popover(gobj, event, kw, src) {
|
|
69172
|
+
if (!popover_is_current(gobj, event, kw, "_node_popover_el", ["node_id"])) return -1;
|
|
69173
|
+
let shape = String(kw.shape || "");
|
|
69174
|
+
drop_preview_undo(gobj, "_node_preview_undo");
|
|
69175
|
+
apply_node_properties(gobj, kw.node_id, kw.fill, kw.stroke, parseInt(kw.line_width) || 1, kw.scope, shape !== kw.shape_before ? shape : "");
|
|
69176
|
+
return 0;
|
|
69177
|
+
}
|
|
69178
|
+
/************************************************************
|
|
69179
|
+
* {node_id} -- cancel of the node popover, which undoes the
|
|
69180
|
+
* preview.
|
|
69181
|
+
************************************************************/
|
|
69182
|
+
function ac_cancel_node_popover(gobj, event, kw, src) {
|
|
69183
|
+
if (!popover_is_current(gobj, event, kw, "_node_popover_el", ["node_id"])) return -1;
|
|
69184
|
+
hide_node_popover(gobj);
|
|
69185
|
+
return 0;
|
|
69186
|
+
}
|
|
69187
|
+
/************************************************************
|
|
69188
|
+
* {edge_id, line_width, color, scope} -- apply of the edge
|
|
69189
|
+
* popover.
|
|
69190
|
+
************************************************************/
|
|
69191
|
+
function ac_apply_edge_popover(gobj, event, kw, src) {
|
|
69192
|
+
if (!popover_is_current(gobj, event, kw, "_edge_popover_el", ["edge_id"])) return -1;
|
|
69193
|
+
drop_preview_undo(gobj, "_edge_preview_undo");
|
|
69194
|
+
apply_edge_properties(gobj, kw.edge_id, parseInt(kw.line_width) || 2, kw.color, kw.scope);
|
|
69195
|
+
return 0;
|
|
69196
|
+
}
|
|
69197
|
+
/************************************************************
|
|
69198
|
+
* {edge_id} -- cancel of the edge popover: the edge is let go,
|
|
69199
|
+
* which undoes the preview.
|
|
69200
|
+
************************************************************/
|
|
69201
|
+
function ac_cancel_edge_popover(gobj, event, kw, src) {
|
|
69202
|
+
if (!popover_is_current(gobj, event, kw, "_edge_popover_el", ["edge_id"])) return -1;
|
|
69203
|
+
deselect_edge(gobj);
|
|
69204
|
+
return 0;
|
|
69205
|
+
}
|
|
69206
|
+
/************************************************************
|
|
69207
|
+
* {node_id, port_key, r_before, shape, r, scope} -- apply of
|
|
69208
|
+
* the port popover.
|
|
69209
|
+
************************************************************/
|
|
69210
|
+
function ac_apply_port_popover(gobj, event, kw, src) {
|
|
69211
|
+
if (!popover_is_current(gobj, event, kw, "_port_popover_el", ["node_id", "port_key"])) return -1;
|
|
69212
|
+
drop_preview_undo(gobj, "_port_preview_undo");
|
|
69213
|
+
apply_port_properties(gobj, kw.node_id, kw.port_key, kw.shape, parseInt(kw.r) || kw.r_before, kw.scope);
|
|
69214
|
+
return 0;
|
|
69215
|
+
}
|
|
69216
|
+
/************************************************************
|
|
69217
|
+
* {node_id, port_key} -- cancel of the port popover, which
|
|
69218
|
+
* undoes the preview.
|
|
69219
|
+
************************************************************/
|
|
69220
|
+
function ac_cancel_port_popover(gobj, event, kw, src) {
|
|
69221
|
+
if (!popover_is_current(gobj, event, kw, "_port_popover_el", ["node_id", "port_key"])) return -1;
|
|
69222
|
+
hide_port_popover(gobj);
|
|
69223
|
+
return 0;
|
|
69224
|
+
}
|
|
69225
|
+
var CONFIRM_POPOVER_OF = {
|
|
69226
|
+
delete_selection: "_delete_confirm_el",
|
|
69227
|
+
delete_node: "_delete_confirm_el",
|
|
69228
|
+
unlink_edge: "_unlink_confirm_el"
|
|
69229
|
+
};
|
|
69230
|
+
function same_question(a, b) {
|
|
69231
|
+
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);
|
|
69232
|
+
}
|
|
69233
|
+
/************************************************************
|
|
69234
|
+
* {what, id|ids} -- the person said no in a confirm popover:
|
|
69235
|
+
* the question it carries must be the one open.
|
|
69236
|
+
************************************************************/
|
|
69237
|
+
function ac_cancel_confirm(gobj, event, kw, src) {
|
|
69238
|
+
let priv = gobj.priv;
|
|
69239
|
+
let key = CONFIRM_POPOVER_OF[kw && kw.what || ""];
|
|
69240
|
+
let asked = key ? priv._confirm_questions[key] : null;
|
|
69241
|
+
if (!key || !priv[key] || !same_question(asked, kw)) {
|
|
69242
|
+
log_error(`${gobj_short_name(gobj)}: ${event} for ${JSON.stringify(kw || {})}, but the question open is ${JSON.stringify(priv[key] && asked || {})}`);
|
|
69243
|
+
return -1;
|
|
69244
|
+
}
|
|
69245
|
+
hide_overlay(gobj, key);
|
|
69246
|
+
return 0;
|
|
69247
|
+
}
|
|
69248
|
+
/************************************************************
|
|
69249
|
+
* {node_id, port_key, client_x, client_y} -- a press on the
|
|
69250
|
+
* link icon of the selected fkey port, which may be a drag.
|
|
69251
|
+
************************************************************/
|
|
69252
|
+
function ac_start_link_drag(gobj, event, kw, src) {
|
|
69253
|
+
let priv = gobj.priv;
|
|
69254
|
+
if (!floating_button_is_current(gobj, event, {
|
|
69255
|
+
node_id: kw && kw.node_id,
|
|
69256
|
+
port_key: kw && kw.port_key
|
|
69257
|
+
})) return -1;
|
|
69258
|
+
if (priv._link_drag) {
|
|
69259
|
+
log_warning(`${gobj_short_name(gobj)}: ${event} with a link drag still in flight`);
|
|
69260
|
+
end_link_drag(gobj);
|
|
69261
|
+
}
|
|
69262
|
+
start_link_drag(gobj, Number(kw.client_x) || 0, Number(kw.client_y) || 0);
|
|
69263
|
+
return 0;
|
|
69264
|
+
}
|
|
69265
|
+
/************************************************************
|
|
69266
|
+
* {client_x, client_y, dragged} -- the pointer of a link drag
|
|
69267
|
+
* went up. Not dragged, it was a click: the click comes next
|
|
69268
|
+
* (EV_ENTER_LINKING_MODE). Dragged, it links to the hook it was
|
|
69269
|
+
* dropped on, or leaves the linking mode.
|
|
69270
|
+
************************************************************/
|
|
69271
|
+
function ac_link_drag_end(gobj, event, kw, src) {
|
|
69272
|
+
let priv = gobj.priv;
|
|
69273
|
+
let drag = priv._link_drag;
|
|
69274
|
+
if (!drag) {
|
|
69275
|
+
log_error(`${gobj_short_name(gobj)}: ${event} with no link drag in flight`);
|
|
69276
|
+
return -1;
|
|
69277
|
+
}
|
|
69278
|
+
end_link_drag(gobj);
|
|
69279
|
+
if (!kw || !kw.dragged) return 0;
|
|
69280
|
+
let cx = Number(kw.client_x) - drag.left;
|
|
69281
|
+
let cy = Number(kw.client_y) - drag.top;
|
|
69282
|
+
let canvasPt = priv.graph.getCanvasByViewport([cx, cy]);
|
|
69283
|
+
let target = find_hook_at_point(gobj, canvasPt[0], canvasPt[1]);
|
|
69284
|
+
if (target) try_complete_link(gobj, target.node_id, target.port_key);
|
|
69285
|
+
else exit_linking_mode(gobj);
|
|
69286
|
+
return 0;
|
|
69287
|
+
}
|
|
69288
|
+
/************************************************************
|
|
69289
|
+
* {} -- the browser took the pointer of a link drag: no drop,
|
|
69290
|
+
* and the linking mode goes.
|
|
69291
|
+
************************************************************/
|
|
69292
|
+
function ac_link_drag_cancel(gobj, event, kw, src) {
|
|
69293
|
+
if (!gobj.priv._link_drag) {
|
|
69294
|
+
log_error(`${gobj_short_name(gobj)}: ${event} with no link drag in flight`);
|
|
69295
|
+
return -1;
|
|
69296
|
+
}
|
|
69297
|
+
end_link_drag(gobj);
|
|
69298
|
+
exit_linking_mode(gobj);
|
|
69299
|
+
return 0;
|
|
69300
|
+
}
|
|
68546
69301
|
/************************************************************
|
|
68547
69302
|
* {what, id|ids} -- the person said yes in a confirm popover.
|
|
68548
69303
|
*
|
|
@@ -68799,16 +69554,101 @@ function create_gclass$4(gclass_name) {
|
|
|
68799
69554
|
ac_request_unlink_edge,
|
|
68800
69555
|
null
|
|
68801
69556
|
],
|
|
69557
|
+
[
|
|
69558
|
+
"EV_TOGGLE_NODE_POPOVER",
|
|
69559
|
+
ac_toggle_node_popover,
|
|
69560
|
+
null
|
|
69561
|
+
],
|
|
69562
|
+
[
|
|
69563
|
+
"EV_TOGGLE_EDGE_POPOVER",
|
|
69564
|
+
ac_toggle_edge_popover,
|
|
69565
|
+
null
|
|
69566
|
+
],
|
|
69567
|
+
[
|
|
69568
|
+
"EV_TOGGLE_PORT_POPOVER",
|
|
69569
|
+
ac_toggle_port_popover,
|
|
69570
|
+
null
|
|
69571
|
+
],
|
|
69572
|
+
[
|
|
69573
|
+
"EV_ENTER_LINKING_MODE",
|
|
69574
|
+
ac_enter_linking_mode,
|
|
69575
|
+
null
|
|
69576
|
+
],
|
|
69577
|
+
[
|
|
69578
|
+
"EV_CLOSE_NODE_DETAIL",
|
|
69579
|
+
ac_close_node_detail,
|
|
69580
|
+
null
|
|
69581
|
+
],
|
|
69582
|
+
[
|
|
69583
|
+
"EV_TOGGLE_CREATE_POPOVER",
|
|
69584
|
+
ac_toggle_create_popover,
|
|
69585
|
+
null
|
|
69586
|
+
],
|
|
69587
|
+
[
|
|
69588
|
+
"EV_CLOSE_CREATE_POPOVER",
|
|
69589
|
+
ac_close_create_popover,
|
|
69590
|
+
null
|
|
69591
|
+
],
|
|
68802
69592
|
[
|
|
68803
69593
|
"EV_SUBMIT_NEW_NODE",
|
|
68804
69594
|
ac_submit_new_node,
|
|
68805
69595
|
null
|
|
68806
69596
|
],
|
|
69597
|
+
[
|
|
69598
|
+
"EV_APPLY_NODE_POPOVER",
|
|
69599
|
+
ac_apply_node_popover,
|
|
69600
|
+
null
|
|
69601
|
+
],
|
|
69602
|
+
[
|
|
69603
|
+
"EV_CANCEL_NODE_POPOVER",
|
|
69604
|
+
ac_cancel_node_popover,
|
|
69605
|
+
null
|
|
69606
|
+
],
|
|
69607
|
+
[
|
|
69608
|
+
"EV_APPLY_EDGE_POPOVER",
|
|
69609
|
+
ac_apply_edge_popover,
|
|
69610
|
+
null
|
|
69611
|
+
],
|
|
69612
|
+
[
|
|
69613
|
+
"EV_CANCEL_EDGE_POPOVER",
|
|
69614
|
+
ac_cancel_edge_popover,
|
|
69615
|
+
null
|
|
69616
|
+
],
|
|
69617
|
+
[
|
|
69618
|
+
"EV_APPLY_PORT_POPOVER",
|
|
69619
|
+
ac_apply_port_popover,
|
|
69620
|
+
null
|
|
69621
|
+
],
|
|
69622
|
+
[
|
|
69623
|
+
"EV_CANCEL_PORT_POPOVER",
|
|
69624
|
+
ac_cancel_port_popover,
|
|
69625
|
+
null
|
|
69626
|
+
],
|
|
68807
69627
|
[
|
|
68808
69628
|
"EV_CONFIRMED",
|
|
68809
69629
|
ac_confirmed$1,
|
|
68810
69630
|
null
|
|
68811
69631
|
],
|
|
69632
|
+
[
|
|
69633
|
+
"EV_CANCEL_CONFIRM",
|
|
69634
|
+
ac_cancel_confirm,
|
|
69635
|
+
null
|
|
69636
|
+
],
|
|
69637
|
+
[
|
|
69638
|
+
"EV_START_LINK_DRAG",
|
|
69639
|
+
ac_start_link_drag,
|
|
69640
|
+
null
|
|
69641
|
+
],
|
|
69642
|
+
[
|
|
69643
|
+
"EV_LINK_DRAG_END",
|
|
69644
|
+
ac_link_drag_end,
|
|
69645
|
+
null
|
|
69646
|
+
],
|
|
69647
|
+
[
|
|
69648
|
+
"EV_LINK_DRAG_CANCEL",
|
|
69649
|
+
ac_link_drag_cancel,
|
|
69650
|
+
null
|
|
69651
|
+
],
|
|
68812
69652
|
[
|
|
68813
69653
|
"EV_CANVAS_CLICK",
|
|
68814
69654
|
ac_canvas_click,
|
|
@@ -69029,8 +69869,25 @@ function create_gclass$4(gclass_name) {
|
|
|
69029
69869
|
["EV_CONTEXT_MENU_ITEM", 0],
|
|
69030
69870
|
["EV_REQUEST_DELETE_NODE", 0],
|
|
69031
69871
|
["EV_REQUEST_UNLINK_EDGE", 0],
|
|
69872
|
+
["EV_TOGGLE_NODE_POPOVER", 0],
|
|
69873
|
+
["EV_TOGGLE_EDGE_POPOVER", 0],
|
|
69874
|
+
["EV_TOGGLE_PORT_POPOVER", 0],
|
|
69875
|
+
["EV_ENTER_LINKING_MODE", 0],
|
|
69876
|
+
["EV_CLOSE_NODE_DETAIL", 0],
|
|
69877
|
+
["EV_TOGGLE_CREATE_POPOVER", 0],
|
|
69878
|
+
["EV_CLOSE_CREATE_POPOVER", 0],
|
|
69032
69879
|
["EV_SUBMIT_NEW_NODE", 0],
|
|
69880
|
+
["EV_APPLY_NODE_POPOVER", 0],
|
|
69881
|
+
["EV_CANCEL_NODE_POPOVER", 0],
|
|
69882
|
+
["EV_APPLY_EDGE_POPOVER", 0],
|
|
69883
|
+
["EV_CANCEL_EDGE_POPOVER", 0],
|
|
69884
|
+
["EV_APPLY_PORT_POPOVER", 0],
|
|
69885
|
+
["EV_CANCEL_PORT_POPOVER", 0],
|
|
69033
69886
|
["EV_CONFIRMED", 0],
|
|
69887
|
+
["EV_CANCEL_CONFIRM", 0],
|
|
69888
|
+
["EV_START_LINK_DRAG", 0],
|
|
69889
|
+
["EV_LINK_DRAG_END", 0],
|
|
69890
|
+
["EV_LINK_DRAG_CANCEL", 0],
|
|
69034
69891
|
["EV_CANVAS_CLICK", 0],
|
|
69035
69892
|
["EV_NODE_DRAG_END", 0],
|
|
69036
69893
|
["EV_BRUSH_SELECT", 0],
|
|
@@ -69380,7 +70237,7 @@ function show_load_error(gobj, message) {
|
|
|
69380
70237
|
$container.insertBefore($err, $container.firstChild);
|
|
69381
70238
|
}
|
|
69382
70239
|
let treedb = gobj_read_attr(gobj, "treedb_name") || "";
|
|
69383
|
-
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || "cannot load treedb");
|
|
70240
|
+
$err.textContent = (treedb ? `${treedb}: ` : "") + (message || t("cannot load treedb"));
|
|
69384
70241
|
}
|
|
69385
70242
|
/************************************************************
|
|
69386
70243
|
* Destroy UI
|
|
@@ -71065,7 +71922,7 @@ function refresh_legend(gobj) {
|
|
|
71065
71922
|
},
|
|
71066
71923
|
hidden ? `${entry.total}` : `${entry.visible}/${entry.total}`
|
|
71067
71924
|
]);
|
|
71068
|
-
|
|
71925
|
+
const body_key = is_main ? "main topic" : hidden ? "show topic" : "hide topic";
|
|
71069
71926
|
let body_attrs = {
|
|
71070
71927
|
class: "GRAPH_LEGEND_ITEM button" + (focused ? " GRAPH_LEGEND_FOCUSED" : "") + (is_main ? " GRAPH_LEGEND_MAIN" : ""),
|
|
71071
71928
|
type: "button",
|
|
@@ -72325,6 +73182,7 @@ function build_graph(gobj) {
|
|
|
72325
73182
|
}
|
|
72326
73183
|
priv.graph = graph;
|
|
72327
73184
|
graph.setTheme(dark ? "dark" : "light");
|
|
73185
|
+
keep_canvas_tab_order(gobj, graph);
|
|
72328
73186
|
graph.on("aftertransform", () => {
|
|
72329
73187
|
yui_graph_update_zoom($container, priv.graph);
|
|
72330
73188
|
});
|
|
@@ -77638,7 +78496,7 @@ function ac_mt_command_answer(gobj, event, kw, src) {
|
|
|
77638
78496
|
}
|
|
77639
78497
|
return late_write_done(gobj, command, topic_name, data);
|
|
77640
78498
|
}
|
|
77641
|
-
if (result < 0) return end_writes(gobj, comment ||
|
|
78499
|
+
if (result < 0) return end_writes(gobj, comment || "the treedb refused the write");
|
|
77642
78500
|
priv.save_wrote = true;
|
|
77643
78501
|
let record = null;
|
|
77644
78502
|
if (command === "delete-node") forget_record(gobj, topic_name, kw_get_str(gobj, md, "record_id", "", 0));
|
|
@@ -78154,7 +79012,8 @@ function confirm_column_delete(gobj, verdict) {
|
|
|
78154
79012
|
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",
|
|
78155
79013
|
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"
|
|
78156
79014
|
};
|
|
78157
|
-
|
|
79015
|
+
const message = "delete this column?";
|
|
79016
|
+
let $warning = null;
|
|
78158
79017
|
if (NOTES[verdict]) {
|
|
78159
79018
|
let children = [[
|
|
78160
79019
|
"p",
|
|
@@ -78184,13 +79043,13 @@ function confirm_column_delete(gobj, verdict) {
|
|
|
78184
79043
|
String(c.scanned)
|
|
78185
79044
|
]]
|
|
78186
79045
|
]);
|
|
78187
|
-
|
|
79046
|
+
$warning = createElement2([
|
|
78188
79047
|
"div",
|
|
78189
79048
|
{ class: "SCHEMA_COLUMN_DATA_WARNING" },
|
|
78190
79049
|
children
|
|
78191
79050
|
]);
|
|
78192
79051
|
}
|
|
78193
|
-
confirm_then(gobj, message, `${c.topic}.${c.col}`, {
|
|
79052
|
+
confirm_then(gobj, $warning ? $warning : message, `${c.topic}.${c.col}`, {
|
|
78194
79053
|
what: "column",
|
|
78195
79054
|
topic: c.topic,
|
|
78196
79055
|
col: c.col
|
|
@@ -81755,7 +82614,9 @@ function build_control_bar() {
|
|
|
81755
82614
|
type: "button",
|
|
81756
82615
|
title: t("machine trace shape"),
|
|
81757
82616
|
"data-i18n-title": "machine trace shape",
|
|
81758
|
-
"data-i18n": "simple mach"
|
|
82617
|
+
"data-i18n": "simple mach",
|
|
82618
|
+
"aria-label": t("simple mach"),
|
|
82619
|
+
"data-i18n-aria-label": "simple mach"
|
|
81759
82620
|
},
|
|
81760
82621
|
t("simple mach"),
|
|
81761
82622
|
{ click: (ev) => {
|
|
@@ -81829,7 +82690,9 @@ function build_control_bar() {
|
|
|
81829
82690
|
type: "button",
|
|
81830
82691
|
title: t(OUT_TITLES[v]),
|
|
81831
82692
|
"data-i18n-title": OUT_TITLES[v],
|
|
81832
|
-
"data-i18n": label
|
|
82693
|
+
"data-i18n": label,
|
|
82694
|
+
"aria-label": t(label),
|
|
82695
|
+
"data-i18n-aria-label": label
|
|
81833
82696
|
},
|
|
81834
82697
|
t(label),
|
|
81835
82698
|
{ click: (ev) => {
|
|
@@ -81857,7 +82720,9 @@ function build_control_bar() {
|
|
|
81857
82720
|
type: "button",
|
|
81858
82721
|
title: t("show this section in the expanded view"),
|
|
81859
82722
|
"data-i18n-title": "show this section in the expanded view",
|
|
81860
|
-
"data-i18n": label
|
|
82723
|
+
"data-i18n": label,
|
|
82724
|
+
"aria-label": t(label),
|
|
82725
|
+
"data-i18n-aria-label": label
|
|
81861
82726
|
},
|
|
81862
82727
|
t(label),
|
|
81863
82728
|
{ click: (ev) => {
|
|
@@ -81956,7 +82821,9 @@ function build_control_bar() {
|
|
|
81956
82821
|
type: "button",
|
|
81957
82822
|
title: t("copy visible traffic to clipboard"),
|
|
81958
82823
|
"data-i18n-title": "copy visible traffic to clipboard",
|
|
81959
|
-
"data-i18n": "copy"
|
|
82824
|
+
"data-i18n": "copy",
|
|
82825
|
+
"aria-label": t("copy"),
|
|
82826
|
+
"data-i18n-aria-label": "copy"
|
|
81960
82827
|
},
|
|
81961
82828
|
t("copy"),
|
|
81962
82829
|
{ click: (ev) => {
|
|
@@ -81978,7 +82845,9 @@ function build_control_bar() {
|
|
|
81978
82845
|
type: "button",
|
|
81979
82846
|
title: t("clear captured traffic"),
|
|
81980
82847
|
"data-i18n-title": "clear captured traffic",
|
|
81981
|
-
"data-i18n": "clear"
|
|
82848
|
+
"data-i18n": "clear",
|
|
82849
|
+
"aria-label": t("clear"),
|
|
82850
|
+
"data-i18n-aria-label": "clear"
|
|
81982
82851
|
},
|
|
81983
82852
|
t("clear"),
|
|
81984
82853
|
{ click: (ev) => {
|