@yuneta/gobj-ui 7.12.0 → 7.13.1
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 +9 -0
- package/dist/gobj-ui.cjs.js +164 -1
- package/dist/gobj-ui.es.js +198 -1
- package/package.json +1 -1
- package/src/c_yui_treedb_topic_with_form.js +64 -0
- package/src/c_yui_treedb_topics.js +3 -1
- package/src/tabulator.css +53 -6
package/README.md
CHANGED
|
@@ -1031,6 +1031,15 @@ from the view's `EV_LANGUAGE_CHANGED` action.
|
|
|
1031
1031
|
table that is not built yet or is already gone. Clear the selection after
|
|
1032
1032
|
acting on it: the rows it names are no longer there.
|
|
1033
1033
|
|
|
1034
|
+
**In the treedb topic table** (`C_YUI_TREEDB_TOPIC_WITH_FORM`, and through it
|
|
1035
|
+
`C_YUI_TREEDB_TOPICS`) the bar is **opt-in**: pass `with_selection_bar: true`.
|
|
1036
|
+
It is off by default because the bar takes its words from the HOST's i18n, and
|
|
1037
|
+
a host that has not defined `"{{n}} selected"` and `"clear selection"` renders
|
|
1038
|
+
the keys. It shows only while the table is in **edition mode** — outside it the
|
|
1039
|
+
checkbox column is hidden, and a count of rows nobody can see or untick is a
|
|
1040
|
+
count you cannot act on. The bar carries no action there: the table's own
|
|
1041
|
+
toolbar already has Delete and Copy, and they act on the selection.
|
|
1042
|
+
|
|
1034
1043
|
`yui_selection_column({visible: false})` is for a table that reveals the column
|
|
1035
1044
|
only in an edit mode — `C_YUI_TREEDB_TOPIC_WITH_FORM` shows it with
|
|
1036
1045
|
`showColumn("_check_box_state_")`, and takes its `selectableRows` and every
|
package/dist/gobj-ui.cjs.js
CHANGED
|
@@ -14496,6 +14496,7 @@ var attrs_table$6 = [
|
|
|
14496
14496
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
14497
14497
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
14498
14498
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
14499
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Each topic table shows the shared selection bar (\"N selected\" + a way out) above it while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, so a host that turns it on must define \"{{n}} selected\" and \"clear selection\""),
|
|
14499
14500
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
14500
14501
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
14501
14502
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -15310,7 +15311,8 @@ function process_treedb_descs$1(gobj) {
|
|
|
15310
15311
|
treedb_name,
|
|
15311
15312
|
topic_name: key,
|
|
15312
15313
|
desc,
|
|
15313
|
-
with_remote_paging: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_remote_paging")
|
|
15314
|
+
with_remote_paging: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_remote_paging"),
|
|
15315
|
+
with_selection_bar: (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_selection_bar")
|
|
15314
15316
|
};
|
|
15315
15317
|
let id = `${(0, _yuneta_gobj_js.gobj_name)(gobj)}?${desc.topic_name}`;
|
|
15316
15318
|
let gobj_topic_form = (0, _yuneta_gobj_js.gobj_create_service)(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
@@ -16403,6 +16405,119 @@ function yui_selected_rows(tabulator) {
|
|
|
16403
16405
|
return [];
|
|
16404
16406
|
}
|
|
16405
16407
|
}
|
|
16408
|
+
/***************************************************************
|
|
16409
|
+
* Drop the selection (after acting on it, or after a
|
|
16410
|
+
* reload that leaves the ticked rows behind).
|
|
16411
|
+
***************************************************************/
|
|
16412
|
+
function yui_clear_selection(tabulator) {
|
|
16413
|
+
if (!tabulator || typeof tabulator.deselectRow !== "function") return;
|
|
16414
|
+
try {
|
|
16415
|
+
tabulator.deselectRow();
|
|
16416
|
+
} catch (e) {}
|
|
16417
|
+
}
|
|
16418
|
+
/***************************************************************
|
|
16419
|
+
* The bar that appears while rows are selected.
|
|
16420
|
+
*
|
|
16421
|
+
* t the HOST's translator
|
|
16422
|
+
* opts:
|
|
16423
|
+
* actions [{label, icon, class, on_click}] -- `label` is an
|
|
16424
|
+
* i18n KEY, `class` extra Bulma classes for the
|
|
16425
|
+
* button (e.g. "is-danger"), `on_click` the DOM
|
|
16426
|
+
* handler, whose job is to send an event
|
|
16427
|
+
* on_clear called by the "clear selection" button
|
|
16428
|
+
* name logical-class prefix, default "TABLE"
|
|
16429
|
+
*
|
|
16430
|
+
* -> {$el, set_count(n), refresh()}
|
|
16431
|
+
*
|
|
16432
|
+
* `refresh()` redraws it in the current language: the count is
|
|
16433
|
+
* composed at render time, so it cannot re-translate itself
|
|
16434
|
+
* through `refresh_language()`. Call it on EV_LANGUAGE_CHANGED.
|
|
16435
|
+
***************************************************************/
|
|
16436
|
+
function yui_selection_bar(t, opts) {
|
|
16437
|
+
let o = opts || {};
|
|
16438
|
+
let actions = Array.isArray(o.actions) ? o.actions : [];
|
|
16439
|
+
let name = o.name || "TABLE";
|
|
16440
|
+
let count = 0;
|
|
16441
|
+
let $count = (0, _yuneta_gobj_js.createElement2)([
|
|
16442
|
+
"span",
|
|
16443
|
+
{ class: `${name}_SELECTION_COUNT has-text-weight-semibold` },
|
|
16444
|
+
""
|
|
16445
|
+
]);
|
|
16446
|
+
let $buttons = [];
|
|
16447
|
+
for (let action of actions) {
|
|
16448
|
+
let $b = (0, _yuneta_gobj_js.createElement2)([
|
|
16449
|
+
"button",
|
|
16450
|
+
{
|
|
16451
|
+
class: `${name}_SELECTION_ACTION button ${action.class || ""}`,
|
|
16452
|
+
type: "button"
|
|
16453
|
+
},
|
|
16454
|
+
[[
|
|
16455
|
+
"span",
|
|
16456
|
+
{ class: "icon" },
|
|
16457
|
+
[["i", { class: action.icon || "yi-check" }]]
|
|
16458
|
+
], [
|
|
16459
|
+
"span",
|
|
16460
|
+
{},
|
|
16461
|
+
""
|
|
16462
|
+
]],
|
|
16463
|
+
{ click: action.on_click }
|
|
16464
|
+
]);
|
|
16465
|
+
$b._yui_label = action.label || "";
|
|
16466
|
+
$buttons.push($b);
|
|
16467
|
+
}
|
|
16468
|
+
let $clear = (0, _yuneta_gobj_js.createElement2)([
|
|
16469
|
+
"button",
|
|
16470
|
+
{
|
|
16471
|
+
class: `${name}_SELECTION_CLEAR button is-ghost`,
|
|
16472
|
+
type: "button"
|
|
16473
|
+
},
|
|
16474
|
+
[[
|
|
16475
|
+
"span",
|
|
16476
|
+
{ class: "icon" },
|
|
16477
|
+
[["i", { class: "yi-xmark" }]]
|
|
16478
|
+
], [
|
|
16479
|
+
"span",
|
|
16480
|
+
{},
|
|
16481
|
+
""
|
|
16482
|
+
]],
|
|
16483
|
+
{ click: function(e) {
|
|
16484
|
+
if (typeof o.on_clear === "function") o.on_clear(e);
|
|
16485
|
+
} }
|
|
16486
|
+
]);
|
|
16487
|
+
$clear._yui_label = "clear selection";
|
|
16488
|
+
let $el = (0, _yuneta_gobj_js.createElement2)([
|
|
16489
|
+
"div",
|
|
16490
|
+
{
|
|
16491
|
+
class: `${name}_SELECTION_BAR is-align-items-center is-flex-wrap-wrap mb-2 is-hidden`,
|
|
16492
|
+
style: "display:flex; gap:0.5rem;"
|
|
16493
|
+
},
|
|
16494
|
+
[$count].concat($buttons, [$clear])
|
|
16495
|
+
]);
|
|
16496
|
+
function label_of($b) {
|
|
16497
|
+
return $b.querySelector("span.icon ~ span");
|
|
16498
|
+
}
|
|
16499
|
+
function refresh() {
|
|
16500
|
+
$count.textContent = t("{{n}} selected", { n: count });
|
|
16501
|
+
for (let $b of $buttons.concat([$clear])) {
|
|
16502
|
+
let $label = label_of($b);
|
|
16503
|
+
let key = $b._yui_label;
|
|
16504
|
+
if ($label && key) $label.textContent = t(key);
|
|
16505
|
+
$b.title = key ? t(key) : "";
|
|
16506
|
+
$b.setAttribute("aria-label", $b.title);
|
|
16507
|
+
}
|
|
16508
|
+
$el.classList.toggle("is-hidden", count <= 0);
|
|
16509
|
+
}
|
|
16510
|
+
function set_count(n) {
|
|
16511
|
+
count = n > 0 ? n : 0;
|
|
16512
|
+
refresh();
|
|
16513
|
+
}
|
|
16514
|
+
refresh();
|
|
16515
|
+
return {
|
|
16516
|
+
$el,
|
|
16517
|
+
set_count,
|
|
16518
|
+
refresh
|
|
16519
|
+
};
|
|
16520
|
+
}
|
|
16406
16521
|
//#endregion
|
|
16407
16522
|
//#region src/treedb_write_plan.js
|
|
16408
16523
|
/***********************************************************************
|
|
@@ -16571,6 +16686,7 @@ var attrs_table$5 = [
|
|
|
16571
16686
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16572
16687
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
16573
16688
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_radio", 0, false, "Auxiliary first column to select one row"),
|
|
16689
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Show the shared selection bar (\"N selected\" + a way out) above the table while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, and a host that has not defined \"{{n}} selected\" and \"clear selection\" would render the keys"),
|
|
16574
16690
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
16575
16691
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
16576
16692
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
@@ -16589,6 +16705,7 @@ var attrs_table$5 = [
|
|
|
16589
16705
|
}, "Default settings for Tabulator"),
|
|
16590
16706
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
16591
16707
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "tabulator", 0, null, "Tabulator instance"),
|
|
16708
|
+
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "selection_bar", 0, null, "The selection bar (yui_table_select.js), when with_selection_bar"),
|
|
16592
16709
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
16593
16710
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
16594
16711
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -17005,6 +17122,15 @@ function build_ui$5(gobj) {
|
|
|
17005
17122
|
style: "margin-top:0px !important;"
|
|
17006
17123
|
}]]
|
|
17007
17124
|
]);
|
|
17125
|
+
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_checkbox") && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_selection_bar")) {
|
|
17126
|
+
let bar = yui_selection_bar(i18next.t, {
|
|
17127
|
+
name: "TREEDB_TABLE",
|
|
17128
|
+
actions: [],
|
|
17129
|
+
on_clear: () => (0, _yuneta_gobj_js.gobj_send_event)(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
17130
|
+
});
|
|
17131
|
+
(0, _yuneta_gobj_js.gobj_write_attr)(gobj, "selection_bar", bar);
|
|
17132
|
+
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
17133
|
+
}
|
|
17008
17134
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
17009
17135
|
if ($table_toolbar instanceof Element) $toolbar_slot.appendChild($table_toolbar);
|
|
17010
17136
|
else $toolbar_slot.appendChild((0, _yuneta_gobj_js.createElement2)(["div", {}]));
|
|
@@ -17013,6 +17139,24 @@ function build_ui$5(gobj) {
|
|
|
17013
17139
|
(0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
|
|
17014
17140
|
}
|
|
17015
17141
|
/************************************************************
|
|
17142
|
+
* How many rows are ticked, on the bar.
|
|
17143
|
+
*
|
|
17144
|
+
* Only while the table is EDITABLE: outside edition its checkbox
|
|
17145
|
+
* column is hidden (`hideColumn`), and a count of rows nobody can
|
|
17146
|
+
* see or untick is a count you cannot act on. The selection itself
|
|
17147
|
+
* is left alone -- coming back to edition finds it, and the bar
|
|
17148
|
+
* recounts from the table.
|
|
17149
|
+
************************************************************/
|
|
17150
|
+
function render_selection_bar(gobj) {
|
|
17151
|
+
let bar = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "selection_bar");
|
|
17152
|
+
if (!bar) return;
|
|
17153
|
+
if (!(0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "editable")) {
|
|
17154
|
+
bar.set_count(0);
|
|
17155
|
+
return;
|
|
17156
|
+
}
|
|
17157
|
+
bar.set_count(yui_selected_rows((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator")).length);
|
|
17158
|
+
}
|
|
17159
|
+
/************************************************************
|
|
17016
17160
|
* Destroy UI
|
|
17017
17161
|
************************************************************/
|
|
17018
17162
|
function destroy_ui$2(gobj) {
|
|
@@ -18202,6 +18346,8 @@ function refuse_if_readonly$2(gobj, event) {
|
|
|
18202
18346
|
* dict. Re-apply it in the new language.
|
|
18203
18347
|
***************************************************************/
|
|
18204
18348
|
function ac_language_changed$2(gobj, event, kw, src) {
|
|
18349
|
+
let bar = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "selection_bar");
|
|
18350
|
+
if (bar) bar.refresh();
|
|
18205
18351
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
18206
18352
|
if (!tabulator) return 0;
|
|
18207
18353
|
yui_tabulator_relocalize(tabulator, i18next.t);
|
|
@@ -18315,6 +18461,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18315
18461
|
$button_copy_record.setAttribute("disabled", true);
|
|
18316
18462
|
$button_paste_record.setAttribute("disabled", true);
|
|
18317
18463
|
}
|
|
18464
|
+
render_selection_bar(gobj);
|
|
18318
18465
|
return 0;
|
|
18319
18466
|
}
|
|
18320
18467
|
/************************************************************
|
|
@@ -18460,6 +18607,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18460
18607
|
$button_copy_record.setAttribute("disabled", true);
|
|
18461
18608
|
}
|
|
18462
18609
|
}
|
|
18610
|
+
render_selection_bar(gobj);
|
|
18463
18611
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "broadcast_select_rows_event")) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, event, kw);
|
|
18464
18612
|
return 0;
|
|
18465
18613
|
}
|
|
@@ -18480,10 +18628,19 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18480
18628
|
$button_copy_record.setAttribute("disabled", true);
|
|
18481
18629
|
}
|
|
18482
18630
|
}
|
|
18631
|
+
render_selection_bar(gobj);
|
|
18483
18632
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "broadcast_select_rows_event")) (0, _yuneta_gobj_js.gobj_publish_event)(gobj, event, kw);
|
|
18484
18633
|
return 0;
|
|
18485
18634
|
}
|
|
18486
18635
|
/************************************************************
|
|
18636
|
+
* The way out of a selection (the bar's clear button).
|
|
18637
|
+
************************************************************/
|
|
18638
|
+
function ac_clear_selection(gobj, event, kw, src) {
|
|
18639
|
+
yui_clear_selection((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator"));
|
|
18640
|
+
render_selection_bar(gobj);
|
|
18641
|
+
return 0;
|
|
18642
|
+
}
|
|
18643
|
+
/************************************************************
|
|
18487
18644
|
* { locale: "es" }
|
|
18488
18645
|
************************************************************/
|
|
18489
18646
|
function ac_change_locale(gobj, event, kw, src) {
|
|
@@ -18960,6 +19117,11 @@ function create_gclass$5(gclass_name) {
|
|
|
18960
19117
|
ac_select_rows,
|
|
18961
19118
|
null
|
|
18962
19119
|
],
|
|
19120
|
+
[
|
|
19121
|
+
"EV_CLEAR_SELECTION",
|
|
19122
|
+
ac_clear_selection,
|
|
19123
|
+
null
|
|
19124
|
+
],
|
|
18963
19125
|
[
|
|
18964
19126
|
"EV_UNSELECT_ROWS",
|
|
18965
19127
|
ac_unselect_rows,
|
|
@@ -19068,6 +19230,7 @@ function create_gclass$5(gclass_name) {
|
|
|
19068
19230
|
["EV_DELETE_ROWS", 0],
|
|
19069
19231
|
["EV_COPY_ROWS", 0],
|
|
19070
19232
|
["EV_PASTE_ROWS", 0],
|
|
19233
|
+
["EV_CLEAR_SELECTION", 0],
|
|
19071
19234
|
["EV_SELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
19072
19235
|
["EV_UNSELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
19073
19236
|
["EV_SHOW_HOOK_DATA", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
package/dist/gobj-ui.es.js
CHANGED
|
@@ -14491,6 +14491,7 @@ var attrs_table$6 = [
|
|
|
14491
14491
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
14492
14492
|
SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
14493
14493
|
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
14494
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Each topic table shows the shared selection bar (\"N selected\" + a way out) above it while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, so a host that turns it on must define \"{{n}} selected\" and \"clear selection\""),
|
|
14494
14495
|
SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
14495
14496
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
14496
14497
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing", 0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -15305,7 +15306,8 @@ function process_treedb_descs$1(gobj) {
|
|
|
15305
15306
|
treedb_name,
|
|
15306
15307
|
topic_name: key,
|
|
15307
15308
|
desc,
|
|
15308
|
-
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging")
|
|
15309
|
+
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging"),
|
|
15310
|
+
with_selection_bar: gobj_read_bool_attr(gobj, "with_selection_bar")
|
|
15309
15311
|
};
|
|
15310
15312
|
let id = `${gobj_name(gobj)}?${desc.topic_name}`;
|
|
15311
15313
|
let gobj_topic_form = gobj_create_service(id, "C_YUI_TREEDB_TOPIC_WITH_FORM", kw_topic_form, gobj);
|
|
@@ -16313,6 +16315,40 @@ function yui_tabulator_relocalize(table, t) {
|
|
|
16313
16315
|
}
|
|
16314
16316
|
//#endregion
|
|
16315
16317
|
//#region src/yui_table_select.js
|
|
16318
|
+
/***********************************************************************
|
|
16319
|
+
* yui_table_select.js
|
|
16320
|
+
*
|
|
16321
|
+
* SELECT ROWS IN A TABLE, and act on the lot.
|
|
16322
|
+
*
|
|
16323
|
+
* Deleting twenty rows one confirmation at a time is not a
|
|
16324
|
+
* workflow, it is a punishment, and every table that lets you
|
|
16325
|
+
* remove a row will eventually be asked to remove twenty. This
|
|
16326
|
+
* is that facility, once: the checkbox column, the settings
|
|
16327
|
+
* that make selection behave, and the bar that appears while
|
|
16328
|
+
* something is selected and carries what can be done to it.
|
|
16329
|
+
*
|
|
16330
|
+
* Two decisions are baked in, both learned in the treedb
|
|
16331
|
+
* topic table:
|
|
16332
|
+
*
|
|
16333
|
+
* - Selection is driven ONLY by the checkbox, never by
|
|
16334
|
+
* clicking the row (`selectableRows: "highlight"`). A table
|
|
16335
|
+
* row is full of things to click -- an editor, an icon, a
|
|
16336
|
+
* nested table -- and click-to-select ticks a row every time
|
|
16337
|
+
* you reach for one of them.
|
|
16338
|
+
*
|
|
16339
|
+
* - The header checkbox covers the ACTIVE rows, the ones the
|
|
16340
|
+
* filters leave on screen. "Select all" over rows nobody can
|
|
16341
|
+
* see is how a filtered delete takes the whole topic with
|
|
16342
|
+
* it.
|
|
16343
|
+
*
|
|
16344
|
+
* The bar takes its words from the HOST's `t`: this library
|
|
16345
|
+
* translates through the app's i18next, and the app owns the
|
|
16346
|
+
* keys. It needs "{{n}} selected" and "clear selection"; each
|
|
16347
|
+
* action brings its own key.
|
|
16348
|
+
*
|
|
16349
|
+
* Copyright (c) 2026, ArtGins.
|
|
16350
|
+
* All Rights Reserved.
|
|
16351
|
+
***********************************************************************/
|
|
16316
16352
|
/***************************************************************
|
|
16317
16353
|
* The checkbox column. Put it FIRST in the column list.
|
|
16318
16354
|
*
|
|
@@ -16364,6 +16400,119 @@ function yui_selected_rows(tabulator) {
|
|
|
16364
16400
|
return [];
|
|
16365
16401
|
}
|
|
16366
16402
|
}
|
|
16403
|
+
/***************************************************************
|
|
16404
|
+
* Drop the selection (after acting on it, or after a
|
|
16405
|
+
* reload that leaves the ticked rows behind).
|
|
16406
|
+
***************************************************************/
|
|
16407
|
+
function yui_clear_selection(tabulator) {
|
|
16408
|
+
if (!tabulator || typeof tabulator.deselectRow !== "function") return;
|
|
16409
|
+
try {
|
|
16410
|
+
tabulator.deselectRow();
|
|
16411
|
+
} catch (e) {}
|
|
16412
|
+
}
|
|
16413
|
+
/***************************************************************
|
|
16414
|
+
* The bar that appears while rows are selected.
|
|
16415
|
+
*
|
|
16416
|
+
* t the HOST's translator
|
|
16417
|
+
* opts:
|
|
16418
|
+
* actions [{label, icon, class, on_click}] -- `label` is an
|
|
16419
|
+
* i18n KEY, `class` extra Bulma classes for the
|
|
16420
|
+
* button (e.g. "is-danger"), `on_click` the DOM
|
|
16421
|
+
* handler, whose job is to send an event
|
|
16422
|
+
* on_clear called by the "clear selection" button
|
|
16423
|
+
* name logical-class prefix, default "TABLE"
|
|
16424
|
+
*
|
|
16425
|
+
* -> {$el, set_count(n), refresh()}
|
|
16426
|
+
*
|
|
16427
|
+
* `refresh()` redraws it in the current language: the count is
|
|
16428
|
+
* composed at render time, so it cannot re-translate itself
|
|
16429
|
+
* through `refresh_language()`. Call it on EV_LANGUAGE_CHANGED.
|
|
16430
|
+
***************************************************************/
|
|
16431
|
+
function yui_selection_bar(t, opts) {
|
|
16432
|
+
let o = opts || {};
|
|
16433
|
+
let actions = Array.isArray(o.actions) ? o.actions : [];
|
|
16434
|
+
let name = o.name || "TABLE";
|
|
16435
|
+
let count = 0;
|
|
16436
|
+
let $count = createElement2([
|
|
16437
|
+
"span",
|
|
16438
|
+
{ class: `${name}_SELECTION_COUNT has-text-weight-semibold` },
|
|
16439
|
+
""
|
|
16440
|
+
]);
|
|
16441
|
+
let $buttons = [];
|
|
16442
|
+
for (let action of actions) {
|
|
16443
|
+
let $b = createElement2([
|
|
16444
|
+
"button",
|
|
16445
|
+
{
|
|
16446
|
+
class: `${name}_SELECTION_ACTION button ${action.class || ""}`,
|
|
16447
|
+
type: "button"
|
|
16448
|
+
},
|
|
16449
|
+
[[
|
|
16450
|
+
"span",
|
|
16451
|
+
{ class: "icon" },
|
|
16452
|
+
[["i", { class: action.icon || "yi-check" }]]
|
|
16453
|
+
], [
|
|
16454
|
+
"span",
|
|
16455
|
+
{},
|
|
16456
|
+
""
|
|
16457
|
+
]],
|
|
16458
|
+
{ click: action.on_click }
|
|
16459
|
+
]);
|
|
16460
|
+
$b._yui_label = action.label || "";
|
|
16461
|
+
$buttons.push($b);
|
|
16462
|
+
}
|
|
16463
|
+
let $clear = createElement2([
|
|
16464
|
+
"button",
|
|
16465
|
+
{
|
|
16466
|
+
class: `${name}_SELECTION_CLEAR button is-ghost`,
|
|
16467
|
+
type: "button"
|
|
16468
|
+
},
|
|
16469
|
+
[[
|
|
16470
|
+
"span",
|
|
16471
|
+
{ class: "icon" },
|
|
16472
|
+
[["i", { class: "yi-xmark" }]]
|
|
16473
|
+
], [
|
|
16474
|
+
"span",
|
|
16475
|
+
{},
|
|
16476
|
+
""
|
|
16477
|
+
]],
|
|
16478
|
+
{ click: function(e) {
|
|
16479
|
+
if (typeof o.on_clear === "function") o.on_clear(e);
|
|
16480
|
+
} }
|
|
16481
|
+
]);
|
|
16482
|
+
$clear._yui_label = "clear selection";
|
|
16483
|
+
let $el = createElement2([
|
|
16484
|
+
"div",
|
|
16485
|
+
{
|
|
16486
|
+
class: `${name}_SELECTION_BAR is-align-items-center is-flex-wrap-wrap mb-2 is-hidden`,
|
|
16487
|
+
style: "display:flex; gap:0.5rem;"
|
|
16488
|
+
},
|
|
16489
|
+
[$count].concat($buttons, [$clear])
|
|
16490
|
+
]);
|
|
16491
|
+
function label_of($b) {
|
|
16492
|
+
return $b.querySelector("span.icon ~ span");
|
|
16493
|
+
}
|
|
16494
|
+
function refresh() {
|
|
16495
|
+
$count.textContent = t("{{n}} selected", { n: count });
|
|
16496
|
+
for (let $b of $buttons.concat([$clear])) {
|
|
16497
|
+
let $label = label_of($b);
|
|
16498
|
+
let key = $b._yui_label;
|
|
16499
|
+
if ($label && key) $label.textContent = t(key);
|
|
16500
|
+
$b.title = key ? t(key) : "";
|
|
16501
|
+
$b.setAttribute("aria-label", $b.title);
|
|
16502
|
+
}
|
|
16503
|
+
$el.classList.toggle("is-hidden", count <= 0);
|
|
16504
|
+
}
|
|
16505
|
+
function set_count(n) {
|
|
16506
|
+
count = n > 0 ? n : 0;
|
|
16507
|
+
refresh();
|
|
16508
|
+
}
|
|
16509
|
+
refresh();
|
|
16510
|
+
return {
|
|
16511
|
+
$el,
|
|
16512
|
+
set_count,
|
|
16513
|
+
refresh
|
|
16514
|
+
};
|
|
16515
|
+
}
|
|
16367
16516
|
//#endregion
|
|
16368
16517
|
//#region src/treedb_write_plan.js
|
|
16369
16518
|
/***********************************************************************
|
|
@@ -16532,6 +16681,7 @@ var attrs_table$5 = [
|
|
|
16532
16681
|
SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16533
16682
|
SDATA(data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
16534
16683
|
SDATA(data_type_t.DTP_BOOLEAN, "with_radio", 0, false, "Auxiliary first column to select one row"),
|
|
16684
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Show the shared selection bar (\"N selected\" + a way out) above the table while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, and a host that has not defined \"{{n}} selected\" and \"clear selection\" would render the keys"),
|
|
16535
16685
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
16536
16686
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
16537
16687
|
SDATA(data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
@@ -16550,6 +16700,7 @@ var attrs_table$5 = [
|
|
|
16550
16700
|
}, "Default settings for Tabulator"),
|
|
16551
16701
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
16552
16702
|
SDATA(data_type_t.DTP_POINTER, "tabulator", 0, null, "Tabulator instance"),
|
|
16703
|
+
SDATA(data_type_t.DTP_POINTER, "selection_bar", 0, null, "The selection bar (yui_table_select.js), when with_selection_bar"),
|
|
16553
16704
|
SDATA(data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
16554
16705
|
SDATA(data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
16555
16706
|
SDATA(data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -16966,6 +17117,15 @@ function build_ui$5(gobj) {
|
|
|
16966
17117
|
style: "margin-top:0px !important;"
|
|
16967
17118
|
}]]
|
|
16968
17119
|
]);
|
|
17120
|
+
if (gobj_read_bool_attr(gobj, "with_checkbox") && gobj_read_bool_attr(gobj, "with_selection_bar")) {
|
|
17121
|
+
let bar = yui_selection_bar(t, {
|
|
17122
|
+
name: "TREEDB_TABLE",
|
|
17123
|
+
actions: [],
|
|
17124
|
+
on_clear: () => gobj_send_event(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
17125
|
+
});
|
|
17126
|
+
gobj_write_attr(gobj, "selection_bar", bar);
|
|
17127
|
+
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
17128
|
+
}
|
|
16969
17129
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
16970
17130
|
if ($table_toolbar instanceof Element) $toolbar_slot.appendChild($table_toolbar);
|
|
16971
17131
|
else $toolbar_slot.appendChild(createElement2(["div", {}]));
|
|
@@ -16974,6 +17134,24 @@ function build_ui$5(gobj) {
|
|
|
16974
17134
|
refresh_language($container, t);
|
|
16975
17135
|
}
|
|
16976
17136
|
/************************************************************
|
|
17137
|
+
* How many rows are ticked, on the bar.
|
|
17138
|
+
*
|
|
17139
|
+
* Only while the table is EDITABLE: outside edition its checkbox
|
|
17140
|
+
* column is hidden (`hideColumn`), and a count of rows nobody can
|
|
17141
|
+
* see or untick is a count you cannot act on. The selection itself
|
|
17142
|
+
* is left alone -- coming back to edition finds it, and the bar
|
|
17143
|
+
* recounts from the table.
|
|
17144
|
+
************************************************************/
|
|
17145
|
+
function render_selection_bar(gobj) {
|
|
17146
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
17147
|
+
if (!bar) return;
|
|
17148
|
+
if (!gobj_read_bool_attr(gobj, "editable")) {
|
|
17149
|
+
bar.set_count(0);
|
|
17150
|
+
return;
|
|
17151
|
+
}
|
|
17152
|
+
bar.set_count(yui_selected_rows(gobj_read_attr(gobj, "tabulator")).length);
|
|
17153
|
+
}
|
|
17154
|
+
/************************************************************
|
|
16977
17155
|
* Destroy UI
|
|
16978
17156
|
************************************************************/
|
|
16979
17157
|
function destroy_ui$2(gobj) {
|
|
@@ -18163,6 +18341,8 @@ function refuse_if_readonly$2(gobj, event) {
|
|
|
18163
18341
|
* dict. Re-apply it in the new language.
|
|
18164
18342
|
***************************************************************/
|
|
18165
18343
|
function ac_language_changed$2(gobj, event, kw, src) {
|
|
18344
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
18345
|
+
if (bar) bar.refresh();
|
|
18166
18346
|
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
18167
18347
|
if (!tabulator) return 0;
|
|
18168
18348
|
yui_tabulator_relocalize(tabulator, t);
|
|
@@ -18276,6 +18456,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18276
18456
|
$button_copy_record.setAttribute("disabled", true);
|
|
18277
18457
|
$button_paste_record.setAttribute("disabled", true);
|
|
18278
18458
|
}
|
|
18459
|
+
render_selection_bar(gobj);
|
|
18279
18460
|
return 0;
|
|
18280
18461
|
}
|
|
18281
18462
|
/************************************************************
|
|
@@ -18421,6 +18602,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18421
18602
|
$button_copy_record.setAttribute("disabled", true);
|
|
18422
18603
|
}
|
|
18423
18604
|
}
|
|
18605
|
+
render_selection_bar(gobj);
|
|
18424
18606
|
if (gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) gobj_publish_event(gobj, event, kw);
|
|
18425
18607
|
return 0;
|
|
18426
18608
|
}
|
|
@@ -18441,10 +18623,19 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18441
18623
|
$button_copy_record.setAttribute("disabled", true);
|
|
18442
18624
|
}
|
|
18443
18625
|
}
|
|
18626
|
+
render_selection_bar(gobj);
|
|
18444
18627
|
if (gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) gobj_publish_event(gobj, event, kw);
|
|
18445
18628
|
return 0;
|
|
18446
18629
|
}
|
|
18447
18630
|
/************************************************************
|
|
18631
|
+
* The way out of a selection (the bar's clear button).
|
|
18632
|
+
************************************************************/
|
|
18633
|
+
function ac_clear_selection(gobj, event, kw, src) {
|
|
18634
|
+
yui_clear_selection(gobj_read_attr(gobj, "tabulator"));
|
|
18635
|
+
render_selection_bar(gobj);
|
|
18636
|
+
return 0;
|
|
18637
|
+
}
|
|
18638
|
+
/************************************************************
|
|
18448
18639
|
* { locale: "es" }
|
|
18449
18640
|
************************************************************/
|
|
18450
18641
|
function ac_change_locale(gobj, event, kw, src) {
|
|
@@ -18921,6 +19112,11 @@ function create_gclass$5(gclass_name) {
|
|
|
18921
19112
|
ac_select_rows,
|
|
18922
19113
|
null
|
|
18923
19114
|
],
|
|
19115
|
+
[
|
|
19116
|
+
"EV_CLEAR_SELECTION",
|
|
19117
|
+
ac_clear_selection,
|
|
19118
|
+
null
|
|
19119
|
+
],
|
|
18924
19120
|
[
|
|
18925
19121
|
"EV_UNSELECT_ROWS",
|
|
18926
19122
|
ac_unselect_rows,
|
|
@@ -19029,6 +19225,7 @@ function create_gclass$5(gclass_name) {
|
|
|
19029
19225
|
["EV_DELETE_ROWS", 0],
|
|
19030
19226
|
["EV_COPY_ROWS", 0],
|
|
19031
19227
|
["EV_PASTE_ROWS", 0],
|
|
19228
|
+
["EV_CLEAR_SELECTION", 0],
|
|
19032
19229
|
["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
19033
19230
|
["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
19034
19231
|
["EV_SHOW_HOOK_DATA", event_flag_t.EVF_OUTPUT_EVENT],
|
package/package.json
CHANGED
|
@@ -78,7 +78,9 @@ import {yui_tabulator_lang, yui_tabulator_relocalize} from "./yui_tabulator_i18n
|
|
|
78
78
|
import {
|
|
79
79
|
yui_selection_column,
|
|
80
80
|
yui_selection_settings,
|
|
81
|
+
yui_selection_bar,
|
|
81
82
|
yui_selected_rows,
|
|
83
|
+
yui_clear_selection,
|
|
82
84
|
} from "./yui_table_select.js";
|
|
83
85
|
|
|
84
86
|
import {t} from "i18next";
|
|
@@ -129,6 +131,7 @@ SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"
|
|
|
129
131
|
/*---------------- Selection Mode ----------------*/
|
|
130
132
|
SDATA(data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
131
133
|
SDATA(data_type_t.DTP_BOOLEAN, "with_radio", 0, false, "Auxiliary first column to select one row"),
|
|
134
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Show the shared selection bar (\"N selected\" + a way out) above the table while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, and a host that has not defined \"{{n}} selected\" and \"clear selection\" would render the keys"),
|
|
132
135
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
133
136
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
134
137
|
|
|
@@ -148,6 +151,7 @@ SDATA(data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
|
148
151
|
/*---------------- Internal Attributes ----------------*/
|
|
149
152
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
150
153
|
SDATA(data_type_t.DTP_POINTER, "tabulator", 0, null, "Tabulator instance"),
|
|
154
|
+
SDATA(data_type_t.DTP_POINTER, "selection_bar", 0, null, "The selection bar (yui_table_select.js), when with_selection_bar"),
|
|
151
155
|
SDATA(data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
152
156
|
SDATA(data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
153
157
|
SDATA(data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -648,6 +652,21 @@ function build_ui(gobj)
|
|
|
648
652
|
]
|
|
649
653
|
]]
|
|
650
654
|
);
|
|
655
|
+
/* The shared selection bar, between the toolbar and the table. It is
|
|
656
|
+
* the only thing that says HOW MANY rows are ticked: with 200 rows to a
|
|
657
|
+
* page, the checkboxes that answer that question are not all on screen.
|
|
658
|
+
* Opt-in, because it takes its words from the host's i18n. */
|
|
659
|
+
if(gobj_read_bool_attr(gobj, "with_checkbox") &&
|
|
660
|
+
gobj_read_bool_attr(gobj, "with_selection_bar")) {
|
|
661
|
+
let bar = yui_selection_bar(t, {
|
|
662
|
+
name: "TREEDB_TABLE",
|
|
663
|
+
actions: [], /* the toolbar above already carries them */
|
|
664
|
+
on_clear: () => gobj_send_event(gobj, "EV_CLEAR_SELECTION", {}, gobj)
|
|
665
|
+
});
|
|
666
|
+
gobj_write_attr(gobj, "selection_bar", bar);
|
|
667
|
+
$container.insertBefore(bar.$el, $container.querySelector(`#${table_id}`));
|
|
668
|
+
}
|
|
669
|
+
|
|
651
670
|
let $toolbar_slot = $container.querySelector('.toolbar_tabulator_table');
|
|
652
671
|
if($table_toolbar instanceof Element) {
|
|
653
672
|
$toolbar_slot.appendChild($table_toolbar);
|
|
@@ -660,6 +679,28 @@ function build_ui(gobj)
|
|
|
660
679
|
refresh_language($container, t);
|
|
661
680
|
}
|
|
662
681
|
|
|
682
|
+
/************************************************************
|
|
683
|
+
* How many rows are ticked, on the bar.
|
|
684
|
+
*
|
|
685
|
+
* Only while the table is EDITABLE: outside edition its checkbox
|
|
686
|
+
* column is hidden (`hideColumn`), and a count of rows nobody can
|
|
687
|
+
* see or untick is a count you cannot act on. The selection itself
|
|
688
|
+
* is left alone -- coming back to edition finds it, and the bar
|
|
689
|
+
* recounts from the table.
|
|
690
|
+
************************************************************/
|
|
691
|
+
function render_selection_bar(gobj)
|
|
692
|
+
{
|
|
693
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
694
|
+
if(!bar) {
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
if(!gobj_read_bool_attr(gobj, "editable")) {
|
|
698
|
+
bar.set_count(0);
|
|
699
|
+
return;
|
|
700
|
+
}
|
|
701
|
+
bar.set_count(yui_selected_rows(gobj_read_attr(gobj, "tabulator")).length);
|
|
702
|
+
}
|
|
703
|
+
|
|
663
704
|
/************************************************************
|
|
664
705
|
* Destroy UI
|
|
665
706
|
************************************************************/
|
|
@@ -2435,6 +2476,10 @@ function refuse_if_readonly(gobj, event)
|
|
|
2435
2476
|
***************************************************************/
|
|
2436
2477
|
function ac_language_changed(gobj, event, kw, src)
|
|
2437
2478
|
{
|
|
2479
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
2480
|
+
if(bar) {
|
|
2481
|
+
bar.refresh(); /* a count composed at render time */
|
|
2482
|
+
}
|
|
2438
2483
|
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
2439
2484
|
if(!tabulator) {
|
|
2440
2485
|
return 0;
|
|
@@ -2661,6 +2706,8 @@ function ac_edition_mode(gobj, event, kw, src)
|
|
|
2661
2706
|
$button_paste_record.setAttribute("disabled", true);
|
|
2662
2707
|
}
|
|
2663
2708
|
|
|
2709
|
+
render_selection_bar(gobj);
|
|
2710
|
+
|
|
2664
2711
|
return 0;
|
|
2665
2712
|
}
|
|
2666
2713
|
|
|
@@ -2900,6 +2947,8 @@ function ac_select_rows(gobj, event, kw, src)
|
|
|
2900
2947
|
}
|
|
2901
2948
|
}
|
|
2902
2949
|
|
|
2950
|
+
render_selection_bar(gobj);
|
|
2951
|
+
|
|
2903
2952
|
if(gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) {
|
|
2904
2953
|
gobj_publish_event(gobj, event, kw);
|
|
2905
2954
|
}
|
|
@@ -2931,7 +2980,10 @@ function ac_unselect_rows(gobj, event, kw, src)
|
|
|
2931
2980
|
}
|
|
2932
2981
|
}
|
|
2933
2982
|
|
|
2983
|
+
render_selection_bar(gobj);
|
|
2984
|
+
|
|
2934
2985
|
// WARNING with radio, there is no unselect event.
|
|
2986
|
+
|
|
2935
2987
|
if(gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) {
|
|
2936
2988
|
gobj_publish_event(gobj, event, kw);
|
|
2937
2989
|
}
|
|
@@ -2939,6 +2991,16 @@ function ac_unselect_rows(gobj, event, kw, src)
|
|
|
2939
2991
|
return 0;
|
|
2940
2992
|
}
|
|
2941
2993
|
|
|
2994
|
+
/************************************************************
|
|
2995
|
+
* The way out of a selection (the bar's clear button).
|
|
2996
|
+
************************************************************/
|
|
2997
|
+
function ac_clear_selection(gobj, event, kw, src)
|
|
2998
|
+
{
|
|
2999
|
+
yui_clear_selection(gobj_read_attr(gobj, "tabulator"));
|
|
3000
|
+
render_selection_bar(gobj);
|
|
3001
|
+
return 0;
|
|
3002
|
+
}
|
|
3003
|
+
|
|
2942
3004
|
/************************************************************
|
|
2943
3005
|
* { locale: "es" }
|
|
2944
3006
|
************************************************************/
|
|
@@ -3447,6 +3509,7 @@ function create_gclass(gclass_name)
|
|
|
3447
3509
|
["EV_NEW_ROW", ac_new_row, null],
|
|
3448
3510
|
["EV_DELETE_ROWS", ac_delete_rows, null],
|
|
3449
3511
|
["EV_SELECT_ROWS", ac_select_rows, null],
|
|
3512
|
+
["EV_CLEAR_SELECTION", ac_clear_selection, null],
|
|
3450
3513
|
["EV_UNSELECT_ROWS", ac_unselect_rows, null],
|
|
3451
3514
|
["EV_COPY_ROWS", ac_copy_rows, null],
|
|
3452
3515
|
["EV_PASTE_ROWS", ac_paste_rows, null],
|
|
@@ -3485,6 +3548,7 @@ function create_gclass(gclass_name)
|
|
|
3485
3548
|
["EV_DELETE_ROWS", 0],
|
|
3486
3549
|
["EV_COPY_ROWS", 0],
|
|
3487
3550
|
["EV_PASTE_ROWS", 0],
|
|
3551
|
+
["EV_CLEAR_SELECTION", 0],
|
|
3488
3552
|
["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3489
3553
|
["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3490
3554
|
["EV_SHOW_HOOK_DATA", event_flag_t.EVF_OUTPUT_EVENT],
|
|
@@ -76,6 +76,7 @@ SDATA(data_type_t.DTP_POINTER, "gobj_remote_yuno", 0, null, "Remote yuno for
|
|
|
76
76
|
SDATA(data_type_t.DTP_STRING, "treedb_name", 0, null, "Remote TreeDB service name"),
|
|
77
77
|
SDATA(data_type_t.DTP_JSON, "descs", 0, null, "Description of topics"),
|
|
78
78
|
SDATA(data_type_t.DTP_BOOLEAN, "with_remote_paging", 0, false, "Each topic table pulls its rows a PAGE at a time (`nodes` from/limit) instead of loading the topic whole. Safe against a backend that cannot page: it answers the whole list, which the table reads as one page"),
|
|
79
|
+
SDATA(data_type_t.DTP_BOOLEAN, "with_selection_bar", 0, false, "Each topic table shows the shared selection bar (\"N selected\" + a way out) above it while in edition mode. OFF by default: the bar takes its words from the HOST's i18n, so a host that turns it on must define \"{{n}} selected\" and \"clear selection\""),
|
|
79
80
|
SDATA(data_type_t.DTP_BOOLEAN, "system", 0, false, "Manage system topics (true) or user topics (false)"),
|
|
80
81
|
SDATA(data_type_t.DTP_STRING, "tabs_style", 0, "is-toggle is-fullwidth", "Bulma tab styling"),
|
|
81
82
|
SDATA(data_type_t.DTP_BOOLEAN, "with_cards_landing",0, false, "Land on a grid of topic cards (list->detail): a card opens its table, with the tabs bar + a back-to-grid button. Off = tabs only (legacy)."),
|
|
@@ -1039,7 +1040,8 @@ function process_treedb_descs(gobj)
|
|
|
1039
1040
|
treedb_name: treedb_name,
|
|
1040
1041
|
topic_name: key,
|
|
1041
1042
|
desc: desc,
|
|
1042
|
-
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging")
|
|
1043
|
+
with_remote_paging: gobj_read_bool_attr(gobj, "with_remote_paging"),
|
|
1044
|
+
with_selection_bar: gobj_read_bool_attr(gobj, "with_selection_bar")
|
|
1043
1045
|
};
|
|
1044
1046
|
|
|
1045
1047
|
let id = `${gobj_name(gobj)}?${desc.topic_name}`;
|
package/src/tabulator.css
CHANGED
|
@@ -220,9 +220,7 @@
|
|
|
220
220
|
*/
|
|
221
221
|
[data-theme=dark] .tabulator-row .tabulator-cell.tabulator-editing input,
|
|
222
222
|
[data-theme=dark] .tabulator-row .tabulator-cell.tabulator-editing select,
|
|
223
|
-
[data-theme=dark] .tabulator-row .tabulator-cell.tabulator-editing textarea
|
|
224
|
-
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
225
|
-
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
223
|
+
[data-theme=dark] .tabulator-row .tabulator-cell.tabulator-editing textarea {
|
|
226
224
|
background-color: var(--bulma-grey-darker, #2b2f38);
|
|
227
225
|
color: var(--bulma-text-strong, #f5f6f7) !important;
|
|
228
226
|
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
@@ -234,6 +232,47 @@
|
|
|
234
232
|
color: var(--bulma-text-weak, #8a8f98);
|
|
235
233
|
}
|
|
236
234
|
|
|
235
|
+
/* ====================================================================
|
|
236
|
+
* The HEADER FILTER box is FURNITURE, not an open editor.
|
|
237
|
+
*
|
|
238
|
+
* Both are inputs inside the table, so they shared these rules -- but an
|
|
239
|
+
* editor is a MODE: one cell, while you type into it, and deliberately the
|
|
240
|
+
* brightest thing on screen. A filter box is permanent and there is one per
|
|
241
|
+
* column, so wearing the editor's border a header of eight columns drew
|
|
242
|
+
* eight hard boxes across the top of every table, link-BLUE in dark theme.
|
|
243
|
+
*
|
|
244
|
+
* Discreet at rest -- a hairline in the theme's weakest border colour, no
|
|
245
|
+
* wash of its own -- and only the FOCUSED one stands out, which is the one
|
|
246
|
+
* you are typing in.
|
|
247
|
+
* ==================================================================== */
|
|
248
|
+
.tabulator .tabulator-header .tabulator-header-filter input,
|
|
249
|
+
.tabulator .tabulator-header .tabulator-header-filter select {
|
|
250
|
+
/* A neutral translucent grey, NOT `--bulma-border`: that token does not
|
|
251
|
+
* flip with the theme here -- it stays #dbdbdb, which is a hairline on
|
|
252
|
+
* white and a bright line on near-black. 35% mid-grey reads as the same
|
|
253
|
+
* quiet hairline over both, and needs no per-theme rule. */
|
|
254
|
+
border: 1px solid rgba(128, 128, 128, 0.35);
|
|
255
|
+
border-radius: 3px;
|
|
256
|
+
background-color: transparent;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
260
|
+
.tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
261
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
262
|
+
outline: none;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
266
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
267
|
+
color: var(--bulma-text-strong, #f5f6f7);
|
|
268
|
+
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
272
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
273
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
274
|
+
}
|
|
275
|
+
|
|
237
276
|
[data-theme=dark] .tabulator-row.tabulator-selected {
|
|
238
277
|
background-color: var(--bulma-link) !important;
|
|
239
278
|
color: var(--bulma-link-invert) !important;
|
|
@@ -313,9 +352,7 @@
|
|
|
313
352
|
/* same editor fix as [data-theme=dark] above */
|
|
314
353
|
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing input,
|
|
315
354
|
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing select,
|
|
316
|
-
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing textarea
|
|
317
|
-
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
318
|
-
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
355
|
+
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing textarea {
|
|
319
356
|
background-color: var(--bulma-grey-darker, #2b2f38);
|
|
320
357
|
color: var(--bulma-text-strong, #f5f6f7) !important;
|
|
321
358
|
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
@@ -325,6 +362,16 @@
|
|
|
325
362
|
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input::placeholder {
|
|
326
363
|
color: var(--bulma-text-weak, #8a8f98);
|
|
327
364
|
}
|
|
365
|
+
/* same furniture-not-editor rule as [data-theme=dark] above */
|
|
366
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
367
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
368
|
+
color: var(--bulma-text-strong, #f5f6f7);
|
|
369
|
+
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
370
|
+
}
|
|
371
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
372
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
373
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
374
|
+
}
|
|
328
375
|
[data-theme=system] .tabulator-row.tabulator-selected {
|
|
329
376
|
background-color: var(--bulma-link) !important;
|
|
330
377
|
color: var(--bulma-link-invert) !important;
|