Added Column Filter

This commit is contained in:
Matthias Lotz 2025-12-21 21:48:53 +01:00
parent 479e403b2d
commit dcdc9fe518
7 changed files with 205 additions and 2 deletions

View File

@ -42,6 +42,8 @@ class action_plugin_datatables extends DokuWiki_Action_Plugin
'dom' => 'lBfrtip'
],
'enableForAllTables' => $this->getConf('enableForAllTables'),
'enableColumnFilters' => $this->getConf('enableColumnFilters'),
'columnFiltersPosition' => $this->getConf('columnFiltersPosition'),
];
// find a matching language file
@ -120,6 +122,13 @@ class action_plugin_datatables extends DokuWiki_Action_Plugin
'href' => $style,
];
}
// Add custom plugin CSS for column filters
$event->data['link'][] = [
'type' => 'text/css',
'rel' => 'stylesheet',
'href' => DOKU_BASE . 'lib/plugins/datatables/style.css',
];
}
/**

View File

@ -7,4 +7,6 @@
$conf['excludedPages'] = '(wiki)';
$conf['enableForAllTables'] = 0;
$conf['enableForAllTables'] = 0;
$conf['enableColumnFilters'] = 1;
$conf['columnFiltersPosition'] = 'header';

View File

@ -7,3 +7,6 @@
$meta['excludedPages'] = array('regex');
$meta['enableForAllTables'] = array('onoff');
$meta['enableColumnFilters'] = array('onoff');
$meta['columnFiltersPosition'] = array('multichoice', '_choices' => array('header', 'footer'));

View File

@ -11,3 +11,6 @@
$lang['excludedPages'] = 'Ausgeschlossene Seiten (benutze Regulären Ausdrücke)';
$lang['enableForAllTables'] = 'Aktiviert die Datentabellen für alle "gut formatierte " Tabellen';
$lang['enableLocalization'] = 'Aktiviert die automatische Lokalisierung';
$lang['enableColumnFilters'] = 'Aktiviert Spaltenfilter mit Dropdown und Suchfunktion';
$lang['columnFiltersPosition'] = 'Position der Spaltenfilter (header oder footer)';

View File

@ -10,3 +10,6 @@
$lang['excludedPages'] = 'Excluded pages (insert a regex)';
$lang['enableForAllTables'] = 'Enable DataTables for all "well formatted" tables';
$lang['enableLocalization'] = 'Enable automatic localization';
$lang['enableColumnFilters'] = 'Enable column filters with dropdown and search functionality';
$lang['columnFiltersPosition'] = 'Position of column filters (header or footer)';

105
script.js
View File

@ -48,7 +48,110 @@ jQuery(document).ready(function () {
!jQuery('tbody', $target_table).find('[rowspan], [colspan]').length
) {
$target_table.attr('width', '100%');
$target_table.DataTable(dt_config);
const table = $target_table.DataTable(dt_config);
// Add column filters if enabled
if (JSINFO.plugin.datatables.enableColumnFilters) {
addColumnFilters(table, $target_table);
}
}
}
/**
* Add column filters to DataTable
*
* @param {DataTable} table DataTable instance
* @param {jQuery} $target_table Table jQuery object
*/
function addColumnFilters(table, $target_table) {
const position = JSINFO.plugin.datatables.columnFiltersPosition || 'header';
const $thead = $target_table.find('thead');
// Create filter row
const $filterRow = jQuery('<tr class="dt-column-filters"></tr>');
// Add filter for each column
table.columns().every(function(index) {
const column = this;
const $th = jQuery('<th></th>');
// Create container for input and select
const $filterContainer = jQuery('<div class="dt-filter-container"></div>');
// Create search input for filtering dropdown options
const $searchInput = jQuery('<input type="text" class="dt-filter-search" placeholder="Suchen..." />');
// Create select dropdown
const $select = jQuery('<select class="dt-filter-select"><option value="">Alle anzeigen</option></select>');
// Get unique values from column
const uniqueValues = [];
const uniqueTexts = new Set();
column.data().each(function(d) {
if (d) {
// Extract text content if it contains HTML
const text = jQuery('<div>').html(d).text().trim();
if (text && !uniqueTexts.has(text)) {
uniqueTexts.add(text);
uniqueValues.push(text);
}
}
});
// Sort unique values
uniqueValues.sort();
// Populate select with unique values
uniqueValues.forEach(function(value) {
$select.append('<option value="' + jQuery('<div>').text(value).html() + '">' + value + '</option>');
});
// Filter dropdown options based on search input
$searchInput.on('keyup', function() {
const searchTerm = jQuery(this).val().toLowerCase();
$select.find('option').each(function() {
const optionText = jQuery(this).text().toLowerCase();
if (optionText.indexOf(searchTerm) > -1 || jQuery(this).val() === '') {
jQuery(this).show();
} else {
jQuery(this).hide();
}
});
});
// Filter table when dropdown changes
$select.on('change', function() {
const val = jQuery(this).val();
if (val) {
// Escape special regex characters and search for exact match
const escapedVal = val.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
// Search using regex that matches the text anywhere in the cell
column.search(escapedVal, true, false).draw();
} else {
// Clear search
column.search('').draw();
}
});
// Add elements to container
$filterContainer.append($searchInput);
$filterContainer.append($select);
$th.append($filterContainer);
$filterRow.append($th);
});
// Add filter row to table
if (position === 'header') {
$thead.append($filterRow);
} else {
// Create tfoot if it doesn't exist
let $tfoot = $target_table.find('tfoot');
if ($tfoot.length === 0) {
$tfoot = jQuery('<tfoot></tfoot>');
$target_table.append($tfoot);
}
$tfoot.append($filterRow);
}
}

80
style.css Normal file
View File

@ -0,0 +1,80 @@
/**
* DataTables Plugin - Column Filters Styling
*
* @author Giuseppe Di Terlizzi <giuseppe.diterlizzi@gmail.com>
*/
/* Column filter row styling */
.dt-column-filters th {
padding: 5px !important;
background-color: #f5f5f5;
border-bottom: 2px solid #ddd;
}
/* Filter container */
.dt-filter-container {
display: flex;
flex-direction: column;
gap: 3px;
min-width: 120px;
}
/* Search input styling */
.dt-filter-search {
width: 100%;
padding: 4px 6px;
font-size: 12px;
border: 1px solid #ccc;
border-radius: 3px;
box-sizing: border-box;
background-color: #fff;
}
.dt-filter-search:focus {
outline: none;
border-color: #66afe9;
box-shadow: 0 0 3px rgba(102, 175, 233, 0.5);
}
/* Select dropdown styling */
.dt-filter-select {
width: 100%;
padding: 4px 6px;
font-size: 12px;
border: 1px solid #ccc;
border-radius: 3px;
box-sizing: border-box;
background-color: #fff;
cursor: pointer;
}
.dt-filter-select:focus {
outline: none;
border-color: #66afe9;
box-shadow: 0 0 3px rgba(102, 175, 233, 0.5);
}
/* Responsive adjustments */
@media screen and (max-width: 768px) {
.dt-filter-container {
min-width: 80px;
}
.dt-filter-search,
.dt-filter-select {
font-size: 11px;
padding: 3px 4px;
}
}
/* Theme compatibility - Bootstrap */
.bootstrap3 .dt-filter-search,
.bootstrap3 .dt-filter-select {
height: auto;
}
/* Theme compatibility - jQuery UI */
.dataTables_wrapper.dataTable .dt-filter-search,
.dataTables_wrapper.dataTable .dt-filter-select {
font-family: inherit;
}