From ac10947710290d63a5cd0c5a09f70b3ec6ae8ef0 Mon Sep 17 00:00:00 2001 From: Demetris Manikas Date: Wed, 16 Feb 2022 18:03:46 +0200 Subject: [PATCH 1/2] implement colSearch buttons --- js/buttons.colSearch.js | 278 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 278 insertions(+) create mode 100644 js/buttons.colSearch.js diff --git a/js/buttons.colSearch.js b/js/buttons.colSearch.js new file mode 100644 index 00000000..0c3dbf43 --- /dev/null +++ b/js/buttons.colSearch.js @@ -0,0 +1,278 @@ +/*! + * Column searchability buttons for Buttons and DataTables. + * 2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + module.exports = function (root, $) { + if ( ! root ) { + root = window; + } + + if ( ! $ || ! $.fn.dataTable ) { + $ = require('datatables.net')(root, $).$; + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + + return factory( $, root, root.document ); + }; + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + +var getColumnsSearchability = function ( dt, columns ) { + return dt.columns( columns ).indexes().map( function ( idx ) { + return dt.column( idx ).searchable(); + } ).toArray(); +} + +$.extend( DataTable.ext.buttons, { + // A collection of column searchability buttons + searchable: function ( dt, conf ) { + var node = null; + + var _searchableOriginal = getColumnsSearchability( dt, conf.columns ); + + var buttonConf = { + extend: 'collection', + init: function ( dt, n ) { + node = n; + }, + text: function ( dt ) { + return dt.i18n( 'buttons.searchable', 'Column searchability' ); + }, + className: 'buttons-searchable', + buttons: [ { + extend: 'searchableColumnsToggle', + columns: conf.columns, + columnText: conf.columnText, + _searchableOriginal: _searchableOriginal + } ] + }; + + //Rebuild the collection with the new column structure if columns are reordered + dt.on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) { + var buttons = [{ + extend: 'searchableColumnsToggle', + columns: conf.columns, + columnText: conf.columnText, + prefixButtons: conf.prefixButtons, + postfixButtons: conf.postfixButtons, + _searchableOriginal: _searchableOriginal + }]; + dt.button(null, dt.button(null, node).node()).collectionRebuild(buttons); + }); + + return buttonConf; + }, + + // Selected columns with individual buttons - toggle column searchability + searchableColumnsToggle: function ( dt, conf ) { + var allButtons = []; + var prefixButtons; + var postfixButtons; + + var buttons = dt.columns( conf.columns ).indexes().map( function ( idx ) { + return { + extend: 'searchableColumnToggle', + columns: idx, + allColumns: conf.columns, + columnText: conf.columnText + }; + } ).toArray(); + + function addOriginalSearchable (buttons) { + var res = buttons.map( function (config) { + if (config.extend === 'searchableRestore') { + config._searchableOriginal = conf._searchableOriginal; + } + return config; + }) + return res; + } + if (conf.prefixButtons) { + prefixButtons = addOriginalSearchable(conf.prefixButtons); + allButtons.push(...prefixButtons); + } + + allButtons.push(...buttons); + + if (conf.postfixButtons) { + postfixButtons = addOriginalSearchable(conf.postfixButtons); + allButtons.push(...postfixButtons); + } + + return allButtons; + }, + + // Single button to toggle column searchability + searchableColumnToggle: function ( dt, conf ) { + return { + extend: 'columnSearchability', + columns: conf.columns, + allColumns: conf.allColumns, + columnText: conf.columnText + }; + }, + + // Single button to set column searchability + columnSearchability: { + columns: undefined, // column selector + text: function ( dt, button, conf ) { + return conf._columnText( dt, conf ); + }, + className: 'buttons-columnSearchability', + action: function ( e, dt, button, conf ) { + var col = dt.columns( conf.columns ); + var curr = col.searchable(); + var searchable = conf.searchability !== undefined ? + conf.searchability : + ! (curr.length ? curr[0] : false); + var searchableCurrent = getColumnsSearchability( dt, conf.allColumns ); + + var searchableCnt = searchableCurrent.reduce( function (previousValue, currentValue) { + return currentValue ? previousValue + 1 : previousValue; + }, 0); + + // Do not allow the last searchable to get deselected + if ( !searchable && searchableCnt === 1 ) { + return; + } + + var allSearchable = searchableCurrent.every( function(value) { return value === true; }); + //If all columns are searchable then turn the first deselection to clear + select + if (allSearchable && !searchable) { + dt.columns().every( function () { + this.searchable( false, true ); + } ); + col.searchable( true ); + } + else { + col.searchable( searchable ); + } + }, + + init: function ( dt, button, conf ) { + var that = this; + button.attr( 'data-cs-idx', conf.columns ); + dt + .on( 'column-searchability.dt'+conf.namespace, function (e, settings) { + if ( ! settings.bDestroying && settings.nTable == dt.settings()[0].nTable ) { + that.active( dt.column( conf.columns ).searchable() ); + } + } ) + .on( 'column-reorder.dt'+conf.namespace, function (e, settings, details) { + // Button has been removed from the DOM + if ( conf.destroying ) { + return; + } + + if ( dt.columns( conf.columns ).count() !== 1 ) { + return; + } + + // This button controls the same column index but the text for the column has + // changed + that.text( conf._columnText( dt, conf ) ); + + // Since its a different column, we need to check its searchability + that.active( dt.column( conf.columns ).searchable() ); + } ); + + this.active( dt.column( conf.columns ).searchable() ); + }, + destroy: function ( dt, button, conf ) { + dt + .off( 'column-searchability.dt'+conf.namespace ) + .off( 'column-reorder.dt'+conf.namespace ); + }, + + _columnText: function ( dt, conf ) { + // Use DataTables' internal data structure until this is presented + // is a public API. The other option is to use + // `$( column(col).node() ).text()` but the node might not have been + // populated when Buttons is constructed. + var idx = dt.column( conf.columns ).index(); + var title = dt.settings()[0].aoColumns[ idx ].sTitle; + + if (! title) { + title = dt.column(idx).header().innerHTML; + } + + title = title + .replace(/\n/g," ") // remove new lines + .replace(//gi, " ") // replace line breaks with spaces + .replace(//g, "") // remove select tags, including options text + .replace(//g, "") // strip HTML comments + .replace(/<.*?>/g, "") // strip HTML + .replace(/^\s+|\s+$/g,""); // trim + + return conf.columnText ? + conf.columnText( dt, idx, title ) : + title; + } + }, + + searchableRestore: { + className: 'buttons-searchableRestore', + + text: function ( dt ) { + return dt.i18n( 'buttons.searchableRestore', 'Restore searchable' ); + }, + + init: function ( dt, button, conf ) { + if (!conf._searchableOriginal) { + conf._searchableOriginal = getColumnsSearchability( dt , conf.columns ); + } + }, + + action: function ( e, dt, button, conf ) { + var settings = dt.settings()[0]; + dt.columns( conf.columns ).every( function ( i ) { + // Take into account that ColReorder might have disrupted our + // indexes + var idx = dt.colReorder && dt.colReorder.transpose ? + dt.colReorder.transpose( i, 'toOriginal' ) : + i; + + this.searchable( conf._searchableOriginal[ idx ], true ); + } ); + DataTable.ext.internal._fnCallbackFire( settings, null, 'column-searchability', [settings] ); + } + }, + +} ); + +DataTable.Api.registerPlural( 'columns().searchable()', 'column().searchable()', function ( searchable, silent ) { + return this.iterator( 'column', function ( settings, column ) { + var col = settings.aoColumns[ column ]; + if ( searchable === undefined ) { + return col.bSearchable; + } + else { + col.bSearchable = searchable; + if ( !silent ) { + DataTable.ext.internal._fnCallbackFire( settings, null, 'column-searchability', [settings] ); + } + } + } ); +}); + +return DataTable.Buttons; +})); \ No newline at end of file From 852cef8fad8cb54a1d81b06b2b238aefa452c849 Mon Sep 17 00:00:00 2001 From: Demetris Manikas Date: Thu, 17 Feb 2022 09:32:26 +0200 Subject: [PATCH 2/2] fix restore bug --- js/buttons.colSearch.js | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/js/buttons.colSearch.js b/js/buttons.colSearch.js index 0c3dbf43..b80c2e0e 100644 --- a/js/buttons.colSearch.js +++ b/js/buttons.colSearch.js @@ -37,9 +37,11 @@ var DataTable = $.fn.dataTable; var getColumnsSearchability = function ( dt, columns ) { - return dt.columns( columns ).indexes().map( function ( idx ) { - return dt.column( idx ).searchable(); - } ).toArray(); + var columnSearchability = {}; + dt.columns( columns ).indexes().toArray().forEach(function ( val ) { + columnSearchability[val] = dt.column( val ).searchable(); + }); + return columnSearchability; } $.extend( DataTable.ext.buttons, { @@ -144,18 +146,23 @@ $.extend( DataTable.ext.buttons, { var searchable = conf.searchability !== undefined ? conf.searchability : ! (curr.length ? curr[0] : false); - var searchableCurrent = getColumnsSearchability( dt, conf.allColumns ); - var searchableCnt = searchableCurrent.reduce( function (previousValue, currentValue) { - return currentValue ? previousValue + 1 : previousValue; - }, 0); + var currSearchability = getColumnsSearchability( dt, conf.allColumns ); + + var searchableCnt = 0; + + for (const [key, value] of Object.entries(currSearchability)) { + if (value) { + searchableCnt += 1; + } + } // Do not allow the last searchable to get deselected if ( !searchable && searchableCnt === 1 ) { return; } - var allSearchable = searchableCurrent.every( function(value) { return value === true; }); + var allSearchable = searchableCnt === Object.keys(currSearchability).length; //If all columns are searchable then turn the first deselection to clear + select if (allSearchable && !searchable) { dt.columns().every( function () { @@ -238,21 +245,20 @@ $.extend( DataTable.ext.buttons, { init: function ( dt, button, conf ) { if (!conf._searchableOriginal) { - conf._searchableOriginal = getColumnsSearchability( dt , conf.columns ); + conf._searchableOriginal = getColumnsSearchability( dt ); } }, action: function ( e, dt, button, conf ) { var settings = dt.settings()[0]; - dt.columns( conf.columns ).every( function ( i ) { - // Take into account that ColReorder might have disrupted our - // indexes + + for (const [i, searchable] of Object.entries(conf._searchableOriginal)) { var idx = dt.colReorder && dt.colReorder.transpose ? dt.colReorder.transpose( i, 'toOriginal' ) : i; - this.searchable( conf._searchableOriginal[ idx ], true ); - } ); + dt.column( idx ).searchable( searchable, true ); + } DataTable.ext.internal._fnCallbackFire( settings, null, 'column-searchability', [settings] ); } }, @@ -275,4 +281,4 @@ DataTable.Api.registerPlural( 'columns().searchable()', 'column().searchable()', }); return DataTable.Buttons; -})); \ No newline at end of file +}));