diff --git a/action.php b/action.php
index 2a8eca9..c00df98 100644
--- a/action.php
+++ b/action.php
@@ -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',
+ ];
}
/**
diff --git a/conf/default.php b/conf/default.php
index 20d07fe..fcd60be 100644
--- a/conf/default.php
+++ b/conf/default.php
@@ -7,4 +7,6 @@
$conf['excludedPages'] = '(wiki)';
-$conf['enableForAllTables'] = 0;
\ No newline at end of file
+$conf['enableForAllTables'] = 0;
+$conf['enableColumnFilters'] = 1;
+$conf['columnFiltersPosition'] = 'header';
\ No newline at end of file
diff --git a/conf/metadata.php b/conf/metadata.php
index 87301eb..ac95243 100644
--- a/conf/metadata.php
+++ b/conf/metadata.php
@@ -7,3 +7,6 @@
$meta['excludedPages'] = array('regex');
$meta['enableForAllTables'] = array('onoff');
+$meta['enableColumnFilters'] = array('onoff');
+$meta['columnFiltersPosition'] = array('multichoice', '_choices' => array('header', 'footer'));
+
diff --git a/lang/de/settings.php b/lang/de/settings.php
index 43f5c65..ca26130 100644
--- a/lang/de/settings.php
+++ b/lang/de/settings.php
@@ -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)';
+
diff --git a/lang/en/settings.php b/lang/en/settings.php
index ae28902..9d8b84f 100644
--- a/lang/en/settings.php
+++ b/lang/en/settings.php
@@ -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)';
+
diff --git a/script.js b/script.js
index 6b79473..bc36ef7 100644
--- a/script.js
+++ b/script.js
@@ -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('
');
+
+ // Add filter for each column
+ table.columns().every(function(index) {
+ const column = this;
+ const $th = jQuery(' | ');
+
+ // Create container for input and select
+ const $filterContainer = jQuery('');
+
+ // Create search input for filtering dropdown options
+ const $searchInput = jQuery('');
+
+ // Create select dropdown
+ const $select = jQuery('');
+
+ // 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('').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('');
+ });
+
+ // 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('
');
+ $target_table.append($tfoot);
+ }
+ $tfoot.append($filterRow);
}
}
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..07fbfb0
--- /dev/null
+++ b/style.css
@@ -0,0 +1,80 @@
+/**
+ * DataTables Plugin - Column Filters Styling
+ *
+ * @author Giuseppe Di Terlizzi
+ */
+
+/* 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;
+}