Bugzilla – Attachment 15137 Details for
Bug 9034
Add sorting and filtering on items table (catalogue/detail.pl)
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 9034: Add sorting and filtering on items table (catalogue/detail.pl)
Bug-9034-Add-sorting-and-filtering-on-items-table-.patch (text/plain), 35.81 KB, created by
Jonathan Druart
on 2013-02-07 14:26:17 UTC
(
hide
)
Description:
Bug 9034: Add sorting and filtering on items table (catalogue/detail.pl)
Filename:
MIME Type:
Creator:
Jonathan Druart
Created:
2013-02-07 14:26:17 UTC
Size:
35.81 KB
patch
obsolete
>From c465c099e68bb44e9362047c3cee4e0b84c1c868 Mon Sep 17 00:00:00 2001 >From: Julian Maurice <julian.maurice@biblibre.com> >Date: Thu, 8 Nov 2012 16:58:47 +0100 >Subject: [PATCH] Bug 9034: Add sorting and filtering on items table > (catalogue/detail.pl) > >This patch introduces a new javascript plugin for dataTables >(columnFilter). > >Signed-off-by: Kyle M Hall <kyle@bywatersolutions.com> > >Signed-off-by: Jonathan Druart <jonathan.druart@biblibre.com> >--- > .../plugins/jquery.dataTables.columnFilter.js | 762 ++++++++++++++++++++ > .../prog/en/modules/catalogue/detail.tt | 58 +- > 2 files changed, 802 insertions(+), 18 deletions(-) > create mode 100644 koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jquery.dataTables.columnFilter.js > >diff --git a/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jquery.dataTables.columnFilter.js b/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jquery.dataTables.columnFilter.js >new file mode 100644 >index 0000000..56db7f1 >--- /dev/null >+++ b/koha-tmpl/intranet-tmpl/prog/en/lib/jquery/plugins/jquery.dataTables.columnFilter.js >@@ -0,0 +1,762 @@ >+/* >+* File: jquery.dataTables.columnFilter.js >+* Version: 1.5.0. >+* 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) { >+ ///<summary> >+ ///Return values in the column >+ ///</summary> >+ ///<param name="oSettings" type="Object">DataTables settings</param> >+ ///<param name="iColumn" type="int">Id of the column</param> >+ ///<param name="bUnique" type="bool">Return only distinct values</param> >+ ///<param name="bFiltered" type="bool">Return values only from the filtered rows</param> >+ ///<param name="bIgnoreEmpty" type="bool">Ignore empty cells</param> >+ >+ // 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++) { >+ var iRow = aiRows[i]; >+ var aData = oTable.fnGetData(iRow); >+ var sValue = aData[iColumn]; >+ >+ // ignore empty values? >+ if (bIgnoreEmpty == true && sValue.length == 0) continue; >+ >+ // ignore unique values? >+ 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 = $('<input type="text" class="' + search_init + sCSSClass + '" value="' + inputvalue + '"/>'); >+ if (iMaxLenght != undefined && iMaxLenght != -1) { >+ input.attr('maxlength', iMaxLenght); >+ } >+ th.html(input); >+ if (bIsNumber) >+ th.wrapInner('<span class="filter_column filter_number" />'); >+ else >+ th.wrapInner('<span class="filter_column filter_text" />'); >+ >+ 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 = $('<input type="text" class="number_range_filter" id="' + sFromId + '" rel="' + i + '"/>'); >+ th.append(from); >+ th.append(_fnRangeLabelPart(1)); >+ var sToId = oTable.attr("id") + '_range_to_' + i; >+ var to = $('<input type="text" class="number_range_filter" id="' + sToId + '" rel="' + i + '"/>'); >+ th.append(to); >+ th.append(_fnRangeLabelPart(2)); >+ th.wrapInner('<span class="filter_column filter_number_range" />'); >+ 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) { >+ >+ var aoFragments = sRangeFormat.split(/[}{]/); >+ >+ th.html(""); >+ //th.html(_fnRangeLabelPart(0)); >+ var sFromId = oTable.attr("id") + '_range_from_' + i; >+ var from = $('<input type="text" class="date_range_filter" id="' + sFromId + '" rel="' + i + '"/>'); >+ from.datepicker(); >+ //th.append(from); >+ //th.append(_fnRangeLabelPart(1)); >+ var sToId = oTable.attr("id") + '_range_to_' + i; >+ var to = $('<input type="text" class="date_range_filter" id="' + sToId + '" rel="' + i + '"/>'); >+ //th.append(to); >+ //th.append(_fnRangeLabelPart(2)); >+ >+ for (ti = 0; ti < aoFragments.length; ti++) { >+ >+ if (aoFragments[ti] == properties.sDateFromToken) { >+ th.append(from); >+ } else { >+ if (aoFragments[ti] == properties.sDateToToken) { >+ th.append(to); >+ } else { >+ th.append(aoFragments[ti]); >+ } >+ } >+ >+ >+ } >+ >+ >+ th.wrapInner('<span class="filter_column filter_date_range" />'); >+ to.datepicker(); >+ var index = i; >+ aiCustomSearch_Indexes.push(i); >+ >+ >+ //------------start date range filtering function >+ >+ //$.fn.dataTableExt.afnFiltering.push( >+ oTable.dataTableExt.afnFiltering.push( >+ function (oSettings, aData, iDataIndex) { >+ if (oTable.attr("id") != oSettings.sTableId) >+ return true; >+ >+ var dStartDate = from.datepicker("getDate"); >+ >+ var dEndDate = to.datepicker("getDate"); >+ >+ if (dStartDate == null && dEndDate == null) { >+ return true; >+ } >+ >+ var dCellDate = null; >+ try { >+ if (aData[_fnColumnIndex(index)] == null || aData[_fnColumnIndex(index)] == "") >+ return false; >+ dCellDate = $.datepicker.parseDate($.datepicker.regional[""].dateFormat, aData[_fnColumnIndex(index)]); >+ } catch (ex) { >+ return false; >+ } >+ if (dCellDate == null) >+ return false; >+ >+ >+ if (dStartDate == null && dCellDate <= dEndDate) { >+ return true; >+ } >+ else if (dStartDate <= dCellDate && dEndDate == null) { >+ return true; >+ } >+ else if (dStartDate <= dCellDate && dCellDate <= dEndDate) { >+ return true; >+ } >+ return false; >+ } >+ ); >+ //------------end date range filtering function >+ >+ $('#' + sFromId + ',#' + sToId, th).change(function () { >+ oTable.fnDraw(); >+ fnOnFiltered(); >+ }); >+ >+ >+ } >+ >+ function fnCreateColumnSelect(oTable, aData, iColumn, nTh, sLabel, bRegex, oSelected) { >+ if (aData == null) >+ aData = _fnGetColumnValues(oTable.fnSettings(), iColumn, true, false, true); >+ var index = iColumn; >+ var currentFilter = oTable.fnSettings().aoPreSearchCols[i].sSearch; >+ if (currentFilter == null || currentFilter == "")//Issue 81 >+ currentFilter = oSelected; >+ >+ var r = '<select class="search_init select_filter"><option value="" class="search_init">' + sLabel + '</option>'; >+ 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 += '<option ' + selected + ' value="' + escape(aData[j]) + '">' + aData[j] + '</option>'; >+ } >+ 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 += '<option ' + selected + 'value="' + aData[j].value + '">' + aData[j].label + '</option>'; >+ } else { >+ if (escape(aData[j].value) == currentFilter) selected = 'selected '; >+ r += '<option ' + selected + 'value="' + escape(aData[j].value) + '">' + aData[j].label + '</option>'; >+ } >+ } >+ } >+ >+ var select = $(r + '</select>'); >+ nTh.html(select); >+ nTh.wrapInner('<span class="filter_column filter_select" />'); >+ select.change(function () { >+ //var val = $(this).val(); >+ if ($(this).val() != "") { >+ $(this).removeClass("search_init"); >+ } else { >+ $(this).addClass("search_init"); >+ } >+ if (bRegex) >+ oTable.fnFilter($(this).val(), iColumn, bRegex); //Issue 41 >+ else >+ oTable.fnFilter(unescape($(this).val()), iColumn); //Issue 25 >+ fnOnFiltered(); >+ }); >+ if (currentFilter != null && currentFilter != "")//Issue 81 >+ oTable.fnFilter(unescape(currentFilter), iColumn); >+ } >+ >+ function fnCreateSelect(oTable, aData, bRegex, oSelected) { >+ 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, oSelected); //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, oSelected); //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 >+ var labelBtn = label; >+ if (properties.sFilterButtonText != null || properties.sFilterButtonText != undefined) { >+ labelBtn = properties.sFilterButtonText; >+ } >+ >+ 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 = '<div style="float:left; min-width: ' + divWidth + '%; " >'; >+ var divClose = '</div>'; >+ >+ var uniqueId = oTable.attr("id") + localLabel; >+ var buttonId = "chkBtnOpen" + uniqueId; >+ var checkToggleDiv = uniqueId + "-flt-toggle"; >+ r += '<button id="' + buttonId + '" class="checkbox_filter" > ' + labelBtn + '</button>'; //filter button witch open dialog >+ r += '<div id="' + checkToggleDiv + '" ' >+ + 'title="' + label + '" ' >+ + 'class="toggle-check ui-widget-content ui-corner-all" style="width: ' + (divWidthToggle) + '%; " >'; //dialog div >+ //r+= '<div align="center" style="margin-top: 5px; "> <button id="'+buttonId+'Reset" class="checkbox_filter" > reset </button> </div>'; //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 += '<input class="search_init checkbox_filter" type="checkbox" id= "' + aData[j] + '" name= "' + localLabel + '" value="' + aData[j] + '" >' + aData[j] + '<br/>'; >+ >+ var checkbox = $(r); >+ th.html(checkbox); >+ th.wrapInner('<span class="filter_column filter_checkbox" />'); >+ //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); >+ } >+ } >+ >+ >+ >+ >+ var oTable = this; >+ >+ var defaults = { >+ sPlaceHolder: "foot", >+ sRangeSeparator: "~", >+ iFilteringDelay: 500, >+ aoColumns: null, >+ sRangeFormat: "From {from} to {to}", >+ sDateFromToken: "from", >+ sDateToToken: "to" >+ }; >+ >+ var properties = $.extend(defaults, options); >+ >+ return this.each(function () { >+ >+ if (!oTable.fnSettings().oFeatures.bFilter) >+ return; >+ asInitVals = new Array(); >+ >+ var aoFilterCells = oTable.fnSettings().aoFooter[0]; >+ >+ var oHost = oTable.fnSettings().nTFoot; //Before fix for ColVis >+ var sFilterRow = "tr"; //Before fix for ColVis >+ >+ 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, aoColumn.selected); >+ 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); >diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >index cc68bfe..a0fd3b5 100644 >--- a/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/catalogue/detail.tt >@@ -45,6 +45,25 @@ function verify_images() { > });[% END %] > //]]> > </script> >+<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" /> >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script> >+<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.columnFilter.js"></script> >+[% INCLUDE 'datatables-strings.inc' %] >+<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script> >+<script type="text/javascript"> >+//<![CDATA[ >+ $(document).ready(function() { >+ for (id in {holdings:0, otherholdings:0}) { >+ $("#"+ id +" > table").dataTable($.extend(true, {}, dataTablesDefaults, { >+ 'sDom': 't', >+ 'bPaginate': false >+ })).columnFilter({ >+ 'sPlaceHolder': 'head:after' >+ }); >+ } >+ }); >+//]]> >+</script> > </head> > > <body id="catalog_detail" class="catalog"> >@@ -278,24 +297,27 @@ function verify_images() { > [% BLOCK items_table %] > <table> > <thead> >- <tr> >- [% IF ( item_level_itypes ) %]<th>Item type</th>[% END %] >- <th>Current location</th> >- <th>Home Library</th> >- [% IF ( itemdata_ccode ) %]<th>Collection</th>[% END %] >- <th>Call number</th> >- <th>Status</th> >- <th>Last seen</th> >- <th>Barcode</th> >- [% IF ( volinfo ) %]<th>Publication details</th>[% END %] >- [% IF ( itemdata_uri ) %]<th>url</th>[% END %] >- [% IF ( itemdata_copynumber ) %]<th>Copy no.</th>[% END %] >- [% IF materials %]<th>Materials specified</th>[% END %] >- [% IF ( itemdata_itemnotes ) %]<th>Public notes</th>[% END %] >- [% IF ( SpineLabelShowPrintOnBibDetails ) %]<th>Spine label</th>[% END %] >- [% IF ( hostrecords ) %]<th>Host records</th>[% END %] >- [% IF ( analyze ) %]<th>Used in</th><th></th>[% END %] >- </tr> >+ [%# duplicate the header row for columnFilter %] >+ [% FOREACH i IN [1,2] %] >+ <tr> >+ [% IF ( item_level_itypes ) %]<th>Item type</th>[% END %] >+ <th>Current location</th> >+ <th>Home Library</th> >+ [% IF ( itemdata_ccode ) %]<th>Collection</th>[% END %] >+ <th>Call number</th> >+ <th>Status</th> >+ <th>Last seen</th> >+ <th>Barcode</th> >+ [% IF ( volinfo ) %]<th>Publication details</th>[% END %] >+ [% IF ( itemdata_uri ) %]<th>url</th>[% END %] >+ [% IF ( itemdata_copynumber ) %]<th>Copy no.</th>[% END %] >+ [% IF materials %]<th>Materials specified</th>[% END %] >+ [% IF ( itemdata_itemnotes ) %]<th>Public notes</th>[% END %] >+ [% IF ( SpineLabelShowPrintOnBibDetails ) %]<th>Spine label</th>[% END %] >+ [% IF ( hostrecords ) %]<th>Host records</th>[% END %] >+ [% IF ( analyze ) %]<th>Used in</th><th></th>[% END %] >+ </tr> >+ [% END %] > </thead> > <tbody> > [% FOREACH item IN items %] >-- >1.7.10.4
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 9034
:
13310
|
13338
|
13345
|
13346
|
13368
|
14491
|
14492
|
14493
|
14494
|
14743
| 15137 |
15138
|
15139
|
15140