2 var header = [ 'Planet', 'Radius (km)' ],
5 mercury = [ 'Mercury', '2439.7' ],
6 venus = [ 'Venus', '6051.8' ],
7 earth = [ 'Earth', '6371.0' ],
8 mars = [ 'Mars', '3390.0' ],
9 jupiter = [ 'Jupiter', '69911' ],
10 saturn = [ 'Saturn', '58232' ],
11 planets = [ mercury, venus, earth, mars, jupiter, saturn ],
12 planetsAscName = [ earth, jupiter, mars, mercury, saturn, venus ],
13 planetsAscRadius = [ mercury, mars, venus, earth, saturn, jupiter ],
25 simple = [ a2, b3, a1, a3, b2, b1 ],
26 simpleAsc = [ a1, a2, a3, b1, b2, b3 ],
27 simpleDescasc = [ b1, b2, b3, a1, a2, a3 ],
30 header4 = [ 'column1a', 'column1b', 'column1c', 'column2' ],
31 aaa1 = [ 'A', 'A', 'A', '1' ],
32 aab5 = [ 'A', 'A', 'B', '5' ],
33 abc3 = [ 'A', 'B', 'C', '3' ],
34 bbc2 = [ 'B', 'B', 'C', '2' ],
35 caa4 = [ 'C', 'A', 'A', '4' ],
36 colspanInitial = [ aab5, aaa1, abc3, bbc2, caa4 ],
40 // Some randomly generated fake IPs
44 [ '204.204.132.158' ],
51 // Sort order should go octet by octet
58 [ '204.204.132.158' ],
85 [ 'January, 19 2010' ],
89 [ 'December 12 \'10' ]
95 [ 'January, 19 2010' ],
96 [ 'December 12 \'10' ]
115 // Comma's sort after dots
116 // Not intentional but test to detect changes
137 correctDateSorting1 = [
138 [ '01 January 2010' ],
139 [ '05 February 2010' ],
140 [ '16 January 2010' ]
142 correctDateSortingSorted1 = [
143 [ '01 January 2010' ],
144 [ '16 January 2010' ],
145 [ '05 February 2010' ]
148 correctDateSorting2 = [
149 [ 'January 01 2010' ],
150 [ 'February 05 2010' ],
151 [ 'January 16 2010' ]
153 correctDateSortingSorted2 = [
154 [ 'January 01 2010' ],
155 [ 'January 16 2010' ],
156 [ 'February 05 2010' ]
159 QUnit.module( 'jquery.tablesorter', QUnit.newMwEnvironment( {
161 this.liveMonths = mw.language.months;
162 mw.language.months = {
164 names: [ 'january', 'february', 'march', 'april', 'may_long', 'june',
165 'july', 'august', 'september', 'october', 'november', 'december' ],
166 genitive: [ 'january-gen', 'february-gen', 'march-gen', 'april-gen', 'may-gen', 'june-gen',
167 'july-gen', 'august-gen', 'september-gen', 'october-gen', 'november-gen', 'december-gen' ],
168 abbrev: [ 'jan', 'feb', 'mar', 'apr', 'may', 'jun',
169 'jul', 'aug', 'sep', 'oct', 'nov', 'dec' ]
171 names: [ 'January', 'February', 'March', 'April', 'May', 'June',
172 'July', 'August', 'September', 'October', 'November', 'December' ],
173 genitive: [ 'January', 'February', 'March', 'April', 'May', 'June',
174 'July', 'August', 'September', 'October', 'November', 'December' ],
175 abbrev: [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
176 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
179 teardown: function () {
180 mw.language.months = this.liveMonths;
183 wgDefaultDateFormat: 'dmy',
184 wgSeparatorTransformTable: [ '', '' ],
185 wgDigitTransformTable: [ '', '' ],
186 wgPageContentLanguage: 'en'
191 * Create an HTML table from an array of row arrays containing text strings.
192 * First row will be header row. No fancy rowspan/colspan stuff.
194 * @param {String[]} header
195 * @param {String[][]} data
198 function tableCreate( header, data ) {
200 $table = $( '<table class="sortable"><thead></thead><tbody></tbody></table>' ),
201 $thead = $table.find( 'thead' ),
202 $tbody = $table.find( 'tbody' ),
205 $.each( header, function ( i, str ) {
206 var $th = $( '<th>' );
207 $th.text( str ).appendTo( $tr );
209 $tr.appendTo( $thead );
211 for ( i = 0; i < data.length; i++ ) {
212 /*jshint loopfunc: true */
214 $.each( data[ i ], function ( j, str ) {
215 var $td = $( '<td>' );
216 $td.text( str ).appendTo( $tr );
218 $tr.appendTo( $tbody );
224 * Extract text from table.
226 * @param {jQuery} $table
227 * @return {String[][]}
229 function tableExtract( $table ) {
232 $table.find( 'tbody' ).find( 'tr' ).each( function ( i, tr ) {
234 $( tr ).find( 'td,th' ).each( function ( i, td ) {
235 row.push( $( td ).text() );
243 * Run a table test by building a table with the given data,
244 * running some callback on it, then checking the results.
246 * @param {String} msg text to pass on to qunit for the comparison
247 * @param {String[]} header cols to make the table
248 * @param {String[][]} data rows/cols to make the table
249 * @param {String[][]} expected rows/cols to compare against at end
250 * @param {function($table)} callback something to do with the table before we compare
252 function tableTest( msg, header, data, expected, callback ) {
253 QUnit.test( msg, 1, function ( assert ) {
255 $table = tableCreate( header, data );
257 // Give caller a chance to set up sorting and manipulate the table.
260 // Table sorting is done synchronously; if it ever needs to change back
261 // to asynchronous, we'll need a timeout or a callback here.
262 extracted = tableExtract( $table );
263 assert.deepEqual( extracted, expected, msg );
268 * Run a table test by building a table with the given HTML,
269 * running some callback on it, then checking the results.
271 * @param {String} msg text to pass on to qunit for the comparison
272 * @param {String} HTML to make the table
273 * @param {String[][]} expected rows/cols to compare against at end
274 * @param {function($table)} callback something to do with the table before we compare
276 function tableTestHTML( msg, html, expected, callback ) {
277 QUnit.test( msg, 1, function ( assert ) {
281 // Give caller a chance to set up sorting and manipulate the table.
285 $table.tablesorter();
286 $table.find( '#sortme' ).click();
289 // Table sorting is done synchronously; if it ever needs to change back
290 // to asynchronous, we'll need a timeout or a callback here.
291 extracted = tableExtract( $table );
292 assert.deepEqual( extracted, expected, msg );
296 function reversed( arr ) {
298 var arr2 = arr.slice( 0 );
305 // Sample data set using planets named and their radius
308 'Basic planet table: sorting initially - ascending by name',
312 function ( $table ) {
313 $table.tablesorter( { sortList: [
319 'Basic planet table: sorting initially - descending by radius',
322 reversed( planetsAscRadius ),
323 function ( $table ) {
324 $table.tablesorter( { sortList: [
330 'Basic planet table: ascending by name',
334 function ( $table ) {
335 $table.tablesorter();
336 $table.find( '.headerSort:eq(0)' ).click();
340 'Basic planet table: ascending by name a second time',
344 function ( $table ) {
345 $table.tablesorter();
346 $table.find( '.headerSort:eq(0)' ).click();
350 'Basic planet table: ascending by name (multiple clicks)',
354 function ( $table ) {
355 $table.tablesorter();
356 $table.find( '.headerSort:eq(0)' ).click();
357 $table.find( '.headerSort:eq(1)' ).click();
358 $table.find( '.headerSort:eq(0)' ).click();
362 'Basic planet table: descending by name',
365 reversed( planetsAscName ),
366 function ( $table ) {
367 $table.tablesorter();
368 $table.find( '.headerSort:eq(0)' ).click().click();
372 'Basic planet table: ascending radius',
376 function ( $table ) {
377 $table.tablesorter();
378 $table.find( '.headerSort:eq(1)' ).click();
382 'Basic planet table: descending radius',
385 reversed( planetsAscRadius ),
386 function ( $table ) {
387 $table.tablesorter();
388 $table.find( '.headerSort:eq(1)' ).click().click();
392 'Sorting multiple columns by passing sort list',
396 function ( $table ) {
406 'Sorting multiple columns by programmatically triggering sort()',
410 function ( $table ) {
411 $table.tablesorter();
412 $table.data( 'tablesorter' ).sort(
421 'Reset to initial sorting by triggering sort() without any parameters',
425 function ( $table ) {
432 $table.data( 'tablesorter' ).sort(
438 $table.data( 'tablesorter' ).sort();
442 'Sort via click event after having initialized the tablesorter with initial sorting',
446 function ( $table ) {
448 { sortList: [ { 0: 'asc' }, { 1: 'asc' } ] }
450 $table.find( '.headerSort:eq(0)' ).click();
454 'Multi-sort via click event after having initialized the tablesorter with initial sorting',
458 function ( $table ) {
460 { sortList: [ { 0: 'desc' }, { 1: 'desc' } ] }
462 $table.find( '.headerSort:eq(0)' ).click();
464 // Pretend to click while pressing the multi-sort key
465 var event = $.Event( 'click' );
466 event[ $table.data( 'tablesorter' ).config.sortMultiSortKey ] = true;
467 $table.find( '.headerSort:eq(1)' ).trigger( event );
470 QUnit.test( 'Reset sorting making table appear unsorted', 3, function ( assert ) {
471 var $table = tableCreate( header, simple );
478 $table.data( 'tablesorter' ).sort( [] );
481 $table.find( 'th.headerSortUp' ).length + $table.find( 'th.headerSortDown' ).length,
483 'No sort specific sort classes addign to header cells'
487 $table.find( 'th' ).first().attr( 'title' ),
488 mw.msg( 'sort-ascending' ),
489 'First header cell has default title'
493 $table.find( 'th' ).first().attr( 'title' ),
494 $table.find( 'th' ).last().attr( 'title' ),
495 'Both header cells\' titles match'
499 // Sorting with colspans
501 tableTest( 'Sorting with colspanned headers: spanned column',
504 [ aaa1, aab5, abc3, bbc2, caa4 ],
505 function ( $table ) {
506 // Make colspanned header for test
507 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
508 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
510 $table.tablesorter();
511 $table.find( '.headerSort:eq(0)' ).click();
514 tableTest( 'Sorting with colspanned headers: sort spanned column twice',
517 [ caa4, bbc2, abc3, aab5, aaa1 ],
518 function ( $table ) {
519 // Make colspanned header for test
520 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
521 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
523 $table.tablesorter();
524 $table.find( '.headerSort:eq(0)' ).click();
525 $table.find( '.headerSort:eq(0)' ).click();
528 tableTest( 'Sorting with colspanned headers: subsequent column',
531 [ aaa1, bbc2, abc3, caa4, aab5 ],
532 function ( $table ) {
533 // Make colspanned header for test
534 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
535 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
537 $table.tablesorter();
538 $table.find( '.headerSort:eq(1)' ).click();
541 tableTest( 'Sorting with colspanned headers: sort subsequent column twice',
544 [ aab5, caa4, abc3, bbc2, aaa1 ],
545 function ( $table ) {
546 // Make colspanned header for test
547 $table.find( 'tr:eq(0) th:eq(1), tr:eq(0) th:eq(2)' ).remove();
548 $table.find( 'tr:eq(0) th:eq(0)' ).attr( 'colspan', '3' );
550 $table.tablesorter();
551 $table.find( '.headerSort:eq(1)' ).click();
552 $table.find( '.headerSort:eq(1)' ).click();
556 QUnit.test( 'Basic planet table: one unsortable column', 3, function ( assert ) {
557 var $table = tableCreate( header, planets ),
559 $table.find( 'tr:eq(0) > th:eq(0)' ).addClass( 'unsortable' );
561 $table.tablesorter();
562 $table.find( 'tr:eq(0) > th:eq(0)' ).click();
565 tableExtract( $table ),
570 $cell = $table.find( 'tr:eq(0) > th:eq(0)' );
571 $table.find( 'tr:eq(0) > th:eq(1)' ).click();
574 $cell.hasClass( 'headerSortUp' ) || $cell.hasClass( 'headerSortDown' ),
576 'after sort: no class headerSortUp or headerSortDown'
580 $cell.attr( 'title' ),
582 'after sort: no title tag added'
589 'Bug 28775: German-style (dmy) short numeric dates',
592 // German-style dates are day-month-year
600 // Sorted by ascending date
607 function ( $table ) {
608 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
609 mw.config.set( 'wgPageContentLanguage', 'de' );
611 $table.tablesorter();
612 $table.find( '.headerSort:eq(0)' ).click();
617 'Bug 28775: American-style (mdy) short numeric dates',
620 // American-style dates are month-day-year
628 // Sorted by ascending date
635 function ( $table ) {
636 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
638 $table.tablesorter();
639 $table.find( '.headerSort:eq(0)' ).click();
644 'Bug 17141: IPv4 address sorting',
648 function ( $table ) {
649 $table.tablesorter();
650 $table.find( '.headerSort:eq(0)' ).click();
654 'Bug 17141: IPv4 address sorting (reverse)',
657 reversed( ipv4Sorted ),
658 function ( $table ) {
659 $table.tablesorter();
660 $table.find( '.headerSort:eq(0)' ).click().click();
665 'Accented Characters with custom collation',
669 function ( $table ) {
670 mw.config.set( 'tableSorterCollation', {
677 $table.tablesorter();
678 $table.find( '.headerSort:eq(0)' ).click();
682 QUnit.test( 'Rowspan not exploded on init', 1, function ( assert ) {
683 var $table = tableCreate( header, planets );
685 // Modify the table to have a multiple-row-spanning cell:
686 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
687 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
688 // - Set rowspan for 2nd cell of 3rd row to 3.
689 // This covers the removed cell in the 4th and 5th row.
690 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
692 $table.tablesorter();
695 $table.find( 'tr:eq(2) td:eq(1)' ).prop( 'rowSpan' ),
697 'Rowspan not exploded'
702 [ 'Earth', '6051.8' ],
704 [ 'Mars', '6051.8' ],
709 planetsRowspanII = [ jupiter, mercury, saturn, venus, [ 'Venus', '6371.0' ], [ 'Venus', '3390.0' ] ];
712 'Basic planet table: same value for multiple rows via rowspan',
716 function ( $table ) {
717 // Modify the table to have a multiple-row-spanning cell:
718 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
719 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
720 // - Set rowspan for 2nd cell of 3rd row to 3.
721 // This covers the removed cell in the 4th and 5th row.
722 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
724 $table.tablesorter();
725 $table.find( '.headerSort:eq(0)' ).click();
729 'Basic planet table: same value for multiple rows via rowspan (sorting initially)',
733 function ( $table ) {
734 // Modify the table to have a multiple-row-spanning cell:
735 // - Remove 2nd cell of 4th row, and, 2nd cell or 5th row.
736 $table.find( 'tr:eq(3) td:eq(1), tr:eq(4) td:eq(1)' ).remove();
737 // - Set rowspan for 2nd cell of 3rd row to 3.
738 // This covers the removed cell in the 4th and 5th row.
739 $table.find( 'tr:eq(2) td:eq(1)' ).attr( 'rowspan', '3' );
741 $table.tablesorter( { sortList: [
747 'Basic planet table: Same value for multiple rows via rowspan II',
751 function ( $table ) {
752 // Modify the table to have a multiple-row-spanning cell:
753 // - Remove 1st cell of 4th row, and, 1st cell or 5th row.
754 $table.find( 'tr:eq(3) td:eq(0), tr:eq(4) td:eq(0)' ).remove();
755 // - Set rowspan for 1st cell of 3rd row to 3.
756 // This covers the removed cell in the 4th and 5th row.
757 $table.find( 'tr:eq(2) td:eq(0)' ).attr( 'rowspan', '3' );
759 $table.tablesorter();
760 $table.find( '.headerSort:eq(0)' ).click();
765 'Complex date parsing I',
769 function ( $table ) {
770 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
772 $table.tablesorter();
773 $table.find( '.headerSort:eq(0)' ).click();
778 'Currency parsing I',
782 function ( $table ) {
783 $table.tablesorter();
784 $table.find( '.headerSort:eq(0)' ).click();
788 planetsAscNameLegacy = planetsAscName.slice( 0 );
789 planetsAscNameLegacy[ 4 ] = planetsAscNameLegacy[ 5 ];
790 planetsAscNameLegacy.pop();
793 'Legacy compat with .sortbottom',
796 planetsAscNameLegacy,
797 function ( $table ) {
798 $table.find( 'tr:last' ).addClass( 'sortbottom' );
799 $table.tablesorter();
800 $table.find( '.headerSort:eq(0)' ).click();
804 QUnit.test( 'Test detection routine', 1, function ( assert ) {
807 '<table class="sortable">' +
808 '<caption>CAPTION</caption>' +
809 '<tr><th>THEAD</th></tr>' +
810 '<tr><td>1</td></tr>' +
811 '<tr class="sortbottom"><td>text</td></tr>' +
814 $table.tablesorter();
815 $table.find( '.headerSort:eq(0)' ).click();
818 $table.data( 'tablesorter' ).config.parsers[ 0 ].id,
820 'Correctly detected column content skipping sortbottom'
824 /** FIXME: the diff output is not very readeable. */
825 QUnit.test( 'bug 32047 - caption must be before thead', 1, function ( assert ) {
828 '<table class="sortable">' +
829 '<caption>CAPTION</caption>' +
830 '<tr><th>THEAD</th></tr>' +
831 '<tr><td>A</td></tr>' +
832 '<tr><td>B</td></tr>' +
833 '<tr class="sortbottom"><td>TFOOT</td></tr>' +
836 $table.tablesorter();
839 $table.children().get( 0 ).nodeName,
841 'First element after <thead> must be <caption> (bug 32047)'
845 QUnit.test( 'data-sort-value attribute, when available, should override sorting position', 3, function ( assert ) {
848 // Example 1: All cells except one cell without data-sort-value,
849 // which should be sorted at it's text content value.
851 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
853 '<tr><td>Cheetah</td></tr>' +
854 '<tr><td data-sort-value="Apple">Bird</td></tr>' +
855 '<tr><td data-sort-value="Bananna">Ferret</td></tr>' +
856 '<tr><td data-sort-value="Drupe">Elephant</td></tr>' +
857 '<tr><td data-sort-value="Cherry">Dolphin</td></tr>' +
860 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
863 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
864 $( tr ).find( 'td' ).each( function ( i, td ) {
866 data: $( td ).data( 'sortValue' ),
872 assert.deepEqual( data, [
893 ], 'Order matches expected order (based on data-sort-value attribute values)' );
897 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
899 '<tr><td>D</td></tr>' +
900 '<tr><td data-sort-value="E">A</td></tr>' +
901 '<tr><td>B</td></tr>' +
902 '<tr><td>G</td></tr>' +
903 '<tr><td data-sort-value="F">C</td></tr>' +
906 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
909 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
910 $( tr ).find( 'td' ).each( function ( i, td ) {
912 data: $( td ).data( 'sortValue' ),
918 assert.deepEqual( data, [
939 ], 'Order matches expected order (based on data-sort-value attribute values)' );
941 // Example 3: Test that live changes are used from data-sort-value,
942 // even if they change after the tablesorter is constructed (bug 38152).
944 '<table class="sortable"><thead><tr><th>Data</th></tr></thead>' +
946 '<tr><td>D</td></tr>' +
947 '<tr><td data-sort-value="1">A</td></tr>' +
948 '<tr><td>B</td></tr>' +
949 '<tr><td data-sort-value="2">G</td></tr>' +
950 '<tr><td>C</td></tr>' +
953 // initialize table sorter and sort once
956 .find( '.headerSort:eq(0)' ).click();
958 // Change the sortValue data properties (bug 38152)
960 $table.find( 'td:contains(A)' ).data( 'sortValue', 3 );
962 $table.find( 'td:contains(B)' ).data( 'sortValue', 1 );
963 // - remove data, bring back attribute: 2
964 $table.find( 'td:contains(G)' ).removeData( 'sortValue' );
966 // Now sort again (twice, so it is back at Ascending)
967 $table.find( '.headerSort:eq(0)' ).click();
968 $table.find( '.headerSort:eq(0)' ).click();
971 $table.find( 'tbody > tr' ).each( function ( i, tr ) {
972 $( tr ).find( 'td' ).each( function ( i, td ) {
974 data: $( td ).data( 'sortValue' ),
980 assert.deepEqual( data, [
1001 ], 'Order matches expected order, using the current sortValue in $.data()' );
1005 tableTest( 'bug 8115: sort numbers with commas (ascending)',
1006 [ 'Numbers' ], numbers, numbersAsc,
1007 function ( $table ) {
1008 $table.tablesorter();
1009 $table.find( '.headerSort:eq(0)' ).click();
1013 tableTest( 'bug 8115: sort numbers with commas (descending)',
1014 [ 'Numbers' ], numbers, reversed( numbersAsc ),
1015 function ( $table ) {
1016 $table.tablesorter();
1017 $table.find( '.headerSort:eq(0)' ).click().click();
1020 // TODO add numbers sorting tests for bug 8115 with a different language
1022 QUnit.test( 'bug 32888 - Tables inside a tableheader cell', 2, function ( assert ) {
1025 '<table class="sortable" id="mw-bug-32888">' +
1026 '<tr><th>header<table id="mw-bug-32888-2">' +
1027 '<tr><th>1</th><th>2</th></tr>' +
1028 '</table></th></tr>' +
1029 '<tr><td>A</td></tr>' +
1030 '<tr><td>B</td></tr>' +
1033 $table.tablesorter();
1036 $table.find( '> thead:eq(0) > tr > th.headerSort' ).length,
1038 'Child tables inside a headercell should not interfere with sortable headers (bug 32888)'
1041 $( '#mw-bug-32888-2' ).find( 'th.headerSort' ).length,
1043 'The headers of child tables inside a headercell should not be sortable themselves (bug 32888)'
1048 'Correct date sorting I',
1050 correctDateSorting1,
1051 correctDateSortingSorted1,
1052 function ( $table ) {
1053 mw.config.set( 'wgDefaultDateFormat', 'mdy' );
1055 $table.tablesorter();
1056 $table.find( '.headerSort:eq(0)' ).click();
1061 'Correct date sorting II',
1063 correctDateSorting2,
1064 correctDateSortingSorted2,
1065 function ( $table ) {
1066 mw.config.set( 'wgDefaultDateFormat', 'dmy' );
1068 $table.tablesorter();
1069 $table.find( '.headerSort:eq(0)' ).click();
1073 QUnit.test( 'Sorting images using alt text', 1, function ( assert ) {
1075 '<table class="sortable">' +
1076 '<tr><th>THEAD</th></tr>' +
1077 '<tr><td><img alt="2"/></td></tr>' +
1078 '<tr><td>1</td></tr>' +
1081 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1084 $table.find( 'td' ).first().text(),
1086 'Applied correct sorting order'
1090 QUnit.test( 'Sorting images using alt text (complex)', 1, function ( assert ) {
1092 '<table class="sortable">' +
1093 '<tr><th>THEAD</th></tr>' +
1094 '<tr><td><img alt="D" />A</td></tr>' +
1095 '<tr><td>CC</td></tr>' +
1096 '<tr><td><a><img alt="A" /></a>F</tr>' +
1097 '<tr><td><img alt="A" /><strong>E</strong></tr>' +
1098 '<tr><td><strong><img alt="A" />D</strong></tr>' +
1099 '<tr><td><img alt="A" />C</tr>' +
1102 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1105 $table.find( 'td' ).text(),
1107 'Applied correct sorting order'
1111 QUnit.test( 'Sorting images using alt text (with format autodetection)', 1, function ( assert ) {
1113 '<table class="sortable">' +
1114 '<tr><th>THEAD</th></tr>' +
1115 '<tr><td><img alt="1" />7</td></tr>' +
1116 '<tr><td>1<img alt="6" /></td></tr>' +
1117 '<tr><td>5</td></tr>' +
1118 '<tr><td>4</td></tr>' +
1121 $table.tablesorter().find( '.headerSort:eq(0)' ).click();
1124 $table.find( 'td' ).text(),
1126 'Applied correct sorting order'
1130 QUnit.test( 'bug 38911 - The row with the largest amount of columns should receive the sort indicators', 3, function ( assert ) {
1132 '<table class="sortable">' +
1134 '<tr><th rowspan="2" id="A1">A1</th><th colspan="2">B2a</th></tr>' +
1135 '<tr><th id="B2b">B2b</th><th id="C2b">C2b</th></tr>' +
1137 '<tr><td>A</td><td>Aa</td><td>Ab</td></tr>' +
1138 '<tr><td>B</td><td>Ba</td><td>Bb</td></tr>' +
1141 $table.tablesorter();
1144 $table.find( '#A1' ).attr( 'class' ),
1146 'The first column of the first row should be sortable'
1149 $table.find( '#B2b' ).attr( 'class' ),
1151 'The th element of the 2nd row of the 2nd column should be sortable'
1154 $table.find( '#C2b' ).attr( 'class' ),
1156 'The th element of the 2nd row of the 3rd column should be sortable'
1160 QUnit.test( 'rowspans in table headers should prefer the last row when rows are equal in length', 2, function ( assert ) {
1162 '<table class="sortable">' +
1164 '<tr><th rowspan="2" id="A1">A1</th><th>B2a</th></tr>' +
1165 '<tr><th id="B2b">B2b</th></tr>' +
1167 '<tr><td>A</td><td>Aa</td></tr>' +
1168 '<tr><td>B</td><td>Ba</td></tr>' +
1171 $table.tablesorter();
1174 $table.find( '#A1' ).attr( 'class' ),
1176 'The first column of the first row should be sortable'
1179 $table.find( '#B2b' ).attr( 'class' ),
1181 'The th element of the 2nd row of the 2nd column should be sortable'
1185 QUnit.test( 'holes in the table headers should not throw JS errors', 2, function ( assert ) {
1187 '<table class="sortable">' +
1189 '<tr><th id="A1">A1</th><th>B1</th><th id="C1" rowspan="2">C1</th></tr>' +
1190 '<tr><th id="A2">A2</th></tr>' +
1192 '<tr><td>A</td><td>Aa</td><td>Aaa</td></tr>' +
1193 '<tr><td>B</td><td>Ba</td><td>Bbb</td></tr>' +
1196 $table.tablesorter();
1197 assert.equal( $table.find( '#A2' ).data( 'headerIndex' ),
1199 'A2 should not be a sort header'
1201 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1203 'C1 should be a sort header'
1208 QUnit.test( 'td cells in thead should not be taken into account for longest row calculation', 2, function ( assert ) {
1210 '<table class="sortable">' +
1212 '<tr><th id="A1">A1</th><th>B1</th><td id="C1">C1</td></tr>' +
1213 '<tr><th id="A2">A2</th><th>B2</th><th id="C2">C2</th></tr>' +
1217 $table.tablesorter();
1218 assert.equal( $table.find( '#C2' ).data( 'headerIndex' ),
1220 'C2 should be a sort header'
1222 assert.equal( $table.find( '#C1' ).data( 'headerIndex' ),
1224 'C1 should not be a sort header'
1228 // bug 41889 - exploding rowspans in more complex cases
1230 'Rowspan exploding with row headers',
1231 '<table class="sortable">' +
1232 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1234 '<tr><td>1</td><th rowspan="2">foo</th><td rowspan="2">bar</td><td>baz</td></tr>' +
1235 '<tr><td>2</td><td>baz</td></tr>' +
1238 [ '1', 'foo', 'bar', 'baz' ],
1239 [ '2', 'foo', 'bar', 'baz' ]
1243 // bug 53211 - exploding rowspans in more complex cases
1245 'Rowspan exploding with row headers and colspans', 1, function ( assert ) {
1246 var $table = $( '<table class="sortable">' +
1247 '<thead><tr><th rowspan="2">n</th><th colspan="2">foo</th><th rowspan="2">baz</th></tr>' +
1248 '<tr><th>foo</th><th>bar</th></tr></thead>' +
1250 '<tr><td>1</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1251 '<tr><td>2</td><td>foo</td><td>bar</td><td>baz</td></tr>' +
1252 '</tbody></table>' );
1254 $table.tablesorter();
1255 assert.equal( $table.find( 'tr:eq(1) th:eq(1)' ).data( 'headerIndex' ),
1257 'Incorrect index of sort header'
1263 'Rowspan exploding with colspanned cells',
1264 '<table class="sortable">' +
1265 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1267 '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td></tr>' +
1268 '<tr><td>2</td><td colspan="2">foobar</td></tr>' +
1271 [ '1', 'foo', 'bar', 'baz' ],
1272 [ '2', 'foobar', 'baz' ]
1277 'Rowspan exploding with colspanned cells (2)',
1278 '<table class="sortable">' +
1279 '<thead><tr><th>n</th><th>foo</th><th>bar</th><th>baz</th><th id="sortme">n2</th></tr></thead>' +
1281 '<tr><td>1</td><td>foo</td><td>bar</td><td rowspan="2">baz</td><td>2</td></tr>' +
1282 '<tr><td>2</td><td colspan="2">foobar</td><td>1</td></tr>' +
1285 [ '2', 'foobar', 'baz', '1' ],
1286 [ '1', 'foo', 'bar', 'baz', '2' ]
1291 'Rowspan exploding with rightmost rows spanning most',
1292 '<table class="sortable">' +
1293 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th></tr></thead>' +
1295 '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td></tr>' +
1296 '<tr><td>2</td></tr>' +
1297 '<tr><td>3</td><td rowspan="2">foo</td></tr>' +
1298 '<tr><td>4</td></tr>' +
1301 [ '1', 'foo', 'bar' ],
1302 [ '2', 'foo', 'bar' ],
1303 [ '3', 'foo', 'bar' ],
1304 [ '4', 'foo', 'bar' ]
1309 'Rowspan exploding with rightmost rows spanning most (2)',
1310 '<table class="sortable">' +
1311 '<thead><tr><th id="sortme">n</th><th>foo</th><th>bar</th><th>baz</th></tr></thead>' +
1313 '<tr><td>1</td><td rowspan="2">foo</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1314 '<tr><td>2</td><td>baz</td></tr>' +
1315 '<tr><td>3</td><td rowspan="2">foo</td><td>baz</td></tr>' +
1316 '<tr><td>4</td><td>baz</td></tr>' +
1319 [ '1', 'foo', 'bar', 'baz' ],
1320 [ '2', 'foo', 'bar', 'baz' ],
1321 [ '3', 'foo', 'bar', 'baz' ],
1322 [ '4', 'foo', 'bar', 'baz' ]
1327 'Rowspan exploding with row-and-colspanned cells',
1328 '<table class="sortable">' +
1329 '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>bar</th><th>baz</th></tr></thead>' +
1331 '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="4">bar</td><td>baz</td></tr>' +
1332 '<tr><td>2</td><td>baz</td></tr>' +
1333 '<tr><td>3</td><td colspan="2" rowspan="2">foo</td><td>baz</td></tr>' +
1334 '<tr><td>4</td><td>baz</td></tr>' +
1337 [ '1', 'foo1', 'foo2', 'bar', 'baz' ],
1338 [ '2', 'foo1', 'foo2', 'bar', 'baz' ],
1339 [ '3', 'foo', 'bar', 'baz' ],
1340 [ '4', 'foo', 'bar', 'baz' ]
1345 'Rowspan exploding with uneven rowspan layout',
1346 '<table class="sortable">' +
1347 '<thead><tr><th id="sortme">n</th><th>foo1</th><th>foo2</th><th>foo3</th><th>bar</th><th>baz</th></tr></thead>' +
1349 '<tr><td>1</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>bar</td><td>baz</td></tr>' +
1350 '<tr><td>2</td><td rowspan="3">bar</td><td>baz</td></tr>' +
1351 '<tr><td>3</td><td rowspan="2">foo1</td><td rowspan="2">foo2</td><td rowspan="2">foo3</td><td>baz</td></tr>' +
1352 '<tr><td>4</td><td>baz</td></tr>' +
1355 [ '1', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1356 [ '2', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1357 [ '3', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ],
1358 [ '4', 'foo1', 'foo2', 'foo3', 'bar', 'baz' ]
1362 QUnit.test( 'bug 105731 - incomplete rows in table body', 3, function ( assert ) {
1363 var $table, parsers;
1365 '<table class="sortable">' +
1366 '<tr><th>A</th><th>B</th></tr>' +
1367 '<tr><td>3</td></tr>' +
1368 '<tr><td>1</td><td>2</td></tr>' +
1371 $table.tablesorter();
1372 $table.find( '.headerSort:eq(0)' ).click();
1373 // now the first row have 2 columns
1374 $table.find( '.headerSort:eq(1)' ).click();
1376 parsers = $table.data( 'tablesorter' ).config.parsers;
1381 'detectParserForColumn() detect 2 parsers'
1387 'detectParserForColumn() detect parser.id "number" for second column'
1391 parsers[ 1 ].format( $table.find( 'tbody > tr > td:eq(1)' ).text() ),
1393 'empty cell is sorted as number 0'
1397 }( jQuery, mediaWiki ) );