modified ajaxProcessing in pager plugin

This commit is contained in:
Rob Garrison 2012-03-16 23:13:22 -05:00
parent c15ada9bd9
commit c967fac099
10 changed files with 334 additions and 164 deletions

View File

@ -27,13 +27,51 @@ Included all original [document pages](http://mottie.github.com/tablesorter/docs
###Licensing
* Copyright (c) 2007 Christian Bach
* Main Examples and docs at: [http://tablesorter.com](http://tablesorter.com)
* Original examples and docs at: [http://tablesorter.com](http://tablesorter.com)
* Dual licensed under the [MIT](http://www.opensource.org/licenses/mit-license.php) and [GPL](http://www.gnu.org/licenses/gpl.html) licenses:
###Change Log
View the [complete listing here](http://mottie.github.com/tablesorter/changelog.txt).
#### Version 2.1.3 (3/12/2012)
* Added `usNumberFormat` option.
* Set to `true` for U.S. number format: `1,234,567.89`
* Set to `false` for German `1.234.567,89` or French `1 234 567,89` formats.'
* Fix for [issue #34](https://github.com/Mottie/tablesorter/issues/34) and [issue # 31](https://github.com/Mottie/tablesorter/issues/31#issuecomment-4236945).
* Changed pager plugin ajax functions & demo
* The `ajaxProcessing` function now must now return two or three pieces of information: [ total, rows, headers ]
* `total` is the total number of rows in the database.
* `rows` is an array of table rows with an array of table cells in each row.
* `headers` is an array of header cell text (optional).
```javascript
// process ajax so that the following information is returned:
// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
// example:
[
// total # rows contained in the database
100,
// row data: array of arrays; each internal array has the table data
[
[ "row1cell1", "row1cell2", ... "row1cellN" ],
[ "row2cell1", "row2cell2", ... "row2cellN" ],
...
[ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
],
// header text (optional)
[ "Header1", "Header2", ... "HeaderN" ]
]
```
* Modified pager plugin ajax demo to hopefully make the data processing a bit more clear by changing `data` inside of the City#.json files to `rows`.
* The demo json data should now render the unicode characters properly. Switched the files to the proper utf-8 encoding.
* When no data is returned, the table will now:
* Insert a row into the header showing the ajax error. If a row is inserted into the tbody, clicking on the header would cause a parser error.
* Disable the pager so the pager counter won't show zero total rows.
* Fix for issue dicussed within [issue #31](https://github.com/Mottie/tablesorter/issues/31#issuecomment-4390379).
#### Version 2.1.2 (3/11/2012)
* Added `table` and `cellIndex` variables to the `textExtraction` function to allow using a more general function for text extraction.

View File

@ -1,6 +1,6 @@
/*
* tablesorter pager plugin
* updated 3/8/2012
* updated 3/16/2012
*/
(function($) {
@ -14,8 +14,20 @@
// where {page} is replaced by the page number and {size} is replaced by the number of records to show
ajaxUrl: null,
// process ajax so that the data object is returned along with the total number of rows
ajaxProcessing: function(ajax){ return [ [{ "key" : "value" }], 100 ]; },
// 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}'
output: '{startRow} to {endRow} of {totalRows} rows', // '{page}/{totalPages}'
@ -68,21 +80,23 @@
},
updatePageDisplay = function(table, c) {
c.startRow = c.size * (c.page) + 1;
c.endRow = Math.min(c.totalRows, c.size * (c.page+1));
var out = $(c.cssPageDisplay, c.container),
// form the output string
s = c.output.replace(/\{(page|totalPages|startRow|endRow|totalRows)\}/gi, function(m){
return {
'{page}' : c.page + 1,
'{totalPages}' : c.totalPages,
'{startRow}' : c.startRow,
'{endRow}' : c.endRow,
'{totalRows}' : c.totalRows
}[m];
});
if (out[0]) {
out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
if (c.totalPages > 0) {
c.startRow = c.size * (c.page) + 1;
c.endRow = Math.min(c.totalRows, c.size * (c.page+1));
var out = $(c.cssPageDisplay, c.container),
// form the output string
s = c.output.replace(/\{(page|totalPages|startRow|endRow|totalRows)\}/gi, function(m){
return {
'{page}' : c.page + 1,
'{totalPages}' : c.totalPages,
'{startRow}' : c.startRow,
'{endRow}' : c.endRow,
'{totalRows}' : c.totalRows
}[m];
});
if (out[0]) {
out[ (out[0].tagName === 'INPUT') ? 'val' : 'html' ](s);
}
}
pagerArrows(c);
$(table).trigger('pagerComplete', c);
@ -134,59 +148,77 @@
}
},
renderAjax = function(data, table, c, exception){
// process data
if (typeof(c.ajaxProcessing) === "function") {
// ajaxProcessing result: [ total, rows, headers ]
var i, j, k, hsh, $sh, $t = $(table), $b = $(table.tBodies[0]),
hl = $t.find('thead th').length, tf = '', tds = '',
err = '<tr class="remove-me"><td style="text-align: center;" colspan="' + hl + '">' +
(exception ? exception.message + ' (' + exception.name + ')' : 'No rows found') + '</td></tr>',
result = c.ajaxProcessing(data) || [ 0, [] ],
d = result[1] || [], l = d.length, th = result[2];
if (l > 0) {
for ( i=0; i < l; i++ ) {
tds += '<tr>';
for (j=0; j < d[i].length; j++) {
// build tbody cells
tds += '<td>' + d[i][j] + '</td>';
}
tds += '</tr>';
}
}
// only add new header text if the length matches
if (th && th.length === hl) {
hsh = $t.hasClass('hasStickyHeaders');
$sh = $t.find('.' + ((c.widgetOptions && c.widgetOptions.stickyHeaders) || 'tablesorter-stickyheader'));
$t.find('thead tr.tablesorter-header th').each(function(j){
var $t = $(this),
// add new test within the first span it finds, or just in the header
tar = ($t.find('span').length) ? $t.find('span:first') : $t;
tar.html(th[j]);
// update sticky headers
if (hsh && $sh.length){
tar = $sh.find('th').eq(j);
tar = (tar.find('span').length) ? tar.find('span:first') : tar;
tar.html(th[j]);
}
tf += '<th>' + th[j] + '</th>';
});
$t.find('tfoot').html('<tr>' + tf + '</tr>');
}
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
}
c.temp.remove(); // remove loading icon
$t.trigger('update');
c.totalRows = result[0] || 0;
c.totalPages = Math.ceil(c.totalRows / c.size);
updatePageDisplay(table, c);
fixHeight(table, c);
$t.trigger('pagerChange', c);
}
},
getAjax = function(table, c){
var i, $load, $t = $(table), $b = $(table.tBodies[0]),
var $t = $(table),
url = c.ajaxUrl.replace(/\{page\}/g, c.page).replace(/\{size\}/g, c.size);
if (url !== '') {
// loading icon
$load = $('<div/>', {
c.temp = $('<div/>', {
id : 'tablesorterPagerLoading',
width : $t.outerWidth(true),
height: $t.outerHeight(true)
});
$t.before($load);
$t.before(c.temp);
$(document).ajaxError(function(e, xhr, settings, exception) {
renderAjax(null, table, c, exception);
});
$.getJSON(url, function(data) {
// process data
if (typeof(c.ajaxProcessing) === "function") {
var result = c.ajaxProcessing(data), d = result[0], l = d.length,
i, k, th = [], tds = '', tf = '', hsh = $(table).addClass('hasStickyHeaders'),
sh = '.' + ((table.config.widgetOptions && table.config.widgetOptions.stickyHeaders) || 'tablesorter-stickyheader'),
$sh = $t.find(sh);
for ( i=0; i < l; i++ ) {
tds += '<tr>';
for (k in d[i]) {
if (typeof(k) === "string") {
// get new header text
if ( i === 0 ) { th.push(k); }
// build tbody cells
tds += '<td>' + d[i][k] + '</td>';
}
}
tds += '</tr>';
}
$t.find('thead tr.tablesorter-header th').each(function(j){
var $t = $(this),
// add new test within the first span it finds, or just in the header
tar = ($t.find('span').length) ? $t.find('span:first') : $t;
tar.html(th[j]);
// update sticky headers
if (hsh && $sh.length){
tar = $sh.find('th').eq(j);
tar = (tar.find('span').length) ? tar.find('span:first') : tar;
tar.html(th[j]);
}
tf += '<th>' + th[j] + '</th>';
});
$t.find('tfoot').html('<tr>' + tf + '</tr>');
$b.html(tds); // add tbody
$load.remove(); // remove loading icon
$t.trigger('update');
c.totalRows = result[1];
c.totalPages = Math.ceil(c.totalRows / c.size);
updatePageDisplay(table, c);
fixHeight(table, c);
$t.trigger('pagerChange', c);
}
renderAjax(data, table, c);
});
}
},

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,44 @@
TableSorter Change Log
Version 2.1.3 (3/12/2012)
============================
* Added `usNumberFormat` option.
* Set to `true` for U.S. number format: `1,234,567.89`
* Set to `false` for German `1.234.567,89` or French `1 234 567,89` formats.'
* Fix for [issue #34](https://github.com/Mottie/tablesorter/issues/34) and [issue # 31](https://github.com/Mottie/tablesorter/issues/31#issuecomment-4236945).
* Changed pager plugin ajax functions & demo
* The `ajaxProcessing` function now must now return two or three pieces of information: [ total, rows, headers ]
* `total` is the total number of rows in the database.
* `rows` is an array of table rows with an array of table cells in each row.
* `headers` is an array of header cell text (optional).
```javascript
// process ajax so that the following information is returned:
// [ total_rows (number), rows (array of arrays), headers (array; optional) ]
// example:
[
// total # rows contained in the database
100,
// row data: array of arrays; each internal array has the table data
[
[ "row1cell1", "row1cell2", ... "row1cellN" ],
[ "row2cell1", "row2cell2", ... "row2cellN" ],
...
[ "rowNcell1", "rowNcell2", ... "rowNcellN" ]
],
// header text (optional)
[ "Header1", "Header2", ... "HeaderN" ]
]
```
* Modified pager plugin ajax demo to hopefully make the data processing a bit more clear by changing `data` inside of the City#.json files to `rows`.
* The demo json data should now render the unicode characters properly. Switched the files to the proper utf-8 encoding.
* When no data is returned, the table will now:
* Insert a row into the header showing the ajax error. If a row is inserted into the tbody, clicking on the header would cause a parser error.
* Disable the pager so the pager counter won't show zero total rows.
* Fix for issue dicussed within [issue #31](https://github.com/Mottie/tablesorter/issues/31#issuecomment-4390379).
Version 2.1.2 (3/11/2012)
============================

View File

@ -1,7 +1,11 @@
{
{
"total_rows": "80",
"data" : [{
"cols" : [
"ID", "Name", "Country Code", "District", "Population"
],
"rows" : [{
"ID": 1,
"Name": "Kabul",
"CountryCode": "AFG",
@ -117,7 +121,7 @@
"Population": 135621
}, {
"ID": 20,
"Name": "´s-Hertogenbosch",
"Name": "´s-Hertogenbosch",
"CountryCode": "NLD",
"District": "Noord-Brabant",
"Population": 129170

View File

@ -1,7 +1,11 @@
{
"total_rows": "80",
"data" : [{
"cols" : [
"ID", "Name", "Country Code", "District", "Population"
],
"rows" : [{
"ID": 26,
"Name": "Zoetermeer",
"CountryCode": "NLD",
@ -47,7 +51,7 @@
"ID": 33,
"Name": "Willemstad",
"CountryCode": "ANT",
"District": "Curaçao",
"District": "Curaçao",
"Population": 2345
}, {
"ID": 34,
@ -87,15 +91,15 @@
"Population": 183377
}, {
"ID": 40,
"Name": "Sétif",
"Name": "Sétif",
"CountryCode": "DZA",
"District": "Sétif",
"District": "Sétif",
"Population": 179055
}, {
"ID": 41,
"Name": "Sidi Bel Abbès",
"Name": "Sidi Bel Abbès",
"CountryCode": "DZA",
"District": "Sidi Bel Abbès",
"District": "Sidi Bel Abbès",
"Population": 153106
}, {
"ID": 42,
@ -117,9 +121,9 @@
"Population": 127284
}, {
"ID": 45,
"Name": "Béjaïa",
"Name": "Béjaïa",
"CountryCode": "DZA",
"District": "Béjaïa",
"District": "Béjaïa",
"Population": 117162
}, {
"ID": 46,
@ -129,9 +133,9 @@
"Population": 115212
}, {
"ID": 47,
"Name": "Tébessa",
"Name": "Tébessa",
"CountryCode": "DZA",
"District": "Tébessa",
"District": "Tébessa",
"Population": 112007
}, {
"ID": 48,
@ -141,9 +145,9 @@
"Population": 110242
}, {
"ID": 49,
"Name": "Béchar",
"Name": "Béchar",
"CountryCode": "DZA",
"District": "Béchar",
"District": "Béchar",
"Population": 107311
}, {
"ID": 50,

View File

@ -1,7 +1,11 @@
{
"total_rows": "80",
"data" : [{
"cols" : [
"ID", "Name", "Country Code", "District", "Population"
],
"rows" : [{
"ID": 51,
"Name": "Ech-Chleff (el-Asnam)",
"CountryCode": "DZA",
@ -9,9 +13,9 @@
"Population": 96794
}, {
"ID": 52,
"Name": "Ghardaïa",
"Name": "Ghardaïa",
"CountryCode": "DZA",
"District": "Ghardaïa",
"District": "Ghardaïa",
"Population": 89415
}, {
"ID": 53,
@ -65,17 +69,17 @@
"ID": 61,
"Name": "South Hill",
"CountryCode": "AIA",
"District": "",
"District": "",
"Population": 961
}, {
"ID": 62,
"Name": "The Valley",
"CountryCode": "AIA",
"District": "",
"District": "",
"Population": 595
}, {
"ID": 63,
"Name": "Saint John´s",
"Name": "Saint John´s",
"CountryCode": "ATG",
"District": "St John",
"Population": 24000
@ -123,15 +127,15 @@
"Population": 1266461
}, {
"ID": 71,
"Name": "Córdoba",
"Name": "Córdoba",
"CountryCode": "ARG",
"District": "Córdoba",
"District": "Córdoba",
"Population": 1157507
}, {
"ID": 72,
"Name": "Rosario",
"CountryCode": "ARG",
"District": "Santa Fé",
"District": "Santa Fé",
"Population": 907718
}, {
"ID": 73,

View File

@ -1,7 +1,11 @@
{
"total_rows": "80",
"data" : [{
"cols" : [
"ID", "Name", "Country Code", "District", "Population"
],
"rows" : [{
"ID": 76,
"Name": "La Plata",
"CountryCode": "ARG",
@ -15,13 +19,13 @@
"Population": 512880
}, {
"ID": 78,
"Name": "San Miguel de Tucumán",
"Name": "San Miguel de Tucumán",
"CountryCode": "ARG",
"District": "Tucumán",
"District": "Tucumán",
"Population": 470809
}, {
"ID": 79,
"Name": "Lanús",
"Name": "Lanús",
"CountryCode": "ARG",
"District": "Buenos Aires",
"Population": 469735

View File

@ -17,47 +17,12 @@
<link rel="stylesheet" href="../css/blue/style.css">
<script src="../js/jquery.tablesorter.js"></script>
<!-- Tablesorter: optional -->
<!-- Tablesorter pager: required -->
<link rel="stylesheet" href="../addons/pager/jquery.tablesorter.pager.css">
<script src="../addons/pager/jquery.tablesorter.pager.js"></script>
<style id="css">div.tablesorterPager {
padding: 10px 0 10px 0;
background-color: #D6D2C2;
text-align: center;
}
div.tablesorterPager span {
padding: 0 5px 0 5px;
}
div.tablesorterPager input.prev {
width: auto;
margin-right: 10px;
}
div.tablesorterPager input.next {
width: auto;
margin-left: 10px;
}
div.tablesorterPager input {
font-size: 8px;
width: 50px;
border: 1px solid #330000;
text-align: center;
}
#tablesorterPagerLoading {
background: rgba(255,255,255,0.8) url(icons/loading.gif) center center no-repeat;
position: absolute;
z-index: 1000;
}/*** css used when "updateArrows" option is true ***/
/* the pager itself gets a disabled class when the number of rows is less than the size */
.pager.disabled {
display: none;
}
/* hide or fade out pager arrows when the first or last row is visible */
.pager img.disabled {
/* visibility: hidden */
opacity: 0.5;
filter: alpha(opacity=50);
}</style>
<!-- Tablesorter: optional -->
<script src="../js/jquery.tablesorter.widgets.js"></script>
<script id="js">$(function(){
@ -84,12 +49,43 @@ div.tablesorterPager input {
// use this url format "http:/mydatabase.com?page={page}&size={size}"
ajaxUrl : 'assets/City{page}.json',
// process ajax so that the data object is returned along with the total number of rows
// example: { "data" : [{ "ID": 1, "Name": "Foo", "Last": "Bar" }], "total_rows" : 100 }
ajaxProcessing: function(ajax){
if (ajax && ajax.hasOwnProperty('data')) {
// return [ "data", "total_rows" ];
return [ ajax.data, ajax.total_rows ];
// 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(data){
if (data && data.hasOwnProperty('rows')) {
var r, row, c, d = data.rows,
// total number of rows (required)
total = data.total_rows,
// array of header names (optional)
headers = data.cols,
// all rows: array of arrays; each internal array has the table cell data for that row
rows = [],
// len should match pager set size (c.size)
len = d.length;
// this will depend on how the json is set up - see City0.json
// rows
for ( r=0; r < len; r++ ) {
row = []; // new row array
// cells
for ( c in d[r] ) {
if (typeof(c) === "string") {
row.push(d[r][c]); // add each table cell data to row array
}
}
rows.push(row); // add new row array to rows array
}
return [ total, rows, headers ];
}
},
@ -142,19 +138,22 @@ div.tablesorterPager input {
<em>NOTE!</em>:
<ul>
<li>This update to the pager plugin that interacts with a database via ajax was added in version 2.0.32 and can be applied to the original tablesorter.</li>
<li>The <code>ajaxUrl</code> and <code>ajaxProcessing</code> function are both required options for this interaction to work properly.</li>
<li>The <code>ajaxUrl</code> contains a replaceable string to sent the requested page (<code>{page}</code>) and block size (<code>{size}</code>).</li>
<li>The <code>ajaxProcessing</code> function must* return the data in the following format (Note that JSON is not allowed to include comments):
<pre class="js"><code>{
"data" : [
{ "header column 1": "r1c1 text", "header column 2": "r1c2 text", ... }, // row 1 of tbody (r1c1 = row 1, column 1)
{ "header column 1": "r2c1 text", "header column 2": "r2c2 text", ... }, // row 2 of tbody
...
{ "header column 1": "rNc1 text", "header column 2": "rNc2 text", ... }, // row N of tbody
<li>The <code class="hilight">ajaxUrl</code> and <code class="hilight">ajaxProcessing</code> function are both required options for this interaction to work properly.</li>
<li>The <code class="hilight">ajaxUrl</code> contains a replaceable string to sent the requested page (<code class="hilight">{page}</code>) and block size (<code>{size}</code>).</li>
<li>The <code class="hilight">ajaxProcessing</code> function must* return the data in the following format <code class="hilight">[ total, rows, headers ]</code> - <span class="tip"><em>Modified</em></span> in 2.1.3:
<pre class="js"><code>[
// total # rows contained in the database
100,
// row data: array of arrays; each internal array has the table cell data for that row
[
[ "row1cell1", "row1cell2", ... "row1cellN" ], // first row
[ "row2cell1", "row2cell2", ... "row2cellN" ], // second row
...
[ "rowNcell1", "rowNcell2", ... "rowNcellN" ] // last row
],
"total_rows" : 100 // total # rows contained in the database
} </code></pre></li>
// header text (optional)
[ "Header1", "Header2", ... "HeaderN" ]
] </code></pre></li>
<li>The table header and footer text will be updated to match the JSON "header column #" text; but there is an issue with the table rendering improperly if the number of columns in the HTML and the number of columns in the JSON don't match.</li>
<li>Limitations of this demo:
<ul>
@ -219,24 +218,59 @@ div.tablesorterPager input {
</div>
<h1>CSS</h1>
<div id="css">
<pre class="css"></pre>
<div>
<pre class="css">div.tablesorterPager {
padding: 10px 0 10px 0;
background-color: #D6D2C2;
text-align: center;
}
div.tablesorterPager span {
padding: 0 5px 0 5px;
}
div.tablesorterPager input.prev {
width: auto;
margin-right: 10px;
}
div.tablesorterPager input.next {
width: auto;
margin-left: 10px;
}
div.tablesorterPager input {
font-size: 8px;
width: 50px;
border: 1px solid #330000;
text-align: center;
}
#tablesorterPagerLoading {
background: rgba(255,255,255,0.8) url(icons/loading.gif) center center no-repeat;
position: absolute;
z-index: 1000;
}
/*** css used when "updateArrows" option is true ***/
/* the pager itself gets a disabled class when the number of rows is less than the size */
.pager.disabled {
display: none;
}
/* hide or fade out pager arrows when the first or last row is visible */
.pager img.disabled {
/* visibility: hidden */
opacity: 0.5;
filter: alpha(opacity=50);
}</pre>
</div>
<h1>HTML</h1>
<div id="html">
<pre class="html">&lt;!-- pager --&gt;
&lt;div id=&quot;pager&quot; class=&quot;pager&quot;&gt;
&lt;form&gt;
&lt;img src=&quot;first.png&quot; class=&quot;first&quot;/&gt;
&lt;img src=&quot;prev.png&quot; class=&quot;prev&quot;/&gt;
&lt;span class=&quot;pagedisplay&quot;&gt;&lt;/span&gt; &lt;!-- this can be any element, including an input --&gt;
&lt;img src=&quot;next.png&quot; class=&quot;next&quot;/&gt;
&lt;img src=&quot;last.png&quot; class=&quot;last&quot;/&gt;
&lt;select class=&quot;pagesize&quot;&gt;
&lt;option selected=&quot;selected&quot; value=&quot;25&quot;&gt;25&lt;/option&gt;
&lt;/select&gt;
&lt;/form&gt;
&lt;div class=&quot;pager&quot;&gt;
&lt;img src=&quot;first.png&quot; class=&quot;first&quot;/&gt;
&lt;img src=&quot;prev.png&quot; class=&quot;prev&quot;/&gt;
&lt;span class=&quot;pagedisplay&quot;&gt;&lt;/span&gt; &lt;!-- this can be any element, including an input --&gt;
&lt;img src=&quot;next.png&quot; class=&quot;next&quot;/&gt;
&lt;img src=&quot;last.png&quot; class=&quot;last&quot;/&gt;
&lt;select class=&quot;pagesize&quot;&gt;
&lt;option selected=&quot;selected&quot; value=&quot;25&quot;&gt;25&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;
&lt;table class=&quot;tablesorter&quot;&gt;
@ -260,7 +294,18 @@ div.tablesorterPager input {
&lt;/tfoot&gt;
&lt;tbody&gt; &lt;!-- tbody will be loaded via JSON --&gt;
&lt;/tbody&gt;
&lt;/table&gt;</pre>
&lt;/table&gt;
&lt;div class=&quot;pager&quot;&gt;
&lt;img src=&quot;first.png&quot; class=&quot;first&quot;/&gt;
&lt;img src=&quot;prev.png&quot; class=&quot;prev&quot;/&gt;
&lt;span class=&quot;pagedisplay&quot;&gt;&lt;/span&gt; &lt;!-- this can be any element, including an input --&gt;
&lt;img src=&quot;next.png&quot; class=&quot;next&quot;/&gt;
&lt;img src=&quot;last.png&quot; class=&quot;last&quot;/&gt;
&lt;select class=&quot;pagesize&quot;&gt;
&lt;option selected=&quot;selected&quot; value=&quot;25&quot;&gt;25&lt;/option&gt;
&lt;/select&gt;
&lt;/div&gt;</pre>
</div>

View File

@ -1,6 +1,6 @@
{
"name": "tablesorter",
"version": "2.1.2",
"version": "2.1.3",
"title": "tablesorter",
"author": {
"name": "Christian Bach",