From 8be0ac497debd2a971471c3f01d571c31a2c2d61 Mon Sep 17 00:00:00 2001
From: Frank van Os <frank@sosocio.com>
Date: Mon, 25 Jan 2016 14:43:02 +0100
Subject: [PATCH 1/5] ADDED page based pagination

---
 pagination/dynamic_pagination.js | 227 +++++++++++++++++++++++++++++++
 1 file changed, 227 insertions(+)
 create mode 100644 pagination/dynamic_pagination.js

diff --git a/pagination/dynamic_pagination.js b/pagination/dynamic_pagination.js
new file mode 100644
index 0000000..62c5684
--- /dev/null
+++ b/pagination/dynamic_pagination.js
@@ -0,0 +1,227 @@
+/**
+ * This pagination plug-in provides multiple navigation types ( Select box, input, or basic navigation )
+ * 
+ * To set the limits:
+ *
+ * 'maxNormalPages' is used for the maximum pages in normal mode
+ * 'maxSelectPages' is used for the selectbox mode
+ * 'maxInputPages' is used for the input mode,
+ * 'bootstrapTooltip' is used to display max input value for the input mode with bootstrap tooltip plugin
+ *
+ *  @name Dynamic input,select or basic navigation
+ *
+ *  @summary Show a `dt-tag select`,`dt-tag input` or basic navigation the user can use to navigate through the tables.
+ *  @author Frank van Os
+ *
+ *  @example
+ *    $(document).ready(function() {
+ *        $('#example').dataTable( {
+ *            "sPaginationType": "dynamic_pagination"
+ *        } );
+ *    } );
+ */
+$.fn.dataTableExt.oPagination.dynamic_pagination = {
+     'maxNormalPages': 10,
+     'maxSelectPages': 20,
+     'maxInputPages': 50,
+     'bootstrapTooltip': false,
+     '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;
+    },
+	/*
+	 * Function: oPagination.dynamic_pagination.fnInit
+	 * Purpose:  Initalise dom elements required for pagination with listbox input
+	 * Returns:  -
+	 * Inputs:   object:oSettings - dataTables settings object
+	 *             node:nPaging - the DIV which contains this pagination control
+	 *             function:fnCallbackDraw - draw function which must be called on update
+	 */
+	"fnInit": function (oSettings, nPaging, fnCallbackDraw) {
+		
+		if (oSettings.sTableId !== '') {
+			$(nPaging).attr('id', oSettings.sTableId + '_paginate');
+		}
+		
+		var oClasses = oSettings.oClasses,
+			oLang = oSettings.oLanguage.oPaginate;
+		
+		var PagingHolder = $('<ul/>').addClass('pagination');
+		var nInputText = $('<input/>').attr('type','text').css('display','none');
+		var nInputSelect = $('<select/>').css('display','none').addClass('form-control');
+        
+		var nFirst = $('<li/>').addClass(oClasses.sPageButton+' first').html($('<a/>').attr('href','#').text(oLang.sFirst));
+		var nNext = $('<li/>').addClass(oClasses.sPageButton+' next').html($('<a/>').attr('href','#').text(oLang.sNext));
+		var nInput = $('<li/>').attr('id',oSettings.sTableId+'_pagination_controls').addClass(oClasses.sPageButton).append(nInputText,nInputSelect);
+		var nPrev = $('<li/>').addClass(oClasses.sPageButton+' previous').html($('<a/>').attr('href','#').text(oLang.sPrevious));
+		var nLast = $('<li/>').addClass(oClasses.sPageButton+' last').html($('<a/>').attr('href','#').text(oLang.sLast));
+		
+        
+		$(PagingHolder).append(nFirst, nPrev, nInput, nNext, nLast).appendTo(nPaging);
+		
+        $(nPaging).on('click','li:not(#'+oSettings.sTableId+'_pagination_controls) a',function (event) {
+	        if(!$(this).parent('li').hasClass('disabled')){
+	        	var nav = $(this).parent('li').attr('class').split(' ').pop();
+			
+				if($.inArray(nav,['first','last','previous','next']) !== -1){
+				    oSettings.oApi._fnPageChange( oSettings, nav );
+				    fnCallbackDraw( oSettings );
+				}
+			}
+            event.preventDefault();
+        } );
+         
+		function updatePage(element){
+			if (element.val() === '' || element.val().match(/[^0-9]/)) {
+				/* Nothing entered or non-numeric character */
+				element.val() = element.val().replace(/[^\d]/g, ''); // don't even allow anything but digits
+				return;
+			}
+
+			var iNewStart = oSettings._iDisplayLength * (element.val() - 1);
+			if (iNewStart < 0) {
+				iNewStart = 0;
+			}
+			if (iNewStart >= oSettings.fnRecordsDisplay()) {
+				iNewStart = (Math.ceil((oSettings.fnRecordsDisplay() - 1) / oSettings._iDisplayLength) - 1) * oSettings._iDisplayLength;
+			}
+			
+			oSettings._iDisplayStart = iNewStart;
+			fnCallbackDraw(oSettings);
+		}
+		
+		$(nInputText).keypress(function (e) {
+			// On return navigate to given page
+			if(e.which === 13){
+				updatePage($(this));
+			}
+		});
+
+		$(nInputSelect).change(function (e) { // Set DataTables page property and redraw the grid on listbox change event.
+			updatePage($(this));
+		});
+
+        /* Disallow text selection */
+        $('li.first,li.next,li.previous,li.last').bind( 'selectstart', function (evt) { evt.preventDefault(); } );
+		
+	},
+	 
+	/*
+	 * Function: oPagination.listbox.fnUpdate
+	 * Purpose:  Update the listbox element
+	 * Returns:  -
+	 * Inputs:   object:oSettings - dataTables settings object
+	 *             function:fnCallbackDraw - draw function which must be called on update
+	 */
+	"fnUpdate": function (oSettings, fnCallbackDraw) {
+		if (!oSettings.aanFeatures.p) {
+			return;
+		}
+        
+		var iPages = Math.ceil((oSettings.fnRecordsDisplay()) / oSettings._iDisplayLength);
+		var iCurrentPage = Math.ceil(oSettings._iDisplayStart / oSettings._iDisplayLength) + 1; /* Loop over each instance of the pager */
+		var paging = oSettings.aanFeatures.p;
+        var oClasses = oSettings.oClasses;
+		var info = oSettings.aanFeatures.i;
+        var that = this;
+		
+        for (var i = 0, iLen = paging.length; i < iLen; i++) {
+
+            if ( oSettings._iDisplayStart === 0 ){
+                $(paging).find('.first').attr('class',"paginate_button disabled first");
+                $(paging).find('.previous').attr('class',"paginate_button disabled previous");
+            }
+            else {
+                $(paging).find('.first').attr('class',"paginate_button first");
+                $(paging).find('.previous').attr('class',"paginate_button previous");
+            }
+
+            if ( oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay() ){
+                $(paging).find('.next').attr('class',"paginate_button disabled next");
+                $(paging).find('.last').attr('class',"paginate_button disabled last");
+            }
+            else{
+                $(paging).find('.next').attr('class',"paginate_button next");
+                $(paging).find('.last').attr('class',"paginate_button last");
+            }
+
+            // Hide pagination block and info block
+			$(paging).hide();
+			$(info).hide();
+			
+            if(iPages < that.maxNormalPages){
+                $(paging).find('select,input').css('display','none');
+
+				// Erase
+              	$('#'+oSettings.sTableId+'_pagination_controls').find('a.paginate_button').remove();
+              					
+                for (var j = 0; j < iPages; j++) { //add the pages
+                    var oNumber = $('<a/>',{
+                        'class': oClasses.sPageButton,
+                        'aria-controls': oSettings.sTableId,
+                        'data-dt-idx': j,
+                        'tabindex': oSettings.iTabIndex
+                    }).text( oSettings.fnFormatNumber(j+1) );
+                    if (iCurrentPage === j+1) {
+                        oNumber.addClass('active').attr('disabled', true);
+                    } else {
+                        oNumber.click({ 'fnCallbackDraw': fnCallbackDraw, 'oSettings': oSettings, 'sPage': j }, that.fnClickHandler);
+                    }
+                    $(oNumber).appendTo('#'+oSettings.sTableId+'_pagination_controls');
+                }
+            }
+            else if(iPages > that.maxSelectPages) {
+
+				// Erase
+              	$('#'+oSettings.sTableId+'_pagination_controls').find('a.paginate_button').remove();
+            	
+                var inputType = (iPages>that.maxInputPages) ? 'input' : 'select';
+                var input = $(paging).find(inputType);
+            
+                $(input).css('display','inline');
+			
+                if(oSettings._iDisplayStart === 0 && oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay()){
+                    $(input).attr('disabled','disabled').attr('class','form-control disabled');
+                }
+                else{
+                    $(input)
+                        .removeAttr('disabled','disabled')
+                        .attr('class','form-control');
+                }
+                
+                if(inputType=='select'){
+                    for (var j = 0; j < iPages; j++) { //add the pages
+                        $(input).append($('<option>', {value:j+1,text:j+1}));
+                    }
+                    $(input).val(iCurrentPage);
+
+                    $(paging).find('input').css('display','none');
+                }
+                else if(inputType=='input'){
+                    if(that.bootstrapTooltip){
+                        $('.pagination > li > input').attr('data-title','Max. page number: '+iPages).tooltip({
+                            container: '.pagination',
+                            placement: 'top'
+                        });
+                    }
+                    $(input).val(iCurrentPage);
+                    $(paging).find('select').css('display','none');                    
+                }
+            }
+            				
+            // When there are pages show pagination block and info block
+            $(paging).show();
+            $(info).show();
+		}
+	}
+};
\ No newline at end of file

From 079321f2743a064de3cac8b1b2101f1bf5fcd44b Mon Sep 17 00:00:00 2001
From: Frank van Os <frank@sosocio.com>
Date: Mon, 25 Jan 2016 15:02:19 +0100
Subject: [PATCH 2/5] ADDED clearing selectbox

---
 pagination/dynamic_pagination.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pagination/dynamic_pagination.js b/pagination/dynamic_pagination.js
index 62c5684..84ad2b1 100644
--- a/pagination/dynamic_pagination.js
+++ b/pagination/dynamic_pagination.js
@@ -200,6 +200,7 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
                 }
                 
                 if(inputType=='select'){
+                    $(input).empty();
                     for (var j = 0; j < iPages; j++) { //add the pages
                         $(input).append($('<option>', {value:j+1,text:j+1}));
                     }

From 90ec7405cd6fe771d8a72673fe6d9e0aee8b892d Mon Sep 17 00:00:00 2001
From: Frank van Os <frank@sosocio.com>
Date: Thu, 28 Jan 2016 10:30:46 +0100
Subject: [PATCH 3/5] FIXED checking limits

---
 pagination/dynamic_pagination.js | 85 ++++++++++++++------------------
 1 file changed, 38 insertions(+), 47 deletions(-)

diff --git a/pagination/dynamic_pagination.js b/pagination/dynamic_pagination.js
index 84ad2b1..985807c 100644
--- a/pagination/dynamic_pagination.js
+++ b/pagination/dynamic_pagination.js
@@ -5,12 +5,9 @@
  *
  * 'maxNormalPages' is used for the maximum pages in normal mode
  * 'maxSelectPages' is used for the selectbox mode
- * 'maxInputPages' is used for the input mode,
- * 'bootstrapTooltip' is used to display max input value for the input mode with bootstrap tooltip plugin
  *
- *  @name Dynamic input,select or basic navigation
- *
- *  @summary Show a `dt-tag select`,`dt-tag input` or basic navigation the user can use to navigate through the tables.
+ *  @name Dynamic input,select list
+ *  @summary Show a `dt-tag select` `dt-tag input` list of pages the user can pick from.
  *  @author Frank van Os
  *
  *  @example
@@ -23,7 +20,6 @@
 $.fn.dataTableExt.oPagination.dynamic_pagination = {
      'maxNormalPages': 10,
      'maxSelectPages': 20,
-     'maxInputPages': 50,
      'bootstrapTooltip': false,
      'fnClickHandler': function(e) {
         var fnCallbackDraw = e.data.fnCallbackDraw,
@@ -84,20 +80,16 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
 		function updatePage(element){
 			if (element.val() === '' || element.val().match(/[^0-9]/)) {
 				/* Nothing entered or non-numeric character */
-				element.val() = element.val().replace(/[^\d]/g, ''); // don't even allow anything but digits
-				return;
-			}
-
-			var iNewStart = oSettings._iDisplayLength * (element.val() - 1);
-			if (iNewStart < 0) {
-				iNewStart = 0;
-			}
-			if (iNewStart >= oSettings.fnRecordsDisplay()) {
-				iNewStart = (Math.ceil((oSettings.fnRecordsDisplay() - 1) / oSettings._iDisplayLength) - 1) * oSettings._iDisplayLength;
-			}
-			
-			oSettings._iDisplayStart = iNewStart;
-			fnCallbackDraw(oSettings);
+                return;
+            }
+            var iNewStart = oSettings._iDisplayLength * (element.val() - 1);
+            if (iNewStart > oSettings.fnRecordsDisplay()) { /* Display overrun */
+                oSettings._iDisplayStart = (Math.ceil((oSettings.fnRecordsDisplay() - 1) / oSettings._iDisplayLength) - 1) * oSettings._iDisplayLength;
+                fnCallbackDraw(oSettings);
+                return;
+            }
+            oSettings._iDisplayStart = iNewStart;
+            fnCallbackDraw(oSettings);
 		}
 		
 		$(nInputText).keypress(function (e) {
@@ -135,7 +127,7 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
 		var info = oSettings.aanFeatures.i;
         var that = this;
 		
-        for (var i = 0, iLen = paging.length; i < iLen; i++) {
+		for (var i = 0, iLen = paging.length; i < iLen; i++) {
 
             if ( oSettings._iDisplayStart === 0 ){
                 $(paging).find('.first').attr('class',"paginate_button disabled first");
@@ -158,8 +150,8 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
             // Hide pagination block and info block
 			$(paging).hide();
 			$(info).hide();
-			
-            if(iPages < that.maxNormalPages){
+            
+            if(iPages <= that.maxNormalPages){
                 $(paging).find('select,input').css('display','none');
 
 				// Erase
@@ -180,45 +172,44 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
                     $(oNumber).appendTo('#'+oSettings.sTableId+'_pagination_controls');
                 }
             }
-            else if(iPages > that.maxSelectPages) {
+            else if(iPages > that.maxNormalPages && iPages <= that.maxSelectPages) {
 
 				// Erase
               	$('#'+oSettings.sTableId+'_pagination_controls').find('a.paginate_button').remove();
             	
-                var inputType = (iPages>that.maxInputPages) ? 'input' : 'select';
-                var input = $(paging).find(inputType);
+                var input = $(paging).find('select');
             
-                $(input).css('display','inline');
+                input.css('display','inline');
 			
                 if(oSettings._iDisplayStart === 0 && oSettings.fnDisplayEnd() == oSettings.fnRecordsDisplay()){
-                    $(input).attr('disabled','disabled').attr('class','form-control disabled');
+                    input.attr('disabled','disabled').attr('class','form-control disabled');
                 }
                 else{
-                    $(input)
+                    input
                         .removeAttr('disabled','disabled')
                         .attr('class','form-control');
                 }
                 
-                if(inputType=='select'){
-                    $(input).empty();
-                    for (var j = 0; j < iPages; j++) { //add the pages
-                        $(input).append($('<option>', {value:j+1,text:j+1}));
-                    }
-                    $(input).val(iCurrentPage);
+                input.empty();
+		        for (var j = 0; j < iPages; j++) { //add the pages
+		            input.append($('<option>', {value:j+1,text:j+1}));
+				}
+                input.val(iCurrentPage);
 
-                    $(paging).find('input').css('display','none');
-                }
-                else if(inputType=='input'){
-                    if(that.bootstrapTooltip){
-                        $('.pagination > li > input').attr('data-title','Max. page number: '+iPages).tooltip({
-                            container: '.pagination',
-                            placement: 'top'
-                        });
-                    }
-                    $(input).val(iCurrentPage);
-                    $(paging).find('select').css('display','none');                    
-                }
+                $(paging).find('input').css('display','none');
             }
+            else if(iPages > that.maxNormalPages && iPages > that.maxSelectPages){
+				var input = $(paging).find('input');
+				input.css('display','inline');
+			    if(that.bootstrapTooltip){
+			        $('.pagination > li > input').attr('data-title','Max. page number: '+iPages).tooltip({
+			            container: '.pagination',
+			            placement: 'top'
+			        });
+			    }
+			    input.val(iCurrentPage);
+			    $(paging).find('select').css('display','none');                    
+			}
             				
             // When there are pages show pagination block and info block
             $(paging).show();

From 3f214143eb0ffa5e578d78f31875675bb46ab452 Mon Sep 17 00:00:00 2001
From: Frank van Os <frank@sosocio.com>
Date: Thu, 28 Jan 2016 10:45:56 +0100
Subject: [PATCH 4/5] ADDED remove pagination buttons

---
 pagination/dynamic_pagination.js | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/pagination/dynamic_pagination.js b/pagination/dynamic_pagination.js
index 985807c..6675b77 100644
--- a/pagination/dynamic_pagination.js
+++ b/pagination/dynamic_pagination.js
@@ -199,6 +199,9 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
                 $(paging).find('input').css('display','none');
             }
             else if(iPages > that.maxNormalPages && iPages > that.maxSelectPages){
+				// Remove paging buttons
+				$('#'+oSettings.sTableId+'_pagination_controls').find('a.paginate_button').remove();
+				
 				var input = $(paging).find('input');
 				input.css('display','inline');
 			    if(that.bootstrapTooltip){

From 8960315a972024703303f1c8b9d6e72d4d5fa00e Mon Sep 17 00:00:00 2001
From: Frank van Os <frank@sosocio.com>
Date: Thu, 28 Jan 2016 11:45:28 +0100
Subject: [PATCH 5/5] CHANGED bootstrap tooltip

---
 pagination/dynamic_pagination.js | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/pagination/dynamic_pagination.js b/pagination/dynamic_pagination.js
index 6675b77..a3f9bbb 100644
--- a/pagination/dynamic_pagination.js
+++ b/pagination/dynamic_pagination.js
@@ -204,14 +204,16 @@ $.fn.dataTableExt.oPagination.dynamic_pagination = {
 				
 				var input = $(paging).find('input');
 				input.css('display','inline');
+
 			    if(that.bootstrapTooltip){
-			        $('.pagination > li > input').attr('data-title','Max. page number: '+iPages).tooltip({
+			        input.attr('data-original-title','Max. page number: '+Math.ceil(oSettings.fnRecordsDisplay() / oSettings._iDisplayLength));
+			        input.tooltip({
 			            container: '.pagination',
 			            placement: 'top'
 			        });
 			    }
 			    input.val(iCurrentPage);
-			    $(paging).find('select').css('display','none');                    
+			    $(paging).find('select').css('display','none');             
 			}
             				
             // When there are pages show pagination block and info block