From 188aab1d7d50d375b0c828726bbe71ed009a840f Mon Sep 17 00:00:00 2001 From: Jonathan Druart Date: Thu, 26 Oct 2023 07:31:05 +0200 Subject: [PATCH] Bug 34913: Upgrade dataTables.columFilters.js Signed-off-by: Jonathan Druart Signed-off-by: Martin Renvoize Signed-off-by: Katrin Fischer --- .../plugins/jquery.dataTables.columnFilter.js | 325 +++++++++++++----- 1 file changed, 238 insertions(+), 87 deletions(-) diff --git a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.columnFilter.js b/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.columnFilter.js index f3d7d7714c..fe0182f592 100644 --- a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.columnFilter.js +++ b/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.columnFilter.js @@ -1,9 +1,14 @@ +/** + * Forked from initial Jovan Popovic plugin for column Filter + * This Forked corrects the incompatibility between the last DataTables version (1.10.x) and the plugin. + * + */ /* * File: jquery.dataTables.columnFilter.js -* Version: 1.5.0. +* Version: 1.5.6. * Author: Jovan Popovic * -* Copyright 2011-2012 Jovan Popovic, all rights reserved. +* Copyright 2011-2014 Jovan Popovic, all rights reserved. * * This source file is free software, under either the GPL v2 license or a * BSD style license, as supplied with this software. @@ -96,9 +101,9 @@ } function fnCreateInput(oTable, regex, smart, bIsNumber, iFilterLength, iMaxLenght) { - var sCSSClass = "text_filter"; + var sCSSClass = "text_filter form-control"; if (bIsNumber) - sCSSClass = "number_filter"; + sCSSClass = "number_filter form-control"; label = label.replace(/(^\s*)|(\s*$)/g, ""); var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; @@ -112,7 +117,7 @@ search_init = ''; } - var input = $(''); + var input = $(''); if (iMaxLenght != undefined && iMaxLenght != -1) { input.attr('maxlength', iMaxLenght); } @@ -178,14 +183,14 @@ //var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; th.html(_fnRangeLabelPart(0)); var sFromId = oTable.attr("id") + '_range_from_' + i; - var from = $(''); + var from = $(''); th.append(from); th.append(_fnRangeLabelPart(1)); var sToId = oTable.attr("id") + '_range_to_' + i; - var to = $(''); + var to = $(''); th.append(to); th.append(_fnRangeLabelPart(2)); - th.wrapInner(''); + th.wrapInner(''); var index = i; aiCustomSearch_Indexes.push(i); @@ -241,7 +246,96 @@ } - function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel, bRegex, oSelected) { + + function fnCreateDateRangeInput(oTable) { + + var aoFragments = sRangeFormat.split(/[}{]/); + + th.html(""); + //th.html(_fnRangeLabelPart(0)); + var sFromId = oTable.attr("id") + '_range_from_' + i; + var from = $(''); + from.datepicker(); + //th.append(from); + //th.append(_fnRangeLabelPart(1)); + var sToId = oTable.attr("id") + '_range_to_' + i; + var to = $(''); + //th.append(to); + //th.append(_fnRangeLabelPart(2)); + + for (ti = 0; ti < aoFragments.length; ti++) { + + if (aoFragments[ti] == properties.sDateFromToken) { + th.append(from); + } else { + if (aoFragments[ti] == properties.sDateToToken) { + th.append(to); + } else { + th.append(aoFragments[ti]); + } + } + + + } + + + th.wrapInner(''); + to.datepicker(); + var index = i; + aiCustomSearch_Indexes.push(i); + + + //------------start date range filtering function + + //$.fn.dataTableExt.afnFiltering.push( + oTable.dataTableExt.afnFiltering.push( + function (oSettings, aData, iDataIndex) { + if (oTable.attr("id") != oSettings.sTableId) + return true; + + var dStartDate = from.datepicker("getDate"); + + var dEndDate = to.datepicker("getDate"); + + if (dStartDate == null && dEndDate == null) { + return true; + } + + var dCellDate = null; + try { + if (aData[_fnColumnIndex(index)] == null || aData[_fnColumnIndex(index)] == "") + return false; + dCellDate = $.datepicker.parseDate($.datepicker.regional[""].dateFormat, aData[_fnColumnIndex(index)]); + } catch (ex) { + return false; + } + if (dCellDate == null) + return false; + + + if (dStartDate == null && dCellDate <= dEndDate) { + return true; + } + else if (dStartDate <= dCellDate && dEndDate == null) { + return true; + } + else if (dStartDate <= dCellDate && dCellDate <= dEndDate) { + return true; + } + return false; + } + ); + //------------end date range filtering function + + $('#' + sFromId + ',#' + sToId, th).change(function () { + oTable.fnDraw(); + fnOnFiltered(); + }); + + + } + + function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel, bRegex, oSelected, bMultiselect) { if (aData == null) aData = _fnGetColumnValues(oTable.fnSettings(), iColumn, true, false, true); var index = iColumn; @@ -249,7 +343,10 @@ if (currentFilter == null || currentFilter == "")//Issue 81 currentFilter = oSelected; - var r = ''; + if(bMultiselect) { + r = ''); nTh.html(select); nTh.wrapInner(''); - select.change(function () { - //var val = $(this).val(); - if ($(this).val() != "") { - $(this).removeClass("search_init"); - } else { - $(this).addClass("search_init"); - } - if (bRegex) - oTable.fnFilter($(this).val(), iColumn, bRegex); //Issue 41 - else - oTable.fnFilter(unescape($(this).val()), iColumn); //Issue 25 - fnOnFiltered(); - }); - if (currentFilter != null && currentFilter != "")//Issue 81 - oTable.fnFilter(unescape(currentFilter), iColumn); + + if(bMultiselect) { + select.change(function () { + if ($(this).val() != "") { + $(this).removeClass("search_init"); + } else { + $(this).addClass("search_init"); + } + var selectedOptions = $(this).val(); + var asEscapedFilters = []; + if(selectedOptions==null || selectedOptions==[]){ + var re = '^(.*)$'; + }else{ + $.each( selectedOptions, function( i, sFilter ) { + asEscapedFilters.push( fnRegExpEscape( sFilter ) ); + } ); + var re = '^(' + asEscapedFilters.join('|') + ')$'; + } + + oTable.fnFilter( re, index, true, false ); + }); + } else { + select.change(function () { + //var val = $(this).val(); + if ($(this).val() != "") { + $(this).removeClass("search_init"); + } else { + $(this).addClass("search_init"); + } + if (bRegex) + oTable.fnFilter($(this).val(), iColumn, bRegex); //Issue 41 + else + oTable.fnFilter(unescape($(this).val()), iColumn); //Issue 25 + fnOnFiltered(); + }); + if (currentFilter != null && currentFilter != "")//Issue 81 + oTable.fnFilter(unescape(currentFilter), iColumn); + } } - function fnCreateSelect(oTable, aData, bRegex, oSelected) { + function fnCreateSelect(oTable, aData, bRegex, oSelected, bMultiselect) { var oSettings = oTable.fnSettings(); - if (aData == null && oSettings.sAjaxSource != "" && !oSettings.oFeatures.bServerSide) { + if ( (aData == null || typeof(aData) == 'function' ) && oSettings.sAjaxSource != "" && !oSettings.oFeatures.bServerSide) { // Add a function to the draw callback, which will check for the Ajax data having // been loaded. Use a closure for the individual column elements that are used to // built the column filter, since 'i' and 'th' (etc) are locally "global". oSettings.aoDrawCallback.push({ "fn": (function (iColumn, nTh, sLabel) { - return function () { + return function (oSettings) { // Only rebuild the select on the second draw - i.e. when the Ajax // data has been loaded. if (oSettings.iDraw == 2 && oSettings.sAjaxSource != null && oSettings.sAjaxSource != "" && !oSettings.oFeatures.bServerSide) { - return fnCreateColumnSelect(oTable, null, _fnColumnIndex(iColumn), nTh, sLabel, bRegex, oSelected); //Issue 37 + return fnCreateColumnSelect(oTable, aData && aData(oSettings.aoData, oSettings), _fnColumnIndex(iColumn), nTh, sLabel, bRegex, oSelected, bMultiselect); //Issue 37 } }; })(i, th, label), @@ -314,10 +434,30 @@ }); } // Regardless of the Ajax state, build the select on first pass - fnCreateColumnSelect(oTable, aData, _fnColumnIndex(i), th, label, bRegex, oSelected); //Issue 37 + fnCreateColumnSelect(oTable, typeof(aData) == 'function' ? null: aData, _fnColumnIndex(i), th, label, bRegex, oSelected, bMultiselect); //Issue 37 } + function fnRegExpEscape( sText ) { + return sText.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); + }; + + function fnCreateDropdown(aData) { + var index = i; + var r = ''); + th.html(select); + th.wrapInner(''); + select.find('li').click(function () { + oTable.fnFilter($(this).data('value'), index); + }); + } + + function fnCreateCheckbox(oTable, aData) { if (aData == null) @@ -359,10 +499,11 @@ var uniqueId = oTable.attr("id") + localLabel; var buttonId = "chkBtnOpen" + uniqueId; var checkToggleDiv = uniqueId + "-flt-toggle"; - r += ''; //filter button witch open dialog + r += ''; //filter button witch open dialog r += '
'; //dialog div + + 'title="' + label + '" ' + + 'rel="' + i + '" ' + + 'class="toggle-check ui-widget-content ui-corner-all" style="width: ' + (divWidthToggle) + '%; " >'; //dialog div //r+= '
'; //reset button and its div r += divRowDef; @@ -373,8 +514,16 @@ r += divClose + divRowDef; } + var sLabel = aData[j]; + var sValue = aData[j]; + + if (typeof (aData[j]) == 'object') { + sLabel = aData[j].label; + sValue = aData[j].value; + } + //check button - r += '' + aData[j] + '
'; + r += '' + sLabel + '
'; var checkbox = $(r); th.html(checkbox); @@ -390,7 +539,7 @@ //search = search + ' ' + $(this).val(); //concatenation for selected checks in or if ((index == 0 && resSize == 1) - || (index != 0 && index == resSize - 1)) { + || (index != 0 && index == resSize - 1)) { or = ''; } //trim @@ -400,6 +549,13 @@ }); + + if (search != "") { + $('input:checkbox[name="' + localLabel + '"]').removeClass("search_init"); + } else { + $('input:checkbox[name="' + localLabel + '"]').addClass("search_init"); + } + /* Old code for setting search_init CSS class on checkboxes if any of them is checked for (var jj = 0; jj < iLen; jj++) { if (search != "") { $('#' + aData[jj]).removeClass("search_init"); @@ -407,6 +563,7 @@ $('#' + aData[jj]).addClass("search_init"); } } + */ //execute search oTable.fnFilter(search, index, true, false); @@ -523,20 +680,17 @@ var sFilterRow = "tr"; //Before fix for ColVis if (properties.sPlaceHolder == "head:after") { - - if (!properties.bFiltersAlreadyActivated) { - var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); - //tr.appendTo($(oTable.fnSettings().nTHead)); - if (oTable.fnSettings().bSortCellsTop) { - tr.prependTo($(oTable.fnSettings().nTHead)); - //tr.appendTo($("thead", oTable)); - aoFilterCells = oTable.fnSettings().aoHeader[1]; - } - else { - tr.appendTo($(oTable.fnSettings().nTHead)); - //tr.prependTo($("thead", oTable)); - aoFilterCells = oTable.fnSettings().aoHeader[0]; - } + var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); + //tr.appendTo($(oTable.fnSettings().nTHead)); + if (oTable.fnSettings().bSortCellsTop) { + tr.prependTo($(oTable.fnSettings().nTHead)); + //tr.appendTo($("thead", oTable)); + aoFilterCells = oTable.fnSettings().aoHeader[1]; + } + else { + tr.appendTo($(oTable.fnSettings().nTHead)); + //tr.prependTo($("thead", oTable)); + aoFilterCells = oTable.fnSettings().aoHeader[0]; } sFilterRow = "tr:last"; @@ -544,30 +698,27 @@ } else if (properties.sPlaceHolder == "head:before") { - if (!properties.bFiltersAlreadyActivated) { - if (oTable.fnSettings().bSortCellsTop) { - var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); - tr.appendTo($(oTable.fnSettings().nTHead)); - aoFilterCells = oTable.fnSettings().aoHeader[1]; - } else { - aoFilterCells = oTable.fnSettings().aoHeader[0]; - } - /*else { - //tr.prependTo($("thead", oTable)); - sFilterRow = "tr:first"; - }*/ + if (oTable.fnSettings().bSortCellsTop) { + var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); + tr.appendTo($(oTable.fnSettings().nTHead)); + aoFilterCells = oTable.fnSettings().aoHeader[1]; + } else { + aoFilterCells = oTable.fnSettings().aoHeader[0]; } + /*else { + //tr.prependTo($("thead", oTable)); + sFilterRow = "tr:first"; + }*/ sFilterRow = "tr:first"; + oHost = oTable.fnSettings().nTHead; + } - $(sFilterRow + " th", oHost).each(function (index) { - //$(aoFilterCells).each(function (index) {//fix for ColVis - - var bHeaderHasInput = $(this).find('input').length; - + //$(sFilterRow + " th", oHost).each(function (index) {//bug with ColVis + $(aoFilterCells).each(function (index) {//fix for ColVis i = index; var aoColumn = { type: "text", bRegex: false, @@ -575,20 +726,16 @@ iMaxLenght: -1, iFilterLength: 0 }; - if (properties.aoColumns != null) { if (properties.aoColumns.length < i || properties.aoColumns[i] == null) return; aoColumn = properties.aoColumns[i]; } - if (bHeaderHasInput) - label = $(this).find('input').val(); - else - label = $(this).text(); - //label = $($(this)[0].cell).text(); //Fix for ColVis + //label = $(this).text(); //Before fix for ColVis + label = $($(this)[0].cell).text(); //Fix for ColVis if (aoColumn.sSelector == null) { - th = $($(this)[0]); - //th = $($(this)[0].cell); //Fix for ColVis + //th = $($(this)[0]);//Before fix for ColVis + th = $($(this)[0].cell); //Fix for ColVis } else { th = $(aoColumn.sSelector); @@ -610,7 +757,7 @@ case "select": if (aoColumn.bRegex != true) aoColumn.bRegex = false; - fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex, aoColumn.selected); + fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex, aoColumn.selected, aoColumn.multiple); break; case "number-range": fnCreateRangeInput(oTable); @@ -620,6 +767,10 @@ break; case "checkbox": fnCreateCheckbox(oTable, aoColumn.values); + break; + case "twitter-dropdown": + case "dropdown": + fnCreateDropdown(aoColumn.values); break; case "text": default: @@ -641,27 +792,30 @@ afnSearch_.push(fnSearch_); } - if (oTable.fnSettings().oFeatures.bServerSide) { - var fnServerDataOriginal = oTable.fnSettings().fnServerData; + if (oTable.api().settings().context[0].bAjaxDataGet) { - oTable.fnSettings().fnServerData = function (sSource, aoData, fnCallback) { + var fnServerDataOriginal = oTable.api().settings().ajax; + + oTable.api().settings().ajax = function (data, callback, settings) { for (j = 0; j < aiCustomSearch_Indexes.length; j++) { var index = aiCustomSearch_Indexes[j]; - for (k = 0; k < aoData.length; k++) { - if (aoData[k].name == "sSearch_" + index) - aoData[k].value = afnSearch_[j](); + + for (k = 0; k < data.length; k++) { + if (data[k][searchable] === true) + data[k][search][value] = afnSearch_[j](); } } - aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator }); + // We don't need because we don't trust the user input ;) + //aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator }); if (fnServerDataOriginal != null) { try { - fnServerDataOriginal(sSource, aoData, fnCallback, oTable.fnSettings()); //TODO: See Issue 18 + fnServerDataOriginal(data, callback, settings, oTable.fnSettings()); //TODO: See Issue 18 } catch (ex) { - fnServerDataOriginal(sSource, aoData, fnCallback); + fnServerDataOriginal(data, callback, settings); } } else { @@ -677,7 +831,4 @@ }; - - - })(jQuery);