@yuneta/gobj-ui 7.23.12 → 7.23.14
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 +36 -3
- package/dist/gobj-ui.cjs.js +155 -39
- package/dist/gobj-ui.es.js +155 -39
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +25 -4
- package/src/c_yui_treedb_graph.js +64 -2
- package/src/g6_touch_gestures.js +148 -58
- package/src/lib_graph.css +34 -0
- package/src/press_arbiter.js +84 -0
- package/src/press_arbiter.test.js +63 -0
package/dist/gobj-ui.es.js
CHANGED
|
@@ -9498,6 +9498,29 @@ function yui_graph_fold_items(gobj, wide) {
|
|
|
9498
9498
|
function yui_graph_refresh_item(gobj, wide) {
|
|
9499
9499
|
return camera_button(gobj, "yi-arrows-rotate", "EV_REFRESH", "refresh", wide);
|
|
9500
9500
|
}
|
|
9501
|
+
/***************************************************************
|
|
9502
|
+
* Arbitration
|
|
9503
|
+
***************************************************************/
|
|
9504
|
+
/************************************************************
|
|
9505
|
+
* Did the finger travel far enough to mean a DRAG?
|
|
9506
|
+
*
|
|
9507
|
+
* `press` is what the pointerdown recorded: {x, y, t0}.
|
|
9508
|
+
************************************************************/
|
|
9509
|
+
function press_moved(press, x, y) {
|
|
9510
|
+
if (!press) return false;
|
|
9511
|
+
return Math.abs(x - press.x) > 10 || Math.abs(y - press.y) > 10;
|
|
9512
|
+
}
|
|
9513
|
+
/************************************************************
|
|
9514
|
+
* What the press meant, asked when the finger comes up.
|
|
9515
|
+
*
|
|
9516
|
+
* Answers "none" when there was no press to arbitrate.
|
|
9517
|
+
************************************************************/
|
|
9518
|
+
function classify_press(press, x, y, t) {
|
|
9519
|
+
if (!press) return "none";
|
|
9520
|
+
if (press_moved(press, x, y)) return "drag";
|
|
9521
|
+
if (t - press.t0 >= 500) return "long";
|
|
9522
|
+
return "tap";
|
|
9523
|
+
}
|
|
9501
9524
|
//#endregion
|
|
9502
9525
|
//#region src/g6_touch_gestures.js
|
|
9503
9526
|
/***********************************************************************
|
|
@@ -9534,6 +9557,21 @@ function yui_graph_refresh_item(gobj, wide) {
|
|
|
9534
9557
|
* forwarded event object -- which is why the plugin's
|
|
9535
9558
|
* `getItems(e)` receives exactly the shape it expects.
|
|
9536
9559
|
*
|
|
9560
|
+
* ONE finger has to serve three commands -- move the
|
|
9561
|
+
* node, act on it, open its menu -- so the press is
|
|
9562
|
+
* arbitrated, and arbitrated at the RELEASE:
|
|
9563
|
+
*
|
|
9564
|
+
* moved -> drag
|
|
9565
|
+
* still, let go fast -> the element's own action
|
|
9566
|
+
* still, held >= 500ms -> the context menu
|
|
9567
|
+
*
|
|
9568
|
+
* A menu opened on a TIMER instead cannot be arbitrated
|
|
9569
|
+
* at all: it opens while `drag-element` is already
|
|
9570
|
+
* carrying the node, so the same press means both things
|
|
9571
|
+
* and the user gets a menu over a card running away
|
|
9572
|
+
* underneath it. `classify_press` is where the three
|
|
9573
|
+
* live, and it is pure.
|
|
9574
|
+
*
|
|
9537
9575
|
* Both are built on ONE per-graph record of the fingers
|
|
9538
9576
|
* on the glass, read from the NATIVE touch events -- see
|
|
9539
9577
|
* `touch_state_of` for why the pointer stream, which looks
|
|
@@ -9546,11 +9584,6 @@ function yui_graph_refresh_item(gobj, wide) {
|
|
|
9546
9584
|
* All Rights Reserved.
|
|
9547
9585
|
***********************************************************************/
|
|
9548
9586
|
/***************************************************************
|
|
9549
|
-
* Constants
|
|
9550
|
-
***************************************************************/
|
|
9551
|
-
var LONG_PRESS_MS = 500;
|
|
9552
|
-
var LONG_PRESS_SLOP = 10;
|
|
9553
|
-
/***************************************************************
|
|
9554
9587
|
* Per-graph record of the fingers on the glass
|
|
9555
9588
|
***************************************************************/
|
|
9556
9589
|
var __touch_state__ = /* @__PURE__ */ new WeakMap();
|
|
@@ -9577,7 +9610,9 @@ function touch_state_of(graph) {
|
|
|
9577
9610
|
if (state) return state;
|
|
9578
9611
|
state = {
|
|
9579
9612
|
count: 0,
|
|
9580
|
-
|
|
9613
|
+
multi: false,
|
|
9614
|
+
container: null,
|
|
9615
|
+
long_press_click: false
|
|
9581
9616
|
};
|
|
9582
9617
|
__touch_state__.set(graph, state);
|
|
9583
9618
|
let container = graph.getCanvas?.()?.getContainer?.();
|
|
@@ -9585,11 +9620,16 @@ function touch_state_of(graph) {
|
|
|
9585
9620
|
state.container = container;
|
|
9586
9621
|
let read = (event) => {
|
|
9587
9622
|
state.count = event.touches ? event.touches.length : 0;
|
|
9623
|
+
if (state.count >= 2) state.multi = true;
|
|
9624
|
+
else if (state.count === 0) state.multi = false;
|
|
9588
9625
|
};
|
|
9589
9626
|
container.addEventListener("touchstart", read, { passive: true });
|
|
9590
9627
|
container.addEventListener("touchmove", read, { passive: true });
|
|
9591
9628
|
container.addEventListener("touchend", read, { passive: true });
|
|
9592
9629
|
container.addEventListener("touchcancel", read, { passive: true });
|
|
9630
|
+
container.addEventListener("contextmenu", (event) => {
|
|
9631
|
+
if (state.count > 0) event.preventDefault();
|
|
9632
|
+
}, { capture: true });
|
|
9593
9633
|
return state;
|
|
9594
9634
|
}
|
|
9595
9635
|
/************************************************************
|
|
@@ -9690,6 +9730,24 @@ function ensure_pinch_zoom_patch() {
|
|
|
9690
9730
|
* Long press
|
|
9691
9731
|
***************************/
|
|
9692
9732
|
/************************************************************
|
|
9733
|
+
* Is the click being dispatched right now the tail of a long
|
|
9734
|
+
* press? Answers true ONCE, to the first asker.
|
|
9735
|
+
*
|
|
9736
|
+
* @antv/g does not take `click` from the DOM either: it makes
|
|
9737
|
+
* one out of the pointerdown/pointerup pair itself, inside
|
|
9738
|
+
* the same `onPointerUp` that just fed us the release. So
|
|
9739
|
+
* the press that opened the menu goes on to click whatever it
|
|
9740
|
+
* opened the menu ON -- selecting the node, or worse, dropping
|
|
9741
|
+
* a selection of several -- unless the handler asks.
|
|
9742
|
+
************************************************************/
|
|
9743
|
+
function consume_long_press_click(graph) {
|
|
9744
|
+
if (!graph) return false;
|
|
9745
|
+
let state = __touch_state__.get(graph);
|
|
9746
|
+
if (!state || !state.long_press_click) return false;
|
|
9747
|
+
state.long_press_click = false;
|
|
9748
|
+
return true;
|
|
9749
|
+
}
|
|
9750
|
+
/************************************************************
|
|
9693
9751
|
* Make a long press open the context menu.
|
|
9694
9752
|
*
|
|
9695
9753
|
* Returns the function that uninstalls it.
|
|
@@ -9699,19 +9757,26 @@ function ensure_pinch_zoom_patch() {
|
|
|
9699
9757
|
* the name the plugin listens for, so `getItems(e)` and
|
|
9700
9758
|
* `enable(e)` see the same object a right-click would give
|
|
9701
9759
|
* them -- same `target`, same `targetType`, same `client`.
|
|
9760
|
+
*
|
|
9761
|
+
* `options.enable(event)` decides, at the DOWN, whether this
|
|
9762
|
+
* press is even a candidate. Pass the plugin's own predicate:
|
|
9763
|
+
* a press on the empty canvas would otherwise arm a menu the
|
|
9764
|
+
* plugin then refuses to show, and swallow the click that
|
|
9765
|
+
* would have cleared the selection.
|
|
9702
9766
|
************************************************************/
|
|
9703
|
-
function install_long_press_contextmenu(graph) {
|
|
9767
|
+
function install_long_press_contextmenu(graph, options) {
|
|
9704
9768
|
if (!graph) return () => {};
|
|
9769
|
+
let enable = options?.enable;
|
|
9705
9770
|
let state = touch_state_of(graph);
|
|
9706
9771
|
let pending = null;
|
|
9707
|
-
let
|
|
9708
|
-
|
|
9709
|
-
clearTimeout(pending.timer);
|
|
9710
|
-
pending = null;
|
|
9711
|
-
}
|
|
9772
|
+
let disarm = () => {
|
|
9773
|
+
pending = null;
|
|
9712
9774
|
};
|
|
9713
9775
|
let fire = (event) => {
|
|
9714
|
-
|
|
9776
|
+
state.long_press_click = true;
|
|
9777
|
+
setTimeout(() => {
|
|
9778
|
+
state.long_press_click = false;
|
|
9779
|
+
}, 0);
|
|
9715
9780
|
let swallow = (evt) => {
|
|
9716
9781
|
evt.stopPropagation();
|
|
9717
9782
|
document.removeEventListener("click", swallow, true);
|
|
@@ -9720,51 +9785,60 @@ function install_long_press_contextmenu(graph) {
|
|
|
9720
9785
|
setTimeout(() => {
|
|
9721
9786
|
document.removeEventListener("click", swallow, true);
|
|
9722
9787
|
}, 1e3);
|
|
9723
|
-
let container = graph.getCanvas?.()?.getContainer?.();
|
|
9724
|
-
if (container) container.addEventListener("contextmenu", (evt) => {
|
|
9725
|
-
evt.preventDefault();
|
|
9726
|
-
}, {
|
|
9727
|
-
once: true,
|
|
9728
|
-
capture: true
|
|
9729
|
-
});
|
|
9730
9788
|
graph.emit(`${event.targetType}:${CommonEvent.CONTEXT_MENU}`, event);
|
|
9731
9789
|
graph.emit(CommonEvent.CONTEXT_MENU, event);
|
|
9732
9790
|
};
|
|
9733
9791
|
let on_down = (event) => {
|
|
9734
|
-
|
|
9792
|
+
disarm();
|
|
9735
9793
|
if (event.pointerType !== "touch") return;
|
|
9736
|
-
if (state.count > 1) return;
|
|
9794
|
+
if (state.count > 1 || state.multi) return;
|
|
9795
|
+
if (enable && !enable(event)) return;
|
|
9737
9796
|
let x = event.client?.x;
|
|
9738
9797
|
let y = event.client?.y;
|
|
9739
9798
|
if (x === void 0 || y === void 0) return;
|
|
9740
|
-
let frozen = Object.assign({}, event);
|
|
9741
9799
|
pending = {
|
|
9742
9800
|
x,
|
|
9743
9801
|
y,
|
|
9744
|
-
|
|
9745
|
-
|
|
9746
|
-
}, LONG_PRESS_MS)
|
|
9802
|
+
t0: Date.now(),
|
|
9803
|
+
event: Object.assign({}, event)
|
|
9747
9804
|
};
|
|
9748
9805
|
};
|
|
9749
9806
|
let on_move = (event) => {
|
|
9750
9807
|
if (!pending) return;
|
|
9751
|
-
if (state.count > 1) {
|
|
9752
|
-
|
|
9808
|
+
if (state.count > 1 || state.multi) {
|
|
9809
|
+
disarm();
|
|
9753
9810
|
return;
|
|
9754
9811
|
}
|
|
9755
9812
|
let x = event.client?.x;
|
|
9756
9813
|
let y = event.client?.y;
|
|
9757
9814
|
if (x === void 0 || y === void 0) return;
|
|
9758
|
-
if (
|
|
9815
|
+
if (press_moved(pending, x, y)) disarm();
|
|
9759
9816
|
};
|
|
9817
|
+
let on_up = (event) => {
|
|
9818
|
+
let press = pending;
|
|
9819
|
+
pending = null;
|
|
9820
|
+
if (!press) return;
|
|
9821
|
+
if (state.multi) return;
|
|
9822
|
+
let x = event.client?.x;
|
|
9823
|
+
let y = event.client?.y;
|
|
9824
|
+
if (x === void 0) x = press.x;
|
|
9825
|
+
if (y === void 0) y = press.y;
|
|
9826
|
+
if (classify_press(press, x, y, Date.now()) !== "long") return;
|
|
9827
|
+
fire(press.event);
|
|
9828
|
+
};
|
|
9829
|
+
let on_touch_cancel = () => {
|
|
9830
|
+
disarm();
|
|
9831
|
+
};
|
|
9832
|
+
state.container?.addEventListener("touchcancel", on_touch_cancel);
|
|
9760
9833
|
graph.on(CommonEvent.POINTER_DOWN, on_down);
|
|
9761
9834
|
graph.on(CommonEvent.POINTER_MOVE, on_move);
|
|
9762
|
-
graph.on(CommonEvent.POINTER_UP,
|
|
9835
|
+
graph.on(CommonEvent.POINTER_UP, on_up);
|
|
9763
9836
|
return () => {
|
|
9764
|
-
|
|
9837
|
+
disarm();
|
|
9838
|
+
state.container?.removeEventListener("touchcancel", on_touch_cancel);
|
|
9765
9839
|
graph.off(CommonEvent.POINTER_DOWN, on_down);
|
|
9766
9840
|
graph.off(CommonEvent.POINTER_MOVE, on_move);
|
|
9767
|
-
graph.off(CommonEvent.POINTER_UP,
|
|
9841
|
+
graph.off(CommonEvent.POINTER_UP, on_up);
|
|
9768
9842
|
};
|
|
9769
9843
|
}
|
|
9770
9844
|
//#endregion
|
|
@@ -47964,6 +48038,7 @@ function configure_events(gobj) {
|
|
|
47964
48038
|
let priv = gobj.priv;
|
|
47965
48039
|
let graph = priv.graph;
|
|
47966
48040
|
graph.on(CanvasEvent.CLICK, (evt) => {
|
|
48041
|
+
if (consume_long_press_click(graph)) return;
|
|
47967
48042
|
gobj_send_event(gobj, "EV_CANVAS_CLICK", { evt }, gobj);
|
|
47968
48043
|
});
|
|
47969
48044
|
graph.on(NodeEvent.DRAG, (evt) => {
|
|
@@ -47977,12 +48052,14 @@ function configure_events(gobj) {
|
|
|
47977
48052
|
gobj_send_event(gobj, "EV_NODE_DRAG_END", { evt }, gobj);
|
|
47978
48053
|
});
|
|
47979
48054
|
graph.on(NodeEvent.CLICK, (evt) => {
|
|
48055
|
+
if (consume_long_press_click(graph)) return;
|
|
47980
48056
|
gobj_send_event(gobj, "EV_NODE_CLICK", { evt }, gobj);
|
|
47981
48057
|
});
|
|
47982
48058
|
graph.on(NodeEvent.CONTEXT_MENU, (evt) => {
|
|
47983
48059
|
gobj_send_event(gobj, "EV_NODE_CONTEXT_MENU", { evt }, gobj);
|
|
47984
48060
|
});
|
|
47985
48061
|
graph.on(EdgeEvent.CLICK, (evt) => {
|
|
48062
|
+
if (consume_long_press_click(graph)) return;
|
|
47986
48063
|
gobj_send_event(gobj, "EV_EDGE_CLICK", { evt }, gobj);
|
|
47987
48064
|
});
|
|
47988
48065
|
graph.on("aftertransform", () => {
|
|
@@ -48046,6 +48123,9 @@ function configure_plugins(gobj) {
|
|
|
48046
48123
|
update_toolbar(gobj);
|
|
48047
48124
|
}
|
|
48048
48125
|
});
|
|
48126
|
+
let menu_enable = (e) => {
|
|
48127
|
+
return e.targetType === "node" || e.targetType === "edge";
|
|
48128
|
+
};
|
|
48049
48129
|
graph_add_plugin(gobj, "contextmenu", {
|
|
48050
48130
|
trigger: "contextmenu",
|
|
48051
48131
|
onClick: (value) => {
|
|
@@ -48054,12 +48134,10 @@ function configure_plugins(gobj) {
|
|
|
48054
48134
|
getItems: (e) => {
|
|
48055
48135
|
return build_context_menu_items(gobj, e);
|
|
48056
48136
|
},
|
|
48057
|
-
enable:
|
|
48058
|
-
return e.targetType === "node" || e.targetType === "edge";
|
|
48059
|
-
}
|
|
48137
|
+
enable: menu_enable
|
|
48060
48138
|
});
|
|
48061
48139
|
if (priv._uninstall_long_press) priv._uninstall_long_press();
|
|
48062
|
-
priv._uninstall_long_press = install_long_press_contextmenu(priv.graph);
|
|
48140
|
+
priv._uninstall_long_press = install_long_press_contextmenu(priv.graph, { enable: menu_enable });
|
|
48063
48141
|
if (gobj_read_bool_attr(gobj, "with_toolbar")) {
|
|
48064
48142
|
configure_toolbar(gobj);
|
|
48065
48143
|
configure_toolbar_edit(gobj);
|
|
@@ -53123,6 +53201,40 @@ function destroy_ui$1(gobj) {
|
|
|
53123
53201
|
}
|
|
53124
53202
|
}
|
|
53125
53203
|
/************************************************************
|
|
53204
|
+
* The label of an option of the two selects of the toolbar.
|
|
53205
|
+
*
|
|
53206
|
+
* Both of them used to render their RAW names -- `reading`,
|
|
53207
|
+
* `edition`, `dagre`, `manual` -- in every language, because
|
|
53208
|
+
* neither went through `t()` at all. Not a missing key: a
|
|
53209
|
+
* missing call.
|
|
53210
|
+
*
|
|
53211
|
+
* Written as one literal per case, and deliberately not as
|
|
53212
|
+
* `t(name)`: a consumer's `validate-locales.mjs` reads
|
|
53213
|
+
* LITERALS, so a variable key is invisible to it -- the app
|
|
53214
|
+
* ships without the entry and nothing says so, because
|
|
53215
|
+
* i18next answers an unknown key with the key itself, which
|
|
53216
|
+
* is exactly the English word that was there before. The
|
|
53217
|
+
* same reason the keys are listed in the README.
|
|
53218
|
+
*
|
|
53219
|
+
* The default is what a host that adds a layout of its own
|
|
53220
|
+
* gets: the name it chose, which is what all of them got
|
|
53221
|
+
* until now.
|
|
53222
|
+
************************************************************/
|
|
53223
|
+
function option_label(name) {
|
|
53224
|
+
switch (name) {
|
|
53225
|
+
case "reading": return t("reading");
|
|
53226
|
+
case "operation": return t("operation");
|
|
53227
|
+
case "writing": return t("writing");
|
|
53228
|
+
case "edition": return t("edition");
|
|
53229
|
+
case "manual": return t("manual");
|
|
53230
|
+
case "dagre": return t("dagre");
|
|
53231
|
+
case "antv-dagre": return t("antv-dagre");
|
|
53232
|
+
case "d3-force": return t("d3-force");
|
|
53233
|
+
case "force-atlas2": return t("force-atlas2");
|
|
53234
|
+
default: return name;
|
|
53235
|
+
}
|
|
53236
|
+
}
|
|
53237
|
+
/************************************************************
|
|
53126
53238
|
*
|
|
53127
53239
|
************************************************************/
|
|
53128
53240
|
function make_toolbar(gobj) {
|
|
@@ -53165,8 +53277,11 @@ function make_toolbar(gobj) {
|
|
|
53165
53277
|
{ class: "GRAPH_MODE_SELECT" },
|
|
53166
53278
|
modes.map((item) => [
|
|
53167
53279
|
"option",
|
|
53168
|
-
{
|
|
53169
|
-
|
|
53280
|
+
{
|
|
53281
|
+
value: item,
|
|
53282
|
+
"data-i18n": item
|
|
53283
|
+
},
|
|
53284
|
+
option_label(item)
|
|
53170
53285
|
])
|
|
53171
53286
|
]],
|
|
53172
53287
|
{ change: (evt) => {
|
|
@@ -53505,7 +53620,8 @@ function populate_nodes_tree_options(gobj) {
|
|
|
53505
53620
|
for (let name of layout_names) {
|
|
53506
53621
|
let option = document.createElement("option");
|
|
53507
53622
|
option.value = name;
|
|
53508
|
-
option.
|
|
53623
|
+
option.setAttribute("data-i18n", name);
|
|
53624
|
+
option.textContent = option_label(name);
|
|
53509
53625
|
$layout_select.appendChild(option);
|
|
53510
53626
|
}
|
|
53511
53627
|
let current_layout = gobj_read_str_attr(priv.gobj_nodes_tree, "layout");
|
package/package.json
CHANGED
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -111,6 +111,7 @@ import {
|
|
|
111
111
|
import {
|
|
112
112
|
ensure_pinch_zoom_patch,
|
|
113
113
|
install_long_press_contextmenu,
|
|
114
|
+
consume_long_press_click,
|
|
114
115
|
} from "./g6_touch_gestures.js";
|
|
115
116
|
import {yui_theme_now, yui_watch_theme} from "./yui_theme.js";
|
|
116
117
|
|
|
@@ -784,7 +785,14 @@ function configure_events(gobj)
|
|
|
784
785
|
let priv = gobj.priv;
|
|
785
786
|
let graph = priv.graph;
|
|
786
787
|
|
|
788
|
+
/* @antv/g makes a `click` out of every pointerdown/pointerup
|
|
789
|
+
* pair, this one included -- so the press that just opened the
|
|
790
|
+
* context menu goes on to click what it opened the menu ON. One
|
|
791
|
+
* press, one meaning: the press was already spent. */
|
|
787
792
|
graph.on(CanvasEvent.CLICK, (evt) => {
|
|
793
|
+
if(consume_long_press_click(graph)) {
|
|
794
|
+
return;
|
|
795
|
+
}
|
|
788
796
|
gobj_send_event(gobj, "EV_CANVAS_CLICK", {evt: evt}, gobj);
|
|
789
797
|
});
|
|
790
798
|
|
|
@@ -801,6 +809,9 @@ function configure_events(gobj)
|
|
|
801
809
|
});
|
|
802
810
|
|
|
803
811
|
graph.on(NodeEvent.CLICK, (evt) => {
|
|
812
|
+
if(consume_long_press_click(graph)) {
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
804
815
|
gobj_send_event(gobj, "EV_NODE_CLICK", {evt: evt}, gobj);
|
|
805
816
|
});
|
|
806
817
|
|
|
@@ -809,6 +820,9 @@ function configure_events(gobj)
|
|
|
809
820
|
});
|
|
810
821
|
|
|
811
822
|
graph.on(EdgeEvent.CLICK, (evt) => {
|
|
823
|
+
if(consume_long_press_click(graph)) {
|
|
824
|
+
return;
|
|
825
|
+
}
|
|
812
826
|
gobj_send_event(gobj, "EV_EDGE_CLICK", {evt: evt}, gobj);
|
|
813
827
|
});
|
|
814
828
|
|
|
@@ -948,6 +962,13 @@ function configure_plugins(gobj)
|
|
|
948
962
|
);
|
|
949
963
|
}
|
|
950
964
|
|
|
965
|
+
/* What the menu is FOR: a node or an edge. Shared with the long
|
|
966
|
+
* press below, so the gesture arms itself on exactly what the
|
|
967
|
+
* menu would agree to open on. */
|
|
968
|
+
let menu_enable = (e) => {
|
|
969
|
+
return e.targetType === 'node' || e.targetType === 'edge';
|
|
970
|
+
};
|
|
971
|
+
|
|
951
972
|
graph_add_plugin(
|
|
952
973
|
gobj,
|
|
953
974
|
'contextmenu',
|
|
@@ -959,9 +980,7 @@ function configure_plugins(gobj)
|
|
|
959
980
|
getItems: (e) => {
|
|
960
981
|
return build_context_menu_items(gobj, e);
|
|
961
982
|
},
|
|
962
|
-
enable:
|
|
963
|
-
return e.targetType === 'node' || e.targetType === 'edge';
|
|
964
|
-
},
|
|
983
|
+
enable: menu_enable,
|
|
965
984
|
}
|
|
966
985
|
);
|
|
967
986
|
|
|
@@ -976,7 +995,9 @@ function configure_plugins(gobj)
|
|
|
976
995
|
if(priv._uninstall_long_press) {
|
|
977
996
|
priv._uninstall_long_press();
|
|
978
997
|
}
|
|
979
|
-
priv._uninstall_long_press = install_long_press_contextmenu(
|
|
998
|
+
priv._uninstall_long_press = install_long_press_contextmenu(
|
|
999
|
+
priv.graph, {enable: menu_enable}
|
|
1000
|
+
);
|
|
980
1001
|
|
|
981
1002
|
if(gobj_read_bool_attr(gobj, "with_toolbar")) {
|
|
982
1003
|
configure_toolbar(gobj);
|
|
@@ -452,6 +452,56 @@ function destroy_ui(gobj)
|
|
|
452
452
|
}
|
|
453
453
|
}
|
|
454
454
|
|
|
455
|
+
/************************************************************
|
|
456
|
+
* The label of an option of the two selects of the toolbar.
|
|
457
|
+
*
|
|
458
|
+
* Both of them used to render their RAW names -- `reading`,
|
|
459
|
+
* `edition`, `dagre`, `manual` -- in every language, because
|
|
460
|
+
* neither went through `t()` at all. Not a missing key: a
|
|
461
|
+
* missing call.
|
|
462
|
+
*
|
|
463
|
+
* Written as one literal per case, and deliberately not as
|
|
464
|
+
* `t(name)`: a consumer's `validate-locales.mjs` reads
|
|
465
|
+
* LITERALS, so a variable key is invisible to it -- the app
|
|
466
|
+
* ships without the entry and nothing says so, because
|
|
467
|
+
* i18next answers an unknown key with the key itself, which
|
|
468
|
+
* is exactly the English word that was there before. The
|
|
469
|
+
* same reason the keys are listed in the README.
|
|
470
|
+
*
|
|
471
|
+
* The default is what a host that adds a layout of its own
|
|
472
|
+
* gets: the name it chose, which is what all of them got
|
|
473
|
+
* until now.
|
|
474
|
+
************************************************************/
|
|
475
|
+
function option_label(name)
|
|
476
|
+
{
|
|
477
|
+
switch(name) {
|
|
478
|
+
/* Operation modes (`operation_modes` attr). */
|
|
479
|
+
case "reading":
|
|
480
|
+
return t("reading");
|
|
481
|
+
case "operation":
|
|
482
|
+
return t("operation");
|
|
483
|
+
case "writing":
|
|
484
|
+
return t("writing");
|
|
485
|
+
case "edition":
|
|
486
|
+
return t("edition");
|
|
487
|
+
|
|
488
|
+
/* Layouts (`layout_names` of the G6 child). */
|
|
489
|
+
case "manual":
|
|
490
|
+
return t("manual");
|
|
491
|
+
case "dagre":
|
|
492
|
+
return t("dagre");
|
|
493
|
+
case "antv-dagre":
|
|
494
|
+
return t("antv-dagre");
|
|
495
|
+
case "d3-force":
|
|
496
|
+
return t("d3-force");
|
|
497
|
+
case "force-atlas2":
|
|
498
|
+
return t("force-atlas2");
|
|
499
|
+
|
|
500
|
+
default:
|
|
501
|
+
return name;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
455
505
|
/************************************************************
|
|
456
506
|
*
|
|
457
507
|
************************************************************/
|
|
@@ -468,7 +518,14 @@ function make_toolbar(gobj)
|
|
|
468
518
|
* one that draws the create / delete / link affordances. */
|
|
469
519
|
modes = modes.filter(mode => mode !== "edition");
|
|
470
520
|
}
|
|
471
|
-
|
|
521
|
+
/* `value` EXPLICIT, and that is not decoration: an <option>
|
|
522
|
+
* with no value attribute answers with its own TEXT, so the
|
|
523
|
+
* moment the label is translated `evt.target.value` becomes
|
|
524
|
+
* "Edición" and the mode the FSM is told to enter is a word
|
|
525
|
+
* no `switch` of this gclass knows. */
|
|
526
|
+
let mode_options = modes.map(item =>
|
|
527
|
+
['option', {value: item, 'data-i18n': item}, option_label(item)]
|
|
528
|
+
);
|
|
472
529
|
|
|
473
530
|
/*
|
|
474
531
|
* Left: layout and mode selectors
|
|
@@ -876,7 +933,12 @@ function populate_nodes_tree_options(gobj)
|
|
|
876
933
|
for(let name of layout_names) {
|
|
877
934
|
let option = document.createElement('option');
|
|
878
935
|
option.value = name;
|
|
879
|
-
|
|
936
|
+
/* The key travels in the attribute so a language change
|
|
937
|
+
* re-translates it: `refresh_language()` only touches a
|
|
938
|
+
* node that carries its own key, and this select is built
|
|
939
|
+
* once, after the child answers with its layouts. */
|
|
940
|
+
option.setAttribute('data-i18n', name);
|
|
941
|
+
option.textContent = option_label(name);
|
|
880
942
|
$layout_select.appendChild(option);
|
|
881
943
|
}
|
|
882
944
|
// Restore persisted layout selection
|