@yuneta/gobj-ui 7.25.1 → 7.25.3
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 +22 -0
- package/dist/gobj-ui.cjs.js +191 -17
- package/dist/gobj-ui.es.js +191 -17
- package/package.json +1 -1
- package/src/c_yui_schema_editor.js +30 -1
- package/src/c_yui_treedb_topic_with_form.js +10 -20
- package/src/c_yui_treedb_topics.js +59 -1
- package/src/form_busy.js +54 -0
- package/src/form_busy.test.js +84 -0
- package/src/form_writes_in_flight.js +60 -0
- package/src/form_writes_in_flight.test.js +45 -0
- package/src/host_drafts.js +68 -0
- package/src/host_drafts.test.js +62 -0
package/README.md
CHANGED
|
@@ -783,6 +783,12 @@ answer EVERY way the write can end: refused before it left (read-only, no
|
|
|
783
783
|
session) as well as answered by the backend, or the form waits forever. A host
|
|
784
784
|
that does not answer leaves the attribute off, and the form closes when the
|
|
785
785
|
write is published, as before 7.23.193 — whatever the backend says.
|
|
786
|
+
`C_YUI_TREEDB_TOPICS` answers them all since 7.25.2: a write sent with no
|
|
787
|
+
session is refused before it is sent (the command would never leave, and
|
|
788
|
+
`C_IEVENT_CLI` answers `null` for that as for a command that went), and the
|
|
789
|
+
writes in flight when the transport closes are answered refused on the
|
|
790
|
+
transport edge (`form_writes_in_flight.js`), so the form comes back on what
|
|
791
|
+
was typed instead of staying busy for ever.
|
|
786
792
|
|
|
787
793
|
```js
|
|
788
794
|
// A host of C_YUI_TREEDB_TOPIC_WITH_FORM that answers the form's writes
|
|
@@ -2015,6 +2021,22 @@ and the column screen says so in a banner; the host sends `EV_REFRESH` after a
|
|
|
2015
2021
|
save, and the reload forgets the drafts. The export (C literal and JSON) warns
|
|
2016
2022
|
while there are drafts: the literal carries the versions a save publishes.
|
|
2017
2023
|
|
|
2024
|
+
**A draft survives a reload** (7.25.3). The mark of a write lived in the
|
|
2025
|
+
session's memory only, so a reload of the page, a reconnect or a refresh of
|
|
2026
|
+
the model showed no draft while `__system__` still differed from the file in
|
|
2027
|
+
use. The host tells the editor what IS a draft, from data: `C_TREEDB`'s
|
|
2028
|
+
`saved-schema` answers `draft_changed` per treedb (yunetas 7.25.3+), and the
|
|
2029
|
+
host sends it as `EV_DRAFTS`; `drafts_of_saved_answer()` reads the unnamed
|
|
2030
|
+
answer into the shape the event takes. What the session wrote stays marked;
|
|
2031
|
+
what the host said is applied again after every reload of the model.
|
|
2032
|
+
|
|
2033
|
+
```js
|
|
2034
|
+
// The host, when its saved-schema answers land (rows = the unnamed answer's data)
|
|
2035
|
+
import {drafts_of_saved_answer} from "@yuneta/gobj-ui/src/host_drafts.js";
|
|
2036
|
+
gobj_send_event(editor, "EV_DRAFTS", {drafts: drafts_of_saved_answer(rows)}, gobj);
|
|
2037
|
+
// -> {drafts: {treedb_authzs: ["users"]}}
|
|
2038
|
+
```
|
|
2039
|
+
|
|
2018
2040
|
What the screens offer:
|
|
2019
2041
|
|
|
2020
2042
|
| Screen | What it is for |
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -23021,6 +23021,53 @@ function yui_shell_show_route_map(shell, opts) {
|
|
|
23021
23021
|
return modal_ref.modal;
|
|
23022
23022
|
}
|
|
23023
23023
|
//#endregion
|
|
23024
|
+
//#region src/form_writes_in_flight.js
|
|
23025
|
+
/***********************************************************************
|
|
23026
|
+
* form_writes_in_flight.js
|
|
23027
|
+
*
|
|
23028
|
+
* The writes of topic forms a C_YUI_TREEDB_TOPICS view has sent
|
|
23029
|
+
* and not yet answered, by their `form_write` serial. A form that
|
|
23030
|
+
* waits for its answer (form_waits_for_answer) stays open and
|
|
23031
|
+
* busy until the host answers, so the host has to answer EVERY
|
|
23032
|
+
* way a write ends -- and the transport closing under a write in
|
|
23033
|
+
* flight, or a command that never left because there was no
|
|
23034
|
+
* session, are two of them that nobody answered: the form stayed
|
|
23035
|
+
* busy for ever (N8 of the 2026-09-22 review).
|
|
23036
|
+
*
|
|
23037
|
+
* Copyright (c) 2026, ArtGins.
|
|
23038
|
+
* All Rights Reserved.
|
|
23039
|
+
***********************************************************************/
|
|
23040
|
+
/************************************************************
|
|
23041
|
+
* A write left: remember whose it is
|
|
23042
|
+
************************************************************/
|
|
23043
|
+
function track_form_write(in_flight, form_write, topic_name) {
|
|
23044
|
+
if (!in_flight || !form_write) return;
|
|
23045
|
+
in_flight[form_write] = topic_name || "";
|
|
23046
|
+
}
|
|
23047
|
+
/************************************************************
|
|
23048
|
+
* A write was answered, one way or the other
|
|
23049
|
+
************************************************************/
|
|
23050
|
+
function settle_form_write(in_flight, form_write) {
|
|
23051
|
+
if (!in_flight || !form_write) return;
|
|
23052
|
+
delete in_flight[form_write];
|
|
23053
|
+
}
|
|
23054
|
+
/************************************************************
|
|
23055
|
+
* Nothing in flight can be answered any more: take them all,
|
|
23056
|
+
* as [{form_write, topic_name}], and leave the map empty.
|
|
23057
|
+
************************************************************/
|
|
23058
|
+
function abandon_form_writes(in_flight) {
|
|
23059
|
+
const abandoned = [];
|
|
23060
|
+
if (!in_flight) return abandoned;
|
|
23061
|
+
Object.keys(in_flight).forEach((serial) => {
|
|
23062
|
+
abandoned.push({
|
|
23063
|
+
form_write: Number(serial),
|
|
23064
|
+
topic_name: in_flight[serial]
|
|
23065
|
+
});
|
|
23066
|
+
delete in_flight[serial];
|
|
23067
|
+
});
|
|
23068
|
+
return abandoned;
|
|
23069
|
+
}
|
|
23070
|
+
//#endregion
|
|
23024
23071
|
//#region src/nodes_answer.js
|
|
23025
23072
|
/***********************************************************************
|
|
23026
23073
|
* nodes_answer.js
|
|
@@ -23587,6 +23634,7 @@ var __gclass__$6 = null;
|
|
|
23587
23634
|
* Framework Method: Create
|
|
23588
23635
|
***************************************************************/
|
|
23589
23636
|
function mt_create$6(gobj) {
|
|
23637
|
+
gobj.priv.form_writes = {};
|
|
23590
23638
|
build_ui$6(gobj);
|
|
23591
23639
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
23592
23640
|
if (!subscriber) subscriber = (0, _yuneta_gobj_js.gobj_parent)(gobj);
|
|
@@ -24743,6 +24791,7 @@ function treedb_update_node$1(gobj, treedb_name, topic_name, record, options, fo
|
|
|
24743
24791
|
(0, _yuneta_gobj_js.log_error)(ret);
|
|
24744
24792
|
return -1;
|
|
24745
24793
|
}
|
|
24794
|
+
track_form_write(gobj.priv.form_writes, form_write, topic_name);
|
|
24746
24795
|
return 0;
|
|
24747
24796
|
}
|
|
24748
24797
|
/************************************************************
|
|
@@ -25006,6 +25055,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25006
25055
|
if (command === "update-node" || command === "create-node") {
|
|
25007
25056
|
let failed_topic = (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0);
|
|
25008
25057
|
if (failed_topic) (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_REFRESH_TOPIC", { topic_name: failed_topic }, gobj);
|
|
25058
|
+
settle_form_write(gobj.priv.form_writes, (0, _yuneta_gobj_js.kw_get_int)(gobj, kw_command, "form_write", 0, 0));
|
|
25009
25059
|
answer_form_write(gobj, get_gobj_formtable(gobj, failed_topic), (0, _yuneta_gobj_js.kw_get_int)(gobj, kw_command, "form_write", 0, 0), false);
|
|
25010
25060
|
}
|
|
25011
25061
|
}
|
|
@@ -25043,6 +25093,7 @@ function ac_mt_command_answer$2(gobj, event, kw, src) {
|
|
|
25043
25093
|
created: command === "create-node",
|
|
25044
25094
|
command
|
|
25045
25095
|
});
|
|
25096
|
+
settle_form_write(gobj.priv.form_writes, (0, _yuneta_gobj_js.kw_get_int)(gobj, kw_command, "form_write", 0, 0));
|
|
25046
25097
|
answer_form_write(gobj, get_gobj_formtable(gobj, (0, _yuneta_gobj_js.kw_get_str)(gobj, kw_command, "topic_name", "", 0)), (0, _yuneta_gobj_js.kw_get_int)(gobj, kw_command, "form_write", 0, 0), true);
|
|
25047
25098
|
break;
|
|
25048
25099
|
case "delete-node": break;
|
|
@@ -25193,7 +25244,12 @@ function ac_back_to_topics(gobj, event, kw, src) {
|
|
|
25193
25244
|
* the session).
|
|
25194
25245
|
************************************************************/
|
|
25195
25246
|
function ac_transport_state$2(gobj, event, kw, src) {
|
|
25196
|
-
|
|
25247
|
+
let connected = !!(kw && kw.connected);
|
|
25248
|
+
refresh_toolbar_buttons(gobj, connected);
|
|
25249
|
+
if (!connected) abandon_form_writes(gobj.priv.form_writes).forEach((w) => {
|
|
25250
|
+
(0, _yuneta_gobj_js.log_warning)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: transport closed, the write ${w.form_write} of '${w.topic_name}' is lost`);
|
|
25251
|
+
answer_form_write(gobj, get_gobj_formtable(gobj, w.topic_name), w.form_write, false);
|
|
25252
|
+
});
|
|
25197
25253
|
return 0;
|
|
25198
25254
|
}
|
|
25199
25255
|
/************************************************************
|
|
@@ -25267,6 +25323,10 @@ function ac_create_record(gobj, event, kw, src) {
|
|
|
25267
25323
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
25268
25324
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
25269
25325
|
let record = kw.record;
|
|
25326
|
+
if (refuse_without_session(gobj, topic_name)) {
|
|
25327
|
+
answer_form_write(gobj, src, form_write, false);
|
|
25328
|
+
return -1;
|
|
25329
|
+
}
|
|
25270
25330
|
if (treedb_update_node$1(gobj, treedb_name, topic_name, record, {
|
|
25271
25331
|
list_dict: true,
|
|
25272
25332
|
create: true,
|
|
@@ -25434,6 +25494,10 @@ function ac_update_record(gobj, event, kw, src) {
|
|
|
25434
25494
|
let treedb_name = (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name");
|
|
25435
25495
|
let topic_name = (0, _yuneta_gobj_js.gobj_read_attr)(src, "topic_name");
|
|
25436
25496
|
let record = kw.record;
|
|
25497
|
+
if (refuse_without_session(gobj, topic_name)) {
|
|
25498
|
+
answer_form_write(gobj, src, form_write, false);
|
|
25499
|
+
return -1;
|
|
25500
|
+
}
|
|
25437
25501
|
if (treedb_update_node$1(gobj, treedb_name, topic_name, record, {
|
|
25438
25502
|
list_dict: true,
|
|
25439
25503
|
autolink: true
|
|
@@ -25444,6 +25508,18 @@ function ac_update_record(gobj, event, kw, src) {
|
|
|
25444
25508
|
return 0;
|
|
25445
25509
|
}
|
|
25446
25510
|
/************************************************************
|
|
25511
|
+
* A write sent with no session never leaves: C_IEVENT_CLI logs
|
|
25512
|
+
* "Not in session" and answers null, as it does when the command
|
|
25513
|
+
* went -- so a form waiting for the answer waited for ever (N8 of
|
|
25514
|
+
* the 2026-09-22 review). Refused before it is sent, aloud.
|
|
25515
|
+
************************************************************/
|
|
25516
|
+
function refuse_without_session(gobj, topic_name) {
|
|
25517
|
+
if (is_connected$1(gobj)) return false;
|
|
25518
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no session, the write of '${topic_name}' was not sent`);
|
|
25519
|
+
yui_shell_show_error(yui_shell_of(gobj), "no session", { t: i18next.t });
|
|
25520
|
+
return true;
|
|
25521
|
+
}
|
|
25522
|
+
/************************************************************
|
|
25447
25523
|
* Tell a topic form how its write ended: EV_WRITE_DONE closes
|
|
25448
25524
|
* it, EV_WRITE_REFUSED leaves it open on what was typed. Every
|
|
25449
25525
|
* way a form's write can end passes here -- refused before it
|
|
@@ -26511,6 +26587,49 @@ function delete_impact(desc, records) {
|
|
|
26511
26587
|
return out;
|
|
26512
26588
|
}
|
|
26513
26589
|
//#endregion
|
|
26590
|
+
//#region src/form_busy.js
|
|
26591
|
+
/***********************************************************************
|
|
26592
|
+
* form_busy.js
|
|
26593
|
+
*
|
|
26594
|
+
* The toolbar of a topic form while a write is in flight: every
|
|
26595
|
+
* button disabled, the save button spinning. Bulma's `is-loading`
|
|
26596
|
+
* is the spinner; `disabled` is what stops the second click.
|
|
26597
|
+
*
|
|
26598
|
+
* A transition, not a setting: each button remembers whether it
|
|
26599
|
+
* was disabled BEFORE the toolbar went busy, and busy(false) puts
|
|
26600
|
+
* that back. So a second busy(true) while already busy must not
|
|
26601
|
+
* run at all -- it read the buttons it had just disabled as
|
|
26602
|
+
* "disabled on their own", and the busy(false) of a refused write
|
|
26603
|
+
* left Save and Cancel dead (N9 of the 2026-09-22 review: a record
|
|
26604
|
+
* with a picked file went busy for the read, then busy again for
|
|
26605
|
+
* the write). The caller owns `state` ({busy}) for the form's life.
|
|
26606
|
+
*
|
|
26607
|
+
* Copyright (c) 2026, ArtGins.
|
|
26608
|
+
* All Rights Reserved.
|
|
26609
|
+
***********************************************************************/
|
|
26610
|
+
/************************************************************
|
|
26611
|
+
* Move the toolbar to `busy`. Returns true when it moved, false when
|
|
26612
|
+
* it was already there (nothing touched).
|
|
26613
|
+
************************************************************/
|
|
26614
|
+
function set_toolbar_busy($container, state, busy) {
|
|
26615
|
+
busy = !!busy;
|
|
26616
|
+
if (!$container || !state) return false;
|
|
26617
|
+
if (!!state.busy === busy) return false;
|
|
26618
|
+
state.busy = busy;
|
|
26619
|
+
$container.querySelectorAll(".yui-toolbar-form button").forEach(($b) => {
|
|
26620
|
+
if (busy) {
|
|
26621
|
+
$b.dataset.was_disabled = $b.disabled ? "1" : "0";
|
|
26622
|
+
$b.disabled = true;
|
|
26623
|
+
} else if ($b.dataset.was_disabled !== void 0) {
|
|
26624
|
+
$b.disabled = $b.dataset.was_disabled === "1";
|
|
26625
|
+
delete $b.dataset.was_disabled;
|
|
26626
|
+
}
|
|
26627
|
+
});
|
|
26628
|
+
const $save = $container.querySelector(".yui-toolbar-form .button-save");
|
|
26629
|
+
if ($save) $save.classList.toggle("is-loading", busy);
|
|
26630
|
+
return true;
|
|
26631
|
+
}
|
|
26632
|
+
//#endregion
|
|
26514
26633
|
//#region src/table_cell_text.js
|
|
26515
26634
|
/****************************************************************************
|
|
26516
26635
|
* table_cell_text.js
|
|
@@ -26795,6 +26914,7 @@ function mt_create$5(gobj) {
|
|
|
26795
26914
|
gobj.priv.read_serial = 0;
|
|
26796
26915
|
gobj.priv.awaiting_write = 0;
|
|
26797
26916
|
gobj.priv.write_serial = 0;
|
|
26917
|
+
gobj.priv.form_busy = { busy: false };
|
|
26798
26918
|
let name = (0, _yuneta_gobj_js.clean_name)((0, _yuneta_gobj_js.gobj_name)(gobj));
|
|
26799
26919
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "table_id", "table" + name);
|
|
26800
26920
|
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "toolbar_id", "toolbar" + name);
|
|
@@ -28198,6 +28318,7 @@ function teardown_form_child(gobj) {
|
|
|
28198
28318
|
let priv = gobj.priv;
|
|
28199
28319
|
priv.reading_files = 0;
|
|
28200
28320
|
priv.awaiting_write = 0;
|
|
28321
|
+
priv.form_busy = { busy: false };
|
|
28201
28322
|
if (priv.form) {
|
|
28202
28323
|
if ((0, _yuneta_gobj_js.gobj_is_running)(priv.form)) (0, _yuneta_gobj_js.gobj_stop)(priv.form);
|
|
28203
28324
|
(0, _yuneta_gobj_js.gobj_destroy)(priv.form);
|
|
@@ -29422,26 +29543,16 @@ function ac_form_save_record(gobj, event, kw, src) {
|
|
|
29422
29543
|
return 0;
|
|
29423
29544
|
}
|
|
29424
29545
|
/************************************************************
|
|
29425
|
-
* The form's toolbar while a read is in flight: every
|
|
29426
|
-
* disabled, the save button spinning.
|
|
29427
|
-
*
|
|
29546
|
+
* The form's toolbar while a read or a write is in flight: every
|
|
29547
|
+
* button disabled, the save button spinning (set_toolbar_busy). A
|
|
29548
|
+
* transition: busy(true) while busy touches nothing, or a record
|
|
29549
|
+
* with a picked file -- busy for the read, busy again for the
|
|
29550
|
+
* write -- came back from a refusal with Save and Cancel dead.
|
|
29428
29551
|
************************************************************/
|
|
29429
29552
|
function set_form_busy(gobj, busy) {
|
|
29430
29553
|
let priv = gobj.priv;
|
|
29431
29554
|
if (!priv.form) return;
|
|
29432
|
-
|
|
29433
|
-
if (!$container) return;
|
|
29434
|
-
$container.querySelectorAll(".yui-toolbar-form button").forEach(($b) => {
|
|
29435
|
-
if (busy) {
|
|
29436
|
-
$b.dataset.was_disabled = $b.disabled ? "1" : "0";
|
|
29437
|
-
$b.disabled = true;
|
|
29438
|
-
} else if ($b.dataset.was_disabled !== void 0) {
|
|
29439
|
-
$b.disabled = $b.dataset.was_disabled === "1";
|
|
29440
|
-
delete $b.dataset.was_disabled;
|
|
29441
|
-
}
|
|
29442
|
-
});
|
|
29443
|
-
const $save = $container.querySelector(".yui-toolbar-form .button-save");
|
|
29444
|
-
if ($save) $save.classList.toggle("is-loading", !!busy);
|
|
29555
|
+
set_toolbar_busy((0, _yuneta_gobj_js.gobj_read_attr)(priv.form, "$container"), priv.form_busy, busy);
|
|
29445
29556
|
}
|
|
29446
29557
|
/************************************************************
|
|
29447
29558
|
* Is this the read the view is waiting for? A read whose form was
|
|
@@ -70144,6 +70255,44 @@ function register_c_yui_treedb_schema() {
|
|
|
70144
70255
|
return create_gclass$2(GCLASS_NAME$2);
|
|
70145
70256
|
}
|
|
70146
70257
|
//#endregion
|
|
70258
|
+
//#region src/host_drafts.js
|
|
70259
|
+
/***********************************************************************
|
|
70260
|
+
* host_drafts.js
|
|
70261
|
+
*
|
|
70262
|
+
* The topics a schema editor shows as DRAFTS (edited in
|
|
70263
|
+
* __system__, not yet saved), told by the host from data. The
|
|
70264
|
+
* editor marks a topic when a write of this session lands on
|
|
70265
|
+
* it, and that mark lived in the memory of the session only:
|
|
70266
|
+
* a reload of the page, a reconnect or a refresh of the model
|
|
70267
|
+
* lost the chip, the banner and the export warning while
|
|
70268
|
+
* __system__ still differed from the file in use (N13 of the
|
|
70269
|
+
* 2026-09-22 review). The host reads that difference from
|
|
70270
|
+
* C_TREEDB's `saved-schema` (`draft_changed`, by treedb) and
|
|
70271
|
+
* hands it here; the editor applies it to its model.
|
|
70272
|
+
*
|
|
70273
|
+
* Copyright (c) 2026, ArtGins.
|
|
70274
|
+
* All Rights Reserved.
|
|
70275
|
+
***********************************************************************/
|
|
70276
|
+
/************************************************************
|
|
70277
|
+
* Mark in `written` the topics of `model` the host names as
|
|
70278
|
+
* drafts: `drafts` is {treedb_name: [topic names]}. A treedb or a
|
|
70279
|
+
* topic the model does not hold is ignored. Returns how many were
|
|
70280
|
+
* marked.
|
|
70281
|
+
************************************************************/
|
|
70282
|
+
function mark_host_drafts(written, model, drafts) {
|
|
70283
|
+
let marked = 0;
|
|
70284
|
+
if (!written || !model || !Array.isArray(model.treedbs) || !drafts) return marked;
|
|
70285
|
+
for (let treedb of model.treedbs) {
|
|
70286
|
+
const names = drafts[treedb.id];
|
|
70287
|
+
if (!Array.isArray(names) || names.length === 0) continue;
|
|
70288
|
+
for (let topic of treedb.topics || []) if (names.includes(topic.name)) {
|
|
70289
|
+
written[topic.id] = true;
|
|
70290
|
+
marked++;
|
|
70291
|
+
}
|
|
70292
|
+
}
|
|
70293
|
+
return marked;
|
|
70294
|
+
}
|
|
70295
|
+
//#endregion
|
|
70147
70296
|
//#region src/schema_validate.js
|
|
70148
70297
|
/***********************************************************************
|
|
70149
70298
|
* schema_validate.js
|
|
@@ -71870,6 +72019,7 @@ function mt_create$1(gobj) {
|
|
|
71870
72019
|
let priv = gobj.priv;
|
|
71871
72020
|
priv.baseline = {};
|
|
71872
72021
|
priv.written = {};
|
|
72022
|
+
priv.host_drafts = {};
|
|
71873
72023
|
priv.save_queue = [];
|
|
71874
72024
|
build_ui$1(gobj);
|
|
71875
72025
|
let subscriber = (0, _yuneta_gobj_js.gobj_read_pointer_attr)(gobj, "subscriber");
|
|
@@ -72111,6 +72261,7 @@ function start_measuring(gobj) {
|
|
|
72111
72261
|
priv.written = {};
|
|
72112
72262
|
if (!priv.model) return;
|
|
72113
72263
|
for (let treedb of priv.model.treedbs) for (let topic of treedb.topics) priv.baseline[topic.id] = topic.topic_version;
|
|
72264
|
+
mark_host_drafts(priv.written, priv.model, priv.host_drafts);
|
|
72114
72265
|
}
|
|
72115
72266
|
/***************************************************************
|
|
72116
72267
|
* "This topic was written in this session and is not saved."
|
|
@@ -74548,6 +74699,23 @@ function ac_refresh$1(gobj, event, kw, src) {
|
|
|
74548
74699
|
return request_model(gobj);
|
|
74549
74700
|
}
|
|
74550
74701
|
/***************************************************************
|
|
74702
|
+
* {drafts: {treedb_name: [topic names]}} -- the host says which
|
|
74703
|
+
* topics hold a draft in __system__ that the file in use does not
|
|
74704
|
+
* have (C_TREEDB's saved-schema, `draft_changed`). The mark of a
|
|
74705
|
+
* write lived in this session's memory only, so a reload of the
|
|
74706
|
+
* page, a reconnect or a refresh showed no draft while __system__
|
|
74707
|
+
* still differed from the file (N13 of the 2026-09-22 review).
|
|
74708
|
+
* Replaces what the host said before; what this session wrote
|
|
74709
|
+
* stays marked.
|
|
74710
|
+
***************************************************************/
|
|
74711
|
+
function ac_drafts(gobj, event, kw, src) {
|
|
74712
|
+
let priv = gobj.priv;
|
|
74713
|
+
priv.host_drafts = kw && kw.drafts && typeof kw.drafts === "object" ? kw.drafts : {};
|
|
74714
|
+
mark_host_drafts(priv.written, priv.model, priv.host_drafts);
|
|
74715
|
+
if (priv.model) render(gobj);
|
|
74716
|
+
return 0;
|
|
74717
|
+
}
|
|
74718
|
+
/***************************************************************
|
|
74551
74719
|
* Moving about.
|
|
74552
74720
|
***************************************************************/
|
|
74553
74721
|
function ac_select_treedb(gobj, event, kw, src) {
|
|
@@ -75021,6 +75189,11 @@ function create_gclass$1(gclass_name) {
|
|
|
75021
75189
|
"EV_REFRESH",
|
|
75022
75190
|
ac_refresh$1,
|
|
75023
75191
|
null
|
|
75192
|
+
],
|
|
75193
|
+
[
|
|
75194
|
+
"EV_DRAFTS",
|
|
75195
|
+
ac_drafts,
|
|
75196
|
+
null
|
|
75024
75197
|
]
|
|
75025
75198
|
];
|
|
75026
75199
|
const TREEDB_WIDE = [
|
|
@@ -75169,6 +75342,7 @@ function create_gclass$1(gclass_name) {
|
|
|
75169
75342
|
["EV_TRANSPORT_STATE", 0],
|
|
75170
75343
|
["EV_LANGUAGE_CHANGED", 0],
|
|
75171
75344
|
["EV_REFRESH", 0],
|
|
75345
|
+
["EV_DRAFTS", 0],
|
|
75172
75346
|
["EV_SELECT_TREEDB", 0],
|
|
75173
75347
|
["EV_SELECT_TOPIC", 0],
|
|
75174
75348
|
["EV_BACK", 0],
|