@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.
@@ -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
+ });
@@ -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
+ });