From 662bb9c848b74542bd3bbf6386ffa309861f713b Mon Sep 17 00:00:00 2001 From: Pedro Amorim Date: Wed, 4 Jun 2025 12:08:28 +0000 Subject: [PATCH] Bug 40013: [ALTERNATIVE WIP] Add 'searchable' option to OPAC table columns This is a WIP of my suggestion. It provides column search inputs for each of the 'searchable': true columns. This provides value to all OPAC tables, as it adds the functionality at the datatables layer. This is a copy paste from the datatables.js in intranet-tmpl, ideally it'd be DRY, but we don't live in an ideal world. More work needs to be done: 1) Clicking on the input sorts the column (it shouldnt) 2) Columns like 'status' ideally would have a dropdown of values, not a text input. 3) Searching on extended_attributes requires additional work so my suggestion for now would be to have 'searchable': false for these cases. --- .../intranet-tmpl/prog/js/ill-list-table.js | 3 +- .../bootstrap/en/modules/opac-illrequests.tt | 5 +- .../opac-tmpl/bootstrap/js/datatables.js | 132 +++++++++++++++++- 3 files changed, 137 insertions(+), 3 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js b/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js index 413b9f9458c..1f185ad4e98 100644 --- a/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js +++ b/koha-tmpl/intranet-tmpl/prog/js/ill-list-table.js @@ -316,6 +316,7 @@ $(document).ready(function () { }, { data: "ill_batch.name", // batch + searchable: true, orderable: false, render: function (data, type, row, meta) { return row.ill_batch @@ -537,7 +538,7 @@ $(document).ready(function () { ], }, table_settings, - null, + 1, additional_filters, undefined, external_filter_nodes diff --git a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt index 20b8fea7627..bb835775ed7 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt +++ b/koha-tmpl/opac-tmpl/bootstrap/en/modules/opac-illrequests.tt @@ -442,6 +442,7 @@ }, { data: 'author', + searchable: false, sortable: false, render: (data, type, row, meta) => { return display_extended_attribute(row, 'author'); @@ -449,6 +450,7 @@ }, { data: 'title', + searchable: false, sortable: false, render: (data, type, row, meta) => { return display_extended_attribute(row, 'title'); @@ -460,6 +462,7 @@ }, { data: 'type', + searchable: false, sortable: false, render: (data, type, row, meta) => { return display_extended_attribute(row, 'type'); @@ -494,7 +497,7 @@ }, } ] - }); + }, undefined, 1, undefined, undefined); $("#backend-dropdown-options").removeClass("nojs"); [% IF services_json.length > 0 %] var services = [% services_json | $raw %]; diff --git a/koha-tmpl/opac-tmpl/bootstrap/js/datatables.js b/koha-tmpl/opac-tmpl/bootstrap/js/datatables.js index 114dfcd22a2..43326dfc891 100644 --- a/koha-tmpl/opac-tmpl/bootstrap/js/datatables.js +++ b/koha-tmpl/opac-tmpl/bootstrap/js/datatables.js @@ -587,7 +587,8 @@ function _dt_visibility(table_settings, table_dt) { options = {}, table_settings = undefined, add_filters, - default_filters + default_filters, + filters_options ) { // Early return if the node does not exist if (!this.length) return; @@ -666,6 +667,16 @@ function _dt_visibility(table_settings, table_dt) { var table_dt = table.DataTable(); + if (add_filters) { + _dt_add_filters(this, table_dt, filters_options); + } + + table_dt.on("column-visibility.dt", function () { + if (add_filters) { + _dt_add_filters(this, table_dt, filters_options); + } + }); + table_dt.on("search.dt", function (e, settings) { // When the DataTables search function is triggered, // enable or disable the "Clear filter" button based on @@ -688,4 +699,123 @@ function _dt_visibility(table_settings, table_dt) { return table; }; + + function _dt_add_filters(table_node, table_dt, filters_options = {}) { + if (!$(table_node).length) return; + + $(table_node).find("thead tr:eq(1)").remove(); // Remove if one exists already + $(table_node) + .find("thead tr") + .clone() + .appendTo($(table_node).find("thead")); + + let visibility = table_dt.columns().visible(); + let columns = table_dt.settings()[0].aoColumns; + table_dt.columns().every(function () { + var column = this; + let i = column.index(); + var visible_i = table_dt.column.index("fromData", i); + let th = $(table_node).find( + "thead tr:eq(1) th:eq(%s)".format(visible_i) + ); + var is_searchable = table_dt.settings()[0].aoColumns[i].bSearchable; + $(this) + .removeClass("sorting") + .removeClass("sorting_asc") + .removeClass("sorting_desc"); + $(this).data("th-id", i); + if (is_searchable || $(this).data("filter") || filters_options[i]) { + let input_type = "input"; + let existing_search = column.search(); + if ($(th).data("filter") || filters_options.hasOwnProperty(i)) { + input_type = "select"; + let filter_type = $(th).data("filter"); + let select = $( + ''.format( + existing_search + ) + ); + } else { + var search_title = __("%s search").format(title); + $(th).html( + ''.format( + search_title + ) + ); + } + } + } else { + $(th).html(""); + } + }); + _dt_add_delay_filters(table_dt, table_node); + table_dt.fixedHeader?.adjust(); + } + + function _dt_add_delay_filters(table_dt, table_node) { + let delay_ms = 500; + + let col_input_search = DataTable.util.debounce(function (i, val) { + table_dt.column(i).search(val).draw(); + }, delay_ms); + let col_select_search = DataTable.util.debounce(function (i, val) { + table_dt.column(i).search(val, true, false).draw(); + }, delay_ms); + + $(table_node) + .find("thead tr:eq(1) th") + .each(function (visible_i) { + var i = table_dt.column.index("fromVisible", visible_i); + $(this) + .find("input") + .unbind() + .bind("keyup change", function (e) { + if (e.keyCode === undefined) return; + col_input_search(i, this.value); + }); + + $(this) + .find("select") + .unbind() + .bind("keyup change", function () { + let value = this.value.length + ? "^" + this.value + "$" + : ""; + col_select_search(i, this.value); + }); + }); + } })(jQuery); -- 2.39.5