diff --git a/airtime_mvc/application/controllers/ApiController.php b/airtime_mvc/application/controllers/ApiController.php index 23ff08d01..bafbb00ea 100644 --- a/airtime_mvc/application/controllers/ApiController.php +++ b/airtime_mvc/application/controllers/ApiController.php @@ -337,6 +337,7 @@ class ApiController extends Zend_Controller_Action $this->_helper->viewRenderer->setNoRender(true); $data = Application_Model_Schedule::getSchedule(); + header("Content-Type: application/json"); echo json_encode($data, JSON_FORCE_OBJECT); } @@ -701,9 +702,12 @@ class ApiController extends Zend_Controller_Action { $request = $this->getRequest(); $dir_id = $request->getParam('dir_id'); + $all = $request->getParam('all'); + + Logging::info("All param is: $all"); $this->view->files = - Application_Model_StoredFile::listAllFiles($dir_id,$all=true); + Application_Model_StoredFile::listAllFiles($dir_id,$all); } public function listAllWatchedDirsAction() diff --git a/airtime_mvc/application/models/Preference.php b/airtime_mvc/application/models/Preference.php index a2f563b11..d157bc9bf 100644 --- a/airtime_mvc/application/models/Preference.php +++ b/airtime_mvc/application/models/Preference.php @@ -31,12 +31,6 @@ class Application_Model_Preference $result = Application_Common_Database::prepareAndExecute($sql, $paramMap, 'column'); - if ($value == "") { - $value = "NULL"; - } else { - $value = "$value"; - } - $paramMap = array(); if ($result == 1) { // result found diff --git a/airtime_mvc/application/models/StoredFile.php b/airtime_mvc/application/models/StoredFile.php index 4f5dcaf49..af14d4af0 100644 --- a/airtime_mvc/application/models/StoredFile.php +++ b/airtime_mvc/application/models/StoredFile.php @@ -51,11 +51,6 @@ class Application_Model_StoredFile "owner_id" => "DbOwnerId" ); - public function __construct() - { - - } - public function getId() { return $this->_file->getDbId(); diff --git a/airtime_mvc/application/models/Webstream.php b/airtime_mvc/application/models/Webstream.php index e634dbd17..87a9157cb 100644 --- a/airtime_mvc/application/models/Webstream.php +++ b/airtime_mvc/application/models/Webstream.php @@ -268,7 +268,6 @@ class Application_Model_Webstream implements Application_Model_LibraryEditable private static function getPlsUrl($url) { $content = self::getUrlData($url); - $ini = parse_ini_string($content, true); if ($ini !== false && isset($ini["playlist"]) && isset($ini["playlist"]["File1"])) { diff --git a/airtime_mvc/public/index.php b/airtime_mvc/public/index.php index 78f94c489..46b97adfc 100644 --- a/airtime_mvc/public/index.php +++ b/airtime_mvc/public/index.php @@ -1,8 +1,12 @@ bootstrap()->run(); } } catch (Exception $e) { + echo $e->getMessage(); Logging::info($e->getMessage()); } diff --git a/airtime_mvc/public/js/airtime/library/library.js b/airtime_mvc/public/js/airtime/library/library.js index 3e82f391d..91e15f878 100644 --- a/airtime_mvc/public/js/airtime/library/library.js +++ b/airtime_mvc/public/js/airtime/library/library.js @@ -480,14 +480,13 @@ var AIRTIME = (function(AIRTIME) { "fnServerData": function ( sSource, aoData, fnCallback ) { var type; - aoData.push( { name: "format", value: "json"} ); //push whether to search files/playlists or all. type = $("#library_display_type").find("select").val(); type = (type === undefined) ? 0 : type; aoData.push( { name: "type", value: type} ); - + $.ajax( { "dataType": 'json', "type": "POST", @@ -971,3 +970,145 @@ function addQtipToSCIcons(){ } }); } + +/* + * This function is called from dataTables.columnFilter.js + */ +function validateAdvancedSearch(divs) { + var valid = true, + fieldName, + fields, + searchTerm = Array(), + searchTermType, + regExpr, + timeRegEx = "\\d{2}[:]([0-5]){1}([0-9]){1}[:]([0-5]){1}([0-9]){1}([.]\\d{1,6})?", + dateRegEx = "\\d{4}[-]\\d{2}[-]\\d{2}?", + integerRegEx = "^\\d+$", + numericRegEx = "^\\d+[.]?\\d*$"; + + searchTerm[0] = ""; + searchTerm[1] = ""; + + $.each(divs, function(i, div){ + fieldName = $(div).children(':nth-child(2)').attr('id'); + fields = $(div).children().find('input'); + searchTermType = validationTypes[fieldName]; + + $.each(fields, function(i, field){ + searchTerm[i] = $(field).val(); + + if (searchTerm[i] !== "") { + + if (searchTermType === "l") { + regExpr = new RegExp("^" +timeRegEx+ "$"); + } else if (searchTermType === "t") { + var pieces = searchTerm[i].split(" "); + if (pieces.length === 2) { + regExpr = new RegExp("^" +dateRegEx+ " " +timeRegEx+ "$"); + } else if (pieces.length === 1) { + regExpr = new RegExp("^" +dateRegEx+ "$"); + } + } else if (searchTermType === "i") { + regExpr = new RegExp(integerRegEx); + } else if (searchTermType === "n") { + regExpr = new RegExp(numericRegEx); + if (searchTerm[i].charAt(0) === "-") { + searchTerm[i] = searchTerm[i].substr(1); + } + } + + //string fields do not need validation + if (searchTermType !== "s") { + valid = regExpr.test(searchTerm[i]); + } + + addRemoveValidationIcons(valid, $(field)); + + /* Empty fields should not have valid/invalid indicator + * Range values are considered valid even if only the + * 'From' value is provided. Therefore, if the 'To' value + * is empty but the 'From' value is not empty we need to + * keep the validation icon on screen. + */ + } else if (searchTerm[0] === "" && searchTerm[1] !== "" || + searchTerm[0] === "" && searchTerm[1] === ""){ + if ($(field).closest('div').children(':last-child').hasClass('checked-icon') || + $(field).closest('div').children(':last-child').hasClass('not-available-icon')) { + $(field).closest('div').children(':last-child').remove(); + } + } + + if (!valid) { + return false; + } + }); + + if (!valid) { + return false; + } + }); + + return valid; +} + +function addRemoveValidationIcons(valid, field) { + var validIndicator = "", + invalidIndicator = ""; + + if (valid) { + if (!field.closest('div').children(':last-child').hasClass('checked-icon')) { + //remove invalid icon before adding valid icon + if (field.closest('div').children(':last-child').hasClass('not-available-icon')) { + field.closest('div').children(':last-child').remove(); + } + field.closest('div').append(validIndicator); + } + } else { + if (!field.closest('div').children(':last-child').hasClass('not-available-icon')) { + //remove valid icon before adding invalid icon + if (field.closest('div').children(':last-child').hasClass('checked-icon')) { + field.closest('div').children(':last-child').remove(); + } + field.closest('div').append(invalidIndicator); + } + } +} + +/* Validation types: + * s => string + * i => integer + * n => numeric (positive/negative, whole/decimals) + * t => timestamp + * l => length + */ +var validationTypes = { + "album_title" : "s", + "artist_name" : "s", + "bit_rate" : "i", + "bpm" : "i", + "comments" : "s", + "composer" : "s", + "conductor" : "s", + "copyright" : "s", + "utime" : "t", + "mtime" : "t", + "lptime" : "t", + "disc_number" : "i", + "genre" : "s", + "isrc_number" : "s", + "label" : "s", + "language" : "s", + "length" : "l", + "lyricist" : "s", + "mood" : "s", + "name" : "s", + "orchestra" : "s", + "owner_id" : "i", + "rating" : "i", + "replay_gain" : "n", + "sample_rate" : "i", + "track_title" : "s", + "track_number" : "i", + "info_url" : "s", + "year" : "i" +}; diff --git a/airtime_mvc/public/js/airtime/library/spl.js b/airtime_mvc/public/js/airtime/library/spl.js index 907078e18..357bf87be 100644 --- a/airtime_mvc/public/js/airtime/library/spl.js +++ b/airtime_mvc/public/js/airtime/library/spl.js @@ -635,7 +635,9 @@ var AIRTIME = (function(AIRTIME){ if (json.error !== undefined) { alert(json.error); } - AIRTIME.playlist.fnOpenPlaylist(json); + if (json.html !== undefined) { + AIRTIME.playlist.fnOpenPlaylist(json); + } setModified(json.modified); if (obj_type == "block") { callback(data, "save"); diff --git a/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README b/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README new file mode 100644 index 000000000..a86836562 --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/AIRTIME_DEV_README @@ -0,0 +1,108 @@ +Before you overwrite dataTables.columnFilter.js, note that we have changed a few lines +in this file. + +Running a diff between the original column filter plugin (dataTables.columnFilter_orig.js) and +our modified one (dataTables.columnFilter.js): + +denise@denise-DX4860:~/airtime/airtime_mvc/public/js/datatables/plugin$ diff -u dataTables.columnFilter_orig.js dataTables.columnFilter.js +--- dataTables.columnFilter_orig.js 2012-09-10 14:26:30.041095663 -0400 ++++ dataTables.columnFilter.js 2012-09-10 17:04:21.017464447 -0400 +@@ -103,7 +103,8 @@ + label = label.replace(/(^\s*)|(\s*$)/g, ""); + var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; + var search_init = 'search_init '; +- var inputvalue = label; ++ //var inputvalue = label; ++ var inputvalue = ''; + if (currentFilter != '' && currentFilter != '^') { + if (bIsNumber && currentFilter.charAt(0) == '^') + inputvalue = currentFilter.substr(1); //ignore trailing ^ +@@ -133,29 +134,32 @@ + }); + } 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); ++ var advSearchFields = $("div#advanced_search").children(':visible'); ++ if(validateAdvancedSearch(advSearchFields)){ ++ 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(); + } +- /* Filter on the column (the index) of this element */ +- oTable.fnFilter(this.value, _fnColumnIndex(index), regex, smart); //Issue 37 +- fnOnFiltered(); + }); + } + +@@ -168,7 +172,8 @@ + input.blur(function () { + if (this.value == "") { + $(this).addClass("search_init"); +- this.value = asInitVals[index]; ++ //this.value = asInitVals[index]; ++ this.value = ""; + } + }); + } +@@ -228,14 +233,16 @@ + + + $('#' + 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(); ++ var advSearchFields = $("div#advanced_search").children(':visible'); ++ if(validateAdvancedSearch(advSearchFields)){ ++ 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(); ++ } + }); + + diff --git a/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js index 4f36c9a71..1bab38a3c 100644 --- a/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js +++ b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter.js @@ -1,733 +1,740 @@ -/* -* 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 = ''); - 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 += ''; //filter button witch open dialog - r += '
'; //dialog div - //r+= '
'; //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) - }); - } - }; - - } - - }); - - }; - - - - +/* +* 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; + var inputvalue = ''; + 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 () { + var advSearchFields = $("div#advanced_search").children(':visible'); + if(validateAdvancedSearch(advSearchFields)){ + 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]; + this.value = ""; + } + }); + } + + 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 advSearchFields = $("div#advanced_search").children(':visible'); + if(validateAdvancedSearch(advSearchFields)){ + 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 = ''); + 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 += ''; //filter button witch open dialog + r += '
'; //dialog div + //r+= '
'; //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 diff --git a/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter_orig.js b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter_orig.js new file mode 100644 index 000000000..13339de88 --- /dev/null +++ b/airtime_mvc/public/js/datatables/plugin/dataTables.columnFilter_orig.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 = ''); + 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 += ''; //filter button witch open dialog + r += '
'; //dialog div + //r+= '
'; //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 diff --git a/install_full/ubuntu/airtime-full-install b/install_full/ubuntu/airtime-full-install index 57faff468..6d1142bdb 100755 --- a/install_full/ubuntu/airtime-full-install +++ b/install_full/ubuntu/airtime-full-install @@ -64,15 +64,15 @@ apt-get -y --force-yes install libmp3lame-dev lame icecast2 #Ubuntu Lucid has both zendframework and zend-framework. Difference appears to be that zendframework is for #1.10 and zend-framework is 1.11 if [ "$dist" = "Debian" ]; then - apt-get -y install zendframework + apt-get -y --force-yes install zendframework else - apt-get -y install libzend-framework-php + apt-get -y --force-yes install libzend-framework-php fi if [ "$code" = "lucid" ]; then - apt-get -y install timeout + apt-get -y --force-yes install timeout else - apt-get -y install coreutils + apt-get -y --force-yes install coreutils fi diff --git a/install_full/ubuntu/airtime-full-install-nginx b/install_full/ubuntu/airtime-full-install-nginx index c00e3f159..a41937b11 100755 --- a/install_full/ubuntu/airtime-full-install-nginx +++ b/install_full/ubuntu/airtime-full-install-nginx @@ -38,7 +38,7 @@ fi apt-get update # Updated package list -apt-get -y install tar gzip curl nginx php5-pgsql php5-fpm \ +apt-get -y --force-yes install tar gzip curl nginx php5-pgsql php5-fpm \ php-pear php5-gd postgresql odbc-postgresql python libsoundtouch-ocaml \ libtaglib-ocaml libao-ocaml libmad-ocaml ecasound \ libesd0 libportaudio2 libsamplerate0 rabbitmq-server patch \ @@ -54,15 +54,15 @@ apt-get -y --force-yes install libmp3lame-dev lame icecast2 #Ubuntu Lucid has both zendframework and zend-framework. Difference appears to be that zendframework is for #1.10 and zend-framework is 1.11 if [ "$dist" = "Debian" ]; then - apt-get -y install zendframework + apt-get -y install --force-yes zendframework else - apt-get -y install libzend-framework-php + apt-get -y install --force-yes libzend-framework-php fi if [ "$code" = "lucid" ]; then - apt-get -y install timeout + apt-get -y install --force-yes timeout else - apt-get -y install coreutils + apt-get -y install --force-yes coreutils fi # NGINX Config File diff --git a/python_apps/api_clients/api_client.cfg b/python_apps/api_clients/api_client.cfg index fdd7c3b1b..efdcc763f 100644 --- a/python_apps/api_clients/api_client.cfg +++ b/python_apps/api_clients/api_client.cfg @@ -34,7 +34,7 @@ upload_recorded = 'upload-recorded/format/json/api_key/%%api_key%%/fileid/%%file update_media_url = 'reload-metadata/format/json/api_key/%%api_key%%/mode/%%mode%%' # URL to tell Airtime we want a listing of all files it knows about -list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%' +list_all_db_files = 'list-all-files/format/json/api_key/%%api_key%%/dir_id/%%dir_id%%/all/%%all%%' # URL to tell Airtime we want a listing of all dirs its watching (including the stor dir) list_all_watched_dirs = 'list-all-watched-dirs/format/json/api_key/%%api_key%%' diff --git a/python_apps/api_clients/api_client.py b/python_apps/api_clients/api_client.py index 983b59281..130724f66 100644 --- a/python_apps/api_clients/api_client.py +++ b/python_apps/api_clients/api_client.py @@ -474,11 +474,13 @@ class AirtimeApiClient(): #{"files":["path/to/file1", "path/to/file2"]} #Note that these are relative paths to the given directory. The full #path is not returned. - def list_all_db_files(self, dir_id): + def list_all_db_files(self, dir_id, all_files=True): logger = self.logger try: + all_files = u"1" if all_files else u"0" url = self.construct_url("list_all_db_files") url = url.replace("%%dir_id%%", dir_id) + url = url.replace("%%all%%", all_files) response = self.get_response_from_server(url) response = json.loads(response) except Exception, e: @@ -488,7 +490,8 @@ class AirtimeApiClient(): try: return response["files"] except KeyError: - self.logger.error("Could not find index 'files' in dictionary: %s", str(response)) + self.logger.error("Could not find index 'files' in dictionary: %s", + str(response)) return [] def list_all_watched_dirs(self): diff --git a/python_apps/media-monitor2/media/monitor/airtime.py b/python_apps/media-monitor2/media/monitor/airtime.py index 208556f71..a295686b1 100644 --- a/python_apps/media-monitor2/media/monitor/airtime.py +++ b/python_apps/media-monitor2/media/monitor/airtime.py @@ -54,6 +54,7 @@ class AirtimeNotifier(Loggable): message.ack() self.logger.info("Received md from RabbitMQ: %s" % str(body)) m = json.loads(message.body) + if 'directory' in m: m['directory'] = normpath(m['directory']) self.handler.message(m) class AirtimeMessageReceiver(Loggable): @@ -119,6 +120,7 @@ class AirtimeMessageReceiver(Loggable): % md_path, e) def new_watch(self, msg): + msg['directory'] = normpath(msg['directory']) self.logger.info("Creating watch for directory: '%s'" % msg['directory']) if not os.path.exists(msg['directory']): @@ -126,7 +128,10 @@ class AirtimeMessageReceiver(Loggable): except Exception as e: self.fatal_exception("Failed to create watched dir '%s'" % msg['directory'],e) - else: self.new_watch(msg) + else: + self.logger.info("Created new watch directory: '%s'" % + msg['directory']) + self.new_watch(msg) else: self.__request_now_bootstrap( directory=msg['directory'] ) self.manager.add_watch_directory(msg['directory']) diff --git a/python_apps/media-monitor2/media/monitor/pure.py b/python_apps/media-monitor2/media/monitor/pure.py index 9fe1b41df..480778ebc 100644 --- a/python_apps/media-monitor2/media/monitor/pure.py +++ b/python_apps/media-monitor2/media/monitor/pure.py @@ -239,7 +239,7 @@ def normalized_metadata(md, original_path): """ new_md = copy.deepcopy(md) # replace all slashes with dashes - for k,v in new_md.iteritems(): new_md[k] = unicode(v).replace('/','-') + #for k,v in new_md.iteritems(): new_md[k] = unicode(v).replace('/','-') # Specific rules that are applied in a per attribute basis format_rules = { 'MDATA_KEY_TRACKNUMBER' : parse_int, @@ -296,7 +296,7 @@ def organized_path(old_path, root_path, orig_md): filepath = None ext = extension(old_path) def default_f(dictionary, key): - if key in dictionary: return len(dictionary[key]) == 0 + if key in dictionary: return len(str(dictionary[key])) == 0 else: return True # We set some metadata elements to a default "unknown" value because we use # these fields to create a path hence they cannot be empty Here "normal"