From 402e95a8b44a37ea77ba697a121c3eaf864658ef Mon Sep 17 00:00:00 2001
From: Kyle M Hall <kyle@bywatersolutions.com>
Date: Fri, 14 Feb 2014 09:43:55 -0500
Subject: [PATCH] Bug 11703 [QA Followup 4] - Add back in Today's checkouts/Previous checkouts rows

---
 .../plugins/jquery.dataTables.rowGrouping.js       |  690 ++++++++++++++++++++
 koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js    |   36 +-
 .../prog/en/modules/circ/circulation.tt            |    2 +
 .../prog/en/modules/members/moremember.tt          |    2 +
 4 files changed, 727 insertions(+), 3 deletions(-)
 create mode 100644 koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js

diff --git a/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js b/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js
new file mode 100644
index 0000000..40ee66b
--- /dev/null
+++ b/koha-tmpl/intranet-tmpl/lib/jquery/plugins/jquery.dataTables.rowGrouping.js
@@ -0,0 +1,690 @@
+/*
+* File:        jquery.dataTables.grouping.js
+* Version:     1.2.9.
+* Author:      Jovan Popovic
+*
+* Copyright 2013 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:
+* @iGroupingColumnIndex                                 Integer             Index of the column that will be used for grouping - default 0
+* @sGroupingColumnSortDirection                         Enumeration         Sort direction of the group
+* @iGroupingOrderByColumnIndex                          Integer             Index of the column that will be used for ordering groups
+* @sGroupingClass                                       String              Class that will be associated to the group row. Default - "group"
+* @sGroupItemClass                                      String              Class that will be associated to the group row of group items. Default - "group-item"
+* @bSetGroupingClassOnTR                                Boolean             If set class will be set to the TR instead of the TD withing the grouping TR
+* @bHideGroupingColumn                                  Boolean             Hide column used for grouping once results are grouped. Default - true
+* @bHideGroupingOrderByColumn                           Boolean             Hide column used for ordering groups once results are grouped. Default - true
+* @sGroupBy                                             Enumeration         Type of grouping that should be applied. Values "name"(default), "letter", "year"
+* @sGroupLabelPrefix                                    String              Prefix that will be added to each group cell
+* @bExpandableGrouping                                  Boolean             Attach expand/collapse handlers to the grouping rows
+* @bExpandSingleGroup                                   Boolean             Use accordon grouping
+* @iExpandGroupOffset                                   Integer             Number of pixels to set scroll position above the currently selected group. If -1 scroll will be alligned to the table
+* General settings
+* @sDateFormat: "dd/MM/yyyy"                            String              Date format used for grouping
+* @sEmptyGroupLabel                                     String              Lable that will be placed as group if grouping cells are empty. Default "-"
+
+* Parameters used in the second level grouping
+* @iGroupingColumnIndex2                                Integer             Index of the secondary column that will be used for grouping - default 0
+* @sGroupingColumnSortDirection2                        Enumeration         Sort direction of the secondary group
+* @iGroupingOrderByColumnIndex2                         Integer             Index of the column that will be used for ordering secondary groups
+* @sGroupingClass2                                      String              Class that will be associated to the secondary group row. Default "subgroup"
+* @sGroupItemClass2                                     String              Class that will be associated to the secondary group row of group items. Default "subgroup-item"
+* @bHideGroupingColumn2                                 Boolean             Hide column used for secondary grouping once results are grouped. Default - true,
+* @bHideGroupingOrderByColumn2                          Boolean             Hide column used for ordering secondary groups once results are grouped. Default - true,
+* @sGroupBy2                                            Enumeration         Type of grouping that should be applied to secondary column. Values "name"(default), "letter", "year",
+* @sGroupLabelPrefix2                                   String              Prefix that will be added to each secondary group cell
+* @fnOnGrouped                                          Function            Function that is called when grouping is finished. Function has no parameters.
+*/
+(function ($) {
+
+ "use strict";
+
+    $.fn.rowGrouping = function (options) {
+
+        function _fnOnGrouped() {
+
+        }
+
+        function _fnOnGroupCreated(oGroup, sGroup, iLevel) {
+            ///<summary>
+            ///Function called when a new grouping row is created(it should be overriden in properties)
+            ///</summary>
+        }
+
+           function _fnOnGroupCompleted(oGroup, sGroup, iLevel) {
+            ///<summary>
+            ///Function called when a new grouping row is created(it should be overriden in properties)
+            ///</summary>
+        }
+
+        function _getMonthName(iMonth) {
+            var asMonths = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
+            return asMonths[iMonth - 1];
+        }
+
+        var defaults = {
+
+            iGroupingColumnIndex: 0,
+            sGroupingColumnSortDirection: "",
+            iGroupingOrderByColumnIndex: -1,
+            sGroupingClass: "group",
+                        sGroupItemClass: "group-item",
+            bHideGroupingColumn: true,
+            bHideGroupingOrderByColumn: true,
+            sGroupBy: "name",
+            sGroupLabelPrefix: "",
+            fnGroupLabelFormat: function (label) { return label; },
+            bExpandableGrouping: false,
+            bExpandSingleGroup: false,
+            iExpandGroupOffset: 100,
+            asExpandedGroups: null,
+
+            sDateFormat: "dd/MM/yyyy",
+            sEmptyGroupLabel: "-",
+            bSetGroupingClassOnTR: false,
+
+            iGroupingColumnIndex2: -1,
+            sGroupingColumnSortDirection2: "",
+            iGroupingOrderByColumnIndex2: -1,
+            sGroupingClass2: "subgroup",
+            sGroupItemClass2: "subgroup-item",
+            bHideGroupingColumn2: true,
+            bHideGroupingOrderByColumn2: true,
+            sGroupBy2: "name",
+            sGroupLabelPrefix2: "",
+            fnGroupLabelFormat2: function (label) { return label; },
+            bExpandableGrouping2: false,
+
+            fnOnGrouped: _fnOnGrouped,
+
+            fnOnGroupCreated: _fnOnGroupCreated,
+            fnOnGroupCompleted: _fnOnGroupCompleted,
+
+            oHideEffect: null, // { method: "hide", duration: "fast", easing: "linear" },
+            oShowEffect: null,//{ method: "show", duration: "slow", easing: "linear" }
+
+                   bUseFilteringForGrouping: false // This is still work in progress option
+        };
+        return this.each(function (index, elem) {
+
+            var oTable = $(elem).dataTable();
+
+            var aoGroups = new Array();
+            $(this).dataTableExt.aoGroups = aoGroups;
+
+            function fnCreateGroupRow(sGroupCleaned, sGroup, iColspan) {
+                var nGroup = document.createElement('tr');
+                var nCell = document.createElement('td');
+                nGroup.id = "group-id-" + oTable.attr("id") + "_" + sGroupCleaned;
+
+                var oGroup = { id: nGroup.id, key: sGroupCleaned, text: sGroup, level: 0, groupItemClass: ".group-item-" + sGroupCleaned, dataGroup: sGroupCleaned, aoSubgroups: new Array() };
+
+
+
+                if (properties.bSetGroupingClassOnTR) {
+                    nGroup.className = properties.sGroupingClass + " " + sGroupCleaned;
+                } else {
+                    nCell.className = properties.sGroupingClass + " " + sGroupCleaned;
+                }
+
+                nCell.colSpan = iColspan;
+                nCell.innerHTML = properties.sGroupLabelPrefix + properties.fnGroupLabelFormat(sGroup == "" ? properties.sEmptyGroupLabel : sGroup, oGroup );
+                if (properties.bExpandableGrouping) {
+
+                    if (!_fnIsGroupCollapsed(sGroupCleaned)) {
+                        nCell.className += " expanded-group";
+                        oGroup.state = "expanded";
+                    } else {
+                        nCell.className += " collapsed-group";
+                        oGroup.state = "collapsed";
+                    }
+                    nCell.className += " group-item-expander";
+                    $(nCell).attr('data-group', oGroup.dataGroup); //Fix provided by mssskhalsa (Issue 5)
+                    $(nCell).attr("data-group-level", oGroup.level);
+                    $(nCell).click(_fnOnGroupClick);
+                }
+                nGroup.appendChild(nCell);
+                aoGroups[sGroupCleaned] = oGroup;
+                oGroup.nGroup = nGroup;
+                properties.fnOnGroupCreated(oGroup, sGroupCleaned, 1);
+                return oGroup;
+            }
+
+            function _fnCreateGroup2Row(sGroup2, sGroupLabel, iColspan, oParentGroup) {
+
+                var nGroup2 = document.createElement('tr');
+                nGroup2.id = oParentGroup.id + "_" + sGroup2;
+                var nCell2 = document.createElement('td');
+                var dataGroup = oParentGroup.dataGroup + '_' + sGroup2;
+
+                var oGroup = { id: nGroup2.id, key: sGroup2, text: sGroupLabel, level: oParentGroup.level + 1, groupItemClass: ".group-item-" + dataGroup,
+                    dataGroup: dataGroup, aoSubgroups: new Array()
+                };
+
+                if (properties.bSetGroupingClassOnTR) {
+                    nGroup2.className = properties.sGroupingClass2 + " " + sGroup2;
+                } else {
+                    nCell2.className = properties.sGroupingClass2 + " " + sGroup2;
+                }
+
+                nCell2.colSpan = iColspan;
+                nCell2.innerHTML = properties.sGroupLabelPrefix2 + properties.fnGroupLabelFormat2(sGroupLabel == "" ? properties.sEmptyGroupLabel : sGroupLabel, oGroup);
+
+                if (properties.bExpandableGrouping) {
+
+                    nGroup2.className += " group-item-" + oParentGroup.dataGroup;
+                }
+
+
+                if (properties.bExpandableGrouping && properties.bExpandableGrouping2) {
+
+                    if (!_fnIsGroupCollapsed(oGroup.dataGroup)) {
+                        nCell2.className += " expanded-group";
+                        oGroup.state = "expanded";
+                    } else {
+                        nCell2.className += " collapsed-group";
+                        oGroup.state = "collapsed";
+                    }
+                    nCell2.className += " group-item-expander";
+                    $(nCell2).attr('data-group', oGroup.dataGroup);
+                    $(nCell2).attr("data-group-level", oGroup.level);
+                    $(nCell2).click(_fnOnGroupClick);
+                }
+
+                nGroup2.appendChild(nCell2);
+
+                oParentGroup.aoSubgroups[oGroup.dataGroup] = oGroup;
+                aoGroups[oGroup.dataGroup] = oGroup;
+                oGroup.nGroup = nGroup2;
+                properties.fnOnGroupCreated(oGroup, sGroup2, 2);
+                return oGroup;
+            }
+
+            function _fnIsGroupCollapsed(sGroup) {
+                if (aoGroups[sGroup] != null)
+                    return (aoGroups[sGroup].state == "collapsed");
+                else
+                    if (sGroup.indexOf("_") > -1)
+                        true;
+                    else
+                                             if(bInitialGrouping && (asExpandedGroups==null || asExpandedGroups.length == 0))
+                                                       return false;// initially if asExpandedGroups is empty - no one is collapsed
+                                           else
+                                                   return ($.inArray(sGroup, asExpandedGroups) == -1); //the last chance check asExpandedGroups
+            }
+
+            function _fnGetYear(x) {
+                               if(x.length< (iYearIndex+iYearLength) )
+                                        return x;
+                              else
+                                   return x.substr(iYearIndex, iYearLength);
+            }
+            function _fnGetGroupByName(x) {
+                return x;
+            }
+
+            function _fnGetGroupByLetter(x) {
+                return x.substr(0, 1);
+            }
+
+            function _fnGetGroupByYear(x) {
+                return _fnGetYear(x);
+                //return Date.parseExact(x, properties.sDateFormat).getFullYear();//slooooow
+            }
+
+            function _fnGetGroupByYearMonth(x) {
+                //var date = Date.parseExact(x, "dd/MM/yyyy");
+                //return date.getFullYear() + " / " + date.getMonthName();
+                //return x.substr(iYearIndex, iYearLength) + '/' + x.substr(iMonthIndex, iMonthLength);
+                return x.substr(iYearIndex, iYearLength) + ' ' + _getMonthName(x.substr(iMonthIndex, iMonthLength));
+            }
+
+            function _fnGetCleanedGroup(sGroup) {
+
+                if (sGroup === "") return "-";
+                return sGroup.toLowerCase().replace(/[^a-zA-Z0-9\u0080-\uFFFF]+/g, "-"); //fix for unicode characters (Issue 23)
+                //return sGroup.toLowerCase().replace(/\W+/g, "-"); //Fix provided by bmathews (Issue 7)
+            }
+
+                       function _rowGroupingRowFilter(oSettings, aData, iDataIndex) {
+                     ///<summary>Used to expand/collapse groups with DataTables filtering</summary>
+                if (oSettings.nTable.id !== oTable[0].id) return true;
+                var sColData = aData[properties.iGroupingColumnIndex];
+                if (typeof sColData === "undefined")
+                    sColData = aData[oSettings.aoColumns[properties.iGroupingColumnIndex].mDataProp];
+                if (_fnIsGroupCollapsed(_fnGetCleanedGroup(sColData))) {
+                    if (oTable.fnIsOpen(oTable.fnGetNodes(iDataIndex)))
+                                   {
+                                              if (properties.fnOnRowClosed != null) {
+                            properties.fnOnRowClosed(this); //    $(this.cells[0].children[0]).attr('src', '../../Images/details.png');
+                        }
+                        oTable.fnClose(oTable.fnGetNodes(iDataIndex));
+                    }
+                    return false;
+                };
+                            return true;
+            } //end of function _rowGroupingRowFilter
+
+
+            function fnExpandGroup(sGroup) {
+                ///<summary>Expand group if expanadable grouping is used</summary>
+
+                      aoGroups[sGroup].state = "expanded";
+
+                              $("td[data-group^='" + sGroup + "']").removeClass("collapsed-group");
+                $("td[data-group^='" + sGroup + "']").addClass("expanded-group");
+
+
+                              if(properties.bUseFilteringForGrouping)
+                                {
+                                      oTable.fnDraw();
+                                       return;//Because rows are expanded with _rowGroupingRowFilter function
+                         }
+
+                             if (jQuery.inArray(sGroup, asExpandedGroups)==-1)
+                    asExpandedGroups.push(sGroup);
+
+                if (properties.oHideEffect != null)
+                    $(".group-item-" + sGroup, oTable)
+                                       [properties.oShowEffect.method](properties.oShowEffect.duration,
+                                                                       properties.oShowEffect.easing,
+                                                                 function () { });
+                else
+                    $(".group-item-" + sGroup, oTable).show();
+
+
+            } //end of function fnExpandGroup
+
+            function fnCollapseGroup(sGroup) {
+                ///<summary>Collapse group if expanadable grouping is used</summary>
+
+                            aoGroups[sGroup].state = "collapsed";
+                          $("td[data-group^='" + sGroup + "']").removeClass("expanded-group");
+                $("td[data-group^='" + sGroup + "']").addClass("collapsed-group");
+
+                               if(properties.bUseFilteringForGrouping)
+                                {
+                                      oTable.fnDraw();
+                                       return;//Because rows are expanded with _rowGroupingRowFilter function
+                         }
+                              //var index = $.inArray(sGroup, asExpandedGroups);
+                //asExpandedGroups.splice(index, 1);
+
+                $('.group-item-' + sGroup).each(function () {
+                    //Issue 24 - Patch provided by Bob Graham
+                    if (oTable.fnIsOpen(this)) {
+                        if (properties.fnOnRowClosed != null) {
+                            properties.fnOnRowClosed(this); //    $(this.cells[0].children[0]).attr('src', '../../Images/details.png');
+                        }
+                        oTable.fnClose(this);
+                    }
+                });
+
+                if (properties.oHideEffect != null)
+                    $(".group-item-" + sGroup, oTable)
+                                    [properties.oHideEffect.method](properties.oHideEffect.duration,
+                                                                       properties.oHideEffect.easing,
+                                                                 function () { });
+                else
+                    $(".group-item-" + sGroup, oTable).hide();
+
+            } //end of function fnCollapseGroup
+
+            function _fnOnGroupClick(e) {
+                ///<summary>
+                ///Function that is called when user click on the group cell in order to
+                ///expand of collapse group
+                ///</summary>
+
+                //var sGroup = $(this).attr("rel");
+                var sGroup = $(this).attr("data-group");
+                var iGroupLevel = $(this).attr("data-group-level");
+
+                var bIsExpanded = !_fnIsGroupCollapsed(sGroup);
+                if (properties.bExpandSingleGroup) {
+                    if (!bIsExpanded) {
+                        var sCurrentGroup = $("td.expanded-group").attr("data-group");
+                        fnCollapseGroup(sCurrentGroup);
+                        fnExpandGroup(sGroup);
+
+                        if (properties.iExpandGroupOffset != -1) {
+                            var position = $("#group-id-" + oTable.attr("id") + "_" + sGroup).offset().top - properties.iExpandGroupOffset;
+                            window.scroll(0, position);
+                        } else {
+                            var position = oTable.offset().top;
+                            window.scroll(0, position);
+                        }
+                    }
+                } else {
+                    if (bIsExpanded) {
+                        fnCollapseGroup(sGroup);
+                    } else {
+                        fnExpandGroup(sGroup);
+                    }
+                }
+                e.preventDefault();
+
+            }; //end function _fnOnGroupClick
+
+
+                     function _fnDrawCallBackWithGrouping (oSettings) {
+
+                if (oTable.fnSettings().oFeatures.bServerSide)
+                    bInitialGrouping = true;
+                var bUseSecondaryGrouping = false;
+
+                if (properties.iGroupingColumnIndex2 != -1)
+                    bUseSecondaryGrouping = true;
+
+                //-----Start grouping
+
+                if (oSettings.aiDisplayMaster.length == 0) { //aiDisplay
+                    return;
+                }
+
+                var nTrs = $('tbody tr', oTable);
+                var iColspan = 0; //nTrs[0].getElementsByTagName('td').length;
+                for (var iColIndex = 0; iColIndex < oSettings.aoColumns.length; iColIndex++) {
+                    if (oSettings.aoColumns[iColIndex].bVisible)
+                        iColspan += 1;
+                }
+                var sLastGroup = null;
+                var sLastGroup2 = null;
+                if (oSettings.aiDisplay.length > 0) {
+                    for (var i = 0; i < nTrs.length; i++) {
+
+
+                        var iDisplayIndex = oSettings._iDisplayStart + i;
+                        if (oTable.fnSettings().oFeatures.bServerSide)
+                            iDisplayIndex = i;
+                        var sGroupData = "";
+                        var sGroup = null;
+                        var sGroupData2 = "";
+                        var sGroup2 = null;
+
+                        //Issue 31 - Start fix provided by Fabien Taysse
+//                      sGroupData = oSettings.aoData[oSettings.aiDisplay[iDisplayIndex]]._aData[properties.iGroupingColumnIndex];
+//                      if (sGroupData == undefined)
+//                          sGroupData = oSettings.aoData[oSettings.aiDisplay[iDisplayIndex]]._aData[oSettings.aoColumns[properties.iGroupingColumnIndex].mDataProp];
+                        sGroupData = this.fnGetData(nTrs[i], properties.iGroupingColumnIndex);
+                        //Issue 31 - End fix provided by Fabien Taysse
+
+                        var sGroup = sGroupData;
+                        if (properties.sGroupBy != "year")
+                            sGroup = fnGetGroup(sGroupData);
+
+                        if (bUseSecondaryGrouping) {
+                            sGroupData2 = oSettings.aoData[oSettings.aiDisplay[iDisplayIndex]]._aData[properties.iGroupingColumnIndex2];
+                            if (sGroupData2 == undefined)
+                                sGroupData2 = oSettings.aoData[oSettings.aiDisplay[iDisplayIndex]]._aData[oSettings.aoColumns[properties.iGroupingColumnIndex2].mDataProp];
+                            if (properties.sGroupBy2 != "year")
+                                sGroup2 = fnGetGroup(sGroupData2);
+                        }
+
+
+                        if (sLastGroup == null || _fnGetCleanedGroup(sGroup) != _fnGetCleanedGroup(sLastGroup)) { // new group encountered (or first of group)
+                            var sGroupCleaned = _fnGetCleanedGroup(sGroup);
+
+                            if(sLastGroup != null)
+                            {
+				properties.fnOnGroupCompleted(aoGroups[_fnGetCleanedGroup(sLastGroup)]);
+                            }
+                                                   /*
+                            if (properties.bExpandableGrouping && bInitialGrouping) {
+                                if (properties.bExpandSingleGroup) {
+                                    if (asExpandedGroups.length == 0)
+                                        asExpandedGroups.push(sGroupCleaned);
+                                } else {
+                                    asExpandedGroups.push(sGroupCleaned);
+                                }
+                            }
+                                                   */
+                                                     if(properties.bAddAllGroupsAsExpanded && jQuery.inArray(sGroupCleaned,asExpandedGroups) == -1)
+                                                         asExpandedGroups.push(sGroupCleaned);
+
+                            var oGroup = fnCreateGroupRow(sGroupCleaned, sGroup, iColspan);
+                            var nGroup = oGroup.nGroup;
+
+                                                    if(nTrs[i].parentNode!=null)
+                                                           nTrs[i].parentNode.insertBefore(nGroup, nTrs[i]);
+                                                      else
+                                                           $(nTrs[i]).before(nGroup);
+
+                            sLastGroup = sGroup;
+                            sLastGroup2 = null; //to reset second level grouping
+
+
+
+
+
+                        } // end if (sLastGroup == null || sGroup != sLastGroup)
+
+                                           $(nTrs[i]).attr("data-group", aoGroups[sGroupCleaned].dataGroup);
+
+                        $(nTrs[i]).addClass(properties.sGroupItemClass);
+                        $(nTrs[i]).addClass("group-item-" + sGroupCleaned);
+                        if (properties.bExpandableGrouping) {
+                            if (_fnIsGroupCollapsed(sGroupCleaned) && !properties.bUseFilteringForGrouping) {
+                                $(nTrs[i]).hide();
+                            }
+                        }
+
+
+                        if (bUseSecondaryGrouping) {
+
+                            if (sLastGroup2 == null || _fnGetCleanedGroup(sGroup2) != _fnGetCleanedGroup(sLastGroup2)) {
+                                var sGroup2Id = _fnGetCleanedGroup(sGroup) + '-' + _fnGetCleanedGroup(sGroup2);
+                                var oGroup2 = _fnCreateGroup2Row(sGroup2Id, sGroup2, iColspan, aoGroups[sGroupCleaned])
+                                var nGroup2 = oGroup2.nGroup;
+                                nTrs[i].parentNode.insertBefore(nGroup2, nTrs[i]);
+
+                                sLastGroup2 = sGroup2;
+                            }
+
+                            $(nTrs[i]).attr("data-group", oGroup2.dataGroup)
+                                                                           .addClass(properties.sGroupItemClass2)
+                                        .addClass("group-item-" + oGroup2.dataGroup);
+                        } //end if (bUseSecondaryGrouping)
+
+
+
+                    } // end for (var i = 0; i < nTrs.length; i++)
+                }; // if (oSettings.aiDisplay.length > 0)
+
+                               if(sLastGroup != null)
+                     {
+				properties.fnOnGroupCompleted(aoGroups[_fnGetCleanedGroup(sLastGroup)]);
+                         }
+
+
+                //-----End grouping
+                properties.fnOnGrouped(aoGroups);
+
+                bInitialGrouping = false;
+
+            }; // end of _fnDrawCallBackWithGrouping = function (oSettings)
+
+
+            //var oTable = this;
+            var iYearIndex = 6;
+            var iYearLength = 4;
+            var asExpandedGroups = new Array();
+            var bInitialGrouping = true;
+
+            var properties = $.extend(defaults, options);
+
+            if (properties.iGroupingOrderByColumnIndex == -1) {
+                properties.bCustomColumnOrdering = false;
+                properties.iGroupingOrderByColumnIndex = properties.iGroupingColumnIndex;
+            } else {
+                properties.bCustomColumnOrdering = true;
+            }
+
+            if (properties.sGroupingColumnSortDirection == "") {
+                if (properties.sGroupBy == "year")
+                    properties.sGroupingColumnSortDirection = "desc";
+                else
+                    properties.sGroupingColumnSortDirection = "asc";
+            }
+
+
+            if (properties.iGroupingOrderByColumnIndex2 == -1) {
+                properties.bCustomColumnOrdering2 = false;
+                properties.iGroupingOrderByColumnIndex2 = properties.iGroupingColumnIndex2;
+            } else {
+                properties.bCustomColumnOrdering2 = true;
+            }
+
+            if (properties.sGroupingColumnSortDirection2 == "") {
+                if (properties.sGroupBy2 == "year")
+                    properties.sGroupingColumnSortDirection2 = "desc";
+                else
+                    properties.sGroupingColumnSortDirection2 = "asc";
+            }
+
+
+
+            iYearIndex = properties.sDateFormat.toLowerCase().indexOf('yy');
+            iYearLength = properties.sDateFormat.toLowerCase().lastIndexOf('y') - properties.sDateFormat.toLowerCase().indexOf('y') + 1;
+
+            var iMonthIndex = properties.sDateFormat.toLowerCase().indexOf('mm');
+            var iMonthLength = properties.sDateFormat.toLowerCase().lastIndexOf('m') - properties.sDateFormat.toLowerCase().indexOf('m') + 1;
+
+            var fnGetGroup = _fnGetGroupByName;
+            switch (properties.sGroupBy) {
+                case "letter": fnGetGroup = _fnGetGroupByLetter;
+                    break;
+                case "year": fnGetGroup = _fnGetGroupByYear;
+                    break;
+                case "month": fnGetGroup = _fnGetGroupByYearMonth;
+                    break;
+                default: fnGetGroup = _fnGetGroupByName;
+                    break;
+            }
+
+
+            if (properties.asExpandedGroups != null) {
+                if (properties.asExpandedGroups == "NONE") {
+                    properties.asExpandedGroups = [];
+                    asExpandedGroups = properties.asExpandedGroups;
+                    bInitialGrouping = false;
+                } else if (properties.asExpandedGroups == "ALL") {
+                                     properties.bAddAllGroupsAsExpanded = true;
+                } else if (properties.asExpandedGroups.constructor == String) {
+                    var currentGroup = properties.asExpandedGroups;
+                    properties.asExpandedGroups = new Array();
+                    properties.asExpandedGroups.push(_fnGetCleanedGroup(currentGroup));
+                    asExpandedGroups = properties.asExpandedGroups;
+                    bInitialGrouping = false;
+                } else if (properties.asExpandedGroups.constructor == Array) {
+                    for (var i = 0; i < properties.asExpandedGroups.length; i++) {
+                        asExpandedGroups.push(_fnGetCleanedGroup(properties.asExpandedGroups[i]));
+                        if (properties.bExpandSingleGroup)
+                            break;
+                    }
+                    bInitialGrouping = false;
+                }
+            }else{
+                            properties.asExpandedGroups = new Array();
+                             properties.bAddAllGroupsAsExpanded = true;
+                     }
+                      if(properties.bExpandSingleGroup){
+                         var nTrs = $('tbody tr', oTable);
+                          var sGroupData = oTable.fnGetData(nTrs[0], properties.iGroupingColumnIndex);
+
+                          var sGroup = sGroupData;
+                if (properties.sGroupBy != "year")
+                    sGroup = fnGetGroup(sGroupData);
+
+                              var sGroupCleaned = _fnGetCleanedGroup(sGroup);
+                                properties.asExpandedGroups = new Array();
+                             properties.asExpandedGroups.push(sGroupCleaned);
+
+                      }
+
+            oTable.fnSetColumnVis(properties.iGroupingColumnIndex, !properties.bHideGroupingColumn);
+            if (properties.bCustomColumnOrdering) {
+                oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex, !properties.bHideGroupingOrderByColumn);
+            }
+            if (properties.iGroupingColumnIndex2 != -1) {
+                oTable.fnSetColumnVis(properties.iGroupingColumnIndex2, !properties.bHideGroupingColumn2);
+            }
+            if (properties.bCustomColumnOrdering2) {
+                oTable.fnSetColumnVis(properties.iGroupingOrderByColumnIndex2, !properties.bHideGroupingOrderByColumn2);
+            }
+            oTable.fnSettings().aoDrawCallback.push({
+                "fn": _fnDrawCallBackWithGrouping,
+                "sName": "fnRowGrouping"
+            });
+
+            var aaSortingFixed = new Array();
+            aaSortingFixed.push([properties.iGroupingOrderByColumnIndex, properties.sGroupingColumnSortDirection]);
+            if (properties.iGroupingColumnIndex2 != -1) {
+                aaSortingFixed.push([properties.iGroupingOrderByColumnIndex2, properties.sGroupingColumnSortDirection2]);
+            } // end of if (properties.iGroupingColumnIndex2 != -1)
+
+            oTable.fnSettings().aaSortingFixed = aaSortingFixed;
+            //Old way
+            //oTable.fnSettings().aaSortingFixed = [[properties.iGroupingOrderByColumnIndex, properties.sGroupingColumnSortDirection]];
+
+            switch (properties.sGroupBy) {
+                case "name":
+                    break;
+
+
+                case "letter":
+
+                    /* Create an array with the values of all the input boxes in a column */
+                    oTable.fnSettings().aoColumns[properties.iGroupingOrderByColumnIndex].sSortDataType = "rg-letter";
+                    $.fn.dataTableExt.afnSortData['rg-letter'] = function (oSettings, iColumn) {
+                        var aData = [];
+                        $('td:eq(' + iColumn + ')', oSettings.oApi._fnGetTrNodes(oSettings)).each(function () {
+                            aData.push(_fnGetGroupByLetter(this.innerHTML));
+                        });
+                        return aData;
+                    }
+
+
+                    break;
+
+
+                case "year":
+                    /* Create an array with the values of all the input boxes in a column */
+                    oTable.fnSettings().aoColumns[properties.iGroupingOrderByColumnIndex].sSortDataType = "rg-date";
+                    $.fn.dataTableExt.afnSortData['rg-date'] = function (oSettings, iColumn) {
+                        var aData = [];
+                                              var nTrs = oSettings.oApi._fnGetTrNodes(oSettings);
+                                            for(i = 0; i< nTrs.length; i++)
+                                                {
+                                                      aData.push(_fnGetYear( oTable.fnGetData( nTrs[i], iColumn) ));
+                                         }
+
+/*
+                        $('td:eq(' + iColumn + ')', oSettings.oApi._fnGetTrNodes(oSettings)).each(function () {
+                            aData.push(_fnGetYear(this.innerHTML));
+                        });
+*/
+                        return aData;
+                    }
+                    break;
+                default:
+                    break;
+
+            } // end of switch (properties.sGroupBy)
+
+                     if(properties.bUseFilteringForGrouping)
+                                        $.fn.dataTableExt.afnFiltering.push(_rowGroupingRowFilter);
+
+            oTable.fnDraw();
+
+
+
+        });
+    };
+})(jQuery);
\ No newline at end of file
diff --git a/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js b/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js
index 04b24e3..8902ab5 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js
+++ b/koha-tmpl/intranet-tmpl/prog/en/js/checkouts.js
@@ -124,12 +124,23 @@ $(document).ready(function() {
 
     var ymd = $.datepicker.formatDate('yy-mm-dd', new Date());
 
-    $("#issues-table").dataTable({
+    var issuesTable;
+    var drawn = 0;
+    issuesTable = $("#issues-table").dataTable({
         "sDom": "<'row-fluid'<'span6'><'span6'>r>t<'row-fluid'>t",
-        "aaSorting": [],
+        "aaSorting": [[ 0, "desc" ]],
         "aoColumns": [
             {
                 "mDataProp": function( oObj ) {
+                    if ( $.datepicker.formatDate('yy-mm-dd', new Date(oObj.issuedate) ) == ymd ) {
+                        return "<strong>" + _("Today's checkouts") + "</strong>";
+                    } else {
+                        return "<strong>" + _("Previous checkouts") + "</strong>";
+                    }
+                }
+            },
+            {
+                "mDataProp": function( oObj ) {
                     var today = new Date();
                     var due = new Date( oObj.date_due );
                     if ( today > due ) {
@@ -281,7 +292,26 @@ $(document).ready(function() {
                 fnCallback(json)
             } );
         },
-    });
+        "fnInitComplete": function(oSettings) {
+            // Disable rowGrouping plugin after first use
+            // so any sorting on the table doesn't use it
+            var oSettings = issuesTable.fnSettings();
+
+            for (f = 0; f < oSettings.aoDrawCallback.length; f++) {
+                if (oSettings.aoDrawCallback[f].sName == 'fnRowGrouping') {
+                    oSettings.aoDrawCallback.splice(f, 1);
+                    break;
+                }
+            }
+
+            oSettings.aaSortingFixed = null;
+        },
+    }).rowGrouping(
+        {
+            iGroupingOrderByColumnIndex: 0,
+            sGroupingColumnSortDirection: "desc"
+        }
+    );
 
     $("#issues-table_processing").position({
         of: $( "#issues-table" ),
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
index b481059..fa7ce74 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/circ/circulation.tt
@@ -20,6 +20,7 @@
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
 <script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery-ui-timepicker-addon.min.js"></script>
 [% INCLUDE 'timepicker.inc' %]
+<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.dataTables.rowGrouping.js"></script>
 <script type="text/javascript" src="[% themelang %]/js/pages/circulation.js"></script>
 <script type="text/javascript" src="[% themelang %]/js/checkouts.js"></script>
 <script type="text/javascript" src="[% themelang %]/js/holds.js"></script>
@@ -673,6 +674,7 @@ No patron matched <span class="ex">[% message %]</span>
         <table id="issues-table">
             <thead>
                 <tr>
+                    <th scope="col">&nbsp;</th>
                     <th scope="col">Due date</th>
                     <th scope="col">Title</th>
                     <th scope="col">Item type</th>
diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
index 5c58754..7cb3545 100644
--- a/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
+++ b/koha-tmpl/intranet-tmpl/prog/en/modules/members/moremember.tt
@@ -14,6 +14,7 @@
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.checkboxes.min.js"></script>
 <script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery-ui-timepicker-addon.js"></script>
 [% INCLUDE 'timepicker.inc' %]
+<script type="text/javascript" src="[% interface %]/lib/jquery/plugins/jquery.dataTables.rowGrouping.js"></script>
 <script type="text/javascript" src="[% themelang %]/js/checkouts.js"></script>
 <script type="text/javascript" src="[% themelang %]/js/holds.js"></script>
 <script type="text/JavaScript">
@@ -407,6 +408,7 @@ function validate1(date) {
                 <table id="issues-table" style="width: 100% !Important;">
                     <thead>
                         <tr>
+                            <th scope="col">&nbsp;</th>
                             <th scope="col">Due date</th>
                             <th scope="col">Title</th>
                             <th scope="col">Item type</th>
-- 
1.7.2.5