@yuneta/gobj-ui 7.23.185 → 7.23.187
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/dist/gobj-ui.cjs.js +201 -43
- package/dist/gobj-ui.es.js +202 -44
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +105 -39
- package/src/c_yui_schema_editor.js +3 -1
- package/src/c_yui_treedb_topics.js +81 -11
- package/src/graph_save_plan.js +108 -0
- package/src/graph_save_plan.test.js +146 -0
- package/src/yui_icons.css +9 -0
package/dist/gobj-ui.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SDATA, SDATA_END, clean_name, createElement2, createOneHtml, create_template_record, data_type_t, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat_diff, gclass_create, gclass_find_by_name, gclass_flag_t, getPositionRelativeToBody, gobj_bottom_gobj, gobj_change_state, gobj_command, gobj_create, gobj_create_pure_child, gobj_create_service, gobj_current_state, gobj_destroy, gobj_find_child, gobj_find_service, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level2, gobj_global_trace_level, gobj_global_trace_no_level, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_match_children, gobj_name, gobj_parent, gobj_post_event, gobj_publish_event, gobj_read_attr, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_save_persistent_attrs, gobj_send_event, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_tree, gobj_stop, gobj_stop_children, gobj_subscribe_event, gobj_unsubscribe_event, gobj_write_attr, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_name, is_array, is_boolean, is_date, is_gobj, is_null, is_number, is_object, is_string, json2flat, json_deep_copy, json_object_size, json_object_update, json_object_update_missing, json_size, kw_clone_by_keys, kw_flag_t, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_local_storage_value, kw_get_str, kw_has_key, kw_set_dict_value, kw_set_local_storage_value, kwid_find_one_record, kwid_new_dict, log_error, log_warning, msg_iev_get_stack, parseBoolean, parseSVG, refresh_language, safeSrc, sdata_flag_t, set_console_log_enabled, set_log_callback, sprintf, str_in_list, template_get_field_desc, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size } from "@yuneta/gobj-js";
|
|
1
|
+
import { SDATA, SDATA_END, clean_name, createElement2, createOneHtml, create_template_record, data_type_t, debounce, delete_from_list, duplicate_objects, empty_json, empty_string, escapeHtml, event_flag_t, flat_diff, gclass_create, gclass_find_by_name, gclass_flag_t, getPositionRelativeToBody, gobj_bottom_gobj, gobj_change_state, gobj_command, gobj_create, gobj_create_pure_child, gobj_create_service, gobj_current_state, gobj_destroy, gobj_find_child, gobj_find_service, gobj_full_name, gobj_gclass_name, gobj_get_gclass_trace_level2, gobj_global_trace_level, gobj_global_trace_no_level, gobj_is_destroying, gobj_is_playing, gobj_is_pure_child, gobj_is_running, gobj_is_service, gobj_is_volatil, gobj_match_children, gobj_name, gobj_parent, gobj_post_event, gobj_publish_event, gobj_read_attr, gobj_read_bool_attr, gobj_read_integer_attr, gobj_read_pointer_attr, gobj_read_str_attr, gobj_save_persistent_attrs, gobj_send_event, gobj_set_trace_machine_format, gobj_short_name, gobj_start, gobj_start_tree, gobj_stop, gobj_stop_children, gobj_subscribe_event, gobj_unsubscribe_event, gobj_write_attr, gobj_write_bool_attr, gobj_write_integer_attr, gobj_write_str_attr, gobj_yuno, gobj_yuno_name, is_array, is_boolean, is_date, is_gobj, is_null, is_number, is_object, is_string, json2flat, json_deep_copy, json_is_identical, json_object_size, json_object_update, json_object_update_missing, json_size, kw_clone_by_keys, kw_flag_t, kw_get_dict, kw_get_dict_value, kw_get_int, kw_get_local_storage_value, kw_get_str, kw_has_key, kw_set_dict_value, kw_set_local_storage_value, kwid_find_one_record, kwid_new_dict, log_error, log_warning, msg_iev_get_stack, parseBoolean, parseSVG, refresh_language, safeSrc, sdata_flag_t, set_console_log_enabled, set_log_callback, sprintf, str_in_list, template_get_field_desc, trace_level_t, trace_msg, treedb_decoder_fkey, treedb_encoder_fkey, treedb_get_field_desc, treedb_hook_data_size } from "@yuneta/gobj-js";
|
|
2
2
|
import i18next, { t } from "i18next";
|
|
3
3
|
import TomSelect from "tom-select";
|
|
4
4
|
import { createJSONEditor } from "vanilla-jsoneditor";
|
|
@@ -23709,7 +23709,7 @@ function build_ui$6(gobj) {
|
|
|
23709
23709
|
[[
|
|
23710
23710
|
"span",
|
|
23711
23711
|
{ class: "icon" },
|
|
23712
|
-
[yui_toolbar_icon("yi-
|
|
23712
|
+
[yui_toolbar_icon("yi-compass-drafting")]
|
|
23713
23713
|
], [
|
|
23714
23714
|
"span",
|
|
23715
23715
|
{ i18n: "schema" },
|
|
@@ -23720,6 +23720,29 @@ function build_ui$6(gobj) {
|
|
|
23720
23720
|
gobj_send_event(gobj, "EV_TOGGLE_LANDING_VIEW", {}, gobj);
|
|
23721
23721
|
} }
|
|
23722
23722
|
],
|
|
23723
|
+
[
|
|
23724
|
+
"button",
|
|
23725
|
+
{
|
|
23726
|
+
class: "button TREEDB_SCHEMA_JSON_BTN is-hidden",
|
|
23727
|
+
title: t("schema json"),
|
|
23728
|
+
"aria-label": t("schema json"),
|
|
23729
|
+
"data-i18n-title": "schema json",
|
|
23730
|
+
"data-i18n-aria-label": "schema json"
|
|
23731
|
+
},
|
|
23732
|
+
[[
|
|
23733
|
+
"span",
|
|
23734
|
+
{ class: "icon" },
|
|
23735
|
+
[yui_toolbar_icon("yi-code")]
|
|
23736
|
+
], [
|
|
23737
|
+
"span",
|
|
23738
|
+
{ i18n: "schema json" },
|
|
23739
|
+
"schema json"
|
|
23740
|
+
]],
|
|
23741
|
+
{ click: (evt) => {
|
|
23742
|
+
evt.stopPropagation();
|
|
23743
|
+
gobj_send_event(gobj, "EV_OPEN_SCHEMA_JSON", {}, gobj);
|
|
23744
|
+
} }
|
|
23745
|
+
],
|
|
23723
23746
|
[
|
|
23724
23747
|
"div",
|
|
23725
23748
|
{
|
|
@@ -24163,6 +24186,7 @@ function show_topics_landing(gobj) {
|
|
|
24163
24186
|
let $info = $container.querySelector(".TREEDB_TOPIC_INFO");
|
|
24164
24187
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
24165
24188
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
24189
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
24166
24190
|
if ($tabs) $tabs.classList.add("is-hidden");
|
|
24167
24191
|
if ($sub) $sub.classList.add("is-hidden");
|
|
24168
24192
|
if ($info) $info.classList.add("is-hidden");
|
|
@@ -24172,6 +24196,7 @@ function show_topics_landing(gobj) {
|
|
|
24172
24196
|
$toggle.classList.remove("is-hidden");
|
|
24173
24197
|
$toggle.classList.toggle("is-primary", schema_mode);
|
|
24174
24198
|
}
|
|
24199
|
+
if ($schema_json) $schema_json.classList.toggle("is-hidden", !schema_mode);
|
|
24175
24200
|
if (schema_mode) {
|
|
24176
24201
|
if ($landing) $landing.classList.add("is-hidden");
|
|
24177
24202
|
if ($schema) $schema.classList.remove("is-hidden");
|
|
@@ -24241,9 +24266,11 @@ function show_topic_detail(gobj) {
|
|
|
24241
24266
|
let $info = $container.querySelector(".TREEDB_TOPIC_INFO");
|
|
24242
24267
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
24243
24268
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
24269
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
24244
24270
|
if ($landing) $landing.classList.add("is-hidden");
|
|
24245
24271
|
if ($schema) $schema.classList.add("is-hidden");
|
|
24246
24272
|
if ($info) $info.classList.add("is-hidden");
|
|
24273
|
+
if ($schema_json) $schema_json.classList.add("is-hidden");
|
|
24247
24274
|
if ($toggle) $toggle.classList.add("is-hidden");
|
|
24248
24275
|
if ($tabs) $tabs.classList.remove("is-hidden");
|
|
24249
24276
|
if ($sub) $sub.classList.remove("is-hidden");
|
|
@@ -24284,8 +24311,10 @@ function show_topic_info(gobj, topic) {
|
|
|
24284
24311
|
let $schema = $container.querySelector(".TREEDB_TOPICS_SCHEMA");
|
|
24285
24312
|
let $back = $container.querySelector(".TREEDB_TOPICS_BACK");
|
|
24286
24313
|
let $toggle = $container.querySelector(".TREEDB_LANDING_TOGGLE");
|
|
24314
|
+
let $schema_json = $container.querySelector(".TREEDB_SCHEMA_JSON_BTN");
|
|
24287
24315
|
if ($landing) $landing.classList.add("is-hidden");
|
|
24288
24316
|
if ($schema) $schema.classList.add("is-hidden");
|
|
24317
|
+
if ($schema_json) $schema_json.classList.add("is-hidden");
|
|
24289
24318
|
if ($toggle) $toggle.classList.add("is-hidden");
|
|
24290
24319
|
if ($tabs) $tabs.classList.add("is-hidden");
|
|
24291
24320
|
if ($sub) $sub.classList.add("is-hidden");
|
|
@@ -24560,7 +24589,7 @@ function register_sub_routes$1(gobj) {
|
|
|
24560
24589
|
if (is_object(gobj_read_attr(gobj, "landing_routes"))) nodes.push({
|
|
24561
24590
|
route: base + "/schema",
|
|
24562
24591
|
label: "schema",
|
|
24563
|
-
icon: "yi-
|
|
24592
|
+
icon: "yi-compass-drafting",
|
|
24564
24593
|
gclass: "C_YUI_TREEDB_SCHEMA"
|
|
24565
24594
|
});
|
|
24566
24595
|
if (is_object(descs)) for (let topic of Object.keys(descs)) {
|
|
@@ -24703,10 +24732,11 @@ function is_mobile$2() {
|
|
|
24703
24732
|
* whole service (lazy drill). CHILD model: the viewer publishes
|
|
24704
24733
|
* EV_EXPAND_PATH to us.
|
|
24705
24734
|
************************************************************/
|
|
24706
|
-
function open_json_viewer$1(gobj) {
|
|
24735
|
+
function open_json_viewer$1(gobj, opts) {
|
|
24707
24736
|
let priv = gobj.priv;
|
|
24737
|
+
let schema = !!(opts && opts.schema);
|
|
24708
24738
|
if (priv.json_win || priv.json_modal) {
|
|
24709
|
-
request_print_tranger$1(gobj, "");
|
|
24739
|
+
if (!schema) request_print_tranger$1(gobj, "");
|
|
24710
24740
|
return;
|
|
24711
24741
|
}
|
|
24712
24742
|
if (!gclass_find_by_name("C_YUI_JSON")) {
|
|
@@ -24716,7 +24746,10 @@ function open_json_viewer$1(gobj) {
|
|
|
24716
24746
|
}
|
|
24717
24747
|
let mobile = is_mobile$2();
|
|
24718
24748
|
let shell = yui_shell_of(gobj);
|
|
24719
|
-
let jv = gobj_create_service(`treedb-topics-json-${clean_name(gobj_name(gobj))}`, "C_YUI_JSON", {
|
|
24749
|
+
let jv = gobj_create_service(`treedb-topics-json-${clean_name(gobj_name(gobj))}`, "C_YUI_JSON", {
|
|
24750
|
+
subscriber: gobj,
|
|
24751
|
+
json_data: schema ? gobj_read_attr(gobj, "descs") : null
|
|
24752
|
+
}, gobj);
|
|
24720
24753
|
if (!jv) {
|
|
24721
24754
|
log_error(`${gobj_short_name(gobj)}: cannot create the JSON viewer`);
|
|
24722
24755
|
return;
|
|
@@ -24734,7 +24767,7 @@ function open_json_viewer$1(gobj) {
|
|
|
24734
24767
|
dialog: true,
|
|
24735
24768
|
logical_class: "TREEDB_JSON_SHEET",
|
|
24736
24769
|
title_prefix: priv.treedb_name,
|
|
24737
|
-
title: "raw json",
|
|
24770
|
+
title: schema ? "schema json" : "raw json",
|
|
24738
24771
|
t,
|
|
24739
24772
|
on_close: () => {
|
|
24740
24773
|
if (gobj_is_destroying(gobj)) return;
|
|
@@ -24756,8 +24789,8 @@ function open_json_viewer$1(gobj) {
|
|
|
24756
24789
|
height: 620,
|
|
24757
24790
|
logical_class: "TREEDB_JSON_WINDOW",
|
|
24758
24791
|
title_prefix: priv.treedb_name,
|
|
24759
|
-
title: "raw json",
|
|
24760
|
-
icon: "yi-eye",
|
|
24792
|
+
title: schema ? "schema json" : "raw json",
|
|
24793
|
+
icon: schema ? "yi-code" : "yi-eye",
|
|
24761
24794
|
body: $box,
|
|
24762
24795
|
manager: null,
|
|
24763
24796
|
on_close: () => {
|
|
@@ -24772,7 +24805,7 @@ function open_json_viewer$1(gobj) {
|
|
|
24772
24805
|
}
|
|
24773
24806
|
gobj_start(priv.json_win);
|
|
24774
24807
|
}
|
|
24775
|
-
request_print_tranger$1(gobj, "");
|
|
24808
|
+
if (!schema) request_print_tranger$1(gobj, "");
|
|
24776
24809
|
}
|
|
24777
24810
|
/************************************************************
|
|
24778
24811
|
* Close the JSON viewer (user dismiss / teardown).
|
|
@@ -25366,6 +25399,19 @@ function ac_open_json$1(gobj, event, kw, src) {
|
|
|
25366
25399
|
return 0;
|
|
25367
25400
|
}
|
|
25368
25401
|
/********************************************
|
|
25402
|
+
* The schema, as the json it is: the `descs` the schema graph is
|
|
25403
|
+
* drawing. Same viewer and same host as the tranger's raw json --
|
|
25404
|
+
* one at a time, so it closes whatever was open first.
|
|
25405
|
+
********************************************/
|
|
25406
|
+
function ac_open_schema_json(gobj, event, kw, src) {
|
|
25407
|
+
if (!is_object(gobj_read_attr(gobj, "descs"))) {
|
|
25408
|
+
log_error(`${gobj_short_name(gobj)}: schema json with no descs`);
|
|
25409
|
+
return -1;
|
|
25410
|
+
}
|
|
25411
|
+
open_json_viewer$1(gobj, { schema: true });
|
|
25412
|
+
return 0;
|
|
25413
|
+
}
|
|
25414
|
+
/********************************************
|
|
25369
25415
|
* Open the graph where the reader left it: its last visited
|
|
25370
25416
|
* route under the graph's base -- `<graph>/<topic>` when a topic
|
|
25371
25417
|
* was focused there -- or the bare base when the graph was never
|
|
@@ -25499,6 +25545,11 @@ function create_gclass$6(gclass_name) {
|
|
|
25499
25545
|
ac_open_json$1,
|
|
25500
25546
|
null
|
|
25501
25547
|
],
|
|
25548
|
+
[
|
|
25549
|
+
"EV_OPEN_SCHEMA_JSON",
|
|
25550
|
+
ac_open_schema_json,
|
|
25551
|
+
null
|
|
25552
|
+
],
|
|
25502
25553
|
[
|
|
25503
25554
|
"EV_OPEN_GRAPH",
|
|
25504
25555
|
ac_open_graph,
|
|
@@ -25571,6 +25622,7 @@ function create_gclass$6(gclass_name) {
|
|
|
25571
25622
|
["EV_RECORD_WRITTEN", event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],
|
|
25572
25623
|
["EV_REFRESH_TOPIC", 0],
|
|
25573
25624
|
["EV_OPEN_JSON", 0],
|
|
25625
|
+
["EV_OPEN_SCHEMA_JSON", 0],
|
|
25574
25626
|
["EV_OPEN_GRAPH", 0],
|
|
25575
25627
|
["EV_EXPAND_PATH", 0],
|
|
25576
25628
|
["EV_JSON_CLOSED", 0],
|
|
@@ -30255,6 +30307,88 @@ function register_c_yui_treedb_topic_with_form() {
|
|
|
30255
30307
|
return create_gclass$5(GCLASS_NAME$5);
|
|
30256
30308
|
}
|
|
30257
30309
|
//#endregion
|
|
30310
|
+
//#region src/graph_save_plan.js
|
|
30311
|
+
/***********************************************************************
|
|
30312
|
+
* graph_save_plan.js
|
|
30313
|
+
*
|
|
30314
|
+
* Which topics a Save of the graph has to write, and which it
|
|
30315
|
+
* must leave alone.
|
|
30316
|
+
*
|
|
30317
|
+
* The arrangement of a treedb graph lives in `__graphs__`, ONE
|
|
30318
|
+
* record per topic. The Save collected every topic the view had
|
|
30319
|
+
* loaded and wrote all of them, whatever had moved: on a treedb
|
|
30320
|
+
* of five topics, dragging one card appended five records, four
|
|
30321
|
+
* of them saying exactly what the record under them said. The
|
|
30322
|
+
* store is append-only, so those four are there for ever.
|
|
30323
|
+
*
|
|
30324
|
+
* This module is the decision, and nothing else: no G6, no DOM,
|
|
30325
|
+
* no gobj. Give it what the view is holding and what the backend
|
|
30326
|
+
* already has, and it answers which topics differ.
|
|
30327
|
+
*
|
|
30328
|
+
* Two things it deliberately does NOT do:
|
|
30329
|
+
*
|
|
30330
|
+
* - It does not ask the history plugin. The Save button lights
|
|
30331
|
+
* from two places -- `history.canUndo()` for what G6 records
|
|
30332
|
+
* (a move, a resize) and `mark_graph_dirty()` for what it does
|
|
30333
|
+
* not (a colour, a pill, a per-topic default) -- so the undo
|
|
30334
|
+
* stack is not the list of what changed, and reading it as one
|
|
30335
|
+
* would silently drop half the changes. A value comparison
|
|
30336
|
+
* sees both, and keeps working through undo, redo and a
|
|
30337
|
+
* history that was just cleared.
|
|
30338
|
+
*
|
|
30339
|
+
* - It does not compare `__origin__`. That key is the node_uuid
|
|
30340
|
+
* of whoever wrote the record, bookkeeping about the write and
|
|
30341
|
+
* not about the arrangement; comparing it would make every
|
|
30342
|
+
* topic differ the first time a second browser saved, and the
|
|
30343
|
+
* record it forces would say nothing new.
|
|
30344
|
+
*
|
|
30345
|
+
* Copyright (c) 2026, ArtGins.
|
|
30346
|
+
* All Rights Reserved.
|
|
30347
|
+
***********************************************************************/
|
|
30348
|
+
/***************************************************************
|
|
30349
|
+
* The properties as they are worth comparing: everything
|
|
30350
|
+
* except who wrote them.
|
|
30351
|
+
***************************************************************/
|
|
30352
|
+
function arrangement_of(properties) {
|
|
30353
|
+
if (!is_object(properties)) return {};
|
|
30354
|
+
let out = {};
|
|
30355
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
30356
|
+
if (key === "__origin__") continue;
|
|
30357
|
+
out[key] = value;
|
|
30358
|
+
}
|
|
30359
|
+
return out;
|
|
30360
|
+
}
|
|
30361
|
+
/***************************************************************
|
|
30362
|
+
* TRUE when the arrangement the view holds for `topic_name`
|
|
30363
|
+
* is not the one the backend already has.
|
|
30364
|
+
*
|
|
30365
|
+
* A topic with no saved record has never been written, so
|
|
30366
|
+
* anything it holds is a change -- and an EMPTY arrangement
|
|
30367
|
+
* is not: a topic the view loaded and nobody ever arranged
|
|
30368
|
+
* has nothing to say, and saying it would create a record
|
|
30369
|
+
* that means "no layout".
|
|
30370
|
+
***************************************************************/
|
|
30371
|
+
function topic_arrangement_changed(live, saved) {
|
|
30372
|
+
let a = arrangement_of(live);
|
|
30373
|
+
if (!saved) return Object.keys(a).length > 0;
|
|
30374
|
+
return !json_is_identical(a, arrangement_of(saved));
|
|
30375
|
+
}
|
|
30376
|
+
/***************************************************************
|
|
30377
|
+
* The topics a Save has to write.
|
|
30378
|
+
*
|
|
30379
|
+
* live {topic_name: properties} what the view holds
|
|
30380
|
+
* saved {topic_name: properties} what the backend has
|
|
30381
|
+
*
|
|
30382
|
+
* Returns their names, in the order the view holds them.
|
|
30383
|
+
***************************************************************/
|
|
30384
|
+
function plan_graph_saves(live, saved) {
|
|
30385
|
+
let plan = [];
|
|
30386
|
+
if (!is_object(live)) return plan;
|
|
30387
|
+
let have = is_object(saved) ? saved : {};
|
|
30388
|
+
for (const [topic_name, properties] of Object.entries(live)) if (topic_arrangement_changed(properties, have[topic_name])) plan.push(topic_name);
|
|
30389
|
+
return plan;
|
|
30390
|
+
}
|
|
30391
|
+
//#endregion
|
|
30258
30392
|
//#region src/treedb_node_label.js
|
|
30259
30393
|
/***********************************************************************
|
|
30260
30394
|
* treedb_node_label.js
|
|
@@ -58482,6 +58616,7 @@ var PRIVATE_DATA$4 = {
|
|
|
58482
58616
|
graph: null,
|
|
58483
58617
|
__graphs__: [],
|
|
58484
58618
|
_graph_properties: {},
|
|
58619
|
+
_saved_graph_properties: {},
|
|
58485
58620
|
yet_showed: false,
|
|
58486
58621
|
edit_mode: false,
|
|
58487
58622
|
operation_mode: null,
|
|
@@ -58732,7 +58867,7 @@ function build_graph$1(gobj) {
|
|
|
58732
58867
|
container: priv.$container,
|
|
58733
58868
|
animation: false,
|
|
58734
58869
|
autoResize: false,
|
|
58735
|
-
zoomRange: [.
|
|
58870
|
+
zoomRange: [.02, 4],
|
|
58736
58871
|
node: {
|
|
58737
58872
|
palette: {
|
|
58738
58873
|
type: "group",
|
|
@@ -59988,6 +60123,7 @@ function draw_link(gobj, child_topic, child_id, source_col, fkey, verbose) {
|
|
|
59988
60123
|
parent_topic,
|
|
59989
60124
|
parent_id,
|
|
59990
60125
|
hook_name,
|
|
60126
|
+
child_topic,
|
|
59991
60127
|
child_id,
|
|
59992
60128
|
is_tree
|
|
59993
60129
|
});
|
|
@@ -60067,11 +60203,15 @@ function clear_link(gobj, child_topic, child_id, source_col, fkey, verbose) {
|
|
|
60067
60203
|
function build_graph_properties(gobj) {
|
|
60068
60204
|
let priv = gobj.priv;
|
|
60069
60205
|
priv._graph_properties = {};
|
|
60206
|
+
priv._saved_graph_properties = {};
|
|
60070
60207
|
for (let i = 0; i < priv.__graphs__.length; i++) {
|
|
60071
60208
|
let rec = priv.__graphs__[i];
|
|
60072
60209
|
if (!rec.active || !rec.topic) continue;
|
|
60073
60210
|
let props = rec.properties;
|
|
60074
|
-
if (is_object(props))
|
|
60211
|
+
if (is_object(props)) {
|
|
60212
|
+
priv._graph_properties[rec.topic] = props;
|
|
60213
|
+
priv._saved_graph_properties[rec.topic] = json_deep_copy(props);
|
|
60214
|
+
}
|
|
60075
60215
|
}
|
|
60076
60216
|
}
|
|
60077
60217
|
/************************************************************
|
|
@@ -60156,35 +60296,22 @@ function save_geometry(gobj) {
|
|
|
60156
60296
|
}
|
|
60157
60297
|
const edges = graph.getData().edges;
|
|
60158
60298
|
for (let i = 0; i < edges.length; i++) update_edge_geometry(gobj, edges[i].id);
|
|
60159
|
-
let
|
|
60160
|
-
for (
|
|
60161
|
-
properties.__origin__ = origin;
|
|
60162
|
-
let kw_update = {
|
|
60163
|
-
treedb_name: priv.treedb_name,
|
|
60164
|
-
topic_name: "__graphs__",
|
|
60165
|
-
record: {
|
|
60166
|
-
id: topic_name,
|
|
60167
|
-
topic: topic_name,
|
|
60168
|
-
active: true,
|
|
60169
|
-
properties
|
|
60170
|
-
},
|
|
60171
|
-
options: {
|
|
60172
|
-
list_dict: true,
|
|
60173
|
-
autolink: false,
|
|
60174
|
-
create: true
|
|
60175
|
-
}
|
|
60176
|
-
};
|
|
60177
|
-
gobj_publish_event(gobj, "EV_UPDATE_NODE", kw_update);
|
|
60178
|
-
}
|
|
60299
|
+
let plan = plan_graph_saves(priv._graph_properties, priv._saved_graph_properties);
|
|
60300
|
+
for (let i = 0; i < plan.length; i++) save_topic_graph_properties(gobj, plan[i]);
|
|
60179
60301
|
}
|
|
60180
60302
|
/************************************************************
|
|
60181
60303
|
* Save __graphs__ properties for a single topic to backend.
|
|
60304
|
+
*
|
|
60305
|
+
* The ONE door to `__graphs__`: a caller that knows a topic moved
|
|
60306
|
+
* says so, and this decides whether the backend needs telling.
|
|
60182
60307
|
************************************************************/
|
|
60183
60308
|
function save_topic_graph_properties(gobj, topic_name) {
|
|
60184
60309
|
let priv = gobj.priv;
|
|
60185
60310
|
let properties = priv._graph_properties[topic_name];
|
|
60186
60311
|
if (!properties) return;
|
|
60312
|
+
if (!topic_arrangement_changed(properties, priv._saved_graph_properties[topic_name])) return;
|
|
60187
60313
|
properties.__origin__ = gobj_read_str_attr(gobj_yuno(), "node_uuid");
|
|
60314
|
+
priv._saved_graph_properties[topic_name] = json_deep_copy(properties);
|
|
60188
60315
|
let kw_update = {
|
|
60189
60316
|
treedb_name: priv.treedb_name,
|
|
60190
60317
|
topic_name: "__graphs__",
|
|
@@ -60503,7 +60630,7 @@ async function graph_fit_selection(gobj, ids) {
|
|
|
60503
60630
|
let bw = Math.max(1, maxx - minx);
|
|
60504
60631
|
let bh = Math.max(1, maxy - miny);
|
|
60505
60632
|
let zoom = Math.min(vw / bw, vh / bh);
|
|
60506
|
-
let range = graph.getZoomRange() || [.
|
|
60633
|
+
let range = graph.getZoomRange() || [.02, 4];
|
|
60507
60634
|
zoom = Math.max(range[0], Math.min(range[1], zoom));
|
|
60508
60635
|
await graph.zoomTo(zoom);
|
|
60509
60636
|
await graph.focusElement(ids);
|
|
@@ -63240,16 +63367,14 @@ function refresh_html_nodes_theme(gobj, theme) {
|
|
|
63240
63367
|
function refresh_default_edges_theme(gobj, theme) {
|
|
63241
63368
|
let graph = gobj.priv.graph;
|
|
63242
63369
|
if (!graph) return;
|
|
63243
|
-
let dark = theme === "dark";
|
|
63244
63370
|
let edges = graph.getData().edges || [];
|
|
63245
63371
|
let updates = [];
|
|
63246
63372
|
for (let i = 0; i < edges.length; i++) {
|
|
63247
63373
|
let d = edges[i].data || {};
|
|
63248
63374
|
if (!d.themed_default) continue;
|
|
63249
|
-
let stroke = d.is_tree ? dark ? "#22a7c2" : "#0e7490" : dark ? "#8b94a3" : "#6b7280";
|
|
63250
63375
|
updates.push({
|
|
63251
63376
|
id: edges[i].id,
|
|
63252
|
-
style: { stroke }
|
|
63377
|
+
style: { stroke: default_edge_stroke(gobj, d, theme) }
|
|
63253
63378
|
});
|
|
63254
63379
|
}
|
|
63255
63380
|
if (updates.length > 0) graph.updateEdgeData(updates);
|
|
@@ -63821,21 +63946,54 @@ function apply_edge_properties(gobj, edge_id, lineWidth, stroke, scope) {
|
|
|
63821
63946
|
deselect_edge(gobj);
|
|
63822
63947
|
}
|
|
63823
63948
|
/************************************************************
|
|
63949
|
+
* The colour a link is DRAWN in: the colour of the two knobs it
|
|
63950
|
+
* joins.
|
|
63951
|
+
*
|
|
63952
|
+
* Both ends of a link wear the CHILD topic's colour -- the
|
|
63953
|
+
* parent's hook port is painted with the colour of whatever may
|
|
63954
|
+
* hang there, and the child's fkey port with its own (see
|
|
63955
|
+
* build_ports) -- so the line between them has one obvious
|
|
63956
|
+
* colour, and a reader follows a link by its hue instead of
|
|
63957
|
+
* tracing a grey thread across the canvas.
|
|
63958
|
+
*
|
|
63959
|
+
* It goes through port_rim(): the FILL of a port says which
|
|
63960
|
+
* topic, and a line on the canvas is a graphical object that
|
|
63961
|
+
* needs 3:1 against it, which that mix clears in both themes
|
|
63962
|
+
* (9.11 dark, 3.80 light) while keeping the hue. So a link is
|
|
63963
|
+
* drawn in exactly the colour of the rim of the two knobs it
|
|
63964
|
+
* ends on.
|
|
63965
|
+
*
|
|
63966
|
+
* The containment/tree relation (parent and child of the same
|
|
63967
|
+
* topic) is no longer marked by a teal of its own -- it is that
|
|
63968
|
+
* topic's colour like any other link, and what still tells it
|
|
63969
|
+
* apart is its WIDTH.
|
|
63970
|
+
*
|
|
63971
|
+
* A topic with no colour, or an edge of a graph with no schema
|
|
63972
|
+
* yet, keeps the neutral grey this used to give everything.
|
|
63973
|
+
************************************************************/
|
|
63974
|
+
function default_edge_stroke(gobj, d, theme) {
|
|
63975
|
+
let priv = gobj.priv;
|
|
63976
|
+
let desc = is_object(priv.descs) ? priv.descs[d.child_topic] : null;
|
|
63977
|
+
if (desc && desc.color) return port_rim(desc.color, theme);
|
|
63978
|
+
let dark = theme === "dark";
|
|
63979
|
+
return d.is_tree ? dark ? "#22a7c2" : "#0e7490" : dark ? "#8b94a3" : "#6b7280";
|
|
63980
|
+
}
|
|
63981
|
+
/************************************************************
|
|
63824
63982
|
* The style an edge INHERITS, before anything saved for the
|
|
63825
63983
|
* edge itself: its hook's default in the parent topic, else the
|
|
63826
63984
|
* parent topic's default for every edge, else the library's.
|
|
63827
63985
|
*
|
|
63828
|
-
* The library's:
|
|
63829
|
-
*
|
|
63830
|
-
*
|
|
63831
|
-
* library's, so a theme toggle re-themes it and leaves
|
|
63832
|
-
* one alone.
|
|
63986
|
+
* The library's: the colour of the ports it joins (see
|
|
63987
|
+
* default_edge_stroke), and a wider line for the
|
|
63988
|
+
* containment/tree relation. `themed_default` says the colour is
|
|
63989
|
+
* still the library's, so a theme toggle re-themes it and leaves
|
|
63990
|
+
* a chosen one alone.
|
|
63833
63991
|
************************************************************/
|
|
63834
63992
|
function edge_inherited_style_of(gobj, d) {
|
|
63835
|
-
let
|
|
63993
|
+
let priv = gobj.priv;
|
|
63836
63994
|
let style = {
|
|
63837
63995
|
lineWidth: d.is_tree ? 2 : 1.6,
|
|
63838
|
-
stroke: d.
|
|
63996
|
+
stroke: default_edge_stroke(gobj, d, priv.theme),
|
|
63839
63997
|
themed_default: true
|
|
63840
63998
|
};
|
|
63841
63999
|
let defs = topic_defaults_of(gobj, d.parent_topic);
|
|
@@ -71656,7 +71814,7 @@ function render_toolbar(gobj) {
|
|
|
71656
71814
|
]);
|
|
71657
71815
|
let $right = [];
|
|
71658
71816
|
if (priv.treedb_id && has_model) {
|
|
71659
|
-
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-
|
|
71817
|
+
$right.push(toolbar_button("SCHEMA_DIAGRAM_BTN", "yi-compass-drafting", priv.diagram ? "topics" : "diagram", "EV_TOGGLE_DIAGRAM", false));
|
|
71660
71818
|
$right.push(toolbar_button("SCHEMA_VALIDATE_BTN", "yi-square-check", "check", "EV_VALIDATE", false));
|
|
71661
71819
|
$right.push(toolbar_button("SCHEMA_EXPORT_BTN", "yi-download", "export", "EV_EXPORT", false));
|
|
71662
71820
|
if (!readonly) $right.push(toolbar_button("SCHEMA_IMPORT_BTN", "yi-upload", "import", "EV_IMPORT", false));
|