From 5d21da1fe33814045ccc072adf191500561beb1c Mon Sep 17 00:00:00 2001 From: Brent McSharry Date: Sat, 12 Apr 2014 23:30:31 +1200 Subject: [PATCH] no html input at top of column annotated display = false --- .../Content/jquery.dataTables.columnFilter.js | 386 +++++++++++------- Mvc.JQuery.Datatables/DataTableConfigVm.cs | 9 +- 2 files changed, 241 insertions(+), 154 deletions(-) diff --git a/Mvc.JQuery.Datatables.Templates/Content/jquery.dataTables.columnFilter.js b/Mvc.JQuery.Datatables.Templates/Content/jquery.dataTables.columnFilter.js index 1ad289a..8445cdb 100644 --- a/Mvc.JQuery.Datatables.Templates/Content/jquery.dataTables.columnFilter.js +++ b/Mvc.JQuery.Datatables.Templates/Content/jquery.dataTables.columnFilter.js @@ -1,9 +1,9 @@ -/* +/* * File: jquery.dataTables.columnFilter.js -* Version: 1.4.1. +* Version: 1.5.6. * Author: Jovan Popovic * -* Copyright 2011 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. @@ -62,28 +62,28 @@ // use only filtered rows if (bFiltered == true) aiRows = oSettings.aiDisplay; - // use all rows + // use all rows else aiRows = oSettings.aiDisplayMaster; // all row numbers // set up data array var asResultData = new Array(); for (var i = 0, c = aiRows.length; i < c; i++) { - iRow = aiRows[i]; + var iRow = aiRows[i]; var aData = oTable.fnGetData(iRow); var sValue = aData[iColumn]; // ignore empty values? if (bIgnoreEmpty == true && sValue.length == 0) continue; - // ignore unique values? + // ignore unique values? else if (bUnique == true && jQuery.inArray(sValue, asResultData) > -1) continue; - // else push the value onto the result data array + // else push the value onto the result data array else asResultData.push(sValue); } - return asResultData; + return asResultData.sort(); } function _fnColumnIndex(iColumnIndex) { @@ -95,10 +95,10 @@ //return oTable.fnSettings().oApi._fnColumnIndexToVisible(oTable.fnSettings(), iColumnIndex); } - function fnCreateInput(oTable, regex, smart, bIsNumber, iFilterLength) { - var sCSSClass = "text_filter"; + function fnCreateInput(oTable, regex, smart, bIsNumber, iFilterLength, iMaxLenght) { + 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,12 +112,16 @@ search_init = ''; } - var input = $(''); + var input = $(''); + if (iMaxLenght != undefined && iMaxLenght != -1) { + input.attr('maxlength', iMaxLenght); + } th.html(input); if (bIsNumber) th.wrapInner(''); else th.wrapInner(''); + asInitVals[i] = label; var index = i; @@ -139,8 +143,8 @@ iLastFilterLength = 0; var iCurrentFilterLength = this.value.length; if (Math.abs(iCurrentFilterLength - iLastFilterLength) < iFilterLength - //&& currentFilter.length == 0 //Why this? - ) { + //&& currentFilter.length == 0 //Why this? + ) { //Cancel the filtering return; } @@ -170,26 +174,18 @@ } function fnCreateRangeInput(oTable) { - var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; - var fromDatePre = ''; - var toDatePre = ''; - if (currentFilter != '' && currentFilter != 'undefined') { - var arrDates = currentFilter.split("~"); - fromDatePre = arrDates[0]; - toDatePre = arrDates[1]; - } - + //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); @@ -206,6 +202,9 @@ function (oSettings, aData, iDataIndex) { if (oTable.attr("id") != oSettings.sTableId) return true; + // Try to handle missing nodes more gracefully + if (document.getElementById(sFromId) == null) + return true; var iMin = document.getElementById(sFromId).value * 1; var iMax = document.getElementById(sToId).value * 1; var iValue = aData[_fnColumnIndex(index)] == "-" ? 0 : aData[_fnColumnIndex(index)] * 1; @@ -244,26 +243,38 @@ function fnCreateDateRangeInput(oTable) { - var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; - var fromDatePre = ''; - var toDatePre = ''; - if (currentFilter != '' && currentFilter != 'undefined') { - var arrDates = currentFilter.split("~"); - fromDatePre = arrDates[0]; - toDatePre = arrDates[1]; - } - th.html(_fnRangeLabelPart(0)); + var aoFragments = sRangeFormat.split(/[}{]/); + + th.html(""); + //th.html(_fnRangeLabelPart(0)); var sFromId = oTable.attr("id") + '_range_from_' + i; - var from = $(''); + var from = $(''); from.datepicker(); - th.append(from); - th.append(_fnRangeLabelPart(1)); + //th.append(from); + //th.append(_fnRangeLabelPart(1)); var sToId = oTable.attr("id") + '_range_to_' + i; - var to = $(''); - th.append(to); - th.append(_fnRangeLabelPart(2)); - th.wrapInner(''); + 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); @@ -319,56 +330,98 @@ } - function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel) { + function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel, bRegex, oSelected, bMultiselect) { if (aData == null) aData = _fnGetColumnValues(oTable.fnSettings(), iColumn, true, false, true); var index = iColumn; var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; + 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"); - } - oTable.fnFilter(unescape($(this).val()), iColumn); //Issue 37 - fnOnFiltered(); - }); + nTh.wrapInner(''); + + 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) { + 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); //Issue 37 + return fnCreateColumnSelect(oTable, aData && aData(oSettings.aoData, oSettings), _fnColumnIndex(iColumn), nTh, sLabel, bRegex, oSelected, bMultiselect); //Issue 37 } }; })(i, th, label), @@ -376,17 +429,30 @@ }); } // Regardless of the Ajax state, build the select on first pass - fnCreateColumnSelect(oTable, aData, _fnColumnIndex(i), th, label); //Issue 37 - - /* - var fnOnFilteredCurrent = fnOnFiltered; - fnOnFiltered = function(){ - fnCreateColumnSelect(oTable, aData, i, th, label); - fnOnFilteredCurrent(); - };*/ + 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) @@ -396,15 +462,14 @@ var r = '', j, iLen = aData.length; //clean the string - var localLabel = label.replace('%', 'Perc').replace("&", "AND").replace("$", "DOL").replace("£", "STERL").replace("@", "AT").replace(/\s/g, "_"); + var localLabel = label.replace('%', 'Perc').replace("&", "AND").replace("$", "DOL").replace("£", "STERL").replace("@", "AT").replace(/\s/g, "_"); localLabel = localLabel.replace(/[^a-zA-Z 0-9]+/g, ''); //clean the string //button label override + var labelBtn = label; if (properties.sFilterButtonText != null || properties.sFilterButtonText != undefined) { labelBtn = properties.sFilterButtonText; - } else { - labelBtn = label || "filter"; } var relativeDivWidthToggleSize = 10; @@ -429,16 +494,14 @@ 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 //r+= '
'; //reset button and its div r += divRowDef; - var storedValues = oTable.fnSettings().aoPreSearchCols[i].sSearch; - - var previousValues = storedValues ? storedValues.split("|") : []; for (j = 0; j < iLen; j++) { //if last check close div @@ -446,13 +509,20 @@ r += divClose + divRowDef; } - var checked = $.inArray("^" + aData[j] + "$", previousValues) > -1; + 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); - th.wrapInner(''); + th.wrapInner(''); //on every checkbox selection checkbox.change(function () { @@ -474,6 +544,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"); @@ -481,6 +558,7 @@ $('#' + aData[jj]).addClass("search_init"); } } + */ //execute search oTable.fnFilter(search, index, true, false); @@ -495,7 +573,7 @@ //height: 140, autoOpen: false, //show: "blind", - //hide: "blind", + hide: "blind", buttons: [{ text: "Reset", click: function () { @@ -513,7 +591,7 @@ text: "Close", click: function () { $(this).dialog("close"); } } - ] + ] }); @@ -521,8 +599,7 @@ $('#' + checkToggleDiv).dialog('open'); var target = $(this); - $('#' + checkToggleDiv).dialog("widget").position({ - my: 'top', + $('#' + checkToggleDiv).dialog("widget").position({ my: 'top', at: 'bottom', of: target }); @@ -534,8 +611,7 @@ fnOnFiltered = function () { var target = $('#' + buttonId); - $('#' + checkToggleDiv).dialog("widget").position({ - my: 'top', + $('#' + checkToggleDiv).dialog("widget").position({ my: 'top', at: 'bottom', of: target }); @@ -573,57 +649,76 @@ - oTable = this; + var oTable = this; var defaults = { sPlaceHolder: "foot", sRangeSeparator: "~", iFilteringDelay: 500, aoColumns: null, - sRangeFormat: "From {from} to {to}" + sRangeFormat: "From {from} to {to}", + sDateFromToken: "from", + sDateToToken: "to" }; - properties = $.extend(defaults, options); + var properties = $.extend(defaults, options); return this.each(function () { if (!oTable.fnSettings().oFeatures.bFilter) return; + asInitVals = new Array(); + var aoFilterCells = oTable.fnSettings().aoFooter[0]; + + var oHost = oTable.fnSettings().nTFoot; //Before fix for ColVis + var sFilterRow = "tr"; //Before fix for ColVis - asInitVals = new Array(); - var sFilterRow = "tfoot tr"; if (properties.sPlaceHolder == "head:after") { - var tr = $("thead tr:last", oTable).detach(); + var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); + //tr.appendTo($(oTable.fnSettings().nTHead)); if (oTable.fnSettings().bSortCellsTop) { - tr.appendTo($("thead", oTable)); + tr.prependTo($(oTable.fnSettings().nTHead)); + //tr.appendTo($("thead", oTable)); + aoFilterCells = oTable.fnSettings().aoHeader[1]; } else { - tr.prependTo($("thead", oTable)); + tr.appendTo($(oTable.fnSettings().nTHead)); + //tr.prependTo($("thead", oTable)); + aoFilterCells = oTable.fnSettings().aoHeader[0]; } - sFilterRow = "thead tr:last"; + + sFilterRow = "tr:last"; + oHost = oTable.fnSettings().nTHead; + } else if (properties.sPlaceHolder == "head:before") { - var tr = $("thead tr:first", oTable).detach(); - //tr.attr("id", 1); + if (oTable.fnSettings().bSortCellsTop) { - tr.appendTo($("thead", oTable)); - } - else { - tr.prependTo($("thead", oTable)); + var tr = $("tr:first", oTable.fnSettings().nTHead).detach(); + tr.appendTo($(oTable.fnSettings().nTHead)); + aoFilterCells = oTable.fnSettings().aoHeader[1]; + } else { + aoFilterCells = oTable.fnSettings().aoHeader[0]; } - sFilterRow = "thead tr:first"; - } - var tableColumnDefs = oTable.fnSettings().aoColumns; - var row = $(sFilterRow + " th", oTable); - var thIndex = -1; - $(tableColumnDefs).each(function (index) { - i = index; + /*else { + //tr.prependTo($("thead", oTable)); + sFilterRow = "tr:first"; + }*/ + + sFilterRow = "tr:first"; + oHost = oTable.fnSettings().nTHead; - var aoColumn = { - type: "text", + + } + + //$(sFilterRow + " th", oHost).each(function (index) {//bug with ColVis + $(aoFilterCells).each(function (index) {//fix for ColVis + i = index; + var aoColumn = { type: "text", bRegex: false, bSmart: true, + iMaxLenght: -1, iFilterLength: 0 }; if (properties.aoColumns != null) { @@ -631,29 +726,33 @@ return; aoColumn = properties.aoColumns[i]; } - - - if (this.bVisible) { - thIndex++; - } else { - if (aoColumn.sSelector == null) return; //if hidden column and sSelector is empty + //label = $(this).text(); //Before fix for ColVis + label = $($(this)[0].cell).text(); //Fix for ColVis + if (aoColumn.sSelector == null) { + //th = $($(this)[0]);//Before fix for ColVis + th = $($(this)[0].cell); //Fix for ColVis } - th = $(row[thIndex]); - if (aoColumn.sSelector != null) { + else { th = $(aoColumn.sSelector); + if (th.length == 0) + th = $($(this)[0].cell); } - label = th.text(); //"Search by " + $(this).text(); - if (aoColumn != null) { - sRangeFormat = aoColumn.sRangeFormat != null ? aoColumn.sRangeFormat : properties.sRangeFormat; - + if (aoColumn.sRangeFormat != null) + sRangeFormat = aoColumn.sRangeFormat; + else + sRangeFormat = properties.sRangeFormat; switch (aoColumn.type) { + case "null": + break; case "number": - fnCreateInput(oTable, true, false, true, aoColumn.iFilterLength); + fnCreateInput(oTable, true, false, true, aoColumn.iFilterLength, aoColumn.iMaxLenght); break; case "select": - fnCreateSelect(oTable, aoColumn.values); + if (aoColumn.bRegex != true) + aoColumn.bRegex = false; + fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex, aoColumn.selected, aoColumn.multiple); break; case "number-range": fnCreateRangeInput(oTable); @@ -663,24 +762,28 @@ break; case "checkbox": fnCreateCheckbox(oTable, aoColumn.values); + break; + case "twitter-dropdown": + case "dropdown": + fnCreateDropdown(aoColumn.values); break; case "text": default: bRegex = (aoColumn.bRegex == null ? false : aoColumn.bRegex); bSmart = (aoColumn.bSmart == null ? false : aoColumn.bSmart); - fnCreateInput(oTable, bRegex, bSmart, false, aoColumn.iFilterLength); + fnCreateInput(oTable, bRegex, bSmart, false, aoColumn.iFilterLength, aoColumn.iMaxLenght); break; + } } - }); - + for (j = 0; j < aiCustomSearch_Indexes.length; j++) { //var index = aiCustomSearch_Indexes[j]; var fnSearch_ = function () { var id = oTable.attr("id"); return $("#" + id + "_range_from_" + aiCustomSearch_Indexes[j]).val() + properties.sRangeSeparator + $("#" + id + "_range_to_" + aiCustomSearch_Indexes[j]).val() - }; + } afnSearch_.push(fnSearch_); } @@ -694,11 +797,8 @@ var index = aiCustomSearch_Indexes[j]; for (k = 0; k < aoData.length; k++) { - if (aoData[k].name == "sSearch_" + index) { + if (aoData[k].name == "sSearch_" + index) aoData[k].value = afnSearch_[j](); - // Added this line to force the value in - oTable.fnSettings().aoPreSearchCols[index].sSearch = aoData[k].value; - } } } aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator }); @@ -715,24 +815,6 @@ fnCallback(json) }); } - - /* - if (fnServerDataOriginal != null) { - if (properties.iDelay != 0) { - if (oFunctionTimeout != null) - window.clearTimeout(oFunctionTimeout); - oFunctionTimeout = window.setTimeout(function () { - fnServerDataOriginal(sSource, aoData, fnCallback); - }, properties.iDelay); - } else { - fnServerDataOriginal(sSource, aoData, fnCallback); - } - } - else - $.getJSON(sSource, aoData, function (json) { - fnCallback(json) - }); - */ }; } diff --git a/Mvc.JQuery.Datatables/DataTableConfigVm.cs b/Mvc.JQuery.Datatables/DataTableConfigVm.cs index 950911b..fe92947 100644 --- a/Mvc.JQuery.Datatables/DataTableConfigVm.cs +++ b/Mvc.JQuery.Datatables/DataTableConfigVm.cs @@ -27,7 +27,11 @@ public FilterDef(Type t) private void SetDefaultValuesAccordingToColumnType(Type t) { - if (DateTypes.Contains(t)) + if (t==null) + { + type = "null"; + } + else if (DateTypes.Contains(t)) { type = "date-range"; } @@ -299,9 +303,10 @@ public ColumnFilterSettingsVm(DataTableConfigVm vm) public override string ToString() { + var noColumnFilter = new FilterDef(null); this["aoColumns"] = _vm.Columns //.Where(c => c.Visible || c.Filter["sSelector"] != null) - .Select(c => c.Filter).ToArray(); + .Select(c => c.Searchable?c.Filter:noColumnFilter).ToArray(); return new JavaScriptSerializer().Serialize(this); } }