diff --git a/share/static/css/main.css b/share/static/css/main.css
index ab80cb8abc..40250a1b2c 100644
--- a/share/static/css/main.css
+++ b/share/static/css/main.css
@@ -213,6 +213,10 @@ div.dataTables_paginate {
margin: 0;
}
+div.dataTables_paginate a.btn {
+ margin-left: 3px;
+}
+
/* ---------
Datatable Field (inside modal)
------------*/
diff --git a/share/static/js/libs/datatables-bootstrap-paging.js b/share/static/js/libs/datatables-bootstrap-paging.js
index b2af271429..f53d7d9841 100644
--- a/share/static/js/libs/datatables-bootstrap-paging.js
+++ b/share/static/js/libs/datatables-bootstrap-paging.js
@@ -1,91 +1,132 @@
-
-/* API method to get paging information */
-$.fn.dataTableExt.oApi.fnPagingInfo = function ( oSettings )
-{
- return {
- "iStart": oSettings._iDisplayStart,
- "iEnd": oSettings.fnDisplayEnd(),
- "iLength": oSettings._iDisplayLength,
- "iTotal": oSettings.fnRecordsTotal(),
- "iFilteredTotal": oSettings.fnRecordsDisplay(),
- "iPage": Math.ceil( oSettings._iDisplayStart / oSettings._iDisplayLength ),
- "iTotalPages": Math.ceil( oSettings.fnRecordsDisplay() / oSettings._iDisplayLength )
- };
-}
-
-/* Bootstrap style pagination control */
-$.extend( $.fn.dataTableExt.oPagination, {
- "bootstrap": {
- "fnInit": function( oSettings, nPaging, fnDraw ) {
- var oLang = oSettings.oLanguage.oPaginate;
- var fnClickHandler = function ( e ) {
- e.preventDefault();
- if ( oSettings.oApi._fnPageChange(oSettings, e.data.action) ) {
- fnDraw( oSettings );
- }
- };
-
- $(nPaging).addClass('pagination').append(
- '
'
- );
- var els = $('a', nPaging);
- $(els[0]).bind( 'click.DT', { action: "previous" }, fnClickHandler );
- $(els[1]).bind( 'click.DT', { action: "next" }, fnClickHandler );
- },
-
- "fnUpdate": function ( oSettings, fnDraw ) {
- var iListLength = 5;
- var oPaging = oSettings.oInstance.fnPagingInfo();
- var an = oSettings.aanFeatures.p;
- var i, j, sClass, iStart, iEnd, iHalf=Math.floor(iListLength/2);
-
- if ( oPaging.iTotalPages < iListLength) {
- iStart = 1;
- iEnd = oPaging.iTotalPages;
- }
- else if ( oPaging.iPage <= iHalf ) {
- iStart = 1;
- iEnd = iListLength;
- } else if ( oPaging.iPage >= (oPaging.iTotalPages-iHalf) ) {
- iStart = oPaging.iTotalPages - iListLength + 1;
- iEnd = oPaging.iTotalPages;
- } else {
- iStart = oPaging.iPage - iHalf + 1;
- iEnd = iStart + iListLength - 1;
- }
-
- for ( i=0, iLen=an.length ; i'+j+'')
- .insertBefore( $('li:last', an[i])[0] )
- .bind('click', function (e) {
- e.preventDefault();
- oSettings._iDisplayStart = (parseInt($('a', this).text(),10)-1) * oPaging.iLength;
- fnDraw( oSettings );
- } );
- }
-
- // Add / remove disabled classes from the static elements
- if ( oPaging.iPage === 0 ) {
- $('li:first', an[i]).addClass('disabled');
- } else {
- $('li:first', an[i]).removeClass('disabled');
- }
-
- if ( oPaging.iPage === oPaging.iTotalPages-1 || oPaging.iTotalPages === 0 ) {
- $('li:last', an[i]).addClass('disabled');
- } else {
- $('li:last', an[i]).removeClass('disabled');
- }
- }
- }
- }
-} );
+$.extend($.fn.dataTableExt.oStdClasses, {
+ 'sPageEllipsis': 'paginate_ellipsis',
+ 'sPageNumber': 'paginate_number',
+ 'sPageNumbers': 'paginate_numbers'
+});
+
+$.fn.dataTableExt.oPagination.bootstrap = {
+ 'oDefaults': {
+ 'iShowPages': 5
+ },
+ 'fnClickHandler': function(e) {
+ var fnCallbackDraw = e.data.fnCallbackDraw,
+ oSettings = e.data.oSettings,
+ sPage = e.data.sPage;
+
+ if ($(this).is('[disabled]')) {
+ return false;
+ }
+
+ oSettings.oApi._fnPageChange(oSettings, sPage);
+ fnCallbackDraw(oSettings);
+
+ return true;
+ },
+ // fnInit is called once for each instance of pager
+ 'fnInit': function(oSettings, nPager, fnCallbackDraw) {
+ var oClasses = oSettings.oClasses,
+ oLang = oSettings.oLanguage.oPaginate,
+ that = this;
+
+ var iShowPages = oSettings.oInit.iShowPages || this.oDefaults.iShowPages,
+ iShowPagesHalf = Math.floor(iShowPages / 2);
+
+ $.extend(oSettings, {
+ _iShowPages: iShowPages,
+ _iShowPagesHalf: iShowPagesHalf,
+ });
+
+ var oFirst = $('⇐'),
+ oPrevious = $('←'),
+ oNumbers = $(''),
+ oNext = $('→'),
+ oLast = $('⇒');
+
+ oFirst.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': 'first' }, that.fnClickHandler);
+ oPrevious.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': 'previous' }, that.fnClickHandler);
+ oNext.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': 'next' }, that.fnClickHandler);
+ oLast.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': 'last' }, that.fnClickHandler);
+
+ // Draw
+ $(nPager).append(oFirst, oPrevious, oNumbers, oNext, oLast);
+ },
+ // fnUpdate is only called once while table is rendered
+ 'fnUpdate': function(oSettings, fnCallbackDraw) {
+ var oClasses = oSettings.oClasses,
+ that = this;
+
+ var tableWrapper = oSettings.nTableWrapper;
+
+ // Update stateful properties
+ this.fnUpdateState(oSettings);
+
+ if (oSettings._iCurrentPage === 1) {
+ $('.paging_first', tableWrapper).attr('disabled', true);
+ $('.paging_prev', tableWrapper).attr('disabled', true);
+ } else {
+ $('.paging_first', tableWrapper).removeAttr('disabled');
+ $('.paging_prev', tableWrapper).removeAttr('disabled');
+ }
+
+ if (oSettings._iTotalPages === 0 || oSettings._iCurrentPage === oSettings._iTotalPages) {
+ $('.paging_next', tableWrapper).attr('disabled', true);
+ $('.paging_last', tableWrapper).attr('disabled', true);
+ } else {
+ $('.paging_next', tableWrapper).removeAttr('disabled');
+ $('.paging_last', tableWrapper).removeAttr('disabled');
+ }
+
+ var i, oNumber, oNumbers = $('.paging_num', tableWrapper);
+
+ // Erase
+ oNumbers.html('');
+
+ for (i = oSettings._iFirstPage; i <= oSettings._iLastPage; i++) {
+ oNumber = $('' + oSettings.fnFormatNumber(i) + '');
+
+ if (oSettings._iCurrentPage === i) {
+ oNumber.attr('active', true).attr('disabled', true).addClass('btn-primary');
+ } else {
+ oNumber.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': i - 1 }, that.fnClickHandler);
+ }
+
+ // Draw
+ oNumbers.append(oNumber);
+ }
+
+ // Add ellipses
+ if (1 < oSettings._iFirstPage) {
+ oNumbers.prepend('...');
+ }
+
+ if (oSettings._iLastPage < oSettings._iTotalPages) {
+ oNumbers.append('...');
+ }
+ },
+ // fnUpdateState used to be part of fnUpdate
+ // The reason for moving is so we can access current state info before fnUpdate is called
+ 'fnUpdateState': function(oSettings) {
+ var iCurrentPage = Math.ceil((oSettings._iDisplayStart + 1) / oSettings._iDisplayLength),
+ iTotalPages = Math.ceil(oSettings.fnRecordsTotal() / oSettings._iDisplayLength),
+ iFirstPage = iCurrentPage - oSettings._iShowPagesHalf,
+ iLastPage = iCurrentPage + oSettings._iShowPagesHalf;
+
+ if (iTotalPages < oSettings._iShowPages) {
+ iFirstPage = 1;
+ iLastPage = iTotalPages;
+ } else if (iFirstPage < 1) {
+ iFirstPage = 1;
+ iLastPage = oSettings._iShowPages;
+ } else if (iLastPage > iTotalPages) {
+ iFirstPage = (iTotalPages - oSettings._iShowPages) + 1;
+ iLastPage = iTotalPages;
+ }
+
+ $.extend(oSettings, {
+ _iCurrentPage: iCurrentPage,
+ _iTotalPages: iTotalPages,
+ _iFirstPage: iFirstPage,
+ _iLastPage: iLastPage
+ });
+ }
+};
diff --git a/share/templates/helpers/datatables.tt b/share/templates/helpers/datatables.tt
index 5cb61edee1..acc94a4ad9 100644
--- a/share/templates/helpers/datatables.tt
+++ b/share/templates/helpers/datatables.tt
@@ -20,6 +20,7 @@ $(document).ready(function() {
"bSort": true,
"bInfo": true,
"iDisplayLength": 5,
+ 'iShowPages': 5,
"sAjaxSource": "[% helper.ajax_uri %]",
[% IF helper.column_sort -%]
"aaSorting": [
diff --git a/share/templates/helpers/datatables_field.tt b/share/templates/helpers/datatables_field.tt
index 3c74a2503e..b1354919df 100644
--- a/share/templates/helpers/datatables_field.tt
+++ b/share/templates/helpers/datatables_field.tt
@@ -23,6 +23,7 @@ $(document).ready(function() {
"bSort": true,
"bInfo": true,
"iDisplayLength": 4,
+ 'iShowPages': 5,
"sAjaxSource": "[% ajax_src %]",
"aoColumns": [