@yuneta/gobj-ui 7.23.168 → 7.23.170

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.
@@ -1,33 +1,38 @@
1
1
  /***********************************************************************
2
2
  * yui_row_search.js
3
3
  *
4
- * ¿ESTÁ ESTE TÉRMINO EN ESTA FILA?
4
+ * IS THIS TERM IN THIS ROW?
5
5
  *
6
- * La caja de búsqueda de una tabla de treedb miraba los valores de
7
- * la fila con `String(val)`, y una fila de treedb no es plana: un
8
- * fkey llega como una LISTA DE OBJETOS
9
- * `[{id, topic_name, hook_name}]`, y `String()` de eso es
10
- * `"[object Object]"`. O sea que buscar el taller de un equipo --
11
- * que es donde vive el dato que un operador tiene en la cabeza --
12
- * no encontraba nunca nada, y la caja no daba ninguna pista de que
13
- * había mirado en otro sitio.
6
+ * The search box of a treedb table looked at the row's values with
7
+ * `String(val)`, and a treedb row is not flat: an fkey arrives as a
8
+ * LIST OF OBJECTS `[{id, topic_name, hook_name}]`, and `String()`
9
+ * of that is `"[object Object]"`. So looking for the workshop of
10
+ * a device -- which is where the datum an operator has in mind
11
+ * lives -- never found anything, and the box gave no hint that it
12
+ * had looked somewhere else.
14
13
  *
15
- * DOS REGLAS, Y LA SEGUNDA ES LA QUE HACE QUE SIRVA:
14
+ * THREE RULES, AND THE LAST TWO ARE WHAT MAKE IT USEFUL:
16
15
  *
17
- * - Se baja por listas y objetos hasta una profundidad corta: un
18
- * fkey está a dos niveles y nada de lo que se busca está más
19
- * hondo.
20
- * - **De un fkey se mira sólo el `id`.** `topic_name` y
21
- * `hook_name` son las MISMAS dos palabras en todas las filas, así
22
- * que mirarlas convierte el término en un comodín: buscar
23
- * "devices" traería el topic entero. El `id` es lo único que
24
- * nombra la cosa enlazada.
16
+ * - It walks down lists and objects to a short depth: an fkey is
17
+ * two levels down and nothing anybody searches for is deeper.
18
+ * - **Of an fkey only the `id` is looked at.** `topic_name` and
19
+ * `hook_name` are the SAME two words on every row, so looking at
20
+ * them turns the term into a wildcard: searching "devices" would
21
+ * bring the whole topic. The `id` is the only thing that names
22
+ * the linked thing.
23
+ * - **A hook read as its COUNT is not looked at at all.** Since
24
+ * `hook_size` (7.23.163) a topic table loads a hook as
25
+ * `[{"size": N}]` instead of the id of every child, and that
26
+ * number is not a value of the row: matching it made "5" answer
27
+ * every row whose hook happens to hold 5 children, next to the
28
+ * rows that really say 5. A count nobody can see in the cell as
29
+ * text is not what a person typing in a search box is after.
25
30
  *
26
- * Las claves que empiezan por `_` no se miran en ningún nivel: son
27
- * del armazón (`_check_box_state_`, `_operation`) o metadatos
28
- * (`__md_treedb__`), y nadie busca por ellas.
31
+ * Keys that start with `_` are not looked at on any level: they
32
+ * belong to the scaffolding (`_check_box_state_`, `_operation`) or
33
+ * are metadata (`__md_treedb__`), and nobody searches by them.
29
34
  *
30
- * Copyright (c) 2026, ArtGins.
35
+ * Copyright (c) 2024-2026, ArtGins.
31
36
  * All Rights Reserved.
32
37
  ***********************************************************************/
33
38
 
@@ -35,7 +40,7 @@ const MAX_DEPTH = 4;
35
40
 
36
41
 
37
42
  /***************************************************************
38
- * Un fkey, tal y como `nodes` lo contesta con `list_dict`.
43
+ * An fkey, as `nodes` answers it with `list_dict`.
39
44
  ***************************************************************/
40
45
  function is_fkey_ref(value)
41
46
  {
@@ -47,9 +52,29 @@ function is_fkey_ref(value)
47
52
  && ("hook_name" in value);
48
53
  }
49
54
 
55
+
56
+ /***************************************************************
57
+ * A hook read with `hook_size`: the COUNT of its children,
58
+ * `[{"size": N}]`, in the place of the children themselves.
59
+ * The same shape `delete_impact`'s `ref_count()` reads.
60
+ ***************************************************************/
61
+ function is_hook_size(value)
62
+ {
63
+ if(!Array.isArray(value) || value.length !== 1) {
64
+ return false;
65
+ }
66
+ const first = value[0];
67
+ return !!first
68
+ && typeof first === "object"
69
+ && !Array.isArray(first)
70
+ && typeof first.size === "number"
71
+ && Object.keys(first).length === 1;
72
+ }
73
+
74
+
50
75
  /***************************************************************
51
- * ¿Contiene `value` el término? El término viene YA en
52
- * minúsculas: quien busca lo baja una vez y no una por celda.
76
+ * Does `value` hold the term? The term comes ALREADY in lower
77
+ * case: whoever searches lowers it once, not once per cell.
53
78
  ***************************************************************/
54
79
  function value_matches(value, term, depth)
55
80
  {
@@ -59,6 +84,9 @@ function value_matches(value, term, depth)
59
84
  if(depth > MAX_DEPTH) {
60
85
  return false;
61
86
  }
87
+ if(is_hook_size(value)) {
88
+ return false;
89
+ }
62
90
  if(Array.isArray(value)) {
63
91
  return value.some((v) => value_matches(v, term, depth + 1));
64
92
  }
@@ -76,8 +104,9 @@ function value_matches(value, term, depth)
76
104
  return String(value).toLowerCase().includes(term);
77
105
  }
78
106
 
107
+
79
108
  /***************************************************************
80
- * ¿Está el término en alguna parte de esta fila?
109
+ * Is the term anywhere in this row?
81
110
  ***************************************************************/
82
111
  function row_matches(row, term)
83
112
  {
@@ -93,4 +122,4 @@ function row_matches(row, term)
93
122
  }
94
123
 
95
124
 
96
- export {row_matches, value_matches, is_fkey_ref};
125
+ export {row_matches, value_matches, is_fkey_ref, is_hook_size};
@@ -1,6 +1,6 @@
1
1
  import {describe, it, expect} from "vitest";
2
2
 
3
- import {row_matches, is_fkey_ref} from "./yui_row_search.js";
3
+ import {row_matches, is_fkey_ref, is_hook_size} from "./yui_row_search.js";
4
4
 
5
5
  describe("row_matches", () => {
6
6
  const row = {
@@ -52,6 +52,41 @@ describe("row_matches", () => {
52
52
  });
53
53
  });
54
54
 
55
+ describe("row_matches, on a table loaded with hook_size", () => {
56
+ /* What a topic table gets since 7.23.163: the hook is the COUNT
57
+ * of its children, not their ids. */
58
+ const row = {
59
+ id: "places-madrid",
60
+ name: "Madrid",
61
+ devices: [{size: 400}],
62
+ __md_treedb__: {topic_name: "places"}
63
+ };
64
+
65
+ it("does NOT match the count of a hook", () => {
66
+ /* It did, and "400" then answered every place holding 400
67
+ * devices together with the ones that really say 400. */
68
+ expect(row_matches(row, "400")).toBe(false);
69
+ expect(row_matches(row, "40")).toBe(false);
70
+ expect(row_matches(row, "0")).toBe(false);
71
+ });
72
+
73
+ it("still matches the rest of the row", () => {
74
+ expect(row_matches(row, "madrid")).toBe(true);
75
+ });
76
+
77
+ it("still walks a hook that DID come with its children", () => {
78
+ /* A node event carries whole hooks whatever the table asked
79
+ * for, so both shapes reach this row. */
80
+ const loaded = {
81
+ id: "places-madrid",
82
+ devices: [
83
+ {id: "E22003089", topic_name: "devices", hook_name: "places"}
84
+ ]
85
+ };
86
+ expect(row_matches(loaded, "e22003089")).toBe(true);
87
+ });
88
+ });
89
+
55
90
  describe("is_fkey_ref", () => {
56
91
  it("wants the three keys", () => {
57
92
  expect(is_fkey_ref({id: "a", topic_name: "t", hook_name: "h"})).toBe(true);
@@ -60,3 +95,18 @@ describe("is_fkey_ref", () => {
60
95
  expect(is_fkey_ref(null)).toBe(false);
61
96
  });
62
97
  });
98
+
99
+ describe("is_hook_size", () => {
100
+ it("wants the one-element list holding only a numeric size", () => {
101
+ expect(is_hook_size([{size: 5}])).toBe(true);
102
+ expect(is_hook_size([{size: 0}])).toBe(true);
103
+ expect(is_hook_size([])).toBe(false);
104
+ expect(is_hook_size([{size: 5}, {size: 6}])).toBe(false);
105
+ expect(is_hook_size([{size: "5"}])).toBe(false);
106
+ expect(is_hook_size({size: 5})).toBe(false);
107
+ /* A record that happens to carry a `size` column is data, and
108
+ * is searched like any other. */
109
+ expect(is_hook_size([{id: "a", size: 5}])).toBe(false);
110
+ expect(is_hook_size(null)).toBe(false);
111
+ });
112
+ });