diff --git a/airtime_mvc/application/controllers/LibraryController.php b/airtime_mvc/application/controllers/LibraryController.php
index 32db3e06b..d1b48f371 100644
--- a/airtime_mvc/application/controllers/LibraryController.php
+++ b/airtime_mvc/application/controllers/LibraryController.php
@@ -37,6 +37,7 @@ class LibraryController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
+ $this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/utilities/utilities.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
diff --git a/airtime_mvc/application/controllers/ScheduleController.php b/airtime_mvc/application/controllers/ScheduleController.php
index 5494d6d0b..755781e45 100644
--- a/airtime_mvc/application/controllers/ScheduleController.php
+++ b/airtime_mvc/application/controllers/ScheduleController.php
@@ -74,6 +74,7 @@ class ScheduleController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.TableTools.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
+ $this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($this->view->baseUrl('/js/airtime/library/events/library_showbuilder.js?'.$CC_CONFIG['airtime_version']),'text/javascript');
diff --git a/airtime_mvc/application/controllers/ShowbuilderController.php b/airtime_mvc/application/controllers/ShowbuilderController.php
index 666a06c2f..6f02a1467 100644
--- a/airtime_mvc/application/controllers/ShowbuilderController.php
+++ b/airtime_mvc/application/controllers/ShowbuilderController.php
@@ -50,6 +50,7 @@ class ShowbuilderController extends Zend_Controller_Action
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColVis.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.ColReorder.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.FixedColumns.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
+ $this->view->headScript()->appendFile($baseUrl.'/js/datatables/plugin/dataTables.columnFilter.js?'.$CC_CONFIG['airtime_version'], 'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/blockui/jquery.blockUI.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
$this->view->headScript()->appendFile($baseUrl.'/js/airtime/buttons/buttons.js?'.$CC_CONFIG['airtime_version'],'text/javascript');
diff --git a/airtime_mvc/application/models/Datatables.php b/airtime_mvc/application/models/Datatables.php
index c4ec7df35..5989a0d83 100644
--- a/airtime_mvc/application/models/Datatables.php
+++ b/airtime_mvc/application/models/Datatables.php
@@ -2,12 +2,74 @@
class Application_Model_Datatables
{
+ private static function buildWhereClauseForAdvancedSearch($dbname2searchTerm)
+ {
+ $where = array();
+ foreach ($dbname2searchTerm as $dbname=>$term) {
+ $isRange = false;
+ if (strstr($term, '~')) {
+ $info = explode('~', $term);
+ $input1 = isset($info[0])?$info[0]:null;
+ $input2 = isset($info[1])?$info[1]:null;
+ $isRange = true;
+ } else {
+ $input1 = $term;
+ }
+
+ if ($isRange) {
+ $sub = array();
+ if ($input1 != null) {
+ $sub[] = $dbname." >= '".$input1."'";
+ }
+ if ($input2 != null) {
+ $sub[] = $dbname." <= '".$input2."'";
+ }
+ if (!empty($sub)) {
+ $where[] = "(".implode(' AND ', $sub).")";
+ }
+ } else {
+ if (trim($input1) !== "") {
+ $where[] = $dbname." ILIKE "."'%".$input1."%'";
+ }
+ }
+ }
+ return implode(" AND ", $where);
+ }
/*
* query used to return data for a paginated/searchable datatable.
*/
public static function findEntries($con, $displayColumns, $fromTable, $data, $dataProp = "aaData")
{
+ $librarySetting = Application_Model_Preference::getCurrentLibraryTableSetting();
+
+ // map that maps original column position to db name
+ $current2dbname = array();
+ // array of search terms
+ $orig2searchTerm= array();
+ foreach ($data as $key=>$d) {
+ if (strstr($key, "mDataProp_")) {
+ list($dump, $index) = explode("_", $key);
+ $current2dbname[$index] = $d;
+ } else if (strstr($key, "sSearch_")) {
+ list($dump, $index) = explode("_", $key);
+ $orig2searchTerm[$index] = $d;
+ }
+ }
+ // map that maps current column position to original position
+ $current2orig = $librarySetting['ColReorder'];
+
+ // map that maps dbname to searchTerm
+ $dbname2searchTerm = array();
+ foreach ($current2dbname as $currentPos=>$dbname) {
+ $dbname2searchTerm[$dbname] = $orig2searchTerm[$current2orig[$currentPos]];
+ }
+
$where = array();
+
+ $advancedWhere = self::buildWhereClauseForAdvancedSearch($dbname2searchTerm);
+ if ($advancedWhere != "") {
+ $where[] = $advancedWhere;
+ }
if ($data["sSearch"] !== "") {
$searchTerms = explode(" ", $data["sSearch"]);
diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php
index 60ece9575..8d37df41e 100644
--- a/airtime_mvc/application/models/Preference.php
+++ b/airtime_mvc/application/models/Preference.php
@@ -1099,4 +1099,8 @@ class Application_Model_Preference
return true;
}
}
+
+ public static function getCurrentLibraryTableSetting(){
+ return unserialize(self::getValue("library_datatable"));
+ }
}
diff --git a/airtime_mvc/application/views/scripts/library/library.phtml b/airtime_mvc/application/views/scripts/library/library.phtml
index 9bdb1c387..e0d889f76 100644
--- a/airtime_mvc/application/views/scripts/library/library.phtml
+++ b/airtime_mvc/application/views/scripts/library/library.phtml
@@ -1,2 +1,5 @@
diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js
index 653d11997..baed0bd82 100644
--- a/airtime_mvc/public/js/airtime/library/library.js
+++ b/airtime_mvc/public/js/airtime/library/library.js
@@ -8,6 +8,35 @@ var AIRTIME = (function(AIRTIME) {
chosenItems = {},
visibleChosenItems = {};
+ var criteriaTypes = {
+ 0 : "",
+ "album_title" : "s",
+ "artist_name" : "s",
+ "bit_rate" : "n",
+ "bpm" : "n",
+ "comments" : "s",
+ "composer" : "s",
+ "conductor" : "s",
+ "utime" : "n",
+ "mtime" : "n",
+ "lptime" : "n",
+ "disc_number" : "n",
+ "genre" : "s",
+ "isrc_number" : "s",
+ "label" : "s",
+ "language" : "s",
+ "length" : "n",
+ "lyricist" : "s",
+ "mood" : "s",
+ "name" : "s",
+ "orchestra" : "s",
+ "rating" : "n",
+ "sample_rate" : "n",
+ "track_title" : "s",
+ "track_num" : "n",
+ "year" : "n"
+ };
+
if (AIRTIME.library === undefined) {
AIRTIME.library = {};
}
@@ -303,11 +332,57 @@ var AIRTIME = (function(AIRTIME) {
$el.removeClass("ui-state-hover");
}
});
-
+
+ var colReorderMap = new Array();
+
$libTable = $libContent.find("table");
var tableHeight = $libContent.height() - 130;
+ function setColumnFilter(oTable){
+ var aoCols = oTable.fnSettings().aoColumns;
+ var colsForAdvancedSearch = new Array();
+ var advanceSearchDiv = $("div#advanced_search");
+ advanceSearchDiv.empty();
+ $.each(aoCols, function(i,ele){
+ if (ele.bSearchable) {
+ var currentColId = ele._ColReorder_iOrigCol;
+ if (ele.bVisible) {
+ advanceSearchDiv.append("
"+ele.sTitle+" :
");
+ } else {
+ advanceSearchDiv.append("
"+ele.sTitle+" :
");
+ }
+ if (criteriaTypes[ele.mDataProp] == "s") {
+ var obj = { sSelector: "#"+ele.mDataProp }
+ } else {
+ var obj = { sSelector: "#"+ele.mDataProp, type: "number-range" }
+ }
+ colsForAdvancedSearch.push(obj);
+ } else {
+ colsForAdvancedSearch.push(null);
+ }
+ });
+
+ oTable.columnFilter({
+ aoColumns: colsForAdvancedSearch,
+ bUseColVis: true,
+ sPlaceHolder: "head:before"
+ }
+ );
+ }
+
+ function setFilterElement(iColumn, bVisible){
+ var actualId = colReorderMap[iColumn];
+ var selector = "div#advanced_search_col_"+actualId;
+ if (bVisible) {
+ $(selector).show();
+ } else {
+ $(selector).hide();
+ }
+ }
+
+ var currentColOrder = new Array();
+
oTable = $libTable.dataTable( {
//put hidden columns at the top to insure they can never be visible on the table through column reordering.
@@ -323,19 +398,19 @@ var AIRTIME = (function(AIRTIME) {
/* Length */ {"sTitle": "Length", "mDataProp": "length", "sClass": "library_length", "sWidth": "80px"},
/* Upload Time */ {"sTitle": "Uploaded", "mDataProp": "utime", "sClass": "library_upload_time", "sWidth": "125px"},
/* Last Modified */ {"sTitle": "Last Modified", "mDataProp": "mtime", "bVisible": false, "sClass": "library_modified_time", "sWidth": "125px"},
- /* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bSearchable": false, "bVisible": false, "sClass": "library_track", "sWidth": "65px"},
- /* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bSearchable": false, "bVisible": false, "sClass": "library_mood", "sWidth": "70px"},
- /* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bSearchable": false, "bVisible": false, "sClass": "library_bpm", "sWidth": "50px"},
- /* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bSearchable": false, "bVisible": false, "sClass": "library_composer", "sWidth": "150px"},
- /* Website */ {"sTitle": "Website", "mDataProp": "info_url", "bSearchable": false, "bVisible": false, "sClass": "library_url", "sWidth": "150px"},
- /* Bit Rate */ {"sTitle": "Bit Rate", "mDataProp": "bit_rate", "bSearchable": false, "bVisible": false, "sClass": "library_bitrate", "sWidth": "80px"},
- /* Sample Rate */ {"sTitle": "Sample", "mDataProp": "sample_rate", "bSearchable": false, "bVisible": false, "sClass": "library_sr", "sWidth": "80px"},
- /* ISRC Number */ {"sTitle": "ISRC", "mDataProp": "isrc_number", "bSearchable": false, "bVisible": false, "sClass": "library_isrc", "sWidth": "150px"},
- /* Encoded */ {"sTitle": "Encoded", "mDataProp": "encoded_by", "bSearchable": false, "bVisible": false, "sClass": "library_encoded", "sWidth": "150px"},
- /* Label */ {"sTitle": "Label", "mDataProp": "label", "bSearchable": false, "bVisible": false, "sClass": "library_label", "sWidth": "125px"},
- /* Copyright */ {"sTitle": "Copyright", "mDataProp": "copyright", "bSearchable": false, "bVisible": false, "sClass": "library_copyright", "sWidth": "125px"},
- /* Mime */ {"sTitle": "Mime", "mDataProp": "mime", "bSearchable": false, "bVisible": false, "sClass": "library_mime", "sWidth": "80px"},
- /* Language */ {"sTitle": "Language", "mDataProp": "language", "bSearchable": false, "bVisible": false, "sClass": "library_language", "sWidth": "125px"}
+ /* Track Number */ {"sTitle": "Track", "mDataProp": "track_number", "bVisible": false, "sClass": "library_track", "sWidth": "65px"},
+ /* Mood */ {"sTitle": "Mood", "mDataProp": "mood", "bVisible": false, "sClass": "library_mood", "sWidth": "70px"},
+ /* BPM */ {"sTitle": "BPM", "mDataProp": "bpm", "bVisible": false, "sClass": "library_bpm", "sWidth": "50px"},
+ /* Composer */ {"sTitle": "Composer", "mDataProp": "composer", "bVisible": false, "sClass": "library_composer", "sWidth": "150px"},
+ /* Website */ {"sTitle": "Website", "mDataProp": "info_url", "bVisible": false, "sClass": "library_url", "sWidth": "150px"},
+ /* Bit Rate */ {"sTitle": "Bit Rate", "mDataProp": "bit_rate", "bVisible": false, "sClass": "library_bitrate", "sWidth": "80px"},
+ /* Sample Rate */ {"sTitle": "Sample", "mDataProp": "sample_rate", "bVisible": false, "sClass": "library_sr", "sWidth": "80px"},
+ /* ISRC Number */ {"sTitle": "ISRC", "mDataProp": "isrc_number", "bVisible": false, "sClass": "library_isrc", "sWidth": "150px"},
+ /* Encoded */ {"sTitle": "Encoded", "mDataProp": "encoded_by", "bVisible": false, "sClass": "library_encoded", "sWidth": "150px"},
+ /* Label */ {"sTitle": "Label", "mDataProp": "label", "bVisible": false, "sClass": "library_label", "sWidth": "125px"},
+ /* Copyright */ {"sTitle": "Copyright", "mDataProp": "copyright", "bVisible": false, "sClass": "library_copyright", "sWidth": "125px"},
+ /* Mime */ {"sTitle": "Mime", "mDataProp": "mime", "bVisible": false, "sClass": "library_mime", "sWidth": "80px"},
+ /* Language */ {"sTitle": "Language", "mDataProp": "language", "bVisible": false, "sClass": "library_language", "sWidth": "125px"}
],
"bProcessing": true,
@@ -350,15 +425,15 @@ var AIRTIME = (function(AIRTIME) {
delete oData.aoSearchCols;
},
"fnStateSave": function (oSettings, oData) {
-
localStorage.setItem('datatables-library', JSON.stringify(oData));
-
$.ajax({
url: "/usersettings/set-library-datatable",
type: "POST",
data: {settings : oData, format: "json"},
dataType: "json"
});
+
+ colReorderMap = oData.ColReorder;
},
"fnStateLoad": function fnLibStateLoad(oSettings) {
var settings = localStorage.getItem('datatables-library');
@@ -371,7 +446,7 @@ var AIRTIME = (function(AIRTIME) {
var i,
length,
a = oData.abVisCols;
-
+
//putting serialized data back into the correct js type to make
//sure everything works properly.
for (i = 0, length = a.length; i < length; i++) {
@@ -386,7 +461,7 @@ var AIRTIME = (function(AIRTIME) {
a[i] = parseInt(a[i], 10);
}
}
-
+
oData.iEnd = parseInt(oData.iEnd, 10);
oData.iLength = parseInt(oData.iLength, 10);
oData.iStart = parseInt(oData.iStart, 10);
@@ -526,7 +601,8 @@ var AIRTIME = (function(AIRTIME) {
"oColVis": {
"sAlign": "right",
"aiExclude": [0, 1, 2],
- "sSize": "css"
+ "sSize": "css",
+ "fnStateChange": setFilterElement
},
"oColReorder": {
@@ -534,6 +610,7 @@ var AIRTIME = (function(AIRTIME) {
}
});
+ setColumnFilter(oTable);
oTable.fnSetFilteringDelay(350);
$libContent.find(".dataTables_scrolling").css("max-height", tableHeight);
diff --git a/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js
new file mode 100644
index 000000000..4f36c9a71
--- /dev/null
+++ b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js
@@ -0,0 +1,733 @@
+/*
+* File: jquery.dataTables.columnFilter.js
+* Version: 1.4.8.
+* Author: Jovan Popovic
+*
+* Copyright 2011-2012 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.
+*
+* This source file is distributed in the hope that it will be useful, but
+* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+* or FITNESS FOR A PARTICULAR PURPOSE.
+*
+* Parameters:"
+* @sPlaceHolder String Place where inline filtering function should be placed ("tfoot", "thead:before", "thead:after"). Default is "tfoot"
+* @sRangeSeparator String Separator that will be used when range values are sent to the server-side. Default value is "~".
+* @sRangeFormat string Default format of the From ... to ... range inputs. Default is From {from} to {to}
+* @aoColumns Array Array of the filter settings that will be applied on the columns
+*/
+(function ($) {
+
+
+ $.fn.columnFilter = function (options) {
+
+ var asInitVals, i, label, th;
+
+ //var sTableId = "table";
+ var sRangeFormat = "From {from} to {to}";
+ //Array of the functions that will override sSearch_ parameters
+ var afnSearch_ = new Array();
+ var aiCustomSearch_Indexes = new Array();
+
+ var oFunctionTimeout = null;
+
+ var fnOnFiltered = function () { };
+
+ function _fnGetColumnValues(oSettings, iColumn, bUnique, bFiltered, bIgnoreEmpty) {
+ ///
+ ///Return values in the column
+ ///
+ ///
DataTables settings
+ ///
Id of the column
+ ///
Return only distinct values
+ ///
Return values only from the filtered rows
+ ///
Ignore empty cells
+
+ // check that we have a column id
+ if (typeof iColumn == "undefined") return new Array();
+
+ // by default we only wany unique data
+ if (typeof bUnique == "undefined") bUnique = true;
+
+ // by default we do want to only look at filtered data
+ if (typeof bFiltered == "undefined") bFiltered = true;
+
+ // by default we do not wany to include empty values
+ if (typeof bIgnoreEmpty == "undefined") bIgnoreEmpty = true;
+
+ // list of rows which we're going to loop through
+ var aiRows;
+
+ // use only filtered rows
+ if (bFiltered == true) aiRows = oSettings.aiDisplay;
+ // 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 aData = oTable.fnGetData(iRow);
+ var sValue = aData[iColumn];
+
+ // ignore empty values?
+ if (bIgnoreEmpty == true && sValue.length == 0) continue;
+
+ // ignore unique values?
+ else if (bUnique == true && jQuery.inArray(sValue, asResultData) > -1) continue;
+
+ // else push the value onto the result data array
+ else asResultData.push(sValue);
+ }
+
+ return asResultData.sort();
+ }
+
+ function _fnColumnIndex(iColumnIndex) {
+ if (properties.bUseColVis)
+ return iColumnIndex;
+ else
+ return oTable.fnSettings().oApi._fnVisibleToColumnIndex(oTable.fnSettings(), iColumnIndex);
+ //return iColumnIndex;
+ //return oTable.fnSettings().oApi._fnColumnIndexToVisible(oTable.fnSettings(), iColumnIndex);
+ }
+
+ function fnCreateInput(oTable, regex, smart, bIsNumber, iFilterLength, iMaxLenght) {
+ var sCSSClass = "text_filter";
+ if (bIsNumber)
+ sCSSClass = "number_filter";
+
+ label = label.replace(/(^\s*)|(\s*$)/g, "");
+ var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
+ var search_init = 'search_init ';
+ var inputvalue = label;
+ if (currentFilter != '' && currentFilter != '^') {
+ if (bIsNumber && currentFilter.charAt(0) == '^')
+ inputvalue = currentFilter.substr(1); //ignore trailing ^
+ else
+ inputvalue = currentFilter;
+ search_init = '';
+ }
+
+ 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;
+
+ if (bIsNumber && !oTable.fnSettings().oFeatures.bServerSide) {
+ input.keyup(function () {
+ /* Filter on the column all numbers that starts with the entered value */
+ oTable.fnFilter('^' + this.value, _fnColumnIndex(index), true, false); //Issue 37
+ fnOnFiltered();
+ });
+ } else {
+ input.keyup(function () {
+ if (oTable.fnSettings().oFeatures.bServerSide && iFilterLength != 0) {
+ //If filter length is set in the server-side processing mode
+ //Check has the user entered at least iFilterLength new characters
+
+ var currentFilter = oTable.fnSettings().aoPreSearchCols[index].sSearch;
+ var iLastFilterLength = $(this).data("dt-iLastFilterLength");
+ if (typeof iLastFilterLength == "undefined")
+ iLastFilterLength = 0;
+ var iCurrentFilterLength = this.value.length;
+ if (Math.abs(iCurrentFilterLength - iLastFilterLength) < iFilterLength
+ //&& currentFilter.length == 0 //Why this?
+ ) {
+ //Cancel the filtering
+ return;
+ }
+ else {
+ //Remember the current filter length
+ $(this).data("dt-iLastFilterLength", iCurrentFilterLength);
+ }
+ }
+ /* Filter on the column (the index) of this element */
+ oTable.fnFilter(this.value, _fnColumnIndex(index), regex, smart); //Issue 37
+ fnOnFiltered();
+ });
+ }
+
+ input.focus(function () {
+ if ($(this).hasClass("search_init")) {
+ $(this).removeClass("search_init");
+ this.value = "";
+ }
+ });
+ input.blur(function () {
+ if (this.value == "") {
+ $(this).addClass("search_init");
+ this.value = asInitVals[index];
+ }
+ });
+ }
+
+ function fnCreateRangeInput(oTable) {
+
+ //var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
+ th.html(_fnRangeLabelPart(0));
+ var sFromId = oTable.attr("id") + '_range_from_' + i;
+ var from = $('
');
+ 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 index = i;
+ aiCustomSearch_Indexes.push(i);
+
+
+
+ //------------start range filtering function
+
+
+ /* Custom filtering function which will filter data in column four between two values
+ * Author: Allan Jardine, Modified by Jovan Popovic
+ */
+ //$.fn.dataTableExt.afnFiltering.push(
+ oTable.dataTableExt.afnFiltering.push(
+ 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;
+ if (iMin == "" && iMax == "") {
+ return true;
+ }
+ else if (iMin == "" && iValue <= iMax) {
+ return true;
+ }
+ else if (iMin <= iValue && "" == iMax) {
+ return true;
+ }
+ else if (iMin <= iValue && iValue <= iMax) {
+ return true;
+ }
+ return false;
+ }
+ );
+ //------------end range filtering function
+
+
+
+ $('#' + sFromId + ',#' + sToId, th).keyup(function () {
+
+ var iMin = document.getElementById(sFromId).value * 1;
+ var iMax = document.getElementById(sToId).value * 1;
+ if (iMin != 0 && iMax != 0 && iMin > iMax)
+ return;
+
+ oTable.fnDraw();
+ fnOnFiltered();
+ });
+
+
+ }
+
+
+ function fnCreateDateRangeInput(oTable) {
+ 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));
+ 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) {
+ if (aData == null)
+ aData = _fnGetColumnValues(oTable.fnSettings(), iColumn, true, false, true);
+ var index = iColumn;
+ var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch;
+
+ var r = '
' + sLabel + ' ';
+ var j = 0;
+ var iLen = aData.length;
+ for (j = 0; j < iLen; j++) {
+ if (typeof (aData[j]) != 'object') {
+ var selected = '';
+ if (escape(aData[j]) == currentFilter || escape(aData[j]) == escape(currentFilter)) selected = 'selected '
+ r += '' + aData[j] + ' ';
+ }
+ else {
+ var selected = '';
+ if (bRegex) {
+ //Do not escape values if they are explicitely set to avoid escaping special characters in the regexp
+ if (aData[j].value == currentFilter) selected = 'selected ';
+ r += '' + aData[j].label + ' ';
+ } else {
+ if (escape(aData[j].value) == currentFilter) selected = 'selected ';
+ r += '' + aData[j].label + ' ';
+ }
+ }
+ }
+
+ var select = $(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();
+ });
+ }
+
+ function fnCreateSelect(oTable, aData, bRegex) {
+ var oSettings = oTable.fnSettings();
+ if (aData == null && 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 () {
+ // 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); //Issue 37
+ }
+ };
+ })(i, th, label),
+ "sName": "column_filter_" + i
+ });
+ }
+ // Regardless of the Ajax state, build the select on first pass
+ fnCreateColumnSelect(oTable, aData, _fnColumnIndex(i), th, label, bRegex); //Issue 37
+
+ }
+
+ function fnCreateCheckbox(oTable, aData) {
+
+ if (aData == null)
+ aData = _fnGetColumnValues(oTable.fnSettings(), i, true, true, true);
+ var index = i;
+
+ 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, "_");
+ localLabel = localLabel.replace(/[^a-zA-Z 0-9]+/g, '');
+ //clean the string
+
+ //button label override
+ if (properties.sFilterButtonText != null || properties.sFilterButtonText != undefined) {
+ labelBtn = properties.sFilterButtonText;
+ } else {
+ labelBtn = label;
+ }
+
+ var relativeDivWidthToggleSize = 10;
+ var numRow = 12; //numero di checkbox per colonna
+ var numCol = Math.floor(iLen / numRow);
+ if (iLen % numRow > 0) {
+ numCol = numCol + 1;
+ };
+
+ //count how many column should be generated and split the div size
+ var divWidth = 100 / numCol - 2;
+
+ var divWidthToggle = relativeDivWidthToggleSize * numCol;
+
+ if (numCol == 1) {
+ divWidth = 20;
+ }
+
+ var divRowDef = '
';
+ var divClose = '
';
+
+ var uniqueId = oTable.attr("id") + localLabel;
+ var buttonId = "chkBtnOpen" + uniqueId;
+ var checkToggleDiv = uniqueId + "-flt-toggle";
+ r += '
' + labelBtn + ' '; //filter button witch open dialog
+ r += '
'; //dialog div
+ //r+= '
reset
'; //reset button and its div
+ r += divRowDef;
+
+ for (j = 0; j < iLen; j++) {
+
+ //if last check close div
+ if (j % numRow == 0 && j != 0) {
+ r += divClose + divRowDef;
+ }
+
+ //check button
+ r += '
' + aData[j] + '
';
+
+ var checkbox = $(r);
+ th.html(checkbox);
+ th.wrapInner('
');
+ //on every checkbox selection
+ checkbox.change(function () {
+
+ var search = '';
+ var or = '|'; //var for select checks in 'or' into the regex
+ var resSize = $('input:checkbox[name="' + localLabel + '"]:checked').size();
+ $('input:checkbox[name="' + localLabel + '"]:checked').each(function (index) {
+
+ //search = search + ' ' + $(this).val();
+ //concatenation for selected checks in or
+ if ((index == 0 && resSize == 1)
+ || (index != 0 && index == resSize - 1)) {
+ or = '';
+ }
+ //trim
+ search = search.replace(/^\s+|\s+$/g, "");
+ search = search + $(this).val() + or;
+ or = '|';
+
+ });
+
+ for (var jj = 0; jj < iLen; jj++) {
+ if (search != "") {
+ $('#' + aData[jj]).removeClass("search_init");
+ } else {
+ $('#' + aData[jj]).addClass("search_init");
+ }
+ }
+
+ //execute search
+ oTable.fnFilter(search, index, true, false);
+ fnOnFiltered();
+ });
+ }
+
+ //filter button
+ $('#' + buttonId).button();
+ //dialog
+ $('#' + checkToggleDiv).dialog({
+ //height: 140,
+ autoOpen: false,
+ //show: "blind",
+ hide: "blind",
+ buttons: [{
+ text: "Reset",
+ click: function () {
+ //$('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
+ $('input:checkbox[name="' + localLabel + '"]:checked').each(function (index3) {
+ $(this).attr('checked', false);
+ $(this).addClass("search_init");
+ });
+ oTable.fnFilter('', index, true, false);
+ fnOnFiltered();
+ return false;
+ }
+ },
+ {
+ text: "Close",
+ click: function () { $(this).dialog("close"); }
+ }
+ ]
+ });
+
+
+ $('#' + buttonId).click(function () {
+
+ $('#' + checkToggleDiv).dialog('open');
+ var target = $(this);
+ $('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
+ at: 'bottom',
+ of: target
+ });
+
+ return false;
+ });
+
+ var fnOnFilteredCurrent = fnOnFiltered;
+
+ fnOnFiltered = function () {
+ var target = $('#' + buttonId);
+ $('#' + checkToggleDiv).dialog("widget").position({ my: 'top',
+ at: 'bottom',
+ of: target
+ });
+ fnOnFilteredCurrent();
+ };
+ //reset
+ /*
+ $('#'+buttonId+"Reset").button();
+ $('#'+buttonId+"Reset").click(function(){
+ $('#'+buttonId).removeClass("filter_selected"); //LM remove border if filter selected
+ $('input:checkbox[name="'+localLabel+'"]:checked').each(function(index3) {
+ $(this).attr('checked', false);
+ $(this).addClass("search_init");
+ });
+ oTable.fnFilter('', index, true, false);
+ return false;
+ });
+ */
+ }
+
+
+
+
+ function _fnRangeLabelPart(iPlace) {
+ switch (iPlace) {
+ case 0:
+ return sRangeFormat.substring(0, sRangeFormat.indexOf("{from}"));
+ case 1:
+ return sRangeFormat.substring(sRangeFormat.indexOf("{from}") + 6, sRangeFormat.indexOf("{to}"));
+ default:
+ return sRangeFormat.substring(sRangeFormat.indexOf("{to}") + 4);
+ }
+ }
+
+
+
+
+ oTable = this;
+
+ var defaults = {
+ sPlaceHolder: "foot",
+ sRangeSeparator: "~",
+ iFilteringDelay: 500,
+ aoColumns: null,
+ sRangeFormat: "From {from} to {to}"
+ };
+
+ properties = $.extend(defaults, options);
+
+ return this.each(function () {
+
+ if (!oTable.fnSettings().oFeatures.bFilter)
+ return;
+ asInitVals = new Array();
+
+ aoFilterCells = oTable.fnSettings().aoFooter[0];
+
+ var oHost = oTable.fnSettings().nTFoot; //Before fix for ColVis
+ var sFilterRow = "tr"; //Before fix for ColVis
+
+ if (properties.sPlaceHolder == "head:after") {
+ 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";
+ oHost = oTable.fnSettings().nTHead;
+
+ } else if (properties.sPlaceHolder == "head:before") {
+
+ 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) {//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) {
+ if (properties.aoColumns.length < i || properties.aoColumns[i] == null)
+ return;
+ aoColumn = properties.aoColumns[i];
+ }
+ //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
+ }
+ else {
+ th = $(aoColumn.sSelector);
+ if (th.length == 0)
+ th = $($(this)[0].cell);
+ }
+
+ if (aoColumn != null) {
+ 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, aoColumn.iMaxLenght);
+ break;
+ case "select":
+ if (aoColumn.bRegex != true)
+ aoColumn.bRegex = false;
+ fnCreateSelect(oTable, aoColumn.values, aoColumn.bRegex);
+ break;
+ case "number-range":
+ fnCreateRangeInput(oTable);
+ break;
+ case "date-range":
+ fnCreateDateRangeInput(oTable);
+ break;
+ case "checkbox":
+ fnCreateCheckbox(oTable, 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, 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_);
+ }
+
+ if (oTable.fnSettings().oFeatures.bServerSide) {
+
+ var fnServerDataOriginal = oTable.fnSettings().fnServerData;
+
+ oTable.fnSettings().fnServerData = function (sSource, aoData, fnCallback) {
+
+ 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]();
+ }
+ }
+ aoData.push({ "name": "sRangeSeparator", "value": properties.sRangeSeparator });
+
+ if (fnServerDataOriginal != null) {
+ try {
+ fnServerDataOriginal(sSource, aoData, fnCallback, oTable.fnSettings()); //TODO: See Issue 18
+ } catch (ex) {
+ fnServerDataOriginal(sSource, aoData, fnCallback);
+ }
+ }
+ else {
+ $.getJSON(sSource, aoData, function (json) {
+ fnCallback(json)
+ });
+ }
+ };
+
+ }
+
+ });
+
+ };
+
+
+
+
+})(jQuery);
\ No newline at end of file