@yuneta/gobj-ui 7.11.1 → 7.13.0
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 +17 -0
- package/dist/gobj-ui.cjs.js +262 -15
- package/dist/gobj-ui.es.js +262 -15
- package/package.json +1 -1
- package/src/c_yui_treedb_topic_with_form.js +95 -16
- package/src/c_yui_treedb_topics.js +3 -1
- package/src/tabulator.css +51 -6
- package/src/yui_table_select.js +11 -2
package/README.md
CHANGED
|
@@ -1031,6 +1031,23 @@ 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
|
+
|
|
1043
|
+
`yui_selection_column({visible: false})` is for a table that reveals the column
|
|
1044
|
+
only in an edit mode — `C_YUI_TREEDB_TOPIC_WITH_FORM` shows it with
|
|
1045
|
+
`showColumn("_check_box_state_")`, and takes its `selectableRows` and every
|
|
1046
|
+
read of its selection from here too. A **radio** column (pick ONE row) is not
|
|
1047
|
+
this facility: it is `formatter: "rowSelection"` with no `titleFormatter` and
|
|
1048
|
+
`selectableRows: 1`, and the header checkbox, the count and the bar all mean
|
|
1049
|
+
nothing there.
|
|
1050
|
+
|
|
1034
1051
|
## Conventions
|
|
1035
1052
|
|
|
1036
1053
|
### i18n: a string must be able to CHANGE language, not just be translated once
|
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);
|
|
@@ -16317,6 +16319,206 @@ function yui_tabulator_relocalize(table, t) {
|
|
|
16317
16319
|
}
|
|
16318
16320
|
}
|
|
16319
16321
|
//#endregion
|
|
16322
|
+
//#region src/yui_table_select.js
|
|
16323
|
+
/***********************************************************************
|
|
16324
|
+
* yui_table_select.js
|
|
16325
|
+
*
|
|
16326
|
+
* SELECT ROWS IN A TABLE, and act on the lot.
|
|
16327
|
+
*
|
|
16328
|
+
* Deleting twenty rows one confirmation at a time is not a
|
|
16329
|
+
* workflow, it is a punishment, and every table that lets you
|
|
16330
|
+
* remove a row will eventually be asked to remove twenty. This
|
|
16331
|
+
* is that facility, once: the checkbox column, the settings
|
|
16332
|
+
* that make selection behave, and the bar that appears while
|
|
16333
|
+
* something is selected and carries what can be done to it.
|
|
16334
|
+
*
|
|
16335
|
+
* Two decisions are baked in, both learned in the treedb
|
|
16336
|
+
* topic table:
|
|
16337
|
+
*
|
|
16338
|
+
* - Selection is driven ONLY by the checkbox, never by
|
|
16339
|
+
* clicking the row (`selectableRows: "highlight"`). A table
|
|
16340
|
+
* row is full of things to click -- an editor, an icon, a
|
|
16341
|
+
* nested table -- and click-to-select ticks a row every time
|
|
16342
|
+
* you reach for one of them.
|
|
16343
|
+
*
|
|
16344
|
+
* - The header checkbox covers the ACTIVE rows, the ones the
|
|
16345
|
+
* filters leave on screen. "Select all" over rows nobody can
|
|
16346
|
+
* see is how a filtered delete takes the whole topic with
|
|
16347
|
+
* it.
|
|
16348
|
+
*
|
|
16349
|
+
* The bar takes its words from the HOST's `t`: this library
|
|
16350
|
+
* translates through the app's i18next, and the app owns the
|
|
16351
|
+
* keys. It needs "{{n}} selected" and "clear selection"; each
|
|
16352
|
+
* action brings its own key.
|
|
16353
|
+
*
|
|
16354
|
+
* Copyright (c) 2026, ArtGins.
|
|
16355
|
+
* All Rights Reserved.
|
|
16356
|
+
***********************************************************************/
|
|
16357
|
+
/***************************************************************
|
|
16358
|
+
* The checkbox column. Put it FIRST in the column list.
|
|
16359
|
+
*
|
|
16360
|
+
* opts:
|
|
16361
|
+
* field the (virtual) field name, default "_select"
|
|
16362
|
+
* width default 44
|
|
16363
|
+
* visible default true; `false` for a table that reveals
|
|
16364
|
+
* the column only in an edit mode (the treedb topic
|
|
16365
|
+
* table shows it with `showColumn(field)`)
|
|
16366
|
+
*
|
|
16367
|
+
* This is the SELECT-MANY widget. A table that lets you pick ONE
|
|
16368
|
+
* row uses a radio column of its own (`formatter: "rowSelection"`
|
|
16369
|
+
* with no `titleFormatter`, `selectableRows: 1`): the header
|
|
16370
|
+
* checkbox, the count and the bar all mean nothing there.
|
|
16371
|
+
***************************************************************/
|
|
16372
|
+
function yui_selection_column(opts) {
|
|
16373
|
+
let o = opts || {};
|
|
16374
|
+
return {
|
|
16375
|
+
title: "",
|
|
16376
|
+
field: o.field || "_select",
|
|
16377
|
+
width: o.width || 44,
|
|
16378
|
+
minWidth: o.width || 44,
|
|
16379
|
+
visible: o.visible !== false,
|
|
16380
|
+
hozAlign: "center",
|
|
16381
|
+
headerHozAlign: "center",
|
|
16382
|
+
headerSort: false,
|
|
16383
|
+
resizable: false,
|
|
16384
|
+
formatter: "rowSelection",
|
|
16385
|
+
titleFormatter: "rowSelection",
|
|
16386
|
+
titleFormatterParams: { rowRange: "active" },
|
|
16387
|
+
cssClass: "TABLE_SELECT_CELL"
|
|
16388
|
+
};
|
|
16389
|
+
}
|
|
16390
|
+
/***************************************************************
|
|
16391
|
+
* What the Tabulator settings need for the column above.
|
|
16392
|
+
* Spread it into the settings object.
|
|
16393
|
+
***************************************************************/
|
|
16394
|
+
function yui_selection_settings() {
|
|
16395
|
+
return { selectableRows: "highlight" };
|
|
16396
|
+
}
|
|
16397
|
+
/***************************************************************
|
|
16398
|
+
* The rows selected right now (never null).
|
|
16399
|
+
***************************************************************/
|
|
16400
|
+
function yui_selected_rows(tabulator) {
|
|
16401
|
+
if (!tabulator || typeof tabulator.getSelectedData !== "function") return [];
|
|
16402
|
+
try {
|
|
16403
|
+
return tabulator.getSelectedData() || [];
|
|
16404
|
+
} catch (e) {
|
|
16405
|
+
return [];
|
|
16406
|
+
}
|
|
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
|
+
}
|
|
16521
|
+
//#endregion
|
|
16320
16522
|
//#region src/treedb_write_plan.js
|
|
16321
16523
|
/***********************************************************************
|
|
16322
16524
|
* treedb_write_plan.js
|
|
@@ -16484,6 +16686,7 @@ var attrs_table$5 = [
|
|
|
16484
16686
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16485
16687
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
16486
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"),
|
|
16487
16690
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
16488
16691
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
16489
16692
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
@@ -16502,6 +16705,7 @@ var attrs_table$5 = [
|
|
|
16502
16705
|
}, "Default settings for Tabulator"),
|
|
16503
16706
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
16504
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"),
|
|
16505
16709
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
16506
16710
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
16507
16711
|
(0, _yuneta_gobj_js.SDATA)(_yuneta_gobj_js.data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -16918,6 +17122,15 @@ function build_ui$5(gobj) {
|
|
|
16918
17122
|
style: "margin-top:0px !important;"
|
|
16919
17123
|
}]]
|
|
16920
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
|
+
}
|
|
16921
17134
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
16922
17135
|
if ($table_toolbar instanceof Element) $toolbar_slot.appendChild($table_toolbar);
|
|
16923
17136
|
else $toolbar_slot.appendChild((0, _yuneta_gobj_js.createElement2)(["div", {}]));
|
|
@@ -16926,6 +17139,24 @@ function build_ui$5(gobj) {
|
|
|
16926
17139
|
(0, _yuneta_gobj_js.refresh_language)($container, i18next.t);
|
|
16927
17140
|
}
|
|
16928
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
|
+
/************************************************************
|
|
16929
17160
|
* Destroy UI
|
|
16930
17161
|
************************************************************/
|
|
16931
17162
|
function destroy_ui$2(gobj) {
|
|
@@ -16996,16 +17227,11 @@ function create_tabulator(gobj) {
|
|
|
16996
17227
|
let columns = [];
|
|
16997
17228
|
let with_checkbox = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_checkbox");
|
|
16998
17229
|
let with_radio = (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_radio");
|
|
16999
|
-
if (with_checkbox) columns.push({
|
|
17000
|
-
formatter: "rowSelection",
|
|
17001
|
-
titleFormatter: "rowSelection",
|
|
17230
|
+
if (with_checkbox) columns.push(yui_selection_column({
|
|
17002
17231
|
field: "_check_box_state_",
|
|
17003
|
-
hozAlign: "center",
|
|
17004
|
-
headerHozAlign: "center",
|
|
17005
17232
|
width: 40,
|
|
17006
|
-
visible: false
|
|
17007
|
-
|
|
17008
|
-
});
|
|
17233
|
+
visible: false
|
|
17234
|
+
}));
|
|
17009
17235
|
else if (with_radio) columns.push({
|
|
17010
17236
|
formatter: "rowSelection",
|
|
17011
17237
|
field: "_check_box_state_",
|
|
@@ -17234,7 +17460,9 @@ function create_tabulator(gobj) {
|
|
|
17234
17460
|
}
|
|
17235
17461
|
});
|
|
17236
17462
|
let pkey = desc.pkey || "id";
|
|
17237
|
-
let selectable =
|
|
17463
|
+
let selectable = false;
|
|
17464
|
+
if (with_checkbox) selectable = yui_selection_settings().selectableRows;
|
|
17465
|
+
else if (with_radio) selectable = 1;
|
|
17238
17466
|
let tabulator_settings = (0, _yuneta_gobj_js.json_deep_copy)((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator_settings"));
|
|
17239
17467
|
if ((0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "with_remote_paging")) {
|
|
17240
17468
|
let page_size = (0, _yuneta_gobj_js.gobj_read_integer_attr)(gobj, "page_size") || 200;
|
|
@@ -18118,6 +18346,8 @@ function refuse_if_readonly$2(gobj, event) {
|
|
|
18118
18346
|
* dict. Re-apply it in the new language.
|
|
18119
18347
|
***************************************************************/
|
|
18120
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();
|
|
18121
18351
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
18122
18352
|
if (!tabulator) return 0;
|
|
18123
18353
|
yui_tabulator_relocalize(tabulator, i18next.t);
|
|
@@ -18216,7 +18446,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18216
18446
|
tabulator.showColumn("_check_box_state_");
|
|
18217
18447
|
$button_new_record.removeAttribute("disabled");
|
|
18218
18448
|
$button_paste_record.removeAttribute("disabled");
|
|
18219
|
-
if (tabulator
|
|
18449
|
+
if (yui_selected_rows(tabulator).length) {
|
|
18220
18450
|
$button_delete_record.removeAttribute("disabled");
|
|
18221
18451
|
$button_copy_record.removeAttribute("disabled");
|
|
18222
18452
|
}
|
|
@@ -18231,6 +18461,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18231
18461
|
$button_copy_record.setAttribute("disabled", true);
|
|
18232
18462
|
$button_paste_record.setAttribute("disabled", true);
|
|
18233
18463
|
}
|
|
18464
|
+
render_selection_bar(gobj);
|
|
18234
18465
|
return 0;
|
|
18235
18466
|
}
|
|
18236
18467
|
/************************************************************
|
|
@@ -18274,7 +18505,7 @@ function ac_delete_rows(gobj, event, kw, src) {
|
|
|
18274
18505
|
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
18275
18506
|
let tabulator = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator");
|
|
18276
18507
|
if ((0, _yuneta_gobj_js.json_size)(kw) === 0) {
|
|
18277
|
-
let rows = tabulator
|
|
18508
|
+
let rows = yui_selected_rows(tabulator);
|
|
18278
18509
|
if (!rows.length) {
|
|
18279
18510
|
yui_shell_confirm_ok(yui_shell_of(gobj), "please select some row", {
|
|
18280
18511
|
t: i18next.t,
|
|
@@ -18310,7 +18541,7 @@ function ac_delete_rows(gobj, event, kw, src) {
|
|
|
18310
18541
|
* From internal
|
|
18311
18542
|
************************************************************/
|
|
18312
18543
|
function ac_copy_rows(gobj, event, kw, src) {
|
|
18313
|
-
let rows = (0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator")
|
|
18544
|
+
let rows = yui_selected_rows((0, _yuneta_gobj_js.gobj_read_attr)(gobj, "tabulator"));
|
|
18314
18545
|
if (!rows.length) {
|
|
18315
18546
|
yui_shell_confirm_ok(yui_shell_of(gobj), "please select some row", {
|
|
18316
18547
|
t: i18next.t,
|
|
@@ -18368,7 +18599,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18368
18599
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
18369
18600
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
18370
18601
|
if ($button_delete_record) {
|
|
18371
|
-
if (tabulator
|
|
18602
|
+
if (yui_selected_rows(tabulator).length && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "editable")) {
|
|
18372
18603
|
$button_delete_record.removeAttribute("disabled");
|
|
18373
18604
|
$button_copy_record.removeAttribute("disabled");
|
|
18374
18605
|
} else {
|
|
@@ -18376,6 +18607,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18376
18607
|
$button_copy_record.setAttribute("disabled", true);
|
|
18377
18608
|
}
|
|
18378
18609
|
}
|
|
18610
|
+
render_selection_bar(gobj);
|
|
18379
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);
|
|
18380
18612
|
return 0;
|
|
18381
18613
|
}
|
|
@@ -18388,7 +18620,7 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18388
18620
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
18389
18621
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
18390
18622
|
if ($button_delete_record) {
|
|
18391
|
-
if (tabulator
|
|
18623
|
+
if (yui_selected_rows(tabulator).length && (0, _yuneta_gobj_js.gobj_read_bool_attr)(gobj, "editable")) {
|
|
18392
18624
|
$button_delete_record.removeAttribute("disabled");
|
|
18393
18625
|
$button_copy_record.removeAttribute("disabled");
|
|
18394
18626
|
} else {
|
|
@@ -18396,10 +18628,19 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18396
18628
|
$button_copy_record.setAttribute("disabled", true);
|
|
18397
18629
|
}
|
|
18398
18630
|
}
|
|
18631
|
+
render_selection_bar(gobj);
|
|
18399
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);
|
|
18400
18633
|
return 0;
|
|
18401
18634
|
}
|
|
18402
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
|
+
/************************************************************
|
|
18403
18644
|
* { locale: "es" }
|
|
18404
18645
|
************************************************************/
|
|
18405
18646
|
function ac_change_locale(gobj, event, kw, src) {
|
|
@@ -18876,6 +19117,11 @@ function create_gclass$5(gclass_name) {
|
|
|
18876
19117
|
ac_select_rows,
|
|
18877
19118
|
null
|
|
18878
19119
|
],
|
|
19120
|
+
[
|
|
19121
|
+
"EV_CLEAR_SELECTION",
|
|
19122
|
+
ac_clear_selection,
|
|
19123
|
+
null
|
|
19124
|
+
],
|
|
18879
19125
|
[
|
|
18880
19126
|
"EV_UNSELECT_ROWS",
|
|
18881
19127
|
ac_unselect_rows,
|
|
@@ -18984,6 +19230,7 @@ function create_gclass$5(gclass_name) {
|
|
|
18984
19230
|
["EV_DELETE_ROWS", 0],
|
|
18985
19231
|
["EV_COPY_ROWS", 0],
|
|
18986
19232
|
["EV_PASTE_ROWS", 0],
|
|
19233
|
+
["EV_CLEAR_SELECTION", 0],
|
|
18987
19234
|
["EV_SELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
18988
19235
|
["EV_UNSELECT_ROWS", _yuneta_gobj_js.event_flag_t.EVF_OUTPUT_EVENT],
|
|
18989
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);
|
|
@@ -16312,6 +16314,206 @@ function yui_tabulator_relocalize(table, t) {
|
|
|
16312
16314
|
}
|
|
16313
16315
|
}
|
|
16314
16316
|
//#endregion
|
|
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
|
+
***********************************************************************/
|
|
16352
|
+
/***************************************************************
|
|
16353
|
+
* The checkbox column. Put it FIRST in the column list.
|
|
16354
|
+
*
|
|
16355
|
+
* opts:
|
|
16356
|
+
* field the (virtual) field name, default "_select"
|
|
16357
|
+
* width default 44
|
|
16358
|
+
* visible default true; `false` for a table that reveals
|
|
16359
|
+
* the column only in an edit mode (the treedb topic
|
|
16360
|
+
* table shows it with `showColumn(field)`)
|
|
16361
|
+
*
|
|
16362
|
+
* This is the SELECT-MANY widget. A table that lets you pick ONE
|
|
16363
|
+
* row uses a radio column of its own (`formatter: "rowSelection"`
|
|
16364
|
+
* with no `titleFormatter`, `selectableRows: 1`): the header
|
|
16365
|
+
* checkbox, the count and the bar all mean nothing there.
|
|
16366
|
+
***************************************************************/
|
|
16367
|
+
function yui_selection_column(opts) {
|
|
16368
|
+
let o = opts || {};
|
|
16369
|
+
return {
|
|
16370
|
+
title: "",
|
|
16371
|
+
field: o.field || "_select",
|
|
16372
|
+
width: o.width || 44,
|
|
16373
|
+
minWidth: o.width || 44,
|
|
16374
|
+
visible: o.visible !== false,
|
|
16375
|
+
hozAlign: "center",
|
|
16376
|
+
headerHozAlign: "center",
|
|
16377
|
+
headerSort: false,
|
|
16378
|
+
resizable: false,
|
|
16379
|
+
formatter: "rowSelection",
|
|
16380
|
+
titleFormatter: "rowSelection",
|
|
16381
|
+
titleFormatterParams: { rowRange: "active" },
|
|
16382
|
+
cssClass: "TABLE_SELECT_CELL"
|
|
16383
|
+
};
|
|
16384
|
+
}
|
|
16385
|
+
/***************************************************************
|
|
16386
|
+
* What the Tabulator settings need for the column above.
|
|
16387
|
+
* Spread it into the settings object.
|
|
16388
|
+
***************************************************************/
|
|
16389
|
+
function yui_selection_settings() {
|
|
16390
|
+
return { selectableRows: "highlight" };
|
|
16391
|
+
}
|
|
16392
|
+
/***************************************************************
|
|
16393
|
+
* The rows selected right now (never null).
|
|
16394
|
+
***************************************************************/
|
|
16395
|
+
function yui_selected_rows(tabulator) {
|
|
16396
|
+
if (!tabulator || typeof tabulator.getSelectedData !== "function") return [];
|
|
16397
|
+
try {
|
|
16398
|
+
return tabulator.getSelectedData() || [];
|
|
16399
|
+
} catch (e) {
|
|
16400
|
+
return [];
|
|
16401
|
+
}
|
|
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
|
+
}
|
|
16516
|
+
//#endregion
|
|
16315
16517
|
//#region src/treedb_write_plan.js
|
|
16316
16518
|
/***********************************************************************
|
|
16317
16519
|
* treedb_write_plan.js
|
|
@@ -16479,6 +16681,7 @@ var attrs_table$5 = [
|
|
|
16479
16681
|
SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"),
|
|
16480
16682
|
SDATA(data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
16481
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"),
|
|
16482
16685
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
16483
16686
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
16484
16687
|
SDATA(data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
@@ -16497,6 +16700,7 @@ var attrs_table$5 = [
|
|
|
16497
16700
|
}, "Default settings for Tabulator"),
|
|
16498
16701
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
16499
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"),
|
|
16500
16704
|
SDATA(data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
16501
16705
|
SDATA(data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
16502
16706
|
SDATA(data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -16913,6 +17117,15 @@ function build_ui$5(gobj) {
|
|
|
16913
17117
|
style: "margin-top:0px !important;"
|
|
16914
17118
|
}]]
|
|
16915
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
|
+
}
|
|
16916
17129
|
let $toolbar_slot = $container.querySelector(".toolbar_tabulator_table");
|
|
16917
17130
|
if ($table_toolbar instanceof Element) $toolbar_slot.appendChild($table_toolbar);
|
|
16918
17131
|
else $toolbar_slot.appendChild(createElement2(["div", {}]));
|
|
@@ -16921,6 +17134,24 @@ function build_ui$5(gobj) {
|
|
|
16921
17134
|
refresh_language($container, t);
|
|
16922
17135
|
}
|
|
16923
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
|
+
/************************************************************
|
|
16924
17155
|
* Destroy UI
|
|
16925
17156
|
************************************************************/
|
|
16926
17157
|
function destroy_ui$2(gobj) {
|
|
@@ -16991,16 +17222,11 @@ function create_tabulator(gobj) {
|
|
|
16991
17222
|
let columns = [];
|
|
16992
17223
|
let with_checkbox = gobj_read_bool_attr(gobj, "with_checkbox");
|
|
16993
17224
|
let with_radio = gobj_read_bool_attr(gobj, "with_radio");
|
|
16994
|
-
if (with_checkbox) columns.push({
|
|
16995
|
-
formatter: "rowSelection",
|
|
16996
|
-
titleFormatter: "rowSelection",
|
|
17225
|
+
if (with_checkbox) columns.push(yui_selection_column({
|
|
16997
17226
|
field: "_check_box_state_",
|
|
16998
|
-
hozAlign: "center",
|
|
16999
|
-
headerHozAlign: "center",
|
|
17000
17227
|
width: 40,
|
|
17001
|
-
visible: false
|
|
17002
|
-
|
|
17003
|
-
});
|
|
17228
|
+
visible: false
|
|
17229
|
+
}));
|
|
17004
17230
|
else if (with_radio) columns.push({
|
|
17005
17231
|
formatter: "rowSelection",
|
|
17006
17232
|
field: "_check_box_state_",
|
|
@@ -17229,7 +17455,9 @@ function create_tabulator(gobj) {
|
|
|
17229
17455
|
}
|
|
17230
17456
|
});
|
|
17231
17457
|
let pkey = desc.pkey || "id";
|
|
17232
|
-
let selectable =
|
|
17458
|
+
let selectable = false;
|
|
17459
|
+
if (with_checkbox) selectable = yui_selection_settings().selectableRows;
|
|
17460
|
+
else if (with_radio) selectable = 1;
|
|
17233
17461
|
let tabulator_settings = json_deep_copy(gobj_read_attr(gobj, "tabulator_settings"));
|
|
17234
17462
|
if (gobj_read_bool_attr(gobj, "with_remote_paging")) {
|
|
17235
17463
|
let page_size = gobj_read_integer_attr(gobj, "page_size") || 200;
|
|
@@ -18113,6 +18341,8 @@ function refuse_if_readonly$2(gobj, event) {
|
|
|
18113
18341
|
* dict. Re-apply it in the new language.
|
|
18114
18342
|
***************************************************************/
|
|
18115
18343
|
function ac_language_changed$2(gobj, event, kw, src) {
|
|
18344
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
18345
|
+
if (bar) bar.refresh();
|
|
18116
18346
|
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
18117
18347
|
if (!tabulator) return 0;
|
|
18118
18348
|
yui_tabulator_relocalize(tabulator, t);
|
|
@@ -18211,7 +18441,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18211
18441
|
tabulator.showColumn("_check_box_state_");
|
|
18212
18442
|
$button_new_record.removeAttribute("disabled");
|
|
18213
18443
|
$button_paste_record.removeAttribute("disabled");
|
|
18214
|
-
if (tabulator
|
|
18444
|
+
if (yui_selected_rows(tabulator).length) {
|
|
18215
18445
|
$button_delete_record.removeAttribute("disabled");
|
|
18216
18446
|
$button_copy_record.removeAttribute("disabled");
|
|
18217
18447
|
}
|
|
@@ -18226,6 +18456,7 @@ function ac_edition_mode(gobj, event, kw, src) {
|
|
|
18226
18456
|
$button_copy_record.setAttribute("disabled", true);
|
|
18227
18457
|
$button_paste_record.setAttribute("disabled", true);
|
|
18228
18458
|
}
|
|
18459
|
+
render_selection_bar(gobj);
|
|
18229
18460
|
return 0;
|
|
18230
18461
|
}
|
|
18231
18462
|
/************************************************************
|
|
@@ -18269,7 +18500,7 @@ function ac_delete_rows(gobj, event, kw, src) {
|
|
|
18269
18500
|
if (refuse_if_readonly$2(gobj, event)) return -1;
|
|
18270
18501
|
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
18271
18502
|
if (json_size(kw) === 0) {
|
|
18272
|
-
let rows = tabulator
|
|
18503
|
+
let rows = yui_selected_rows(tabulator);
|
|
18273
18504
|
if (!rows.length) {
|
|
18274
18505
|
yui_shell_confirm_ok(yui_shell_of(gobj), "please select some row", {
|
|
18275
18506
|
t,
|
|
@@ -18305,7 +18536,7 @@ function ac_delete_rows(gobj, event, kw, src) {
|
|
|
18305
18536
|
* From internal
|
|
18306
18537
|
************************************************************/
|
|
18307
18538
|
function ac_copy_rows(gobj, event, kw, src) {
|
|
18308
|
-
let rows = gobj_read_attr(gobj, "tabulator")
|
|
18539
|
+
let rows = yui_selected_rows(gobj_read_attr(gobj, "tabulator"));
|
|
18309
18540
|
if (!rows.length) {
|
|
18310
18541
|
yui_shell_confirm_ok(yui_shell_of(gobj), "please select some row", {
|
|
18311
18542
|
t,
|
|
@@ -18363,7 +18594,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18363
18594
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
18364
18595
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
18365
18596
|
if ($button_delete_record) {
|
|
18366
|
-
if (tabulator
|
|
18597
|
+
if (yui_selected_rows(tabulator).length && gobj_read_bool_attr(gobj, "editable")) {
|
|
18367
18598
|
$button_delete_record.removeAttribute("disabled");
|
|
18368
18599
|
$button_copy_record.removeAttribute("disabled");
|
|
18369
18600
|
} else {
|
|
@@ -18371,6 +18602,7 @@ function ac_select_rows(gobj, event, kw, src) {
|
|
|
18371
18602
|
$button_copy_record.setAttribute("disabled", true);
|
|
18372
18603
|
}
|
|
18373
18604
|
}
|
|
18605
|
+
render_selection_bar(gobj);
|
|
18374
18606
|
if (gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) gobj_publish_event(gobj, event, kw);
|
|
18375
18607
|
return 0;
|
|
18376
18608
|
}
|
|
@@ -18383,7 +18615,7 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18383
18615
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
18384
18616
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
18385
18617
|
if ($button_delete_record) {
|
|
18386
|
-
if (tabulator
|
|
18618
|
+
if (yui_selected_rows(tabulator).length && gobj_read_bool_attr(gobj, "editable")) {
|
|
18387
18619
|
$button_delete_record.removeAttribute("disabled");
|
|
18388
18620
|
$button_copy_record.removeAttribute("disabled");
|
|
18389
18621
|
} else {
|
|
@@ -18391,10 +18623,19 @@ function ac_unselect_rows(gobj, event, kw, src) {
|
|
|
18391
18623
|
$button_copy_record.setAttribute("disabled", true);
|
|
18392
18624
|
}
|
|
18393
18625
|
}
|
|
18626
|
+
render_selection_bar(gobj);
|
|
18394
18627
|
if (gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) gobj_publish_event(gobj, event, kw);
|
|
18395
18628
|
return 0;
|
|
18396
18629
|
}
|
|
18397
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
|
+
/************************************************************
|
|
18398
18639
|
* { locale: "es" }
|
|
18399
18640
|
************************************************************/
|
|
18400
18641
|
function ac_change_locale(gobj, event, kw, src) {
|
|
@@ -18871,6 +19112,11 @@ function create_gclass$5(gclass_name) {
|
|
|
18871
19112
|
ac_select_rows,
|
|
18872
19113
|
null
|
|
18873
19114
|
],
|
|
19115
|
+
[
|
|
19116
|
+
"EV_CLEAR_SELECTION",
|
|
19117
|
+
ac_clear_selection,
|
|
19118
|
+
null
|
|
19119
|
+
],
|
|
18874
19120
|
[
|
|
18875
19121
|
"EV_UNSELECT_ROWS",
|
|
18876
19122
|
ac_unselect_rows,
|
|
@@ -18979,6 +19225,7 @@ function create_gclass$5(gclass_name) {
|
|
|
18979
19225
|
["EV_DELETE_ROWS", 0],
|
|
18980
19226
|
["EV_COPY_ROWS", 0],
|
|
18981
19227
|
["EV_PASTE_ROWS", 0],
|
|
19228
|
+
["EV_CLEAR_SELECTION", 0],
|
|
18982
19229
|
["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
18983
19230
|
["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
18984
19231
|
["EV_SHOW_HOOK_DATA", event_flag_t.EVF_OUTPUT_EVENT],
|
package/package.json
CHANGED
|
@@ -75,6 +75,14 @@ import {attach_clear} from "./yui_inputs.js";
|
|
|
75
75
|
|
|
76
76
|
import {yui_tabulator_lang, yui_tabulator_relocalize} from "./yui_tabulator_i18n.js";
|
|
77
77
|
|
|
78
|
+
import {
|
|
79
|
+
yui_selection_column,
|
|
80
|
+
yui_selection_settings,
|
|
81
|
+
yui_selection_bar,
|
|
82
|
+
yui_selected_rows,
|
|
83
|
+
yui_clear_selection,
|
|
84
|
+
} from "./yui_table_select.js";
|
|
85
|
+
|
|
78
86
|
import {t} from "i18next";
|
|
79
87
|
|
|
80
88
|
import {plan_treedb_writes} from "./treedb_write_plan.js";
|
|
@@ -123,6 +131,7 @@ SDATA(data_type_t.DTP_BOOLEAN, "editable", 0, false, "Edit state"
|
|
|
123
131
|
/*---------------- Selection Mode ----------------*/
|
|
124
132
|
SDATA(data_type_t.DTP_BOOLEAN, "with_checkbox", 0, true, "Auxiliary first column to select rows"),
|
|
125
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"),
|
|
126
135
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_select_rows_event", 0, false, "Broadcast select rows event"),
|
|
127
136
|
SDATA(data_type_t.DTP_BOOLEAN, "broadcast_unselect_rows_event", 0, false, "Broadcast unselect rows event"),
|
|
128
137
|
|
|
@@ -142,6 +151,7 @@ SDATA(data_type_t.DTP_JSON, "tabulator_settings", 0, {
|
|
|
142
151
|
/*---------------- Internal Attributes ----------------*/
|
|
143
152
|
SDATA(data_type_t.DTP_POINTER, "$container", 0, null, "HTML container for UI"),
|
|
144
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"),
|
|
145
155
|
SDATA(data_type_t.DTP_STRING, "table_id", 0, null, "Table div ID"),
|
|
146
156
|
SDATA(data_type_t.DTP_STRING, "toolbar_id", 0, null, "Toolbar ID"),
|
|
147
157
|
SDATA(data_type_t.DTP_STRING, "popup_id", 0, null, "Edit form popup ID"),
|
|
@@ -642,6 +652,21 @@ function build_ui(gobj)
|
|
|
642
652
|
]
|
|
643
653
|
]]
|
|
644
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
|
+
|
|
645
670
|
let $toolbar_slot = $container.querySelector('.toolbar_tabulator_table');
|
|
646
671
|
if($table_toolbar instanceof Element) {
|
|
647
672
|
$toolbar_slot.appendChild($table_toolbar);
|
|
@@ -654,6 +679,28 @@ function build_ui(gobj)
|
|
|
654
679
|
refresh_language($container, t);
|
|
655
680
|
}
|
|
656
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
|
+
|
|
657
704
|
/************************************************************
|
|
658
705
|
* Destroy UI
|
|
659
706
|
************************************************************/
|
|
@@ -748,16 +795,20 @@ function create_tabulator(gobj)
|
|
|
748
795
|
let with_checkbox = gobj_read_bool_attr(gobj, "with_checkbox");
|
|
749
796
|
let with_radio = gobj_read_bool_attr(gobj, "with_radio");
|
|
750
797
|
if(with_checkbox) {
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
798
|
+
/* The SHARED column (yui_table_select.js), not a copy of it: this
|
|
799
|
+
* table is where its two decisions were learned, and it was the one
|
|
800
|
+
* table not applying the second. Its header checkbox took
|
|
801
|
+
* `selectRow(undefined)` -- Tabulator's "every row LOADED", the ones
|
|
802
|
+
* the header filters hide included -- and the button beside it
|
|
803
|
+
* DELETES. It now ticks the active rows, the ones on screen.
|
|
804
|
+
*
|
|
805
|
+
* Still `visible: false` and still 40px wide: this table reveals the
|
|
806
|
+
* column in edit mode (`showColumn`), and the geometry is its own. */
|
|
807
|
+
columns.push(yui_selection_column({
|
|
808
|
+
field: "_check_box_state_", // WARNING _check_box_state_ widely used
|
|
809
|
+
width: 40,
|
|
810
|
+
visible: false
|
|
811
|
+
}));
|
|
761
812
|
} else if(with_radio) {
|
|
762
813
|
columns.push({
|
|
763
814
|
formatter: "rowSelection",
|
|
@@ -1098,7 +1149,12 @@ function create_tabulator(gobj)
|
|
|
1098
1149
|
* (it calls toggleSelect() directly) while disabling click-to-select,
|
|
1099
1150
|
* so opening the edit (yi-pen) form no longer implicitly ticks the
|
|
1100
1151
|
* row. Radio keeps single click-select (its own widget). */
|
|
1101
|
-
let selectable =
|
|
1152
|
+
let selectable = false;
|
|
1153
|
+
if(with_checkbox) {
|
|
1154
|
+
selectable = yui_selection_settings().selectableRows;
|
|
1155
|
+
} else if(with_radio) {
|
|
1156
|
+
selectable = 1; /* pick ONE: the radio's own widget */
|
|
1157
|
+
}
|
|
1102
1158
|
|
|
1103
1159
|
let tabulator_settings = json_deep_copy(gobj_read_attr(gobj, "tabulator_settings"));
|
|
1104
1160
|
|
|
@@ -2420,6 +2476,10 @@ function refuse_if_readonly(gobj, event)
|
|
|
2420
2476
|
***************************************************************/
|
|
2421
2477
|
function ac_language_changed(gobj, event, kw, src)
|
|
2422
2478
|
{
|
|
2479
|
+
let bar = gobj_read_attr(gobj, "selection_bar");
|
|
2480
|
+
if(bar) {
|
|
2481
|
+
bar.refresh(); /* a count composed at render time */
|
|
2482
|
+
}
|
|
2423
2483
|
let tabulator = gobj_read_attr(gobj, "tabulator");
|
|
2424
2484
|
if(!tabulator) {
|
|
2425
2485
|
return 0;
|
|
@@ -2623,7 +2683,7 @@ function ac_edition_mode(gobj, event, kw, src)
|
|
|
2623
2683
|
$button_new_record.removeAttribute("disabled");
|
|
2624
2684
|
$button_paste_record.removeAttribute("disabled");
|
|
2625
2685
|
|
|
2626
|
-
let rows = tabulator
|
|
2686
|
+
let rows = yui_selected_rows(tabulator);
|
|
2627
2687
|
if (rows.length) {
|
|
2628
2688
|
$button_delete_record.removeAttribute("disabled");
|
|
2629
2689
|
$button_copy_record.removeAttribute("disabled");
|
|
@@ -2646,6 +2706,8 @@ function ac_edition_mode(gobj, event, kw, src)
|
|
|
2646
2706
|
$button_paste_record.setAttribute("disabled", true);
|
|
2647
2707
|
}
|
|
2648
2708
|
|
|
2709
|
+
render_selection_bar(gobj);
|
|
2710
|
+
|
|
2649
2711
|
return 0;
|
|
2650
2712
|
}
|
|
2651
2713
|
|
|
@@ -2715,7 +2777,7 @@ function ac_delete_rows(gobj, event, kw, src)
|
|
|
2715
2777
|
/*----------------------------*
|
|
2716
2778
|
* Delete selected rows
|
|
2717
2779
|
*----------------------------*/
|
|
2718
|
-
let rows = tabulator
|
|
2780
|
+
let rows = yui_selected_rows(tabulator);
|
|
2719
2781
|
if (!rows.length) {
|
|
2720
2782
|
yui_shell_confirm_ok(
|
|
2721
2783
|
yui_shell_of(gobj), 'please select some row',
|
|
@@ -2778,7 +2840,7 @@ function ac_copy_rows(gobj, event, kw, src)
|
|
|
2778
2840
|
/*----------------------------*
|
|
2779
2841
|
* Copy selected rows
|
|
2780
2842
|
*----------------------------*/
|
|
2781
|
-
let rows = tabulator
|
|
2843
|
+
let rows = yui_selected_rows(tabulator);
|
|
2782
2844
|
if (!rows.length) {
|
|
2783
2845
|
yui_shell_confirm_ok(
|
|
2784
2846
|
yui_shell_of(gobj), 'please select some row',
|
|
@@ -2875,7 +2937,7 @@ function ac_select_rows(gobj, event, kw, src)
|
|
|
2875
2937
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
2876
2938
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
2877
2939
|
if($button_delete_record) {
|
|
2878
|
-
let selectedRows = tabulator
|
|
2940
|
+
let selectedRows = yui_selected_rows(tabulator);
|
|
2879
2941
|
if (selectedRows.length && gobj_read_bool_attr(gobj, "editable")) {
|
|
2880
2942
|
$button_delete_record.removeAttribute("disabled");
|
|
2881
2943
|
$button_copy_record.removeAttribute("disabled");
|
|
@@ -2885,6 +2947,8 @@ function ac_select_rows(gobj, event, kw, src)
|
|
|
2885
2947
|
}
|
|
2886
2948
|
}
|
|
2887
2949
|
|
|
2950
|
+
render_selection_bar(gobj);
|
|
2951
|
+
|
|
2888
2952
|
if(gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) {
|
|
2889
2953
|
gobj_publish_event(gobj, event, kw);
|
|
2890
2954
|
}
|
|
@@ -2906,7 +2970,7 @@ function ac_unselect_rows(gobj, event, kw, src)
|
|
|
2906
2970
|
let $button_delete_record = $container.querySelector(`.button-delete-record`);
|
|
2907
2971
|
let $button_copy_record = $container.querySelector(`.button-copy-record`);
|
|
2908
2972
|
if($button_delete_record) {
|
|
2909
|
-
let selectedRows = tabulator
|
|
2973
|
+
let selectedRows = yui_selected_rows(tabulator);
|
|
2910
2974
|
if (selectedRows.length && gobj_read_bool_attr(gobj, "editable")) {
|
|
2911
2975
|
$button_delete_record.removeAttribute("disabled");
|
|
2912
2976
|
$button_copy_record.removeAttribute("disabled");
|
|
@@ -2916,7 +2980,10 @@ function ac_unselect_rows(gobj, event, kw, src)
|
|
|
2916
2980
|
}
|
|
2917
2981
|
}
|
|
2918
2982
|
|
|
2983
|
+
render_selection_bar(gobj);
|
|
2984
|
+
|
|
2919
2985
|
// WARNING with radio, there is no unselect event.
|
|
2986
|
+
|
|
2920
2987
|
if(gobj_read_bool_attr(gobj, "broadcast_select_rows_event")) {
|
|
2921
2988
|
gobj_publish_event(gobj, event, kw);
|
|
2922
2989
|
}
|
|
@@ -2924,6 +2991,16 @@ function ac_unselect_rows(gobj, event, kw, src)
|
|
|
2924
2991
|
return 0;
|
|
2925
2992
|
}
|
|
2926
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
|
+
|
|
2927
3004
|
/************************************************************
|
|
2928
3005
|
* { locale: "es" }
|
|
2929
3006
|
************************************************************/
|
|
@@ -3432,6 +3509,7 @@ function create_gclass(gclass_name)
|
|
|
3432
3509
|
["EV_NEW_ROW", ac_new_row, null],
|
|
3433
3510
|
["EV_DELETE_ROWS", ac_delete_rows, null],
|
|
3434
3511
|
["EV_SELECT_ROWS", ac_select_rows, null],
|
|
3512
|
+
["EV_CLEAR_SELECTION", ac_clear_selection, null],
|
|
3435
3513
|
["EV_UNSELECT_ROWS", ac_unselect_rows, null],
|
|
3436
3514
|
["EV_COPY_ROWS", ac_copy_rows, null],
|
|
3437
3515
|
["EV_PASTE_ROWS", ac_paste_rows, null],
|
|
@@ -3470,6 +3548,7 @@ function create_gclass(gclass_name)
|
|
|
3470
3548
|
["EV_DELETE_ROWS", 0],
|
|
3471
3549
|
["EV_COPY_ROWS", 0],
|
|
3472
3550
|
["EV_PASTE_ROWS", 0],
|
|
3551
|
+
["EV_CLEAR_SELECTION", 0],
|
|
3473
3552
|
["EV_SELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3474
3553
|
["EV_UNSELECT_ROWS", event_flag_t.EVF_OUTPUT_EVENT],
|
|
3475
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,44 @@
|
|
|
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
|
+
border: 1px solid var(--bulma-border-weak, #e8eaee);
|
|
251
|
+
border-radius: 3px;
|
|
252
|
+
background-color: transparent;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
256
|
+
.tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
257
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
258
|
+
outline: none;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
262
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
263
|
+
border-color: var(--bulma-border, #3a3f4a);
|
|
264
|
+
color: var(--bulma-text-strong, #f5f6f7);
|
|
265
|
+
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
269
|
+
[data-theme=dark] .tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
270
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
271
|
+
}
|
|
272
|
+
|
|
237
273
|
[data-theme=dark] .tabulator-row.tabulator-selected {
|
|
238
274
|
background-color: var(--bulma-link) !important;
|
|
239
275
|
color: var(--bulma-link-invert) !important;
|
|
@@ -313,9 +349,7 @@
|
|
|
313
349
|
/* same editor fix as [data-theme=dark] above */
|
|
314
350
|
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing input,
|
|
315
351
|
[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 {
|
|
352
|
+
[data-theme=system] .tabulator-row .tabulator-cell.tabulator-editing textarea {
|
|
319
353
|
background-color: var(--bulma-grey-darker, #2b2f38);
|
|
320
354
|
color: var(--bulma-text-strong, #f5f6f7) !important;
|
|
321
355
|
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
@@ -325,6 +359,17 @@
|
|
|
325
359
|
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input::placeholder {
|
|
326
360
|
color: var(--bulma-text-weak, #8a8f98);
|
|
327
361
|
}
|
|
362
|
+
/* same furniture-not-editor rule as [data-theme=dark] above */
|
|
363
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input,
|
|
364
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter select {
|
|
365
|
+
border-color: var(--bulma-border, #3a3f4a);
|
|
366
|
+
color: var(--bulma-text-strong, #f5f6f7);
|
|
367
|
+
caret-color: var(--bulma-text-strong, #f5f6f7);
|
|
368
|
+
}
|
|
369
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter input:focus,
|
|
370
|
+
[data-theme=system] .tabulator .tabulator-header .tabulator-header-filter select:focus {
|
|
371
|
+
border-color: var(--bulma-link, #4a9eff);
|
|
372
|
+
}
|
|
328
373
|
[data-theme=system] .tabulator-row.tabulator-selected {
|
|
329
374
|
background-color: var(--bulma-link) !important;
|
|
330
375
|
color: var(--bulma-link-invert) !important;
|
package/src/yui_table_select.js
CHANGED
|
@@ -38,8 +38,16 @@ import {createElement2, log_error} from "@yuneta/gobj-js";
|
|
|
38
38
|
* The checkbox column. Put it FIRST in the column list.
|
|
39
39
|
*
|
|
40
40
|
* opts:
|
|
41
|
-
* field
|
|
42
|
-
* width
|
|
41
|
+
* field the (virtual) field name, default "_select"
|
|
42
|
+
* width default 44
|
|
43
|
+
* visible default true; `false` for a table that reveals
|
|
44
|
+
* the column only in an edit mode (the treedb topic
|
|
45
|
+
* table shows it with `showColumn(field)`)
|
|
46
|
+
*
|
|
47
|
+
* This is the SELECT-MANY widget. A table that lets you pick ONE
|
|
48
|
+
* row uses a radio column of its own (`formatter: "rowSelection"`
|
|
49
|
+
* with no `titleFormatter`, `selectableRows: 1`): the header
|
|
50
|
+
* checkbox, the count and the bar all mean nothing there.
|
|
43
51
|
***************************************************************/
|
|
44
52
|
function yui_selection_column(opts)
|
|
45
53
|
{
|
|
@@ -49,6 +57,7 @@ function yui_selection_column(opts)
|
|
|
49
57
|
field: o.field || "_select",
|
|
50
58
|
width: o.width || 44,
|
|
51
59
|
minWidth: o.width || 44,
|
|
60
|
+
visible: o.visible !== false,
|
|
52
61
|
hozAlign: "center",
|
|
53
62
|
headerHozAlign: "center",
|
|
54
63
|
headerSort: false,
|