tablesorter/addons/pager/jquery.tablesorter.pager.js
evanboho 554c5269f7 Fix table reset on pagination change
We were getting an issue we were getting:
1) filtering to, say, 15 rows
2) moving to the last page
3) changing the pagination to more than 15 (or whatever)
4) no rows displayed

This seemed to fix it.
2014-03-18 15:25:37 -07:00

809 lines
27 KiB
JavaScript

/*!
* tablesorter pager plugin
* updated 3/7/2014 (v2.15.6)
*/
/*jshint browser:true, jquery:true, unused:false */
;(function($) {
"use strict";
/*jshint supernew:true */
var ts = $.tablesorter;
$.extend({ tablesorterPager: new function() {
this.defaults = {
// target the pager markup
container: null,
// 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,
// modify the url after all processing has been applied
customAjaxUrl: function(table, url) { return url; },
// modify the $.ajax object to allow complete control over your ajax requests
ajaxObject: {
dataType: 'json'
},
// set this to false if you want to block ajax loading on init
processAjaxOnInit: true,
// process ajax so that the following information is returned:
// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
// example:
// [
// 100, // total rows
// [
// [ "row1cell1", "row1cell2", ... "row1cellN" ],
// [ "row2cell1", "row2cell2", ... "row2cellN" ],
// ...
// [ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
// ],
// [ "header1", "header2", ... "headerN" ] // optional
// ]
ajaxProcessing: function(ajax){ return [ 0, [], null ]; },
// output default: '{page}/{totalPages}'
// possible variables: {page}, {totalPages}, {filteredPages}, {startRow}, {endRow}, {filteredRows} and {totalRows}
output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}'
// apply disabled classname to the pager arrows when the rows at either extreme is visible
updateArrows: true,
// starting page of the pager (zero based index)
page: 0,
// Number of visible rows
size: 10,
// Save pager page & size if the storage script is loaded (requires $.tablesorter.storage in jquery.tablesorter.widgets.js)
savePages: true,
// defines custom storage key
storageKey: 'tablesorter-pager',
// if true, the table will remain the same height no matter how many records are displayed. The space is made up by an empty
// table row set to a height to compensate; default is false
fixedHeight: false,
// count child rows towards the set page size? (set true if it is a visible table row within the pager)
// if true, child row(s) may not appear to be attached to its parent row, may be split across pages or
// may distort the table if rowspan or cellspans are included.
countChildRows: false,
// remove rows from the table to speed up the sort of large tables.
// setting this to false, only hides the non-visible rows; needed if you plan to add/remove rows with the pager enabled.
removeRows: false, // removing rows in larger tables speeds up the sort
// css class names of pager arrows
cssFirst: '.first', // go to first page arrow
cssPrev: '.prev', // previous page arrow
cssNext: '.next', // next page arrow
cssLast: '.last', // go to last page arrow
cssGoto: '.gotoPage', // go to page selector - select dropdown that sets the current page
cssPageDisplay: '.pagedisplay', // location of where the "output" is displayed
cssPageSize: '.pagesize', // page size selector - select dropdown that sets the "size" option
cssErrorRow: 'tablesorter-errorRow', // error information row
// class added to arrows when at the extremes (i.e. prev/first arrows are "disabled" when on the first page)
cssDisabled: 'disabled', // Note there is no period "." in front of this class name
// stuff not set by the user
totalRows: 0,
totalPages: 0,
filteredRows: 0,
filteredPages: 0,
ajaxCounter: 0,
currentFilters: [],
startRow: 0,
endRow: 0,
$size: null,
last: {}
};
var $this = this,
// hide arrows at extremes
pagerArrows = function(p, disable) {
var a = 'addClass',
r = 'removeClass',
d = p.cssDisabled,
dis = !!disable,
first = ( dis || p.page === 0 ),
tp = Math.min( p.totalPages, p.filteredPages ),
last = ( dis || (p.page === tp - 1) || p.totalPages === 0 );
if ( p.updateArrows ) {
p.$container.find(p.cssFirst + ',' + p.cssPrev)[ first ? a : r ](d).attr('aria-disabled', first);
p.$container.find(p.cssNext + ',' + p.cssLast)[ last ? a : r ](d).attr('aria-disabled', last);
}
},
updatePageDisplay = function(table, p, completed) {
var i, pg, s, out,
c = table.config,
f = c.$table.hasClass('hasFilters') && !p.ajaxUrl,
t = (c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered') + ',' + c.selectorRemove +
(p.countChildRows ? '' : ',.' + c.cssChildRow),
sz = p.size || 10; // don't allow dividing by zero
p.totalPages = Math.ceil( p.totalRows / sz ); // needed for "pageSize" method
p.filteredRows = (f) ? c.$tbodies.eq(0).children('tr').not('.' + t ).length : p.totalRows;
p.filteredPages = (f) ? Math.ceil( p.filteredRows / sz ) || 1 : p.totalPages;
if ( Math.min( p.totalPages, p.filteredPages ) >= 0 ) {
t = (p.size * p.page > p.filteredRows);
p.startRow = (t) ? 1 : (p.filteredRows === 0 ? 0 : p.size * p.page + 1);
p.page = (t) ? 0 : p.page;
p.endRow = Math.min( p.filteredRows, p.totalRows, p.size * ( p.page + 1 ) );
out = p.$container.find(p.cssPageDisplay);
// form the output string (can now get a new output string from the server)
s = ( p.ajaxData && p.ajaxData.output ? p.ajaxData.output || p.output : p.output )
// {page} = one-based index; {page+#} = zero based index +/- value
.replace(/\{page([\-+]\d+)?\}/gi, function(m,n){
return p.totalPages ? p.page + (n ? parseInt(n, 10) : 1) : 0;
})
// {totalPages}, {extra}, {extra:0} (array) or {extra : key} (object)
.replace(/\{\w+(\s*:\s*\w+)?\}/gi, function(m){
var str = m.replace(/[{}\s]/g,''),
extra = str.split(':'),
data = p.ajaxData,
// return zero for default page/row numbers
deflt = /(rows?|pages?)$/i.test(str) ? 0 : '';
return extra.length > 1 && data && data[extra[0]] ? data[extra[0]][extra[1]] : p[str] || (data ? data[str] : deflt) || deflt;
});
if (out.length) {
out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
if ( p.$goto.length ) {
t = '';
pg = Math.min( p.totalPages, p.filteredPages );
for ( i = 1; i <= pg; i++ ) {
t += '<option>' + i + '</option>';
}
p.$goto.html(t).val( p.page + 1 );
}
}
}
pagerArrows(p);
if (p.initialized && completed !== false) {
c.$table.trigger('pagerComplete', p);
// save pager info to storage
if (p.savePages && ts.storage) {
ts.storage(table, p.storageKey, {
page : p.page,
size : p.size
});
}
}
},
fixHeight = function(table, p) {
var d, h,
c = table.config,
$b = c.$tbodies.eq(0);
if (p.fixedHeight) {
$b.find('tr.pagerSavedHeightSpacer').remove();
h = $.data(table, 'pagerSavedHeight');
if (h) {
d = h - $b.height();
if ( d > 5 && $.data(table, 'pagerLastSize') === p.size && $b.children('tr:visible').length < p.size ) {
$b.append('<tr class="pagerSavedHeightSpacer ' + c.selectorRemove.replace(/(tr)?\./g,'') + '" style="height:' + d + 'px;"></tr>');
}
}
}
},
changeHeight = function(table, p) {
var $b = table.config.$tbodies.eq(0);
$b.find('tr.pagerSavedHeightSpacer').remove();
$.data(table, 'pagerSavedHeight', $b.height());
fixHeight(table, p);
$.data(table, 'pagerLastSize', p.size);
},
hideRows = function(table, p){
if (!p.ajaxUrl) {
var i,
c = table.config,
rows = c.$tbodies.eq(0).children(),
l = rows.length,
s = ( p.page * p.size ),
e = s + p.size,
f = c.widgetOptions && c.widgetOptions.filter_filteredRow || 'filtered',
j = 0; // size counter
for ( i = 0; i < l; i++ ){
if ( !rows[i].className.match(f) ) {
rows[i].style.display = ( j >= s && j < e ) ? '' : 'none';
// don't count child rows
j += rows[i].className.match(c.cssChildRow + '|' + c.selectorRemove.slice(1)) && !p.countChildRows ? 0 : 1;
}
}
}
},
hideRowsSetup = function(table, p){
p.size = parseInt( p.$size.val(), 10 ) || p.size;
$.data(table, 'pagerLastSize', p.size);
pagerArrows(p);
if ( !p.removeRows ) {
hideRows(table, p);
$(table).bind('sortEnd.pager filterEnd.pager', function(){
hideRows(table, p);
});
}
},
renderAjax = function(data, table, p, xhr, exception){
// process data
if ( typeof(p.ajaxProcessing) === "function" ) {
// ajaxProcessing result: [ total, rows, headers ]
var i, j, hsh, $f, $sh, t, th, d, l, rr_count,
c = table.config,
$t = c.$table,
tds = '',
result = p.ajaxProcessing(data, table) || [ 0, [] ],
hl = $t.find('thead th').length;
// Clean up any previous error.
ts.showError(table);
if ( exception ) {
if (c.debug) {
ts.log('Ajax Error', xhr, exception);
}
ts.showError(table,
xhr.status === 0 ? 'Not connected, verify Network' :
xhr.status === 404 ? 'Requested page not found [404]' :
xhr.status === 500 ? 'Internal Server Error [500]' :
exception === 'parsererror' ? 'Requested JSON parse failed' :
exception === 'timeout' ? 'Time out error' :
exception === 'abort' ? 'Ajax Request aborted' :
'Uncaught error: ' + xhr.statusText + ' [' + xhr.status + ']' );
c.$tbodies.eq(0).empty();
p.totalRows = 0;
} else {
// process ajax object
if (!$.isArray(result)) {
p.ajaxData = result;
p.totalRows = result.total;
th = result.headers;
d = result.rows;
} else {
// allow [ total, rows, headers ] or [ rows, total, headers ]
t = isNaN(result[0]) && !isNaN(result[1]);
// ensure a zero returned row count doesn't fail the logical ||
rr_count = result[t ? 1 : 0];
p.totalRows = isNaN(rr_count) ? p.totalRows || 0 : rr_count;
d = p.totalRows === 0 ? [""] : result[t ? 0 : 1] || []; // row data
th = result[2]; // headers
}
l = d.length;
if (d instanceof jQuery) {
// append jQuery object
c.$tbodies.eq(0).empty().append(d);
} else if (l) {
// build table from array
for ( i = 0; i < l; i++ ) {
tds += '<tr>';
for ( j = 0; j < d[i].length; j++ ) {
// build tbody cells; watch for data containing HTML markup - see #434
tds += /^\s*<td/.test(d[i][j]) ? $.trim(d[i][j]) : '<td>' + d[i][j] + '</td>';
}
tds += '</tr>';
}
// add rows to first tbody
if (p.processAjaxOnInit) {
c.$tbodies.eq(0).html( tds );
} else {
p.processAjaxOnInit = true;
}
}
// only add new header text if the length matches
if ( th && th.length === hl ) {
hsh = $t.hasClass('hasStickyHeaders');
$sh = hsh ? c.widgetOptions.$sticky.children('thead:first').children().children() : '';
$f = $t.find('tfoot tr:first').children();
// don't change td headers (may contain pager)
c.$headers.filter('th').each(function(j){
var $t = $(this), icn;
// add new test within the first span it finds, or just in the header
if ( $t.find('.' + ts.css.icon).length ) {
icn = $t.find('.' + ts.css.icon).clone(true);
$t.find('.tablesorter-header-inner').html( th[j] ).append(icn);
if ( hsh && $sh.length ) {
icn = $sh.eq(j).find('.' + ts.css.icon).clone(true);
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] ).append(icn);
}
} else {
$t.find('.tablesorter-header-inner').html( th[j] );
if (hsh && $sh.length) {
$sh.eq(j).find('.tablesorter-header-inner').html( th[j] );
}
}
$f.eq(j).html( th[j] );
});
}
}
if (c.showProcessing) {
ts.isProcessing(table); // remove loading icon
}
// make sure last pager settings are saved, prevents multiple server side calls with
// the same parameters
p.totalPages = Math.ceil( p.totalRows / ( p.size || 10 ) );
p.last.totalRows = p.totalRows;
p.last.currentFilters = p.currentFilters;
p.last.sortList = (c.sortList || []).join(',');
updatePageDisplay(table, p);
fixHeight(table, p);
$t.trigger('updateCache', [function(){
if (p.initialized) {
// apply widgets after table has rendered
$t
.trigger('applyWidgets')
.trigger('pagerChange', p);
}
}]);
}
if (!p.initialized) {
p.initialized = true;
$(table)
.trigger('applyWidgets')
.trigger('pagerInitialized', p);
}
},
getAjax = function(table, p){
var url = getAjaxUrl(table, p),
$doc = $(document),
counter,
c = table.config;
if ( url !== '' ) {
if (c.showProcessing) {
ts.isProcessing(table, true); // show loading icon
}
$doc.bind('ajaxError.pager', function(e, xhr, settings, exception) {
renderAjax(null, table, p, xhr, exception);
$doc.unbind('ajaxError.pager');
});
counter = ++p.ajaxCounter;
p.ajaxObject.url = url; // from the ajaxUrl option and modified by customAjaxUrl
p.ajaxObject.success = function(data) {
// Refuse to process old ajax commands that were overwritten by new ones - see #443
if (counter < p.ajaxCounter){
return;
}
renderAjax(data, table, p);
$doc.unbind('ajaxError.pager');
if (typeof p.oldAjaxSuccess === 'function') {
p.oldAjaxSuccess(data);
}
};
if (c.debug) {
ts.log('ajax initialized', p.ajaxObject);
}
$.ajax(p.ajaxObject);
}
},
getAjaxUrl = function(table, p) {
var c = table.config,
url = (p.ajaxUrl) ? p.ajaxUrl
// allow using "{page+1}" in the url string to switch to a non-zero based index
.replace(/\{page([\-+]\d+)?\}/, function(s,n){ return p.page + (n ? parseInt(n, 10) : 0); })
.replace(/\{size\}/g, p.size) : '',
sl = c.sortList,
fl = p.currentFilters || $(table).data('lastSearch') || [],
sortCol = url.match(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/),
filterCol = url.match(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/),
arry = [];
if (sortCol) {
sortCol = sortCol[1];
$.each(sl, function(i,v){
arry.push(sortCol + '[' + v[0] + ']=' + v[1]);
});
// if the arry is empty, just add the col parameter... "&{sortList:col}" becomes "&col"
url = url.replace(/\{\s*sort(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : sortCol );
arry = [];
}
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(/\{\s*filter(?:List)?\s*:\s*(\w*)\s*\}/g, arry.length ? arry.join('&') : filterCol );
p.currentFilters = fl;
}
if ( typeof(p.customAjaxUrl) === "function" ) {
url = p.customAjaxUrl(table, url);
}
if (c.debug) {
ts.log('Pager ajax url: ' + url);
}
return url;
},
renderTable = function(table, rows, p) {
var i, $tb,
$t = $(table),
c = table.config,
l = rows && rows.length || 0, // rows may be undefined
s = ( p.page * p.size ),
e = ( s + p.size );
if ( l < 1 ) { return; } // empty table, abort!
if ( p.page >= p.totalPages ) {
// lets not render the table more than once
moveToLastPage(table, p);
}
p.isDisabled = false; // needed because sorting will change the page and re-enable the pager
if (p.initialized) { $t.trigger('pagerChange', p); }
if ( !p.removeRows ) {
hideRows(table, p);
} else {
if ( e > rows.length ) {
e = rows.length;
}
ts.clearTableBody(table);
$tb = ts.processTbody(table, c.$tbodies.eq(0), true);
for ( i = s; i < e; i++ ) {
$tb.append(rows[i]);
}
ts.processTbody(table, $tb, false);
}
updatePageDisplay(table, p);
if ( !p.isDisabled ) { fixHeight(table, p); }
$t.trigger('applyWidgets');
if (table.isUpdating) {
$t.trigger("updateComplete", table);
}
},
showAllRows = function(table, p){
if ( p.ajax ) {
pagerArrows(p, true);
} else {
p.isDisabled = true;
$.data(table, 'pagerLastPage', p.page);
$.data(table, 'pagerLastSize', p.size);
p.page = 0;
p.size = p.totalRows;
p.totalPages = 1;
$(table)
.addClass('pagerDisabled')
.removeAttr('aria-describedby')
.find('tr.pagerSavedHeightSpacer').remove();
renderTable(table, table.config.rowsCopy, p);
if (table.config.debug) {
ts.log('pager disabled');
}
}
// disable size selector
p.$size.add(p.$goto).each(function(){
$(this).attr('aria-disabled', 'true').addClass(p.cssDisabled)[0].disabled = true;
});
},
moveToPage = function(table, p, pageMoved) {
if ( p.isDisabled ) { return; }
var c = table.config,
$t = $(table),
l = p.last,
pg = Math.min( p.totalPages, p.filteredPages );
if ( p.page < 0 ) { p.page = 0; }
if ( p.page > ( pg - 1 ) && pg !== 0 ) { p.page = pg - 1; }
// fixes issue where one currentFilter is [] and the other is ['','',''],
// making the next if comparison think the filters are different (joined by commas). Fixes #202.
l.currentFilters = (l.currentFilters || []).join('') === '' ? [] : l.currentFilters;
p.currentFilters = (p.currentFilters || []).join('') === '' ? [] : p.currentFilters;
// don't allow rendering multiple times on the same page/size/totalRows/filters/sorts
if ( l.page === p.page && l.size === p.size && l.totalRows === p.totalRows &&
(l.currentFilters || []).join(',') === (p.currentFilters || []).join(',') &&
l.sortList === (c.sortList || []).join(',') ) { return; }
if (c.debug) {
ts.log('Pager changing to page ' + p.page);
}
p.last = {
page : p.page,
size : p.size,
// fixes #408; modify sortList otherwise it auto-updates
sortList : (c.sortList || []).join(','),
totalRows : p.totalRows,
currentFilters : p.currentFilters || []
};
if (p.ajax) {
getAjax(table, p);
} else if (!p.ajax) {
renderTable(table, c.rowsCopy, p);
}
$.data(table, 'pagerLastPage', p.page);
if (p.initialized && pageMoved !== false) {
$t
.trigger('pageMoved', p)
.trigger('applyWidgets');
if (table.isUpdating) {
$t.trigger('updateComplete');
}
}
},
setPageSize = function(table, size, p) {
p.size = size || p.size || 10;
p.$size.val(p.size);
$.data(table, 'pagerLastPage', p.page);
$.data(table, 'pagerLastSize', p.size);
p.totalPages = Math.ceil( p.totalRows / p.size );
p.filteredPages = Math.ceil( p.filteredRows / p.size );
moveToPage(table, p);
},
moveToFirstPage = function(table, p) {
p.page = 0;
moveToPage(table, p);
},
moveToLastPage = function(table, p) {
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
moveToPage(table, p);
},
moveToNextPage = function(table, p) {
p.page++;
if ( p.page >= ( Math.min( p.totalPages, p.filteredPages ) - 1 ) ) {
p.page = ( Math.min( p.totalPages, p.filteredPages ) - 1 );
}
moveToPage(table, p);
},
moveToPrevPage = function(table, p) {
p.page--;
if ( p.page <= 0 ) {
p.page = 0;
}
moveToPage(table, p);
},
destroyPager = function(table, p){
showAllRows(table, p);
p.$container.hide(); // hide pager
table.config.appender = null; // remove pager appender function
p.initialized = false;
$(table).unbind('destroy.pager sortEnd.pager filterEnd.pager enable.pager disable.pager');
if (ts.storage) {
ts.storage(table, p.storageKey, '');
}
},
enablePager = function(table, p, triggered){
var info,
c = table.config;
p.$size.add(p.$goto).removeClass(p.cssDisabled).removeAttr('disabled').attr('aria-disabled', 'false');
p.isDisabled = false;
p.page = $.data(table, 'pagerLastPage') || p.page || 0;
p.size = $.data(table, 'pagerLastSize') || parseInt(p.$size.find('option[selected]').val(), 10) || p.size || 10;
p.$size.val(p.size); // set page size
p.totalPages = Math.ceil( Math.min( p.totalRows, p.filteredRows ) / p.size );
// if table id exists, include page display with aria info
if ( table.id ) {
info = table.id + '_pager_info';
p.$container.find(p.cssPageDisplay).attr('id', info);
c.$table.attr('aria-describedby', info);
}
if ( triggered ) {
c.$table.trigger('updateRows');
setPageSize(table, p.size, p);
hideRowsSetup(table, p);
fixHeight(table, p);
if (c.debug) {
ts.log('pager enabled');
}
}
};
$this.appender = function(table, rows) {
var c = table.config,
p = c.pager;
if ( !p.ajax ) {
c.rowsCopy = rows;
p.totalRows = p.countChildRows ? c.$tbodies.eq(0).children().length : rows.length;
p.size = $.data(table, 'pagerLastSize') || p.size || 10;
p.totalPages = Math.ceil( p.totalRows / p.size );
renderTable(table, rows, p);
// update display here in case all rows are removed
updatePageDisplay(table, p, false);
}
};
$this.construct = function(settings) {
return this.each(function() {
// check if tablesorter has initialized
if (!(this.config && this.hasInitialized)) { return; }
var t, ctrls, fxn,
table = this,
c = table.config,
p = c.pager = $.extend( {}, $.tablesorterPager.defaults, settings ),
$t = c.$table,
// added in case the pager is reinitialized after being destroyed.
pager = p.$container = $(p.container).addClass('tablesorter-pager').show();
if (c.debug) {
ts.log('Pager initializing');
}
p.oldAjaxSuccess = p.oldAjaxSuccess || p.ajaxObject.success;
c.appender = $this.appender;
if (ts.filter && $.inArray('filter', c.widgets) >= 0) {
// get any default filter settings (data-value attribute) fixes #388
p.currentFilters = c.$table.data('lastSearch') || ts.filter.setDefaults(table, c, c.widgetOptions) || [];
// set, but don't apply current filters
ts.setFilters(table, p.currentFilters, false);
}
if (p.savePages && ts.storage) {
t = ts.storage(table, p.storageKey) || {}; // fixes #387
p.page = isNaN(t.page) ? p.page : t.page;
p.size = ( isNaN(t.size) ? p.size : t.size ) || 10;
$.data(table, 'pagerLastSize', p.size);
}
$t
.unbind('filterStart filterEnd sortEnd disable enable destroy update updateRows updateAll addRows pageSize '.split(' ').join('.pager '))
.bind('filterStart.pager', function(e, filters) {
p.currentFilters = filters;
p.page = 0; // fixes #456
})
// update pager after filter widget completes
.bind('filterEnd.pager sortEnd.pager', function() {
if (p.initialized) {
moveToPage(table, p, false);
updatePageDisplay(table, p, false);
fixHeight(table, p);
}
})
.bind('disable.pager', function(e){
e.stopPropagation();
showAllRows(table, p);
})
.bind('enable.pager', function(e){
e.stopPropagation();
enablePager(table, p, true);
})
.bind('destroy.pager', function(e){
e.stopPropagation();
destroyPager(table, p);
})
.bind('update updateRows updateAll addRows '.split(' ').join('.pager '), function(e){
e.stopPropagation();
hideRows(table, p);
})
.bind('pageSize.pager', function(e,v){
e.stopPropagation();
setPageSize(table, parseInt(v, 10) || 10, p);
hideRows(table, p);
updatePageDisplay(table, p, false);
if (p.$size.length) { p.$size.val(p.size); } // twice?
})
.bind('pageSet.pager', function(e,v){
e.stopPropagation();
p.page = (parseInt(v, 10) || 1) - 1;
if (p.$goto.length) { p.$goto.val(p.size); } // twice?
moveToPage(table, p);
updatePageDisplay(table, p, false);
});
// clicked controls
ctrls = [ p.cssFirst, p.cssPrev, p.cssNext, p.cssLast ];
fxn = [ moveToFirstPage, moveToPrevPage, moveToNextPage, moveToLastPage ];
pager.find(ctrls.join(','))
.attr("tabindex", 0)
.unbind('click.pager')
.bind('click.pager', function(e){
e.stopPropagation();
var i, $t = $(this), l = ctrls.length;
if ( !$t.hasClass(p.cssDisabled) ) {
for (i = 0; i < l; i++) {
if ($t.is(ctrls[i])) {
fxn[i](table, p);
break;
}
}
}
});
// goto selector
p.$goto = pager.find(p.cssGoto);
if ( p.$goto.length ) {
p.$goto
.unbind('change')
.bind('change', function(){
p.page = $(this).val() - 1;
moveToPage(table, p);
updatePageDisplay(table, p, false);
});
}
// page size selector
p.$size = pager.find(p.cssPageSize);
if ( p.$size.length ) {
p.$size.unbind('change.pager').bind('change.pager', function() {
p.$size.val( $(this).val() ); // in case there are more than one pagers
if ( !$(this).hasClass(p.cssDisabled) ) {
setPageSize(table, parseInt( $(this).val(), 10 ), p);
changeHeight(table, p);
}
return false;
});
}
// clear initialized flag
p.initialized = false;
// before initialization event
$t.trigger('pagerBeforeInitialized', p);
enablePager(table, p, false);
if ( typeof(p.ajaxUrl) === 'string' ) {
// ajax pager; interact with database
p.ajax = true;
//When filtering with ajax, allow only custom filtering function, disable default filtering since it will be done server side.
c.widgetOptions.filter_serversideFiltering = true;
c.serverSideSorting = true;
moveToPage(table, p);
} else {
p.ajax = false;
// Regular pager; all rows stored in memory
$(this).trigger("appendCache", true);
hideRowsSetup(table, p);
}
changeHeight(table, p);
// pager initialized
if (!p.ajax) {
p.initialized = true;
$(table).trigger('pagerInitialized', p);
}
});
};
}() });
// see #486
ts.showError = function(table, message){
$(table).each(function(){
var $row,
c = this.config,
errorRow = c.pager && c.pager.cssErrorRow || c.widgetOptions.pager_css && c.widgetOptions.pager_css.errorRow || 'tablesorter-errorRow';
if (c) {
if (typeof message === 'undefined') {
c.$table.find('thead').find(c.selectorRemove).remove();
} else {
$row = ( /tr\>/.test(message) ? $(message) : $('<tr><td colspan="' + c.columns + '">' + message + '</td></tr>') )
.click(function(){
$(this).remove();
})
// add error row to thead instead of tbody, or clicking on the header will result in a parser error
.appendTo( c.$table.find('thead:first') )
.addClass( errorRow + ' ' + c.selectorRemove.replace(/^[.#]/, '') )
.attr({
role : 'alert',
'aria-live' : 'assertive'
});
}
}
});
};
// extend plugin scope
$.fn.extend({
tablesorterPager: $.tablesorterPager.construct
});
})(jQuery);