@yuneta/gobj-ui 7.23.192 → 7.23.193
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 +24 -0
- package/dist/gobj-ui.cjs.js +238 -62
- package/dist/gobj-ui.es.js +238 -62
- package/package.json +1 -1
- package/src/c_g6_nodes_tree.js +15 -2
- package/src/c_yui_treedb_topic_with_form.js +143 -49
- package/src/c_yui_treedb_topics.js +62 -15
- package/src/graph_save_plan.js +40 -0
- package/src/graph_save_plan.test.js +57 -1
- package/src/yui_row_search.js +7 -2
- package/src/yui_row_search.test.js +22 -0
- package/src/yui_table_select.js +50 -0
- package/src/yui_table_select.test.js +54 -0
|
@@ -110,3 +110,25 @@ describe("is_hook_size", () => {
|
|
|
110
110
|
expect(is_hook_size(null)).toBe(false);
|
|
111
111
|
});
|
|
112
112
|
});
|
|
113
|
+
|
|
114
|
+
/*
|
|
115
|
+
* The children of a hook as the NODE EVENTS deliver them: `{id,
|
|
116
|
+
* topic_name}`, with no hook_name. Not taken for a reference, their
|
|
117
|
+
* topic_name -- the same word on every row -- was a wildcard for every
|
|
118
|
+
* row that had received an UPDATED (M30 of the 2026-09-21 review).
|
|
119
|
+
*/
|
|
120
|
+
describe("a hook's children as the node events deliver them", () => {
|
|
121
|
+
const row = {id: "w1", devices: [{id: "d7", topic_name: "devices"}]};
|
|
122
|
+
|
|
123
|
+
it("are references: only their id is looked at", () => {
|
|
124
|
+
expect(is_fkey_ref({id: "d7", topic_name: "devices"})).toBe(true);
|
|
125
|
+
expect(row_matches(row, "d7")).toBe(true);
|
|
126
|
+
expect(row_matches(row, "devices")).toBe(false);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("an object that carries more than a reference is data, searched whole", () => {
|
|
130
|
+
const data = {id: "x", topic_name: "devices", note: "blue"};
|
|
131
|
+
expect(is_fkey_ref(data)).toBe(false);
|
|
132
|
+
expect(row_matches({id: "r", payload: data}, "blue")).toBe(true);
|
|
133
|
+
});
|
|
134
|
+
});
|
package/src/yui_table_select.js
CHANGED
|
@@ -94,6 +94,54 @@ function yui_selected_rows(tabulator)
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
+
/***************************************************************
|
|
98
|
+
* The IDENTITY of some rows: the value of the table's `index`
|
|
99
|
+
* field (Tabulator's default is `id`). This is what crosses a
|
|
100
|
+
* confirmation dialog -- never the rows' POSITIONS, which the
|
|
101
|
+
* table regenerates with every addData / deleteRow while the
|
|
102
|
+
* dialog is open, so a position names whatever row sits there
|
|
103
|
+
* when the person answers.
|
|
104
|
+
***************************************************************/
|
|
105
|
+
function yui_row_ids(tabulator, rows)
|
|
106
|
+
{
|
|
107
|
+
let field = (tabulator && tabulator.options && tabulator.options.index) || "id";
|
|
108
|
+
let ids = [];
|
|
109
|
+
for(let row of (rows || [])) {
|
|
110
|
+
let id = row ? row[field] : undefined;
|
|
111
|
+
if(id !== undefined && id !== null && id !== "") {
|
|
112
|
+
ids.push(id);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return ids;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/***************************************************************
|
|
119
|
+
* The rows that carry these ids NOW -> {rows, missing}.
|
|
120
|
+
* `rows` are the rows' data; `missing` the ids no row carries
|
|
121
|
+
* any more. A missing id is never replaced by another row.
|
|
122
|
+
***************************************************************/
|
|
123
|
+
function yui_rows_by_ids(tabulator, ids)
|
|
124
|
+
{
|
|
125
|
+
let rows = [];
|
|
126
|
+
let missing = [];
|
|
127
|
+
for(let id of (ids || [])) {
|
|
128
|
+
let row = null;
|
|
129
|
+
if(tabulator && typeof tabulator.getRow === "function") {
|
|
130
|
+
try {
|
|
131
|
+
row = tabulator.getRow(id) || null;
|
|
132
|
+
} catch(e) {
|
|
133
|
+
row = null; /* the table is gone */
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if(row) {
|
|
137
|
+
rows.push(row.getData());
|
|
138
|
+
} else {
|
|
139
|
+
missing.push(id);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return {rows: rows, missing: missing};
|
|
143
|
+
}
|
|
144
|
+
|
|
97
145
|
/***************************************************************
|
|
98
146
|
* Drop the selection (after acting on it, or after a
|
|
99
147
|
* reload that leaves the ticked rows behind).
|
|
@@ -240,6 +288,8 @@ export {
|
|
|
240
288
|
yui_selection_column,
|
|
241
289
|
yui_selection_settings,
|
|
242
290
|
yui_selected_rows,
|
|
291
|
+
yui_row_ids,
|
|
292
|
+
yui_rows_by_ids,
|
|
243
293
|
yui_clear_selection,
|
|
244
294
|
yui_wire_selection,
|
|
245
295
|
yui_selection_bar,
|
|
@@ -12,6 +12,8 @@ import {
|
|
|
12
12
|
yui_selection_settings,
|
|
13
13
|
yui_selected_rows,
|
|
14
14
|
yui_clear_selection,
|
|
15
|
+
yui_row_ids,
|
|
16
|
+
yui_rows_by_ids,
|
|
15
17
|
} from "./yui_table_select.js";
|
|
16
18
|
|
|
17
19
|
describe("the column", () => {
|
|
@@ -52,3 +54,55 @@ describe("reading and dropping the selection", () => {
|
|
|
52
54
|
.not.toThrow();
|
|
53
55
|
});
|
|
54
56
|
});
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* A table as the delete of the treedb topic table meets it AFTER a
|
|
60
|
+
* confirmation: rows came and went while the dialog was open. A position
|
|
61
|
+
* names whatever row sits there now; an id names the row the question named
|
|
62
|
+
* (the regression of d60ec78, A6 of the 2026-09-21 review).
|
|
63
|
+
*/
|
|
64
|
+
function fake_table(rows, index)
|
|
65
|
+
{
|
|
66
|
+
return {
|
|
67
|
+
options: index ? {index: index} : {},
|
|
68
|
+
getRow(id) {
|
|
69
|
+
let data = rows.find((r) => r[index || "id"] === id);
|
|
70
|
+
return data ? {getData: () => data} : false;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe("row identity across a confirmation", () => {
|
|
76
|
+
test("the ids are read from the table's index field", () => {
|
|
77
|
+
let table = fake_table([], "name");
|
|
78
|
+
expect(yui_row_ids(table, [{name: "a"}, {name: "b"}])).toEqual(["a", "b"]);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("with no index configured the field is `id`, Tabulator's default", () => {
|
|
82
|
+
expect(yui_row_ids(fake_table([]), [{id: "x"}])).toEqual(["x"]);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("a row with no id has no identity to carry", () => {
|
|
86
|
+
expect(yui_row_ids(fake_table([]), [{id: ""}, {}, null, {id: "k"}])).toEqual(["k"]);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
test("the rows are the ones that carry the ids NOW, not the ones at a position", () => {
|
|
90
|
+
/* The question named "b". Before the answer, "a" went away: at
|
|
91
|
+
* position 2 there is now "c", and a position would delete it. */
|
|
92
|
+
let table = fake_table([{id: "b"}, {id: "c"}]);
|
|
93
|
+
let found = yui_rows_by_ids(table, ["b"]);
|
|
94
|
+
expect(found.rows).toEqual([{id: "b"}]);
|
|
95
|
+
expect(found.missing).toEqual([]);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
test("an id that is gone is reported, never replaced by another row", () => {
|
|
99
|
+
let table = fake_table([{id: "c"}]);
|
|
100
|
+
let found = yui_rows_by_ids(table, ["b", "c"]);
|
|
101
|
+
expect(found.rows).toEqual([{id: "c"}]);
|
|
102
|
+
expect(found.missing).toEqual(["b"]);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test("no table: nothing found, everything missing", () => {
|
|
106
|
+
expect(yui_rows_by_ids(null, ["b"])).toEqual({rows: [], missing: ["b"]});
|
|
107
|
+
});
|
|
108
|
+
});
|