diff --git a/addons/pager/jquery.tablesorter.pager.js b/addons/pager/jquery.tablesorter.pager.js
index 6b1e193b2..d2b5248c3 100644
--- a/addons/pager/jquery.tablesorter.pager.js
+++ b/addons/pager/jquery.tablesorter.pager.js
@@ -11,10 +11,12 @@
// target the pager markup
container: null,
- // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}"
- // where {page} is replaced by the page number and {size} is replaced by the number of records to show
- // {sortList:col} adds the sortList to the url into a "col" array.
+ // use this format: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
+ // where {page} is replaced by the page number, {size} is replaced by the number of records to show,
+ // {sortList:col} adds the sortList to the url into a "col" array, and {filterList:fcol} adds
+ // the filterList to the url into an "fcol" array.
// So a sortList = [[2,0],[3,0]] becomes "&col[2]=0&col[3]=0" in the url
+ // and a filterList = [[2,Blue],[3,13]] becomes "&fcol[2]=Blue&fcol[3]=13" in the url
ajaxUrl: null,
// process ajax so that the following information is returned:
@@ -69,7 +71,8 @@
totalRows: 0,
totalPages: 0,
filteredRows: 0,
- filteredPages: 0
+ filteredPages: 0,
+ cssErrorRow: 'tablesorter-errorRow'
};
@@ -81,7 +84,6 @@
r = 'removeClass',
d = c.cssDisabled,
dis = !!disable,
- // tr = Math.min( c.totalRows, c.filteredRows ),
tp = Math.min( c.totalPages, c.filteredPages );
if ( c.updateArrows ) {
$(c.cssFirst + ',' + c.cssPrev, c.container)[ ( dis || c.page === 0 ) ? a : r ](d);
@@ -90,7 +92,7 @@
},
updatePageDisplay = function(table, c) {
- var i, p, s, t, out, f = $(table).hasClass('hasFilters');
+ var i, p, s, t, out, f = $(table).hasClass('hasFilters') && !c.ajaxUrl;
c.filteredRows = (f) ? $(table).find('tbody tr:not(.filtered)').length : c.totalRows;
c.filteredPages = (f) ? Math.ceil( c.filteredRows / c.size ) : c.totalPages;
if ( Math.min( c.totalPages, c.filteredPages ) > 0 ) {
@@ -187,7 +189,7 @@
tc = table.config,
$b = $(table.tBodies).filter(':not(.' + tc.cssInfoBlock + ')'),
hl = $t.find('thead th').length, tds = '',
- err = '
' +
+ err = ' |
' +
(exception ? exception.message + ' (' + exception.name + ')' : 'No rows found') + ' |
',
result = c.ajaxProcessing(data) || [ 0, [] ],
d = result[1] || [],
@@ -225,13 +227,17 @@
$f.eq(j).html( th[j] );
});
}
+
+ $t.find('thead tr.' + c.cssErrorRow).remove(); //Clean up any previous error.
if ( exception ) {
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
$t.find('thead').append(err);
} else {
$b.html( tds ); // add tbody
}
- $.tablesorter.isProcessing(table); // remove loading icon
+ if (tc.showProcessing) {
+ $.tablesorter.isProcessing(table); // remove loading icon
+ }
$t.trigger('update');
c.totalRows = result[0] || 0;
c.totalPages = Math.ceil( c.totalRows / c.size );
@@ -246,28 +252,52 @@
},
getAjax = function(table, c){
+ var url = getAjaxUrl(table, c),
+ tc = table.config;
+ if ( url !== '' ) {
+ if (tc.showProcessing) {
+ $.tablesorter.isProcessing(table, true); // show loading icon
+ }
+ $(document).bind('ajaxError.pager', function(e, xhr, settings, exception) {
+ if (settings.url == url) {
+ renderAjax(null, table, c, exception);
+ $(document).unbind('ajaxError.pager');
+ }
+ });
+ $.getJSON(url, function(data) {
+ renderAjax(data, table, c);
+ $(document).unbind('ajaxError.pager');
+ });
+ }
+ },
+
+ getAjaxUrl = function(table, c) {
var url = (c.ajaxUrl) ? c.ajaxUrl.replace(/\{page\}/g, c.page).replace(/\{size\}/g, c.size) : '',
- arry = [],
sl = table.config.sortList,
- col = url.match(/\{sortList[\s+]?:[\s+]?(.*)\}/);
- if (col) {
- col = col[1];
+ fl = c.currentFilters || [],
+ sortCol = url.match(/\{sortList[\s+]?:[\s+]?([^}]*)\}/),
+ filterCol = url.match(/\{filterList[\s+]?:[\s+]?([^}]*)\}/),
+ arry = [];
+ if (sortCol) {
+ sortCol = sortCol[1];
$.each(sl, function(i,v){
- arry.push(col + '[' + v[0] + ']=' + v[1]);
+ arry.push(sortCol + '[' + v[0] + ']=' + v[1]);
});
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
- url = url.replace(/\{sortList[\s+]?:[\s+]?(.*)\}/g, arry.length ? arry.join('&') : col );
+ url = url.replace(/\{sortList[\s+]?:[\s+]?([^}]*)\}/g, arry.length ? arry.join('&') : sortCol );
}
- if ( url !== '' ) {
- // loading icon
- $.tablesorter.isProcessing(table, true);
- $(document).ajaxError(function(e, xhr, settings, exception) {
- renderAjax(null, table, c, exception);
- });
- $.getJSON(url, function(data) {
- renderAjax(data, table, c);
+ if (filterCol) {
+ filterCol = filterCol[1];
+ $.each(fl, function(i,v){
+ if (v) {
+ arry.push(filterCol + '[' + i + ']=' + encodeURIComponent(v));
+ }
});
+ // if the arry is empty, just add the fcol parameter... "&{filterList:fcol}" becomes "&fcol"
+ url = url.replace(/\{filterList[\s+]?:[\s+]?([^}]*)\}/g, arry.length ? arry.join('&') : filterCol );
}
+
+ return url;
},
renderTable = function(table, rows, c) {
@@ -329,13 +359,13 @@
if ( c.page < 0 || c.page > ( p - 1 ) ) {
c.page = 0;
}
- // change if page changed - fixes #182
- if (c.ajax && $.data(table, 'pagerLastPage') !== c.page) {
+ if (c.ajax) {
getAjax(table, c);
} else if (!c.ajax) {
renderTable(table, table.config.rowsCopy, c);
}
$.data(table, 'pagerLastPage', c.page);
+ $.data(table, 'pagerUpdateTriggered', true);
if (c.initialized) { $(table).trigger('pageMoved', c); }
},
@@ -414,6 +444,7 @@
var config = this.config,
c = config.pager = $.extend( {}, $.tablesorterPager.defaults, settings ),
table = this,
+ tc = table.config,
$t = $(table),
pager = $(c.container).addClass('tablesorter-pager').show(); // added in case the pager is reinitialized after being destroyed.
config.appender = $this.appender;
@@ -423,6 +454,9 @@
if ( typeof(c.ajaxUrl) === 'string' ) {
// ajax pager; interact with database
c.ajax = true;
+ //When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side.
+ tc.widgetOptions.filter_serversideFiltering = true;
+ tc.serverSideSorting = true;
getAjax(table, c);
} else {
c.ajax = false;
@@ -430,17 +464,27 @@
$(this).trigger("appendCache", true);
hideRowsSetup(table, c);
}
-
+
+ $(table)
+ .unbind('filterStart.pager')
+ .bind('filterStart.pager', function(e, filters) {
+ c.currentFilters = filters;
+ });
+
// update pager after filter widget completes
$(table)
- .unbind('filterEnd.pager updateComplete.pager ')
- .bind('filterEnd.pager updateComplete.pager', function() {
- if ($(this).hasClass('hasFilters')) {
- c.page = 0;
- updatePageDisplay(table, c);
- moveToPage(table, c);
- changeHeight(table, c);
+ .unbind('filterEnd.pager sortEnd.pager')
+ .bind('filterEnd.pager sortEnd.pager', function() {
+ //Prevent infinite event loops from occuring by setting this in all moveToPage calls and catching it here.
+ if ($.data(table, 'pagerUpdateTriggered')) {
+ $.data(table, 'pagerUpdateTriggered', false);
+ return;
}
+
+ c.page = 0;
+ updatePageDisplay(table, c);
+ moveToPage(table, c);
+ changeHeight(table, c);
});
if ( $(c.cssGoto, pager).length ) {
diff --git a/js/jquery.tablesorter.js b/js/jquery.tablesorter.js
index 3c6c290fc..188f01a90 100644
--- a/js/jquery.tablesorter.js
+++ b/js/jquery.tablesorter.js
@@ -40,6 +40,7 @@
sortMultiSortKey : 'shiftKey', // key used to select additional columns
usNumberFormat : true, // false for German "1.234.567,89" or French "1 234 567,89"
delayInit : false, // if false, the parsed table contents will not update until the first sort
+ serverSideSorting : false, // if true, server-side sorting should be performed because client-side sorting will be disabled, but the ui and events will still be used.
// sort options
headers : {}, // set sorter, string, empty, locked order, sortInitialOrder, filter, etc.
@@ -459,6 +460,9 @@
var dynamicExp, sortWrapper, col, mx = 0, dir = 0, tc = table.config,
sortList = tc.sortList, l = sortList.length, bl = table.tBodies.length,
sortTime, i, j, k, c, colMax, cache, lc, s, e, order, orgOrderCol;
+ if (tc.serverSideSorting) {
+ return;
+ }
if (tc.debug) { sortTime = new Date(); }
for (k = 0; k < bl; k++) {
colMax = tc.cache[k].colMax;
diff --git a/js/jquery.tablesorter.widgets.js b/js/jquery.tablesorter.widgets.js
index df1a4d072..99424581d 100644
--- a/js/jquery.tablesorter.widgets.js
+++ b/js/jquery.tablesorter.widgets.js
@@ -282,6 +282,7 @@ $.tablesorter.addWidget({
filter_searchDelay : 300 // typing delay in milliseconds before starting a search
filter_startsWith : false // if true, filter start from the beginning of the cell contents
filter_useParsedData : false // filter all data using parsed content
+ filter_serversideFiltering : false // if true, server-side filtering should be performed because client-side filtering will be disabled, but the ui and events will still be used.
**************************/
$.tablesorter.addWidget({
id: "filter",
@@ -353,7 +354,7 @@ $.tablesorter.addWidget({
$tb = $.tablesorter.processTbody(table, $(b[k]), true);
$tr = $tb.children('tr');
l = $tr.length;
- if (cv === ''){
+ if (cv === '' || wo.filter_serversideFiltering){
$tr.show().removeClass('filtered');
} else {
// loop through the rows