@yuneta/gobj-ui 7.23.83 → 7.23.85
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 +47 -7
- package/dist/gobj-ui.cjs.js +281 -104
- package/dist/gobj-ui.es.js +281 -104
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +267 -88
- package/src/c_yui_treedb_graph.js +59 -3
- package/src/treedb_layout.js +55 -16
- package/src/treedb_layout.test.js +15 -0
package/src/c_g6_nodes_tree.js
CHANGED
|
@@ -58,6 +58,7 @@ import {
|
|
|
58
58
|
gobj_short_name,
|
|
59
59
|
gobj_is_destroying,
|
|
60
60
|
gobj_subscribe_event,
|
|
61
|
+
gobj_unsubscribe_event,
|
|
61
62
|
gobj_publish_event,
|
|
62
63
|
gobj_send_event,
|
|
63
64
|
gobj_post_event,
|
|
@@ -143,7 +144,7 @@ import {
|
|
|
143
144
|
} from '@antv/g6';
|
|
144
145
|
|
|
145
146
|
import {Circle as CircleGeometry, Rect as RectGeometry} from '@antv/g';
|
|
146
|
-
import
|
|
147
|
+
import {t} from "i18next";
|
|
147
148
|
|
|
148
149
|
import {inject_svg_icons} from "./lib_icons.js";
|
|
149
150
|
import {ensure_drag_canvas_patch} from "./g6_drag_canvas_touch.js";
|
|
@@ -157,6 +158,7 @@ import {
|
|
|
157
158
|
consume_long_press_click,
|
|
158
159
|
} from "./g6_touch_gestures.js";
|
|
159
160
|
import {yui_theme_now, yui_watch_theme} from "./yui_theme.js";
|
|
161
|
+
import {yui_shell_of} from "./c_yui_shell.js";
|
|
160
162
|
|
|
161
163
|
/***************************************************************
|
|
162
164
|
* YuiToolbar — G6 Toolbar subclass that adds per-item className
|
|
@@ -465,11 +467,14 @@ let PRIVATE_DATA = {
|
|
|
465
467
|
_edge_icon_el: null, // floating properties icon element
|
|
466
468
|
_edge_delete_el: null, // floating delete icon element for edge
|
|
467
469
|
_edge_popover_el: null, // edge properties popover element
|
|
470
|
+
_edge_preview_undo: null, // ...and how to undo what it previewed
|
|
468
471
|
_port_icon_el: null, // floating port properties icon element
|
|
469
472
|
_port_popover_el: null, // port properties popover element
|
|
473
|
+
_port_preview_undo: null, // ...and how to undo what it previewed
|
|
470
474
|
_node_icon_el: null, // floating node properties icon element
|
|
471
475
|
_node_delete_el: null, // floating delete icon element for node
|
|
472
476
|
_node_popover_el: null, // node properties popover element
|
|
477
|
+
_node_preview_undo: null, // ...and how to undo what it previewed
|
|
473
478
|
_node_detail_el: null, // read-only detail popover (on click)
|
|
474
479
|
_detail_node_id: null, // node id the detail popover is showing
|
|
475
480
|
_delete_confirm_el: null, // delete confirmation popover
|
|
@@ -613,6 +618,18 @@ function mt_writing(gobj, path)
|
|
|
613
618
|
***************************************************************/
|
|
614
619
|
function mt_start(gobj)
|
|
615
620
|
{
|
|
621
|
+
/* A language change reaches the toolbars and the `+N` chips as
|
|
622
|
+
* the shell's EVENT, not as a raw i18next listener: what the
|
|
623
|
+
* toolbar draws and what a chip says are built here, out of
|
|
624
|
+
* reach of refresh_language(), so somebody has to repaint them
|
|
625
|
+
* -- and that somebody is an action of this machine, where the
|
|
626
|
+
* `machine` trace can see it. Same wiring as C_YUI_PERIOD and
|
|
627
|
+
* C_YUI_GOBJ_TREE_JS. */
|
|
628
|
+
let shell = yui_shell_of(gobj);
|
|
629
|
+
if(shell) {
|
|
630
|
+
gobj_subscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
631
|
+
}
|
|
632
|
+
|
|
616
633
|
return 0;
|
|
617
634
|
}
|
|
618
635
|
|
|
@@ -621,6 +638,11 @@ function mt_start(gobj)
|
|
|
621
638
|
***************************************************************/
|
|
622
639
|
function mt_stop(gobj)
|
|
623
640
|
{
|
|
641
|
+
let shell = yui_shell_of(gobj);
|
|
642
|
+
if(shell) {
|
|
643
|
+
gobj_unsubscribe_event(shell, "EV_LANGUAGE_CHANGED", {}, gobj);
|
|
644
|
+
}
|
|
645
|
+
|
|
624
646
|
return 0;
|
|
625
647
|
}
|
|
626
648
|
|
|
@@ -631,11 +653,6 @@ function mt_destroy(gobj)
|
|
|
631
653
|
{
|
|
632
654
|
let priv = gobj.priv;
|
|
633
655
|
|
|
634
|
-
if(priv._on_language_changed) {
|
|
635
|
-
i18next.off('languageChanged', priv._on_language_changed);
|
|
636
|
-
priv._on_language_changed = null;
|
|
637
|
-
}
|
|
638
|
-
|
|
639
656
|
uninstall_fold_listener(gobj);
|
|
640
657
|
|
|
641
658
|
if(priv._on_pointerdown_focus) {
|
|
@@ -1022,12 +1039,6 @@ function configure_events(gobj)
|
|
|
1022
1039
|
}
|
|
1023
1040
|
});
|
|
1024
1041
|
|
|
1025
|
-
// Re-render G6 toolbars (and the `+N` chips' titles) when language changes
|
|
1026
|
-
priv._on_language_changed = () => {
|
|
1027
|
-
update_toolbar(gobj);
|
|
1028
|
-
repaint_more_chips(gobj);
|
|
1029
|
-
};
|
|
1030
|
-
i18next.on('languageChanged', priv._on_language_changed);
|
|
1031
1042
|
|
|
1032
1043
|
/* Clicking a CARD is clicking a DOM element inside the container,
|
|
1033
1044
|
* and that takes the keyboard away from G6's canvas -- the only
|
|
@@ -1865,6 +1876,17 @@ const LR_LAYOUTS = ["dagre"];
|
|
|
1865
1876
|
* toolbar's +/-, and the two-finger pinch of g6_touch_gestures.
|
|
1866
1877
|
* `enable` on the scroll keeps the two apart: a Ctrl wheel is
|
|
1867
1878
|
* the zoom's, so the scroll stands aside for it.
|
|
1879
|
+
*
|
|
1880
|
+
* And the two have to name the SAME key, or the gesture falls
|
|
1881
|
+
* between them: the scroll stood aside for Meta as well, while
|
|
1882
|
+
* the zoom listened for Control alone, so Cmd + wheel neither
|
|
1883
|
+
* scrolled nor zoomed. It is ONE key and not two because a G6
|
|
1884
|
+
* `trigger` is a CHORD, not a list of alternatives -- its
|
|
1885
|
+
* `Shortcut.match()` compares the held keys to the bound ones
|
|
1886
|
+
* as a SET, so ["Control", "Meta"] means both keys down at
|
|
1887
|
+
* once. Control it is, on every platform: it is what a
|
|
1888
|
+
* trackpad pinch arrives as, so a Mac keeps its pinch and
|
|
1889
|
+
* gains nothing to press by mistake.
|
|
1868
1890
|
************************************************************/
|
|
1869
1891
|
function camera_behaviors()
|
|
1870
1892
|
{
|
|
@@ -1872,7 +1894,7 @@ function camera_behaviors()
|
|
|
1872
1894
|
{
|
|
1873
1895
|
type: "scroll-canvas",
|
|
1874
1896
|
key: "scroll-canvas",
|
|
1875
|
-
enable: (event) => !(event &&
|
|
1897
|
+
enable: (event) => !(event && event.ctrlKey),
|
|
1876
1898
|
},
|
|
1877
1899
|
{
|
|
1878
1900
|
type: "zoom-canvas",
|
|
@@ -2081,6 +2103,54 @@ function topic_defaults_of(gobj, topic_name)
|
|
|
2081
2103
|
topic_props.defaults : null;
|
|
2082
2104
|
}
|
|
2083
2105
|
|
|
2106
|
+
/************************************************************
|
|
2107
|
+
* What a node is PAINTED with: its own colours, then the
|
|
2108
|
+
* topic's default, then the topic's colour.
|
|
2109
|
+
*
|
|
2110
|
+
* A card is html, and its html was built with `desc.color`
|
|
2111
|
+
* every time it was repainted -- so a colour chosen in the node
|
|
2112
|
+
* properties popover lasted until the next selection, focus,
|
|
2113
|
+
* theme or pill change, and was never written to `__graphs__`
|
|
2114
|
+
* at all. Only the `shape` view kept it, because a figure is a
|
|
2115
|
+
* native G6 node and `style.fill` is what paints it. The FIGURE
|
|
2116
|
+
* was already remembered (`node_shape`); this is the wiring the
|
|
2117
|
+
* colour was missing.
|
|
2118
|
+
************************************************************/
|
|
2119
|
+
function node_paint_of(gobj, desc, geometry)
|
|
2120
|
+
{
|
|
2121
|
+
let defaults = topic_defaults_of(gobj, desc.topic_name);
|
|
2122
|
+
let g = is_object(geometry)? geometry : {};
|
|
2123
|
+
let fill = g.fill || (defaults && defaults.fill) || desc.color;
|
|
2124
|
+
let stroke = g.stroke || (defaults && defaults.stroke) || getStrokeColor(fill);
|
|
2125
|
+
let line_width = g.lineWidth || (defaults && defaults.lineWidth) || 1;
|
|
2126
|
+
return {fill: fill, stroke: stroke, lineWidth: line_width};
|
|
2127
|
+
}
|
|
2128
|
+
|
|
2129
|
+
/************************************************************
|
|
2130
|
+
* Write a chosen paint into an entry of `__graphs__` -- a
|
|
2131
|
+
* node's or a topic's defaults.
|
|
2132
|
+
*
|
|
2133
|
+
* A colour nobody chose is not saved: the topic's own colour,
|
|
2134
|
+
* with the stroke and the line width that go with it, is what a
|
|
2135
|
+
* card wears anyway, and writing it down would freeze today's
|
|
2136
|
+
* palette on that card -- the trap the SIZES fell into in
|
|
2137
|
+
* 7.23.80, and the palette is assigned by POSITION (`ac_descs`),
|
|
2138
|
+
* so it moves when a topic is added. Choosing it back MEANS
|
|
2139
|
+
* forgetting the entry.
|
|
2140
|
+
************************************************************/
|
|
2141
|
+
function paint_into(entry, desc, fill, stroke, line_width)
|
|
2142
|
+
{
|
|
2143
|
+
if(fill === desc.color && stroke === getStrokeColor(desc.color) && line_width === 1) {
|
|
2144
|
+
delete entry.fill;
|
|
2145
|
+
delete entry.stroke;
|
|
2146
|
+
delete entry.lineWidth;
|
|
2147
|
+
return;
|
|
2148
|
+
}
|
|
2149
|
+
entry.fill = fill;
|
|
2150
|
+
entry.stroke = stroke;
|
|
2151
|
+
entry.lineWidth = line_width;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2084
2154
|
/************************************************************
|
|
2085
2155
|
* The CARD: an html node, the tier's size, the ports, the
|
|
2086
2156
|
* saved geometry on top. The flags (focus, selection, anchor)
|
|
@@ -2093,11 +2163,12 @@ function card_shape_of(gobj, desc, record, geometry, pills_html)
|
|
|
2093
2163
|
let node_treedb_type = desc.node_treedb_type;
|
|
2094
2164
|
let label = node_label(desc, record);
|
|
2095
2165
|
let ports = build_ports(gobj, desc);
|
|
2166
|
+
let paint = node_paint_of(gobj, desc, geometry);
|
|
2096
2167
|
|
|
2097
2168
|
let style = {
|
|
2098
|
-
fill:
|
|
2099
|
-
stroke:
|
|
2100
|
-
lineWidth:
|
|
2169
|
+
fill: paint.fill,
|
|
2170
|
+
stroke: paint.stroke,
|
|
2171
|
+
lineWidth: paint.lineWidth,
|
|
2101
2172
|
lineDash: [],
|
|
2102
2173
|
halo: false,
|
|
2103
2174
|
labelText: "", /* a card says its name inside; the label is the square's */
|
|
@@ -2114,20 +2185,20 @@ function card_shape_of(gobj, desc, record, geometry, pills_html)
|
|
|
2114
2185
|
// Pure child (LEAF): smallest tier. Rounded-rect chip,
|
|
2115
2186
|
// same card language as entities, lighter.
|
|
2116
2187
|
style.innerHTML = build_chip_innerHTML(
|
|
2117
|
-
|
|
2188
|
+
paint.fill, priv.theme, record.icon, label, record.id
|
|
2118
2189
|
);
|
|
2119
2190
|
} else if(node_treedb_type === 'extended') {
|
|
2120
2191
|
// Extended (structural / INTERMEDIATE): middle tier. Card
|
|
2121
2192
|
// with name; "structural" style (neutral grey, dashed
|
|
2122
2193
|
// border) to read as a container/junction.
|
|
2123
2194
|
style.innerHTML = build_node_innerHTML(
|
|
2124
|
-
|
|
2195
|
+
paint.fill, priv.theme, record.icon, label,
|
|
2125
2196
|
desc.topic_name, true, record.id, false, false, false, pills_html
|
|
2126
2197
|
);
|
|
2127
2198
|
} else {
|
|
2128
2199
|
// Hierarchical entity (ROOT / container): largest tier.
|
|
2129
2200
|
style.innerHTML = build_node_innerHTML(
|
|
2130
|
-
|
|
2201
|
+
paint.fill, priv.theme, record.icon, label,
|
|
2131
2202
|
desc.topic_name, false, record.id, false, false, false, pills_html
|
|
2132
2203
|
);
|
|
2133
2204
|
}
|
|
@@ -2230,11 +2301,12 @@ function pill_shape_of(gobj, desc, record, geometry)
|
|
|
2230
2301
|
let tier = desc.node_treedb_type;
|
|
2231
2302
|
let size = PILL_SIZE[tier] || PILL_SIZE.hierarchical;
|
|
2232
2303
|
let ports = build_ports(gobj, desc);
|
|
2304
|
+
let paint = node_paint_of(gobj, desc, geometry);
|
|
2233
2305
|
|
|
2234
2306
|
let style = {
|
|
2235
|
-
fill:
|
|
2236
|
-
stroke:
|
|
2237
|
-
lineWidth:
|
|
2307
|
+
fill: paint.fill,
|
|
2308
|
+
stroke: paint.stroke,
|
|
2309
|
+
lineWidth: paint.lineWidth,
|
|
2238
2310
|
lineDash: [],
|
|
2239
2311
|
halo: false,
|
|
2240
2312
|
labelText: "",
|
|
@@ -2242,7 +2314,7 @@ function pill_shape_of(gobj, desc, record, geometry)
|
|
|
2242
2314
|
dx: -size[0] / 2,
|
|
2243
2315
|
dy: -size[1] / 2,
|
|
2244
2316
|
innerHTML: build_chip_innerHTML(
|
|
2245
|
-
|
|
2317
|
+
paint.fill, priv.theme, record.icon, node_label(desc, record), record.id
|
|
2246
2318
|
),
|
|
2247
2319
|
};
|
|
2248
2320
|
dress_ports(gobj, style, ports, geometry, topic_defaults_of(gobj, desc.topic_name),
|
|
@@ -2256,7 +2328,7 @@ function pill_innerHTML_of(gobj, nd, theme, highlight, selected, anchored)
|
|
|
2256
2328
|
let desc = nd.data.desc;
|
|
2257
2329
|
let record = nd.data.record || {};
|
|
2258
2330
|
return build_chip_innerHTML(
|
|
2259
|
-
|
|
2331
|
+
node_fill_of(nd), theme, record.icon, node_label(desc, record), record.id,
|
|
2260
2332
|
highlight, selected, anchored
|
|
2261
2333
|
);
|
|
2262
2334
|
}
|
|
@@ -2293,9 +2365,10 @@ function figure_shape_of(gobj, desc, record, geometry, flags)
|
|
|
2293
2365
|
let side = SHAPE_SIZE[tier] || SHAPE_SIZE.hierarchical;
|
|
2294
2366
|
let labels = gobj_read_bool_attr(gobj, "node_labels");
|
|
2295
2367
|
let figure = node_figure_of(gobj, desc, geometry || {});
|
|
2368
|
+
let paint = node_paint_of(gobj, desc, geometry);
|
|
2296
2369
|
|
|
2297
|
-
let stroke =
|
|
2298
|
-
let line_width = 1.5;
|
|
2370
|
+
let stroke = paint.stroke;
|
|
2371
|
+
let line_width = Math.max(paint.lineWidth, 1.5);
|
|
2299
2372
|
if(f.selected) {
|
|
2300
2373
|
stroke = SELECT_RING;
|
|
2301
2374
|
line_width = 3;
|
|
@@ -2318,7 +2391,7 @@ function figure_shape_of(gobj, desc, record, geometry, flags)
|
|
|
2318
2391
|
let style = {
|
|
2319
2392
|
size: [side, side],
|
|
2320
2393
|
radius: (figure === 'square')? Math.round(side / 5) : 0,
|
|
2321
|
-
fill:
|
|
2394
|
+
fill: paint.fill,
|
|
2322
2395
|
stroke: stroke,
|
|
2323
2396
|
lineWidth: line_width,
|
|
2324
2397
|
lineDash: dash,
|
|
@@ -4046,6 +4119,42 @@ function hide_overlay(gobj, ...keys)
|
|
|
4046
4119
|
/************************************************************
|
|
4047
4120
|
* Enable the save button (mark graph as dirty).
|
|
4048
4121
|
************************************************************/
|
|
4122
|
+
/************************************************************
|
|
4123
|
+
* A popover that PREVIEWS its changes owes an undo.
|
|
4124
|
+
*
|
|
4125
|
+
* What the preview writes is not the reader's answer until
|
|
4126
|
+
* `apply` is pressed, and `cancel` used to be the only way
|
|
4127
|
+
* back: every other way out of the popover -- a click on the
|
|
4128
|
+
* canvas, the icon pressed again, the element going away --
|
|
4129
|
+
* left the preview standing on the element, and the next Save
|
|
4130
|
+
* wrote it to `__graphs__`. So the undo is kept beside the
|
|
4131
|
+
* popover and run by whoever hides it; `apply` drops it first,
|
|
4132
|
+
* because then the preview IS the answer.
|
|
4133
|
+
************************************************************/
|
|
4134
|
+
function set_preview_undo(gobj, key, undo)
|
|
4135
|
+
{
|
|
4136
|
+
gobj.priv[key] = undo;
|
|
4137
|
+
}
|
|
4138
|
+
|
|
4139
|
+
function drop_preview_undo(gobj, key)
|
|
4140
|
+
{
|
|
4141
|
+
gobj.priv[key] = null;
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
function run_preview_undo(gobj, key)
|
|
4145
|
+
{
|
|
4146
|
+
let undo = gobj.priv[key];
|
|
4147
|
+
gobj.priv[key] = null;
|
|
4148
|
+
if(!undo || gobj_is_destroying(gobj)) {
|
|
4149
|
+
return;
|
|
4150
|
+
}
|
|
4151
|
+
try {
|
|
4152
|
+
undo();
|
|
4153
|
+
} catch(e) {
|
|
4154
|
+
log_error(`${gobj_short_name(gobj)}: cannot undo the preview: ${e}`);
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
|
|
4049
4158
|
function mark_graph_dirty(gobj)
|
|
4050
4159
|
{
|
|
4051
4160
|
let $container = gobj_read_attr(gobj, "$container");
|
|
@@ -4990,6 +5099,34 @@ function port_hit_slop_world(graph)
|
|
|
4990
5099
|
return slop / zoom;
|
|
4991
5100
|
}
|
|
4992
5101
|
|
|
5102
|
+
/************************************************************
|
|
5103
|
+
* Whether a point landed on a port, by the port's SHAPE.
|
|
5104
|
+
*
|
|
5105
|
+
* A port was a circle and the test was a radius; since 7.23.81
|
|
5106
|
+
* it can be a square, a diamond or a triangle too, and a circle
|
|
5107
|
+
* around a diamond answers for the air off its corners while
|
|
5108
|
+
* missing the middle of its edges. `r` is the drawn radius with
|
|
5109
|
+
* the hit slop already added, and the shapes are the ones
|
|
5110
|
+
* TreedbCard.drawPortShapes() draws from it.
|
|
5111
|
+
*
|
|
5112
|
+
* dx, dy the point, relative to the port's centre
|
|
5113
|
+
************************************************************/
|
|
5114
|
+
function port_shape_hit(shape, dx, dy, r)
|
|
5115
|
+
{
|
|
5116
|
+
switch(shape) {
|
|
5117
|
+
case 'square':
|
|
5118
|
+
return Math.abs(dx) <= r && Math.abs(dy) <= r;
|
|
5119
|
+
case 'diamond':
|
|
5120
|
+
return Math.abs(dx) + Math.abs(dy) <= r;
|
|
5121
|
+
case 'triangle':
|
|
5122
|
+
/* (0,-r), (r,r), (-r,r): under the base and inside the
|
|
5123
|
+
* two slanted sides, which meet at 2|x| - y = r. */
|
|
5124
|
+
return dy <= r && (2 * Math.abs(dx) - dy) <= r;
|
|
5125
|
+
default:
|
|
5126
|
+
return Math.hypot(dx, dy) <= r;
|
|
5127
|
+
}
|
|
5128
|
+
}
|
|
5129
|
+
|
|
4993
5130
|
/************************************************************
|
|
4994
5131
|
* Detect if a click in canvas coordinates hits a port.
|
|
4995
5132
|
* Returns the port key string, or null if no port hit.
|
|
@@ -5021,8 +5158,9 @@ function detect_port_click(gobj, node_id, canvasX, canvasY)
|
|
|
5021
5158
|
let dist = Math.sqrt(dx * dx + dy * dy);
|
|
5022
5159
|
|
|
5023
5160
|
/* Nearest wins, so the enlarged areas of two ports
|
|
5024
|
-
* overlapping is not a tie -- it is the closer one.
|
|
5025
|
-
|
|
5161
|
+
* overlapping is not a tie -- it is the closer one. The
|
|
5162
|
+
* distance ranks them; the SHAPE says who is in the running. */
|
|
5163
|
+
if(port_shape_hit(ports[i].shape, dx, dy, r + slop) && dist < best_dist) {
|
|
5026
5164
|
best_dist = dist;
|
|
5027
5165
|
best_key = ports[i].key;
|
|
5028
5166
|
}
|
|
@@ -5240,6 +5378,7 @@ function toggle_port_popover(gobj)
|
|
|
5240
5378
|
|
|
5241
5379
|
function hide_port_popover(gobj)
|
|
5242
5380
|
{
|
|
5381
|
+
run_preview_undo(gobj, '_port_preview_undo');
|
|
5243
5382
|
hide_overlay(gobj, '_port_popover_el');
|
|
5244
5383
|
}
|
|
5245
5384
|
|
|
@@ -5280,6 +5419,17 @@ function show_port_popover(gobj)
|
|
|
5280
5419
|
xy.x + floating_popover_dx(), xy.y, 'g6-port-popover', '#d9d9d9', 180
|
|
5281
5420
|
);
|
|
5282
5421
|
|
|
5422
|
+
/* What the preview writes on this port, undone: whoever hides
|
|
5423
|
+
* the popover without applying runs it (see set_preview_undo). */
|
|
5424
|
+
let undo_port = () => {
|
|
5425
|
+
graph.updateNodeData([{id: node_id, style: {
|
|
5426
|
+
ports: ports_with(nodeData.style.ports, port_key, {shape: orig_shape, r: orig_r}),
|
|
5427
|
+
}}]);
|
|
5428
|
+
graph.draw().then(() => {
|
|
5429
|
+
update_port_resize_handles_position(gobj);
|
|
5430
|
+
});
|
|
5431
|
+
};
|
|
5432
|
+
|
|
5283
5433
|
/* Live preview on THIS port; the others wait for apply. */
|
|
5284
5434
|
function preview_port() {
|
|
5285
5435
|
let r = parseInt(rInput.value) || orig_r;
|
|
@@ -5313,13 +5463,7 @@ function show_port_popover(gobj)
|
|
|
5313
5463
|
text: 'cancel',
|
|
5314
5464
|
style: BTN_STYLE_CANCEL,
|
|
5315
5465
|
onClick: () => {
|
|
5316
|
-
|
|
5317
|
-
ports: ports_with(nodeData.style.ports, port_key, {shape: orig_shape, r: orig_r}),
|
|
5318
|
-
}}]);
|
|
5319
|
-
graph.draw().then(() => {
|
|
5320
|
-
update_port_resize_handles_position(gobj);
|
|
5321
|
-
});
|
|
5322
|
-
hide_port_popover(gobj);
|
|
5466
|
+
hide_port_popover(gobj); /* which undoes the preview */
|
|
5323
5467
|
},
|
|
5324
5468
|
},
|
|
5325
5469
|
{
|
|
@@ -5327,6 +5471,7 @@ function show_port_popover(gobj)
|
|
|
5327
5471
|
style: 'flex:1;padding:6px;background:#1890ff;color:#fff;border:none;' +
|
|
5328
5472
|
'border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;',
|
|
5329
5473
|
onClick: () => {
|
|
5474
|
+
drop_preview_undo(gobj, '_port_preview_undo');
|
|
5330
5475
|
apply_port_properties(gobj, node_id, port_key,
|
|
5331
5476
|
shapeSelect.value, parseInt(rInput.value) || orig_r, scopeSelect.value
|
|
5332
5477
|
);
|
|
@@ -5336,6 +5481,7 @@ function show_port_popover(gobj)
|
|
|
5336
5481
|
|
|
5337
5482
|
priv.$container.appendChild(popover);
|
|
5338
5483
|
priv._port_popover_el = popover;
|
|
5484
|
+
set_preview_undo(gobj, '_port_preview_undo', undo_port);
|
|
5339
5485
|
clamp_popover_position(gobj, popover);
|
|
5340
5486
|
}
|
|
5341
5487
|
|
|
@@ -6184,6 +6330,12 @@ function show_edge_popover(gobj)
|
|
|
6184
6330
|
'g6-edge-popover', '#d9d9d9', 180
|
|
6185
6331
|
);
|
|
6186
6332
|
|
|
6333
|
+
/* What the preview writes, undone (see set_preview_undo). */
|
|
6334
|
+
let undo_edge = () => {
|
|
6335
|
+
graph.updateEdgeData([{ id: edge_id, style: { lineWidth: origLW, stroke: origStroke } }]);
|
|
6336
|
+
graph.draw();
|
|
6337
|
+
};
|
|
6338
|
+
|
|
6187
6339
|
// Live preview: update the selected edge in real time
|
|
6188
6340
|
function preview_edge() {
|
|
6189
6341
|
let lw = parseInt(lwInput.value) || 2;
|
|
@@ -6213,9 +6365,7 @@ function show_edge_popover(gobj)
|
|
|
6213
6365
|
text: 'cancel',
|
|
6214
6366
|
style: BTN_STYLE_CANCEL,
|
|
6215
6367
|
onClick: () => {
|
|
6216
|
-
|
|
6217
|
-
graph.draw();
|
|
6218
|
-
deselect_edge(gobj);
|
|
6368
|
+
deselect_edge(gobj); /* which undoes the preview */
|
|
6219
6369
|
},
|
|
6220
6370
|
},
|
|
6221
6371
|
{
|
|
@@ -6223,6 +6373,7 @@ function show_edge_popover(gobj)
|
|
|
6223
6373
|
style: 'flex:1;padding:6px;background:#52c41a;color:#fff;border:none;' +
|
|
6224
6374
|
'border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;',
|
|
6225
6375
|
onClick: () => {
|
|
6376
|
+
drop_preview_undo(gobj, '_edge_preview_undo');
|
|
6226
6377
|
apply_edge_properties(gobj, edge_id,
|
|
6227
6378
|
parseInt(lwInput.value) || 2,
|
|
6228
6379
|
colorInput.value,
|
|
@@ -6234,6 +6385,7 @@ function show_edge_popover(gobj)
|
|
|
6234
6385
|
|
|
6235
6386
|
priv.$container.appendChild(popover);
|
|
6236
6387
|
priv._edge_popover_el = popover;
|
|
6388
|
+
set_preview_undo(gobj, '_edge_preview_undo', undo_edge);
|
|
6237
6389
|
|
|
6238
6390
|
// Clamp popover inside the container
|
|
6239
6391
|
clamp_popover_position(gobj, popover);
|
|
@@ -6278,6 +6430,7 @@ function clamp_popover_position(gobj, popover)
|
|
|
6278
6430
|
|
|
6279
6431
|
function hide_edge_popover(gobj)
|
|
6280
6432
|
{
|
|
6433
|
+
run_preview_undo(gobj, '_edge_preview_undo');
|
|
6281
6434
|
hide_overlay(gobj, '_edge_popover_el');
|
|
6282
6435
|
}
|
|
6283
6436
|
|
|
@@ -6401,27 +6554,26 @@ function show_node_popover(gobj)
|
|
|
6401
6554
|
'g6-node-popover', '#d9d9d9', 180
|
|
6402
6555
|
);
|
|
6403
6556
|
|
|
6404
|
-
|
|
6405
|
-
|
|
6557
|
+
/* Paint the node with these colours, whatever it is wearing:
|
|
6558
|
+
* the style for a figure, and the html of a card or a pill,
|
|
6559
|
+
* which repaint_cards() rebuilds from the style it is given
|
|
6560
|
+
* here (node_fill_of). */
|
|
6561
|
+
let paint_node = (fill, stroke, lw) => {
|
|
6562
|
+
graph.updateNodeData([{
|
|
6563
|
+
id: node_id, style: {fill: fill, stroke: stroke, lineWidth: lw},
|
|
6564
|
+
}]);
|
|
6565
|
+
repaint_cards(gobj, new Set([node_id]));
|
|
6566
|
+
graph.draw();
|
|
6567
|
+
};
|
|
6568
|
+
|
|
6569
|
+
/* What the preview writes, undone (see set_preview_undo). */
|
|
6570
|
+
let undo_node = () => {
|
|
6571
|
+
paint_node(origFill, origStroke, origLW);
|
|
6572
|
+
};
|
|
6406
6573
|
|
|
6407
6574
|
// Live preview
|
|
6408
6575
|
function preview_node() {
|
|
6409
|
-
|
|
6410
|
-
let stroke = strokeInput.value;
|
|
6411
|
-
let lw = parseInt(lwInput.value) || 1;
|
|
6412
|
-
let updateStyle = { fill: fill, stroke: stroke, lineWidth: lw };
|
|
6413
|
-
|
|
6414
|
-
if(node_graph_type === 'hierarchical') {
|
|
6415
|
-
let record = nodeData.data.record || {};
|
|
6416
|
-
updateStyle.innerHTML = build_node_innerHTML(
|
|
6417
|
-
fill, priv.theme, record.icon,
|
|
6418
|
-
node_label(nodeData.data.desc, record),
|
|
6419
|
-
nodeData.data.desc.topic_name, false, record.id,
|
|
6420
|
-
false, false, false, pills_html_of(gobj, nodeData)
|
|
6421
|
-
);
|
|
6422
|
-
}
|
|
6423
|
-
graph.updateNodeData([{ id: node_id, style: updateStyle }]);
|
|
6424
|
-
graph.draw();
|
|
6576
|
+
paint_node(fillInput.value, strokeInput.value, parseInt(lwInput.value) || 1);
|
|
6425
6577
|
}
|
|
6426
6578
|
|
|
6427
6579
|
// Fill color
|
|
@@ -6460,19 +6612,7 @@ function show_node_popover(gobj)
|
|
|
6460
6612
|
text: 'cancel',
|
|
6461
6613
|
style: BTN_STYLE_CANCEL,
|
|
6462
6614
|
onClick: () => {
|
|
6463
|
-
|
|
6464
|
-
if(node_graph_type === 'hierarchical') {
|
|
6465
|
-
let record = nodeData.data.record || {};
|
|
6466
|
-
restoreStyle.innerHTML = build_node_innerHTML(
|
|
6467
|
-
origFill, priv.theme, record.icon,
|
|
6468
|
-
node_label(nodeData.data.desc, record),
|
|
6469
|
-
nodeData.data.desc.topic_name, false, record.id,
|
|
6470
|
-
false, false, false, pills_html_of(gobj, nodeData)
|
|
6471
|
-
);
|
|
6472
|
-
}
|
|
6473
|
-
graph.updateNodeData([{ id: node_id, style: restoreStyle }]);
|
|
6474
|
-
graph.draw();
|
|
6475
|
-
hide_node_popover(gobj);
|
|
6615
|
+
hide_node_popover(gobj); /* which undoes the preview */
|
|
6476
6616
|
},
|
|
6477
6617
|
},
|
|
6478
6618
|
{
|
|
@@ -6480,6 +6620,7 @@ function show_node_popover(gobj)
|
|
|
6480
6620
|
style: 'flex:1;padding:6px;background:#1890ff;color:#fff;border:none;' +
|
|
6481
6621
|
'border-radius:4px;cursor:pointer;font-size:13px;font-weight:500;',
|
|
6482
6622
|
onClick: () => {
|
|
6623
|
+
drop_preview_undo(gobj, '_node_preview_undo');
|
|
6483
6624
|
apply_node_properties(gobj, node_id,
|
|
6484
6625
|
fillInput.value,
|
|
6485
6626
|
strokeInput.value,
|
|
@@ -6493,6 +6634,7 @@ function show_node_popover(gobj)
|
|
|
6493
6634
|
|
|
6494
6635
|
priv.$container.appendChild(popover);
|
|
6495
6636
|
priv._node_popover_el = popover;
|
|
6637
|
+
set_preview_undo(gobj, '_node_preview_undo', undo_node);
|
|
6496
6638
|
|
|
6497
6639
|
// Clamp popover inside the container
|
|
6498
6640
|
clamp_popover_position(gobj, popover);
|
|
@@ -6500,6 +6642,7 @@ function show_node_popover(gobj)
|
|
|
6500
6642
|
|
|
6501
6643
|
function hide_node_popover(gobj)
|
|
6502
6644
|
{
|
|
6645
|
+
run_preview_undo(gobj, '_node_preview_undo');
|
|
6503
6646
|
hide_overlay(gobj, '_node_popover_el');
|
|
6504
6647
|
}
|
|
6505
6648
|
|
|
@@ -6824,6 +6967,16 @@ function refresh_minimap(gobj)
|
|
|
6824
6967
|
* same three-way choice — it lived inline in the theme refresh and is
|
|
6825
6968
|
* shared now. Returns null for a node that carries no desc.
|
|
6826
6969
|
************************************************************/
|
|
6970
|
+
/* The colour a node is WEARING, from its live style: the shape
|
|
6971
|
+
* functions put the node's own paint there when it has one (see
|
|
6972
|
+
* node_paint_of), and a repaint has to keep it -- rebuilding the
|
|
6973
|
+
* html from `desc.color` is what threw away every colour applied
|
|
6974
|
+
* to a card at the first selection. */
|
|
6975
|
+
function node_fill_of(nd)
|
|
6976
|
+
{
|
|
6977
|
+
return (nd && nd.style && nd.style.fill) || nd.data.desc.color;
|
|
6978
|
+
}
|
|
6979
|
+
|
|
6827
6980
|
function node_innerHTML_of(nd, theme, highlight, selected, anchored, pills_html)
|
|
6828
6981
|
{
|
|
6829
6982
|
if(!nd || !nd.data || !nd.data.desc) {
|
|
@@ -6832,22 +6985,23 @@ function node_innerHTML_of(nd, theme, highlight, selected, anchored, pills_html)
|
|
|
6832
6985
|
let desc = nd.data.desc;
|
|
6833
6986
|
let record = nd.data.record || {};
|
|
6834
6987
|
let label = node_label(desc, record);
|
|
6988
|
+
let fill = node_fill_of(nd);
|
|
6835
6989
|
|
|
6836
6990
|
switch(desc.node_treedb_type) {
|
|
6837
6991
|
case 'child':
|
|
6838
6992
|
return build_chip_innerHTML(
|
|
6839
|
-
|
|
6993
|
+
fill, theme, record.icon, label, record.id,
|
|
6840
6994
|
highlight, selected, anchored
|
|
6841
6995
|
);
|
|
6842
6996
|
case 'extended':
|
|
6843
6997
|
return build_node_innerHTML(
|
|
6844
|
-
|
|
6998
|
+
fill, theme, record.icon, label,
|
|
6845
6999
|
desc.topic_name, true, record.id, highlight, selected, anchored,
|
|
6846
7000
|
pills_html
|
|
6847
7001
|
);
|
|
6848
7002
|
case 'hierarchical':
|
|
6849
7003
|
return build_node_innerHTML(
|
|
6850
|
-
|
|
7004
|
+
fill, theme, record.icon, label,
|
|
6851
7005
|
desc.topic_name, false, record.id, highlight, selected, anchored,
|
|
6852
7006
|
pills_html
|
|
6853
7007
|
);
|
|
@@ -7692,21 +7846,33 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope, sh
|
|
|
7692
7846
|
|
|
7693
7847
|
let source_topic = nodeData.data.desc ? nodeData.data.desc.topic_name : null;
|
|
7694
7848
|
let updates = [];
|
|
7849
|
+
let repaint = new Set();
|
|
7695
7850
|
const nodes = graph.getData().nodes;
|
|
7696
7851
|
|
|
7697
|
-
/* The figure: written where Save reads
|
|
7698
|
-
* `__graphs__`), and as the topic's default for
|
|
7699
|
-
* scopes, so a record that arrives later is born with
|
|
7852
|
+
/* The figure AND the colours: written where Save reads them (the
|
|
7853
|
+
* node's entry in `__graphs__`), and as the topic's default for
|
|
7854
|
+
* the wider scopes, so a record that arrives later is born with
|
|
7855
|
+
* them. The colours used to be written on the live style alone,
|
|
7856
|
+
* which on an html card is under the html: the first repaint
|
|
7857
|
+
* rebuilt that html from the topic's colour and the choice was
|
|
7858
|
+
* gone, and nothing of it ever reached the store. */
|
|
7700
7859
|
let figure = (shape && str_in_list(NODE_SHAPES, shape))? shape : "";
|
|
7701
7860
|
let reshaped = [];
|
|
7702
|
-
if(
|
|
7861
|
+
if(scope !== 'this') {
|
|
7703
7862
|
let topics = (scope === 'same_topic')? [source_topic] : Object.keys(priv.descs || {});
|
|
7704
7863
|
for(let topic_name of topics) {
|
|
7864
|
+
let desc = priv.descs[topic_name];
|
|
7865
|
+
if(!desc) {
|
|
7866
|
+
continue;
|
|
7867
|
+
}
|
|
7705
7868
|
if(!is_object(priv._graph_properties[topic_name])) {
|
|
7706
7869
|
priv._graph_properties[topic_name] = {};
|
|
7707
7870
|
}
|
|
7708
7871
|
let defaults = priv._graph_properties[topic_name].defaults || {};
|
|
7709
|
-
|
|
7872
|
+
if(figure) {
|
|
7873
|
+
defaults.node_shape = figure;
|
|
7874
|
+
}
|
|
7875
|
+
paint_into(defaults, desc, fill, stroke, lineWidth);
|
|
7710
7876
|
priv._graph_properties[topic_name].defaults = defaults;
|
|
7711
7877
|
}
|
|
7712
7878
|
}
|
|
@@ -7724,24 +7890,21 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope, sh
|
|
|
7724
7890
|
continue;
|
|
7725
7891
|
}
|
|
7726
7892
|
|
|
7893
|
+
let entry = node_props_entry(gobj, nd);
|
|
7727
7894
|
if(figure) {
|
|
7728
|
-
|
|
7895
|
+
entry.node_shape = figure;
|
|
7729
7896
|
if(node_mode_of(gobj, nodes[i].id) === 'shape') {
|
|
7730
7897
|
reshaped.push(nodes[i].id);
|
|
7731
7898
|
}
|
|
7732
7899
|
}
|
|
7900
|
+
paint_into(entry, nd.data.desc, fill, stroke, lineWidth);
|
|
7733
7901
|
|
|
7902
|
+
/* The style for the figure, the html for the card and the
|
|
7903
|
+
* pill: every tier is repainted, and the repaint reads the
|
|
7904
|
+
* style it is given here (node_fill_of). */
|
|
7734
7905
|
let updateStyle = { fill: fill, stroke: stroke, lineWidth: lineWidth };
|
|
7735
|
-
if(nd.data.desc.node_treedb_type === 'hierarchical') {
|
|
7736
|
-
let record = nd.data.record || {};
|
|
7737
|
-
updateStyle.innerHTML = build_node_innerHTML(
|
|
7738
|
-
fill, priv.theme, record.icon,
|
|
7739
|
-
node_label(nd.data.desc, record),
|
|
7740
|
-
nd.data.desc.topic_name, false, record.id,
|
|
7741
|
-
false, false, false, pills_html_of(gobj, nd)
|
|
7742
|
-
);
|
|
7743
|
-
}
|
|
7744
7906
|
updates.push({ id: nodes[i].id, style: updateStyle });
|
|
7907
|
+
repaint.add(nodes[i].id);
|
|
7745
7908
|
}
|
|
7746
7909
|
|
|
7747
7910
|
if(updates.length > 0) {
|
|
@@ -7749,6 +7912,7 @@ function apply_node_properties(gobj, node_id, fill, stroke, lineWidth, scope, sh
|
|
|
7749
7912
|
if(reshaped.length) {
|
|
7750
7913
|
reshape_nodes(gobj, reshaped);
|
|
7751
7914
|
}
|
|
7915
|
+
repaint_cards(gobj, repaint);
|
|
7752
7916
|
graph.draw().then(() => {
|
|
7753
7917
|
mark_graph_dirty(gobj);
|
|
7754
7918
|
});
|
|
@@ -8980,6 +9144,19 @@ async function reconcile_fold_apply(gobj, opts, visible)
|
|
|
8980
9144
|
return changed;
|
|
8981
9145
|
}
|
|
8982
9146
|
|
|
9147
|
+
/************************************************************
|
|
9148
|
+
* The application changed language: what this gclass DRAWS has
|
|
9149
|
+
* to be drawn again. `refresh_language()` reaches what carries
|
|
9150
|
+
* an i18n key in the DOM; a G6 toolbar and the html of a chip
|
|
9151
|
+
* are built here and carry none.
|
|
9152
|
+
************************************************************/
|
|
9153
|
+
function ac_language_changed(gobj, event, kw, src)
|
|
9154
|
+
{
|
|
9155
|
+
update_toolbar(gobj);
|
|
9156
|
+
repaint_more_chips(gobj);
|
|
9157
|
+
return 0;
|
|
9158
|
+
}
|
|
9159
|
+
|
|
8983
9160
|
/************************************************************
|
|
8984
9161
|
* Repaint the `+N` chips (theme or language changed).
|
|
8985
9162
|
************************************************************/
|
|
@@ -10527,6 +10704,7 @@ function create_gclass(gclass_name)
|
|
|
10527
10704
|
["EV_HIDE", ac_hide, null],
|
|
10528
10705
|
["EV_RESIZE", ac_resize, null],
|
|
10529
10706
|
["EV_THEME", ac_theme, null],
|
|
10707
|
+
["EV_LANGUAGE_CHANGED", ac_language_changed, null],
|
|
10530
10708
|
]]
|
|
10531
10709
|
];
|
|
10532
10710
|
|
|
@@ -10621,6 +10799,7 @@ function create_gclass(gclass_name)
|
|
|
10621
10799
|
["EV_HIDE", 0],
|
|
10622
10800
|
["EV_RESIZE", 0],
|
|
10623
10801
|
["EV_THEME", 0],
|
|
10802
|
+
["EV_LANGUAGE_CHANGED", 0],
|
|
10624
10803
|
];
|
|
10625
10804
|
|
|
10626
10805
|
/*----------------------------------------*
|