@yuneta/gobj-ui 7.23.161 → 7.23.163
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 +69 -0
- package/dist/gobj-ui.cjs.js +341 -97
- package/dist/gobj-ui.es.js +342 -98
- package/package.json +1 -1
- package/src/c_yui_treedb_topic_with_form.css +30 -0
- package/src/c_yui_treedb_topic_with_form.js +296 -101
- package/src/c_yui_treedb_topics.js +61 -7
- package/src/delete_impact.js +7 -0
- package/src/delete_impact.test.js +8 -0
package/README.md
CHANGED
|
@@ -805,6 +805,75 @@ Searching is a user action, so it crosses the FSM (`EV_SEARCH`) like the rest;
|
|
|
805
805
|
it used to call `tabulator.setFilter` straight from the DOM handler, where the
|
|
806
806
|
`machine` trace could not see it.
|
|
807
807
|
|
|
808
|
+
### A hook opens the rows it links
|
|
809
|
+
|
|
810
|
+
A hook cell shows how many children the row has (`[5675]`). A click on it
|
|
811
|
+
opens the **child topic's table, filtered** to the rows whose fkey names this
|
|
812
|
+
row (since `7.23.162`). Above the table, a chip says which filter is on,
|
|
813
|
+
"filtered by device_types electric_bt", and its ✕ brings the whole topic back.
|
|
814
|
+
|
|
815
|
+
The child table already pages, searches, opens a record and exports. Until
|
|
816
|
+
`7.23.162` the click opened a popup that listed every child id instead:
|
|
817
|
+
5,675 rows in a box with no height, no scroll and no way to close it but a
|
|
818
|
+
click inside, and the ids did nothing.
|
|
819
|
+
|
|
820
|
+
- The child topic and its fkey come from the hook's own mapping in the
|
|
821
|
+
schema, `{child_topic: fkey_col}`:
|
|
822
|
+
|
|
823
|
+
```c
|
|
824
|
+
'devices': {
|
|
825
|
+
'header': 'Equipos',
|
|
826
|
+
'type': 'object',
|
|
827
|
+
'flag': ['hook'],
|
|
828
|
+
'hook': {
|
|
829
|
+
'devices': 'place'
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
```
|
|
833
|
+
|
|
834
|
+
A click on this hook opens `devices`, filtered to the rows whose `place`
|
|
835
|
+
names the clicked row.
|
|
836
|
+
- A hook whose children live in more than one topic asks which one, in the
|
|
837
|
+
standardized dialog (Escape, Back and a click outside close it).
|
|
838
|
+
- The switch goes through the same entry point as a tab click, so the host
|
|
839
|
+
puts it in the URL and Back returns to the topic the hook was on. The
|
|
840
|
+
filter itself is not in the URL.
|
|
841
|
+
- The parent filter and the search box are **one** filter. Tabulator's
|
|
842
|
+
`setFilter()` replaces every programmatic filter, so as two filters each
|
|
843
|
+
would wipe the other.
|
|
844
|
+
- A child row matches when its fkey names the parent id, and also its topic
|
|
845
|
+
and hook when the ref carries them: one row can hang from the same parent
|
|
846
|
+
through two hooks.
|
|
847
|
+
- The filter works on the rows the table holds. With `with_remote_paging`
|
|
848
|
+
that is one page, which is one more reason that flag stays off.
|
|
849
|
+
|
|
850
|
+
The table asks its host to switch, because the tabs belong to the host:
|
|
851
|
+
|
|
852
|
+
```
|
|
853
|
+
C_YUI_TREEDB_TOPIC_WITH_FORM C_YUI_TREEDB_TOPICS
|
|
854
|
+
EV_OPEN_LINKED {topic_name: "devices", fkey: "place",
|
|
855
|
+
parent_topic: "places", parent_id: "es", hook: "devices"} ──►
|
|
856
|
+
select the tab of `devices`
|
|
857
|
+
EV_FILTER_BY_PARENT {fkey, parent_topic, parent_id, hook} ◄── to that topic's table
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
`EV_CLEAR_PARENT_FILTER` is the ✕, and `EV_CHOOSE_LINKED` is a pick in the
|
|
861
|
+
"which topic" dialog. All three are input events; `EV_OPEN_LINKED` is the one
|
|
862
|
+
output event, and `C_YUI_TREEDB_TOPICS` declares it.
|
|
863
|
+
|
|
864
|
+
**The table loads a hook as its count** (since `7.23.163`). Its three loads
|
|
865
|
+
ask with `hook_size`, so a hook arrives as `[{"size": N}]` and not as the ids
|
|
866
|
+
of its children, which nothing in the table reads any more:
|
|
867
|
+
|
|
868
|
+
```js
|
|
869
|
+
const TABLE_READ_OPTIONS = {list_dict: true, hook_size: true};
|
|
870
|
+
```
|
|
871
|
+
|
|
872
|
+
The node events still carry whole hooks, so after a live update a row can
|
|
873
|
+
hold the list again; the cell and a delete's question count either shape. The
|
|
874
|
+
search box no longer finds a parent row by the id of one of its children: to
|
|
875
|
+
find what hangs from a row, click its hook.
|
|
876
|
+
|
|
808
877
|
### Read-only treedbs: `readonly`
|
|
809
878
|
|
|
810
879
|
`C_YUI_TREEDB_TOPICS` and `C_YUI_TREEDB_GRAPH` take a **`readonly`** attr; the
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -23057,6 +23057,10 @@ function nodes_answer(data) {
|
|
|
23057
23057
|
* Constants
|
|
23058
23058
|
***************************************************************/
|
|
23059
23059
|
var GCLASS_NAME$6 = "C_YUI_TREEDB_TOPICS";
|
|
23060
|
+
var TABLE_READ_OPTIONS = {
|
|
23061
|
+
list_dict: true,
|
|
23062
|
+
hook_size: true
|
|
23063
|
+
};
|
|
23060
23064
|
/***************************************************************
|
|
23061
23065
|
* Data
|
|
23062
23066
|
***************************************************************/
|
|
@@ -24089,7 +24093,7 @@ function get_nodes$1(gobj, topic_name) {
|
|
|
24089
24093
|
subscribe_treedb$1(gobj, topic_name);
|
|
24090
24094
|
let gobj_topic_form = get_gobj_formtable(gobj, topic_name);
|
|
24091
24095
|
if (gobj_topic_form && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj_topic_form, "with_remote_paging")) return;
|
|
24092
|
-
treedb_nodes$1(gobj, treedb_name, topic_name, {
|
|
24096
|
+
treedb_nodes$1(gobj, treedb_name, topic_name, Object.assign({}, TABLE_READ_OPTIONS));
|
|
24093
24097
|
}
|
|
24094
24098
|
/************************************************************
|
|
24095
24099
|
*
|
|
@@ -24672,7 +24676,7 @@ function ac_request_page(gobj, event, kw, src) {
|
|
|
24672
24676
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a page request with no topic or no id`);
|
|
24673
24677
|
return -1;
|
|
24674
24678
|
}
|
|
24675
|
-
if (treedb_nodes$1(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name"), topic_name, {
|
|
24679
|
+
if (treedb_nodes$1(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name"), topic_name, Object.assign({}, TABLE_READ_OPTIONS), {
|
|
24676
24680
|
from: kw.from,
|
|
24677
24681
|
limit: kw.limit,
|
|
24678
24682
|
req_id: kw.req_id
|
|
@@ -24683,6 +24687,36 @@ function ac_request_page(gobj, event, kw, src) {
|
|
|
24683
24687
|
return 0;
|
|
24684
24688
|
}
|
|
24685
24689
|
/********************************************
|
|
24690
|
+
* Event from formtable: open the records a hook of one row links --
|
|
24691
|
+
* the CHILD topic's table, filtered to the rows whose fkey names that
|
|
24692
|
+
* row. A hook is the question "which records hang from this one", and
|
|
24693
|
+
* the child's table is where that answer can be read: it pages, it
|
|
24694
|
+
* searches, it opens a record and it exports -- which a list of ids in
|
|
24695
|
+
* a popup could not do past a few dozen of them.
|
|
24696
|
+
* {
|
|
24697
|
+
* topic_name: the child topic
|
|
24698
|
+
* fkey: its fkey column that points back
|
|
24699
|
+
* parent_topic: the topic of the row the hook is on
|
|
24700
|
+
* parent_id: that row's id
|
|
24701
|
+
* hook: the hook column
|
|
24702
|
+
* }
|
|
24703
|
+
********************************************/
|
|
24704
|
+
function ac_open_linked(gobj, event, kw, src) {
|
|
24705
|
+
let child = get_gobj_formtable(gobj, kw.topic_name);
|
|
24706
|
+
if (!child) {
|
|
24707
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: cannot open '${kw.topic_name}', linked from '${kw.parent_topic}^${kw.parent_id}': that topic is not in this view`);
|
|
24708
|
+
return -1;
|
|
24709
|
+
}
|
|
24710
|
+
select_topic_by_id(gobj, (0, _yuneta_gobj_js.gobj_name)(child));
|
|
24711
|
+
(0, _yuneta_gobj_js.gobj_send_event)(child, "EV_FILTER_BY_PARENT", {
|
|
24712
|
+
fkey: kw.fkey,
|
|
24713
|
+
parent_topic: kw.parent_topic,
|
|
24714
|
+
parent_id: kw.parent_id,
|
|
24715
|
+
hook: kw.hook
|
|
24716
|
+
}, gobj);
|
|
24717
|
+
return 0;
|
|
24718
|
+
}
|
|
24719
|
+
/********************************************
|
|
24686
24720
|
* Event from formtable: the bytes of one asset a `file` column names,
|
|
24687
24721
|
* for the form's preview or the table's file popup.
|
|
24688
24722
|
*
|
|
@@ -24796,7 +24830,8 @@ function ac_refresh_topic(gobj, event, kw, src) {
|
|
|
24796
24830
|
(0, _yuneta_gobj_js.gobj_send_event)(gobj_topic_form, "EV_REPULL_PAGE", {}, gobj);
|
|
24797
24831
|
return 0;
|
|
24798
24832
|
}
|
|
24799
|
-
|
|
24833
|
+
let options = Object.assign({}, TABLE_READ_OPTIONS);
|
|
24834
|
+
treedb_nodes$1(gobj, (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "treedb_name"), kw.topic_name, options);
|
|
24800
24835
|
return 0;
|
|
24801
24836
|
}
|
|
24802
24837
|
/********************************************
|
|
@@ -24915,6 +24950,11 @@ function create_gclass$6(gclass_name) {
|
|
|
24915
24950
|
ac_request_asset,
|
|
24916
24951
|
null
|
|
24917
24952
|
],
|
|
24953
|
+
[
|
|
24954
|
+
"EV_OPEN_LINKED",
|
|
24955
|
+
ac_open_linked,
|
|
24956
|
+
null
|
|
24957
|
+
],
|
|
24918
24958
|
[
|
|
24919
24959
|
"EV_DELETE_RECORD",
|
|
24920
24960
|
ac_delete_record,
|
|
@@ -24996,6 +25036,7 @@ function create_gclass$6(gclass_name) {
|
|
|
24996
25036
|
["EV_UPDATE_FIELD", 0],
|
|
24997
25037
|
["EV_REQUEST_PAGE", 0],
|
|
24998
25038
|
["EV_REQUEST_ASSET", 0],
|
|
25039
|
+
["EV_OPEN_LINKED", 0],
|
|
24999
25040
|
["EV_DELETE_RECORD", 0],
|
|
25000
25041
|
["EV_RECORD_WRITTEN", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT | _yuneta_gobj_js.event_flag_t.EVF_NO_WARN_SUBS],
|
|
25001
25042
|
["EV_REFRESH_TOPIC", 0],
|
|
@@ -25660,6 +25701,7 @@ function plan_treedb_writes(flags) {
|
|
|
25660
25701
|
* How many things a hook/fkey value holds.
|
|
25661
25702
|
***************************************************************/
|
|
25662
25703
|
function ref_count(value) {
|
|
25704
|
+
if (Array.isArray(value) && value.length === 1 && value[0] && typeof value[0] === "object" && typeof value[0].size === "number") return value[0].size;
|
|
25663
25705
|
if (Array.isArray(value)) return value.length;
|
|
25664
25706
|
if (value && typeof value === "object") return Object.keys(value).length;
|
|
25665
25707
|
if (typeof value === "string" && value.length > 0) return 1;
|
|
@@ -25806,7 +25848,11 @@ var PRIVATE_DATA$5 = {
|
|
|
25806
25848
|
cell_file_modal: null,
|
|
25807
25849
|
cell_file_win: null,
|
|
25808
25850
|
_pending_assets: null,
|
|
25809
|
-
_asset_seq: 0
|
|
25851
|
+
_asset_seq: 0,
|
|
25852
|
+
parent_filter: null,
|
|
25853
|
+
search_term: "",
|
|
25854
|
+
$parent_filter: null,
|
|
25855
|
+
hook_choice_modal: null
|
|
25810
25856
|
};
|
|
25811
25857
|
var __gclass__$5 = null;
|
|
25812
25858
|
function is_mobile$1() {
|
|
@@ -25940,6 +25986,7 @@ function mt_stop$5(gobj) {
|
|
|
25940
25986
|
close_schema_dialog(gobj);
|
|
25941
25987
|
close_cell_json_dialog(gobj);
|
|
25942
25988
|
close_cell_file_dialog(gobj);
|
|
25989
|
+
close_hook_choice(gobj);
|
|
25943
25990
|
drop_pending_assets(gobj);
|
|
25944
25991
|
table__destroy(gobj);
|
|
25945
25992
|
}
|
|
@@ -25951,6 +25998,7 @@ function mt_destroy$5(gobj) {
|
|
|
25951
25998
|
close_schema_dialog(gobj);
|
|
25952
25999
|
close_cell_json_dialog(gobj);
|
|
25953
26000
|
close_cell_file_dialog(gobj);
|
|
26001
|
+
close_hook_choice(gobj);
|
|
25954
26002
|
drop_pending_assets(gobj);
|
|
25955
26003
|
destroy_ui$2(gobj);
|
|
25956
26004
|
}
|
|
@@ -26310,6 +26358,50 @@ function build_ui$5(gobj) {
|
|
|
26310
26358
|
bar.$el.style.flex = "none";
|
|
26311
26359
|
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
26312
26360
|
}
|
|
26361
|
+
let $parent_filter = (0, _yuneta_gobj_js.createElement2)([
|
|
26362
|
+
"div",
|
|
26363
|
+
{
|
|
26364
|
+
class: "TREEDB_PARENT_FILTER is-hidden",
|
|
26365
|
+
style: "flex:none;"
|
|
26366
|
+
},
|
|
26367
|
+
[
|
|
26368
|
+
[
|
|
26369
|
+
"span",
|
|
26370
|
+
{
|
|
26371
|
+
class: "PARENT_FILTER_LABEL",
|
|
26372
|
+
i18n: "filtered by"
|
|
26373
|
+
},
|
|
26374
|
+
"filtered by"
|
|
26375
|
+
],
|
|
26376
|
+
[
|
|
26377
|
+
"span",
|
|
26378
|
+
{ class: "PARENT_FILTER_TOPIC" },
|
|
26379
|
+
""
|
|
26380
|
+
],
|
|
26381
|
+
[
|
|
26382
|
+
"strong",
|
|
26383
|
+
{ class: "PARENT_FILTER_ID" },
|
|
26384
|
+
""
|
|
26385
|
+
],
|
|
26386
|
+
[
|
|
26387
|
+
"button",
|
|
26388
|
+
{
|
|
26389
|
+
class: "delete PARENT_FILTER_CLEAR",
|
|
26390
|
+
type: "button",
|
|
26391
|
+
title: (0, i18next.t)("clear filter"),
|
|
26392
|
+
"data-i18n-title": "clear filter",
|
|
26393
|
+
"aria-label": (0, i18next.t)("clear filter"),
|
|
26394
|
+
"data-i18n-aria-label": "clear filter"
|
|
26395
|
+
},
|
|
26396
|
+
[],
|
|
26397
|
+
{ click: () => {
|
|
26398
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CLEAR_PARENT_FILTER", {}, gobj);
|
|
26399
|
+
} }
|
|
26400
|
+
]
|
|
26401
|
+
]
|
|
26402
|
+
]);
|
|
26403
|
+
gobj.priv.$parent_filter = $parent_filter;
|
|
26404
|
+
$container.insertBefore($parent_filter, $container.querySelector(`#${table_id}`));
|
|
26313
26405
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
26314
26406
|
if ($table_toolbar instanceof Element) $toolbar_slot.appendChild($table_toolbar);
|
|
26315
26407
|
else $toolbar_slot.appendChild((0, _yuneta_gobj_js.createElement2)(["div", {}]));
|
|
@@ -26802,6 +26894,7 @@ function create_tabulator(gobj) {
|
|
|
26802
26894
|
yui_tabulator_name_filters(tabulator, i18next.t);
|
|
26803
26895
|
yui_tabulator_name_row_selects(tabulator, i18next.t);
|
|
26804
26896
|
tabulator._ready = true;
|
|
26897
|
+
apply_row_filters(gobj);
|
|
26805
26898
|
update_rowcount();
|
|
26806
26899
|
yui_table_filter_clear(tabulator);
|
|
26807
26900
|
if (tabulator._pendingData !== void 0) {
|
|
@@ -27009,15 +27102,18 @@ function transform__treedb_value_2_table_value(gobj, col, value, row, field) {
|
|
|
27009
27102
|
break;
|
|
27010
27103
|
case "hook":
|
|
27011
27104
|
let items = (0, _yuneta_gobj_js.treedb_hook_data_size)(value);
|
|
27012
|
-
if (items > 0)
|
|
27013
|
-
"
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27017
|
-
|
|
27018
|
-
|
|
27019
|
-
|
|
27020
|
-
|
|
27105
|
+
if (items > 0) {
|
|
27106
|
+
let hook_title = String((0, i18next.t)("show linked records")).replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
27107
|
+
value = [
|
|
27108
|
+
"<a class=\"hook_cell\" ",
|
|
27109
|
+
`title="${hook_title}" aria-label="${hook_title}" `,
|
|
27110
|
+
`data-row_id="${row.id}" `,
|
|
27111
|
+
`data-col_id="${col.id}" > `,
|
|
27112
|
+
"<span style=\"\" class=\"icon yi-eye\"></span>",
|
|
27113
|
+
`<span>[ <u>${items}</u> ]</span>`,
|
|
27114
|
+
"</a>"
|
|
27115
|
+
].join("");
|
|
27116
|
+
} else value = "";
|
|
27021
27117
|
break;
|
|
27022
27118
|
case "file":
|
|
27023
27119
|
case "fkey":
|
|
@@ -27652,6 +27748,153 @@ function close_cell_file_dialog(gobj) {
|
|
|
27652
27748
|
teardown_cell_file(gobj);
|
|
27653
27749
|
}
|
|
27654
27750
|
/************************************************************
|
|
27751
|
+
* Ask the host to open the rows of `topic_name` whose `fkey`
|
|
27752
|
+
* names this row -- what a hook of this row links.
|
|
27753
|
+
************************************************************/
|
|
27754
|
+
function publish_open_linked(gobj, topic_name, fkey, parent_id, hook) {
|
|
27755
|
+
(0, _yuneta_gobj_js.gobj_publish_event)(gobj, "EV_OPEN_LINKED", {
|
|
27756
|
+
topic_name,
|
|
27757
|
+
fkey,
|
|
27758
|
+
parent_topic: (0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name"),
|
|
27759
|
+
parent_id,
|
|
27760
|
+
hook
|
|
27761
|
+
});
|
|
27762
|
+
}
|
|
27763
|
+
/************************************************************
|
|
27764
|
+
* "Which child topic?" -- for a hook whose children live in
|
|
27765
|
+
* more than one. The standardized dialog, so Escape, Back and
|
|
27766
|
+
* a click outside close it like every other one.
|
|
27767
|
+
************************************************************/
|
|
27768
|
+
function open_hook_choice_dialog(gobj, targets, parent_id, hook) {
|
|
27769
|
+
close_hook_choice(gobj);
|
|
27770
|
+
let priv = gobj.priv;
|
|
27771
|
+
let shell = yui_shell_of(gobj);
|
|
27772
|
+
if (!shell) {
|
|
27773
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no shell, cannot ask which topic to open`);
|
|
27774
|
+
return;
|
|
27775
|
+
}
|
|
27776
|
+
priv.hook_choice_modal = yui_shell_show_modal(shell, (0, _yuneta_gobj_js.createElement2)([
|
|
27777
|
+
"div",
|
|
27778
|
+
{ class: "TREEDB_HOOK_CHOICE" },
|
|
27779
|
+
targets.map((tg) => {
|
|
27780
|
+
return [
|
|
27781
|
+
"button",
|
|
27782
|
+
{
|
|
27783
|
+
class: "button HOOK_CHOICE_TOPIC",
|
|
27784
|
+
type: "button",
|
|
27785
|
+
title: (0, i18next.t)(tg.topic_name),
|
|
27786
|
+
"data-i18n-title": tg.topic_name,
|
|
27787
|
+
"aria-label": (0, i18next.t)(tg.topic_name),
|
|
27788
|
+
"data-i18n-aria-label": tg.topic_name
|
|
27789
|
+
},
|
|
27790
|
+
[[
|
|
27791
|
+
"span",
|
|
27792
|
+
{ i18n: tg.topic_name },
|
|
27793
|
+
tg.topic_name
|
|
27794
|
+
]],
|
|
27795
|
+
{ click: () => {
|
|
27796
|
+
(0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CHOOSE_LINKED", {
|
|
27797
|
+
topic_name: tg.topic_name,
|
|
27798
|
+
fkey: tg.fkey,
|
|
27799
|
+
parent_id,
|
|
27800
|
+
hook
|
|
27801
|
+
}, gobj);
|
|
27802
|
+
} }
|
|
27803
|
+
];
|
|
27804
|
+
})
|
|
27805
|
+
]), {
|
|
27806
|
+
dialog: true,
|
|
27807
|
+
logical_class: "TREEDB_HOOK_CHOICE_SHEET",
|
|
27808
|
+
title: "choose a topic",
|
|
27809
|
+
t: i18next.t,
|
|
27810
|
+
on_close: function() {
|
|
27811
|
+
priv.hook_choice_modal = null;
|
|
27812
|
+
}
|
|
27813
|
+
});
|
|
27814
|
+
}
|
|
27815
|
+
/************************************************************
|
|
27816
|
+
* Close "which child topic?" if it is open.
|
|
27817
|
+
************************************************************/
|
|
27818
|
+
function close_hook_choice(gobj) {
|
|
27819
|
+
let priv = gobj.priv;
|
|
27820
|
+
if (priv.hook_choice_modal) {
|
|
27821
|
+
let modal = priv.hook_choice_modal;
|
|
27822
|
+
priv.hook_choice_modal = null;
|
|
27823
|
+
modal.close();
|
|
27824
|
+
}
|
|
27825
|
+
}
|
|
27826
|
+
/************************************************************
|
|
27827
|
+
* Does this row's `pf.fkey` name the parent record? The fkey
|
|
27828
|
+
* arrives as one ref, a list of them or a dict keyed by ref,
|
|
27829
|
+
* each in any of the shapes treedb_decoder_fkey() reads. The
|
|
27830
|
+
* topic and the hook are compared when the ref carries them:
|
|
27831
|
+
* one row can hang from the same parent through two hooks.
|
|
27832
|
+
************************************************************/
|
|
27833
|
+
function row_links_to(gobj, data, pf) {
|
|
27834
|
+
let col = get_schema_col(gobj, pf.fkey);
|
|
27835
|
+
let v = data ? data[pf.fkey] : null;
|
|
27836
|
+
if (!col || v === null || v === void 0 || v === "") return false;
|
|
27837
|
+
let refs;
|
|
27838
|
+
if ((0, _yuneta_gobj_js.is_array)(v)) refs = v;
|
|
27839
|
+
else if ((0, _yuneta_gobj_js.is_object)(v) && v.id === void 0) refs = Object.keys(v);
|
|
27840
|
+
else refs = [v];
|
|
27841
|
+
for (let ref of refs) {
|
|
27842
|
+
if (ref === null || ref === void 0 || ref === "") continue;
|
|
27843
|
+
let fk = (0, _yuneta_gobj_js.treedb_decoder_fkey)(col, ref);
|
|
27844
|
+
if (!fk || String(fk.id) !== pf.parent_id) continue;
|
|
27845
|
+
if (fk.topic_name && pf.parent_topic && fk.topic_name !== pf.parent_topic) continue;
|
|
27846
|
+
if (fk.hook_name && pf.hook && fk.hook_name !== pf.hook) continue;
|
|
27847
|
+
return true;
|
|
27848
|
+
}
|
|
27849
|
+
return false;
|
|
27850
|
+
}
|
|
27851
|
+
/************************************************************
|
|
27852
|
+
* The ONE programmatic filter of the table: the parent filter
|
|
27853
|
+
* AND the search term. Kept as state and applied here, because
|
|
27854
|
+
* Tabulator's setFilter() replaces every programmatic filter.
|
|
27855
|
+
* Before `tableBuilt` the state waits; tableBuilt applies it.
|
|
27856
|
+
************************************************************/
|
|
27857
|
+
function apply_row_filters(gobj) {
|
|
27858
|
+
let priv = gobj.priv;
|
|
27859
|
+
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
27860
|
+
if (!tabulator) {
|
|
27861
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no table to filter`);
|
|
27862
|
+
return;
|
|
27863
|
+
}
|
|
27864
|
+
if (!tabulator._ready) return;
|
|
27865
|
+
let term = priv.search_term || "";
|
|
27866
|
+
let pf = priv.parent_filter;
|
|
27867
|
+
if (!term && !pf) {
|
|
27868
|
+
tabulator.clearFilter();
|
|
27869
|
+
return;
|
|
27870
|
+
}
|
|
27871
|
+
tabulator.setFilter(function(data) {
|
|
27872
|
+
if (pf && !row_links_to(gobj, data, pf)) return false;
|
|
27873
|
+
return !term || row_matches(data, term);
|
|
27874
|
+
});
|
|
27875
|
+
}
|
|
27876
|
+
/************************************************************
|
|
27877
|
+
* Show or hide the chip that says the parent filter is on.
|
|
27878
|
+
************************************************************/
|
|
27879
|
+
function render_parent_filter(gobj) {
|
|
27880
|
+
let priv = gobj.priv;
|
|
27881
|
+
let $chip = priv.$parent_filter;
|
|
27882
|
+
if (!$chip) {
|
|
27883
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no parent-filter chip to paint`);
|
|
27884
|
+
return;
|
|
27885
|
+
}
|
|
27886
|
+
let pf = priv.parent_filter;
|
|
27887
|
+
if (!pf) {
|
|
27888
|
+
$chip.classList.add("is-hidden");
|
|
27889
|
+
return;
|
|
27890
|
+
}
|
|
27891
|
+
let $topic = $chip.querySelector(".PARENT_FILTER_TOPIC");
|
|
27892
|
+
$topic.setAttribute("data-i18n", pf.parent_topic);
|
|
27893
|
+
$topic.textContent = (0, i18next.t)(pf.parent_topic);
|
|
27894
|
+
$chip.querySelector(".PARENT_FILTER_ID").textContent = pf.parent_id;
|
|
27895
|
+
$chip.classList.remove("is-hidden");
|
|
27896
|
+
}
|
|
27897
|
+
/************************************************************
|
|
27655
27898
|
* True if the topic's pkey col carries the "rowid" flag.
|
|
27656
27899
|
************************************************************/
|
|
27657
27900
|
function pkey_is_rowid(gobj) {
|
|
@@ -27908,74 +28151,6 @@ function build_fkey_ref(gobj, col, value) {
|
|
|
27908
28151
|
}
|
|
27909
28152
|
return refs;
|
|
27910
28153
|
}
|
|
27911
|
-
/***************************************************************************
|
|
27912
|
-
* TODO con límite máximo o máximo height o con scroll
|
|
27913
|
-
* en un gobj propio para gestionar los datos en "page"s
|
|
27914
|
-
* que los hook no vengan rellenos si son muchos y que se puedan gestionar
|
|
27915
|
-
* con un gobj
|
|
27916
|
-
***************************************************************************/
|
|
27917
|
-
function show_dropdown_popup_menu(gobj, x, y, items, callback) {
|
|
27918
|
-
let $element = (0, _yuneta_gobj_js.createElement2)([
|
|
27919
|
-
"div",
|
|
27920
|
-
{ class: "dropdown popup" },
|
|
27921
|
-
[[
|
|
27922
|
-
"div",
|
|
27923
|
-
{
|
|
27924
|
-
class: "dropdown-menu",
|
|
27925
|
-
role: "menu",
|
|
27926
|
-
style: "min-width:4rem; border: 2px solid var(--bulma-border); padding: 0px;"
|
|
27927
|
-
},
|
|
27928
|
-
[[
|
|
27929
|
-
"div",
|
|
27930
|
-
{
|
|
27931
|
-
class: "dropdown-content",
|
|
27932
|
-
style: "padding: 0;"
|
|
27933
|
-
},
|
|
27934
|
-
[]
|
|
27935
|
-
]]
|
|
27936
|
-
]],
|
|
27937
|
-
{ "click": (evt) => {
|
|
27938
|
-
evt.stopPropagation();
|
|
27939
|
-
destroyModal();
|
|
27940
|
-
if (callback) callback(evt);
|
|
27941
|
-
} }
|
|
27942
|
-
]);
|
|
27943
|
-
const destroyModal = () => {
|
|
27944
|
-
$element.classList.remove("is-active");
|
|
27945
|
-
$element.parentNode.removeChild($element);
|
|
27946
|
-
};
|
|
27947
|
-
let $dropdown_content = $element.querySelector(".dropdown-content");
|
|
27948
|
-
let ids = (0, _yuneta_gobj_js.kwid_get_ids)(gobj, items);
|
|
27949
|
-
for (let id of ids) {
|
|
27950
|
-
let $item = (0, _yuneta_gobj_js.createElement2)([
|
|
27951
|
-
"a",
|
|
27952
|
-
{
|
|
27953
|
-
class: "dropdown-item flex-horizontal-section",
|
|
27954
|
-
"data-value": `${id}`,
|
|
27955
|
-
style: "margin:0px;"
|
|
27956
|
-
},
|
|
27957
|
-
[[
|
|
27958
|
-
"span",
|
|
27959
|
-
{ i18n: `${id}` },
|
|
27960
|
-
`${id}`
|
|
27961
|
-
]],
|
|
27962
|
-
{ "click": (evt) => {
|
|
27963
|
-
evt.stopPropagation();
|
|
27964
|
-
destroyModal();
|
|
27965
|
-
if (callback) callback(evt, this.dataset.value);
|
|
27966
|
-
} }
|
|
27967
|
-
]);
|
|
27968
|
-
$dropdown_content.appendChild($item);
|
|
27969
|
-
}
|
|
27970
|
-
(0, _yuneta_gobj_js.refresh_language)($element, i18next.t);
|
|
27971
|
-
popup_mount_layer(gobj).appendChild($element);
|
|
27972
|
-
$element.style.position = "absolute";
|
|
27973
|
-
$element.style.top = y + "px";
|
|
27974
|
-
$element.style.left = x + "px";
|
|
27975
|
-
$element.classList.add("is-active");
|
|
27976
|
-
let $with_focus = $element.querySelector(".with-focus");
|
|
27977
|
-
if ($with_focus) $with_focus.focus();
|
|
27978
|
-
}
|
|
27979
28154
|
/***************************************************************
|
|
27980
28155
|
* A read-only topic refuses the write EVENTS too, not only their
|
|
27981
28156
|
* buttons. The buttons are gone, but an event can still arrive: a
|
|
@@ -28415,12 +28590,69 @@ function ac_change_locale(gobj, event, kw, src) {
|
|
|
28415
28590
|
* };
|
|
28416
28591
|
************************************************************/
|
|
28417
28592
|
function ac_show_hook_data$1(gobj, event, kw, src) {
|
|
28418
|
-
let
|
|
28419
|
-
let
|
|
28420
|
-
if (
|
|
28421
|
-
|
|
28422
|
-
|
|
28593
|
+
let col = get_schema_col(gobj, kw.col_id);
|
|
28594
|
+
let hook = col && (0, _yuneta_gobj_js.is_object)(col.hook) ? col.hook : null;
|
|
28595
|
+
if (!hook || kw.row_id === void 0 || kw.row_id === null) {
|
|
28596
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: hook '${kw.col_id}' names no child topic to open`);
|
|
28597
|
+
return -1;
|
|
28598
|
+
}
|
|
28599
|
+
let targets = Object.keys(hook).map((topic) => {
|
|
28600
|
+
return {
|
|
28601
|
+
topic_name: topic,
|
|
28602
|
+
fkey: hook[topic]
|
|
28603
|
+
};
|
|
28604
|
+
});
|
|
28605
|
+
if (targets.length === 1) {
|
|
28606
|
+
publish_open_linked(gobj, targets[0].topic_name, targets[0].fkey, String(kw.row_id), kw.col_id);
|
|
28607
|
+
return 0;
|
|
28608
|
+
}
|
|
28609
|
+
open_hook_choice_dialog(gobj, targets, String(kw.row_id), kw.col_id);
|
|
28610
|
+
return 0;
|
|
28611
|
+
}
|
|
28612
|
+
/************************************************************
|
|
28613
|
+
* A hook with several child topics: pick one.
|
|
28614
|
+
* {topic_name, fkey, parent_id, hook}
|
|
28615
|
+
************************************************************/
|
|
28616
|
+
function ac_choose_linked(gobj, event, kw, src) {
|
|
28617
|
+
close_hook_choice(gobj);
|
|
28618
|
+
publish_open_linked(gobj, kw.topic_name, kw.fkey, kw.parent_id, kw.hook);
|
|
28619
|
+
return 0;
|
|
28620
|
+
}
|
|
28621
|
+
/************************************************************
|
|
28622
|
+
* Show only the rows linked to one record of another topic.
|
|
28623
|
+
* Sent by the host when a hook of that record was clicked.
|
|
28624
|
+
* {fkey, parent_topic, parent_id, hook}
|
|
28625
|
+
*
|
|
28626
|
+
* Over the rows the table HOLDS: with `with_remote_paging` that
|
|
28627
|
+
* is one page, which is one of the reasons that flag stays off.
|
|
28628
|
+
************************************************************/
|
|
28629
|
+
function ac_filter_by_parent(gobj, event, kw, src) {
|
|
28630
|
+
let priv = gobj.priv;
|
|
28631
|
+
if (!kw || !kw.fkey || kw.parent_id === void 0 || kw.parent_id === null) {
|
|
28632
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: a parent filter with no fkey or no parent`);
|
|
28633
|
+
return -1;
|
|
28634
|
+
}
|
|
28635
|
+
if (!get_schema_col(gobj, kw.fkey)) {
|
|
28636
|
+
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: parent filter on '${kw.fkey}', which is not a column of '${(0, _yuneta_gobj_js.gobj_read_str_attr)(gobj, "topic_name")}'`);
|
|
28637
|
+
return -1;
|
|
28423
28638
|
}
|
|
28639
|
+
priv.parent_filter = {
|
|
28640
|
+
fkey: kw.fkey,
|
|
28641
|
+
parent_topic: kw.parent_topic || "",
|
|
28642
|
+
parent_id: String(kw.parent_id),
|
|
28643
|
+
hook: kw.hook || ""
|
|
28644
|
+
};
|
|
28645
|
+
render_parent_filter(gobj);
|
|
28646
|
+
apply_row_filters(gobj);
|
|
28647
|
+
return 0;
|
|
28648
|
+
}
|
|
28649
|
+
/************************************************************
|
|
28650
|
+
* The ✕ of the parent filter: back to the whole topic.
|
|
28651
|
+
************************************************************/
|
|
28652
|
+
function ac_clear_parent_filter(gobj, event, kw, src) {
|
|
28653
|
+
gobj.priv.parent_filter = null;
|
|
28654
|
+
render_parent_filter(gobj);
|
|
28655
|
+
apply_row_filters(gobj);
|
|
28424
28656
|
return 0;
|
|
28425
28657
|
}
|
|
28426
28658
|
/************************************************************
|
|
@@ -28731,19 +28963,12 @@ function ac_page_timeout(gobj, event, kw, src) {
|
|
|
28731
28963
|
* cleared search box does not silently undo them.
|
|
28732
28964
|
************************************************************/
|
|
28733
28965
|
function ac_search(gobj, event, kw, src) {
|
|
28734
|
-
|
|
28735
|
-
if (!tabulator) {
|
|
28966
|
+
if (!(0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator")) {
|
|
28736
28967
|
(0, _yuneta_gobj_js.log_error)(`${(0, _yuneta_gobj_js.gobj_short_name)(gobj)}: no table to search`);
|
|
28737
28968
|
return -1;
|
|
28738
28969
|
}
|
|
28739
|
-
|
|
28740
|
-
|
|
28741
|
-
tabulator.clearFilter();
|
|
28742
|
-
return 0;
|
|
28743
|
-
}
|
|
28744
|
-
tabulator.setFilter(function(data) {
|
|
28745
|
-
return row_matches(data, term);
|
|
28746
|
-
});
|
|
28970
|
+
gobj.priv.search_term = (kw && kw.text || "").toLowerCase();
|
|
28971
|
+
apply_row_filters(gobj);
|
|
28747
28972
|
return 0;
|
|
28748
28973
|
}
|
|
28749
28974
|
/************************************************************
|
|
@@ -28991,6 +29216,21 @@ function create_gclass$5(gclass_name) {
|
|
|
28991
29216
|
ac_show_hook_data$1,
|
|
28992
29217
|
null
|
|
28993
29218
|
],
|
|
29219
|
+
[
|
|
29220
|
+
"EV_CHOOSE_LINKED",
|
|
29221
|
+
ac_choose_linked,
|
|
29222
|
+
null
|
|
29223
|
+
],
|
|
29224
|
+
[
|
|
29225
|
+
"EV_FILTER_BY_PARENT",
|
|
29226
|
+
ac_filter_by_parent,
|
|
29227
|
+
null
|
|
29228
|
+
],
|
|
29229
|
+
[
|
|
29230
|
+
"EV_CLEAR_PARENT_FILTER",
|
|
29231
|
+
ac_clear_parent_filter,
|
|
29232
|
+
null
|
|
29233
|
+
],
|
|
28994
29234
|
[
|
|
28995
29235
|
"EV_SHOW_CELL_JSON",
|
|
28996
29236
|
ac_show_cell_json,
|
|
@@ -29109,7 +29349,11 @@ function create_gclass$5(gclass_name) {
|
|
|
29109
29349
|
["EV_CLEAR_SELECTION", 0],
|
|
29110
29350
|
["EV_SELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
29111
29351
|
["EV_UNSELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
29112
|
-
["EV_SHOW_HOOK_DATA",
|
|
29352
|
+
["EV_SHOW_HOOK_DATA", 0],
|
|
29353
|
+
["EV_CHOOSE_LINKED", 0],
|
|
29354
|
+
["EV_FILTER_BY_PARENT", 0],
|
|
29355
|
+
["EV_CLEAR_PARENT_FILTER", 0],
|
|
29356
|
+
["EV_OPEN_LINKED", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
29113
29357
|
["EV_SHOW_CELL_JSON", 0],
|
|
29114
29358
|
["EV_SHOW_CELL_FILE", 0],
|
|
29115
29359
|
["EV_ASSET_LOADED", 0],
|